Neko 1.99.9
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
gmres.f90
Go to the documentation of this file.
1! Copyright (c) 2020-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 gmres
35 !$ use omp_lib
36 use krylov, only : ksp_t, ksp_monitor_t
37 use precon, only : pc_t
38 use ax_product, only : ax_t
39 use num_types, only : rp, xp
40 use field, only : field_t
41 use coefs, only : coef_t
42 use gather_scatter, only : gs_t, gs_op_add
46 use math, only : glsc3, rzero, copy, sub2, cmult2, abscmp
47 use neko_config, only : neko_blk_size
49 use mpi_f08, only : mpi_allreduce, mpi_in_place, mpi_sum
50 implicit none
51 private
52
54 type, public, extends(ksp_t) :: gmres_t
55 integer :: lgmres = 30
56 real(kind=rp), allocatable :: w(:)
57 real(kind=rp), allocatable :: r(:)
58 real(kind=rp), allocatable :: z(:,:)
59 real(kind=rp), allocatable :: v(:,:)
61 real(kind=xp), allocatable :: h(:,:)
62 real(kind=xp), allocatable :: s(:)
63 real(kind=xp), allocatable :: gam(:)
64 real(kind=xp), allocatable :: c(:)
66 real(kind=xp), allocatable :: hp(:,:)
67 contains
68 procedure, pass(this) :: init => gmres_init
69 procedure, pass(this) :: free => gmres_free
70 procedure, pass(this) :: solve => gmres_solve
71 procedure, pass(this) :: solve_coupled => gmres_solve_coupled
72 end type gmres_t
73
74contains
75
77 subroutine gmres_init(this, n, max_iter, M, rel_tol, abs_tol, monitor)
78 class(gmres_t), target, intent(inout) :: this
79 integer, intent(in) :: n
80 integer, intent(in) :: max_iter
81 class(pc_t), optional, intent(in), target :: M
82 real(kind=rp), optional, intent(in) :: rel_tol
83 real(kind=rp), optional, intent(in) :: abs_tol
84 logical, optional, intent(in) :: monitor
85 integer :: nthrds
86
87 call this%free()
88
89 if (present(m)) then
90 this%M => m
91 end if
92
93 allocate(this%w(n))
94 allocate(this%r(n))
95
96 allocate(this%c(this%lgmres))
97 allocate(this%s(this%lgmres))
98 allocate(this%gam(this%lgmres + 1))
99
100 allocate(this%z(n, this%lgmres))
101 allocate(this%v(n, this%lgmres))
102
103 allocate(this%h(this%lgmres, this%lgmres))
104
105 nthrds = 1
106 !$ nthrds = omp_get_max_threads()
107 allocate(this%hp(this%lgmres, nthrds))
108
109 if (present(rel_tol) .and. present(abs_tol) .and. present(monitor)) then
110 call this%ksp_init(max_iter, rel_tol, abs_tol, monitor = monitor)
111 else if (present(rel_tol) .and. present(abs_tol)) then
112 call this%ksp_init(max_iter, rel_tol, abs_tol)
113 else if (present(monitor) .and. present(abs_tol)) then
114 call this%ksp_init(max_iter, abs_tol = abs_tol, monitor = monitor)
115 else if (present(rel_tol) .and. present(monitor)) then
116 call this%ksp_init(max_iter, rel_tol, monitor = monitor)
117 else if (present(rel_tol)) then
118 call this%ksp_init(max_iter, rel_tol = rel_tol)
119 else if (present(abs_tol)) then
120 call this%ksp_init(max_iter, abs_tol = abs_tol)
121 else if (present(monitor)) then
122 call this%ksp_init(max_iter, monitor = monitor)
123 else
124 call this%ksp_init(max_iter)
125 end if
126
127 end subroutine gmres_init
128
130 subroutine gmres_free(this)
131 class(gmres_t), intent(inout) :: this
132
133 call this%ksp_free()
134
135 if (allocated(this%w)) then
136 deallocate(this%w)
137 end if
138
139 if (allocated(this%c)) then
140 deallocate(this%c)
141 end if
142
143 if (allocated(this%r)) then
144 deallocate(this%r)
145 end if
146
147 if (allocated(this%z)) then
148 deallocate(this%z)
149 end if
150
151 if (allocated(this%h)) then
152 deallocate(this%h)
153 end if
154
155 if (allocated(this%v)) then
156 deallocate(this%v)
157 end if
158
159 if (allocated(this%s)) then
160 deallocate(this%s)
161 end if
162
163
164 if (allocated(this%gam)) then
165 deallocate(this%gam)
166 end if
167
168 if (allocated(this%hp)) then
169 deallocate(this%hp)
170 end if
171
172 nullify(this%M)
173
174 end subroutine gmres_free
175
177 function gmres_solve(this, Ax, x, f, n, coef, bc_projector, gs_h, niter) &
178 result(ksp_results)
179 class(gmres_t), intent(inout) :: this
180 class(ax_t), intent(in) :: ax
181 type(field_t), intent(inout) :: x
182 integer, intent(in) :: n
183 real(kind=rp), dimension(n), intent(in) :: f
184 type(coef_t), intent(inout) :: coef
185 class(scalar_bc_projector_t), intent(inout) :: bc_projector
186 type(gs_t), intent(inout) :: gs_h
187 type(ksp_monitor_t) :: ksp_results
188 integer, optional, intent(in) :: niter
189 integer :: iter, max_iter
190 integer :: i, j, k, l, ierr, tid, nthrds
191 real(kind=xp) :: w_plus(neko_blk_size), x_plus(neko_blk_size)
192 real(kind=xp) :: hl(this%lgmres)
193 real(kind=xp) :: alpha, lr, alpha2, norm_fac, tmp, acc
194 real(kind=rp) :: temp, rnorm
195 logical :: conv
196
197 conv = .false.
198 iter = 0
199 rnorm = 0.0_rp
200
201 if (present(niter)) then
202 max_iter = niter
203 else
204 max_iter = this%max_iter
205 end if
206
207 nthrds = 1
208 !$ nthrds = omp_get_max_threads()
209
210 associate(w => this%w, c => this%c, r => this%r, z => this%z, h => this%h, &
211 v => this%v, s => this%s, gam => this%gam, hp => this%hp)
212
213 norm_fac = 1.0_rp / sqrt(coef%volume)
214 call rzero(x%x, n)
215 gam = 0.0_xp
216 s = 1.0_xp
217 c = 1.0_xp
218 h = 0.0_xp
219 call this%monitor_start('GMRES')
220 do while (.not. conv .and. iter .lt. max_iter)
221
222 if (iter .eq. 0) then
223 call copy(r, f, n)
224 else
225 call copy(r, f, n)
226 call ax%compute(w, x%x, coef, x%msh, x%Xh)
227 call gs_h%op(w, n, gs_op_add)
228 call bc_projector%apply(w, n)
229 call sub2(r, w, n)
230 end if
231
232 gam(1) = sqrt(glsc3(r, r, coef%mult, n))
233 if (iter .eq. 0) then
234 ksp_results%res_start = gam(1) * norm_fac
235 end if
236
237 if (abscmp(gam(1), 0.0_xp)) exit
238
239 rnorm = 0.0_rp
240 temp = 1.0_rp / gam(1)
241 call cmult2(v(1,1), r, temp, n)
242 do j = 1, this%lgmres
243 iter = iter+1
244
245 call this%M%solve(z(1,j), v(1,j), n)
246
247 call ax%compute(w, z(1,j), coef, x%msh, x%Xh)
248 call gs_h%op(w, n, gs_op_add)
249 call bc_projector%apply(w, n)
250
251 ! Classical Gram-Schmidt orthogonalization: accumulate
252 ! <w, v_l>_mult for l=1..j in a thread-private array hl,
253 ! publish it once per thread into a column of hp, merge
254 ! across threads, then one MPI_Allreduce of length j.
255 !$omp parallel private(i, k, l, tid, acc, hl)
256 tid = 1
257 !$ tid = omp_get_thread_num() + 1
258 do l = 1, j
259 hl(l) = 0.0_xp
260 end do
261 !$omp do
262 do i = 0, n-1, neko_blk_size
263 if (i + neko_blk_size .le. n) then
264 do l = 1, j
265 acc = hl(l)
266 !$omp simd reduction(+:acc)
267 do k = 1, neko_blk_size
268 acc = acc + &
269 w(i+k) * v(i+k,l) * coef%mult(i+k,1,1,1)
270 end do
271 hl(l) = acc
272 end do
273 else
274 do l = 1, j
275 do k = 1, n - i
276 hl(l) = hl(l) + &
277 w(i+k) * v(i+k,l) * coef%mult(i+k,1,1,1)
278 end do
279 end do
280 end if
281 end do
282 !$omp end do nowait
283 do l = 1, j
284 hp(l,tid) = hl(l)
285 end do
286 !$omp end parallel
287
288 ! Cross-thread merge into hp(:, 1), then one Allreduce of j.
289 do k = 2, nthrds
290 do l = 1, j
291 hp(l,1) = hp(l,1) + hp(l,k)
292 end do
293 end do
294 call mpi_allreduce(mpi_in_place, hp(1,1), j, &
295 mpi_extra_precision, mpi_sum, neko_comm, ierr)
296
297 do l = 1, j
298 h(l,j) = hp(l,1)
299 end do
300
301 ! Projection w = w - sum h(l,j) v_l, with fused <w,w>_mult
302 ! reduction for the post-projection norm. alpha2 is computed
303 ! directly (not by Pythagoras) so accuracy is preserved when
304 ! the Krylov subspace is becoming invariant.
305 alpha2 = 0.0_xp
306 !$omp parallel do private(k, l, w_plus, tmp) reduction(+:alpha2)
307 do i = 0, n-1, neko_blk_size
308 if (i + neko_blk_size .le. n) then
309 !$omp simd
310 do k = 1, neko_blk_size
311 w_plus(k) = 0.0_xp
312 end do
313 do l = 1, j
314 !$omp simd
315 do k = 1, neko_blk_size
316 w_plus(k) = w_plus(k) - h(l,j) * v(i+k,l)
317 end do
318 end do
319 !$omp simd reduction(+:alpha2)
320 do k = 1, neko_blk_size
321 w(i+k) = w(i+k) + w_plus(k)
322 alpha2 = alpha2 + w(i+k)**2 * coef%mult(i+k,1,1,1)
323 end do
324 else
325 do k = 1, n - i
326 tmp = 0.0_xp
327 do l = 1, j
328 tmp = tmp - h(l,j) * v(i+k,l)
329 end do
330 w(i+k) = w(i+k) + tmp
331 alpha2 = alpha2 + w(i+k)**2 * coef%mult(i+k,1,1,1)
332 end do
333 end if
334 end do
335 !$omp end parallel do
336 call mpi_allreduce(mpi_in_place, alpha2, 1, &
337 mpi_extra_precision, mpi_sum, neko_comm, ierr)
338 alpha = sqrt(alpha2)
339 do i = 1, j-1
340 temp = h(i,j)
341 h(i,j) = c(i)*temp + s(i) * h(i+1,j)
342 h(i+1,j) = -s(i)*temp + c(i) * h(i+1,j)
343 end do
344
345 rnorm = 0.0_rp
346 if (abscmp(alpha, 0.0_xp)) then
347 conv = .true.
348 exit
349 end if
350
351 lr = sqrt(h(j,j) * h(j,j) + alpha2)
352 temp = 1.0_rp / lr
353 c(j) = h(j,j) * temp
354 s(j) = alpha * temp
355 h(j,j) = lr
356 gam(j+1) = -s(j) * gam(j)
357 gam(j) = c(j) * gam(j)
358 rnorm = abs(gam(j+1)) * norm_fac
359 call this%monitor_iter(iter, rnorm)
360 if (rnorm .lt. this%abs_tol) then
361 conv = .true.
362 exit
363 end if
364
365 if (iter + 1 .gt. max_iter) exit
366
367 if (j .lt. this%lgmres) then
368 temp = 1.0_rp / alpha
369 call cmult2(v(1,j+1), w, temp, n)
370 end if
371
372 end do
373
374 j = min(j, this%lgmres)
375 do k = j, 1, -1
376 temp = gam(k)
377 do i = j, k+1, -1
378 temp = temp - h(k,i) * c(i)
379 end do
380 c(k) = temp / h(k,k)
381 end do
382
383 !$omp parallel do private(k, l, x_plus, tmp)
384 do i = 0, n-1, neko_blk_size
385 if (i + neko_blk_size .le. n) then
386 !$omp simd
387 do k = 1, neko_blk_size
388 x_plus(k) = 0.0_xp
389 end do
390 do l = 1, j
391 !$omp simd
392 do k = 1, neko_blk_size
393 x_plus(k) = x_plus(k) + c(l) * z(i+k,l)
394 end do
395 end do
396 !$omp simd
397 do k = 1, neko_blk_size
398 x%x(i+k,1,1,1) = x%x(i+k,1,1,1) + x_plus(k)
399 end do
400 else
401 do k = 1, n - i
402 tmp = 0.0_xp
403 do l = 1, j
404 tmp = tmp + c(l) * z(i+k,l)
405 end do
406 x%x(i+k,1,1,1) = x%x(i+k,1,1,1) + tmp
407 end do
408 end if
409 end do
410 !$omp end parallel do
411 end do
412
413 end associate
414 call this%monitor_stop()
415 ksp_results%res_final = rnorm
416 ksp_results%iter = iter
417 ksp_results%converged = this%is_converged(iter, rnorm)
418
419 end function gmres_solve
420
422 function gmres_solve_coupled(this, Ax, x, y, z, fx, fy, fz, &
423 n, coef, bc_projector, gs_h, niter) result(ksp_results)
424 class(gmres_t), intent(inout) :: this
425 class(ax_t), intent(in) :: ax
426 type(field_t), intent(inout) :: x
427 type(field_t), intent(inout) :: y
428 type(field_t), intent(inout) :: z
429 integer, intent(in) :: n
430 real(kind=rp), dimension(n), intent(in) :: fx
431 real(kind=rp), dimension(n), intent(in) :: fy
432 real(kind=rp), dimension(n), intent(in) :: fz
433 type(coef_t), intent(inout) :: coef
434 class(vector_bc_projector_t), intent(inout) :: bc_projector
435 type(gs_t), intent(inout) :: gs_h
436 type(ksp_monitor_t), dimension(3) :: ksp_results
437 integer, optional, intent(in) :: niter
438 type(scalar_bc_projector_t), pointer :: bc_x, bc_y, bc_z
439
440 call vector_bc_projector_components(bc_projector, bc_x, bc_y, bc_z)
441 ksp_results(1) = this%solve(ax, x, fx, n, coef, bc_x, gs_h, niter)
442 ksp_results(2) = this%solve(ax, y, fy, n, coef, bc_y, gs_h, niter)
443 ksp_results(3) = this%solve(ax, z, fz, n, coef, bc_z, gs_h, niter)
444
445 end function gmres_solve_coupled
446
447end module gmres
__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
Coefficients.
Definition coef.f90:34
Definition comm.F90:1
type(mpi_comm), public neko_comm
MPI communicator.
Definition comm.F90:46
type(mpi_datatype), public mpi_extra_precision
Definition comm.F90:55
Defines a field.
Definition field.f90:34
Gather-scatter.
Defines various GMRES methods.
Definition gmres.f90:34
type(ksp_monitor_t) function, dimension(3) gmres_solve_coupled(this, ax, x, y, z, fx, fy, fz, n, coef, bc_projector, gs_h, niter)
Standard GMRES coupled solve.
Definition gmres.f90:424
subroutine gmres_free(this)
Deallocate a standard GMRES solver.
Definition gmres.f90:131
type(ksp_monitor_t) function gmres_solve(this, ax, x, f, n, coef, bc_projector, gs_h, niter)
Standard GMRES solve.
Definition gmres.f90:179
subroutine gmres_init(this, n, max_iter, m, rel_tol, abs_tol, monitor)
Initialise a standard GMRES solver.
Definition gmres.f90:78
Implements the base abstract type for Krylov solvers plus helper types.
Definition krylov.f90:34
Definition math.f90:60
subroutine, public cmult2(a, b, c, n)
Multiplication by constant c .
Definition math.f90:523
real(kind=rp) function, public glsc3(a, b, c, n)
Weighted inner product .
Definition math.f90:1326
subroutine, public copy(a, b, n)
Copy a vector .
Definition math.f90:295
subroutine, public rzero(a, n)
Zero a real vector.
Definition math.f90:239
subroutine, public sub2(a, b, n)
Vector substraction .
Definition math.f90:987
Build configurations.
integer, parameter neko_blk_size
integer, parameter, public xp
Definition num_types.f90:16
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:14
Krylov preconditioner.
Definition precon.f90:34
Implements scalar_projector_t.
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
Coefficients defined on a given (mesh, ) tuple. Arrays use indices (i,j,k,e): element e,...
Definition coef.f90:135
Gather-scatter kernel.
Standard preconditioned generalized minimal residual method.
Definition gmres.f90:54
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.
Abstract type for resolving vector boundary conditions.