FE-Project
Loading...
Searching...
No Matches
scale_linalgebra Module Reference

Module common / Linear algebra. More...

Data Types

interface  linalgebra_solvelineq
 Solve a linear equation Ax=b using a direct solver. More...

Functions/Subroutines

real(rp) function, dimension(size(a, 1), size(a, 2)), public linalgebra_inv (a)
 Calculate a inversion of matrix A.
subroutine, public linalgebra_lu (a_lu, ipiv)
 Perform LU factorization.
subroutine, public linalgebra_solvelineq_bndmat (a, b, ipiv, n, kl, ku, nrhs, use_lapack)
 Calculate the solution of linear equations with a band matrix.
subroutine, public linalgebra_solvelineq_gmres (a, b, x, m, restart_num, conv_crit)
 Solve a linear equation Ax=b using the Generalized Minimal Residual solver (GMRES)

Detailed Description

Module common / Linear algebra.

Description
A module to provide utilities for linear algebra
Reference
Author
Yuta Kawai, Team SCALE

Function/Subroutine Documentation

◆ linalgebra_inv()

real(rp) function, dimension(size(a,1),size(a,2)), public scale_linalgebra::linalgebra_inv ( real(rp), dimension(:,:), intent(in) a)

Calculate a inversion of matrix A.

Parameters
[in]aMatrix A
Returns
Result of matrix inversion

Definition at line 76 of file scale_linalgebra.F90.

77 implicit none
78 real(RP), intent(in) :: A(:,:) !< Matrix A
79 real(RP) :: Ainv(size(A,1),size(A,2)) !< Result of matrix inversion
80
81 real(RP) :: work(size(A,1))
82 integer :: ipiv(size(A,1))
83 integer :: n, info
84
85 !---------------------------------------------------------------------------
86
87 ainv(:,:) = a
88 n = size(a,1)
89
90 call dgetrf(n, n, ainv, n, ipiv, info)
91 if (info /=0 ) then
92 log_error("linalgebra_inv",*) "Matrix is singular"
93 call prc_abort
94 end if
95
96 call dgetri(n, ainv, n, ipiv, work, n, info)
97 if (info /=0 ) then
98 log_error("linalgebra_inv",*) "Matrix inversion is failed"
99 call prc_abort
100 end if
101
102 return

Referenced by scale_element_base::elementbase_construct_massmat(), get_pmatd_lu(), scale_element_hexahedral::hexhedralelement_init(), scale_element_line::lineelement_init(), and scale_element_quadrilateral::quadrilateralelement_init().

◆ linalgebra_lu()

subroutine, public scale_linalgebra::linalgebra_lu ( real(rp), dimension(:,:), intent(inout) a_lu,
integer, dimension(size(a_lu,1)), intent(out) ipiv )

Perform LU factorization.

Definition at line 173 of file scale_linalgebra.F90.

174 implicit none
175 real(RP), intent(inout) :: A_lu(:,:) !> Matrix performed LU factorization. Note that original matrix is overwritten.
176 integer, intent(out) :: ipiv(size(A_lu,1)) !> Array storing the pivoting information
177
178 integer :: n
179 integer :: info
180
181 !---------------------------------------------------------------------------
182 n = size(a_lu,1)
183
184 call dgetrf(n, n, a_lu, n, ipiv, info)
185 if (info /=0 ) then
186 log_error("linalgebra_LU",*) "Matrix is singular"
187 call prc_abort
188 end if
189
190 return

Referenced by scale_atm_dyn_dgm_nonhydro3d_hevi_gmres::atm_dyn_dgm_nonhydro3d_hevi_cal_vi(), get_pmatd_lu(), and scale_atm_dyn_dgm_hydrostatic::hydrostaic_build_rho_xyz::hydrostaic_build_rho_xyz_moist().

◆ linalgebra_solvelineq_bndmat()

subroutine, public scale_linalgebra::linalgebra_solvelineq_bndmat ( real(rp), dimension(2*kl+ku+1,n), intent(inout) a,
real(rp), dimension(n,nrhs), intent(inout) b,
integer, dimension(n), intent(out) ipiv,
integer, intent(in) n,
integer, intent(in) kl,
integer, intent(in) ku,
integer, intent(in) nrhs,
logical, intent(in), optional use_lapack )

Calculate the solution of linear equations with a band matrix.

