49 use,
intrinsic :: iso_c_binding
55 logical :: isleaf = .true.
59 integer,
allocatable :: dofs(:)
60 real(kind=
rp) :: xyz(3)
61 real(kind=
rp),
allocatable :: interp_r(:)
62 real(kind=
rp),
allocatable :: interp_p(:)
72 integer :: fine_lvl_dofs = 0
73 real(kind=
rp),
allocatable :: wrk_in(:)
74 type(c_ptr) :: wrk_in_d = c_null_ptr
75 real(kind=
rp),
allocatable :: wrk_out(:)
76 type(c_ptr) :: wrk_out_d = c_null_ptr
77 integer,
allocatable :: map_finest2lvl(:)
78 type(c_ptr) :: map_finest2lvl_d = c_null_ptr
80 integer,
allocatable :: map_f2c(:)
81 type(c_ptr) :: map_f2c_d = c_null_ptr
98 type(
gs_t),
pointer :: gs_h
125 subroutine tamg_init(this, ax, Xh, coef, msh, gs_h, nlvls, blst)
127 class(
ax_t),
target,
intent(in) :: ax
128 type(
space_t),
target,
intent(in) :: Xh
129 type(
coef_t),
target,
intent(in) :: coef
130 type(
mesh_t),
target,
intent(in) :: msh
131 type(
gs_t),
target,
intent(in) :: gs_h
132 integer,
intent(in) :: nlvls
133 type(
bc_list_t),
target,
intent(in) :: blst
143 if (nlvls .lt. 2)
then
144 call neko_error(
"Need to request at least two multigrid levels.")
148 allocate( this%lvl(this%nlvls) )
151 allocate( this%lvl(i)%map_finest2lvl( 0:coef%dof%size() ))
153 call device_map(this%lvl(i)%map_finest2lvl, this%lvl(i)%map_finest2lvl_d, coef%dof%size()+1)
163 if (
allocated(this%lvl))
then
167 do i = 1,
size(this%lvl)
168 call this%lvl(i)%free()
187 integer,
intent(in) :: lvl
188 integer,
intent(in) :: nnodes
189 integer,
intent(in) :: ndofs
192 tamg_lvl%nnodes = nnodes
193 allocate( tamg_lvl%nodes(tamg_lvl%nnodes) )
194 allocate( tamg_lvl%map_f2c(0:ndofs) )
196 call device_map(tamg_lvl%map_f2c, tamg_lvl%map_f2c_d, ndofs+1)
199 tamg_lvl%fine_lvl_dofs = ndofs
200 allocate( tamg_lvl%wrk_in( ndofs ) )
201 allocate( tamg_lvl%wrk_out( ndofs ) )
203 call device_map(tamg_lvl%wrk_in, tamg_lvl%wrk_in_d, ndofs)
205 call device_map(tamg_lvl%wrk_out, tamg_lvl%wrk_out_d, ndofs)
218 if (
allocated(this%nodes))
then
219 do i = 1, this%nnodes
220 call this%nodes(i)%free()
222 deallocate(this%nodes)
224 if (
allocated(this%wrk_in))
then
228 deallocate(this%wrk_in)
230 if (
allocated(this%wrk_out))
then
234 deallocate(this%wrk_out)
236 if (
allocated(this%map_f2c))
then
240 deallocate(this%map_f2c)
242 if (
allocated(this%map_finest2lvl))
then
244 call device_unmap(this%map_finest2lvl, this%map_finest2lvl_d)
246 deallocate(this%map_finest2lvl)
250 this%fine_lvl_dofs = 0
259 integer,
intent(in) :: gid
260 integer,
intent(in) :: ndofs
264 allocate( node%dofs( node%ndofs) )
266 allocate( node%interp_r( node%ndofs) )
267 allocate( node%interp_p( node%ndofs) )
268 node%interp_r = 1.0_rp
269 node%interp_p = 1.0_rp
276 if (
allocated(this%dofs))
then
277 deallocate(this%dofs)
279 if (
allocated(this%interp_r))
then
280 deallocate(this%interp_r)
282 if (
allocated(this%interp_p))
then
283 deallocate(this%interp_p)
295 real(kind=
rp),
intent(inout) :: vec_out(:)
296 real(kind=
rp),
intent(inout) :: vec_in(:)
297 integer,
intent(in) :: lvl_out
312 real(kind=
rp),
intent(inout) :: vec_out(:)
313 real(kind=
rp),
intent(inout) :: vec_in(:)
314 integer,
intent(in) :: lvl
315 integer,
intent(in) :: lvl_out
322 call this%gs_h%op(vec_in, n, gs_op_add)
323 call col2( vec_in, this%coef%mult, n)
325 call this%ax%compute(vec_out, vec_in, this%coef, this%msh, this%Xh)
326 call this%gs_h%op(vec_out, n, gs_op_add)
327 call this%blst%apply(vec_out, n)
329 if (lvl_out .ne. 0)
then
330 call col2(vec_out, this%coef%mult, n)
334 if (lvl_out .ge. lvl)
then
337 associate( wrk_in => this%lvl(lvl)%wrk_in, wrk_out => this%lvl(lvl)%wrk_out)
338 n = this%lvl(lvl)%fine_lvl_dofs
339 call rzero(wrk_in, n)
340 call rzero(vec_out, this%lvl(lvl)%nnodes)
341 do n = 1, this%lvl(lvl)%nnodes
342 associate(node => this%lvl(lvl)%nodes(n))
344 wrk_in( node%dofs(i) ) = wrk_in( node%dofs(i) ) + vec_in( node%gid ) * node%interp_p( i )
349 call this%matvec_impl(wrk_out, wrk_in, lvl-1, lvl_out)
352 do n = 1, this%lvl(lvl)%nnodes
353 associate(node => this%lvl(lvl)%nodes(n))
355 vec_out( node%gid ) = vec_out(node%gid ) + wrk_out( node%dofs(i) ) * node%interp_r( i )
360 else if (lvl_out .lt. lvl)
then
362 call this%matvec_impl(vec_out, vec_in, lvl-1, lvl_out)
364 call neko_error(
"TAMG: matvec level numbering problem.")
373 real(kind=rp),
intent(inout) :: vec_out(:)
374 real(kind=rp),
intent(inout) :: vec_in(:)
375 integer,
intent(in) :: lvl_blah
376 integer,
intent(in) :: lvl_out
377 integer :: i, n, cdof, lvl
380 n = this%lvl(1)%fine_lvl_dofs
382 call this%ax%compute(vec_out, vec_in, this%coef, this%msh, this%Xh)
383 call this%gs_h%op(vec_out, n, gs_op_add)
384 call this%blst%apply(vec_out, n)
386 associate( wrk_in => this%lvl(1)%wrk_in, wrk_out => this%lvl(1)%wrk_out)
389 cdof = this%lvl(lvl)%map_finest2lvl(i)
390 wrk_in(i) = vec_in( cdof )
394 call this%gs_h%op(wrk_in, n, gs_op_add)
395 call col2( wrk_in, this%coef%mult, n)
396 call this%blst%apply(wrk_in, n)
399 call this%ax%compute(wrk_out, wrk_in, this%coef, this%msh, this%Xh)
400 call this%gs_h%op(wrk_out, n, gs_op_add)
401 call this%blst%apply(wrk_out, n)
403 call col2(wrk_out, this%coef%mult, n)
406 call rzero(vec_out, this%lvl(lvl)%nnodes)
409 cdof = this%lvl(lvl)%map_finest2lvl(i)
411 vec_out(cdof) = vec_out(cdof) + wrk_out( i )
426 real(kind=rp),
intent(inout) :: vec_out(:)
427 real(kind=rp),
intent(inout) :: vec_in(:)
428 integer,
intent(in) :: lvl
429 integer :: i, n, node_start, node_end, node_id
432 if (lvl-1 .eq. 0)
then
433 call col2(vec_in, this%coef%mult, this%lvl(lvl)%fine_lvl_dofs)
435 do n = 1, this%lvl(lvl)%nnodes
436 associate(node => this%lvl(lvl)%nodes(n))
438 vec_out( node%gid ) = vec_out( node%gid ) + vec_in( node%dofs(i) ) * node%interp_r( i )
450 real(kind=rp),
intent(inout) :: vec_out(:)
451 real(kind=rp),
intent(inout) :: vec_in(:)
452 integer,
intent(in) :: lvl
453 integer :: i, n, node_start, node_end, node_id
456 do n = 1, this%lvl(lvl)%nnodes
457 associate(node => this%lvl(lvl)%nodes(n))
459 vec_out( node%dofs(i) ) = vec_out( node%dofs(i) ) + vec_in( node%gid ) * node%interp_p( i )
463 if (lvl-1 .eq. 0)
then
464 call this%gs_h%op(vec_out, this%lvl(lvl)%fine_lvl_dofs, gs_op_add)
465 call col2(vec_out, this%coef%mult, this%lvl(lvl)%fine_lvl_dofs)
466 call this%blst%apply(vec_out, this%lvl(lvl)%fine_lvl_dofs)
473 real(kind=rp),
intent(inout) :: vec_out(:)
474 real(kind=rp),
intent(inout) :: vec_in(:)
475 type(c_ptr) :: vec_out_d
476 type(c_ptr) :: vec_in_d
477 integer,
intent(in) :: lvl_out
478 integer :: i, n, cdof, lvl
481 n = this%lvl(1)%fine_lvl_dofs
483 call this%ax%compute(vec_out, vec_in, this%coef, this%msh, this%Xh)
484 call this%gs_h%op(vec_out, n, gs_op_add, glb_cmd_event)
485 call device_stream_wait_event(glb_cmd_queue, glb_cmd_event, 0)
486 call this%blst%apply(vec_out, n)
489 associate( wrk_in_d => this%lvl(1)%wrk_in_d, wrk_out_d => this%lvl(1)%wrk_out_d)
491 call device_masked_gather_copy_0(wrk_in_d, vec_in_d, this%lvl(lvl)%map_finest2lvl_d, this%lvl(lvl)%nnodes, n)
493 call this%gs_h%op(this%lvl(1)%wrk_in, n, gs_op_add, glb_cmd_event)
494 call device_stream_wait_event(glb_cmd_queue, glb_cmd_event, 0)
495 call device_col2( wrk_in_d, this%coef%mult_d, n)
496 call this%blst%apply(this%lvl(1)%wrk_in, n)
499 call this%ax%compute(this%lvl(1)%wrk_out, this%lvl(1)%wrk_in, this%coef, this%msh, this%Xh)
500 call this%gs_h%op(this%lvl(1)%wrk_out, n, gs_op_add, glb_cmd_event)
501 call device_stream_wait_event(glb_cmd_queue, glb_cmd_event, 0)
502 call this%blst%apply(this%lvl(1)%wrk_out, n)
504 call device_col2( wrk_out_d, this%coef%mult_d, n)
507 call device_rzero(vec_out_d, this%lvl(lvl)%nnodes)
508 call device_masked_atomic_reduction_0(vec_out_d, wrk_out_d, this%lvl(lvl)%map_finest2lvl_d, this%lvl(lvl)%nnodes, n)
516 type(c_ptr) :: vec_out_d
517 type(c_ptr) :: vec_in_d
518 integer,
intent(in) :: lvl
520 n = this%lvl(lvl)%nnodes
521 m = this%lvl(lvl)%fine_lvl_dofs
522 if (lvl-1 .eq. 0)
then
523 call device_col2(vec_in_d, this%coef%mult_d, m)
525 call device_rzero(vec_out_d, n)
526 call device_masked_atomic_reduction_0(vec_out_d, vec_in_d, this%lvl(lvl)%map_f2c_d, n, m)
531 real(kind=rp),
intent(inout) :: vec_out(:)
532 type(c_ptr) :: vec_out_d
533 type(c_ptr) :: vec_in_d
534 integer,
intent(in) :: lvl
536 n = this%lvl(lvl)%nnodes
537 m = this%lvl(lvl)%fine_lvl_dofs
538 call device_masked_gather_copy_0(vec_out_d, vec_in_d, this%lvl(lvl)%map_f2c_d, n, m)
539 if (lvl-1 .eq. 0)
then
540 call this%gs_h%op(vec_out, m, gs_op_add, glb_cmd_event)
541 call device_stream_wait_event(glb_cmd_queue, glb_cmd_event, 0)
542 call device_col2( vec_out_d, this%coef%mult_d, m)
543 call this%blst%apply( vec_out, m)
Map a Fortran array to a device (allocate and associate)
Synchronize a device or stream.
Unmap a Fortran array from a device (deassociate and free)
Defines a Matrix-vector product.
subroutine, public device_masked_atomic_reduction_0(a_d, b_d, mask_d, n, n_mask, strm)
subroutine, public device_rzero(a_d, n, strm)
Zero a real vector.
subroutine, public device_col2(a_d, b_d, n, strm)
Vector multiplication .
subroutine, public device_masked_gather_copy_0(a_d, b_d, mask_d, n, n_mask, strm)
Gather a masked vector .
subroutine, public device_cfill(a_d, c, n, strm)
Set all elements to a constant c .
Device abstraction, common interface for various accelerators.
subroutine, public device_stream_wait_event(stream, event, flags)
Synchronize a device stream with an event.
type(c_ptr), bind(C), public glb_cmd_queue
Global command queue.
type(c_ptr), bind(C), public glb_cmd_event
Event for the global command queue.
subroutine, public col2(a, b, n)
Vector multiplication .
subroutine, public rzero(a, n)
Zero a real vector.
integer, parameter neko_bcknd_device
integer, parameter, public rp
Global precision used in computations.
Defines a function space.
Implements the base type for TreeAMG hierarchy structure.
subroutine tamg_device_matvec_flat_impl(this, vec_out, vec_in, vec_out_d, vec_in_d, lvl_out)
subroutine tamg_device_prolongation_operator(this, vec_out_d, vec_in_d, lvl, vec_out)
subroutine lvl_free(this)
deallocate tamg level
recursive subroutine tamg_matvec_impl(this, vec_out, vec_in, lvl, lvl_out)
Matrix vector product using the TreeAMG hierarchy structure b=Ax done as vec_out = A * vec_in This is...
subroutine, public tamg_node_init(node, gid, ndofs)
Initialization of a TreeAMG tree node.
subroutine tamg_restriction_operator(this, vec_out, vec_in, lvl)
Restriction operator for TreeAMG. vec_out = R * vec_in.
subroutine tamg_prolongation_operator(this, vec_out, vec_in, lvl)
Prolongation operator for TreeAMG. vec_out = P * vec_in.
subroutine node_free(this)
deallocate tamg tree node
subroutine, public tamg_lvl_init(tamg_lvl, lvl, nnodes, ndofs)
Initialization of a TreeAMG level.
subroutine tamg_free(this)
deallocate tamg hierarchy
recursive subroutine tamg_matvec(this, vec_out, vec_in, lvl_out)
Wrapper for matrix vector product using the TreeAMG hierarchy structure b=Ax done as vec_out = A * ve...
subroutine tamg_device_restriction_operator(this, vec_out_d, vec_in_d, lvl)
subroutine tamg_init(this, ax, xh, coef, msh, gs_h, nlvls, blst)
Initialization of TreeAMG hierarchy.
recursive subroutine tamg_matvec_flat_impl(this, vec_out, vec_in, lvl_blah, lvl_out)
Ignore this. For piecewise constant, can create index map directly to finest level.
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 storing TreeAMG level information.
Type for storing TreeAMG tree node information.