(git:f2099e5)
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
36 USE cp_fm_types, ONLY: cp_fm_create,&
47 USE kinds, ONLY: dp
50#include "./base/base_uses.f90"
51
52 IMPLICIT NONE
53
54 PRIVATE
55
56 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'preconditioner_solvers'
57
59
60CONTAINS
61
62! **************************************************************************************************
63!> \brief ...
64!> \param my_solver_type ...
65!> \param preconditioner_env ...
66!> \param matrix_s ...
67!> \param matrix_h ...
68! **************************************************************************************************
69 SUBROUTINE solve_preconditioner(my_solver_type, preconditioner_env, matrix_s, &
70 matrix_h)
71 INTEGER :: my_solver_type
72 TYPE(preconditioner_type) :: preconditioner_env
73 TYPE(dbcsr_type), OPTIONAL, POINTER :: matrix_s
74 TYPE(dbcsr_type), POINTER :: matrix_h
75
76 REAL(dp) :: occ_matrix
77
78! here comes the solver
79
80 SELECT CASE (my_solver_type)
82 !
83 ! compute the full inverse
84 preconditioner_env%solver = ot_precond_solver_inv_chol
85 CALL make_full_inverse_cholesky(preconditioner_env, matrix_s)
87 !
88 ! prepare for the direct solver
89 preconditioner_env%solver = ot_precond_solver_direct
90 CALL make_full_fact_cholesky(preconditioner_env, matrix_s)
92 !
93 ! uses an update of the full inverse (needs to be computed the first time)
94 ! make sure preconditioner_env is not destroyed in between
95 occ_matrix = 1.0_dp
96 IF (ASSOCIATED(preconditioner_env%sparse_matrix)) THEN
97 IF (preconditioner_env%condition_num < 0.0_dp) THEN
98 CALL estimate_cond_num(preconditioner_env%sparse_matrix, preconditioner_env%condition_num)
99 END IF
100 CALL dbcsr_filter(preconditioner_env%sparse_matrix, &
101 1.0_dp/preconditioner_env%condition_num*0.01_dp)
102 occ_matrix = dbcsr_get_occupation(preconditioner_env%sparse_matrix)
103 END IF
104 ! check whether we are in the first step and if it is a good idea to use cholesky (matrix sparsity)
105 IF (preconditioner_env%solver /= ot_precond_solver_update .AND. occ_matrix > 0.5_dp) THEN
106 preconditioner_env%solver = ot_precond_solver_update
107 CALL make_full_inverse_cholesky(preconditioner_env, matrix_s)
108 ELSE
109 preconditioner_env%solver = ot_precond_solver_update
110 CALL make_inverse_update(preconditioner_env, matrix_h)
111 END IF
113 IF (preconditioner_env%in_use /= ot_precond_full_kinetic) THEN
114 cpabort("PRECOND_SOLVER CHEBYSHEV currently requires PRECONDITIONER FULL_KINETIC")
115 END IF
116 preconditioner_env%solver = ot_precond_solver_chebyshev
117 cpassert(ASSOCIATED(preconditioner_env%sparse_matrix))
118 CALL estimate_cond_num(preconditioner_env%sparse_matrix, preconditioner_env%condition_num, &
119 max_eigenvalue=preconditioner_env%polynomial_max, &
120 min_eigenvalue=preconditioner_env%polynomial_min)
121 ! Extremal Ritz values can converge from inside the exact spectrum. Halve
122 ! the estimated lower edge as a safety margin and use a rigorous row-sum
123 ! upper bound for the Chebyshev interval.
124 preconditioner_env%polynomial_min = 0.5_dp*preconditioner_env%polynomial_min
125 preconditioner_env%polynomial_max = &
126 (1.0_dp + 100.0_dp*epsilon(1.0_dp))*dbcsr_gershgorin_norm(preconditioner_env%sparse_matrix)
127 IF (preconditioner_env%polynomial_min <= sqrt(epsilon(1.0_dp)) .OR. &
128 preconditioner_env%polynomial_max <= preconditioner_env%polynomial_min) THEN
129 cpwarn("Invalid Chebyshev bounds; using Cholesky inverse")
130 preconditioner_env%solver = ot_precond_solver_inv_chol
131 CALL make_full_inverse_cholesky(preconditioner_env, matrix_s)
132 ELSE
133 ! Preserve the SPD operator instead of replacing it with its inverse.
134 CALL transfer_dbcsr_to_fm(preconditioner_env%sparse_matrix, preconditioner_env%fm, &
135 preconditioner_env%para_env, preconditioner_env%ctxt)
136 END IF
138 preconditioner_env%solver = ot_precond_solver_default
139 CASE DEFAULT
140 !
141 cpabort("Doesn't know this type of solver")
142 END SELECT
143
144 END SUBROUTINE solve_preconditioner
145
146! **************************************************************************************************
147!> \brief Compute the inverse using cholseky factorization
148!> \param preconditioner_env ...
149!> \param matrix_s ...
150! **************************************************************************************************
151 SUBROUTINE make_full_inverse_cholesky(preconditioner_env, matrix_s)
152
153 TYPE(preconditioner_type) :: preconditioner_env
154 TYPE(dbcsr_type), OPTIONAL, POINTER :: matrix_s
155
156 CHARACTER(len=*), PARAMETER :: routinen = 'make_full_inverse_cholesky'
157
158 INTEGER :: handle, info
159 TYPE(cp_fm_type) :: fm_work
160 TYPE(cp_fm_type), POINTER :: fm
161
162 CALL timeset(routinen, handle)
163
164 ! Maybe we will get a sparse Cholesky at a given point then this can go,
165 ! if stuff was stored in fm anyway this simple returns
166 CALL transfer_dbcsr_to_fm(preconditioner_env%sparse_matrix, preconditioner_env%fm, &
167 preconditioner_env%para_env, preconditioner_env%ctxt)
168 fm => preconditioner_env%fm
169
170 CALL cp_fm_create(fm_work, fm%matrix_struct, name="fm_work")
171 !
172 ! compute the inverse of SPD matrix fm using the Cholesky factorization
173 CALL cp_fm_cholesky_decompose(fm, info_out=info)
174
175 !
176 ! if fm not SPD we go with the overlap matrix
177 IF (info /= 0) THEN
178 !
179 ! just the overlap matrix
180 IF (PRESENT(matrix_s)) THEN
181 CALL copy_dbcsr_to_fm(matrix_s, fm)
183 ELSE
184 CALL cp_fm_set_all(fm, alpha=0._dp, beta=1._dp)
185 END IF
186 END IF
187 CALL cp_fm_cholesky_invert(fm)
188
189 CALL cp_fm_uplo_to_full(fm, fm_work)
190 CALL cp_fm_release(fm_work)
191
192 CALL timestop(handle)
193
194 END SUBROUTINE make_full_inverse_cholesky
195
196! **************************************************************************************************
197!> \brief Only perform the factorization, can be used later to solve the linear
198!> system on the fly
199!> \param preconditioner_env ...
200!> \param matrix_s ...
201! **************************************************************************************************
202 SUBROUTINE make_full_fact_cholesky(preconditioner_env, matrix_s)
203
204 TYPE(preconditioner_type) :: preconditioner_env
205 TYPE(dbcsr_type), OPTIONAL, POINTER :: matrix_s
206
207 CHARACTER(len=*), PARAMETER :: routinen = 'make_full_fact_cholesky'
208
209 INTEGER :: handle, info_out
210 TYPE(cp_fm_type), POINTER :: fm
211
212 CALL timeset(routinen, handle)
213
214 ! Maybe we will get a sparse Cholesky at a given point then this can go,
215 ! if stuff was stored in fm anyway this simple returns
216 CALL transfer_dbcsr_to_fm(preconditioner_env%sparse_matrix, preconditioner_env%fm, &
217 preconditioner_env%para_env, preconditioner_env%ctxt)
218
219 fm => preconditioner_env%fm
220 !
221 ! compute the inverse of SPD matrix fm using the Cholesky factorization
222 CALL cp_fm_cholesky_decompose(fm, info_out=info_out)
223 !
224 ! if fm not SPD we go with the overlap matrix
225 IF (info_out /= 0) THEN
226 !
227 ! just the overlap matrix
228 IF (PRESENT(matrix_s)) THEN
229 CALL copy_dbcsr_to_fm(matrix_s, fm)
231 ELSE
232 CALL cp_fm_set_all(fm, alpha=0._dp, beta=1._dp)
233 END IF
234 END IF
235
236 CALL timestop(handle)
237
238 END SUBROUTINE make_full_fact_cholesky
239
240! **************************************************************************************************
241!> \brief computes an approximate inverse using Hotelling iterations
242!> \param preconditioner_env ...
243!> \param matrix_h as S is not always present this is a safe template for the transfer
244! **************************************************************************************************
245 SUBROUTINE make_inverse_update(preconditioner_env, matrix_h)
246 TYPE(preconditioner_type) :: preconditioner_env
247 TYPE(dbcsr_type), POINTER :: matrix_h
248
249 CHARACTER(len=*), PARAMETER :: routinen = 'make_inverse_update'
250
251 INTEGER :: handle
252 LOGICAL :: use_guess
253 REAL(kind=dp) :: filter_eps
254
255 CALL timeset(routinen, handle)
256 use_guess = .true.
257 !
258 ! uses an update of the full inverse (needs to be computed the first time)
259 ! make sure preconditioner_env is not destroyed in between
260
261 CALL cite_reference(schiffmann2015)
262
263 ! Maybe I gonna add a fm Hotelling, ... for now the same as above make sure we are dbcsr
264 CALL transfer_fm_to_dbcsr(preconditioner_env%fm, preconditioner_env%sparse_matrix, matrix_h)
265 IF (.NOT. ASSOCIATED(preconditioner_env%dbcsr_matrix)) THEN
266 use_guess = .false.
267 CALL dbcsr_init_p(preconditioner_env%dbcsr_matrix)
268 CALL dbcsr_create(preconditioner_env%dbcsr_matrix, "prec_dbcsr", &
269 template=matrix_h, matrix_type=dbcsr_type_no_symmetry)
270 END IF
271
272 ! Try to get a reasonbale guess for the filtering threshold
273 filter_eps = 1.0_dp/preconditioner_env%condition_num*0.1_dp
274
275 ! Aggressive filtering on the initial guess is needed to avoid fill ins and retain sparsity
276 CALL dbcsr_filter(preconditioner_env%dbcsr_matrix, filter_eps*100.0_dp)
277 ! We don't need a high accuracy for the inverse so 0.4 is reasonable for convergence
278 CALL invert_hotelling(preconditioner_env%dbcsr_matrix, preconditioner_env%sparse_matrix, filter_eps*10.0_dp, &
279 use_inv_as_guess=use_guess, norm_convergence=0.4_dp, filter_eps=filter_eps)
280
281 CALL timestop(handle)
282
283 END SUBROUTINE make_inverse_update
284
285! **************************************************************************************************
286!> \brief computes an approximation to the condition number of a matrix using
287!> arnoldi iterations
288!> \param matrix ...
289!> \param cond_num ...
290!> \param max_eigenvalue ...
291!> \param min_eigenvalue ...
292! **************************************************************************************************
293 SUBROUTINE estimate_cond_num(matrix, cond_num, max_eigenvalue, min_eigenvalue)
294 TYPE(dbcsr_type), POINTER :: matrix
295 REAL(kind=dp) :: cond_num
296 REAL(kind=dp), INTENT(OUT), OPTIONAL :: max_eigenvalue, min_eigenvalue
297
298 CHARACTER(len=*), PARAMETER :: routinen = 'estimate_cond_num'
299
300 INTEGER :: handle
301 REAL(kind=dp) :: max_ev, min_ev
302 TYPE(arnoldi_env_type) :: arnoldi_env
303 TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrices
304
305 CALL timeset(routinen, handle)
306
307 ! its better to do 2 calculations as the maximum should quickly converge and the minimum won't need iram
308 ALLOCATE (matrices(1))
309 matrices(1)%matrix => matrix
310 ! compute the minimum ev
311 CALL setup_arnoldi_env(arnoldi_env, matrices, max_iter=20, threshold=5.0e-4_dp, selection_crit=2, &
312 nval_request=1, nrestarts=15, generalized_ev=.false., iram=.false.)
313 CALL arnoldi_ev(matrices, arnoldi_env)
314 max_ev = real(get_selected_ritz_val(arnoldi_env, 1), dp)
315 CALL deallocate_arnoldi_env(arnoldi_env)
316
317 CALL setup_arnoldi_env(arnoldi_env, matrices, max_iter=20, threshold=5.0e-4_dp, selection_crit=3, &
318 nval_request=1, nrestarts=15, generalized_ev=.false., iram=.false.)
319 CALL arnoldi_ev(matrices, arnoldi_env)
320 min_ev = real(get_selected_ritz_val(arnoldi_env, 1), dp)
321 CALL deallocate_arnoldi_env(arnoldi_env)
322
323 cond_num = max_ev/min_ev
324 IF (PRESENT(max_eigenvalue)) max_eigenvalue = max_ev
325 IF (PRESENT(min_eigenvalue)) min_eigenvalue = min_ev
326 DEALLOCATE (matrices)
327
328 CALL timestop(handle)
329 END SUBROUTINE estimate_cond_num
330
331! **************************************************************************************************
332!> \brief transfers a full matrix to a dbcsr
333!> \param fm_matrix a full matrix gets deallocated in the end
334!> \param dbcsr_matrix a dbcsr matrix, gets create from a template
335!> \param template_mat the template which is used for the structure
336! **************************************************************************************************
337 SUBROUTINE transfer_fm_to_dbcsr(fm_matrix, dbcsr_matrix, template_mat)
338
339 TYPE(cp_fm_type), POINTER :: fm_matrix
340 TYPE(dbcsr_type), POINTER :: dbcsr_matrix, template_mat
341
342 CHARACTER(len=*), PARAMETER :: routinen = 'transfer_fm_to_dbcsr'
343
344 INTEGER :: handle
345
346 CALL timeset(routinen, handle)
347 IF (ASSOCIATED(fm_matrix)) THEN
348 IF (.NOT. ASSOCIATED(dbcsr_matrix)) THEN
349 CALL dbcsr_init_p(dbcsr_matrix)
350 CALL dbcsr_create(dbcsr_matrix, template=template_mat, &
351 name="preconditioner_env%dbcsr_matrix", &
352 matrix_type=dbcsr_type_no_symmetry)
353 END IF
354 CALL copy_fm_to_dbcsr(fm_matrix, dbcsr_matrix)
355 CALL cp_fm_release(fm_matrix)
356 DEALLOCATE (fm_matrix)
357 NULLIFY (fm_matrix)
358 END IF
359
360 CALL timestop(handle)
361
362 END SUBROUTINE transfer_fm_to_dbcsr
363
364! **************************************************************************************************
365!> \brief transfers a dbcsr to a full matrix
366!> \param dbcsr_matrix a dbcsr matrix, gets deallocated at the end
367!> \param fm_matrix a full matrix gets created if not yet done
368!> \param para_env the para_env
369!> \param context the blacs context
370! **************************************************************************************************
371 SUBROUTINE transfer_dbcsr_to_fm(dbcsr_matrix, fm_matrix, para_env, context)
372
373 TYPE(dbcsr_type), POINTER :: dbcsr_matrix
374 TYPE(cp_fm_type), POINTER :: fm_matrix
375 TYPE(mp_para_env_type), POINTER :: para_env
376 TYPE(cp_blacs_env_type), POINTER :: context
377
378 CHARACTER(len=*), PARAMETER :: routinen = 'transfer_dbcsr_to_fm'
379
380 INTEGER :: handle, n
381 TYPE(cp_fm_struct_type), POINTER :: fm_struct_tmp
382
383 CALL timeset(routinen, handle)
384 IF (ASSOCIATED(dbcsr_matrix)) THEN
385 NULLIFY (fm_struct_tmp)
386
387 IF (ASSOCIATED(fm_matrix)) THEN
388 CALL cp_fm_release(fm_matrix)
389 DEALLOCATE (fm_matrix)
390 END IF
391
392 CALL dbcsr_get_info(dbcsr_matrix, nfullrows_total=n)
393 CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=n, ncol_global=n, &
394 context=context, para_env=para_env)
395 ALLOCATE (fm_matrix)
396 CALL cp_fm_create(fm_matrix, fm_struct_tmp)
397 CALL cp_fm_struct_release(fm_struct_tmp)
398
399 CALL copy_dbcsr_to_fm(dbcsr_matrix, fm_matrix)
400 CALL dbcsr_release(dbcsr_matrix)
401 DEALLOCATE (dbcsr_matrix)
402 END IF
403
404 CALL timestop(handle)
405
406 END SUBROUTINE transfer_dbcsr_to_fm
407
408END 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)
...
real(dp) function, public dbcsr_gershgorin_norm(matrix)
Compute the gershgorin norm of a dbcsr matrix.
DBCSR operations in CP2K.
subroutine, public copy_dbcsr_to_fm(matrix, fm, plan)
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_chebyshev
integer, parameter, public ot_precond_full_kinetic
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