51 use mpi_f08,
only: mpi_allreduce, mpi_min, mpi_in_place, mpi_integer
67 use,
intrinsic :: iso_c_binding
73 real(kind=
rp),
allocatable :: r(:)
74 real(kind=
rp),
allocatable :: b(:)
75 real(kind=
rp),
allocatable :: x(:)
76 type(c_ptr) :: r_d = c_null_ptr
77 type(c_ptr) :: b_d = c_null_ptr
78 type(c_ptr) :: x_d = c_null_ptr
109 max_iter, cheby_degree)
111 class(
ax_t),
target,
intent(in) :: ax
112 type(
space_t),
target,
intent(in) :: Xh
113 type(
coef_t),
target,
intent(in) :: coef
114 type(
mesh_t),
target,
intent(in) :: msh
115 type(
gs_t),
target,
intent(in) :: gs_h
116 type(
bc_list_t),
target,
intent(in) :: blst
117 integer,
intent(in) :: nlvls
118 integer,
intent(in) :: max_iter
119 integer,
intent(in) :: cheby_degree
120 integer :: lvl, n, mlvl, target_num_aggs
121 integer,
allocatable :: agg_nhbr(:,:), nhbr_tmp(:,:)
122 character(len=LOG_SIZE) :: log_buf
123 integer :: glb_min_target_aggs
124 logical :: use_greedy_agg
128 write(log_buf,
'(A28,I2,A8)')
'Creating AMG hierarchy with', &
133 call this%amg%init(ax, xh, coef, msh, gs_h, nlvls, blst)
136 use_greedy_agg = .true.
141 allocate( agg_nhbr, source = msh%facet_neigh )
144 if (use_greedy_agg)
then
145 target_num_aggs = this%amg%lvl(mlvl-1)%nnodes / 8
147 target_num_aggs = this%amg%lvl(mlvl-1)%nnodes / 2
150 glb_min_target_aggs = target_num_aggs
151 call mpi_allreduce(mpi_in_place, glb_min_target_aggs, 1, &
153 if (glb_min_target_aggs .lt. 4 )
then
155 "TAMG: Too many levels. Not enough DOFs for coarsest grid.")
156 this%amg%nlvls = mlvl
160 if (use_greedy_agg)
then
171 deallocate( nhbr_tmp )
173 deallocate( agg_nhbr )
178 this%max_iter = max_iter
180 this%nlvls = this%amg%nlvls
181 if (this%nlvls .gt. this%amg%nlvls)
then
183 "Requested number multigrid levels &
184 & is greater than the initialized AMG levels")
188 allocate(this%smoo(0:(this%amg%nlvls)))
189 do lvl = 0, this%amg%nlvls-1
190 n = this%amg%lvl(lvl+1)%fine_lvl_dofs
191 call this%smoo(lvl)%init(n, lvl, cheby_degree)
195 allocate(this%wrk(0:(this%amg%nlvls)))
196 do lvl = 0, this%amg%nlvls-1
197 n = this%amg%lvl(lvl+1)%fine_lvl_dofs
199 allocate( this%wrk(lvl)%r(n) )
200 allocate( this%wrk(lvl)%b(n) )
201 allocate( this%wrk(lvl)%x(n) )
203 call device_map( this%wrk(lvl)%r, this%wrk(lvl)%r_d, n)
204 call device_map( this%wrk(lvl)%b, this%wrk(lvl)%b_d, n)
205 call device_map( this%wrk(lvl)%x, this%wrk(lvl)%x_d, n)
226 if (
allocated(this%amg))
then
230 if (
allocated(this%smoo))
then
231 do i = 0, (
size(this%smoo)-1)
232 call this%smoo(i)%free()
234 deallocate(this%smoo)
236 if (
allocated(this%wrk))
then
237 do i = 0, (
size(this%wrk)-1)
238 if (
allocated(this%wrk(i)%r))
then
240 c_associated(this%wrk(i)%r_d))
then
243 deallocate(this%wrk(i)%r)
245 if (
allocated(this%wrk(i)%b))
then
247 c_associated(this%wrk(i)%b_d))
then
250 deallocate(this%wrk(i)%b)
252 if (
allocated(this%wrk(i)%x))
then
254 c_associated(this%wrk(i)%x_d))
then
257 deallocate(this%wrk(i)%x)
269 integer,
intent(in) :: n
271 real(kind=
rp),
dimension(n),
intent(inout) :: z
272 real(kind=
rp),
dimension(n),
intent(inout) :: r
275 integer :: iter, max_iter, i
276 logical :: zero_initial_guess
278 max_iter = this%max_iter
287 zero_initial_guess = .true.
289 do iter = 1, max_iter
290 call this%mg_cycle_d(zero_initial_guess)
291 zero_initial_guess = .false.
302 this%wrk(0)%x(i) = 0.0_rp
303 this%wrk(0)%b(i) = r(i)
306 zero_initial_guess = .true.
308 do iter = 1, max_iter
309 call this%mg_cycle(zero_initial_guess)
310 zero_initial_guess = .false.
312 call copy(z, this%wrk(0)%x, n)
322 logical,
intent(inout) :: zero_initial_guess
323 character(len=2) :: lvl_name
324 integer :: max_lvl, lvl
326 max_lvl = this%nlvls-1
328 do lvl = 0, max_lvl-1
329 write(lvl_name,
'(I0)') lvl
331 associate(x => this%wrk(lvl)%x, b => this%wrk(lvl)%b, &
332 r => this%wrk(lvl)%r, n => this%wrk(lvl)%n)
336 call this%smoo(lvl)%solve(x, b, n, this%amg, &
345 call this%amg%interp_f2c(this%wrk(lvl+1)%b, r, lvl+1)
347 call rzero(this%wrk(lvl+1)%x, this%wrk(lvl+1)%n)
348 zero_initial_guess = .true.
352 write(lvl_name,
'(I0)') max_lvl
357 call this%smoo(max_lvl)%solve(this%wrk(max_lvl)%x, &
358 this%wrk(max_lvl)%b, this%amg%lvl(max_lvl)%nnodes, this%amg, &
362 zero_initial_guess = .false.
364 do lvl = max_lvl-1, 0, -1
365 write(lvl_name,
'(I0)') lvl
367 associate(x => this%wrk(lvl)%x, b => this%wrk(lvl)%b, &
368 r => this%wrk(lvl)%r, n => this%wrk(lvl)%n)
372 call this%amg%interp_c2f(r, this%wrk(lvl+1)%x, lvl+1)
380 call this%smoo(lvl)%solve(x, b, n, this%amg)
382 call profiler_end_region(
"AMG_level_" // trim(lvl_name))
391 logical,
intent(inout) :: zero_initial_guess
392 character(len=2) :: lvl_name
393 integer :: max_lvl, lvl
395 max_lvl = this%nlvls-1
397 do lvl = 0, max_lvl-1
398 write(lvl_name,
'(I0)') lvl
399 call profiler_start_region(
"AMG_level_" // trim(lvl_name))
400 associate(x => this%wrk(lvl)%x, x_d => this%wrk(lvl)%x_d, &
401 b => this%wrk(lvl)%b, b_d => this%wrk(lvl)%b_d, &
402 r => this%wrk(lvl)%r, r_d => this%wrk(lvl)%r_d, &
403 n => this%wrk(lvl)%n)
407 call this%smoo(lvl)%device_solve(x, b, x_d, b_d, n, this%amg, &
412 call this%amg%device_matvec(r, x, r_d, x_d, lvl)
413 call device_sub3(r_d, b_d, r_d, n)
417 call this%amg%interp_f2c_d(this%wrk(lvl+1)%b_d, r_d, lvl+1)
419 call device_rzero(this%wrk(lvl+1)%x_d, this%wrk(lvl+1)%n)
420 zero_initial_guess = .true.
422 call profiler_end_region(
"AMG_level_" // trim(lvl_name))
424 write(lvl_name,
'(I0)') max_lvl
425 call profiler_start_region(
"AMG_level_" // trim(lvl_name))
429 call this%smoo(max_lvl)%device_solve( &
430 this%wrk(max_lvl)%x, this%wrk(max_lvl)%b, &
431 this%wrk(max_lvl)%x_d, this%wrk(max_lvl)%b_d, &
432 this%amg%lvl(max_lvl)%nnodes, this%amg, &
434 call profiler_end_region(
"AMG_level_" // trim(lvl_name))
436 zero_initial_guess = .false.
438 do lvl = max_lvl-1, 0, -1
439 write(lvl_name,
'(I0)') lvl
440 call profiler_start_region(
"AMG_level_" // trim(lvl_name))
441 associate(x => this%wrk(lvl)%x, x_d => this%wrk(lvl)%x_d, &
442 b => this%wrk(lvl)%b, b_d => this%wrk(lvl)%b_d, &
443 r => this%wrk(lvl)%r, r_d => this%wrk(lvl)%r_d, &
444 n => this%wrk(lvl)%n)
448 call this%amg%interp_c2f_d(r_d, this%wrk(lvl+1)%x_d, lvl+1, r)
452 call device_add2(x_d, r_d, n)
456 call this%smoo(lvl)%device_solve(x, b, x_d, b_d, n, this%amg)
458 call profiler_end_region(
"AMG_level_" // trim(lvl_name))
471 integer,
intent(in) :: n
472 real(kind=rp),
intent(inout) :: r(n)
473 real(kind=rp),
intent(inout) :: x(n)
474 real(kind=rp),
intent(inout) :: b(n)
475 type(tamg_hierarchy_t),
intent(inout) :: amg
476 integer,
intent(in) :: lvl
478 call amg%matvec(r, x, lvl)
479 call add2s1(r, b, -1.0_rp, n)
484 integer,
intent(in) :: lvl, nagg, agg_type
485 character(len=LOG_SIZE) :: log_buf
487 if (agg_type .eq. 1)
then
488 write(log_buf,
'(A8,I2,A31)')
'-- level', lvl, &
489 '-- Calling Greedy Aggregation'
490 else if (agg_type .eq. 2)
then
491 write(log_buf,
'(A8,I2,A33)')
'-- level', lvl, &
492 '-- Calling Pairwise Aggregation'
494 write(log_buf,
'(A8,I2,A31)')
'-- level', lvl, &
495 '-- UNKNOWN Aggregation'
497 call neko_log%message(log_buf)
498 write(log_buf,
'(A33,I6)')
'Target Aggregates:', nagg
499 call neko_log%message(log_buf)
503 integer,
intent(in) :: lvl, n
504 real(kind=rp),
intent(inout) :: r(n)
505 real(kind=rp),
intent(inout) :: x(n)
506 real(kind=rp),
intent(inout) :: b(n)
510 type(tamg_hierarchy_t),
intent(inout) :: amg
512 character(len=LOG_SIZE) :: log_buf
514 call amg%device_matvec(r, x, r_d, x_d, lvl)
515 call device_sub3(r_d, b_d, r_d, n)
516 val = device_glsc2(r_d, r_d, n)
518 write(log_buf,
'(A33,I6,F12.6)')
'tAMG resid:', lvl, val
519 call neko_log%message(log_buf)
525 type(tamg_hierarchy_t),
intent(inout) :: amg
526 integer :: i, j, k, l, nid, n
527 do j = 1, amg%lvl(1)%nnodes
528 do k = 1, amg%lvl(1)%nodes(j)%ndofs
529 nid = amg%lvl(1)%nodes(j)%dofs(k)
530 amg%lvl(1)%map_finest2lvl(nid) = amg%lvl(1)%nodes(j)%gid
533 n =
size(amg%lvl(1)%map_finest2lvl)
536 nid = amg%lvl(l-1)%map_finest2lvl(i)
537 do j = 1, amg%lvl(l)%nnodes
538 do k = 1, amg%lvl(l)%nodes(j)%ndofs
539 if (nid .eq. amg%lvl(l)%nodes(j)%dofs(k))
then
540 amg%lvl(l)%map_finest2lvl(i) = amg%lvl(l)%nodes(j)%gid
546 if (neko_bcknd_device .eq. 1)
then
548 amg%lvl(l)%map_finest2lvl(0) = n
549 call device_memcpy( amg%lvl(l)%map_finest2lvl, &
550 amg%lvl(l)%map_finest2lvl_d, n, &
551 host_to_device, .true.)
552 call device_memcpy( amg%lvl(l)%map_f2c, &
553 amg%lvl(l)%map_f2c_d, amg%lvl(l)%fine_lvl_dofs+1, &
554 host_to_device, .true.)
__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_cycle_d(this, zero_initial_guess)
multigrid cycle for the TreeAMG solver object on device
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.