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