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) :: alpha, lr, alpha2, norm_fac, tmp, acc
193 real(kind=rp) :: temp, rnorm
194 logical :: conv
195
196 conv = .false.
197 iter = 0
198 rnorm = 0.0_rp
199
200 if (present(niter)) then
201 max_iter = niter
202 else
203 max_iter = this%max_iter
204 end if
205
206 nthrds = 1
207 !$ nthrds = omp_get_max_threads()
208
209 associate(w => this%w, c => this%c, r => this%r, z => this%z, h => this%h, &
210 v => this%v, s => this%s, gam => this%gam, hp => this%hp)
211
212 norm_fac = 1.0_rp / sqrt(coef%volume)
213 call rzero(x%x, n)
214 gam = 0.0_xp
215 s = 1.0_xp
216 c = 1.0_xp
217 h = 0.0_xp
218 call this%monitor_start('GMRES')
219 do while (.not. conv .and. iter .lt. max_iter)
220
221 if (iter .eq. 0) then
222 call copy(r, f, n)
223 else
224 call copy(r, f, n)
225 call ax%compute(w, x%x, coef, x%msh, x%Xh)
226 call gs_h%op(w, n, gs_op_add)
227 call bc_projector%apply(w, n)
228 call sub2(r, w, n)
229 end if
230
231 gam(1) = sqrt(glsc3(r, r, coef%mult, n))
232 if (iter .eq. 0) then
233 ksp_results%res_start = gam(1) * norm_fac
234 end if
235
236 if (abscmp(gam(1), 0.0_xp)) exit
237
238 rnorm = 0.0_rp
239 temp = 1.0_rp / gam(1)
240 call cmult2(v(1,1), r, temp, n)
241 do j = 1, this%lgmres
242 iter = iter+1
243
244 call this%M%solve(z(1,j), v(1,j), n)
245
246 call ax%compute(w, z(1,j), coef, x%msh, x%Xh)
247 call gs_h%op(w, n, gs_op_add)
248 call bc_projector%apply(w, n)
249
250 ! Classical Gram-Schmidt orthogonalization: accumulate
251 ! <w, v_l>_mult for l=1..j into per-thread columns of hp,
252 ! merge across threads, then one MPI_Allreduce of length j.
253 !$omp parallel private(i, k, l, tid, acc)
254 tid = 1
255 !$ tid = omp_get_thread_num() + 1
256 do l = 1, j
257 hp(l,tid) = 0.0_xp
258 end do
259 !$omp do
260 do i = 0, n-1, neko_blk_size
261 if (i + neko_blk_size .le. n) then
262 do l = 1, j
263 acc = hp(l,tid)
264 !$omp simd reduction(+:acc)
265 do k = 1, neko_blk_size
266 acc = acc + &
267 w(i+k) * v(i+k,l) * coef%mult(i+k,1,1,1)
268 end do
269 hp(l,tid) = acc
270 end do
271 else
272 do l = 1, j
273 do k = 1, n - i
274 hp(l,tid) = hp(l,tid) + &
275 w(i+k) * v(i+k,l) * coef%mult(i+k,1,1,1)
276 end do
277 end do
278 end if
279 end do
280 !$omp end do
281 !$omp end parallel
282
283 ! Cross-thread merge into hp(:, 1), then one Allreduce of j.
284 do k = 2, nthrds
285 do l = 1, j
286 hp(l,1) = hp(l,1) + hp(l,k)
287 end do
288 end do
289 call mpi_allreduce(mpi_in_place, hp(1,1), j, &
290 mpi_extra_precision, mpi_sum, neko_comm, ierr)
291
292 do l = 1, j
293 h(l,j) = hp(l,1)
294 end do
295
296 ! Projection w = w - sum h(l,j) v_l, with fused <w,w>_mult
297 ! reduction for the post-projection norm. alpha2 is computed
298 ! directly (not by Pythagoras) so accuracy is preserved when
299 ! the Krylov subspace is becoming invariant.
300 alpha2 = 0.0_xp
301 !$omp parallel do private(k, l, w_plus, tmp) reduction(+:alpha2)
302 do i = 0, n-1, neko_blk_size
303 if (i + neko_blk_size .le. n) then
304 !$omp simd
305 do k = 1, neko_blk_size
306 w_plus(k) = 0.0_xp
307 end do
308 do l = 1, j
309 !$omp simd
310 do k = 1, neko_blk_size
311 w_plus(k) = w_plus(k) - h(l,j) * v(i+k,l)
312 end do
313 end do
314 do k = 1, neko_blk_size
315 w(i+k) = w(i+k) + w_plus(k)
316 alpha2 = alpha2 + w(i+k)**2 * coef%mult(i+k,1,1,1)
317 end do
318 else
319 do k = 1, n - i
320 tmp = 0.0_xp
321 do l = 1, j
322 tmp = tmp - h(l,j) * v(i+k,l)
323 end do
324 w(i+k) = w(i+k) + tmp
325 alpha2 = alpha2 + w(i+k)**2 * coef%mult(i+k,1,1,1)
326 end do
327 end if
328 end do
329 !$omp end parallel do
330 call mpi_allreduce(mpi_in_place, alpha2, 1, &
331 mpi_extra_precision, mpi_sum, neko_comm, ierr)
332 alpha = sqrt(alpha2)
333 do i = 1, j-1
334 temp = h(i,j)
335 h(i,j) = c(i)*temp + s(i) * h(i+1,j)
336 h(i+1,j) = -s(i)*temp + c(i) * h(i+1,j)
337 end do
338
339 rnorm = 0.0_rp
340 if (abscmp(alpha, 0.0_xp)) then
341 conv = .true.
342 exit
343 end if
344
345 lr = sqrt(h(j,j) * h(j,j) + alpha2)
346 temp = 1.0_rp / lr
347 c(j) = h(j,j) * temp
348 s(j) = alpha * temp
349 h(j,j) = lr
350 gam(j+1) = -s(j) * gam(j)
351 gam(j) = c(j) * gam(j)
352 rnorm = abs(gam(j+1)) * norm_fac
353 call this%monitor_iter(iter, rnorm)
354 if (rnorm .lt. this%abs_tol) then
355 conv = .true.
356 exit
357 end if
358
359 if (iter + 1 .gt. max_iter) exit
360
361 if (j .lt. this%lgmres) then
362 temp = 1.0_rp / alpha
363 call cmult2(v(1,j+1), w, temp, n)
364 end if
365
366 end do
367
368 j = min(j, this%lgmres)
369 do k = j, 1, -1
370 temp = gam(k)
371 do i = j, k+1, -1
372 temp = temp - h(k,i) * c(i)
373 end do
374 c(k) = temp / h(k,k)
375 end do
376
377 !$omp parallel do private(k, l, x_plus, tmp)
378 do i = 0, n-1, neko_blk_size
379 if (i + neko_blk_size .le. n) then
380 !$omp simd
381 do k = 1, neko_blk_size
382 x_plus(k) = 0.0_xp
383 end do
384 do l = 1, j
385 !$omp simd
386 do k = 1, neko_blk_size
387 x_plus(k) = x_plus(k) + c(l) * z(i+k,l)
388 end do
389 end do
390 !$omp simd
391 do k = 1, neko_blk_size
392 x%x(i+k,1,1,1) = x%x(i+k,1,1,1) + x_plus(k)
393 end do
394 else
395 do k = 1, n - i
396 tmp = 0.0_xp
397 do l = 1, j
398 tmp = tmp + c(l) * z(i+k,l)
399 end do
400 x%x(i+k,1,1,1) = x%x(i+k,1,1,1) + tmp
401 end do
402 end if
403 end do
404 !$omp end parallel do
405 end do
406
407 end associate
408 call this%monitor_stop()
409 ksp_results%res_final = rnorm
410 ksp_results%iter = iter
411 ksp_results%converged = this%is_converged(iter, rnorm)
412
413 end function gmres_solve
414
416 function gmres_solve_coupled(this, Ax, x, y, z, fx, fy, fz, &
417 n, coef, bc_projector, gs_h, niter) result(ksp_results)
418 class(gmres_t), intent(inout) :: this
419 class(ax_t), intent(in) :: ax
420 type(field_t), intent(inout) :: x
421 type(field_t), intent(inout) :: y
422 type(field_t), intent(inout) :: z
423 integer, intent(in) :: n
424 real(kind=rp), dimension(n), intent(in) :: fx
425 real(kind=rp), dimension(n), intent(in) :: fy
426 real(kind=rp), dimension(n), intent(in) :: fz
427 type(coef_t), intent(inout) :: coef
428 class(vector_bc_projector_t), intent(inout) :: bc_projector
429 type(gs_t), intent(inout) :: gs_h
430 type(ksp_monitor_t), dimension(3) :: ksp_results
431 integer, optional, intent(in) :: niter
432 type(scalar_bc_projector_t), pointer :: bc_x, bc_y, bc_z
433
434 call vector_bc_projector_components(bc_projector, bc_x, bc_y, bc_z)
435 ksp_results(1) = this%solve(ax, x, fx, n, coef, bc_x, gs_h, niter)
436 ksp_results(2) = this%solve(ax, y, fy, n, coef, bc_y, gs_h, niter)
437 ksp_results(3) = this%solve(ax, z, fz, n, coef, bc_z, gs_h, niter)
438
439 end function gmres_solve_coupled
440
441end 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:418
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:522
real(kind=rp) function, public glsc3(a, b, c, n)
Weighted inner product .
Definition math.f90:1290
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
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:93
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.