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