(git:98357aa)
Loading...
Searching...
No Matches
preconditioner_solvers.F
Go to the documentation of this file.
1!--------------------------------------------------------------------------------------------------!
2! CP2K: A general program to perform molecular dynamics simulations !
3! Copyright 2000-2026 CP2K developers group <https://cp2k.org> !
4! !
5! SPDX-License-Identifier: GPL-2.0-or-later !
6!--------------------------------------------------------------------------------------------------!
7
8! **************************************************************************************************
9!> \brief solves the preconditioner, contains to utility function for
10!> fm<->dbcsr transfers, should be moved soon
11!> \par History
12!> - [UB] 2009-05-13 Adding stable approximate inverse (full and sparse)
13!> \author Joost VandeVondele (09.2002)
14! **************************************************************************************************
16 USE arnoldi_api, ONLY: arnoldi_env_type,&
18 deallocate_arnoldi_env,&
19 get_selected_ritz_val,&
20 setup_arnoldi_env
21 USE bibliography, ONLY: schiffmann2015,&
22 cite_reference
24 USE cp_dbcsr_api, ONLY: &
26 dbcsr_p_type, dbcsr_release, dbcsr_type, dbcsr_type_no_symmetry
35 USE cp_fm_types, ONLY: cp_fm_create,&
44 USE kinds, ONLY: dp
47#include "./base/base_uses.f90"
48
49 IMPLICIT NONE
50
51 PRIVATE
52
53 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'preconditioner_solvers'
54
56
57CONTAINS
58
59! **************************************************************************************************
60!> \brief ...
61!> \param my_solver_type ...
62!> \param preconditioner_env ...
63!> \param matrix_s ...
64!> \param matrix_h ...
65! **************************************************************************************************
66 SUBROUTINE solve_preconditioner(my_solver_type, preconditioner_env, matrix_s, &
67 matrix_h)
68 INTEGER :: my_solver_type
69 TYPE(preconditioner_type) :: preconditioner_env
70 TYPE(dbcsr_type), OPTIONAL, POINTER :: matrix_s
71 TYPE(dbcsr_type), POINTER :: matrix_h
72
73 REAL(dp) :: occ_matrix
74
75! here comes the solver
76
77 SELECT CASE (my_solver_type)
79 !
80 ! compute the full inverse
81 preconditioner_env%solver = ot_precond_solver_inv_chol
82 CALL make_full_inverse_cholesky(preconditioner_env, matrix_s)
84 !
85 ! prepare for the direct solver
86 preconditioner_env%solver = ot_precond_solver_direct
87 CALL make_full_fact_cholesky(preconditioner_env, matrix_s)
89 !
90 ! uses an update of the full inverse (needs to be computed the first time)
91 ! make sure preconditioner_env is not destroyed in between
92 occ_matrix = 1.0_dp
93 IF (ASSOCIATED(preconditioner_env%sparse_matrix)) THEN
94 IF (preconditioner_env%condition_num < 0.0_dp) THEN
95 CALL estimate_cond_num(preconditioner_env%sparse_matrix, preconditioner_env%condition_num)
96 END IF
97 CALL dbcsr_filter(preconditioner_env%sparse_matrix, &
98 1.0_dp/preconditioner_env%condition_num*0.01_dp)
99 occ_matrix = dbcsr_get_occupation(preconditioner_env%sparse_matrix)
100 END IF
101 ! check whether we are in the first step and if it is a good idea to use cholesky (matrix sparsity)
102 IF (preconditioner_env%solver /= ot_precond_solver_update .AND. occ_matrix > 0.5_dp) THEN
103 preconditioner_env%solver = ot_precond_solver_update
104 CALL make_full_inverse_cholesky(preconditioner_env, matrix_s)
105 ELSE
106 preconditioner_env%solver = ot_precond_solver_update
107 CALL make_inverse_update(preconditioner_env, matrix_h)
108 END IF
110 preconditioner_env%solver = ot_precond_solver_default
111 CASE DEFAULT
112 !
113 cpabort("Doesn't know this type of solver")
114 END SELECT
115
116 END SUBROUTINE solve_preconditioner
117
118! **************************************************************************************************
119!> \brief Compute the inverse using cholseky factorization
120!> \param preconditioner_env ...
121!> \param matrix_s ...
122! **************************************************************************************************
123 SUBROUTINE make_full_inverse_cholesky(preconditioner_env, matrix_s)
124
125 TYPE(preconditioner_type) :: preconditioner_env
126 TYPE(dbcsr_type), OPTIONAL, POINTER :: matrix_s
127
128 CHARACTER(len=*), PARAMETER :: routinen = 'make_full_inverse_cholesky'
129
130 INTEGER :: handle, info
131 TYPE(cp_fm_type) :: fm_work
132 TYPE(cp_fm_type), POINTER :: fm
133
134 CALL timeset(routinen, handle)
135
136 ! Maybe we will get a sparse Cholesky at a given point then this can go,
137 ! if stuff was stored in fm anyway this simple returns
138 CALL transfer_dbcsr_to_fm(preconditioner_env%sparse_matrix, preconditioner_env%fm, &
139 preconditioner_env%para_env, preconditioner_env%ctxt)
140 fm => preconditioner_env%fm
141
142 CALL cp_fm_create(fm_work, fm%matrix_struct, name="fm_work")
143 !
144 ! compute the inverse of SPD matrix fm using the Cholesky factorization
145 CALL cp_fm_cholesky_decompose(fm, info_out=info)
146
147 !
148 ! if fm not SPD we go with the overlap matrix
149 IF (info /= 0) THEN
150 !
151 ! just the overlap matrix
152 IF (PRESENT(matrix_s)) THEN
153 CALL copy_dbcsr_to_fm(matrix_s, fm)
155 ELSE
156 CALL cp_fm_set_all(fm, alpha=0._dp, beta=1._dp)
157 END IF
158 END IF
159 CALL cp_fm_cholesky_invert(fm)
160
161 CALL cp_fm_uplo_to_full(fm, fm_work)
162 CALL cp_fm_release(fm_work)
163
164 CALL timestop(handle)
165
166 END SUBROUTINE make_full_inverse_cholesky
167
168! **************************************************************************************************
169!> \brief Only perform the factorization, can be used later to solve the linear
170!> system on the fly
171!> \param preconditioner_env ...
172!> \param matrix_s ...
173! **************************************************************************************************
174 SUBROUTINE make_full_fact_cholesky(preconditioner_env, matrix_s)
175
176 TYPE(preconditioner_type) :: preconditioner_env
177 TYPE(dbcsr_type), OPTIONAL, POINTER :: matrix_s
178
179 CHARACTER(len=*), PARAMETER :: routinen = 'make_full_fact_cholesky'
180
181 INTEGER :: handle, info_out
182 TYPE(cp_fm_type), POINTER :: fm
183
184 CALL timeset(routinen, handle)
185
186 ! Maybe we will get a sparse Cholesky at a given point then this can go,
187 ! if stuff was stored in fm anyway this simple returns
188 CALL transfer_dbcsr_to_fm(preconditioner_env%sparse_matrix, preconditioner_env%fm, &
189 preconditioner_env%para_env, preconditioner_env%ctxt)
190
191 fm => preconditioner_env%fm
192 !
193 ! compute the inverse of SPD matrix fm using the Cholesky factorization
194 CALL cp_fm_cholesky_decompose(fm, info_out=info_out)
195 !
196 ! if fm not SPD we go with the overlap matrix
197 IF (info_out /= 0) THEN
198 !
199 ! just the overlap matrix
200 IF (PRESENT(matrix_s)) THEN
201 CALL copy_dbcsr_to_fm(matrix_s, fm)
203 ELSE
204 CALL cp_fm_set_all(fm, alpha=0._dp, beta=1._dp)
205 END IF
206 END IF
207
208 CALL timestop(handle)
209
210 END SUBROUTINE make_full_fact_cholesky
211
212! **************************************************************************************************
213!> \brief computes an approximate inverse using Hotelling iterations
214!> \param preconditioner_env ...
215!> \param matrix_h as S is not always present this is a safe template for the transfer
216! **************************************************************************************************
217 SUBROUTINE make_inverse_update(preconditioner_env, matrix_h)
218 TYPE(preconditioner_type) :: preconditioner_env
219 TYPE(dbcsr_type), POINTER :: matrix_h
220
221 CHARACTER(len=*), PARAMETER :: routinen = 'make_inverse_update'
222
223 INTEGER :: handle
224 LOGICAL :: use_guess
225 REAL(kind=dp) :: filter_eps
226
227 CALL timeset(routinen, handle)
228 use_guess = .true.
229 !
230 ! uses an update of the full inverse (needs to be computed the first time)
231 ! make sure preconditioner_env is not destroyed in between
232
233 CALL cite_reference(schiffmann2015)
234
235 ! Maybe I gonna add a fm Hotelling, ... for now the same as above make sure we are dbcsr
236 CALL transfer_fm_to_dbcsr(preconditioner_env%fm, preconditioner_env%sparse_matrix, matrix_h)
237 IF (.NOT. ASSOCIATED(preconditioner_env%dbcsr_matrix)) THEN
238 use_guess = .false.
239 CALL dbcsr_init_p(preconditioner_env%dbcsr_matrix)
240 CALL dbcsr_create(preconditioner_env%dbcsr_matrix, "prec_dbcsr", &
241 template=matrix_h, matrix_type=dbcsr_type_no_symmetry)
242 END IF
243
244 ! Try to get a reasonbale guess for the filtering threshold
245 filter_eps = 1.0_dp/preconditioner_env%condition_num*0.1_dp
246
247 ! Aggressive filtering on the initial guess is needed to avoid fill ins and retain sparsity
248 CALL dbcsr_filter(preconditioner_env%dbcsr_matrix, filter_eps*100.0_dp)
249 ! We don't need a high accuracy for the inverse so 0.4 is reasonable for convergence
250 CALL invert_hotelling(preconditioner_env%dbcsr_matrix, preconditioner_env%sparse_matrix, filter_eps*10.0_dp, &
251 use_inv_as_guess=use_guess, norm_convergence=0.4_dp, filter_eps=filter_eps)
252
253 CALL timestop(handle)
254
255 END SUBROUTINE make_inverse_update
256
257! **************************************************************************************************
258!> \brief computes an approximation to the condition number of a matrix using
259!> arnoldi iterations
260!> \param matrix ...
261!> \param cond_num ...
262! **************************************************************************************************
263 SUBROUTINE estimate_cond_num(matrix, cond_num)
264 TYPE(dbcsr_type), POINTER :: matrix
265 REAL(kind=dp) :: cond_num
266
267 CHARACTER(len=*), PARAMETER :: routinen = 'estimate_cond_num'
268
269 INTEGER :: handle
270 REAL(kind=dp) :: max_ev, min_ev
271 TYPE(arnoldi_env_type) :: arnoldi_env
272 TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrices
273
274 CALL timeset(routinen, handle)
275
276 ! its better to do 2 calculations as the maximum should quickly converge and the minimum won't need iram
277 ALLOCATE (matrices(1))
278 matrices(1)%matrix => matrix
279 ! compute the minimum ev
280 CALL setup_arnoldi_env(arnoldi_env, matrices, max_iter=20, threshold=5.0e-4_dp, selection_crit=2, &
281 nval_request=1, nrestarts=15, generalized_ev=.false., iram=.false.)
282 CALL arnoldi_ev(matrices, arnoldi_env)
283 max_ev = real(get_selected_ritz_val(arnoldi_env, 1), dp)
284 CALL deallocate_arnoldi_env(arnoldi_env)
285
286 CALL setup_arnoldi_env(arnoldi_env, matrices, max_iter=20, threshold=5.0e-4_dp, selection_crit=3, &
287 nval_request=1, nrestarts=15, generalized_ev=.false., iram=.false.)
288 CALL arnoldi_ev(matrices, arnoldi_env)
289 min_ev = real(get_selected_ritz_val(arnoldi_env, 1), dp)
290 CALL deallocate_arnoldi_env(arnoldi_env)
291
292 cond_num = max_ev/min_ev
293 DEALLOCATE (matrices)
294
295 CALL timestop(handle)
296 END SUBROUTINE estimate_cond_num
297
298! **************************************************************************************************
299!> \brief transfers a full matrix to a dbcsr
300!> \param fm_matrix a full matrix gets deallocated in the end
301!> \param dbcsr_matrix a dbcsr matrix, gets create from a template
302!> \param template_mat the template which is used for the structure
303! **************************************************************************************************
304 SUBROUTINE transfer_fm_to_dbcsr(fm_matrix, dbcsr_matrix, template_mat)
305
306 TYPE(cp_fm_type), POINTER :: fm_matrix
307 TYPE(dbcsr_type), POINTER :: dbcsr_matrix, template_mat
308
309 CHARACTER(len=*), PARAMETER :: routinen = 'transfer_fm_to_dbcsr'
310
311 INTEGER :: handle
312
313 CALL timeset(routinen, handle)
314 IF (ASSOCIATED(fm_matrix)) THEN
315 IF (.NOT. ASSOCIATED(dbcsr_matrix)) THEN
316 CALL dbcsr_init_p(dbcsr_matrix)
317 CALL dbcsr_create(dbcsr_matrix, template=template_mat, &
318 name="preconditioner_env%dbcsr_matrix", &
319 matrix_type=dbcsr_type_no_symmetry)
320 END IF
321 CALL copy_fm_to_dbcsr(fm_matrix, dbcsr_matrix)
322 CALL cp_fm_release(fm_matrix)
323 DEALLOCATE (fm_matrix)
324 NULLIFY (fm_matrix)
325 END IF
326
327 CALL timestop(handle)
328
329 END SUBROUTINE transfer_fm_to_dbcsr
330
331! **************************************************************************************************
332!> \brief transfers a dbcsr to a full matrix
333!> \param dbcsr_matrix a dbcsr matrix, gets deallocated at the end
334!> \param fm_matrix a full matrix gets created if not yet done
335!> \param para_env the para_env
336!> \param context the blacs context
337! **************************************************************************************************
338 SUBROUTINE transfer_dbcsr_to_fm(dbcsr_matrix, fm_matrix, para_env, context)
339
340 TYPE(dbcsr_type), POINTER :: dbcsr_matrix
341 TYPE(cp_fm_type), POINTER :: fm_matrix
342 TYPE(mp_para_env_type), POINTER :: para_env
343 TYPE(cp_blacs_env_type), POINTER :: context
344
345 CHARACTER(len=*), PARAMETER :: routinen = 'transfer_dbcsr_to_fm'
346
347 INTEGER :: handle, n
348 TYPE(cp_fm_struct_type), POINTER :: fm_struct_tmp
349
350 CALL timeset(routinen, handle)
351 IF (ASSOCIATED(dbcsr_matrix)) THEN
352 NULLIFY (fm_struct_tmp)
353
354 IF (ASSOCIATED(fm_matrix)) THEN
355 CALL cp_fm_release(fm_matrix)
356 DEALLOCATE (fm_matrix)
357 END IF
358
359 CALL dbcsr_get_info(dbcsr_matrix, nfullrows_total=n)
360 CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=n, ncol_global=n, &
361 context=context, para_env=para_env)
362 ALLOCATE (fm_matrix)
363 CALL cp_fm_create(fm_matrix, fm_struct_tmp)
364 CALL cp_fm_struct_release(fm_struct_tmp)
365
366 CALL copy_dbcsr_to_fm(dbcsr_matrix, fm_matrix)
367 CALL dbcsr_release(dbcsr_matrix)
368 DEALLOCATE (dbcsr_matrix)
369 END IF
370
371 CALL timestop(handle)
372
373 END SUBROUTINE transfer_dbcsr_to_fm
374
375END MODULE preconditioner_solvers
arnoldi iteration using dbcsr
Definition arnoldi_api.F:16
subroutine, public arnoldi_ev(matrix, arnoldi_env)
Driver routine for different arnoldi eigenvalue methods the selection which one is to be taken is mad...
Definition arnoldi_api.F:69
collects all references to literature in CP2K as new algorithms / method are included from literature...
integer, save, public schiffmann2015
methods related to the blacs parallel environment
subroutine, public dbcsr_get_info(matrix, nblkrows_total, nblkcols_total, nfullrows_total, nfullcols_total, nblkrows_local, nblkcols_local, nfullrows_local, nfullcols_local, my_prow, my_pcol, local_rows, local_cols, proc_row_dist, proc_col_dist, row_blk_size, col_blk_size, row_blk_offset, col_blk_offset, distribution, name, matrix_type, group)
...
subroutine, public dbcsr_init_p(matrix)
...
subroutine, public dbcsr_filter(matrix, eps)
...
real(kind=dp) function, public dbcsr_get_occupation(matrix)
...
subroutine, public dbcsr_release(matrix)
...
DBCSR operations in CP2K.
subroutine, public copy_dbcsr_to_fm(matrix, fm)
Copy a DBCSR matrix to a BLACS matrix.
subroutine, public copy_fm_to_dbcsr(fm, matrix, keep_sparsity)
Copy a BLACS matrix to a dbcsr matrix.
Basic linear algebra operations for full matrices.
subroutine, public cp_fm_uplo_to_full(matrix, work, uplo)
given a triangular matrix according to uplo, computes the corresponding full matrix
various cholesky decomposition related routines
subroutine, public cp_fm_cholesky_invert(matrix, n, info_out)
used to replace the cholesky decomposition by the inverse
subroutine, public cp_fm_cholesky_decompose(matrix, n, info_out)
used to replace a symmetric positive def. matrix M with its cholesky decomposition U: M = U^T * U,...
represent the structure of a full matrix
subroutine, public cp_fm_struct_create(fmstruct, para_env, context, nrow_global, ncol_global, nrow_block, ncol_block, descriptor, first_p_pos, local_leading_dimension, template_fmstruct, square_blocks, force_block)
allocates and initializes a full matrix structure
subroutine, public cp_fm_struct_release(fmstruct)
releases a full matrix structure
represent a full matrix distributed on many processors
Definition cp_fm_types.F:15
subroutine, public cp_fm_set_all(matrix, alpha, beta)
set all elements of a matrix to the same value, and optionally the diagonal to a different one
subroutine, public cp_fm_create(matrix, matrix_struct, name, nrow, ncol, set_zero)
creates a new full matrix with the given structure
collects all constants needed in input so that they can be used without circular dependencies
integer, parameter, public ot_precond_solver_default
integer, parameter, public ot_precond_solver_inv_chol
integer, parameter, public ot_precond_solver_update
integer, parameter, public ot_precond_solver_direct
Routines useful for iterative matrix calculations.
subroutine, public invert_hotelling(matrix_inverse, matrix, threshold, use_inv_as_guess, norm_convergence, filter_eps, accelerator_order, max_iter_lanczos, eps_lanczos, silent)
invert a symmetric positive definite matrix by Hotelling's method explicit symmetrization makes this ...
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34
Interface to the message passing library MPI.
solves the preconditioner, contains to utility function for fm<->dbcsr transfers, should be moved soo...
subroutine, public transfer_dbcsr_to_fm(dbcsr_matrix, fm_matrix, para_env, context)
transfers a dbcsr to a full matrix
subroutine, public solve_preconditioner(my_solver_type, preconditioner_env, matrix_s, matrix_h)
...
subroutine, public transfer_fm_to_dbcsr(fm_matrix, dbcsr_matrix, template_mat)
transfers a full matrix to a dbcsr
types of preconditioners
represent a blacs multidimensional parallel environment (for the mpi corrispective see cp_paratypes/m...
keeps the information about the structure of a full matrix
represent a full matrix
stores all the informations relevant to an mpi environment