Neko 0.9.99
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
tree_amg_multigrid.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!
45 use num_types
46 use utils
47 use math
48 use comm
49 use coefs, only : coef_t
50 use mesh, only : mesh_t
51 use space, only : space_t
52 use ax_product, only: ax_t
53 use bc_list, only : bc_list_t
54 use gather_scatter, only : gs_t, gs_op_add
58 use logger, only : neko_log, log_size
59 implicit none
60 private
61
63 type, public :: tamg_solver_t
64 type(tamg_hierarchy_t), allocatable :: amg
65 type(amg_cheby_t), allocatable :: smoo(:)
66 !type(amg_jacobi_t), allocatable :: jsmoo(:)
67 integer :: nlvls
68 integer :: max_iter
69 contains
70 procedure, pass(this) :: init => tamg_mg_init
71 procedure, pass(this) :: solve => tamg_mg_solve
72 end type tamg_solver_t
73
74contains
75
85 subroutine tamg_mg_init(this, ax, Xh, coef, msh, gs_h, nlvls_in, blst, max_iter)
86 class(tamg_solver_t), intent(inout), target :: this
87 class(ax_t), target, intent(in) :: ax
88 type(space_t),target, intent(in) :: Xh
89 type(coef_t), target, intent(in) :: coef
90 type(mesh_t), target, intent(in) :: msh
91 type(gs_t), target, intent(in) :: gs_h
92 type(bc_list_t), target, intent(in) :: blst
93 integer, intent(in) :: nlvls_in
94 integer, intent(in) :: max_iter
95 integer :: nlvls, lvl, n, cheby_degree, env_len, mlvl, target_num_aggs
96 integer, allocatable :: agg_nhbr(:,:), asdf(:,:)
97 character(len=255) :: env_cheby_degree, env_mlvl
98 character(len=LOG_SIZE) :: log_buf
99
100 call neko_log%section('AMG')
101
102 call get_environment_variable("NEKO_TAMG_MAX_LVL", &
103 env_mlvl, env_len)
104 if (env_len .eq. 0) then
105 !yeah...
106 nlvls = nlvls_in
107 else
108 read(env_mlvl(1:env_len), *) mlvl
109 nlvls = mlvl
110 end if
111
112 write(log_buf, '(A28,I2,A8)') 'Creating AMG hierarchy with', nlvls, 'levels.'
113 call neko_log%message(log_buf)
114
115 allocate( this%amg )
116 call this%amg%init(ax, xh, coef, msh, gs_h, nlvls, blst)
117
119 call aggregate_finest_level(this%amg, xh%lx, xh%ly, xh%lz, msh%nelv)
120
122 allocate( agg_nhbr, source=msh%facet_neigh )
123 do mlvl = 2, nlvls-1
124 target_num_aggs = this%amg%lvl(mlvl-1)%nnodes / 8
125 call print_preagg_info( mlvl, target_num_aggs)
126 if ( target_num_aggs .lt. 4 ) then
127 call neko_error("TAMG: Too many levels. Not enough DOFs for coarsest grid.")
128 end if
129 call aggregate_greedy( this%amg, mlvl, target_num_aggs, agg_nhbr, asdf)
130 agg_nhbr = asdf
131 deallocate( asdf )
132 end do
133 deallocate( agg_nhbr )
134
136 call aggregate_end(this%amg, nlvls)
137
138 this%max_iter = max_iter
139
140 this%nlvls = this%amg%nlvls!TODO: read from parameter
141 if (this%nlvls .gt. this%amg%nlvls) then
142 call neko_error("Requested number multigrid levels is greater than the initialized AMG levels")
143 end if
144
145 call get_environment_variable("NEKO_TAMG_CHEBY_DEGREE", &
146 env_cheby_degree, env_len)
147 if (env_len .eq. 0) then
148 cheby_degree = 10
149 else
150 read(env_cheby_degree(1:env_len), *) cheby_degree
151 end if
152
153 allocate(this%smoo(0:(nlvls)))
154 do lvl = 0, nlvls-1
155 n = this%amg%lvl(lvl+1)%fine_lvl_dofs
156 call this%smoo(lvl)%init(n ,lvl, cheby_degree)
157 end do
158
159 !allocate(this%jsmoo(0:(nlvls)))
160 !do lvl = 0, nlvls-1
161 ! n = this%amg%lvl(lvl+1)%fine_lvl_dofs
162 ! call this%jsmoo(lvl)%init(n ,lvl, cheby_degree)
163 !end do
164
165 call fill_lvl_map(this%amg)
166
167 call neko_log%end_section()
168
169 end subroutine tamg_mg_init
170
171
176 subroutine tamg_mg_solve(this, z, r, n)
177 integer, intent(in) :: n
178 class(tamg_solver_t), intent(inout) :: this
179 real(kind=rp), dimension(n), intent(inout) :: z
180 real(kind=rp), dimension(n), intent(inout) :: r
181 integer :: iter, max_iter
182
183 max_iter = this%max_iter
184
185 ! Zero out the initial guess becuase we do not handle null spaces very well...
186 z = 0d0
187
188 ! Call the amg cycle
189 do iter = 1, max_iter
190 call tamg_mg_cycle(z, r, n, 0, this%amg, this)
191 end do
192 end subroutine tamg_mg_solve
193
201 recursive subroutine tamg_mg_cycle(x, b, n, lvl, amg, mgstuff)
202 integer, intent(in) :: n
203 real(kind=rp), intent(inout) :: x(n)
204 real(kind=rp), intent(inout) :: b(n)
205 type(tamg_hierarchy_t), intent(inout) :: amg
206 type(tamg_solver_t), intent(inout) :: mgstuff
207 integer, intent(in) :: lvl
208 real(kind=rp) :: r(n)
209 real(kind=rp) :: rc(n)
210 real(kind=rp) :: tmp(n)
211 integer :: iter, num_iter
212 integer :: max_lvl
213 integer :: i, cyt
214
215 r = 0d0
216 rc = 0d0
217 tmp = 0d0
218
219 max_lvl = mgstuff%nlvls-1
220
221 !call calc_resid(r,x,b,amg,lvl,n)!> TODO: for debug
222 !print *, "LVL:",lvl, "PRE RESID:", sqrt(glsc2(r, r, n))
226 call mgstuff%smoo(lvl)%solve(x,b, n, amg)
227 !call mgstuff%jsmoo(lvl)%solve(x,b, n, amg)
228 if (lvl .eq. max_lvl) then
229 return
230 end if
231
235 call calc_resid(r,x,b,amg,lvl,n)
236
240 if (lvl .eq. 0) then
241 call average_duplicates(r,amg,lvl,n)
242 end if
243 call amg%interp_f2c(rc, r, lvl+1)
244
248 tmp = 0d0
249 call tamg_mg_cycle(tmp, rc, amg%lvl(lvl+1)%nnodes, lvl+1, amg, mgstuff)
250
254 call amg%interp_c2f(r, tmp, lvl+1)
255 if (lvl .eq. 0) then
256 call average_duplicates(r,amg,lvl,n)
257 end if
258
262 call add2(x, r, n)
263
267 call mgstuff%smoo(lvl)%solve(x,b, n, amg)
268 !call mgstuff%jsmoo(lvl)%solve(x,b, n, amg)
269
273 !call calc_resid(r,x,b,amg,lvl,n)!> TODO: for debug
274 !print *, "LVL:",lvl, "POST RESID:", sqrt(glsc2(r, r, n))
275 end subroutine tamg_mg_cycle
276
277
285 subroutine calc_resid(r, x, b, amg, lvl, n)
286 integer, intent(in) :: n
287 real(kind=rp), intent(inout) :: r(n)
288 real(kind=rp), intent(inout) :: x(n)
289 real(kind=rp), intent(inout) :: b(n)
290 type(tamg_hierarchy_t), intent(inout) :: amg
291 integer, intent(in) :: lvl
292 integer :: i
293 r = 0d0
294 !call my_matvec(r, x, n, lvl, amg)
295 call amg%matvec(r, x, lvl)
296 do i = 1, n
297 r(i) = b(i) - r(i)
298 end do
299 end subroutine calc_resid
300
306 subroutine average_duplicates(U, amg, lvl, n)
307 integer, intent(in) :: n
308 real(kind=rp), intent(inout) :: u(n)
309 type(tamg_hierarchy_t), intent(inout) :: amg
310 integer, intent(in) :: lvl
311 integer :: i
312 call amg%gs_h%op(u, n, gs_op_add)
313 do i = 1, n
314 u(i) = u(i) * amg%coef%mult(i,1,1,1)
315 end do
316 end subroutine average_duplicates
317
318 subroutine print_preagg_info(lvl,nagg)
319 integer, intent(in) :: lvl,nagg
320 character(len=LOG_SIZE) :: log_buf
321 !TODO: calculate min and max agg size
322 write(log_buf, '(A8,I2,A31)') '-- level',lvl,'-- Calling Greedy Aggregation'
323 call neko_log%message(log_buf)
324 write(log_buf, '(A33,I6)') 'Target Aggregates:',nagg
325 call neko_log%message(log_buf)
326 end subroutine print_preagg_info
327
328 subroutine fill_lvl_map(amg)
329 type(tamg_hierarchy_t), intent(inout) :: amg
330 integer :: i, j, k, l, nid, n
331 do j = 1, amg%lvl(1)%nnodes
332 do k = 1, amg%lvl(1)%nodes(j)%ndofs
333 nid = amg%lvl(1)%nodes(j)%dofs(k)
334 amg%lvl(1)%map_f2c_dof(nid) = amg%lvl(1)%nodes(j)%gid
335 end do
336 end do
337 n = size(amg%lvl(1)%map_f2c_dof)
338 do l = 2, amg%nlvls
339 do i = 1, n
340 nid = amg%lvl(l-1)%map_f2c_dof(i)
341 do j = 1, amg%lvl(l)%nnodes
342 do k = 1, amg%lvl(l)%nodes(j)%ndofs
343 if (nid .eq. amg%lvl(l)%nodes(j)%dofs(k)) then
344 amg%lvl(l)%map_f2c_dof(i) = amg%lvl(l)%nodes(j)%gid
345 end if
346 end do
347 end do
348 end do
349 end do
350 end subroutine
351end module tree_amg_multigrid
Defines a Matrix-vector product.
Definition ax.f90:34
Defines a list of bc_t.
Definition bc_list.f90:34
Coefficients.
Definition coef.f90:34
Definition comm.F90:1
Gather-scatter.
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
Definition math.f90:60
subroutine, public add2(a, b, n)
Vector addition .
Definition math.f90:586
Defines a mesh.
Definition mesh.f90:34
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:12
Defines a function space.
Definition space.f90:34
Implements an aggregation for TreeAMG hierarchy structure.
subroutine aggregate_end(tamg, lvl_id)
Aggregate all dofs to a single point to form a tree-like structure.
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.
Implements multigrid using the TreeAMG hierarchy structure. USE:
subroutine calc_resid(r, x, b, amg, lvl, n)
Wrapper function to calculate residyal.
recursive subroutine tamg_mg_cycle(x, b, n, lvl, amg, mgstuff)
Recrsive multigrid cycle for the TreeAMG solver object.
subroutine tamg_mg_init(this, ax, xh, coef, msh, gs_h, nlvls_in, blst, max_iter)
Initialization of the TreeAMG multigrid solver.
subroutine print_preagg_info(lvl, nagg)
subroutine average_duplicates(u, amg, lvl, n)
Wrapper function to gather scatter and average the duplicates.
subroutine fill_lvl_map(amg)
subroutine tamg_mg_solve(this, z, r, n)
Solver function for the TreeAMG solver object.
Implements smoothers for use with TreeAMG matrix vector product.
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
Base type for a matrix-vector product providing .
Definition ax.f90:43
A list of allocatable `bc_t`. Follows the standard interface of lists.
Definition bc_list.f90:46
Coefficients defined on a given (mesh, ) tuple. Arrays use indices (i,j,k,e): element e,...
Definition coef.f90:55
The function space for the SEM solution fields.
Definition space.f90:62
Type for a TreeAMG hierarchy.
Definition tree_amg.f90:83
Type for the TreeAMG solver.
Type for Chebyshev iteration using TreeAMG matvec.