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