(git:d18deda)
Loading...
Searching...
No Matches
qs_ot_eigensolver.F
Go to the documentation of this file.
1!--------------------------------------------------------------------------------------------------!
2! CP2K: A general program to perform molecular dynamics simulations !
3! Copyright 2000-2025 CP2K developers group <https://cp2k.org> !
4! !
5! SPDX-License-Identifier: GPL-2.0-or-later !
6!--------------------------------------------------------------------------------------------------!
7
8! **************************************************************************************************
9!> \brief an eigen-space solver for the generalised symmetric eigenvalue problem
10!> for sparse matrices, needing only multiplications
11!> \author Joost VandeVondele (25.08.2002)
12! **************************************************************************************************
14 USE cp_dbcsr_api, ONLY: &
16 dbcsr_set, dbcsr_type, dbcsr_type_no_symmetry
24 USE cp_fm_types, ONLY: cp_fm_get_info,&
27 USE kinds, ONLY: dp
31 USE qs_ot, ONLY: qs_ot_get_orbitals,&
34 USE qs_ot_minimizer, ONLY: ot_mini
35 USE qs_ot_types, ONLY: qs_ot_allocate,&
41#include "./base/base_uses.f90"
42
43 IMPLICIT NONE
44 PRIVATE
45
46! *** Global parameters ***
47
48 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_ot_eigensolver'
49
50! *** Public subroutines ***
51
52 PUBLIC :: ot_eigensolver
53
54CONTAINS
55
56! on input c contains the initial guess (should not be zero !)
57! on output c spans the subspace
58! **************************************************************************************************
59!> \brief ...
60!> \param matrix_h ...
61!> \param matrix_s ...
62!> \param matrix_orthogonal_space_fm ...
63!> \param matrix_c_fm ...
64!> \param preconditioner ...
65!> \param eps_gradient ...
66!> \param iter_max ...
67!> \param size_ortho_space ...
68!> \param silent ...
69!> \param ot_settings ...
70! **************************************************************************************************
71 SUBROUTINE ot_eigensolver(matrix_h, matrix_s, matrix_orthogonal_space_fm, &
72 matrix_c_fm, preconditioner, eps_gradient, &
73 iter_max, size_ortho_space, silent, ot_settings)
74
75 TYPE(dbcsr_type), POINTER :: matrix_h, matrix_s
76 TYPE(cp_fm_type), INTENT(IN), OPTIONAL :: matrix_orthogonal_space_fm
77 TYPE(cp_fm_type), INTENT(INOUT) :: matrix_c_fm
78 TYPE(preconditioner_type), OPTIONAL, POINTER :: preconditioner
79 REAL(kind=dp) :: eps_gradient
80 INTEGER, INTENT(IN) :: iter_max
81 INTEGER, INTENT(IN), OPTIONAL :: size_ortho_space
82 LOGICAL, INTENT(IN), OPTIONAL :: silent
83 TYPE(qs_ot_settings_type), INTENT(IN), OPTIONAL :: ot_settings
84
85 CHARACTER(len=*), PARAMETER :: routinen = 'ot_eigensolver'
86 INTEGER, PARAMETER :: max_iter_inner_loop = 40
87 REAL(kind=dp), PARAMETER :: rone = 1.0_dp, rzero = 0.0_dp
88
89 INTEGER :: handle, ieigensolver, iter_total, k, n, &
90 ortho_k, ortho_space_k, output_unit
91 LOGICAL :: energy_only, my_silent, ortho
92 REAL(kind=dp) :: delta, energy
93 TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_hc
94 TYPE(dbcsr_type), POINTER :: matrix_buf1_ortho, matrix_buf2_ortho, &
95 matrix_c, matrix_orthogonal_space, &
96 matrix_os_ortho, matrix_s_ortho
97 TYPE(qs_ot_type), DIMENSION(:), POINTER :: qs_ot_env
98
99 CALL timeset(routinen, handle)
100
101 output_unit = cp_logger_get_default_io_unit()
102
103 IF (PRESENT(silent)) THEN
104 my_silent = silent
105 ELSE
106 my_silent = .false.
107 END IF
108
109 NULLIFY (matrix_c) ! fm->dbcsr
110
111 CALL cp_fm_get_info(matrix_c_fm, nrow_global=n, ncol_global=k) ! fm->dbcsr
112 ALLOCATE (matrix_c)
113 CALL cp_fm_to_dbcsr_row_template(matrix_c, fm_in=matrix_c_fm, template=matrix_h)
114
115 iter_total = 0
116
117 outer_scf: DO
118
119 NULLIFY (qs_ot_env)
120
121 NULLIFY (matrix_s_ortho)
122 NULLIFY (matrix_os_ortho)
123 NULLIFY (matrix_buf1_ortho)
124 NULLIFY (matrix_buf2_ortho)
125 NULLIFY (matrix_orthogonal_space)
126
127 ALLOCATE (qs_ot_env(1))
128 ALLOCATE (matrix_hc(1))
129 NULLIFY (matrix_hc(1)%matrix)
130 CALL dbcsr_init_p(matrix_hc(1)%matrix)
131 CALL dbcsr_copy(matrix_hc(1)%matrix, matrix_c, 'matrix_hc')
132
133 ortho = .false.
134 IF (PRESENT(matrix_orthogonal_space_fm)) ortho = .true.
135
136 ! decide settings
137 IF (PRESENT(ot_settings)) THEN
138 qs_ot_env(1)%settings = ot_settings
139 ELSE
140 CALL qs_ot_settings_init(qs_ot_env(1)%settings)
141 ! overwrite defaults
142 qs_ot_env(1)%settings%ds_min = 0.10_dp
143 END IF
144
145 IF (ortho) THEN
146 ALLOCATE (matrix_orthogonal_space)
147 CALL cp_fm_to_dbcsr_row_template(matrix_orthogonal_space, fm_in=matrix_orthogonal_space_fm, template=matrix_h)
148 CALL cp_fm_get_info(matrix_orthogonal_space_fm, ncol_global=ortho_space_k)
149
150 IF (PRESENT(size_ortho_space)) ortho_space_k = size_ortho_space
151 ortho_k = ortho_space_k + k
152 ELSE
153 ortho_k = k
154 END IF
155
156 ! allocate
157 CALL qs_ot_allocate(qs_ot_env(1), matrix_s, matrix_c_fm%matrix_struct, ortho_k=ortho_k)
158
159 IF (ortho) THEN
160 ! construct an initial guess that is orthogonal to matrix_orthogonal_space
161
162 CALL dbcsr_init_p(matrix_s_ortho)
163 CALL dbcsr_copy(matrix_s_ortho, matrix_orthogonal_space, name="matrix_s_ortho")
164
165 CALL dbcsr_init_p(matrix_os_ortho)
166 CALL cp_dbcsr_m_by_n_from_template(matrix_os_ortho, template=matrix_h, m=ortho_space_k, n=ortho_space_k, &
167 sym=dbcsr_type_no_symmetry)
168
169 CALL dbcsr_init_p(matrix_buf1_ortho)
170 CALL cp_dbcsr_m_by_n_from_template(matrix_buf1_ortho, template=matrix_h, m=ortho_space_k, n=k, &
171 sym=dbcsr_type_no_symmetry)
172
173 CALL dbcsr_init_p(matrix_buf2_ortho)
174 CALL cp_dbcsr_m_by_n_from_template(matrix_buf2_ortho, template=matrix_h, m=ortho_space_k, n=k, &
175 sym=dbcsr_type_no_symmetry)
176
177 CALL dbcsr_multiply('N', 'N', 1.0_dp, matrix_s, matrix_orthogonal_space, &
178 0.0_dp, matrix_s_ortho)
179 CALL dbcsr_multiply('T', 'N', rone, matrix_s_ortho, matrix_s_ortho, &
180 rzero, matrix_os_ortho)
181
182 CALL cp_dbcsr_cholesky_decompose(matrix_os_ortho, &
183 para_env=qs_ot_env(1)%para_env, blacs_env=qs_ot_env(1)%blacs_env)
184 CALL cp_dbcsr_cholesky_invert(matrix_os_ortho, &
185 para_env=qs_ot_env(1)%para_env, blacs_env=qs_ot_env(1)%blacs_env, &
186 uplo_to_full=.true.)
187
188 CALL dbcsr_multiply('T', 'N', rone, matrix_s_ortho, matrix_c, &
189 rzero, matrix_buf1_ortho)
190 CALL dbcsr_multiply('N', 'N', rone, matrix_os_ortho, matrix_buf1_ortho, &
191 rzero, matrix_buf2_ortho)
192 CALL dbcsr_multiply('N', 'N', -rone, matrix_s_ortho, matrix_buf2_ortho, &
193 rone, matrix_c)
194
195 ! make matrix_c0 an orthogonal basis, matrix_c contains sc0
196 CALL dbcsr_copy(qs_ot_env(1)%matrix_c0, matrix_c)
197 CALL dbcsr_multiply('N', 'N', 1.0_dp, matrix_s, qs_ot_env(1)%matrix_c0, &
198 0.0_dp, matrix_c)
199
200 CALL make_basis_sv(qs_ot_env(1)%matrix_c0, k, matrix_c, &
201 qs_ot_env(1)%para_env, qs_ot_env(1)%blacs_env)
202
203 ! copy sc0 and matrix_s_ortho in qs_ot_env(1)%matrix_sc0
204 !CALL dbcsr_copy_columns(qs_ot_env(1)%matrix_sc0,matrix_s_ortho,ortho_space_k,1,1)
205 CALL dbcsr_copy_columns_hack(qs_ot_env(1)%matrix_sc0, matrix_s_ortho, ortho_space_k, 1, 1, &
206 para_env=qs_ot_env(1)%para_env, blacs_env=qs_ot_env(1)%blacs_env)
207 !CALL dbcsr_copy_columns(qs_ot_env(1)%matrix_sc0,matrix_c,k,1,ortho_space_k+1)
208 CALL dbcsr_copy_columns_hack(qs_ot_env(1)%matrix_sc0, matrix_c, k, 1, ortho_space_k + 1, &
209 para_env=qs_ot_env(1)%para_env, blacs_env=qs_ot_env(1)%blacs_env)
210
211 CALL dbcsr_release_p(matrix_buf1_ortho)
212 CALL dbcsr_release_p(matrix_buf2_ortho)
213 CALL dbcsr_release_p(matrix_os_ortho)
214 CALL dbcsr_release_p(matrix_s_ortho)
215
216 ELSE
217
218 ! set c0,sc0
219 CALL dbcsr_copy(qs_ot_env(1)%matrix_c0, matrix_c)
220 CALL dbcsr_multiply('N', 'N', 1.0_dp, matrix_s, qs_ot_env(1)%matrix_c0, &
221 0.0_dp, qs_ot_env(1)%matrix_sc0)
222
223 CALL make_basis_sv(qs_ot_env(1)%matrix_c0, k, qs_ot_env(1)%matrix_sc0, &
224 qs_ot_env(1)%para_env, qs_ot_env(1)%blacs_env)
225 END IF
226
227 ! init
228 CALL qs_ot_init(qs_ot_env(1))
229 energy_only = qs_ot_env(1)%energy_only
230
231 ! set x
232 CALL dbcsr_set(qs_ot_env(1)%matrix_x, 0.0_dp)
233 CALL dbcsr_set(qs_ot_env(1)%matrix_sx, 0.0_dp)
234
235 ! get c
236 CALL qs_ot_get_p(qs_ot_env(1)%matrix_x, qs_ot_env(1)%matrix_sx, qs_ot_env(1))
237 CALL qs_ot_get_orbitals(matrix_c, qs_ot_env(1)%matrix_x, qs_ot_env(1))
238
239 ! if present preconditioner, use it
240
241 IF (PRESENT(preconditioner)) THEN
242 IF (ASSOCIATED(preconditioner)) THEN
244 CALL qs_ot_new_preconditioner(qs_ot_env(1), preconditioner)
245 ELSE
246 ! we should presumably make one
247 END IF
248 END IF
249 END IF
250
251 ! *** Eigensolver loop ***
252 ieigensolver = 0
253 eigensolver_loop: DO
254
255 ieigensolver = ieigensolver + 1
256 iter_total = iter_total + 1
257
258 ! the energy is cHc, the gradient is 2*H*c
259 CALL dbcsr_multiply('N', 'N', 1.0_dp, matrix_h, matrix_c, &
260 0.0_dp, matrix_hc(1)%matrix)
261 CALL dbcsr_dot(matrix_c, matrix_hc(1)%matrix, energy)
262 IF (.NOT. energy_only) THEN
263 CALL dbcsr_scale(matrix_hc(1)%matrix, 2.0_dp)
264 END IF
265
266 qs_ot_env(1)%etotal = energy
267 CALL ot_mini(qs_ot_env, matrix_hc)
268 delta = qs_ot_env(1)%delta
269 energy_only = qs_ot_env(1)%energy_only
270
271 CALL dbcsr_multiply('N', 'N', 1.0_dp, matrix_s, qs_ot_env(1)%matrix_x, &
272 0.0_dp, qs_ot_env(1)%matrix_sx)
273
274 CALL qs_ot_get_p(qs_ot_env(1)%matrix_x, qs_ot_env(1)%matrix_sx, qs_ot_env(1))
275 CALL qs_ot_get_orbitals(matrix_c, qs_ot_env(1)%matrix_x, qs_ot_env(1))
276
277 ! exit on convergence or if maximum of inner loop cycles is reached
278 IF (delta < eps_gradient .OR. ieigensolver >= max_iter_inner_loop) EXIT eigensolver_loop
279 ! exit if total number of steps is reached, but not during a line search step
280 IF (iter_total >= iter_max .AND. qs_ot_env(1)%OT_METHOD_FULL /= "OT LS") EXIT eigensolver_loop
281
282 END DO eigensolver_loop
283
284 CALL qs_ot_destroy(qs_ot_env(1))
285 DEALLOCATE (qs_ot_env)
286 CALL dbcsr_release_p(matrix_hc(1)%matrix)
287 DEALLOCATE (matrix_hc)
288 CALL dbcsr_release_p(matrix_orthogonal_space)
289
290 IF (delta < eps_gradient) THEN
291 IF ((output_unit > 0) .AND. .NOT. my_silent) THEN
292 WRITE (unit=output_unit, fmt="(T2,A,I0,A)") &
293 "OT| Eigensolver reached convergence in ", iter_total, " iterations"
294 END IF
295 EXIT outer_scf
296 END IF
297 IF (iter_total >= iter_max) THEN
298 IF (output_unit > 0) THEN
299 IF (my_silent) THEN
300 WRITE (output_unit, "(A,T60,E20.10)") " WARNING OT eigensolver did not converge: current gradient", delta
301 ELSE
302 WRITE (output_unit, *) "WARNING : did not converge in ot_eigensolver"
303 WRITE (output_unit, *) "number of iterations ", iter_total, " exceeded maximum"
304 WRITE (output_unit, *) "current gradient / target gradient", delta, " / ", eps_gradient
305 END IF
306 END IF
307 EXIT outer_scf
308 END IF
309
310 END DO outer_scf
311
312 CALL copy_dbcsr_to_fm(matrix_c, matrix_c_fm) ! fm->dbcsr
313 CALL dbcsr_release_p(matrix_c) ! fm->dbcsr
314
315 CALL timestop(handle)
316
317 END SUBROUTINE ot_eigensolver
318
319END MODULE qs_ot_eigensolver
subroutine, public dbcsr_release_p(matrix)
...
subroutine, public dbcsr_scale(matrix, alpha_scalar)
...
subroutine, public dbcsr_copy(matrix_b, matrix_a, name, keep_sparsity, keep_imaginary)
...
subroutine, public dbcsr_multiply(transa, transb, alpha, matrix_a, matrix_b, beta, matrix_c, first_row, last_row, first_column, last_column, first_k, last_k, retain_sparsity, filter_eps, flop)
...
subroutine, public dbcsr_init_p(matrix)
...
subroutine, public dbcsr_set(matrix, alpha)
...
Interface to (sca)lapack for the Cholesky based procedures.
subroutine, public cp_dbcsr_cholesky_decompose(matrix, n, para_env, blacs_env)
used to replace a symmetric positive def. matrix M with its cholesky decomposition U: M = U^T * U,...
subroutine, public cp_dbcsr_cholesky_invert(matrix, n, para_env, blacs_env, uplo_to_full)
used to replace the cholesky decomposition by the inverse
subroutine, public dbcsr_dot(matrix_a, matrix_b, trace)
Computes the dot product of two matrices, also known as the trace of their matrix product.
DBCSR operations in CP2K.
subroutine, public copy_dbcsr_to_fm(matrix, fm)
Copy a DBCSR matrix to a BLACS matrix.
subroutine, public cp_fm_to_dbcsr_row_template(matrix, fm_in, template)
Utility function to copy a specially shaped fm to dbcsr_matrix The result matrix will be the matrix i...
subroutine, public cp_dbcsr_m_by_n_from_template(matrix, template, m, n, sym)
Utility function to create an arbitrary shaped dbcsr matrix with the same processor grid as the templ...
subroutine, public dbcsr_copy_columns_hack(matrix_b, matrix_a, ncol, source_start, target_start, para_env, blacs_env)
hack for dbcsr_copy_columns
represent a full matrix distributed on many processors
Definition cp_fm_types.F:15
subroutine, public cp_fm_get_info(matrix, name, nrow_global, ncol_global, nrow_block, ncol_block, nrow_local, ncol_local, row_indices, col_indices, local_data, context, nrow_locals, ncol_locals, matrix_struct, para_env)
returns all kind of information about the full matrix
various routines to log and control the output. The idea is that decisions about where to log should ...
integer function, public cp_logger_get_default_io_unit(logger)
returns the unit nr for the ionode (-1 on all other processors) skips as well checks if the procs cal...
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34
types of preconditioners
logical function, public preconditioner_in_use(preconditioner)
...
computes preconditioners, and implements methods to apply them currently used in qs_ot
collects routines that perform operations directly related to MOs
an eigen-space solver for the generalised symmetric eigenvalue problem for sparse matrices,...
subroutine, public ot_eigensolver(matrix_h, matrix_s, matrix_orthogonal_space_fm, matrix_c_fm, preconditioner, eps_gradient, iter_max, size_ortho_space, silent, ot_settings)
...
orbital transformations
subroutine, public ot_mini(qs_ot_env, matrix_hc)
...
orbital transformations
Definition qs_ot_types.F:15
subroutine, public qs_ot_init(qs_ot_env)
init matrices, needs c0 and sc0 so that c0*sc0=1
subroutine, public qs_ot_allocate(qs_ot_env, matrix_s, fm_struct_ref, ortho_k)
allocates the data in qs_ot_env, for a calculation with fm_struct_ref ortho_k allows for specifying a...
subroutine, public qs_ot_settings_init(settings)
sets default values for the settings type
subroutine, public qs_ot_destroy(qs_ot_env)
deallocates data
orbital transformations
Definition qs_ot.F:15
subroutine, public qs_ot_get_p(matrix_x, matrix_sx, qs_ot_env)
computes p=x*S*x and the matrix functionals related matrices
Definition qs_ot.F:748
subroutine, public qs_ot_get_orbitals(matrix_c, matrix_x, qs_ot_env)
c=(c0*cos(p^0.5)+x*sin(p^0.5)*p^(-0.5)) x rot_mat_u this assumes that x is already ortho to S*C0,...
Definition qs_ot.F:1020
subroutine, public qs_ot_new_preconditioner(qs_ot_env, preconditioner)
gets ready to use the preconditioner/ or renew the preconditioner only keeps a pointer to the precond...
Definition qs_ot.F:73
represent a full matrix
notice, this variable needs to be copyable, needed for spins as e.g. in qs_ot_scf
Definition qs_ot_types.F:63