Neko 1.99.9
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
cg.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 cg
35 use neko_config, only : neko_blk_size
36 use num_types, only : rp, xp
38 use precon, only : pc_t
39 use ax_product, only : ax_t
40 use field, only : field_t
41 use coefs, only : coef_t
42 use gather_scatter, only : gs_t, gs_op_add
46 use matrix, only : matrix_t
48 use math, only : glsc3, abscmp
50 use mpi_f08, only : mpi_allreduce, mpi_in_place, mpi_sum
51 implicit none
52 private
53
54 integer, parameter :: cg_p_space = 7
55
60 type, public, extends(ksp_t) :: cg_t
62 real(kind=rp), pointer :: w(:) => null()
64 real(kind=rp), pointer :: r(:) => null()
66 type(matrix_t), pointer :: p => null()
68 real(kind=rp), pointer :: z(:) => null()
70 real(kind=rp), pointer :: alpha(:) => null()
71 contains
73 procedure, pass(this) :: init => cg_init
75 procedure, pass(this) :: free => cg_free
77 procedure, pass(this) :: solve => cg_solve
79 procedure, pass(this) :: solve_coupled => cg_solve_coupled
80 end type cg_t
81
82contains
83
85 subroutine cg_init(this, n, max_iter, M, rel_tol, abs_tol, monitor)
86 class(cg_t), intent(inout), target :: this
87 integer, intent(in) :: max_iter
88 class(pc_t), optional, intent(in), target :: M
89 integer, intent(in) :: n
90 real(kind=rp), optional, intent(in) :: rel_tol
91 real(kind=rp), optional, intent(in) :: abs_tol
92 logical, optional, intent(in) :: monitor
93
94 call this%free()
95
96 if (present(m)) then
97 this%M => m
98 end if
99 if (present(rel_tol) .and. present(abs_tol) .and. present(monitor)) then
100 call this%ksp_init(max_iter, rel_tol, abs_tol, monitor = monitor)
101 else if (present(rel_tol) .and. present(abs_tol)) then
102 call this%ksp_init(max_iter, rel_tol, abs_tol)
103 else if (present(monitor) .and. present(abs_tol)) then
104 call this%ksp_init(max_iter, abs_tol = abs_tol, monitor = monitor)
105 else if (present(rel_tol) .and. present(monitor)) then
106 call this%ksp_init(max_iter, rel_tol, monitor = monitor)
107 else if (present(rel_tol)) then
108 call this%ksp_init(max_iter, rel_tol = rel_tol)
109 else if (present(abs_tol)) then
110 call this%ksp_init(max_iter, abs_tol = abs_tol)
111 else if (present(monitor)) then
112 call this%ksp_init(max_iter, monitor = monitor)
113 else
114 call this%ksp_init(max_iter)
115 end if
116
117 end subroutine cg_init
118
120 subroutine cg_free(this)
121 class(cg_t), intent(inout) :: this
122
123 call this%ksp_free()
124
125 nullify(this%w)
126 nullify(this%r)
127 nullify(this%p)
128 nullify(this%z)
129 nullify(this%alpha)
130
131 nullify(this%M)
132
133 end subroutine cg_free
134
136 function cg_solve(this, Ax, x, f, n, coef, bc_projector, gs_h, niter) &
137 result(ksp_results)
138 class(cg_t), intent(inout) :: this
139 class(ax_t), intent(in) :: ax
140 type(field_t), intent(inout) :: x
141 integer, intent(in) :: n
142 real(kind=rp), dimension(n), intent(in) :: f
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 type(ksp_monitor_t) :: ksp_results
147 integer, optional, intent(in) :: niter
148 integer :: iter, max_iter, i, j, k, p_cur, p_prev, ierr
149 real(kind=rp) :: rnorm, rtr, rtz2, rtz1, x_plus(neko_blk_size)
150 real(kind=rp) :: beta, pap, norm_fac, tmp
151 integer :: temp_indices(5)
152
153 if (present(niter)) then
154 max_iter = niter
155 else
156 max_iter = this%max_iter
157 end if
158 norm_fac = 1.0_rp / sqrt(coef%volume)
159
160 call neko_scratch_registry%request(this%w, temp_indices(1), n, .false.)
161 call neko_scratch_registry%request(this%r, temp_indices(2), n, .false.)
162 call neko_scratch_registry%request(this%p, temp_indices(3), &
163 n, cg_p_space, .false.)
164 call neko_scratch_registry%request(this%z, temp_indices(4), n, .false.)
165 call neko_scratch_registry%request(this%alpha, temp_indices(5), &
166 cg_p_space, .false.)
167
168 associate(w => this%w, r => this%r, p => this%p%x, &
169 z => this%z, alpha => this%alpha)
170
171 rtz1 = 1.0_rp
172 rtr = 0.0_rp
173 !$omp parallel do reduction(+:rtr)
174 do i = 1, n
175 x%x(i,1,1,1) = 0.0_rp
176 p(i, cg_p_space) = 0.0_rp
177 r(i) = f(i)
178 rtr = rtr + (r(i) * coef%mult(i,1,1,1) * r(i))
179 end do
180 !$omp end parallel do
181
182 call mpi_allreduce(mpi_in_place, rtr, 1, &
183 mpi_real_precision, mpi_sum, neko_comm, ierr)
184
185 rnorm = sqrt(rtr) * norm_fac
186 ksp_results%res_start = rnorm
187 ksp_results%res_final = rnorm
188 ksp_results%iter = 0
189 if (abscmp(rnorm, 0.0_rp)) then
190 ksp_results%converged = .true.
191 nullify(this%w, this%r, this%p, this%z, this%alpha)
192 call neko_scratch_registry%relinquish(temp_indices)
193 return
194 end if
195
196 p_prev = cg_p_space
197 p_cur = 1
198 call this%monitor_start('CG')
199 do iter = 1, max_iter
200 call this%M%solve(z, r, n)
201 rtz2 = rtz1
202 rtz1 = glsc3(r, coef%mult, z, n)
203
204 beta = rtz1 / rtz2
205 if (iter .eq. 1) beta = 0.0_rp
206 !$omp parallel do
207 do i = 1, n
208 p(i, p_cur) = z(i) + beta * p(i, p_prev)
209 end do
210 !$omp end parallel do
211
212 call ax%compute(w, p(1, p_cur), coef, x%msh, x%Xh)
213 call gs_h%op(w, n, gs_op_add)
214 call bc_projector%apply(w, n)
215
216 pap = glsc3(w, coef%mult, p(1, p_cur), n)
217
218 alpha(p_cur) = rtz1 / pap
219 call second_cg_part(rtr, r, coef%mult, w, alpha(p_cur), n)
220 rnorm = sqrt(rtr) * norm_fac
221 call this%monitor_iter(iter, rnorm)
222
223 if ((p_cur .eq. cg_p_space) .or. &
224 (rnorm .lt. this%abs_tol) .or. iter .eq. max_iter) then
225 !$omp parallel do private(j, k, x_plus, tmp)
226 do i = 0, n-1, neko_blk_size
227 if (i + neko_blk_size .le. n) then
228 !$omp simd
229 do k = 1, neko_blk_size
230 x_plus(k) = 0.0_rp
231 end do
232 do j = 1, p_cur
233 !$omp simd
234 do k = 1, neko_blk_size
235 x_plus(k) = x_plus(k) + alpha(j) * p(i+k,j)
236 end do
237 end do
238 !$omp simd
239 do k = 1, neko_blk_size
240 x%x(i+k,1,1,1) = x%x(i+k,1,1,1) + x_plus(k)
241 end do
242 else
243 do k = 1, n - i
244 tmp = 0.0_rp
245 do j = 1, p_cur
246 tmp = tmp + alpha(j) * p(i+k,j)
247 end do
248 x%x(i+k,1,1,1) = x%x(i+k,1,1,1) + tmp
249 end do
250 end if
251 end do
252 !$omp end parallel do
253 p_prev = p_cur
254 p_cur = 1
255 if (rnorm .lt. this%abs_tol) exit
256 else
257 p_prev = p_cur
258 p_cur = p_cur + 1
259 end if
260 end do
261 end associate
262 nullify(this%w, this%r, this%p, this%z, this%alpha)
263 call neko_scratch_registry%relinquish(temp_indices)
264 call this%monitor_stop()
265 ksp_results%res_final = rnorm
266 ksp_results%iter = iter
267 ksp_results%converged = this%is_converged(iter, rnorm)
268 end function cg_solve
269
270 subroutine second_cg_part(rtr, r, mult, w, alpha, n)
271 integer, intent(in) :: n
272 real(kind=rp), intent(inout) :: r(n), rtr
273 real(kind=xp) :: tmp
274 real(kind=rp), intent(in) ::mult(n), w(n), alpha
275 integer :: i, ierr
276
277 tmp = 0.0_xp
278 !$omp parallel do reduction(+:tmp)
279 do i = 1, n
280 r(i) = r(i) - alpha*w(i)
281 tmp = tmp + r(i) * r(i) * mult(i)
282 end do
283 !$omp end parallel do
284 call mpi_allreduce(mpi_in_place, tmp, 1, &
285 mpi_extra_precision, mpi_sum, neko_comm, ierr)
286 rtr = tmp
287
288 end subroutine second_cg_part
289
291 function cg_solve_coupled(this, Ax, x, y, z, fx, fy, fz, &
292 n, coef, bc_projector, gs_h, niter) result(ksp_results)
293 class(cg_t), intent(inout) :: this
294 class(ax_t), intent(in) :: ax
295 type(field_t), intent(inout) :: x
296 type(field_t), intent(inout) :: y
297 type(field_t), intent(inout) :: z
298 integer, intent(in) :: n
299 real(kind=rp), dimension(n), intent(in) :: fx
300 real(kind=rp), dimension(n), intent(in) :: fy
301 real(kind=rp), dimension(n), intent(in) :: fz
302 type(coef_t), intent(inout) :: coef
303 class(vector_bc_projector_t), intent(inout) :: bc_projector
304 type(gs_t), intent(inout) :: gs_h
305 type(ksp_monitor_t), dimension(3) :: ksp_results
306 integer, optional, intent(in) :: niter
307 type(scalar_bc_projector_t), pointer :: bc_x, bc_y, bc_z
308
309 call vector_bc_projector_components(bc_projector, bc_x, bc_y, bc_z)
310 ksp_results(1) = this%solve(ax, x, fx, n, coef, bc_x, gs_h, niter)
311 ksp_results(2) = this%solve(ax, y, fy, n, coef, bc_y, gs_h, niter)
312 ksp_results(3) = this%solve(ax, z, fz, n, coef, bc_z, gs_h, niter)
313
314 end function cg_solve_coupled
315
316end module cg
__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 various Conjugate Gradient methods.
Definition cg.f90:34
subroutine cg_free(this)
Free a CPU PCG solver.
Definition cg.f90:121
integer, parameter cg_p_space
Definition cg.f90:54
type(ksp_monitor_t) function cg_solve(this, ax, x, f, n, coef, bc_projector, gs_h, niter)
Solve a linear system with the standard PCG method.
Definition cg.f90:138
subroutine cg_init(this, n, max_iter, m, rel_tol, abs_tol, monitor)
Initialise a CPU PCG solver.
Definition cg.f90:86
type(ksp_monitor_t) function, dimension(3) cg_solve_coupled(this, ax, x, y, z, fx, fy, fz, n, coef, bc_projector, gs_h, niter)
Solve three independent systems with the standard PCG method.
Definition cg.f90:293
subroutine second_cg_part(rtr, r, mult, w, alpha, n)
Definition cg.f90:271
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
type(mpi_datatype), public mpi_extra_precision
Definition comm.F90:55
Defines a field.
Definition field.f90:34
Gather-scatter.
Implements the base abstract type for Krylov solvers plus helper types.
Definition krylov.f90:34
integer, parameter, public ksp_max_iter
Maximum number of iters.
Definition krylov.f90:52
Definition math.f90:60
real(kind=rp) function, public glsc3(a, b, c, n)
Weighted inner product .
Definition math.f90:1326
Defines a matrix.
Definition matrix.f90:34
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.
Defines a registry for storing and requesting temporary objects This can be used when you have a func...
type(scratch_registry_t), target, public neko_scratch_registry
Global scratch registry.
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
CPU implementation of the preconditioned conjugate gradient method.
Definition cg.f90:60
Coefficients defined on a given (mesh, ) tuple. Arrays use indices (i,j,k,e): element e,...
Definition coef.f90:136
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:44
Projector for scalar boundary conditions.
Abstract type for resolving vector boundary conditions.