Neko 1.99.9
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
gmres_sx.f90
Go to the documentation of this file.
1! Copyright (c) 2021-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!
35 use krylov, only : ksp_t, ksp_monitor_t
36 use gmres, only : gmres_space_size
37 use precon, only : pc_t
38 use ax_product, only : ax_t
39 use num_types, only : rp
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, rone, copy, cmult2, col2, col3, add2s2, abscmp
48 use mpi_f08
49 use utils, only : neko_error
50 use json_module, only : json_file
52 use logger, only : neko_log, log_size
53 implicit none
54 private
55
57 type, public, extends(ksp_t) :: sx_gmres_t
58 integer :: lgmres = gmres_space_size
59 real(kind=rp), allocatable :: w(:)
60 real(kind=rp), allocatable :: c(:)
61 real(kind=rp), allocatable :: r(:)
62 real(kind=rp), allocatable :: z(:,:)
63 real(kind=rp), allocatable :: h(:,:)
64 real(kind=rp), allocatable :: ml(:)
65 real(kind=rp), allocatable :: v(:,:)
66 real(kind=rp), allocatable :: s(:)
67 real(kind=rp), allocatable :: mu(:)
68 real(kind=rp), allocatable :: gam(:)
69 real(kind=rp), allocatable :: wk1(:)
70 real(kind=rp) :: rnorm
71 contains
72 procedure, pass(this) :: init => sx_gmres_init
73 procedure, pass(this) :: init_from_json => sx_gmres_init_from_json
74 procedure, pass(this) :: free => sx_gmres_free
75 procedure, pass(this) :: solve => sx_gmres_solve
76 procedure, pass(this) :: solve_coupled => sx_gmres_solve_coupled
77 end type sx_gmres_t
78
79contains
80
82 subroutine sx_gmres_init(this, n, max_iter, M, rel_tol, abs_tol, monitor)
83 class(sx_gmres_t), target, intent(inout) :: this
84 integer, intent(in) :: n
85 integer, intent(in) :: max_iter
86 class(pc_t), optional, intent(in), target :: M
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
93 if (present(m)) then
94 this%M => m
95 end if
96
97 allocate(this%w(n))
98 allocate(this%r(n))
99 allocate(this%ml(n))
100 allocate(this%mu(n))
101 allocate(this%wk1(n))
102
103 allocate(this%c(this%lgmres))
104 allocate(this%s(this%lgmres))
105 allocate(this%gam(this%lgmres + 1))
106
107 allocate(this%z(n, this%lgmres))
108 allocate(this%v(n, this%lgmres))
109
110 allocate(this%h(this%lgmres, this%lgmres))
111
112
113 if (present(rel_tol) .and. present(abs_tol) .and. present(monitor)) then
114 call this%ksp_init(max_iter, rel_tol, abs_tol, monitor = monitor)
115 else if (present(rel_tol) .and. present(abs_tol)) then
116 call this%ksp_init(max_iter, rel_tol, abs_tol)
117 else if (present(monitor) .and. present(abs_tol)) then
118 call this%ksp_init(max_iter, abs_tol = abs_tol, monitor = monitor)
119 else if (present(rel_tol) .and. present(monitor)) then
120 call this%ksp_init(max_iter, rel_tol, monitor = monitor)
121 else if (present(rel_tol)) then
122 call this%ksp_init(max_iter, rel_tol = rel_tol)
123 else if (present(abs_tol)) then
124 call this%ksp_init(max_iter, abs_tol = abs_tol)
125 else if (present(monitor)) then
126 call this%ksp_init(max_iter, monitor = monitor)
127 else
128 call this%ksp_init(max_iter)
129 end if
130
131 end subroutine sx_gmres_init
132
136 subroutine sx_gmres_init_from_json(this, n, json, M)
137 class(sx_gmres_t), target, intent(inout) :: this
138 integer, intent(in) :: n
139 type(json_file), intent(inout) :: json
140 class(pc_t), optional, intent(in), target :: M
141 character(len=LOG_SIZE) :: log_buf
142
143 call json_get_or_lookup_or_default(json, 'space_size', &
144 this%lgmres, gmres_space_size)
145 if (this%lgmres .lt. 1) then
146 call neko_error('GMRES space_size must be at least 1')
147 end if
148 write(log_buf, '(A,I0)') 'GMRES space: ', this%lgmres
149 call neko_log%message(log_buf)
150
151 call this%ksp_init_from_json(n, json, m = m)
152
153 end subroutine sx_gmres_init_from_json
154
156 subroutine sx_gmres_free(this)
157 class(sx_gmres_t), intent(inout) :: this
158
159 call this%ksp_free()
160
161 if (allocated(this%w)) then
162 deallocate(this%w)
163 end if
164
165 if (allocated(this%c)) then
166 deallocate(this%c)
167 end if
168
169 if (allocated(this%r)) then
170 deallocate(this%r)
171 end if
172
173 if (allocated(this%z)) then
174 deallocate(this%z)
175 end if
176
177 if (allocated(this%h)) then
178 deallocate(this%h)
179 end if
180
181 if (allocated(this%ml)) then
182 deallocate(this%ml)
183 end if
184
185 if (allocated(this%v)) then
186 deallocate(this%v)
187 end if
188
189 if (allocated(this%s)) then
190 deallocate(this%s)
191 end if
192
193 if (allocated(this%mu)) then
194 deallocate(this%mu)
195 end if
196
197 if (allocated(this%gam)) then
198 deallocate(this%gam)
199 end if
200
201 if (allocated(this%wk1)) then
202 deallocate(this%wk1)
203 end if
204
205 nullify(this%M)
206
207 end subroutine sx_gmres_free
208
210 function sx_gmres_solve(this, Ax, x, f, n, coef, bc_projector, gs_h, niter) &
211 result(ksp_results)
212 class(sx_gmres_t), intent(inout) :: this
213 class(ax_t), intent(in) :: ax
214 type(field_t), intent(inout) :: x
215 integer, intent(in) :: n
216 real(kind=rp), dimension(n), intent(in) :: f
217 type(coef_t), intent(inout) :: coef
218 class(scalar_bc_projector_t), intent(inout) :: bc_projector
219 type(gs_t), intent(inout) :: gs_h
220 type(ksp_monitor_t) :: ksp_results
221 integer, optional, intent(in) :: niter
222 integer :: iter, max_iter, glb_n
223 integer :: i, j, k, ierr
224 real(kind=rp), parameter :: one = 1.0
225 real(kind=rp) :: rnorm
226 real(kind=rp) :: alpha, temp, l
227 real(kind=rp) :: ratio, div0, norm_fac
228 logical :: conv
229 integer outer
230
231 conv = .false.
232 iter = 0
233 rnorm = 0.0_rp
234 glb_n = n / x%msh%nelv * x%msh%glb_nelv
235
236 if (present(niter)) then
237 max_iter = niter
238 else
239 max_iter = this%max_iter
240 end if
241
242 call rone(this%ml, n)
243 call rone(this%mu, n)
244 norm_fac = one / sqrt(coef%volume)
245 call rzero(x%x, n)
246 call rzero(this%gam, this%lgmres + 1)
247 call rone(this%s, this%lgmres)
248 call rone(this%c, this%lgmres)
249 call rzero(this%h, this%lgmres * this%lgmres)
250 outer = 0
251 call this%monitor_start('GMRES')
252 do while (.not. conv .and. iter .lt. max_iter)
253 outer = outer + 1
254
255 if (iter .eq. 0) then
256 call col3(this%r, this%ml, f, n)
257 else
258 !update residual
259 call copy (this%r,f,n)
260 call ax%compute(this%w, x%x, coef, x%msh, x%Xh)
261 call gs_h%op(this%w, n, gs_op_add)
262 call bc_projector%apply(this%w, n)
263 call add2s2(this%r, this%w, -one, n)
264 call col2(this%r, this%ml, n)
265 end if
266 this%gam(1) = sqrt(glsc3(this%r, this%r, coef%mult, n))
267 if (iter .eq. 0) then
268 div0 = this%gam(1) * norm_fac
269 ksp_results%res_start = div0
270 end if
271
272 if (abscmp(this%gam(1), 0.0_rp)) exit
273
274 rnorm = 0.0_rp
275 temp = one / this%gam(1)
276 call cmult2(this%v(1,1), this%r, temp, n)
277 do j = 1, this%lgmres
278 iter = iter+1
279 call col3(this%w, this%mu, this%v(1,j), n)
280
281 !Apply precond
282 call this%M%solve(this%z(1,j), this%w, n)
283
284 call ax%compute(this%w, this%z(1,j), coef, x%msh, x%Xh)
285 call gs_h%op(this%w, n, gs_op_add)
286 call bc_projector%apply(this%w, n)
287 call col2(this%w, this%ml, n)
288
289 do i = 1, j
290 this%h(i,j) = 0.0_rp
291 do k = 1, n
292 this%h(i,j) = this%h(i,j) + &
293 this%w(k) * this%v(k,i) * coef%mult(k,1,1,1)
294 end do
295 end do
296
297 !Could probably be done inplace...
298 call mpi_allreduce(this%h(1,j), this%wk1, j, &
299 mpi_real_precision, mpi_sum, neko_comm, ierr)
300 call copy(this%h(1,j), this%wk1, j)
301
302 do i = 1, j
303 do k = 1, n
304 this%w(k) = this%w(k) - this%h(i,j) * this%v(k,i)
305 end do
306 end do
307
308 !apply Givens rotations to new column
309 do i = 1, j-1
310 temp = this%h(i,j)
311 this%h(i ,j) = this%c(i)*temp + this%s(i)*this%h(i+1,j)
312 this%h(i+1,j) = -this%s(i)*temp + this%c(i)*this%h(i+1,j)
313 end do
314
315 alpha = sqrt(glsc3(this%w, this%w, coef%mult, n))
316 rnorm = 0.0_rp
317 if (abscmp(alpha, 0.0_rp)) then
318 conv = .true.
319 exit
320 end if
321 l = sqrt(this%h(j,j) * this%h(j,j) + alpha**2)
322 temp = one / l
323 this%c(j) = this%h(j,j) * temp
324 this%s(j) = alpha * temp
325 this%h(j,j) = l
326 this%gam(j+1) = -this%s(j) * this%gam(j)
327 this%gam(j) = this%c(j) * this%gam(j)
328
329 rnorm = abs(this%gam(j+1)) * norm_fac
330 call this%monitor_iter(iter, rnorm)
331 ratio = rnorm / div0
332 if (rnorm .lt. this%abs_tol) then
333 conv = .true.
334 exit
335 end if
336
337 if (iter + 1 .gt. max_iter) exit
338
339 if (j .lt. this%lgmres) then
340 temp = one / alpha
341 call cmult2(this%v(1,j+1), this%w, temp, n)
342 end if
343 end do
344 j = min(j, this%lgmres)
345 !back substitution
346 do k = j, 1, -1
347 temp = this%gam(k)
348 do i = j, k+1, -1
349 temp = temp - this%h(k,i) * this%c(i)
350 end do
351 this%c(k) = temp / this%h(k,k)
352 end do
353 !sum up Arnoldi vectors
354 do i = 1, j
355 do k = 1, n
356 x%x(k,1,1,1) = x%x(k,1,1,1) + this%c(i) * this%z(k,i)
357 end do
358 end do
359 end do
360 call this%monitor_stop()
361 ksp_results%res_final = rnorm
362 ksp_results%iter = iter
363 ksp_results%converged = this%is_converged(iter, rnorm)
364 end function sx_gmres_solve
365
367 function sx_gmres_solve_coupled(this, Ax, x, y, z, fx, fy, fz, &
368 n, coef, bc_projector, gs_h, niter) result(ksp_results)
369 class(sx_gmres_t), intent(inout) :: this
370 class(ax_t), intent(in) :: ax
371 type(field_t), intent(inout) :: x
372 type(field_t), intent(inout) :: y
373 type(field_t), intent(inout) :: z
374 integer, intent(in) :: n
375 real(kind=rp), dimension(n), intent(in) :: fx
376 real(kind=rp), dimension(n), intent(in) :: fy
377 real(kind=rp), dimension(n), intent(in) :: fz
378 type(coef_t), intent(inout) :: coef
379 class(vector_bc_projector_t), intent(inout) :: bc_projector
380 type(gs_t), intent(inout) :: gs_h
381 type(ksp_monitor_t), dimension(3) :: ksp_results
382 integer, optional, intent(in) :: niter
383 type(scalar_bc_projector_t), pointer :: bc_x, bc_y, bc_z
384
385 call vector_bc_projector_components(bc_projector, bc_x, bc_y, bc_z)
386 ksp_results(1) = this%solve(ax, x, fx, n, coef, bc_x, gs_h, niter)
387 ksp_results(2) = this%solve(ax, y, fy, n, coef, bc_y, gs_h, niter)
388 ksp_results(3) = this%solve(ax, z, fz, n, coef, bc_z, gs_h, niter)
389
390 end function sx_gmres_solve_coupled
391
392end module gmres_sx
__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_datatype), public mpi_real_precision
MPI type for working precision of REAL types.
Definition comm.F90:54
type(mpi_comm), public neko_comm
MPI communicator.
Definition comm.F90:46
Defines a field.
Definition field.f90:34
Gather-scatter.
Defines various GMRES methods.
Definition gmres_sx.f90:34
subroutine sx_gmres_init(this, n, max_iter, m, rel_tol, abs_tol, monitor)
Initialise a standard GMRES solver.
Definition gmres_sx.f90:83
subroutine sx_gmres_free(this)
Deallocate a standard GMRES solver.
Definition gmres_sx.f90:157
type(ksp_monitor_t) function sx_gmres_solve(this, ax, x, f, n, coef, bc_projector, gs_h, niter)
Standard PCG solve.
Definition gmres_sx.f90:212
subroutine sx_gmres_init_from_json(this, n, json, m)
Initialise a standard GMRES solver from a JSON solver block. Reads space_size (default GMRES_SPACE_SI...
Definition gmres_sx.f90:137
type(ksp_monitor_t) function, dimension(3) sx_gmres_solve_coupled(this, ax, x, y, z, fx, fy, fz, n, coef, bc_projector, gs_h, niter)
Standard GMRES coupled solve.
Definition gmres_sx.f90:369
Implements gmres_t.
Definition gmres.f90:34
integer, parameter, public gmres_space_size
Default Krylov space size (restart length) of the GMRES solvers.
Definition gmres.f90:60
Utilities for retrieving parameters from the case files.
Implements the base abstract type for Krylov solvers plus helper types.
Definition krylov.f90:34
Logging routines.
Definition log.f90:34
type(log_t), public neko_log
Global log stream.
Definition log.f90:92
integer, parameter, public log_size
Definition log.f90:46
Definition math.F90:60
subroutine, public cmult2(a, b, c, n)
Multiplication by constant c .
Definition math.F90:533
real(kind=rp) function, public glsc3(a, b, c, n)
Weighted inner product .
Definition math.F90:1336
subroutine, public rone(a, n)
Set all elements to one.
Definition math.F90:291
subroutine, public col2(a, b, n)
Vector multiplication .
Definition math.F90:1095
subroutine, public copy(a, b, n)
Copy a vector .
Definition math.F90:305
subroutine, public col3(a, b, c, n)
Vector multiplication with 3 vectors .
Definition math.F90:1110
subroutine, public rzero(a, n)
Zero a real vector.
Definition math.F90:249
subroutine, public add2s2(a, b, c1, n)
Vector addition with scalar multiplication (multiplication on second argument)
Definition math.F90:1047
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:14
Krylov preconditioner.
Definition precon.f90:34
Implements scalar_projector_t.
Utilities.
Definition utils.f90:35
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:44
Coefficients defined on a given (mesh, ) tuple. Arrays use indices (i,j,k,e): element e,...
Definition coef.f90:136
Gather-scatter kernel.
Standard preconditioned generalized minimal residual method (SX version)
Definition gmres_sx.f90:57
Type for storing initial and final residuals in a Krylov solver.
Definition krylov.f90:60
Base abstract type for a canonical Krylov method, solving .
Definition krylov.f90:77
Defines a canonical Krylov preconditioner.
Definition precon.f90:44
Projector for scalar boundary conditions.
Abstract type for resolving vector boundary conditions.