(git:374b731)
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-2024 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_data_type,&
18 deallocate_arnoldi_data,&
19 get_selected_ritz_val,&
20 setup_arnoldi_data
21 USE bibliography, ONLY: schiffmann2015,&
22 cite_reference
32 USE cp_fm_types, ONLY: cp_fm_create,&
36 USE dbcsr_api, ONLY: &
37 dbcsr_create, dbcsr_filter, dbcsr_get_info, dbcsr_get_occupation, dbcsr_init_p, &
38 dbcsr_p_type, dbcsr_release, dbcsr_type, dbcsr_type_no_symmetry, dbcsr_type_real_8
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) &
95 CALL estimate_cond_num(preconditioner_env%sparse_matrix, preconditioner_env%condition_num)
96 CALL dbcsr_filter(preconditioner_env%sparse_matrix, &
97 1.0_dp/preconditioner_env%condition_num*0.01_dp)
98 occ_matrix = dbcsr_get_occupation(preconditioner_env%sparse_matrix)
99 END IF
100 ! check whether we are in the first step and if it is a good idea to use cholesky (matrix sparsity)
101 IF (preconditioner_env%solver .NE. ot_precond_solver_update .AND. occ_matrix > 0.5_dp) THEN
102 preconditioner_env%solver = ot_precond_solver_update
103 CALL make_full_inverse_cholesky(preconditioner_env, matrix_s)
104 ELSE
105 preconditioner_env%solver = ot_precond_solver_update
106 CALL make_inverse_update(preconditioner_env, matrix_h)
107 END IF
109 preconditioner_env%solver = ot_precond_solver_default
110 CASE DEFAULT
111 !
112 cpabort("Doesn't know this type of solver")
113 END SELECT
114
115 END SUBROUTINE solve_preconditioner
116
117! **************************************************************************************************
118!> \brief Compute the inverse using cholseky factorization
119!> \param preconditioner_env ...
120!> \param matrix_s ...
121! **************************************************************************************************
122 SUBROUTINE make_full_inverse_cholesky(preconditioner_env, matrix_s)
123
124 TYPE(preconditioner_type) :: preconditioner_env
125 TYPE(dbcsr_type), OPTIONAL, POINTER :: matrix_s
126
127 CHARACTER(len=*), PARAMETER :: routinen = 'make_full_inverse_cholesky'
128
129 INTEGER :: handle, info
130 TYPE(cp_fm_type) :: fm_work
131 TYPE(cp_fm_type), POINTER :: fm
132
133 CALL timeset(routinen, handle)
134
135 ! Maybe we will get a sparse Cholesky at a given point then this can go,
136 ! if stuff was stored in fm anyway this simple returns
137 CALL transfer_dbcsr_to_fm(preconditioner_env%sparse_matrix, preconditioner_env%fm, &
138 preconditioner_env%para_env, preconditioner_env%ctxt)
139 fm => preconditioner_env%fm
140
141 CALL cp_fm_create(fm_work, fm%matrix_struct, name="fm_work")
142 !
143 ! compute the inverse of SPD matrix fm using the Cholesky factorization
144 CALL cp_fm_cholesky_decompose(fm, info_out=info)
145
146 !
147 ! if fm not SPD we go with the overlap matrix
148 IF (info /= 0) THEN
149 !
150 ! just the overlap matrix
151 IF (PRESENT(matrix_s)) THEN
152 CALL copy_dbcsr_to_fm(matrix_s, fm)
154 ELSE
155 CALL cp_fm_set_all(fm, alpha=0._dp, beta=1._dp)
156 END IF
157 END IF
158 CALL cp_fm_cholesky_invert(fm)
159
160 CALL cp_fm_upper_to_full(fm, fm_work)
161 CALL cp_fm_release(fm_work)
162
163 CALL timestop(handle)
164
165 END SUBROUTINE make_full_inverse_cholesky
166
167! **************************************************************************************************
168!> \brief Only perform the factorization, can be used later to solve the linear
169!> system on the fly
170!> \param preconditioner_env ...
171!> \param matrix_s ...
172! **************************************************************************************************
173 SUBROUTINE make_full_fact_cholesky(preconditioner_env, matrix_s)
174
175 TYPE(preconditioner_type) :: preconditioner_env
176 TYPE(dbcsr_type), OPTIONAL, POINTER :: matrix_s
177
178 CHARACTER(len=*), PARAMETER :: routinen = 'make_full_fact_cholesky'
179
180 INTEGER :: handle, info_out
181 TYPE(cp_fm_type), POINTER :: fm
182
183 CALL timeset(routinen, handle)
184
185 ! Maybe we will get a sparse Cholesky at a given point then this can go,
186 ! if stuff was stored in fm anyway this simple returns
187 CALL transfer_dbcsr_to_fm(preconditioner_env%sparse_matrix, preconditioner_env%fm, &
188 preconditioner_env%para_env, preconditioner_env%ctxt)
189
190 fm => preconditioner_env%fm
191 !
192 ! compute the inverse of SPD matrix fm using the Cholesky factorization
193 CALL cp_fm_cholesky_decompose(fm, info_out=info_out)
194 !
195 ! if fm not SPD we go with the overlap matrix
196 IF (info_out .NE. 0) THEN
197 !
198 ! just the overlap matrix
199 IF (PRESENT(matrix_s)) THEN
200 CALL copy_dbcsr_to_fm(matrix_s, fm)
202 ELSE
203 CALL cp_fm_set_all(fm, alpha=0._dp, beta=1._dp)
204 END IF
205 END IF
206
207 CALL timestop(handle)
208
209 END SUBROUTINE make_full_fact_cholesky
210
211! **************************************************************************************************
212!> \brief computes an approximate inverse using Hotelling iterations
213!> \param preconditioner_env ...
214!> \param matrix_h as S is not always present this is a safe template for the transfer
215! **************************************************************************************************
216 SUBROUTINE make_inverse_update(preconditioner_env, matrix_h)
217 TYPE(preconditioner_type) :: preconditioner_env
218 TYPE(dbcsr_type), POINTER :: matrix_h
219
220 CHARACTER(len=*), PARAMETER :: routinen = 'make_inverse_update'
221
222 INTEGER :: handle
223 LOGICAL :: use_guess
224 REAL(kind=dp) :: filter_eps
225
226 CALL timeset(routinen, handle)
227 use_guess = .true.
228 !
229 ! uses an update of the full inverse (needs to be computed the first time)
230 ! make sure preconditioner_env is not destroyed in between
231
232 CALL cite_reference(schiffmann2015)
233
234 ! Maybe I gonna add a fm Hotelling, ... for now the same as above make sure we are dbcsr
235 CALL transfer_fm_to_dbcsr(preconditioner_env%fm, preconditioner_env%sparse_matrix, matrix_h)
236 IF (.NOT. ASSOCIATED(preconditioner_env%dbcsr_matrix)) THEN
237 use_guess = .false.
238 CALL dbcsr_init_p(preconditioner_env%dbcsr_matrix)
239 CALL dbcsr_create(preconditioner_env%dbcsr_matrix, "prec_dbcsr", &
240 template=matrix_h, matrix_type=dbcsr_type_no_symmetry)
241 END IF
242
243 ! Try to get a reasonbale guess for the filtering threshold
244 filter_eps = 1.0_dp/preconditioner_env%condition_num*0.1_dp
245
246 ! Aggressive filtering on the initial guess is needed to avoid fill ins and retain sparsity
247 CALL dbcsr_filter(preconditioner_env%dbcsr_matrix, filter_eps*100.0_dp)
248 ! We don't need a high accuracy for the inverse so 0.4 is reasonable for convergence
249 CALL invert_hotelling(preconditioner_env%dbcsr_matrix, preconditioner_env%sparse_matrix, filter_eps*10.0_dp, &
250 use_inv_as_guess=use_guess, norm_convergence=0.4_dp, filter_eps=filter_eps)
251
252 CALL timestop(handle)
253
254 END SUBROUTINE make_inverse_update
255
256! **************************************************************************************************
257!> \brief computes an approximation to the condition number of a matrix using
258!> arnoldi iterations
259!> \param matrix ...
260!> \param cond_num ...
261! **************************************************************************************************
262 SUBROUTINE estimate_cond_num(matrix, cond_num)
263 TYPE(dbcsr_type), POINTER :: matrix
264 REAL(kind=dp) :: cond_num
265
266 CHARACTER(len=*), PARAMETER :: routinen = 'estimate_cond_num'
267
268 INTEGER :: handle
269 REAL(kind=dp) :: max_ev, min_ev
270 TYPE(arnoldi_data_type) :: my_arnoldi
271 TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrices
272
273 CALL timeset(routinen, handle)
274
275 ! its better to do 2 calculations as the maximum should quickly converge and the minimum won't need iram
276 ALLOCATE (matrices(1))
277 matrices(1)%matrix => matrix
278 ! compute the minimum ev
279 CALL setup_arnoldi_data(my_arnoldi, matrices, max_iter=20, threshold=5.0e-4_dp, selection_crit=2, &
280 nval_request=1, nrestarts=15, generalized_ev=.false., iram=.false.)
281 CALL arnoldi_ev(matrices, my_arnoldi)
282 max_ev = real(get_selected_ritz_val(my_arnoldi, 1), dp)
283 CALL deallocate_arnoldi_data(my_arnoldi)
284
285 CALL setup_arnoldi_data(my_arnoldi, matrices, max_iter=20, threshold=5.0e-4_dp, selection_crit=3, &
286 nval_request=1, nrestarts=15, generalized_ev=.false., iram=.false.)
287 CALL arnoldi_ev(matrices, my_arnoldi)
288 min_ev = real(get_selected_ritz_val(my_arnoldi, 1), dp)
289 CALL deallocate_arnoldi_data(my_arnoldi)
290
291 cond_num = max_ev/min_ev
292 DEALLOCATE (matrices)
293
294 CALL timestop(handle)
295 END SUBROUTINE estimate_cond_num
296
297! **************************************************************************************************
298!> \brief transfers a full matrix to a dbcsr
299!> \param fm_matrix a full matrix gets deallocated in the end
300!> \param dbcsr_matrix a dbcsr matrix, gets create from a template
301!> \param template_mat the template which is used for the structure
302! **************************************************************************************************
303 SUBROUTINE transfer_fm_to_dbcsr(fm_matrix, dbcsr_matrix, template_mat)
304
305 TYPE(cp_fm_type), POINTER :: fm_matrix
306 TYPE(dbcsr_type), POINTER :: dbcsr_matrix, template_mat
307
308 CHARACTER(len=*), PARAMETER :: routinen = 'transfer_fm_to_dbcsr'
309
310 INTEGER :: handle
311
312 CALL timeset(routinen, handle)
313 IF (ASSOCIATED(fm_matrix)) THEN
314 IF (.NOT. ASSOCIATED(dbcsr_matrix)) THEN
315 CALL dbcsr_init_p(dbcsr_matrix)
316 CALL dbcsr_create(dbcsr_matrix, template=template_mat, &
317 name="preconditioner_env%dbcsr_matrix", &
318 matrix_type=dbcsr_type_no_symmetry, &
319 nze=0, data_type=dbcsr_type_real_8)
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:15
subroutine, public arnoldi_ev(matrix, arnoldi_data)
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
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_upper_to_full(matrix, work)
given an upper triangular matrix 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, use_sp)
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