51 use mpi_f08,
only: mpi_allreduce, mpi_min, mpi_in_place, mpi_integer
67 use,
intrinsic :: iso_c_binding
74 real(kind=
rp),
allocatable :: r(:)
75 real(kind=
rp),
allocatable :: b(:)
76 real(kind=
rp),
allocatable :: x(:)
77 type(c_ptr) :: r_d = c_null_ptr
78 type(c_ptr) :: b_d = c_null_ptr
79 type(c_ptr) :: x_d = c_null_ptr
112 max_iter, cheby_degree)
114 class(
ax_t),
target,
intent(in) :: ax
115 type(
space_t),
target,
intent(in) :: Xh
116 type(
coef_t),
target,
intent(in) :: coef
117 type(
mesh_t),
target,
intent(in) :: msh
118 type(
gs_t),
target,
intent(in) :: gs_h
119 type(
bc_list_t),
target,
intent(in) :: blst
120 integer,
intent(in) :: nlvls
121 integer,
intent(in) :: max_iter
122 integer,
intent(in) :: cheby_degree
123 integer :: lvl, n, mlvl, target_num_aggs
124 integer,
allocatable :: agg_nhbr(:,:), nhbr_tmp(:,:)
125 character(len=LOG_SIZE) :: log_buf
126 integer :: glb_min_target_aggs
127 logical :: use_greedy_agg
131 write(log_buf,
'(A28,I2,A8)')
'Creating AMG hierarchy with', &
136 call this%amg%init(ax, xh, coef, msh, gs_h, nlvls, blst)
139 use_greedy_agg = .true.
144 allocate( agg_nhbr, source = msh%facet_neigh )
147 if (use_greedy_agg)
then
148 target_num_aggs = this%amg%lvl(mlvl-1)%nnodes / 8
150 target_num_aggs = this%amg%lvl(mlvl-1)%nnodes / 2
153 glb_min_target_aggs = target_num_aggs
154 call mpi_allreduce(mpi_in_place, glb_min_target_aggs, 1, &
156 if (glb_min_target_aggs .lt. 4 )
then
158 "TAMG: Too many levels. Not enough DOFs for coarsest grid.")
159 this%amg%nlvls = mlvl
163 if (use_greedy_agg)
then
174 deallocate( nhbr_tmp )
176 deallocate( agg_nhbr )
181 this%max_iter = max_iter
183 this%nlvls = this%amg%nlvls
184 if (this%nlvls .gt. this%amg%nlvls)
then
186 "Requested number multigrid levels &
187 & is greater than the initialized AMG levels")
191 allocate(this%smoo(0:(this%amg%nlvls)))
192 do lvl = 0, this%amg%nlvls-1
193 n = this%amg%lvl(lvl+1)%fine_lvl_dofs
194 call this%smoo(lvl)%init(n, lvl, cheby_degree)
198 allocate(this%wrk(0:(this%amg%nlvls)))
199 do lvl = 0, this%amg%nlvls-1
200 n = this%amg%lvl(lvl+1)%fine_lvl_dofs
202 allocate( this%wrk(lvl)%r(n) )
203 allocate( this%wrk(lvl)%b(n) )
204 allocate( this%wrk(lvl)%x(n) )
206 call device_map( this%wrk(lvl)%r, this%wrk(lvl)%r_d, n)
207 call device_map( this%wrk(lvl)%b, this%wrk(lvl)%b_d, n)
208 call device_map( this%wrk(lvl)%x, this%wrk(lvl)%x_d, n)
233 if (
allocated(this%amg))
then
237 if (
allocated(this%smoo))
then
238 do i = 0, (
size(this%smoo)-1)
239 call this%smoo(i)%free()
241 deallocate(this%smoo)
243 if (
allocated(this%wrk))
then
244 do i = 0, (
size(this%wrk)-1)
245 if (
allocated(this%wrk(i)%r))
then
247 c_associated(this%wrk(i)%r_d))
then
250 deallocate(this%wrk(i)%r)
252 if (
allocated(this%wrk(i)%b))
then
254 c_associated(this%wrk(i)%b_d))
then
257 deallocate(this%wrk(i)%b)
259 if (
allocated(this%wrk(i)%x))
then
261 c_associated(this%wrk(i)%x_d))
then
264 deallocate(this%wrk(i)%x)
276 do lvl = 0, this%amg%nlvls-1
277 this%smoo(lvl)%recompute_eigs = .true.
287 logical,
intent(in) :: warm_start
288 integer,
intent(in) :: power_its_refresh
290 do lvl = 0, this%amg%nlvls-1
291 this%smoo(lvl)%warm_start_eigs = warm_start
292 this%smoo(lvl)%power_its_refresh = power_its_refresh
302 integer,
intent(in) :: n
304 real(kind=
rp),
dimension(n),
intent(inout) :: z
305 real(kind=
rp),
dimension(n),
intent(inout) :: r
308 integer :: iter, max_iter, i
309 logical :: zero_initial_guess
311 max_iter = this%max_iter
320 zero_initial_guess = .true.
322 do iter = 1, max_iter
323 call this%mg_cycle_d(zero_initial_guess)
324 zero_initial_guess = .false.
336 this%wrk(0)%x(i) = 0.0_rp
337 this%wrk(0)%b(i) = r(i)
340 zero_initial_guess = .true.
342 do iter = 1, max_iter
343 call this%mg_cycle(zero_initial_guess)
344 zero_initial_guess = .false.
346 call copy(z, this%wrk(0)%x, n)
356 logical,
intent(inout) :: zero_initial_guess
357 character(len=2) :: lvl_name
358 integer :: max_lvl, lvl
360 max_lvl = this%nlvls-1
362 do lvl = 0, max_lvl-1
363 write(lvl_name,
'(I0)') lvl
365 associate(x => this%wrk(lvl)%x, b => this%wrk(lvl)%b, &
366 r => this%wrk(lvl)%r, n => this%wrk(lvl)%n)
370 call this%smoo(lvl)%solve(x, b, n, this%amg, &
379 call this%amg%interp_f2c(this%wrk(lvl+1)%b, r, lvl+1)
381 call rzero(this%wrk(lvl+1)%x, this%wrk(lvl+1)%n)
382 zero_initial_guess = .true.
386 write(lvl_name,
'(I0)') max_lvl
391 call this%smoo(max_lvl)%solve(this%wrk(max_lvl)%x, &
392 this%wrk(max_lvl)%b, this%amg%lvl(max_lvl)%nnodes, this%amg, &
396 zero_initial_guess = .false.
398 do lvl = max_lvl-1, 0, -1
399 write(lvl_name,
'(I0)') lvl
401 associate(x => this%wrk(lvl)%x, b => this%wrk(lvl)%b, &
402 r => this%wrk(lvl)%r, n => this%wrk(lvl)%n)
406 call this%amg%interp_c2f(r, this%wrk(lvl+1)%x, lvl+1)
414 call this%smoo(lvl)%solve(x, b, n, this%amg)
416 call profiler_end_region(
"AMG_level_" // trim(lvl_name))
425 logical,
intent(inout) :: zero_initial_guess
426 character(len=2) :: lvl_name
427 integer :: max_lvl, lvl
429 max_lvl = this%nlvls-1
431 do lvl = 0, max_lvl-1
432 write(lvl_name,
'(I0)') lvl
433 call profiler_start_region(
"AMG_level_" // trim(lvl_name))
434 associate(x => this%wrk(lvl)%x, x_d => this%wrk(lvl)%x_d, &
435 b => this%wrk(lvl)%b, b_d => this%wrk(lvl)%b_d, &
436 r => this%wrk(lvl)%r, r_d => this%wrk(lvl)%r_d, &
437 n => this%wrk(lvl)%n)
441 call this%smoo(lvl)%device_solve(x, b, x_d, b_d, n, this%amg, &
446 call this%amg%device_matvec(r, x, r_d, x_d, lvl)
447 call device_sub3(r_d, b_d, r_d, n)
451 call this%amg%interp_f2c_d(this%wrk(lvl+1)%b_d, r_d, lvl+1)
453 call device_rzero(this%wrk(lvl+1)%x_d, this%wrk(lvl+1)%n)
454 zero_initial_guess = .true.
456 call profiler_end_region(
"AMG_level_" // trim(lvl_name))
458 write(lvl_name,
'(I0)') max_lvl
459 call profiler_start_region(
"AMG_level_" // trim(lvl_name))
463 call this%smoo(max_lvl)%device_solve( &
464 this%wrk(max_lvl)%x, this%wrk(max_lvl)%b, &
465 this%wrk(max_lvl)%x_d, this%wrk(max_lvl)%b_d, &
466 this%amg%lvl(max_lvl)%nnodes, this%amg, &
468 call profiler_end_region(
"AMG_level_" // trim(lvl_name))
470 zero_initial_guess = .false.
472 do lvl = max_lvl-1, 0, -1
473 write(lvl_name,
'(I0)') lvl
474 call profiler_start_region(
"AMG_level_" // trim(lvl_name))
475 associate(x => this%wrk(lvl)%x, x_d => this%wrk(lvl)%x_d, &
476 b => this%wrk(lvl)%b, b_d => this%wrk(lvl)%b_d, &
477 r => this%wrk(lvl)%r, r_d => this%wrk(lvl)%r_d, &
478 n => this%wrk(lvl)%n)
482 call this%amg%interp_c2f_d(r_d, this%wrk(lvl+1)%x_d, lvl+1, r)
486 call device_add2(x_d, r_d, n)
490 call this%smoo(lvl)%device_solve(x, b, x_d, b_d, n, this%amg)
492 call profiler_end_region(
"AMG_level_" // trim(lvl_name))
505 integer,
intent(in) :: n
506 real(kind=rp),
intent(inout) :: r(n)
507 real(kind=rp),
intent(inout) :: x(n)
508 real(kind=rp),
intent(inout) :: b(n)
509 type(tamg_hierarchy_t),
intent(inout) :: amg
510 integer,
intent(in) :: lvl
512 call amg%matvec(r, x, lvl)
513 call add2s1(r, b, -1.0_rp, n)
518 integer,
intent(in) :: lvl, nagg, agg_type
519 character(len=LOG_SIZE) :: log_buf
521 if (agg_type .eq. 1)
then
522 write(log_buf,
'(A8,I2,A31)')
'-- level', lvl, &
523 '-- Calling Greedy Aggregation'
524 else if (agg_type .eq. 2)
then
525 write(log_buf,
'(A8,I2,A33)')
'-- level', lvl, &
526 '-- Calling Pairwise Aggregation'
528 write(log_buf,
'(A8,I2,A31)')
'-- level', lvl, &
529 '-- UNKNOWN Aggregation'
531 call neko_log%message(log_buf)
532 write(log_buf,
'(A33,I6)')
'Target Aggregates:', nagg
533 call neko_log%message(log_buf)
537 integer,
intent(in) :: lvl, n
538 real(kind=rp),
intent(inout) :: r(n)
539 real(kind=rp),
intent(inout) :: x(n)
540 real(kind=rp),
intent(inout) :: b(n)
544 type(tamg_hierarchy_t),
intent(inout) :: amg
546 character(len=LOG_SIZE) :: log_buf
548 call amg%device_matvec(r, x, r_d, x_d, lvl)
549 call device_sub3(r_d, b_d, r_d, n)
550 val = device_glsc2(r_d, r_d, n)
552 write(log_buf,
'(A33,I6,F12.6)')
'tAMG resid:', lvl, val
553 call neko_log%message(log_buf)
559 type(tamg_hierarchy_t),
intent(inout) :: amg
560 integer,
allocatable :: dof2gid(:)
561 integer :: i, j, k, l, nid, n, nmap
562 do j = 1, amg%lvl(1)%nnodes
563 do k = 1, amg%lvl(1)%nodes(j)%ndofs
564 nid = amg%lvl(1)%nodes(j)%dofs(k)
565 amg%lvl(1)%map_finest2lvl(nid) = amg%lvl(1)%nodes(j)%gid
571 n = amg%lvl(1)%fine_lvl_dofs
576 allocate(dof2gid(amg%lvl(l)%fine_lvl_dofs))
578 do j = 1, amg%lvl(l)%nnodes
579 do k = 1, amg%lvl(l)%nodes(j)%ndofs
580 dof2gid(amg%lvl(l)%nodes(j)%dofs(k)) = amg%lvl(l)%nodes(j)%gid
584 nid = amg%lvl(l-1)%map_finest2lvl(i)
585 if (nid .ge. 1 .and. nid .le. amg%lvl(l)%fine_lvl_dofs)
then
586 if (dof2gid(nid) .gt. 0)
then
587 amg%lvl(l)%map_finest2lvl(i) = dof2gid(nid)
593 if (neko_bcknd_device .eq. 1)
then
596 nmap =
size(amg%lvl(1)%map_finest2lvl)
598 amg%lvl(l)%map_finest2lvl(0) = nmap
599 call device_memcpy( amg%lvl(l)%map_finest2lvl, &
600 amg%lvl(l)%map_finest2lvl_d, nmap, &
601 host_to_device, .true.)
602 call device_memcpy( amg%lvl(l)%map_f2c, &
603 amg%lvl(l)%map_f2c_d, amg%lvl(l)%fine_lvl_dofs+1, &
604 host_to_device, .true.)
616 type(tamg_hierarchy_t),
intent(inout) :: amg
620 integer,
parameter :: PART_PAD = 32
621 integer,
allocatable :: fill(:), seen(:)
622 integer :: l, i, j, k, c, n, nagg, nthrds, ldpart
624 n = amg%lvl(1)%fine_lvl_dofs
634 allocate(seen(amg%lvl(l)%fine_lvl_dofs))
636 do j = 1, amg%lvl(l)%nnodes
637 do k = 1, amg%lvl(l)%nodes(j)%ndofs
638 i = amg%lvl(l)%nodes(j)%dofs(k)
639 if (i .lt. 1 .or. i .gt. amg%lvl(l)%fine_lvl_dofs)
then
640 call neko_error(
'TAMG: node dof outside the level')
642 if (seen(i) .ne. 0)
then
643 call neko_error(
'TAMG: dof shared by two nodes on a level')
652 nagg = amg%lvl(l)%nnodes
654 allocate(amg%lvl(l)%agg_ptr(nagg + 1))
655 allocate(amg%lvl(l)%agg_dof(n))
667 if (nagg .lt. 2 * nthrds)
then
668 ldpart = ((nagg + part_pad - 1) / part_pad) * part_pad
669 allocate(amg%lvl(l)%agg_part(ldpart, nthrds))
672 associate(aptr => amg%lvl(l)%agg_ptr, adof => amg%lvl(l)%agg_dof, &
673 map => amg%lvl(l)%map_finest2lvl)
681 if (c .lt. 1 .or. c .gt. nagg)
then
682 call neko_error(
'TAMG: dof not covered by the aggregation')
684 aptr(c + 1) = aptr(c + 1) + 1
690 aptr(c + 1) = aptr(c + 1) + aptr(c)
698 adof(aptr(c) + fill(c)) = i
699 fill(c) = fill(c) + 1
__device__ T solve(const T u, const T y, const T guess, const T nu, const T kappa, const T B)
Return the device pointer for an associated Fortran array.
Map a Fortran array to a device (allocate and associate)
Copy data between host and device (or device and device)
Unmap a Fortran array from a device (deassociate and free)
Defines a Matrix-vector product.
type(mpi_comm), public neko_comm
MPI communicator.
subroutine, public device_sub3(a_d, b_d, c_d, n, strm)
Vector subtraction .
subroutine, public device_add2(a_d, b_d, n, strm)
Vector addition .
subroutine, public device_rzero(a_d, n, strm)
Zero a real vector.
subroutine, public device_copy(a_d, b_d, n, strm)
Copy a vector .
subroutine, public device_col2(a_d, b_d, n, strm)
Vector multiplication .
real(kind=rp) function, public device_glsc2(a_d, b_d, n, strm)
Weighted inner product .
Device abstraction, common interface for various accelerators.
integer, parameter, public host_to_device
type(log_t), public neko_log
Global log stream.
integer, parameter, public log_size
subroutine, public add2s1(a, b, c1, n)
Vector addition with scalar multiplication (multiplication on first argument)
real(kind=rp) function, public glsc2(a, b, n)
Weighted inner product .
subroutine, public add2(a, b, n)
Vector addition .
subroutine, public col2(a, b, n)
Vector multiplication .
subroutine, public copy(a, b, n)
Copy a vector .
subroutine, public rzero(a, n)
Zero a real vector.
integer, parameter neko_bcknd_device
integer, parameter, public rp
Global precision used in computations.
subroutine, public profiler_start_region(name, region_id)
Started a named (name) profiler region.
subroutine, public profiler_end_region(name, region_id)
End the most recently started profiler region.
Defines a function space.
Implements an aggregation for TreeAMG hierarchy structure.
subroutine aggregate_end(tamg, lvl_id)
Aggregate all dofs to a single point to form a tree-like structure.
subroutine aggregate_pairs(tamg, lvl_id, max_aggs, facet_neigh, agg_nhbr)
Aggregates pairs of dofs based on adjacent dofs.
subroutine aggregate_greedy(tamg, lvl_id, max_aggs, facet_neigh, agg_nhbr)
Aggregates dofs based on adjacent dofs.
subroutine aggregate_finest_level(tamg, lx, ly, lz, ne)
Aggregaiton on finest level Aggregates all dofs in an element into a single aggregate.
Implements multigrid using the TreeAMG hierarchy structure. USE:
subroutine calc_resid(r, x, b, amg, lvl, n)
Wrapper function to calculate residyal.
subroutine tamg_mg_set_eig_refresh(this, warm_start, power_its_refresh)
Set the eigenvalue re-estimation policy on every level.
subroutine tamg_mg_cycle_d(this, zero_initial_guess)
multigrid cycle for the TreeAMG solver object on device
subroutine build_agg_csr(amg)
Build the transpose of map_finest2lvl in CSR form: for every aggregate on a level,...
subroutine tamg_mg_invalidate_eigs(this)
Re-estimate every level's eigenvalues on the next solve. Needed when the operator changes underneath ...
subroutine tamg_mg_free(this)
free tree amg solver object
subroutine fill_lvl_map(amg)
Create index mapping between levels and directly to finest level.
subroutine print_resid_info(r, x, b, r_d, x_d, b_d, amg, lvl, n)
subroutine tamg_mg_solve(this, z, r, n)
Solver function for the TreeAMG solver object.
subroutine tamg_mg_cycle(this, zero_initial_guess)
multigrid cycle for the TreeAMG solver object
subroutine print_preagg_info(lvl, nagg, agg_type)
subroutine tamg_mg_init(this, ax, xh, coef, msh, gs_h, nlvls, blst, max_iter, cheby_degree)
Initialization of the TreeAMG multigrid solver.
Implements smoothers for use with TreeAMG matrix vector product.
Implements the base type for TreeAMG hierarchy structure.
subroutine, public tamg_node_init(node, gid, ndofs)
Initialization of a TreeAMG tree node.
subroutine, public tamg_lvl_init(tamg_lvl, lvl, nnodes, ndofs)
Initialization of a TreeAMG level.
subroutine, public neko_warning(warning_msg)
Reports a warning to standard output.
Base type for a matrix-vector product providing .
A list of allocatable `bc_t`. Follows the standard interface of lists.
Coefficients defined on a given (mesh, ) tuple. Arrays use indices (i,j,k,e): element e,...
The function space for the SEM solution fields.
Type for a TreeAMG hierarchy.
Type for the TreeAMG solver.
Type for Chebyshev iteration using TreeAMG matvec.