Line data Source code
1 : !--------------------------------------------------------------------------------------------------!
2 : ! CP2K: A general program to perform molecular dynamics simulations !
3 : ! Copyright 2000-2026 CP2K developers group <https://cp2k.org> !
4 : ! !
5 : ! SPDX-License-Identifier: GPL-2.0-or-later !
6 : !--------------------------------------------------------------------------------------------------!
7 :
8 : MODULE qs_tddfpt2_restart
9 : USE cp_blacs_env, ONLY: cp_blacs_env_type
10 : USE cp_dbcsr_api, ONLY: dbcsr_type
11 : USE cp_dbcsr_operations, ONLY: cp_dbcsr_sm_fm_multiply
12 : USE cp_files, ONLY: close_file,&
13 : open_file
14 : USE cp_fm_basic_linalg, ONLY: cp_fm_column_scale,&
15 : cp_fm_scale_and_add,&
16 : cp_fm_trace
17 : USE cp_fm_pool_types, ONLY: cp_fm_pool_p_type,&
18 : fm_pool_create_fm,&
19 : fm_pool_give_back_fm
20 : USE cp_fm_struct, ONLY: cp_fm_struct_create,&
21 : cp_fm_struct_release,&
22 : cp_fm_struct_type
23 : USE cp_fm_types, ONLY: cp_fm_create,&
24 : cp_fm_get_info,&
25 : cp_fm_read_unformatted,&
26 : cp_fm_release,&
27 : cp_fm_type,&
28 : cp_fm_write_formatted,&
29 : cp_fm_write_info,&
30 : cp_fm_write_unformatted
31 : USE cp_log_handling, ONLY: cp_logger_type
32 : USE cp_output_handling, ONLY: cp_p_file,&
33 : cp_print_key_finished_output,&
34 : cp_print_key_generate_filename,&
35 : cp_print_key_should_output,&
36 : cp_print_key_unit_nr
37 : USE input_section_types, ONLY: section_vals_get_subs_vals,&
38 : section_vals_type,&
39 : section_vals_val_get
40 : USE kinds, ONLY: default_path_length,&
41 : dp
42 : USE message_passing, ONLY: mp_para_env_type
43 : USE parallel_gemm_api, ONLY: parallel_gemm
44 : USE qs_tddfpt2_subgroups, ONLY: tddfpt_subgroup_env_type
45 : USE qs_tddfpt2_types, ONLY: tddfpt_ground_state_mos
46 : USE string_utilities, ONLY: integer_to_string
47 : #include "./base/base_uses.f90"
48 :
49 : IMPLICIT NONE
50 :
51 : PRIVATE
52 :
53 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_tddfpt2_restart'
54 :
55 : LOGICAL, PARAMETER, PRIVATE :: debug_this_module = .FALSE.
56 : ! number of first derivative components (3: d/dx, d/dy, d/dz)
57 : INTEGER, PARAMETER, PRIVATE :: nderivs = 3
58 : INTEGER, PARAMETER, PRIVATE :: maxspins = 2
59 :
60 : PUBLIC :: tddfpt_write_restart, tddfpt_read_restart, tddfpt_write_newtonx_output, tddfpt_check_orthonormality
61 :
62 : ! **************************************************************************************************
63 :
64 : CONTAINS
65 :
66 : ! **************************************************************************************************
67 : !> \brief Write Ritz vectors to a binary restart file.
68 : !> \param evects vectors to store
69 : !> \param evals TDDFPT eigenvalues
70 : !> \param gs_mos structure that holds ground state occupied and virtual
71 : !> molecular orbitals
72 : !> \param logger a logger object
73 : !> \param tddfpt_print_section TDDFPT%PRINT input section
74 : !> \par History
75 : !> * 08.2016 created [Sergey Chulkov]
76 : ! **************************************************************************************************
77 8260 : SUBROUTINE tddfpt_write_restart(evects, evals, gs_mos, logger, tddfpt_print_section)
78 : TYPE(cp_fm_type), DIMENSION(:, :), INTENT(in) :: evects
79 : REAL(kind=dp), DIMENSION(:), INTENT(in) :: evals
80 : TYPE(tddfpt_ground_state_mos), DIMENSION(:), &
81 : INTENT(in) :: gs_mos
82 : TYPE(cp_logger_type), POINTER :: logger
83 : TYPE(section_vals_type), POINTER :: tddfpt_print_section
84 :
85 : CHARACTER(LEN=*), PARAMETER :: routineN = 'tddfpt_write_restart'
86 :
87 : INTEGER :: handle, ispin, istate, nao, nspins, &
88 : nstates, ounit
89 : INTEGER, DIMENSION(maxspins) :: nmo_active
90 :
91 8260 : IF (BTEST(cp_print_key_should_output(logger%iter_info, tddfpt_print_section, "RESTART"), cp_p_file)) THEN
92 1468 : CALL timeset(routineN, handle)
93 :
94 1468 : nspins = SIZE(evects, 1)
95 1468 : nstates = SIZE(evects, 2)
96 :
97 : IF (debug_this_module) THEN
98 : CPASSERT(SIZE(evals) == nstates)
99 : CPASSERT(nspins > 0)
100 : CPASSERT(nstates > 0)
101 : END IF
102 :
103 1468 : CALL cp_fm_get_info(evects(1, 1), nrow_global=nao)
104 3112 : DO ispin = 1, nspins
105 3112 : CALL cp_fm_get_info(evects(ispin, 1), ncol_global=nmo_active(ispin))
106 : END DO
107 :
108 : ounit = cp_print_key_unit_nr(logger, tddfpt_print_section, "RESTART", &
109 : extension=".tdwfn", file_status="REPLACE", file_action="WRITE", &
110 1468 : do_backup=.TRUE., file_form="UNFORMATTED")
111 :
112 1468 : IF (ounit > 0) THEN
113 734 : WRITE (ounit) nstates, nspins, nao
114 734 : WRITE (ounit) nmo_active(1:nspins)
115 734 : WRITE (ounit) evals
116 : END IF
117 :
118 5222 : DO istate = 1, nstates
119 9600 : DO ispin = 1, nspins
120 : ! TDDFPT wave function is actually stored as a linear combination of virtual MOs
121 : ! that replaces the corresponding deoccupied MO. Unfortunately, the phase
122 : ! of the occupied MOs varies depending on the eigensolver used as well as
123 : ! how eigenvectors are distributed across computational cores. The phase is important
124 : ! because TDDFPT wave functions are used to compute a response electron density
125 : ! \rho^{-} = 1/2 * [C_{0} * evect^T + evect * C_{0}^{-}], where C_{0} is the expansion
126 : ! coefficients of the reference ground-state wave function. To make the restart file
127 : ! transferable, TDDFPT wave functions are stored in assumption that all ground state
128 : ! MOs have a positive phase.
129 4378 : CALL cp_fm_column_scale(evects(ispin, istate), gs_mos(ispin)%phases_occ)
130 :
131 4378 : CALL cp_fm_write_unformatted(evects(ispin, istate), ounit)
132 :
133 8132 : CALL cp_fm_column_scale(evects(ispin, istate), gs_mos(ispin)%phases_occ)
134 : END DO
135 : END DO
136 :
137 1468 : CALL cp_print_key_finished_output(ounit, logger, tddfpt_print_section, "RESTART")
138 :
139 1468 : CALL timestop(handle)
140 : END IF
141 :
142 8260 : END SUBROUTINE tddfpt_write_restart
143 :
144 : ! **************************************************************************************************
145 : !> \brief Initialise initial guess vectors by reading (un-normalised) Ritz vectors
146 : !> from a binary restart file.
147 : !> \param evects vectors to initialise (initialised on exit)
148 : !> \param evals TDDFPT eigenvalues (initialised on exit)
149 : !> \param gs_mos structure that holds ground state occupied and virtual
150 : !> molecular orbitals
151 : !> \param logger a logger object
152 : !> \param tddfpt_section TDDFPT input section
153 : !> \param tddfpt_print_section TDDFPT%PRINT input section
154 : !> \param fm_pool_ao_mo_active pools of dense matrices with shape [nao x nmo_active(spin)]
155 : !> \param blacs_env_global BLACS parallel environment involving all the processor
156 : !> \return the number of excited states found in the restart file
157 : !> \par History
158 : !> * 08.2016 created [Sergey Chulkov]
159 : ! **************************************************************************************************
160 12 : FUNCTION tddfpt_read_restart(evects, evals, gs_mos, logger, tddfpt_section, tddfpt_print_section, &
161 6 : fm_pool_ao_mo_active, blacs_env_global) RESULT(nstates_read)
162 : TYPE(cp_fm_type), DIMENSION(:, :), INTENT(inout) :: evects
163 : REAL(kind=dp), DIMENSION(:), INTENT(out) :: evals
164 : TYPE(tddfpt_ground_state_mos), DIMENSION(:), &
165 : INTENT(in) :: gs_mos
166 : TYPE(cp_logger_type), POINTER :: logger
167 : TYPE(section_vals_type), POINTER :: tddfpt_section, tddfpt_print_section
168 : TYPE(cp_fm_pool_p_type), DIMENSION(:), INTENT(in) :: fm_pool_ao_mo_active
169 : TYPE(cp_blacs_env_type), POINTER :: blacs_env_global
170 : INTEGER :: nstates_read
171 :
172 : CHARACTER(LEN=*), PARAMETER :: routineN = 'tddfpt_read_restart'
173 :
174 : CHARACTER(len=20) :: read_str, ref_str
175 : CHARACTER(LEN=default_path_length) :: filename
176 : INTEGER :: handle, ispin, istate, iunit, n_rep_val, &
177 : nao, nao_read, nspins, nspins_read, &
178 : nstates
179 : INTEGER, DIMENSION(maxspins) :: nmo_active, nmo_active_read
180 : LOGICAL :: file_exists
181 6 : REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: evals_read
182 : TYPE(cp_fm_type) :: evtest
183 : TYPE(mp_para_env_type), POINTER :: para_env_global
184 : TYPE(section_vals_type), POINTER :: print_key
185 :
186 6 : CALL timeset(routineN, handle)
187 :
188 6 : CPASSERT(ASSOCIATED(tddfpt_section))
189 :
190 : ! generate restart file name
191 6 : CALL section_vals_val_get(tddfpt_section, "WFN_RESTART_FILE_NAME", n_rep_val=n_rep_val)
192 6 : IF (n_rep_val > 0) THEN
193 0 : CALL section_vals_val_get(tddfpt_section, "WFN_RESTART_FILE_NAME", c_val=filename)
194 : ELSE
195 6 : print_key => section_vals_get_subs_vals(tddfpt_print_section, "RESTART")
196 : filename = cp_print_key_generate_filename(logger, print_key, &
197 6 : extension=".tdwfn", my_local=.FALSE.)
198 : END IF
199 :
200 6 : CALL blacs_env_global%get(para_env=para_env_global)
201 :
202 6 : IF (para_env_global%is_source()) THEN
203 3 : INQUIRE (FILE=filename, exist=file_exists)
204 :
205 3 : IF (.NOT. file_exists) THEN
206 2 : nstates_read = 0
207 2 : CALL para_env_global%bcast(nstates_read)
208 :
209 : CALL cp_warn(__LOCATION__, &
210 : "User requested to restart the TDDFPT wave functions from the file '"//TRIM(filename)// &
211 2 : "' which does not exist. Guess wave functions will be constructed using Kohn-Sham orbitals.")
212 2 : CALL timestop(handle)
213 2 : RETURN
214 : END IF
215 :
216 : CALL open_file(file_name=filename, file_action="READ", file_form="UNFORMATTED", &
217 1 : file_status="OLD", unit_number=iunit)
218 : END IF
219 :
220 4 : nspins = SIZE(evects, 1)
221 4 : nstates = SIZE(evects, 2)
222 :
223 12 : DO ispin = 1, nspins
224 8 : CALL fm_pool_create_fm(fm_pool_ao_mo_active(ispin)%pool, evtest)
225 8 : CALL cp_fm_get_info(evtest, nrow_global=nao, ncol_global=nmo_active(ispin))
226 12 : CALL fm_pool_give_back_fm(fm_pool_ao_mo_active(ispin)%pool, evtest)
227 : END DO
228 :
229 4 : IF (para_env_global%is_source()) THEN
230 1 : READ (iunit) nstates_read, nspins_read, nao_read
231 :
232 1 : IF (nspins_read /= nspins) THEN
233 0 : CALL integer_to_string(nspins, ref_str)
234 0 : CALL integer_to_string(nspins_read, read_str)
235 : CALL cp_abort(__LOCATION__, &
236 : "Restarted TDDFPT wave function contains incompatible number of spin components ("// &
237 0 : TRIM(read_str)//" instead of "//TRIM(ref_str)//").")
238 : END IF
239 :
240 1 : IF (nao_read /= nao) THEN
241 0 : CALL integer_to_string(nao, ref_str)
242 0 : CALL integer_to_string(nao_read, read_str)
243 : CALL cp_abort(__LOCATION__, &
244 0 : "Incompatible number of atomic orbitals ("//TRIM(read_str)//" instead of "//TRIM(ref_str)//").")
245 : END IF
246 :
247 1 : READ (iunit) nmo_active_read(1:nspins)
248 :
249 3 : DO ispin = 1, nspins
250 3 : IF (nmo_active_read(ispin) /= nmo_active(ispin)) THEN
251 : CALL cp_abort(__LOCATION__, &
252 0 : "Incompatible number of electrons and/or multiplicity.")
253 : END IF
254 : END DO
255 :
256 1 : IF (nstates_read /= nstates) THEN
257 0 : CALL integer_to_string(nstates, ref_str)
258 0 : CALL integer_to_string(nstates_read, read_str)
259 : CALL cp_warn(__LOCATION__, &
260 : "TDDFPT restart file contains "//TRIM(read_str)// &
261 : " wave function(s) however "//TRIM(ref_str)// &
262 0 : " excited states were requested.")
263 : END IF
264 : END IF
265 4 : CALL para_env_global%bcast(nstates_read)
266 :
267 : ! exit if restart file does not exist
268 4 : IF (nstates_read <= 0) THEN
269 2 : CALL timestop(handle)
270 2 : RETURN
271 : END IF
272 :
273 2 : IF (para_env_global%is_source()) THEN
274 3 : ALLOCATE (evals_read(nstates_read))
275 1 : READ (iunit) evals_read
276 1 : IF (nstates_read <= nstates) THEN
277 4 : evals(1:nstates_read) = evals_read(1:nstates_read)
278 : ELSE
279 0 : evals(1:nstates) = evals_read(1:nstates)
280 : END IF
281 1 : DEALLOCATE (evals_read)
282 : END IF
283 14 : CALL para_env_global%bcast(evals)
284 :
285 8 : DO istate = 1, nstates_read
286 20 : DO ispin = 1, nspins
287 18 : IF (istate <= nstates) THEN
288 12 : CALL fm_pool_create_fm(fm_pool_ao_mo_active(ispin)%pool, evects(ispin, istate))
289 :
290 12 : CALL cp_fm_read_unformatted(evects(ispin, istate), iunit)
291 :
292 12 : CALL cp_fm_column_scale(evects(ispin, istate), gs_mos(ispin)%phases_occ)
293 : END IF
294 : END DO
295 : END DO
296 :
297 2 : IF (para_env_global%is_source()) THEN
298 1 : CALL close_file(unit_number=iunit)
299 : END IF
300 :
301 2 : CALL timestop(handle)
302 :
303 12 : END FUNCTION tddfpt_read_restart
304 : ! **************************************************************************************************
305 : !> \brief Write Ritz vectors to a binary restart file.
306 : !> \param evects vectors to store
307 : !> \param evals TDDFPT eigenvalues
308 : !> \param gs_mos structure that holds ground state occupied and virtual
309 : !> molecular orbitals
310 : !> \param logger a logger object
311 : !> \param tddfpt_print_section TDDFPT%PRINT input section
312 : !> \param matrix_s ...
313 : !> \param S_evects ...
314 : !> \param sub_env ...
315 : ! **************************************************************************************************
316 2 : SUBROUTINE tddfpt_write_newtonx_output(evects, evals, gs_mos, logger, tddfpt_print_section, &
317 2 : matrix_s, S_evects, sub_env)
318 :
319 : TYPE(cp_fm_type), DIMENSION(:, :), INTENT(in) :: evects
320 : REAL(kind=dp), DIMENSION(:), INTENT(in) :: evals
321 : TYPE(tddfpt_ground_state_mos), DIMENSION(:), &
322 : INTENT(in) :: gs_mos
323 : TYPE(cp_logger_type), INTENT(in), POINTER :: logger
324 : TYPE(section_vals_type), INTENT(in), POINTER :: tddfpt_print_section
325 : TYPE(dbcsr_type), INTENT(in), POINTER :: matrix_s
326 : TYPE(cp_fm_type), DIMENSION(:, :), INTENT(INOUT) :: S_evects
327 : TYPE(tddfpt_subgroup_env_type), INTENT(in) :: sub_env
328 :
329 : CHARACTER(LEN=*), PARAMETER :: routineN = 'tddfpt_write_newtonx_output'
330 :
331 : INTEGER :: handle, iocc, ispin, istate, ivirt, nao, &
332 : nspins, nstates, ounit
333 : INTEGER, DIMENSION(maxspins) :: nmo_active, nmo_occ, nmo_virt
334 : LOGICAL :: print_phases, print_virtuals, &
335 : scale_with_phases
336 2 : REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: phase_evects
337 : TYPE(cp_fm_struct_type), POINTER :: fmstruct
338 2 : TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:, :) :: evects_mo
339 :
340 2 : IF (BTEST(cp_print_key_should_output(logger%iter_info, tddfpt_print_section, "NAMD_PRINT"), cp_p_file)) THEN
341 2 : CALL timeset(routineN, handle)
342 2 : CALL section_vals_val_get(tddfpt_print_section, "NAMD_PRINT%PRINT_VIRTUALS", l_val=print_virtuals)
343 2 : CALL section_vals_val_get(tddfpt_print_section, "NAMD_PRINT%PRINT_PHASES", l_val=print_phases)
344 2 : CALL section_vals_val_get(tddfpt_print_section, "NAMD_PRINT%SCALE_WITH_PHASES", l_val=scale_with_phases)
345 :
346 2 : nspins = SIZE(evects, 1)
347 2 : nstates = SIZE(evects, 2)
348 :
349 : IF (debug_this_module) THEN
350 : CPASSERT(SIZE(evals) == nstates)
351 : CPASSERT(nspins > 0)
352 : CPASSERT(nstates > 0)
353 : END IF
354 :
355 2 : CALL cp_fm_get_info(gs_mos(1)%mos_occ, nrow_global=nao)
356 :
357 2 : IF (sub_env%is_split) THEN
358 : CALL cp_abort(__LOCATION__, "NEWTONX interface print not possible when states"// &
359 0 : " are distributed to different CPU pools.")
360 : END IF
361 :
362 : ! test for reduced active orbitals
363 4 : DO ispin = 1, nspins
364 2 : nmo_occ(ispin) = SIZE(gs_mos(ispin)%evals_occ)
365 2 : CALL cp_fm_get_info(evects(ispin, 1), ncol_global=nmo_active(ispin))
366 4 : IF (nmo_occ(ispin) /= nmo_active(ispin)) THEN
367 : CALL cp_abort(__LOCATION__, "NEWTONX interface print not possible when using"// &
368 0 : " a reduced set of active occupied orbitals.")
369 : END IF
370 : END DO
371 :
372 : ounit = cp_print_key_unit_nr(logger, tddfpt_print_section, "NAMD_PRINT", &
373 2 : extension=".inp", file_form="FORMATTED", file_action="WRITE", file_status="REPLACE")
374 : IF (debug_this_module) CALL tddfpt_check_orthonormality(evects, ounit, S_evects, matrix_s)
375 :
376 : ! print eigenvectors
377 2 : IF (print_virtuals) THEN
378 12 : ALLOCATE (evects_mo(nspins, nstates))
379 4 : DO istate = 1, nstates
380 6 : DO ispin = 1, nspins
381 :
382 : ! transform eigenvectors
383 2 : NULLIFY (fmstruct)
384 2 : nmo_occ(ispin) = SIZE(gs_mos(ispin)%evals_occ)
385 2 : nmo_virt(ispin) = SIZE(gs_mos(ispin)%evals_virt)
386 : CALL cp_fm_struct_create(fmstruct, para_env=sub_env%para_env, &
387 : context=sub_env%blacs_env, &
388 2 : nrow_global=nmo_virt(ispin), ncol_global=nmo_occ(ispin))
389 2 : CALL cp_fm_create(evects_mo(ispin, istate), fmstruct)
390 2 : CALL cp_fm_struct_release(fmstruct)
391 : CALL cp_dbcsr_sm_fm_multiply(matrix_s, evects(ispin, istate), S_evects(ispin, istate), &
392 4 : ncol=nmo_occ(ispin), alpha=1.0_dp, beta=0.0_dp)
393 : END DO
394 : END DO
395 4 : DO istate = 1, nstates
396 6 : DO ispin = 1, nspins
397 : CALL parallel_gemm("T", "N", &
398 : nmo_virt(ispin), &
399 : nmo_occ(ispin), &
400 : nao, &
401 : 1.0_dp, &
402 : gs_mos(ispin)%mos_virt, &
403 : S_evects(ispin, istate), & !this also needs to be orthogonalized
404 : 0.0_dp, &
405 4 : evects_mo(ispin, istate))
406 : END DO
407 : END DO
408 : END IF
409 :
410 4 : DO istate = 1, nstates
411 6 : DO ispin = 1, nspins
412 :
413 2 : IF (.NOT. print_virtuals) THEN
414 0 : CALL cp_fm_column_scale(evects(ispin, istate), gs_mos(ispin)%phases_occ)
415 0 : IF (ounit > 0) THEN
416 0 : WRITE (ounit, "(/,A)") "ES EIGENVECTORS SIZE"
417 0 : CALL cp_fm_write_info(evects(ispin, istate), ounit)
418 : END IF
419 0 : CALL cp_fm_write_formatted(evects(ispin, istate), ounit, "ES EIGENVECTORS")
420 : ELSE
421 2 : CALL cp_fm_column_scale(evects_mo(ispin, istate), gs_mos(ispin)%phases_occ)
422 2 : IF (ounit > 0) THEN
423 1 : WRITE (ounit, "(/,A)") "ES EIGENVECTORS SIZE"
424 1 : CALL cp_fm_write_info(evects_mo(ispin, istate), ounit)
425 : END IF
426 2 : CALL cp_fm_write_formatted(evects_mo(ispin, istate), ounit, "ES EIGENVECTORS")
427 : END IF
428 :
429 : ! compute and print phase of eigenvectors
430 2 : nmo_occ(ispin) = SIZE(gs_mos(ispin)%evals_occ)
431 6 : ALLOCATE (phase_evects(nmo_occ(ispin)))
432 2 : IF (print_virtuals) THEN
433 2 : CALL compute_phase_eigenvectors(evects_mo(ispin, istate), phase_evects, sub_env)
434 : ELSE
435 0 : CALL compute_phase_eigenvectors(evects(ispin, istate), phase_evects, sub_env)
436 : END IF
437 2 : IF (ounit > 0) THEN
438 1 : WRITE (ounit, "(/,A,/)") "PHASES ES EIGENVECTORS"
439 5 : DO iocc = 1, nmo_occ(ispin)
440 5 : WRITE (ounit, "(F20.14)") phase_evects(iocc)
441 : END DO
442 : END IF
443 4 : DEALLOCATE (phase_evects)
444 :
445 : END DO
446 : END DO
447 :
448 2 : IF (print_virtuals) THEN
449 2 : CALL cp_fm_release(evects_mo)
450 : END IF
451 :
452 4 : DO ispin = 1, nspins
453 2 : IF (ounit > 0) THEN
454 1 : WRITE (ounit, "(/,A)") "OCCUPIED MOS SIZE"
455 1 : CALL cp_fm_write_info(gs_mos(ispin)%mos_occ, ounit)
456 : END IF
457 4 : CALL cp_fm_write_formatted(gs_mos(ispin)%mos_occ, ounit, "OCCUPIED MO COEFFICIENTS")
458 : END DO
459 :
460 2 : IF (ounit > 0) THEN
461 1 : WRITE (ounit, "(A)") "OCCUPIED MO EIGENVALUES"
462 2 : DO ispin = 1, nspins
463 1 : nmo_occ(ispin) = SIZE(gs_mos(ispin)%evals_occ)
464 6 : DO iocc = 1, nmo_occ(ispin)
465 5 : WRITE (ounit, "(F20.14)") gs_mos(ispin)%evals_occ(iocc)
466 : END DO
467 : END DO
468 : END IF
469 : !
470 2 : IF (print_virtuals) THEN
471 4 : DO ispin = 1, nspins
472 2 : IF (ounit > 0) THEN
473 1 : WRITE (ounit, "(/,A)") "VIRTUAL MOS SIZE"
474 1 : CALL cp_fm_write_info(gs_mos(ispin)%mos_virt, ounit)
475 : END IF
476 4 : CALL cp_fm_write_formatted(gs_mos(ispin)%mos_virt, ounit, "VIRTUAL MO COEFFICIENTS")
477 : END DO
478 :
479 2 : IF (ounit > 0) THEN
480 1 : WRITE (ounit, "(A)") "VIRTUAL MO EIGENVALUES"
481 2 : DO ispin = 1, nspins
482 1 : nmo_virt(ispin) = SIZE(gs_mos(ispin)%evals_virt)
483 21 : DO ivirt = 1, nmo_virt(ispin)
484 20 : WRITE (ounit, "(F20.14)") gs_mos(ispin)%evals_virt(ivirt)
485 : END DO
486 : END DO
487 : END IF
488 : END IF
489 :
490 : ! print phases of molecular orbitals
491 :
492 2 : IF (print_phases) THEN
493 0 : IF (ounit > 0) THEN
494 0 : WRITE (ounit, "(A)") "PHASES OCCUPIED ORBITALS"
495 0 : DO ispin = 1, nspins
496 0 : DO iocc = 1, nmo_occ(ispin)
497 0 : WRITE (ounit, "(F20.14)") gs_mos(ispin)%phases_occ(iocc)
498 : END DO
499 : END DO
500 0 : IF (print_virtuals) THEN
501 0 : WRITE (ounit, "(A)") "PHASES VIRTUAL ORBITALS"
502 0 : DO ispin = 1, nspins
503 0 : DO ivirt = 1, nmo_virt(ispin)
504 0 : WRITE (ounit, "(F20.14)") gs_mos(ispin)%phases_virt(ivirt)
505 : END DO
506 : END DO
507 : END IF
508 : END IF
509 : END IF
510 :
511 2 : CALL cp_print_key_finished_output(ounit, logger, tddfpt_print_section, "NAMD_PRINT")
512 :
513 2 : CALL timestop(handle)
514 : END IF
515 :
516 2 : END SUBROUTINE tddfpt_write_newtonx_output
517 : ! **************************************************************************************************
518 : !> \brief ...
519 : !> \param evects ...
520 : !> \param ounit ...
521 : !> \param S_evects ...
522 : !> \param matrix_s ...
523 : ! **************************************************************************************************
524 0 : SUBROUTINE tddfpt_check_orthonormality(evects, ounit, S_evects, matrix_s)
525 :
526 : TYPE(cp_fm_type), DIMENSION(:, :), INTENT(in) :: evects
527 : INTEGER, INTENT(in) :: ounit
528 : TYPE(cp_fm_type), DIMENSION(:, :), INTENT(INOUT) :: S_evects
529 : TYPE(dbcsr_type), INTENT(in), POINTER :: matrix_s
530 :
531 : CHARACTER(LEN=*), PARAMETER :: routineN = 'tddfpt_check_orthonormality'
532 :
533 : INTEGER :: handle, ispin, ivect, jvect, nspins, &
534 : nvects_total
535 : INTEGER, DIMENSION(maxspins) :: nactive
536 : REAL(kind=dp) :: norm
537 : REAL(kind=dp), DIMENSION(maxspins) :: weights
538 :
539 0 : CALL timeset(routineN, handle)
540 :
541 0 : nspins = SIZE(evects, 1)
542 0 : nvects_total = SIZE(evects, 2)
543 :
544 : IF (debug_this_module) THEN
545 : CPASSERT(SIZE(S_evects, 1) == nspins)
546 : CPASSERT(SIZE(S_evects, 2) == nvects_total)
547 : END IF
548 :
549 0 : DO ispin = 1, nspins
550 0 : CALL cp_fm_get_info(matrix=evects(ispin, 1), ncol_global=nactive(ispin))
551 : END DO
552 :
553 0 : DO jvect = 1, nvects_total
554 : ! <psi1_i | psi1_j>
555 0 : DO ivect = 1, jvect - 1
556 0 : CALL cp_fm_trace(evects(:, jvect), S_evects(:, ivect), weights(1:nspins), accurate=.FALSE.)
557 0 : norm = SUM(weights(1:nspins))
558 :
559 0 : DO ispin = 1, nspins
560 0 : CALL cp_fm_scale_and_add(1.0_dp, evects(ispin, jvect), -norm, evects(ispin, ivect))
561 : END DO
562 : END DO
563 :
564 : ! <psi1_j | psi1_j>
565 0 : DO ispin = 1, nspins
566 : CALL cp_dbcsr_sm_fm_multiply(matrix_s, evects(ispin, jvect), S_evects(ispin, jvect), &
567 0 : ncol=nactive(ispin), alpha=1.0_dp, beta=0.0_dp)
568 : END DO
569 :
570 0 : CALL cp_fm_trace(evects(:, jvect), S_evects(:, jvect), weights(1:nspins), accurate=.FALSE.)
571 :
572 0 : norm = SUM(weights(1:nspins))
573 : norm = 1.0_dp/SQRT(norm)
574 :
575 0 : IF ((ounit > 0) .AND. debug_this_module) WRITE (ounit, '(A,F10.8)') "norm", norm
576 :
577 : END DO
578 :
579 0 : CALL timestop(handle)
580 :
581 0 : END SUBROUTINE tddfpt_check_orthonormality
582 : ! **************************************************************************************************
583 : !> \brief ...
584 : !> \param evects ...
585 : !> \param phase_evects ...
586 : !> \param sub_env ...
587 : ! **************************************************************************************************
588 2 : SUBROUTINE compute_phase_eigenvectors(evects, phase_evects, sub_env)
589 :
590 : ! copied from parts of tddgpt_init_ground_state_mos by S. Chulkov
591 :
592 : TYPE(cp_fm_type), INTENT(in) :: evects
593 : REAL(kind=dp), DIMENSION(:), INTENT(out) :: phase_evects
594 : TYPE(tddfpt_subgroup_env_type), INTENT(in) :: sub_env
595 :
596 : CHARACTER(len=*), PARAMETER :: routineN = 'compute_phase_eigenvectors'
597 : REAL(kind=dp), PARAMETER :: eps_dp = EPSILON(0.0_dp)
598 :
599 : INTEGER :: handle, icol_global, icol_local, irow_global, irow_local, ncol_global, &
600 : ncol_local, nrow_global, nrow_local, sign_int
601 : INTEGER, ALLOCATABLE, DIMENSION(:) :: minrow_neg_array, minrow_pos_array, &
602 : sum_sign_array
603 2 : INTEGER, DIMENSION(:), POINTER :: col_indices, row_indices
604 : REAL(kind=dp) :: element
605 : REAL(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
606 2 : POINTER :: my_block
607 :
608 2 : CALL timeset(routineN, handle)
609 :
610 : ! compute and print the phase of excited-state eigenvectors:
611 : CALL cp_fm_get_info(evects, nrow_global=nrow_global, ncol_global=ncol_global, &
612 : nrow_local=nrow_local, ncol_local=ncol_local, local_data=my_block, &
613 2 : row_indices=row_indices, col_indices=col_indices) ! nrow_global either nao or nocc
614 :
615 10 : ALLOCATE (minrow_neg_array(ncol_global), minrow_pos_array(ncol_global), sum_sign_array(ncol_global))
616 10 : minrow_neg_array(:) = nrow_global
617 10 : minrow_pos_array(:) = nrow_global
618 2 : sum_sign_array(:) = 0
619 :
620 10 : DO icol_local = 1, ncol_local
621 8 : icol_global = col_indices(icol_local)
622 :
623 86 : DO irow_local = 1, nrow_local
624 76 : irow_global = row_indices(irow_local)
625 :
626 76 : element = my_block(irow_local, icol_local)
627 :
628 76 : sign_int = 0
629 76 : IF (element >= eps_dp) THEN
630 : sign_int = 1
631 36 : ELSE IF (element <= -eps_dp) THEN
632 36 : sign_int = -1
633 : END IF
634 :
635 76 : sum_sign_array(icol_global) = sum_sign_array(icol_global) + sign_int
636 :
637 84 : IF (sign_int > 0) THEN
638 40 : IF (minrow_pos_array(icol_global) > irow_global) THEN
639 8 : minrow_pos_array(icol_global) = irow_global
640 : END IF
641 36 : ELSE IF (sign_int < 0) THEN
642 36 : IF (minrow_neg_array(icol_global) > irow_global) THEN
643 8 : minrow_neg_array(icol_global) = irow_global
644 : END IF
645 : END IF
646 :
647 : END DO
648 : END DO
649 :
650 2 : CALL sub_env%para_env%sum(sum_sign_array)
651 2 : CALL sub_env%para_env%min(minrow_neg_array)
652 2 : CALL sub_env%para_env%min(minrow_pos_array)
653 :
654 10 : DO icol_global = 1, ncol_global
655 :
656 10 : IF (sum_sign_array(icol_global) > 0) THEN
657 : ! most of the expansion coefficients are positive => MO's phase = +1
658 6 : phase_evects(icol_global) = 1.0_dp
659 2 : ELSE IF (sum_sign_array(icol_global) < 0) THEN
660 : ! most of the expansion coefficients are negative => MO's phase = -1
661 2 : phase_evects(icol_global) = -1.0_dp
662 : ELSE
663 : ! equal number of positive and negative expansion coefficients
664 0 : IF (minrow_pos_array(icol_global) <= minrow_neg_array(icol_global)) THEN
665 : ! the first positive expansion coefficient has a lower index then
666 : ! the first negative expansion coefficient; MO's phase = +1
667 0 : phase_evects(icol_global) = 1.0_dp
668 : ELSE
669 : ! MO's phase = -1
670 0 : phase_evects(icol_global) = -1.0_dp
671 : END IF
672 : END IF
673 :
674 : END DO
675 :
676 2 : DEALLOCATE (minrow_neg_array, minrow_pos_array, sum_sign_array)
677 :
678 2 : CALL timestop(handle)
679 :
680 2 : END SUBROUTINE compute_phase_eigenvectors
681 :
682 : END MODULE qs_tddfpt2_restart
|