Neko 1.99.9
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
cg_coupled.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 cg_cpld
35 use num_types, only : rp, xp
37 use precon, only : pc_t
38 use ax_product, only : ax_t
39 use field, only : field_t
40 use coefs, only : coef_t
41 use gather_scatter, only : gs_t, gs_op_add
45 use math, only : abscmp
47 use mpi_f08, only : mpi_allreduce, mpi_in_place, mpi_sum
48 use utils, only : neko_error
49 use operators, only : rotate_cyc
50 implicit none
51 private
52
59 type, public, extends(ksp_t) :: cg_cpld_t
61 real(kind=rp), pointer :: w1(:) => null()
63 real(kind=rp), pointer :: w2(:) => null()
65 real(kind=rp), pointer :: w3(:) => null()
67 real(kind=rp), pointer :: r1(:) => null()
69 real(kind=rp), pointer :: r2(:) => null()
71 real(kind=rp), pointer :: r3(:) => null()
73 real(kind=rp), pointer :: p1(:) => null()
75 real(kind=rp), pointer :: p2(:) => null()
77 real(kind=rp), pointer :: p3(:) => null()
79 real(kind=rp), pointer :: z1(:) => null()
81 real(kind=rp), pointer :: z2(:) => null()
83 real(kind=rp), pointer :: z3(:) => null()
84 contains
86 procedure, pass(this) :: init => cg_cpld_init
88 procedure, pass(this) :: free => cg_cpld_free
90 procedure, pass(this) :: solve => cg_cpld_nop
92 procedure, pass(this) :: solve_coupled => cg_cpld_solve
93 end type cg_cpld_t
94
95contains
96
105 subroutine cg_cpld_init(this, n, max_iter, M, rel_tol, abs_tol, monitor)
106 class(cg_cpld_t), target, intent(inout) :: this
107 integer, intent(in) :: max_iter
108 class(pc_t), optional, intent(in), target :: M
109 integer, intent(in) :: n
110 real(kind=rp), optional, intent(in) :: rel_tol
111 real(kind=rp), optional, intent(in) :: abs_tol
112 logical, optional, intent(in) :: monitor
113
114 call this%free()
115
116 if (present(m)) then
117 this%M => m
118 end if
119
120 if (present(rel_tol) .and. present(abs_tol) .and. present(monitor)) then
121 call this%ksp_init(max_iter, rel_tol, abs_tol, monitor = monitor)
122 else if (present(rel_tol) .and. present(abs_tol)) then
123 call this%ksp_init(max_iter, rel_tol, abs_tol)
124 else if (present(monitor) .and. present(abs_tol)) then
125 call this%ksp_init(max_iter, abs_tol = abs_tol, monitor = monitor)
126 else if (present(rel_tol) .and. present(monitor)) then
127 call this%ksp_init(max_iter, rel_tol, monitor = monitor)
128 else if (present(rel_tol)) then
129 call this%ksp_init(max_iter, rel_tol = rel_tol)
130 else if (present(abs_tol)) then
131 call this%ksp_init(max_iter, abs_tol = abs_tol)
132 else if (present(monitor)) then
133 call this%ksp_init(max_iter, monitor = monitor)
134 else
135 call this%ksp_init(max_iter)
136 end if
137
138 end subroutine cg_cpld_init
139
141 subroutine cg_cpld_free(this)
142 class(cg_cpld_t), intent(inout) :: this
143
144 call this%ksp_free()
145
146 nullify(this%w1, this%w2, this%w3)
147 nullify(this%r1, this%r2, this%r3)
148 nullify(this%p1, this%p2, this%p3)
149 nullify(this%z1, this%z2, this%z3)
150
151 nullify(this%M)
152
153 end subroutine cg_cpld_free
154
165 function cg_cpld_nop(this, Ax, x, f, n, coef, bc_projector, gs_h, niter) &
166 result(ksp_results)
167 class(cg_cpld_t), intent(inout) :: this
168 class(ax_t), intent(in) :: ax
169 type(field_t), intent(inout) :: x
170 integer, intent(in) :: n
171 real(kind=rp), dimension(n), intent(in) :: f
172 type(coef_t), intent(inout) :: coef
173 class(scalar_bc_projector_t), intent(inout) :: bc_projector
174 type(gs_t), intent(inout) :: gs_h
175 type(ksp_monitor_t) :: ksp_results
176 integer, optional, intent(in) :: niter
177
178 call neko_error('The cpldcg solver is only defined for coupled solves')
179
180 ksp_results%res_final = 0.0
181 ksp_results%iter = 0
182 end function cg_cpld_nop
183
203 function cg_cpld_solve(this, Ax, x, y, z, fx, fy, fz, &
204 n, coef, bc_projector, gs_h, niter) result(ksp_results)
205 class(cg_cpld_t), intent(inout) :: this
206 class(ax_t), intent(in) :: ax
207 type(field_t), intent(inout) :: x
208 type(field_t), intent(inout) :: y
209 type(field_t), intent(inout) :: z
210 integer, intent(in) :: n
211 real(kind=rp), dimension(n), intent(in) :: fx
212 real(kind=rp), dimension(n), intent(in) :: fy
213 real(kind=rp), dimension(n), intent(in) :: fz
214 type(coef_t), intent(inout) :: coef
215 class(vector_bc_projector_t), intent(inout) :: bc_projector
216 type(gs_t), intent(inout) :: gs_h
217 type(ksp_monitor_t), dimension(3) :: ksp_results
218 integer, optional, intent(in) :: niter
219 integer :: i, iter, max_iter, ierr
220 real(kind=rp) :: rnorm, rtr, rtr0, rtz2, rtz1
221 real(kind=rp) :: beta, pap, alpha, norm_fac
222 real(kind=xp) :: tmp_xp, r1_xp, r2_xp, r3_xp, mult_xp
223 integer :: temp_indices(12)
224
225 if (present(niter)) then
226 max_iter = niter
227 else
228 max_iter = this%max_iter
229 end if
230 norm_fac = 1.0_rp / sqrt(coef%volume)
231
232 call neko_scratch_registry%request(this%w1, temp_indices(1), n, .false.)
233 call neko_scratch_registry%request(this%w2, temp_indices(2), n, .false.)
234 call neko_scratch_registry%request(this%w3, temp_indices(3), n, .false.)
235 call neko_scratch_registry%request(this%r1, temp_indices(4), n, .false.)
236 call neko_scratch_registry%request(this%r2, temp_indices(5), n, .false.)
237 call neko_scratch_registry%request(this%r3, temp_indices(6), n, .false.)
238 call neko_scratch_registry%request(this%p1, temp_indices(7), n, .false.)
239 call neko_scratch_registry%request(this%p2, temp_indices(8), n, .false.)
240 call neko_scratch_registry%request(this%p3, temp_indices(9), n, .false.)
241 call neko_scratch_registry%request(this%z1, temp_indices(10), n, .false.)
242 call neko_scratch_registry%request(this%z2, temp_indices(11), n, .false.)
243 call neko_scratch_registry%request(this%z3, temp_indices(12), n, .false.)
244
245 associate(p1 => this%p1, p2 => this%p2, p3 => this%p3, z1 => this%z1, &
246 z2 => this%z2, z3 => this%z3, r1 => this%r1, r2 => this%r2, &
247 r3 => this%r3, w1 => this%w1, w2 => this%w2, w3 => this%w3)
248
249 rtz1 = 1.0_rp
250 tmp_xp = 0.0_xp
251 !$omp parallel do reduction(+:tmp_xp)
252 do i = 1, n
253 x%x(i,1,1,1) = 0.0_rp
254 y%x(i,1,1,1) = 0.0_rp
255 z%x(i,1,1,1) = 0.0_rp
256 p1(i) = 0.0_rp
257 p2(i) = 0.0_rp
258 p3(i) = 0.0_rp
259 z1(i) = 0.0_rp
260 z2(i) = 0.0_rp
261 z3(i) = 0.0_rp
262 r1(i) = fx(i)
263 r2(i) = fy(i)
264 r3(i) = fz(i)
265 tmp_xp = tmp_xp + (r1(i)**2 + r2(i)**2 + r3(i)**2) &
266 * coef%mult(i,1,1,1)
267 end do
268 !$omp end parallel do
269
270 call mpi_allreduce(mpi_in_place, tmp_xp, 1, mpi_extra_precision, &
271 mpi_sum, neko_comm, ierr)
272 rtr = tmp_xp
273 rnorm = sqrt(rtr)*norm_fac
274 ksp_results%res_start = rnorm
275 ksp_results%res_final = rnorm
276 ksp_results%iter = 0
277 if (abscmp(rnorm, 0.0_rp)) then
278 ksp_results%converged = .true.
279 nullify(this%w1, this%w2, this%w3)
280 nullify(this%r1, this%r2, this%r3)
281 nullify(this%p1, this%p2, this%p3)
282 nullify(this%z1, this%z2, this%z3)
283 call neko_scratch_registry%relinquish_host_array(temp_indices)
284 return
285 end if
286
287 call this%monitor_start('cpldCG')
288 do iter = 1, max_iter
289 call this%M%solve(z1, this%r1, n)
290 call this%M%solve(z2, this%r2, n)
291 call this%M%solve(z3, this%r3, n)
292 rtz2 = rtz1
293
294 tmp_xp = 0.0_xp
295 !$omp parallel do reduction(+:tmp_xp)
296 do i = 1, n
297 tmp_xp = tmp_xp + (z1(i) * r1(i) &
298 + z2(i) * r2(i) &
299 + z3(i) * r3(i)) * coef%mult(i,1,1,1)
300 end do
301 !$omp end parallel do
302
303 call mpi_allreduce(mpi_in_place, tmp_xp, 1, mpi_extra_precision, &
304 mpi_sum, neko_comm, ierr)
305 rtz1 = tmp_xp
306
307 beta = rtz1 / rtz2
308 if (iter .eq. 1) beta = 0.0_rp
309 !$omp parallel do
310 do i = 1, n
311 p1(i) = p1(i) * beta + z1(i)
312 p2(i) = p2(i) * beta + z2(i)
313 p3(i) = p3(i) * beta + z3(i)
314 end do
315 !$omp end parallel do
316
317 call ax%compute_vector(w1, w2, w3, p1, p2, p3, coef, x%msh, x%Xh)
318
319 call rotate_cyc(w1, w2, w3, 1, coef)
320 call gs_h%op(w1, w2, w3, n, gs_op_add)
321 call rotate_cyc(w1, w2, w3, 0, coef)
322
323 call bc_projector%apply(w1, w2, w3, n)
324
325 tmp_xp = 0.0_xp
326 !$omp parallel do reduction(+:tmp_xp)
327 do i = 1, n
328 tmp_xp = tmp_xp + (w1(i) * p1(i) &
329 + w2(i) * p2(i) &
330 + w3(i) * p3(i)) * coef%mult(i,1,1,1)
331 end do
332 !$omp end parallel do
333
334 call mpi_allreduce(mpi_in_place, tmp_xp, 1, mpi_extra_precision, &
335 mpi_sum, neko_comm, ierr)
336 pap = tmp_xp
337
338 alpha = rtz1 / pap
339 tmp_xp = 0.0_xp
340
341 !$omp parallel private (i, r1_xp, r2_xp, r3_xp, mult_xp)
342 !$omp do
343 do i = 1, n
344 x%x(i,1,1,1) = x%x(i,1,1,1) + alpha * p1(i)
345 y%x(i,1,1,1) = y%x(i,1,1,1) + alpha * p2(i)
346 z%x(i,1,1,1) = z%x(i,1,1,1) + alpha * p3(i)
347 end do
348 !$omp end do nowait
349
350 !$omp do reduction(+:tmp_xp)
351 do i = 1, n
352 r1(i) = r1(i) - alpha * w1(i)
353 r2(i) = r2(i) - alpha * w2(i)
354 r3(i) = r3(i) - alpha * w3(i)
355 r1_xp = real(r1(i), kind=xp)
356 r2_xp = real(r2(i), kind=xp)
357 r3_xp = real(r3(i), kind=xp)
358 mult_xp = real(coef%mult(i,1,1,1), kind=xp)
359 tmp_xp = tmp_xp + &
360 (r1_xp * r1_xp + r2_xp * r2_xp + r3_xp * r3_xp) * mult_xp
361 end do
362 !$omp end do nowait
363 !$omp end parallel
364
365 call mpi_allreduce(mpi_in_place, tmp_xp, 1, mpi_extra_precision, &
366 mpi_sum, neko_comm, ierr)
367 rtr = tmp_xp
368
369 if (iter .eq. 1) rtr0 = rtr
370 rnorm = sqrt(rtr) * norm_fac
371 call this%monitor_iter(iter, rnorm)
372 if (rnorm .lt. this%abs_tol) then
373 exit
374 end if
375 end do
376 end associate
377 nullify(this%w1, this%w2, this%w3)
378 nullify(this%r1, this%r2, this%r3)
379 nullify(this%p1, this%p2, this%p3)
380 nullify(this%z1, this%z2, this%z3)
381 call neko_scratch_registry%relinquish_host_array(temp_indices)
382 call this%monitor_stop()
383 ksp_results%res_final = rnorm
384 ksp_results%iter = iter
385 ksp_results%converged = this%is_converged(iter, rnorm)
386 end function cg_cpld_solve
387
388end module cg_cpld
__device__ T solve(const T u, const T y, const T guess, const T nu, const T kappa, const T B)
double real
Apply cyclic boundary condition to a vector field.
Defines a Matrix-vector product.
Definition ax.f90:34
Defines a coupled Conjugate Gradient method.
type(ksp_monitor_t) function cg_cpld_nop(this, ax, x, f, n, coef, bc_projector, gs_h, niter)
Reject scalar solves, which are not supported by this type.
type(ksp_monitor_t) function, dimension(3) cg_cpld_solve(this, ax, x, y, z, fx, fy, fz, n, coef, bc_projector, gs_h, niter)
Solve a three-component coupled system with the CPU PCG method.
subroutine cg_cpld_free(this)
Free a coupled CPU PCG solver.
subroutine cg_cpld_init(this, n, max_iter, m, rel_tol, abs_tol, monitor)
Initialise a coupled CPU PCG solver.
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.
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
integer, parameter, public xp
Definition num_types.f90:16
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:14
Operators.
Definition operators.f90:34
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.
Utilities.
Definition utils.f90:35
Implements boundary condition projectors for vector fields. Two types concrete types are provided: se...
Base type for a matrix-vector product providing .
Definition ax.f90:44
CPU implementation of the coupled preconditioned conjugate gradient method.
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.