In this module, we treat a linear equations system, A * X = B where A is a band matrix of order N with KL subdiagonals and KU superdiagonals, and X and B are matrices whose size is N * NRHS.

Parameters
AMatrix A in band storage same as in dgbsv of LAPACK
bRight hand side matrix B with N-by-RHS
ipivPivot indices that define the permutation matrix
KLNumber of subdiagonals within the band of A
KUNumber of superdiagonals within the band of A
NRHSNumber of right hand sides
use_lapackFlag whether LAPACK is used

Definition at line 208 of file scale_linalgebra.F90.

210 implicit none
211 integer, intent(in) :: N
212 integer, intent(in) :: KL
213 integer, intent(in) :: KU
214 integer, intent(in) :: NRHS
215 real(RP), intent(inout) :: A(2*KL+KU+1,N)
216 real(RP), intent(inout) :: b(N,NRHS)
217 integer, intent(out) :: ipiv(N)
218 logical, intent(in), optional :: use_lapack
219
220 integer :: i, j, l, lm, p
221 integer :: km
222 integer :: ju, jp
223 integer :: KV
224 real(RP) :: tmp
225 integer :: LDA, LDB
226 logical :: use_lapack_
227
228 integer :: info
229 !---------------------------------------------------------------------------
230
231 if (present(use_lapack)) then
232 use_lapack_ = use_lapack
233 else
234 use_lapack_ = .false.
235 end if
236
237 if ( use_lapack_ ) then
238 call dgbsv( n, kl, ku, nrhs, a, 2*kl+ku+1, ipiv, b, n, info)
239 return
240 end if
241
242 !--
243 kv = kl + ku
244 lda = size(a,1)
245 ldb = size(b,1)
246
247 do j=ku+2, min(kv, n)
248 do i=kv-j+2, kl
249 a(i,j) = 0.0_rp
250 end do
251 end do
252
253 ju = 1
254 do j=1, n
255 if ( j+kv <= n ) then
256 do i=1, kl
257 a(i,j+kv) = 0.0_rp
258 end do
259 end if
260
261 km = min(kl, n-j)
262 call my_idamax( km+1, a(kv+1,j), &
263 jp )
264 ipiv(j) = jp + j - 1
265
266 if ( a(kv+jp,j) /= 0.0_rp ) then
267 ju = max( ju, min(j+ku+jp-1,n) )
268
269 if ( jp /= 1 ) then
270 call my_swap( ju-j+1, a(kv+jp,j), lda-1, &
271 a(kv +1,j), lda-1 )
272 end if
273
274 if ( km > 0 ) then
275 tmp = 1.0_rp / a(kv+1,j)
276 do l=kv+2, kv+1+km
277 a(l,j) = tmp * a(l,j)
278 end do
279 call my_dger( km, ju-j, &
280 a(kv+2,j ), &
281 a(kv ,j+1), lda-1, &
282 a(kv+1,j+1), lda-1 )
283 end if
284 end if
285 end do
286
287 !--
288 ! Solve L*X = B, overwriting B with X
289
290 if ( kl > 0 ) then
291 do j=1, n-1
292 lm = min( kl, n-j )
293 l = ipiv(j)
294 if ( l /= j ) call my_swap( nrhs, b(l,1), ldb, b(j,1), ldb )
295 call my_dger( lm, nrhs, &
296 a(kv+2,j), &
297 b(j ,1), ldb, &
298 b(j+1,1), ldb )
299 end do
300 end if
301
302 !--
303 ! Solve U*X = B, overwriting B with X
304 do p=1, nrhs
305 do j=n, 1, -1
306 l = kv + 1 - j
307 b(j,p) = b(j,p) / a(kv+1,j)
308 tmp = b(j,p)
309 do i=j-1, max(1,j-kv),-1
310 b(i,p) = b(i,p) - tmp * a(l+i,j)
311 end do
312 end do
313 end do
314
315 return

Referenced by scale_atm_dyn_dgm_globalnonhydro3d_rhot_hevi::atm_dyn_dgm_globalnonhydro3d_rhot_hevi_cal_vi_asis(), scale_atm_dyn_dgm_nonhydro3d_rhot_hevi::atm_dyn_dgm_nonhydro3d_rhot_hevi_cal_vi_asis(), and scale_atm_dyn_dgm_nonhydro3d_rhot_hevi_splitform::atm_dyn_dgm_nonhydro3d_rhot_hevi_splitform_cal_vi().

