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 Methods for X-Ray absorption spectroscopy (XAS) using TDDFPT
10 : !> \author AB (11.2017)
11 : ! **************************************************************************************************
12 :
13 : MODULE xas_tdp_methods
14 : USE admm_types, ONLY: admm_type
15 : USE admm_utils, ONLY: admm_correct_for_eigenvalues,&
16 : admm_uncorrect_for_eigenvalues
17 : USE atomic_kind_types, ONLY: atomic_kind_type,&
18 : get_atomic_kind
19 : USE basis_set_types, ONLY: &
20 : allocate_sto_basis_set, create_gto_from_sto_basis, deallocate_gto_basis_set, &
21 : deallocate_sto_basis_set, get_gto_basis_set, gto_basis_set_type, init_orb_basis_set, &
22 : set_sto_basis_set, srules, sto_basis_set_type
23 : USE bibliography, ONLY: Bussy2021a,&
24 : cite_reference
25 : USE cell_types, ONLY: cell_type,&
26 : pbc
27 : USE cp_blacs_env, ONLY: cp_blacs_env_type
28 : USE cp_control_types, ONLY: dft_control_type
29 : USE cp_dbcsr_api, ONLY: &
30 : dbcsr_complete_redistribute, dbcsr_copy, dbcsr_create, dbcsr_filter, dbcsr_finalize, &
31 : dbcsr_get_info, dbcsr_get_occupation, dbcsr_multiply, dbcsr_p_type, dbcsr_release, &
32 : dbcsr_set, dbcsr_type, dbcsr_type_antisymmetric, dbcsr_type_no_symmetry, &
33 : dbcsr_type_symmetric
34 : USE cp_dbcsr_contrib, ONLY: dbcsr_add_on_diag
35 : USE cp_dbcsr_operations, ONLY: copy_dbcsr_to_fm,&
36 : copy_fm_to_dbcsr,&
37 : cp_dbcsr_sm_fm_multiply
38 : USE cp_files, ONLY: close_file,&
39 : open_file
40 : USE cp_fm_basic_linalg, ONLY: cp_fm_column_scale
41 : USE cp_fm_diag, ONLY: cp_fm_geeig,&
42 : cp_fm_power,&
43 : cp_fm_syevd
44 : USE cp_fm_struct, ONLY: cp_fm_struct_create,&
45 : cp_fm_struct_release,&
46 : cp_fm_struct_type
47 : USE cp_fm_types, ONLY: &
48 : cp_fm_copy_general, cp_fm_create, cp_fm_get_diag, cp_fm_get_info, cp_fm_get_submatrix, &
49 : cp_fm_read_unformatted, cp_fm_release, cp_fm_set_all, cp_fm_to_fm, cp_fm_to_fm_submat, &
50 : cp_fm_type, cp_fm_write_unformatted
51 : USE cp_log_handling, ONLY: cp_get_default_logger,&
52 : cp_logger_get_default_io_unit,&
53 : cp_logger_type,&
54 : cp_to_string
55 : USE cp_output_handling, ONLY: cp_p_file,&
56 : cp_print_key_finished_output,&
57 : cp_print_key_generate_filename,&
58 : cp_print_key_should_output,&
59 : cp_print_key_unit_nr,&
60 : debug_print_level
61 : USE input_constants, ONLY: &
62 : do_admm_purify_cauchy_subspace, do_admm_purify_mo_diag, do_admm_purify_none, do_loc_none, &
63 : do_potential_coulomb, do_potential_id, do_potential_short, do_potential_truncated, &
64 : op_loc_berry, state_loc_list, tddfpt_singlet, tddfpt_spin_cons, tddfpt_spin_flip, &
65 : tddfpt_triplet, xas_1s_type, xas_2p_type, xas_2s_type, xas_dip_len, xas_dip_vel, &
66 : xas_not_excited, xas_tdp_by_index, xas_tdp_by_kind
67 : USE input_cp2k_loc, ONLY: create_localize_section
68 : USE input_section_types, ONLY: section_release,&
69 : section_type,&
70 : section_vals_create,&
71 : section_vals_get_subs_vals,&
72 : section_vals_type,&
73 : section_vals_val_get,&
74 : section_vals_val_set
75 : USE kinds, ONLY: default_path_length,&
76 : default_string_length,&
77 : dp
78 : USE libint_wrapper, ONLY: cp_libint_static_init
79 : USE machine, ONLY: m_flush
80 : USE mathlib, ONLY: get_diag
81 : USE memory_utilities, ONLY: reallocate
82 : USE message_passing, ONLY: mp_comm_type,&
83 : mp_para_env_type
84 : USE parallel_gemm_api, ONLY: parallel_gemm
85 : USE parallel_rng_types, ONLY: UNIFORM,&
86 : rng_stream_type
87 : USE particle_methods, ONLY: get_particle_set
88 : USE particle_types, ONLY: particle_type
89 : USE periodic_table, ONLY: ptable
90 : USE physcon, ONLY: a_fine,&
91 : angstrom,&
92 : evolt
93 : USE qs_environment_types, ONLY: get_qs_env,&
94 : qs_environment_type
95 : USE qs_interactions, ONLY: init_interaction_radii_orb_basis
96 : USE qs_kind_types, ONLY: get_qs_kind,&
97 : qs_kind_type
98 : USE qs_loc_main, ONLY: qs_loc_driver
99 : USE qs_loc_methods, ONLY: centers_spreads_berry,&
100 : qs_print_cubes
101 : USE qs_loc_types, ONLY: get_qs_loc_env,&
102 : localized_wfn_control_create,&
103 : localized_wfn_control_type,&
104 : qs_loc_env_create,&
105 : qs_loc_env_release,&
106 : qs_loc_env_type
107 : USE qs_loc_utils, ONLY: qs_loc_control_init,&
108 : qs_loc_env_init,&
109 : set_loc_centers
110 : USE qs_mo_io, ONLY: write_mo_set_low
111 : USE qs_mo_methods, ONLY: calculate_subspace_eigenvalues
112 : USE qs_mo_types, ONLY: allocate_mo_set,&
113 : deallocate_mo_set,&
114 : duplicate_mo_set,&
115 : get_mo_set,&
116 : init_mo_set,&
117 : mo_set_type
118 : USE qs_operators_ao, ONLY: p_xyz_ao,&
119 : rRc_xyz_ao
120 : USE qs_pdos, ONLY: calculate_projected_dos
121 : USE qs_rho_types, ONLY: qs_rho_get,&
122 : qs_rho_type
123 : USE qs_scf_types, ONLY: ot_method_nr
124 : USE util, ONLY: get_limit,&
125 : locate,&
126 : sort_unique
127 : USE xas_methods, ONLY: calc_stogto_overlap
128 : USE xas_tdp_atom, ONLY: init_xas_atom_env,&
129 : integrate_fxc_atoms,&
130 : integrate_soc_atoms
131 : USE xas_tdp_correction, ONLY: GW2X_shift,&
132 : get_soc_splitting
133 : USE xas_tdp_integrals, ONLY: compute_ri_3c_coulomb,&
134 : compute_ri_3c_exchange,&
135 : compute_ri_coulomb2_int,&
136 : compute_ri_exchange2_int
137 : USE xas_tdp_types, ONLY: &
138 : donor_state_create, donor_state_type, free_ds_memory, free_exat_memory, &
139 : read_xas_tdp_control, set_donor_state, set_xas_tdp_env, xas_atom_env_create, &
140 : xas_atom_env_release, xas_atom_env_type, xas_tdp_control_create, xas_tdp_control_release, &
141 : xas_tdp_control_type, xas_tdp_env_create, xas_tdp_env_release, xas_tdp_env_type
142 : USE xas_tdp_utils, ONLY: include_os_soc,&
143 : include_rcs_soc,&
144 : setup_xas_tdp_prob,&
145 : solve_xas_tdp_prob
146 : USE xc_write_output, ONLY: xc_write
147 : #include "./base/base_uses.f90"
148 :
149 : IMPLICIT NONE
150 : PRIVATE
151 :
152 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'xas_tdp_methods'
153 :
154 : PUBLIC :: xas_tdp, xas_tdp_init
155 :
156 : CONTAINS
157 :
158 : ! **************************************************************************************************
159 : !> \brief Driver for XAS TDDFT calculations.
160 : !> \param qs_env the inherited qs_environment
161 : !> \author AB
162 : !> \note Empty for now...
163 : ! **************************************************************************************************
164 100 : SUBROUTINE xas_tdp(qs_env)
165 :
166 : TYPE(qs_environment_type), POINTER :: qs_env
167 :
168 : CHARACTER(len=*), PARAMETER :: routineN = 'xas_tdp'
169 :
170 : CHARACTER(default_string_length) :: rst_filename
171 : INTEGER :: handle, n_rep, output_unit
172 : LOGICAL :: do_restart
173 : TYPE(section_vals_type), POINTER :: xas_tdp_section
174 :
175 50 : CALL timeset(routineN, handle)
176 :
177 : ! Logger initialization and XAS TDP banner printing
178 50 : NULLIFY (xas_tdp_section)
179 50 : xas_tdp_section => section_vals_get_subs_vals(qs_env%input, "DFT%XAS_TDP")
180 50 : output_unit = cp_logger_get_default_io_unit()
181 :
182 50 : IF (output_unit > 0) THEN
183 : WRITE (UNIT=output_unit, FMT="(/,T3,A,/,T3,A,/,T3,A,/,T3,A,/)") &
184 25 : "!===========================================================================!", &
185 25 : "! XAS TDP !", &
186 25 : "! Starting TDDFPT driven X-rays absorption spectroscopy calculations !", &
187 50 : "!===========================================================================!"
188 : END IF
189 :
190 50 : CALL cite_reference(Bussy2021a)
191 :
192 : ! Check whether this is a restart calculation, i.e. is a restart file is provided
193 50 : CALL section_vals_val_get(xas_tdp_section, "RESTART_FROM_FILE", n_rep_val=n_rep)
194 :
195 50 : IF (n_rep < 1) THEN
196 : do_restart = .FALSE.
197 : ELSE
198 2 : CALL section_vals_val_get(xas_tdp_section, "RESTART_FROM_FILE", c_val=rst_filename)
199 : do_restart = .TRUE.
200 : END IF
201 :
202 : ! Restart the calculation if needed
203 : IF (do_restart) THEN
204 :
205 2 : IF (output_unit > 0) THEN
206 : WRITE (UNIT=output_unit, FMT="(/,T3,A)") &
207 1 : "# This is a RESTART calculation for PDOS and/or CUBE printing"
208 : END IF
209 :
210 2 : CALL restart_calculation(rst_filename, xas_tdp_section, qs_env)
211 :
212 : ! or run the core XAS_TDP routine if not
213 : ELSE
214 48 : CALL xas_tdp_core(xas_tdp_section, qs_env)
215 : END IF
216 :
217 50 : IF (output_unit > 0) THEN
218 : WRITE (UNIT=output_unit, FMT="(/,T3,A,/,T3,A,/,T3,A,/)") &
219 25 : "!===========================================================================!", &
220 25 : "! End of TDDFPT driven X-rays absorption spectroscopy calculations !", &
221 50 : "!===========================================================================!"
222 : END IF
223 :
224 50 : CALL timestop(handle)
225 :
226 50 : END SUBROUTINE xas_tdp
227 :
228 : ! **************************************************************************************************
229 : !> \brief The core workflow of the XAS_TDP method
230 : !> \param xas_tdp_section the input values for XAS_TDP
231 : !> \param qs_env ...
232 : ! **************************************************************************************************
233 48 : SUBROUTINE xas_tdp_core(xas_tdp_section, qs_env)
234 :
235 : TYPE(section_vals_type), POINTER :: xas_tdp_section
236 : TYPE(qs_environment_type), POINTER :: qs_env
237 :
238 : CHARACTER(LEN=default_string_length) :: kind_name
239 : INTEGER :: batch_size, bo(2), current_state_index, iat, iatom, ibatch, ikind, ispin, istate, &
240 : nbatch, nex_atom, output_unit, tmp_index
241 48 : INTEGER, ALLOCATABLE, DIMENSION(:) :: batch_atoms, ex_atoms_of_kind
242 48 : INTEGER, DIMENSION(:), POINTER :: atoms_of_kind
243 : LOGICAL :: do_os, end_of_batch, unique
244 : TYPE(admm_type), POINTER :: admm_env
245 48 : TYPE(atomic_kind_type), DIMENSION(:), POINTER :: atomic_kind_set
246 48 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_ks
247 : TYPE(dft_control_type), POINTER :: dft_control
248 : TYPE(donor_state_type), POINTER :: current_state
249 : TYPE(gto_basis_set_type), POINTER :: tmp_basis
250 48 : TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
251 : TYPE(xas_atom_env_type), POINTER :: xas_atom_env
252 : TYPE(xas_tdp_control_type), POINTER :: xas_tdp_control
253 : TYPE(xas_tdp_env_type), POINTER :: xas_tdp_env
254 :
255 48 : NULLIFY (xas_tdp_env, xas_tdp_control, atomic_kind_set, atoms_of_kind, current_state)
256 48 : NULLIFY (xas_atom_env, dft_control, matrix_ks, admm_env, qs_kind_set, tmp_basis)
257 :
258 : ! Initialization
259 96 : output_unit = cp_logger_get_default_io_unit()
260 :
261 48 : IF (output_unit > 0) THEN
262 : WRITE (UNIT=output_unit, FMT="(/,T3,A)") &
263 24 : "# Create and initialize the XAS_TDP environment"
264 : END IF
265 48 : CALL get_qs_env(qs_env, dft_control=dft_control)
266 48 : CALL xas_tdp_init(xas_tdp_env, xas_tdp_control, qs_env)
267 48 : CALL print_info(output_unit, xas_tdp_control, qs_env)
268 :
269 48 : IF (output_unit > 0) THEN
270 24 : IF (xas_tdp_control%check_only) THEN
271 0 : CPWARN("This is a CHECK_ONLY run for donor MOs verification")
272 : END IF
273 : END IF
274 :
275 : ! Localization of the core orbitals if requested (used for better identification of donor states)
276 48 : IF (xas_tdp_control%do_loc) THEN
277 32 : IF (output_unit > 0) THEN
278 : WRITE (UNIT=output_unit, FMT="(/,T3,A,/)") &
279 16 : "# Localizing core orbitals for better identification"
280 : END IF
281 : ! closed shell or ROKS => myspin=1
282 32 : IF (xas_tdp_control%do_uks) THEN
283 6 : DO ispin = 1, dft_control%nspins
284 : CALL qs_loc_driver(qs_env, xas_tdp_env%qs_loc_env, &
285 6 : xas_tdp_control%print_loc_subsection, myspin=ispin)
286 : END DO
287 : ELSE
288 : CALL qs_loc_driver(qs_env, xas_tdp_env%qs_loc_env, &
289 30 : xas_tdp_control%print_loc_subsection, myspin=1)
290 : END IF
291 : END IF
292 :
293 : ! Find the MO centers
294 48 : CALL find_mo_centers(xas_tdp_env, xas_tdp_control, qs_env)
295 :
296 : ! Assign lowest energy orbitals to excited atoms
297 48 : CALL assign_mos_to_ex_atoms(xas_tdp_env, xas_tdp_control, qs_env)
298 :
299 : ! Once assigned, diagonalize the MOs wrt the KS matrix in the subspace associated to each atom
300 48 : IF (xas_tdp_control%do_loc) THEN
301 32 : IF (output_unit > 0) THEN
302 : WRITE (UNIT=output_unit, FMT="(/,T3,A,/,T5,A)") &
303 16 : "# Diagonalize localized MOs wrt the KS matrix in the subspace of each excited", &
304 32 : "atom for better donor state identification."
305 : END IF
306 32 : CALL diagonalize_assigned_mo_subset(xas_tdp_env, xas_tdp_control, qs_env)
307 : ! update MO centers
308 32 : CALL find_mo_centers(xas_tdp_env, xas_tdp_control, qs_env)
309 : END IF
310 :
311 48 : IF (output_unit > 0) THEN
312 : WRITE (UNIT=output_unit, FMT="(/,T3,A,I4,A,/)") &
313 24 : "# Assign the relevant subset of the ", xas_tdp_control%n_search, &
314 48 : " lowest energy MOs to excited atoms"
315 : END IF
316 48 : CALL write_mos_to_ex_atoms_association(xas_tdp_env, xas_tdp_control, qs_env)
317 :
318 : ! If CHECK_ONLY run, check the donor MOs
319 48 : IF (xas_tdp_control%check_only) CALL print_checks(xas_tdp_env, xas_tdp_control, qs_env)
320 :
321 : ! If not simply exact exchange, setup a xas_atom_env and compute the xc integrals on the atomic grids
322 : ! Also needed if SOC is included or XPS GW2X(). Done before looping on atoms as it's all done at once
323 : IF ((xas_tdp_control%do_xc .OR. xas_tdp_control%do_soc .OR. xas_tdp_control%do_gw2x) &
324 48 : .AND. .NOT. xas_tdp_control%check_only) THEN
325 :
326 48 : IF (output_unit > 0 .AND. xas_tdp_control%do_xc) THEN
327 : WRITE (UNIT=output_unit, FMT="(/,T3,A,I4,A)") &
328 19 : "# Integrating the xc kernel on the atomic grids ..."
329 19 : CALL m_flush(output_unit)
330 : END IF
331 :
332 48 : CALL xas_atom_env_create(xas_atom_env)
333 48 : CALL init_xas_atom_env(xas_atom_env, xas_tdp_env, xas_tdp_control, qs_env)
334 48 : do_os = xas_tdp_control%do_uks .OR. xas_tdp_control%do_roks
335 :
336 48 : IF (xas_tdp_control%do_xc .AND. (.NOT. xas_tdp_control%xps_only)) THEN
337 38 : CALL integrate_fxc_atoms(xas_tdp_env%ri_fxc, xas_atom_env, xas_tdp_control, qs_env)
338 : END IF
339 :
340 48 : IF (xas_tdp_control%do_soc .OR. xas_tdp_control%do_gw2x) THEN
341 22 : CALL integrate_soc_atoms(xas_tdp_env%orb_soc, xas_atom_env=xas_atom_env, qs_env=qs_env)
342 : END IF
343 :
344 48 : CALL xas_atom_env_release(xas_atom_env)
345 : END IF
346 :
347 : ! Compute the 3-center Coulomb integrals for the whole system
348 48 : IF ((.NOT. (xas_tdp_control%check_only .OR. xas_tdp_control%xps_only)) .AND. &
349 : (xas_tdp_control%do_xc .OR. xas_tdp_control%do_coulomb)) THEN
350 44 : IF (output_unit > 0) THEN
351 : WRITE (UNIT=output_unit, FMT="(/,T3,A,I4,A)") &
352 22 : "# Computing the RI 3-center Coulomb integrals ..."
353 22 : CALL m_flush(output_unit)
354 : END IF
355 44 : CALL compute_ri_3c_coulomb(xas_tdp_env, qs_env)
356 :
357 : END IF
358 :
359 : ! Loop over donor states for calculation
360 48 : CALL get_qs_env(qs_env=qs_env, atomic_kind_set=atomic_kind_set)
361 48 : current_state_index = 1
362 :
363 : ! Loop over atomic kinds
364 122 : DO ikind = 1, SIZE(atomic_kind_set)
365 :
366 74 : IF (xas_tdp_control%check_only) EXIT
367 102 : IF (.NOT. ANY(xas_tdp_env%ex_kind_indices == ikind)) CYCLE
368 :
369 : CALL get_atomic_kind(atomic_kind=atomic_kind_set(ikind), name=kind_name, &
370 52 : atom_list=atoms_of_kind)
371 :
372 : ! compute the RI coulomb2 inverse for this kind, and RI exchange2 if needed
373 52 : CALL compute_ri_coulomb2_int(ikind, xas_tdp_env, xas_tdp_control, qs_env)
374 52 : IF (xas_tdp_control%do_hfx) THEN
375 42 : CALL compute_ri_exchange2_int(ikind, xas_tdp_env, xas_tdp_control, qs_env)
376 : END IF
377 :
378 : !Randomly distribute excited atoms of current kinds into batches for optimal load balance
379 : !of RI 3c exchange integrals. Take batch sizes of 2 to avoid taxing memory too much, while
380 : !greatly improving load balance
381 52 : batch_size = 2
382 52 : CALL get_ri_3c_batches(ex_atoms_of_kind, nbatch, batch_size, atoms_of_kind, xas_tdp_env)
383 52 : nex_atom = SIZE(ex_atoms_of_kind)
384 :
385 : !Loop over batches
386 104 : DO ibatch = 1, nbatch
387 :
388 52 : bo = get_limit(nex_atom, nbatch, ibatch - 1)
389 52 : batch_size = bo(2) - bo(1) + 1
390 156 : ALLOCATE (batch_atoms(batch_size))
391 52 : iatom = 0
392 110 : DO iat = bo(1), bo(2)
393 58 : iatom = iatom + 1
394 110 : batch_atoms(iatom) = ex_atoms_of_kind(iat)
395 : END DO
396 52 : CALL sort_unique(batch_atoms, unique)
397 :
398 : !compute RI 3c exchange integrals on batch, if so required
399 52 : IF (xas_tdp_control%do_hfx) THEN
400 42 : IF (output_unit > 0) THEN
401 : WRITE (UNIT=output_unit, FMT="(/,T3,A,I4,A,I4,A,I1,A,A)") &
402 21 : "# Computing the RI 3-center Exchange integrals for batch ", ibatch, "(/", nbatch, ") of ", &
403 42 : batch_size, " atoms of kind: ", TRIM(kind_name)
404 21 : CALL m_flush(output_unit)
405 : END IF
406 42 : CALL compute_ri_3c_exchange(batch_atoms, xas_tdp_env, xas_tdp_control, qs_env)
407 : END IF
408 :
409 : ! Loop over atoms of batch
410 110 : DO iat = 1, batch_size
411 58 : iatom = batch_atoms(iat)
412 :
413 58 : tmp_index = locate(xas_tdp_env%ex_atom_indices, iatom)
414 :
415 : !if dipole in length rep, compute the dipole in the AO basis for this atom
416 : !if quadrupole is required, compute it there too (in length rep)
417 58 : IF (xas_tdp_control%dipole_form == xas_dip_len .OR. xas_tdp_control%do_quad) THEN
418 24 : CALL compute_lenrep_multipole(iatom, xas_tdp_env, xas_tdp_control, qs_env)
419 : END IF
420 :
421 : ! Loop over states of excited atom of kind
422 126 : DO istate = 1, SIZE(xas_tdp_env%state_types, 1)
423 :
424 68 : IF (xas_tdp_env%state_types(istate, tmp_index) == xas_not_excited) CYCLE
425 :
426 68 : current_state => xas_tdp_env%donor_states(current_state_index)
427 : CALL set_donor_state(current_state, at_index=iatom, &
428 : at_symbol=kind_name, kind_index=ikind, &
429 68 : state_type=xas_tdp_env%state_types(istate, tmp_index))
430 :
431 : ! Initial write for the donor state of interest
432 68 : IF (output_unit > 0) THEN
433 : WRITE (UNIT=output_unit, FMT="(/,T3,A,A2,A,I4,A,A,/)") &
434 34 : "# Start of calculations for donor state of type ", &
435 34 : xas_tdp_env%state_type_char(current_state%state_type), " for atom", &
436 68 : current_state%at_index, " of kind ", TRIM(current_state%at_symbol)
437 34 : CALL m_flush(output_unit)
438 : END IF
439 :
440 : ! Assign best fitting MO(s) to current core donnor state
441 68 : CALL assign_mos_to_donor_state(current_state, xas_tdp_env, xas_tdp_control, qs_env)
442 :
443 : ! Perform MO restricted Mulliken pop analysis for verification
444 68 : CALL perform_mulliken_on_donor_state(current_state, qs_env)
445 :
446 : ! GW2X correction
447 68 : IF (xas_tdp_control%do_gw2x) THEN
448 30 : CALL GW2X_shift(current_state, xas_tdp_env, xas_tdp_control, qs_env)
449 : END IF
450 :
451 : ! Do main XAS calculations here
452 68 : IF (.NOT. xas_tdp_control%xps_only) THEN
453 56 : CALL setup_xas_tdp_prob(current_state, qs_env, xas_tdp_env, xas_tdp_control)
454 :
455 56 : IF (xas_tdp_control%do_spin_cons) THEN
456 : CALL solve_xas_tdp_prob(current_state, xas_tdp_control, xas_tdp_env, qs_env, &
457 8 : ex_type=tddfpt_spin_cons)
458 8 : CALL compute_dipole_fosc(current_state, xas_tdp_control, xas_tdp_env)
459 8 : IF (xas_tdp_control%do_quad) CALL compute_quadrupole_fosc(current_state, &
460 0 : xas_tdp_control, xas_tdp_env)
461 : CALL xas_tdp_post(tddfpt_spin_cons, current_state, xas_tdp_env, &
462 8 : xas_tdp_section, qs_env)
463 8 : CALL write_donor_state_restart(tddfpt_spin_cons, current_state, xas_tdp_section, qs_env)
464 : END IF
465 :
466 56 : IF (xas_tdp_control%do_spin_flip) THEN
467 : CALL solve_xas_tdp_prob(current_state, xas_tdp_control, xas_tdp_env, qs_env, &
468 2 : ex_type=tddfpt_spin_flip)
469 : !no dipole in spin-flip (spin-forbidden)
470 : CALL xas_tdp_post(tddfpt_spin_flip, current_state, xas_tdp_env, &
471 2 : xas_tdp_section, qs_env)
472 2 : CALL write_donor_state_restart(tddfpt_spin_flip, current_state, xas_tdp_section, qs_env)
473 : END IF
474 :
475 56 : IF (xas_tdp_control%do_singlet) THEN
476 : CALL solve_xas_tdp_prob(current_state, xas_tdp_control, xas_tdp_env, qs_env, &
477 48 : ex_type=tddfpt_singlet)
478 48 : CALL compute_dipole_fosc(current_state, xas_tdp_control, xas_tdp_env)
479 48 : IF (xas_tdp_control%do_quad) CALL compute_quadrupole_fosc(current_state, &
480 0 : xas_tdp_control, xas_tdp_env)
481 : CALL xas_tdp_post(tddfpt_singlet, current_state, xas_tdp_env, &
482 48 : xas_tdp_section, qs_env)
483 48 : CALL write_donor_state_restart(tddfpt_singlet, current_state, xas_tdp_section, qs_env)
484 : END IF
485 :
486 56 : IF (xas_tdp_control%do_triplet) THEN
487 : CALL solve_xas_tdp_prob(current_state, xas_tdp_control, xas_tdp_env, qs_env, &
488 2 : ex_type=tddfpt_triplet)
489 : !no dipole for triplets by construction
490 : CALL xas_tdp_post(tddfpt_triplet, current_state, xas_tdp_env, &
491 2 : xas_tdp_section, qs_env)
492 2 : CALL write_donor_state_restart(tddfpt_triplet, current_state, xas_tdp_section, qs_env)
493 : END IF
494 :
495 : ! Include the SOC if required, only for 2p donor stataes
496 56 : IF (xas_tdp_control%do_soc .AND. current_state%state_type == xas_2p_type) THEN
497 4 : IF (xas_tdp_control%do_singlet .AND. xas_tdp_control%do_triplet) THEN
498 2 : CALL include_rcs_soc(current_state, xas_tdp_env, xas_tdp_control, qs_env)
499 : END IF
500 4 : IF (xas_tdp_control%do_spin_cons .AND. xas_tdp_control%do_spin_flip) THEN
501 2 : CALL include_os_soc(current_state, xas_tdp_env, xas_tdp_control, qs_env)
502 : END IF
503 : END IF
504 :
505 : ! Print the requested properties
506 56 : CALL print_xas_tdp_to_file(current_state, xas_tdp_env, xas_tdp_control, xas_tdp_section)
507 : END IF !xps_only
508 68 : IF (xas_tdp_control%do_gw2x) CALL print_xps(current_state, xas_tdp_env, xas_tdp_control, qs_env)
509 :
510 : ! Free some unneeded attributes of current_state
511 68 : CALL free_ds_memory(current_state)
512 :
513 68 : current_state_index = current_state_index + 1
514 126 : NULLIFY (current_state)
515 :
516 : END DO ! state type
517 :
518 58 : end_of_batch = .FALSE.
519 58 : IF (iat == batch_size) end_of_batch = .TRUE.
520 110 : CALL free_exat_memory(xas_tdp_env, iatom, end_of_batch)
521 : END DO ! atom of batch
522 156 : DEALLOCATE (batch_atoms)
523 : END DO !ibatch
524 174 : DEALLOCATE (ex_atoms_of_kind)
525 : END DO ! kind
526 :
527 : ! Return to ususal KS matrix
528 48 : IF (dft_control%do_admm) THEN
529 4 : CALL get_qs_env(qs_env, matrix_ks=matrix_ks, admm_env=admm_env)
530 8 : DO ispin = 1, dft_control%nspins
531 8 : CALL admm_uncorrect_for_eigenvalues(ispin, admm_env, matrix_ks(ispin)%matrix)
532 : END DO
533 : END IF
534 :
535 : ! Return to initial basis set radii
536 48 : IF (xas_tdp_control%eps_pgf > 0.0_dp) THEN
537 0 : CALL get_qs_env(qs_env, qs_kind_set=qs_kind_set)
538 0 : DO ikind = 1, SIZE(atomic_kind_set)
539 0 : CALL get_qs_kind(qs_kind_set(ikind), basis_set=tmp_basis, basis_type="ORB")
540 0 : CALL init_interaction_radii_orb_basis(tmp_basis, eps_pgf_orb=dft_control%qs_control%eps_pgf_orb)
541 : END DO
542 : END IF
543 :
544 : ! Clean-up
545 48 : CALL xas_tdp_env_release(xas_tdp_env)
546 48 : CALL xas_tdp_control_release(xas_tdp_control)
547 :
548 96 : END SUBROUTINE xas_tdp_core
549 :
550 : ! **************************************************************************************************
551 : !> \brief Overall control and environment types initialization
552 : !> \param xas_tdp_env the environment type to initialize
553 : !> \param xas_tdp_control the control type to initialize
554 : !> \param qs_env the inherited qs environement type
555 : ! **************************************************************************************************
556 48 : SUBROUTINE xas_tdp_init(xas_tdp_env, xas_tdp_control, qs_env)
557 :
558 : TYPE(xas_tdp_env_type), POINTER :: xas_tdp_env
559 : TYPE(xas_tdp_control_type), POINTER :: xas_tdp_control
560 : TYPE(qs_environment_type), POINTER :: qs_env
561 :
562 : CHARACTER(LEN=default_string_length) :: kind_name
563 : INTEGER :: at_ind, i, ispin, j, k, kind_ind, &
564 : n_donor_states, n_kinds, nao, &
565 : nat_of_kind, natom, nex_atoms, &
566 : nex_kinds, nmatch, nspins
567 : INTEGER, DIMENSION(2) :: homo, n_mo, n_moloc
568 48 : INTEGER, DIMENSION(:), POINTER :: ind_of_kind
569 : LOGICAL :: do_os, do_uks, unique
570 : REAL(dp) :: fact
571 48 : REAL(dp), DIMENSION(:), POINTER :: mo_evals
572 : TYPE(admm_type), POINTER :: admm_env
573 48 : TYPE(atomic_kind_type), DIMENSION(:), POINTER :: at_kind_set
574 : TYPE(cell_type), POINTER :: cell
575 : TYPE(cp_fm_type), POINTER :: mo_coeff
576 48 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_ks, matrix_s, rho_ao
577 : TYPE(dbcsr_type) :: matrix_tmp
578 : TYPE(dft_control_type), POINTER :: dft_control
579 : TYPE(gto_basis_set_type), POINTER :: tmp_basis
580 48 : TYPE(mo_set_type), DIMENSION(:), POINTER :: mos
581 48 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
582 48 : TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
583 : TYPE(qs_loc_env_type), POINTER :: qs_loc_env
584 : TYPE(qs_rho_type), POINTER :: rho
585 : TYPE(section_type), POINTER :: dummy_section
586 : TYPE(section_vals_type), POINTER :: loc_section, xas_tdp_section
587 :
588 48 : NULLIFY (xas_tdp_section, at_kind_set, ind_of_kind, dft_control, qs_kind_set, tmp_basis)
589 48 : NULLIFY (qs_loc_env, loc_section, mos, particle_set, rho, rho_ao, mo_evals, cell)
590 48 : NULLIFY (mo_coeff, matrix_ks, admm_env, dummy_section)
591 :
592 : ! XAS TDP control type initialization
593 96 : xas_tdp_section => section_vals_get_subs_vals(qs_env%input, "DFT%XAS_TDP")
594 :
595 48 : CALL get_qs_env(qs_env, dft_control=dft_control)
596 48 : CALL xas_tdp_control_create(xas_tdp_control)
597 48 : CALL read_xas_tdp_control(xas_tdp_control, xas_tdp_section)
598 :
599 : ! Check the qs_env for a LSD/ROKS calculation
600 48 : IF (dft_control%uks) xas_tdp_control%do_uks = .TRUE.
601 48 : IF (dft_control%roks) xas_tdp_control%do_roks = .TRUE.
602 48 : do_uks = xas_tdp_control%do_uks
603 48 : do_os = do_uks .OR. xas_tdp_control%do_roks
604 :
605 : ! XAS TDP environment type initialization
606 48 : CALL xas_tdp_env_create(xas_tdp_env)
607 :
608 : ! Retrieving the excited atoms indices and correspondig state types
609 48 : IF (xas_tdp_control%define_excited == xas_tdp_by_index) THEN
610 :
611 : ! simply copy indices from xas_tdp_control
612 26 : nex_atoms = SIZE(xas_tdp_control%list_ex_atoms)
613 26 : CALL set_xas_tdp_env(xas_tdp_env, nex_atoms=nex_atoms)
614 78 : ALLOCATE (xas_tdp_env%ex_atom_indices(nex_atoms))
615 104 : ALLOCATE (xas_tdp_env%state_types(SIZE(xas_tdp_control%state_types, 1), nex_atoms))
616 86 : xas_tdp_env%ex_atom_indices = xas_tdp_control%list_ex_atoms
617 146 : xas_tdp_env%state_types = xas_tdp_control%state_types
618 :
619 : ! Test that these indices are within the range of available atoms
620 26 : CALL get_qs_env(qs_env=qs_env, natom=natom)
621 56 : IF (ANY(xas_tdp_env%ex_atom_indices > natom)) THEN
622 0 : CPABORT("Invalid index for the ATOM_LIST keyword.")
623 : END IF
624 :
625 : ! Check atom kinds and fill corresponding array
626 52 : ALLOCATE (xas_tdp_env%ex_kind_indices(nex_atoms))
627 56 : xas_tdp_env%ex_kind_indices = 0
628 26 : k = 0
629 26 : CALL get_qs_env(qs_env, particle_set=particle_set)
630 56 : DO i = 1, nex_atoms
631 30 : at_ind = xas_tdp_env%ex_atom_indices(i)
632 30 : CALL get_atomic_kind(particle_set(at_ind)%atomic_kind, kind_number=j)
633 90 : IF (ALL(ABS(xas_tdp_env%ex_kind_indices - j) .NE. 0)) THEN
634 28 : k = k + 1
635 28 : xas_tdp_env%ex_kind_indices(k) = j
636 : END IF
637 : END DO
638 26 : nex_kinds = k
639 26 : CALL set_xas_tdp_env(xas_tdp_env, nex_kinds=nex_kinds)
640 26 : CALL reallocate(xas_tdp_env%ex_kind_indices, 1, nex_kinds)
641 :
642 22 : ELSE IF (xas_tdp_control%define_excited == xas_tdp_by_kind) THEN
643 :
644 : ! need to find out which atom of which kind is excited
645 22 : CALL get_qs_env(qs_env=qs_env, atomic_kind_set=at_kind_set)
646 22 : n_kinds = SIZE(at_kind_set)
647 22 : nex_atoms = 0
648 :
649 22 : nex_kinds = SIZE(xas_tdp_control%list_ex_kinds)
650 66 : ALLOCATE (xas_tdp_env%ex_kind_indices(nex_kinds))
651 22 : k = 0
652 :
653 66 : DO i = 1, n_kinds
654 : CALL get_atomic_kind(atomic_kind=at_kind_set(i), name=kind_name, &
655 44 : natom=nat_of_kind, kind_number=kind_ind)
656 90 : IF (ANY(xas_tdp_control%list_ex_kinds == kind_name)) THEN
657 24 : nex_atoms = nex_atoms + nat_of_kind
658 24 : k = k + 1
659 24 : xas_tdp_env%ex_kind_indices(k) = kind_ind
660 : END IF
661 : END DO
662 :
663 66 : ALLOCATE (xas_tdp_env%ex_atom_indices(nex_atoms))
664 88 : ALLOCATE (xas_tdp_env%state_types(SIZE(xas_tdp_control%state_types, 1), nex_atoms))
665 22 : nex_atoms = 0
666 22 : nmatch = 0
667 :
668 66 : DO i = 1, n_kinds
669 : CALL get_atomic_kind(atomic_kind=at_kind_set(i), name=kind_name, &
670 44 : natom=nat_of_kind, atom_list=ind_of_kind)
671 116 : DO j = 1, nex_kinds
672 94 : IF (xas_tdp_control%list_ex_kinds(j) == kind_name) THEN
673 80 : xas_tdp_env%ex_atom_indices(nex_atoms + 1:nex_atoms + nat_of_kind) = ind_of_kind
674 58 : DO k = 1, SIZE(xas_tdp_control%state_types, 1)
675 : xas_tdp_env%state_types(k, nex_atoms + 1:nex_atoms + nat_of_kind) = &
676 96 : xas_tdp_control%state_types(k, j)
677 : END DO
678 24 : nex_atoms = nex_atoms + nat_of_kind
679 24 : nmatch = nmatch + 1
680 : END IF
681 : END DO
682 : END DO
683 :
684 22 : CALL set_xas_tdp_env(xas_tdp_env, nex_atoms=nex_atoms, nex_kinds=nex_kinds)
685 :
686 : ! Verifying that the input was valid
687 22 : IF (nmatch .NE. SIZE(xas_tdp_control%list_ex_kinds)) THEN
688 0 : CPABORT("Invalid kind(s) for the KIND_LIST keyword.")
689 : END IF
690 :
691 : END IF
692 :
693 : ! Sort the excited atoms indices (for convinience and use of locate function)
694 48 : CALL sort_unique(xas_tdp_env%ex_atom_indices, unique)
695 48 : IF (.NOT. unique) THEN
696 0 : CPABORT("Excited atoms not uniquely defined.")
697 : END IF
698 :
699 : ! Check for periodicity
700 48 : CALL get_qs_env(qs_env, cell=cell)
701 144 : IF (ALL(cell%perd == 0)) THEN
702 32 : xas_tdp_control%is_periodic = .FALSE.
703 64 : ELSE IF (ALL(cell%perd == 1)) THEN
704 16 : xas_tdp_control%is_periodic = .TRUE.
705 : ELSE
706 0 : CPABORT("XAS TDP only implemented for full PBCs or non-PBCs")
707 : END IF
708 :
709 : ! Allocating memory for the array of donor states
710 174 : n_donor_states = COUNT(xas_tdp_env%state_types /= xas_not_excited)
711 212 : ALLOCATE (xas_tdp_env%donor_states(n_donor_states))
712 116 : DO i = 1, n_donor_states
713 116 : CALL donor_state_create(xas_tdp_env%donor_states(i))
714 : END DO
715 :
716 : ! In case of ADMM, for the whole duration of the XAS_TDP, we need the total KS matrix
717 48 : IF (dft_control%do_admm) THEN
718 4 : CALL get_qs_env(qs_env, admm_env=admm_env, matrix_ks=matrix_ks)
719 :
720 8 : DO ispin = 1, dft_control%nspins
721 8 : CALL admm_correct_for_eigenvalues(ispin, admm_env, matrix_ks(ispin)%matrix)
722 : END DO
723 : END IF
724 :
725 : ! In case of externally imposed EPS_PGF_XAS, need to update ORB and RI_XAS interaction radii
726 48 : IF (xas_tdp_control%eps_pgf > 0.0_dp) THEN
727 0 : CALL get_qs_env(qs_env, qs_kind_set=qs_kind_set)
728 :
729 0 : DO i = 1, SIZE(qs_kind_set)
730 0 : CALL get_qs_kind(qs_kind_set(i), basis_set=tmp_basis, basis_type="ORB")
731 0 : CALL init_interaction_radii_orb_basis(tmp_basis, eps_pgf_orb=xas_tdp_control%eps_pgf)
732 0 : CALL get_qs_kind(qs_kind_set(i), basis_set=tmp_basis, basis_type="RI_XAS")
733 0 : CALL init_interaction_radii_orb_basis(tmp_basis, eps_pgf_orb=xas_tdp_control%eps_pgf)
734 : END DO
735 : END IF
736 :
737 : ! In case of ground state OT optimization, compute the MO eigenvalues and get canonical MOs
738 48 : IF (qs_env%scf_env%method == ot_method_nr) THEN
739 :
740 4 : CALL get_qs_env(qs_env, mos=mos, matrix_ks=matrix_ks)
741 4 : nspins = 1; IF (do_uks) nspins = 2
742 :
743 8 : DO ispin = 1, nspins
744 4 : CALL get_mo_set(mos(ispin), mo_coeff=mo_coeff, eigenvalues=mo_evals)
745 8 : CALL calculate_subspace_eigenvalues(mo_coeff, matrix_ks(ispin)%matrix, evals_arg=mo_evals)
746 : END DO
747 : END IF
748 :
749 : ! Initializing the qs_loc_env from the LOCALIZE subsection of XAS_TDP (largely inpired by MI's XAS)
750 : ! We create the LOCALIZE subsection here, since it is completely overwritten anyways
751 48 : CALL create_localize_section(dummy_section)
752 48 : CALL section_vals_create(xas_tdp_control%loc_subsection, dummy_section)
753 : CALL section_vals_val_set(xas_tdp_control%loc_subsection, "_SECTION_PARAMETERS_", &
754 48 : l_val=xas_tdp_control%do_loc)
755 48 : CALL section_release(dummy_section)
756 : xas_tdp_control%print_loc_subsection => section_vals_get_subs_vals( &
757 48 : xas_tdp_control%loc_subsection, "PRINT")
758 :
759 336 : ALLOCATE (xas_tdp_env%qs_loc_env)
760 48 : CALL qs_loc_env_create(xas_tdp_env%qs_loc_env)
761 48 : qs_loc_env => xas_tdp_env%qs_loc_env
762 48 : loc_section => xas_tdp_control%loc_subsection
763 : ! getting the number of MOs
764 48 : CALL get_qs_env(qs_env, mos=mos)
765 48 : CALL get_mo_set(mos(1), nmo=n_mo(1), homo=homo(1), nao=nao)
766 48 : n_mo(2) = n_mo(1)
767 48 : homo(2) = homo(1)
768 48 : nspins = 1
769 48 : IF (do_os) CALL get_mo_set(mos(2), nmo=n_mo(2), homo=homo(2))
770 48 : IF (do_uks) nspins = 2 !in roks, same MOs for both spins
771 :
772 : ! by default, all (doubly occupied) homo are localized
773 144 : IF (xas_tdp_control%n_search < 0 .OR. xas_tdp_control%n_search > MINVAL(homo)) &
774 0 : xas_tdp_control%n_search = MINVAL(homo)
775 : CALL qs_loc_control_init(qs_loc_env, loc_section, do_homo=.TRUE., do_xas=.TRUE., &
776 48 : nloc_xas=xas_tdp_control%n_search, spin_xas=1)
777 :
778 : ! do_xas argument above only prepares spin-alpha localization
779 48 : IF (do_uks) THEN
780 6 : qs_loc_env%localized_wfn_control%nloc_states(2) = xas_tdp_control%n_search
781 6 : qs_loc_env%localized_wfn_control%lu_bound_states(1, 2) = 1
782 6 : qs_loc_env%localized_wfn_control%lu_bound_states(2, 2) = xas_tdp_control%n_search
783 : END IF
784 :
785 : ! final qs_loc_env initialization. Impose Berry operator
786 48 : qs_loc_env%localized_wfn_control%operator_type = op_loc_berry
787 48 : qs_loc_env%localized_wfn_control%max_iter = 25000
788 48 : IF (.NOT. xas_tdp_control%do_loc) THEN
789 16 : qs_loc_env%localized_wfn_control%localization_method = do_loc_none
790 : ELSE
791 96 : n_moloc = qs_loc_env%localized_wfn_control%nloc_states
792 32 : CALL set_loc_centers(qs_loc_env%localized_wfn_control, n_moloc, nspins)
793 32 : IF (do_uks) THEN
794 : CALL qs_loc_env_init(qs_loc_env, qs_loc_env%localized_wfn_control, &
795 2 : qs_env, do_localize=.TRUE.)
796 : ELSE
797 : CALL qs_loc_env_init(qs_loc_env, qs_loc_env%localized_wfn_control, &
798 30 : qs_env, do_localize=.TRUE., myspin=1)
799 : END IF
800 : END IF
801 :
802 : ! Allocating memory for the array of excited atoms MOs. Worst case senario, all searched MOs are
803 : ! associated to the same atom
804 240 : ALLOCATE (xas_tdp_env%mos_of_ex_atoms(xas_tdp_control%n_search, nex_atoms, nspins))
805 :
806 : ! Compute the projector on the unoccupied, unperturbed ground state: Q = 1 - SP, sor each spin
807 48 : IF (do_os) nspins = 2
808 48 : CALL get_qs_env(qs_env, rho=rho, matrix_s=matrix_s)
809 48 : CALL qs_rho_get(rho, rho_ao=rho_ao)
810 :
811 198 : ALLOCATE (xas_tdp_env%q_projector(nspins))
812 48 : ALLOCATE (xas_tdp_env%q_projector(1)%matrix)
813 : CALL dbcsr_create(xas_tdp_env%q_projector(1)%matrix, name="Q PROJECTOR ALPHA", &
814 48 : template=matrix_s(1)%matrix, matrix_type=dbcsr_type_no_symmetry)
815 48 : IF (do_os) THEN
816 6 : ALLOCATE (xas_tdp_env%q_projector(2)%matrix)
817 : CALL dbcsr_create(xas_tdp_env%q_projector(2)%matrix, name="Q PROJECTOR BETA", &
818 6 : template=matrix_s(1)%matrix, matrix_type=dbcsr_type_no_symmetry)
819 : END IF
820 :
821 : ! In the case of spin-restricted calculations, rho_ao includes double occupency => 0.5 prefactor
822 48 : fact = -0.5_dp; IF (do_os) fact = -1.0_dp
823 : CALL dbcsr_multiply('N', 'N', fact, matrix_s(1)%matrix, rho_ao(1)%matrix, 0.0_dp, &
824 48 : xas_tdp_env%q_projector(1)%matrix, filter_eps=xas_tdp_control%eps_filter)
825 48 : CALL dbcsr_add_on_diag(xas_tdp_env%q_projector(1)%matrix, 1.0_dp)
826 48 : CALL dbcsr_finalize(xas_tdp_env%q_projector(1)%matrix)
827 :
828 48 : IF (do_os) THEN
829 : CALL dbcsr_multiply('N', 'N', fact, matrix_s(1)%matrix, rho_ao(2)%matrix, 0.0_dp, &
830 6 : xas_tdp_env%q_projector(2)%matrix, filter_eps=xas_tdp_control%eps_filter)
831 6 : CALL dbcsr_add_on_diag(xas_tdp_env%q_projector(2)%matrix, 1.0_dp)
832 6 : CALL dbcsr_finalize(xas_tdp_env%q_projector(2)%matrix)
833 : END IF
834 :
835 : ! Create the structure for the dipole in the AO basis
836 192 : ALLOCATE (xas_tdp_env%dipmat(3))
837 192 : DO i = 1, 3
838 144 : ALLOCATE (xas_tdp_env%dipmat(i)%matrix)
839 144 : CALL dbcsr_copy(matrix_tmp, matrix_s(1)%matrix, name="XAS TDP dipole matrix")
840 144 : IF (xas_tdp_control%dipole_form == xas_dip_vel) THEN
841 : CALL dbcsr_create(xas_tdp_env%dipmat(i)%matrix, template=matrix_s(1)%matrix, &
842 90 : matrix_type=dbcsr_type_antisymmetric)
843 90 : CALL dbcsr_complete_redistribute(matrix_tmp, xas_tdp_env%dipmat(i)%matrix)
844 : ELSE
845 : CALL dbcsr_create(xas_tdp_env%dipmat(i)%matrix, template=matrix_s(1)%matrix, &
846 54 : matrix_type=dbcsr_type_symmetric)
847 54 : CALL dbcsr_copy(xas_tdp_env%dipmat(i)%matrix, matrix_tmp)
848 : END IF
849 144 : CALL dbcsr_set(xas_tdp_env%dipmat(i)%matrix, 0.0_dp)
850 192 : CALL dbcsr_release(matrix_tmp)
851 : END DO
852 :
853 : ! Create the structure for the electric quadrupole in the AO basis, if required
854 48 : IF (xas_tdp_control%do_quad) THEN
855 0 : ALLOCATE (xas_tdp_env%quadmat(6))
856 0 : DO i = 1, 6
857 0 : ALLOCATE (xas_tdp_env%quadmat(i)%matrix)
858 0 : CALL dbcsr_copy(xas_tdp_env%quadmat(i)%matrix, matrix_s(1)%matrix, name="XAS TDP quadrupole matrix")
859 0 : CALL dbcsr_set(xas_tdp_env%quadmat(i)%matrix, 0.0_dp)
860 : END DO
861 : END IF
862 :
863 : ! Precompute it in the velocity representation, if so chosen
864 48 : IF (xas_tdp_control%dipole_form == xas_dip_vel) THEN
865 : !enforce minimum image to avoid any PBCs related issues. Ok because very localized densities
866 30 : CALL p_xyz_ao(xas_tdp_env%dipmat, qs_env, minimum_image=.TRUE.)
867 : END IF
868 :
869 : ! Allocate SOC in AO basis matrices
870 48 : IF (xas_tdp_control%do_soc .OR. xas_tdp_control%do_gw2x) THEN
871 88 : ALLOCATE (xas_tdp_env%orb_soc(3))
872 88 : DO i = 1, 3
873 114 : ALLOCATE (xas_tdp_env%orb_soc(i)%matrix)
874 : END DO
875 : END IF
876 :
877 : ! Check that everything is allowed
878 48 : CALL safety_check(xas_tdp_control, qs_env)
879 :
880 : ! Initialize libint for the 3-center integrals
881 48 : CALL cp_libint_static_init()
882 :
883 : ! Compute LUMOs as guess for OT solver and/or for GW2X correction
884 48 : IF (xas_tdp_control%do_ot .OR. xas_tdp_control%do_gw2x) THEN
885 20 : CALL make_lumo_guess(xas_tdp_env, xas_tdp_control, qs_env)
886 : END IF
887 :
888 144 : END SUBROUTINE xas_tdp_init
889 :
890 : ! **************************************************************************************************
891 : !> \brief splits the excited atoms of a kind into batches for RI 3c integrals load balance
892 : !> \param ex_atoms_of_kind the excited atoms for the current kind, randomly shuffled
893 : !> \param nbatch number of batches to loop over
894 : !> \param batch_size standard size of a batch
895 : !> \param atoms_of_kind number of atoms for the current kind (excited or not)
896 : !> \param xas_tdp_env ...
897 : ! **************************************************************************************************
898 52 : SUBROUTINE get_ri_3c_batches(ex_atoms_of_kind, nbatch, batch_size, atoms_of_kind, xas_tdp_env)
899 :
900 : INTEGER, ALLOCATABLE, DIMENSION(:), INTENT(INOUT) :: ex_atoms_of_kind
901 : INTEGER, INTENT(OUT) :: nbatch
902 : INTEGER, INTENT(IN) :: batch_size
903 : INTEGER, DIMENSION(:), INTENT(IN) :: atoms_of_kind
904 : TYPE(xas_tdp_env_type), POINTER :: xas_tdp_env
905 :
906 : INTEGER :: iat, iatom, nex_atom
907 52 : TYPE(rng_stream_type), ALLOCATABLE :: rng_stream
908 :
909 : !Get the atoms from atoms_of_kind that are excited
910 52 : nex_atom = 0
911 268 : DO iat = 1, SIZE(atoms_of_kind)
912 216 : iatom = atoms_of_kind(iat)
913 444 : IF (.NOT. ANY(xas_tdp_env%ex_atom_indices == iatom)) CYCLE
914 268 : nex_atom = nex_atom + 1
915 : END DO
916 :
917 156 : ALLOCATE (ex_atoms_of_kind(nex_atom))
918 52 : nex_atom = 0
919 268 : DO iat = 1, SIZE(atoms_of_kind)
920 216 : iatom = atoms_of_kind(iat)
921 444 : IF (.NOT. ANY(xas_tdp_env%ex_atom_indices == iatom)) CYCLE
922 58 : nex_atom = nex_atom + 1
923 268 : ex_atoms_of_kind(nex_atom) = iatom
924 : END DO
925 :
926 : !We shuffle those atoms to spread them
927 52 : rng_stream = rng_stream_type(name="uniform_rng", distribution_type=UNIFORM)
928 52 : CALL rng_stream%shuffle(ex_atoms_of_kind(1:nex_atom))
929 :
930 52 : nbatch = nex_atom/batch_size
931 52 : IF (nbatch*batch_size .NE. nex_atom) nbatch = nbatch + 1
932 :
933 52 : END SUBROUTINE get_ri_3c_batches
934 :
935 : ! **************************************************************************************************
936 : !> \brief Checks for forbidden keywords combinations
937 : !> \param xas_tdp_control ...
938 : !> \param qs_env ...
939 : ! **************************************************************************************************
940 48 : SUBROUTINE safety_check(xas_tdp_control, qs_env)
941 :
942 : TYPE(xas_tdp_control_type), POINTER :: xas_tdp_control
943 : TYPE(qs_environment_type), POINTER :: qs_env
944 :
945 : TYPE(dft_control_type), POINTER :: dft_control
946 :
947 : !PB only available without exact exchange
948 : IF (xas_tdp_control%is_periodic .AND. xas_tdp_control%do_hfx &
949 48 : .AND. xas_tdp_control%x_potential%potential_type == do_potential_coulomb) THEN
950 0 : CPABORT("XAS TDP with Coulomb operator for exact exchange only supports non-periodic BCs")
951 : END IF
952 :
953 : !open-shell/closed-shell tests
954 48 : IF (xas_tdp_control%do_roks .OR. xas_tdp_control%do_uks) THEN
955 :
956 6 : IF (.NOT. (xas_tdp_control%do_spin_cons .OR. xas_tdp_control%do_spin_flip)) THEN
957 0 : CPABORT("Need spin-conserving and/or spin-flip excitations for open-shell systems")
958 : END IF
959 :
960 6 : IF (xas_tdp_control%do_singlet .OR. xas_tdp_control%do_triplet) THEN
961 0 : CPABORT("Singlet/triplet excitations only for restricted closed-shell systems")
962 : END IF
963 :
964 6 : IF (xas_tdp_control%do_soc .AND. .NOT. &
965 : (xas_tdp_control%do_spin_flip .AND. xas_tdp_control%do_spin_cons)) THEN
966 :
967 0 : CPABORT("Both spin-conserving and spin-flip excitations are required for SOC")
968 : END IF
969 : ELSE
970 :
971 42 : IF (.NOT. (xas_tdp_control%do_singlet .OR. xas_tdp_control%do_triplet)) THEN
972 0 : CPABORT("Need singlet and/or triplet excitations for closed-shell systems")
973 : END IF
974 :
975 42 : IF (xas_tdp_control%do_spin_cons .OR. xas_tdp_control%do_spin_flip) THEN
976 0 : CPABORT("Spin-conserving/spin-flip excitations only for open-shell systems")
977 : END IF
978 :
979 42 : IF (xas_tdp_control%do_soc .AND. .NOT. &
980 : (xas_tdp_control%do_singlet .AND. xas_tdp_control%do_triplet)) THEN
981 :
982 0 : CPABORT("Both singlet and triplet excitations are needed for SOC")
983 : END IF
984 : END IF
985 :
986 : !Warn against using E_RANGE with SOC
987 48 : IF (xas_tdp_control%do_soc .AND. xas_tdp_control%e_range > 0.0_dp) THEN
988 0 : CPWARN("Using E_RANGE and SOC together may lead to crashes, use N_EXCITED for safety.")
989 : END IF
990 :
991 : !TDA, full-TDDFT and diagonalization
992 48 : IF (.NOT. xas_tdp_control%tamm_dancoff) THEN
993 :
994 6 : IF (xas_tdp_control%do_spin_flip) THEN
995 0 : CPABORT("Spin-flip kernel only implemented for Tamm-Dancoff approximation")
996 : END IF
997 :
998 6 : IF (xas_tdp_control%do_ot) THEN
999 0 : CPABORT("OT diagonalization only available within the Tamm-Dancoff approximation")
1000 : END IF
1001 : END IF
1002 :
1003 : !GW2X, need hfx kernel and LOCALIZE
1004 48 : IF (xas_tdp_control%do_gw2x) THEN
1005 18 : IF (.NOT. xas_tdp_control%do_hfx) THEN
1006 0 : CPABORT("GW2x requires the definition of the EXACT_EXCHANGE kernel")
1007 : END IF
1008 18 : IF (.NOT. xas_tdp_control%do_loc) THEN
1009 0 : CPABORT("GW2X requires the LOCALIZE keyword in DONOR_STATES")
1010 : END IF
1011 : END IF
1012 :
1013 : !Only allow ADMM schemes that correct for eigenvalues
1014 48 : CALL get_qs_env(qs_env, dft_control=dft_control)
1015 48 : IF (dft_control%do_admm) THEN
1016 : IF ((.NOT. qs_env%admm_env%purification_method == do_admm_purify_none) .AND. &
1017 4 : (.NOT. qs_env%admm_env%purification_method == do_admm_purify_cauchy_subspace) .AND. &
1018 : (.NOT. qs_env%admm_env%purification_method == do_admm_purify_mo_diag)) THEN
1019 :
1020 0 : CPABORT("XAS_TDP only compatible with ADMM purification NONE, CAUCHY_SUBSPACE and MO_DIAG")
1021 :
1022 : END IF
1023 : END IF
1024 :
1025 48 : END SUBROUTINE safety_check
1026 :
1027 : ! **************************************************************************************************
1028 : !> \brief Prints some basic info about the chosen parameters
1029 : !> \param ou the output unis
1030 : !> \param xas_tdp_control ...
1031 : !> \param qs_env ...
1032 : ! **************************************************************************************************
1033 48 : SUBROUTINE print_info(ou, xas_tdp_control, qs_env)
1034 :
1035 : INTEGER, INTENT(IN) :: ou
1036 : TYPE(xas_tdp_control_type), POINTER :: xas_tdp_control
1037 : TYPE(qs_environment_type), POINTER :: qs_env
1038 :
1039 : INTEGER :: i
1040 : REAL(dp) :: occ
1041 48 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_s
1042 : TYPE(dft_control_type), POINTER :: dft_control
1043 : TYPE(section_vals_type), POINTER :: input, kernel_section
1044 :
1045 48 : NULLIFY (input, kernel_section, dft_control, matrix_s)
1046 :
1047 48 : CALL get_qs_env(qs_env, input=input, dft_control=dft_control, matrix_s=matrix_s)
1048 :
1049 : !Overlap matrix sparsity
1050 48 : occ = dbcsr_get_occupation(matrix_s(1)%matrix)
1051 :
1052 48 : IF (ou .LE. 0) RETURN
1053 :
1054 : !Reference calculation
1055 24 : IF (xas_tdp_control%do_uks) THEN
1056 : WRITE (UNIT=ou, FMT="(/,T3,A)") &
1057 3 : "XAS_TDP| Reference calculation: Unrestricted Kohn-Sham"
1058 21 : ELSE IF (xas_tdp_control%do_roks) THEN
1059 : WRITE (UNIT=ou, FMT="(/,T3,A)") &
1060 0 : "XAS_TDP| Reference calculation: Restricted Open-Shell Kohn-Sham"
1061 : ELSE
1062 : WRITE (UNIT=ou, FMT="(/,T3,A)") &
1063 21 : "XAS_TDP| Reference calculation: Restricted Closed-Shell Kohn-Sham"
1064 : END IF
1065 :
1066 : !TDA
1067 24 : IF (xas_tdp_control%tamm_dancoff) THEN
1068 : WRITE (UNIT=ou, FMT="(T3,A)") &
1069 21 : "XAS_TDP| Tamm-Dancoff Approximation (TDA): On"
1070 : ELSE
1071 : WRITE (UNIT=ou, FMT="(T3,A)") &
1072 3 : "XAS_TDP| Tamm-Dancoff Approximation (TDA): Off"
1073 : END IF
1074 :
1075 : !Dipole form
1076 24 : IF (xas_tdp_control%dipole_form == xas_dip_vel) THEN
1077 : WRITE (UNIT=ou, FMT="(T3,A)") &
1078 15 : "XAS_TDP| Transition Dipole Representation: VELOCITY"
1079 : ELSE
1080 : WRITE (UNIT=ou, FMT="(T3,A)") &
1081 9 : "XAS_TDP| Transition Dipole Representation: LENGTH"
1082 : END IF
1083 :
1084 : !Quadrupole
1085 24 : IF (xas_tdp_control%do_quad) THEN
1086 : WRITE (UNIT=ou, FMT="(T3,A)") &
1087 0 : "XAS_TDP| Transition Quadrupole: On"
1088 : END IF
1089 :
1090 : !EPS_PGF
1091 24 : IF (xas_tdp_control%eps_pgf > 0.0_dp) THEN
1092 : WRITE (UNIT=ou, FMT="(T3,A,ES7.1)") &
1093 0 : "XAS_TDP| EPS_PGF_XAS: ", xas_tdp_control%eps_pgf
1094 : ELSE
1095 : WRITE (UNIT=ou, FMT="(T3,A,ES7.1,A)") &
1096 24 : "XAS_TDP| EPS_PGF_XAS: ", dft_control%qs_control%eps_pgf_orb, " (= EPS_PGF_ORB)"
1097 : END IF
1098 :
1099 : !EPS_FILTER
1100 : WRITE (UNIT=ou, FMT="(T3,A,ES7.1)") &
1101 24 : "XAS_TDP| EPS_FILTER: ", xas_tdp_control%eps_filter
1102 :
1103 : !Grid info
1104 24 : IF (xas_tdp_control%do_xc) THEN
1105 : WRITE (UNIT=ou, FMT="(T3,A)") &
1106 19 : "XAS_TDP| Radial Grid(s) Info: Kind, na, nr"
1107 40 : DO i = 1, SIZE(xas_tdp_control%grid_info, 1)
1108 : WRITE (UNIT=ou, FMT="(T3,A,A6,A,A,A,A)") &
1109 21 : " ", TRIM(xas_tdp_control%grid_info(i, 1)), ", ", &
1110 61 : TRIM(xas_tdp_control%grid_info(i, 2)), ", ", TRIM(xas_tdp_control%grid_info(i, 3))
1111 : END DO
1112 : END IF
1113 :
1114 : !No kernel
1115 24 : IF (.NOT. xas_tdp_control%do_coulomb) THEN
1116 : WRITE (UNIT=ou, FMT="(/,T3,A)") &
1117 0 : "XAS_TDP| No kernel (standard DFT)"
1118 : END IF
1119 :
1120 : !XC kernel
1121 24 : IF (xas_tdp_control%do_xc) THEN
1122 :
1123 : WRITE (UNIT=ou, FMT="(/,T3,A,F5.2,A)") &
1124 19 : "XAS_TDP| RI Region's Radius: ", xas_tdp_control%ri_radius*angstrom, " Ang"
1125 :
1126 : WRITE (UNIT=ou, FMT="(T3,A,/)") &
1127 19 : "XAS_TDP| XC Kernel Functional(s) used for the kernel:"
1128 :
1129 19 : kernel_section => section_vals_get_subs_vals(input, "DFT%XAS_TDP%KERNEL")
1130 19 : CALL xc_write(ou, kernel_section, lsd=.TRUE.)
1131 : END IF
1132 :
1133 : !HFX kernel
1134 24 : IF (xas_tdp_control%do_hfx) THEN
1135 : WRITE (UNIT=ou, FMT="(/,T3,A,/,/,T3,A,F5.3)") &
1136 19 : "XAS_TDP| Exact Exchange Kernel: Yes ", &
1137 38 : "EXACT_EXCHANGE| Scale: ", xas_tdp_control%sx
1138 19 : IF (xas_tdp_control%x_potential%potential_type == do_potential_coulomb) THEN
1139 : WRITE (UNIT=ou, FMT="(T3,A)") &
1140 12 : "EXACT_EXCHANGE| Potential : Coulomb"
1141 7 : ELSE IF (xas_tdp_control%x_potential%potential_type == do_potential_truncated) THEN
1142 : WRITE (UNIT=ou, FMT="(T3,A,/,T3,A,F5.2,A,/,T3,A,A)") &
1143 3 : "EXACT_EXCHANGE| Potential: Truncated Coulomb", &
1144 3 : "EXACT_EXCHANGE| Range: ", xas_tdp_control%x_potential%cutoff_radius*angstrom, ", (Ang)", &
1145 6 : "EXACT_EXCHANGE| T_C_G_DATA: ", TRIM(xas_tdp_control%x_potential%filename)
1146 4 : ELSE IF (xas_tdp_control%x_potential%potential_type == do_potential_short) THEN
1147 : WRITE (UNIT=ou, FMT="(T3,A,/,T3,A,F5.2,A,/,T3,A,F5.2,A,/,T3,A,ES7.1)") &
1148 4 : "EXACT_EXCHANGE| Potential: Short Range", &
1149 4 : "EXACT_EXCHANGE| Omega: ", xas_tdp_control%x_potential%omega, ", (1/a0)", &
1150 4 : "EXACT_EXCHANGE| Effective Range: ", xas_tdp_control%x_potential%cutoff_radius*angstrom, ", (Ang)", &
1151 8 : "EXACT_EXCHANGE| EPS_RANGE: ", xas_tdp_control%eps_range
1152 : END IF
1153 19 : IF (xas_tdp_control%eps_screen > 1.0E-16) THEN
1154 : WRITE (UNIT=ou, FMT="(T3,A,ES7.1)") &
1155 19 : "EXACT_EXCHANGE| EPS_SCREENING: ", xas_tdp_control%eps_screen
1156 : END IF
1157 :
1158 : !RI metric
1159 19 : IF (xas_tdp_control%do_ri_metric) THEN
1160 :
1161 : WRITE (UNIT=ou, FMT="(/,T3,A)") &
1162 3 : "EXACT_EXCHANGE| Using a RI metric"
1163 3 : IF (xas_tdp_control%ri_m_potential%potential_type == do_potential_id) THEN
1164 : WRITE (UNIT=ou, FMT="(T3,A)") &
1165 1 : "EXACT_EXCHANGE RI_METRIC| Potential : Overlap"
1166 2 : ELSE IF (xas_tdp_control%ri_m_potential%potential_type == do_potential_truncated) THEN
1167 : WRITE (UNIT=ou, FMT="(T3,A,/,T3,A,F5.2,A,/,T3,A,A)") &
1168 1 : "EXACT_EXCHANGE RI_METRIC| Potential: Truncated Coulomb", &
1169 1 : "EXACT_EXCHANGE RI_METRIC| Range: ", xas_tdp_control%ri_m_potential%cutoff_radius &
1170 1 : *angstrom, ", (Ang)", &
1171 2 : "EXACT_EXCHANGE RI_METRIC| T_C_G_DATA: ", TRIM(xas_tdp_control%ri_m_potential%filename)
1172 1 : ELSE IF (xas_tdp_control%ri_m_potential%potential_type == do_potential_short) THEN
1173 : WRITE (UNIT=ou, FMT="(T3,A,/,T3,A,F5.2,A,/,T3,A,F5.2,A,/,T3,A,ES7.1)") &
1174 1 : "EXACT_EXCHANGE RI_METRIC| Potential: Short Range", &
1175 1 : "EXACT_EXCHANGE RI_METRIC| Omega: ", xas_tdp_control%ri_m_potential%omega, ", (1/a0)", &
1176 1 : "EXACT_EXCHANGE RI_METRIC| Effective Range: ", &
1177 1 : xas_tdp_control%ri_m_potential%cutoff_radius*angstrom, ", (Ang)", &
1178 2 : "EXACT_EXCHANGE RI_METRIC| EPS_RANGE: ", xas_tdp_control%eps_range
1179 : END IF
1180 : END IF
1181 : ELSE
1182 : WRITE (UNIT=ou, FMT="(/,T3,A,/)") &
1183 5 : "XAS_TDP| Exact Exchange Kernel: No "
1184 : END IF
1185 :
1186 : !overlap mtrix occupation
1187 : WRITE (UNIT=ou, FMT="(/,T3,A,F5.2)") &
1188 24 : "XAS_TDP| Overlap matrix occupation: ", occ
1189 :
1190 : !GW2X parameter
1191 24 : IF (xas_tdp_control%do_gw2x) THEN
1192 : WRITE (UNIT=ou, FMT="(T3,A,/)") &
1193 9 : "XAS_TDP| GW2X correction enabled"
1194 :
1195 9 : IF (xas_tdp_control%xps_only) THEN
1196 : WRITE (UNIT=ou, FMT="(T3,A)") &
1197 2 : "GW2X| Only computing ionizations potentials for XPS"
1198 : END IF
1199 :
1200 9 : IF (xas_tdp_control%pseudo_canonical) THEN
1201 : WRITE (UNIT=ou, FMT="(T3,A)") &
1202 8 : "GW2X| Using the pseudo-canonical scheme"
1203 : ELSE
1204 : WRITE (UNIT=ou, FMT="(T3,A)") &
1205 1 : "GW2X| Using the GW2X* scheme"
1206 : END IF
1207 :
1208 : WRITE (UNIT=ou, FMT="(T3,A,ES7.1)") &
1209 9 : "GW2X| EPS_GW2X: ", xas_tdp_control%gw2x_eps
1210 :
1211 : WRITE (UNIT=ou, FMT="(T3,A,I5)") &
1212 9 : "GW2X| contraction batch size: ", xas_tdp_control%batch_size
1213 :
1214 9 : IF ((INT(xas_tdp_control%c_os) .NE. 1) .OR. (INT(xas_tdp_control%c_ss) .NE. 1)) THEN
1215 : WRITE (UNIT=ou, FMT="(T3,A,F7.4,/,T3,A,F7.4)") &
1216 1 : "GW2X| Same-spin scaling factor: ", xas_tdp_control%c_ss, &
1217 2 : "GW2X| Opposite-spin scaling factor: ", xas_tdp_control%c_os
1218 : END IF
1219 :
1220 : END IF
1221 :
1222 48 : END SUBROUTINE print_info
1223 :
1224 : ! **************************************************************************************************
1225 : !> \brief Assosciate (possibly localized) lowest energy MOs to each excited atoms. The procedure
1226 : !> looks for MOs "centered" on the excited atoms by comparing distances. It
1227 : !> then fills the mos_of_ex_atoms arrays of the xas_tdp_env. Only the xas_tdp_control%n_search
1228 : !> lowest energy MOs are considered. Largely inspired by MI's implementation of XAS
1229 : !> It is assumed that the Berry phase is used to compute centers.
1230 : !> \param xas_tdp_env ...
1231 : !> \param xas_tdp_control ...
1232 : !> \param qs_env ...
1233 : !> \note Whether localization took place or not, the procedure is the same as centers are stored in
1234 : !> xas_tdp_env%qs_loc_env%localized_wfn_control%centers_set
1235 : !> Assumes that find_mo_centers has been run previously
1236 : ! **************************************************************************************************
1237 48 : SUBROUTINE assign_mos_to_ex_atoms(xas_tdp_env, xas_tdp_control, qs_env)
1238 :
1239 : TYPE(xas_tdp_env_type), POINTER :: xas_tdp_env
1240 : TYPE(xas_tdp_control_type), POINTER :: xas_tdp_control
1241 : TYPE(qs_environment_type), POINTER :: qs_env
1242 :
1243 : INTEGER :: at_index, iat, iat_memo, imo, ispin, &
1244 : n_atoms, n_search, nex_atoms, nspins
1245 : INTEGER, DIMENSION(3) :: perd_init
1246 48 : INTEGER, DIMENSION(:, :, :), POINTER :: mos_of_ex_atoms
1247 : REAL(dp) :: dist, dist_min
1248 : REAL(dp), DIMENSION(3) :: at_pos, r_ac, wfn_center
1249 : TYPE(cell_type), POINTER :: cell
1250 : TYPE(localized_wfn_control_type), POINTER :: localized_wfn_control
1251 48 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
1252 :
1253 48 : NULLIFY (localized_wfn_control, mos_of_ex_atoms, cell, particle_set)
1254 :
1255 : ! Initialization. mos_of_ex_atoms filled with -1, meaning no assigned state
1256 48 : mos_of_ex_atoms => xas_tdp_env%mos_of_ex_atoms
1257 524 : mos_of_ex_atoms(:, :, :) = -1
1258 48 : n_search = xas_tdp_control%n_search
1259 48 : nex_atoms = xas_tdp_env%nex_atoms
1260 48 : localized_wfn_control => xas_tdp_env%qs_loc_env%localized_wfn_control
1261 48 : CALL get_qs_env(qs_env=qs_env, particle_set=particle_set, cell=cell)
1262 48 : n_atoms = SIZE(particle_set)
1263 48 : nspins = 1; IF (xas_tdp_control%do_uks) nspins = 2
1264 :
1265 : ! Temporarly impose periodic BCs because of Berry's phase operator used for localization
1266 192 : perd_init = cell%perd
1267 192 : cell%perd = 1
1268 :
1269 : ! Loop over n_search lowest energy MOs and all atoms, for each spin
1270 102 : DO ispin = 1, nspins
1271 374 : DO imo = 1, n_search
1272 : ! retrieve MO wave function center coordinates.
1273 1088 : wfn_center(1:3) = localized_wfn_control%centers_set(ispin)%array(1:3, imo)
1274 272 : iat_memo = 0
1275 :
1276 : ! a large enough value to avoid bad surprises
1277 272 : dist_min = 10000.0_dp
1278 7590 : DO iat = 1, n_atoms
1279 29272 : at_pos = particle_set(iat)%r
1280 7318 : r_ac = pbc(at_pos, wfn_center, cell)
1281 29272 : dist = NORM2(r_ac)
1282 :
1283 : ! keep memory of which atom is the closest to the wave function center
1284 7590 : IF (dist < dist_min) THEN
1285 646 : iat_memo = iat
1286 646 : dist_min = dist
1287 : END IF
1288 : END DO
1289 :
1290 : ! Verify that the closest atom is actually excited and assign the MO if so
1291 556 : IF (ANY(xas_tdp_env%ex_atom_indices == iat_memo)) THEN
1292 114 : at_index = locate(xas_tdp_env%ex_atom_indices, iat_memo)
1293 114 : mos_of_ex_atoms(imo, at_index, ispin) = 1
1294 : END IF
1295 : END DO !imo
1296 : END DO !ispin
1297 :
1298 : ! Go back to initial BCs
1299 192 : cell%perd = perd_init
1300 :
1301 48 : END SUBROUTINE assign_mos_to_ex_atoms
1302 :
1303 : ! **************************************************************************************************
1304 : !> \brief Re-initialize the qs_loc_env to the current MOs.
1305 : !> \param qs_loc_env the env to re-initialize
1306 : !> \param n_loc_states the number of states to include
1307 : !> \param do_uks in cas of spin unrestricted calculation, initialize for both spins
1308 : !> \param qs_env ...
1309 : !> \note Useful when one needs to make use of qs_loc features and it is either with canonical MOs
1310 : !> or the localized MOs have been modified. do_localize is overwritten.
1311 : !> Same loc range for both spins
1312 : ! **************************************************************************************************
1313 80 : SUBROUTINE reinit_qs_loc_env(qs_loc_env, n_loc_states, do_uks, qs_env)
1314 :
1315 : TYPE(qs_loc_env_type), POINTER :: qs_loc_env
1316 : INTEGER, INTENT(IN) :: n_loc_states
1317 : LOGICAL, INTENT(IN) :: do_uks
1318 : TYPE(qs_environment_type), POINTER :: qs_env
1319 :
1320 : INTEGER :: i, nspins
1321 : TYPE(localized_wfn_control_type), POINTER :: loc_wfn_control
1322 :
1323 : ! First, release the old env
1324 80 : CALL qs_loc_env_release(qs_loc_env)
1325 :
1326 : ! Re-create it
1327 80 : CALL qs_loc_env_create(qs_loc_env)
1328 80 : CALL localized_wfn_control_create(qs_loc_env%localized_wfn_control)
1329 80 : loc_wfn_control => qs_loc_env%localized_wfn_control
1330 :
1331 : ! Initialize it
1332 80 : loc_wfn_control%localization_method = do_loc_none
1333 80 : loc_wfn_control%operator_type = op_loc_berry
1334 240 : loc_wfn_control%nloc_states(:) = n_loc_states
1335 80 : loc_wfn_control%eps_occ = 0.0_dp
1336 240 : loc_wfn_control%lu_bound_states(1, :) = 1
1337 240 : loc_wfn_control%lu_bound_states(2, :) = n_loc_states
1338 80 : loc_wfn_control%set_of_states = state_loc_list
1339 80 : loc_wfn_control%do_homo = .TRUE.
1340 240 : ALLOCATE (loc_wfn_control%loc_states(n_loc_states, 2))
1341 550 : DO i = 1, n_loc_states
1342 1490 : loc_wfn_control%loc_states(i, :) = i
1343 : END DO
1344 :
1345 80 : nspins = 1; IF (do_uks) nspins = 2
1346 80 : CALL set_loc_centers(loc_wfn_control, loc_wfn_control%nloc_states, nspins=nspins)
1347 : ! need to set do_localize=.TRUE. because otherwise no routine works
1348 80 : IF (do_uks) THEN
1349 8 : CALL qs_loc_env_init(qs_loc_env, loc_wfn_control, qs_env, do_localize=.TRUE.)
1350 : ELSE
1351 72 : CALL qs_loc_env_init(qs_loc_env, loc_wfn_control, qs_env, myspin=1, do_localize=.TRUE.)
1352 : END IF
1353 :
1354 80 : END SUBROUTINE reinit_qs_loc_env
1355 :
1356 : ! *************************************************************************************************
1357 : !> \brief Diagonalize the subset of previously localized MOs that are associated to each excited
1358 : !> atoms. Updates the MO coeffs accordingly.
1359 : !> \param xas_tdp_env ...
1360 : !> \param xas_tdp_control ...
1361 : !> \param qs_env ...
1362 : !> \note Needed because after localization, the MOs loose their identity (1s, 2s , 2p, etc)
1363 : ! **************************************************************************************************
1364 32 : SUBROUTINE diagonalize_assigned_mo_subset(xas_tdp_env, xas_tdp_control, qs_env)
1365 :
1366 : TYPE(xas_tdp_env_type), POINTER :: xas_tdp_env
1367 : TYPE(xas_tdp_control_type), POINTER :: xas_tdp_control
1368 : TYPE(qs_environment_type), POINTER :: qs_env
1369 :
1370 : INTEGER :: i, iat, ilmo, ispin, nao, nlmo, nspins
1371 32 : REAL(dp), ALLOCATABLE, DIMENSION(:) :: evals
1372 : TYPE(cp_blacs_env_type), POINTER :: blacs_env
1373 : TYPE(cp_fm_struct_type), POINTER :: ks_struct, lmo_struct
1374 : TYPE(cp_fm_type) :: evecs, ks_fm, lmo_fm, work
1375 : TYPE(cp_fm_type), POINTER :: mo_coeff
1376 32 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_ks
1377 32 : TYPE(mo_set_type), DIMENSION(:), POINTER :: mos
1378 : TYPE(mp_para_env_type), POINTER :: para_env
1379 :
1380 32 : NULLIFY (mos, mo_coeff, matrix_ks, para_env, blacs_env, lmo_struct, ks_struct)
1381 :
1382 : ! Get what we need from qs_env
1383 32 : CALL get_qs_env(qs_env, mos=mos, matrix_ks=matrix_ks, para_env=para_env, blacs_env=blacs_env)
1384 :
1385 32 : nspins = 1; IF (xas_tdp_control%do_uks) nspins = 2
1386 :
1387 : ! Loop over the excited atoms and spin
1388 66 : DO ispin = 1, nspins
1389 110 : DO iat = 1, xas_tdp_env%nex_atoms
1390 :
1391 : ! get the MOs
1392 44 : CALL get_mo_set(mos(ispin), mo_coeff=mo_coeff, nao=nao)
1393 :
1394 : ! count how many MOs are associated to this atom and create a fm/struct
1395 342 : nlmo = COUNT(xas_tdp_env%mos_of_ex_atoms(:, iat, ispin) == 1)
1396 : CALL cp_fm_struct_create(lmo_struct, nrow_global=nao, ncol_global=nlmo, &
1397 44 : para_env=para_env, context=blacs_env)
1398 44 : CALL cp_fm_create(lmo_fm, lmo_struct)
1399 44 : CALL cp_fm_create(work, lmo_struct)
1400 :
1401 : CALL cp_fm_struct_create(ks_struct, nrow_global=nlmo, ncol_global=nlmo, &
1402 44 : para_env=para_env, context=blacs_env)
1403 44 : CALL cp_fm_create(ks_fm, ks_struct)
1404 44 : CALL cp_fm_create(evecs, ks_struct)
1405 :
1406 : ! Loop over the localized MOs associated to this atom
1407 44 : i = 0
1408 342 : DO ilmo = 1, xas_tdp_control%n_search
1409 298 : IF (xas_tdp_env%mos_of_ex_atoms(ilmo, iat, ispin) == -1) CYCLE
1410 :
1411 60 : i = i + 1
1412 : ! put the coeff in our atom-restricted lmo_fm
1413 : CALL cp_fm_to_fm_submat(mo_coeff, lmo_fm, nrow=nao, ncol=1, s_firstrow=1, &
1414 342 : s_firstcol=ilmo, t_firstrow=1, t_firstcol=i)
1415 :
1416 : END DO !ilmo
1417 :
1418 : ! Computing the KS matrix in the subset of MOs
1419 44 : CALL cp_dbcsr_sm_fm_multiply(matrix_ks(ispin)%matrix, lmo_fm, work, ncol=nlmo)
1420 44 : CALL parallel_gemm('T', 'N', nlmo, nlmo, nao, 1.0_dp, lmo_fm, work, 0.0_dp, ks_fm)
1421 :
1422 : ! Diagonalizing the KS matrix in the subset of MOs
1423 132 : ALLOCATE (evals(nlmo))
1424 44 : CALL cp_fm_syevd(ks_fm, evecs, evals)
1425 44 : DEALLOCATE (evals)
1426 :
1427 : ! Express the MOs in the basis that diagonalizes KS
1428 44 : CALL parallel_gemm('N', 'N', nao, nlmo, nlmo, 1.0_dp, lmo_fm, evecs, 0.0_dp, work)
1429 :
1430 : ! Replacing the new MOs back in the MO coeffs
1431 44 : i = 0
1432 342 : DO ilmo = 1, xas_tdp_control%n_search
1433 298 : IF (xas_tdp_env%mos_of_ex_atoms(ilmo, iat, ispin) == -1) CYCLE
1434 :
1435 60 : i = i + 1
1436 : CALL cp_fm_to_fm_submat(work, mo_coeff, nrow=nao, ncol=1, s_firstrow=1, &
1437 342 : s_firstcol=i, t_firstrow=1, t_firstcol=ilmo)
1438 :
1439 : END DO
1440 :
1441 : ! Excited atom clean-up
1442 44 : CALL cp_fm_release(lmo_fm)
1443 44 : CALL cp_fm_release(work)
1444 44 : CALL cp_fm_struct_release(lmo_struct)
1445 44 : CALL cp_fm_release(ks_fm)
1446 44 : CALL cp_fm_release(evecs)
1447 210 : CALL cp_fm_struct_release(ks_struct)
1448 : END DO !iat
1449 : END DO !ispin
1450 :
1451 64 : END SUBROUTINE diagonalize_assigned_mo_subset
1452 :
1453 : ! **************************************************************************************************
1454 : !> \brief Assign core MO(s) to a given donor_state, taking the type (1S, 2S, etc) into account.
1455 : !> The projection on a representative Slater-type orbital basis is used as a indicator.
1456 : !> It is assumed that MOs are already assigned to excited atoms based on their center
1457 : !> \param donor_state the donor_state to which a MO must be assigned
1458 : !> \param xas_tdp_env ...
1459 : !> \param xas_tdp_control ...
1460 : !> \param qs_env ...
1461 : ! **************************************************************************************************
1462 68 : SUBROUTINE assign_mos_to_donor_state(donor_state, xas_tdp_env, xas_tdp_control, qs_env)
1463 :
1464 : TYPE(donor_state_type), POINTER :: donor_state
1465 : TYPE(xas_tdp_env_type), POINTER :: xas_tdp_env
1466 : TYPE(xas_tdp_control_type), POINTER :: xas_tdp_control
1467 : TYPE(qs_environment_type), POINTER :: qs_env
1468 :
1469 : INTEGER :: at_index, i, iat, imo, ispin, l, my_mo, &
1470 : n_search, n_states, nao, ndo_so, nj, &
1471 : nsgf_kind, nsgf_sto, nspins, &
1472 : output_unit, zval
1473 68 : INTEGER, ALLOCATABLE, DIMENSION(:, :) :: my_mos
1474 : INTEGER, DIMENSION(2) :: next_best_overlap_ind
1475 : INTEGER, DIMENSION(4, 7) :: ne
1476 68 : INTEGER, DIMENSION(:), POINTER :: first_sgf, lq, nq
1477 68 : INTEGER, DIMENSION(:, :, :), POINTER :: mos_of_ex_atoms
1478 : LOGICAL :: unique
1479 : REAL(dp) :: zeff
1480 68 : REAL(dp), ALLOCATABLE, DIMENSION(:) :: diag, overlap, sto_overlap
1481 68 : REAL(dp), ALLOCATABLE, DIMENSION(:, :) :: max_overlap
1482 : REAL(dp), DIMENSION(2) :: next_best_overlap
1483 68 : REAL(dp), DIMENSION(:), POINTER :: mo_evals, zeta
1484 68 : REAL(dp), DIMENSION(:, :), POINTER :: overlap_matrix, tmp_coeff
1485 : TYPE(cp_blacs_env_type), POINTER :: blacs_env
1486 : TYPE(cp_fm_struct_type), POINTER :: eval_mat_struct, gs_struct
1487 : TYPE(cp_fm_type) :: eval_mat, work_mat
1488 : TYPE(cp_fm_type), POINTER :: gs_coeffs, mo_coeff
1489 68 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_ks
1490 : TYPE(gto_basis_set_type), POINTER :: kind_basis_set, sto_to_gto_basis_set
1491 68 : TYPE(mo_set_type), DIMENSION(:), POINTER :: mos
1492 : TYPE(mp_para_env_type), POINTER :: para_env
1493 68 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
1494 68 : TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
1495 : TYPE(sto_basis_set_type), POINTER :: sto_basis_set
1496 :
1497 68 : NULLIFY (sto_basis_set, sto_to_gto_basis_set, qs_kind_set, kind_basis_set, lq, nq, zeta)
1498 68 : NULLIFY (overlap_matrix, mos, mo_coeff, mos_of_ex_atoms, tmp_coeff, first_sgf, particle_set)
1499 68 : NULLIFY (mo_evals, matrix_ks, para_env, blacs_env)
1500 68 : NULLIFY (eval_mat_struct, gs_struct, gs_coeffs)
1501 :
1502 136 : output_unit = cp_logger_get_default_io_unit()
1503 :
1504 : CALL get_qs_env(qs_env=qs_env, qs_kind_set=qs_kind_set, mos=mos, particle_set=particle_set, &
1505 68 : matrix_ks=matrix_ks, para_env=para_env, blacs_env=blacs_env)
1506 :
1507 68 : nspins = 1; IF (xas_tdp_control%do_uks) nspins = 2
1508 :
1509 : ! Construction of a STO that fits the type of orbital we look for
1510 68 : ALLOCATE (zeta(1))
1511 68 : ALLOCATE (lq(1))
1512 68 : ALLOCATE (nq(1))
1513 : ! Retrieving quantum numbers
1514 68 : IF (donor_state%state_type == xas_1s_type) THEN
1515 54 : nq(1) = 1
1516 54 : lq(1) = 0
1517 54 : n_states = 1
1518 14 : ELSE IF (donor_state%state_type == xas_2s_type) THEN
1519 6 : nq(1) = 2
1520 6 : lq(1) = 0
1521 6 : n_states = 1
1522 8 : ELSE IF (donor_state%state_type == xas_2p_type) THEN
1523 8 : nq(1) = 2
1524 8 : lq(1) = 1
1525 8 : n_states = 3
1526 : ELSE
1527 0 : CPABORT("Procedure for required type not implemented")
1528 : END IF
1529 272 : ALLOCATE (my_mos(n_states, nspins))
1530 204 : ALLOCATE (max_overlap(n_states, nspins))
1531 :
1532 : ! Getting the atomic number
1533 68 : CALL get_qs_kind(qs_kind_set(donor_state%kind_index), zeff=zeff)
1534 68 : zval = INT(zeff)
1535 :
1536 : ! Electronic configuration (copied from MI's XAS)
1537 68 : ne = 0
1538 340 : DO l = 1, 4
1539 272 : nj = 2*(l - 1) + 1
1540 1836 : DO i = l, 7
1541 1496 : ne(l, i) = ptable(zval)%e_conv(l - 1) - 2*nj*(i - l)
1542 1496 : ne(l, i) = MAX(ne(l, i), 0)
1543 1768 : ne(l, i) = MIN(ne(l, i), 2*nj)
1544 : END DO
1545 : END DO
1546 :
1547 : ! computing zeta with the Slater sum rules
1548 68 : zeta(1) = srules(zval, ne, nq(1), lq(1))
1549 :
1550 : ! Allocating memory and initiate STO
1551 68 : CALL allocate_sto_basis_set(sto_basis_set)
1552 68 : CALL set_sto_basis_set(sto_basis_set, nshell=1, nq=nq, lq=lq, zet=zeta)
1553 :
1554 : ! Some clean-up
1555 68 : DEALLOCATE (nq, lq, zeta)
1556 :
1557 : ! Expanding the STO into (normalized) GTOs for later calculations, use standard 3 gaussians
1558 : CALL create_gto_from_sto_basis(sto_basis_set=sto_basis_set, &
1559 : gto_basis_set=sto_to_gto_basis_set, &
1560 68 : ngauss=3)
1561 68 : sto_to_gto_basis_set%norm_type = 2
1562 68 : CALL init_orb_basis_set(sto_to_gto_basis_set)
1563 :
1564 : ! Retrieving the atomic kind related GTO in which MOs are expanded
1565 68 : CALL get_qs_kind(qs_kind_set(donor_state%kind_index), basis_set=kind_basis_set)
1566 :
1567 : ! Allocating and computing the overlap between the two basis (they share the same center)
1568 68 : CALL get_gto_basis_set(gto_basis_set=kind_basis_set, nsgf=nsgf_kind)
1569 68 : CALL get_gto_basis_set(gto_basis_set=sto_to_gto_basis_set, nsgf=nsgf_sto)
1570 272 : ALLOCATE (overlap_matrix(nsgf_sto, nsgf_kind))
1571 :
1572 : ! Making use of MI's subroutine
1573 68 : CALL calc_stogto_overlap(sto_to_gto_basis_set, kind_basis_set, overlap_matrix)
1574 :
1575 : ! Some clean-up
1576 68 : CALL deallocate_sto_basis_set(sto_basis_set)
1577 68 : CALL deallocate_gto_basis_set(sto_to_gto_basis_set)
1578 :
1579 : ! Looping over the potential donor states to compute overlap with STO basis
1580 68 : mos_of_ex_atoms => xas_tdp_env%mos_of_ex_atoms
1581 68 : n_search = xas_tdp_control%n_search
1582 68 : at_index = donor_state%at_index
1583 68 : iat = locate(xas_tdp_env%ex_atom_indices, at_index)
1584 204 : ALLOCATE (first_sgf(SIZE(particle_set))) !probably do not need that
1585 68 : CALL get_particle_set(particle_set=particle_set, qs_kind_set=qs_kind_set, first_sgf=first_sgf)
1586 204 : ALLOCATE (tmp_coeff(nsgf_kind, 1))
1587 136 : ALLOCATE (sto_overlap(nsgf_kind))
1588 204 : ALLOCATE (overlap(n_search))
1589 :
1590 68 : next_best_overlap = 0.0_dp
1591 240 : max_overlap = 0.0_dp
1592 :
1593 144 : DO ispin = 1, nspins
1594 :
1595 76 : CALL get_mo_set(mos(ispin), mo_coeff=mo_coeff, nao=nao)
1596 482 : overlap = 0.0_dp
1597 :
1598 76 : my_mo = 0
1599 482 : DO imo = 1, n_search
1600 482 : IF (mos_of_ex_atoms(imo, iat, ispin) > 0) THEN
1601 :
1602 3960 : sto_overlap = 0.0_dp
1603 4124 : tmp_coeff = 0.0_dp
1604 :
1605 : ! Getting the relevant coefficients for the candidate state
1606 : CALL cp_fm_get_submatrix(fm=mo_coeff, target_m=tmp_coeff, start_row=first_sgf(at_index), &
1607 164 : start_col=imo, n_rows=nsgf_kind, n_cols=1, transpose=.FALSE.)
1608 :
1609 : ! Computing the product overlap_matrix*coeffs
1610 : CALL dgemm('N', 'N', nsgf_sto, 1, nsgf_kind, 1.0_dp, overlap_matrix, nsgf_sto, &
1611 164 : tmp_coeff, nsgf_kind, 0.0_dp, sto_overlap, nsgf_sto)
1612 :
1613 : ! Each element of column vector sto_overlap is the overlap of a basis element of the
1614 : ! generated STO basis with the kind specific orbital basis. Take the sum of the absolute
1615 : ! values so that rotation (of the px, py, pz for example) does not hinder our search
1616 3960 : overlap(imo) = SUM(ABS(sto_overlap))
1617 :
1618 : END IF
1619 : END DO
1620 :
1621 : ! Finding the best overlap(s)
1622 172 : DO i = 1, n_states
1623 602 : my_mo = MAXLOC(overlap, 1)
1624 96 : my_mos(i, ispin) = my_mo
1625 698 : max_overlap(i, ispin) = MAXVAL(overlap, 1)
1626 172 : overlap(my_mo) = 0.0_dp
1627 : END DO
1628 : ! Getting the next best overlap (for validation purposes)
1629 558 : next_best_overlap(ispin) = MAXVAL(overlap, 1)
1630 482 : next_best_overlap_ind(ispin) = MAXLOC(overlap, 1)
1631 :
1632 : ! Sort MO indices
1633 220 : CALL sort_unique(my_mos(:, ispin), unique)
1634 :
1635 : END DO !ispin
1636 :
1637 : ! Some clean-up
1638 68 : DEALLOCATE (overlap_matrix, tmp_coeff)
1639 :
1640 : ! Dealing with the result
1641 480 : IF (ALL(my_mos > 0) .AND. ALL(my_mos <= n_search)) THEN
1642 : ! Assigning the MO indices to the donor_state
1643 136 : ALLOCATE (donor_state%mo_indices(n_states, nspins))
1644 240 : donor_state%mo_indices = my_mos
1645 68 : donor_state%ndo_mo = n_states
1646 :
1647 : ! Storing the MOs in the donor_state, as vectors column: first columns alpha spin, then beta
1648 : CALL cp_fm_struct_create(gs_struct, nrow_global=nao, ncol_global=n_states*nspins, &
1649 68 : para_env=para_env, context=blacs_env)
1650 68 : ALLOCATE (donor_state%gs_coeffs)
1651 68 : CALL cp_fm_create(donor_state%gs_coeffs, gs_struct)
1652 :
1653 144 : DO ispin = 1, nspins
1654 76 : CALL get_mo_set(mos(ispin), mo_coeff=mo_coeff)
1655 240 : DO i = 1, n_states
1656 : CALL cp_fm_to_fm_submat(msource=mo_coeff, mtarget=donor_state%gs_coeffs, nrow=nao, &
1657 : ncol=1, s_firstrow=1, s_firstcol=my_mos(i, ispin), &
1658 172 : t_firstrow=1, t_firstcol=(ispin - 1)*n_states + i)
1659 : END DO
1660 : END DO
1661 68 : gs_coeffs => donor_state%gs_coeffs
1662 :
1663 : !Keep the subset of the coeffs centered on the excited atom as global array (used a lot)
1664 272 : ALLOCATE (donor_state%contract_coeffs(nsgf_kind, n_states*nspins))
1665 : CALL cp_fm_get_submatrix(gs_coeffs, donor_state%contract_coeffs, start_row=first_sgf(at_index), &
1666 68 : start_col=1, n_rows=nsgf_kind, n_cols=n_states*nspins)
1667 :
1668 : ! Assigning corresponding energy eigenvalues and writing some info in standard input file
1669 :
1670 : !standard eigenvalues as gotten from the KS diagonalization in the ground state
1671 68 : IF (.NOT. xas_tdp_control%do_loc .AND. .NOT. xas_tdp_control%do_roks) THEN
1672 20 : IF (output_unit > 0) THEN
1673 : WRITE (UNIT=output_unit, FMT="(T5,A,/,T5,A,/,T5,A)") &
1674 10 : "The following canonical MO(s) have been associated with the donor state(s)", &
1675 10 : "based on the overlap with the components of a minimal STO basis: ", &
1676 20 : " Spin MO index overlap(sum)"
1677 : END IF
1678 :
1679 40 : ALLOCATE (donor_state%energy_evals(n_states, nspins))
1680 80 : donor_state%energy_evals = 0.0_dp
1681 :
1682 : ! Canonical MO, no change in eigenvalues, only diagonal elements
1683 44 : DO ispin = 1, nspins
1684 24 : CALL get_mo_set(mos(ispin), eigenvalues=mo_evals)
1685 80 : DO i = 1, n_states
1686 36 : donor_state%energy_evals(i, ispin) = mo_evals(my_mos(i, ispin))
1687 :
1688 60 : IF (output_unit > 0) THEN
1689 : WRITE (UNIT=output_unit, FMT="(T46,I4,I11,F17.5)") &
1690 18 : ispin, my_mos(i, ispin), max_overlap(i, ispin)
1691 : END IF
1692 : END DO
1693 : END DO
1694 :
1695 : !either localization of MOs or ROKS, in both cases the MO eigenvalues from the KS
1696 : !digonalization mat have changed
1697 : ELSE
1698 48 : IF (output_unit > 0) THEN
1699 : WRITE (UNIT=output_unit, FMT="(T5,A,/,T5,A,/,T5,A)") &
1700 24 : "The following localized MO(s) have been associated with the donor state(s)", &
1701 24 : "based on the overlap with the components of a minimal STO basis: ", &
1702 48 : " Spin MO index overlap(sum)"
1703 : END IF
1704 :
1705 : ! Loop over the donor states and print
1706 100 : DO ispin = 1, nspins
1707 160 : DO i = 1, n_states
1708 :
1709 : ! Print info
1710 112 : IF (output_unit > 0) THEN
1711 : WRITE (UNIT=output_unit, FMT="(T46,I4,I11,F17.5)") &
1712 30 : ispin, my_mos(i, ispin), max_overlap(i, ispin)
1713 : END IF
1714 : END DO
1715 : END DO
1716 :
1717 : ! MO have been rotated or non-physical ROKS MO eigrenvalues:
1718 : ! => need epsilon_ij = <psi_i|F|psi_j> = sum_{pq} c_{qi}c_{pj} F_{pq}
1719 : ! Note: only have digonal elements by construction
1720 48 : ndo_so = nspins*n_states
1721 48 : CALL cp_fm_create(work_mat, gs_struct)
1722 : CALL cp_fm_struct_create(eval_mat_struct, nrow_global=ndo_so, ncol_global=ndo_so, &
1723 48 : para_env=para_env, context=blacs_env)
1724 48 : CALL cp_fm_create(eval_mat, eval_mat_struct)
1725 144 : ALLOCATE (diag(ndo_so))
1726 :
1727 48 : IF (.NOT. xas_tdp_control%do_roks) THEN
1728 :
1729 96 : ALLOCATE (donor_state%energy_evals(n_states, nspins))
1730 160 : donor_state%energy_evals = 0.0_dp
1731 :
1732 : ! Compute gs_coeff^T * matrix_ks * gs_coeff to get the epsilon_ij matrix
1733 100 : DO ispin = 1, nspins
1734 52 : CALL cp_dbcsr_sm_fm_multiply(matrix_ks(ispin)%matrix, gs_coeffs, work_mat, ncol=ndo_so)
1735 52 : CALL parallel_gemm('T', 'N', ndo_so, ndo_so, nao, 1.0_dp, gs_coeffs, work_mat, 0.0_dp, eval_mat)
1736 :
1737 : ! Put the epsilon_ii into the donor_state. No off-diagonal element because of subset diag
1738 52 : CALL cp_fm_get_diag(eval_mat, diag)
1739 160 : donor_state%energy_evals(:, ispin) = diag((ispin - 1)*n_states + 1:ispin*n_states)
1740 :
1741 : END DO
1742 :
1743 : ELSE
1744 : ! If ROKS, slightly different procedure => 2 KS matrices but one type of MOs
1745 0 : ALLOCATE (donor_state%energy_evals(n_states, 2))
1746 0 : donor_state%energy_evals = 0.0_dp
1747 :
1748 : ! Compute gs_coeff^T * matrix_ks * gs_coeff to get the epsilon_ij matrix
1749 0 : DO ispin = 1, 2
1750 0 : CALL cp_dbcsr_sm_fm_multiply(matrix_ks(ispin)%matrix, gs_coeffs, work_mat, ncol=ndo_so)
1751 0 : CALL parallel_gemm('T', 'N', ndo_so, ndo_so, nao, 1.0_dp, gs_coeffs, work_mat, 0.0_dp, eval_mat)
1752 :
1753 0 : CALL cp_fm_get_diag(eval_mat, diag)
1754 0 : donor_state%energy_evals(:, ispin) = diag(:)
1755 :
1756 : END DO
1757 :
1758 0 : DEALLOCATE (diag)
1759 : END IF
1760 :
1761 : ! Clean-up
1762 48 : CALL cp_fm_release(work_mat)
1763 48 : CALL cp_fm_release(eval_mat)
1764 144 : CALL cp_fm_struct_release(eval_mat_struct)
1765 :
1766 : END IF ! do_localize and/or ROKS
1767 :
1768 : ! Allocate and initialize GW2X corrected IPs as energy_evals
1769 272 : ALLOCATE (donor_state%gw2x_evals(SIZE(donor_state%energy_evals, 1), SIZE(donor_state%energy_evals, 2)))
1770 240 : donor_state%gw2x_evals(:, :) = donor_state%energy_evals(:, :)
1771 :
1772 : ! Clean-up
1773 68 : CALL cp_fm_struct_release(gs_struct)
1774 68 : DEALLOCATE (first_sgf)
1775 :
1776 68 : IF (output_unit > 0) WRITE (UNIT=output_unit, FMT="(T5,A)") " "
1777 :
1778 144 : DO ispin = 1, nspins
1779 144 : IF (output_unit > 0) THEN
1780 : WRITE (UNIT=output_unit, FMT="(T5,A,I1,A,F7.5,A,I4)") &
1781 38 : "The next best overlap for spin ", ispin, " is ", next_best_overlap(ispin), &
1782 76 : " for MO with index ", next_best_overlap_ind(ispin)
1783 : END IF
1784 : END DO
1785 68 : IF (output_unit > 0) WRITE (UNIT=output_unit, FMT="(T5,A)") " "
1786 :
1787 : ELSE
1788 0 : CPABORT("A core donor state could not be assigned MO(s). Increasing NSEARCH might help.")
1789 : END IF
1790 :
1791 272 : END SUBROUTINE assign_mos_to_donor_state
1792 :
1793 : ! **************************************************************************************************
1794 : !> \brief Compute the centers and spreads of (core) MOs using the Berry phase operator
1795 : !> \param xas_tdp_env ...
1796 : !> \param xas_tdp_control ...
1797 : !> \param qs_env ...
1798 : !> \note xas_tdp_env%qs_loc_env is used and modified. OK since no localization done after this
1799 : !> subroutine is used.
1800 : ! **************************************************************************************************
1801 80 : SUBROUTINE find_mo_centers(xas_tdp_env, xas_tdp_control, qs_env)
1802 :
1803 : TYPE(xas_tdp_env_type), POINTER :: xas_tdp_env
1804 : TYPE(xas_tdp_control_type), POINTER :: xas_tdp_control
1805 : TYPE(qs_environment_type), POINTER :: qs_env
1806 :
1807 : INTEGER :: dim_op, i, ispin, j, n_centers, nao, &
1808 : nspins
1809 : REAL(dp), DIMENSION(6) :: weights
1810 : TYPE(cell_type), POINTER :: cell
1811 : TYPE(cp_blacs_env_type), POINTER :: blacs_env
1812 : TYPE(cp_fm_struct_type), POINTER :: tmp_fm_struct
1813 : TYPE(cp_fm_type) :: opvec
1814 80 : TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:, :) :: zij_fm_set
1815 80 : TYPE(cp_fm_type), DIMENSION(:), POINTER :: moloc_coeff
1816 : TYPE(cp_fm_type), POINTER :: vectors
1817 80 : TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER :: op_sm_set
1818 : TYPE(mp_para_env_type), POINTER :: para_env
1819 : TYPE(qs_loc_env_type), POINTER :: qs_loc_env
1820 : TYPE(section_vals_type), POINTER :: print_loc_section, prog_run_info
1821 :
1822 80 : NULLIFY (qs_loc_env, cell, print_loc_section, op_sm_set, moloc_coeff, vectors)
1823 80 : NULLIFY (tmp_fm_struct, para_env, blacs_env, prog_run_info)
1824 :
1825 : ! Initialization
1826 80 : print_loc_section => xas_tdp_control%print_loc_subsection
1827 80 : n_centers = xas_tdp_control%n_search
1828 80 : CALL get_qs_env(qs_env=qs_env, para_env=para_env, blacs_env=blacs_env, cell=cell)
1829 :
1830 : ! Set print option to debug to keep clean output file
1831 80 : prog_run_info => section_vals_get_subs_vals(print_loc_section, "PROGRAM_RUN_INFO")
1832 : CALL section_vals_val_set(prog_run_info, keyword_name="_SECTION_PARAMETERS_", &
1833 80 : i_val=debug_print_level)
1834 :
1835 : ! Re-initialize the qs_loc_env to get the current MOs. Use force_loc because needed for centers
1836 80 : CALL reinit_qs_loc_env(xas_tdp_env%qs_loc_env, n_centers, xas_tdp_control%do_uks, qs_env)
1837 80 : qs_loc_env => xas_tdp_env%qs_loc_env
1838 :
1839 : ! Get what we need from the qs_lovc_env
1840 : CALL get_qs_loc_env(qs_loc_env=qs_loc_env, weights=weights, op_sm_set=op_sm_set, &
1841 80 : moloc_coeff=moloc_coeff)
1842 :
1843 : ! Prepare for zij
1844 80 : vectors => moloc_coeff(1)
1845 80 : CALL cp_fm_get_info(vectors, nrow_global=nao)
1846 80 : CALL cp_fm_create(opvec, vectors%matrix_struct)
1847 :
1848 : CALL cp_fm_struct_create(tmp_fm_struct, para_env=para_env, context=blacs_env, &
1849 80 : ncol_global=n_centers, nrow_global=n_centers)
1850 :
1851 80 : IF (cell%orthorhombic) THEN
1852 : dim_op = 3
1853 : ELSE
1854 0 : dim_op = 6
1855 : END IF
1856 880 : ALLOCATE (zij_fm_set(2, dim_op))
1857 320 : DO i = 1, dim_op
1858 800 : DO j = 1, 2
1859 720 : CALL cp_fm_create(zij_fm_set(j, i), tmp_fm_struct)
1860 : END DO
1861 : END DO
1862 :
1863 : ! If spin-unrestricted, need to go spin by spin
1864 80 : nspins = 1; IF (xas_tdp_control%do_uks) nspins = 2
1865 :
1866 168 : DO ispin = 1, nspins
1867 : ! zij computation, copied from qs_loc_methods:optimize_loc_berry
1868 88 : vectors => moloc_coeff(ispin)
1869 352 : DO i = 1, dim_op
1870 880 : DO j = 1, 2
1871 528 : CALL cp_fm_set_all(zij_fm_set(j, i), 0.0_dp)
1872 528 : CALL cp_dbcsr_sm_fm_multiply(op_sm_set(j, i)%matrix, vectors, opvec, ncol=n_centers)
1873 : CALL parallel_gemm("T", "N", n_centers, n_centers, nao, 1.0_dp, vectors, opvec, 0.0_dp, &
1874 792 : zij_fm_set(j, i))
1875 : END DO
1876 : END DO
1877 :
1878 : ! Compute centers (and spread)
1879 : CALL centers_spreads_berry(qs_loc_env=qs_loc_env, zij=zij_fm_set, nmoloc=n_centers, &
1880 : cell=cell, weights=weights, ispin=ispin, &
1881 168 : print_loc_section=print_loc_section, only_initial_out=.TRUE.)
1882 : END DO !ispins
1883 :
1884 : ! Clean-up
1885 80 : CALL cp_fm_release(opvec)
1886 80 : CALL cp_fm_struct_release(tmp_fm_struct)
1887 80 : CALL cp_fm_release(zij_fm_set)
1888 :
1889 : ! Make sure we leave with the correct do_loc value
1890 80 : qs_loc_env%do_localize = xas_tdp_control%do_loc
1891 :
1892 240 : END SUBROUTINE find_mo_centers
1893 :
1894 : ! **************************************************************************************************
1895 : !> \brief Prints the MO to donor_state assocaition with overlap and Mulliken population analysis
1896 : !> \param xas_tdp_env ...
1897 : !> \param xas_tdp_control ...
1898 : !> \param qs_env ...
1899 : !> \note Called only in case of CHECK_ONLY run
1900 : ! **************************************************************************************************
1901 0 : SUBROUTINE print_checks(xas_tdp_env, xas_tdp_control, qs_env)
1902 :
1903 : TYPE(xas_tdp_env_type), POINTER :: xas_tdp_env
1904 : TYPE(xas_tdp_control_type), POINTER :: xas_tdp_control
1905 : TYPE(qs_environment_type), POINTER :: qs_env
1906 :
1907 : CHARACTER(LEN=default_string_length) :: kind_name
1908 : INTEGER :: current_state_index, iat, iatom, ikind, &
1909 : istate, output_unit, tmp_index
1910 0 : INTEGER, DIMENSION(:), POINTER :: atoms_of_kind
1911 0 : TYPE(atomic_kind_type), DIMENSION(:), POINTER :: atomic_kind_set
1912 : TYPE(donor_state_type), POINTER :: current_state
1913 :
1914 0 : NULLIFY (atomic_kind_set, atoms_of_kind, current_state)
1915 :
1916 0 : output_unit = cp_logger_get_default_io_unit()
1917 :
1918 0 : IF (output_unit > 0) THEN
1919 : WRITE (output_unit, "(/,T3,A,/,T3,A,/,T3,A)") &
1920 0 : "# Check the donor states for their quality. They need to have a well defined type ", &
1921 0 : " (1s, 2s, etc) which is indicated by the overlap. They also need to be localized, ", &
1922 0 : " for which the Mulliken population analysis is one indicator (must be close to 1.0)"
1923 : END IF
1924 :
1925 : ! Loop over the donor states (as in the main xas_tdp loop)
1926 0 : CALL get_qs_env(qs_env=qs_env, atomic_kind_set=atomic_kind_set)
1927 0 : current_state_index = 1
1928 :
1929 : !loop over atomic kinds
1930 0 : DO ikind = 1, SIZE(atomic_kind_set)
1931 :
1932 : CALL get_atomic_kind(atomic_kind=atomic_kind_set(ikind), name=kind_name, &
1933 0 : atom_list=atoms_of_kind)
1934 :
1935 0 : IF (.NOT. ANY(xas_tdp_env%ex_kind_indices == ikind)) CYCLE
1936 :
1937 : !loop over atoms of kind
1938 0 : DO iat = 1, SIZE(atoms_of_kind)
1939 0 : iatom = atoms_of_kind(iat)
1940 :
1941 0 : IF (.NOT. ANY(xas_tdp_env%ex_atom_indices == iatom)) CYCLE
1942 0 : tmp_index = locate(xas_tdp_env%ex_atom_indices, iatom)
1943 :
1944 : !loop over states of excited atom
1945 0 : DO istate = 1, SIZE(xas_tdp_env%state_types, 1)
1946 :
1947 0 : IF (xas_tdp_env%state_types(istate, tmp_index) == xas_not_excited) CYCLE
1948 :
1949 0 : current_state => xas_tdp_env%donor_states(current_state_index)
1950 : CALL set_donor_state(current_state, at_index=iatom, &
1951 : at_symbol=kind_name, kind_index=ikind, &
1952 0 : state_type=xas_tdp_env%state_types(istate, tmp_index))
1953 :
1954 0 : IF (output_unit > 0) THEN
1955 : WRITE (output_unit, "(/,T4,A,A2,A,I4,A,A,A)") &
1956 0 : "-Donor state of type ", xas_tdp_env%state_type_char(current_state%state_type), &
1957 0 : " for atom", current_state%at_index, " of kind ", TRIM(current_state%at_symbol), ":"
1958 : END IF
1959 :
1960 : !Assign the MOs and perform Mulliken
1961 0 : CALL assign_mos_to_donor_state(current_state, xas_tdp_env, xas_tdp_control, qs_env)
1962 0 : CALL perform_mulliken_on_donor_state(current_state, qs_env)
1963 :
1964 0 : current_state_index = current_state_index + 1
1965 0 : NULLIFY (current_state)
1966 :
1967 : END DO !istate
1968 : END DO !iat
1969 : END DO !ikind
1970 :
1971 0 : IF (output_unit > 0) THEN
1972 : WRITE (output_unit, "(/,T5,A)") &
1973 0 : "Use LOCALIZE and/or increase N_SEARCH for better results, if so required."
1974 : END IF
1975 :
1976 0 : END SUBROUTINE print_checks
1977 :
1978 : ! **************************************************************************************************
1979 : !> \brief Computes the required multipole moment in the length representation for a given atom
1980 : !> \param iatom index of the given atom
1981 : !> \param xas_tdp_env ...
1982 : !> \param xas_tdp_control ...
1983 : !> \param qs_env ...
1984 : !> \note Assumes that wither dipole or quadrupole in length rep is required
1985 : ! **************************************************************************************************
1986 24 : SUBROUTINE compute_lenrep_multipole(iatom, xas_tdp_env, xas_tdp_control, qs_env)
1987 :
1988 : INTEGER, INTENT(IN) :: iatom
1989 : TYPE(xas_tdp_env_type), POINTER :: xas_tdp_env
1990 : TYPE(xas_tdp_control_type), POINTER :: xas_tdp_control
1991 : TYPE(qs_environment_type), POINTER :: qs_env
1992 :
1993 : INTEGER :: i, order
1994 : REAL(dp), DIMENSION(3) :: rc
1995 24 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: work
1996 24 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
1997 :
1998 24 : NULLIFY (work, particle_set)
1999 :
2000 24 : CALL get_qs_env(qs_env, particle_set=particle_set)
2001 96 : rc = particle_set(iatom)%r
2002 :
2003 240 : ALLOCATE (work(9))
2004 24 : IF (xas_tdp_control%dipole_form == xas_dip_len) THEN
2005 96 : DO i = 1, 3
2006 72 : CALL dbcsr_set(xas_tdp_env%dipmat(i)%matrix, 0.0_dp)
2007 96 : work(i)%matrix => xas_tdp_env%dipmat(i)%matrix
2008 : END DO
2009 24 : order = 1
2010 : END IF
2011 24 : IF (xas_tdp_control%do_quad) THEN
2012 0 : DO i = 1, 6
2013 0 : CALL dbcsr_set(xas_tdp_env%quadmat(i)%matrix, 0.0_dp)
2014 0 : work(3 + i)%matrix => xas_tdp_env%quadmat(i)%matrix
2015 : END DO
2016 0 : order = 2
2017 0 : IF (xas_tdp_control%dipole_form == xas_dip_vel) order = -2
2018 : END IF
2019 :
2020 : !enforce minimum image to avoid PBCs related issues, ok because localized densities
2021 24 : CALL rRc_xyz_ao(work, qs_env, rc, order=order, minimum_image=.TRUE.)
2022 24 : DEALLOCATE (work)
2023 :
2024 24 : END SUBROUTINE compute_lenrep_multipole
2025 :
2026 : ! **************************************************************************************************
2027 : !> \brief Computes the oscillator strength based on the dipole moment (velocity or length rep) for
2028 : !> all available excitation energies and store the results in the donor_state. There is no
2029 : !> triplet dipole in the spin-restricted ground state.
2030 : !> \param donor_state the donor state which is excited
2031 : !> \param xas_tdp_control ...
2032 : !> \param xas_tdp_env ...
2033 : !> \note The oscillator strength is a scalar: osc_str = 2/(3*omega)*(dipole_v)^2 in the velocity rep
2034 : !> or : osc_str = 2/3*omega*(dipole_r)^2 in the length representation
2035 : !> The formulae for the dipoles come from the trace of the dipole operator with the transition
2036 : !> densities, i.e. what we get from solving the xas_tdp problem. Same procedure with or wo TDA
2037 : ! **************************************************************************************************
2038 56 : SUBROUTINE compute_dipole_fosc(donor_state, xas_tdp_control, xas_tdp_env)
2039 :
2040 : TYPE(donor_state_type), POINTER :: donor_state
2041 : TYPE(xas_tdp_control_type), POINTER :: xas_tdp_control
2042 : TYPE(xas_tdp_env_type), POINTER :: xas_tdp_env
2043 :
2044 : CHARACTER(len=*), PARAMETER :: routineN = 'compute_dipole_fosc'
2045 :
2046 : INTEGER :: handle, iosc, j, nao, ndo_mo, ndo_so, &
2047 : ngs, nosc, nspins
2048 : LOGICAL :: do_sc, do_sg
2049 : REAL(dp) :: osc_xyz, pref
2050 56 : REAL(dp), ALLOCATABLE, DIMENSION(:) :: tot_contr
2051 56 : REAL(dp), ALLOCATABLE, DIMENSION(:, :) :: dip_block
2052 56 : REAL(dp), DIMENSION(:), POINTER :: lr_evals
2053 56 : REAL(dp), DIMENSION(:, :), POINTER :: osc_str
2054 : TYPE(cp_blacs_env_type), POINTER :: blacs_env
2055 : TYPE(cp_fm_struct_type), POINTER :: col_struct, mat_struct
2056 : TYPE(cp_fm_type) :: col_work, mat_work
2057 : TYPE(cp_fm_type), POINTER :: lr_coeffs
2058 56 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: dipmat
2059 : TYPE(mp_para_env_type), POINTER :: para_env
2060 :
2061 56 : NULLIFY (dipmat, col_struct, mat_struct, para_env, blacs_env, lr_coeffs)
2062 56 : NULLIFY (lr_evals, osc_str)
2063 :
2064 56 : CALL timeset(routineN, handle)
2065 :
2066 : ! Initialization
2067 56 : do_sc = xas_tdp_control%do_spin_cons
2068 56 : do_sg = xas_tdp_control%do_singlet
2069 56 : IF (do_sc) THEN
2070 8 : nspins = 2
2071 8 : lr_evals => donor_state%sc_evals
2072 8 : lr_coeffs => donor_state%sc_coeffs
2073 48 : ELSE IF (do_sg) THEN
2074 48 : nspins = 1
2075 48 : lr_evals => donor_state%sg_evals
2076 48 : lr_coeffs => donor_state%sg_coeffs
2077 : ELSE
2078 0 : CPABORT("Dipole oscilaltor strength only for singlets and spin-conserving excitations.")
2079 : END IF
2080 56 : ndo_mo = donor_state%ndo_mo
2081 56 : ndo_so = ndo_mo*nspins
2082 56 : ngs = ndo_so; IF (xas_tdp_control%do_roks) ngs = ndo_mo !in ROKS, same gs coeffs
2083 56 : nosc = SIZE(lr_evals)
2084 168 : ALLOCATE (donor_state%osc_str(nosc, 4))
2085 56 : osc_str => donor_state%osc_str
2086 3704 : osc_str = 0.0_dp
2087 56 : dipmat => xas_tdp_env%dipmat
2088 :
2089 : ! do some work matrix initialization
2090 : CALL cp_fm_get_info(donor_state%gs_coeffs, matrix_struct=col_struct, para_env=para_env, &
2091 56 : context=blacs_env, nrow_global=nao)
2092 : CALL cp_fm_struct_create(mat_struct, para_env=para_env, context=blacs_env, &
2093 56 : nrow_global=ndo_so*nosc, ncol_global=ngs)
2094 56 : CALL cp_fm_create(mat_work, mat_struct)
2095 56 : CALL cp_fm_create(col_work, col_struct)
2096 :
2097 336 : ALLOCATE (tot_contr(ndo_mo), dip_block(ndo_so, ngs))
2098 56 : pref = 2.0_dp; IF (do_sc) pref = 1.0_dp !because of singlet definition u = 1/sqrt(2)(c_a+c_b)
2099 :
2100 : ! Looping over cartesian coord
2101 224 : DO j = 1, 3
2102 :
2103 : !Compute dip*gs_coeffs
2104 168 : CALL cp_dbcsr_sm_fm_multiply(dipmat(j)%matrix, donor_state%gs_coeffs, col_work, ncol=ngs)
2105 : !compute lr_coeffs*dip*gs_coeffs
2106 168 : CALL parallel_gemm('T', 'N', ndo_so*nosc, ngs, nao, 1.0_dp, lr_coeffs, col_work, 0.0_dp, mat_work)
2107 :
2108 : !Loop over the excited states
2109 2792 : DO iosc = 1, nosc
2110 :
2111 5424 : tot_contr = 0.0_dp
2112 : CALL cp_fm_get_submatrix(fm=mat_work, target_m=dip_block, start_row=(iosc - 1)*ndo_so + 1, &
2113 2568 : start_col=1, n_rows=ndo_so, n_cols=ngs)
2114 2568 : IF (do_sg) THEN
2115 1944 : tot_contr(:) = get_diag(dip_block)
2116 624 : ELSE IF (do_sc .AND. xas_tdp_control%do_uks) THEN
2117 624 : tot_contr(:) = get_diag(dip_block(1:ndo_mo, 1:ndo_mo)) !alpha
2118 1392 : tot_contr(:) = tot_contr(:) + get_diag(dip_block(ndo_mo + 1:ndo_so, ndo_mo + 1:ndo_so)) !beta
2119 : ELSE
2120 : !roks
2121 0 : tot_contr(:) = get_diag(dip_block(1:ndo_mo, :)) !alpha
2122 0 : tot_contr(:) = tot_contr(:) + get_diag(dip_block(ndo_mo + 1:ndo_so, :)) !beta
2123 : END IF
2124 :
2125 5424 : osc_xyz = SUM(tot_contr)**2
2126 2568 : osc_str(iosc, 4) = osc_str(iosc, 4) + osc_xyz
2127 2736 : osc_str(iosc, j) = osc_xyz
2128 :
2129 : END DO !iosc
2130 : END DO !j
2131 :
2132 : !compute the prefactor
2133 280 : DO j = 1, 4
2134 280 : IF (xas_tdp_control%dipole_form == xas_dip_len) THEN
2135 3248 : osc_str(:, j) = pref*2.0_dp/3.0_dp*lr_evals(:)*osc_str(:, j)
2136 : ELSE
2137 4048 : osc_str(:, j) = pref*2.0_dp/3.0_dp/lr_evals(:)*osc_str(:, j)
2138 : END IF
2139 : END DO
2140 :
2141 : !clean-up
2142 56 : CALL cp_fm_release(mat_work)
2143 56 : CALL cp_fm_release(col_work)
2144 56 : CALL cp_fm_struct_release(mat_struct)
2145 :
2146 56 : CALL timestop(handle)
2147 :
2148 224 : END SUBROUTINE compute_dipole_fosc
2149 :
2150 : ! **************************************************************************************************
2151 : !> \brief Computes the oscillator strength due to the electric quadrupole moment and store it in
2152 : !> the donor_state (for singlet or spin-conserving)
2153 : !> \param donor_state the donor state which is excited
2154 : !> \param xas_tdp_control ...
2155 : !> \param xas_tdp_env ...
2156 : !> \note Formula: 1/20*a_fine^2*omega^3 * sum_ab (sum_i r_ia*r_ib - 1/3*ri^2*delta_ab)
2157 : ! **************************************************************************************************
2158 0 : SUBROUTINE compute_quadrupole_fosc(donor_state, xas_tdp_control, xas_tdp_env)
2159 :
2160 : TYPE(donor_state_type), POINTER :: donor_state
2161 : TYPE(xas_tdp_control_type), POINTER :: xas_tdp_control
2162 : TYPE(xas_tdp_env_type), POINTER :: xas_tdp_env
2163 :
2164 : CHARACTER(len=*), PARAMETER :: routineN = 'compute_quadrupole_fosc'
2165 :
2166 : INTEGER :: handle, iosc, j, nao, ndo_mo, ndo_so, &
2167 : ngs, nosc, nspins
2168 : LOGICAL :: do_sc, do_sg
2169 : REAL(dp) :: pref
2170 0 : REAL(dp), ALLOCATABLE, DIMENSION(:) :: tot_contr, trace
2171 0 : REAL(dp), ALLOCATABLE, DIMENSION(:, :) :: quad_block
2172 0 : REAL(dp), DIMENSION(:), POINTER :: lr_evals, osc_str
2173 : TYPE(cp_blacs_env_type), POINTER :: blacs_env
2174 : TYPE(cp_fm_struct_type), POINTER :: col_struct, mat_struct
2175 : TYPE(cp_fm_type) :: col_work, mat_work
2176 : TYPE(cp_fm_type), POINTER :: lr_coeffs
2177 0 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: quadmat
2178 : TYPE(mp_para_env_type), POINTER :: para_env
2179 :
2180 0 : NULLIFY (lr_evals, osc_str, lr_coeffs, col_struct, mat_struct, para_env)
2181 0 : NULLIFY (blacs_env)
2182 :
2183 0 : CALL timeset(routineN, handle)
2184 :
2185 : ! Initialization
2186 0 : do_sc = xas_tdp_control%do_spin_cons
2187 0 : do_sg = xas_tdp_control%do_singlet
2188 0 : IF (do_sc) THEN
2189 0 : nspins = 2
2190 0 : lr_evals => donor_state%sc_evals
2191 0 : lr_coeffs => donor_state%sc_coeffs
2192 0 : ELSE IF (do_sg) THEN
2193 0 : nspins = 1
2194 0 : lr_evals => donor_state%sg_evals
2195 0 : lr_coeffs => donor_state%sg_coeffs
2196 : ELSE
2197 0 : CPABORT("Quadrupole oscillator strengths only for singlet and spin-conserving excitations")
2198 : END IF
2199 0 : ndo_mo = donor_state%ndo_mo
2200 0 : ndo_so = ndo_mo*nspins
2201 0 : ngs = ndo_so; IF (xas_tdp_control%do_roks) ngs = ndo_mo !only alpha do_mo in ROKS
2202 0 : nosc = SIZE(lr_evals)
2203 0 : ALLOCATE (donor_state%quad_osc_str(nosc))
2204 0 : osc_str => donor_state%quad_osc_str
2205 0 : osc_str = 0.0_dp
2206 0 : quadmat => xas_tdp_env%quadmat
2207 :
2208 : !work matrices init
2209 : CALL cp_fm_get_info(donor_state%gs_coeffs, matrix_struct=col_struct, para_env=para_env, &
2210 0 : context=blacs_env, nrow_global=nao)
2211 : CALL cp_fm_struct_create(mat_struct, para_env=para_env, context=blacs_env, &
2212 0 : nrow_global=ndo_so*nosc, ncol_global=ngs)
2213 0 : CALL cp_fm_create(mat_work, mat_struct)
2214 0 : CALL cp_fm_create(col_work, col_struct)
2215 :
2216 0 : ALLOCATE (quad_block(ndo_so, ngs), tot_contr(ndo_mo))
2217 0 : pref = 2.0_dp; IF (do_sc) pref = 1.0_dp !because of singlet definition u = 1/sqrt(2)*...
2218 0 : ALLOCATE (trace(nosc))
2219 0 : trace = 0.0_dp
2220 :
2221 : !Loop over the cartesioan coord :x2, xy, xz, y2, yz, z2
2222 0 : DO j = 1, 6
2223 :
2224 : !Compute quad*gs_coeffs
2225 0 : CALL cp_dbcsr_sm_fm_multiply(quadmat(j)%matrix, donor_state%gs_coeffs, col_work, ncol=ngs)
2226 : !compute lr_coeffs*quadmat*gs_coeffs
2227 0 : CALL parallel_gemm('T', 'N', ndo_so*nosc, ngs, nao, 1.0_dp, lr_coeffs, col_work, 0.0_dp, mat_work)
2228 :
2229 : !Loop over the excited states
2230 0 : DO iosc = 1, nosc
2231 :
2232 0 : tot_contr = 0.0_dp
2233 : CALL cp_fm_get_submatrix(fm=mat_work, target_m=quad_block, start_row=(iosc - 1)*ndo_so + 1, &
2234 0 : start_col=1, n_rows=ndo_so, n_cols=ngs)
2235 :
2236 0 : IF (do_sg) THEN
2237 0 : tot_contr(:) = get_diag(quad_block)
2238 0 : ELSE IF (do_sc .AND. xas_tdp_control%do_uks) THEN
2239 0 : tot_contr(:) = get_diag(quad_block(1:ndo_mo, 1:ndo_mo)) !alpha
2240 0 : tot_contr(:) = tot_contr(:) + get_diag(quad_block(ndo_mo + 1:ndo_so, ndo_mo + 1:ndo_so)) !beta
2241 : ELSE
2242 : !roks
2243 0 : tot_contr(:) = get_diag(quad_block(1:ndo_mo, :)) !alpha
2244 0 : tot_contr(:) = tot_contr(:) + get_diag(quad_block(ndo_mo + 1:ndo_so, :)) !beta
2245 : END IF
2246 :
2247 : !if x2, y2, or z2 direction, need to update the trace (for later)
2248 0 : IF (j == 1 .OR. j == 4 .OR. j == 6) THEN
2249 0 : osc_str(iosc) = osc_str(iosc) + SUM(tot_contr)**2
2250 0 : trace(iosc) = trace(iosc) + SUM(tot_contr)
2251 :
2252 : !if xy, xz or yz, need to count twice the contribution (for yx, zx and zy)
2253 : ELSE
2254 0 : osc_str(iosc) = osc_str(iosc) + 2.0_dp*SUM(tot_contr)**2
2255 : END IF
2256 :
2257 : END DO !iosc
2258 : END DO !j
2259 :
2260 : !compute the prefactor, and remove 1/3*trace^2
2261 0 : osc_str(:) = pref*1._dp/20._dp*a_fine**2*lr_evals(:)**3*(osc_str(:) - 1._dp/3._dp*trace(:)**2)
2262 :
2263 : !clean-up
2264 0 : CALL cp_fm_release(mat_work)
2265 0 : CALL cp_fm_release(col_work)
2266 0 : CALL cp_fm_struct_release(mat_struct)
2267 :
2268 0 : CALL timestop(handle)
2269 :
2270 0 : END SUBROUTINE compute_quadrupole_fosc
2271 :
2272 : ! **************************************************************************************************
2273 : !> \brief Writes the core MOs to excited atoms associations in the main output file
2274 : !> \param xas_tdp_env ...
2275 : !> \param xas_tdp_control ...
2276 : !> \param qs_env ...
2277 : !> \note Look at alpha spin MOs, as we are dealing with core states and alpha/beta MOs are the same
2278 : ! **************************************************************************************************
2279 48 : SUBROUTINE write_mos_to_ex_atoms_association(xas_tdp_env, xas_tdp_control, qs_env)
2280 :
2281 : TYPE(xas_tdp_env_type), POINTER :: xas_tdp_env
2282 : TYPE(xas_tdp_control_type), POINTER :: xas_tdp_control
2283 : TYPE(qs_environment_type), POINTER :: qs_env
2284 :
2285 : CHARACTER(LEN=default_string_length) :: kind_name
2286 : INTEGER :: at_index, imo, ispin, nmo, nspins, &
2287 : output_unit, tmp_index
2288 : INTEGER, DIMENSION(3) :: perd_init
2289 48 : INTEGER, DIMENSION(:), POINTER :: ex_atom_indices
2290 48 : INTEGER, DIMENSION(:, :, :), POINTER :: mos_of_ex_atoms
2291 : REAL(dp) :: dist, mo_spread
2292 : REAL(dp), DIMENSION(3) :: at_pos, r_ac, wfn_center
2293 : TYPE(cell_type), POINTER :: cell
2294 48 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
2295 :
2296 48 : NULLIFY (cell, particle_set, mos_of_ex_atoms, ex_atom_indices)
2297 :
2298 96 : output_unit = cp_logger_get_default_io_unit()
2299 :
2300 48 : IF (output_unit > 0) THEN
2301 : WRITE (UNIT=output_unit, FMT="(/,T3,A,/,T3,A,/,T3,A)") &
2302 24 : " Associated Associated Distance to MO spread (Ang^2)", &
2303 24 : "Spin MO index atom index atom kind MO center (Ang) -w_i ln(|z_ij|^2)", &
2304 48 : "---------------------------------------------------------------------------------"
2305 : END IF
2306 :
2307 : ! Initialization
2308 48 : nspins = 1; IF (xas_tdp_control%do_uks) nspins = 2
2309 48 : mos_of_ex_atoms => xas_tdp_env%mos_of_ex_atoms
2310 48 : ex_atom_indices => xas_tdp_env%ex_atom_indices
2311 48 : nmo = xas_tdp_control%n_search
2312 48 : CALL get_qs_env(qs_env=qs_env, particle_set=particle_set, cell=cell)
2313 :
2314 : ! because the use of Berry's phase operator implies PBCs
2315 192 : perd_init = cell%perd
2316 192 : cell%perd = 1
2317 :
2318 : ! Retrieving all the info for each MO and spin
2319 304 : DO imo = 1, nmo
2320 576 : DO ispin = 1, nspins
2321 :
2322 : ! each Mo is associated to at most one atom (only 1 in array of -1)
2323 758 : IF (ANY(mos_of_ex_atoms(imo, :, ispin) == 1)) THEN
2324 252 : tmp_index = MAXLOC(mos_of_ex_atoms(imo, :, ispin), 1)
2325 114 : at_index = ex_atom_indices(tmp_index)
2326 114 : kind_name = particle_set(at_index)%atomic_kind%name
2327 :
2328 456 : at_pos = particle_set(at_index)%r
2329 456 : wfn_center = xas_tdp_env%qs_loc_env%localized_wfn_control%centers_set(ispin)%array(1:3, imo)
2330 114 : r_ac = pbc(at_pos, wfn_center, cell)
2331 456 : dist = NORM2(r_ac)
2332 : ! convert distance from a.u. to Angstrom
2333 114 : dist = dist*angstrom
2334 :
2335 114 : mo_spread = xas_tdp_env%qs_loc_env%localized_wfn_control%centers_set(ispin)%array(4, imo)
2336 114 : mo_spread = mo_spread*angstrom*angstrom
2337 :
2338 114 : IF (output_unit > 0) THEN
2339 : WRITE (UNIT=output_unit, FMT="(T3,I4,I10,I14,A14,ES19.3,ES20.3)") &
2340 57 : ispin, imo, at_index, TRIM(kind_name), dist, mo_spread
2341 : END IF
2342 :
2343 : END IF
2344 : END DO !ispin
2345 : END DO !imo
2346 :
2347 48 : IF (output_unit > 0) THEN
2348 : WRITE (UNIT=output_unit, FMT="(T3,A,/)") &
2349 24 : "---------------------------------------------------------------------------------"
2350 : END IF
2351 :
2352 : ! Go back to initial BCs
2353 192 : cell%perd = perd_init
2354 :
2355 48 : END SUBROUTINE write_mos_to_ex_atoms_association
2356 :
2357 : ! **************************************************************************************************
2358 : !> \brief Performs Mulliken population analysis for the MO(s) of a donor_state_type so that user
2359 : !> can verify it is indeed a core state
2360 : !> \param donor_state ...
2361 : !> \param qs_env ...
2362 : !> \note This is a specific case of Mulliken analysis. In general one computes sum_i (SP)_ii, where
2363 : !> i labels the basis function centered on the atom of interest. For a specific MO with index
2364 : !> j, one need to compute sum_{ik} c_{ij} S_{ik} c_{kj}, k = 1,nao
2365 : ! **************************************************************************************************
2366 68 : SUBROUTINE perform_mulliken_on_donor_state(donor_state, qs_env)
2367 : TYPE(donor_state_type), POINTER :: donor_state
2368 : TYPE(qs_environment_type), POINTER :: qs_env
2369 :
2370 : INTEGER :: at_index, i, ispin, nao, natom, ndo_mo, &
2371 : ndo_so, nsgf, nspins, output_unit
2372 68 : INTEGER, DIMENSION(:), POINTER :: first_sgf, last_sgf
2373 68 : INTEGER, DIMENSION(:, :), POINTER :: mo_indices
2374 68 : REAL(dp), ALLOCATABLE, DIMENSION(:, :) :: mul_pop, pop_mat
2375 68 : REAL(dp), DIMENSION(:, :), POINTER :: work_array
2376 : TYPE(cp_blacs_env_type), POINTER :: blacs_env
2377 : TYPE(cp_fm_struct_type), POINTER :: col_vect_struct
2378 : TYPE(cp_fm_type) :: work_vect
2379 : TYPE(cp_fm_type), POINTER :: gs_coeffs
2380 68 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_s
2381 : TYPE(mp_para_env_type), POINTER :: para_env
2382 68 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
2383 68 : TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
2384 :
2385 68 : NULLIFY (mo_indices, qs_kind_set, particle_set, first_sgf, work_array)
2386 68 : NULLIFY (matrix_s, para_env, blacs_env, col_vect_struct, last_sgf)
2387 :
2388 : ! Initialization
2389 68 : at_index = donor_state%at_index
2390 68 : mo_indices => donor_state%mo_indices
2391 68 : ndo_mo = donor_state%ndo_mo
2392 68 : gs_coeffs => donor_state%gs_coeffs
2393 136 : output_unit = cp_logger_get_default_io_unit()
2394 68 : nspins = 1; IF (SIZE(mo_indices, 2) == 2) nspins = 2
2395 68 : ndo_so = ndo_mo*nspins
2396 272 : ALLOCATE (mul_pop(ndo_mo, nspins))
2397 240 : mul_pop = 0.0_dp
2398 :
2399 : CALL get_qs_env(qs_env=qs_env, particle_set=particle_set, qs_kind_set=qs_kind_set, &
2400 68 : para_env=para_env, blacs_env=blacs_env, matrix_s=matrix_s)
2401 68 : CALL cp_fm_get_info(gs_coeffs, nrow_global=nao, matrix_struct=col_vect_struct)
2402 :
2403 68 : natom = SIZE(particle_set, 1)
2404 204 : ALLOCATE (first_sgf(natom))
2405 136 : ALLOCATE (last_sgf(natom))
2406 :
2407 68 : CALL get_particle_set(particle_set, qs_kind_set, first_sgf=first_sgf, last_sgf=last_sgf)
2408 68 : nsgf = last_sgf(at_index) - first_sgf(at_index) + 1
2409 :
2410 68 : CALL cp_fm_create(work_vect, col_vect_struct)
2411 :
2412 : ! Take the product of S*coeffs
2413 68 : CALL cp_dbcsr_sm_fm_multiply(matrix_s(1)%matrix, gs_coeffs, work_vect, ncol=ndo_so)
2414 :
2415 : ! Only consider the product coeffs^T * S * coeffs on the atom of interest
2416 272 : ALLOCATE (work_array(nsgf, ndo_so))
2417 272 : ALLOCATE (pop_mat(ndo_so, ndo_so))
2418 :
2419 : CALL cp_fm_get_submatrix(fm=work_vect, target_m=work_array, start_row=first_sgf(at_index), &
2420 68 : start_col=1, n_rows=nsgf, n_cols=ndo_so, transpose=.FALSE.)
2421 :
2422 : CALL dgemm('T', 'N', ndo_so, ndo_so, nsgf, 1.0_dp, donor_state%contract_coeffs, nsgf, &
2423 68 : work_array, nsgf, 0.0_dp, pop_mat, ndo_so)
2424 :
2425 : ! The Mullikan population for the MOs in on the diagonal.
2426 144 : DO ispin = 1, nspins
2427 240 : DO i = 1, ndo_mo
2428 172 : mul_pop(i, ispin) = pop_mat((ispin - 1)*ndo_mo + i, (ispin - 1)*ndo_mo + i)
2429 : END DO
2430 : END DO
2431 :
2432 : ! Printing in main output file
2433 68 : IF (output_unit > 0) THEN
2434 : WRITE (UNIT=output_unit, FMT="(T5,A,/,T5,A)") &
2435 34 : "Mulliken population analysis retricted to the associated MO(s) yields: ", &
2436 68 : " Spin MO index charge"
2437 72 : DO ispin = 1, nspins
2438 120 : DO i = 1, ndo_mo
2439 : WRITE (UNIT=output_unit, FMT="(T51,I4,I10,F11.3)") &
2440 86 : ispin, mo_indices(i, ispin), mul_pop(i, ispin)
2441 : END DO
2442 : END DO
2443 : END IF
2444 :
2445 : ! Clean-up
2446 68 : DEALLOCATE (first_sgf, last_sgf, work_array)
2447 68 : CALL cp_fm_release(work_vect)
2448 :
2449 272 : END SUBROUTINE perform_mulliken_on_donor_state
2450 :
2451 : ! **************************************************************************************************
2452 : !> \brief write the PDOS wrt the LR-orbitals for the current donor_state and/or the CUBES files
2453 : !> \param ex_type the excitation type: singlet, triplet, spin-conserving, etc
2454 : !> \param donor_state ...
2455 : !> \param xas_tdp_env ...
2456 : !> \param xas_tdp_section ...
2457 : !> \param qs_env ...
2458 : ! **************************************************************************************************
2459 74 : SUBROUTINE xas_tdp_post(ex_type, donor_state, xas_tdp_env, xas_tdp_section, qs_env)
2460 :
2461 : INTEGER, INTENT(IN) :: ex_type
2462 : TYPE(donor_state_type), POINTER :: donor_state
2463 : TYPE(xas_tdp_env_type), POINTER :: xas_tdp_env
2464 : TYPE(section_vals_type), POINTER :: xas_tdp_section
2465 : TYPE(qs_environment_type), POINTER :: qs_env
2466 :
2467 : CHARACTER(len=*), PARAMETER :: routineN = 'xas_tdp_post'
2468 :
2469 : CHARACTER(len=default_string_length) :: domo, domon, excite, pos, xas_mittle
2470 : INTEGER :: ex_state_idx, handle, ic, ido_mo, imo, irep, ispin, n_dependent, n_rep, nao, &
2471 : ncubes, ndo_mo, ndo_so, nlumo, nmo, nspins, output_unit
2472 62 : INTEGER, DIMENSION(:), POINTER :: bounds, list, state_list
2473 : LOGICAL :: append_cube, do_cubes, do_pdos, &
2474 : do_wfn_restart
2475 62 : REAL(dp), DIMENSION(:), POINTER :: lr_evals
2476 62 : REAL(dp), DIMENSION(:, :), POINTER :: centers
2477 62 : TYPE(atomic_kind_type), DIMENSION(:), POINTER :: atomic_kind_set
2478 : TYPE(cp_blacs_env_type), POINTER :: blacs_env
2479 : TYPE(cp_fm_struct_type), POINTER :: fm_struct, mo_struct
2480 : TYPE(cp_fm_type) :: mo_coeff, work_fm
2481 : TYPE(cp_fm_type), POINTER :: lr_coeffs
2482 : TYPE(cp_logger_type), POINTER :: logger
2483 62 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_s
2484 62 : TYPE(mo_set_type), DIMENSION(:), POINTER :: mos
2485 : TYPE(mo_set_type), POINTER :: mo_set
2486 : TYPE(mp_para_env_type), POINTER :: para_env
2487 62 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
2488 62 : TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
2489 : TYPE(section_vals_type), POINTER :: print_key
2490 :
2491 62 : NULLIFY (atomic_kind_set, particle_set, qs_kind_set, mo_set, lr_evals, lr_coeffs)
2492 62 : NULLIFY (mo_struct, para_env, blacs_env, fm_struct, matrix_s, print_key, logger)
2493 62 : NULLIFY (bounds, state_list, list, mos)
2494 :
2495 : !Tests on what to do
2496 124 : logger => cp_get_default_logger()
2497 62 : do_pdos = .FALSE.; do_cubes = .FALSE.; do_wfn_restart = .FALSE.
2498 :
2499 62 : IF (BTEST(cp_print_key_should_output(logger%iter_info, xas_tdp_section, &
2500 2 : "PRINT%PDOS"), cp_p_file)) do_pdos = .TRUE.
2501 :
2502 62 : IF (BTEST(cp_print_key_should_output(logger%iter_info, xas_tdp_section, &
2503 2 : "PRINT%CUBES"), cp_p_file)) do_cubes = .TRUE.
2504 :
2505 62 : IF (BTEST(cp_print_key_should_output(logger%iter_info, xas_tdp_section, &
2506 2 : "PRINT%RESTART_WFN"), cp_p_file)) do_wfn_restart = .TRUE.
2507 :
2508 62 : IF (.NOT. (do_pdos .OR. do_cubes .OR. do_wfn_restart)) RETURN
2509 :
2510 4 : CALL timeset(routineN, handle)
2511 :
2512 : !Initialization
2513 : CALL get_qs_env(qs_env, atomic_kind_set=atomic_kind_set, particle_set=particle_set, &
2514 : qs_kind_set=qs_kind_set, para_env=para_env, blacs_env=blacs_env, &
2515 4 : matrix_s=matrix_s, mos=mos)
2516 :
2517 4 : SELECT CASE (ex_type)
2518 : CASE (tddfpt_spin_cons)
2519 0 : lr_evals => donor_state%sc_evals
2520 0 : lr_coeffs => donor_state%sc_coeffs
2521 0 : nspins = 2
2522 0 : excite = "spincons"
2523 : CASE (tddfpt_spin_flip)
2524 0 : lr_evals => donor_state%sf_evals
2525 0 : lr_coeffs => donor_state%sf_coeffs
2526 0 : nspins = 2
2527 0 : excite = "spinflip"
2528 : CASE (tddfpt_singlet)
2529 4 : lr_evals => donor_state%sg_evals
2530 4 : lr_coeffs => donor_state%sg_coeffs
2531 4 : nspins = 1
2532 4 : excite = "singlet"
2533 : CASE (tddfpt_triplet)
2534 0 : lr_evals => donor_state%tp_evals
2535 0 : lr_coeffs => donor_state%tp_coeffs
2536 0 : nspins = 1
2537 4 : excite = "triplet"
2538 : END SELECT
2539 :
2540 8 : SELECT CASE (donor_state%state_type)
2541 : CASE (xas_1s_type)
2542 4 : domo = "1s"
2543 : CASE (xas_2s_type)
2544 0 : domo = "2s"
2545 : CASE (xas_2p_type)
2546 4 : domo = "2p"
2547 : END SELECT
2548 :
2549 4 : ndo_mo = donor_state%ndo_mo
2550 4 : ndo_so = ndo_mo*nspins
2551 4 : nmo = SIZE(lr_evals)
2552 4 : CALL dbcsr_get_info(matrix_s(1)%matrix, nfullrows_total=nao)
2553 :
2554 : CALL cp_fm_struct_create(mo_struct, context=blacs_env, para_env=para_env, &
2555 4 : nrow_global=nao, ncol_global=nmo)
2556 4 : CALL cp_fm_create(mo_coeff, mo_struct)
2557 :
2558 : !Dump the TDDFT excited state AMEW wavefunction into a file for restart in RTP
2559 4 : IF (do_wfn_restart) THEN
2560 2 : BLOCK
2561 6 : TYPE(mo_set_type), DIMENSION(2) :: restart_mos
2562 2 : IF (.NOT. (nspins == 1 .AND. donor_state%state_type == xas_1s_type)) THEN
2563 0 : CPABORT("RESTART.wfn file only available for RKS K-edge XAS spectroscopy")
2564 : END IF
2565 :
2566 2 : CALL section_vals_val_get(xas_tdp_section, "PRINT%RESTART_WFN%EXCITED_STATE_INDEX", n_rep_val=n_rep)
2567 :
2568 4 : DO irep = 1, n_rep
2569 : CALL section_vals_val_get(xas_tdp_section, "PRINT%RESTART_WFN%EXCITED_STATE_INDEX", &
2570 2 : i_rep_val=irep, i_val=ex_state_idx)
2571 2 : CPASSERT(ex_state_idx <= SIZE(lr_evals))
2572 :
2573 6 : DO ispin = 1, 2
2574 4 : CALL duplicate_mo_set(restart_mos(ispin), mos(1))
2575 : ! Set the new occupation number in the case of spin-independent based calculaltion since the restart is spin-depedent
2576 4 : IF (SIZE(mos) == 1) &
2577 26 : restart_mos(ispin)%occupation_numbers = mos(1)%occupation_numbers/2
2578 : END DO
2579 :
2580 : CALL cp_fm_to_fm_submat(msource=lr_coeffs, mtarget=restart_mos(1)%mo_coeff, nrow=nao, &
2581 : ncol=1, s_firstrow=1, s_firstcol=ex_state_idx, t_firstrow=1, &
2582 2 : t_firstcol=donor_state%mo_indices(1, 1))
2583 :
2584 : xas_mittle = 'xasat'//TRIM(ADJUSTL(cp_to_string(donor_state%at_index)))//'_'//TRIM(domo)// &
2585 2 : '_'//TRIM(excite)//'_idx'//TRIM(ADJUSTL(cp_to_string(ex_state_idx)))
2586 : output_unit = cp_print_key_unit_nr(logger, xas_tdp_section, "PRINT%RESTART_WFN", &
2587 : extension=".wfn", file_status="REPLACE", &
2588 : file_action="WRITE", file_form="UNFORMATTED", &
2589 2 : middle_name=xas_mittle)
2590 :
2591 : CALL write_mo_set_low(restart_mos, particle_set=particle_set, &
2592 2 : qs_kind_set=qs_kind_set, ires=output_unit)
2593 :
2594 2 : CALL cp_print_key_finished_output(output_unit, logger, xas_tdp_section, "PRINT%RESTART_WFN")
2595 :
2596 10 : DO ispin = 1, 2
2597 6 : CALL deallocate_mo_set(restart_mos(ispin))
2598 : END DO
2599 : END DO
2600 : END BLOCK
2601 : END IF
2602 :
2603 : !PDOS related stuff
2604 4 : IF (do_pdos) THEN
2605 :
2606 : !If S^0.5 not yet stored, compute it once and for all
2607 2 : IF (.NOT. ASSOCIATED(xas_tdp_env%matrix_shalf) .AND. do_pdos) THEN
2608 : CALL cp_fm_struct_create(fm_struct, context=blacs_env, para_env=para_env, &
2609 2 : nrow_global=nao, ncol_global=nao)
2610 2 : ALLOCATE (xas_tdp_env%matrix_shalf)
2611 2 : CALL cp_fm_create(xas_tdp_env%matrix_shalf, fm_struct)
2612 2 : CALL cp_fm_create(work_fm, fm_struct)
2613 :
2614 2 : CALL copy_dbcsr_to_fm(matrix_s(1)%matrix, xas_tdp_env%matrix_shalf)
2615 2 : CALL cp_fm_power(xas_tdp_env%matrix_shalf, work_fm, 0.5_dp, EPSILON(0.0_dp), n_dependent)
2616 :
2617 2 : CALL cp_fm_release(work_fm)
2618 2 : CALL cp_fm_struct_release(fm_struct)
2619 : END IF
2620 :
2621 : !Giving some PDOS info
2622 2 : output_unit = cp_logger_get_default_io_unit()
2623 2 : IF (output_unit > 0) THEN
2624 : WRITE (UNIT=output_unit, FMT="(/,T5,A,/,T5,A,/,T5,A)") &
2625 1 : "Computing the PDOS of linear-response orbitals for spectral features analysis", &
2626 1 : "Note: using standard PDOS routines => ignore mentions of KS states and MO ", &
2627 2 : " occupation numbers. Eigenvalues in *.pdos files are excitations energies."
2628 : END IF
2629 :
2630 : !Check on NLUMO
2631 2 : CALL section_vals_val_get(xas_tdp_section, "PRINT%PDOS%NLUMO", i_val=nlumo)
2632 2 : IF (nlumo .NE. 0) THEN
2633 0 : CPWARN("NLUMO is irrelevant for XAS_TDP PDOS. It was overwritten to 0.")
2634 : END IF
2635 2 : CALL section_vals_val_set(xas_tdp_section, "PRINT%PDOS%NLUMO", i_val=0)
2636 : END IF
2637 :
2638 : !CUBES related stuff
2639 4 : IF (do_cubes) THEN
2640 :
2641 2 : print_key => section_vals_get_subs_vals(xas_tdp_section, "PRINT%CUBES")
2642 :
2643 2 : CALL section_vals_val_get(print_key, "CUBES_LU_BOUNDS", i_vals=bounds)
2644 2 : ncubes = bounds(2) - bounds(1) + 1
2645 2 : IF (ncubes > 0) THEN
2646 0 : ALLOCATE (state_list(ncubes))
2647 0 : DO ic = 1, ncubes
2648 0 : state_list(ic) = bounds(1) + ic - 1
2649 : END DO
2650 : END IF
2651 :
2652 2 : IF (.NOT. ASSOCIATED(state_list)) THEN
2653 2 : CALL section_vals_val_get(print_key, "CUBES_LIST", n_rep_val=n_rep)
2654 :
2655 2 : ncubes = 0
2656 4 : DO irep = 1, n_rep
2657 2 : NULLIFY (list)
2658 2 : CALL section_vals_val_get(print_key, "CUBES_LIST", i_rep_val=irep, i_vals=list)
2659 4 : IF (ASSOCIATED(list)) THEN
2660 2 : CALL reallocate(state_list, 1, ncubes + SIZE(list))
2661 4 : DO ic = 1, SIZE(list)
2662 4 : state_list(ncubes + ic) = list(ic)
2663 : END DO
2664 2 : ncubes = ncubes + SIZE(list)
2665 : END IF
2666 : END DO
2667 : END IF
2668 :
2669 2 : IF (.NOT. ASSOCIATED(state_list)) THEN
2670 0 : ncubes = 1
2671 0 : ALLOCATE (state_list(1))
2672 0 : state_list(1) = 1
2673 : END IF
2674 :
2675 2 : CALL section_vals_val_get(print_key, "APPEND", l_val=append_cube)
2676 2 : pos = "REWIND"
2677 2 : IF (append_cube) pos = "APPEND"
2678 :
2679 6 : ALLOCATE (centers(6, ncubes))
2680 18 : centers = 0.0_dp
2681 :
2682 : END IF
2683 :
2684 : !Loop over MOs and spin, one PDOS/CUBE for each
2685 8 : DO ido_mo = 1, ndo_mo
2686 12 : DO ispin = 1, nspins
2687 :
2688 : !need to create a mo set for the LR-orbitals
2689 4 : ALLOCATE (mo_set)
2690 : CALL allocate_mo_set(mo_set, nao=nao, nmo=nmo, nelectron=nmo, n_el_f=REAL(nmo, dp), &
2691 4 : maxocc=1.0_dp, flexible_electron_count=0.0_dp)
2692 4 : CALL init_mo_set(mo_set, fm_ref=mo_coeff, name="PDOS XAS_TDP MOs")
2693 156 : mo_set%eigenvalues(:) = lr_evals(:)
2694 :
2695 : !get the actual coeff => most common case: closed-shell K-edge, can directly take lr_coeffs
2696 4 : IF (nspins == 1 .AND. ndo_mo == 1) THEN
2697 4 : CALL cp_fm_to_fm(lr_coeffs, mo_set%mo_coeff)
2698 : ELSE
2699 0 : DO imo = 1, nmo
2700 : CALL cp_fm_to_fm_submat(msource=lr_coeffs, mtarget=mo_set%mo_coeff, &
2701 : nrow=nao, ncol=1, s_firstrow=1, &
2702 : s_firstcol=(imo - 1)*ndo_so + (ispin - 1)*ndo_mo + ido_mo, &
2703 0 : t_firstrow=1, t_firstcol=imo)
2704 : END DO
2705 : END IF
2706 :
2707 : !naming the output
2708 4 : domon = domo
2709 4 : IF (donor_state%state_type == xas_2p_type) domon = TRIM(domo)//TRIM(ADJUSTL(cp_to_string(ido_mo)))
2710 : xas_mittle = 'xasat'//TRIM(ADJUSTL(cp_to_string(donor_state%at_index)))//'_'// &
2711 4 : TRIM(domon)//'_'//TRIM(excite)
2712 :
2713 4 : IF (do_pdos) THEN
2714 : CALL calculate_projected_dos(mo_set, atomic_kind_set, qs_kind_set, particle_set, &
2715 : qs_env, xas_tdp_section, ispin, xas_mittle, &
2716 2 : external_matrix_shalf=xas_tdp_env%matrix_shalf)
2717 : END IF
2718 :
2719 4 : IF (do_cubes) THEN
2720 : CALL qs_print_cubes(qs_env, mo_set%mo_coeff, ncubes, state_list, centers, &
2721 : print_key=print_key, root=xas_mittle, ispin=ispin, &
2722 2 : file_position=pos)
2723 : END IF
2724 :
2725 : !clean-up
2726 4 : CALL deallocate_mo_set(mo_set)
2727 8 : DEALLOCATE (mo_set)
2728 :
2729 : END DO
2730 : END DO
2731 :
2732 : !clean-up
2733 4 : CALL cp_fm_release(mo_coeff)
2734 4 : CALL cp_fm_struct_release(mo_struct)
2735 4 : IF (do_cubes) DEALLOCATE (centers, state_list)
2736 :
2737 4 : CALL timestop(handle)
2738 :
2739 62 : END SUBROUTINE xas_tdp_post
2740 :
2741 : ! **************************************************************************************************
2742 : !> \brief Computed the LUMOs for the OT eigensolver guesses
2743 : !> \param xas_tdp_env ...
2744 : !> \param xas_tdp_control ...
2745 : !> \param qs_env ...
2746 : !> \note Uses stendard diagonalization. Do not use the stendard make_lumo subroutine as it uses
2747 : !> the OT eigensolver and there is no guarantee that it will converge fast
2748 : ! **************************************************************************************************
2749 20 : SUBROUTINE make_lumo_guess(xas_tdp_env, xas_tdp_control, qs_env)
2750 :
2751 : TYPE(xas_tdp_env_type), POINTER :: xas_tdp_env
2752 : TYPE(xas_tdp_control_type), POINTER :: xas_tdp_control
2753 : TYPE(qs_environment_type), POINTER :: qs_env
2754 :
2755 : CHARACTER(len=*), PARAMETER :: routineN = 'make_lumo_guess'
2756 :
2757 : INTEGER :: handle, ispin, nao, nelec_spin(2), &
2758 : nlumo(2), nocc(2), nspins
2759 : LOGICAL :: do_os
2760 20 : REAL(dp), ALLOCATABLE, DIMENSION(:) :: evals
2761 : TYPE(cp_blacs_env_type), POINTER :: blacs_env
2762 : TYPE(cp_fm_struct_type), POINTER :: fm_struct, lumo_struct
2763 : TYPE(cp_fm_type) :: amatrix, bmatrix, evecs, work_fm
2764 20 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_ks, matrix_s
2765 : TYPE(mp_para_env_type), POINTER :: para_env
2766 :
2767 20 : NULLIFY (matrix_ks, matrix_s, para_env, blacs_env)
2768 20 : NULLIFY (lumo_struct, fm_struct)
2769 :
2770 20 : CALL timeset(routineN, handle)
2771 :
2772 20 : do_os = xas_tdp_control%do_uks .OR. xas_tdp_control%do_roks
2773 2 : nspins = 1; IF (do_os) nspins = 2
2774 62 : ALLOCATE (xas_tdp_env%lumo_evecs(nspins))
2775 62 : ALLOCATE (xas_tdp_env%lumo_evals(nspins))
2776 : CALL get_qs_env(qs_env, matrix_ks=matrix_ks, matrix_s=matrix_s, nelectron_spin=nelec_spin, &
2777 20 : para_env=para_env, blacs_env=blacs_env)
2778 20 : CALL dbcsr_get_info(matrix_s(1)%matrix, nfullrows_total=nao)
2779 :
2780 20 : IF (do_os) THEN
2781 6 : nlumo = nao - nelec_spin
2782 2 : nocc = nelec_spin
2783 : ELSE
2784 54 : nlumo = nao - nelec_spin(1)/2
2785 54 : nocc = nelec_spin(1)/2
2786 : END IF
2787 :
2788 62 : ALLOCATE (xas_tdp_env%ot_prec(nspins))
2789 :
2790 42 : DO ispin = 1, nspins
2791 :
2792 : !Going through fm to diagonalize
2793 : CALL cp_fm_struct_create(fm_struct, para_env=para_env, context=blacs_env, &
2794 22 : nrow_global=nao, ncol_global=nao)
2795 22 : CALL cp_fm_create(amatrix, fm_struct)
2796 22 : CALL cp_fm_create(bmatrix, fm_struct)
2797 22 : CALL cp_fm_create(evecs, fm_struct)
2798 22 : CALL cp_fm_create(work_fm, fm_struct)
2799 66 : ALLOCATE (evals(nao))
2800 66 : ALLOCATE (xas_tdp_env%lumo_evals(ispin)%array(nlumo(ispin)))
2801 :
2802 22 : CALL copy_dbcsr_to_fm(matrix_ks(ispin)%matrix, amatrix)
2803 22 : CALL copy_dbcsr_to_fm(matrix_s(1)%matrix, bmatrix)
2804 :
2805 : !The actual diagonalization through Cholesky decomposition
2806 22 : CALL cp_fm_geeig(amatrix, bmatrix, evecs, evals, work_fm)
2807 :
2808 : !Storing results
2809 : CALL cp_fm_struct_create(lumo_struct, para_env=para_env, context=blacs_env, &
2810 22 : nrow_global=nao, ncol_global=nlumo(ispin))
2811 22 : CALL cp_fm_create(xas_tdp_env%lumo_evecs(ispin), lumo_struct)
2812 :
2813 : CALL cp_fm_to_fm_submat(evecs, xas_tdp_env%lumo_evecs(ispin), nrow=nao, &
2814 : ncol=nlumo(ispin), s_firstrow=1, s_firstcol=nocc(ispin) + 1, &
2815 22 : t_firstrow=1, t_firstcol=1)
2816 :
2817 1098 : xas_tdp_env%lumo_evals(ispin)%array(1:nlumo(ispin)) = evals(nocc(ispin) + 1:nao)
2818 :
2819 22 : CALL build_ot_spin_prec(evecs, evals, ispin, xas_tdp_env, xas_tdp_control, qs_env)
2820 :
2821 : !clean-up
2822 22 : CALL cp_fm_release(amatrix)
2823 22 : CALL cp_fm_release(bmatrix)
2824 22 : CALL cp_fm_release(evecs)
2825 22 : CALL cp_fm_release(work_fm)
2826 22 : CALL cp_fm_struct_release(fm_struct)
2827 22 : CALL cp_fm_struct_release(lumo_struct)
2828 64 : DEALLOCATE (evals)
2829 : END DO
2830 :
2831 20 : CALL timestop(handle)
2832 :
2833 60 : END SUBROUTINE make_lumo_guess
2834 :
2835 : ! **************************************************************************************************
2836 : !> \brief Builds a preconditioner for the OT eigensolver, based on some heurstics that prioritize
2837 : !> LUMOs with lower eigenvalues
2838 : !> \param evecs all the ground state eigenvectors
2839 : !> \param evals all the ground state eigenvalues
2840 : !> \param ispin ...
2841 : !> \param xas_tdp_env ...
2842 : !> \param xas_tdp_control ...
2843 : !> \param qs_env ...
2844 : !> \note assumes that the preconditioner matrix array is allocated
2845 : ! **************************************************************************************************
2846 22 : SUBROUTINE build_ot_spin_prec(evecs, evals, ispin, xas_tdp_env, xas_tdp_control, qs_env)
2847 :
2848 : TYPE(cp_fm_type), INTENT(IN) :: evecs
2849 : REAL(dp), DIMENSION(:) :: evals
2850 : INTEGER :: ispin
2851 : TYPE(xas_tdp_env_type), POINTER :: xas_tdp_env
2852 : TYPE(xas_tdp_control_type), POINTER :: xas_tdp_control
2853 : TYPE(qs_environment_type), POINTER :: qs_env
2854 :
2855 : CHARACTER(len=*), PARAMETER :: routineN = 'build_ot_spin_prec'
2856 :
2857 : INTEGER :: handle, nao, nelec_spin(2), nguess, &
2858 : nocc, nspins
2859 : LOGICAL :: do_os
2860 : REAL(dp) :: shift
2861 : REAL(dp), ALLOCATABLE, DIMENSION(:) :: scaling
2862 : TYPE(cp_fm_struct_type), POINTER :: fm_struct
2863 : TYPE(cp_fm_type) :: fm_prec, work_fm
2864 22 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_s
2865 : TYPE(mp_para_env_type), POINTER :: para_env
2866 :
2867 22 : NULLIFY (fm_struct, para_env, matrix_s)
2868 :
2869 22 : CALL timeset(routineN, handle)
2870 :
2871 22 : do_os = xas_tdp_control%do_uks .OR. xas_tdp_control%do_roks
2872 22 : CALL get_qs_env(qs_env, para_env=para_env, nelectron_spin=nelec_spin, matrix_s=matrix_s)
2873 22 : CALL cp_fm_get_info(evecs, nrow_global=nao, matrix_struct=fm_struct)
2874 22 : CALL cp_fm_create(fm_prec, fm_struct)
2875 66 : ALLOCATE (scaling(nao))
2876 22 : nocc = nelec_spin(1)/2
2877 22 : nspins = 1
2878 22 : IF (do_os) THEN
2879 4 : nocc = nelec_spin(ispin)
2880 4 : nspins = 2
2881 : END IF
2882 :
2883 : !rough estimate of the number of required evals
2884 22 : nguess = nao - nocc
2885 22 : IF (xas_tdp_control%n_excited > 0 .AND. xas_tdp_control%n_excited < nguess) THEN
2886 4 : nguess = xas_tdp_control%n_excited/nspins
2887 18 : ELSE IF (xas_tdp_control%e_range > 0.0_dp) THEN
2888 514 : nguess = COUNT(evals(nocc + 1:nao) - evals(nocc + 1) .LE. xas_tdp_control%e_range)
2889 : END IF
2890 :
2891 : !Give max weight to the first LUMOs
2892 540 : scaling(nocc + 1:nocc + nguess) = 100.0_dp
2893 : !Then gradually decrease weight
2894 22 : shift = evals(nocc + 1) - 0.01_dp
2895 602 : scaling(nocc + nguess:nao) = 1.0_dp/(evals(nocc + nguess:nao) - shift)
2896 : !HOMOs do not matter, but need well behaved matrix
2897 616 : scaling(1:nocc) = 1.0_dp
2898 :
2899 : !Building the precond as an fm
2900 22 : CALL cp_fm_create(work_fm, fm_struct)
2901 :
2902 22 : CALL cp_fm_copy_general(evecs, work_fm, para_env)
2903 22 : CALL cp_fm_column_scale(work_fm, scaling)
2904 :
2905 22 : CALL parallel_gemm('N', 'T', nao, nao, nao, 1.0_dp, work_fm, evecs, 0.0_dp, fm_prec)
2906 :
2907 : !Copy into dbcsr format
2908 22 : ALLOCATE (xas_tdp_env%ot_prec(ispin)%matrix)
2909 22 : CALL dbcsr_create(xas_tdp_env%ot_prec(ispin)%matrix, template=matrix_s(1)%matrix, name="OT_PREC")
2910 22 : CALL copy_fm_to_dbcsr(fm_prec, xas_tdp_env%ot_prec(ispin)%matrix)
2911 22 : CALL dbcsr_filter(xas_tdp_env%ot_prec(ispin)%matrix, xas_tdp_control%eps_filter)
2912 :
2913 22 : CALL cp_fm_release(work_fm)
2914 22 : CALL cp_fm_release(fm_prec)
2915 :
2916 22 : CALL timestop(handle)
2917 :
2918 88 : END SUBROUTINE build_ot_spin_prec
2919 :
2920 : ! **************************************************************************************************
2921 : !> \brief Prints GW2X corrected ionization potentials to main output file, including SOC splitting
2922 : !> \param donor_state ...
2923 : !> \param xas_tdp_env ...
2924 : !> \param xas_tdp_control ...
2925 : !> \param qs_env ...
2926 : ! **************************************************************************************************
2927 30 : SUBROUTINE print_xps(donor_state, xas_tdp_env, xas_tdp_control, qs_env)
2928 :
2929 : TYPE(donor_state_type), POINTER :: donor_state
2930 : TYPE(xas_tdp_env_type), POINTER :: xas_tdp_env
2931 : TYPE(xas_tdp_control_type), POINTER :: xas_tdp_control
2932 : TYPE(qs_environment_type), POINTER :: qs_env
2933 :
2934 : INTEGER :: ido_mo, ispin, nspins, output_unit
2935 30 : REAL(dp), ALLOCATABLE, DIMENSION(:, :) :: IPs, soc_shifts
2936 :
2937 30 : output_unit = cp_logger_get_default_io_unit()
2938 :
2939 30 : nspins = 1; IF (xas_tdp_control%do_uks .OR. xas_tdp_control%do_roks) nspins = 2
2940 :
2941 120 : ALLOCATE (IPs(SIZE(donor_state%gw2x_evals, 1), SIZE(donor_state%gw2x_evals, 2)))
2942 106 : IPs(:, :) = donor_state%gw2x_evals(:, :)
2943 :
2944 : !IPs in PBCs cannot be trusted because of a lack of a potential reference
2945 30 : IF (.NOT. xas_tdp_control%is_periodic) THEN
2946 :
2947 : !Apply SOC splitting
2948 26 : IF (donor_state%ndo_mo > 1) THEN
2949 : CALL get_soc_splitting(soc_shifts, donor_state, xas_tdp_env, xas_tdp_control, qs_env)
2950 20 : IPs(:, :) = IPs(:, :) + soc_shifts
2951 :
2952 4 : IF (output_unit > 0) THEN
2953 : WRITE (output_unit, FMT="(/,T5,A,F23.6)") &
2954 2 : "Ionization potentials for XPS (GW2X + SOC): ", -IPs(1, 1)*evolt
2955 :
2956 4 : DO ispin = 1, nspins
2957 10 : DO ido_mo = 1, donor_state%ndo_mo
2958 :
2959 6 : IF (ispin == 1 .AND. ido_mo == 1) CYCLE
2960 :
2961 : WRITE (output_unit, FMT="(T5,A,F23.6)") &
2962 8 : " ", -IPs(ido_mo, ispin)*evolt
2963 :
2964 : END DO
2965 : END DO
2966 : END IF
2967 :
2968 : ELSE
2969 :
2970 : ! No SOC, only 1 donor MO per spin
2971 22 : IF (output_unit > 0) THEN
2972 : WRITE (output_unit, FMT="(/,T5,A,F29.6)") &
2973 11 : "Ionization potentials for XPS (GW2X): ", -IPs(1, 1)*evolt
2974 :
2975 11 : IF (nspins == 2) THEN
2976 : WRITE (output_unit, FMT="(T5,A,F29.6)") &
2977 2 : " ", -IPs(1, 2)*evolt
2978 : END IF
2979 : END IF
2980 :
2981 : END IF
2982 : END IF
2983 :
2984 30 : END SUBROUTINE print_xps
2985 :
2986 : ! **************************************************************************************************
2987 : !> \brief Prints the excitation energies and the oscillator strengths for a given donor_state in a file
2988 : !> \param donor_state the donor_state to print
2989 : !> \param xas_tdp_env ...
2990 : !> \param xas_tdp_control ...
2991 : !> \param xas_tdp_section ...
2992 : ! **************************************************************************************************
2993 56 : SUBROUTINE print_xas_tdp_to_file(donor_state, xas_tdp_env, xas_tdp_control, xas_tdp_section)
2994 :
2995 : TYPE(donor_state_type), POINTER :: donor_state
2996 : TYPE(xas_tdp_env_type), POINTER :: xas_tdp_env
2997 : TYPE(xas_tdp_control_type), POINTER :: xas_tdp_control
2998 : TYPE(section_vals_type), POINTER :: xas_tdp_section
2999 :
3000 : INTEGER :: i, output_unit, xas_tdp_unit
3001 : TYPE(cp_logger_type), POINTER :: logger
3002 :
3003 56 : NULLIFY (logger)
3004 56 : logger => cp_get_default_logger()
3005 :
3006 : xas_tdp_unit = cp_print_key_unit_nr(logger, xas_tdp_section, "PRINT%SPECTRUM", &
3007 : extension=".spectrum", file_position="APPEND", &
3008 56 : file_action="WRITE", file_form="FORMATTED")
3009 :
3010 56 : output_unit = cp_logger_get_default_io_unit()
3011 :
3012 56 : IF (output_unit > 0) THEN
3013 : WRITE (output_unit, FMT="(/,T5,A,/)") &
3014 28 : "Calculations done: "
3015 : END IF
3016 :
3017 56 : IF (xas_tdp_control%do_spin_cons) THEN
3018 8 : IF (xas_tdp_unit > 0) THEN
3019 :
3020 : ! Printing the general donor state information
3021 : WRITE (xas_tdp_unit, FMT="(A,/,A,A,A/,A,I5,A,I5,A,A,/,A)") &
3022 4 : "==================================================================================", &
3023 4 : "XAS TDP open-shell spin-conserving (no SOC) excitations for DONOR STATE: ", &
3024 4 : xas_tdp_env%state_type_char(donor_state%state_type), ",", &
3025 4 : "from EXCITED ATOM: ", donor_state%at_index, ", of KIND (index/symbol): ", &
3026 4 : donor_state%kind_index, "/", TRIM(donor_state%at_symbol), &
3027 8 : "=================================================================================="
3028 :
3029 : ! Simply dump the excitation energies/ oscillator strength as they come
3030 :
3031 4 : IF (xas_tdp_control%do_quad) THEN
3032 : WRITE (xas_tdp_unit, FMT="(T3,A)") &
3033 0 : " Index Excitation energy (eV) fosc dipole (a.u.) fosc quadrupole (a.u.)"
3034 0 : DO i = 1, SIZE(donor_state%sc_evals)
3035 : WRITE (xas_tdp_unit, FMT="(T3,I6,F27.6,F22.6,F25.6)") &
3036 0 : i, donor_state%sc_evals(i)*evolt, donor_state%osc_str(i, 4), &
3037 0 : donor_state%quad_osc_str(i)
3038 : END DO
3039 4 : ELSE IF (xas_tdp_control%xyz_dip) THEN
3040 : WRITE (xas_tdp_unit, FMT="(T3,A)") &
3041 0 : " Index Excitation energy (eV) fosc dipole (a.u.) x-component y-component z-component"
3042 0 : DO i = 1, SIZE(donor_state%sc_evals)
3043 : WRITE (xas_tdp_unit, FMT="(T3,I6,F27.6,F22.6,F14.6,F14.6,F14.6)") &
3044 0 : i, donor_state%sc_evals(i)*evolt, donor_state%osc_str(i, 4), &
3045 0 : donor_state%osc_str(i, 1), donor_state%osc_str(i, 2), donor_state%osc_str(i, 3)
3046 : END DO
3047 : ELSE
3048 : WRITE (xas_tdp_unit, FMT="(T3,A)") &
3049 4 : " Index Excitation energy (eV) fosc dipole (a.u.)"
3050 108 : DO i = 1, SIZE(donor_state%sc_evals)
3051 : WRITE (xas_tdp_unit, FMT="(T3,I6,F27.6,F22.6)") &
3052 108 : i, donor_state%sc_evals(i)*evolt, donor_state%osc_str(i, 4)
3053 : END DO
3054 : END IF
3055 :
3056 4 : WRITE (xas_tdp_unit, FMT="(A,/)") " "
3057 : END IF !xas_tdp_unit > 0
3058 :
3059 8 : IF (output_unit > 0) THEN
3060 : WRITE (output_unit, FMT="(T5,A,F17.6)") &
3061 4 : "First spin-conserving XAS excitation energy (eV): ", donor_state%sc_evals(1)*evolt
3062 : END IF
3063 :
3064 : END IF ! do_spin_cons
3065 :
3066 56 : IF (xas_tdp_control%do_spin_flip) THEN
3067 2 : IF (xas_tdp_unit > 0) THEN
3068 :
3069 : ! Printing the general donor state information
3070 : WRITE (xas_tdp_unit, FMT="(A,/,A,A,A/,A,I5,A,I5,A,A,/,A)") &
3071 1 : "==================================================================================", &
3072 1 : "XAS TDP open-shell spin-flip (no SOC) excitations for DONOR STATE: ", &
3073 1 : xas_tdp_env%state_type_char(donor_state%state_type), ",", &
3074 1 : "from EXCITED ATOM: ", donor_state%at_index, ", of KIND (index/symbol): ", &
3075 1 : donor_state%kind_index, "/", TRIM(donor_state%at_symbol), &
3076 2 : "=================================================================================="
3077 :
3078 : ! Simply dump the excitation energies/ oscillator strength as they come
3079 :
3080 1 : IF (xas_tdp_control%do_quad) THEN
3081 : WRITE (xas_tdp_unit, FMT="(T3,A)") &
3082 0 : " Index Excitation energy (eV) fosc dipole (a.u.) fosc quadrupole (a.u.)"
3083 0 : DO i = 1, SIZE(donor_state%sf_evals)
3084 : WRITE (xas_tdp_unit, FMT="(T3,I6,F27.6,F22.6,F25.6)") &
3085 0 : i, donor_state%sf_evals(i)*evolt, 0.0_dp, 0.0_dp !spin-forbidden !
3086 : END DO
3087 1 : ELSE IF (xas_tdp_control%xyz_dip) THEN
3088 : WRITE (xas_tdp_unit, FMT="(T3,A)") &
3089 0 : " Index Excitation energy (eV) fosc dipole (a.u.) x-component y-component z-component"
3090 0 : DO i = 1, SIZE(donor_state%sf_evals)
3091 : WRITE (xas_tdp_unit, FMT="(T3,I6,F27.6,F22.6,F14.6,F14.6,F14.6)") &
3092 0 : i, donor_state%sf_evals(i)*evolt, 0.0_dp, 0.0_dp, 0.0_dp, 0.0_dp
3093 : END DO
3094 : ELSE
3095 : WRITE (xas_tdp_unit, FMT="(T3,A)") &
3096 1 : " Index Excitation energy (eV) fosc dipole (a.u.)"
3097 13 : DO i = 1, SIZE(donor_state%sf_evals)
3098 : WRITE (xas_tdp_unit, FMT="(T3,I6,F27.6,F22.6)") &
3099 13 : i, donor_state%sf_evals(i)*evolt, 0.0_dp
3100 : END DO
3101 : END IF
3102 :
3103 1 : WRITE (xas_tdp_unit, FMT="(A,/)") " "
3104 : END IF !xas_tdp_unit
3105 :
3106 2 : IF (output_unit > 0) THEN
3107 : WRITE (output_unit, FMT="(T5,A,F23.6)") &
3108 1 : "First spin-flip XAS excitation energy (eV): ", donor_state%sf_evals(1)*evolt
3109 : END IF
3110 : END IF ! do_spin_flip
3111 :
3112 56 : IF (xas_tdp_control%do_singlet) THEN
3113 48 : IF (xas_tdp_unit > 0) THEN
3114 :
3115 : ! Printing the general donor state information
3116 : WRITE (xas_tdp_unit, FMT="(A,/,A,A,A/,A,I5,A,I5,A,A,/,A)") &
3117 24 : "==================================================================================", &
3118 24 : "XAS TDP singlet excitations (no SOC) for DONOR STATE: ", &
3119 24 : xas_tdp_env%state_type_char(donor_state%state_type), ",", &
3120 24 : "from EXCITED ATOM: ", donor_state%at_index, ", of KIND (index/symbol): ", &
3121 24 : donor_state%kind_index, "/", TRIM(donor_state%at_symbol), &
3122 48 : "=================================================================================="
3123 :
3124 : ! Simply dump the excitation energies/ oscillator strength as they come
3125 :
3126 24 : IF (xas_tdp_control%do_quad) THEN
3127 : WRITE (xas_tdp_unit, FMT="(T3,A)") &
3128 0 : " Index Excitation energy (eV) fosc dipole (a.u.) fosc quadrupole (a.u.)"
3129 0 : DO i = 1, SIZE(donor_state%sg_evals)
3130 : WRITE (xas_tdp_unit, FMT="(T3,I6,F27.6,F22.6,F25.6)") &
3131 0 : i, donor_state%sg_evals(i)*evolt, donor_state%osc_str(i, 4), &
3132 0 : donor_state%quad_osc_str(i)
3133 : END DO
3134 24 : ELSE IF (xas_tdp_control%xyz_dip) THEN
3135 : WRITE (xas_tdp_unit, FMT="(T3,A)") &
3136 0 : " Index Excitation energy (eV) fosc dipole (a.u.) x-component y-component z-component"
3137 0 : DO i = 1, SIZE(donor_state%sg_evals)
3138 : WRITE (xas_tdp_unit, FMT="(T3,I6,F27.6,F22.6,F14.6,F14.6,F14.6)") &
3139 0 : i, donor_state%sg_evals(i)*evolt, donor_state%osc_str(i, 4), &
3140 0 : donor_state%osc_str(i, 1), donor_state%osc_str(i, 2), donor_state%osc_str(i, 3)
3141 : END DO
3142 : ELSE
3143 : WRITE (xas_tdp_unit, FMT="(T3,A)") &
3144 24 : " Index Excitation energy (eV) fosc dipole (a.u.)"
3145 348 : DO i = 1, SIZE(donor_state%sg_evals)
3146 : WRITE (xas_tdp_unit, FMT="(T3,I6,F27.6,F22.6)") &
3147 348 : i, donor_state%sg_evals(i)*evolt, donor_state%osc_str(i, 4)
3148 : END DO
3149 : END IF
3150 :
3151 24 : WRITE (xas_tdp_unit, FMT="(A,/)") " "
3152 : END IF !xas_tdp_unit
3153 :
3154 48 : IF (output_unit > 0) THEN
3155 : WRITE (output_unit, FMT="(T5,A,F25.6)") &
3156 24 : "First singlet XAS excitation energy (eV): ", donor_state%sg_evals(1)*evolt
3157 : END IF
3158 : END IF ! do_singlet
3159 :
3160 56 : IF (xas_tdp_control%do_triplet) THEN
3161 2 : IF (xas_tdp_unit > 0) THEN
3162 :
3163 : ! Printing the general donor state information
3164 : WRITE (xas_tdp_unit, FMT="(A,/,A,A,A/,A,I5,A,I5,A,A,/,A)") &
3165 1 : "==================================================================================", &
3166 1 : "XAS TDP triplet excitations (no SOC) for DONOR STATE: ", &
3167 1 : xas_tdp_env%state_type_char(donor_state%state_type), ",", &
3168 1 : "from EXCITED ATOM: ", donor_state%at_index, ", of KIND (index/symbol): ", &
3169 1 : donor_state%kind_index, "/", TRIM(donor_state%at_symbol), &
3170 2 : "=================================================================================="
3171 :
3172 : ! Simply dump the excitation energies/ oscillator strength as they come
3173 :
3174 1 : IF (xas_tdp_control%do_quad) THEN
3175 : WRITE (xas_tdp_unit, FMT="(T3,A)") &
3176 0 : " Index Excitation energy (eV) fosc dipole (a.u.) fosc quadrupole (a.u.)"
3177 0 : DO i = 1, SIZE(donor_state%tp_evals)
3178 : WRITE (xas_tdp_unit, FMT="(T3,I6,F27.6,F22.6,F25.6)") &
3179 0 : i, donor_state%tp_evals(i)*evolt, 0.0_dp, 0.0_dp !spin-forbidden !
3180 : END DO
3181 1 : ELSE IF (xas_tdp_control%xyz_dip) THEN
3182 : WRITE (xas_tdp_unit, FMT="(T3,A)") &
3183 0 : " Index Excitation energy (eV) fosc dipole (a.u.) x-component y-component z-component"
3184 0 : DO i = 1, SIZE(donor_state%tp_evals)
3185 : WRITE (xas_tdp_unit, FMT="(T3,I6,F27.6,F22.6,F14.6,F14.6,F14.6)") &
3186 0 : i, donor_state%tp_evals(i)*evolt, 0.0_dp, 0.0_dp, 0.0_dp, 0.0_dp
3187 : END DO
3188 : ELSE
3189 : WRITE (xas_tdp_unit, FMT="(T3,A)") &
3190 1 : " Index Excitation energy (eV) fosc dipole (a.u.)"
3191 13 : DO i = 1, SIZE(donor_state%tp_evals)
3192 : WRITE (xas_tdp_unit, FMT="(T3,I6,F27.6,F22.6)") &
3193 13 : i, donor_state%tp_evals(i)*evolt, 0.0_dp
3194 : END DO
3195 : END IF
3196 :
3197 1 : WRITE (xas_tdp_unit, FMT="(A,/)") " "
3198 : END IF !xas_tdp_unit
3199 :
3200 2 : IF (output_unit > 0) THEN
3201 : WRITE (output_unit, FMT="(T5,A,F25.6)") &
3202 1 : "First triplet XAS excitation energy (eV): ", donor_state%tp_evals(1)*evolt
3203 : END IF
3204 : END IF ! do_triplet
3205 :
3206 56 : IF (xas_tdp_control%do_soc .AND. donor_state%state_type == xas_2p_type) THEN
3207 4 : IF (xas_tdp_unit > 0) THEN
3208 :
3209 : ! Printing the general donor state information
3210 : WRITE (xas_tdp_unit, FMT="(A,/,A,A,A/,A,I5,A,I5,A,A,/,A)") &
3211 2 : "==================================================================================", &
3212 2 : "XAS TDP excitations after spin-orbit coupling for DONOR STATE: ", &
3213 2 : xas_tdp_env%state_type_char(donor_state%state_type), ",", &
3214 2 : "from EXCITED ATOM: ", donor_state%at_index, ", of KIND (index/symbol): ", &
3215 2 : donor_state%kind_index, "/", TRIM(donor_state%at_symbol), &
3216 4 : "=================================================================================="
3217 :
3218 : ! Simply dump the excitation energies/ oscillator strength as they come
3219 2 : IF (xas_tdp_control%do_quad) THEN
3220 : WRITE (xas_tdp_unit, FMT="(T3,A)") &
3221 0 : " Index Excitation energy (eV) fosc dipole (a.u.) fosc quadrupole (a.u.)"
3222 0 : DO i = 1, SIZE(donor_state%soc_evals)
3223 : WRITE (xas_tdp_unit, FMT="(T3,I6,F27.6,F22.6,F25.6)") &
3224 0 : i, donor_state%soc_evals(i)*evolt, donor_state%soc_osc_str(i, 4), &
3225 0 : donor_state%soc_quad_osc_str(i)
3226 : END DO
3227 2 : ELSE IF (xas_tdp_control%xyz_dip) THEN
3228 : WRITE (xas_tdp_unit, FMT="(T3,A)") &
3229 0 : " Index Excitation energy (eV) fosc dipole (a.u.) x-component y-component z-component"
3230 0 : DO i = 1, SIZE(donor_state%soc_evals)
3231 : WRITE (xas_tdp_unit, FMT="(T3,I6,F27.6,F22.6,F14.6,F14.6,F14.6)") &
3232 0 : i, donor_state%soc_evals(i)*evolt, donor_state%soc_osc_str(i, 4), &
3233 0 : donor_state%soc_osc_str(i, 1), donor_state%soc_osc_str(i, 2), donor_state%soc_osc_str(i, 3)
3234 : END DO
3235 : ELSE
3236 : WRITE (xas_tdp_unit, FMT="(T3,A)") &
3237 2 : " Index Excitation energy (eV) fosc dipole (a.u.)"
3238 74 : DO i = 1, SIZE(donor_state%soc_evals)
3239 : WRITE (xas_tdp_unit, FMT="(T3,I6,F27.6,F22.6)") &
3240 74 : i, donor_state%soc_evals(i)*evolt, donor_state%soc_osc_str(i, 4)
3241 : END DO
3242 : END IF
3243 :
3244 2 : WRITE (xas_tdp_unit, FMT="(A,/)") " "
3245 : END IF !xas_tdp_unit
3246 :
3247 4 : IF (output_unit > 0) THEN
3248 : WRITE (output_unit, FMT="(T5,A,F29.6)") &
3249 2 : "First SOC XAS excitation energy (eV): ", donor_state%soc_evals(1)*evolt
3250 : END IF
3251 : END IF !do_soc
3252 :
3253 56 : CALL cp_print_key_finished_output(xas_tdp_unit, logger, xas_tdp_section, "PRINT%SPECTRUM")
3254 :
3255 56 : END SUBROUTINE print_xas_tdp_to_file
3256 :
3257 : ! **************************************************************************************************
3258 : !> \brief Prints the donor_state and excitation_type info into a RESTART file for cheap PDOS and/or
3259 : !> CUBE printing without expensive computation
3260 : !> \param ex_type singlet, triplet, etc.
3261 : !> \param donor_state ...
3262 : !> \param xas_tdp_section ...
3263 : !> \param qs_env ...
3264 : ! **************************************************************************************************
3265 64 : SUBROUTINE write_donor_state_restart(ex_type, donor_state, xas_tdp_section, qs_env)
3266 :
3267 : INTEGER, INTENT(IN) :: ex_type
3268 : TYPE(donor_state_type), POINTER :: donor_state
3269 : TYPE(section_vals_type), POINTER :: xas_tdp_section
3270 : TYPE(qs_environment_type), POINTER :: qs_env
3271 :
3272 : CHARACTER(len=*), PARAMETER :: routineN = 'write_donor_state_restart'
3273 :
3274 : CHARACTER(len=default_path_length) :: filename
3275 : CHARACTER(len=default_string_length) :: domo, excite, my_middle
3276 : INTEGER :: ex_atom, handle, ispin, nao, ndo_mo, &
3277 : nex, nspins, output_unit, rst_unit, &
3278 : state_type
3279 60 : INTEGER, DIMENSION(:, :), POINTER :: mo_indices
3280 : LOGICAL :: do_print
3281 60 : REAL(dp), DIMENSION(:), POINTER :: lr_evals
3282 : TYPE(cp_fm_type), POINTER :: lr_coeffs
3283 : TYPE(cp_logger_type), POINTER :: logger
3284 60 : TYPE(mo_set_type), DIMENSION(:), POINTER :: mos
3285 : TYPE(section_vals_type), POINTER :: print_key
3286 :
3287 60 : NULLIFY (logger, lr_coeffs, lr_evals, print_key, mos)
3288 :
3289 : !Initialization
3290 120 : logger => cp_get_default_logger()
3291 60 : do_print = .FALSE.
3292 60 : IF (BTEST(cp_print_key_should_output(logger%iter_info, xas_tdp_section, &
3293 : "PRINT%RESTART", used_print_key=print_key), cp_p_file)) do_print = .TRUE.
3294 :
3295 58 : IF (.NOT. do_print) RETURN
3296 :
3297 2 : CALL timeset(routineN, handle)
3298 :
3299 2 : output_unit = cp_logger_get_default_io_unit()
3300 :
3301 : !Get general info
3302 2 : SELECT CASE (ex_type)
3303 : CASE (tddfpt_spin_cons)
3304 0 : lr_evals => donor_state%sc_evals
3305 0 : lr_coeffs => donor_state%sc_coeffs
3306 0 : excite = "spincons"
3307 0 : nspins = 2
3308 : CASE (tddfpt_spin_flip)
3309 0 : lr_evals => donor_state%sf_evals
3310 0 : lr_coeffs => donor_state%sf_coeffs
3311 0 : excite = "spinflip"
3312 0 : nspins = 2
3313 : CASE (tddfpt_singlet)
3314 2 : lr_evals => donor_state%sg_evals
3315 2 : lr_coeffs => donor_state%sg_coeffs
3316 2 : excite = "singlet"
3317 2 : nspins = 1
3318 : CASE (tddfpt_triplet)
3319 0 : lr_evals => donor_state%tp_evals
3320 0 : lr_coeffs => donor_state%tp_coeffs
3321 0 : excite = "triplet"
3322 2 : nspins = 1
3323 : END SELECT
3324 :
3325 4 : SELECT CASE (donor_state%state_type)
3326 : CASE (xas_1s_type)
3327 2 : domo = "1s"
3328 : CASE (xas_2s_type)
3329 0 : domo = "2s"
3330 : CASE (xas_2p_type)
3331 2 : domo = "2p"
3332 : END SELECT
3333 :
3334 2 : ndo_mo = donor_state%ndo_mo
3335 2 : nex = SIZE(lr_evals)
3336 2 : CALL cp_fm_get_info(lr_coeffs, nrow_global=nao)
3337 2 : state_type = donor_state%state_type
3338 2 : ex_atom = donor_state%at_index
3339 2 : mo_indices => donor_state%mo_indices
3340 :
3341 : !Opening restart file
3342 2 : rst_unit = -1
3343 2 : my_middle = 'xasat'//TRIM(ADJUSTL(cp_to_string(ex_atom)))//'_'//TRIM(domo)//'_'//TRIM(excite)
3344 : rst_unit = cp_print_key_unit_nr(logger, xas_tdp_section, "PRINT%RESTART", extension=".rst", &
3345 : file_status="REPLACE", file_action="WRITE", &
3346 2 : file_form="UNFORMATTED", middle_name=TRIM(my_middle))
3347 :
3348 : filename = cp_print_key_generate_filename(logger, print_key, middle_name=TRIM(my_middle), &
3349 2 : extension=".rst", my_local=.FALSE.)
3350 :
3351 2 : IF (output_unit > 0) THEN
3352 : WRITE (UNIT=output_unit, FMT="(/,T5,A,/T5,A,A,A)") &
3353 1 : "Linear-response orbitals and excitation energies are written in: ", &
3354 2 : '"', TRIM(filename), '"'
3355 : END IF
3356 :
3357 : !Writing
3358 2 : IF (rst_unit > 0) THEN
3359 1 : WRITE (rst_unit) ex_atom, state_type, ndo_mo, ex_type
3360 1 : WRITE (rst_unit) nao, nex, nspins
3361 1 : WRITE (rst_unit) mo_indices(:, :)
3362 1 : WRITE (rst_unit) lr_evals(:)
3363 : END IF
3364 2 : CALL cp_fm_write_unformatted(lr_coeffs, rst_unit)
3365 :
3366 : !The MOs as well (because the may have been localized)
3367 2 : CALL get_qs_env(qs_env, mos=mos)
3368 4 : DO ispin = 1, nspins
3369 4 : CALL cp_fm_write_unformatted(mos(ispin)%mo_coeff, rst_unit)
3370 : END DO
3371 :
3372 : !closing
3373 2 : CALL cp_print_key_finished_output(rst_unit, logger, xas_tdp_section, "PRINT%RESTART")
3374 :
3375 2 : CALL timestop(handle)
3376 :
3377 60 : END SUBROUTINE write_donor_state_restart
3378 :
3379 : ! **************************************************************************************************
3380 : !> \brief Reads donor_state info from a restart file
3381 : !> \param donor_state the pre-allocated donor_state
3382 : !> \param ex_type the excitations stored in this specific file
3383 : !> \param filename the restart file to read from
3384 : !> \param qs_env ...
3385 : ! **************************************************************************************************
3386 2 : SUBROUTINE read_donor_state_restart(donor_state, ex_type, filename, qs_env)
3387 :
3388 : TYPE(donor_state_type), POINTER :: donor_state
3389 : INTEGER, INTENT(OUT) :: ex_type
3390 : CHARACTER(len=*), INTENT(IN) :: filename
3391 : TYPE(qs_environment_type), POINTER :: qs_env
3392 :
3393 : CHARACTER(len=*), PARAMETER :: routineN = 'read_donor_state_restart'
3394 :
3395 : INTEGER :: handle, ispin, nao, nex, nspins, &
3396 : output_unit, read_params(7), rst_unit
3397 2 : INTEGER, DIMENSION(:, :), POINTER :: mo_indices
3398 : LOGICAL :: file_exists
3399 2 : REAL(dp), DIMENSION(:), POINTER :: lr_evals
3400 : TYPE(cp_blacs_env_type), POINTER :: blacs_env
3401 : TYPE(cp_fm_struct_type), POINTER :: fm_struct
3402 : TYPE(cp_fm_type), POINTER :: lr_coeffs
3403 2 : TYPE(mo_set_type), DIMENSION(:), POINTER :: mos
3404 : TYPE(mp_comm_type) :: group
3405 : TYPE(mp_para_env_type), POINTER :: para_env
3406 :
3407 2 : NULLIFY (lr_evals, lr_coeffs, para_env, fm_struct, blacs_env, mos)
3408 :
3409 2 : CALL timeset(routineN, handle)
3410 :
3411 2 : output_unit = cp_logger_get_default_io_unit()
3412 2 : CPASSERT(ASSOCIATED(donor_state))
3413 2 : CALL get_qs_env(qs_env, para_env=para_env, blacs_env=blacs_env)
3414 2 : group = para_env
3415 :
3416 2 : file_exists = .FALSE.
3417 2 : rst_unit = -1
3418 :
3419 2 : IF (para_env%is_source()) THEN
3420 :
3421 1 : INQUIRE (FILE=filename, EXIST=file_exists)
3422 1 : IF (.NOT. file_exists) CPABORT("Trying to read non-existing XAS_TDP restart file")
3423 :
3424 : CALL open_file(file_name=TRIM(filename), file_action="READ", file_form="UNFORMATTED", &
3425 1 : file_position="REWIND", file_status="OLD", unit_number=rst_unit)
3426 : END IF
3427 :
3428 2 : IF (output_unit > 0) THEN
3429 : WRITE (UNIT=output_unit, FMT="(/,T5,A,/,T5,A,A,A)") &
3430 1 : "Reading linear-response orbitals and excitation energies from file: ", &
3431 2 : '"', filename, '"'
3432 : END IF
3433 :
3434 : !read general params
3435 2 : IF (rst_unit > 0) THEN
3436 1 : READ (rst_unit) read_params(1:4)
3437 1 : READ (rst_unit) read_params(5:7)
3438 : END IF
3439 2 : CALL group%bcast(read_params)
3440 2 : donor_state%at_index = read_params(1)
3441 2 : donor_state%state_type = read_params(2)
3442 2 : donor_state%ndo_mo = read_params(3)
3443 2 : ex_type = read_params(4)
3444 2 : nao = read_params(5)
3445 2 : nex = read_params(6)
3446 2 : nspins = read_params(7)
3447 :
3448 8 : ALLOCATE (mo_indices(donor_state%ndo_mo, nspins))
3449 2 : IF (rst_unit > 0) THEN
3450 1 : READ (rst_unit) mo_indices(1:donor_state%ndo_mo, 1:nspins)
3451 : END IF
3452 10 : CALL group%bcast(mo_indices)
3453 2 : donor_state%mo_indices => mo_indices
3454 :
3455 : !read evals
3456 6 : ALLOCATE (lr_evals(nex))
3457 2 : IF (rst_unit > 0) READ (rst_unit) lr_evals(1:nex)
3458 78 : CALL group%bcast(lr_evals)
3459 :
3460 : !read evecs
3461 : CALL cp_fm_struct_create(fm_struct, context=blacs_env, para_env=para_env, &
3462 2 : nrow_global=nao, ncol_global=nex*donor_state%ndo_mo*nspins)
3463 2 : ALLOCATE (lr_coeffs)
3464 2 : CALL cp_fm_create(lr_coeffs, fm_struct)
3465 2 : CALL cp_fm_read_unformatted(lr_coeffs, rst_unit)
3466 2 : CALL cp_fm_struct_release(fm_struct)
3467 :
3468 : !read MO coeffs and replace in qs_env
3469 2 : CALL get_qs_env(qs_env, mos=mos)
3470 4 : DO ispin = 1, nspins
3471 4 : CALL cp_fm_read_unformatted(mos(ispin)%mo_coeff, rst_unit)
3472 : END DO
3473 :
3474 : !closing file
3475 2 : IF (para_env%is_source()) THEN
3476 1 : CALL close_file(unit_number=rst_unit)
3477 : END IF
3478 :
3479 : !case study on excitation type
3480 2 : SELECT CASE (ex_type)
3481 : CASE (tddfpt_spin_cons)
3482 0 : donor_state%sc_evals => lr_evals
3483 0 : donor_state%sc_coeffs => lr_coeffs
3484 : CASE (tddfpt_spin_flip)
3485 0 : donor_state%sf_evals => lr_evals
3486 0 : donor_state%sf_coeffs => lr_coeffs
3487 : CASE (tddfpt_singlet)
3488 2 : donor_state%sg_evals => lr_evals
3489 2 : donor_state%sg_coeffs => lr_coeffs
3490 : CASE (tddfpt_triplet)
3491 0 : donor_state%tp_evals => lr_evals
3492 2 : donor_state%tp_coeffs => lr_coeffs
3493 : END SELECT
3494 :
3495 2 : CALL timestop(handle)
3496 :
3497 4 : END SUBROUTINE read_donor_state_restart
3498 :
3499 : ! **************************************************************************************************
3500 : !> \brief Checks whether this is a restart calculation and runs it if so
3501 : !> \param rst_filename the file to read for restart
3502 : !> \param xas_tdp_section ...
3503 : !> \param qs_env ...
3504 : ! **************************************************************************************************
3505 4 : SUBROUTINE restart_calculation(rst_filename, xas_tdp_section, qs_env)
3506 :
3507 : CHARACTER(len=*), INTENT(IN) :: rst_filename
3508 : TYPE(section_vals_type), POINTER :: xas_tdp_section
3509 : TYPE(qs_environment_type), POINTER :: qs_env
3510 :
3511 : INTEGER :: ex_type
3512 : TYPE(donor_state_type), POINTER :: donor_state
3513 : TYPE(xas_tdp_env_type), POINTER :: xas_tdp_env
3514 :
3515 2 : NULLIFY (xas_tdp_env, donor_state)
3516 :
3517 : !create a donor_state that we fill with the information we read
3518 2 : ALLOCATE (donor_state)
3519 2 : CALL donor_state_create(donor_state)
3520 2 : CALL read_donor_state_restart(donor_state, ex_type, rst_filename, qs_env)
3521 :
3522 : !create a dummy xas_tdp_env and compute the post XAS_TDP stuff
3523 2 : CALL xas_tdp_env_create(xas_tdp_env)
3524 2 : CALL xas_tdp_post(ex_type, donor_state, xas_tdp_env, xas_tdp_section, qs_env)
3525 :
3526 : !clean-up
3527 2 : CALL xas_tdp_env_release(xas_tdp_env)
3528 2 : CALL free_ds_memory(donor_state)
3529 2 : DEALLOCATE (donor_state%mo_indices)
3530 2 : DEALLOCATE (donor_state)
3531 :
3532 2 : END SUBROUTINE restart_calculation
3533 :
3534 : END MODULE xas_tdp_methods
|