Neko 1.99.7
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
cheby.f90
Go to the documentation of this file.
1! Copyright (c) 2024-2026, 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!
34module cheby
35 use krylov, only : ksp_t, ksp_monitor_t
36 use precon, only : pc_t
37 use ax_product, only : ax_t
38 use num_types, only: rp
40 use field, only : field_t
41 use coefs, only : coef_t
42 use mesh, only : mesh_t
43 use space, only : space_t
44 use gather_scatter, only : gs_t, gs_op_add
45 use bc_list, only : bc_list_t
46 use schwarz, only : schwarz_t
47 use math, only : glsc3, rzero, rone, copy, sub2, cmult2, abscmp, glsc2, &
49 implicit none
50 private
51
53 type, public, extends(ksp_t) :: cheby_t
54 real(kind=rp), allocatable :: d(:)
55 real(kind=rp), allocatable :: w(:)
56 real(kind=rp), allocatable :: r(:)
57 real(kind=rp) :: tha, dlt
58 integer :: power_its = 150
60 integer :: power_its_refresh = 20
62 logical :: warm_start_eigs = .false.
64 logical :: eigs_computed = .false.
66 real(kind=rp), allocatable :: ev(:)
67 logical :: recompute_eigs = .true.
68 logical :: zero_initial_guess = .false.
69 type(schwarz_t), pointer :: schwarz => null()
70 contains
71 procedure, pass(this) :: init => cheby_init
72 procedure, pass(this) :: free => cheby_free
73 procedure, pass(this) :: solve => cheby_impl
74 procedure, pass(this) :: solve_coupled => cheby_solve_coupled
75 end type cheby_t
76
77contains
78
80 subroutine cheby_init(this, n, max_iter, M, rel_tol, abs_tol, monitor)
81 class(cheby_t), intent(inout), target :: this
82 integer, intent(in) :: max_iter
83 class(pc_t), optional, intent(in), target :: M
84 integer, intent(in) :: n
85 real(kind=rp), optional, intent(in) :: rel_tol
86 real(kind=rp), optional, intent(in) :: abs_tol
87 logical, optional, intent(in) :: monitor
88
89 call this%free()
90 allocate(this%d(n))
91 allocate(this%w(n))
92 allocate(this%r(n))
93
94 if (present(m)) then
95 this%M => m
96 end if
97
98 if (present(rel_tol) .and. present(abs_tol) .and. present(monitor)) then
99 call this%ksp_init(max_iter, rel_tol, abs_tol, monitor = monitor)
100 else if (present(rel_tol) .and. present(abs_tol)) then
101 call this%ksp_init(max_iter, rel_tol, abs_tol)
102 else if (present(monitor) .and. present(abs_tol)) then
103 call this%ksp_init(max_iter, abs_tol = abs_tol, monitor = monitor)
104 else if (present(rel_tol) .and. present(monitor)) then
105 call this%ksp_init(max_iter, rel_tol, monitor = monitor)
106 else if (present(rel_tol)) then
107 call this%ksp_init(max_iter, rel_tol = rel_tol)
108 else if (present(abs_tol)) then
109 call this%ksp_init(max_iter, abs_tol = abs_tol)
110 else if (present(monitor)) then
111 call this%ksp_init(max_iter, monitor = monitor)
112 else
113 call this%ksp_init(max_iter)
114 end if
115
116 end subroutine cheby_init
117
118 subroutine cheby_free(this)
119 class(cheby_t), intent(inout) :: this
120 if (allocated(this%d)) then
121 deallocate(this%d)
122 end if
123
124 if (allocated(this%w)) then
125 deallocate(this%w)
126 end if
127
128 if (allocated(this%r)) then
129 deallocate(this%r)
130 end if
131 if (allocated(this%ev)) then
132 deallocate(this%ev)
133 end if
134 end subroutine cheby_free
135
136 subroutine cheby_power(this, Ax, x, n, coef, blst, gs_h)
137 class(cheby_t), intent(inout) :: this
138 class(ax_t), intent(in) :: Ax
139 type(field_t), intent(inout) :: x
140 integer, intent(in) :: n
141 type(coef_t), intent(inout) :: coef
142 type(bc_list_t), intent(inout) :: blst
143 type(gs_t), intent(inout) :: gs_h
144 real(kind=rp) :: lam, b, a, rn
145 real(kind=rp) :: boost = 1.1_rp
146 real(kind=rp) :: lam_factor = 30.0_rp
147 real(kind=rp) :: wtw, dtw, dtd
148 integer, allocatable :: fixed_seed(:), saved_seed(:)
149 integer :: i, rnd_n, its
150 logical :: warm
151
152 call profiler_start_region('cheby_power')
153 warm = this%warm_start_eigs .and. this%eigs_computed .and. &
154 allocated(this%ev)
155 associate(w => this%w, d => this%d, r => this%r)
156
157 if (warm) then
158 its = this%power_its_refresh
159 call copy(d, this%ev, n)
160 else
161 its = this%power_its
162
163 ! Save current random seed and set a fixed seed
164 call random_seed(size = rnd_n)
165 allocate(saved_seed(rnd_n))
166 allocate(fixed_seed(rnd_n))
167 fixed_seed = 3901
168 call random_seed(get = saved_seed)
169 call random_seed(put = fixed_seed)
170
171 do i = 1, n
172 call random_number(rn)
173 d(i) = rn + 10.0_rp
174 end do
175
176 ! Restore saved random seed
177 call random_seed(put = saved_seed)
178
179 call gs_h%op(d, n, gs_op_add)
180 call blst%apply(d, n)
181 end if
182
183 !Power method to get lambda max
184 do i = 1, its
185 call ax%compute(w, d, coef, x%msh, x%Xh)
186 call gs_h%op(w, n, gs_op_add)
187 call blst%apply(w, n)
188 if (associated(this%schwarz)) then
189 call this%schwarz%compute(r, w)
190 call copy(w, r, n)
191 else
192 call this%M%solve(r, w, n)
193 call copy(w, r, n)
194 end if
195
196 wtw = glsc3(w, coef%mult, w, n)
197 call cmult2(d, w, 1.0_rp/sqrt(wtw), n)
198 call blst%apply(d, n)
199 end do
200
201 call ax%compute(w, d, coef, x%msh, x%Xh)
202 call gs_h%op(w, n, gs_op_add)
203 call blst%apply(w, n)
204 if (associated(this%schwarz)) then
205 call this%schwarz%compute(r, w)
206 call copy(w, r, n)
207 else
208 call this%M%solve(r, w, n)
209 call copy(w, r, n)
210 end if
211
212 dtw = glsc3(d, coef%mult, w, n)
213 dtd = glsc3(d, coef%mult, d, n)
214 lam = dtw / dtd
215 b = lam * boost
216 a = lam / lam_factor
217 this%tha = (b+a)/2.0_rp
218 this%dlt = (b-a)/2.0_rp
219
220 if (this%warm_start_eigs) then
221 if (.not. allocated(this%ev)) then
222 allocate(this%ev(size(this%d)))
223 end if
224 call copy(this%ev, d, n)
225 end if
226 this%eigs_computed = .true.
227
228 this%recompute_eigs = .false.
229 end associate
230 call profiler_end_region('cheby_power')
231 end subroutine cheby_power
232
234 function cheby_solve(this, Ax, x, f, n, coef, blst, gs_h, niter) &
235 result(ksp_results)
236 class(cheby_t), intent(inout) :: this
237 class(ax_t), intent(in) :: ax
238 type(field_t), intent(inout) :: x
239 integer, intent(in) :: n
240 real(kind=rp), dimension(n), intent(in) :: f
241 type(coef_t), intent(inout) :: coef
242 type(bc_list_t), intent(inout) :: blst
243 type(gs_t), intent(inout) :: gs_h
244 type(ksp_monitor_t) :: ksp_results
245 integer, optional, intent(in) :: niter
246 integer :: iter, max_iter
247 real(kind=rp) :: a, b, rtr, rnorm, norm_fac
248
249 if (this%recompute_eigs) then
250 call cheby_power(this, ax, x, n, coef, blst, gs_h)
251 end if
252
253 if (present(niter)) then
254 max_iter = niter
255 else
256 max_iter = this%max_iter
257 end if
258 norm_fac = 1.0_rp / sqrt(coef%volume)
259
260 associate( w => this%w, r => this%r, d => this%d)
261 ! calculate residual
262 call copy(r, f, n)
263 call ax%compute(w, x%x, coef, x%msh, x%Xh)
264 call gs_h%op(w, n, gs_op_add)
265 call blst%apply(w, n)
266 call sub2(r, w, n)
267
268 rtr = glsc3(r, coef%mult, r, n)
269 rnorm = sqrt(rtr) * norm_fac
270 ksp_results%res_start = rnorm
271 ksp_results%res_final = rnorm
272 ksp_results%iter = 0
273
274 ! First iteration
275 call this%M%solve(w, r, n)
276 call copy(d, w, n)
277 a = 2.0_rp / this%tha
278 call add2s2(x%x, d, a, n)! x = x + a*d
279
280 ! Rest of the iterations
281 do iter = 2, max_iter
282 ! calculate residual
283 call copy(r, f, n)
284 call ax%compute(w, x%x, coef, x%msh, x%Xh)
285 call gs_h%op(w, n, gs_op_add)
286 call blst%apply(w, n)
287 call sub2(r, w, n)
288
289 call this%M%solve(w, r, n)
290
291 if (iter .eq. 2) then
292 b = 0.5_rp * (this%dlt * a)**2
293 else
294 b = (this%dlt * a / 2.0_rp)**2
295 end if
296 a = 1.0_rp/(this%tha - b/a)
297 call add2s1(d, w, b, n)! d = w + b*d
298
299 call add2s2(x%x, d, a, n)! x = x + a*d
300 end do
301
302 ! calculate residual
303 call copy(r, f, n)
304 call ax%compute(w, x%x, coef, x%msh, x%Xh)
305 call gs_h%op(w, n, gs_op_add)
306 call blst%apply(w, n)
307 call sub2(r, w, n)
308 rtr = glsc3(r, coef%mult, r, n)
309 rnorm = sqrt(rtr) * norm_fac
310 ksp_results%res_final = rnorm
311 ksp_results%iter = iter
312 ksp_results%converged = this%is_converged(iter, rnorm)
313 end associate
314 end function cheby_solve
315
317 function cheby_impl(this, Ax, x, f, n, coef, blst, gs_h, niter) &
318 result(ksp_results)
319 class(cheby_t), intent(inout) :: this
320 class(ax_t), intent(in) :: ax
321 type(field_t), intent(inout) :: x
322 integer, intent(in) :: n
323 real(kind=rp), dimension(n), intent(in) :: f
324 type(coef_t), intent(inout) :: coef
325 type(bc_list_t), intent(inout) :: blst
326 type(gs_t), intent(inout) :: gs_h
327 type(ksp_monitor_t) :: ksp_results
328 integer, optional, intent(in) :: niter
329 integer :: iter, max_iter, i
330 real(kind=rp) :: a, b, rtr, rnorm, norm_fac
331 real(kind=rp) :: rhok, rhokp1, sig1, tmp1, tmp2, inv_tha
332
333 if (this%recompute_eigs) then
334 call cheby_power(this, ax, x, n, coef, blst, gs_h)
335 end if
336
337 if (present(niter)) then
338 max_iter = niter
339 else
340 max_iter = this%max_iter
341 end if
342 norm_fac = 1.0_rp / sqrt(coef%volume)
343
344 associate( w => this%w, r => this%r, d => this%d)
345 ! calculate residual
346 if (.not.this%zero_initial_guess) then
347 call ax%compute(w, x%x, coef, x%msh, x%Xh)
348 call gs_h%op(w, n, gs_op_add)
349 call blst%apply(w, n)
350 call sub3(r, f, w, n)
351 else
352 call copy(r, f, n)
353 this%zero_initial_guess = .false.
354 end if
355
356 ! First iteration
357 if (associated(this%schwarz)) then
358 call this%schwarz%compute(d, r)
359 else
360 call this%M%solve(d, r, n)
361 end if
362
363 inv_tha = 1.0_rp / this%tha
364 !OCL NORECURRENCE, NOVREC, NOALIAS
365 !DIR$ CONCURRENT
366 !DIR$ IVDEP
367 !GCC$ ivdep
368 !$omp parallel do
369 do i = 1, n
370 d(i) = inv_tha * d(i)
371 x%x(i,1,1,1) = x%x(i,1,1,1) + d(i)
372 end do
373 !$omp end parallel do
374
375 sig1 = this%tha / this%dlt
376 rhok = 1.0_rp / sig1
377
378 ! Rest of the iterations
379 do iter = 2, max_iter
380 rhokp1 = 1.0_rp / (2.0_rp * sig1 - rhok)
381 tmp1 = rhokp1 * rhok
382 tmp2 = 2.0_rp * rhokp1 / this%dlt
383 rhok = rhokp1
384 ! calculate residual
385 call ax%compute(w, x%x, coef, x%msh, x%Xh)
386 call gs_h%op(w, n, gs_op_add)
387 call blst%apply(w, n)
388 call sub3(r, f, w, n)
389
390 if (associated(this%schwarz)) then
391 call this%schwarz%compute(w, r)
392 else
393 call this%M%solve(w, r, n)
394 end if
395 !OCL NORECURRENCE, NOVREC, NOALIAS
396 !DIR$ CONCURRENT
397 !DIR$ IVDEP
398 !GCC$ ivdep
399 !$omp parallel do
400 do i = 1, n
401 d(i) = tmp1 * d(i) + tmp2 * w(i)
402 x%x(i,1,1,1) = x%x(i,1,1,1) + d(i)
403 end do
404 !$omp end parallel do
405 end do
406
407 end associate
408 end function cheby_impl
409
411 function cheby_solve_coupled(this, Ax, x, y, z, fx, fy, fz, &
412 n, coef, blstx, blsty, blstz, gs_h, niter) result(ksp_results)
413 class(cheby_t), intent(inout) :: this
414 class(ax_t), intent(in) :: ax
415 type(field_t), intent(inout) :: x
416 type(field_t), intent(inout) :: y
417 type(field_t), intent(inout) :: z
418 integer, intent(in) :: n
419 real(kind=rp), dimension(n), intent(in) :: fx
420 real(kind=rp), dimension(n), intent(in) :: fy
421 real(kind=rp), dimension(n), intent(in) :: fz
422 type(coef_t), intent(inout) :: coef
423 type(bc_list_t), intent(inout) :: blstx
424 type(bc_list_t), intent(inout) :: blsty
425 type(bc_list_t), intent(inout) :: blstz
426 type(gs_t), intent(inout) :: gs_h
427 type(ksp_monitor_t), dimension(3) :: ksp_results
428 integer, optional, intent(in) :: niter
429
430 ksp_results(1) = this%solve(ax, x, fx, n, coef, blstx, gs_h, niter)
431 ksp_results(2) = this%solve(ax, y, fy, n, coef, blsty, gs_h, niter)
432 ksp_results(3) = this%solve(ax, z, fz, n, coef, blstz, gs_h, niter)
433
434 end function cheby_solve_coupled
435
436end module cheby
__device__ T solve(const T u, const T y, const T guess, const T nu, const T kappa, const T B)
Defines a Matrix-vector product.
Definition ax.f90:34
Defines a list of bc_t.
Definition bc_list.f90:34
Chebyshev preconditioner.
Definition cheby.f90:34
type(ksp_monitor_t) function cheby_impl(this, ax, x, f, n, coef, blst, gs_h, niter)
A chebyshev preconditioner.
Definition cheby.f90:319
subroutine cheby_free(this)
Definition cheby.f90:119
type(ksp_monitor_t) function, dimension(3) cheby_solve_coupled(this, ax, x, y, z, fx, fy, fz, n, coef, blstx, blsty, blstz, gs_h, niter)
Standard Chebyshev coupled solve.
Definition cheby.f90:413
subroutine cheby_init(this, n, max_iter, m, rel_tol, abs_tol, monitor)
Initialise a standard solver.
Definition cheby.f90:81
subroutine cheby_power(this, ax, x, n, coef, blst, gs_h)
Definition cheby.f90:137
type(ksp_monitor_t) function cheby_solve(this, ax, x, f, n, coef, blst, gs_h, niter)
A chebyshev preconditioner.
Definition cheby.f90:236
Coefficients.
Definition coef.f90:34
Defines a field.
Definition field.f90:34
Gather-scatter.
Implements the base abstract type for Krylov solvers plus helper types.
Definition krylov.f90:34
Definition math.f90:60
subroutine, public cmult(a, c, n)
Multiplication by constant c .
Definition math.f90:504
subroutine, public cmult2(a, b, c, n)
Multiplication by constant c .
Definition math.f90:519
real(kind=rp) function, public glsc3(a, b, c, n)
Weighted inner product .
Definition math.f90:1287
subroutine, public add2s1(a, b, c1, n)
Vector addition with scalar multiplication (multiplication on first argument)
Definition math.f90:981
real(kind=rp) function, public glsc2(a, b, n)
Weighted inner product .
Definition math.f90:1266
subroutine, public rone(a, n)
Set all elements to one.
Definition math.f90:277
subroutine, public sub3(a, b, c, n)
Vector subtraction .
Definition math.f90:963
subroutine, public add2(a, b, n)
Vector addition .
Definition math.f90:900
subroutine, public copy(a, b, n)
Copy a vector .
Definition math.f90:291
subroutine, public rzero(a, n)
Zero a real vector.
Definition math.f90:235
subroutine, public sub2(a, b, n)
Vector substraction .
Definition math.f90:948
subroutine, public add2s2(a, b, c1, n)
Vector addition with scalar multiplication (multiplication on second argument)
Definition math.f90:998
Defines a mesh.
Definition mesh.f90:34
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:12
Krylov preconditioner.
Definition precon.f90:34
Profiling interface.
Definition profiler.F90:34
subroutine, public profiler_start_region(name, region_id)
Started a named (name) profiler region.
Definition profiler.F90:79
subroutine, public profiler_end_region(name, region_id)
End the most recently started profiler region.
Definition profiler.F90:116
Overlapping schwarz solves.
Definition schwarz.f90:61
Defines a function space.
Definition space.f90:34
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:49
Defines a Chebyshev preconditioner.
Definition cheby.f90:53
Coefficients defined on a given (mesh, ) tuple. Arrays use indices (i,j,k,e): element e,...
Definition coef.f90:63
Gather-scatter kernel.
Type for storing initial and final residuals in a Krylov solver.
Definition krylov.f90:56
Base abstract type for a canonical Krylov method, solving .
Definition krylov.f90:73
Defines a canonical Krylov preconditioner.
Definition precon.f90:40
The function space for the SEM solution fields.
Definition space.f90:64