Line data Source code
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 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_checksum,&
18 : dbcsr_copy,&
19 : dbcsr_p_type,&
20 : dbcsr_set,&
21 : dbcsr_type
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 5042 : 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 5042 : 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 5042 : TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:) :: Ap, chc, mo_coeff_array, p, r, z
232 5042 : TYPE(cp_fm_type), DIMENSION(:), POINTER :: Sc
233 : TYPE(cp_fm_type), POINTER :: mo_coeff
234 5042 : 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 5042 : TYPE(mo_set_type), DIMENSION(:), POINTER :: mos
239 : TYPE(mp_para_env_type), POINTER :: para_env
240 :
241 5042 : CALL timeset(routineN, handle)
242 :
243 5042 : NULLIFY (dft_control, linres_control, matrix_s, matrix_t, matrix_ks, para_env)
244 5042 : NULLIFY (mos, tmp_fm_struct, mo_coeff)
245 :
246 5042 : 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 5042 : mos=mos)
256 :
257 5042 : nspins = dft_control%nspins
258 5042 : CALL cp_fm_get_info(psi1(1), nrow_global=nao)
259 5042 : maxnmo = 0
260 12136 : DO ispin = 1, nspins
261 7094 : CALL cp_fm_get_info(psi1(ispin), ncol_global=ncol)
262 12136 : maxnmo = MAX(maxnmo, ncol)
263 : END DO
264 : !
265 5042 : 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 83838 : r(nspins), p(nspins), z(nspins), Ap(nspins))
270 : !
271 12136 : DO ispin = 1, nspins
272 7094 : CALL cp_fm_create(r(ispin), psi1(ispin)%matrix_struct)
273 7094 : CALL cp_fm_create(p(ispin), psi1(ispin)%matrix_struct)
274 7094 : CALL cp_fm_create(z(ispin), psi1(ispin)%matrix_struct)
275 12136 : CALL cp_fm_create(Ap(ispin), psi1(ispin)%matrix_struct)
276 : END DO
277 : !
278 : ! build C0 occupied vectors and S*C0 matrix
279 34356 : ALLOCATE (Sc(nspins), mo_coeff_array(nspins))
280 12136 : DO ispin = 1, nspins
281 7094 : CALL get_mo_set(mos(ispin), mo_coeff=mo_coeff, homo=nocc)
282 7094 : 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 7094 : context=mo_coeff%matrix_struct%context)
286 7094 : CALL cp_fm_create(mo_coeff_array(ispin), tmp_fm_struct)
287 7094 : CALL cp_fm_to_fm(mo_coeff, mo_coeff_array(ispin), nocc)
288 7094 : CALL cp_fm_create(Sc(ispin), tmp_fm_struct)
289 19230 : CALL cp_fm_struct_release(tmp_fm_struct)
290 : END DO
291 : !
292 : ! Allocate C0_order'*H*C0_order
293 22220 : ALLOCATE (chc(nspins))
294 12136 : DO ispin = 1, nspins
295 7094 : CALL cp_fm_get_info(psi1(ispin), ncol_global=nmo)
296 7094 : 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 7094 : context=mo_coeff%matrix_struct%context)
300 7094 : CALL cp_fm_create(chc(ispin), tmp_fm_struct)
301 19230 : CALL cp_fm_struct_release(tmp_fm_struct)
302 : END DO
303 : !
304 12136 : DO ispin = 1, nspins
305 : !
306 : ! C0_order' * H * C0_order
307 : ASSOCIATE (mo_coeff => psi0_order(ispin))
308 7094 : CALL cp_fm_create(buf, mo_coeff%matrix_struct)
309 7094 : CALL cp_fm_get_info(mo_coeff, ncol_global=ncol)
310 7094 : CALL cp_dbcsr_sm_fm_multiply(matrix_ks(ispin)%matrix, mo_coeff, buf, ncol)
311 7094 : CALL parallel_gemm('T', 'N', ncol, ncol, nao, -1.0_dp, mo_coeff, buf, 0.0_dp, chc(ispin))
312 7094 : CALL cp_fm_release(buf)
313 : END ASSOCIATE
314 : !
315 : ! S * C0
316 7094 : CALL cp_fm_get_info(mo_coeff_array(ispin), ncol_global=ncol)
317 19230 : CALL cp_dbcsr_sm_fm_multiply(matrix_s(1)%matrix, mo_coeff_array(ispin), Sc(ispin), ncol)
318 : END DO
319 : !
320 : ! header
321 5042 : IF (iounit > 0) THEN
322 : WRITE (iounit, "(/,T3,A,T16,A,T25,A,T38,A,T52,A,T72,A,/,T3,A)") &
323 2513 : "Iteration", "Method", "Restart", "Stepsize", "Convergence", "Time", &
324 5026 : REPEAT("-", 78)
325 : END IF
326 : !
327 : ! orthogonalize x with respect to the psi0
328 5042 : CALL preortho(psi1, mo_coeff_array, Sc)
329 : !
330 : ! build the preconditioner
331 5042 : IF (linres_control%preconditioner_type /= ot_precond_none) THEN
332 5042 : IF (p_env%new_preconditioner) THEN
333 2668 : DO ispin = 1, nspins
334 2668 : 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 1408 : 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 1236 : p_env%new_preconditioner = .FALSE.
348 : END IF
349 : END IF
350 : !
351 : ! initialization of the linear solver
352 : !
353 : ! A * x0
354 5042 : CALL apply_op(qs_env, p_env, psi0_order, psi1, Ap, chc)
355 : !
356 : !
357 : ! r_0 = b - Ax0
358 12136 : DO ispin = 1, nspins
359 7094 : CALL cp_fm_to_fm(h1_psi0(ispin), r(ispin))
360 12136 : CALL cp_fm_scale_and_add(-1.0_dp, r(ispin), -1.0_dp, Ap(ispin))
361 : END DO
362 : !
363 : ! proj r
364 5042 : CALL postortho(r, mo_coeff_array, Sc)
365 : !
366 : ! preconditioner
367 5042 : linres_control%flag = ""
368 5042 : 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 12136 : DO ispin = 1, nspins
379 : CALL apply_preconditioner(p_env%preconditioner(ispin), r(ispin), &
380 12136 : z(ispin))
381 : END DO
382 5042 : linres_control%flag = "PCG"
383 : END IF
384 : !
385 12136 : DO ispin = 1, nspins
386 : !
387 : ! p_0 = z_0
388 7094 : CALL cp_fm_to_fm(z(ispin), p(ispin))
389 : !
390 : ! trace(r_0 * z_0)
391 12136 : CALL cp_fm_trace(r(ispin), z(ispin), tr_rz0(ispin))
392 : END DO
393 12136 : IF (SUM(tr_rz0) < 0.0_dp) CPABORT("tr(r_j*z_j) < 0")
394 12136 : norm_res = ABS(SUM(tr_rz0))/SQRT(REAL(nspins*nao*maxnmo, dp))
395 : !
396 5042 : alpha = 0.0_dp
397 5042 : restart = .FALSE.
398 5042 : should_stop = .FALSE.
399 33264 : iteration: DO iter = 1, linres_control%max_iter
400 : !
401 : ! check convergence
402 31960 : linres_control%converged = .FALSE.
403 31960 : IF (norm_res .LT. linres_control%eps) THEN
404 3738 : linres_control%converged = .TRUE.
405 : END IF
406 : !
407 31960 : 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 31960 : IF (iounit > 0) THEN
411 : WRITE (iounit, "(T5,I5,T18,A3,T28,L1,T38,1E8.2,T48,F16.10,T68,F8.2)") &
412 15914 : iter, linres_control%flag, restart, alpha, norm_res, t2 - t1
413 15914 : CALL m_flush(iounit)
414 : END IF
415 : END IF
416 : !
417 31960 : IF (linres_control%converged) THEN
418 3738 : IF (iounit > 0) THEN
419 1861 : WRITE (iounit, "(T3,A,I4,A)") "The linear solver converged in ", iter, " iterations."
420 1861 : CALL m_flush(iounit)
421 : END IF
422 : EXIT iteration
423 28222 : 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 28222 : 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 28222 : CALL apply_op(qs_env, p_env, psi0_order, p, Ap, chc)
443 : !
444 : ! proj Ap onto the virtual subspace
445 28222 : CALL postortho(Ap, mo_coeff_array, Sc)
446 : !
447 69252 : DO ispin = 1, nspins
448 : !
449 : ! tr(Ap_j*p_j)
450 69252 : 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 69252 : IF (SUM(tr_pAp) < 1.0e-10_dp) THEN
455 172 : alpha = 1.0_dp
456 : ELSE
457 109766 : alpha = SUM(tr_rz0)/SUM(tr_pAp)
458 : END IF
459 69252 : DO ispin = 1, nspins
460 : !
461 : ! x_j+1 = x_j + alpha * p_j
462 69252 : 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 28222 : restart = .FALSE.
467 28222 : IF (MOD(iter, linres_control%restart_every) .EQ. 0) THEN
468 : !
469 : ! r_j+1 = b - A * x_j+1
470 208 : CALL apply_op(qs_env, p_env, psi0_order, psi1, Ap, chc)
471 : !
472 452 : DO ispin = 1, nspins
473 244 : CALL cp_fm_to_fm(h1_psi0(ispin), r(ispin))
474 452 : CALL cp_fm_scale_and_add(-1.0_dp, r(ispin), -1.0_dp, Ap(ispin))
475 : END DO
476 208 : CALL postortho(r, mo_coeff_array, Sc)
477 : !
478 208 : restart = .TRUE.
479 : ELSE
480 : ! proj Ap onto the virtual subspace
481 28014 : CALL postortho(Ap, mo_coeff_array, Sc)
482 : !
483 : ! r_j+1 = r_j - alpha * Ap_j
484 68800 : DO ispin = 1, nspins
485 68800 : CALL cp_fm_scale_and_add(1.0_dp, r(ispin), -alpha, Ap(ispin))
486 : END DO
487 28014 : restart = .FALSE.
488 : END IF
489 : !
490 : ! preconditioner
491 28222 : linres_control%flag = ""
492 28222 : 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 69252 : DO ispin = 1, nspins
503 : CALL apply_preconditioner(p_env%preconditioner(ispin), r(ispin), &
504 69252 : z(ispin))
505 : END DO
506 28222 : linres_control%flag = "PCG"
507 : END IF
508 : !
509 69252 : DO ispin = 1, nspins
510 : !
511 : ! tr(r_j+1*z_j+1)
512 69252 : CALL cp_fm_trace(r(ispin), z(ispin), tr_rz1(ispin))
513 : END DO
514 69252 : IF (SUM(tr_rz1) < 0.0_dp) CPABORT("tr(r_j+1*z_j+1) < 0")
515 69252 : 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 69252 : IF (SUM(tr_rz0) < 1.0e-10_dp) THEN
519 210 : beta = 0.0_dp
520 : ELSE
521 109652 : beta = SUM(tr_rz1)/SUM(tr_rz0)
522 : END IF
523 69252 : DO ispin = 1, nspins
524 : !
525 : ! p_j+1 = z_j+1 + beta * p_j
526 41030 : CALL cp_fm_scale_and_add(beta, p(ispin), 1.0_dp, z(ispin))
527 41030 : tr_rz00(ispin) = tr_rz0(ispin)
528 69252 : 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 29526 : start_time=qs_env%start_time)
534 :
535 : END DO iteration
536 : !
537 : ! proj psi1
538 5042 : CALL preortho(psi1, mo_coeff_array, Sc)
539 : !
540 : !
541 : ! clean up
542 5042 : CALL cp_fm_release(r)
543 5042 : CALL cp_fm_release(p)
544 5042 : CALL cp_fm_release(z)
545 5042 : CALL cp_fm_release(Ap)
546 : !
547 5042 : CALL cp_fm_release(mo_coeff_array)
548 5042 : CALL cp_fm_release(Sc)
549 5042 : CALL cp_fm_release(chc)
550 : !
551 5042 : DEALLOCATE (tr_pAp, tr_rz0, tr_rz00, tr_rz1)
552 : !
553 5042 : CALL timestop(handle)
554 : !
555 15126 : 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 33472 : 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, Av, chc
571 :
572 : CHARACTER(LEN=*), PARAMETER :: routineN = 'apply_op'
573 :
574 : INTEGER :: handle, ispin, nc1, nc2, nc3, nc4, nr1, &
575 : nr2, nr3, nr4, nspins
576 : REAL(dp) :: chksum
577 33472 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_ks, matrix_s
578 : TYPE(dft_control_type), POINTER :: dft_control
579 : TYPE(linres_control_type), POINTER :: linres_control
580 : TYPE(qs_rho_type), POINTER :: rho
581 :
582 33472 : CALL timeset(routineN, handle)
583 :
584 33472 : NULLIFY (dft_control, matrix_ks, matrix_s, linres_control)
585 : CALL get_qs_env(qs_env=qs_env, &
586 : matrix_ks=matrix_ks, &
587 : matrix_s=matrix_s, &
588 : dft_control=dft_control, &
589 33472 : linres_control=linres_control)
590 :
591 33472 : nspins = dft_control%nspins
592 :
593 81840 : DO ispin = 1, nspins
594 : !c0, v, Av, chc
595 48368 : CALL cp_fm_get_info(c0(ispin), ncol_global=nc1, nrow_global=nr1)
596 48368 : CALL cp_fm_get_info(v(ispin), ncol_global=nc2, nrow_global=nr2)
597 48368 : CALL cp_fm_get_info(Av(ispin), ncol_global=nc3, nrow_global=nr3)
598 48368 : CALL cp_fm_get_info(chc(ispin), ncol_global=nc4, nrow_global=nr4)
599 48368 : IF (.NOT. (nc1 == nc2 .AND. nr1 == nr2 .AND. nc1 == nc3 .AND. nr1 == nr3 &
600 81840 : .AND. nc4 == nr4 .AND. nc1 <= nc4)) THEN
601 : CALL cp_abort(__LOCATION__, &
602 0 : "Number of vectors inconsistent or CHC matrix too small")
603 : END IF
604 : END DO
605 :
606 : ! apply the uncoupled operator
607 81840 : DO ispin = 1, nspins
608 : CALL apply_op_1(v(ispin), Av(ispin), matrix_ks(ispin)%matrix, &
609 81840 : matrix_s(1)%matrix, chc(ispin))
610 : END DO
611 :
612 33472 : IF (linres_control%do_kernel) THEN
613 :
614 : ! build DM, refill p1, build_dm_response keeps sparse structure
615 19294 : DO ispin = 1, nspins
616 19294 : CALL dbcsr_copy(p_env%p1(ispin)%matrix, matrix_s(1)%matrix)
617 : END DO
618 9144 : CALL build_dm_response(c0, v, p_env%p1)
619 :
620 9144 : chksum = 0.0_dp
621 19294 : DO ispin = 1, nspins
622 19294 : chksum = chksum + dbcsr_checksum(p_env%p1(ispin)%matrix)
623 : END DO
624 :
625 : ! skip the kernel if the DM is very small
626 9144 : IF (chksum .GT. 1.0E-14_dp) THEN
627 :
628 7714 : CALL p_env_check_i_alloc(p_env, qs_env)
629 :
630 7714 : CALL p_env_update_rho(p_env, qs_env)
631 :
632 7714 : CALL get_qs_env(qs_env, rho=rho) ! that could be called before
633 7714 : CALL qs_rho_update_rho(rho, qs_env=qs_env) ! that could be called before
634 7714 : IF (dft_control%qs_control%gapw) THEN
635 776 : CALL prepare_gapw_den(qs_env)
636 6938 : ELSEIF (dft_control%qs_control%gapw_xc) THEN
637 352 : CALL prepare_gapw_den(qs_env, do_rho0=.FALSE.)
638 : END IF
639 :
640 16284 : DO ispin = 1, nspins
641 8570 : CALL dbcsr_set(p_env%kpp1(ispin)%matrix, 0.0_dp)
642 16284 : IF (ASSOCIATED(p_env%kpp1_admm)) CALL dbcsr_set(p_env%kpp1_admm(ispin)%matrix, 0.0_dp)
643 : END DO
644 :
645 7714 : CALL apply_op_2(qs_env, p_env, c0, Av)
646 :
647 : END IF
648 :
649 : END IF
650 :
651 33472 : CALL timestop(handle)
652 :
653 33472 : END SUBROUTINE apply_op
654 :
655 : ! **************************************************************************************************
656 : !> \brief ...
657 : !> \param v ...
658 : !> \param Av ...
659 : !> \param matrix_ks ...
660 : !> \param matrix_s ...
661 : !> \param chc ...
662 : ! **************************************************************************************************
663 145104 : SUBROUTINE apply_op_1(v, Av, matrix_ks, matrix_s, chc)
664 : !
665 : TYPE(cp_fm_type), INTENT(IN) :: v, Av
666 : TYPE(dbcsr_type), INTENT(IN) :: matrix_ks, matrix_s
667 : TYPE(cp_fm_type), INTENT(IN) :: chc
668 :
669 : CHARACTER(LEN=*), PARAMETER :: routineN = 'apply_op_1'
670 :
671 : INTEGER :: handle, ncol, nrow
672 : TYPE(cp_fm_type) :: buf
673 :
674 48368 : CALL timeset(routineN, handle)
675 : !
676 48368 : CALL cp_fm_create(buf, v%matrix_struct)
677 : !
678 48368 : CALL cp_fm_get_info(v, ncol_global=ncol, nrow_global=nrow)
679 : ! H * v
680 48368 : CALL cp_dbcsr_sm_fm_multiply(matrix_ks, v, Av, ncol)
681 : ! v * e (chc already multiplied by -1)
682 48368 : CALL parallel_gemm('N', 'N', nrow, ncol, ncol, 1.0_dp, v, chc, 0.0_dp, buf)
683 : ! S * ve
684 48368 : CALL cp_dbcsr_sm_fm_multiply(matrix_s, buf, Av, ncol, alpha=1.0_dp, beta=1.0_dp)
685 : !Results is H*C1 - S*<iHj>*C1
686 : !
687 48368 : CALL cp_fm_release(buf)
688 : !
689 48368 : CALL timestop(handle)
690 : !
691 48368 : END SUBROUTINE apply_op_1
692 :
693 : !MERGE
694 : ! **************************************************************************************************
695 : !> \brief ...
696 : !> \param v ...
697 : !> \param psi0 ...
698 : !> \param S_psi0 ...
699 : ! **************************************************************************************************
700 10084 : SUBROUTINE preortho(v, psi0, S_psi0)
701 : !v = (I-PS)v
702 : !
703 : TYPE(cp_fm_type), DIMENSION(:), INTENT(IN) :: v, psi0, S_psi0
704 :
705 : CHARACTER(LEN=*), PARAMETER :: routineN = 'preortho'
706 :
707 : INTEGER :: handle, ispin, mp, mt, mv, np, nspins, &
708 : nt, nv
709 : TYPE(cp_fm_struct_type), POINTER :: tmp_fm_struct
710 : TYPE(cp_fm_type) :: buf
711 :
712 10084 : CALL timeset(routineN, handle)
713 : !
714 10084 : NULLIFY (tmp_fm_struct)
715 : !
716 10084 : nspins = SIZE(v, 1)
717 : !
718 24272 : DO ispin = 1, nspins
719 14188 : CALL cp_fm_get_info(v(ispin), ncol_global=mv, nrow_global=nv)
720 14188 : CALL cp_fm_get_info(psi0(ispin), ncol_global=mp, nrow_global=np)
721 : !
722 : CALL cp_fm_struct_create(tmp_fm_struct, nrow_global=nv, ncol_global=mp, &
723 : para_env=v(ispin)%matrix_struct%para_env, &
724 14188 : context=v(ispin)%matrix_struct%context)
725 14188 : CALL cp_fm_create(buf, tmp_fm_struct)
726 14188 : CALL cp_fm_struct_release(tmp_fm_struct)
727 : !
728 14188 : CALL cp_fm_get_info(buf, ncol_global=mt, nrow_global=nt)
729 14188 : CPASSERT(nv == np)
730 14188 : CPASSERT(mt >= mv)
731 14188 : CPASSERT(mt >= mp)
732 14188 : CPASSERT(nt == nv)
733 : !
734 : ! buf = v' * S_psi0
735 14188 : CALL parallel_gemm('T', 'N', mv, mp, nv, 1.0_dp, v(ispin), S_psi0(ispin), 0.0_dp, buf)
736 : ! v = v - psi0 * buf'
737 14188 : CALL parallel_gemm('N', 'T', nv, mv, mp, -1.0_dp, psi0(ispin), buf, 1.0_dp, v(ispin))
738 : !
739 66836 : CALL cp_fm_release(buf)
740 : END DO
741 : !
742 10084 : CALL timestop(handle)
743 : !
744 10084 : END SUBROUTINE preortho
745 :
746 : ! **************************************************************************************************
747 : !> \brief projects first index of v onto the virtual subspace
748 : !> \param v matrix to be projected
749 : !> \param psi0 matrix with occupied orbitals
750 : !> \param S_psi0 matrix containing product of metric and occupied orbitals
751 : ! **************************************************************************************************
752 61486 : SUBROUTINE postortho(v, psi0, S_psi0)
753 : !v = (I-SP)v
754 : !
755 : TYPE(cp_fm_type), DIMENSION(:), INTENT(IN) :: v, psi0, S_psi0
756 :
757 : CHARACTER(LEN=*), PARAMETER :: routineN = 'postortho'
758 :
759 : INTEGER :: handle, ispin, mp, mt, mv, np, nspins, &
760 : nt, nv
761 : TYPE(cp_fm_struct_type), POINTER :: tmp_fm_struct
762 : TYPE(cp_fm_type) :: buf
763 :
764 61486 : CALL timeset(routineN, handle)
765 : !
766 61486 : NULLIFY (tmp_fm_struct)
767 : !
768 61486 : nspins = SIZE(v, 1)
769 : !
770 150640 : DO ispin = 1, nspins
771 89154 : CALL cp_fm_get_info(v(ispin), ncol_global=mv, nrow_global=nv)
772 89154 : CALL cp_fm_get_info(psi0(ispin), ncol_global=mp, nrow_global=np)
773 : !
774 : CALL cp_fm_struct_create(tmp_fm_struct, nrow_global=nv, ncol_global=mp, &
775 : para_env=v(ispin)%matrix_struct%para_env, &
776 89154 : context=v(ispin)%matrix_struct%context)
777 89154 : CALL cp_fm_create(buf, tmp_fm_struct)
778 89154 : CALL cp_fm_struct_release(tmp_fm_struct)
779 : !
780 89154 : CALL cp_fm_get_info(buf, ncol_global=mt, nrow_global=nt)
781 89154 : CPASSERT(nv == np)
782 89154 : CPASSERT(mt >= mv)
783 89154 : CPASSERT(mt >= mp)
784 89154 : CPASSERT(nt == nv)
785 : !
786 : ! buf = v' * psi0
787 89154 : CALL parallel_gemm('T', 'N', mv, mp, nv, 1.0_dp, v(ispin), psi0(ispin), 0.0_dp, buf)
788 : ! v = v - S_psi0 * buf'
789 89154 : CALL parallel_gemm('N', 'T', nv, mv, mp, -1.0_dp, S_psi0(ispin), buf, 1.0_dp, v(ispin))
790 : !
791 418102 : CALL cp_fm_release(buf)
792 : END DO
793 : !
794 61486 : CALL timestop(handle)
795 : !
796 61486 : END SUBROUTINE postortho
797 :
798 : ! **************************************************************************************************
799 : !> \brief ...
800 : !> \param qs_env ...
801 : !> \param linres_section ...
802 : !> \param vec ...
803 : !> \param ivec ...
804 : !> \param tag ...
805 : !> \param ind ...
806 : ! **************************************************************************************************
807 3522 : SUBROUTINE linres_write_restart(qs_env, linres_section, vec, ivec, tag, ind)
808 : TYPE(qs_environment_type), POINTER :: qs_env
809 : TYPE(section_vals_type), POINTER :: linres_section
810 : TYPE(cp_fm_type), DIMENSION(:), INTENT(IN) :: vec
811 : INTEGER, INTENT(IN) :: ivec
812 : CHARACTER(LEN=*) :: tag
813 : INTEGER, INTENT(IN), OPTIONAL :: ind
814 :
815 : CHARACTER(LEN=*), PARAMETER :: routineN = 'linres_write_restart'
816 :
817 : CHARACTER(LEN=default_path_length) :: filename
818 : CHARACTER(LEN=default_string_length) :: my_middle, my_pos, my_status
819 : INTEGER :: handle, i, i_block, ia, ie, iounit, &
820 : ispin, j, max_block, nao, nmo, nspins, &
821 : rst_unit
822 3522 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: vecbuffer
823 : TYPE(cp_fm_type), POINTER :: mo_coeff
824 : TYPE(cp_logger_type), POINTER :: logger
825 3522 : TYPE(mo_set_type), DIMENSION(:), POINTER :: mos
826 : TYPE(mp_para_env_type), POINTER :: para_env
827 : TYPE(section_vals_type), POINTER :: print_key
828 :
829 3522 : NULLIFY (logger, mo_coeff, mos, para_env, print_key, vecbuffer)
830 :
831 3522 : CALL timeset(routineN, handle)
832 :
833 3522 : logger => cp_get_default_logger()
834 :
835 3522 : IF (BTEST(cp_print_key_should_output(logger%iter_info, linres_section, "PRINT%RESTART", &
836 : used_print_key=print_key), &
837 : cp_p_file)) THEN
838 :
839 : iounit = cp_print_key_unit_nr(logger, linres_section, &
840 3522 : "PRINT%PROGRAM_RUN_INFO", extension=".Log")
841 :
842 : CALL get_qs_env(qs_env=qs_env, &
843 : mos=mos, &
844 3522 : para_env=para_env)
845 :
846 3522 : nspins = SIZE(mos)
847 :
848 3522 : my_status = "REPLACE"
849 3522 : my_pos = "REWIND"
850 3522 : CALL XSTRING(tag, ia, ie)
851 3522 : IF (PRESENT(ind)) THEN
852 2460 : my_middle = "RESTART-"//tag(ia:ie)//TRIM(ADJUSTL(cp_to_string(ivec)))
853 : ELSE
854 1062 : my_middle = "RESTART-"//tag(ia:ie)
855 1062 : IF (ivec > 1) THEN
856 708 : my_status = "OLD"
857 708 : my_pos = "APPEND"
858 : END IF
859 : END IF
860 : rst_unit = cp_print_key_unit_nr(logger, linres_section, "PRINT%RESTART", &
861 : extension=".lr", middle_name=TRIM(my_middle), file_status=TRIM(my_status), &
862 3522 : file_position=TRIM(my_pos), file_action="WRITE", file_form="UNFORMATTED")
863 :
864 : filename = cp_print_key_generate_filename(logger, print_key, &
865 3522 : extension=".lr", middle_name=TRIM(my_middle), my_local=.FALSE.)
866 :
867 3522 : IF (iounit > 0) THEN
868 : WRITE (UNIT=iounit, FMT="(T2,A)") &
869 1761 : "LINRES| Writing response functions to the restart file <"//TRIM(ADJUSTL(filename))//">"
870 : END IF
871 :
872 : !
873 : ! write data to file
874 : ! use the scalapack block size as a default for buffering columns
875 3522 : CALL get_mo_set(mos(1), mo_coeff=mo_coeff)
876 3522 : CALL cp_fm_get_info(mo_coeff, nrow_global=nao, ncol_block=max_block)
877 14088 : ALLOCATE (vecbuffer(nao, max_block))
878 :
879 3522 : IF (PRESENT(ind)) THEN
880 2460 : IF (rst_unit > 0) WRITE (rst_unit) ind, ivec, nspins, nao
881 : ELSE
882 1062 : IF (rst_unit > 0) WRITE (rst_unit) ivec, nspins, nao
883 : END IF
884 :
885 8934 : DO ispin = 1, nspins
886 5412 : CALL cp_fm_get_info(vec(ispin), ncol_global=nmo)
887 :
888 5412 : IF (rst_unit > 0) WRITE (rst_unit) nmo
889 :
890 19758 : DO i = 1, nmo, MAX(max_block, 1)
891 5412 : i_block = MIN(max_block, nmo - i + 1)
892 5412 : CALL cp_fm_get_submatrix(vec(ispin), vecbuffer, 1, i, nao, i_block)
893 : ! doing this in one write would increase efficiency, but breaks RESTART compatibility.
894 : ! to old ones, and in cases where max_block is different between runs, as might happen during
895 : ! restarts with a different number of CPUs
896 47616 : DO j = 1, i_block
897 42204 : IF (rst_unit > 0) WRITE (rst_unit) vecbuffer(1:nao, j)
898 : END DO
899 : END DO
900 : END DO
901 :
902 3522 : DEALLOCATE (vecbuffer)
903 :
904 : CALL cp_print_key_finished_output(rst_unit, logger, linres_section, &
905 7044 : "PRINT%RESTART")
906 : END IF
907 :
908 3522 : CALL timestop(handle)
909 :
910 3522 : END SUBROUTINE linres_write_restart
911 :
912 : ! **************************************************************************************************
913 : !> \brief ...
914 : !> \param qs_env ...
915 : !> \param linres_section ...
916 : !> \param vec ...
917 : !> \param ivec ...
918 : !> \param tag ...
919 : !> \param ind ...
920 : ! **************************************************************************************************
921 72 : SUBROUTINE linres_read_restart(qs_env, linres_section, vec, ivec, tag, ind)
922 : TYPE(qs_environment_type), POINTER :: qs_env
923 : TYPE(section_vals_type), POINTER :: linres_section
924 : TYPE(cp_fm_type), DIMENSION(:), INTENT(IN) :: vec
925 : INTEGER, INTENT(IN) :: ivec
926 : CHARACTER(LEN=*) :: tag
927 : INTEGER, INTENT(INOUT), OPTIONAL :: ind
928 :
929 : CHARACTER(LEN=*), PARAMETER :: routineN = 'linres_read_restart'
930 :
931 : CHARACTER(LEN=default_path_length) :: filename
932 : CHARACTER(LEN=default_string_length) :: my_middle
933 : INTEGER :: handle, i, i_block, ia, ie, iostat, iounit, ispin, iv, iv1, ivec_tmp, j, &
934 : max_block, n_rep_val, nao, nao_tmp, nmo, nmo_tmp, nspins, nspins_tmp, rst_unit
935 : LOGICAL :: file_exists
936 72 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: vecbuffer
937 : TYPE(cp_fm_type), POINTER :: mo_coeff
938 : TYPE(cp_logger_type), POINTER :: logger
939 72 : TYPE(mo_set_type), DIMENSION(:), POINTER :: mos
940 : TYPE(mp_para_env_type), POINTER :: para_env
941 : TYPE(section_vals_type), POINTER :: print_key
942 :
943 72 : file_exists = .FALSE.
944 :
945 72 : CALL timeset(routineN, handle)
946 :
947 72 : NULLIFY (mos, para_env, logger, print_key, vecbuffer)
948 72 : logger => cp_get_default_logger()
949 :
950 : iounit = cp_print_key_unit_nr(logger, linres_section, &
951 72 : "PRINT%PROGRAM_RUN_INFO", extension=".Log")
952 :
953 : CALL get_qs_env(qs_env=qs_env, &
954 : para_env=para_env, &
955 72 : mos=mos)
956 :
957 72 : nspins = SIZE(mos)
958 :
959 72 : rst_unit = -1
960 72 : IF (para_env%is_source()) THEN
961 : CALL section_vals_val_get(linres_section, "WFN_RESTART_FILE_NAME", &
962 36 : n_rep_val=n_rep_val)
963 :
964 36 : CALL XSTRING(tag, ia, ie)
965 36 : IF (PRESENT(ind)) THEN
966 9 : my_middle = "RESTART-"//tag(ia:ie)//TRIM(ADJUSTL(cp_to_string(ivec)))
967 : ELSE
968 27 : my_middle = "RESTART-"//tag(ia:ie)
969 : END IF
970 :
971 36 : IF (n_rep_val > 0) THEN
972 18 : CALL section_vals_val_get(linres_section, "WFN_RESTART_FILE_NAME", c_val=filename)
973 18 : CALL xstring(filename, ia, ie)
974 18 : filename = filename(ia:ie)//TRIM(my_middle)//".lr"
975 : ELSE
976 : ! try to read from the filename that is generated automatically from the printkey
977 18 : print_key => section_vals_get_subs_vals(linres_section, "PRINT%RESTART")
978 : filename = cp_print_key_generate_filename(logger, print_key, &
979 18 : extension=".lr", middle_name=TRIM(my_middle), my_local=.FALSE.)
980 : END IF
981 36 : INQUIRE (FILE=filename, exist=file_exists)
982 : !
983 : ! open file
984 36 : IF (file_exists) THEN
985 : CALL open_file(file_name=TRIM(filename), &
986 : file_action="READ", &
987 : file_form="UNFORMATTED", &
988 : file_position="REWIND", &
989 : file_status="OLD", &
990 15 : unit_number=rst_unit)
991 :
992 15 : IF (iounit > 0) WRITE (iounit, "(T2,A)") &
993 15 : "LINRES| Reading response wavefunctions from the restart file <"//TRIM(ADJUSTL(filename))//">"
994 : ELSE
995 21 : IF (iounit > 0) WRITE (iounit, "(T2,A)") &
996 21 : "LINRES| Restart file <"//TRIM(ADJUSTL(filename))//"> not found"
997 : END IF
998 : END IF
999 :
1000 72 : CALL para_env%bcast(file_exists)
1001 :
1002 72 : IF (file_exists) THEN
1003 :
1004 30 : CALL get_mo_set(mos(1), mo_coeff=mo_coeff)
1005 30 : CALL cp_fm_get_info(mo_coeff, nrow_global=nao, ncol_block=max_block)
1006 :
1007 120 : ALLOCATE (vecbuffer(nao, max_block))
1008 : !
1009 : ! read headers
1010 30 : IF (PRESENT(ind)) THEN
1011 6 : iv1 = ivec
1012 : ELSE
1013 : iv1 = 1
1014 : END IF
1015 54 : DO iv = iv1, ivec
1016 :
1017 54 : IF (PRESENT(ind)) THEN
1018 6 : IF (rst_unit > 0) READ (rst_unit, IOSTAT=iostat) ind, ivec_tmp, nspins_tmp, nao_tmp
1019 6 : CALL para_env%bcast(iostat)
1020 6 : CALL para_env%bcast(ind)
1021 : ELSE
1022 48 : IF (rst_unit > 0) READ (rst_unit, IOSTAT=iostat) ivec_tmp, nspins_tmp, nao_tmp
1023 48 : CALL para_env%bcast(iostat)
1024 : END IF
1025 :
1026 54 : IF (iostat .NE. 0) EXIT
1027 54 : CALL para_env%bcast(ivec_tmp)
1028 54 : CALL para_env%bcast(nspins_tmp)
1029 54 : CALL para_env%bcast(nao_tmp)
1030 :
1031 : ! check that the number nao, nmo and nspins are
1032 : ! the same as in the current mos
1033 54 : IF (nspins_tmp .NE. nspins) CPABORT("nspins not consistent")
1034 54 : IF (nao_tmp .NE. nao) CPABORT("nao not consistent")
1035 : !
1036 108 : DO ispin = 1, nspins
1037 54 : CALL get_mo_set(mos(ispin), mo_coeff=mo_coeff)
1038 54 : CALL cp_fm_get_info(mo_coeff, ncol_global=nmo)
1039 : !
1040 54 : IF (rst_unit > 0) READ (rst_unit) nmo_tmp
1041 54 : CALL para_env%bcast(nmo_tmp)
1042 54 : IF (nmo_tmp .NE. nmo) CPABORT("nmo not consistent")
1043 : !
1044 : ! read the response
1045 216 : DO i = 1, nmo, MAX(max_block, 1)
1046 54 : i_block = MIN(max_block, nmo - i + 1)
1047 270 : DO j = 1, i_block
1048 270 : IF (rst_unit > 0) READ (rst_unit) vecbuffer(1:nao, j)
1049 : END DO
1050 108 : IF (iv .EQ. ivec_tmp) THEN
1051 10422 : CALL para_env%bcast(vecbuffer)
1052 54 : CALL cp_fm_set_submatrix(vec(ispin), vecbuffer, 1, i, nao, i_block)
1053 : END IF
1054 : END DO
1055 : END DO
1056 54 : IF (ivec .EQ. ivec_tmp) EXIT
1057 : END DO
1058 :
1059 30 : IF (iostat /= 0) THEN
1060 0 : IF (iounit > 0) WRITE (iounit, "(T2,A)") &
1061 0 : "LINRES| Restart file <"//TRIM(ADJUSTL(filename))//"> not found"
1062 : END IF
1063 :
1064 60 : DEALLOCATE (vecbuffer)
1065 :
1066 : END IF
1067 :
1068 72 : IF (para_env%is_source()) THEN
1069 36 : IF (file_exists) CALL close_file(unit_number=rst_unit)
1070 : END IF
1071 :
1072 72 : CALL timestop(handle)
1073 :
1074 72 : END SUBROUTINE linres_read_restart
1075 :
1076 : ! **************************************************************************************************
1077 : !> \brief ...
1078 : !> \param p_env ...
1079 : !> \param linres_control ...
1080 : !> \param nspins ...
1081 : ! **************************************************************************************************
1082 5042 : SUBROUTINE check_p_env_init(p_env, linres_control, nspins)
1083 : !
1084 : TYPE(qs_p_env_type) :: p_env
1085 : TYPE(linres_control_type), INTENT(IN) :: linres_control
1086 : INTEGER, INTENT(IN) :: nspins
1087 :
1088 : INTEGER :: ispin, ncol, nrow
1089 :
1090 5042 : IF (linres_control%preconditioner_type /= ot_precond_none) THEN
1091 5042 : CPASSERT(ASSOCIATED(p_env%preconditioner))
1092 12136 : DO ispin = 1, nspins
1093 7094 : CALL cp_fm_get_info(p_env%PS_psi0(ispin), nrow_global=nrow, ncol_global=ncol)
1094 7094 : CPASSERT(nrow == p_env%n_ao(ispin))
1095 19230 : CPASSERT(ncol == p_env%n_mo(ispin))
1096 : END DO
1097 : END IF
1098 :
1099 5042 : END SUBROUTINE check_p_env_init
1100 :
1101 : END MODULE qs_linres_methods
|