39 use mpi_f08,
only : mpi_allreduce, mpi_integer, mpi_integer8, &
40 mpi_min, mpi_max, mpi_sum
51 integer :: phase1_naggs
52 integer :: phase1_ndof_aggregated
53 integer :: phase2_naggs
54 integer :: phase2_ndof_aggregated
68 integer,
intent(in) :: lx, ly, lz, ne
69 integer :: i, j, k, l, nl, nt
70 integer :: lid, gid_ptr
87 tamg%lvl(lvl_id)%nodes(l)%dofs(lid) =
linear_index(i, j, k, l, &
90 tamg%lvl(lvl_id)%map_f2c(
linear_index(i,j,k,l,lx,ly,lz)) = l
111 facet_neigh, offset_el, n_facet, is_aggregated, aggregate_size)
112 integer,
intent(inout):: naggs
113 integer,
intent(in) :: max_aggs, n_elements
114 integer,
intent(in) :: facet_neigh(:,:)
115 integer,
intent(in) :: offset_el, n_facet
116 integer,
intent(inout) :: is_aggregated(:)
117 integer,
allocatable,
intent(inout) :: aggregate_size(:)
118 integer,
allocatable :: as_tmp(:)
119 integer,
allocatable :: rand_order(:)
120 real(kind=
dp) :: random_value, r
121 integer :: i, side, nhbr, j, tmp
122 logical :: no_nhbr_agg
125 allocate( rand_order( n_elements ) )
130 do i = n_elements, 2, -1
131 call random_number(r)
132 j = int(r *
real(i, kind=
rp)) + 1
134 rand_order(i) = rand_order(j)
142 do tmp = 1, n_elements
144 if (is_aggregated(i) .eq. -1)
then
148 nhbr = facet_neigh(side, i) - offset_el
149 if ((nhbr .gt. 0).and.(nhbr .le. n_elements)) then
150 if (is_aggregated(nhbr) .ne. -1)
then
151 no_nhbr_agg = .false.
157 if (no_nhbr_agg)
then
159 is_aggregated(i) = naggs
160 if(
size(aggregate_size).lt.naggs)
then
161 allocate(as_tmp(naggs + 20))
162 as_tmp(1:
size(aggregate_size)) = aggregate_size
163 call move_alloc(as_tmp, aggregate_size)
165 aggregate_size(naggs) = 1
167 nhbr = facet_neigh(side, i) - offset_el
168 if ((nhbr .gt. 0).and.(nhbr .le. n_elements)) then
169 if (is_aggregated(nhbr) .eq. -1)
then
170 is_aggregated(nhbr) = naggs
171 aggregate_size(naggs) = aggregate_size(naggs) + 1
191 facet_neigh, offset_el, n_facet, is_aggregated, aggregate_size)
192 integer,
intent(inout):: naggs
193 integer,
intent(in) :: max_aggs, n_elements
194 integer,
intent(in) :: facet_neigh(:,:)
195 integer,
intent(in) :: offset_el, n_facet
196 integer,
intent(inout) :: is_aggregated(:)
197 integer,
intent(inout) :: aggregate_size(:)
198 integer :: i, side, nhbr
199 integer :: tnt_agg, tst_agg, tnt_size, tst_size
203 if (is_aggregated(i) .eq. -1)
then
210 nhbr = facet_neigh(side, i) - offset_el
211 if ((nhbr .gt. 0).and.(nhbr .le. n_elements)) then
212 if (is_aggregated(nhbr) .ne. -1)
then
213 tst_agg = is_aggregated(nhbr)
214 tst_size = aggregate_size(tst_agg)
215 if (tst_size .lt. tnt_size)
then
223 if (tnt_agg .ne. -1)
then
225 is_aggregated(i) = tnt_agg
226 aggregate_size(tnt_agg) = aggregate_size(tnt_agg) + 1
230 if (naggs .gt.
size(aggregate_size)) then
231 call neko_error(
"Creating too many aggregates... something might be wrong... try increasing max_aggs")
233 is_aggregated(i) = naggs
234 aggregate_size(naggs) = 1
237 nhbr = facet_neigh(side, i) - offset_el
238 if ((nhbr .gt. 0).and.(nhbr .le. n_elements)) then
239 if (is_aggregated(nhbr) .eq. -1)
then
240 aggregate_size(naggs) = aggregate_size(naggs) + 1
241 is_aggregated(nhbr) = naggs
260 facet_neigh, offset_el, n_facet, is_aggregated)
261 integer,
allocatable,
intent(inout) :: agg_nhbr(:,:)
262 integer,
intent(inout) :: n_agg_nhbr
263 integer,
intent(in) :: n_elements
264 integer,
intent(in) :: facet_neigh(:,:)
265 integer,
intent(in) :: offset_el, n_facet
266 integer,
intent(inout) :: is_aggregated(:)
267 integer :: i, j, side, nhbr, tst_agg, tnt_agg, n_nhbr_loc
269 integer,
allocatable :: agg_nhbr_counter(:)
274 allocate(agg_nhbr_counter( maxval(is_aggregated)), source=0)
278 tnt_agg = is_aggregated(i)
281 nhbr = facet_neigh(side,i) - offset_el
282 if ((nhbr .gt. 0).and.(nhbr .le. n_elements)) then
283 tst_agg = is_aggregated(nhbr)
284 if (tst_agg .le. 0)
call neko_error(
"Unaggregated element detected. We do not want to handle that here...")
285 if (tst_agg .ne. tnt_agg)
then
286 agg_nhbr_counter(tnt_agg) = agg_nhbr_counter(tnt_agg) + 1
290 n_agg_nhbr =
max(n_agg_nhbr, agg_nhbr_counter(tnt_agg))
294 allocate(agg_nhbr(n_agg_nhbr, maxval(is_aggregated)), source=-1)
298 tnt_agg = is_aggregated(i)
300 nhbr = facet_neigh(side,i) - offset_el
301 if ((nhbr .gt. 0).and.(nhbr .le. n_elements)) then
302 tst_agg = is_aggregated(nhbr)
303 if (tst_agg .le. 0)
call neko_error(
"Unaggregated element detected. We do not want to handle that here...")
304 if (tst_agg .ne. tnt_agg)
then
307 if ((agg_nhbr(j,tnt_agg) .eq. tst_agg))
then
309 else if ((agg_nhbr(j,tnt_agg).eq.-1).and.(.not.agg_added))
then
310 agg_nhbr(j,tnt_agg) = tst_agg
312 n_agg_nhbr =
max(n_agg_nhbr, j)
315 if (.not.agg_added)
call neko_error(
"Aggregates have too many neighbors... probably. Or some other error.")
329 type(tamg_hierarchy_t),
intent(inout) :: tamg
330 integer,
intent(in) :: lvl_id
331 integer,
intent(in) :: max_aggs
332 integer,
intent(in) :: facet_neigh(:,:)
333 integer,
intent(inout),
allocatable :: agg_nhbr(:,:)
334 integer,
allocatable :: is_aggregated(:)
335 integer,
allocatable :: aggregate_size(:)
336 integer :: n_elements, naggs, n_facet, offset_el
337 integer :: i, j, l, ntot, n_agg_facet, gid_ptr
339 if (lvl_id .lt. 2)
then
340 call neko_error(
"For now, can only use greedy agg after elms have been aggregated to points (level 1)")
341 else if (lvl_id .eq. 2)
then
343 offset_el = tamg%msh%offset_el
345 n_facet =
size(facet_neigh, 1)
350 n_elements = tamg%lvl(lvl_id-1)%nnodes
351 allocate( is_aggregated( n_elements ) )
352 allocate( aggregate_size( max_aggs ) )
358 aggregate_size = huge(i)
362 facet_neigh, offset_el, n_facet, &
363 is_aggregated, aggregate_size)
369 facet_neigh, offset_el, n_facet, &
370 is_aggregated, aggregate_size)
376 facet_neigh, offset_el, n_facet, is_aggregated)
382 ntot = ntot + aggregate_size(l)
385 call tamg_lvl_init( tamg%lvl(lvl_id), lvl_id, naggs, ntot)
389 call tamg_node_init( tamg%lvl(lvl_id)%nodes(l), l, aggregate_size(l))
392 if (is_aggregated(i) .eq. l)
then
394 tamg%lvl(lvl_id)%nodes(l)%dofs(j) = i
396 tamg%lvl(lvl_id)%map_f2c(i) = l
397 gid_ptr = gid_ptr + 1
400 if (j .ne. tamg%lvl(lvl_id)%nodes(l)%ndofs)
then
401 call neko_error(
"Aggregation problem. Not enough dofs in node.")
403 ntot = ntot + aggregate_size(l)
408 deallocate( is_aggregated )
409 deallocate( aggregate_size )
416 type(tamg_hierarchy_t),
intent(inout) :: tamg
417 integer,
intent(in) :: lvl_id
420 nt = tamg%lvl(lvl_id-1)%nnodes
422 call tamg_lvl_init( tamg%lvl(lvl_id), lvl_id, 1, nt)
425 call tamg_node_init( tamg%lvl(lvl_id)%nodes(1), 1, nt)
427 do i = 1, tamg%lvl(lvl_id-1)%nnodes
428 tamg%lvl(lvl_id)%nodes(1)%dofs(i) = tamg%lvl(lvl_id-1)%nodes(i)%gid
430 tamg%lvl(lvl_id)%map_f2c(i) = 1
436 integer,
intent(in) :: lvl,ndof,nagg
437 integer :: na_max, na_min, na_avg, na_sum
438 character(len=LOG_SIZE) :: log_buf
440 write(log_buf,
'(A8,I2,A37)')
'-- level',lvl,
'-- Aggregation: Element-as-Aggregate'
442 call neko_log%message(log_buf)
444 call mpi_allreduce(nagg, na_max, 1, mpi_integer, mpi_max, neko_comm)
445 call mpi_allreduce(nagg, na_min, 1, mpi_integer, mpi_min, neko_comm)
446 call mpi_allreduce(nagg, na_sum, 1, mpi_integer, mpi_sum, neko_comm)
447 na_avg = na_sum / pe_size
448 write(log_buf,
'(A35,I6,A1,I6,A1,I6,A1)')
'Number of Aggregates: (',na_min,
',',na_avg,
',',na_max,
')'
449 call neko_log%message(log_buf)
454 integer,
intent(in) :: lvl,ndof,nagg
455 integer,
intent(in) :: is_aggregated(:)
456 integer :: num_aggregated, i, na_max, na_min, na_avg, na_sum
457 real(kind=rp) :: agg_frac
458 integer(kind=i8) :: glb_dof, glb_aggd, loc_dof, loc_aggd
459 character(len=LOG_SIZE) :: log_buf
462 if (is_aggregated(i) .gt. -1)
then
463 num_aggregated = num_aggregated + 1
468 write(log_buf,
'(A27)')
'Aggregation: phase1'
469 call neko_log%message(log_buf)
471 loc_aggd = int(num_aggregated, i8)
472 loc_dof = int(ndof, i8)
473 call mpi_allreduce(loc_dof, glb_dof, 1, mpi_integer8, mpi_sum, neko_comm)
474 call mpi_allreduce(loc_aggd, glb_aggd, 1, mpi_integer8, mpi_sum, neko_comm)
475 agg_frac =
real(glb_aggd,rp) /
real(glb_dof,rp)
477 call mpi_allreduce(nagg, na_max, 1, mpi_integer, mpi_max, neko_comm)
478 call mpi_allreduce(nagg, na_min, 1, mpi_integer, mpi_min, neko_comm)
479 call mpi_allreduce(nagg, na_sum, 1, mpi_integer, mpi_sum, neko_comm)
480 na_avg = na_sum / pe_size
481 write(log_buf,
'(A35,I6,A1,I6,A1,I6,A1)')
'Number of Aggregates: (',na_min,
',',na_avg,
',',na_max,
')'
482 call neko_log%message(log_buf)
484 call mpi_allreduce(num_aggregated, na_max, 1, mpi_integer, mpi_max, neko_comm)
485 call mpi_allreduce(num_aggregated, na_min, 1, mpi_integer, mpi_min, neko_comm)
486 call mpi_allreduce(num_aggregated, na_sum, 1, mpi_integer, mpi_sum, neko_comm)
487 na_avg = na_sum / pe_size
488 write(log_buf,
'(A35,I6,A1,I6,A1,I6,A1,F6.2)')
'Aggregated: (',na_min,
',',na_avg,
',',na_max,
')',(agg_frac*100)
489 call neko_log%message(log_buf)
493 integer,
intent(in) :: lvl,ndof,nagg
494 integer,
intent(in) :: is_aggregated(:)
495 integer :: num_aggregated, i, na_max, na_min, na_avg, na_sum
496 real(kind=rp) :: agg_frac
497 integer(kind=i8) :: glb_dof, glb_aggd, loc_dof, loc_aggd
498 character(len=LOG_SIZE) :: log_buf
501 if (is_aggregated(i) .gt. -1)
then
502 num_aggregated = num_aggregated + 1
506 write(log_buf,
'(A27)')
'Aggregation: phase2'
507 call neko_log%message(log_buf)
509 loc_aggd = int(num_aggregated, i8)
510 loc_dof = int(ndof, i8)
511 call mpi_allreduce(loc_dof, glb_dof, 1, mpi_integer8, mpi_sum, neko_comm)
512 call mpi_allreduce(loc_aggd, glb_aggd, 1, mpi_integer8, mpi_sum, neko_comm)
513 agg_frac =
real(glb_aggd,rp) /
real(glb_dof,rp)
515 call mpi_allreduce(nagg, na_max, 1, mpi_integer, mpi_max, neko_comm)
516 call mpi_allreduce(nagg, na_min, 1, mpi_integer, mpi_min, neko_comm)
517 call mpi_allreduce(nagg, na_sum, 1, mpi_integer, mpi_sum, neko_comm)
518 na_avg = na_sum / pe_size
519 write(log_buf,
'(A35,I6,A1,I6,A1,I6,A1)')
'Number of Aggregates: (',na_min,
',',na_avg,
',',na_max,
')'
520 call neko_log%message(log_buf)
522 call mpi_allreduce(num_aggregated, na_max, 1, mpi_integer, mpi_max, neko_comm)
523 call mpi_allreduce(num_aggregated, na_min, 1, mpi_integer, mpi_min, neko_comm)
524 call mpi_allreduce(num_aggregated, na_sum, 1, mpi_integer, mpi_sum, neko_comm)
525 na_avg = na_sum / pe_size
526 write(log_buf,
'(A35,I6,A1,I6,A1,I6,A1,F6.2)')
'Aggregated: (',na_min,
',',na_avg,
',',na_max,
')',(agg_frac*100)
527 call neko_log%message(log_buf)
531 integer,
intent(in) :: lvl,ndof,nagg
532 character(len=LOG_SIZE) :: log_buf
535 write(log_buf,
'(A26,I6)')
'Aggregation: Done.', nagg
536 call neko_log%message(log_buf)
546 type(tamg_hierarchy_t),
intent(inout) :: tamg
547 integer,
intent(in) :: lvl_id
548 integer,
intent(in) :: max_aggs
549 integer,
intent(in) :: facet_neigh(:,:)
550 integer,
intent(inout),
allocatable :: agg_nhbr(:,:)
551 integer,
allocatable :: is_aggregated(:)
552 integer,
allocatable :: aggregate_size(:)
553 integer,
allocatable :: rand_order(:)
554 integer :: n_elements, naggs, n_facet, offset_el
555 integer :: i, j, l, ntot, n_agg_facet, gid_ptr, n_agg_nhbr
556 integer :: n_pairs, tmp
557 integer :: side, nhbr, nhbr_id
558 real(kind=rp) :: nhbr_msr, nhbr_tst, r
560 if (lvl_id .lt. 2)
then
561 call neko_error(
"For now, can only use greedy agg after elms have been aggregated to points (level 1)")
562 else if (lvl_id .eq. 2)
then
564 offset_el = tamg%msh%offset_el
566 n_facet =
size(facet_neigh, 1)
570 n_elements = tamg%lvl(lvl_id-1)%nnodes
571 n_pairs = n_elements / 2
572 allocate( is_aggregated( n_elements ) )
573 allocate( aggregate_size( n_elements ) )
577 aggregate_size = huge(i)
580 allocate( rand_order( n_elements ) )
585 do i = n_elements, 2, -1
586 call random_number(r)
587 j = int(r *
real(i,kind=rp)) + 1
589 rand_order(i) = rand_order(j)
595 do tmp = 1, n_elements
597 if (is_aggregated(i) .eq. -1)
then
602 nhbr = facet_neigh(side, i) - offset_el
603 if ((nhbr .gt. 0).and.(nhbr .le. n_elements))
then
604 if (is_aggregated(nhbr) .eq. -1)
then
606 if (nhbr_tst .gt. nhbr_msr) then
614 if (nhbr_id .ne. -1)
then
616 is_aggregated(i) = naggs
617 is_aggregated(nhbr_id) = naggs
618 aggregate_size(naggs) = 2
621 is_aggregated(i) = naggs
622 aggregate_size(naggs) = 1
627 facet_neigh, offset_el, n_facet, is_aggregated)
632 call tamg_lvl_init( tamg%lvl(lvl_id), lvl_id, naggs, ntot)
636 call tamg_node_init( tamg%lvl(lvl_id)%nodes(l), l, aggregate_size(l))
639 if (is_aggregated(i) .eq. l)
then
641 tamg%lvl(lvl_id)%nodes(l)%dofs(j) = i
643 tamg%lvl(lvl_id)%map_f2c(i) = l
644 gid_ptr = gid_ptr + 1
647 if (j .ne. tamg%lvl(lvl_id)%nodes(l)%ndofs)
then
648 call neko_error(
"Aggregation problem. Not enough dofs in node.")
650 ntot = ntot + aggregate_size(l)
653 deallocate( is_aggregated )
654 deallocate( aggregate_size )
type(mpi_datatype), public mpi_real_precision
MPI type for working precision of REAL types.
integer, public pe_size
MPI size of communicator.
type(mpi_comm), public neko_comm
MPI communicator.
type(log_t), public neko_log
Global log stream.
integer, parameter, public log_size
integer, parameter, public i8
integer, parameter, public dp
integer, parameter, public rp
Global precision used in computations.
Implements an aggregation for TreeAMG hierarchy structure.
subroutine agg_greedy_first_pass(naggs, max_aggs, n_elements, facet_neigh, offset_el, n_facet, is_aggregated, aggregate_size)
First pass of a greedy aggregation Loop through all dofs and aggregate on dof that has all unaggregat...
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 aggregation_monitor_phase2(lvl, ndof, nagg, is_aggregated)
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.
subroutine aggregation_monitor_final(lvl, ndof, nagg)
subroutine agg_greedy_second_pass(naggs, max_aggs, n_elements, facet_neigh, offset_el, n_facet, is_aggregated, aggregate_size)
Second pass of a greedy aggregation Loop through all unaggregated dofs and add them to a neighboring ...
subroutine aggregation_monitor_finest(lvl, ndof, nagg)
subroutine agg_fill_nhbr_info(agg_nhbr, n_agg_nhbr, n_elements, facet_neigh, offset_el, n_facet, is_aggregated)
Create information on which aggregates are "adjacent" to eachother.
subroutine aggregation_monitor_phase1(lvl, ndof, nagg, is_aggregated)
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.
pure integer function, public linear_index(i, j, k, l, lx, ly, lz)
Compute the address of a (i,j,k,l) array with sizes (1:lx, 1:ly, 1:lz, :)
Type for a TreeAMG hierarchy.