27 type(ddx_params_type),
intent(in) :: params
28 type(ddx_constants_type),
intent(in) :: constants
29 real(dp),
intent(in) :: x(constants % nbasis, params % nsph)
31 type(ddx_workspace_type),
intent(inout) :: workspace
33 real(dp),
intent(out) :: y(constants % nbasis, params % nsph)
34 type(ddx_error_type),
intent(inout) :: ddx_error
44 type(ddx_params_type),
intent(in) :: params
45 type(ddx_constants_type),
intent(in) :: constants
46 real(dp),
intent(in) :: x(constants % nbasis, params % nsph, 2)
48 type(ddx_workspace_type),
intent(inout) :: workspace
50 real(dp),
intent(out) :: y(constants % nbasis, params % nsph, 2)
51 type(ddx_error_type),
intent(inout) :: ddx_error
55 real(dp) function norm_interface(lmax, nbasis, nsph, x)
59 integer,
intent(in) :: lmax, nbasis, nsph
60 real(dp),
intent(in) :: x(nbasis, nsph)
84subroutine jacobi_diis(params, constants, workspace, tol, rhs, x, niter, &
85 & x_rel_diff, matvec, dm1vec, norm_func, ddx_error)
87 type(ddx_params_type),
intent(in) :: params
88 type(ddx_constants_type),
intent(in) :: constants
89 real(dp),
intent(in) :: tol, rhs(constants % n)
91 type(ddx_workspace_type),
intent(inout) :: workspace
93 real(dp),
intent(inout) :: x(constants % n)
94 integer,
intent(inout) :: niter
95 real(dp),
intent(out) :: x_rel_diff(niter)
96 type(ddx_error_type),
intent(inout) :: ddx_error
102 real(dp) :: diff, norm, rel_diff
109 call matvec(params, constants, workspace, x, workspace % tmp_y, ddx_error)
110 workspace % tmp_y = rhs - workspace % tmp_y
111 if (ddx_error % flag .ne. 0)
then
112 call update_error(ddx_error,
'Matvec error, exiting')
116 call dm1vec(params, constants, workspace, workspace % tmp_y, &
117 & workspace % tmp_x_new, ddx_error)
118 if (ddx_error % flag .ne. 0)
then
119 call update_error(ddx_error,
'Preconditioning error, exiting')
123 if (params % jacobi_ndiis .gt. 2)
then
124 workspace % tmp_x_diis(:, nmat) = workspace % tmp_x_new
125 workspace % tmp_e_diis(:, nmat) = workspace % tmp_x_new - x
126 call diis(constants % n, nmat, params % jacobi_ndiis, &
127 & workspace % tmp_x_diis, workspace % tmp_e_diis, &
128 & workspace % tmp_bmat, workspace % tmp_x_new)
131 x = workspace % tmp_x_new - x
132 diff = norm_func(params % lmax, constants % nbasis, params % nsph, x)
133 norm = norm_func(params % lmax, constants % nbasis, params % nsph, &
134 & workspace % tmp_x_new)
137 if (diff.eq.zero .and. norm.eq.zero)
then
140 rel_diff = diff / norm
143 if (params % verbose)
then
144 write(params % iunit,
'(A,I3,1X,A,E10.2)') &
145 &
'Iteration:', it,
'Rel. diff:', rel_diff
146 flush(params % iunit)
149 x_rel_diff(it) = rel_diff
151 x = workspace % tmp_x_new
153 if (rel_diff .le. tol)
then
158 call update_error(ddx_error,
"Jacobi solver did not converge")
162subroutine diis(n, nmat, ndiis, x, e, b, xnew)
164 integer,
intent(in) :: n, ndiis
165 integer,
intent(inout) :: nmat
166 real(dp),
dimension(n,ndiis),
intent(inout) :: x, e
167 real(dp),
dimension(ndiis+1,ndiis+1),
intent(inout) :: b
168 real(dp),
dimension(n),
intent(inout) :: xnew
169 integer :: nmat1, i, istatus, info
171 real(dp),
allocatable :: bloc(:,:), cex(:)
172 integer,
allocatable :: ipiv(:)
175 delta = min(10, ndiis-1)
177 if (nmat.ge.ndiis)
then
178 do j = 2, nmat - delta
179 do k = 2, nmat - delta
180 b(j, k) = b(j+delta, k+delta)
183 do j = 1, nmat - delta
184 x(:, j) = x(:, j+delta)
185 e(:, j) = e(:, j+delta)
191 allocate(bloc(nmat1, nmat1), cex(nmat1), ipiv(nmat1), stat=istatus)
193 call makeb(n, nmat, ndiis, e, b)
194 bloc = b(1:nmat1, 1:nmat1)
197 call dgesv(nmat1, 1, bloc, nmat1, ipiv, cex, nmat1, info)
206 call daxpy(n,cex(i+1),x(:, i),1,xnew,1)
210 deallocate (bloc, cex, stat=istatus)
214subroutine makeb(n, nmat, ndiis, e, b)
216 integer,
intent(in) :: n, nmat, ndiis
217 real(dp),
dimension(n,ndiis),
intent(in) :: e
218 real(dp),
dimension(ndiis+1,ndiis+1),
intent(inout) :: b
233 b(2,2) = dot_product(e(:,1),e(:,1))
246 bij = dot_product(e(:,i), e(:,nmat))
250 b(nmat+1,nmat+1) = dot_product(e(:,nmat),e(:,nmat))
264 & x_rel_diff, matvec, dm1vec, norm_func, ddx_error)
265 type(ddx_params_type),
intent(in) :: params
266 type(ddx_constants_type),
intent(inout) :: constants
267 type(ddx_workspace_type),
intent(inout) :: workspace
269 integer,
intent(in) :: n
270 real(dp),
intent(in) :: tol
271 real(dp),
dimension(n),
intent(in) :: rhs
273 real(dp),
dimension(n),
intent(inout) :: x
274 integer,
intent(inout) :: n_iter
275 type(ddx_error_type),
intent(inout) :: ddx_error
276 real(dp),
intent(out) :: x_rel_diff(n_iter)
277 external :: matvec, dm1vec
280 integer :: it, nmat, istatus, lenb, nsph_u
281 real(dp) :: diff, norm, rel_diff = zero
283 real(dp),
allocatable :: x_new(:), y(:), x_diis(:,:), e_diis(:,:), bmat(:,:)
285 dodiis = (params%jacobi_ndiis.gt.0)
289 lenb = params % jacobi_ndiis + 1
290 allocate( x_diis(n,params % jacobi_ndiis), e_diis(n,params % jacobi_ndiis), bmat(lenb,lenb) , stat=istatus )
291 if (istatus .ne. 0)
then
292 call update_error(ddx_error,
'jacobi_diis_external: failed allocation (diis)')
300 allocate( x_new(n), y(n) , stat=istatus )
301 if (istatus .ne. 0)
then
302 call update_error(ddx_error,
'jacobi_diis_external: failed allocation (diis)')
308 call matvec(params, constants, workspace, x, y, ddx_error)
311 call dm1vec(params, constants, workspace, y, x_new, ddx_error)
314 x_diis(:,nmat) = x_new
315 e_diis(:,nmat) = x_new - x
316 call diis(n,nmat,params % jacobi_ndiis,x_diis,e_diis,bmat,x_new)
324 nsph_u = n/constants % nbasis
325 diff = norm_func(params % lmax, constants % nbasis, nsph_u, x)
326 norm = norm_func(params % lmax, constants % nbasis, nsph_u, x_new)
328 if (diff.eq.zero .and. norm.eq.zero)
then
331 rel_diff = diff / norm
333 x_rel_diff(it) = rel_diff
334 constants % inner_tol = max(rel_diff*sqrt(tol), tol/100.0d0)
338 if (rel_diff .le. tol)
then
343 call update_error(ddx_error,
'Jacobi external solver failed to converge')
Core routines and parameters of the ddX software.
Compile-time constants and definitions.
Core routines and parameters of ddX software.
subroutine jacobi_diis_external(params, constants, workspace, n, tol, rhs, x, n_iter, x_rel_diff, matvec, dm1vec, norm_func, ddx_error)
jacobi_diis_solver_external WARNING: code duplication is bad, but here it makes a very specific sense...
subroutine diis(n, nmat, ndiis, x, e, b, xnew)
DIIS helper routine.
subroutine makeb(n, nmat, ndiis, e, b)
DIIS helper routine.
subroutine jacobi_diis(params, constants, workspace, tol, rhs, x, niter, x_rel_diff, matvec, dm1vec, norm_func, ddx_error)
Jacobi iterative solver.