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 GW using RI-RS Approximation for molecules
10 : !> \par History
11 : !> 04.2026 created [Ritaj Tyagi]
12 : ! **************************************************************************************************
13 :
14 : MODULE gw_ri_rs_non_periodic
15 : USE cp_dbcsr_api, ONLY: dbcsr_get_info
16 : USE cp_fm_diag, ONLY: cp_fm_geeig
17 : USE cp_fm_types, ONLY: cp_fm_create,&
18 : cp_fm_get_diag,&
19 : cp_fm_release,&
20 : cp_fm_to_fm,&
21 : cp_fm_type
22 : USE gw_compute_V_and_W, ONLY: compute_W
23 : USE gw_ri_rs_chi_sigma_kernels, ONLY: compute_Sigma_c,&
24 : compute_Sigma_x,&
25 : get_mat_chi_Gamma_tau
26 : USE gw_tensor_large_cell_Gamma, ONLY: delete_unnecessary_files
27 : USE gw_utils, ONLY: analyt_conti_and_print,&
28 : de_init_bs_env
29 : USE gw_utils_fm, ONLY: fm_contract_ABA
30 : USE input_constants, ONLY: G0W0,&
31 : evGW0
32 : USE kinds, ONLY: dp,&
33 : int_8,&
34 : max_line_length
35 : USE message_passing, ONLY: mp_mem_avail_per_rank_GB,&
36 : mp_print_mem_per_rank
37 : USE physcon, ONLY: evolt
38 : USE post_scf_bandstructure_types, ONLY: post_scf_bandstructure_type
39 : USE post_scf_bandstructure_utils, ONLY: get_all_VBM_CBM_bandgaps
40 : USE qs_environment_types, ONLY: qs_environment_type
41 : USE ri_rs_matrices, ONLY: mask_grid_blocks_near_panel,&
42 : panel_mem_estimate_GB,&
43 : panel_template_elems,&
44 : resolve_grid_panels
45 : USE ri_rs_setup, ONLY: ensure_ri_rs_representation
46 : USE time_frequency_grids, ONLY: negative_time,&
47 : positive_time,&
48 : transform_time_to_frequency
49 : #include "./base/base_uses.f90"
50 :
51 : IMPLICIT NONE
52 :
53 : PRIVATE
54 :
55 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'gw_ri_rs_non_periodic'
56 :
57 : PUBLIC :: gw_calc_ri_rs_non_periodic
58 :
59 : CONTAINS
60 :
61 : ! **************************************************************************************************
62 : !> \brief GW calculation using RI-RS formalism for molecules
63 : !> \param qs_env ...
64 : !> \param bs_env Band-structure environment containing GW parameters.
65 : ! **************************************************************************************************
66 40 : SUBROUTINE gw_calc_ri_rs_non_periodic(qs_env, bs_env)
67 :
68 : TYPE(qs_environment_type), POINTER :: qs_env
69 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
70 :
71 : CHARACTER(LEN=*), PARAMETER :: routineN = 'gw_calc_ri_rs_non_periodic'
72 :
73 : INTEGER :: handle
74 40 : TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:) :: fm_Sigma_x_Gamma, fm_W_time
75 :
76 40 : CALL timeset(routineN, handle)
77 :
78 : ! Build the common grid, phi and Z representation with the system's boundary conditions.
79 40 : CALL ensure_ri_rs_representation(qs_env, bs_env)
80 40 : IF (bs_env%unit_nr > 0) WRITE (bs_env%unit_nr, '(A)') ' '
81 40 : CALL print_ri_rs_memory_estimate(bs_env)
82 :
83 : CALL mp_print_mem_per_rank(bs_env%para_env, bs_env%unit_nr, &
84 40 : label='Memory per MPI process after computing Z_lP:')
85 :
86 : ! ==============================================================================
87 : ! 4. Polarizability matrix χ on the imaginary-time grid
88 : ! G^occ_µλ(i|τ|) = Σ_n^occ C_µn e^(-|(ϵ_n-ϵ_F)τ|) C_λn
89 : ! G^vir_µλ(i|τ|) = Σ_n^vir C_µn e^(-|(ϵ_n-ϵ_F)τ|) C_λn
90 : ! G^occ_ll'(i|τ|) = Σ_µν ϕ_µ(r_l) G^occ_µν ϕ_ν(r_l') (G^vir analogous)
91 : ! χ_ll'(iτ) = G^occ_ll'(i|τ|) ∘ G^vir_ll'(i|τ|) (element-wise)
92 : ! χ_PQ(iτ) = Σ_ll' Z_lP χ_ll'(iτ) Z_l'Q
93 : ! ==============================================================================
94 40 : CALL get_mat_chi_Gamma_tau(bs_env, bs_env%mat_chi_Gamma_tau, bs_env%ri_rs%cutoff_radius_v_w)
95 :
96 : ! ==============================================================================
97 : ! 5. Screened Coulomb interaction W (RI basis)
98 : ! χ_PQ(iτ) -> χ_PQ(iω) -> ε_PQ(iω) -> W_PQ(iω) -> W_PQ(iτ)
99 : ! ==============================================================================
100 40 : CALL compute_W(bs_env, qs_env, bs_env%mat_chi_Gamma_tau, fm_W_time)
101 :
102 : ! ==============================================================================
103 : ! 6. Exact-exchange self-energy Σ^x
104 : ! D_µν = Σ_n^occ C_µn C_νn (density matrix)
105 : ! D_ll' = Σ_µν ϕ_µ(r_l) D_µν ϕ_ν(r_l')
106 : ! V^tr_ll' = Σ_PQ Z_lP V^tr_PQ Z_l'Q (truncated Coulomb)
107 : ! Σ^x_ll' = D_ll' ∘ V^tr_ll'
108 : ! Σ^x_λσ(k=0) = -Σ_ll' ϕ_λ(r_l) Σ^x_ll' ϕ_σ(r_l')
109 : ! ==============================================================================
110 40 : CALL compute_Sigma_x(bs_env, qs_env, fm_Sigma_x_Gamma, bs_env%ri_rs%cutoff_radius_v_w)
111 :
112 : ! ==============================================================================
113 : ! 7. Correlation self-energy Σ^c and quasiparticle energies, iterated
114 : ! until eigenvalue self-consistency if the &EVGW0 section is given and
115 : ! done in a single pass for G0W0.
116 : !
117 : ! (a) W_ll'(iτ) = Σ_PQ Z_lP W^MIC_PQ(iτ) Z_l'Q
118 : ! Σ^c_ll'(iτ) = -G^occ_ll'(i|τ|) ∘ W_ll'(iτ), τ < 0
119 : ! Σ^c_ll'(iτ) = G^vir_ll'(i|τ|) ∘ W_ll'(iτ), τ > 0
120 : ! Σ^c_λσ(iτ) = Σ_ll' ϕ_λ(r_l) Σ^c_ll'(iτ) ϕ_σ(r_l')
121 : ! (b) Σ^c_λσ(iτ) -> Σ^c_nn(ϵ)
122 : ! ϵ_n^GW,(i) = ϵ_n^DFT + Σ^c_nn[G^(i-1),W](ϵ_n^GW,(i)) + Σ^x_nn - v^xc_nn
123 : ! ==============================================================================
124 40 : CALL compute_Sigma_c_and_QP_energies(bs_env, fm_W_time, fm_Sigma_x_Gamma)
125 :
126 40 : CALL de_init_bs_env(qs_env, bs_env)
127 :
128 40 : CALL timestop(handle)
129 :
130 40 : END SUBROUTINE gw_calc_ri_rs_non_periodic
131 :
132 : ! **************************************************************************************************
133 : !> \brief Correlation self-energy and quasiparticle energies, iterated to eigenvalue
134 : !> self-consistency in G (evGW0).
135 : !>
136 : !> For G0W0 this runs once with G^(0) built from the DFT eigenvalues. For evGW0 the
137 : !> Green's function is rebuilt from the quasiparticle energies of all states until the
138 : !> quasiparticle HOMO, LUMO and HOMO-LUMO gap change by less than EPS_ITER between two
139 : !> cycles, or MAX_ITER cycles are spent. W, Σ^x and everything computed before this
140 : !> routine stay frozen: they either do not depend on the eigenvalues at all (Σ^x is G
141 : !> at τ = 0, a pure density matrix) or are held fixed by construction in GW0. The
142 : !> imaginary-time grid is fixed as well, since W(iτ) lives on it.
143 : !>
144 : !> \param bs_env ...
145 : !> \param fm_W_time ...
146 : !> \param fm_Sigma_x_Gamma ...
147 : ! **************************************************************************************************
148 40 : SUBROUTINE compute_Sigma_c_and_QP_energies(bs_env, fm_W_time, fm_Sigma_x_Gamma)
149 :
150 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
151 : TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:) :: fm_W_time, fm_Sigma_x_Gamma
152 :
153 : CHARACTER(LEN=*), PARAMETER :: routineN = 'compute_Sigma_c_and_QP_energies'
154 :
155 : INTEGER :: handle, i_iter, n_iter
156 : LOGICAL :: converged
157 40 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: eigenval_scf_Gamma_dft
158 : REAL(KIND=dp), DIMENSION(2) :: e_fermi_dft
159 : REAL(KIND=dp), DIMENSION(3, 2) :: band_prev
160 40 : TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:, :, :) :: fm_Sigma_c_Gamma_time
161 :
162 40 : CALL timeset(routineN, handle)
163 :
164 : converged = .FALSE.
165 :
166 40 : CALL init_evGW0(bs_env, n_iter, band_prev, eigenval_scf_Gamma_dft, e_fermi_dft)
167 :
168 : ! evGW0 self-consistency loop; for G0W0, loop is terminated after one iteration
169 54 : DO i_iter = 1, n_iter
170 :
171 54 : bs_env%evgw0_i_iter = i_iter
172 :
173 : ! W_ll'(iτ) = Σ_PQ Z_lP W^MIC_PQ(iτ) Z_l'Q
174 : ! Σ^c_ll'(iτ) = -G^occ_ll'(i|τ|) ∘ W_ll'(iτ), τ < 0
175 : ! Σ^c_ll'(iτ) = G^vir_ll'(i|τ|) ∘ W_ll'(iτ), τ > 0
176 : ! Σ^c_λσ(iτ) = Σ_ll' ϕ_λ(r_l) Σ^c_ll'(iτ) ϕ_σ(r_l')
177 : CALL compute_Sigma_c(bs_env, fm_W_time, fm_Sigma_c_Gamma_time, &
178 54 : bs_env%ri_rs%cutoff_radius_v_w, keep_w_and_files=.TRUE.)
179 :
180 : ! Σ^c_λσ(iτ) -> Σ^c_nn(ϵ)
181 : ! ϵ_n^GW,(i) = ϵ_n^DFT + Σ^c_nn[G^(i-1),W](ϵ_n^GW,(i)) + Σ^x_nn - v^xc_nn
182 54 : CALL compute_QP_energies(bs_env, fm_Sigma_x_Gamma, fm_Sigma_c_Gamma_time)
183 :
184 54 : IF (bs_env%gw_flavour == G0W0) EXIT
185 :
186 18 : CALL print_evGW0_band_edges(bs_env, band_prev, i_iter, n_iter, converged)
187 :
188 18 : IF (i_iter == n_iter .OR. converged) EXIT
189 :
190 : ! eigenvalues ϵ_n to be updated in G:
191 : ! G^occ_µλ(i|τ|) = Σ_n^occ C_µn e^(-|(ϵ_n-ϵ_F)τ|) C_λn
192 : ! G^vir_µλ(i|τ|) = Σ_n^vir C_µn e^(-|(ϵ_n-ϵ_F)τ|) C_λn
193 72 : CALL update_eigenvalues_G(bs_env)
194 :
195 : END DO
196 :
197 40 : CALL cp_fm_release(fm_W_time)
198 :
199 40 : CALL reset_and_clean_bs_env(bs_env, eigenval_scf_Gamma_dft, e_fermi_dft, fm_Sigma_x_Gamma)
200 :
201 40 : CALL delete_unnecessary_files(bs_env)
202 :
203 40 : CALL timestop(handle)
204 :
205 40 : END SUBROUTINE compute_Sigma_c_and_QP_energies
206 :
207 : ! **************************************************************************************************
208 : !> \brief Sets up the evGW0 eigenvalue self-consistency loop: the cycle count, the eigenvalues
209 : !> the first Green's function is built from, and the DFT reference that the loop
210 : !> overwrites. A G0W0 run reduces to a single cycle and needs none of it.
211 : !> \param bs_env ...
212 : !> \param n_iter ...
213 : !> \param band_prev ...
214 : !> \param eigenval_scf_Gamma_dft ...
215 : !> \param e_fermi_dft ...
216 : ! **************************************************************************************************
217 40 : SUBROUTINE init_evGW0(bs_env, n_iter, band_prev, eigenval_scf_Gamma_dft, e_fermi_dft)
218 :
219 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
220 : INTEGER, INTENT(OUT) :: n_iter
221 : REAL(KIND=dp), DIMENSION(3, 2), INTENT(OUT) :: band_prev
222 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :), &
223 : INTENT(OUT) :: eigenval_scf_Gamma_dft
224 : REAL(KIND=dp), DIMENSION(2), INTENT(OUT) :: e_fermi_dft
225 :
226 : CHARACTER(LEN=*), PARAMETER :: routineN = 'init_evGW0'
227 :
228 : INTEGER :: handle
229 :
230 40 : CALL timeset(routineN, handle)
231 :
232 40 : n_iter = 1
233 40 : band_prev(:, :) = 0.0_dp
234 40 : e_fermi_dft(:) = 0.0_dp
235 :
236 40 : IF (bs_env%gw_flavour == evGW0) THEN
237 4 : n_iter = bs_env%evgw0_iter
238 :
239 : ! eigenvalues currently in G; the first cycle starts is a plain G0W0 step
240 70 : bs_env%eigenval_evGW0(:, :, :) = bs_env%eigenval_scf(:, :, :)
241 : ! the loop overwrites these; post-GW printing expects the DFT values back
242 76 : ALLOCATE (eigenval_scf_Gamma_dft, SOURCE=bs_env%eigenval_scf_Gamma)
243 12 : e_fermi_dft(:) = bs_env%e_fermi(:)
244 : END IF
245 :
246 40 : CALL timestop(handle)
247 :
248 40 : END SUBROUTINE init_evGW0
249 :
250 : ! **************************************************************************************************
251 : !> \brief Feeds the quasiparticle energies of the current evGW0 cycle back into the Green's
252 : !> function used by the next one, and re-centres the Fermi level between the new
253 : !> quasiparticle HOMO and LUMO.
254 : !> \param bs_env ...
255 : ! **************************************************************************************************
256 14 : SUBROUTINE update_eigenvalues_G(bs_env)
257 :
258 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
259 :
260 : CHARACTER(LEN=*), PARAMETER :: routineN = 'update_eigenvalues_G'
261 :
262 : INTEGER :: handle, i_mo, ispin
263 :
264 14 : CALL timeset(routineN, handle)
265 :
266 : ! record this cycle's evGW0 result; it is also what the next Green's function is built from
267 230 : bs_env%eigenval_evGW0(:, :, :) = bs_env%eigenval_GW(:, :, :)
268 :
269 34 : DO ispin = 1, bs_env%n_spin
270 : ! Update all physical states; exclude linear-dependency placeholders.
271 196 : DO i_mo = 1, bs_env%n_mo_retained
272 196 : bs_env%eigenval_scf_Gamma(i_mo, ispin) = bs_env%eigenval_GW(i_mo, 1, ispin)
273 : END DO
274 : bs_env%e_fermi(ispin) = &
275 : 0.5_dp*(bs_env%eigenval_GW(bs_env%n_occ(ispin), 1, ispin) + &
276 34 : bs_env%eigenval_GW(bs_env%n_occ(ispin) + 1, 1, ispin))
277 : END DO
278 :
279 14 : CALL timestop(handle)
280 :
281 14 : END SUBROUTINE update_eigenvalues_G
282 :
283 : ! **************************************************************************************************
284 : !> \brief Restores the DFT reference that the evGW0 loop overwrote and cleanup
285 : !> \param bs_env ...
286 : !> \param eigenval_scf_Gamma_dft ...
287 : !> \param e_fermi_dft ...
288 : !> \param fm_Sigma_x_Gamma ..
289 : ! **************************************************************************************************
290 40 : SUBROUTINE reset_and_clean_bs_env(bs_env, eigenval_scf_Gamma_dft, e_fermi_dft, fm_Sigma_x_Gamma)
291 :
292 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
293 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :), &
294 : INTENT(INOUT) :: eigenval_scf_Gamma_dft
295 : REAL(KIND=dp), DIMENSION(2), INTENT(IN) :: e_fermi_dft
296 : TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:) :: fm_Sigma_x_Gamma
297 :
298 : CHARACTER(LEN=*), PARAMETER :: routineN = 'reset_and_clean_bs_env'
299 :
300 : INTEGER :: handle
301 :
302 40 : CALL timeset(routineN, handle)
303 :
304 40 : IF (bs_env%gw_flavour == evGW0) THEN
305 : ! Update array with final evGW0 result
306 70 : bs_env%eigenval_evGW0(:, :, :) = bs_env%eigenval_GW(:, :, :)
307 : ! put the DFT reference back for the post-GW DOS/band-edge printing
308 64 : bs_env%eigenval_scf_Gamma(:, :) = eigenval_scf_Gamma_dft(:, :)
309 12 : bs_env%e_fermi(:) = e_fermi_dft(:)
310 4 : DEALLOCATE (eigenval_scf_Gamma_dft)
311 4 : CALL cp_fm_release(fm_Sigma_x_Gamma)
312 : END IF
313 :
314 40 : CALL timestop(handle)
315 :
316 40 : END SUBROUTINE reset_and_clean_bs_env
317 :
318 : ! **************************************************************************************************
319 : !> \brief Print the quasiparticle HOMO, LUMO and HOMO-LUMO gap of the current evGW0 cycle
320 : !> \param bs_env ...
321 : !> \param band_prev ...
322 : !> \param i_iter ...
323 : !> \param n_iter ...
324 : !> \param converged ...
325 : ! **************************************************************************************************
326 18 : SUBROUTINE print_evGW0_band_edges(bs_env, band_prev, i_iter, n_iter, converged)
327 :
328 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
329 : REAL(KIND=dp), DIMENSION(3, 2), INTENT(INOUT) :: band_prev
330 : INTEGER, INTENT(IN) :: i_iter, n_iter
331 : LOGICAL, INTENT(OUT) :: converged
332 :
333 : CHARACTER(LEN=*), PARAMETER :: routineN = 'print_evGW0_band_edges'
334 :
335 : INTEGER :: handle, homo, ispin, u
336 : REAL(KIND=dp) :: max_delta
337 : REAL(KIND=dp), DIMENSION(3) :: band
338 :
339 18 : CALL timeset(routineN, handle)
340 :
341 18 : u = bs_env%unit_nr
342 :
343 18 : converged = (i_iter > 1)
344 18 : max_delta = 0.0_dp
345 :
346 18 : IF (u > 0) THEN
347 9 : WRITE (u, '(A)') ' '
348 9 : WRITE (u, '(T2,A)') REPEAT('-', 79)
349 9 : WRITE (u, '(T2,A,I4,A,I4)') 'evGW0 cycle', i_iter, ' /', n_iter
350 9 : WRITE (u, '(T2,A)') REPEAT('-', 79)
351 : END IF
352 :
353 44 : DO ispin = 1, bs_env%n_spin
354 :
355 26 : homo = bs_env%n_occ(ispin)
356 26 : band(1) = bs_env%eigenval_GW(homo, 1, ispin)
357 26 : band(2) = bs_env%eigenval_GW(homo + 1, 1, ispin)
358 26 : band(3) = band(2) - band(1)
359 :
360 26 : IF (i_iter > 1) THEN
361 80 : max_delta = MAX(max_delta, MAXVAL(ABS(band(:) - band_prev(:, ispin))))
362 : END IF
363 :
364 26 : IF (u > 0) THEN
365 13 : IF (bs_env%n_spin == 2) WRITE (u, '(T2,A,I0)') 'Spin ', ispin
366 13 : WRITE (u, '(T2,A,T61,F20.3)') 'evGW0 HOMO (eV)', band(1)*evolt
367 13 : WRITE (u, '(T2,A,T61,F20.3)') 'evGW0 LUMO (eV)', band(2)*evolt
368 13 : WRITE (u, '(T2,A,T61,F20.3)') 'evGW0 HOMO-LUMO gap (eV)', band(3)*evolt
369 : END IF
370 :
371 122 : band_prev(:, ispin) = band(:)
372 :
373 : END DO
374 :
375 18 : IF (i_iter > 1) THEN
376 14 : converged = (max_delta < bs_env%evgw0_eps_iter)
377 21 : IF (u > 0) WRITE (u, '(T2,A,T61,F20.6)') 'Max. change to previous cycle (eV)', &
378 14 : max_delta*evolt
379 : END IF
380 :
381 11 : IF (u > 0) WRITE (u, '(T2,A)') REPEAT('-', 79)
382 :
383 18 : IF (converged) THEN
384 4 : IF (u > 0) THEN
385 2 : WRITE (u, '(A)') ' '
386 : WRITE (u, '(T2,A,I4,A)') &
387 2 : 'evGW0 eigenvalue self-consistency reached in', i_iter, ' cycles.'
388 2 : WRITE (u, '(A)') ' '
389 : END IF
390 14 : ELSE IF (i_iter == n_iter) THEN
391 : CALL cp_warn(__LOCATION__, &
392 : "The evGW0 eigenvalue self-consistency cycle did not converge "// &
393 : "within MAX_ITER cycles. The reported quasiparticle energies are "// &
394 0 : "those of the last cycle.")
395 : END IF
396 :
397 18 : CALL timestop(handle)
398 :
399 18 : END SUBROUTINE print_evGW0_band_edges
400 :
401 : ! **************************************************************************************************
402 : !> \brief Estimates and prints per-process memory requirements for the RI-RS GW calculation.
403 : !> \param bs_env ...
404 : ! **************************************************************************************************
405 40 : SUBROUTINE print_ri_rs_memory_estimate(bs_env)
406 :
407 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
408 :
409 : CHARACTER(LEN=*), PARAMETER :: routineN = 'print_ri_rs_memory_estimate'
410 :
411 : CHARACTER(LEN=max_line_length) :: msg
412 : INTEGER :: handle, ipan, n_grid_total, n_procs, &
413 : n_RI, pan_rows, pan_width
414 : INTEGER(KIND=int_8) :: nze_tmpl
415 40 : INTEGER, ALLOCATABLE, DIMENSION(:) :: pan_first, pan_last
416 40 : INTEGER, DIMENSION(:), POINTER :: r_blk_sizes
417 : LOGICAL :: use_cutoff
418 40 : LOGICAL, ALLOCATABLE, DIMENSION(:) :: grid_used
419 : REAL(KIND=dp) :: mem_avail_GB, mem_pan_GB, mem_panels_GB, &
420 : mem_Z_lP_GB
421 :
422 40 : CALL timeset(routineN, handle)
423 :
424 40 : n_grid_total = bs_env%ri_rs%n_grid_points
425 40 : CALL dbcsr_get_info(bs_env%ri_rs%mat_phi_mu_l, row_blk_size=r_blk_sizes)
426 570 : CPASSERT(SUM(r_blk_sizes) == n_grid_total)
427 40 : n_RI = bs_env%n_RI
428 40 : n_procs = bs_env%para_env%num_pe
429 :
430 : ! Z_lP upper bound: dense n_grid × n_RI, distributed evenly across all ranks.
431 : ! The actual sparse Z_lP is smaller due to the per-atom locality cutoff.
432 : mem_Z_lP_GB = REAL(n_grid_total, dp)*REAL(n_RI, dp)*8.0_dp/ &
433 40 : REAL(n_procs, dp)*1.0E-9_dp
434 :
435 : ! Peak panel memory during Σ^c: two G panels (A_occ, A_vir) + one W panel plus the
436 : ! grid × RI / grid × AO intermediates. With the CUTOFF_RADIUS_RL_W restriction the panel
437 : ! matrices only allocate the geo-template blocks, so use the same nze-aware model as the
438 : ! panel planner (panel_mem_estimate_GB); without the cutoff, dense panel_rows × n_grid.
439 : ! Plus the n_RI × n_RI W_aux matrix. Distributed over n_procs ranks.
440 : use_cutoff = bs_env%ri_rs%cutoff_radius_v_w > 0.0_dp .AND. &
441 40 : ALLOCATED(bs_env%ri_rs%chunk_centroids)
442 : CALL resolve_grid_panels(bs_env%ri_rs, bs_env%para_env, bs_env%dbcsr_msg_elem_limit, &
443 40 : pan_first, pan_last, bs_env%ri_rs%cutoff_radius_v_w)
444 40 : mem_panels_GB = 0.0_dp
445 80 : DO ipan = 1, SIZE(pan_first)
446 570 : pan_rows = SUM(r_blk_sizes(pan_first(ipan):pan_last(ipan)))
447 40 : IF (use_cutoff) THEN
448 : CALL mask_grid_blocks_near_panel(bs_env%ri_rs%chunk_centroids, pan_first(ipan), &
449 : pan_last(ipan), bs_env%ri_rs%cutoff_radius_v_w, &
450 2 : grid_used)
451 44 : pan_width = SUM(r_blk_sizes, MASK=grid_used)
452 : CALL panel_template_elems(r_blk_sizes, bs_env%ri_rs%chunk_centroids, &
453 : grid_used, pan_first(ipan), pan_last(ipan), &
454 2 : bs_env%ri_rs%cutoff_radius_v_w, nze_tmpl)
455 : ELSE
456 38 : pan_width = n_grid_total
457 38 : nze_tmpl = INT(pan_rows, int_8)*INT(pan_width, int_8)
458 : END IF
459 : CALL panel_mem_estimate_GB(nze_tmpl, pan_rows, pan_width, n_grid_total, &
460 40 : n_RI, bs_env%n_ao, n_procs, mem_pan_GB)
461 80 : mem_panels_GB = MAX(mem_panels_GB, mem_pan_GB)
462 : END DO
463 : mem_panels_GB = mem_panels_GB + &
464 40 : REAL(n_RI, dp)*REAL(n_RI, dp)*8.0_dp/REAL(n_procs, dp)*1.0E-9_dp
465 :
466 : ! Available memory per process = node MemLikelyFree / ranks-per-node, min across ranks
467 : ! (0 on non-Linux => warnings suppressed below).
468 40 : CALL mp_mem_avail_per_rank_GB(bs_env%para_env, mem_avail_GB)
469 :
470 40 : IF (bs_env%unit_nr > 0) THEN
471 20 : WRITE (bs_env%unit_nr, '(A)') ' '
472 20 : WRITE (bs_env%unit_nr, '(T2,A)') 'RI-RS memory estimate per MPI process:'
473 : WRITE (bs_env%unit_nr, '(T4,A,F37.2,A)') &
474 20 : 'Available memory per process (system)', mem_avail_GB, ' GB'
475 : WRITE (bs_env%unit_nr, '(T4,A,F18.2,A)') &
476 20 : 'Required for Z_lP (dense upper bound; actual is sparser)', mem_Z_lP_GB, ' GB'
477 : WRITE (bs_env%unit_nr, '(T4,A,F25.2,A)') &
478 20 : 'Required for χ, W, Σ panels (peak per panel step)', mem_panels_GB, ' GB'
479 20 : IF (bs_env%ri_rs%Z_lP_exists .AND. .NOT. bs_env%auto_ri%enabled) THEN
480 1 : WRITE (bs_env%unit_nr, '(T4,A)') 'Z_lP fitting skipped (matrix read from restart)'
481 : END IF
482 :
483 : END IF
484 :
485 40 : IF (mem_avail_GB > 0.0_dp .AND. mem_Z_lP_GB > mem_avail_GB) THEN
486 : WRITE (msg, '(A,F0.2,A,F0.2,A)') &
487 0 : "The estimated memory for Z_lP, ", mem_Z_lP_GB, " GB per process, exceeds the "// &
488 0 : "available ", mem_avail_GB, " GB. Z_lP (n_grid x n_RI) is distributed across all "// &
489 0 : "MPI ranks, so add nodes or use fewer MPI ranks per node."
490 0 : CPWARN(TRIM(msg))
491 : END IF
492 :
493 40 : IF (mem_avail_GB > 0.0_dp .AND. mem_panels_GB > mem_avail_GB) THEN
494 : WRITE (msg, '(A,F0.2,A,F0.2,A)') &
495 0 : "The estimated peak memory of the chi/W/Sigma panels, ", mem_panels_GB, &
496 0 : " GB per process, exceeds the available ", mem_avail_GB, " GB. Panel memory "// &
497 : "scales roughly as 3*panel_size*n_grid/n_procs, so add nodes, use fewer MPI ranks "// &
498 0 : "per node."
499 0 : CPWARN(TRIM(msg))
500 : END IF
501 :
502 40 : CALL timestop(handle)
503 :
504 80 : END SUBROUTINE print_ri_rs_memory_estimate
505 :
506 : ! **************************************************************************************************
507 : !> \brief Σ^c_λσ(iτ) -> Σ^c_nn(ϵ) and the quasi-particle levels of the non-periodic RI-RS path,
508 : !> ϵ_n^GW = ϵ_n^DFT + Σ^c_nn(ϵ_n^GW) + Σ^x_nn - v^xc_nn.
509 : !> \param bs_env ...
510 : !> \param fm_Sigma_x_Gamma ...
511 : !> \param fm_Sigma_c_Gamma_time ...
512 : ! **************************************************************************************************
513 54 : SUBROUTINE compute_QP_energies(bs_env, fm_Sigma_x_Gamma, fm_Sigma_c_Gamma_time)
514 :
515 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
516 : TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:) :: fm_Sigma_x_Gamma
517 : TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:, :, :) :: fm_Sigma_c_Gamma_time
518 :
519 : CHARACTER(LEN=*), PARAMETER :: routineN = 'compute_QP_energies'
520 :
521 : COMPLEX(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: Sigma_c_n_freq
522 : INTEGER :: handle, ispin, j_t
523 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: Sigma_x_n, V_xc_n
524 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: Sigma_c_n_time
525 : TYPE(cp_fm_type) :: fm_ks, fm_mos, fm_s, fm_work
526 :
527 54 : CALL timeset(routineN, handle)
528 :
529 54 : CALL cp_fm_create(fm_ks, bs_env%fm_s_Gamma%matrix_struct)
530 54 : CALL cp_fm_create(fm_s, bs_env%fm_s_Gamma%matrix_struct)
531 54 : CALL cp_fm_create(fm_mos, bs_env%fm_s_Gamma%matrix_struct)
532 54 : CALL cp_fm_create(fm_work, bs_env%fm_s_Gamma%matrix_struct)
533 :
534 216 : ALLOCATE (V_xc_n(bs_env%n_ao), Sigma_x_n(bs_env%n_ao))
535 270 : ALLOCATE (Sigma_c_n_time(bs_env%n_ao, bs_env%num_time_freq_points, 2))
536 216 : ALLOCATE (Sigma_c_n_freq(bs_env%n_ao, bs_env%num_freq_points_fit))
537 :
538 120 : DO ispin = 1, bs_env%n_spin
539 :
540 : ! 1. Roothaan-Hall H^KS_µν C_νn = S_µν C_νn ϵ_n
541 66 : CALL cp_fm_to_fm(bs_env%fm_ks_Gamma(ispin), fm_ks)
542 66 : CALL cp_fm_to_fm(bs_env%fm_s_Gamma, fm_s)
543 66 : CALL cp_fm_geeig(fm_ks, fm_s, fm_mos, bs_env%eigenval_scf(:, 1, ispin), fm_work)
544 :
545 : ! 2. v^xc_µν -> v^xc_nn and Σ^x_µν -> Σ^x_nn
546 66 : CALL to_Gamma_and_mo_real(V_xc_n, bs_env%fm_V_xc_Gamma(ispin), fm_mos)
547 66 : CALL to_Gamma_and_mo_real(Sigma_x_n, fm_Sigma_x_Gamma(ispin), fm_mos)
548 :
549 : ! 3. Σ^c_µν(+/-i|τ_j|) -> Σ^c_nn(+/-i|τ_j|)
550 896 : DO j_t = 1, bs_env%num_time_freq_points
551 : CALL to_Gamma_and_mo_real(Sigma_c_n_time(:, j_t, positive_time), &
552 830 : fm_Sigma_c_Gamma_time(j_t, positive_time, ispin), fm_mos)
553 : CALL to_Gamma_and_mo_real(Sigma_c_n_time(:, j_t, negative_time), &
554 896 : fm_Sigma_c_Gamma_time(j_t, negative_time, ispin), fm_mos)
555 : END DO
556 :
557 : ! 4. Σ^c_nn(iτ) -> Σ^c_nn(iω)
558 66 : CALL transform_time_to_frequency(bs_env%time_frequency_grid, Sigma_c_n_time, Sigma_c_n_freq)
559 818 : Sigma_c_n_freq(1:bs_env%n_occ(ispin), :) = CONJG(Sigma_c_n_freq(1:bs_env%n_occ(ispin), :))
560 :
561 : ! 5. Analytic continuation Σ^c_nn(iω) -> Σ^c_nn(ϵ) and the QP levels
562 : CALL analyt_conti_and_print(bs_env, Sigma_c_n_freq, Sigma_x_n, V_xc_n, &
563 120 : bs_env%eigenval_scf(:, 1, ispin), 1, ispin)
564 :
565 : END DO ! ispin
566 :
567 54 : CALL get_all_VBM_CBM_bandgaps(bs_env)
568 :
569 54 : IF (bs_env%gw_flavour == G0W0) CALL cp_fm_release(fm_Sigma_x_Gamma)
570 54 : CALL cp_fm_release(fm_Sigma_c_Gamma_time)
571 :
572 54 : CALL cp_fm_release(fm_ks)
573 54 : CALL cp_fm_release(fm_s)
574 54 : CALL cp_fm_release(fm_mos)
575 54 : CALL cp_fm_release(fm_work)
576 :
577 54 : CALL timestop(handle)
578 :
579 108 : END SUBROUTINE compute_QP_energies
580 :
581 : ! **************************************************************************************************
582 : !> \brief AO -> MO transform of a Γ-point matrix
583 : !> \param array_n ...
584 : !> \param fm_Gamma ...
585 : !> \param fm_mos ...
586 : ! **************************************************************************************************
587 1792 : SUBROUTINE to_Gamma_and_mo_real(array_n, fm_Gamma, fm_mos)
588 :
589 : REAL(KIND=dp), DIMENSION(:) :: array_n
590 : TYPE(cp_fm_type) :: fm_Gamma, fm_mos
591 :
592 : CHARACTER(LEN=*), PARAMETER :: routineN = 'to_Gamma_and_mo_real'
593 :
594 : INTEGER :: handle
595 : TYPE(cp_fm_type) :: fm_mo
596 :
597 1792 : CALL timeset(routineN, handle)
598 :
599 1792 : CALL cp_fm_create(fm_mo, fm_Gamma%matrix_struct)
600 :
601 : ! A_nn' = Σ_μν C_μn A_μν C_νn'
602 1792 : CALL fm_contract_ABA(fm_mos, fm_Gamma, fm_mo)
603 :
604 1792 : CALL cp_fm_get_diag(fm_mo, array_n)
605 :
606 1792 : CALL cp_fm_release(fm_mo)
607 :
608 1792 : CALL timestop(handle)
609 :
610 1792 : END SUBROUTINE to_Gamma_and_mo_real
611 :
612 : END MODULE gw_ri_rs_non_periodic
|