◆ linalgebra_solvelineq_gmres()

subroutine, public scale_linalgebra::linalgebra_solvelineq_gmres ( type(sparsemat), intent(in) a,
real(rp), dimension(:), intent(in) b,
real(rp), dimension(:), intent(inout) x,
integer, intent(in) m,
integer, intent(in) restart_num,
real(rp), intent(in) conv_crit )

Solve a linear equation Ax=b using the Generalized Minimal Residual solver (GMRES)

Parameters
[in]aObject managing sparse matrix A
[in]bRight hand side vector
[in,out]xSolution vector
[in]restart_numNumber of times by which restarting is performed if convergence condition is not satisfied
[in]conv_critThreshold for finishing the iteration solver

Definition at line 320 of file scale_linalgebra.F90.

322 implicit none
323
324 type(SparseMat), intent(in) :: A !< Object managing sparse matrix A
325 real(RP), intent(in) :: b(:) !< Right hand side vector
326 real(RP), intent(inout) :: x(:) !< Solution vector
327 integer, intent(in) :: m !<
328 integer, intent(in) ::restart_num !< Number of times by which restarting is performed if convergence condition is not satisfied
329 real(RP), intent(in) :: CONV_CRIT !< Threshold for finishing the iteration solver
330
331 real(RP) :: x0(size(x))
332 real(RP) :: w(size(x))
333 real(RP) :: v(size(x),m+1)
334 real(RP) :: z(size(x),m+1)
335 real(RP) :: Av(size(x))
336 real(RP) :: g(size(x)+1)
337 real(RP) :: r0_l2, r0_l2_new
338 real(RP) :: h(m+1,m)
339 real(RP) :: r(m,m)
340 real(RP) :: c(m), s(m)
341 real(RP) :: y(m)
342 real(RP) :: tmp, tmp1, tmp2
343 integer :: i, j
344 integer :: restart_i
345
346 type(SparseMat) :: M_PC
347
348 !---------------------------------------------------------------------------
349
350 call precondstep_ilu0_constructmat(a, m_pc)
351 x0(:) = x
352
353 do restart_i=1, restart_num
354
355 if (restart_i == 1) then
356 call sparsemat_matmul(a, x, av)
357 v(:,1) = b - av
358 r0_l2 = sqrt(sum(v(:,1)**2))
359 end if
360 v(:,1) = v(:,1)/r0_l2
361 g(1) = r0_l2
362
363 do j=1, m
364
365 call precondstep_ilu0_solve(m_pc, v(:,j), z(:,j))
366
367 call sparsemat_matmul(a, z(:,j), w)
368
369 do i=1, j
370 h(i,j) = sum(w*v(:,i))
371 w(:) = w - h(i,j)*v(:,i)
372 end do
373 h(j+1,j) = sqrt(sum(w**2))
374 v(:,j+1) = w(:)/h(j+1,j)
375
376 r(1,j) = h(1,j)
377 do i=1, j-1
378 tmp1 = c(i)*r(i,j) + s(i)*h(i+1,j)
379 tmp2 = -s(i)*r(i,j) + c(i)*h(i+1,j)
380 r(i,j) = tmp1
381 r(i+1,j) = tmp2
382 end do
383
384 tmp = sqrt(r(j,j)**2 + h(j+1,j)**2)
385 c(j) = r(j,j)/tmp
386 s(j) = h(j+1,j)/tmp
387
388 g(j+1) = -s(j)*g(j)
389 g(j) = c(j)*g(j)
390 r(j,j) = c(j)*r(j,j) + s(j)*h(j+1,j)
391 end do
392
393 y(m) = g(m)/r(m,m)
394 do i=m-1,1,-1
395 y(i) = (g(i) - sum(r(i,i+1:m)*y(i+1:m)))/r(i,i)
396 end do
397
398 x(:) = x + matmul(z(:,1:m),y)
399
400 !write(*,*) "x:", x
401 !write(*,*) "x0:", x0
402
403 call sparsemat_matmul(a, x, av)
404 v(:,1) = b - av
405 r0_l2_new = sqrt(sum(v(:,1)**2))
406
407 !write(*,*) "r:", r0_l2, "->", r0_l2_new
408 if (r0_l2_new < conv_crit) exit
409 r0_l2 = r0_l2_new
410 end do
411
412 return
Module common / sparsemat.

References scale_sparsemat::sparsemat_storage_typeid_csr.