Neko 1.99.2
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)) = l
91 gid_ptr = gid_ptr + 1
92 end do
93 end do
94 end do
95 end do
96
97 call aggregation_monitor_finest(lvl_id,nt,ne)
98
99 end subroutine aggregate_finest_level
100
110 subroutine agg_greedy_first_pass(naggs, max_aggs, n_elements, &
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
123
124 ! Initialize a random permutation
125 allocate( rand_order( n_elements ) )
126 do i = 1, n_elements
127 rand_order(i) = i
128 end do
129 ! Shuffle rand_order using Fisher-Yates algorithm
130 do i = n_elements, 2, -1
131 call random_number(r)
132 j = int(r * real(i, kind=rp)) + 1
133 tmp = rand_order(i)
134 rand_order(i) = rand_order(j)
135 rand_order(j) = tmp
136 end do
137
138!-----! do while (naggs .le. max_aggs)
139!-----! call random_number(random_value)
140!-----! i = floor(random_value * n_elements + 1)
141 !do i = 1, n_elements! THE NON-RANDOM VERSION...
142 do tmp = 1, n_elements
143 i = rand_order(tmp)
144 if (is_aggregated(i) .eq. -1) then
145 ! Check to see if any of the points neighbors are aggregated
146 no_nhbr_agg = .true.
147 do side = 1, n_facet
148 nhbr = facet_neigh(side, i) - offset_el
149 if ((nhbr .gt. 0).and.(nhbr .le. n_elements)) then! if nhbr exists
150 if (is_aggregated(nhbr) .ne. -1) then
151 no_nhbr_agg = .false.
152 end if
153 end if
154 end do! side
155
156 ! if no neighbors are aggregated, create new aggregate
157 if (no_nhbr_agg) then
158 naggs = naggs + 1
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)
164 end if
165 aggregate_size(naggs) = 1
166 do side = 1, n_facet
167 nhbr = facet_neigh(side, i) - offset_el
168 if ((nhbr .gt. 0).and.(nhbr .le. n_elements)) then! if nhbr exists
169 if (is_aggregated(nhbr) .eq. -1) then
170 is_aggregated(nhbr) = naggs
171 aggregate_size(naggs) = aggregate_size(naggs) + 1
172 end if
173 end if
174 end do! side
175 end if! no_nhbr_agg
176 end if! is_aggregated(i)
177 end do
178 end subroutine agg_greedy_first_pass
179
190 subroutine agg_greedy_second_pass(naggs, max_aggs, n_elements, &
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
200
201 ! Add remaining unaggregated nodes to aggregates
202 do i = 1, n_elements
203 if (is_aggregated(i) .eq. -1) then
204 ! dof i is unaggregated. Check neighbors, add to smallest neighbor
205 tnt_agg = -1
206 tnt_size = 999!TODO: replace with large number
207 tst_agg = -1
208 tst_size = 999!TODO: replace with large number
209 do side = 1, n_facet
210 nhbr = facet_neigh(side, i) - offset_el
211 if ((nhbr .gt. 0).and.(nhbr .le. n_elements)) then! if nhbr exists
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
216 tnt_size = tst_size
217 tnt_agg = tst_agg
218 end if
219 end if
220 end if
221 end do
222
223 if (tnt_agg .ne. -1) then
224 ! if neighbor aggregate found add to that aggregate
225 is_aggregated(i) = tnt_agg
226 aggregate_size(tnt_agg) = aggregate_size(tnt_agg) + 1
227 else
228 ! if none of the neignbors are aggregated. might as well make a new aggregate
229 naggs = naggs + 1
230 if (naggs .gt. size(aggregate_size)) then!TODO: another movealoc here? Error? the max_aggs needs to change though...
231 call neko_error("Creating too many aggregates... something might be wrong... try increasing max_aggs")
232 end if
233 is_aggregated(i) = naggs
234 aggregate_size(naggs) = 1
235 ! Add neighbors to aggregate if unaggregated
236 do side = 1, n_facet
237 nhbr = facet_neigh(side, i) - offset_el
238 if ((nhbr .gt. 0).and.(nhbr .le. n_elements)) then! if nhbr exists
239 if (is_aggregated(nhbr) .eq. -1) then
240 aggregate_size(naggs) = aggregate_size(naggs) + 1
241 is_aggregated(nhbr) = naggs
242 end if
243 end if
244 end do
245 end if
246
247 end if
248 end do
249 end subroutine agg_greedy_second_pass
250
259 subroutine agg_fill_nhbr_info(agg_nhbr, n_agg_nhbr, n_elements, &
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
268 logical :: agg_added
269 integer, allocatable :: agg_nhbr_counter(:)
270
271 n_agg_nhbr = 0
272 n_nhbr_loc = 0
273
274 allocate(agg_nhbr_counter( maxval(is_aggregated)), source=0)
275
276 ! Count max possible neighbors to an aggregate
277 do i = 1, n_elements!TODO: this is the lazy expensive way...
278 tnt_agg = is_aggregated(i)
279 n_nhbr_loc = 0
280 do side = 1, n_facet
281 nhbr = facet_neigh(side,i) - offset_el
282 if ((nhbr .gt. 0).and.(nhbr .le. n_elements)) then! if nhbr exists
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
287 end if
288 end if
289 end do
290 n_agg_nhbr = max(n_agg_nhbr, agg_nhbr_counter(tnt_agg))
291 end do
292
293 ! Allocate for neighbor info
294 allocate(agg_nhbr(n_agg_nhbr, maxval(is_aggregated)), source=-1)
295
296 ! fill neighbor info
297 do i = 1, n_elements!TODO: this is the lazy expensive way...
298 tnt_agg = is_aggregated(i)
299 do side = 1, n_facet
300 nhbr = facet_neigh(side,i) - offset_el
301 if ((nhbr .gt. 0).and.(nhbr .le. n_elements)) then! if nhbr exists
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
305 agg_added = .false.
306 do j = 1, n_agg_nhbr
307 if ((agg_nhbr(j,tnt_agg) .eq. tst_agg)) then
308 agg_added = .true.
309 else if ((agg_nhbr(j,tnt_agg).eq.-1).and.(.not.agg_added)) then
310 agg_nhbr(j,tnt_agg) = tst_agg
311 agg_added = .true.
312 n_agg_nhbr = max(n_agg_nhbr, j)
313 end if
314 end do! j
315 if (.not.agg_added) call neko_error("Aggregates have too many neighbors... probably. Or some other error.")
316 end if
317 end if
318 end do! side
319 end do! i
320 end subroutine agg_fill_nhbr_info
321
328 subroutine aggregate_greedy(tamg, lvl_id, max_aggs, facet_neigh, agg_nhbr)
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
338
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
342 n_facet = 6 ! NEKO elements are hexes, thus have 6 face neighbors
343 offset_el = tamg%msh%offset_el
344 else
345 n_facet = size(facet_neigh, 1)
346 offset_el = 0
347 end if
348
349 naggs = 0
350 n_elements = tamg%lvl(lvl_id-1)%nnodes
351 allocate( is_aggregated( n_elements ) )
352 allocate( aggregate_size( max_aggs ) )
353
354 ! fill with false
355 is_aggregated = -1
356
357 ! Fill with large number
358 aggregate_size = huge(i)!999999
359
360 ! First pass of greedy aggregation.
361 call agg_greedy_first_pass(naggs, max_aggs, n_elements, &
362 facet_neigh, offset_el, n_facet, &
363 is_aggregated, aggregate_size)
364
365 call aggregation_monitor_phase1(lvl_id, n_elements, naggs, is_aggregated)
366
367 ! Second pass of greedy aggregation, adding unaggregated dofs to neighboring aggregates.
368 call agg_greedy_second_pass(naggs, max_aggs, n_elements, &
369 facet_neigh, offset_el, n_facet, &
370 is_aggregated, aggregate_size)
371
372 call aggregation_monitor_phase2(lvl_id, n_elements, naggs, is_aggregated)
373
374 if (.true.) then! if needed on next level...
375 call agg_fill_nhbr_info(agg_nhbr, n_agg_facet, n_elements, &
376 facet_neigh, offset_el, n_facet, is_aggregated)
377 end if
378
379 ! count things
380 ntot = 0
381 do l = 1, naggs
382 ntot = ntot + aggregate_size(l)
383 end do
384 ! Allocate and fill lvl and nodes
385 call tamg_lvl_init( tamg%lvl(lvl_id), lvl_id, naggs, ntot)
386 ntot = 0
387 gid_ptr = 1
388 do l = 1, naggs
389 call tamg_node_init( tamg%lvl(lvl_id)%nodes(l), l, aggregate_size(l))
390 j = 0
391 do i = 1, n_elements!TODO: this is the lazy expensive way...
392 if (is_aggregated(i) .eq. l) then
393 j = j+1
394 tamg%lvl(lvl_id)%nodes(l)%dofs(j) = i
395
396 tamg%lvl(lvl_id)%map_f2c(i) = l
397 gid_ptr = gid_ptr + 1
398 end if
399 end do
400 if (j .ne. tamg%lvl(lvl_id)%nodes(l)%ndofs) then
401 call neko_error("Aggregation problem. Not enough dofs in node.")
402 end if
403 ntot = ntot + aggregate_size(l)
404 end do
405
406 call aggregation_monitor_final(lvl_id,ntot,naggs)
407
408 deallocate( is_aggregated )
409 deallocate( aggregate_size )
410 end subroutine aggregate_greedy
411
415 subroutine aggregate_end( tamg, lvl_id)
416 type(tamg_hierarchy_t), intent(inout) :: tamg
417 integer, intent(in) :: lvl_id
418 integer :: nt, i
419 ! link all branches together at a point
420 nt = tamg%lvl(lvl_id-1)%nnodes
421 ! Allocate lvl
422 call tamg_lvl_init( tamg%lvl(lvl_id), lvl_id, 1, nt)
423
424 ! Allocate node
425 call tamg_node_init( tamg%lvl(lvl_id)%nodes(1), 1, nt)
426 ! Fill node
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
429
430 tamg%lvl(lvl_id)%map_f2c(i) = 1
431 end do
432
433 end subroutine aggregate_end
434
435 subroutine aggregation_monitor_finest(lvl,ndof,nagg)
436 integer, intent(in) :: lvl,ndof,nagg
437 integer :: na_max, na_min, na_avg, na_sum
438 character(len=LOG_SIZE) :: log_buf
439
440 write(log_buf, '(A8,I2,A37)') '-- level',lvl,'-- Aggregation: Element-as-Aggregate'
441 !write(log_buf, '(A44)') 'Aggregation: Element-as-Aggregate'
442 call neko_log%message(log_buf)
443
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)
450
451 end subroutine aggregation_monitor_finest
452
453 subroutine aggregation_monitor_phase1(lvl,ndof,nagg,is_aggregated)
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
460 num_aggregated = 0
461 do i = 1, ndof
462 if (is_aggregated(i) .gt. -1) then
463 num_aggregated = num_aggregated + 1
464 end if
465 end do
466
467 !write(log_buf, '(A8,I2,A24)') '-- level',lvl,'-- Aggregation: phase1'
468 write(log_buf, '(A27)') 'Aggregation: phase1'
469 call neko_log%message(log_buf)
470
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)
476
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)
483
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)
490 end subroutine aggregation_monitor_phase1
491
492 subroutine aggregation_monitor_phase2(lvl,ndof,nagg,is_aggregated)
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
499 num_aggregated = 0
500 do i = 1, ndof
501 if (is_aggregated(i) .gt. -1) then
502 num_aggregated = num_aggregated + 1
503 end if
504 end do
505 !write(log_buf, '(A8,I2,A24)') '-- level',lvl,'-- Aggregation: phase2'
506 write(log_buf, '(A27)') 'Aggregation: phase2'
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, 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)
514
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)
521
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)
528 end subroutine aggregation_monitor_phase2
529
530 subroutine aggregation_monitor_final(lvl,ndof,nagg)
531 integer, intent(in) :: lvl,ndof,nagg
532 character(len=LOG_SIZE) :: log_buf
533 !TODO: calculate min and max agg size
534 !write(log_buf, '(A8,I2,A23,I6)') '-- level',lvl,'-- Aggregation: Done.', nagg
535 write(log_buf, '(A26,I6)') 'Aggregation: Done.', nagg
536 call neko_log%message(log_buf)
537 end subroutine aggregation_monitor_final
538
545 subroutine aggregate_pairs(tamg, lvl_id, max_aggs, facet_neigh, agg_nhbr)
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
559
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
563 n_facet = 6
564 offset_el = tamg%msh%offset_el
565 else
566 n_facet = size(facet_neigh, 1)
567 offset_el = 0
568 end if
569
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 ) )
574 ! fill with false
575 is_aggregated = -1
576 ! fill with large number
577 aggregate_size = huge(i)
578
579 ! Initialize a random permutation
580 allocate( rand_order( n_elements ) )
581 do i = 1, n_elements
582 rand_order(i) = i
583 end do
584 ! Shuffle rand_order using Fisher-Yates algorithm
585 do i = n_elements, 2, -1
586 call random_number(r)
587 j = int(r * real(i,kind=rp)) + 1
588 tmp = rand_order(i)
589 rand_order(i) = rand_order(j)
590 rand_order(j) = tmp
591 end do
592
593 naggs = 0
594 ! first pass of pair agg
595 do tmp = 1, n_elements
596 i = rand_order(tmp)
597 if (is_aggregated(i) .eq. -1) then
598 nhbr_id = -1
599 nhbr_msr = -1.0_rp
600 nhbr_tst = -1.0_rp
601 do side = 1, n_facet
602 nhbr = facet_neigh(side, i) - offset_el
603 if ((nhbr .gt. 0).and.(nhbr .le. n_elements)) then ! nhbr exists
604 if (is_aggregated(nhbr) .eq. -1) then
605 nhbr_tst = 1.0_rp! insert desired metric here
606 if (nhbr_tst .gt. nhbr_msr) then! if nhbr has goodest metric
607 nhbr_id = nhbr
608 nhbr_msr = nhbr_tst
609 end if
610 end if! is_aggregated(nhbr)
611 end if! nhbr exists
612 end do! side
613
614 if (nhbr_id .ne. -1) then
615 naggs = naggs + 1
616 is_aggregated(i) = naggs
617 is_aggregated(nhbr_id) = naggs
618 aggregate_size(naggs) = 2
619 else! singleton, in theory we want to avoid
620 naggs = naggs + 1
621 is_aggregated(i) = naggs
622 aggregate_size(naggs) = 1
623 endif
624 end if! is_aggregated(i)
625 end do
626 call agg_fill_nhbr_info( agg_nhbr, n_agg_nhbr, n_elements, &
627 facet_neigh, offset_el, n_facet, is_aggregated)
628
629 ! count things
630 ntot = n_elements
631 ! Allocate and fill lvl and nodes
632 call tamg_lvl_init( tamg%lvl(lvl_id), lvl_id, naggs, ntot)
633 ntot = 0
634 gid_ptr = 1
635 do l = 1, naggs
636 call tamg_node_init( tamg%lvl(lvl_id)%nodes(l), l, aggregate_size(l))
637 j = 0
638 do i = 1, n_elements!TODO: this is the lazy expensive way...
639 if (is_aggregated(i) .eq. l) then
640 j = j+1
641 tamg%lvl(lvl_id)%nodes(l)%dofs(j) = i
642
643 tamg%lvl(lvl_id)%map_f2c(i) = l
644 gid_ptr = gid_ptr + 1
645 end if
646 end do
647 if (j .ne. tamg%lvl(lvl_id)%nodes(l)%ndofs) then
648 call neko_error("Aggregation problem. Not enough dofs in node.")
649 end if
650 ntot = ntot + aggregate_size(l)
651 end do
652 call aggregation_monitor_final(lvl_id,ntot,naggs)
653 deallocate( is_aggregated )
654 deallocate( aggregate_size )
655 end subroutine aggregate_pairs
656
657end 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:51
integer, public pe_size
MPI size of communicator.
Definition comm.F90:59
type(mpi_comm), public neko_comm
MPI communicator.
Definition comm.F90:43
Logging routines.
Definition log.f90:34
type(log_t), public neko_log
Global log stream.
Definition log.f90:76
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:237
Type for a TreeAMG hierarchy.
Definition tree_amg.f90:87
#define max(a, b)
Definition tensor.cu:40