Line data Source code
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 localize wavefunctions
10 : !> linear response scf
11 : !> \par History
12 : !> created 07-2005 [MI]
13 : !> \author MI
14 : ! **************************************************************************************************
15 : MODULE qs_linres_methods
16 : USE cp_control_types, ONLY: dft_control_type
17 : USE cp_dbcsr_api, ONLY: dbcsr_copy,&
18 : dbcsr_p_type,&
19 : dbcsr_set,&
20 : dbcsr_type
21 : USE cp_dbcsr_contrib, ONLY: dbcsr_checksum
22 : USE cp_dbcsr_operations, ONLY: cp_dbcsr_sm_fm_multiply
23 : USE cp_external_control, ONLY: external_control
24 : USE cp_files, ONLY: close_file,&
25 : open_file
26 : USE cp_fm_basic_linalg, ONLY: cp_fm_scale_and_add,&
27 : cp_fm_trace
28 : USE cp_fm_struct, ONLY: cp_fm_struct_create,&
29 : cp_fm_struct_release,&
30 : cp_fm_struct_type
31 : USE cp_fm_types, ONLY: cp_fm_create,&
32 : cp_fm_get_info,&
33 : cp_fm_get_submatrix,&
34 : cp_fm_release,&
35 : cp_fm_set_submatrix,&
36 : cp_fm_to_fm,&
37 : cp_fm_type
38 : USE cp_log_handling, ONLY: cp_get_default_logger,&
39 : cp_logger_type,&
40 : cp_to_string
41 : USE cp_output_handling, ONLY: cp_p_file,&
42 : cp_print_key_finished_output,&
43 : cp_print_key_generate_filename,&
44 : cp_print_key_should_output,&
45 : cp_print_key_unit_nr
46 : USE input_constants, ONLY: do_loc_none,&
47 : op_loc_berry,&
48 : ot_precond_none,&
49 : ot_precond_solver_default,&
50 : state_loc_all
51 : USE input_section_types, ONLY: section_vals_get_subs_vals,&
52 : section_vals_type,&
53 : section_vals_val_get
54 : USE kinds, ONLY: default_path_length,&
55 : default_string_length,&
56 : dp
57 : USE machine, ONLY: m_flush,&
58 : m_walltime
59 : USE message_passing, ONLY: mp_para_env_type
60 : USE parallel_gemm_api, ONLY: parallel_gemm
61 : USE preconditioner, ONLY: apply_preconditioner,&
62 : make_preconditioner
63 : USE qs_2nd_kernel_ao, ONLY: build_dm_response
64 : USE qs_environment_types, ONLY: get_qs_env,&
65 : qs_environment_type
66 : USE qs_gapw_densities, ONLY: prepare_gapw_den
67 : USE qs_linres_kernel, ONLY: apply_op_2
68 : USE qs_linres_types, ONLY: linres_control_type
69 : USE qs_loc_main, ONLY: qs_loc_driver
70 : USE qs_loc_types, ONLY: get_qs_loc_env,&
71 : localized_wfn_control_type,&
72 : qs_loc_env_create,&
73 : qs_loc_env_type
74 : USE qs_loc_utils, ONLY: loc_write_restart,&
75 : qs_loc_control_init,&
76 : qs_loc_init
77 : USE qs_mo_types, ONLY: get_mo_set,&
78 : mo_set_type
79 : USE qs_p_env_methods, ONLY: p_env_check_i_alloc,&
80 : p_env_update_rho
81 : USE qs_p_env_types, ONLY: qs_p_env_type
82 : USE qs_rho_methods, ONLY: qs_rho_update_rho
83 : USE qs_rho_types, ONLY: qs_rho_type
84 : USE string_utilities, ONLY: xstring
85 : #include "./base/base_uses.f90"
86 :
87 : IMPLICIT NONE
88 :
89 : PRIVATE
90 :
91 : ! *** Public subroutines ***
92 : PUBLIC :: linres_localize, linres_solver
93 : PUBLIC :: linres_write_restart, linres_read_restart
94 : PUBLIC :: build_dm_response
95 :
96 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_linres_methods'
97 :
98 : ! **************************************************************************************************
99 :
100 : CONTAINS
101 :
102 : ! **************************************************************************************************
103 : !> \brief Find the centers and spreads of the wfn,
104 : !> if required apply a localization algorithm
105 : !> \param qs_env ...
106 : !> \param linres_control ...
107 : !> \param nspins ...
108 : !> \param centers_only ...
109 : !> \par History
110 : !> 07.2005 created [MI]
111 : !> \author MI
112 : ! **************************************************************************************************
113 190 : SUBROUTINE linres_localize(qs_env, linres_control, nspins, centers_only)
114 :
115 : TYPE(qs_environment_type), POINTER :: qs_env
116 : TYPE(linres_control_type), POINTER :: linres_control
117 : INTEGER, INTENT(IN) :: nspins
118 : LOGICAL, INTENT(IN), OPTIONAL :: centers_only
119 :
120 : INTEGER :: iounit, ispin, istate, nmoloc(2)
121 : LOGICAL :: my_centers_only
122 190 : TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:) :: mos_localized
123 : TYPE(cp_fm_type), POINTER :: mo_coeff
124 : TYPE(cp_logger_type), POINTER :: logger
125 : TYPE(localized_wfn_control_type), POINTER :: localized_wfn_control
126 190 : TYPE(mo_set_type), DIMENSION(:), POINTER :: mos
127 : TYPE(qs_loc_env_type), POINTER :: qs_loc_env
128 : TYPE(section_vals_type), POINTER :: loc_print_section, loc_section, &
129 : lr_section
130 :
131 190 : NULLIFY (logger, lr_section, loc_section, loc_print_section, localized_wfn_control)
132 380 : logger => cp_get_default_logger()
133 190 : lr_section => section_vals_get_subs_vals(qs_env%input, "PROPERTIES%LINRES")
134 190 : loc_section => section_vals_get_subs_vals(lr_section, "LOCALIZE")
135 190 : loc_print_section => section_vals_get_subs_vals(lr_section, "LOCALIZE%PRINT")
136 : iounit = cp_print_key_unit_nr(logger, lr_section, "PRINT%PROGRAM_RUN_INFO", &
137 190 : extension=".linresLog")
138 190 : my_centers_only = .FALSE.
139 190 : IF (PRESENT(centers_only)) my_centers_only = centers_only
140 :
141 190 : NULLIFY (mos, mo_coeff, qs_loc_env)
142 190 : CALL get_qs_env(qs_env=qs_env, mos=mos)
143 1520 : ALLOCATE (qs_loc_env)
144 190 : CALL qs_loc_env_create(qs_loc_env)
145 190 : linres_control%qs_loc_env => qs_loc_env
146 190 : CALL qs_loc_control_init(qs_loc_env, loc_section, do_homo=.TRUE.)
147 190 : CALL get_qs_loc_env(qs_loc_env, localized_wfn_control=localized_wfn_control)
148 :
149 838 : ALLOCATE (mos_localized(nspins))
150 458 : DO ispin = 1, nspins
151 268 : CALL get_mo_set(mo_set=mos(ispin), mo_coeff=mo_coeff)
152 268 : CALL cp_fm_create(mos_localized(ispin), mo_coeff%matrix_struct)
153 458 : CALL cp_fm_to_fm(mo_coeff, mos_localized(ispin))
154 : END DO
155 :
156 : nmoloc(1:2) = 0
157 190 : IF (my_centers_only) THEN
158 0 : localized_wfn_control%set_of_states = state_loc_all
159 0 : localized_wfn_control%localization_method = do_loc_none
160 0 : localized_wfn_control%operator_type = op_loc_berry
161 : END IF
162 :
163 : CALL qs_loc_init(qs_env, qs_loc_env, loc_section, mos_localized=mos_localized, &
164 190 : do_homo=.TRUE.)
165 :
166 : ! The orbital centers are stored in linres_control%localized_wfn_control
167 458 : DO ispin = 1, nspins
168 : CALL qs_loc_driver(qs_env, qs_loc_env, loc_print_section, myspin=ispin, &
169 268 : ext_mo_coeff=mos_localized(ispin))
170 268 : CALL get_mo_set(mo_set=mos(ispin), mo_coeff=mo_coeff)
171 458 : CALL cp_fm_to_fm(mos_localized(ispin), mo_coeff)
172 : END DO
173 :
174 : CALL loc_write_restart(qs_loc_env, loc_print_section, mos, &
175 190 : mos_localized, do_homo=.TRUE.)
176 190 : CALL cp_fm_release(mos_localized)
177 :
178 : ! Write Centers and Spreads on std out
179 190 : IF (iounit > 0) THEN
180 229 : DO ispin = 1, nspins
181 : WRITE (iounit, "(/,T2,A,I2)") &
182 134 : "WANNIER CENTERS for spin ", ispin
183 : WRITE (iounit, "(/,T18,A,3X,A)") &
184 134 : "--------------- Centers --------------- ", &
185 268 : "--- Spreads ---"
186 1102 : DO istate = 1, SIZE(localized_wfn_control%centers_set(ispin)%array, 2)
187 : WRITE (iounit, "(T5,A6,I6,2X,3f12.6,5X,f12.6)") &
188 3492 : 'state ', istate, localized_wfn_control%centers_set(ispin)%array(1:3, istate), &
189 1880 : localized_wfn_control%centers_set(ispin)%array(4, istate)
190 : END DO
191 : END DO
192 95 : CALL m_flush(iounit)
193 : END IF
194 :
195 570 : END SUBROUTINE linres_localize
196 :
197 : ! **************************************************************************************************
198 : !> \brief scf loop to optimize the first order wavefunctions (psi1)
199 : !> given a perturbation as an operator applied to the ground
200 : !> state orbitals (h1_psi0)
201 : !> psi1 is defined wrt psi0_order (can be a subset of the occupied space)
202 : !> The reference ground state is defined through qs_env (density and ground state MOs)
203 : !> psi1 is orthogonal to the occupied orbitals in the ground state MO set (qs_env%mos)
204 : !> \param p_env ...
205 : !> \param qs_env ...
206 : !> \param psi1 ...
207 : !> \param h1_psi0 ...
208 : !> \param psi0_order ...
209 : !> \param iounit ...
210 : !> \param should_stop ...
211 : !> \par History
212 : !> 07.2005 created [MI]
213 : !> \author MI
214 : ! **************************************************************************************************
215 5044 : SUBROUTINE linres_solver(p_env, qs_env, psi1, h1_psi0, psi0_order, iounit, should_stop)
216 : TYPE(qs_p_env_type) :: p_env
217 : TYPE(qs_environment_type), POINTER :: qs_env
218 : TYPE(cp_fm_type), DIMENSION(:), INTENT(IN) :: psi1, h1_psi0, psi0_order
219 : INTEGER, INTENT(IN) :: iounit
220 : LOGICAL, INTENT(OUT) :: should_stop
221 :
222 : CHARACTER(LEN=*), PARAMETER :: routineN = 'linres_solver'
223 :
224 : INTEGER :: handle, ispin, iter, maxnmo, nao, ncol, &
225 : nmo, nocc, nspins
226 : LOGICAL :: restart
227 : REAL(dp) :: alpha, beta, norm_res, t1, t2
228 5044 : REAL(dp), DIMENSION(:), POINTER :: tr_pAp, tr_rz0, tr_rz00, tr_rz1
229 : TYPE(cp_fm_struct_type), POINTER :: tmp_fm_struct
230 : TYPE(cp_fm_type) :: buf
231 5044 : TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:) :: Ap, chc, mo_coeff_array, p, r, z
232 5044 : TYPE(cp_fm_type), DIMENSION(:), POINTER :: Sc
233 : TYPE(cp_fm_type), POINTER :: mo_coeff
234 5044 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_ks, matrix_s, matrix_t
235 : TYPE(dbcsr_type), POINTER :: matrix_x
236 : TYPE(dft_control_type), POINTER :: dft_control
237 : TYPE(linres_control_type), POINTER :: linres_control
238 5044 : TYPE(mo_set_type), DIMENSION(:), POINTER :: mos
239 : TYPE(mp_para_env_type), POINTER :: para_env
240 :
241 5044 : CALL timeset(routineN, handle)
242 :
243 5044 : NULLIFY (dft_control, linres_control, matrix_s, matrix_t, matrix_ks, para_env)
244 5044 : NULLIFY (mos, tmp_fm_struct, mo_coeff)
245 :
246 5044 : t1 = m_walltime()
247 :
248 : CALL get_qs_env(qs_env=qs_env, &
249 : matrix_ks=matrix_ks, &
250 : matrix_s=matrix_s, &
251 : kinetic=matrix_t, &
252 : dft_control=dft_control, &
253 : linres_control=linres_control, &
254 : para_env=para_env, &
255 5044 : mos=mos)
256 :
257 5044 : nspins = dft_control%nspins
258 5044 : CALL cp_fm_get_info(psi1(1), nrow_global=nao)
259 5044 : maxnmo = 0
260 12140 : DO ispin = 1, nspins
261 7096 : CALL cp_fm_get_info(psi1(ispin), ncol_global=ncol)
262 12140 : maxnmo = MAX(maxnmo, ncol)
263 : END DO
264 : !
265 5044 : CALL check_p_env_init(p_env, linres_control, nspins)
266 : !
267 : ! allocate the vectors
268 : ALLOCATE (tr_pAp(nspins), tr_rz0(nspins), tr_rz00(nspins), tr_rz1(nspins), &
269 83868 : r(nspins), p(nspins), z(nspins), Ap(nspins))
270 : !
271 12140 : DO ispin = 1, nspins
272 7096 : CALL cp_fm_create(r(ispin), psi1(ispin)%matrix_struct)
273 7096 : CALL cp_fm_create(p(ispin), psi1(ispin)%matrix_struct)
274 7096 : CALL cp_fm_create(z(ispin), psi1(ispin)%matrix_struct)
275 12140 : CALL cp_fm_create(Ap(ispin), psi1(ispin)%matrix_struct)
276 : END DO
277 : !
278 : ! build C0 occupied vectors and S*C0 matrix
279 34368 : ALLOCATE (Sc(nspins), mo_coeff_array(nspins))
280 12140 : DO ispin = 1, nspins
281 7096 : CALL get_mo_set(mos(ispin), mo_coeff=mo_coeff, homo=nocc)
282 7096 : NULLIFY (tmp_fm_struct)
283 : CALL cp_fm_struct_create(tmp_fm_struct, nrow_global=nao, &
284 : ncol_global=nocc, para_env=para_env, &
285 7096 : context=mo_coeff%matrix_struct%context)
286 7096 : CALL cp_fm_create(mo_coeff_array(ispin), tmp_fm_struct)
287 7096 : CALL cp_fm_to_fm(mo_coeff, mo_coeff_array(ispin), nocc)
288 7096 : CALL cp_fm_create(Sc(ispin), tmp_fm_struct)
289 19236 : CALL cp_fm_struct_release(tmp_fm_struct)
290 : END DO
291 : !
292 : ! Allocate C0_order'*H*C0_order
293 22228 : ALLOCATE (chc(nspins))
294 12140 : DO ispin = 1, nspins
295 7096 : CALL cp_fm_get_info(psi1(ispin), ncol_global=nmo)
296 7096 : NULLIFY (tmp_fm_struct)
297 : CALL cp_fm_struct_create(tmp_fm_struct, nrow_global=nmo, &
298 : ncol_global=nmo, para_env=para_env, &
299 7096 : context=mo_coeff%matrix_struct%context)
300 7096 : CALL cp_fm_create(chc(ispin), tmp_fm_struct)
301 19236 : CALL cp_fm_struct_release(tmp_fm_struct)
302 : END DO
303 : !
304 12140 : DO ispin = 1, nspins
305 : !
306 : ! C0_order' * H * C0_order
307 : ASSOCIATE (mo_coeff => psi0_order(ispin))
308 7096 : CALL cp_fm_create(buf, mo_coeff%matrix_struct)
309 7096 : CALL cp_fm_get_info(mo_coeff, ncol_global=ncol)
310 7096 : CALL cp_dbcsr_sm_fm_multiply(matrix_ks(ispin)%matrix, mo_coeff, buf, ncol)
311 7096 : CALL parallel_gemm('T', 'N', ncol, ncol, nao, -1.0_dp, mo_coeff, buf, 0.0_dp, chc(ispin))
312 7096 : CALL cp_fm_release(buf)
313 : END ASSOCIATE
314 : !
315 : ! S * C0
316 7096 : CALL cp_fm_get_info(mo_coeff_array(ispin), ncol_global=ncol)
317 19236 : CALL cp_dbcsr_sm_fm_multiply(matrix_s(1)%matrix, mo_coeff_array(ispin), Sc(ispin), ncol)
318 : END DO
319 : !
320 : ! header
321 5044 : IF (iounit > 0) THEN
322 : WRITE (iounit, "(/,T3,A,T16,A,T25,A,T38,A,T52,A,T72,A,/,T3,A)") &
323 2514 : "Iteration", "Method", "Restart", "Stepsize", "Convergence", "Time", &
324 5028 : REPEAT("-", 78)
325 : END IF
326 : !
327 : ! orthogonalize x with respect to the psi0
328 5044 : CALL preortho(psi1, mo_coeff_array, Sc)
329 : !
330 : ! build the preconditioner
331 5044 : IF (linres_control%preconditioner_type /= ot_precond_none) THEN
332 5044 : IF (p_env%new_preconditioner) THEN
333 2672 : DO ispin = 1, nspins
334 2672 : IF (ASSOCIATED(matrix_t)) THEN
335 : CALL make_preconditioner(p_env%preconditioner(ispin), &
336 : linres_control%preconditioner_type, ot_precond_solver_default, &
337 : matrix_ks(ispin)%matrix, matrix_s(1)%matrix, matrix_t(1)%matrix, &
338 1410 : mos(ispin), linres_control%energy_gap)
339 : ELSE
340 24 : NULLIFY (matrix_x)
341 : CALL make_preconditioner(p_env%preconditioner(ispin), &
342 : linres_control%preconditioner_type, ot_precond_solver_default, &
343 : matrix_ks(ispin)%matrix, matrix_s(1)%matrix, matrix_x, &
344 24 : mos(ispin), linres_control%energy_gap)
345 : END IF
346 : END DO
347 1238 : p_env%new_preconditioner = .FALSE.
348 : END IF
349 : END IF
350 : !
351 : ! initialization of the linear solver
352 : !
353 : ! A * x0
354 5044 : CALL apply_op(qs_env, p_env, psi0_order, psi1, Ap, chc)
355 : !
356 : !
357 : ! r_0 = b - Ax0
358 12140 : DO ispin = 1, nspins
359 7096 : CALL cp_fm_to_fm(h1_psi0(ispin), r(ispin))
360 12140 : CALL cp_fm_scale_and_add(-1.0_dp, r(ispin), -1.0_dp, Ap(ispin))
361 : END DO
362 : !
363 : ! proj r
364 5044 : CALL postortho(r, mo_coeff_array, Sc)
365 : !
366 : ! preconditioner
367 5044 : linres_control%flag = ""
368 5044 : IF (linres_control%preconditioner_type .EQ. ot_precond_none) THEN
369 : !
370 : ! z_0 = r_0
371 0 : DO ispin = 1, nspins
372 0 : CALL cp_fm_to_fm(r(ispin), z(ispin))
373 : END DO
374 0 : linres_control%flag = "CG"
375 : ELSE
376 : !
377 : ! z_0 = M * r_0
378 12140 : DO ispin = 1, nspins
379 : CALL apply_preconditioner(p_env%preconditioner(ispin), r(ispin), &
380 12140 : z(ispin))
381 : END DO
382 5044 : linres_control%flag = "PCG"
383 : END IF
384 : !
385 12140 : DO ispin = 1, nspins
386 : !
387 : ! p_0 = z_0
388 7096 : CALL cp_fm_to_fm(z(ispin), p(ispin))
389 : !
390 : ! trace(r_0 * z_0)
391 12140 : CALL cp_fm_trace(r(ispin), z(ispin), tr_rz0(ispin))
392 : END DO
393 12140 : IF (SUM(tr_rz0) < 0.0_dp) CPABORT("tr(r_j*z_j) < 0")
394 12140 : norm_res = ABS(SUM(tr_rz0))/SQRT(REAL(nspins*nao*maxnmo, dp))
395 : !
396 5044 : alpha = 0.0_dp
397 5044 : restart = .FALSE.
398 5044 : should_stop = .FALSE.
399 33138 : iteration: DO iter = 1, linres_control%max_iter
400 : !
401 : ! check convergence
402 31834 : linres_control%converged = .FALSE.
403 31834 : IF (norm_res .LT. linres_control%eps) THEN
404 3740 : linres_control%converged = .TRUE.
405 : END IF
406 : !
407 31834 : t2 = m_walltime()
408 : IF (iter .EQ. 1 .OR. MOD(iter, 1) .EQ. 0 .OR. linres_control%converged &
409 : .OR. restart .OR. should_stop) THEN
410 31834 : IF (iounit > 0) THEN
411 : WRITE (iounit, "(T5,I5,T18,A3,T28,L1,T38,1E8.2,T48,F16.10,T68,F8.2)") &
412 15851 : iter, linres_control%flag, restart, alpha, norm_res, t2 - t1
413 15851 : CALL m_flush(iounit)
414 : END IF
415 : END IF
416 : !
417 31834 : IF (linres_control%converged) THEN
418 3740 : IF (iounit > 0) THEN
419 1862 : WRITE (iounit, "(T3,A,I4,A)") "The linear solver converged in ", iter, " iterations."
420 1862 : CALL m_flush(iounit)
421 : END IF
422 : EXIT iteration
423 28094 : ELSE IF (should_stop) THEN
424 0 : IF (iounit > 0) THEN
425 0 : WRITE (iounit, "(T3,A,I4,A)") "The linear solver did NOT converge! External stop"
426 0 : CALL m_flush(iounit)
427 : END IF
428 : EXIT iteration
429 : END IF
430 : !
431 : ! Max number of iteration reached
432 28094 : IF (iter == linres_control%max_iter) THEN
433 1304 : IF (iounit > 0) THEN
434 : CALL cp_warn(__LOCATION__, &
435 652 : "The linear solver didn't converge! Maximum number of iterations reached.")
436 652 : CALL m_flush(iounit)
437 : END IF
438 1304 : linres_control%converged = .FALSE.
439 : END IF
440 : !
441 : ! Apply the operators that do not depend on the perturbation
442 28094 : CALL apply_op(qs_env, p_env, psi0_order, p, Ap, chc)
443 : !
444 : ! proj Ap onto the virtual subspace
445 28094 : CALL postortho(Ap, mo_coeff_array, Sc)
446 : !
447 68852 : DO ispin = 1, nspins
448 : !
449 : ! tr(Ap_j*p_j)
450 68852 : CALL cp_fm_trace(Ap(ispin), p(ispin), tr_pAp(ispin))
451 : END DO
452 : !
453 : ! alpha = tr(r_j*z_j) / tr(Ap_j*p_j)
454 68852 : IF (SUM(tr_pAp) < 1.0e-10_dp) THEN
455 172 : alpha = 1.0_dp
456 : ELSE
457 109094 : alpha = SUM(tr_rz0)/SUM(tr_pAp)
458 : END IF
459 68852 : DO ispin = 1, nspins
460 : !
461 : ! x_j+1 = x_j + alpha * p_j
462 68852 : CALL cp_fm_scale_and_add(1.0_dp, psi1(ispin), alpha, p(ispin))
463 : END DO
464 : !
465 : ! need to recompute the residue
466 28094 : restart = .FALSE.
467 28094 : IF (MOD(iter, linres_control%restart_every) .EQ. 0) THEN
468 : !
469 : ! r_j+1 = b - A * x_j+1
470 206 : CALL apply_op(qs_env, p_env, psi0_order, psi1, Ap, chc)
471 : !
472 446 : DO ispin = 1, nspins
473 240 : CALL cp_fm_to_fm(h1_psi0(ispin), r(ispin))
474 446 : CALL cp_fm_scale_and_add(-1.0_dp, r(ispin), -1.0_dp, Ap(ispin))
475 : END DO
476 206 : CALL postortho(r, mo_coeff_array, Sc)
477 : !
478 206 : restart = .TRUE.
479 : ELSE
480 : ! proj Ap onto the virtual subspace
481 27888 : CALL postortho(Ap, mo_coeff_array, Sc)
482 : !
483 : ! r_j+1 = r_j - alpha * Ap_j
484 68406 : DO ispin = 1, nspins
485 68406 : CALL cp_fm_scale_and_add(1.0_dp, r(ispin), -alpha, Ap(ispin))
486 : END DO
487 27888 : restart = .FALSE.
488 : END IF
489 : !
490 : ! preconditioner
491 28094 : linres_control%flag = ""
492 28094 : IF (linres_control%preconditioner_type .EQ. ot_precond_none) THEN
493 : !
494 : ! z_j+1 = r_j+1
495 0 : DO ispin = 1, nspins
496 0 : CALL cp_fm_to_fm(r(ispin), z(ispin))
497 : END DO
498 0 : linres_control%flag = "CG"
499 : ELSE
500 : !
501 : ! z_j+1 = M * r_j+1
502 68852 : DO ispin = 1, nspins
503 : CALL apply_preconditioner(p_env%preconditioner(ispin), r(ispin), &
504 68852 : z(ispin))
505 : END DO
506 28094 : linres_control%flag = "PCG"
507 : END IF
508 : !
509 68852 : DO ispin = 1, nspins
510 : !
511 : ! tr(r_j+1*z_j+1)
512 68852 : CALL cp_fm_trace(r(ispin), z(ispin), tr_rz1(ispin))
513 : END DO
514 68852 : IF (SUM(tr_rz1) < 0.0_dp) CPABORT("tr(r_j+1*z_j+1) < 0")
515 68852 : norm_res = SUM(tr_rz1)/SQRT(REAL(nspins*nao*maxnmo, dp))
516 : !
517 : ! beta = tr(r_j+1*z_j+1) / tr(r_j*z_j)
518 68852 : IF (SUM(tr_rz0) < 1.0e-10_dp) THEN
519 210 : beta = 0.0_dp
520 : ELSE
521 108980 : beta = SUM(tr_rz1)/SUM(tr_rz0)
522 : END IF
523 68852 : DO ispin = 1, nspins
524 : !
525 : ! p_j+1 = z_j+1 + beta * p_j
526 40758 : CALL cp_fm_scale_and_add(beta, p(ispin), 1.0_dp, z(ispin))
527 40758 : tr_rz00(ispin) = tr_rz0(ispin)
528 68852 : tr_rz0(ispin) = tr_rz1(ispin)
529 : END DO
530 : !
531 : ! Can we exit the SCF loop?
532 : CALL external_control(should_stop, "LINRES", target_time=qs_env%target_time, &
533 29398 : start_time=qs_env%start_time)
534 :
535 : END DO iteration
536 : !
537 : ! proj psi1
538 5044 : CALL preortho(psi1, mo_coeff_array, Sc)
539 : !
540 : !
541 : ! clean up
542 5044 : CALL cp_fm_release(r)
543 5044 : CALL cp_fm_release(p)
544 5044 : CALL cp_fm_release(z)
545 5044 : CALL cp_fm_release(Ap)
546 : !
547 5044 : CALL cp_fm_release(mo_coeff_array)
548 5044 : CALL cp_fm_release(Sc)
549 5044 : CALL cp_fm_release(chc)
550 : !
551 5044 : DEALLOCATE (tr_pAp, tr_rz0, tr_rz00, tr_rz1)
552 : !
553 5044 : CALL timestop(handle)
554 : !
555 15132 : END SUBROUTINE linres_solver
556 :
557 : ! **************************************************************************************************
558 : !> \brief ...
559 : !> \param qs_env ...
560 : !> \param p_env ...
561 : !> \param c0 ...
562 : !> \param v ...
563 : !> \param Av ...
564 : !> \param chc ...
565 : ! **************************************************************************************************
566 33344 : SUBROUTINE apply_op(qs_env, p_env, c0, v, Av, chc)
567 : !
568 : TYPE(qs_environment_type), INTENT(IN), POINTER :: qs_env
569 : TYPE(qs_p_env_type) :: p_env
570 : TYPE(cp_fm_type), DIMENSION(:), INTENT(IN) :: c0, v
571 : TYPE(cp_fm_type), DIMENSION(:), INTENT(INOUT) :: Av
572 : TYPE(cp_fm_type), DIMENSION(:), INTENT(IN) :: chc
573 :
574 : CHARACTER(LEN=*), PARAMETER :: routineN = 'apply_op'
575 :
576 : INTEGER :: handle, ispin, nc1, nc2, nc3, nc4, nr1, &
577 : nr2, nr3, nr4, nspins
578 : REAL(dp) :: chksum
579 33344 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_ks, matrix_s
580 : TYPE(dft_control_type), POINTER :: dft_control
581 : TYPE(linres_control_type), POINTER :: linres_control
582 : TYPE(qs_rho_type), POINTER :: rho
583 :
584 33344 : CALL timeset(routineN, handle)
585 :
586 33344 : NULLIFY (dft_control, matrix_ks, matrix_s, linres_control)
587 : CALL get_qs_env(qs_env=qs_env, &
588 : matrix_ks=matrix_ks, &
589 : matrix_s=matrix_s, &
590 : dft_control=dft_control, &
591 33344 : linres_control=linres_control)
592 :
593 33344 : nspins = dft_control%nspins
594 :
595 81438 : DO ispin = 1, nspins
596 : !c0, v, Av, chc
597 48094 : CALL cp_fm_get_info(c0(ispin), ncol_global=nc1, nrow_global=nr1)
598 48094 : CALL cp_fm_get_info(v(ispin), ncol_global=nc2, nrow_global=nr2)
599 48094 : CALL cp_fm_get_info(Av(ispin), ncol_global=nc3, nrow_global=nr3)
600 48094 : CALL cp_fm_get_info(chc(ispin), ncol_global=nc4, nrow_global=nr4)
601 48094 : IF (.NOT. (nc1 == nc2 .AND. nr1 == nr2 .AND. nc1 == nc3 .AND. nr1 == nr3 &
602 81438 : .AND. nc4 == nr4 .AND. nc1 <= nc4)) THEN
603 : CALL cp_abort(__LOCATION__, &
604 0 : "Number of vectors inconsistent or CHC matrix too small")
605 : END IF
606 : END DO
607 :
608 : ! apply the uncoupled operator
609 81438 : DO ispin = 1, nspins
610 : CALL apply_op_1(v(ispin), Av(ispin), matrix_ks(ispin)%matrix, &
611 81438 : matrix_s(1)%matrix, chc(ispin))
612 : END DO
613 :
614 33344 : IF (linres_control%do_kernel) THEN
615 :
616 : ! build DM, refill p1, build_dm_response keeps sparse structure
617 19330 : DO ispin = 1, nspins
618 19330 : CALL dbcsr_copy(p_env%p1(ispin)%matrix, matrix_s(1)%matrix)
619 : END DO
620 9162 : CALL build_dm_response(c0, v, p_env%p1)
621 :
622 9162 : chksum = 0.0_dp
623 19330 : DO ispin = 1, nspins
624 19330 : chksum = chksum + dbcsr_checksum(p_env%p1(ispin)%matrix)
625 : END DO
626 :
627 : ! skip the kernel if the DM is very small
628 9162 : IF (chksum .GT. 1.0E-14_dp) THEN
629 :
630 7730 : CALL p_env_check_i_alloc(p_env, qs_env)
631 :
632 7730 : CALL p_env_update_rho(p_env, qs_env)
633 :
634 7730 : CALL get_qs_env(qs_env, rho=rho) ! that could be called before
635 7730 : CALL qs_rho_update_rho(rho, qs_env=qs_env) ! that could be called before
636 7730 : IF (dft_control%qs_control%gapw) THEN
637 792 : CALL prepare_gapw_den(qs_env)
638 6938 : ELSEIF (dft_control%qs_control%gapw_xc) THEN
639 352 : CALL prepare_gapw_den(qs_env, do_rho0=.FALSE.)
640 : END IF
641 :
642 16316 : DO ispin = 1, nspins
643 8586 : CALL dbcsr_set(p_env%kpp1(ispin)%matrix, 0.0_dp)
644 16316 : IF (ASSOCIATED(p_env%kpp1_admm)) CALL dbcsr_set(p_env%kpp1_admm(ispin)%matrix, 0.0_dp)
645 : END DO
646 :
647 7730 : CALL apply_op_2(qs_env, p_env, c0, Av)
648 :
649 : END IF
650 :
651 : END IF
652 :
653 33344 : CALL timestop(handle)
654 :
655 33344 : END SUBROUTINE apply_op
656 :
657 : ! **************************************************************************************************
658 : !> \brief ...
659 : !> \param v ...
660 : !> \param Av ...
661 : !> \param matrix_ks ...
662 : !> \param matrix_s ...
663 : !> \param chc ...
664 : ! **************************************************************************************************
665 144282 : SUBROUTINE apply_op_1(v, Av, matrix_ks, matrix_s, chc)
666 : !
667 : TYPE(cp_fm_type), INTENT(IN) :: v
668 : TYPE(cp_fm_type), INTENT(INOUT) :: Av
669 : TYPE(dbcsr_type), INTENT(IN) :: matrix_ks, matrix_s
670 : TYPE(cp_fm_type), INTENT(IN) :: chc
671 :
672 : CHARACTER(LEN=*), PARAMETER :: routineN = 'apply_op_1'
673 :
674 : INTEGER :: handle, ncol, nrow
675 : TYPE(cp_fm_type) :: buf
676 :
677 48094 : CALL timeset(routineN, handle)
678 : !
679 48094 : CALL cp_fm_create(buf, v%matrix_struct)
680 : !
681 48094 : CALL cp_fm_get_info(v, ncol_global=ncol, nrow_global=nrow)
682 : ! H * v
683 48094 : CALL cp_dbcsr_sm_fm_multiply(matrix_ks, v, Av, ncol)
684 : ! v * e (chc already multiplied by -1)
685 48094 : CALL parallel_gemm('N', 'N', nrow, ncol, ncol, 1.0_dp, v, chc, 0.0_dp, buf)
686 : ! S * ve
687 48094 : CALL cp_dbcsr_sm_fm_multiply(matrix_s, buf, Av, ncol, alpha=1.0_dp, beta=1.0_dp)
688 : !Results is H*C1 - S*<iHj>*C1
689 : !
690 48094 : CALL cp_fm_release(buf)
691 : !
692 48094 : CALL timestop(handle)
693 : !
694 48094 : END SUBROUTINE apply_op_1
695 :
696 : !MERGE
697 : ! **************************************************************************************************
698 : !> \brief ...
699 : !> \param v ...
700 : !> \param psi0 ...
701 : !> \param S_psi0 ...
702 : ! **************************************************************************************************
703 10088 : SUBROUTINE preortho(v, psi0, S_psi0)
704 : !v = (I-PS)v
705 : !
706 : TYPE(cp_fm_type), DIMENSION(:), INTENT(IN) :: v, psi0, S_psi0
707 :
708 : CHARACTER(LEN=*), PARAMETER :: routineN = 'preortho'
709 :
710 : INTEGER :: handle, ispin, mp, mt, mv, np, nspins, &
711 : nt, nv
712 : TYPE(cp_fm_struct_type), POINTER :: tmp_fm_struct
713 : TYPE(cp_fm_type) :: buf
714 :
715 10088 : CALL timeset(routineN, handle)
716 : !
717 10088 : NULLIFY (tmp_fm_struct)
718 : !
719 10088 : nspins = SIZE(v, 1)
720 : !
721 24280 : DO ispin = 1, nspins
722 14192 : CALL cp_fm_get_info(v(ispin), ncol_global=mv, nrow_global=nv)
723 14192 : CALL cp_fm_get_info(psi0(ispin), ncol_global=mp, nrow_global=np)
724 : !
725 : CALL cp_fm_struct_create(tmp_fm_struct, nrow_global=nv, ncol_global=mp, &
726 : para_env=v(ispin)%matrix_struct%para_env, &
727 14192 : context=v(ispin)%matrix_struct%context)
728 14192 : CALL cp_fm_create(buf, tmp_fm_struct)
729 14192 : CALL cp_fm_struct_release(tmp_fm_struct)
730 : !
731 14192 : CALL cp_fm_get_info(buf, ncol_global=mt, nrow_global=nt)
732 14192 : CPASSERT(nv == np)
733 14192 : CPASSERT(mt >= mv)
734 14192 : CPASSERT(mt >= mp)
735 14192 : CPASSERT(nt == nv)
736 : !
737 : ! buf = v' * S_psi0
738 14192 : CALL parallel_gemm('T', 'N', mv, mp, nv, 1.0_dp, v(ispin), S_psi0(ispin), 0.0_dp, buf)
739 : ! v = v - psi0 * buf'
740 14192 : CALL parallel_gemm('N', 'T', nv, mv, mp, -1.0_dp, psi0(ispin), buf, 1.0_dp, v(ispin))
741 : !
742 66856 : CALL cp_fm_release(buf)
743 : END DO
744 : !
745 10088 : CALL timestop(handle)
746 : !
747 10088 : END SUBROUTINE preortho
748 :
749 : ! **************************************************************************************************
750 : !> \brief projects first index of v onto the virtual subspace
751 : !> \param v matrix to be projected
752 : !> \param psi0 matrix with occupied orbitals
753 : !> \param S_psi0 matrix containing product of metric and occupied orbitals
754 : ! **************************************************************************************************
755 61232 : SUBROUTINE postortho(v, psi0, S_psi0)
756 : !v = (I-SP)v
757 : !
758 : TYPE(cp_fm_type), DIMENSION(:), INTENT(IN) :: v, psi0, S_psi0
759 :
760 : CHARACTER(LEN=*), PARAMETER :: routineN = 'postortho'
761 :
762 : INTEGER :: handle, ispin, mp, mt, mv, np, nspins, &
763 : nt, nv
764 : TYPE(cp_fm_struct_type), POINTER :: tmp_fm_struct
765 : TYPE(cp_fm_type) :: buf
766 :
767 61232 : CALL timeset(routineN, handle)
768 : !
769 61232 : NULLIFY (tmp_fm_struct)
770 : !
771 61232 : nspins = SIZE(v, 1)
772 : !
773 149844 : DO ispin = 1, nspins
774 88612 : CALL cp_fm_get_info(v(ispin), ncol_global=mv, nrow_global=nv)
775 88612 : CALL cp_fm_get_info(psi0(ispin), ncol_global=mp, nrow_global=np)
776 : !
777 : CALL cp_fm_struct_create(tmp_fm_struct, nrow_global=nv, ncol_global=mp, &
778 : para_env=v(ispin)%matrix_struct%para_env, &
779 88612 : context=v(ispin)%matrix_struct%context)
780 88612 : CALL cp_fm_create(buf, tmp_fm_struct)
781 88612 : CALL cp_fm_struct_release(tmp_fm_struct)
782 : !
783 88612 : CALL cp_fm_get_info(buf, ncol_global=mt, nrow_global=nt)
784 88612 : CPASSERT(nv == np)
785 88612 : CPASSERT(mt >= mv)
786 88612 : CPASSERT(mt >= mp)
787 88612 : CPASSERT(nt == nv)
788 : !
789 : ! buf = v' * psi0
790 88612 : CALL parallel_gemm('T', 'N', mv, mp, nv, 1.0_dp, v(ispin), psi0(ispin), 0.0_dp, buf)
791 : ! v = v - S_psi0 * buf'
792 88612 : CALL parallel_gemm('N', 'T', nv, mv, mp, -1.0_dp, S_psi0(ispin), buf, 1.0_dp, v(ispin))
793 : !
794 415680 : CALL cp_fm_release(buf)
795 : END DO
796 : !
797 61232 : CALL timestop(handle)
798 : !
799 61232 : END SUBROUTINE postortho
800 :
801 : ! **************************************************************************************************
802 : !> \brief ...
803 : !> \param qs_env ...
804 : !> \param linres_section ...
805 : !> \param vec ...
806 : !> \param ivec ...
807 : !> \param tag ...
808 : !> \param ind ...
809 : ! **************************************************************************************************
810 3522 : SUBROUTINE linres_write_restart(qs_env, linres_section, vec, ivec, tag, ind)
811 : TYPE(qs_environment_type), POINTER :: qs_env
812 : TYPE(section_vals_type), POINTER :: linres_section
813 : TYPE(cp_fm_type), DIMENSION(:), INTENT(IN) :: vec
814 : INTEGER, INTENT(IN) :: ivec
815 : CHARACTER(LEN=*) :: tag
816 : INTEGER, INTENT(IN), OPTIONAL :: ind
817 :
818 : CHARACTER(LEN=*), PARAMETER :: routineN = 'linres_write_restart'
819 :
820 : CHARACTER(LEN=default_path_length) :: filename
821 : CHARACTER(LEN=default_string_length) :: my_middle, my_pos, my_status
822 : INTEGER :: handle, i, i_block, ia, ie, iounit, &
823 : ispin, j, max_block, nao, nmo, nspins, &
824 : rst_unit
825 3522 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: vecbuffer
826 : TYPE(cp_fm_type), POINTER :: mo_coeff
827 : TYPE(cp_logger_type), POINTER :: logger
828 3522 : TYPE(mo_set_type), DIMENSION(:), POINTER :: mos
829 : TYPE(mp_para_env_type), POINTER :: para_env
830 : TYPE(section_vals_type), POINTER :: print_key
831 :
832 3522 : NULLIFY (logger, mo_coeff, mos, para_env, print_key, vecbuffer)
833 :
834 3522 : CALL timeset(routineN, handle)
835 :
836 3522 : logger => cp_get_default_logger()
837 :
838 3522 : IF (BTEST(cp_print_key_should_output(logger%iter_info, linres_section, "PRINT%RESTART", &
839 : used_print_key=print_key), &
840 : cp_p_file)) THEN
841 :
842 : iounit = cp_print_key_unit_nr(logger, linres_section, &
843 3522 : "PRINT%PROGRAM_RUN_INFO", extension=".Log")
844 :
845 : CALL get_qs_env(qs_env=qs_env, &
846 : mos=mos, &
847 3522 : para_env=para_env)
848 :
849 3522 : nspins = SIZE(mos)
850 :
851 3522 : my_status = "REPLACE"
852 3522 : my_pos = "REWIND"
853 3522 : CALL XSTRING(tag, ia, ie)
854 3522 : IF (PRESENT(ind)) THEN
855 2460 : my_middle = "RESTART-"//tag(ia:ie)//TRIM(ADJUSTL(cp_to_string(ivec)))
856 : ELSE
857 1062 : my_middle = "RESTART-"//tag(ia:ie)
858 1062 : IF (ivec > 1) THEN
859 708 : my_status = "OLD"
860 708 : my_pos = "APPEND"
861 : END IF
862 : END IF
863 : rst_unit = cp_print_key_unit_nr(logger, linres_section, "PRINT%RESTART", &
864 : extension=".lr", middle_name=TRIM(my_middle), file_status=TRIM(my_status), &
865 3522 : file_position=TRIM(my_pos), file_action="WRITE", file_form="UNFORMATTED")
866 :
867 : filename = cp_print_key_generate_filename(logger, print_key, &
868 3522 : extension=".lr", middle_name=TRIM(my_middle), my_local=.FALSE.)
869 :
870 3522 : IF (iounit > 0) THEN
871 : WRITE (UNIT=iounit, FMT="(T2,A)") &
872 1761 : "LINRES| Writing response functions to the restart file <"//TRIM(ADJUSTL(filename))//">"
873 : END IF
874 :
875 : !
876 : ! write data to file
877 : ! use the scalapack block size as a default for buffering columns
878 3522 : CALL get_mo_set(mos(1), mo_coeff=mo_coeff)
879 3522 : CALL cp_fm_get_info(mo_coeff, nrow_global=nao, ncol_block=max_block)
880 14088 : ALLOCATE (vecbuffer(nao, max_block))
881 :
882 3522 : IF (PRESENT(ind)) THEN
883 2460 : IF (rst_unit > 0) WRITE (rst_unit) ind, ivec, nspins, nao
884 : ELSE
885 1062 : IF (rst_unit > 0) WRITE (rst_unit) ivec, nspins, nao
886 : END IF
887 :
888 8934 : DO ispin = 1, nspins
889 5412 : CALL cp_fm_get_info(vec(ispin), ncol_global=nmo)
890 :
891 5412 : IF (rst_unit > 0) WRITE (rst_unit) nmo
892 :
893 22494 : DO i = 1, nmo, MAX(max_block, 1)
894 8148 : i_block = MIN(max_block, nmo - i + 1)
895 8148 : CALL cp_fm_get_submatrix(vec(ispin), vecbuffer, 1, i, nao, i_block)
896 : ! doing this in one write would increase efficiency, but breaks RESTART compatibility.
897 : ! to old ones, and in cases where max_block is different between runs, as might happen during
898 : ! restarts with a different number of CPUs
899 50352 : DO j = 1, i_block
900 44940 : IF (rst_unit > 0) WRITE (rst_unit) vecbuffer(1:nao, j)
901 : END DO
902 : END DO
903 : END DO
904 :
905 3522 : DEALLOCATE (vecbuffer)
906 :
907 : CALL cp_print_key_finished_output(rst_unit, logger, linres_section, &
908 7044 : "PRINT%RESTART")
909 : END IF
910 :
911 3522 : CALL timestop(handle)
912 :
913 3522 : END SUBROUTINE linres_write_restart
914 :
915 : ! **************************************************************************************************
916 : !> \brief ...
917 : !> \param qs_env ...
918 : !> \param linres_section ...
919 : !> \param vec ...
920 : !> \param ivec ...
921 : !> \param tag ...
922 : !> \param ind ...
923 : ! **************************************************************************************************
924 72 : SUBROUTINE linres_read_restart(qs_env, linres_section, vec, ivec, tag, ind)
925 : TYPE(qs_environment_type), POINTER :: qs_env
926 : TYPE(section_vals_type), POINTER :: linres_section
927 : TYPE(cp_fm_type), DIMENSION(:), INTENT(IN) :: vec
928 : INTEGER, INTENT(IN) :: ivec
929 : CHARACTER(LEN=*) :: tag
930 : INTEGER, INTENT(INOUT), OPTIONAL :: ind
931 :
932 : CHARACTER(LEN=*), PARAMETER :: routineN = 'linres_read_restart'
933 :
934 : CHARACTER(LEN=default_path_length) :: filename
935 : CHARACTER(LEN=default_string_length) :: my_middle
936 : INTEGER :: handle, i, i_block, ia, ie, iostat, iounit, ispin, iv, iv1, ivec_tmp, j, &
937 : max_block, n_rep_val, nao, nao_tmp, nmo, nmo_tmp, nspins, nspins_tmp, rst_unit
938 : LOGICAL :: file_exists
939 72 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: vecbuffer
940 : TYPE(cp_fm_type), POINTER :: mo_coeff
941 : TYPE(cp_logger_type), POINTER :: logger
942 72 : TYPE(mo_set_type), DIMENSION(:), POINTER :: mos
943 : TYPE(mp_para_env_type), POINTER :: para_env
944 : TYPE(section_vals_type), POINTER :: print_key
945 :
946 72 : file_exists = .FALSE.
947 :
948 72 : CALL timeset(routineN, handle)
949 :
950 72 : NULLIFY (mos, para_env, logger, print_key, vecbuffer)
951 72 : logger => cp_get_default_logger()
952 :
953 : iounit = cp_print_key_unit_nr(logger, linres_section, &
954 72 : "PRINT%PROGRAM_RUN_INFO", extension=".Log")
955 :
956 : CALL get_qs_env(qs_env=qs_env, &
957 : para_env=para_env, &
958 72 : mos=mos)
959 :
960 72 : nspins = SIZE(mos)
961 :
962 72 : rst_unit = -1
963 72 : IF (para_env%is_source()) THEN
964 : CALL section_vals_val_get(linres_section, "WFN_RESTART_FILE_NAME", &
965 36 : n_rep_val=n_rep_val)
966 :
967 36 : CALL XSTRING(tag, ia, ie)
968 36 : IF (PRESENT(ind)) THEN
969 9 : my_middle = "RESTART-"//tag(ia:ie)//TRIM(ADJUSTL(cp_to_string(ivec)))
970 : ELSE
971 27 : my_middle = "RESTART-"//tag(ia:ie)
972 : END IF
973 :
974 36 : IF (n_rep_val > 0) THEN
975 18 : CALL section_vals_val_get(linres_section, "WFN_RESTART_FILE_NAME", c_val=filename)
976 18 : CALL xstring(filename, ia, ie)
977 18 : filename = filename(ia:ie)//TRIM(my_middle)//".lr"
978 : ELSE
979 : ! try to read from the filename that is generated automatically from the printkey
980 18 : print_key => section_vals_get_subs_vals(linres_section, "PRINT%RESTART")
981 : filename = cp_print_key_generate_filename(logger, print_key, &
982 18 : extension=".lr", middle_name=TRIM(my_middle), my_local=.FALSE.)
983 : END IF
984 36 : INQUIRE (FILE=filename, exist=file_exists)
985 : !
986 : ! open file
987 36 : IF (file_exists) THEN
988 : CALL open_file(file_name=TRIM(filename), &
989 : file_action="READ", &
990 : file_form="UNFORMATTED", &
991 : file_position="REWIND", &
992 : file_status="OLD", &
993 15 : unit_number=rst_unit)
994 :
995 15 : IF (iounit > 0) WRITE (iounit, "(T2,A)") &
996 15 : "LINRES| Reading response wavefunctions from the restart file <"//TRIM(ADJUSTL(filename))//">"
997 : ELSE
998 21 : IF (iounit > 0) WRITE (iounit, "(T2,A)") &
999 21 : "LINRES| Restart file <"//TRIM(ADJUSTL(filename))//"> not found"
1000 : END IF
1001 : END IF
1002 :
1003 72 : CALL para_env%bcast(file_exists)
1004 :
1005 72 : IF (file_exists) THEN
1006 :
1007 30 : CALL get_mo_set(mos(1), mo_coeff=mo_coeff)
1008 30 : CALL cp_fm_get_info(mo_coeff, nrow_global=nao, ncol_block=max_block)
1009 :
1010 120 : ALLOCATE (vecbuffer(nao, max_block))
1011 : !
1012 : ! read headers
1013 30 : IF (PRESENT(ind)) THEN
1014 6 : iv1 = ivec
1015 : ELSE
1016 : iv1 = 1
1017 : END IF
1018 54 : DO iv = iv1, ivec
1019 :
1020 54 : IF (PRESENT(ind)) THEN
1021 6 : IF (rst_unit > 0) READ (rst_unit, IOSTAT=iostat) ind, ivec_tmp, nspins_tmp, nao_tmp
1022 6 : CALL para_env%bcast(iostat)
1023 6 : CALL para_env%bcast(ind)
1024 : ELSE
1025 48 : IF (rst_unit > 0) READ (rst_unit, IOSTAT=iostat) ivec_tmp, nspins_tmp, nao_tmp
1026 48 : CALL para_env%bcast(iostat)
1027 : END IF
1028 :
1029 54 : IF (iostat .NE. 0) EXIT
1030 54 : CALL para_env%bcast(ivec_tmp)
1031 54 : CALL para_env%bcast(nspins_tmp)
1032 54 : CALL para_env%bcast(nao_tmp)
1033 :
1034 : ! check that the number nao, nmo and nspins are
1035 : ! the same as in the current mos
1036 54 : IF (nspins_tmp .NE. nspins) CPABORT("nspins not consistent")
1037 54 : IF (nao_tmp .NE. nao) CPABORT("nao not consistent")
1038 : !
1039 108 : DO ispin = 1, nspins
1040 54 : CALL get_mo_set(mos(ispin), mo_coeff=mo_coeff)
1041 54 : CALL cp_fm_get_info(mo_coeff, ncol_global=nmo)
1042 : !
1043 54 : IF (rst_unit > 0) READ (rst_unit) nmo_tmp
1044 54 : CALL para_env%bcast(nmo_tmp)
1045 54 : IF (nmo_tmp .NE. nmo) CPABORT("nmo not consistent")
1046 : !
1047 : ! read the response
1048 216 : DO i = 1, nmo, MAX(max_block, 1)
1049 54 : i_block = MIN(max_block, nmo - i + 1)
1050 270 : DO j = 1, i_block
1051 270 : IF (rst_unit > 0) READ (rst_unit) vecbuffer(1:nao, j)
1052 : END DO
1053 108 : IF (iv .EQ. ivec_tmp) THEN
1054 10422 : CALL para_env%bcast(vecbuffer)
1055 54 : CALL cp_fm_set_submatrix(vec(ispin), vecbuffer, 1, i, nao, i_block)
1056 : END IF
1057 : END DO
1058 : END DO
1059 54 : IF (ivec .EQ. ivec_tmp) EXIT
1060 : END DO
1061 :
1062 30 : IF (iostat /= 0) THEN
1063 0 : IF (iounit > 0) WRITE (iounit, "(T2,A)") &
1064 0 : "LINRES| Restart file <"//TRIM(ADJUSTL(filename))//"> not found"
1065 : END IF
1066 :
1067 60 : DEALLOCATE (vecbuffer)
1068 :
1069 : END IF
1070 :
1071 72 : IF (para_env%is_source()) THEN
1072 36 : IF (file_exists) CALL close_file(unit_number=rst_unit)
1073 : END IF
1074 :
1075 72 : CALL timestop(handle)
1076 :
1077 72 : END SUBROUTINE linres_read_restart
1078 :
1079 : ! **************************************************************************************************
1080 : !> \brief ...
1081 : !> \param p_env ...
1082 : !> \param linres_control ...
1083 : !> \param nspins ...
1084 : ! **************************************************************************************************
1085 5044 : SUBROUTINE check_p_env_init(p_env, linres_control, nspins)
1086 : !
1087 : TYPE(qs_p_env_type) :: p_env
1088 : TYPE(linres_control_type), INTENT(IN) :: linres_control
1089 : INTEGER, INTENT(IN) :: nspins
1090 :
1091 : INTEGER :: ispin, ncol, nrow
1092 :
1093 5044 : IF (linres_control%preconditioner_type /= ot_precond_none) THEN
1094 5044 : CPASSERT(ASSOCIATED(p_env%preconditioner))
1095 12140 : DO ispin = 1, nspins
1096 7096 : CALL cp_fm_get_info(p_env%PS_psi0(ispin), nrow_global=nrow, ncol_global=ncol)
1097 7096 : CPASSERT(nrow == p_env%n_ao(ispin))
1098 19236 : CPASSERT(ncol == p_env%n_mo(ispin))
1099 : END DO
1100 : END IF
1101 :
1102 5044 : END SUBROUTINE check_p_env_init
1103 :
1104 : END MODULE qs_linres_methods
|