7
7
submodule(stdlib_linalg_iterative_solvers) stdlib_linalg_iterative_pccg
8
8
use stdlib_kinds
9
9
use stdlib_sparse
10
+ use stdlib_linalg, only: diag
10
11
use stdlib_constants
11
12
use stdlib_linalg_iterative_solvers
12
13
implicit none
13
14
15
+ enum, bind(c)
16
+ enumerator :: none = 0
17
+ enumerator :: jacobi
18
+ enumerator :: ssor
19
+ enumerator :: ichol
20
+ end enum
21
+
14
22
contains
15
23
16
24
#:for k, t, s in R_KINDS_TYPES
@@ -78,7 +86,7 @@ contains
78
86
79
87
#:for matrix in MATRIX_TYPES
80
88
#:for k, t, s in R_KINDS_TYPES
81
- module subroutine solve_pccg_${matrix}$_${s}$(A,b,x,di,tol,maxiter,restart,M,workspace)
89
+ module subroutine solve_pccg_${matrix}$_${s}$(A,b,x,di,tol,maxiter,restart,precond, M,workspace)
82
90
#:if matrix == "dense"
83
91
${t}$, intent(in) :: A(:,:)
84
92
#:else
@@ -90,6 +98,7 @@ contains
90
98
logical(1), intent(in), optional, target :: di(:)
91
99
integer, intent(in), optional :: maxiter
92
100
logical, intent(in), optional :: restart
101
+ integer, intent(in), optional :: precond !> preconditionner method flag
93
102
class(linop_${s}$), optional , intent(in), target :: M !> preconditionner
94
103
type(solver_workspace_${s}$), optional, intent(inout), target :: workspace
95
104
!-------------------------
@@ -101,25 +110,53 @@ contains
101
110
logical :: restart_
102
111
logical(1), pointer :: di_(:)
103
112
!-------------------------
113
+ ! working data for preconditionner
114
+ integer :: precond_
115
+ ${t}$, allocatable :: diagonal(:)
116
+ #:if matrix == "dense"
117
+ ${t}$, allocatable:: L(:,:) !> lower triangular
118
+ #:else
119
+ type(${matrix}$_${s}$_type) :: L !> lower triangular
120
+ #:endif
121
+ !-------------------------
104
122
n = size(b)
105
123
maxiter_ = n; if(present(maxiter)) maxiter_ = maxiter
106
124
restart_ = .true.; if(present(restart)) restart_ = restart
107
125
tol_ = 1.e-4_${s}$; if(present(tol)) tol_ = tol
108
-
126
+ precond_ = none ; if(present(precond)) precond_ = precond
109
127
!-------------------------
110
128
! internal memory setup
111
- op%apply => default_matvec
129
+ op%apply => matvec
112
130
if(present(M)) then
113
131
M_ => M
114
132
else
115
133
allocate( M_ )
116
- M_%apply => default_preconditionner
134
+ select case(precond_)
135
+ case(jacobi)
136
+ #:if matrix == "dense"
137
+ diagonal = diag(A)
138
+ #:else
139
+ call diag(A,diagonal)
140
+ #:endif
141
+ where(abs(diagonal)>epsilon(0.d0)) diagonal = 1._dp/diagonal
142
+ M_%apply => precond_jacobi
143
+ case(ssor)
144
+ #:if matrix == "dense"
145
+ diagonal = diag(A)
146
+ #:else
147
+ call diag(A,diagonal)
148
+ #:endif
149
+ where(abs(diagonal)>epsilon(0.d0)) diagonal = 1._dp/diagonal
150
+ ! TODO: Extract the lower triangular part of A in L
151
+ M_%apply => precond_ldl
152
+ case(ichol)
153
+ ! TODO: Add LDL^t factorization
154
+ M_%apply => precond_ldl
155
+ case default
156
+ M_%apply => precond_none
157
+ end select
117
158
end if
118
- !> TODO: factorize the preconditionner
119
- !> Jacobi: M = diag(A)^{-1}
120
- !> SOR: M = (w/(2-w)) (D/w+L) D^{-1} (D/w+U) ; A = D + L + U
121
- !> ILU: M = ( LU )^{-1} ; A = LU
122
- !> ICHOL: M = (L*D*U)^{-1} ; A = L*D*U
159
+
123
160
if(present(di))then
124
161
di_ => di
125
162
else
@@ -151,7 +188,7 @@ contains
151
188
workspace_ => null()
152
189
contains
153
190
154
- subroutine default_matvec (x,y,alpha,beta)
191
+ subroutine matvec (x,y,alpha,beta)
155
192
${t}$, intent(in) :: x(:)
156
193
${t}$, intent(inout) :: y(:)
157
194
${t}$, intent(in) :: alpha
@@ -163,13 +200,30 @@ contains
163
200
#:endif
164
201
y = merge( zero_${s}$, y, di_ )
165
202
end subroutine
166
- subroutine default_preconditionner(x,y,alpha,beta)
203
+
204
+ subroutine precond_none(x,y,alpha,beta)
167
205
${t}$, intent(in) :: x(:)
168
206
${t}$, intent(inout) :: y(:)
169
207
${t}$, intent(in) :: alpha
170
208
${t}$, intent(in) :: beta
171
209
y = merge( zero_${s}$, x, di_ )
172
210
end subroutine
211
+ subroutine precond_jacobi(x,y,alpha,beta)
212
+ ${t}$, intent(in) :: x(:)
213
+ ${t}$, intent(inout) :: y(:)
214
+ ${t}$, intent(in) :: alpha
215
+ ${t}$, intent(in) :: beta
216
+ y = merge( zero_${s}$, diagonal * x, di_ ) !> inverted diagonal
217
+ end subroutine
218
+ subroutine precond_ldl(x,y,alpha,beta)
219
+ ${t}$, intent(in) :: x(:)
220
+ ${t}$, intent(inout) :: y(:)
221
+ ${t}$, intent(in) :: alpha
222
+ ${t}$, intent(in) :: beta
223
+ call solve_forward_triangular( L , x , y )
224
+ y = merge( zero_${s}$, diagonal * y, di_ ) !> inverted diagonal
225
+ call solve_backward_triangular( L , y , y )
226
+ end subroutine
173
227
end subroutine
174
228
175
229
#:endfor
0 commit comments