Neko 1.99.9
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
tree_amg.f90
Go to the documentation of this file.
1! Copyright (c) 2024-2026, The Neko Authors
2! All rights reserved.
3!
4! Redistribution and use in source and binary forms, with or without
5! modification, are permitted provided that the following conditions
6! are met:
7!
8! * Redistributions of source code must retain the above copyright
9! notice, this list of conditions and the following disclaimer.
10!
11! * Redistributions in binary form must reproduce the above
12! copyright notice, this list of conditions and the following
13! disclaimer in the documentation and/or other materials provided
14! with the distribution.
15!
16! * Neither the name of the authors nor the names of its
17! contributors may be used to endorse or promote products derived
18! from this software without specific prior written permission.
19!
20! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23! FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24! COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25! INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26! BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27! LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29! LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30! ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31! POSSIBILITY OF SUCH DAMAGE.
32!
35 use num_types, only : rp
36 use utils, only : neko_error
37 use math, only : rzero, col2
41 use coefs, only : coef_t
42 use mesh, only : mesh_t
43 use space, only : space_t
44 use ax_product, only : ax_t
46 use gather_scatter, only : gs_t, gs_op_add
50 use, intrinsic :: iso_c_binding
51 !$ use omp_lib, only : omp_get_thread_num
52 implicit none
53 private
54
56 type, private :: tamg_node_t
57 logical :: isleaf = .true.
58 integer :: gid = -1
59 integer :: lvl = -1
60 integer :: ndofs = 0
61 integer, allocatable :: dofs(:)
62 real(kind=rp) :: xyz(3)
63 real(kind=rp), allocatable :: interp_r(:)
64 real(kind=rp), allocatable :: interp_p(:)
65 contains
66 procedure, pass(this) :: free => node_free
67 end type tamg_node_t
68
70 type, private :: tamg_lvl_t
71 integer :: lvl = -1
72 integer :: nnodes = 0
73 type(tamg_node_t), allocatable :: nodes(:)
74 integer :: fine_lvl_dofs = 0
75 real(kind=rp), allocatable :: wrk_in(:)
76 type(c_ptr) :: wrk_in_d = c_null_ptr
77 real(kind=rp), allocatable :: wrk_out(:)
78 type(c_ptr) :: wrk_out_d = c_null_ptr
79 integer, allocatable :: map_finest2lvl(:)
80 type(c_ptr) :: map_finest2lvl_d = c_null_ptr
81 !--!
82 integer, allocatable :: map_f2c(:)
83 type(c_ptr) :: map_f2c_d = c_null_ptr
88 integer, allocatable :: agg_ptr(:)
89 integer, allocatable :: agg_dof(:)
95 real(kind=rp), allocatable :: agg_part(:,:)
96 contains
97 procedure, pass(this) :: free => lvl_free
98 end type tamg_lvl_t
99
101 type, public :: tamg_hierarchy_t
103 integer :: nlvls
105 type(tamg_lvl_t), allocatable :: lvl(:)
106
108 class(ax_t), pointer :: ax
109 type(mesh_t), pointer :: msh
110 type(space_t), pointer :: xh
111 type(coef_t), pointer :: coef
112 type(gs_t), pointer :: gs_h
113 type(scalar_bc_projector_t), pointer :: bc_projector
114
115 contains
116 procedure, pass(this) :: init => tamg_init
117 procedure, pass(this) :: free => tamg_free
118 procedure, pass(this) :: matvec => tamg_matvec
119 procedure, pass(this) :: matvec_impl => tamg_matvec_impl
120 procedure, pass(this) :: interp_f2c => tamg_restriction_operator
121 procedure, pass(this) :: interp_c2f => tamg_prolongation_operator
122 procedure, pass(this) :: interp_f2c_d => tamg_device_restriction_operator
123 procedure, pass(this) :: interp_c2f_d => tamg_device_prolongation_operator
124 procedure, pass(this) :: device_matvec => tamg_device_matvec_flat_impl
125 end type tamg_hierarchy_t
126
128
129contains
130
139 subroutine tamg_init(this, ax, Xh, coef, msh, gs_h, nlvls, bc_projector)
140 class(tamg_hierarchy_t), target, intent(inout) :: this
141 class(ax_t), target, intent(in) :: ax
142 type(space_t), target, intent(in) :: Xh
143 type(coef_t), target, intent(in) :: coef
144 type(mesh_t), target, intent(in) :: msh
145 type(gs_t), target, intent(in) :: gs_h
146 integer, intent(in) :: nlvls
147 type(scalar_bc_projector_t), target, intent(in) :: bc_projector
148 integer :: i, n
149
150 this%ax => ax
151 this%msh => msh
152 this%Xh => xh
153 this%coef => coef
154 this%gs_h => gs_h
155 this%bc_projector => bc_projector
156
157 if (nlvls .lt. 2) then
158 call neko_error("Need to request at least two multigrid levels.")
159 end if
160
161 this%nlvls = nlvls
162 allocate( this%lvl(this%nlvls) )
163
164 do i = 1, nlvls
165 allocate( this%lvl(i)%map_finest2lvl( 0:coef%dof%size() ))
166 if (neko_bcknd_device .eq. 1) then
167 call device_map(this%lvl(i)%map_finest2lvl, &
168 this%lvl(i)%map_finest2lvl_d, coef%dof%size() + 1)
169 end if
170 end do
171
172 end subroutine tamg_init
173
175 subroutine tamg_free(this)
176 class(tamg_hierarchy_t), intent(inout) :: this
177 integer :: i
178 if (allocated(this%lvl)) then
179 ! using size() instead of this%nlvls since
180 ! this%nlvls may be less than the allocated number of levels due to early
181 ! termination of aggregation
182 do i = 1, size(this%lvl)
183 call this%lvl(i)%free()
184 end do
185 deallocate(this%lvl)
186 end if
187 nullify(this%ax)
188 nullify(this%msh)
189 nullify(this%Xh)
190 nullify(this%coef)
191 nullify(this%gs_h)
192 nullify(this%bc_projector)
193 end subroutine tamg_free
194
200 subroutine tamg_lvl_init(tamg_lvl, lvl, nnodes, ndofs)
201 type(tamg_lvl_t), intent(inout) :: tamg_lvl
202 integer, intent(in) :: lvl
203 integer, intent(in) :: nnodes
204 integer, intent(in) :: ndofs
205
206 tamg_lvl%lvl = lvl
207 tamg_lvl%nnodes = nnodes
208 allocate( tamg_lvl%nodes(tamg_lvl%nnodes) )
209 allocate( tamg_lvl%map_f2c(0:ndofs) )
210 if (neko_bcknd_device .eq. 1) then
211 call device_map(tamg_lvl%map_f2c, tamg_lvl%map_f2c_d, ndofs+1)
212 end if
213
214 tamg_lvl%fine_lvl_dofs = ndofs
215 allocate( tamg_lvl%wrk_in( ndofs ) )
216 allocate( tamg_lvl%wrk_out( ndofs ) )
217 if (neko_bcknd_device .eq. 1) then
218 call device_map(tamg_lvl%wrk_in, tamg_lvl%wrk_in_d, ndofs)
219 call device_cfill(tamg_lvl%wrk_in_d, 0.0_rp, ndofs)
220 call device_map(tamg_lvl%wrk_out, tamg_lvl%wrk_out_d, ndofs)
221 call device_cfill(tamg_lvl%wrk_out_d, 0.0_rp, ndofs)
222 ! Order the async fills against host writes; on unified memory
223 ! the device pointers may alias the work arrays
224 call device_sync()
225 end if
226 end subroutine tamg_lvl_init
227
229 subroutine lvl_free(this)
230 class(tamg_lvl_t), intent(inout) :: this
231 integer :: i
232
233 if (allocated(this%nodes)) then
234 do i = 1, this%nnodes
235 call this%nodes(i)%free()
236 end do
237 deallocate(this%nodes)
238 end if
239 if (allocated(this%wrk_in)) then
240 if (neko_bcknd_device .eq. 1 .and. c_associated(this%wrk_in_d)) then
241 call device_unmap(this%wrk_in, this%wrk_in_d)
242 end if
243 deallocate(this%wrk_in)
244 end if
245 if (allocated(this%wrk_out)) then
246 if (neko_bcknd_device .eq. 1 .and. c_associated(this%wrk_out_d)) then
247 call device_unmap(this%wrk_out, this%wrk_out_d)
248 end if
249 deallocate(this%wrk_out)
250 end if
251 if (allocated(this%map_f2c)) then
252 if (neko_bcknd_device .eq. 1 .and. c_associated(this%map_f2c_d)) then
253 call device_unmap(this%map_f2c, this%map_f2c_d)
254 end if
255 deallocate(this%map_f2c)
256 end if
257 if (allocated(this%map_finest2lvl)) then
258 if (neko_bcknd_device .eq. 1 .and. c_associated(this%map_finest2lvl_d)) then
259 call device_unmap(this%map_finest2lvl, this%map_finest2lvl_d)
260 end if
261 deallocate(this%map_finest2lvl)
262 end if
263 if (allocated(this%agg_ptr)) then
264 deallocate(this%agg_ptr)
265 end if
266 if (allocated(this%agg_dof)) then
267 deallocate(this%agg_dof)
268 end if
269 if (allocated(this%agg_part)) then
270 deallocate(this%agg_part)
271 end if
272 this%nnodes = 0
273 this%lvl = -1
274 this%fine_lvl_dofs = 0
275 end subroutine lvl_free
276
281 subroutine tamg_node_init(node, gid, ndofs)
282 type(tamg_node_t), intent(inout) :: node
283 integer, intent(in) :: gid
284 integer, intent(in) :: ndofs
285
286 node%gid = gid
287 node%ndofs = ndofs
288 allocate( node%dofs( node%ndofs) )
289 node%dofs = -1
290 allocate( node%interp_r( node%ndofs) )
291 allocate( node%interp_p( node%ndofs) )
292 node%interp_r = 1.0_rp
293 node%interp_p = 1.0_rp
294 end subroutine tamg_node_init
295
297 subroutine node_free(this)
298 class(tamg_node_t), intent(inout) :: this
299
300 if (allocated(this%dofs)) then
301 deallocate(this%dofs)
302 end if
303 if (allocated(this%interp_r)) then
304 deallocate(this%interp_r)
305 end if
306 if (allocated(this%interp_p)) then
307 deallocate(this%interp_p)
308 end if
309 end subroutine node_free
310
317 recursive subroutine tamg_matvec(this, vec_out, vec_in, lvl_out)
318 class(tamg_hierarchy_t), intent(inout) :: this
319 real(kind=rp), intent(inout) :: vec_out(:)
320 real(kind=rp), intent(inout) :: vec_in(:)
321 integer, intent(in) :: lvl_out
322 integer :: i, n, e
323 !call this%matvec_impl(vec_out, vec_in, this%nlvls, lvl_out)
324 call tamg_matvec_flat_impl(this, vec_out, vec_in, this%nlvls, lvl_out)
325 end subroutine tamg_matvec
326
334 recursive subroutine tamg_matvec_impl(this, vec_out, vec_in, lvl, lvl_out)
335 class(tamg_hierarchy_t), intent(inout) :: this
336 real(kind=rp), intent(inout) :: vec_out(:)
337 real(kind=rp), intent(inout) :: vec_in(:)
338 integer, intent(in) :: lvl
339 integer, intent(in) :: lvl_out
340 integer :: i, n, e
341
342 if (lvl .eq. 0) then
344 n = size(vec_in)
346 call this%gs_h%op(vec_in, n, gs_op_add)
347 call col2( vec_in, this%coef%mult, n)
348
349 call this%ax%compute(vec_out, vec_in, this%coef, this%msh, this%Xh)
350 call this%gs_h%op(vec_out, n, gs_op_add)
351 call this%bc_projector%apply(vec_out, n)
352
353 if (lvl_out .ne. 0) then
354 call col2(vec_out, this%coef%mult, n)
355 end if
357 else
358 if (lvl_out .ge. lvl) then
361 associate(wrk_in => this%lvl(lvl)%wrk_in, &
362 wrk_out => this%lvl(lvl)%wrk_out)
363 n = this%lvl(lvl)%fine_lvl_dofs
364 call rzero(wrk_in, n)
365 call rzero(vec_out, this%lvl(lvl)%nnodes)
366 do n = 1, this%lvl(lvl)%nnodes
367 associate(node => this%lvl(lvl)%nodes(n))
368 do i = 1, node%ndofs
369 wrk_in(node%dofs(i)) = wrk_in(node%dofs(i)) + &
370 vec_in(node%gid) * node%interp_p(i)
371 end do
372 end associate
373 end do
374
375 call this%matvec_impl(wrk_out, wrk_in, lvl-1, lvl_out)
376
378 do n = 1, this%lvl(lvl)%nnodes
379 associate(node => this%lvl(lvl)%nodes(n))
380 do i = 1, node%ndofs
381 vec_out(node%gid) = vec_out(node%gid) + &
382 wrk_out(node%dofs(i)) * node%interp_r(i)
383 end do
384 end associate
385 end do
386 end associate
387 else if (lvl_out .lt. lvl) then
389 call this%matvec_impl(vec_out, vec_in, lvl-1, lvl_out)
390 else
391 call neko_error("TAMG: matvec level numbering problem.")
392 end if
393 end if
394 end subroutine tamg_matvec_impl
395
396
399 recursive subroutine tamg_matvec_flat_impl(this, vec_out, vec_in, lvl_blah, &
400 lvl_out)
401 class(tamg_hierarchy_t), intent(inout) :: this
402 real(kind=rp), intent(inout) :: vec_out(:)
403 real(kind=rp), intent(inout) :: vec_in(:)
404 integer, intent(in) :: lvl_blah
405 integer, intent(in) :: lvl_out
406 integer :: i, n, lvl, c, k, nagg, tid, nthrds
407 real(kind=rp) :: val, acc
408 logical :: use_partials
409
410 lvl = lvl_out
411 n = this%lvl(1)%fine_lvl_dofs
412 if (lvl .eq. 0) then
413 call this%ax%compute(vec_out, vec_in, this%coef, this%msh, this%Xh)
414 call this%gs_h%op(vec_out, n, gs_op_add)
415 call this%bc_projector%apply(vec_out, n)
416 else
417 ! Hoisted out of the associate below: associate names in OpenMP
418 ! data-sharing contexts have been unreliable with frt and CCE, and
419 ! an associate name to an allocatable is not itself allocatable, so
420 ! the branch below cannot query it.
421 nagg = this%lvl(lvl)%nnodes
422 use_partials = allocated(this%lvl(lvl)%agg_part)
423 nthrds = 1
424 if (use_partials) nthrds = size(this%lvl(lvl)%agg_part, 2)
425
426 ! agg_part is deliberately not associated here: it is unallocated on
427 ! the levels that take the aggregate-parallel branch, and associating
428 ! with an unallocated allocatable is not conforming even when the
429 ! branch using it is never taken.
430 associate( wrk_in => this%lvl(1)%wrk_in, &
431 wrk_out => this%lvl(1)%wrk_out, &
432 aptr => this%lvl(lvl)%agg_ptr, adof => this%lvl(lvl)%agg_dof, &
433 map => this%lvl(lvl)%map_finest2lvl)
434
438 !$omp parallel do private(c, k, val)
439 do c = 1, nagg
440 val = vec_in(c)
441 do k = aptr(c), aptr(c + 1) - 1
442 wrk_in(adof(k)) = val
443 end do
444 end do
445 !$omp end parallel do
446
448 call this%gs_h%op(wrk_in, n, gs_op_add)
449 call col2( wrk_in, this%coef%mult, n)
450 call this%bc_projector%apply(wrk_in, n)
451
453 call this%ax%compute(wrk_out, wrk_in, this%coef, this%msh, this%Xh)
454 call this%gs_h%op(wrk_out, n, gs_op_add)
455 call this%bc_projector%apply(wrk_out, n)
456
457 call col2(wrk_out, this%coef%mult, n)
458
466 if (.not. use_partials) then
467 !$omp parallel do private(c, k, acc)
468 do c = 1, nagg
469 acc = 0.0_rp
470 do k = aptr(c), aptr(c + 1) - 1
471 acc = acc + wrk_out(adof(k))
472 end do
473 vec_out(c) = acc
474 end do
475 !$omp end parallel do
476 else
486 this%lvl(lvl)%agg_part = 0.0_rp
487
488 !$omp parallel num_threads(nthrds) private(tid, i, c)
489 tid = 1
490 !$ tid = omp_get_thread_num() + 1
491 !$omp do
492 do i = 1, n
493 c = map(i)
494 this%lvl(lvl)%agg_part(c, tid) = &
495 this%lvl(lvl)%agg_part(c, tid) + wrk_out(i)
496 end do
497 !$omp end do
498 !$omp end parallel
499
500 do c = 1, nagg
501 acc = 0.0_rp
502 do k = 1, nthrds
503 acc = acc + this%lvl(lvl)%agg_part(c, k)
504 end do
505 vec_out(c) = acc
506 end do
507 end if
508 end associate
509 end if
510 end subroutine tamg_matvec_flat_impl
511
512
513
518 subroutine tamg_restriction_operator(this, vec_out, vec_in, lvl)
519 class(tamg_hierarchy_t), intent(inout) :: this
520 real(kind=rp), intent(inout) :: vec_out(:)
521 real(kind=rp), intent(inout) :: vec_in(:)
522 integer, intent(in) :: lvl
523 integer :: i, n, nagg, node_start, node_end, node_id
524 real(kind=rp) :: acc
525
526 vec_out = 0d0
527 if (lvl-1 .eq. 0) then
528 call col2(vec_in, this%coef%mult, this%lvl(lvl)%fine_lvl_dofs)
529 end if
530 nagg = this%lvl(lvl)%nnodes
531 ! Each node contributes to vec_out(node%gid) only, and gids are unique
532 ! across the nodes of a level, so the writes are already disjoint:
533 ! accumulate into a scalar and the node loop threads as-is. Indexed
534 ! rather than associated, since associate names inside an OpenMP loop
535 ! have been unreliable with frt and CCE.
536 !$omp parallel do private(i, acc)
537 do n = 1, nagg
538 acc = 0.0_rp
539 do i = 1, this%lvl(lvl)%nodes(n)%ndofs
540 acc = acc + vec_in( this%lvl(lvl)%nodes(n)%dofs(i) ) &
541 * this%lvl(lvl)%nodes(n)%interp_r( i )
542 end do
543 vec_out( this%lvl(lvl)%nodes(n)%gid ) = acc
544 end do
545 !$omp end parallel do
546 end subroutine tamg_restriction_operator
547
553 subroutine tamg_prolongation_operator(this, vec_out, vec_in, lvl)
554 class(tamg_hierarchy_t), intent(inout) :: this
555 real(kind=rp), intent(inout) :: vec_out(:)
556 real(kind=rp), intent(inout) :: vec_in(:)
557 integer, intent(in) :: lvl
558 integer :: i, n, nagg, node_start, node_end, node_id
559 real(kind=rp) :: val
560
561 vec_out = 0d0
562 nagg = this%lvl(lvl)%nnodes
563 ! The nodes of a level partition the dofs of the level below (checked
564 ! once in build_agg_csr), so no two nodes write the same vec_out entry
565 ! and the node loop threads as-is. vec_in(node%gid) is loop-invariant,
566 ! hoist it. Indexed rather than associated, since associate names
567 ! inside an OpenMP loop have been unreliable with frt and CCE.
568 !$omp parallel do private(i, val)
569 do n = 1, nagg
570 val = vec_in( this%lvl(lvl)%nodes(n)%gid )
571 do i = 1, this%lvl(lvl)%nodes(n)%ndofs
572 vec_out( this%lvl(lvl)%nodes(n)%dofs(i) ) = &
573 vec_out( this%lvl(lvl)%nodes(n)%dofs(i) ) &
574 + val * this%lvl(lvl)%nodes(n)%interp_p( i )
575 end do
576 end do
577 !$omp end parallel do
578 if (lvl-1 .eq. 0) then
579 call this%gs_h%op(vec_out, this%lvl(lvl)%fine_lvl_dofs, gs_op_add)
580 call col2(vec_out, this%coef%mult, this%lvl(lvl)%fine_lvl_dofs)
581 call this%bc_projector%apply(vec_out, this%lvl(lvl)%fine_lvl_dofs)
582 end if
583 end subroutine tamg_prolongation_operator
584
585
586 subroutine tamg_device_matvec_flat_impl(this, vec_out, vec_in, vec_out_d, &
587 vec_in_d, lvl_out)
588 class(tamg_hierarchy_t), intent(inout) :: this
589 real(kind=rp), intent(inout) :: vec_out(:)
590 real(kind=rp), intent(inout) :: vec_in(:)
591 type(c_ptr) :: vec_out_d
592 type(c_ptr) :: vec_in_d
593 integer, intent(in) :: lvl_out
594 integer :: i, n, cdof, lvl
595
596 lvl = lvl_out
597 n = this%lvl(1)%fine_lvl_dofs
598 if (lvl .eq. 0) then
599 call this%ax%compute(vec_out, vec_in, this%coef, this%msh, this%Xh)
600 call this%gs_h%op(vec_out, n, gs_op_add, glb_cmd_event)
601 call device_stream_wait_event(glb_cmd_queue, glb_cmd_event, 0)
602 call this%bc_projector%apply(vec_out, n)
603 else
604
605 associate(wrk_in_d => this%lvl(1)%wrk_in_d, &
606 wrk_out_d => this%lvl(1)%wrk_out_d)
608 call device_masked_gather_copy_0(wrk_in_d, vec_in_d, &
609 this%lvl(lvl)%map_finest2lvl_d, this%lvl(lvl)%nnodes, n)
611 call this%gs_h%op(this%lvl(1)%wrk_in, n, gs_op_add, glb_cmd_event)
612 call device_stream_wait_event(glb_cmd_queue, glb_cmd_event, 0)
613 call device_col2( wrk_in_d, this%coef%mult_d, n)
614 call this%bc_projector%apply(this%lvl(1)%wrk_in, n)
615
617 call this%ax%compute(this%lvl(1)%wrk_out, this%lvl(1)%wrk_in, &
618 this%coef, this%msh, this%Xh)
619 call this%gs_h%op(this%lvl(1)%wrk_out, n, gs_op_add, glb_cmd_event)
620 call device_stream_wait_event(glb_cmd_queue, glb_cmd_event, 0)
621 call this%bc_projector%apply(this%lvl(1)%wrk_out, n)
622
623 call device_col2( wrk_out_d, this%coef%mult_d, n)
624
626 call device_rzero(vec_out_d, this%lvl(lvl)%nnodes)
627 call device_masked_atomic_reduction_0(vec_out_d, wrk_out_d, &
628 this%lvl(lvl)%map_finest2lvl_d, this%lvl(lvl)%nnodes, n)
629 end associate
630
631 end if
632 end subroutine tamg_device_matvec_flat_impl
633
634 subroutine tamg_device_restriction_operator(this, vec_out_d, vec_in_d, lvl)
635 class(tamg_hierarchy_t), intent(inout) :: this
636 type(c_ptr) :: vec_out_d
637 type(c_ptr) :: vec_in_d
638 integer, intent(in) :: lvl
639 integer :: i, n, m
640 n = this%lvl(lvl)%nnodes
641 m = this%lvl(lvl)%fine_lvl_dofs
642 if (lvl-1 .eq. 0) then
643 call device_col2(vec_in_d, this%coef%mult_d, m)
644 end if
645 call device_rzero(vec_out_d, n)
646 call device_masked_atomic_reduction_0(vec_out_d, vec_in_d, &
647 this%lvl(lvl)%map_f2c_d, n, m)
649
650 subroutine tamg_device_prolongation_operator(this, vec_out_d, vec_in_d, &
651 lvl, vec_out)
652 class(tamg_hierarchy_t), intent(inout) :: this
653 real(kind=rp), intent(inout) :: vec_out(:)
654 type(c_ptr) :: vec_out_d
655 type(c_ptr) :: vec_in_d
656 integer, intent(in) :: lvl
657 integer :: i, n, m
658 n = this%lvl(lvl)%nnodes
659 m = this%lvl(lvl)%fine_lvl_dofs
660 call device_masked_gather_copy_0(vec_out_d, vec_in_d, &
661 this%lvl(lvl)%map_f2c_d, n, m)
662 if (lvl-1 .eq. 0) then
663 call this%gs_h%op(vec_out, m, gs_op_add, glb_cmd_event)
664 call device_stream_wait_event(glb_cmd_queue, glb_cmd_event, 0)
665 call device_col2( vec_out_d, this%coef%mult_d, m)
666 call this%bc_projector%apply(vec_out, m)
667 end if
669
670end module tree_amg
Map a Fortran array to a device (allocate and associate)
Definition device.F90:83
Synchronize a device or stream.
Definition device.F90:119
Unmap a Fortran array from a device (deassociate and free)
Definition device.F90:89
Defines a Matrix-vector product.
Definition ax.f90:34
Coefficients.
Definition coef.f90:34
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.
Definition device.F90:34
subroutine, public device_stream_wait_event(stream, event, flags)
Synchronize a device stream with an event.
Definition device.F90:1544
type(c_ptr), bind(C), public glb_cmd_queue
Global command queue.
Definition device.F90:52
type(c_ptr), bind(C), public glb_cmd_event
Event for the global command queue.
Definition device.F90:63
Gather-scatter.
NEKTON map.
Definition map.f90:3
Definition math.f90:60
subroutine, public col2(a, b, n)
Vector multiplication .
Definition math.f90:1049
subroutine, public rzero(a, n)
Zero a real vector.
Definition math.f90:238
Defines a mesh.
Definition mesh.f90:34
Build configurations.
integer, parameter neko_bcknd_device
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:14
Implements scalar_projector_t.
Defines a function space.
Definition space.f90:34
Implements the base type for TreeAMG hierarchy structure.
Definition tree_amg.f90:34
subroutine tamg_init(this, ax, xh, coef, msh, gs_h, nlvls, bc_projector)
Initialization of TreeAMG hierarchy.
Definition tree_amg.f90:140
subroutine tamg_device_matvec_flat_impl(this, vec_out, vec_in, vec_out_d, vec_in_d, lvl_out)
Definition tree_amg.f90:588
subroutine tamg_device_prolongation_operator(this, vec_out_d, vec_in_d, lvl, vec_out)
Definition tree_amg.f90:652
subroutine lvl_free(this)
deallocate tamg level
Definition tree_amg.f90:230
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...
Definition tree_amg.f90:335
subroutine, public tamg_node_init(node, gid, ndofs)
Initialization of a TreeAMG tree node.
Definition tree_amg.f90:282
subroutine tamg_restriction_operator(this, vec_out, vec_in, lvl)
Restriction operator for TreeAMG. vec_out = R * vec_in.
Definition tree_amg.f90:519
subroutine tamg_prolongation_operator(this, vec_out, vec_in, lvl)
Prolongation operator for TreeAMG. vec_out = P * vec_in.
Definition tree_amg.f90:554
subroutine node_free(this)
deallocate tamg tree node
Definition tree_amg.f90:298
subroutine, public tamg_lvl_init(tamg_lvl, lvl, nnodes, ndofs)
Initialization of a TreeAMG level.
Definition tree_amg.f90:201
subroutine tamg_free(this)
deallocate tamg hierarchy
Definition tree_amg.f90:176
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...
Definition tree_amg.f90:318
subroutine tamg_device_restriction_operator(this, vec_out_d, vec_in_d, lvl)
Definition tree_amg.f90:635
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.
Definition tree_amg.f90:401
Utilities.
Definition utils.f90:35
Base type for a matrix-vector product providing .
Definition ax.f90:43
Coefficients defined on a given (mesh, ) tuple. Arrays use indices (i,j,k,e): element e,...
Definition coef.f90:93
Gather-scatter kernel.
Projector for scalar boundary conditions.
The function space for the SEM solution fields.
Definition space.f90:64
Type for a TreeAMG hierarchy.
Definition tree_amg.f90:101
Type for storing TreeAMG level information.
Definition tree_amg.f90:70
Type for storing TreeAMG tree node information.
Definition tree_amg.f90:56