(git:a145afa)
Loading...
Searching...
No Matches
rt_bse_types.F
Go to the documentation of this file.
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 Data storage and other types for propagation via RT-BSE method.
10!> \author Stepan Marek (01.24)
11! **************************************************************************************************
12
14
15 USE kinds, ONLY: dp
16 USE cp_fm_types, ONLY: cp_fm_type, &
23 USE cp_cfm_types, ONLY: cp_cfm_type, &
29 USE cp_dbcsr_api, ONLY: dbcsr_type, &
35 USE dbt_api, ONLY: dbt_type, &
36 dbt_create, &
37 dbt_destroy
38 USE qs_mo_types, ONLY: mo_set_type
45 eps_qp_gap, &
55 do_bch, &
56 do_exact, &
61 USE physcon, ONLY: evolt
62 USE mathconstants, ONLY: z_zero
66
67#include "../base/base_uses.f90"
68
69 IMPLICIT NONE
70
71 PRIVATE
72
73 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = "rt_bse"
74
75
76
77
78 PUBLIC :: rtbse_env_type, &
85
86 ! ! Created so that we can have an array of pointers to arrays
87 ! TYPE series_real_type
88 ! REAL(kind=dp), DIMENSION(:), POINTER :: series => NULL()
89 ! END TYPE series_real_type
90 ! TYPE series_complex_type
91 ! COMPLEX(kind=dp), DIMENSION(:), POINTER :: series => NULL()
92 ! END TYPE series_complex_type
93
94! **************************************************************************************************
95!> \param n_spin Number of spin channels that are present
96!> \param n_ao Number of atomic orbitals
97!> \param n_RI Number of RI orbitals
98!> \param n_occ Number of occupied orbitals, spin dependent
99!> \param spin_degeneracy Number of electrons per orbital
100!> \param field Electric field calculated at the given timestep
101!> \param moments Moment operators (2nd index = spin) along cartesian directions - centered at zero charge - used for plotting
102!> \param moments_field Moment operators (2nd index = spin) along cartesian directions - used to coupling to the field -
103!> origin bound to unit cell
104!> \param sim_step Current step of the simulation
105!> \param sim_start Starting step of the simulation
106!> \param sim_nsteps Number of steps of the simulation
107!> \param sim_time Current time of the simulation
108!> \param sim_dt Timestep of the simulation
109!> \param sim_dt_restart Original-run timestep read from the trace on restart (< 0 when not a restart)
110!> \param etrs_threshold Self-consistency threshold for enforced time reversal symmetry propagation
111!> \param exp_accuracy Threshold for matrix exponential calculation
112!> \param dft_control DFT control parameters
113!> \param ham_effective Real and imaginary part of the effective Hamiltonian used to propagate
114!> the density matrix
115!> \param ham_reference Reference Hamiltonian, which does not change in the
116!> propagation = DFT+G0W0 - initial Hartree - initial COHSEX
117!> \param ham_workspace Workspace matrices for use with the Hamiltonian propagation - storage of
118!> exponential propagators etc.
119!> \param rho Density matrix at the current time step
120!> \param rho_new Density matrix - workspace in ETRS
121!> \param rho_last Density matrix - workspace in ETRS
122!> \param rho_new_last Density matrix - workspace in ETRS
123!> \param rho_M Density matrix - workspace in ETRS
124!> \param S_inv_fm Inverse overlap matrix, full matrix
125!> \param S_fm Overlap matrix, full matrix
126!> \param S_inv Inverse overlap matrix, sparse matrix
127!> \param rho_dbcsr Density matrix, sparse matrix
128!> \param rho_workspace Matrices for storage of density matrix at different timesteps for
129!> interpolation and self-consistency checks etc.
130!> \param complex_workspace Workspace for complex density (exact diagonalisation)
131!> \param complex_s Complex overlap matrix (exact diagonalisation)
132!> \param real_eigvals Eigenvalues of hermitian matrix (exact diagonalisation)
133!> \param exp_eigvals Exponentiated eigenvalues (exact diagonalisation)
134!> \param v_dbcsr Sparse matrix with bare Coulomb in RI basis
135!> \param w_dbcsr Sparse matrix with correlation part of dressed Coulomb in RI basis (without bare Coulomb)
136!> \param screened_dbt Tensor for screened Coulomb interaction
137!> \param greens_dbt Tensor for greens function/density matrix
138!> \param t_3c_w Tensor containing 3c integrals
139!> \param t_3c_work_RI_AO__AO Tensor sigma contraction
140!> \param t_3c_work2_RI_AO__AO Tensor sigma contraction
141!> \param sigma_SEX Screened exchange self-energy
142!> \param sigma_COH Coulomb hole self-energy
143!> \param hartree_curr Current Hartree matrix
144!> \param etrs_max_iter Maximum number of ETRS iterations
145!> \param ham_reference_type Which Hamiltonian to use as single particle basis
146!> \param mat_exp_method Which method to use for matrix exponentiation
147!> \param unit_nr Number of output unit
148!> \param int_3c_array Array containing the local 3c integrals
149!> \author Stepan Marek (01.24)
150! **************************************************************************************************
152 INTEGER :: n_spin = 1, &
153 n_ao = -1, &
154 n_ri = -1
155 INTEGER, DIMENSION(2) :: n_occ = -1
156 ! Active MO window for linearized RT-BSE truncation. When no truncation is requested,
157 ! first_active_mo=1, last_active_mo=n_ao, and mo_active=n_ao. The window is the
158 ! combined inclusive bound that covers both spin channels.
159 INTEGER :: first_active_mo = 1, &
160 last_active_mo = -1, &
161 mo_active = -1
162 REAL(kind=dp) :: rtbse_energy_cutoff_occ = -1.0_dp, &
163 rtbse_energy_cutoff_empty = -1.0_dp
164 LOGICAL :: active_mo_truncation = .false.
165 LOGICAL :: linearized = .false.
166 ! Tamm-Dancoff approximation switch (linearized RT-BSE only).
167 LOGICAL :: tda_active = .false.
168 ! First-peak shift for the TDA path (linearized RT-BSE only).
169 ! Shifts active-MO single-particle diagonals by +Omega_0/2 (occ) / -Omega_0/2 (virt)
170 ! with Omega_0 = eps_min_ai so the lowest active OV mode oscillates at zero in the
171 ! rotating frame (RK4-exact for peak 1). omega_max becomes the full active OV width
172 ! Delta = eps_max_ai - eps_min_ai. The resulting rotating-frame density is undone
173 ! at I/O so observables stay lab-frame.
174 LOGICAL :: tda_shift_to_first_peak = .false.
175 REAL(kind=dp) :: omega_shift = 0.0_dp
176 ! Debug-only kernel switches shared by initialization and propagation.
177 LOGICAL :: debug_disable_hartree = .false., &
178 debug_disable_sex = .false.
179 ! RI framework for the linRTBSE Hartree + screened-exchange kernels, set by the KERNEL_RI
180 ! input keyword (DEFAULT inherits bs_env%do_gw_ri_rs; RS/AO force; full RT-BSE forced AO).
181 ! .TRUE. = RI-RS grid kernels, .FALSE. = AO-RI. The required grid and V_grid/W0_grid
182 ! kernels are built on demand and reused across steps.
183 LOGICAL :: rirs_kernel = .false.
184 ! Liouvillian eigenvalue diagnostic (TDA + n_spin=1 only). When .TRUE., at job
185 ! init the linearized RT-BSE assembles the OV-subspace Liouvillian by probing
186 ! apply_liouvillian_to_drho with canonical OV basis vectors and diagonalizes
187 ! via cp_cfm_heevd. In TDA this equals the Casida-A eigenvalue problem.
188 ! Run once, no propagation impact.
189 LOGICAL :: diagnose_liouvillian_eig = .false.
190 ! Whether to enforce max_dt within stability region of rk4
191 LOGICAL :: enforce_max_dt = .false.
192 ! Owned fm structures sized to the active MO window. Equal to the full n_ao x n_ao
193 ! when no truncation is active.
194 TYPE(cp_fm_struct_type), POINTER :: fm_struct_mo_active => null()
195 ! n_ao x mo_active fm struct used for C_active and AO<->MO rectangular intermediates.
196 TYPE(cp_fm_struct_type), POINTER :: fm_struct_ao_mo_active => null()
197 ! Liouvillian-diagnostic struct: (N_OV_joint x N_OV_joint), spin blocks stacked, on the
198 ! same BLACS context as fm_struct_mo_active. Allocated only when diagnose_liouvillian_eig=.TRUE..
199 TYPE(cp_fm_struct_type), POINTER :: fm_struct_ov_pairs => null()
200 ! Truncated MO coefficient slabs C_active(:,:) of size n_ao x mo_active for each spin
201 ! (only allocated for the linearized path).
202 TYPE(cp_fm_type), DIMENSION(:), POINTER :: c_active => null()
203 ! Rectangular n_ao x mo_active scratch used by linearized AO<->MO transforms.
204 TYPE(cp_fm_type), DIMENSION(:), POINTER :: ao_mo_workspace => null()
205 REAL(kind=dp) :: spin_degeneracy = 2
206 REAL(kind=dp), DIMENSION(3) :: field = 0.0_dp
207 TYPE(cp_fm_type), DIMENSION(:, :), POINTER :: moments => null(), &
208 moments_field => null()
209 INTEGER :: sim_step = 0, &
210 sim_start = 0, &
211 ! Needed to continue runs by loading previous moments trace
212 sim_start_orig = 0, &
213 sim_nsteps = -1, &
214 ! Default reference point type for output moments
215 ! Field moments always use zero reference
216 moment_ref_type = use_mom_ref_coac
217 ! Restart output bookkeeping: RESTART.trace header+prefix and (linearized) C_active are
218 ! (re)written on the first output_restart call of a run, then .trace is appended per step.
219 LOGICAL :: restart_trace_written = .false., &
220 restart_c_written = .false.
221 REAL(kind=dp), DIMENSION(:), POINTER :: user_moment_ref_point => null()
222 REAL(kind=dp) :: sim_time = 0.0_dp, &
223 sim_dt = 0.1_dp, &
224 ! Original-run dt from the trace header on restart (< 0 when not
225 ! a restart); ENFORCE_MAX_DT reuses it instead of recomputing dt
226 sim_dt_restart = -1.0_dp, &
227 maximum_timestep = -1.0_dp, &
228 omega_max = -1.0_dp, &
229 etrs_threshold = 1.0e-7_dp, &
230 exp_accuracy = 1.0e-10_dp, &
231 ft_damping = 0.0_dp, &
232 ft_start = 0.0_dp
233 ! Which element of polarizability to print out
234 INTEGER, DIMENSION(:, :), POINTER :: pol_elements => null()
235 TYPE(dft_control_type), POINTER :: dft_control => null()
236 ! DEBUG : Trying keeping the reference to previous environments inside this one
237 TYPE(qs_environment_type), POINTER :: qs_env => null()
238 TYPE(post_scf_bandstructure_type), POINTER :: bs_env => null()
239 ! Stores data needed for reading/writing to the restart files
240 TYPE(section_vals_type), POINTER :: restart_section => null(), &
241 field_section => null(), &
242 rho_section => null(), &
243 ft_section => null(), &
244 pol_section => null(), &
245 eig_section => null(), &
246 moments_section => null(), &
247 rtp_section => null()
248 LOGICAL :: restart_extracted = .false.
249
250 ! Different indices signify different spins
251 TYPE(cp_cfm_type), DIMENSION(:), POINTER :: ham_effective => null()
252 TYPE(cp_cfm_type), DIMENSION(:), POINTER :: ham_reference => null()
253 !Only for linearised RTBSE
254 TYPE(cp_cfm_type), DIMENSION(:), POINTER :: ham_reference_singleparticle => null()
255 ! Active single-particle energies = diag(ham_reference_singleparticle), replicated over all
256 ! ranks. Drives the [H^0,rho]_mn = (eps_m - eps_n) rho_mn element-wise commutator (mo_active x n_spin).
257 REAL(kind=dp), DIMENSION(:, :), POINTER :: eps_active => null()
258 ! Original run's active eigenvalues stashed from RESTART.trace at read time; compared against
259 ! the recomputed eps_active once the Hamiltonian is built (consistency heads-up), then freed.
260 REAL(kind=dp), DIMENSION(:, :), POINTER :: eps_active_restart => null()
261 TYPE(cp_cfm_type), DIMENSION(:), POINTER :: ham_workspace => null()
262 TYPE(cp_cfm_type), DIMENSION(:), POINTER :: sigma_sex => null()
263 TYPE(cp_fm_type), DIMENSION(:), POINTER :: sigma_coh => null(), &
264 hartree_curr => null()
265 ! AO-sized scratch buffers used in the linearized RT-BSE path so that the MO-sized
266 ! sigma_COH/sigma_SEX/hartree_curr matrices above can be allocated on
267 ! fm_struct_mo_active. Only allocated when linearized=.TRUE..
268 TYPE(cp_cfm_type), DIMENSION(:), POINTER :: sigma_sex_ao => null()
269 TYPE(cp_fm_type), DIMENSION(:), POINTER :: hartree_curr_ao => null()
270 ! Open-shell cross-spin Hartree (TDA AO-RI), single shared AO buffers built once per
271 ! RK4 stage: rho_total_ao_scratch (fm_s struct, matches rho_ao_scratch for the spin sum);
272 ! hartree_total_ao = V_H[sum] (fm_ks struct, matches sigma_SEX_ao as the Hartree output).
273 TYPE(cp_cfm_type) :: rho_total_ao_scratch = cp_cfm_type(), &
274 hartree_total_ao = cp_cfm_type()
275 ! RI-RS Hartree diagonal reuse: spin-summed grid density n_l = diag(phi.rho.phi^T), harvested
276 ! from the SEX rho_grid (before its Hadamard, scaled by spin_degeneracy) and consumed by
277 ! compute_hartree_ri_rs_from_diag so Hartree never rebuilds the grid product. Re/Im; sized
278 ! n_grid; allocated in initialize_hartree_potential when rirs_kernel. rtbse_env-owned (not
279 ! bs_env%ri_rs) to avoid aliasing bs_env when passed through get_sigma_complex.
280 REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: hartree_diag_re, hartree_diag_im
281 ! mo_active x mo_active real workspace pair used in MO-side transforms (linearized only).
282 TYPE(cp_fm_type), DIMENSION(:), POINTER :: real_workspace_mo => null()
283 ! Liouvillian-diagnostic scratch (allocated only when diagnose_liouvillian_eig=.TRUE.).
284 ! drho_probe(:) / L_drho(:) are per-spin arrays on fm_struct_mo_active: the joint TDA
285 ! diagnostic probes one spin and reads the Liouvillian response on every spin block.
286 ! L_pairs / eigvecs_pairs live on fm_struct_ov_pairs (N_OV_joint x N_OV_joint, the spin
287 ! blocks stacked). A_mat / B_mat / AmB_scratch / ApB_scratch are ABBA-only blocks holding
288 ! A, B, (A-B) -> (A-B)^{1/2}, and (A+B) for the Furche reduction; allocated only
289 ! when .NOT. tda_active (n_spin=1; TDA path uses L_pairs alone).
290 ! eigenvalues_liouvillian holds the N_OV_joint real eigenvalues from cp_cfm_heevd.
291 TYPE(cp_cfm_type) :: l_pairs = cp_cfm_type(), &
292 eigvecs_pairs = cp_cfm_type(), &
293 a_mat = cp_cfm_type(), &
294 b_mat = cp_cfm_type(), &
295 amb_scratch = cp_cfm_type(), &
296 apb_scratch = cp_cfm_type()
297 REAL(kind=dp), DIMENSION(:), POINTER :: eigenvalues_liouvillian => null()
298
299 TYPE(cp_cfm_type), DIMENSION(:), POINTER :: rho => null(), &
300 rho_new => null(), &
301 rho_new_last => null(), &
302 rho_m => null(), &
303 rho_orig => null(), &
304 rho_ao_scratch => null(), &
305 rho_delta_mo => null(), &
306 drho_probe => null(), &
307 l_drho => null()
308 ! Workspace for rk4 in linearized RTBSE
309 TYPE(cp_cfm_type), DIMENSION(:), POINTER :: rk4_coefficients => null()
310
311 TYPE(cp_fm_type) :: s_inv_fm = cp_fm_type(), &
312 s_fm = cp_fm_type()
313 ! Many routines require overlap in the complex format
314 TYPE(cp_cfm_type) :: s_cfm = cp_cfm_type()
315 TYPE(dbcsr_type) :: rho_dbcsr = dbcsr_type(), &
316 v_ao_dbcsr = dbcsr_type()
317 ! Indices only correspond to different workspaces
318 TYPE(cp_cfm_type), DIMENSION(:), POINTER :: rho_workspace => null()
319 ! Many methods use real and imaginary parts separately - prevent unnecessary reallocation
320 TYPE(cp_fm_type), DIMENSION(:), POINTER :: real_workspace => null()
321 ! AO-sized complex scratch used to stage the real part in get_sigma_complex.
322 TYPE(cp_cfm_type), DIMENSION(:), POINTER :: sigma_complex_workspace => null()
323 ! Workspace required for exact matrix exponentiation
324 REAL(kind=dp), DIMENSION(:), POINTER :: real_eigvals => null()
325 COMPLEX(kind=dp), DIMENSION(:), POINTER :: exp_eigvals => null()
326 ! Workspace for saving the values for FT
327 ! TODO : Change back to multi-dimensional arrays
328 ! Index 1 : spin, Index 2 : direction, Index 3 : time point
329 COMPLEX(kind=dp), DIMENSION(:, :, :), POINTER :: moments_trace => null()
330 REAL(kind=dp), DIMENSION(:), POINTER :: time_trace => null()
331 ! Index 1 : direction, Index 2 : time point
332 COMPLEX(kind=dp), DIMENSION(:, :), POINTER :: field_trace => null()
333 ! Workspace required for hartree_pw
334 TYPE(dbcsr_type) :: v_dbcsr = dbcsr_type(), &
335 w_dbcsr = dbcsr_type()
336#if defined(FTN_NO_DEFAULT_INIT)
337 TYPE(dbt_type) :: screened_dbt, &
338 greens_dbt, &
339 t_3c_w, &
340 t_3c_work_ri_ao__ao, &
341 t_3c_work2_ri_ao__ao
342#else
343 TYPE(dbt_type) :: screened_dbt = dbt_type(), &
344 greens_dbt = dbt_type(), &
345 t_3c_w = dbt_type(), &
346 t_3c_work_ri_ao__ao = dbt_type(), &
347 t_3c_work2_ri_ao__ao = dbt_type()
348#endif
349 ! These matrices are always real
350 INTEGER :: etrs_max_iter = 10
351 INTEGER :: ham_reference_type = 2
352 INTEGER :: mat_exp_method = 4
353 INTEGER :: unit_nr = -1
354 REAL(kind=dp), DIMENSION(:, :, :), POINTER :: int_3c_array => null()
355 ! Parameters for Padé refinement
356 REAL(kind=dp) :: pade_e_min = 0.0_dp, &
357 pade_e_max = 100.0_dp, &
358 pade_e_step = 0.05_dp, &
359 pade_fit_e_min = 0.0_dp, &
360 pade_fit_e_max = -1.0_dp
361 INTEGER :: pade_npoints = 0
362 LOGICAL :: pade_requested = .false.
363 COMPLEX(kind=dp), DIMENSION(:), POINTER :: pade_x_eval => null()
364
365 END TYPE rtbse_env_type
366
367CONTAINS
368
369! **************************************************************************************************
370!> \brief Allocates structures and prepares rtbse_env for run
371!> \param rtbse_env rtbse_env_type that is initialised
372!> \param force_env Force environment - entry point of the calculation
373!> \param linearized Optional; when present and .TRUE., configure the environment for the linearized RT-BSE path
374!> \author Stepan Marek
375!> \date 02.2024
376! **************************************************************************************************
377 SUBROUTINE create_rtbse_env(rtbse_env, force_env, linearized)
378 TYPE(rtbse_env_type), POINTER :: rtbse_env
379 TYPE(force_env_type), POINTER :: force_env
380 LOGICAL, OPTIONAL :: linearized
381 TYPE(post_scf_bandstructure_type), POINTER :: bs_env
382 TYPE(rt_prop_type), POINTER :: rtp
383 TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_s
384 TYPE(mo_set_type), DIMENSION(:), POINTER :: mos
385 INTEGER :: i, k, n_ov, i_spin
386 TYPE(section_vals_type), POINTER :: input, bs_sec, md_sec
387 TYPE(cp_fm_struct_type), POINTER :: mo_struct
388
389 ! Allocate the storage for the gwbse environment
390 NULLIFY (rtbse_env, mo_struct)
391 ALLOCATE (rtbse_env)
392 IF (PRESENT(linearized)) rtbse_env%linearized = linearized
393 ! Extract the other types first
394 CALL get_qs_env(force_env%qs_env, &
395 bs_env=bs_env, &
396 rtp=rtp, &
397 matrix_s=matrix_s, &
398 mos=mos, &
399 dft_control=rtbse_env%dft_control, &
400 input=input)
401 bs_sec => section_vals_get_subs_vals(input, "PROPERTIES%BANDSTRUCTURE")
402 IF (.NOT. ASSOCIATED(bs_env)) THEN
403 cpabort("Cannot run RT-BSE without running GW calculation (PROPERTIES) before")
404 END IF
405 ! Number of spins
406 rtbse_env%n_spin = bs_env%n_spin
407 ! Open shell (n_spin>1) is only implemented and tested for the linearized
408 ! propagation; the full RT-BSE open-shell path is untested.
409 IF (rtbse_env%n_spin > 1 .AND. .NOT. rtbse_env%linearized) THEN
410 CALL cp_abort(__location__, &
411 "Open-shell (n_spin>1) RT-BSE is only implemented and tested for the "// &
412 "linearized propagation. Set DFT%REAL_TIME_PROPAGATION%RTBSE%LRRTBSE "// &
413 ".TRUE.; the full (non-linearized) open-shell RT-BSE path is untested.")
414 END IF
415 ! Number of atomic orbitals
416 rtbse_env%n_ao = bs_env%n_ao
417 ! Number of auxiliary basis orbitals
418 rtbse_env%n_RI = bs_env%n_RI
419 ! Number of occupied orbitals - for closed shell equals to half the number of electrons
420 rtbse_env%n_occ(:) = bs_env%n_occ(:)
421 ! Spin degeneracy - number of spins per orbital
422 rtbse_env%spin_degeneracy = bs_env%spin_degeneracy
423 ! Default field is zero
424 rtbse_env%field(:) = 0.0_dp
425 ! Default time is zero
426 rtbse_env%sim_step = 0
427 rtbse_env%sim_time = 0
428 ! Time step is taken from rtp
429 md_sec => section_vals_get_subs_vals(force_env%root_section, "MOTION%MD")
430 CALL section_vals_val_get(md_sec, "TIMESTEP", r_val=rtbse_env%sim_dt)
431 ! rtbse_env%sim_dt = rtp%dt
432 ! Threshold for etrs is taken from the eps_energy from RT propagation
433 rtbse_env%etrs_threshold = rtbse_env%dft_control%rtp_control%eps_ener
434 rtbse_env%exp_accuracy = rtbse_env%dft_control%rtp_control%eps_exp
435 ! Recover custom options
436 CALL section_vals_val_get(input, "DFT%REAL_TIME_PROPAGATION%RTBSE%RTBSE_HAMILTONIAN", &
437 i_val=rtbse_env%ham_reference_type)
438 CALL section_vals_val_get(input, "DFT%REAL_TIME_PROPAGATION%MAX_ITER", &
439 i_val=rtbse_env%etrs_max_iter)
440 CALL section_vals_val_get(input, "DFT%REAL_TIME_PROPAGATION%MAT_EXP", &
441 i_val=rtbse_env%mat_exp_method)
442 CALL section_vals_val_get(input, "DFT%REAL_TIME_PROPAGATION%RTBSE%ENERGY_CUTOFF_OCC", &
443 r_val=rtbse_env%rtbse_energy_cutoff_occ)
444 CALL section_vals_val_get(input, "DFT%REAL_TIME_PROPAGATION%RTBSE%ENERGY_CUTOFF_EMPTY", &
445 r_val=rtbse_env%rtbse_energy_cutoff_empty)
446 CALL section_vals_val_get(input, "DFT%REAL_TIME_PROPAGATION%RTBSE%TDA", &
447 l_val=rtbse_env%tda_active)
448 CALL section_vals_val_get(input, "DFT%REAL_TIME_PROPAGATION%RTBSE%TDA_SHIFT_TO_FIRST_PEAK", &
449 l_val=rtbse_env%tda_shift_to_first_peak)
450 CALL section_vals_val_get(input, "DFT%REAL_TIME_PROPAGATION%RTBSE%ENFORCE_MAX_DT", &
451 l_val=rtbse_env%enforce_max_dt)
452 CALL section_vals_val_get(input, "DFT%REAL_TIME_PROPAGATION%RTBSE%DEBUG_DISABLE_HARTREE", &
453 l_val=rtbse_env%debug_disable_hartree)
454 CALL section_vals_val_get(input, "DFT%REAL_TIME_PROPAGATION%RTBSE%DEBUG_DISABLE_SEX", &
455 l_val=rtbse_env%debug_disable_sex)
456 ! RI-RS kernel switch (KERNEL_RI: DEFAULT=do_gw_ri_rs, RS/AO force, full-RTBSE force-off)
457 ! is resolved by the shared helper so de_init_bs_env reaches the same verdict when
458 ! deciding whether to retain nl_3c.
459 CALL rtbse_resolve_rirs_flag(force_env%qs_env, bs_env, rirs_kernel=rtbse_env%rirs_kernel)
460 CALL section_vals_val_get(input, "DFT%REAL_TIME_PROPAGATION%RTBSE%DIAGNOSE_LIOUVILLIAN_EIG", &
461 l_val=rtbse_env%diagnose_liouvillian_eig)
462
463 IF (.NOT. rtbse_env%dft_control%rtp_control%rtp_method == rtp_method_bse_linearized) THEN
464 rtbse_env%rtbse_energy_cutoff_occ = -1.0_dp
465 rtbse_env%rtbse_energy_cutoff_empty = -1.0_dp
466 rtbse_env%enforce_max_dt = .false.
467 rtbse_env%debug_disable_hartree = .false.
468 rtbse_env%debug_disable_sex = .false.
469 rtbse_env%tda_shift_to_first_peak = .false.
470 ! rirs_kernel is already forced .FALSE. here by rtbse_resolve_rirs_flag.
471 rtbse_env%diagnose_liouvillian_eig = .false.
472 END IF
473 ! First-peak shift only makes sense within TDA; force-disable otherwise.
474 IF (.NOT. rtbse_env%tda_active) rtbse_env%tda_shift_to_first_peak = .false.
475 rtbse_env%omega_shift = 0.0_dp
476
477 IF (rtbse_env%tda_active .AND. .NOT. rtbse_env%linearized) THEN
478 cpabort("RTBSE TDA keyword requires LINEARIZED_BSE_PROPAGATION=.TRUE.")
479 END IF
480 ! Open shell: omega_shift would be referenced to a non-physical cross-spin
481 ! pseudo-gap (global MIN/MAX over both spins); abort until made per-spin.
482 IF (rtbse_env%tda_shift_to_first_peak .AND. rtbse_env%n_spin > 1) THEN
483 CALL cp_abort(__location__, &
484 "TDA_SHIFT_TO_FIRST_PEAK is not implemented for open-shell (n_spin>1) "// &
485 "systems - the first-peak gap estimate would mix spin channels. "// &
486 "Set TDA_SHIFT_TO_FIRST_PEAK=.FALSE. for open-shell runs.")
487 END IF
488 CALL check_qp_gap_sanity(rtbse_env, bs_env)
489 CALL determine_active_mo_window(rtbse_env, bs_env)
490 ! Owned active-MO matrix structure (currently identical to the full n_ao x n_ao struct
491 ! when no truncation is active; will be used by the linearized RT-BSE allocation path).
492 NULLIFY (rtbse_env%fm_struct_mo_active)
493 CALL cp_fm_struct_create(rtbse_env%fm_struct_mo_active, &
494 bs_env%fm_ks_Gamma(1)%matrix_struct%para_env, &
495 bs_env%fm_ks_Gamma(1)%matrix_struct%context, &
496 rtbse_env%mo_active, rtbse_env%mo_active)
497 ! Rectangular n_ao x mo_active struct used for C_active and AO<->MO intermediates
498 NULLIFY (rtbse_env%fm_struct_ao_mo_active)
499 CALL cp_fm_struct_create(rtbse_env%fm_struct_ao_mo_active, &
500 bs_env%fm_ks_Gamma(1)%matrix_struct%para_env, &
501 bs_env%fm_ks_Gamma(1)%matrix_struct%context, &
502 rtbse_env%n_ao, rtbse_env%mo_active)
503 ! Choose the matrix struct used for MO-side persistent matrices.
504 ! Linearized RT-BSE: mo_active x mo_active. Full RT-BSE: full AO struct (unchanged).
505 IF (rtbse_env%linearized) THEN
506 mo_struct => rtbse_env%fm_struct_mo_active
507 ELSE
508 mo_struct => bs_env%fm_ks_Gamma(1)%matrix_struct
509 END IF
510 ! Output unit number, recovered from the post_scf_bandstructure_type
511 rtbse_env%unit_nr = bs_env%unit_nr
512 ! Sim start index and total number of steps as well
513 CALL section_vals_val_get(md_sec, "STEP_START_VAL", i_val=rtbse_env%sim_start)
514 ! Copy this value to sim_start_orig for continuation runs
515 rtbse_env%sim_start_orig = rtbse_env%sim_start
516 CALL section_vals_val_get(md_sec, "STEPS", i_val=rtbse_env%sim_nsteps)
517 ! Get the values for the FT
518 rtbse_env%ft_damping = rtbse_env%dft_control%rtp_control%ft_damping
519 rtbse_env%ft_damping = rtbse_env%dft_control%rtp_control%ft_t0
520 rtbse_env%pol_elements => rtbse_env%dft_control%rtp_control%print_pol_elements
521
522 rtbse_env%rtp_section => section_vals_get_subs_vals(input, "DFT%REAL_TIME_PROPAGATION")
523 ! Get the restart section
524 rtbse_env%restart_section => section_vals_get_subs_vals(rtbse_env%rtp_section, "PRINT%RESTART")
525 rtbse_env%restart_extracted = .false.
526 rtbse_env%field_section => section_vals_get_subs_vals(rtbse_env%rtp_section, "PRINT%FIELD")
527 rtbse_env%moments_section => section_vals_get_subs_vals(rtbse_env%rtp_section, "PRINT%MOMENTS")
528 ! Moment specification
529 CALL section_vals_val_get(rtbse_env%rtp_section, "PRINT%MOMENTS%REFERENCE", &
530 i_val=rtbse_env%moment_ref_type)
531 CALL section_vals_val_get(rtbse_env%rtp_section, "PRINT%MOMENTS%REFERENCE_POINT", &
532 r_vals=rtbse_env%user_moment_ref_point)
533 rtbse_env%rho_section => section_vals_get_subs_vals(rtbse_env%rtp_section, "PRINT%DENSITY_MATRIX")
534 rtbse_env%ft_section => section_vals_get_subs_vals(rtbse_env%rtp_section, "PRINT%MOMENTS_FT")
535 rtbse_env%pol_section => section_vals_get_subs_vals(rtbse_env%rtp_section, "PRINT%POLARIZABILITY")
536 rtbse_env%eig_section => section_vals_get_subs_vals(rtbse_env%rtp_section, "PRINT%LIOUVILLIAN_EIG")
537 ! Warn the user about print sections which are not yet implemented in the RTBSE run
538 CALL warn_section_unused(rtbse_env%rtp_section, "PRINT%CURRENT", &
539 "CURRENT print section not yet implemented for RTBSE.")
540 CALL warn_section_unused(rtbse_env%rtp_section, "PRINT%E_CONSTITUENTS", &
541 "E_CONSTITUENTS print section not yet implemented for RTBSE.")
542 CALL warn_section_unused(rtbse_env%rtp_section, "PRINT%PROGRAM_RUN_INFO", &
543 "PROGRAM_RUN_INFO print section not yet implemented for RTBSE.")
544 CALL warn_section_unused(rtbse_env%rtp_section, "PRINT%PROJECTION_MO", &
545 "PROJECTION_MO print section not yet implemented for RTBSE.")
546 CALL warn_section_unused(rtbse_env%rtp_section, "PRINT%RESTART_HISTORY", &
547 "RESTART_HISTORY print section not yet implemented for RTBSE.")
548 ! References to the parent qs_env / bs_env
549 rtbse_env%qs_env => force_env%qs_env
550 rtbse_env%bs_env => bs_env
551 ! Padé refinement
552 rtbse_env%pade_requested = rtbse_env%dft_control%rtp_control%pade_requested
553 rtbse_env%pade_e_min = rtbse_env%dft_control%rtp_control%pade_e_min
554 rtbse_env%pade_e_step = rtbse_env%dft_control%rtp_control%pade_e_step
555 rtbse_env%pade_e_max = rtbse_env%dft_control%rtp_control%pade_e_max
556 rtbse_env%pade_fit_e_min = rtbse_env%dft_control%rtp_control%pade_fit_e_min
557 rtbse_env%pade_fit_e_max = rtbse_env%dft_control%rtp_control%pade_fit_e_max
558 rtbse_env%pade_npoints = int((rtbse_env%pade_e_max - rtbse_env%pade_e_min)/rtbse_env%pade_e_step)
559 ! Evaluate the evaluation grid
560 IF (rtbse_env%pade_requested) THEN
561 NULLIFY (rtbse_env%pade_x_eval)
562 ALLOCATE (rtbse_env%pade_x_eval(rtbse_env%pade_npoints))
563 DO i = 1, rtbse_env%pade_npoints
564 rtbse_env%pade_x_eval(i) = cmplx(rtbse_env%pade_e_step*real(i - 1, kind=dp), 0.0, kind=dp)
565 END DO
566 END IF
567
568 ! Allocate moments matrices.
569 ! In linearized RT-BSE these store the MO-active transformed dipole moments;
570 ! in full RT-BSE they remain AO-sized (initialized from overlap template).
571 NULLIFY (rtbse_env%moments)
572 ALLOCATE (rtbse_env%moments(3, rtbse_env%n_spin))
573 NULLIFY (rtbse_env%moments_field)
574 ALLOCATE (rtbse_env%moments_field(3, rtbse_env%n_spin))
575 DO i_spin = 1, rtbse_env%n_spin
576 DO k = 1, 3
577 CALL cp_fm_create(rtbse_env%moments(k, i_spin), mo_struct)
578 CALL cp_fm_create(rtbse_env%moments_field(k, i_spin), mo_struct)
579 END DO
580 END DO
581
582 ! Allocate space for density propagation and other operations.
583 ! In linearized RT-BSE these workspaces are MO-active sized; in full RT-BSE
584 ! they remain at the full AO size.
585 NULLIFY (rtbse_env%rho_workspace)
586 ALLOCATE (rtbse_env%rho_workspace(4))
587 DO i = 1, SIZE(rtbse_env%rho_workspace)
588 CALL cp_cfm_create(rtbse_env%rho_workspace(i), mo_struct)
589 CALL cp_cfm_set_all(rtbse_env%rho_workspace(i), cmplx(0.0, 0.0, kind=dp))
590 END DO
591
592 ! TODO: gate workspace allocation so methods skip workspaces they don't need
593
594 ! Allocate real workspace
595 NULLIFY (rtbse_env%real_workspace)
596 IF (rtbse_env%linearized) THEN
597 ALLOCATE (rtbse_env%real_workspace(2))
598 ELSE
599 SELECT CASE (rtbse_env%mat_exp_method)
600 CASE (do_exact)
601 ALLOCATE (rtbse_env%real_workspace(4))
602 CASE (do_bch)
603 ALLOCATE (rtbse_env%real_workspace(2))
604 CASE DEFAULT
605 cpabort("Only exact and BCH matrix propagation implemented in RT-BSE")
606 END SELECT
607 END IF
608 DO i = 1, SIZE(rtbse_env%real_workspace)
609 CALL cp_fm_create(rtbse_env%real_workspace(i), bs_env%fm_ks_Gamma(1)%matrix_struct)
610 CALL cp_fm_set_all(rtbse_env%real_workspace(i), 0.0_dp)
611 END DO
612 NULLIFY (rtbse_env%sigma_complex_workspace)
613 ALLOCATE (rtbse_env%sigma_complex_workspace(1))
614 CALL cp_cfm_create(rtbse_env%sigma_complex_workspace(1), bs_env%fm_ks_Gamma(1)%matrix_struct)
615 CALL cp_cfm_set_all(rtbse_env%sigma_complex_workspace(1), cmplx(0.0_dp, 0.0_dp, kind=dp))
616 ! Allocate density matrix (MO-active sized when linearized; AO-sized otherwise)
617 NULLIFY (rtbse_env%rho)
618 ALLOCATE (rtbse_env%rho(rtbse_env%n_spin))
619 DO i = 1, rtbse_env%n_spin
620 CALL cp_cfm_create(rtbse_env%rho(i), matrix_struct=mo_struct)
621 END DO
622 ! Allocate additional space for AO density matrix
623 ! in linearised RTBSE, where default is MO
624 IF (rtbse_env%linearized) THEN
625 NULLIFY (rtbse_env%rho_ao_scratch)
626 ALLOCATE (rtbse_env%rho_ao_scratch(rtbse_env%n_spin))
627 DO i = 1, rtbse_env%n_spin
628 CALL cp_cfm_create(rtbse_env%rho_ao_scratch(i), matrix_struct=bs_env%fm_s_Gamma%matrix_struct)
629 END DO
630 END IF
631 ! Create the inverse overlap matrix, for use in density propagation
632 ! Start by creating the actual overlap matrix
633 CALL cp_fm_create(rtbse_env%S_fm, bs_env%fm_s_Gamma%matrix_struct)
634 CALL cp_fm_create(rtbse_env%S_inv_fm, bs_env%fm_s_Gamma%matrix_struct)
635 CALL cp_cfm_create(rtbse_env%S_cfm, bs_env%fm_s_Gamma%matrix_struct)
636
637 ! Create the single particle hamiltonian
638 ! Allocate workspace (MO-active sized in linearized RT-BSE; AO sized otherwise)
639 NULLIFY (rtbse_env%ham_workspace)
640 ALLOCATE (rtbse_env%ham_workspace(rtbse_env%n_spin))
641 DO i = 1, rtbse_env%n_spin
642 CALL cp_cfm_create(rtbse_env%ham_workspace(i), mo_struct)
643 CALL cp_cfm_set_all(rtbse_env%ham_workspace(i), cmplx(0.0, 0.0, kind=dp))
644 END DO
645 ! Now onto the Hamiltonian itself
646 ! full RTBSE: Contains energy differences and Hartree/COHSEX ρ_0 parts
647 ! linearised RTBSE: Contains only the Hartree/SEX ρ_0 parts as Δε * Δρ(t) need to be updated
648 NULLIFY (rtbse_env%ham_reference)
649 ALLOCATE (rtbse_env%ham_reference(rtbse_env%n_spin))
650 DO i = 1, rtbse_env%n_spin
651 CALL cp_cfm_create(rtbse_env%ham_reference(i), mo_struct)
652 END DO
653 ! Single particle Hamiltonian (Δε * Δρ(t)) for updates during timesteps in LR-RTBSE
654 IF (rtbse_env%linearized) THEN
655 NULLIFY (rtbse_env%ham_reference_singleparticle)
656 ALLOCATE (rtbse_env%ham_reference_singleparticle(rtbse_env%n_spin))
657 DO i = 1, rtbse_env%n_spin
658 CALL cp_cfm_create(rtbse_env%ham_reference_singleparticle(i), mo_struct)
659 END DO
660 NULLIFY (rtbse_env%eps_active)
661 ALLOCATE (rtbse_env%eps_active(rtbse_env%mo_active, rtbse_env%n_spin))
662 rtbse_env%eps_active(:, :) = 0.0_dp
663 END IF
664
665 ! Create the matrices and workspaces for ETRS propagation
666 NULLIFY (rtbse_env%ham_effective)
667 NULLIFY (rtbse_env%rho_new)
668 NULLIFY (rtbse_env%rho_new_last)
669 NULLIFY (rtbse_env%rho_M)
670 NULLIFY (rtbse_env%rho_orig)
671 ALLOCATE (rtbse_env%ham_effective(rtbse_env%n_spin))
672 ALLOCATE (rtbse_env%rho_new(rtbse_env%n_spin))
673 ALLOCATE (rtbse_env%rho_new_last(rtbse_env%n_spin))
674 ALLOCATE (rtbse_env%rho_M(rtbse_env%n_spin))
675 ALLOCATE (rtbse_env%rho_orig(rtbse_env%n_spin))
676 DO i = 1, rtbse_env%n_spin
677 CALL cp_cfm_create(rtbse_env%ham_effective(i), mo_struct)
678 CALL cp_cfm_set_all(rtbse_env%ham_effective(i), cmplx(0.0, 0.0, kind=dp))
679 CALL cp_cfm_create(rtbse_env%rho_new(i), mo_struct)
680 CALL cp_cfm_set_all(rtbse_env%rho_new(i), cmplx(0.0, 0.0, kind=dp))
681 CALL cp_cfm_create(rtbse_env%rho_new_last(i), mo_struct)
682 CALL cp_cfm_set_all(rtbse_env%rho_new_last(i), cmplx(0.0, 0.0, kind=dp))
683 CALL cp_cfm_create(rtbse_env%rho_M(i), mo_struct)
684 CALL cp_cfm_set_all(rtbse_env%rho_M(i), cmplx(0.0, 0.0, kind=dp))
685 CALL cp_cfm_create(rtbse_env%rho_orig(i), mo_struct)
686 END DO
687
688 !For LR-RTBSE we need RK4 coefficients - create new workspace
689 IF (rtbse_env%linearized) THEN
690 ! Indexed by SPIN, not by RK4 stage: the spin loop is inner to each stage (do_rk4_stage), so every
691 ! spin's current-stage k must be live at once, but only one stage's k per spin - each is folded
692 ! into rho_end and the next stage density before the next stage overwrites it. Hence size n_spin.
693 NULLIFY (rtbse_env%rk4_coefficients)
694 ALLOCATE (rtbse_env%rk4_coefficients(rtbse_env%n_spin))
695 DO i = 1, rtbse_env%n_spin
696 CALL cp_cfm_create(rtbse_env%rk4_coefficients(i), mo_struct)
697 CALL cp_cfm_set_all(rtbse_env%rk4_coefficients(i), cmplx(0.0, 0.0, kind=dp))
698 END DO
699 END IF
700
701 ! Fields for exact diagonalisation
702 NULLIFY (rtbse_env%real_eigvals)
703 ALLOCATE (rtbse_env%real_eigvals(rtbse_env%n_ao))
704 rtbse_env%real_eigvals(:) = 0.0_dp
705 NULLIFY (rtbse_env%exp_eigvals)
706 ALLOCATE (rtbse_env%exp_eigvals(rtbse_env%n_ao))
707 rtbse_env%exp_eigvals(:) = cmplx(0.0, 0.0, kind=dp)
708
709 ! Workspace for FT - includes (in principle) the zeroth step and the extra last step
710 NULLIFY (rtbse_env%moments_trace)
711 ! TODO : Unite the number of steps with TD-DFT
712 ALLOCATE (rtbse_env%moments_trace(rtbse_env%n_spin, 3, rtbse_env%sim_nsteps + 1), source=z_zero)
713 NULLIFY (rtbse_env%field_trace)
714 ALLOCATE (rtbse_env%field_trace(3, rtbse_env%sim_nsteps + 1), source=z_zero)
715 NULLIFY (rtbse_env%time_trace)
716 ALLOCATE (rtbse_env%time_trace(rtbse_env%sim_nsteps + 1), source=0.0_dp)
717
718 ! Allocate self-energy parts and dynamic Hartree potential.
719 ! In linearized RT-BSE these matrices hold the MO-active-sized result of the
720 ! AO->MO transform; the AO-sized buffer is allocated as sigma_*_ao below.
721 NULLIFY (rtbse_env%hartree_curr)
722 NULLIFY (rtbse_env%sigma_SEX)
723 NULLIFY (rtbse_env%sigma_COH)
724 ALLOCATE (rtbse_env%hartree_curr(rtbse_env%n_spin))
725 ALLOCATE (rtbse_env%sigma_SEX(rtbse_env%n_spin))
726 ALLOCATE (rtbse_env%sigma_COH(rtbse_env%n_spin))
727 DO i = 1, rtbse_env%n_spin
728 CALL cp_fm_create(rtbse_env%sigma_COH(i), mo_struct)
729 CALL cp_cfm_create(rtbse_env%sigma_SEX(i), mo_struct)
730 CALL cp_fm_create(rtbse_env%hartree_curr(i), mo_struct)
731 CALL cp_fm_set_all(rtbse_env%sigma_COH(i), 0.0_dp)
732 CALL cp_cfm_set_all(rtbse_env%sigma_SEX(i), cmplx(0.0, 0.0, kind=dp))
733 CALL cp_fm_set_all(rtbse_env%hartree_curr(i), 0.0_dp)
734 END DO
735 ! AO-sized scratch buffers used by the linearized RT-BSE path
736 IF (rtbse_env%linearized) THEN
737 NULLIFY (rtbse_env%hartree_curr_ao)
738 NULLIFY (rtbse_env%sigma_SEX_ao)
739 ALLOCATE (rtbse_env%hartree_curr_ao(rtbse_env%n_spin))
740 ALLOCATE (rtbse_env%sigma_SEX_ao(rtbse_env%n_spin))
741 DO i = 1, rtbse_env%n_spin
742 CALL cp_cfm_create(rtbse_env%sigma_SEX_ao(i), bs_env%fm_ks_Gamma(1)%matrix_struct)
743 CALL cp_fm_create(rtbse_env%hartree_curr_ao(i), bs_env%fm_ks_Gamma(1)%matrix_struct)
744 CALL cp_cfm_set_all(rtbse_env%sigma_SEX_ao(i), cmplx(0.0, 0.0, kind=dp))
745 CALL cp_fm_set_all(rtbse_env%hartree_curr_ao(i), 0.0_dp)
746 END DO
747 ! mo_active x mo_active real workspace pair for MO-side intermediates
748 NULLIFY (rtbse_env%real_workspace_mo)
749 ALLOCATE (rtbse_env%real_workspace_mo(2))
750 DO i = 1, SIZE(rtbse_env%real_workspace_mo)
751 CALL cp_fm_create(rtbse_env%real_workspace_mo(i), rtbse_env%fm_struct_mo_active)
752 CALL cp_fm_set_all(rtbse_env%real_workspace_mo(i), 0.0_dp)
753 END DO
754 NULLIFY (rtbse_env%ao_mo_workspace)
755 ALLOCATE (rtbse_env%ao_mo_workspace(1))
756 CALL cp_fm_create(rtbse_env%ao_mo_workspace(1), rtbse_env%fm_struct_ao_mo_active)
757 CALL cp_fm_set_all(rtbse_env%ao_mo_workspace(1), 0.0_dp)
758 ! Truncated MO coefficient slabs C_active (n_ao x mo_active) for each spin.
759 ! Filled in initialize_rtbse_env from bs_env%fm_mo_coeff_Gamma via submatrix copy.
760 NULLIFY (rtbse_env%C_active)
761 ALLOCATE (rtbse_env%C_active(rtbse_env%n_spin))
762 DO i = 1, rtbse_env%n_spin
763 CALL cp_fm_create(rtbse_env%C_active(i), rtbse_env%fm_struct_ao_mo_active)
764 CALL cp_fm_set_all(rtbse_env%C_active(i), 0.0_dp)
765 END DO
766 ! Masked-copy staging scratch for the builder (all propagation paths including closed-shell ABBA).
767 ! Also used as conjugate-transpose scratch in the TDA consumer.
768 NULLIFY (rtbse_env%rho_delta_mo)
769 ALLOCATE (rtbse_env%rho_delta_mo(rtbse_env%n_spin))
770 DO i = 1, rtbse_env%n_spin
771 CALL cp_cfm_create(rtbse_env%rho_delta_mo(i), rtbse_env%fm_struct_mo_active)
772 CALL cp_cfm_set_all(rtbse_env%rho_delta_mo(i), cmplx(0.0_dp, 0.0_dp, kind=dp))
773 END DO
774 ! Shared AO Hartree buffers: widened from (tda_active .OR. n_spin>1) so n_spin=1 ABBA
775 ! (diagnostic + propagator) gets a dedicated buffer instead of aliasing sigma_SEX_ao.
776 IF (.NOT. rtbse_env%debug_disable_hartree) THEN
777 CALL cp_cfm_create(rtbse_env%rho_total_ao_scratch, bs_env%fm_s_Gamma%matrix_struct)
778 CALL cp_cfm_create(rtbse_env%hartree_total_ao, bs_env%fm_ks_Gamma(1)%matrix_struct)
779 CALL cp_cfm_set_all(rtbse_env%rho_total_ao_scratch, cmplx(0.0_dp, 0.0_dp, kind=dp))
780 CALL cp_cfm_set_all(rtbse_env%hartree_total_ao, cmplx(0.0_dp, 0.0_dp, kind=dp))
781 END IF
782 ! Liouvillian-eigenvalue diagnostic state. n_spin=1 enforced upstream.
783 ! Shared scratch (TDA + ABBA) allocated on diagnose_liouvillian_eig=T;
784 ! ABBA-only A/B/A±B blocks added below under .NOT. tda_active. Mirror of the
785 ! existing shared-scratch pattern, with the extra tda_active gate as the deviation.
786 IF (rtbse_env%diagnose_liouvillian_eig) THEN
787 ! Joint OV dimension: the spin blocks are stacked (n_spin=1 -> the old single-spin
788 ! size). drho_probe/L_drho stay mo_active-sized per spin; L_pairs is N_OV_joint.
789 n_ov = 0
790 DO i = 1, rtbse_env%n_spin
791 n_ov = n_ov + (rtbse_env%n_occ(i) - rtbse_env%first_active_mo + 1)* &
792 (rtbse_env%last_active_mo - rtbse_env%n_occ(i))
793 END DO
794 NULLIFY (rtbse_env%fm_struct_ov_pairs)
795 CALL cp_fm_struct_create(rtbse_env%fm_struct_ov_pairs, &
796 bs_env%fm_ks_Gamma(1)%matrix_struct%para_env, &
797 bs_env%fm_ks_Gamma(1)%matrix_struct%context, &
798 n_ov, n_ov)
799 ALLOCATE (rtbse_env%drho_probe(rtbse_env%n_spin))
800 ALLOCATE (rtbse_env%L_drho(rtbse_env%n_spin))
801 DO i = 1, rtbse_env%n_spin
802 CALL cp_cfm_create(rtbse_env%drho_probe(i), rtbse_env%fm_struct_mo_active)
803 CALL cp_cfm_create(rtbse_env%L_drho(i), rtbse_env%fm_struct_mo_active)
804 CALL cp_cfm_set_all(rtbse_env%drho_probe(i), cmplx(0.0_dp, 0.0_dp, kind=dp))
805 CALL cp_cfm_set_all(rtbse_env%L_drho(i), cmplx(0.0_dp, 0.0_dp, kind=dp))
806 END DO
807 CALL cp_cfm_create(rtbse_env%L_pairs, rtbse_env%fm_struct_ov_pairs)
808 CALL cp_cfm_create(rtbse_env%eigvecs_pairs, rtbse_env%fm_struct_ov_pairs)
809 CALL cp_cfm_set_all(rtbse_env%L_pairs, cmplx(0.0_dp, 0.0_dp, kind=dp))
810 CALL cp_cfm_set_all(rtbse_env%eigvecs_pairs, cmplx(0.0_dp, 0.0_dp, kind=dp))
811 NULLIFY (rtbse_env%eigenvalues_liouvillian)
812 ALLOCATE (rtbse_env%eigenvalues_liouvillian(n_ov))
813 rtbse_env%eigenvalues_liouvillian = 0.0_dp
814 ! ABBA-only Furche-reduction scratch (A, B, A-B->sqrt, A+B).
815 IF (.NOT. rtbse_env%tda_active) THEN
816 CALL cp_cfm_create(rtbse_env%A_mat, rtbse_env%fm_struct_ov_pairs)
817 CALL cp_cfm_create(rtbse_env%B_mat, rtbse_env%fm_struct_ov_pairs)
818 CALL cp_cfm_create(rtbse_env%AmB_scratch, rtbse_env%fm_struct_ov_pairs)
819 CALL cp_cfm_create(rtbse_env%ApB_scratch, rtbse_env%fm_struct_ov_pairs)
820 CALL cp_cfm_set_all(rtbse_env%A_mat, cmplx(0.0_dp, 0.0_dp, kind=dp))
821 CALL cp_cfm_set_all(rtbse_env%B_mat, cmplx(0.0_dp, 0.0_dp, kind=dp))
822 CALL cp_cfm_set_all(rtbse_env%AmB_scratch, cmplx(0.0_dp, 0.0_dp, kind=dp))
823 CALL cp_cfm_set_all(rtbse_env%ApB_scratch, cmplx(0.0_dp, 0.0_dp, kind=dp))
824 END IF
825 END IF
826 END IF
827
828 ! Allocate workspaces for get_sigma
829 CALL create_sigma_workspace(rtbse_env)
830
831 ! Depending on the chosen methods, allocate extra workspace
832 CALL create_hartree_ri_workspace(rtbse_env)
833
834 END SUBROUTINE create_rtbse_env
835
836! **************************************************************************************************
837!> \brief Simple reimplementation of cp_fm_release_pp1 for complex matrices
838!> \param matrices cp_cfm_type(:)
839!> \author Stepan Marek
840!> \date 02.2024
841! **************************************************************************************************
842 SUBROUTINE cp_cfm_release_pa1(matrices)
843 TYPE(cp_cfm_type), DIMENSION(:), POINTER :: matrices
844 INTEGER :: i
845
846 DO i = 1, SIZE(matrices)
847 CALL cp_cfm_release(matrices(i))
848 END DO
849 DEALLOCATE (matrices)
850 NULLIFY (matrices)
851 END SUBROUTINE cp_cfm_release_pa1
852
853! **************************************************************************************************
854!> \brief Releases the environment allocated structures
855!> \param rtbse_env
856!> \author Stepan Marek
857!> \date 02.2024
858! **************************************************************************************************
859 SUBROUTINE release_rtbse_env(rtbse_env)
860 TYPE(rtbse_env_type), POINTER :: rtbse_env
861
862 CALL cp_cfm_release_pa1(rtbse_env%ham_effective)
863 CALL cp_cfm_release_pa1(rtbse_env%ham_workspace)
864 CALL cp_fm_release(rtbse_env%sigma_COH)
865 CALL cp_cfm_release_pa1(rtbse_env%sigma_SEX)
866 CALL cp_fm_release(rtbse_env%hartree_curr)
867 CALL cp_cfm_release_pa1(rtbse_env%ham_reference)
868 IF (ASSOCIATED(rtbse_env%ham_reference_singleparticle)) THEN
869 CALL cp_cfm_release_pa1(rtbse_env%ham_reference_singleparticle)
870 END IF
871 IF (ASSOCIATED(rtbse_env%eps_active)) DEALLOCATE (rtbse_env%eps_active)
872 IF (ASSOCIATED(rtbse_env%eps_active_restart)) DEALLOCATE (rtbse_env%eps_active_restart)
873 CALL cp_cfm_release_pa1(rtbse_env%rho)
874 CALL cp_cfm_release_pa1(rtbse_env%rho_workspace)
875 CALL cp_cfm_release_pa1(rtbse_env%rho_new)
876 CALL cp_cfm_release_pa1(rtbse_env%rho_new_last)
877 CALL cp_cfm_release_pa1(rtbse_env%rho_M)
878 CALL cp_cfm_release_pa1(rtbse_env%rho_orig)
879 IF (ASSOCIATED(rtbse_env%rk4_coefficients)) THEN
880 CALL cp_cfm_release_pa1(rtbse_env%rk4_coefficients)
881 END IF
882 CALL cp_fm_release(rtbse_env%real_workspace)
883 IF (ASSOCIATED(rtbse_env%sigma_complex_workspace)) CALL cp_cfm_release_pa1(rtbse_env%sigma_complex_workspace)
884 CALL cp_fm_release(rtbse_env%S_inv_fm)
885 CALL cp_fm_release(rtbse_env%S_fm)
886 CALL cp_cfm_release(rtbse_env%S_cfm)
887
888 CALL cp_fm_release(rtbse_env%moments)
889 CALL cp_fm_release(rtbse_env%moments_field)
890
891 CALL release_sigma_workspace(rtbse_env)
892
893 CALL release_hartree_ri_workspace(rtbse_env)
894
895 DEALLOCATE (rtbse_env%real_eigvals)
896 DEALLOCATE (rtbse_env%exp_eigvals)
897 DEALLOCATE (rtbse_env%moments_trace)
898 DEALLOCATE (rtbse_env%field_trace)
899 DEALLOCATE (rtbse_env%time_trace)
900
901 IF (ASSOCIATED(rtbse_env%pol_elements)) DEALLOCATE (rtbse_env%pol_elements)
902 IF (ASSOCIATED(rtbse_env%pade_x_eval)) DEALLOCATE (rtbse_env%pade_x_eval)
903
904 ! Deallocate the neighbour list that is not deallocated in gw anymore
905 IF (ASSOCIATED(rtbse_env%bs_env%nl_3c%ij_list)) CALL neighbor_list_3c_destroy(rtbse_env%bs_env%nl_3c)
906 ! Release linearized-only AO scratches and MO-side workspaces
907 IF (ASSOCIATED(rtbse_env%rho_ao_scratch)) CALL cp_cfm_release_pa1(rtbse_env%rho_ao_scratch)
908 IF (ASSOCIATED(rtbse_env%sigma_SEX_ao)) CALL cp_cfm_release_pa1(rtbse_env%sigma_SEX_ao)
909 IF (ASSOCIATED(rtbse_env%hartree_curr_ao)) CALL cp_fm_release(rtbse_env%hartree_curr_ao)
910 IF (ASSOCIATED(rtbse_env%real_workspace_mo)) CALL cp_fm_release(rtbse_env%real_workspace_mo)
911 IF (ASSOCIATED(rtbse_env%ao_mo_workspace)) CALL cp_fm_release(rtbse_env%ao_mo_workspace)
912 IF (ASSOCIATED(rtbse_env%C_active)) CALL cp_fm_release(rtbse_env%C_active)
913 IF (ASSOCIATED(rtbse_env%rho_delta_mo)) CALL cp_cfm_release_pa1(rtbse_env%rho_delta_mo)
914 ! Release shared bare-Hartree scratch. Mirror the alloc gate exactly (linearized .AND.
915 ! .NOT. debug_disable_hartree, every shell incl closed-shell ABBA) — the old
916 ! (tda_active .OR. n_spin>1) gate leaked both buffers on the closed-shell ABBA path.
917 IF (rtbse_env%linearized .AND. .NOT. rtbse_env%debug_disable_hartree) THEN
918 CALL cp_cfm_release(rtbse_env%rho_total_ao_scratch)
919 CALL cp_cfm_release(rtbse_env%hartree_total_ao)
920 END IF
921 ! Release the RI-RS Hartree diagonal-reuse accumulators (allocated in initialize_hartree_potential).
922 IF (ALLOCATED(rtbse_env%hartree_diag_re)) DEALLOCATE (rtbse_env%hartree_diag_re)
923 IF (ALLOCATED(rtbse_env%hartree_diag_im)) DEALLOCATE (rtbse_env%hartree_diag_im)
924 ! Release Liouvillian-diagnostic scratch (only when the diagnostic was requested).
925 IF (rtbse_env%diagnose_liouvillian_eig) THEN
926 IF (ASSOCIATED(rtbse_env%drho_probe)) CALL cp_cfm_release_pa1(rtbse_env%drho_probe)
927 IF (ASSOCIATED(rtbse_env%L_drho)) CALL cp_cfm_release_pa1(rtbse_env%L_drho)
928 CALL cp_cfm_release(rtbse_env%L_pairs)
929 CALL cp_cfm_release(rtbse_env%eigvecs_pairs)
930 IF (ASSOCIATED(rtbse_env%eigenvalues_liouvillian)) DEALLOCATE (rtbse_env%eigenvalues_liouvillian)
931 IF (.NOT. rtbse_env%tda_active) THEN
932 CALL cp_cfm_release(rtbse_env%A_mat)
933 CALL cp_cfm_release(rtbse_env%B_mat)
934 CALL cp_cfm_release(rtbse_env%AmB_scratch)
935 CALL cp_cfm_release(rtbse_env%ApB_scratch)
936 END IF
937 IF (ASSOCIATED(rtbse_env%fm_struct_ov_pairs)) THEN
938 CALL cp_fm_struct_release(rtbse_env%fm_struct_ov_pairs)
939 END IF
940 END IF
941 ! Release owned active-MO matrix structures
942 IF (ASSOCIATED(rtbse_env%fm_struct_mo_active)) THEN
943 CALL cp_fm_struct_release(rtbse_env%fm_struct_mo_active)
944 END IF
945 IF (ASSOCIATED(rtbse_env%fm_struct_ao_mo_active)) THEN
946 CALL cp_fm_struct_release(rtbse_env%fm_struct_ao_mo_active)
947 END IF
948 ! Deallocate the storage for the environment itself
949 DEALLOCATE (rtbse_env)
950 ! Nullify to make sure it is not used again
951 NULLIFY (rtbse_env)
952
953 END SUBROUTINE release_rtbse_env
954
955! **************************************************************************************************
956!> \brief Abort if the quasiparticle spectrum handed to the propagator is inverted or has diverged.
957!>
958!> Tests the fundamental gap per spin channel - not E(HOMO+1) - E(HOMO), since G0W0 reorders levels -
959!> on the very array the propagator consumes. Under RTBSE_HAMILTONIAN KS the quasiparticle energies
960!> never enter the propagator, so a broken G0W0 spectrum is irrelevant there and does not abort.
961!> \param rtbse_env RT-BSE environment with n_ao, n_occ, n_spin, ham_reference_type populated.
962!> \param bs_env Bandstructure environment providing the eigenvalues.
963! **************************************************************************************************
964 SUBROUTINE check_qp_gap_sanity(rtbse_env, bs_env)
965 TYPE(rtbse_env_type), POINTER :: rtbse_env
966 TYPE(post_scf_bandstructure_type), POINTER :: bs_env
967
968 INTEGER :: homo, ispin
969 REAL(kind=dp) :: gap, gap_scf
970
971 IF (rtbse_env%ham_reference_type /= rtp_bse_ham_g0w0) RETURN
972
973 DO ispin = 1, rtbse_env%n_spin
974 homo = rtbse_env%n_occ(ispin)
975 IF (homo < 1 .OR. homo >= rtbse_env%n_ao) cycle
976
977 gap = minval(bs_env%eigenval_G0W0(homo + 1:rtbse_env%n_ao, 1, ispin)) - &
978 maxval(bs_env%eigenval_G0W0(1:homo, 1, ispin))
979 gap_scf = minval(bs_env%eigenval_scf_Gamma(homo + 1:rtbse_env%n_ao, ispin)) - &
980 maxval(bs_env%eigenval_scf_Gamma(1:homo, ispin))
981
982 ! requiring a healthy SCF gap keeps the inversion test from firing on a genuine metal
983 IF (gap < -eps_qp_gap .AND. gap_scf > eps_qp_gap) THEN
984 CALL cp_abort(__location__, &
985 "RTBSE: G0W0 gap of spin "//trim(adjustl(cp_to_string(ispin)))// &
986 " is negative ("//trim(adjustl(cp_to_string(gap*evolt, '(F12.3)')))// &
987 " eV): propagating an inverted spectrum is meaningless. Check the GW "// &
988 "numerical parameters, or use RTBSE_HAMILTONIAN KS.")
989 ELSE IF (abs(gap) > max_qp_gap) THEN
990 CALL cp_abort(__location__, &
991 "RTBSE: G0W0 gap of spin "//trim(adjustl(cp_to_string(ispin)))// &
992 " is implausibly large ("// &
993 trim(adjustl(cp_to_string(gap*evolt, '(F12.3)')))//" eV): the GW step "// &
994 "has likely diverged. Check the GW numerical parameters, or use "// &
995 "RTBSE_HAMILTONIAN KS.")
996 END IF
997 END DO
998
999 END SUBROUTINE check_qp_gap_sanity
1000
1001! **************************************************************************************************
1002!> \brief Determine the combined active MO window for linearized RT-BSE truncation.
1003!>
1004!> Evaluates BSE-like cutoff indices per spin from the requested single-particle spectrum
1005!> (G0W0 or KS Gamma-point eigenvalues) and collapses them into a single combined window
1006!> covering both spin channels by choosing the most inclusive bounds. Issues a CPWARN if the
1007!> spin-resolved cutoff candidates differ. When cutoffs are disabled (or the run is not
1008!> linearized RT-BSE), the window is set to the full MO range.
1009!> \param rtbse_env RT-BSE environment with cutoff values, n_ao, n_occ, n_spin, ham_reference_type
1010!> already populated.
1011!> \param bs_env Bandstructure environment providing the eigenvalues.
1012! **************************************************************************************************
1013 SUBROUTINE determine_active_mo_window(rtbse_env, bs_env)
1014 TYPE(rtbse_env_type), POINTER :: rtbse_env
1015 TYPE(post_scf_bandstructure_type), POINTER :: bs_env
1016 CHARACTER(LEN=*), PARAMETER :: routinen = "determine_active_mo_window"
1017
1018 INTEGER :: handle, ispin, n_ao_full, n_virt
1019 INTEGER :: homo_red, virt_red, homo_incl, virt_incl
1020 INTEGER :: combined_first_occ, combined_last_virt
1021 INTEGER :: first_occ_prev, last_virt_prev
1022 LOGICAL :: spins_differ, do_truncation
1023 REAL(kind=dp) :: cutoff_occ, cutoff_empty
1024
1025 CALL timeset(routinen, handle)
1026
1027 n_ao_full = rtbse_env%n_ao
1028 cutoff_occ = rtbse_env%rtbse_energy_cutoff_occ
1029 cutoff_empty = rtbse_env%rtbse_energy_cutoff_empty
1030 do_truncation = rtbse_env%linearized .AND. (cutoff_occ > 0.0_dp .OR. cutoff_empty > 0.0_dp)
1031
1032 ! Default: full MO window
1033 rtbse_env%first_active_mo = 1
1034 rtbse_env%last_active_mo = n_ao_full
1035 rtbse_env%mo_active = n_ao_full
1036 rtbse_env%active_mo_truncation = .false.
1037
1038 IF (.NOT. do_truncation) THEN
1039 CALL timestop(handle)
1040 RETURN
1041 END IF
1042
1043 combined_first_occ = n_ao_full
1044 combined_last_virt = 1
1045 first_occ_prev = -1
1046 last_virt_prev = -1
1047 spins_differ = .false.
1048
1049 DO ispin = 1, rtbse_env%n_spin
1050 n_virt = n_ao_full - rtbse_env%n_occ(ispin)
1051 ! Cut on the DFT axis, as LRBSE does: it is ascending by construction, so the window is a
1052 ! well-defined contiguous MO range, which is all C_active can extract. The G0W0 axis is
1053 ! not ordered.
1054 CALL determine_cutoff_indices(bs_env%eigenval_scf_Gamma(:, ispin), &
1055 rtbse_env%n_occ(ispin), n_virt, &
1056 homo_red, virt_red, homo_incl, virt_incl, &
1057 cutoff_occ, cutoff_empty)
1058 ! Translate the per-spin candidate to global MO indices [homo_incl, homo + virt_incl]
1059 IF (ispin > 1) THEN
1060 IF (homo_incl /= first_occ_prev .OR. (rtbse_env%n_occ(ispin) + virt_incl) /= last_virt_prev) THEN
1061 spins_differ = .true.
1062 END IF
1063 END IF
1064 first_occ_prev = homo_incl
1065 last_virt_prev = rtbse_env%n_occ(ispin) + virt_incl
1066 combined_first_occ = min(combined_first_occ, homo_incl)
1067 combined_last_virt = max(combined_last_virt, rtbse_env%n_occ(ispin) + virt_incl)
1068 END DO
1069
1070 IF (spins_differ) THEN
1071 cpwarn("RTBSE: spin-resolved active MO cutoff candidates differ; using combined window.")
1072 END IF
1073
1074 rtbse_env%first_active_mo = combined_first_occ
1075 rtbse_env%last_active_mo = combined_last_virt
1076 rtbse_env%mo_active = combined_last_virt - combined_first_occ + 1
1077 rtbse_env%active_mo_truncation = (rtbse_env%mo_active < n_ao_full)
1078
1079 CALL timestop(handle)
1080 END SUBROUTINE determine_active_mo_window
1081
1082! **************************************************************************************************
1083!> \brief Allocates the workspaces for Hartree RI method
1084!> \note RI method calculates the Hartree contraction without the use of DBT, as it cannot emulate vectors
1085!> \param rtbse_env
1086!> \author Stepan Marek
1087!> \date 05.2024
1088! **************************************************************************************************
1089 SUBROUTINE create_hartree_ri_workspace(rtbse_env)
1090 TYPE(rtbse_env_type) :: rtbse_env
1091 TYPE(post_scf_bandstructure_type), POINTER :: bs_env
1092
1093 ! Skip the AO-RI Hartree scratch when the RT-BSE Hartree path is fully RI-RS.
1094 ! In that case rho_dbcsr / v_ao_dbcsr / int_3c_array are never read.
1095 ! get_sigma_real (AO-RI SX) used to borrow rho_dbcsr as a workspace; that
1096 ! cross-dependency was removed by giving get_sigma_real its own local
1097 ! dbcsr scratch (see rt_bse.F::get_sigma_real). rho_dbcsr is now AO-RI
1098 ! Hartree only, as its name suggests.
1099 IF (rtbse_env%rirs_kernel) RETURN
1100
1101 CALL get_qs_env(rtbse_env%qs_env, bs_env=bs_env)
1102
1103 CALL dbcsr_create(rtbse_env%rho_dbcsr, name="Sparse density", template=bs_env%mat_ao_ao%matrix)
1104 CALL dbcsr_create(rtbse_env%v_ao_dbcsr, name="Sparse Hartree", template=bs_env%mat_ao_ao%matrix)
1105
1106 CALL create_hartree_ri_3c(rtbse_env%rho_dbcsr, rtbse_env%int_3c_array, rtbse_env%n_ao, rtbse_env%n_RI, &
1107 bs_env%basis_set_AO, bs_env%basis_set_RI, bs_env%i_RI_start_from_atom, &
1108 bs_env%ri_metric, rtbse_env%qs_env, rtbse_env%unit_nr)
1109 END SUBROUTINE create_hartree_ri_workspace
1110! **************************************************************************************************
1111!> \brief Separated method for allocating the 3c integrals for RI Hartree
1112!> \note RI method calculates the Hartree contraction without the use of DBT, as it cannot emulate vectors
1113!> \param rho_dbcsr matrix used for the description of shape of 3c array
1114!> \param int_3c 3-center integral array to be allocated and filled
1115!> \param n_ao Number of atomic orbitals
1116!> \param n_RI Number of auxiliary RI orbitals
1117!> \param basis_set_AO AO basis set
1118!> \param basis_set_RI RI auxiliary basis set
1119!> \param i_RI_start_from_atom Array of indices where functions of a given atom in RI basis start
1120!> \param unit_nr Unit number used for printing information about the size of int_3c
1121!> \author Stepan Marek
1122!> \date 01.2025
1123! **************************************************************************************************
1124 SUBROUTINE create_hartree_ri_3c(rho_dbcsr, int_3c, n_ao, n_RI, basis_set_AO, basis_set_RI, &
1125 i_RI_start_from_atom, ri_metric, qs_env, unit_nr)
1126 TYPE(dbcsr_type) :: rho_dbcsr
1127 REAL(kind=dp), DIMENSION(:, :, :), POINTER :: int_3c
1128 INTEGER :: n_ao, n_ri
1129 TYPE(gto_basis_set_p_type), DIMENSION(:) :: basis_set_ao, &
1130 basis_set_ri
1131 INTEGER, DIMENSION(:) :: i_ri_start_from_atom
1132 TYPE(libint_potential_type) :: ri_metric
1133 TYPE(qs_environment_type), POINTER :: qs_env
1134 INTEGER :: unit_nr
1135 REAL(kind=dp) :: size_mb
1136 INTEGER :: nblkrows_local, &
1137 nblkcols_local, &
1138 i_blk_local, &
1139 j_blk_local, &
1140 nrows_local, &
1141 ncols_local, &
1142 col_local_offset, &
1143 row_local_offset, &
1144 start_col_index, &
1145 end_col_index, &
1146 start_row_index, &
1147 end_row_index
1148 INTEGER, DIMENSION(:), POINTER :: local_blk_rows, &
1149 local_blk_cols, &
1150 row_blk_size, &
1151 col_blk_size
1152 ! TODO : Implement option/decision to not precompute all the 3c integrals
1153 size_mb = real(n_ao, kind=dp)*real(n_ao, kind=dp)*real(n_ri, kind=dp)* &
1154 REAL(storage_size(size_mb), kind=dp)/8.0_dp/1024.0_dp/1024.0_dp
1155 IF (unit_nr > 0) WRITE (unit_nr, '(A44,E32.2E3,A4)') &
1156 " RTBSE| Approximate size of the 3c integrals", size_mb, " MiB"
1157
1158 ! Get the number of block rows and columns
1159 CALL dbcsr_get_info(rho_dbcsr, nblkrows_local=nblkrows_local, nblkcols_local=nblkcols_local)
1160 ! Get the global indices of local rows and columns
1161 CALL dbcsr_get_info(rho_dbcsr, local_rows=local_blk_rows, local_cols=local_blk_cols)
1162 ! Get the sizes of all blocks
1163 CALL dbcsr_get_info(rho_dbcsr, row_blk_size=row_blk_size, col_blk_size=col_blk_size)
1164
1165 ! Get the total required local rows and cols
1166 nrows_local = 0
1167 DO i_blk_local = 1, nblkrows_local
1168 nrows_local = nrows_local + row_blk_size(local_blk_rows(i_blk_local))
1169 END DO
1170 ncols_local = 0
1171 DO j_blk_local = 1, nblkcols_local
1172 ncols_local = ncols_local + col_blk_size(local_blk_cols(j_blk_local))
1173 END DO
1174
1175 ! Allocate the appropriate storage
1176 ALLOCATE (int_3c(nrows_local, ncols_local, n_ri))
1177
1178 ! Fill the storage with appropriate values, block by block
1179 row_local_offset = 1
1180 DO i_blk_local = 1, nblkrows_local
1181 col_local_offset = 1
1182 DO j_blk_local = 1, nblkcols_local
1183 start_row_index = row_local_offset
1184 end_row_index = start_row_index + row_blk_size(local_blk_rows(i_blk_local)) - 1
1185 start_col_index = col_local_offset
1186 end_col_index = start_col_index + col_blk_size(local_blk_cols(j_blk_local)) - 1
1187 CALL build_3c_integral_block(int_3c(start_row_index:end_row_index, &
1188 start_col_index:end_col_index, &
1189 1:n_ri), &
1190 qs_env, potential_parameter=ri_metric, &
1191 basis_j=basis_set_ao, basis_k=basis_set_ao, &
1192 basis_i=basis_set_ri, &
1193 atom_j=local_blk_rows(i_blk_local), &
1194 atom_k=local_blk_cols(j_blk_local), &
1195 i_bf_start_from_atom=i_ri_start_from_atom)
1196 col_local_offset = col_local_offset + col_blk_size(local_blk_cols(j_blk_local))
1197 END DO
1198 row_local_offset = row_local_offset + row_blk_size(local_blk_rows(i_blk_local))
1199 END DO
1200 END SUBROUTINE create_hartree_ri_3c
1201! **************************************************************************************************
1202!> \brief Releases the workspace for the Hartree RI method
1203!> \param rtbse_env RT-BSE Environment, containing specific RI Hartree storage
1204!> \author Stepan Marek
1205!> \date 09.2024
1206! **************************************************************************************************
1207 SUBROUTINE release_hartree_ri_workspace(rtbse_env)
1208 TYPE(rtbse_env_type) :: rtbse_env
1209
1210 ! Mirror the gate in create_hartree_ri_workspace and the v_dbcsr gate in
1211 ! initialize_hartree_potential. With one KERNEL_RI switch the AO-RI Hartree
1212 ! scratch (3c integrals + dbcsr work + v_dbcsr) is created iff `.NOT. rirs_kernel`.
1213 IF (.NOT. rtbse_env%rirs_kernel) THEN
1214 DEALLOCATE (rtbse_env%int_3c_array)
1215 CALL dbcsr_release(rtbse_env%rho_dbcsr)
1216 CALL dbcsr_release(rtbse_env%v_ao_dbcsr)
1217 CALL dbcsr_release(rtbse_env%v_dbcsr)
1218 END IF
1219 END SUBROUTINE release_hartree_ri_workspace
1220! **************************************************************************************************
1221!> \brief Allocates the workspaces for self-energy determination routine
1222!> \param rtbse_env Structure for holding information and workspace structures
1223!> \author Stepan Marek
1224!> \date 02.2024
1225! **************************************************************************************************
1226 SUBROUTINE create_sigma_workspace(rtbse_env)
1227 TYPE(rtbse_env_type) :: rtbse_env
1228
1229 ! Skip the AO-RI sigma scratch (W matrix + 3c integrals + work tensors)
1230 ! when the RT-BSE SEX path is fully RI-RS — these workspaces are read
1231 ! only by get_sigma in the `.NOT. rirs_kernel` branches.
1232 IF (rtbse_env%rirs_kernel) RETURN
1233
1234 CALL create_sigma_workspace_qs_only(rtbse_env%qs_env, rtbse_env%screened_dbt, rtbse_env%w_dbcsr, &
1235 rtbse_env%t_3c_w, rtbse_env%t_3c_work_RI_AO__AO, &
1236 rtbse_env%t_3c_work2_RI_AO__AO, rtbse_env%greens_dbt)
1237 END SUBROUTINE create_sigma_workspace
1238! **************************************************************************************************
1239!> \brief Allocates the workspaces for self-energy determination routine
1240!> \note Does so without referencing the rtbse_env
1241!> \note References bs_env
1242!> \param rtbse_env Structure for holding information and workspace structures
1243!> \param qs_env Quickstep environment - entry point of calculation
1244!> \author Stepan Marek
1245!> \date 02.2024
1246! **************************************************************************************************
1247 SUBROUTINE create_sigma_workspace_qs_only(qs_env, screened_dbt, screened_dbcsr, int_3c_dbt, &
1248 work_dbt_3c_1, work_dbt_3c_2, work_dbt_2c)
1249 TYPE(qs_environment_type), POINTER :: qs_env
1250 TYPE(dbcsr_type) :: screened_dbcsr
1251 TYPE(dbt_type) :: screened_dbt, &
1252 int_3c_dbt, &
1253 work_dbt_3c_1, &
1254 work_dbt_3c_2, &
1255 work_dbt_2c
1256 TYPE(post_scf_bandstructure_type), POINTER :: bs_env
1257
1258 CALL get_qs_env(qs_env, bs_env=bs_env)
1259
1260 ! t_3c_w
1261 CALL dbt_create(bs_env%t_RI__AO_AO, int_3c_dbt)
1262 ! TODO : Provide option/decision whether to store the 3c integrals precomputed
1263 CALL compute_3c_integrals(qs_env, bs_env, int_3c_dbt)
1264 ! t_3c_work_RI_AO__AO
1265 CALL dbt_create(bs_env%t_RI_AO__AO, work_dbt_3c_1)
1266 ! t_3c_work2_RI_AO__AO
1267 CALL dbt_create(bs_env%t_RI_AO__AO, work_dbt_3c_2)
1268 ! t_W
1269 ! Populate screened_dbt from gw run
1270 CALL dbcsr_create(screened_dbcsr, name="W", template=bs_env%mat_RI_RI%matrix)
1271 CALL dbt_create(screened_dbcsr, screened_dbt)
1272 ! greens_dbt
1273 CALL dbt_create(bs_env%mat_ao_ao%matrix, work_dbt_2c)
1274 END SUBROUTINE create_sigma_workspace_qs_only
1275! **************************************************************************************************
1276!> \brief Releases the workspaces for self-energy determination
1277!> \param rtbse_env
1278!> \author Stepan Marek
1279!> \date 02.2024
1280! **************************************************************************************************
1281 SUBROUTINE release_sigma_workspace(rtbse_env)
1282 TYPE(rtbse_env_type) :: rtbse_env
1283
1284 ! Mirror the gate in create_sigma_workspace.
1285 IF (rtbse_env%rirs_kernel) RETURN
1286
1287 CALL dbt_destroy(rtbse_env%t_3c_w)
1288 CALL dbt_destroy(rtbse_env%t_3c_work_RI_AO__AO)
1289 CALL dbt_destroy(rtbse_env%t_3c_work2_RI_AO__AO)
1290 CALL dbt_destroy(rtbse_env%screened_dbt)
1291 CALL dbt_destroy(rtbse_env%greens_dbt)
1292 CALL dbcsr_release(rtbse_env%w_dbcsr)
1293 END SUBROUTINE release_sigma_workspace
1294! **************************************************************************************************
1295!> \brief Multiplies real matrix by a complex matrix from the right
1296!> \note So far only converts the real matrix to complex one, potentially doubling the work
1297!> \param rtbse_env
1298!> \author Stepan Marek
1299!> \date 09.2024
1300! **************************************************************************************************
1301 SUBROUTINE multiply_fm_cfm(trans_r, trans_c, na, nb, nc, &
1302 alpha, matrix_r, matrix_c, beta, res)
1303 ! Transposition
1304 CHARACTER(len=1) :: trans_r, trans_c
1305 INTEGER :: na, nb, nc
1306 ! accept real numbers
1307 ! TODO : Just use complex numbers and import z_one, z_zero etc.
1308 REAL(kind=dp) :: alpha, beta
1309 TYPE(cp_fm_type) :: matrix_r
1310 TYPE(cp_cfm_type) :: matrix_c, res
1311 TYPE(cp_fm_type) :: work_re, work_im, res_re, res_im
1312 REAL(kind=dp) :: i_unit
1313 CHARACTER(len=1) :: trans_cr
1314
1315 CALL cp_fm_create(work_re, matrix_c%matrix_struct)
1316 CALL cp_fm_create(work_im, matrix_c%matrix_struct)
1317 CALL cp_fm_create(res_re, res%matrix_struct)
1318 CALL cp_fm_create(res_im, res%matrix_struct)
1319 CALL cp_cfm_to_fm(matrix_c, work_re, work_im)
1320 SELECT CASE (trans_c)
1321 CASE ("C")
1322 i_unit = -1.0_dp
1323 trans_cr = "T"
1324 CASE ("T")
1325 i_unit = 1.0_dp
1326 trans_cr = "T"
1327 CASE default
1328 i_unit = 1.0_dp
1329 trans_cr = "N"
1330 END SELECT
1331 ! Actual multiplication
1332 CALL parallel_gemm(trans_r, trans_cr, na, nb, nc, &
1333 alpha, matrix_r, work_re, beta, res_re)
1334 CALL parallel_gemm(trans_r, trans_cr, na, nb, nc, &
1335 i_unit*alpha, matrix_r, work_im, beta, res_im)
1336 CALL cp_fm_to_cfm(res_re, res_im, res)
1337 CALL cp_fm_release(work_re)
1338 CALL cp_fm_release(work_im)
1339 CALL cp_fm_release(res_re)
1340 CALL cp_fm_release(res_im)
1341
1342 END SUBROUTINE multiply_fm_cfm
1343! **************************************************************************************************
1344!> \brief Multiplies complex matrix by a real matrix from the right
1345!> \note So far only converts the real matrix to complex one, potentially doubling the work
1346!> \param rtbse_env
1347!> \author Stepan Marek
1348!> \date 09.2024
1349! **************************************************************************************************
1350 SUBROUTINE multiply_cfm_fm(trans_c, trans_r, na, nb, nc, &
1351 alpha, matrix_c, matrix_r, beta, res)
1352 ! Transposition
1353 CHARACTER(len=1) :: trans_c, trans_r
1354 INTEGER :: na, nb, nc
1355 ! accept real numbers
1356 ! TODO : complex number support via interface?
1357 REAL(kind=dp) :: alpha, beta
1358 TYPE(cp_cfm_type) :: matrix_c, res
1359 TYPE(cp_fm_type) :: matrix_r
1360 TYPE(cp_fm_type) :: work_re, work_im, res_re, res_im
1361 REAL(kind=dp) :: i_unit
1362 CHARACTER(len=1) :: trans_cr
1363
1364 CALL cp_fm_create(work_re, matrix_c%matrix_struct)
1365 CALL cp_fm_create(work_im, matrix_c%matrix_struct)
1366 CALL cp_fm_create(res_re, res%matrix_struct)
1367 CALL cp_fm_create(res_im, res%matrix_struct)
1368 CALL cp_cfm_to_fm(matrix_c, work_re, work_im)
1369 SELECT CASE (trans_c)
1370 CASE ("C")
1371 i_unit = -1.0_dp
1372 trans_cr = "T"
1373 CASE ("T")
1374 i_unit = 1.0_dp
1375 trans_cr = "T"
1376 CASE default
1377 i_unit = 1.0_dp
1378 trans_cr = "N"
1379 END SELECT
1380 ! Actual multiplication
1381 CALL parallel_gemm(trans_cr, trans_r, na, nb, nc, &
1382 alpha, work_re, matrix_r, beta, res_re)
1383 CALL parallel_gemm(trans_cr, trans_r, na, nb, nc, &
1384 i_unit*alpha, work_im, matrix_r, beta, res_im)
1385 CALL cp_fm_to_cfm(res_re, res_im, res)
1386 CALL cp_fm_release(work_re)
1387 CALL cp_fm_release(work_im)
1388 CALL cp_fm_release(res_re)
1389 CALL cp_fm_release(res_im)
1390
1391 END SUBROUTINE multiply_cfm_fm
1392END MODULE rt_bse_types
Auxiliary routines for GW + Bethe-Salpeter for computing electronic excitations.
Definition bse_util.F:13
subroutine, public determine_cutoff_indices(eigenval, homo, virtual, homo_red, virt_red, homo_incl, virt_incl, cutoff_occ, cutoff_empty)
Reads cutoffs for BSE from mp2_env and compares to energies in Eigenval to extract reduced homo/virtu...
Definition bse_util.F:1187
Represents a complex full matrix distributed on many processors.
subroutine, public cp_cfm_release(matrix)
Releases a full matrix.
subroutine, public cp_fm_to_cfm(msourcer, msourcei, mtarget)
Construct a complex full matrix by taking its real and imaginary parts from two separate real-value f...
subroutine, public cp_cfm_create(matrix, matrix_struct, name, nrow, ncol, set_zero)
Creates a new full matrix with the given structure.
subroutine, public cp_cfm_set_all(matrix, alpha, beta)
Set all elements of the full matrix to alpha. Besides, set all diagonal matrix elements to beta (if g...
subroutine, public cp_cfm_to_fm(msource, mtargetr, mtargeti)
Copy real and imaginary parts of a complex full matrix into separate real-value full matrices.
Defines control structures, which contain the parameters and the settings for the DFT-based calculati...
subroutine, public dbcsr_get_info(matrix, nblkrows_total, nblkcols_total, nfullrows_total, nfullcols_total, nblkrows_local, nblkcols_local, nfullrows_local, nfullcols_local, my_prow, my_pcol, local_rows, local_cols, proc_row_dist, proc_col_dist, row_blk_size, col_blk_size, row_blk_offset, col_blk_offset, distribution, name, matrix_type, group)
...
subroutine, public dbcsr_release(matrix)
...
represent the structure of a full matrix
subroutine, public cp_fm_struct_create(fmstruct, para_env, context, nrow_global, ncol_global, nrow_block, ncol_block, descriptor, first_p_pos, local_leading_dimension, template_fmstruct, square_blocks, force_block)
allocates and initializes a full matrix structure
subroutine, public cp_fm_struct_release(fmstruct)
releases a full matrix structure
represent a full matrix distributed on many processors
Definition cp_fm_types.F:15
subroutine, public cp_fm_set_all(matrix, alpha, beta)
set all elements of a matrix to the same value, and optionally the diagonal to a different one
subroutine, public cp_fm_create(matrix, matrix_struct, name, nrow, ncol, set_zero)
creates a new full matrix with the given structure
various routines to log and control the output. The idea is that decisions about where to log should ...
This is the start of a dbt_api, all publically needed functions are exported here....
Definition dbt_api.F:17
Interface for the force calculations.
Utility method to build 3-center integrals for small cell GW.
subroutine, public build_3c_integral_block(int_3c, qs_env, potential_parameter, basis_j, basis_k, basis_i, cell_j, cell_k, cell_i, atom_j, atom_k, atom_i, j_bf_start_from_atom, k_bf_start_from_atom, i_bf_start_from_atom)
...
Routines from paper [Graml2024].
subroutine, public compute_3c_integrals(qs_env, bs_env, t_3c, atoms_ao_1, atoms_ao_2, atoms_ri)
...
subroutine, public rtbse_resolve_rirs_flag(qs_env, bs_env, rirs_kernel)
Resolve the linRTBSE RI-RS kernel switch from the KERNEL_RI input and the GW default.
Definition gw_utils.F:285
collects all constants needed in input so that they can be used without circular dependencies
integer, parameter, public use_mom_ref_coac
integer, parameter, public rtp_method_bse_linearized
integer, parameter, public do_bch
integer, parameter, public do_exact
integer, parameter, public rtp_bse_ham_g0w0
objects that represent the structure of input sections and the data contained in an input section
recursive type(section_vals_type) function, pointer, public section_vals_get_subs_vals(section_vals, subsection_name, i_rep_section, can_return_null)
returns the values of the requested subsection
subroutine, public section_vals_val_get(section_vals, keyword_name, i_rep_section, i_rep_val, n_rep_val, val, l_val, i_val, r_val, c_val, l_vals, i_vals, r_vals, c_vals, explicit)
returns the requested value
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34
2- and 3-center electron repulsion integral routines based on libint2 Currently available operators: ...
Definition of mathematical constants and functions.
complex(kind=dp), parameter, public z_zero
basic linear algebra operations for full matrixes
Definition of physical constants:
Definition physcon.F:68
real(kind=dp), parameter, public evolt
Definition physcon.F:183
real(kind=dp), parameter, public max_qp_gap
real(kind=dp), parameter, public eps_qp_gap
subroutine, public get_qs_env(qs_env, atomic_kind_set, qs_kind_set, cell, super_cell, cell_ref, use_ref_cell, kpoints, dft_control, mos, sab_orb, sab_all, qmmm, qmmm_periodic, mimic, sac_ae, sac_ppl, sac_lri, sap_ppnl, sab_vdw, sab_scp, sap_oce, sab_lrc, sab_se, sab_xtbe, sab_tbe, sab_core, sab_xb, sab_xtb_pp, sab_xtb_nonbond, sab_almo, sab_kp, sab_kp_nosym, sab_cneo, particle_set, energy, force, matrix_h, matrix_h_im, matrix_ks, matrix_ks_im, matrix_vxc, run_rtp, rtp, matrix_h_kp, matrix_h_im_kp, matrix_ks_kp, matrix_ks_im_kp, matrix_vxc_kp, kinetic_kp, matrix_s_kp, matrix_w_kp, matrix_s_ri_aux_kp, matrix_s, matrix_s_ri_aux, matrix_w, matrix_p_mp2, matrix_p_mp2_admm, matrix_vhxc, rho, rho_xc, pw_env, ewald_env, ewald_pw, active_space, mpools, input, para_env, blacs_env, scf_control, rel_control, kinetic, qs_charges, vppl, xcint_weights, rho_core, rho_nlcc, rho_nlcc_g, ks_env, ks_qmmm_env, wf_history, scf_env, local_particles, local_molecules, distribution_2d, dbcsr_dist, molecule_kind_set, molecule_set, subsys, cp_subsys, oce, local_rho_set, rho_atom_set, task_list, task_list_soft, rho0_atom_set, rho0_mpole, rhoz_set, rhoz_cneo_set, ecoul_1c, rho0_s_rs, rho0_s_gs, rhoz_cneo_s_rs, rhoz_cneo_s_gs, do_kpoints, has_unit_metric, requires_mo_derivs, mo_derivs, mo_loc_history, nkind, natom, nelectron_total, nelectron_spin, efield, neighbor_list_id, linres_control, xas_env, virial, cp_ddapc_env, cp_ddapc_ewald, outer_scf_history, outer_scf_ihistory, x_data, et_coupling, dftb_potential, results, se_taper, se_store_int_env, se_nddo_mpole, se_nonbond_env, admm_env, lri_env, lri_density, exstate_env, ec_env, harris_env, dispersion_env, gcp_env, vee, rho_external, external_vxc, mask, mp2_env, bs_env, kg_env, wanniercentres, atprop, ls_scf_env, do_transport, transport_env, v_hartree_rspace, s_mstruct_changed, rho_changed, potential_changed, forces_up_to_date, mscfg_env, almo_scf_env, gradient_history, variable_history, embed_pot, spin_embed_pot, polar_env, mos_last_converged, eeq, rhs, do_rixs, tb_tblite)
Get the QUICKSTEP environment.
Definition and initialisation of the mo data type.
Definition qs_mo_types.F:22
Utility methods to build 3-center integral tensors of various types.
Definition qs_tensors.F:11
subroutine, public neighbor_list_3c_destroy(ijk_list)
Destroy 3c neighborlist.
Definition qs_tensors.F:381
Data storage and other types for propagation via RT-BSE method.
subroutine, public create_rtbse_env(rtbse_env, force_env, linearized)
Allocates structures and prepares rtbse_env for run.
subroutine, public release_rtbse_env(rtbse_env)
Releases the environment allocated structures.
subroutine, public create_hartree_ri_3c(rho_dbcsr, int_3c, n_ao, n_ri, basis_set_ao, basis_set_ri, i_ri_start_from_atom, ri_metric, qs_env, unit_nr)
Separated method for allocating the 3c integrals for RI Hartree.
subroutine, public multiply_cfm_fm(trans_c, trans_r, na, nb, nc, alpha, matrix_c, matrix_r, beta, res)
Multiplies complex matrix by a real matrix from the right.
subroutine, public create_sigma_workspace_qs_only(qs_env, screened_dbt, screened_dbcsr, int_3c_dbt, work_dbt_3c_1, work_dbt_3c_2, work_dbt_2c)
Allocates the workspaces for self-energy determination routine.
subroutine, public multiply_fm_cfm(trans_r, trans_c, na, nb, nc, alpha, matrix_r, matrix_c, beta, res)
Multiplies real matrix by a complex matrix from the right.
Types and set_get for real time propagation depending on runtype and diagonalization method different...
Routines needed for EMD.
subroutine, public warn_section_unused(section, subsection_name, error_message)
Warn about unused sections of the print section - only implemented for some of the methods.
Represent a complex full matrix.
keeps the information about the structure of a full matrix
represent a full matrix
wrapper to abstract the force evaluation of the various methods