Neko 1.99.9
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
pipecg.f90
Go to the documentation of this file.
1! Copyright (c) 2021-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 pipecg
35 use neko_config, only : neko_blk_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, abscmp
48 use mpi_f08, only : mpi_iallreduce, mpi_in_place, mpi_sum, mpi_wait, &
49 mpi_request, mpi_status
50 implicit none
51 private
52
53 integer, parameter :: pipecg_p_space = 7
54
56 type, public, extends(ksp_t) :: pipecg_t
57 real(kind=rp), allocatable :: p(:)
58 real(kind=rp), allocatable :: q(:)
59 real(kind=rp), allocatable :: r(:)
60 real(kind=rp), allocatable :: s(:)
61 real(kind=rp), allocatable :: u(:,:)
62 real(kind=rp), allocatable :: w(:)
63 real(kind=rp), allocatable :: z(:)
64 real(kind=rp), allocatable :: mi(:)
65 real(kind=rp), allocatable :: ni(:)
66 contains
68 procedure, pass(this) :: init => pipecg_init
70 procedure, pass(this) :: free => pipecg_free
72 procedure, pass(this) :: solve => pipecg_solve
74 procedure, pass(this) :: solve_coupled => pipecg_solve_coupled
75 end type pipecg_t
76
77contains
78
80 subroutine pipecg_init(this, n, max_iter, M, rel_tol, abs_tol, monitor)
81 class(pipecg_t), target, intent(inout) :: this
82 integer, intent(in) :: max_iter
83 class(pc_t), optional, intent(in), target :: M
84 integer, intent(in) :: n
85 real(kind=rp), optional, intent(in) :: rel_tol
86 real(kind=rp), optional, intent(in) :: abs_tol
87 logical, optional, intent(in) :: monitor
88
89 call this%free()
90
91 allocate(this%p(n))
92 allocate(this%q(n))
93 allocate(this%r(n))
94 allocate(this%s(n))
95 allocate(this%u(n,pipecg_p_space+1))
96 allocate(this%w(n))
97 allocate(this%z(n))
98 allocate(this%mi(n))
99 allocate(this%ni(n))
100 if (present(m)) then
101 this%M => m
102 end if
103
104 if (present(rel_tol) .and. present(abs_tol) .and. present(monitor)) then
105 call this%ksp_init(max_iter, rel_tol, abs_tol, monitor = monitor)
106 else if (present(rel_tol) .and. present(abs_tol)) then
107 call this%ksp_init(max_iter, rel_tol, abs_tol)
108 else if (present(monitor) .and. present(abs_tol)) then
109 call this%ksp_init(max_iter, abs_tol = abs_tol, monitor = monitor)
110 else if (present(rel_tol) .and. present(monitor)) then
111 call this%ksp_init(max_iter, rel_tol, monitor = monitor)
112 else if (present(rel_tol)) then
113 call this%ksp_init(max_iter, rel_tol = rel_tol)
114 else if (present(abs_tol)) then
115 call this%ksp_init(max_iter, abs_tol = abs_tol)
116 else if (present(monitor)) then
117 call this%ksp_init(max_iter, monitor = monitor)
118 else
119 call this%ksp_init(max_iter)
120 end if
121
122 end subroutine pipecg_init
123
125 subroutine pipecg_free(this)
126 class(pipecg_t), intent(inout) :: this
127
128 call this%ksp_free()
129
130 if (allocated(this%p)) then
131 deallocate(this%p)
132 end if
133 if (allocated(this%q)) then
134 deallocate(this%q)
135 end if
136 if (allocated(this%r)) then
137 deallocate(this%r)
138 end if
139 if (allocated(this%s)) then
140 deallocate(this%s)
141 end if
142 if (allocated(this%u)) then
143 deallocate(this%u)
144 end if
145 if (allocated(this%w)) then
146 deallocate(this%w)
147 end if
148 if (allocated(this%z)) then
149 deallocate(this%z)
150 end if
151 if (allocated(this%mi)) then
152 deallocate(this%mi)
153 end if
154 if (allocated(this%ni)) then
155 deallocate(this%ni)
156 end if
157
158 nullify(this%M)
159
160
161 end subroutine pipecg_free
162
164 function pipecg_solve(this, Ax, x, f, n, coef, bc_projector, gs_h, niter) &
165 result(ksp_results)
166 class(pipecg_t), intent(inout) :: this
167 class(ax_t), intent(in) :: ax
168 type(field_t), intent(inout) :: x
169 integer, intent(in) :: n
170 real(kind=rp), dimension(n), intent(in) :: f
171 type(coef_t), intent(inout) :: coef
172 class(scalar_bc_projector_t), intent(inout) :: bc_projector
173 type(gs_t), intent(inout) :: gs_h
174 type(ksp_monitor_t) :: ksp_results
175 integer, optional, intent(in) :: niter
176 integer :: iter, max_iter, i, j, k, ierr, p_cur, p_prev, u_prev
177 real(kind=rp) :: rnorm, rtr, reduction(3), norm_fac
178 real(kind=rp) :: alpha(pipecg_p_space), beta(pipecg_p_space)
179 real(kind=rp) :: gamma1, gamma2, delta
180 real(kind=rp) :: tmp1, tmp2, tmp3, x_plus(neko_blk_size)
181 type(mpi_request) :: request
182 type(mpi_status) :: status
183
184 if (present(niter)) then
185 max_iter = niter
186 else
187 max_iter = this%max_iter
188 end if
189 norm_fac = 1.0_rp / sqrt(coef%volume)
190
191 associate(p => this%p, q => this%q, r => this%r, s => this%s, &
192 u => this%u, w => this%w, z => this%z, mi => this%mi, ni => this%ni)
193
194 p_prev = pipecg_p_space
195 u_prev = pipecg_p_space+1
196 p_cur = 1
197 !$omp parallel do
198 do i = 1, n
199 x%x(i,1,1,1) = 0.0_rp
200 z(i) = 0.0_rp
201 q(i) = 0.0_rp
202 p(i) = 0.0_rp
203 s(i) = 0.0_rp
204 r(i) = f(i)
205 end do
206 !$omp end parallel do
207 call this%M%solve(u(1,u_prev), r, n)
208 call ax%compute(w, u(1,u_prev), coef, x%msh, x%Xh)
209 call gs_h%op(w, n, gs_op_add)
210 call bc_projector%apply(w, n)
211
212 rtr = glsc3(r, coef%mult, r, n)
213 rnorm = sqrt(rtr)*norm_fac
214 ksp_results%res_start = rnorm
215 ksp_results%res_final = rnorm
216 ksp_results%iter = 0
217
218 if(abscmp(rnorm, 0.0_rp)) then
219 ksp_results%converged = .true.
220 return
221 end if
222
223 gamma1 = 0.0_rp
224 tmp1 = 0.0_rp
225 tmp2 = 0.0_rp
226 tmp3 = 0.0_rp
227 !$omp parallel do reduction(+:tmp1,tmp2,tmp3)
228 do i = 1, n
229 tmp1 = tmp1 + r(i) * coef%mult(i,1,1,1) * u(i,u_prev)
230 tmp2 = tmp2 + w(i) * coef%mult(i,1,1,1) * u(i,u_prev)
231 tmp3 = tmp3 + r(i) * coef%mult(i,1,1,1) * r(i)
232 end do
233 !$omp end parallel do
234 reduction(1) = tmp1
235 reduction(2) = tmp2
236 reduction(3) = tmp3
237
238 call this%monitor_start('PipeCG')
239 do iter = 1, max_iter
240 call mpi_iallreduce(mpi_in_place, reduction, 3, &
241 mpi_real_precision, mpi_sum, neko_comm, request, ierr)
242
243 call this%M%solve(mi, w, n)
244 call ax%compute(ni, mi, coef, x%msh, x%Xh)
245 call gs_h%op(ni, n, gs_op_add)
246 call bc_projector%apply(ni, n)
247
248 call mpi_wait(request, status, ierr)
249 gamma2 = gamma1
250 gamma1 = reduction(1)
251 delta = reduction(2)
252 rtr = reduction(3)
253
254 rnorm = sqrt(rtr)*norm_fac
255 call this%monitor_iter(iter, rnorm)
256 if (rnorm .lt. this%abs_tol) exit
257
258 if (iter .gt. 1) then
259 beta(p_cur) = gamma1 / gamma2
260 alpha(p_cur) = gamma1 / (delta - (beta(p_cur) * gamma1/alpha(p_prev)))
261 else
262 beta(p_cur) = 0.0_rp
263 alpha(p_cur) = gamma1/delta
264 end if
265
266 tmp1 = 0.0_rp
267 tmp2 = 0.0_rp
268 tmp3 = 0.0_rp
269 !$omp parallel do private(k) reduction(+:tmp1,tmp2,tmp3)
270 do i = 0, n-1, neko_blk_size
271 if (i + neko_blk_size .le. n) then
272 !$omp simd reduction(+:tmp1,tmp2,tmp3)
273 do k = 1, neko_blk_size
274 z(i+k) = beta(p_cur) * z(i+k) + ni(i+k)
275 q(i+k) = beta(p_cur) * q(i+k) + mi(i+k)
276 s(i+k) = beta(p_cur) * s(i+k) + w(i+k)
277 r(i+k) = r(i+k) - alpha(p_cur) * s(i+k)
278 u(i+k,p_cur) = u(i+k,u_prev) - alpha(p_cur) * q(i+k)
279 w(i+k) = w(i+k) - alpha(p_cur) * z(i+k)
280 tmp1 = tmp1 + r(i+k) * coef%mult(i+k,1,1,1) * u(i+k,p_cur)
281 tmp2 = tmp2 + w(i+k) * coef%mult(i+k,1,1,1) * u(i+k,p_cur)
282 tmp3 = tmp3 + r(i+k) * coef%mult(i+k,1,1,1) * r(i+k)
283 end do
284 else
285 do k = 1, n - i
286 z(i+k) = beta(p_cur) * z(i+k) + ni(i+k)
287 q(i+k) = beta(p_cur) * q(i+k) + mi(i+k)
288 s(i+k) = beta(p_cur) * s(i+k) + w(i+k)
289 r(i+k) = r(i+k) - alpha(p_cur) * s(i+k)
290 u(i+k,p_cur) = u(i+k,u_prev) - alpha(p_cur) * q(i+k)
291 w(i+k) = w(i+k) - alpha(p_cur) * z(i+k)
292 tmp1 = tmp1 + r(i+k) * coef%mult(i+k,1,1,1) * u(i+k,p_cur)
293 tmp2 = tmp2 + w(i+k) * coef%mult(i+k,1,1,1) * u(i+k,p_cur)
294 tmp3 = tmp3 + r(i+k) * coef%mult(i+k,1,1,1) * r(i+k)
295 end do
296 end if
297 end do
298 !$omp end parallel do
299 reduction(1) = tmp1
300 reduction(2) = tmp2
301 reduction(3) = tmp3
302
303 if (p_cur .eq. pipecg_p_space) then
304 !$omp parallel do private(k, j, p_prev, x_plus)
305 do i = 0, n-1, neko_blk_size
306 if (i + neko_blk_size .le. n) then
307 !$omp simd
308 do k = 1, neko_blk_size
309 x_plus(k) = 0.0_rp
310 end do
311 p_prev = pipecg_p_space+1
312 do j = 1, p_cur
313 !$omp simd
314 do k = 1, neko_blk_size
315 p(i+k) = beta(j) * p(i+k) + u(i+k,p_prev)
316 x_plus(k) = x_plus(k) + alpha(j) * p(i+k)
317 end do
318 p_prev = j
319 end do
320 !$omp simd
321 do k = 1, neko_blk_size
322 x%x(i+k,1,1,1) = x%x(i+k,1,1,1) + x_plus(k)
323 u(i+k,pipecg_p_space+1) = u(i+k,pipecg_p_space)
324 end do
325 else
326 do k = 1, n - i
327 x_plus(k) = 0.0_rp
328 end do
329 p_prev = pipecg_p_space+1
330 do j = 1, p_cur
331 do k = 1, n - i
332 p(i+k) = beta(j) * p(i+k) + u(i+k,p_prev)
333 x_plus(k) = x_plus(k) + alpha(j) * p(i+k)
334 end do
335 p_prev = j
336 end do
337 do k = 1, n - i
338 x%x(i+k,1,1,1) = x%x(i+k,1,1,1) + x_plus(k)
339 u(i+k,pipecg_p_space+1) = u(i+k,pipecg_p_space)
340 end do
341 end if
342 end do
343 !$omp end parallel do
344 p_prev = p_cur
345 u_prev = pipecg_p_space+1
346 alpha(1) = alpha(p_cur)
347 beta(1) = beta(p_cur)
348 p_cur = 1
349 else
350 u_prev = p_cur
351 p_prev = p_cur
352 p_cur = p_cur + 1
353 end if
354 end do
355
356 if ( p_cur .ne. 1) then
357 !$omp parallel do private(k, j, p_prev, x_plus)
358 do i = 0, n-1, neko_blk_size
359 if (i + neko_blk_size .le. n) then
360 !$omp simd
361 do k = 1, neko_blk_size
362 x_plus(k) = 0.0_rp
363 end do
364 p_prev = pipecg_p_space+1
365 do j = 1, p_cur
366 !$omp simd
367 do k = 1, neko_blk_size
368 p(i+k) = beta(j) * p(i+k) + u(i+k,p_prev)
369 x_plus(k) = x_plus(k) + alpha(j) * p(i+k)
370 end do
371 p_prev = j
372 end do
373 !$omp simd
374 do k = 1, neko_blk_size
375 x%x(i+k,1,1,1) = x%x(i+k,1,1,1) + x_plus(k)
376 u(i+k,pipecg_p_space+1) = u(i+k,pipecg_p_space)
377 end do
378 else
379 do k = 1, n - i
380 x_plus(k) = 0.0_rp
381 end do
382 p_prev = pipecg_p_space+1
383 do j = 1, p_cur
384 do k = 1, n - i
385 p(i+k) = beta(j) * p(i+k) + u(i+k,p_prev)
386 x_plus(k) = x_plus(k) + alpha(j) * p(i+k)
387 end do
388 p_prev = j
389 end do
390 do k = 1, n - i
391 x%x(i+k,1,1,1) = x%x(i+k,1,1,1) + x_plus(k)
392 u(i+k,pipecg_p_space+1) = u(i+k,pipecg_p_space)
393 end do
394 end if
395 end do
396 !$omp end parallel do
397 end if
398 call this%monitor_stop()
399 ksp_results%res_final = rnorm
400 ksp_results%iter = iter
401 ksp_results%converged = this%is_converged(iter, rnorm)
402
403 end associate
404
405 end function pipecg_solve
406
408 function pipecg_solve_coupled(this, Ax, x, y, z, fx, fy, fz, &
409 n, coef, bc_projector, gs_h, niter) result(ksp_results)
410 class(pipecg_t), intent(inout) :: this
411 class(ax_t), intent(in) :: ax
412 type(field_t), intent(inout) :: x
413 type(field_t), intent(inout) :: y
414 type(field_t), intent(inout) :: z
415 integer, intent(in) :: n
416 real(kind=rp), dimension(n), intent(in) :: fx
417 real(kind=rp), dimension(n), intent(in) :: fy
418 real(kind=rp), dimension(n), intent(in) :: fz
419 type(coef_t), intent(inout) :: coef
420 class(vector_bc_projector_t), intent(inout) :: bc_projector
421 type(gs_t), intent(inout) :: gs_h
422 type(ksp_monitor_t), dimension(3) :: ksp_results
423 integer, optional, intent(in) :: niter
424 type(scalar_bc_projector_t), pointer :: bc_x, bc_y, bc_z
425
426 call vector_bc_projector_components(bc_projector, bc_x, bc_y, bc_z)
427 ksp_results(1) = this%solve(ax, x, fx, n, coef, bc_x, gs_h, niter)
428 ksp_results(2) = this%solve(ax, y, fy, n, coef, bc_y, gs_h, niter)
429 ksp_results(3) = this%solve(ax, z, fz, n, coef, bc_z, gs_h, niter)
430
431 end function pipecg_solve_coupled
432
433end module pipecg
__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.
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:1290
Build configurations.
integer, parameter neko_blk_size
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:14
Defines a pipelined Conjugate Gradient methods.
Definition pipecg.f90:34
subroutine pipecg_init(this, n, max_iter, m, rel_tol, abs_tol, monitor)
Initialise a pipelined PCG solver.
Definition pipecg.f90:81
subroutine pipecg_free(this)
Deallocate a pipelined PCG solver.
Definition pipecg.f90:126
integer, parameter pipecg_p_space
Definition pipecg.f90:53
type(ksp_monitor_t) function pipecg_solve(this, ax, x, f, n, coef, bc_projector, gs_h, niter)
Pipelined PCG solve.
Definition pipecg.f90:166
type(ksp_monitor_t) function, dimension(3) pipecg_solve_coupled(this, ax, x, y, z, fx, fy, fz, n, coef, bc_projector, gs_h, niter)
Pipelined PCG coupled solve.
Definition pipecg.f90:410
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.
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
Pipelined preconditioned conjugate gradient method.
Definition pipecg.f90:56
Defines a canonical Krylov preconditioner.
Definition precon.f90:40
Projector for scalar boundary conditions.
Abstract type for resolving vector boundary conditions.