Neko 1.99.5
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
tree_amg_aggregate.f90
Go to the documentation of this file.
1! Copyright (c) 2024, 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!
36 use utils, only : neko_error, linear_index
37 use num_types, only : rp, dp, i8
39 use mpi_f08, only : mpi_allreduce, mpi_integer, mpi_integer8, &
40 mpi_min, mpi_max, mpi_sum
41 use mesh, only : mesh_t
42 use logger, only : neko_log, log_size
43 implicit none
44
45 type, public :: tamg_agg_monitor_t
46 ! Summary info
47 integer :: level
48 integer :: num_dofs
49 integer :: num_aggs
50 ! aggregation progress info
51 integer :: phase1_naggs
52 integer :: phase1_ndof_aggregated
53 integer :: phase2_naggs
54 integer :: phase2_ndof_aggregated
55 end type tamg_agg_monitor_t
56
57contains
58
66 subroutine aggregate_finest_level(tamg, lx, ly, lz, ne)
67 type(tamg_hierarchy_t), intent(inout) :: tamg
68 integer, intent(in) :: lx, ly, lz, ne
69 integer :: i, j, k, l, nl, nt
70 integer :: lid, gid_ptr
71 integer :: lvl_id
72 lvl_id = 1
73 ! Count things
74 nl = lx*ly*lz
75 nt = nl*ne
76 ! Allocate. For finest level, each aggregate is a node.
77 call tamg_lvl_init(tamg%lvl(lvl_id), lvl_id, ne, nt)
78 gid_ptr = 1
79 do l = 1, ne
80 call tamg_node_init( tamg%lvl(lvl_id)%nodes(l), l, nl)
81 ! Fill the nodes
82 lid = 0
83 do k = 1, lz
84 do j = 1, ly
85 do i = 1, lx
86 lid = lid + 1
87 tamg%lvl(lvl_id)%nodes(l)%dofs(lid) = linear_index(i, j, k, l, &
88 lx, ly, lz)
89
90 tamg%lvl(lvl_id)%map_f2c(linear_index(i,j,k,l, lx, ly, lz)) = &
91 l
92 gid_ptr = gid_ptr + 1
93 end do
94 end do
95 end do
96 end do
97
98 call aggregation_monitor_finest(lvl_id, nt, ne)
99
100 end subroutine aggregate_finest_level
101
113 subroutine agg_greedy_first_pass(naggs, max_aggs, n_elements, &
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
126
127 ! Save current random seed and set a fixed seed
128 call random_seed( size=rnd_n )
129 allocate(saved_seed(rnd_n))
130 allocate(fixed_seed(rnd_n))
131 fixed_seed = 3901
132 call random_seed( get=saved_seed )
133 call random_seed( put=fixed_seed )
134
135 ! Initialize a random permutation
136 allocate( rand_order( n_elements ) )
137 do i = 1, n_elements
138 rand_order(i) = i
139 end do
140 ! Shuffle rand_order using Fisher-Yates algorithm
141 do i = n_elements, 2, -1
142 call random_number(r)
143 j = int(r * real(i, kind=rp)) + 1
144 tmp = rand_order(i)
145 rand_order(i) = rand_order(j)
146 rand_order(j) = tmp
147 end do
148
149 ! Restore saved random seed
150 call random_seed( put=saved_seed )
151
152 do tmp = 1, n_elements
153 i = rand_order(tmp)
154 if (is_aggregated(i) .eq. -1) then
155 ! Check to see if any of the points neighbors are aggregated
156 no_nhbr_agg = .true.
157 do side = 1, n_facet
158 nhbr = facet_neigh(side, i) - offset_el
159 ! if nhbr exists
160 if ((nhbr .gt. 0) .and. (nhbr .le. n_elements)) then
161 if (is_aggregated(nhbr) .ne. -1) then
162 no_nhbr_agg = .false.
163 end if
164 end if
165 end do ! side
166
167 ! if no neighbors are aggregated, create new aggregate
168 if (no_nhbr_agg) then
169 naggs = naggs + 1
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)
175 end if
176 aggregate_size(naggs) = 1
177 do side = 1, n_facet
178 nhbr = facet_neigh(side, i) - offset_el
179 ! if nhbr exists
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
184 end if
185 end if
186 end do ! side
187 end if ! no_nhbr_agg
188 end if ! is_aggregated(i)
189 end do
190 end subroutine agg_greedy_first_pass
191
203 subroutine agg_greedy_second_pass(naggs, max_aggs, n_elements, &
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
213
214 ! Add remaining unaggregated nodes to aggregates
215 do i = 1, n_elements
216 if (is_aggregated(i) .eq. -1) then
217 ! dof i is unaggregated. Check neighbors, add to smallest neighbor
218 tnt_agg = -1
219 tnt_size = huge(0) ! TODO: replace with large number
220 tst_agg = -1
221 tst_size = huge(0) ! TODO: replace with large number
222 do side = 1, n_facet
223 nhbr = facet_neigh(side, i) - offset_el
224 ! if nhbr exists
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
230 tnt_size = tst_size
231 tnt_agg = tst_agg
232 end if
233 end if
234 end if
235 end do
236
237 if (tnt_agg .ne. -1) then
238 ! if neighbor aggregate found add to that aggregate
239 is_aggregated(i) = tnt_agg
240 aggregate_size(tnt_agg) = aggregate_size(tnt_agg) + 1
241 else
242 ! if none of the neignbors are aggregated. might as well make a
243 ! new aggregate
244 naggs = naggs + 1
245 ! TODO: another movealoc here? Error? the max_aggs needs to
246 ! change though...
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")
250 end if
251 is_aggregated(i) = naggs
252 aggregate_size(naggs) = 1
253 ! Add neighbors to aggregate if unaggregated
254 do side = 1, n_facet
255 nhbr = facet_neigh(side, i) - offset_el
256 ! if nhbr exists
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
261 end if
262 end if
263 end do
264 end if
265
266 end if
267 end do
268 end subroutine agg_greedy_second_pass
269
280 subroutine agg_fill_nhbr_info(agg_nhbr, n_agg_nhbr, n_elements, &
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
289 logical :: agg_added
290 integer, allocatable :: agg_nhbr_counter(:)
291
292 n_agg_nhbr = 0
293 n_nhbr_loc = 0
294
295 allocate(agg_nhbr_counter(maxval(is_aggregated)), source = 0)
296
297 ! Count max possible neighbors to an aggregate
298 do i = 1, n_elements!TODO: this is the lazy expensive way...
299 tnt_agg = is_aggregated(i)
300 n_nhbr_loc = 0
301 do side = 1, n_facet
302 nhbr = facet_neigh(side, i) - offset_el
303 if ((nhbr .gt. 0) .and. (nhbr .le. n_elements)) then ! if nhbr exists
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...")
308 end if
309 if (tst_agg .ne. tnt_agg) then
310 agg_nhbr_counter(tnt_agg) = agg_nhbr_counter(tnt_agg) + 1
311 end if
312 end if
313 end do
314 n_agg_nhbr = max(n_agg_nhbr, agg_nhbr_counter(tnt_agg))
315 end do
316
317 ! Allocate for neighbor info
318 allocate(agg_nhbr(n_agg_nhbr, maxval(is_aggregated)), source = -1)
319
320 ! fill neighbor info
321 do i = 1, n_elements!TODO: this is the lazy expensive way...
322 tnt_agg = is_aggregated(i)
323 do side = 1, n_facet
324 nhbr = facet_neigh(side, i) - offset_el
325 if ((nhbr .gt. 0) .and. (nhbr .le. n_elements)) then ! if nhbr exists
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...")
330 end if
331 if (tst_agg .ne. tnt_agg) then
332 agg_added = .false.
333 do j = 1, n_agg_nhbr
334 if ((agg_nhbr(j, tnt_agg) .eq. tst_agg)) then
335 agg_added = .true.
336 else if ((agg_nhbr(j, tnt_agg) .eq. -1) .and. &
337 (.not. agg_added)) then
338 agg_nhbr(j, tnt_agg) = tst_agg
339 agg_added = .true.
340 n_agg_nhbr = max(n_agg_nhbr, j)
341 end if
342 end do! j
343 if (.not. agg_added) then
344 call neko_error("Aggregates have too many neighbors... " // &
345 "probably. Or some other error.")
346 end if
347 end if
348 end if
349 end do ! side
350 end do ! i
351 end subroutine agg_fill_nhbr_info
352
359 subroutine aggregate_greedy(tamg, lvl_id, max_aggs, facet_neigh, agg_nhbr)
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
369
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
374 n_facet = 6 ! NEKO elements are hexes, thus have 6 face neighbors
375 offset_el = tamg%msh%offset_el
376 else
377 n_facet = size(facet_neigh, 1)
378 offset_el = 0
379 end if
380
381 naggs = 0
382 n_elements = tamg%lvl(lvl_id-1)%nnodes
383 allocate( is_aggregated( n_elements ) )
384 allocate( aggregate_size( max_aggs ) )
385
386 ! fill with false
387 is_aggregated = -1
388
389 ! Fill with large number
390 aggregate_size = huge(i)!999999
391
392 ! First pass of greedy aggregation.
393 call agg_greedy_first_pass(naggs, max_aggs, n_elements, &
394 facet_neigh, offset_el, n_facet, &
395 is_aggregated, aggregate_size)
396
397 call aggregation_monitor_phase1(lvl_id, n_elements, naggs, is_aggregated)
398
399 ! Second pass of greedy aggregation, adding unaggregated dofs to neighboring
400 ! aggregates.
401 call agg_greedy_second_pass(naggs, max_aggs, n_elements, &
402 facet_neigh, offset_el, n_facet, &
403 is_aggregated, aggregate_size)
404
405 call aggregation_monitor_phase2(lvl_id, n_elements, naggs, is_aggregated)
406
407 if (.true.) then! if needed on next level...
408 call agg_fill_nhbr_info(agg_nhbr, n_agg_facet, n_elements, &
409 facet_neigh, offset_el, n_facet, is_aggregated)
410 end if
411
412 ! count things
413 ntot = 0
414 do l = 1, naggs
415 ntot = ntot + aggregate_size(l)
416 end do
417 ! Allocate and fill lvl and nodes
418 call tamg_lvl_init( tamg%lvl(lvl_id), lvl_id, naggs, ntot)
419 ntot = 0
420 gid_ptr = 1
421 do l = 1, naggs
422 call tamg_node_init( tamg%lvl(lvl_id)%nodes(l), l, aggregate_size(l))
423 j = 0
424 do i = 1, n_elements!TODO: this is the lazy expensive way...
425 if (is_aggregated(i) .eq. l) then
426 j = j+1
427 tamg%lvl(lvl_id)%nodes(l)%dofs(j) = i
428
429 tamg%lvl(lvl_id)%map_f2c(i) = l
430 gid_ptr = gid_ptr + 1
431 end if
432 end do
433 if (j .ne. tamg%lvl(lvl_id)%nodes(l)%ndofs) then
434 call neko_error("Aggregation problem. Not enough dofs in node.")
435 end if
436 ntot = ntot + aggregate_size(l)
437 end do
438
439 call aggregation_monitor_final(lvl_id, ntot, naggs)
440
441 deallocate( is_aggregated )
442 deallocate( aggregate_size )
443 end subroutine aggregate_greedy
444
448 subroutine aggregate_end( tamg, lvl_id)
449 type(tamg_hierarchy_t), intent(inout) :: tamg
450 integer, intent(in) :: lvl_id
451 integer :: nt, i
452 ! link all branches together at a point
453 nt = tamg%lvl(lvl_id-1)%nnodes
454 ! Allocate lvl
455 call tamg_lvl_init( tamg%lvl(lvl_id), lvl_id, 1, nt)
456
457 ! Allocate node
458 call tamg_node_init( tamg%lvl(lvl_id)%nodes(1), 1, nt)
459 ! Fill node
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
462
463 tamg%lvl(lvl_id)%map_f2c(i) = 1
464 end do
465
466 end subroutine aggregate_end
467
468 subroutine aggregation_monitor_finest(lvl, ndof, nagg)
469 integer, intent(in) :: lvl, ndof, nagg
470 integer :: na_max, na_min, na_avg, na_sum
471 character(len=LOG_SIZE) :: log_buf
472
473 write(log_buf, '(A8,I2,A37)') '-- level', lvl, &
474 '-- Aggregation: Element-as-Aggregate'
475 !write(log_buf, '(A44)') 'Aggregation: Element-as-Aggregate'
476 call neko_log%message(log_buf)
477
478 call mpi_allreduce(nagg, na_max, 1, mpi_integer, mpi_max, &
479 neko_comm)
480 call mpi_allreduce(nagg, na_min, 1, mpi_integer, mpi_min, &
481 neko_comm)
482 call mpi_allreduce(nagg, na_sum, 1, mpi_integer, mpi_sum, &
483 neko_comm)
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)
488
489 end subroutine aggregation_monitor_finest
490
491 subroutine aggregation_monitor_phase1(lvl, ndof, nagg, is_aggregated)
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
498 num_aggregated = 0
499 do i = 1, ndof
500 if (is_aggregated(i) .gt. -1) then
501 num_aggregated = num_aggregated + 1
502 end if
503 end do
504
505 !write(log_buf, '(A8,I2,A24)') '-- level',lvl,'-- Aggregation: phase1'
506 write(log_buf, '(A27)') 'Aggregation: phase1'
507 call neko_log%message(log_buf)
508
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, &
512 neko_comm)
513 call mpi_allreduce(loc_aggd, glb_aggd, 1, mpi_integer8, mpi_sum, &
514 neko_comm)
515 agg_frac = real(glb_aggd, rp) / real(glb_dof, rp)
516
517 call mpi_allreduce(nagg, na_max, 1, mpi_integer, mpi_max, &
518 neko_comm)
519 call mpi_allreduce(nagg, na_min, 1, mpi_integer, mpi_min, &
520 neko_comm)
521 call mpi_allreduce(nagg, na_sum, 1, mpi_integer, mpi_sum, &
522 neko_comm)
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)
527
528 call mpi_allreduce(num_aggregated, na_max, 1, mpi_integer, mpi_max, &
529 neko_comm)
530 call mpi_allreduce(num_aggregated, na_min, 1, mpi_integer, mpi_min, &
531 neko_comm)
532 call mpi_allreduce(num_aggregated, na_sum, 1, mpi_integer, mpi_sum, &
533 neko_comm)
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)
538 end subroutine aggregation_monitor_phase1
539
540 subroutine aggregation_monitor_phase2(lvl, ndof, nagg, is_aggregated)
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
547 num_aggregated = 0
548 do i = 1, ndof
549 if (is_aggregated(i) .gt. -1) then
550 num_aggregated = num_aggregated + 1
551 end if
552 end do
553 !write(log_buf, '(A8,I2,A24)') '-- level',lvl,'-- Aggregation: phase2'
554 write(log_buf, '(A27)') 'Aggregation: phase2'
555 call neko_log%message(log_buf)
556
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, &
560 neko_comm)
561 call mpi_allreduce(loc_aggd, glb_aggd, 1, mpi_integer8, mpi_sum, &
562 neko_comm)
563 agg_frac = real(glb_aggd, rp) / real(glb_dof, rp)
564
565 call mpi_allreduce(nagg, na_max, 1, mpi_integer, mpi_max, &
566 neko_comm)
567 call mpi_allreduce(nagg, na_min, 1, mpi_integer, mpi_min, &
568 neko_comm)
569 call mpi_allreduce(nagg, na_sum, 1, mpi_integer, mpi_sum, &
570 neko_comm)
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)
575
576 call mpi_allreduce(num_aggregated, na_max, 1, mpi_integer, mpi_max, &
577 neko_comm)
578 call mpi_allreduce(num_aggregated, na_min, 1, mpi_integer, mpi_min, &
579 neko_comm)
580 call mpi_allreduce(num_aggregated, na_sum, 1, mpi_integer, mpi_sum, &
581 neko_comm)
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)
586 end subroutine aggregation_monitor_phase2
587
588 subroutine aggregation_monitor_final(lvl, ndof, nagg)
589 integer, intent(in) :: lvl, ndof, nagg
590 character(len=LOG_SIZE) :: log_buf
591 !TODO: calculate min and max agg size
592 !write(log_buf, '(A8,I2,A23,I6)') '-- level',lvl,'-- Aggregation: Done.', &
593 ! nagg
594 write(log_buf, '(A26,I6)') 'Aggregation: Done.', nagg
595 call neko_log%message(log_buf)
596 end subroutine aggregation_monitor_final
597
604 subroutine aggregate_pairs(tamg, lvl_id, max_aggs, facet_neigh, agg_nhbr)
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
618
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
623 n_facet = 6
624 offset_el = tamg%msh%offset_el
625 else
626 n_facet = size(facet_neigh, 1)
627 offset_el = 0
628 end if
629
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 ) )
634 ! fill with false
635 is_aggregated = -1
636 ! fill with large number
637 aggregate_size = huge(i)
638
639 ! Save current random seed and set a fixed seed
640 call random_seed( size=rnd_n )
641 allocate(saved_seed(rnd_n))
642 allocate(fixed_seed(rnd_n))
643 fixed_seed = 3901
644 call random_seed( get=saved_seed )
645 call random_seed( put=fixed_seed )
646
647 ! Initialize a random permutation
648 allocate( rand_order( n_elements ) )
649 do i = 1, n_elements
650 rand_order(i) = i
651 end do
652 ! Shuffle rand_order using Fisher-Yates algorithm
653 do i = n_elements, 2, -1
654 call random_number(r)
655 j = int(r * real(i, kind=rp)) + 1
656 tmp = rand_order(i)
657 rand_order(i) = rand_order(j)
658 rand_order(j) = tmp
659 end do
660
661 ! Restore saved random seed
662 call random_seed( put=saved_seed )
663
664 naggs = 0
665 ! first pass of pair agg
666 do tmp = 1, n_elements
667 i = rand_order(tmp)
668 if (is_aggregated(i) .eq. -1) then
669 nhbr_id = -1
670 nhbr_msr = -1.0_rp
671 nhbr_tst = -1.0_rp
672 do side = 1, n_facet
673 nhbr = facet_neigh(side, i) - offset_el
674 if ((nhbr .gt. 0) .and. (nhbr .le. n_elements)) then ! nhbr exists
675 if (is_aggregated(nhbr) .eq. -1) then
676 nhbr_tst = 1.0_rp ! insert desired metric here
677 if (nhbr_tst .gt. nhbr_msr) then ! if nhbr has goodest metric
678 nhbr_id = nhbr
679 nhbr_msr = nhbr_tst
680 end if
681 end if ! is_aggregated(nhbr)
682 end if ! nhbr exists
683 end do ! side
684
685 if (nhbr_id .ne. -1) then
686 naggs = naggs + 1
687 is_aggregated(i) = naggs
688 is_aggregated(nhbr_id) = naggs
689 aggregate_size(naggs) = 2
690 else ! singleton, in theory we want to avoid
691 naggs = naggs + 1
692 is_aggregated(i) = naggs
693 aggregate_size(naggs) = 1
694 end if
695 end if ! is_aggregated(i)
696 end do
697 call agg_fill_nhbr_info( agg_nhbr, n_agg_nhbr, n_elements, &
698 facet_neigh, offset_el, n_facet, is_aggregated)
699
700 ! count things
701 ntot = n_elements
702 ! Allocate and fill lvl and nodes
703 call tamg_lvl_init( tamg%lvl(lvl_id), lvl_id, naggs, ntot)
704 ntot = 0
705 gid_ptr = 1
706 do l = 1, naggs
707 call tamg_node_init( tamg%lvl(lvl_id)%nodes(l), l, aggregate_size(l))
708 j = 0
709 do i = 1, n_elements!TODO: this is the lazy expensive way...
710 if (is_aggregated(i) .eq. l) then
711 j = j+1
712 tamg%lvl(lvl_id)%nodes(l)%dofs(j) = i
713
714 tamg%lvl(lvl_id)%map_f2c(i) = l
715 gid_ptr = gid_ptr + 1
716 end if
717 end do
718 if (j .ne. tamg%lvl(lvl_id)%nodes(l)%ndofs) then
719 call neko_error("Aggregation problem. Not enough dofs in node.")
720 end if
721 ntot = ntot + aggregate_size(l)
722 end do
723 call aggregation_monitor_final(lvl_id, ntot, naggs)
724 deallocate( is_aggregated )
725 deallocate( aggregate_size )
726 end subroutine aggregate_pairs
727
728end module tree_amg_aggregate
double real
Definition comm.F90:1
type(mpi_datatype), public mpi_real_precision
MPI type for working precision of REAL types.
Definition comm.F90:53
integer, public pe_size
MPI size of communicator.
Definition comm.F90:61
type(mpi_comm), public neko_comm
MPI communicator.
Definition comm.F90:45
Logging routines.
Definition log.f90:34
type(log_t), public neko_log
Global log stream.
Definition log.f90:80
integer, parameter, public log_size
Definition log.f90:46
Defines a mesh.
Definition mesh.f90:34
integer, parameter, public i8
Definition num_types.f90:7
integer, parameter, public dp
Definition num_types.f90:9
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:12
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.
Definition tree_amg.f90:34
subroutine, public tamg_node_init(node, gid, ndofs)
Initialization of a TreeAMG tree node.
Definition tree_amg.f90:255
subroutine, public tamg_lvl_init(tamg_lvl, lvl, nnodes, ndofs)
Initialization of a TreeAMG level.
Definition tree_amg.f90:186
Utilities.
Definition utils.f90:35
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, :)
Definition utils.f90:289
Type for a TreeAMG hierarchy.
Definition tree_amg.f90:87
#define max(a, b)
Definition tensor.cu:40