Neko 0.9.99
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!
35 use tree_amg
36 use utils
37 use num_types
38 use comm
39 use mesh, only : mesh_t
40 use logger, only : neko_log, log_size
41 implicit none
42
43 type, public :: tamg_agg_monitor_t
45 integer :: level
46 integer :: num_dofs
47 integer :: num_aggs
49 integer :: phase1_naggs
50 integer :: phase1_ndof_aggregated
51 integer :: phase2_naggs
52 integer :: phase2_ndof_aggregated
53 end type tamg_agg_monitor_t
54
55contains
56
64 subroutine aggregate_finest_level(tamg, lx, ly, lz, ne)
65 type(tamg_hierarchy_t), intent(inout) :: tamg
66 integer, intent(in) :: lx, ly, lz, ne
67 integer :: i, j, k, l, nl, nt
68 integer :: lid, gid_ptr
69 integer :: lvl_id
70 lvl_id = 1
72 nl = lx*ly*lz
73 nt = nl*ne
75 call tamg_lvl_init(tamg%lvl(lvl_id), lvl_id, ne, nt)
76 gid_ptr = 1
77 do l = 1, ne
78 tamg%lvl(lvl_id)%nodes_ptr(l) = gid_ptr
79 tamg%lvl(lvl_id)%nodes_gid(l) = l
80 call tamg_node_init( tamg%lvl(lvl_id)%nodes(l), l, nl)
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,lx,ly,lz)
88
89 tamg%lvl(lvl_id)%nodes_dofs(gid_ptr) = linear_index(i,j,k,l,lx,ly,lz)
90 tamg%lvl(lvl_id)%nodes_gids(gid_ptr) = l
91 gid_ptr = gid_ptr + 1
92 end do
93 end do
94 end do
95 end do
96 tamg%lvl(lvl_id)%nodes_ptr(ne+1) = gid_ptr
97
98 call aggregation_monitor_finest(lvl_id,nt,ne)
99
100 end subroutine aggregate_finest_level
101
111 subroutine agg_greedy_first_pass(naggs, max_aggs, n_elements, &
112 facet_neigh, offset_el, n_facet, is_aggregated, aggregate_size)
113 integer, intent(inout):: naggs
114 integer, intent(in) :: max_aggs, n_elements
115 integer, intent(in) :: facet_neigh(:,:)
116 integer, intent(in) :: offset_el, n_facet
117 integer, intent(inout) :: is_aggregated(:)
118 integer, allocatable, intent(inout) :: aggregate_size(:)
119 integer, allocatable :: as_tmp(:)
120 real(kind=dp) :: random_value
121 integer :: i, side, nhbr
122 logical :: no_nhbr_agg
123
124!-----! do while (naggs .le. max_aggs)
125!-----! call random_number(random_value)
126!-----! i = floor(random_value * n_elements + 1)
127 do i = 1, n_elements
128 if (is_aggregated(i) .eq. -1) then
130 no_nhbr_agg = .true.
131 do side = 1, n_facet
132 nhbr = facet_neigh(side, i) - offset_el
133 if ((nhbr .gt. 0).and.(nhbr .le. n_elements)) then
134 if (is_aggregated(nhbr) .ne. -1) then
135 no_nhbr_agg = .false.
136 end if
137 end if
138 end do! side
139
141 if (no_nhbr_agg) then
142 naggs = naggs + 1
143 is_aggregated(i) = naggs
144 if(size(aggregate_size).lt.naggs) then
145 allocate(as_tmp(naggs + 20))
146 as_tmp(1:size(aggregate_size)) = aggregate_size
147 call move_alloc(as_tmp, aggregate_size)
148 end if
149 aggregate_size(naggs) = 1
150 do side = 1, n_facet
151 nhbr = facet_neigh(side, i) - offset_el
152 if ((nhbr .gt. 0).and.(nhbr .le. n_elements)) then
153 if (is_aggregated(nhbr) .eq. -1) then
154 is_aggregated(nhbr) = naggs
155 aggregate_size(naggs) = aggregate_size(naggs) + 1
156 end if
157 end if
158 end do! side
159 end if! no_nhbr_agg
160 end if! is_aggregated(i)
161 end do
162 end subroutine agg_greedy_first_pass
163
174 subroutine agg_greedy_second_pass(naggs, max_aggs, n_elements, &
175 facet_neigh, offset_el, n_facet, is_aggregated, aggregate_size)
176 integer, intent(inout):: naggs
177 integer, intent(in) :: max_aggs, n_elements
178 integer, intent(in) :: facet_neigh(:,:)
179 integer, intent(in) :: offset_el, n_facet
180 integer, intent(inout) :: is_aggregated(:)
181 integer, intent(inout) :: aggregate_size(:)
182 integer :: i, side, nhbr
183 integer :: tnt_agg, tst_agg, tnt_size, tst_size
184
186 do i = 1, n_elements
187 if (is_aggregated(i) .eq. -1) then
189 tnt_agg = -1
190 tnt_size = 999!TODO: replace with large number
191 tst_agg = -1
192 tst_size = 999!TODO: replace with large number
193 do side = 1, n_facet
194 nhbr = facet_neigh(side, i) - offset_el
195 if ((nhbr .gt. 0).and.(nhbr .le. n_elements)) then
196 if (is_aggregated(nhbr) .ne. -1) then
197 tst_agg = is_aggregated(nhbr)
198 tst_size = aggregate_size(tst_agg)
199 if (tst_size .lt. tnt_size) then
200 tnt_size = tst_size
201 tnt_agg = tst_agg
202 end if
203 end if
204 end if
205 end do
206
207 if (tnt_agg .ne. -1) then
209 is_aggregated(i) = tnt_agg
210 aggregate_size(tnt_agg) = aggregate_size(tnt_agg) + 1
211 else
213 naggs = naggs + 1
214 if (naggs .gt. size(aggregate_size)) then!TODO: another movealoc here? Error? the max_aggs needs to change though...
215 call neko_error("Creating too many aggregates... something might be wrong... try increasing max_aggs")
216 end if
217 is_aggregated(i) = naggs
218 aggregate_size(naggs) = 1
220 do side = 1, n_facet
221 nhbr = facet_neigh(side, i) - offset_el
222 if ((nhbr .gt. 0).and.(nhbr .le. n_elements)) then
223 if (is_aggregated(nhbr) .eq. -1) then
224 aggregate_size(naggs) = aggregate_size(naggs) + 1
225 is_aggregated(nhbr) = naggs
226 end if
227 end if
228 end do
229 end if
230
231 end if
232 end do
233 end subroutine agg_greedy_second_pass
234
244 subroutine agg_fill_nhbr_info(agg_nhbr, n_agg_nhbr, n_elements, &
245 facet_neigh, offset_el, n_facet, is_aggregated, aggregate_size)
246 integer, intent(inout) :: agg_nhbr(:,:)
247 integer, intent(inout) :: n_agg_nhbr
248 integer, intent(in) :: n_elements
249 integer, intent(in) :: facet_neigh(:,:)
250 integer, intent(in) :: offset_el, n_facet
251 integer, intent(inout) :: is_aggregated(:)
252 integer, intent(inout) :: aggregate_size(:)
253 integer :: i, j, side, nhbr, tst_agg, tnt_agg
254 logical :: agg_added
255
256 n_agg_nhbr = 0
257
258 do i = 1, n_elements!TODO: this is the lazy expensive way...
259 tnt_agg = is_aggregated(i)
260 do side = 1, n_facet
261 nhbr = facet_neigh(side,i) - offset_el
262 if ((nhbr .gt. 0).and.(nhbr .le. n_elements)) then
263 tst_agg = is_aggregated(nhbr)
264 if (tst_agg .le. 0) call neko_error("Unaggregated element detected. We do not want to handle that here...")
265 if (tst_agg .ne. tnt_agg) then
266 agg_added = .false.
267 do j = 1, 50!TODO: this hard-coded value
268 if ((agg_nhbr(j,tnt_agg) .eq. tst_agg)) then
269 agg_added = .true.
270 else if ((agg_nhbr(j,tnt_agg).eq.-1).and.(.not.agg_added)) then
271 agg_nhbr(j,tnt_agg) = tst_agg
272 agg_added = .true.
273 n_agg_nhbr = max(n_agg_nhbr, j)
274 end if
275 end do! j
276 if (.not.agg_added) call neko_error("Aggregates have too many neighbors... probably. Or some other error.")
277 end if
278 end if
279 end do! side
280 end do! i
281 end subroutine agg_fill_nhbr_info
282
289 subroutine aggregate_greedy(tamg, lvl_id, max_aggs, facet_neigh, agg_nhbr)
290 type(tamg_hierarchy_t), intent(inout) :: tamg
291 integer, intent(in) :: lvl_id
292 integer, intent(in) :: max_aggs
293 integer, intent(in) :: facet_neigh(:,:)
294 integer, intent(inout), allocatable :: agg_nhbr(:,:)
295 integer, allocatable :: is_aggregated(:)
296 integer, allocatable :: aggregate_size(:)
297 integer :: n_elements, naggs, n_facet, offset_el
298 integer :: i, j, l, ntot, n_agg_facet, gid_ptr
299
300 if (lvl_id .lt. 2) then
301 call neko_error("For now, can only use greedy agg after elms have been aggregated to points (level 1)")
302 else if (lvl_id .eq. 2) then
303 n_facet = 6
304 offset_el = tamg%msh%offset_el
305 else
306 n_facet = 50!TODO: this hard-coded value. how many neighbors can there be?
307 offset_el = 0
308 end if
309
310 naggs = 0
311 n_elements = tamg%lvl(lvl_id-1)%nnodes
312 allocate( is_aggregated( n_elements ) )
313 allocate( aggregate_size( max_aggs ) )
314
316 is_aggregated = -1
317
319 aggregate_size = huge(i)!999999
320
322 call agg_greedy_first_pass(naggs, max_aggs, n_elements, &
323 facet_neigh, offset_el, n_facet, &
324 is_aggregated, aggregate_size)
325
326 call aggregation_monitor_phase1(lvl_id, n_elements, naggs, is_aggregated)
327
329 call agg_greedy_second_pass(naggs, max_aggs, n_elements, &
330 facet_neigh, offset_el, n_facet, &
331 is_aggregated, aggregate_size)
332
333 call aggregation_monitor_phase2(lvl_id, n_elements, naggs, is_aggregated)
334
335 if (.true.) then
336 allocate( agg_nhbr(50, max_aggs*2) )!TODO: this hard-coded n_facet value (20)...
337 agg_nhbr = -1
338 call agg_fill_nhbr_info(agg_nhbr, n_agg_facet, n_elements, &
339 facet_neigh, offset_el, n_facet, &
340 is_aggregated, aggregate_size)
341 end if
342
344 ntot = 0
345 do l = 1, naggs
346 ntot = ntot + aggregate_size(l)
347 end do
349 call tamg_lvl_init( tamg%lvl(lvl_id), lvl_id, naggs, ntot)
350 ntot = 0
351 gid_ptr = 1
352 do l = 1, naggs
353 tamg%lvl(lvl_id)%nodes_ptr(l) = gid_ptr
354 tamg%lvl(lvl_id)%nodes_gid(l) = l
355 call tamg_node_init( tamg%lvl(lvl_id)%nodes(l), l, aggregate_size(l))
356 j = 0
357 do i = 1, n_elements!TODO: this is the lazy expensive way...
358 if (is_aggregated(i) .eq. l) then
359 j = j+1
360 tamg%lvl(lvl_id)%nodes(l)%dofs(j) = i
361
362 tamg%lvl(lvl_id)%nodes_dofs(gid_ptr) = i
363 tamg%lvl(lvl_id)%nodes_gids(gid_ptr) = l
364 gid_ptr = gid_ptr + 1
365 end if
366 end do
367 if (j .ne. tamg%lvl(lvl_id)%nodes(l)%ndofs) then
368 call neko_error("Aggregation problem. Not enough dofs in node.")
369 end if
370 ntot = ntot + aggregate_size(l)
371 end do
372 tamg%lvl(lvl_id)%nodes_ptr(naggs+1) = gid_ptr
373
374 call aggregation_monitor_final(lvl_id,ntot,naggs)
375
376 deallocate( is_aggregated )
377 deallocate( aggregate_size )
378 end subroutine aggregate_greedy
379
383 subroutine aggregate_end( tamg, lvl_id)
384 type(tamg_hierarchy_t), intent(inout) :: tamg
385 integer, intent(in) :: lvl_id
386 integer :: nt, i
388 nt = tamg%lvl(lvl_id-1)%nnodes
390 call tamg_lvl_init( tamg%lvl(lvl_id), lvl_id, 1, nt)
391
393 call tamg_node_init( tamg%lvl(lvl_id)%nodes(1), 1, nt)
395 do i = 1, tamg%lvl(lvl_id-1)%nnodes
396 tamg%lvl(lvl_id)%nodes(1)%dofs(i) = tamg%lvl(lvl_id-1)%nodes(i)%gid
397
398 tamg%lvl(lvl_id)%nodes_dofs(i) = tamg%lvl(lvl_id-1)%nodes(i)%gid
399 tamg%lvl(lvl_id)%nodes_gids(i) = 1
400 end do
401
402 tamg%lvl(lvl_id)%nodes_ptr(1) = 1
403 tamg%lvl(lvl_id)%nodes_ptr(2) = 2
404 tamg%lvl(lvl_id)%nodes_gid(1) = 1
405 end subroutine aggregate_end
406
407 subroutine aggregation_monitor_finest(lvl,ndof,nagg)
408 integer, intent(in) :: lvl,ndof,nagg
409 integer :: na_max, na_min, na_avg, na_sum
410 character(len=LOG_SIZE) :: log_buf
411
412 write(log_buf, '(A8,I2,A37)') '-- level',lvl,'-- Aggregation: Element-as-Aggregate'
413 !write(log_buf, '(A44)') 'Aggregation: Element-as-Aggregate'
414 call neko_log%message(log_buf)
415
416 call mpi_allreduce(nagg, na_max, 1, mpi_integer, mpi_max, neko_comm)
417 call mpi_allreduce(nagg, na_min, 1, mpi_integer, mpi_min, neko_comm)
418 call mpi_allreduce(nagg, na_sum, 1, mpi_integer, mpi_sum, neko_comm)
419 na_avg = na_sum / pe_size
420 write(log_buf, '(A35,I6,A1,I6,A1,I6,A1)') 'Number of Aggregates: (',na_min,',',na_avg,',',na_max,')'
421 call neko_log%message(log_buf)
422
423 end subroutine aggregation_monitor_finest
424
425 subroutine aggregation_monitor_phase1(lvl,ndof,nagg,is_aggregated)
426 integer, intent(in) :: lvl,ndof,nagg
427 integer, intent(in) :: is_aggregated(:)
428 integer :: num_aggregated, i, na_max, na_min, na_avg, na_sum
429 real(kind=rp) :: agg_frac
430 integer(kind=i8) :: glb_dof, glb_aggd, loc_dof, loc_aggd
431 character(len=LOG_SIZE) :: log_buf
432 num_aggregated = 0
433 do i = 1, ndof
434 if (is_aggregated(i) .gt. -1) then
435 num_aggregated = num_aggregated + 1
436 end if
437 end do
438
439 !write(log_buf, '(A8,I2,A24)') '-- level',lvl,'-- Aggregation: phase1'
440 write(log_buf, '(A27)') 'Aggregation: phase1'
441 call neko_log%message(log_buf)
442
443 loc_aggd = int(num_aggregated, i8)
444 loc_dof = int(ndof, i8)
445 call mpi_allreduce(loc_dof, glb_dof, 1, mpi_integer8, mpi_sum, neko_comm)
446 call mpi_allreduce(loc_aggd, glb_aggd, 1, mpi_integer8, mpi_sum, neko_comm)
447 agg_frac = real(glb_aggd,rp) / real(glb_dof,rp)
448
449 call mpi_allreduce(nagg, na_max, 1, mpi_integer, mpi_max, neko_comm)
450 call mpi_allreduce(nagg, na_min, 1, mpi_integer, mpi_min, neko_comm)
451 call mpi_allreduce(nagg, na_sum, 1, mpi_integer, mpi_sum, neko_comm)
452 na_avg = na_sum / pe_size
453 write(log_buf, '(A35,I6,A1,I6,A1,I6,A1)') 'Number of Aggregates: (',na_min,',',na_avg,',',na_max,')'
454 call neko_log%message(log_buf)
455
456 call mpi_allreduce(num_aggregated, na_max, 1, mpi_integer, mpi_max, neko_comm)
457 call mpi_allreduce(num_aggregated, na_min, 1, mpi_integer, mpi_min, neko_comm)
458 call mpi_allreduce(num_aggregated, na_sum, 1, mpi_integer, mpi_sum, neko_comm)
459 na_avg = na_sum / pe_size
460 write(log_buf, '(A35,I6,A1,I6,A1,I6,A1,F6.2)') 'Aggregated: (',na_min,',',na_avg,',',na_max,')',(agg_frac*100)
461 call neko_log%message(log_buf)
462 end subroutine aggregation_monitor_phase1
463
464 subroutine aggregation_monitor_phase2(lvl,ndof,nagg,is_aggregated)
465 integer, intent(in) :: lvl,ndof,nagg
466 integer, intent(in) :: is_aggregated(:)
467 integer :: num_aggregated, i, na_max, na_min, na_avg, na_sum
468 real(kind=rp) :: agg_frac
469 integer(kind=i8) :: glb_dof, glb_aggd, loc_dof, loc_aggd
470 character(len=LOG_SIZE) :: log_buf
471 num_aggregated = 0
472 do i = 1, ndof
473 if (is_aggregated(i) .gt. -1) then
474 num_aggregated = num_aggregated + 1
475 end if
476 end do
477 !write(log_buf, '(A8,I2,A24)') '-- level',lvl,'-- Aggregation: phase2'
478 write(log_buf, '(A27)') 'Aggregation: phase2'
479 call neko_log%message(log_buf)
480
481 loc_aggd = int(num_aggregated, i8)
482 loc_dof = int(ndof, i8)
483 call mpi_allreduce(loc_dof, glb_dof, 1, mpi_integer8, mpi_sum, neko_comm)
484 call mpi_allreduce(loc_aggd, glb_aggd, 1, mpi_integer8, mpi_sum, neko_comm)
485 agg_frac = real(glb_aggd,rp) / real(glb_dof,rp)
486
487 call mpi_allreduce(nagg, na_max, 1, mpi_integer, mpi_max, neko_comm)
488 call mpi_allreduce(nagg, na_min, 1, mpi_integer, mpi_min, neko_comm)
489 call mpi_allreduce(nagg, na_sum, 1, mpi_integer, mpi_sum, neko_comm)
490 na_avg = na_sum / pe_size
491 write(log_buf, '(A35,I6,A1,I6,A1,I6,A1)') 'Number of Aggregates: (',na_min,',',na_avg,',',na_max,')'
492 call neko_log%message(log_buf)
493
494 call mpi_allreduce(num_aggregated, na_max, 1, mpi_integer, mpi_max, neko_comm)
495 call mpi_allreduce(num_aggregated, na_min, 1, mpi_integer, mpi_min, neko_comm)
496 call mpi_allreduce(num_aggregated, na_sum, 1, mpi_integer, mpi_sum, neko_comm)
497 na_avg = na_sum / pe_size
498 write(log_buf, '(A35,I6,A1,I6,A1,I6,A1,F6.2)') 'Aggregated: (',na_min,',',na_avg,',',na_max,')',(agg_frac*100)
499 call neko_log%message(log_buf)
500 end subroutine aggregation_monitor_phase2
501
502 subroutine aggregation_monitor_final(lvl,ndof,nagg)
503 integer, intent(in) :: lvl,ndof,nagg
504 character(len=LOG_SIZE) :: log_buf
505 !TODO: calculate min and max agg size
506 !write(log_buf, '(A8,I2,A23,I6)') '-- level',lvl,'-- Aggregation: Done.', nagg
507 write(log_buf, '(A26,I6)') 'Aggregation: Done.', nagg
508 call neko_log%message(log_buf)
509 end subroutine aggregation_monitor_final
510
511end module tree_amg_aggregate
double real
Definition comm.F90:1
Logging routines.
Definition log.f90:34
type(log_t), public neko_log
Global log stream.
Definition log.f90:65
integer, parameter, public log_size
Definition log.f90:42
Defines a mesh.
Definition mesh.f90:34
integer, parameter, public dp
Definition num_types.f90:9
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 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, aggregate_size)
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:178
subroutine, public tamg_lvl_init(tamg_lvl, lvl, nnodes, ndofs)
Initialization of a TreeAMG level.
Definition tree_amg.f90:155
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:174
Type for a TreeAMG hierarchy.
Definition tree_amg.f90:83
#define max(a, b)
Definition tensor.cu:40