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)) = &
114 facet_neigh, offset_el, n_facet, is_aggregated, aggregate_size)
115 integer,
intent(inout):: naggs
116 integer,
intent(in) :: max_aggs, n_elements
117 integer,
intent(in) :: facet_neigh(:, :)
118 integer,
intent(in) :: offset_el, n_facet
119 integer,
intent(inout) :: is_aggregated(:)
120 integer,
allocatable,
intent(inout) :: aggregate_size(:)
121 integer,
allocatable :: as_tmp(:)
122 integer,
allocatable :: rand_order(:), fixed_seed(:), saved_seed(:)
123 real(kind=
dp) :: random_value, r
124 integer :: i, side, nhbr, j, tmp, rnd_n
125 logical :: no_nhbr_agg
128 call random_seed( size=rnd_n )
129 allocate(saved_seed(rnd_n))
130 allocate(fixed_seed(rnd_n))
132 call random_seed( get=saved_seed )
133 call random_seed( put=fixed_seed )
136 allocate( rand_order( n_elements ) )
141 do i = n_elements, 2, -1
142 call random_number(r)
143 j = int(r *
real(i, kind=
rp)) + 1
145 rand_order(i) = rand_order(j)
150 call random_seed( put=saved_seed )
152 do tmp = 1, n_elements
154 if (is_aggregated(i) .eq. -1)
then
158 nhbr = facet_neigh(side, i) - offset_el
160 if ((nhbr .gt. 0) .and. (nhbr .le. n_elements))
then
161 if (is_aggregated(nhbr) .ne. -1)
then
162 no_nhbr_agg = .false.
168 if (no_nhbr_agg)
then
170 is_aggregated(i) = naggs
171 if (
size(aggregate_size) .lt. naggs)
then
172 allocate(as_tmp(naggs + 20))
173 as_tmp(1:
size(aggregate_size)) = aggregate_size
174 call move_alloc(as_tmp, aggregate_size)
176 aggregate_size(naggs) = 1
178 nhbr = facet_neigh(side, i) - offset_el
180 if ((nhbr .gt. 0) .and. (nhbr .le. n_elements))
then
181 if (is_aggregated(nhbr) .eq. -1)
then
182 is_aggregated(nhbr) = naggs
183 aggregate_size(naggs) = aggregate_size(naggs) + 1
204 facet_neigh, offset_el, n_facet, is_aggregated, aggregate_size)
205 integer,
intent(inout):: naggs
206 integer,
intent(in) :: max_aggs, n_elements
207 integer,
intent(in) :: facet_neigh(:, :)
208 integer,
intent(in) :: offset_el, n_facet
209 integer,
intent(inout) :: is_aggregated(:)
210 integer,
intent(inout) :: aggregate_size(:)
211 integer :: i, side, nhbr
212 integer :: tnt_agg, tst_agg, tnt_size, tst_size
216 if (is_aggregated(i) .eq. -1)
then
223 nhbr = facet_neigh(side, i) - offset_el
225 if ((nhbr .gt. 0) .and. (nhbr .le. n_elements))
then
226 if (is_aggregated(nhbr) .ne. -1)
then
227 tst_agg = is_aggregated(nhbr)
228 tst_size = aggregate_size(tst_agg)
229 if (tst_size .lt. tnt_size)
then
237 if (tnt_agg .ne. -1)
then
239 is_aggregated(i) = tnt_agg
240 aggregate_size(tnt_agg) = aggregate_size(tnt_agg) + 1
247 if (naggs .gt.
size(aggregate_size))
then
248 call neko_error(
"Creating too many aggregates... " // &
249 "something might be wrong... try increasing max_aggs")
251 is_aggregated(i) = naggs
252 aggregate_size(naggs) = 1
255 nhbr = facet_neigh(side, i) - offset_el
257 if ((nhbr .gt. 0) .and. (nhbr .le. n_elements))
then
258 if (is_aggregated(nhbr) .eq. -1)
then
259 aggregate_size(naggs) = aggregate_size(naggs) + 1
260 is_aggregated(nhbr) = naggs
281 facet_neigh, offset_el, n_facet, is_aggregated)
282 integer,
allocatable,
intent(inout) :: agg_nhbr(:, :)
283 integer,
intent(inout) :: n_agg_nhbr
284 integer,
intent(in) :: n_elements
285 integer,
intent(in) :: facet_neigh(:, :)
286 integer,
intent(in) :: offset_el, n_facet
287 integer,
intent(inout) :: is_aggregated(:)
288 integer :: i, j, side, nhbr, tst_agg, tnt_agg, n_nhbr_loc
290 integer,
allocatable :: agg_nhbr_counter(:)
295 allocate(agg_nhbr_counter(maxval(is_aggregated)), source = 0)
299 tnt_agg = is_aggregated(i)
302 nhbr = facet_neigh(side, i) - offset_el
303 if ((nhbr .gt. 0) .and. (nhbr .le. n_elements))
then
304 tst_agg = is_aggregated(nhbr)
305 if (tst_agg .le. 0)
then
306 call neko_error(
"Unaggregated element detected. " // &
307 "We do not want to handle that here...")
309 if (tst_agg .ne. tnt_agg)
then
310 agg_nhbr_counter(tnt_agg) = agg_nhbr_counter(tnt_agg) + 1
314 n_agg_nhbr =
max(n_agg_nhbr, agg_nhbr_counter(tnt_agg))
318 allocate(agg_nhbr(n_agg_nhbr, maxval(is_aggregated)), source = -1)
322 tnt_agg = is_aggregated(i)
324 nhbr = facet_neigh(side, i) - offset_el
325 if ((nhbr .gt. 0) .and. (nhbr .le. n_elements))
then
326 tst_agg = is_aggregated(nhbr)
327 if (tst_agg .le. 0)
then
328 call neko_error(
"Unaggregated element detected. " // &
329 "We do not want to handle that here...")
331 if (tst_agg .ne. tnt_agg)
then
334 if ((agg_nhbr(j, tnt_agg) .eq. tst_agg))
then
336 else if ((agg_nhbr(j, tnt_agg) .eq. -1) .and. &
337 (.not. agg_added))
then
338 agg_nhbr(j, tnt_agg) = tst_agg
340 n_agg_nhbr =
max(n_agg_nhbr, j)
343 if (.not. agg_added)
then
344 call neko_error(
"Aggregates have too many neighbors... " // &
345 "probably. Or some other error.")
360 type(tamg_hierarchy_t),
intent(inout) :: tamg
361 integer,
intent(in) :: lvl_id
362 integer,
intent(in) :: max_aggs
363 integer,
intent(in) :: facet_neigh(:, :)
364 integer,
intent(inout),
allocatable :: agg_nhbr(:, :)
365 integer,
allocatable :: is_aggregated(:)
366 integer,
allocatable :: aggregate_size(:)
367 integer :: n_elements, naggs, n_facet, offset_el
368 integer :: i, j, l, ntot, n_agg_facet, gid_ptr
370 if (lvl_id .lt. 2)
then
371 call neko_error(
"For now, can only use greedy agg after elms " // &
372 "have been aggregated to points (level 1)")
373 else if (lvl_id .eq. 2)
then
375 offset_el = tamg%msh%offset_el
377 n_facet =
size(facet_neigh, 1)
382 n_elements = tamg%lvl(lvl_id-1)%nnodes
383 allocate( is_aggregated( n_elements ) )
384 allocate( aggregate_size( max_aggs ) )
390 aggregate_size = huge(i)
394 facet_neigh, offset_el, n_facet, &
395 is_aggregated, aggregate_size)
402 facet_neigh, offset_el, n_facet, &
403 is_aggregated, aggregate_size)
409 facet_neigh, offset_el, n_facet, is_aggregated)
415 ntot = ntot + aggregate_size(l)
418 call tamg_lvl_init( tamg%lvl(lvl_id), lvl_id, naggs, ntot)
422 call tamg_node_init( tamg%lvl(lvl_id)%nodes(l), l, aggregate_size(l))
425 if (is_aggregated(i) .eq. l)
then
427 tamg%lvl(lvl_id)%nodes(l)%dofs(j) = i
429 tamg%lvl(lvl_id)%map_f2c(i) = l
430 gid_ptr = gid_ptr + 1
433 if (j .ne. tamg%lvl(lvl_id)%nodes(l)%ndofs)
then
434 call neko_error(
"Aggregation problem. Not enough dofs in node.")
436 ntot = ntot + aggregate_size(l)
441 deallocate( is_aggregated )
442 deallocate( aggregate_size )
449 type(tamg_hierarchy_t),
intent(inout) :: tamg
450 integer,
intent(in) :: lvl_id
453 nt = tamg%lvl(lvl_id-1)%nnodes
455 call tamg_lvl_init( tamg%lvl(lvl_id), lvl_id, 1, nt)
458 call tamg_node_init( tamg%lvl(lvl_id)%nodes(1), 1, nt)
460 do i = 1, tamg%lvl(lvl_id-1)%nnodes
461 tamg%lvl(lvl_id)%nodes(1)%dofs(i) = tamg%lvl(lvl_id-1)%nodes(i)%gid
463 tamg%lvl(lvl_id)%map_f2c(i) = 1
469 integer,
intent(in) :: lvl, ndof, nagg
470 integer :: na_max, na_min, na_avg, na_sum
471 character(len=LOG_SIZE) :: log_buf
473 write(log_buf,
'(A8,I2,A37)')
'-- level', lvl, &
474 '-- Aggregation: Element-as-Aggregate'
476 call neko_log%message(log_buf)
478 call mpi_allreduce(nagg, na_max, 1, mpi_integer, mpi_max, &
480 call mpi_allreduce(nagg, na_min, 1, mpi_integer, mpi_min, &
482 call mpi_allreduce(nagg, na_sum, 1, mpi_integer, mpi_sum, &
484 na_avg = na_sum / pe_size
485 write(log_buf,
'(A35,I6,A1,I6,A1,I6,A1)')
'Number of Aggregates: (', &
486 na_min,
',', na_avg,
',', na_max,
')'
487 call neko_log%message(log_buf)
492 integer,
intent(in) :: lvl, ndof, nagg
493 integer,
intent(in) :: is_aggregated(:)
494 integer :: num_aggregated, i, na_max, na_min, na_avg, na_sum
495 real(kind=rp) :: agg_frac
496 integer(kind=i8) :: glb_dof, glb_aggd, loc_dof, loc_aggd
497 character(len=LOG_SIZE) :: log_buf
500 if (is_aggregated(i) .gt. -1)
then
501 num_aggregated = num_aggregated + 1
506 write(log_buf,
'(A27)')
'Aggregation: phase1'
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, &
513 call mpi_allreduce(loc_aggd, glb_aggd, 1, mpi_integer8, mpi_sum, &
515 agg_frac =
real(glb_aggd, rp) /
real(glb_dof, rp)
517 call mpi_allreduce(nagg, na_max, 1, mpi_integer, mpi_max, &
519 call mpi_allreduce(nagg, na_min, 1, mpi_integer, mpi_min, &
521 call mpi_allreduce(nagg, na_sum, 1, mpi_integer, mpi_sum, &
523 na_avg = na_sum / pe_size
524 write(log_buf,
'(A35,I6,A1,I6,A1,I6,A1)')
'Number of Aggregates: (', &
525 na_min,
',', na_avg,
',', na_max,
')'
526 call neko_log%message(log_buf)
528 call mpi_allreduce(num_aggregated, na_max, 1, mpi_integer, mpi_max, &
530 call mpi_allreduce(num_aggregated, na_min, 1, mpi_integer, mpi_min, &
532 call mpi_allreduce(num_aggregated, na_sum, 1, mpi_integer, mpi_sum, &
534 na_avg = na_sum / pe_size
535 write(log_buf,
'(A35,I6,A1,I6,A1,I6,A1,F6.2)')
'Aggregated: (', &
536 na_min,
',', na_avg,
',', na_max,
')', (agg_frac*100)
537 call neko_log%message(log_buf)
541 integer,
intent(in) :: lvl, ndof, nagg
542 integer,
intent(in) :: is_aggregated(:)
543 integer :: num_aggregated, i, na_max, na_min, na_avg, na_sum
544 real(kind=rp) :: agg_frac
545 integer(kind=i8) :: glb_dof, glb_aggd, loc_dof, loc_aggd
546 character(len=LOG_SIZE) :: log_buf
549 if (is_aggregated(i) .gt. -1)
then
550 num_aggregated = num_aggregated + 1
554 write(log_buf,
'(A27)')
'Aggregation: phase2'
555 call neko_log%message(log_buf)
557 loc_aggd = int(num_aggregated, i8)
558 loc_dof = int(ndof, i8)
559 call mpi_allreduce(loc_dof, glb_dof, 1, mpi_integer8, mpi_sum, &
561 call mpi_allreduce(loc_aggd, glb_aggd, 1, mpi_integer8, mpi_sum, &
563 agg_frac =
real(glb_aggd, rp) /
real(glb_dof, rp)
565 call mpi_allreduce(nagg, na_max, 1, mpi_integer, mpi_max, &
567 call mpi_allreduce(nagg, na_min, 1, mpi_integer, mpi_min, &
569 call mpi_allreduce(nagg, na_sum, 1, mpi_integer, mpi_sum, &
571 na_avg = na_sum / pe_size
572 write(log_buf,
'(A35,I6,A1,I6,A1,I6,A1)')
'Number of Aggregates: (', &
573 na_min,
',', na_avg,
',', na_max,
')'
574 call neko_log%message(log_buf)
576 call mpi_allreduce(num_aggregated, na_max, 1, mpi_integer, mpi_max, &
578 call mpi_allreduce(num_aggregated, na_min, 1, mpi_integer, mpi_min, &
580 call mpi_allreduce(num_aggregated, na_sum, 1, mpi_integer, mpi_sum, &
582 na_avg = na_sum / pe_size
583 write(log_buf,
'(A35,I6,A1,I6,A1,I6,A1,F6.2)')
'Aggregated: (', &
584 na_min,
',', na_avg,
',', na_max,
')', (agg_frac*100)
585 call neko_log%message(log_buf)
589 integer,
intent(in) :: lvl, ndof, nagg
590 character(len=LOG_SIZE) :: log_buf
594 write(log_buf,
'(A26,I6)')
'Aggregation: Done.', nagg
595 call neko_log%message(log_buf)
605 type(tamg_hierarchy_t),
intent(inout) :: tamg
606 integer,
intent(in) :: lvl_id
607 integer,
intent(in) :: max_aggs
608 integer,
intent(in) :: facet_neigh(:, :)
609 integer,
intent(inout),
allocatable :: agg_nhbr(:, :)
610 integer,
allocatable :: is_aggregated(:)
611 integer,
allocatable :: aggregate_size(:)
612 integer,
allocatable :: rand_order(:), fixed_seed(:), saved_seed(:)
613 integer :: n_elements, naggs, n_facet, offset_el
614 integer :: i, j, l, ntot, n_agg_facet, gid_ptr, n_agg_nhbr
615 integer :: n_pairs, tmp, rnd_n
616 integer :: side, nhbr, nhbr_id
617 real(kind=rp) :: nhbr_msr, nhbr_tst, r
619 if (lvl_id .lt. 2)
then
620 call neko_error(
"For now, can only use greedy agg after elms " // &
621 "have been aggregated to points (level 1)")
622 else if (lvl_id .eq. 2)
then
624 offset_el = tamg%msh%offset_el
626 n_facet =
size(facet_neigh, 1)
630 n_elements = tamg%lvl(lvl_id-1)%nnodes
631 n_pairs = n_elements / 2
632 allocate( is_aggregated( n_elements ) )
633 allocate( aggregate_size( n_elements ) )
637 aggregate_size = huge(i)
640 call random_seed( size=rnd_n )
641 allocate(saved_seed(rnd_n))
642 allocate(fixed_seed(rnd_n))
644 call random_seed( get=saved_seed )
645 call random_seed( put=fixed_seed )
648 allocate( rand_order( n_elements ) )
653 do i = n_elements, 2, -1
654 call random_number(r)
655 j = int(r *
real(i, kind=rp)) + 1
657 rand_order(i) = rand_order(j)
662 call random_seed( put=saved_seed )
666 do tmp = 1, n_elements
668 if (is_aggregated(i) .eq. -1)
then
673 nhbr = facet_neigh(side, i) - offset_el
674 if ((nhbr .gt. 0) .and. (nhbr .le. n_elements))
then
675 if (is_aggregated(nhbr) .eq. -1)
then
677 if (nhbr_tst .gt. nhbr_msr)
then
685 if (nhbr_id .ne. -1)
then
687 is_aggregated(i) = naggs
688 is_aggregated(nhbr_id) = naggs
689 aggregate_size(naggs) = 2
692 is_aggregated(i) = naggs
693 aggregate_size(naggs) = 1
698 facet_neigh, offset_el, n_facet, is_aggregated)
703 call tamg_lvl_init( tamg%lvl(lvl_id), lvl_id, naggs, ntot)
707 call tamg_node_init( tamg%lvl(lvl_id)%nodes(l), l, aggregate_size(l))
710 if (is_aggregated(i) .eq. l)
then
712 tamg%lvl(lvl_id)%nodes(l)%dofs(j) = i
714 tamg%lvl(lvl_id)%map_f2c(i) = l
715 gid_ptr = gid_ptr + 1
718 if (j .ne. tamg%lvl(lvl_id)%nodes(l)%ndofs)
then
719 call neko_error(
"Aggregation problem. Not enough dofs in node.")
721 ntot = ntot + aggregate_size(l)
724 deallocate( is_aggregated )
725 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.