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
10 : !> \author Jan Wilhelm
11 : !> \date 07.2023
12 : ! **************************************************************************************************
13 : MODULE post_scf_bandstructure_utils
14 : USE atomic_kind_types, ONLY: atomic_kind_type,&
15 : get_atomic_kind,&
16 : get_atomic_kind_set
17 : USE bse_input, ONLY: read_bse_section
18 : USE bse_main, ONLY: bse_fulldiag_memory_check
19 : USE bse_types, ONLY: bse_env_type
20 : USE bse_util, ONLY: bse_window_from_dft
21 : USE cell_types, ONLY: cell_type,&
22 : get_cell
23 : USE cp_blacs_env, ONLY: cp_blacs_env_type
24 : USE cp_cfm_basic_linalg, ONLY: cp_cfm_scale
25 : USE cp_cfm_cholesky, ONLY: cp_cfm_cholesky_decompose
26 : USE cp_cfm_diag, ONLY: cp_cfm_geeig,&
27 : cp_cfm_geeig_canon,&
28 : cp_cfm_heevd
29 : USE cp_cfm_types, ONLY: cp_cfm_create,&
30 : cp_cfm_get_info,&
31 : cp_cfm_release,&
32 : cp_cfm_set_all,&
33 : cp_cfm_to_cfm,&
34 : cp_cfm_to_fm,&
35 : cp_cfm_type,&
36 : cp_fm_to_cfm
37 : USE cp_control_types, ONLY: dft_control_type
38 : USE cp_dbcsr_api, ONLY: &
39 : dbcsr_create, dbcsr_deallocate_matrix, dbcsr_desymmetrize, dbcsr_p_type, dbcsr_set, &
40 : dbcsr_type, dbcsr_type_antisymmetric, dbcsr_type_no_symmetry, dbcsr_type_symmetric
41 : USE cp_dbcsr_cp2k_link, ONLY: cp_dbcsr_alloc_block_from_nbl
42 : USE cp_dbcsr_operations, ONLY: copy_dbcsr_to_fm,&
43 : copy_fm_to_dbcsr,&
44 : dbcsr_allocate_matrix_set,&
45 : dbcsr_deallocate_matrix_set
46 : USE cp_files, ONLY: close_file,&
47 : open_file
48 : USE cp_fm_diag, ONLY: cp_fm_geeig_canon
49 : USE cp_fm_struct, ONLY: cp_fm_struct_create,&
50 : cp_fm_struct_release,&
51 : cp_fm_struct_type
52 : USE cp_fm_types, ONLY: cp_fm_create,&
53 : cp_fm_get_diag,&
54 : cp_fm_get_info,&
55 : cp_fm_release,&
56 : cp_fm_set_all,&
57 : cp_fm_to_fm,&
58 : cp_fm_to_fm_submat,&
59 : cp_fm_type
60 : USE cp_log_handling, ONLY: cp_logger_get_default_io_unit,&
61 : cp_to_string
62 : USE cp_parser_methods, ONLY: read_float_object
63 : USE dft_plus_u, ONLY: lowdin_kp_apply,&
64 : lowdin_kp_prepare
65 : USE input_constants, ONLY: &
66 : G0W0, bse_fulldiag, cohsex_off, evGW0, int_ldos_z, ri_rs_large_cell_Gamma, &
67 : ri_rs_non_periodic, smear_fermi_dirac, smear_gaussian, smear_mp, smear_mv, &
68 : tensor_large_cell_Gamma, tensor_small_cell_full_kp, tensor_static_cohsex
69 : USE input_section_types, ONLY: section_vals_get,&
70 : section_vals_get_subs_vals,&
71 : section_vals_type,&
72 : section_vals_val_get
73 : USE kinds, ONLY: default_string_length,&
74 : dp,&
75 : max_line_length
76 : USE kpoint_k_r_trafo_simple, ONLY: fm_gamma_to_kp
77 : USE kpoint_methods, ONLY: kpoint_init_cell_index,&
78 : rskp_transform
79 : USE kpoint_types, ONLY: get_kpoint_info,&
80 : kpoint_create,&
81 : kpoint_env_type,&
82 : kpoint_type
83 : USE machine, ONLY: m_walltime
84 : USE mathconstants, ONLY: gaussi,&
85 : twopi,&
86 : z_one,&
87 : z_zero
88 : USE message_passing, ONLY: mp_para_env_type
89 : USE mo_window, ONLY: mo_window_type
90 : USE parallel_gemm_api, ONLY: parallel_gemm
91 : USE particle_types, ONLY: particle_type
92 : USE physcon, ONLY: angstrom,&
93 : evolt
94 : USE post_scf_bandstructure_types, ONLY: band_edges_type,&
95 : eps_qp_gap,&
96 : max_qp_gap,&
97 : post_scf_bandstructure_type
98 : USE pw_env_types, ONLY: pw_env_get,&
99 : pw_env_type
100 : USE pw_pool_types, ONLY: pw_pool_type
101 : USE pw_types, ONLY: pw_c1d_gs_type,&
102 : pw_r3d_rs_type
103 : USE qs_collocate_density, ONLY: calculate_rho_elec
104 : USE qs_environment_types, ONLY: get_qs_env,&
105 : qs_environment_type
106 : USE qs_ks_types, ONLY: qs_ks_env_type
107 : USE qs_mo_types, ONLY: get_mo_set,&
108 : mo_set_type
109 : USE qs_neighbor_list_types, ONLY: neighbor_list_set_p_type
110 : USE rpa_gw_im_time_util, ONLY: compute_weight_re_im,&
111 : get_atom_index_from_basis_function_index
112 : USE scf_control_types, ONLY: scf_control_type
113 : USE smearing_utils, ONLY: Smearkp,&
114 : Smearkp2
115 : USE soc_pseudopotential_methods, ONLY: V_SOC_xyz_from_pseudopotential,&
116 : remove_soc_outside_energy_window_mo
117 : USE soc_pseudopotential_utils, ONLY: add_cfm_submat,&
118 : add_dbcsr_submat,&
119 : cfm_add_on_diag,&
120 : create_cfm_double,&
121 : get_cfm_submat
122 : USE string_utilities, ONLY: uppercase
123 : #include "base/base_uses.f90"
124 :
125 : IMPLICIT NONE
126 :
127 : PRIVATE
128 :
129 : PUBLIC :: create_and_init_bs_env, &
130 : eval_bandstructure_properties, cfm_ikp_from_fm_Gamma, &
131 : MIC_contribution_from_ikp, compute_xkp, kpoint_init_cell_index_simple, &
132 : rsmat_to_kp, soc, get_VBM_CBM_bandgaps, get_all_VBM_CBM_bandgaps, &
133 : allocate_GW_eigenvalues, gw_flavour_label
134 :
135 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'post_scf_bandstructure_utils'
136 :
137 : CONTAINS
138 :
139 : ! **************************************************************************************************
140 : !> \brief Allocate the arrays holding the GW quasiparticle energies
141 : !> \param bs_env ...
142 : ! **************************************************************************************************
143 156 : SUBROUTINE allocate_GW_eigenvalues(bs_env)
144 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
145 :
146 : CHARACTER(LEN=*), PARAMETER :: routineN = 'allocate_GW_eigenvalues'
147 :
148 : INTEGER :: handle, n_ao, n_spin, nkp
149 :
150 156 : CALL timeset(routineN, handle)
151 :
152 156 : n_ao = bs_env%n_ao
153 156 : nkp = bs_env%nkp_bs_and_DOS
154 156 : n_spin = bs_env%n_spin
155 :
156 156 : IF (.NOT. ALLOCATED(bs_env%eigenval_GW)) THEN
157 700 : ALLOCATE (bs_env%eigenval_GW(n_ao, nkp, n_spin))
158 : END IF
159 156 : IF (.NOT. ALLOCATED(bs_env%eigenval_HF)) THEN
160 700 : ALLOCATE (bs_env%eigenval_HF(n_ao, nkp, n_spin))
161 : END IF
162 :
163 312 : SELECT CASE (bs_env%gw_flavour)
164 : CASE (G0W0, evGW0)
165 156 : IF (.NOT. ALLOCATED(bs_env%eigenval_G0W0)) THEN
166 700 : ALLOCATE (bs_env%eigenval_G0W0(n_ao, nkp, n_spin))
167 : END IF
168 : END SELECT
169 :
170 156 : IF (bs_env%gw_flavour == evGW0 .AND. .NOT. ALLOCATED(bs_env%eigenval_evGW0)) THEN
171 20 : ALLOCATE (bs_env%eigenval_evGW0(n_ao, nkp, n_spin))
172 : END IF
173 :
174 156 : CALL timestop(handle)
175 :
176 156 : END SUBROUTINE allocate_GW_eigenvalues
177 :
178 : ! **************************************************************************************************
179 : !> \brief Name of the GW flavour that was requested, for printing
180 : !> \param bs_env ...
181 : !> \return ...
182 : ! **************************************************************************************************
183 689 : FUNCTION gw_flavour_label(bs_env) RESULT(label)
184 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
185 : CHARACTER(LEN=default_string_length) :: label
186 :
187 744 : SELECT CASE (bs_env%gw_flavour)
188 : CASE (evGW0)
189 55 : label = "evGW0"
190 : CASE DEFAULT
191 689 : label = "G0W0"
192 : END SELECT
193 689 : IF (bs_env%do_static_cohsex) label = "static COHSEX"
194 :
195 689 : END FUNCTION gw_flavour_label
196 :
197 : ! **************************************************************************************************
198 : !> \brief ...
199 : !> \param qs_env ...
200 : !> \param bs_env ...
201 : !> \param post_scf_bandstructure_section ...
202 : ! **************************************************************************************************
203 140 : SUBROUTINE create_and_init_bs_env(qs_env, bs_env, post_scf_bandstructure_section)
204 : TYPE(qs_environment_type), POINTER :: qs_env
205 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
206 : TYPE(section_vals_type), POINTER :: post_scf_bandstructure_section
207 :
208 : CHARACTER(LEN=*), PARAMETER :: routineN = 'create_and_init_bs_env'
209 :
210 : INTEGER :: handle
211 :
212 140 : CALL timeset(routineN, handle)
213 :
214 13720 : ALLOCATE (bs_env)
215 :
216 140 : CALL print_header(bs_env)
217 :
218 140 : CALL read_bandstructure_input_parameters(bs_env, post_scf_bandstructure_section, qs_env)
219 :
220 140 : CALL get_parameters_from_qs_env(qs_env, bs_env)
221 :
222 140 : CALL set_heuristic_parameters(bs_env)
223 :
224 262 : SELECT CASE (bs_env%gw_implementation)
225 : CASE (tensor_large_cell_Gamma, ri_rs_large_cell_Gamma, ri_rs_non_periodic, tensor_static_cohsex)
226 :
227 122 : CALL setup_kpoints_DOS_large_cell_Gamma(qs_env, bs_env, bs_env%kpoints_DOS)
228 :
229 122 : CALL allocate_and_fill_fm_ks_fm_s(qs_env, bs_env)
230 :
231 122 : CALL diagonalize_ks_matrix(bs_env)
232 :
233 122 : CALL check_positive_definite_overlap_mat(bs_env, qs_env)
234 :
235 : CASE (tensor_small_cell_full_kp)
236 :
237 18 : CALL setup_kpoints_scf_desymm(qs_env, bs_env, bs_env%kpoints_scf_desymm, .TRUE.)
238 :
239 18 : CALL setup_kpoints_DOS_small_cell_full_kp(bs_env, bs_env%kpoints_DOS)
240 :
241 18 : CALL allocate_and_fill_fm_ks_fm_s(qs_env, bs_env)
242 :
243 158 : CALL compute_cfm_mo_coeff_kp_and_eigenval_scf_kp(qs_env, bs_env)
244 :
245 : END SELECT
246 :
247 140 : CALL read_bse_input(qs_env, bs_env)
248 :
249 140 : CALL timestop(handle)
250 :
251 140 : END SUBROUTINE create_and_init_bs_env
252 :
253 : ! **************************************************************************************************
254 : !> \brief What PROPERTIES%BSE needs the GW to keep and, with FULLDIAG, the early memory check of the
255 : !> full diagonalization; check_cp2k_input refused the input combinations the BSE cannot run
256 : !> \param qs_env source of the input
257 : !> \param bs_env SCF eigenvalues and occupations of the memory check; keep_W_freq_zero and keep_3c_nl are set
258 : ! **************************************************************************************************
259 140 : SUBROUTINE read_bse_input(qs_env, bs_env)
260 : TYPE(qs_environment_type), POINTER :: qs_env
261 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
262 :
263 : CHARACTER(LEN=*), PARAMETER :: routineN = 'read_bse_input'
264 :
265 : INTEGER :: handle, n_spin
266 : INTEGER, DIMENSION(2) :: n_mo
267 : LOGICAL :: do_bse_props
268 560 : TYPE(bse_env_type) :: bse_env
269 : TYPE(mo_window_type) :: window
270 : TYPE(section_vals_type), POINTER :: bse_sec, input
271 :
272 140 : CALL timeset(routineN, handle)
273 :
274 140 : NULLIFY (bse_sec, input)
275 140 : CALL get_qs_env(qs_env, input=input)
276 140 : bse_sec => section_vals_get_subs_vals(input, "PROPERTIES%BSE")
277 140 : CALL section_vals_get(bse_sec, explicit=do_bse_props)
278 :
279 140 : IF (do_bse_props) THEN
280 : ! the full diagonalization's footprint is known here, before any GW work
281 6 : CALL read_bse_section(bse_sec, bse_env)
282 6 : IF (bse_env%bse_diag_method == bse_fulldiag) THEN
283 4 : n_spin = bs_env%n_spin
284 : ! the canonical orthogonalisation parks the linearly dependent directions above n_mo_retained
285 12 : n_mo(:) = MIN(bs_env%n_mo_retained, bs_env%n_ao)
286 : ! the BSE warns about a combined window when it starts; the estimate stays silent
287 : CALL bse_window_from_dft(bs_env%eigenval_scf_Gamma(1:n_mo(1), 1:n_spin), n_mo(1:n_spin), &
288 : bs_env%n_occ(1:n_spin), bse_env%bse_cutoff_occ, &
289 4 : bse_env%bse_cutoff_empty, window, warn=.FALSE.)
290 : CALL bse_fulldiag_memory_check(bse_env, window, bs_env%n_occ(1:n_spin), bs_env%para_env, &
291 4 : bs_env%unit_nr)
292 : END IF
293 : END IF
294 140 : bs_env%keep_W_freq_zero = do_bse_props
295 140 : bs_env%keep_3c_nl = do_bse_props
296 :
297 140 : CALL timestop(handle)
298 :
299 140 : END SUBROUTINE read_bse_input
300 :
301 : ! **************************************************************************************************
302 : !> \brief ...
303 : !> \param bs_env ...
304 : !> \param bs_sec ...
305 : !> \param qs_env ...
306 : ! **************************************************************************************************
307 140 : SUBROUTINE read_bandstructure_input_parameters(bs_env, bs_sec, qs_env)
308 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
309 : TYPE(section_vals_type), POINTER :: bs_sec
310 : TYPE(qs_environment_type), POINTER :: qs_env
311 :
312 : CHARACTER(LEN=*), PARAMETER :: routineN = 'read_bandstructure_input_parameters'
313 :
314 : CHARACTER(LEN=default_string_length) :: ustr
315 : CHARACTER(LEN=default_string_length), &
316 140 : DIMENSION(:), POINTER :: string_ptr
317 : CHARACTER(LEN=max_line_length) :: error_msg
318 : INTEGER :: handle, i, ikp
319 : REAL(KIND=dp), DIMENSION(3) :: kpptr
320 : REAL(KIND=dp), DIMENSION(3, 3) :: cart_hmat
321 : TYPE(cell_type), POINTER :: cell
322 : TYPE(section_vals_type), POINTER :: dos_pdos_sec, floquet_sec, gw_sec, &
323 : kp_bs_sec, ldos_sec, soc_sec
324 :
325 140 : CALL timeset(routineN, handle)
326 140 : NULLIFY (cell)
327 140 : CALL get_qs_env(qs_env=qs_env, cell=cell)
328 1820 : cart_hmat(:, :) = cell%hmat(:, :)
329 140 : IF (cell%input_cell_canonicalized) cart_hmat(:, :) = cell%input_hmat(:, :)
330 :
331 140 : NULLIFY (gw_sec)
332 140 : gw_sec => section_vals_get_subs_vals(bs_sec, "GW")
333 140 : CALL section_vals_get(gw_sec, explicit=bs_env%do_gw)
334 140 : CALL section_vals_val_get(gw_sec, "COHSEX", i_val=bs_env%cohsex_flavor)
335 140 : bs_env%do_static_cohsex = (bs_env%cohsex_flavor /= cohsex_off)
336 140 : CALL section_vals_val_get(gw_sec, "RI_RS%_SECTION_PARAMETERS_", l_val=bs_env%do_gw_ri_rs)
337 :
338 140 : NULLIFY (soc_sec)
339 140 : soc_sec => section_vals_get_subs_vals(bs_sec, "SOC")
340 140 : CALL section_vals_get(soc_sec, explicit=bs_env%do_soc)
341 :
342 140 : CALL section_vals_val_get(soc_sec, "SOC_WINDOW_OCC", r_val=bs_env%soc_window_occ)
343 140 : CALL section_vals_val_get(soc_sec, "SOC_WINDOW_VIRT", r_val=bs_env%soc_window_virt)
344 140 : CALL section_vals_val_get(soc_sec, "SOC_WINDOW_SMEARING", r_val=bs_env%soc_window_smearing)
345 :
346 140 : CALL section_vals_val_get(soc_sec, "SOC_NBANDS_OCC", i_val=bs_env%soc_nbands_occ)
347 140 : CALL section_vals_val_get(soc_sec, "SOC_NBANDS_VIRT", i_val=bs_env%soc_nbands_virt)
348 :
349 140 : NULLIFY (dos_pdos_sec)
350 140 : dos_pdos_sec => section_vals_get_subs_vals(bs_sec, "DOS")
351 140 : CALL section_vals_get(dos_pdos_sec, explicit=bs_env%do_dos_pdos)
352 :
353 140 : CALL section_vals_val_get(bs_sec, "DOS%KPOINTS", i_vals=bs_env%nkp_grid_DOS_input)
354 140 : CALL section_vals_val_get(bs_sec, "DOS%ENERGY_WINDOW", r_val=bs_env%energy_window_DOS)
355 140 : CALL section_vals_val_get(bs_sec, "DOS%ENERGY_STEP", r_val=bs_env%energy_step_DOS)
356 140 : CALL section_vals_val_get(bs_sec, "DOS%BROADENING", r_val=bs_env%broadening_DOS)
357 :
358 140 : NULLIFY (ldos_sec)
359 140 : ldos_sec => section_vals_get_subs_vals(bs_sec, "DOS%LDOS")
360 140 : CALL section_vals_get(ldos_sec, explicit=bs_env%do_ldos)
361 :
362 140 : CALL section_vals_val_get(ldos_sec, "INTEGRATION", i_val=bs_env%int_ldos_xyz)
363 140 : CALL section_vals_val_get(ldos_sec, "BIN_MESH", i_vals=bs_env%bin_mesh)
364 :
365 140 : NULLIFY (kp_bs_sec)
366 140 : kp_bs_sec => section_vals_get_subs_vals(bs_sec, "BANDSTRUCTURE_PATH")
367 140 : CALL section_vals_val_get(kp_bs_sec, "NPOINTS", i_val=bs_env%input_kp_bs_npoints)
368 140 : CALL section_vals_val_get(kp_bs_sec, "UNITS", c_val=ustr)
369 140 : CALL uppercase(ustr)
370 140 : CALL section_vals_val_get(kp_bs_sec, "SPECIAL_POINT", n_rep_val=bs_env%input_kp_bs_n_sp_pts)
371 :
372 140 : NULLIFY (floquet_sec)
373 140 : floquet_sec => section_vals_get_subs_vals(bs_sec, "FLOQUET")
374 140 : CALL section_vals_get(floquet_sec, explicit=bs_env%do_floquet)
375 140 : CALL section_vals_val_get(floquet_sec, "AMPLITUDE", r_val=bs_env%floquet_amplitude)
376 140 : CALL section_vals_val_get(floquet_sec, "FREQUENCY", r_val=bs_env%floquet_omega)
377 140 : CALL section_vals_val_get(floquet_sec, "POLARISATION", r_vals=bs_env%floquet_polarisation)
378 140 : CALL section_vals_val_get(floquet_sec, "PHASE_OFFSETS", r_vals=bs_env%floquet_phi)
379 140 : CALL section_vals_val_get(floquet_sec, "MAX_FLOQUET_INDEX", i_val=bs_env%max_floquet_index)
380 140 : CALL section_vals_val_get(floquet_sec, "MAX_NMO", i_val=bs_env%max_nmo_floquet)
381 140 : CALL section_vals_val_get(floquet_sec, "EPS_FLOQUET", r_val=bs_env%eps_floquet)
382 140 : CALL section_vals_val_get(floquet_sec, "ENERGY_WINDOW", r_val=bs_env%energy_window_floquet)
383 140 : CALL section_vals_val_get(floquet_sec, "ENERGY_STEP", r_val=bs_env%energy_step_floquet)
384 140 : CALL section_vals_val_get(floquet_sec, "BROADENING", r_val=bs_env%broadening_floquet)
385 140 : CALL section_vals_val_get(floquet_sec, "MEM_FILL_FRACTION", r_val=bs_env%floquet_mem_fill_fraction)
386 140 : CALL section_vals_val_get(floquet_sec, "TEMPERATURE", r_val=bs_env%floquet_temperature)
387 140 : CALL section_vals_val_get(floquet_sec, "FLOQUET_DOS_FILE_NAME", c_val=bs_env%floquet_dos_file)
388 140 : CALL section_vals_val_get(floquet_sec, "QUASI_ENERGIES_FILE_NAME", c_val=bs_env%floquet_qe_file)
389 140 : CALL section_vals_val_get(floquet_sec, "FLOQUET_BS_FILE_NAME", c_val=bs_env%floquet_bs_file)
390 :
391 : ! read special points for band structure
392 284 : ALLOCATE (bs_env%xkp_special(3, bs_env%input_kp_bs_n_sp_pts))
393 150 : DO ikp = 1, bs_env%input_kp_bs_n_sp_pts
394 10 : CALL section_vals_val_get(kp_bs_sec, "SPECIAL_POINT", i_rep_val=ikp, c_vals=string_ptr)
395 10 : CPASSERT(SIZE(string_ptr(:), 1) == 4)
396 40 : DO i = 1, 3
397 30 : CALL read_float_object(string_ptr(i + 1), kpptr(i), error_msg)
398 40 : IF (LEN_TRIM(error_msg) > 0) CPABORT(TRIM(error_msg))
399 : END DO
400 140 : SELECT CASE (ustr)
401 : CASE ("B_VECTOR")
402 40 : bs_env%xkp_special(1:3, ikp) = kpptr(1:3)
403 : CASE ("CART_ANGSTROM")
404 : bs_env%xkp_special(1:3, ikp) = (kpptr(1)*cart_hmat(1, 1:3) + &
405 : kpptr(2)*cart_hmat(2, 1:3) + &
406 0 : kpptr(3)*cart_hmat(3, 1:3))/twopi*angstrom
407 : CASE ("CART_BOHR")
408 : bs_env%xkp_special(1:3, ikp) = (kpptr(1)*cart_hmat(1, 1:3) + &
409 : kpptr(2)*cart_hmat(2, 1:3) + &
410 0 : kpptr(3)*cart_hmat(3, 1:3))/twopi
411 : CASE DEFAULT
412 10 : CPABORT("Unknown unit <"//TRIM(ustr)//"> specified for k-point definition")
413 : END SELECT
414 : END DO
415 :
416 140 : CALL timestop(handle)
417 :
418 140 : END SUBROUTINE read_bandstructure_input_parameters
419 :
420 : ! **************************************************************************************************
421 : !> \brief ...
422 : !> \param bs_env ...
423 : ! **************************************************************************************************
424 140 : SUBROUTINE print_header(bs_env)
425 :
426 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
427 :
428 : CHARACTER(LEN=*), PARAMETER :: routineN = 'print_header'
429 :
430 : INTEGER :: handle, u
431 :
432 140 : CALL timeset(routineN, handle)
433 :
434 140 : bs_env%unit_nr = cp_logger_get_default_io_unit()
435 :
436 140 : u = bs_env%unit_nr
437 :
438 140 : IF (u > 0) THEN
439 70 : WRITE (u, '(T2,A)') ' '
440 70 : WRITE (u, '(T2,A)') REPEAT('-', 79)
441 70 : WRITE (u, '(T2,A,A78)') '-', '-'
442 70 : WRITE (u, '(T2,A,A51,A27)') '-', 'BANDSTRUCTURE CALCULATION', '-'
443 70 : WRITE (u, '(T2,A,A78)') '-', '-'
444 70 : WRITE (u, '(T2,A)') REPEAT('-', 79)
445 70 : WRITE (u, '(T2,A)') ' '
446 : END IF
447 :
448 140 : CALL timestop(handle)
449 :
450 140 : END SUBROUTINE print_header
451 :
452 : ! **************************************************************************************************
453 : !> \brief ...
454 : !> \param qs_env ...
455 : !> \param bs_env ...
456 : !> \param kpoints ...
457 : ! **************************************************************************************************
458 122 : SUBROUTINE setup_kpoints_DOS_large_cell_Gamma(qs_env, bs_env, kpoints)
459 :
460 : TYPE(qs_environment_type), POINTER :: qs_env
461 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
462 : TYPE(kpoint_type), POINTER :: kpoints
463 :
464 : CHARACTER(LEN=*), PARAMETER :: routineN = 'setup_kpoints_DOS_large_cell_Gamma'
465 :
466 : INTEGER :: handle, i_dim, i_kp_in_line, &
467 : i_special_kp, ikk, n_kp_in_line, &
468 : n_special_kp, nkp, nkp_only_bs, &
469 : nkp_only_DOS, u
470 : INTEGER, DIMENSION(3) :: nkp_grid, periodic
471 :
472 122 : CALL timeset(routineN, handle)
473 :
474 : ! routine adapted from mp2_integrals.F
475 122 : NULLIFY (kpoints)
476 122 : CALL kpoint_create(kpoints)
477 :
478 122 : kpoints%kp_scheme = "GENERAL"
479 :
480 122 : n_special_kp = bs_env%input_kp_bs_n_sp_pts
481 122 : n_kp_in_line = bs_env%input_kp_bs_npoints
482 :
483 488 : periodic(1:3) = bs_env%periodic(1:3)
484 :
485 488 : DO i_dim = 1, 3
486 :
487 366 : CPASSERT(periodic(i_dim) == 0 .OR. periodic(i_dim) == 1)
488 :
489 488 : IF (bs_env%nkp_grid_DOS_input(i_dim) < 0) THEN
490 330 : IF (periodic(i_dim) == 1) nkp_grid(i_dim) = 2
491 330 : IF (periodic(i_dim) == 0) nkp_grid(i_dim) = 1
492 : ELSE
493 36 : nkp_grid(i_dim) = bs_env%nkp_grid_DOS_input(i_dim)
494 : END IF
495 :
496 : END DO
497 :
498 : ! use the k <-> -k symmetry to reduce the number of kpoints
499 122 : IF (nkp_grid(1) > 1) THEN
500 8 : nkp_only_DOS = (nkp_grid(1) + 1)/2*nkp_grid(2)*nkp_grid(3)
501 114 : ELSE IF (nkp_grid(2) > 1) THEN
502 6 : nkp_only_DOS = nkp_grid(1)*(nkp_grid(2) + 1)/2*nkp_grid(3)
503 108 : ELSE IF (nkp_grid(3) > 1) THEN
504 2 : nkp_only_DOS = nkp_grid(1)*nkp_grid(2)*(nkp_grid(3) + 1)/2
505 : ELSE
506 106 : nkp_only_DOS = 1
507 : END IF
508 :
509 : ! we will compute the GW QP levels for all k's in the bandstructure path but also
510 : ! for all k-points from the SCF (e.g. for DOS or for self-consistent GW)
511 122 : IF (n_special_kp > 0) THEN
512 0 : nkp_only_bs = n_kp_in_line*(n_special_kp - 1) + 1
513 : ELSE
514 : nkp_only_bs = 0
515 : END IF
516 :
517 122 : nkp = nkp_only_DOS + nkp_only_bs
518 :
519 488 : kpoints%nkp_grid(1:3) = nkp_grid(1:3)
520 122 : kpoints%nkp = nkp
521 :
522 122 : bs_env%nkp_bs_and_DOS = nkp
523 122 : bs_env%nkp_only_bs = nkp_only_bs
524 122 : bs_env%nkp_only_DOS = nkp_only_DOS
525 :
526 610 : ALLOCATE (kpoints%xkp(3, nkp), kpoints%wkp(nkp))
527 262 : kpoints%wkp(:) = 0.0_dp
528 262 : kpoints%wkp(1:nkp_only_DOS) = 1.0_dp/REAL(nkp_only_DOS, KIND=dp)
529 :
530 122 : CALL compute_xkp(kpoints%xkp, 1, nkp_only_DOS, nkp_grid)
531 :
532 122 : IF (n_special_kp > 0) THEN
533 0 : kpoints%xkp(1:3, nkp_only_DOS + 1) = bs_env%xkp_special(1:3, 1)
534 0 : ikk = nkp_only_DOS + 1
535 0 : DO i_special_kp = 2, n_special_kp
536 0 : DO i_kp_in_line = 1, n_kp_in_line
537 0 : ikk = ikk + 1
538 : kpoints%xkp(1:3, ikk) = bs_env%xkp_special(1:3, i_special_kp - 1) + &
539 : REAL(i_kp_in_line, KIND=dp)/REAL(n_kp_in_line, KIND=dp)* &
540 : (bs_env%xkp_special(1:3, i_special_kp) - &
541 0 : bs_env%xkp_special(1:3, i_special_kp - 1))
542 0 : kpoints%wkp(ikk) = 0.0_dp
543 : END DO
544 : END DO
545 : END IF
546 :
547 122 : CALL kpoint_init_cell_index_simple(kpoints, qs_env)
548 :
549 122 : u = bs_env%unit_nr
550 :
551 122 : IF (u > 0 .AND. bs_env%do_periodic) THEN
552 8 : IF (nkp_only_bs > 0) THEN
553 : WRITE (u, FMT="(T2,1A,T77,I4)") &
554 0 : "Number of special k-points for the bandstructure", n_special_kp
555 0 : WRITE (u, FMT="(T2,1A,T77,I4)") "Number of k-points for the bandstructure", nkp
556 : WRITE (u, FMT="(T2,1A,T69,3I4)") &
557 0 : "K-point mesh for the density of states (DOS)", nkp_grid(1:3)
558 : ELSE
559 : WRITE (u, FMT="(T2,1A,T69,3I4)") &
560 8 : "K-point mesh for the density of states (DOS) and the self-energy", nkp_grid(1:3)
561 : END IF
562 : END IF
563 :
564 122 : CALL timestop(handle)
565 :
566 122 : END SUBROUTINE setup_kpoints_DOS_large_cell_Gamma
567 :
568 : ! **************************************************************************************************
569 : !> \brief ...
570 : !> \param qs_env ...
571 : !> \param bs_env ...
572 : !> \param kpoints ...
573 : !> \param do_print ...
574 : ! **************************************************************************************************
575 18 : SUBROUTINE setup_kpoints_scf_desymm(qs_env, bs_env, kpoints, do_print)
576 : TYPE(qs_environment_type), POINTER :: qs_env
577 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
578 : TYPE(kpoint_type), POINTER :: kpoints
579 :
580 : CHARACTER(LEN=*), PARAMETER :: routineN = 'setup_kpoints_scf_desymm'
581 :
582 : INTEGER :: handle, i_cell_x, i_dim, img, j_cell_y, &
583 : k_cell_z, nimages, nkp, u
584 : INTEGER, DIMENSION(3) :: cell_grid, cixd, nkp_grid
585 : TYPE(kpoint_type), POINTER :: kpoints_scf
586 :
587 : LOGICAL:: do_print
588 :
589 18 : CALL timeset(routineN, handle)
590 :
591 18 : NULLIFY (kpoints)
592 18 : CALL kpoint_create(kpoints)
593 :
594 18 : CALL get_qs_env(qs_env=qs_env, kpoints=kpoints_scf)
595 :
596 72 : nkp_grid(1:3) = kpoints_scf%nkp_grid(1:3)
597 18 : nkp = nkp_grid(1)*nkp_grid(2)*nkp_grid(3)
598 :
599 : ! we need in periodic directions at least 4 k-points in the SCF
600 72 : DO i_dim = 1, 3
601 72 : IF (bs_env%periodic(i_dim) == 1) THEN
602 36 : CPASSERT(nkp_grid(i_dim) >= 4)
603 : END IF
604 : END DO
605 :
606 18 : kpoints%kp_scheme = "GENERAL"
607 72 : kpoints%nkp_grid(1:3) = nkp_grid(1:3)
608 18 : kpoints%nkp = nkp
609 18 : bs_env%nkp_scf_desymm = nkp
610 :
611 54 : ALLOCATE (kpoints%xkp(1:3, nkp))
612 18 : CALL compute_xkp(kpoints%xkp, 1, nkp, nkp_grid)
613 :
614 54 : ALLOCATE (kpoints%wkp(nkp))
615 306 : kpoints%wkp(:) = 1.0_dp/REAL(nkp, KIND=dp)
616 :
617 : ! for example 4x3x6 kpoint grid -> 3x3x5 cell grid because we need the same number of
618 : ! neighbor cells on both sides of the unit cell
619 72 : cell_grid(1:3) = nkp_grid(1:3) - MODULO(nkp_grid(1:3) + 1, 2)
620 :
621 : ! cell index: for example for x: from -n_x/2 to +n_x/2, n_x: number of cells in x direction
622 72 : cixd(1:3) = cell_grid(1:3)/2
623 :
624 18 : nimages = cell_grid(1)*cell_grid(2)*cell_grid(3)
625 :
626 18 : bs_env%nimages_scf_desymm = nimages
627 72 : bs_env%cell_grid_scf_desymm(1:3) = cell_grid(1:3)
628 :
629 18 : IF (ASSOCIATED(kpoints%index_to_cell)) DEALLOCATE (kpoints%index_to_cell)
630 18 : IF (ASSOCIATED(kpoints%cell_to_index)) DEALLOCATE (kpoints%cell_to_index)
631 :
632 90 : ALLOCATE (kpoints%cell_to_index(-cixd(1):cixd(1), -cixd(2):cixd(2), -cixd(3):cixd(3)))
633 54 : ALLOCATE (kpoints%index_to_cell(3, nimages))
634 :
635 18 : img = 0
636 44 : DO i_cell_x = -cixd(1), cixd(1)
637 122 : DO j_cell_y = -cixd(2), cixd(2)
638 266 : DO k_cell_z = -cixd(3), cixd(3)
639 162 : img = img + 1
640 162 : kpoints%cell_to_index(i_cell_x, j_cell_y, k_cell_z) = img
641 726 : kpoints%index_to_cell(1:3, img) = [i_cell_x, j_cell_y, k_cell_z]
642 : END DO
643 : END DO
644 : END DO
645 :
646 18 : u = bs_env%unit_nr
647 18 : IF (u > 0 .AND. do_print) THEN
648 9 : WRITE (u, FMT="(T2,A,I49)") "Number of cells for G, χ, W, Σ", nimages
649 : END IF
650 :
651 18 : CALL timestop(handle)
652 :
653 18 : END SUBROUTINE setup_kpoints_scf_desymm
654 :
655 : ! **************************************************************************************************
656 : !> \brief ...
657 : !> \param bs_env ...
658 : !> \param kpoints ...
659 : ! **************************************************************************************************
660 18 : SUBROUTINE setup_kpoints_DOS_small_cell_full_kp(bs_env, kpoints)
661 :
662 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
663 : TYPE(kpoint_type), POINTER :: kpoints
664 :
665 : CHARACTER(LEN=*), PARAMETER :: routineN = 'setup_kpoints_DOS_small_cell_full_kp'
666 :
667 : INTEGER :: handle, i_kp_in_line, i_special_kp, ikk, &
668 : n_kp_in_line, n_special_kp, nkp, &
669 : nkp_only_bs, nkp_scf_desymm, u
670 :
671 18 : CALL timeset(routineN, handle)
672 :
673 : ! routine adapted from mp2_integrals.F
674 18 : NULLIFY (kpoints)
675 18 : CALL kpoint_create(kpoints)
676 :
677 18 : n_special_kp = bs_env%input_kp_bs_n_sp_pts
678 18 : n_kp_in_line = bs_env%input_kp_bs_npoints
679 18 : nkp_scf_desymm = bs_env%nkp_scf_desymm
680 :
681 : ! we will compute the GW QP levels for all k's in the bandstructure path but also
682 : ! for all k-points from the SCF (e.g. for DOS or for self-consistent GW)
683 18 : IF (n_special_kp > 0) THEN
684 4 : nkp_only_bs = n_kp_in_line*(n_special_kp - 1) + 1
685 : ELSE
686 : nkp_only_bs = 0
687 : END IF
688 18 : nkp = nkp_only_bs + nkp_scf_desymm
689 :
690 54 : ALLOCATE (kpoints%xkp(3, nkp))
691 54 : ALLOCATE (kpoints%wkp(nkp))
692 :
693 18 : kpoints%nkp = nkp
694 :
695 18 : bs_env%nkp_bs_and_DOS = nkp
696 18 : bs_env%nkp_only_bs = nkp_only_bs
697 18 : bs_env%nkp_only_DOS = nkp_scf_desymm
698 :
699 2340 : kpoints%xkp(1:3, 1:nkp_scf_desymm) = bs_env%kpoints_scf_desymm%xkp(1:3, 1:nkp_scf_desymm)
700 306 : kpoints%wkp(1:nkp_scf_desymm) = 1.0_dp/REAL(nkp_scf_desymm, KIND=dp)
701 :
702 18 : IF (n_special_kp > 0) THEN
703 32 : kpoints%xkp(1:3, nkp_scf_desymm + 1) = bs_env%xkp_special(1:3, 1)
704 4 : ikk = nkp_scf_desymm + 1
705 10 : DO i_special_kp = 2, n_special_kp
706 70 : DO i_kp_in_line = 1, n_kp_in_line
707 60 : ikk = ikk + 1
708 : kpoints%xkp(1:3, ikk) = bs_env%xkp_special(1:3, i_special_kp - 1) + &
709 : REAL(i_kp_in_line, KIND=dp)/REAL(n_kp_in_line, KIND=dp)* &
710 : (bs_env%xkp_special(1:3, i_special_kp) - &
711 480 : bs_env%xkp_special(1:3, i_special_kp - 1))
712 66 : kpoints%wkp(ikk) = 0.0_dp
713 : END DO
714 : END DO
715 : END IF
716 :
717 18 : IF (ASSOCIATED(kpoints%index_to_cell)) DEALLOCATE (kpoints%index_to_cell)
718 :
719 54 : ALLOCATE (kpoints%index_to_cell(3, bs_env%nimages_scf_desymm))
720 1332 : kpoints%index_to_cell(:, :) = bs_env%kpoints_scf_desymm%index_to_cell(:, :)
721 :
722 18 : u = bs_env%unit_nr
723 :
724 18 : IF (u > 0) THEN
725 9 : WRITE (u, FMT="(T2,1A,T77,I4)") "Number of special k-points for the bandstructure", &
726 18 : n_special_kp
727 9 : WRITE (u, FMT="(T2,1A,T77,I4)") "Number of k-points for the bandstructure", nkp
728 : END IF
729 :
730 18 : CALL timestop(handle)
731 :
732 18 : END SUBROUTINE setup_kpoints_DOS_small_cell_full_kp
733 :
734 : ! **************************************************************************************************
735 : !> \brief ...
736 : !> \param qs_env ...
737 : !> \param bs_env ...
738 : ! **************************************************************************************************
739 18 : SUBROUTINE compute_cfm_mo_coeff_kp_and_eigenval_scf_kp(qs_env, bs_env)
740 : TYPE(qs_environment_type), POINTER :: qs_env
741 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
742 :
743 : CHARACTER(LEN=*), PARAMETER :: routineN = 'compute_cfm_mo_coeff_kp_and_eigenval_scf_kp'
744 :
745 : INTEGER :: handle, ikp, ispin, nkp_bs_and_DOS, &
746 : nmo_retained
747 18 : INTEGER, DIMENSION(:, :, :), POINTER :: cell_to_index_scf
748 : REAL(KIND=dp) :: CBM, VBM
749 : REAL(KIND=dp), DIMENSION(3) :: xkp
750 : TYPE(cp_cfm_type) :: cfm_ks, cfm_mos, cfm_s
751 18 : TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER :: matrix_ks, matrix_s
752 : TYPE(kpoint_env_type), POINTER :: lowdin_kp
753 : TYPE(kpoint_type), POINTER :: kpoints_scf
754 : TYPE(neighbor_list_set_p_type), DIMENSION(:), &
755 18 : POINTER :: sab_nl
756 :
757 18 : CALL timeset(routineN, handle)
758 :
759 : CALL get_qs_env(qs_env, &
760 : matrix_ks_kp=matrix_ks, &
761 : matrix_s_kp=matrix_s, &
762 18 : kpoints=kpoints_scf)
763 :
764 18 : NULLIFY (sab_nl, lowdin_kp)
765 18 : IF (ALLOCATED(kpoints_scf%lowdin_v)) THEN
766 0 : IF (ANY(kpoints_scf%lowdin_v /= 0.0_dp)) ALLOCATE (lowdin_kp)
767 : END IF
768 18 : CALL get_kpoint_info(kpoints_scf, sab_nl=sab_nl, cell_to_index=cell_to_index_scf)
769 :
770 18 : CALL cp_cfm_create(cfm_ks, bs_env%cfm_work_mo%matrix_struct)
771 18 : CALL cp_cfm_create(cfm_s, bs_env%cfm_work_mo%matrix_struct)
772 18 : CALL cp_cfm_create(cfm_mos, bs_env%cfm_work_mo%matrix_struct)
773 :
774 : ! nkp_bs_and_DOS contains desymmetrized k-point mesh from SCF and k-points from GW bandstructure
775 18 : nkp_bs_and_DOS = bs_env%nkp_bs_and_DOS
776 :
777 18 : CALL allocate_GW_eigenvalues(bs_env)
778 :
779 442 : ALLOCATE (bs_env%cfm_mo_coeff_kp(nkp_bs_and_DOS, bs_env%n_spin))
780 442 : ALLOCATE (bs_env%cfm_ks_kp(nkp_bs_and_DOS, bs_env%n_spin))
781 406 : ALLOCATE (bs_env%cfm_s_kp(nkp_bs_and_DOS))
782 370 : DO ikp = 1, nkp_bs_and_DOS
783 704 : DO ispin = 1, bs_env%n_spin
784 352 : CALL cp_cfm_create(bs_env%cfm_mo_coeff_kp(ikp, ispin), bs_env%cfm_work_mo%matrix_struct)
785 704 : CALL cp_cfm_create(bs_env%cfm_ks_kp(ikp, ispin), bs_env%cfm_work_mo%matrix_struct)
786 : END DO
787 370 : CALL cp_cfm_create(bs_env%cfm_s_kp(ikp), bs_env%cfm_work_mo%matrix_struct)
788 : END DO
789 :
790 370 : DO ikp = 1, nkp_bs_and_DOS
791 :
792 1408 : xkp(1:3) = bs_env%kpoints_DOS%xkp(1:3, ikp)
793 :
794 : ! S(k) and its Lowdin projectors are shared by both spin channels.
795 352 : CALL rsmat_to_kp(matrix_s, 1, xkp, cell_to_index_scf, sab_nl, bs_env, cfm_s)
796 352 : CALL cp_cfm_to_cfm(cfm_s, bs_env%cfm_s_kp(ikp))
797 352 : IF (ASSOCIATED(lowdin_kp)) THEN
798 0 : CALL lowdin_kp_prepare(lowdin_kp, kpoints_scf%lowdin_orbitals, .FALSE., cfm_s)
799 : END IF
800 722 : DO ispin = 1, bs_env%n_spin
801 : ! h^KS^R -> h^KS(k)
802 352 : CALL rsmat_to_kp(matrix_ks, ispin, xkp, cell_to_index_scf, sab_nl, bs_env, cfm_ks)
803 352 : IF (ASSOCIATED(lowdin_kp)) THEN
804 0 : CALL lowdin_kp_apply(lowdin_kp, kpoints_scf%lowdin_v(:, ispin), cmat=cfm_ks)
805 : END IF
806 :
807 : ! we store the complex KS matrix as fm matrix because the infrastructure for fm is
808 : ! much nicer compared to cfm
809 352 : CALL cp_cfm_to_cfm(cfm_ks, bs_env%cfm_ks_kp(ikp, ispin))
810 352 : CALL cp_cfm_to_cfm(bs_env%cfm_s_kp(ikp), cfm_s)
811 :
812 : ! Diagonalize KS-matrix via Rothaan-Hall equation:
813 : ! H^KS(k) C(k) = S(k) C(k) ε(k)
814 : CALL cp_cfm_geeig_canon(cfm_ks, cfm_s, cfm_mos, &
815 : bs_env%eigenval_scf(:, ikp, ispin), &
816 : bs_env%cfm_work_mo, bs_env%eps_eigval_mat_s, &
817 352 : nmo_retained=nmo_retained)
818 352 : bs_env%n_mo_retained = MIN(bs_env%n_mo_retained, nmo_retained)
819 :
820 : ! we store the complex MO coeff as fm matrix because the infrastructure for fm is
821 : ! much nicer compared to cfm
822 704 : CALL cp_cfm_to_cfm(cfm_mos, bs_env%cfm_mo_coeff_kp(ikp, ispin))
823 :
824 : END DO
825 : END DO
826 :
827 36 : DO ispin = 1, bs_env%n_spin
828 370 : VBM = MAXVAL(bs_env%eigenval_scf(bs_env%n_occ(ispin), :, ispin))
829 370 : CBM = MINVAL(bs_env%eigenval_scf(bs_env%n_occ(ispin) + 1, :, ispin))
830 :
831 36 : bs_env%e_fermi(ispin) = 0.5_dp*(VBM + CBM)
832 :
833 : END DO
834 :
835 18 : CALL get_VBM_CBM_bandgaps(bs_env%band_edges_scf, bs_env%eigenval_scf, bs_env)
836 :
837 18 : CALL cp_cfm_release(cfm_ks)
838 18 : CALL cp_cfm_release(cfm_s)
839 18 : CALL cp_cfm_release(cfm_mos)
840 18 : IF (ASSOCIATED(lowdin_kp)) THEN
841 0 : CALL cp_cfm_release(lowdin_kp%lowdin_cb)
842 0 : CALL cp_cfm_release(lowdin_kp%lowdin_cwork)
843 0 : CALL lowdin_kp%lowdin_gemm%destroy()
844 0 : DEALLOCATE (lowdin_kp)
845 : END IF
846 :
847 18 : CALL timestop(handle)
848 :
849 36 : END SUBROUTINE compute_cfm_mo_coeff_kp_and_eigenval_scf_kp
850 :
851 : ! **************************************************************************************************
852 : !> \brief ...
853 : !> \param mat_rs ...
854 : !> \param ispin ...
855 : !> \param xkp ...
856 : !> \param cell_to_index_scf ...
857 : !> \param sab_nl ...
858 : !> \param bs_env ...
859 : !> \param cfm_kp ...
860 : !> \param imag_rs_mat ...
861 : ! **************************************************************************************************
862 1976 : SUBROUTINE rsmat_to_kp(mat_rs, ispin, xkp, cell_to_index_scf, sab_nl, bs_env, cfm_kp, imag_rs_mat)
863 : TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER :: mat_rs
864 : INTEGER :: ispin
865 : REAL(KIND=dp), DIMENSION(3) :: xkp
866 : INTEGER, DIMENSION(:, :, :), POINTER :: cell_to_index_scf
867 : TYPE(neighbor_list_set_p_type), DIMENSION(:), &
868 : POINTER :: sab_nl
869 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
870 : TYPE(cp_cfm_type) :: cfm_kp
871 : LOGICAL, OPTIONAL :: imag_rs_mat
872 :
873 : CHARACTER(LEN=*), PARAMETER :: routineN = 'rsmat_to_kp'
874 :
875 : INTEGER :: handle
876 : LOGICAL :: imag_rs_mat_private
877 : TYPE(dbcsr_type), POINTER :: cmat, nsmat, rmat
878 :
879 1976 : CALL timeset(routineN, handle)
880 :
881 1976 : ALLOCATE (rmat, cmat, nsmat)
882 :
883 1976 : imag_rs_mat_private = .FALSE.
884 1976 : IF (PRESENT(imag_rs_mat)) imag_rs_mat_private = imag_rs_mat
885 :
886 954 : IF (imag_rs_mat_private) THEN
887 954 : CALL dbcsr_create(rmat, template=mat_rs(1, 1)%matrix, matrix_type=dbcsr_type_antisymmetric)
888 954 : CALL dbcsr_create(cmat, template=mat_rs(1, 1)%matrix, matrix_type=dbcsr_type_symmetric)
889 : ELSE
890 1022 : CALL dbcsr_create(rmat, template=mat_rs(1, 1)%matrix, matrix_type=dbcsr_type_symmetric)
891 1022 : CALL dbcsr_create(cmat, template=mat_rs(1, 1)%matrix, matrix_type=dbcsr_type_antisymmetric)
892 : END IF
893 1976 : CALL dbcsr_create(nsmat, template=mat_rs(1, 1)%matrix, matrix_type=dbcsr_type_no_symmetry)
894 1976 : CALL cp_dbcsr_alloc_block_from_nbl(rmat, sab_nl)
895 1976 : CALL cp_dbcsr_alloc_block_from_nbl(cmat, sab_nl)
896 :
897 1976 : CALL dbcsr_set(rmat, 0.0_dp)
898 1976 : CALL dbcsr_set(cmat, 0.0_dp)
899 : CALL rskp_transform(rmatrix=rmat, cmatrix=cmat, rsmat=mat_rs, ispin=ispin, &
900 1976 : xkp=xkp, cell_to_index=cell_to_index_scf, sab_nl=sab_nl)
901 :
902 1976 : CALL dbcsr_desymmetrize(rmat, nsmat)
903 1976 : CALL copy_dbcsr_to_fm(nsmat, bs_env%fm_work_mo(1))
904 1976 : CALL dbcsr_desymmetrize(cmat, nsmat)
905 1976 : CALL copy_dbcsr_to_fm(nsmat, bs_env%fm_work_mo(2))
906 1976 : CALL cp_fm_to_cfm(bs_env%fm_work_mo(1), bs_env%fm_work_mo(2), cfm_kp)
907 :
908 1976 : CALL dbcsr_deallocate_matrix(rmat)
909 1976 : CALL dbcsr_deallocate_matrix(cmat)
910 1976 : CALL dbcsr_deallocate_matrix(nsmat)
911 :
912 1976 : CALL timestop(handle)
913 :
914 1976 : END SUBROUTINE rsmat_to_kp
915 :
916 : ! **************************************************************************************************
917 : !> \brief ...
918 : !> \param bs_env ...
919 : ! **************************************************************************************************
920 122 : SUBROUTINE diagonalize_ks_matrix(bs_env)
921 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
922 :
923 : CHARACTER(LEN=*), PARAMETER :: routineN = 'diagonalize_ks_matrix'
924 :
925 : INTEGER :: handle, ikp, ispin, nmo_retained
926 : REAL(KIND=dp) :: CBM, VBM
927 :
928 122 : CALL timeset(routineN, handle)
929 :
930 488 : ALLOCATE (bs_env%eigenval_scf_Gamma(bs_env%n_ao, bs_env%n_spin))
931 :
932 262 : DO ispin = 1, bs_env%n_spin
933 :
934 : ! use work matrices because the matrices are overwritten in cp_fm_geeig_canon
935 140 : CALL cp_fm_to_fm(bs_env%fm_ks_Gamma(ispin), bs_env%fm_work_mo(1))
936 140 : CALL cp_fm_to_fm(bs_env%fm_s_Gamma, bs_env%fm_work_mo(2))
937 :
938 : ! diagonalize the Kohn-Sham matrix to obtain MO coefficients and SCF eigenvalues
939 : ! (at the Gamma-point)
940 : CALL cp_fm_geeig_canon(bs_env%fm_work_mo(1), &
941 : bs_env%fm_work_mo(2), &
942 : bs_env%fm_mo_coeff_Gamma(ispin), &
943 : bs_env%eigenval_scf_Gamma(:, ispin), &
944 : bs_env%fm_work_mo(3), &
945 : bs_env%eps_eigval_mat_s, &
946 140 : nmo_retained=nmo_retained)
947 140 : bs_env%n_mo_retained = MIN(bs_env%n_mo_retained, nmo_retained)
948 :
949 140 : VBM = bs_env%eigenval_scf_Gamma(bs_env%n_occ(ispin), ispin)
950 140 : CBM = bs_env%eigenval_scf_Gamma(bs_env%n_occ(ispin) + 1, ispin)
951 :
952 262 : bs_env%e_fermi(ispin) = 0.5_dp*(VBM + CBM)
953 :
954 : END DO
955 :
956 122 : CALL timestop(handle)
957 :
958 : ! Gamma-only path for molecules: eigenval_scf is filled here from the Gamma eigenvalues
959 262 : DO ispin = 1, bs_env%n_spin
960 424 : DO ikp = 1, bs_env%nkp_bs_and_DOS
961 2280 : bs_env%eigenval_scf(:, ikp, ispin) = bs_env%eigenval_scf_Gamma(:, ispin)
962 : END DO
963 : END DO
964 :
965 122 : END SUBROUTINE diagonalize_ks_matrix
966 :
967 : ! **************************************************************************************************
968 : !> \brief ...
969 : !> \param bs_env ...
970 : !> \param qs_env ...
971 : ! **************************************************************************************************
972 122 : SUBROUTINE check_positive_definite_overlap_mat(bs_env, qs_env)
973 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
974 : TYPE(qs_environment_type), POINTER :: qs_env
975 :
976 : CHARACTER(LEN=*), PARAMETER :: routineN = 'check_positive_definite_overlap_mat'
977 :
978 : INTEGER :: handle, ikp, info, u
979 : TYPE(cp_cfm_type) :: cfm_s_ikp
980 :
981 122 : CALL timeset(routineN, handle)
982 :
983 262 : DO ikp = 1, bs_env%kpoints_DOS%nkp
984 :
985 : ! get S_µν(k_i) from S_µν(k=0)
986 : CALL cfm_ikp_from_fm_Gamma(cfm_s_ikp, bs_env%fm_s_Gamma, &
987 140 : ikp, qs_env, bs_env%kpoints_DOS, "ORB")
988 :
989 : ! check whether S_µν(k_i) is positive definite
990 140 : CALL cp_cfm_cholesky_decompose(matrix=cfm_s_ikp, n=bs_env%n_ao, info_out=info)
991 :
992 : ! check if Cholesky decomposition failed (Cholesky decomposition only works for
993 : ! positive definite matrices
994 262 : IF (info /= 0) THEN
995 0 : u = bs_env%unit_nr
996 :
997 0 : IF (u > 0) THEN
998 0 : WRITE (u, FMT="(T2,A)") ""
999 : WRITE (u, FMT="(T2,A)") "ERROR: The Cholesky decomposition "// &
1000 0 : "of the k-point overlap matrix failed. This is"
1001 : WRITE (u, FMT="(T2,A)") "because the algorithm is "// &
1002 0 : "only correct in the limit of large cells. The cell of "
1003 : WRITE (u, FMT="(T2,A)") "the calculation is too small. "// &
1004 0 : "Use MULTIPLE_UNIT_CELL to create a larger cell "
1005 0 : WRITE (u, FMT="(T2,A)") "and to prevent this error."
1006 : END IF
1007 :
1008 0 : CALL bs_env%para_env%sync()
1009 0 : CPABORT("Please see information on the error above.")
1010 :
1011 : END IF ! Cholesky decomposition failed
1012 :
1013 : END DO ! ikp
1014 :
1015 122 : CALL cp_cfm_release(cfm_s_ikp)
1016 :
1017 122 : CALL timestop(handle)
1018 :
1019 122 : END SUBROUTINE check_positive_definite_overlap_mat
1020 :
1021 : ! **************************************************************************************************
1022 : !> \brief ...
1023 : !> \param qs_env ...
1024 : !> \param bs_env ...
1025 : ! **************************************************************************************************
1026 280 : SUBROUTINE get_parameters_from_qs_env(qs_env, bs_env)
1027 : TYPE(qs_environment_type), POINTER :: qs_env
1028 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
1029 :
1030 : CHARACTER(LEN=*), PARAMETER :: routineN = 'get_parameters_from_qs_env'
1031 :
1032 : INTEGER :: color_sub, handle, homo, n_ao, n_atom, &
1033 : nelectron, u
1034 : INTEGER, DIMENSION(3) :: periodic
1035 : REAL(KIND=dp) :: maxocc
1036 : REAL(KIND=dp), DIMENSION(3, 3) :: hmat
1037 : TYPE(cell_type), POINTER :: cell
1038 : TYPE(dft_control_type), POINTER :: dft_control
1039 140 : TYPE(mo_set_type), DIMENSION(:), POINTER :: mos
1040 : TYPE(mp_para_env_type), POINTER :: para_env
1041 140 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
1042 : TYPE(scf_control_type), POINTER :: scf_control
1043 : TYPE(section_vals_type), POINTER :: input
1044 :
1045 140 : CALL timeset(routineN, handle)
1046 :
1047 : CALL get_qs_env(qs_env, &
1048 : dft_control=dft_control, &
1049 : scf_control=scf_control, &
1050 140 : mos=mos)
1051 :
1052 140 : bs_env%n_spin = dft_control%nspins
1053 140 : IF (bs_env%n_spin == 1) bs_env%spin_degeneracy = 2.0_dp
1054 140 : IF (bs_env%n_spin == 2) bs_env%spin_degeneracy = 1.0_dp
1055 :
1056 140 : CALL get_mo_set(mo_set=mos(1), nao=n_ao, homo=homo, nelectron=nelectron, maxocc=maxocc)
1057 140 : bs_env%n_ao = n_ao
1058 420 : bs_env%n_occ_nosmear(1:2) = NINT(nelectron/maxocc) !fix for moire large-cell Gamma
1059 420 : bs_env%n_electron(1:2) = nelectron
1060 : ! lowered by the diagonalization below if the canonical orthogonalization removes modes
1061 140 : bs_env%n_mo_retained = n_ao
1062 420 : bs_env%n_occ(1:2) = homo
1063 420 : bs_env%n_vir(1:2) = n_ao - homo
1064 140 : IF (bs_env%n_spin == 2) THEN
1065 18 : CALL get_mo_set(mo_set=mos(2), homo=homo, nelectron=nelectron, maxocc=maxocc)
1066 18 : bs_env%n_occ_nosmear(2) = NINT(nelectron/maxocc)
1067 18 : bs_env%n_occ(2) = homo
1068 18 : bs_env%n_vir(2) = n_ao - homo
1069 18 : bs_env%n_electron(2) = nelectron
1070 : END IF
1071 140 : bs_env%eps_eigval_mat_s = scf_control%eps_eigval
1072 : ! reuse the ground-state SCF's &SMEAR settings (if any) for the metal-capable Fermi
1073 : ! level search (get_fermi_level_1c/2c); SMEAR_ENERGY_WINDOW and SMEAR_LIST are not
1074 : ! supported by Smearkp/Smearkp2, so fall back to the T=0 bisection for those
1075 140 : bs_env%do_smear = .FALSE.
1076 140 : bs_env%smear_method = smear_fermi_dirac
1077 140 : bs_env%smear_width = 0.0_dp
1078 140 : IF (scf_control%smear%do_smear) THEN
1079 4 : SELECT CASE (scf_control%smear%method)
1080 : CASE (smear_fermi_dirac)
1081 2 : bs_env%do_smear = .TRUE.
1082 2 : bs_env%smear_method = smear_fermi_dirac
1083 2 : bs_env%smear_width = scf_control%smear%electronic_temperature
1084 : CASE (smear_gaussian, smear_mp, smear_mv)
1085 0 : bs_env%do_smear = .TRUE.
1086 0 : bs_env%smear_method = scf_control%smear%method
1087 0 : bs_env%smear_width = scf_control%smear%smearing_width
1088 : CASE DEFAULT
1089 2 : IF (bs_env%unit_nr > 0) THEN
1090 : WRITE (bs_env%unit_nr, '(T2,A)') &
1091 : 'SMEAR method not supported for the post-SCF Fermi level search, '// &
1092 0 : 'falling back to a T=0 bisection.'
1093 : END IF
1094 : END SELECT
1095 : END IF
1096 140 : CPASSERT(scf_control%smear%fixed_mag_mom <= 0.0_dp)
1097 : ! get para_env from qs_env (bs_env%para_env is identical to para_env in qs_env)
1098 140 : CALL get_qs_env(qs_env, para_env=para_env)
1099 140 : color_sub = 0
1100 140 : ALLOCATE (bs_env%para_env)
1101 140 : CALL bs_env%para_env%from_split(para_env, color_sub)
1102 :
1103 140 : CALL get_qs_env(qs_env, particle_set=particle_set)
1104 :
1105 140 : n_atom = SIZE(particle_set)
1106 140 : bs_env%n_atom = n_atom
1107 :
1108 140 : CALL get_qs_env(qs_env=qs_env, cell=cell)
1109 140 : CALL get_cell(cell=cell, periodic=periodic, h=hmat)
1110 560 : bs_env%periodic(1:3) = periodic(1:3)
1111 480 : bs_env%do_periodic = ANY(bs_env%periodic /= 0)
1112 1820 : bs_env%hmat(1:3, 1:3) = hmat
1113 140 : bs_env%nimages_scf = dft_control%nimages
1114 140 : IF (dft_control%nimages == 1) THEN
1115 122 : IF (bs_env%do_gw_ri_rs) THEN
1116 40 : IF (bs_env%do_periodic) THEN
1117 0 : bs_env%gw_implementation = ri_rs_large_cell_Gamma
1118 : ELSE
1119 40 : bs_env%gw_implementation = ri_rs_non_periodic
1120 : END IF
1121 82 : ELSE IF (bs_env%do_static_cohsex) THEN
1122 8 : bs_env%gw_implementation = tensor_static_cohsex
1123 : ELSE
1124 74 : bs_env%gw_implementation = tensor_large_cell_Gamma
1125 : END IF
1126 18 : ELSE IF (dft_control%nimages > 1) THEN
1127 18 : IF (bs_env%do_gw_ri_rs) THEN
1128 0 : CPABORT("RI-RS Not Implemented for K-point Calculations")
1129 18 : ELSE IF (bs_env%do_static_cohsex) THEN
1130 0 : CPABORT("COHSEX Not Implemented for K-point Calculations")
1131 : ELSE
1132 18 : bs_env%gw_implementation = tensor_small_cell_full_kp
1133 : END IF
1134 : ELSE
1135 0 : CPABORT("Wrong number of cells from DFT calculation.")
1136 : END IF
1137 :
1138 140 : u = bs_env%unit_nr
1139 :
1140 : ! Marek : Get and save the rtp method
1141 140 : CALL get_qs_env(qs_env=qs_env, input=input)
1142 140 : CALL section_vals_val_get(input, "DFT%REAL_TIME_PROPAGATION%RTBSE%_SECTION_PARAMETERS_", i_val=bs_env%rtp_method)
1143 :
1144 140 : IF (u > 0) THEN
1145 70 : WRITE (u, FMT="(T2,2A,T73,I8)") "Number of occupied molecular orbitals (MOs) ", &
1146 140 : "= Number of occupied bands", homo
1147 70 : WRITE (u, FMT="(T2,2A,T73,I8)") "Number of unoccupied (= virtual) MOs ", &
1148 140 : "= Number of unoccupied bands", n_ao - homo
1149 70 : WRITE (u, FMT="(T2,A,T73,I8)") "Number of Gaussian basis functions for MOs", n_ao
1150 70 : IF (bs_env%gw_implementation == tensor_small_cell_full_kp) THEN
1151 9 : WRITE (u, FMT="(T2,2A,T73,I8)") "Number of cells considered in the DFT ", &
1152 18 : "calculation", bs_env%nimages_scf
1153 : END IF
1154 : END IF
1155 :
1156 140 : CALL timestop(handle)
1157 :
1158 140 : END SUBROUTINE get_parameters_from_qs_env
1159 :
1160 : ! **************************************************************************************************
1161 : !> \brief ...
1162 : !> \param bs_env ...
1163 : ! **************************************************************************************************
1164 140 : SUBROUTINE set_heuristic_parameters(bs_env)
1165 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
1166 :
1167 : CHARACTER(LEN=*), PARAMETER :: routineN = 'set_heuristic_parameters'
1168 :
1169 : INTEGER :: handle
1170 :
1171 140 : CALL timeset(routineN, handle)
1172 :
1173 140 : bs_env%n_bins_max_for_printing = 5000
1174 :
1175 140 : CALL timestop(handle)
1176 :
1177 140 : END SUBROUTINE set_heuristic_parameters
1178 :
1179 : ! **************************************************************************************************
1180 : !> \brief ...
1181 : !> \param qs_env ...
1182 : !> \param bs_env ...
1183 : ! **************************************************************************************************
1184 140 : SUBROUTINE allocate_and_fill_fm_ks_fm_s(qs_env, bs_env)
1185 : TYPE(qs_environment_type), POINTER :: qs_env
1186 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
1187 :
1188 : CHARACTER(LEN=*), PARAMETER :: routineN = 'allocate_and_fill_fm_ks_fm_s'
1189 :
1190 : INTEGER :: handle, i_work, ispin
1191 : TYPE(cp_blacs_env_type), POINTER :: blacs_env
1192 : TYPE(cp_fm_struct_type), POINTER :: fm_struct
1193 140 : TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER :: matrix_ks, matrix_s
1194 : TYPE(mp_para_env_type), POINTER :: para_env
1195 :
1196 140 : CALL timeset(routineN, handle)
1197 :
1198 : CALL get_qs_env(qs_env, &
1199 : para_env=para_env, &
1200 : blacs_env=blacs_env, &
1201 : matrix_ks_kp=matrix_ks, &
1202 140 : matrix_s_kp=matrix_s)
1203 :
1204 140 : NULLIFY (fm_struct)
1205 : CALL cp_fm_struct_create(fm_struct, context=blacs_env, nrow_global=bs_env%n_ao, &
1206 140 : ncol_global=bs_env%n_ao, para_env=para_env)
1207 :
1208 700 : DO i_work = 1, SIZE(bs_env%fm_work_mo)
1209 700 : CALL cp_fm_create(bs_env%fm_work_mo(i_work), fm_struct)
1210 : END DO
1211 :
1212 140 : CALL cp_cfm_create(bs_env%cfm_work_mo, fm_struct)
1213 140 : CALL cp_cfm_create(bs_env%cfm_work_mo_2, fm_struct)
1214 :
1215 140 : CALL cp_fm_create(bs_env%fm_s_Gamma, fm_struct)
1216 140 : CALL copy_dbcsr_to_fm(matrix_s(1, 1)%matrix, bs_env%fm_s_Gamma)
1217 :
1218 298 : DO ispin = 1, bs_env%n_spin
1219 158 : CALL cp_fm_create(bs_env%fm_ks_Gamma(ispin), fm_struct)
1220 158 : CALL copy_dbcsr_to_fm(matrix_ks(ispin, 1)%matrix, bs_env%fm_ks_Gamma(ispin))
1221 298 : CALL cp_fm_create(bs_env%fm_mo_coeff_Gamma(ispin), fm_struct)
1222 : END DO
1223 :
1224 140 : CALL cp_fm_struct_release(fm_struct)
1225 :
1226 140 : NULLIFY (bs_env%mat_ao_ao%matrix)
1227 140 : ALLOCATE (bs_env%mat_ao_ao%matrix)
1228 : CALL dbcsr_create(bs_env%mat_ao_ao%matrix, template=matrix_s(1, 1)%matrix, &
1229 140 : matrix_type=dbcsr_type_no_symmetry)
1230 :
1231 700 : ALLOCATE (bs_env%eigenval_scf(bs_env%n_ao, bs_env%nkp_bs_and_DOS, bs_env%n_spin))
1232 :
1233 140 : CALL timestop(handle)
1234 :
1235 140 : END SUBROUTINE allocate_and_fill_fm_ks_fm_s
1236 :
1237 : ! **************************************************************************************************
1238 : !> \brief ...
1239 : !> \param qs_env ...
1240 : !> \param bs_env ...
1241 : ! **************************************************************************************************
1242 140 : SUBROUTINE eval_bandstructure_properties(qs_env, bs_env)
1243 : TYPE(qs_environment_type), POINTER :: qs_env
1244 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
1245 :
1246 : CHARACTER(LEN=*), PARAMETER :: routineN = 'eval_bandstructure_properties'
1247 :
1248 : CHARACTER(LEN=default_string_length) :: gw_label, gw_soc_label
1249 : INTEGER :: handle, homo, homo_1, homo_2, &
1250 : homo_spinor, ikp, ikp_for_file, ispin, &
1251 : n_ao, n_E, nkind, nkp
1252 : LOGICAL :: is_bandstruc_kpoint, print_DOS_kpoints, &
1253 : print_ikp
1254 : REAL(KIND=dp) :: broadening, E_max, E_max_G0W0, E_min, E_min_G0W0, E_total_window, &
1255 : energy_step_DOS, energy_window_DOS, n_el_spinor, t1
1256 140 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: DOS_G0W0, DOS_G0W0_SOC, DOS_scf, DOS_scf_SOC, &
1257 140 : eigenval, eigenval_spinor, eigenval_spinor_G0W0, eigenval_spinor_no_SOC
1258 140 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: eigenval_spinor_all_gw, &
1259 140 : eigenval_spinor_all_scf, PDOS_G0W0, PDOS_G0W0_SOC, PDOS_scf, PDOS_scf_SOC, proj_mo_on_kind
1260 140 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: LDOS_G0W0_2d, LDOS_scf_2d, &
1261 140 : LDOS_scf_2d_SOC
1262 : TYPE(band_edges_type) :: band_edges_G0W0, band_edges_G0W0_SOC, &
1263 : band_edges_scf, band_edges_scf_guess, &
1264 : band_edges_scf_SOC
1265 : TYPE(cp_cfm_type) :: cfm_ks_ikp, cfm_ks_ikp_spinor, cfm_mos_ikp_spinor, cfm_s_ikp, &
1266 : cfm_s_ikp_copy, cfm_s_ikp_spinor, cfm_s_ikp_spinor_copy, cfm_SOC_ikp_spinor, &
1267 : cfm_spinor_wf_ikp, cfm_work_ikp, cfm_work_ikp_spinor
1268 420 : TYPE(cp_cfm_type), DIMENSION(2) :: cfm_mos_ikp
1269 :
1270 140 : CALL timeset(routineN, handle)
1271 :
1272 140 : n_ao = bs_env%n_ao
1273 :
1274 140 : energy_window_DOS = bs_env%energy_window_DOS
1275 140 : energy_step_DOS = bs_env%energy_step_DOS
1276 140 : broadening = bs_env%broadening_DOS
1277 :
1278 : ! if we have done GW or a full kpoint SCF, we already have the band edges
1279 140 : IF (bs_env%do_gw .OR. &
1280 : bs_env%gw_implementation == tensor_small_cell_full_kp) THEN
1281 140 : band_edges_scf = bs_env%band_edges_scf
1282 140 : band_edges_scf_guess = band_edges_scf
1283 : ELSE
1284 :
1285 0 : IF (bs_env%n_spin == 1) THEN
1286 0 : homo = bs_env%n_occ(1)
1287 0 : band_edges_scf_guess%VBM = bs_env%eigenval_scf_Gamma(homo, 1)
1288 0 : band_edges_scf_guess%CBM = bs_env%eigenval_scf_Gamma(homo + 1, 1)
1289 : ELSE
1290 0 : homo_1 = bs_env%n_occ(1)
1291 0 : homo_2 = bs_env%n_occ(2)
1292 : band_edges_scf_guess%VBM = MAX(bs_env%eigenval_scf_Gamma(homo_1, 1), &
1293 0 : bs_env%eigenval_scf_Gamma(homo_2, 2))
1294 : band_edges_scf_guess%CBM = MIN(bs_env%eigenval_scf_Gamma(homo_1 + 1, 1), &
1295 0 : bs_env%eigenval_scf_Gamma(homo_2 + 1, 2))
1296 : END IF
1297 :
1298 : ! initialization
1299 0 : band_edges_scf%VBM = -1000.0_dp
1300 0 : band_edges_scf%CBM = 1000.0_dp
1301 0 : band_edges_scf%DBG = 1000.0_dp
1302 : END IF
1303 :
1304 140 : E_min = band_edges_scf_guess%VBM - 0.5_dp*energy_window_DOS
1305 140 : E_max = band_edges_scf_guess%CBM + 0.5_dp*energy_window_DOS
1306 :
1307 140 : IF (bs_env%do_gw) THEN
1308 138 : band_edges_G0W0 = bs_env%band_edges_GW
1309 138 : E_min_G0W0 = band_edges_G0W0%VBM - 0.5_dp*energy_window_DOS
1310 138 : E_max_G0W0 = band_edges_G0W0%CBM + 0.5_dp*energy_window_DOS
1311 138 : E_min = MIN(E_min, E_min_G0W0)
1312 138 : E_max = MAX(E_max, E_max_G0W0)
1313 : END IF
1314 :
1315 140 : E_total_window = E_max - E_min
1316 :
1317 140 : n_E = INT(E_total_window/energy_step_DOS)
1318 :
1319 140 : CALL get_qs_env(qs_env, nkind=nkind)
1320 :
1321 560 : ALLOCATE (proj_mo_on_kind(n_ao, nkind))
1322 140 : proj_mo_on_kind(:, :) = 0.0_dp
1323 :
1324 420 : ALLOCATE (eigenval(n_ao))
1325 420 : ALLOCATE (eigenval_spinor(2*n_ao))
1326 280 : ALLOCATE (eigenval_spinor_no_SOC(2*n_ao))
1327 280 : ALLOCATE (eigenval_spinor_G0W0(2*n_ao))
1328 :
1329 : ! collect the SOC spinor eigenvalues of every DOS k-point (band-structure-path
1330 : ! k-points are included but carry wkp=0, see get_fermi_level_1c) to later obtain
1331 : ! the SCF+SOC (and, if requested, G0W0+SOC) Fermi level from get_fermi_level_1c
1332 140 : IF (bs_env%do_soc) THEN
1333 88 : ALLOCATE (eigenval_spinor_all_scf(2*n_ao, bs_env%nkp_bs_and_DOS))
1334 22 : IF (bs_env%do_gw) THEN
1335 66 : ALLOCATE (eigenval_spinor_all_gw(2*n_ao, bs_env%nkp_bs_and_DOS))
1336 : END IF
1337 : END IF
1338 :
1339 140 : IF (bs_env%do_dos_pdos) THEN
1340 :
1341 78 : ALLOCATE (DOS_scf(n_E))
1342 26 : DOS_scf(:) = 0.0_dp
1343 104 : ALLOCATE (PDOS_scf(n_E, nkind))
1344 26 : PDOS_scf(:, :) = 0.0_dp
1345 :
1346 26 : IF (bs_env%do_soc) THEN
1347 :
1348 32 : ALLOCATE (DOS_scf_SOC(n_E))
1349 16 : DOS_scf_SOC(:) = 0.0_dp
1350 48 : ALLOCATE (PDOS_scf_SOC(n_E, nkind))
1351 16 : PDOS_scf_SOC(:, :) = 0.0_dp
1352 :
1353 : END IF
1354 :
1355 26 : IF (bs_env%do_gw) THEN
1356 :
1357 52 : ALLOCATE (DOS_G0W0(n_E))
1358 26 : DOS_G0W0(:) = 0.0_dp
1359 78 : ALLOCATE (PDOS_G0W0(n_E, nkind))
1360 26 : PDOS_G0W0(:, :) = 0.0_dp
1361 :
1362 26 : IF (bs_env%do_soc) THEN
1363 :
1364 32 : ALLOCATE (DOS_G0W0_SOC(n_E))
1365 16 : DOS_G0W0_SOC(:) = 0.0_dp
1366 48 : ALLOCATE (PDOS_G0W0_SOC(n_E, nkind))
1367 16 : PDOS_G0W0_SOC(:, :) = 0.0_dp
1368 :
1369 : END IF
1370 : END IF
1371 : END IF
1372 :
1373 140 : CALL cp_cfm_create(cfm_mos_ikp(1), bs_env%fm_ks_Gamma(1)%matrix_struct)
1374 140 : CALL cp_cfm_create(cfm_mos_ikp(2), bs_env%fm_ks_Gamma(1)%matrix_struct)
1375 140 : CALL cp_cfm_create(cfm_work_ikp, bs_env%fm_ks_Gamma(1)%matrix_struct)
1376 140 : CALL cp_cfm_create(cfm_s_ikp_copy, bs_env%fm_ks_Gamma(1)%matrix_struct)
1377 :
1378 140 : IF (bs_env%do_soc) THEN
1379 :
1380 22 : CALL cp_cfm_create(cfm_mos_ikp_spinor, bs_env%cfm_SOC_spinor_ao(1)%matrix_struct)
1381 22 : CALL cp_cfm_create(cfm_work_ikp_spinor, bs_env%cfm_SOC_spinor_ao(1)%matrix_struct)
1382 22 : CALL cp_cfm_create(cfm_s_ikp_spinor_copy, bs_env%cfm_SOC_spinor_ao(1)%matrix_struct)
1383 22 : CALL cp_cfm_create(cfm_ks_ikp_spinor, bs_env%cfm_SOC_spinor_ao(1)%matrix_struct)
1384 22 : CALL cp_cfm_create(cfm_SOC_ikp_spinor, bs_env%cfm_SOC_spinor_ao(1)%matrix_struct)
1385 22 : CALL cp_cfm_create(cfm_s_ikp_spinor, bs_env%cfm_SOC_spinor_ao(1)%matrix_struct)
1386 22 : CALL cp_cfm_create(cfm_spinor_wf_ikp, bs_env%cfm_SOC_spinor_ao(1)%matrix_struct)
1387 :
1388 22 : homo_spinor = bs_env%n_occ(1) + bs_env%n_occ(bs_env%n_spin)
1389 :
1390 18 : SELECT CASE (bs_env%n_spin)
1391 : CASE (1)
1392 18 : n_el_spinor = REAL(bs_env%n_electron(1), KIND=dp)
1393 : CASE (2)
1394 22 : n_el_spinor = REAL(bs_env%n_electron(1) + bs_env%n_electron(2), KIND=dp)
1395 : END SELECT
1396 :
1397 22 : band_edges_scf_SOC%VBM = -1000.0_dp
1398 22 : band_edges_scf_SOC%CBM = 1000.0_dp
1399 22 : band_edges_scf_SOC%DBG = 1000.0_dp
1400 :
1401 22 : IF (bs_env%do_gw) THEN
1402 22 : band_edges_G0W0_SOC%VBM = -1000.0_dp
1403 22 : band_edges_G0W0_SOC%CBM = 1000.0_dp
1404 22 : band_edges_G0W0_SOC%DBG = 1000.0_dp
1405 : END IF
1406 :
1407 22 : IF (bs_env%unit_nr > 0) THEN
1408 11 : WRITE (bs_env%unit_nr, '(A)') ''
1409 11 : IF (bs_env%soc_window_occ > 0.0_dp) THEN
1410 3 : WRITE (bs_env%unit_nr, '(T2,A,T71,F10.2)') 'SOC requested, SOC energy window occ (eV):', &
1411 6 : bs_env%soc_window_occ*evolt
1412 : ELSE
1413 8 : WRITE (bs_env%unit_nr, '(T2,A,T71,A10)') 'SOC requested, SOC energy window occ (eV):', &
1414 16 : ' no window'
1415 : END IF
1416 11 : IF (bs_env%soc_window_virt > 0.0_dp) THEN
1417 3 : WRITE (bs_env%unit_nr, '(T2,A,T71,F10.2)') 'SOC requested, SOC energy window virt (eV):', &
1418 6 : bs_env%soc_window_virt*evolt
1419 : ELSE
1420 8 : WRITE (bs_env%unit_nr, '(T2,A,T71,A10)') 'SOC requested, SOC energy window virt (eV):', &
1421 16 : ' no window'
1422 : END IF
1423 11 : IF (bs_env%soc_window_occ > 0.0_dp .OR. bs_env%soc_window_virt > 0.0_dp) THEN
1424 4 : WRITE (bs_env%unit_nr, '(T2,A,T71,F10.2)') 'SOC requested, SOC window smearing (eV):', &
1425 8 : bs_env%soc_window_smearing*evolt
1426 : END IF
1427 : END IF
1428 : END IF
1429 :
1430 140 : IF (bs_env%do_ldos) THEN
1431 2 : CPASSERT(bs_env%int_ldos_xyz == int_ldos_z)
1432 : END IF
1433 :
1434 140 : IF (bs_env%gw_implementation == tensor_small_cell_full_kp) THEN
1435 18 : CALL cp_cfm_create(cfm_ks_ikp, bs_env%cfm_ks_kp(1, 1)%matrix_struct)
1436 18 : CALL cp_cfm_create(cfm_s_ikp, bs_env%cfm_ks_kp(1, 1)%matrix_struct)
1437 : END IF
1438 :
1439 632 : DO ikp = 1, bs_env%nkp_bs_and_DOS
1440 :
1441 492 : t1 = m_walltime()
1442 :
1443 1006 : DO ispin = 1, bs_env%n_spin
1444 :
1445 676 : SELECT CASE (bs_env%gw_implementation)
1446 : CASE (tensor_large_cell_Gamma, ri_rs_large_cell_Gamma, ri_rs_non_periodic, tensor_static_cohsex)
1447 :
1448 : ! 1. get H^KS_µν(k_i) from H^KS_µν(k=0)
1449 : CALL cfm_ikp_from_fm_Gamma(cfm_ks_ikp, bs_env%fm_ks_Gamma(ispin), &
1450 162 : ikp, qs_env, bs_env%kpoints_DOS, "ORB")
1451 :
1452 : ! 2. get S_µν(k_i) from S_µν(k=0)
1453 : CALL cfm_ikp_from_fm_Gamma(cfm_s_ikp, bs_env%fm_s_Gamma, &
1454 162 : ikp, qs_env, bs_env%kpoints_DOS, "ORB")
1455 162 : CALL cp_cfm_to_cfm(cfm_s_ikp, cfm_s_ikp_copy)
1456 :
1457 : ! 3. Diagonalize (Roothaan-Hall): H_KS(k_i)*C(k_i) = S(k_i)*C(k_i)*ϵ(k_i)
1458 : CALL cp_cfm_geeig(cfm_ks_ikp, cfm_s_ikp_copy, cfm_mos_ikp(ispin), &
1459 162 : eigenval, cfm_work_ikp)
1460 :
1461 2140 : bs_env%eigenval_scf(:, ikp, ispin) = eigenval(:)
1462 :
1463 : CASE (tensor_small_cell_full_kp)
1464 :
1465 : ! 1. get H^KS_µν(k_i)
1466 352 : CALL cp_cfm_to_cfm(bs_env%cfm_ks_kp(ikp, ispin), cfm_ks_ikp)
1467 :
1468 : ! 2. get S_µν(k_i)
1469 352 : CALL cp_cfm_to_cfm(bs_env%cfm_s_kp(ikp), cfm_s_ikp)
1470 :
1471 : ! 3. get C_µn(k_i) and ϵ_n(k_i)
1472 352 : CALL cp_cfm_to_cfm(bs_env%cfm_mo_coeff_kp(ikp, ispin), cfm_mos_ikp(ispin))
1473 5120 : eigenval(:) = bs_env%eigenval_scf(:, ikp, ispin)
1474 :
1475 : END SELECT
1476 :
1477 : ! 4. Projection p_nk^A of MO ψ_nk(r) on atom type A (inspired by Mulliken charge)
1478 : ! p_nk^A = sum_µ^A,ν C*_µ^A,n(k) S_µ^A,ν(k) C_ν,n(k)
1479 514 : CALL compute_proj_mo_on_kind(proj_mo_on_kind, qs_env, cfm_mos_ikp(ispin), cfm_s_ikp)
1480 :
1481 : ! 5. DOS and PDOS
1482 514 : IF (bs_env%do_dos_pdos) THEN
1483 : CALL add_to_DOS_PDOS(DOS_scf, PDOS_scf, eigenval, ikp, bs_env, n_E, E_min, &
1484 250 : proj_mo_on_kind)
1485 :
1486 250 : IF (bs_env%do_gw) THEN
1487 : CALL add_to_DOS_PDOS(DOS_G0W0, PDOS_G0W0, bs_env%eigenval_GW(:, ikp, ispin), &
1488 250 : ikp, bs_env, n_E, E_min, proj_mo_on_kind)
1489 : END IF
1490 : END IF
1491 :
1492 514 : IF (bs_env%do_ldos) THEN
1493 : CALL add_to_LDOS_2d(LDOS_scf_2d, qs_env, ikp, bs_env, cfm_mos_ikp(ispin), &
1494 2 : eigenval(:), band_edges_scf_guess)
1495 :
1496 2 : IF (bs_env%do_gw) THEN
1497 : CALL add_to_LDOS_2d(LDOS_G0W0_2d, qs_env, ikp, bs_env, cfm_mos_ikp(ispin), &
1498 2 : bs_env%eigenval_GW(:, ikp, 1), band_edges_G0W0)
1499 : END IF
1500 :
1501 : END IF
1502 :
1503 514 : homo = bs_env%n_occ(ispin)
1504 :
1505 514 : band_edges_scf%VBM = MAX(band_edges_scf%VBM, eigenval(homo))
1506 514 : band_edges_scf%CBM = MIN(band_edges_scf%CBM, eigenval(homo + 1))
1507 1006 : band_edges_scf%DBG = MIN(band_edges_scf%DBG, eigenval(homo + 1) - eigenval(homo))
1508 :
1509 : END DO ! spin
1510 :
1511 : ! now the same with spin-orbit coupling
1512 492 : IF (bs_env%do_soc) THEN
1513 :
1514 : ! only print eigenvalues of DOS k-points in case no bandstructure path has been given
1515 328 : print_DOS_kpoints = (bs_env%nkp_only_bs <= 0)
1516 : ! in kpoints_DOS, the last nkp_only_bs are bandstructure k-points
1517 328 : is_bandstruc_kpoint = (ikp > bs_env%nkp_only_DOS)
1518 328 : print_ikp = print_DOS_kpoints .OR. is_bandstruc_kpoint
1519 :
1520 328 : IF (print_DOS_kpoints) THEN
1521 234 : nkp = bs_env%nkp_only_DOS
1522 234 : ikp_for_file = ikp
1523 : ELSE
1524 94 : nkp = bs_env%nkp_only_bs
1525 94 : ikp_for_file = ikp - bs_env%nkp_only_DOS
1526 : END IF
1527 :
1528 : ! compute DFT+SOC eigenvalues; based on these, compute band edges, DOS and LDOS
1529 : CALL SOC_ev(bs_env, qs_env, ikp, bs_env%eigenval_scf, &
1530 : E_min, cfm_mos_ikp, DOS_scf_SOC, PDOS_scf_SOC, &
1531 328 : band_edges_scf_SOC, eigenval_spinor, cfm_spinor_wf_ikp)
1532 8472 : eigenval_spinor_all_scf(:, ikp) = eigenval_spinor
1533 328 : IF (.NOT. bs_env%do_gw .AND. print_ikp) THEN
1534 0 : CALL write_SOC_eigenvalues(eigenval_spinor, ikp_for_file, ikp, bs_env)
1535 : END IF
1536 :
1537 328 : IF (bs_env%do_ldos) THEN
1538 : CALL add_to_LDOS_2d(LDOS_scf_2d_SOC, qs_env, ikp, bs_env, cfm_spinor_wf_ikp, &
1539 2 : eigenval_spinor, band_edges_scf_guess, .TRUE., cfm_work_ikp)
1540 : END IF
1541 :
1542 328 : IF (bs_env%do_gw) THEN
1543 :
1544 : ! compute G0W0+SOC eigenvalues; based on these, compute band edges, DOS and LDOS
1545 : CALL SOC_ev(bs_env, qs_env, ikp, bs_env%eigenval_GW, &
1546 : E_min, cfm_mos_ikp, DOS_G0W0_SOC, PDOS_G0W0_SOC, &
1547 328 : band_edges_G0W0_SOC, eigenval_spinor_G0W0, cfm_spinor_wf_ikp)
1548 8472 : eigenval_spinor_all_gw(:, ikp) = eigenval_spinor_G0W0
1549 328 : IF (print_ikp) THEN
1550 : ! write SCF+SOC and G0W0+SOC eigenvalues to file
1551 : ! SCF_and_G0W0_band_structure_for_kpoint_<ikp>_+_SOC
1552 : CALL write_SOC_eigenvalues(eigenval_spinor, ikp_for_file, ikp, bs_env, &
1553 296 : eigenval_spinor_G0W0)
1554 : END IF
1555 :
1556 : END IF ! do_gw
1557 :
1558 : END IF ! do_soc
1559 :
1560 632 : IF (bs_env%unit_nr > 0 .AND. m_walltime() - t1 > 20.0_dp) THEN
1561 : WRITE (bs_env%unit_nr, '(T2,A,T43,I5,A,I3,A,F7.1,A)') &
1562 0 : 'Compute DOS, LDOS for k-point ', ikp, ' /', bs_env%nkp_bs_and_DOS, &
1563 0 : ', Execution time', m_walltime() - t1, ' s'
1564 : END IF
1565 :
1566 : END DO ! ikp_DOS
1567 :
1568 140 : band_edges_scf%IDBG = band_edges_scf%CBM - band_edges_scf%VBM
1569 :
1570 262 : SELECT CASE (bs_env%n_spin)
1571 : CASE (1)
1572 : CALL get_fermi_level_1c(bs_env, bs_env%eigenval_scf(:, :, 1), &
1573 : REAL(bs_env%n_electron(1), KIND=dp), &
1574 : bs_env%spin_degeneracy, band_edges_scf%VBM, &
1575 122 : band_edges_scf%CBM, band_edges_scf%E_fermi)
1576 : CASE (2)
1577 : CALL get_fermi_level_2c(bs_env, bs_env%eigenval_scf(:, :, 1:2), &
1578 : REAL(bs_env%n_electron(1) + bs_env%n_electron(2), KIND=dp), &
1579 140 : band_edges_scf%VBM, band_edges_scf%CBM, band_edges_scf%E_fermi)
1580 : END SELECT
1581 :
1582 140 : IF (bs_env%do_soc) THEN
1583 22 : band_edges_scf_SOC%IDBG = band_edges_scf_SOC%CBM - band_edges_scf_SOC%VBM
1584 : ! SOC merges both spins into 2*n_ao spinor states, each holding at most one
1585 : ! electron (maxocc=1); homo_spinor = n_occ(1)+n_occ(n_spin) is the total spinor
1586 : ! electron count, same quantity SOC_ev uses to locate the occupied/unoccupied edge
1587 : CALL get_fermi_level_1c(bs_env, eigenval_spinor_all_scf, &
1588 : n_el_spinor, 1.0_dp, &
1589 22 : band_edges_scf_SOC%VBM, band_edges_scf_SOC%CBM, band_edges_scf_SOC%E_fermi)
1590 :
1591 22 : IF (bs_env%do_gw) THEN
1592 22 : band_edges_G0W0_SOC%IDBG = band_edges_G0W0_SOC%CBM - band_edges_G0W0_SOC%VBM
1593 : CALL get_fermi_level_1c(bs_env, eigenval_spinor_all_gw, &
1594 : n_el_spinor, 1.0_dp, &
1595 22 : band_edges_G0W0_SOC%VBM, band_edges_G0W0_SOC%CBM, band_edges_G0W0_SOC%E_fermi)
1596 :
1597 : END IF
1598 : END IF
1599 :
1600 140 : CALL write_band_edges(band_edges_scf, "SCF", bs_env)
1601 140 : IF (bs_env%do_dos_pdos) THEN
1602 26 : CALL write_dos_pdos(DOS_scf, PDOS_scf, bs_env, qs_env, "SCF", E_min, band_edges_scf%VBM)
1603 : END IF
1604 140 : IF (bs_env%do_ldos) THEN
1605 2 : CALL print_LDOS_main(LDOS_scf_2d, bs_env, band_edges_scf, "SCF")
1606 : END IF
1607 :
1608 140 : IF (bs_env%do_soc) THEN
1609 22 : CALL write_band_edges(band_edges_scf_SOC, "SCF+SOC", bs_env)
1610 22 : IF (bs_env%do_dos_pdos) THEN
1611 : CALL write_dos_pdos(DOS_scf_SOC, PDOS_scf_SOC, bs_env, qs_env, "SCF_SOC", &
1612 16 : E_min, band_edges_scf_SOC%VBM)
1613 : END IF
1614 22 : IF (bs_env%do_ldos) THEN
1615 : ! argument band_edges_scf is actually correct because the non-SOC band edges
1616 : ! have been used as reference in add_to_LDOS_2d
1617 : CALL print_LDOS_main(LDOS_scf_2d_SOC, bs_env, band_edges_scf, &
1618 2 : "SCF_SOC")
1619 : END IF
1620 : END IF
1621 :
1622 : ! the printed band edges carry the GW flavour that was actually run; the labels handed to
1623 : ! write_dos_pdos / print_LDOS_main below become file names and stay as they are
1624 140 : gw_label = gw_flavour_label(bs_env)
1625 140 : gw_soc_label = TRIM(gw_label)//"+SOC"
1626 :
1627 140 : IF (bs_env%do_gw) THEN
1628 138 : CALL write_band_edges(band_edges_G0W0, TRIM(gw_label), bs_env)
1629 138 : CALL write_band_edges(bs_env%band_edges_HF, "Hartree-Fock with SCF orbitals", bs_env)
1630 138 : IF (bs_env%do_dos_pdos) THEN
1631 : CALL write_dos_pdos(DOS_G0W0, PDOS_G0W0, bs_env, qs_env, "G0W0", E_min, &
1632 26 : band_edges_G0W0%VBM)
1633 : END IF
1634 138 : IF (bs_env%do_ldos) THEN
1635 2 : CALL print_LDOS_main(LDOS_G0W0_2d, bs_env, band_edges_G0W0, "G0W0")
1636 : END IF
1637 : END IF
1638 :
1639 140 : IF (bs_env%do_soc .AND. bs_env%do_gw) THEN
1640 22 : CALL write_band_edges(band_edges_G0W0_SOC, TRIM(gw_soc_label), bs_env)
1641 22 : IF (bs_env%do_dos_pdos) THEN
1642 : CALL write_dos_pdos(DOS_G0W0_SOC, PDOS_G0W0_SOC, bs_env, qs_env, "G0W0_SOC", E_min, &
1643 16 : band_edges_G0W0_SOC%VBM)
1644 : END IF
1645 : END IF
1646 :
1647 140 : CALL cp_cfm_release(cfm_s_ikp)
1648 140 : CALL cp_cfm_release(cfm_ks_ikp)
1649 140 : CALL cp_cfm_release(cfm_mos_ikp(1))
1650 140 : CALL cp_cfm_release(cfm_mos_ikp(2))
1651 140 : CALL cp_cfm_release(cfm_work_ikp)
1652 140 : CALL cp_cfm_release(cfm_s_ikp_copy)
1653 :
1654 140 : CALL cp_cfm_release(cfm_s_ikp_spinor)
1655 140 : CALL cp_cfm_release(cfm_ks_ikp_spinor)
1656 140 : CALL cp_cfm_release(cfm_SOC_ikp_spinor)
1657 140 : CALL cp_cfm_release(cfm_mos_ikp_spinor)
1658 140 : CALL cp_cfm_release(cfm_work_ikp_spinor)
1659 140 : CALL cp_cfm_release(cfm_s_ikp_spinor_copy)
1660 140 : CALL cp_cfm_release(cfm_spinor_wf_ikp)
1661 :
1662 140 : CALL timestop(handle)
1663 :
1664 560 : END SUBROUTINE eval_bandstructure_properties
1665 :
1666 : ! **************************************************************************************************
1667 : !> \brief ...
1668 : !> \param LDOS_2d ...
1669 : !> \param bs_env ...
1670 : !> \param band_edges ...
1671 : !> \param scf_gw_soc ...
1672 : ! **************************************************************************************************
1673 6 : SUBROUTINE print_LDOS_main(LDOS_2d, bs_env, band_edges, scf_gw_soc)
1674 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: LDOS_2d
1675 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
1676 : TYPE(band_edges_type) :: band_edges
1677 : CHARACTER(LEN=*) :: scf_gw_soc
1678 :
1679 : CHARACTER(LEN=*), PARAMETER :: routineN = 'print_LDOS_main'
1680 :
1681 : INTEGER :: handle, i_x, i_x_bin, i_x_end, i_x_end_bin, i_x_end_glob, i_x_start, &
1682 : i_x_start_bin, i_x_start_glob, i_y, i_y_bin, i_y_end, i_y_end_bin, i_y_end_glob, &
1683 : i_y_start, i_y_start_bin, i_y_start_glob, n_E
1684 6 : INTEGER, ALLOCATABLE, DIMENSION(:, :) :: n_sum_for_bins
1685 : INTEGER, DIMENSION(2) :: bin_mesh
1686 : LOGICAL :: do_xy_bins
1687 : REAL(KIND=dp) :: E_min, energy_step, energy_window
1688 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: LDOS_2d_bins
1689 :
1690 6 : CALL timeset(routineN, handle)
1691 :
1692 6 : n_E = SIZE(LDOS_2d, 3)
1693 :
1694 6 : energy_window = bs_env%energy_window_DOS
1695 6 : energy_step = bs_env%energy_step_DOS
1696 6 : E_min = band_edges%VBM - 0.5_dp*energy_window
1697 :
1698 18 : bin_mesh(1:2) = bs_env%bin_mesh(1:2)
1699 6 : do_xy_bins = (bin_mesh(1) > 0 .AND. bin_mesh(2) > 0)
1700 :
1701 6 : i_x_start = LBOUND(LDOS_2d, 1)
1702 6 : i_x_end = UBOUND(LDOS_2d, 1)
1703 6 : i_y_start = LBOUND(LDOS_2d, 2)
1704 6 : i_y_end = UBOUND(LDOS_2d, 2)
1705 :
1706 6 : IF (do_xy_bins) THEN
1707 6 : i_x_start_bin = 1
1708 6 : i_x_end_bin = bin_mesh(1)
1709 6 : i_y_start_bin = 1
1710 6 : i_y_end_bin = bin_mesh(2)
1711 : ELSE
1712 : i_x_start_bin = i_x_start
1713 : i_x_end_bin = i_x_end
1714 : i_y_start_bin = i_y_start
1715 : i_y_end_bin = i_y_end
1716 : END IF
1717 :
1718 30 : ALLOCATE (LDOS_2d_bins(i_x_start_bin:i_x_end_bin, i_y_start_bin:i_y_end_bin, n_E))
1719 6 : LDOS_2d_bins(:, :, :) = 0.0_dp
1720 :
1721 6 : IF (do_xy_bins) THEN
1722 :
1723 6 : i_x_start_glob = i_x_start
1724 6 : i_x_end_glob = i_x_end
1725 6 : i_y_start_glob = i_y_start
1726 6 : i_y_end_glob = i_y_end
1727 :
1728 6 : CALL bs_env%para_env%min(i_x_start_glob)
1729 6 : CALL bs_env%para_env%max(i_x_end_glob)
1730 6 : CALL bs_env%para_env%min(i_y_start_glob)
1731 6 : CALL bs_env%para_env%max(i_y_end_glob)
1732 :
1733 24 : ALLOCATE (n_sum_for_bins(bin_mesh(1), bin_mesh(2)), SOURCE=0)
1734 :
1735 : ! transform interval [i_x_start, i_x_end] to [1, bin_mesh(1)] (and same for y)
1736 390 : DO i_y = i_y_start, i_y_end
1737 4230 : DO i_x = i_x_start, i_x_end
1738 3840 : i_x_bin = bin_mesh(1)*(i_x - i_x_start_glob)/(i_x_end_glob - i_x_start_glob + 1) + 1
1739 3840 : i_y_bin = bin_mesh(2)*(i_y - i_y_start_glob)/(i_y_end_glob - i_y_start_glob + 1) + 1
1740 : LDOS_2d_bins(i_x_bin, i_y_bin, :) = LDOS_2d_bins(i_x_bin, i_y_bin, :) + &
1741 1073920 : LDOS_2d(i_x, i_y, :)
1742 4224 : n_sum_for_bins(i_x_bin, i_y_bin) = n_sum_for_bins(i_x_bin, i_y_bin) + 1
1743 : END DO
1744 : END DO
1745 :
1746 6 : CALL bs_env%para_env%sum(LDOS_2d_bins)
1747 6 : CALL bs_env%para_env%sum(n_sum_for_bins)
1748 :
1749 : ! divide by number of terms in the sum so we have the average LDOS(x,y,E)
1750 30 : DO i_y_bin = 1, bin_mesh(2)
1751 126 : DO i_x_bin = 1, bin_mesh(1)
1752 : LDOS_2d_bins(i_x_bin, i_y_bin, :) = LDOS_2d_bins(i_x_bin, i_y_bin, :)/ &
1753 26872 : REAL(n_sum_for_bins(i_x_bin, i_y_bin), KIND=dp)
1754 : END DO
1755 : END DO
1756 :
1757 : ELSE
1758 :
1759 0 : LDOS_2d_bins(:, :, :) = LDOS_2d(:, :, :)
1760 :
1761 : END IF
1762 :
1763 6 : IF (bin_mesh(1)*bin_mesh(2) < bs_env%n_bins_max_for_printing) THEN
1764 6 : CALL print_LDOS_2d_bins(LDOS_2d_bins, bs_env, E_min, scf_gw_soc)
1765 : ELSE
1766 0 : CPWARN("The number of bins for the LDOS is too large. Decrease BIN_MESH.")
1767 : END IF
1768 :
1769 6 : CALL timestop(handle)
1770 :
1771 12 : END SUBROUTINE print_LDOS_main
1772 :
1773 : ! **************************************************************************************************
1774 : !> \brief ...
1775 : !> \param LDOS_2d_bins ...
1776 : !> \param bs_env ...
1777 : !> \param E_min ...
1778 : !> \param scf_gw_soc ...
1779 : ! **************************************************************************************************
1780 6 : SUBROUTINE print_LDOS_2d_bins(LDOS_2d_bins, bs_env, E_min, scf_gw_soc)
1781 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: LDOS_2d_bins
1782 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
1783 : REAL(KIND=dp) :: E_min
1784 : CHARACTER(LEN=*) :: scf_gw_soc
1785 :
1786 : CHARACTER(LEN=*), PARAMETER :: routineN = 'print_LDOS_2d_bins'
1787 :
1788 : CHARACTER(LEN=18) :: print_format
1789 : CHARACTER(LEN=4) :: print_format_1, print_format_2
1790 : CHARACTER(len=default_string_length) :: fname
1791 : INTEGER :: handle, i_E, i_x, i_x_end, i_x_start, &
1792 : i_y, i_y_end, i_y_start, iunit, n_E, &
1793 : n_x, n_y
1794 : REAL(KIND=dp) :: energy
1795 : REAL(KIND=dp), DIMENSION(3) :: coord, idx
1796 :
1797 6 : CALL timeset(routineN, handle)
1798 :
1799 6 : i_x_start = LBOUND(LDOS_2d_bins, 1)
1800 6 : i_x_end = UBOUND(LDOS_2d_bins, 1)
1801 6 : i_y_start = LBOUND(LDOS_2d_bins, 2)
1802 6 : i_y_end = UBOUND(LDOS_2d_bins, 2)
1803 6 : n_E = SIZE(LDOS_2d_bins, 3)
1804 :
1805 6 : n_x = i_x_end - i_x_start + 1
1806 6 : n_y = i_y_end - i_y_start + 1
1807 :
1808 6 : IF (bs_env%para_env%is_source()) THEN
1809 :
1810 15 : DO i_y = i_y_start, i_y_end
1811 63 : DO i_x = i_x_start, i_x_end
1812 :
1813 48 : idx(1) = (REAL(i_x, KIND=dp) - 0.5_dp)/REAL(n_x, KIND=dp)
1814 48 : idx(2) = (REAL(i_y, KIND=dp) - 0.5_dp)/REAL(n_y, KIND=dp)
1815 48 : idx(3) = 0.0_dp
1816 624 : coord(1:3) = MATMUL(bs_env%hmat, idx)
1817 :
1818 48 : CALL get_print_format(coord(1), print_format_1)
1819 48 : CALL get_print_format(coord(2), print_format_2)
1820 :
1821 48 : print_format = "(3A,"//print_format_1//",A,"//print_format_2//",A)"
1822 :
1823 48 : WRITE (fname, print_format) "LDOS_", scf_gw_soc, &
1824 96 : "_at_x_", coord(1)*angstrom, '_A_and_y_', coord(2)*angstrom, '_A'
1825 :
1826 : CALL open_file(TRIM(fname), unit_number=iunit, file_status="REPLACE", &
1827 48 : file_action="WRITE")
1828 :
1829 48 : WRITE (iunit, "(2A)") " Energy E (eV) average LDOS(x,y,E) (1/(eV*Å^2), ", &
1830 96 : "integrated over z, averaged inside bin)"
1831 :
1832 13424 : DO i_E = 1, n_E
1833 13376 : energy = E_min + i_E*bs_env%energy_step_DOS
1834 13376 : WRITE (iunit, "(2F17.3)") energy*evolt, &
1835 : LDOS_2d_bins(i_x, i_y, i_E)* &
1836 26800 : bs_env%unit_ldos_int_z_inv_Ang2_eV
1837 : END DO
1838 :
1839 60 : CALL close_file(iunit)
1840 :
1841 : END DO
1842 : END DO
1843 :
1844 : END IF
1845 :
1846 6 : CALL timestop(handle)
1847 :
1848 6 : END SUBROUTINE print_LDOS_2d_bins
1849 :
1850 : ! **************************************************************************************************
1851 : !> \brief ...
1852 : !> \param coord ...
1853 : !> \param print_format ...
1854 : ! **************************************************************************************************
1855 96 : SUBROUTINE get_print_format(coord, print_format)
1856 : REAL(KIND=dp) :: coord
1857 : CHARACTER(LEN=4) :: print_format
1858 :
1859 : CHARACTER(LEN=*), PARAMETER :: routineN = 'get_print_format'
1860 :
1861 : INTEGER :: handle
1862 :
1863 96 : CALL timeset(routineN, handle)
1864 :
1865 96 : IF (coord < -10000/angstrom) THEN
1866 0 : print_format = "F9.2"
1867 96 : ELSE IF (coord < -1000/angstrom) THEN
1868 0 : print_format = "F8.2"
1869 96 : ELSE IF (coord < -100/angstrom) THEN
1870 0 : print_format = "F7.2"
1871 96 : ELSE IF (coord < -10/angstrom) THEN
1872 0 : print_format = "F6.2"
1873 96 : ELSE IF (coord < -1/angstrom) THEN
1874 0 : print_format = "F5.2"
1875 96 : ELSE IF (coord < 10/angstrom) THEN
1876 96 : print_format = "F4.2"
1877 0 : ELSE IF (coord < 100/angstrom) THEN
1878 0 : print_format = "F5.2"
1879 0 : ELSE IF (coord < 1000/angstrom) THEN
1880 0 : print_format = "F6.2"
1881 0 : ELSE IF (coord < 10000/angstrom) THEN
1882 0 : print_format = "F7.2"
1883 : ELSE
1884 0 : print_format = "F8.2"
1885 : END IF
1886 :
1887 96 : CALL timestop(handle)
1888 :
1889 96 : END SUBROUTINE get_print_format
1890 :
1891 : ! **************************************************************************************************
1892 : !> \brief ...
1893 : !> \param bs_env ...
1894 : !> \param qs_env ...
1895 : !> \param ikp ...
1896 : !> \param eigenval_no_SOC non-SOC band energies (n_ao, n_kpoints, n_spin)
1897 : !> \param E_min ...
1898 : !> \param cfm_mos_ikp ...
1899 : !> \param DOS ...
1900 : !> \param PDOS ...
1901 : !> \param band_edges ...
1902 : !> \param eigenval_spinor ...
1903 : !> \param cfm_spinor_wf_ikp ...
1904 : ! **************************************************************************************************
1905 656 : SUBROUTINE SOC_ev(bs_env, qs_env, ikp, eigenval_no_SOC, E_min, cfm_mos_ikp, &
1906 : DOS, PDOS, band_edges, eigenval_spinor, cfm_spinor_wf_ikp)
1907 :
1908 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
1909 : TYPE(qs_environment_type), POINTER :: qs_env
1910 : INTEGER :: ikp
1911 : REAL(KIND=dp), DIMENSION(:, :, :) :: eigenval_no_SOC
1912 : REAL(KIND=dp) :: E_min
1913 : TYPE(cp_cfm_type), DIMENSION(2) :: cfm_mos_ikp
1914 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: DOS
1915 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: PDOS
1916 : TYPE(band_edges_type) :: band_edges
1917 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: eigenval_spinor
1918 : TYPE(cp_cfm_type) :: cfm_spinor_wf_ikp
1919 :
1920 : CHARACTER(LEN=*), PARAMETER :: routineN = 'SOC_ev'
1921 :
1922 : INTEGER :: handle
1923 : LOGICAL :: do_truncate
1924 :
1925 656 : CALL timeset(routineN, handle)
1926 :
1927 : !for the window truncation part
1928 656 : do_truncate = (bs_env%soc_nbands_occ > 0 .AND. bs_env%soc_nbands_virt > 0)
1929 :
1930 : IF (do_truncate) THEN
1931 : CALL SOC_ev_truncate_mos(bs_env, qs_env, ikp, eigenval_no_SOC, cfm_mos_ikp, &
1932 0 : band_edges, eigenval_spinor, cfm_spinor_wf_ikp)
1933 : ELSE
1934 : CALL SOC_ev_all_mos(bs_env, qs_env, ikp, eigenval_no_SOC, E_min, cfm_mos_ikp, &
1935 656 : DOS, PDOS, band_edges, eigenval_spinor, cfm_spinor_wf_ikp)
1936 : END IF
1937 :
1938 656 : CALL timestop(handle)
1939 :
1940 656 : END SUBROUTINE SOC_ev
1941 :
1942 : ! **************************************************************************************************
1943 : !> \brief SOC second-variational diagonalization over the full 2*n_ao spinor space (no truncation
1944 : !> window) -- the SOC_NBANDS_OCC/VIRT-truncated path lives in SOC_ev_truncate_mos.
1945 : !> \param bs_env ...
1946 : !> \param qs_env ...
1947 : !> \param ikp ...
1948 : !> \param eigenval_no_SOC non-SOC band energies (n_ao, n_kpoints, n_spin)
1949 : !> \param E_min ...
1950 : !> \param cfm_mos_ikp ...
1951 : !> \param DOS ...
1952 : !> \param PDOS ...
1953 : !> \param band_edges ...
1954 : !> \param eigenval_spinor ...
1955 : !> \param cfm_spinor_wf_ikp ...
1956 : ! **************************************************************************************************
1957 656 : SUBROUTINE SOC_ev_all_mos(bs_env, qs_env, ikp, eigenval_no_SOC, E_min, cfm_mos_ikp, &
1958 : DOS, PDOS, band_edges, eigenval_spinor, cfm_spinor_wf_ikp)
1959 :
1960 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
1961 : TYPE(qs_environment_type), POINTER :: qs_env
1962 : INTEGER :: ikp
1963 : REAL(KIND=dp), DIMENSION(:, :, :) :: eigenval_no_SOC
1964 : REAL(KIND=dp) :: E_min
1965 : TYPE(cp_cfm_type), DIMENSION(2) :: cfm_mos_ikp
1966 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: DOS
1967 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: PDOS
1968 : TYPE(band_edges_type) :: band_edges
1969 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: eigenval_spinor
1970 : TYPE(cp_cfm_type) :: cfm_spinor_wf_ikp
1971 :
1972 : CHARACTER(LEN=*), PARAMETER :: routineN = 'SOC_ev_all_mos'
1973 :
1974 : INTEGER :: handle, homo_spinor, n_ao, n_E, nkind
1975 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: eigenval_spinor_no_SOC
1976 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: proj_mo_on_kind_spinor
1977 : TYPE(cp_cfm_type) :: cfm_eigenvec_ikp_spinor, &
1978 : cfm_ks_ikp_spinor, cfm_mos_ikp_spinor, &
1979 : cfm_SOC_ikp_spinor, cfm_work_ikp_spinor
1980 :
1981 656 : CALL timeset(routineN, handle)
1982 :
1983 656 : n_ao = bs_env%n_ao
1984 656 : homo_spinor = bs_env%n_occ(1) + bs_env%n_occ(bs_env%n_spin)
1985 656 : CALL get_qs_env(qs_env, nkind=nkind)
1986 :
1987 656 : CALL cp_cfm_create(cfm_ks_ikp_spinor, bs_env%cfm_SOC_spinor_ao(1)%matrix_struct)
1988 656 : CALL cp_cfm_create(cfm_SOC_ikp_spinor, bs_env%cfm_SOC_spinor_ao(1)%matrix_struct)
1989 656 : CALL cp_cfm_create(cfm_mos_ikp_spinor, bs_env%cfm_SOC_spinor_ao(1)%matrix_struct)
1990 656 : CALL cp_cfm_create(cfm_work_ikp_spinor, bs_env%cfm_SOC_spinor_ao(1)%matrix_struct)
1991 656 : CALL cp_cfm_create(cfm_eigenvec_ikp_spinor, bs_env%cfm_SOC_spinor_ao(1)%matrix_struct)
1992 :
1993 1968 : ALLOCATE (eigenval_spinor_no_SOC(2*n_ao))
1994 2624 : ALLOCATE (proj_mo_on_kind_spinor(2*n_ao, nkind))
1995 : ! PDOS not yet implemented -> projection is just zero -> PDOS is zero
1996 656 : proj_mo_on_kind_spinor(:, :) = 0.0_dp
1997 :
1998 : ! 1. get V^SOC_µν,σσ'(k_i)
1999 676 : SELECT CASE (bs_env%gw_implementation)
2000 : CASE (tensor_large_cell_Gamma, ri_rs_large_cell_Gamma, ri_rs_non_periodic, tensor_static_cohsex)
2001 :
2002 : ! 1. get V^SOC_µν,σσ'(k_i) from V^SOC_µν,σσ'(k=0)
2003 : CALL cfm_ikp_from_cfm_spinor_Gamma(cfm_SOC_ikp_spinor, &
2004 : bs_env%cfm_SOC_spinor_ao(1), &
2005 : bs_env%fm_s_Gamma%matrix_struct, &
2006 20 : ikp, qs_env, bs_env%kpoints_DOS, "ORB")
2007 :
2008 : CASE (tensor_small_cell_full_kp)
2009 :
2010 : ! 1. V^SOC_µν,σσ'(k_i) already there
2011 656 : CALL cp_cfm_to_cfm(bs_env%cfm_SOC_spinor_ao(ikp), cfm_SOC_ikp_spinor)
2012 :
2013 : END SELECT
2014 :
2015 : ! 2. V^SOC_nn',σσ'(k_i) = sum_µν C^*_µn,σ(k_i) V^SOC_µν,σσ'(k_i) C_νn'(k_i),
2016 : ! C_µn,σ(k_i): MO coefficiencts from diagonalizing KS-matrix h^KS_nn',σσ'(k_i)
2017 :
2018 : ! 2.1 build matrix C_µn,σ(k_i)
2019 656 : CALL cp_cfm_set_all(cfm_mos_ikp_spinor, z_zero)
2020 656 : CALL add_cfm_submat(cfm_mos_ikp_spinor, cfm_mos_ikp(1), 1, 1)
2021 656 : CALL add_cfm_submat(cfm_mos_ikp_spinor, cfm_mos_ikp(bs_env%n_spin), n_ao + 1, n_ao + 1)
2022 :
2023 : ! 2.2 work_nν,σσ' = sum_µ C^*_µn,σ(k_i) V^SOC_µν,σσ'(k_i)
2024 : CALL parallel_gemm('C', 'N', 2*n_ao, 2*n_ao, 2*n_ao, z_one, &
2025 : cfm_mos_ikp_spinor, cfm_SOC_ikp_spinor, &
2026 656 : z_zero, cfm_work_ikp_spinor)
2027 :
2028 : ! 2.3 V^SOC_nn',σσ'(k_i) = sum_ν work_nν,σσ' C_νn'(k_i)
2029 : CALL parallel_gemm('N', 'N', 2*n_ao, 2*n_ao, 2*n_ao, z_one, &
2030 : cfm_work_ikp_spinor, cfm_mos_ikp_spinor, &
2031 656 : z_zero, cfm_ks_ikp_spinor)
2032 :
2033 : ! 3. remove SOC outside of energy window (otherwise, numerical problems arise
2034 : ! because energetically low semicore states and energetically very high
2035 : ! unbound states couple to the states around the Fermi level)
2036 8800 : eigenval_spinor_no_SOC(1:n_ao) = eigenval_no_SOC(1:n_ao, ikp, 1)
2037 8800 : eigenval_spinor_no_SOC(n_ao + 1:) = eigenval_no_SOC(1:n_ao, ikp, bs_env%n_spin)
2038 656 : IF (bs_env%soc_window_occ > 0.0_dp .OR. bs_env%soc_window_virt > 0.0_dp) THEN
2039 : CALL remove_soc_outside_energy_window_mo(cfm_ks_ikp_spinor, &
2040 : bs_env%soc_window_virt, &
2041 : bs_env%soc_window_smearing, &
2042 : eigenval_spinor_no_SOC, &
2043 256 : bs_env%e_fermi(1))
2044 :
2045 : END IF
2046 :
2047 : ! 4. h^G0W0+SOC_nn',σσ'(k_i) = ε_nσ^G0W0(k_i) δ_nn' δ_σσ' + V^SOC_nn',σσ'(k_i)
2048 656 : CALL cfm_add_on_diag(cfm_ks_ikp_spinor, eigenval_spinor_no_SOC)
2049 :
2050 : ! 5. diagonalize h^G0W0+SOC_nn',σσ'(k_i) to get eigenvalues
2051 656 : CALL cp_cfm_heevd(cfm_ks_ikp_spinor, cfm_eigenvec_ikp_spinor, eigenval_spinor)
2052 :
2053 : ! 6. DOS from spinors, no PDOS
2054 656 : IF (bs_env%do_dos_pdos) THEN
2055 452 : n_E = SIZE(DOS)
2056 : CALL add_to_DOS_PDOS(DOS, PDOS, eigenval_spinor, &
2057 452 : ikp, bs_env, n_E, E_min, proj_mo_on_kind_spinor)
2058 : END IF
2059 :
2060 : ! 7. valence band max. (VBM), conduction band min. (CBM) and direct bandgap (DBG)
2061 656 : band_edges%VBM = MAX(band_edges%VBM, eigenval_spinor(homo_spinor))
2062 656 : band_edges%CBM = MIN(band_edges%CBM, eigenval_spinor(homo_spinor + 1))
2063 : band_edges%DBG = MIN(band_edges%DBG, eigenval_spinor(homo_spinor + 1) &
2064 656 : - eigenval_spinor(homo_spinor))
2065 :
2066 : ! 8. spinor wavefunctions:
2067 656 : CALL cp_cfm_set_all(cfm_spinor_wf_ikp, z_zero)
2068 : CALL parallel_gemm('N', 'N', 2*n_ao, 2*n_ao, 2*n_ao, z_one, &
2069 : cfm_mos_ikp_spinor, cfm_eigenvec_ikp_spinor, &
2070 656 : z_zero, cfm_spinor_wf_ikp)
2071 :
2072 656 : CALL cp_cfm_release(cfm_ks_ikp_spinor)
2073 656 : CALL cp_cfm_release(cfm_SOC_ikp_spinor)
2074 656 : CALL cp_cfm_release(cfm_work_ikp_spinor)
2075 656 : CALL cp_cfm_release(cfm_eigenvec_ikp_spinor)
2076 656 : CALL cp_cfm_release(cfm_mos_ikp_spinor)
2077 :
2078 656 : CALL timestop(handle)
2079 :
2080 1968 : END SUBROUTINE SOC_ev_all_mos
2081 :
2082 : ! **************************************************************************************************
2083 : !> \brief SOC second-variational diagonalization truncated to a window of SOC_NBANDS_OCC occupied
2084 : !> and SOC_NBANDS_VIRT virtual states around the Fermi level -- the untruncated, full
2085 : !> 2*n_ao spinor-space path lives in SOC_ev_all_mos.
2086 : !> \param bs_env ...
2087 : !> \param qs_env ...
2088 : !> \param ikp ...
2089 : !> \param eigenval_no_SOC non-SOC band energies (n_ao, n_kpoints, n_spin)
2090 : !> \param cfm_mos_ikp ...
2091 : !> \param band_edges ...
2092 : !> \param eigenval_spinor ...
2093 : !> \param cfm_spinor_wf_ikp ...
2094 : ! **************************************************************************************************
2095 0 : SUBROUTINE SOC_ev_truncate_mos(bs_env, qs_env, ikp, eigenval_no_SOC, cfm_mos_ikp, &
2096 : band_edges, eigenval_spinor, cfm_spinor_wf_ikp)
2097 :
2098 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
2099 : TYPE(qs_environment_type), POINTER :: qs_env
2100 : INTEGER :: ikp
2101 : REAL(KIND=dp), DIMENSION(:, :, :) :: eigenval_no_SOC
2102 : TYPE(cp_cfm_type), DIMENSION(2) :: cfm_mos_ikp
2103 : TYPE(band_edges_type) :: band_edges
2104 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: eigenval_spinor
2105 : TYPE(cp_cfm_type) :: cfm_spinor_wf_ikp
2106 :
2107 : CHARACTER(LEN=*), PARAMETER :: routineN = 'SOC_ev_truncate_mos'
2108 :
2109 : INTEGER :: handle, homo_spinor, homo_used, &
2110 : mo_index_start_1, mo_index_start_2, &
2111 : n_ao, n_window, n_window2tot, nkind, &
2112 : nocc, nvirt
2113 0 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: eig_win_sorted, eigenval_spinor_no_SOC
2114 0 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: proj_mo_on_kind_spinor
2115 : TYPE(cp_cfm_type) :: cfm_eigenvec_ikp_spinor, &
2116 : cfm_ks_ikp_spinor, cfm_mos_ikp_spinor, &
2117 : cfm_SOC_ikp_spinor, cfm_work_ikp_spinor
2118 : TYPE(cp_fm_struct_type), POINTER :: fst_mos, fst_wa, fst_ww
2119 : TYPE(cp_fm_type) :: fm_src_im, fm_src_re, fm_tgt_im, &
2120 : fm_tgt_re
2121 :
2122 0 : CALL timeset(routineN, handle)
2123 :
2124 0 : n_ao = bs_env%n_ao
2125 0 : homo_spinor = bs_env%n_occ(1) + bs_env%n_occ(bs_env%n_spin)
2126 0 : CALL get_qs_env(qs_env, nkind=nkind)
2127 :
2128 0 : nocc = bs_env%soc_nbands_occ
2129 0 : nvirt = bs_env%soc_nbands_virt
2130 0 : CPASSERT(nocc <= bs_env%n_occ_nosmear(1))
2131 0 : CPASSERT(nocc <= bs_env%n_occ_nosmear(bs_env%n_spin))
2132 0 : CPASSERT(nvirt <= n_ao - bs_env%n_occ_nosmear(1))
2133 0 : CPASSERT(nvirt <= n_ao - bs_env%n_occ_nosmear(bs_env%n_spin))
2134 0 : CPASSERT(.NOT. bs_env%do_dos_pdos)
2135 0 : mo_index_start_1 = bs_env%n_occ_nosmear(1) - nocc + 1
2136 0 : mo_index_start_2 = bs_env%n_occ_nosmear(bs_env%n_spin) - nocc + 1
2137 0 : n_window = nocc + nvirt
2138 0 : n_window2tot = 2*n_window
2139 0 : homo_used = 2*nocc
2140 :
2141 0 : NULLIFY (fst_ww, fst_wa, fst_mos)
2142 : CALL cp_fm_struct_create(fst_ww, nrow_global=n_window2tot, ncol_global=n_window2tot, &
2143 0 : template_fmstruct=bs_env%cfm_SOC_spinor_ao(1)%matrix_struct)
2144 : CALL cp_fm_struct_create(fst_wa, nrow_global=n_window2tot, ncol_global=2*n_ao, &
2145 0 : template_fmstruct=bs_env%cfm_SOC_spinor_ao(1)%matrix_struct)
2146 : CALL cp_fm_struct_create(fst_mos, nrow_global=2*n_ao, ncol_global=n_window2tot, &
2147 0 : template_fmstruct=bs_env%cfm_SOC_spinor_ao(1)%matrix_struct)
2148 0 : CALL cp_cfm_create(cfm_ks_ikp_spinor, fst_ww)
2149 0 : CALL cp_cfm_create(cfm_eigenvec_ikp_spinor, fst_ww)
2150 0 : CALL cp_cfm_create(cfm_work_ikp_spinor, fst_wa)
2151 0 : CALL cp_cfm_create(cfm_SOC_ikp_spinor, bs_env%cfm_SOC_spinor_ao(1)%matrix_struct)
2152 0 : CALL cp_cfm_create(cfm_mos_ikp_spinor, fst_mos)
2153 :
2154 0 : ALLOCATE (eigenval_spinor_no_SOC(2*n_ao))
2155 0 : ALLOCATE (proj_mo_on_kind_spinor(2*n_ao, nkind))
2156 : ! PDOS not yet implemented -> projection is just zero -> PDOS is zero
2157 : proj_mo_on_kind_spinor(:, :) = 0.0_dp
2158 :
2159 : ! 1. get V^SOC_µν,σσ'(k_i)
2160 0 : SELECT CASE (bs_env%gw_implementation)
2161 : CASE (tensor_large_cell_Gamma, ri_rs_large_cell_Gamma, ri_rs_non_periodic, tensor_static_cohsex)
2162 :
2163 : ! 1. get V^SOC_µν,σσ'(k_i) from V^SOC_µν,σσ'(k=0)
2164 : CALL cfm_ikp_from_cfm_spinor_Gamma(cfm_SOC_ikp_spinor, &
2165 : bs_env%cfm_SOC_spinor_ao(1), &
2166 : bs_env%fm_s_Gamma%matrix_struct, &
2167 0 : ikp, qs_env, bs_env%kpoints_DOS, "ORB")
2168 :
2169 : CASE (tensor_small_cell_full_kp)
2170 :
2171 : ! 1. V^SOC_µν,σσ'(k_i) already there
2172 0 : CALL cp_cfm_to_cfm(bs_env%cfm_SOC_spinor_ao(ikp), cfm_SOC_ikp_spinor)
2173 :
2174 : END SELECT
2175 :
2176 : ! 2. V^SOC_nn',σσ'(k_i) = sum_µν C^*_µn,σ(k_i) V^SOC_µν,σσ'(k_i) C_νn'(k_i),
2177 : ! C_µn,σ(k_i): MO coefficiencts from diagonalizing KS-matrix h^KS_nn',σσ'(k_i)
2178 :
2179 : ! 2.1 build matrix C_µn,σ(k_i)
2180 0 : CALL cp_cfm_set_all(cfm_mos_ikp_spinor, z_zero)
2181 : ! get_cfm_submat/add_cfm_submat only copy SQUARE blocks, so the rectangular
2182 : ! (n_ao x n_window) column windows are copied with cp_fm_to_fm_submat (separate
2183 : ! nrow/ncol) on the real and imaginary parts separately, then recombined.
2184 0 : CALL cp_fm_create(fm_src_re, cfm_mos_ikp(1)%matrix_struct)
2185 0 : CALL cp_fm_create(fm_src_im, cfm_mos_ikp(1)%matrix_struct)
2186 0 : CALL cp_fm_create(fm_tgt_re, fst_mos)
2187 0 : CALL cp_fm_create(fm_tgt_im, fst_mos)
2188 0 : CALL cp_fm_set_all(fm_tgt_re, 0.0_dp)
2189 0 : CALL cp_fm_set_all(fm_tgt_im, 0.0_dp)
2190 : ! spin 1: MO columns mo_index_start_1..mo_index_start_1+n_window-1 -> rows 1..n_ao, cols 1..n_window
2191 0 : CALL cp_cfm_to_fm(cfm_mos_ikp(1), fm_src_re, fm_src_im)
2192 : CALL cp_fm_to_fm_submat(msource=fm_src_re, mtarget=fm_tgt_re, nrow=n_ao, ncol=n_window, &
2193 0 : s_firstrow=1, s_firstcol=mo_index_start_1, t_firstrow=1, t_firstcol=1)
2194 : CALL cp_fm_to_fm_submat(msource=fm_src_im, mtarget=fm_tgt_im, nrow=n_ao, ncol=n_window, &
2195 0 : s_firstrow=1, s_firstcol=mo_index_start_1, t_firstrow=1, t_firstcol=1)
2196 :
2197 : ! spin 2: MO columns mo_index_start_2..mo_index_start_2+n_window-1 -> rows n_ao+1..2*n_ao, cols n_window+1..2*n_window
2198 0 : CALL cp_cfm_to_fm(cfm_mos_ikp(bs_env%n_spin), fm_src_re, fm_src_im)
2199 : CALL cp_fm_to_fm_submat(msource=fm_src_re, mtarget=fm_tgt_re, nrow=n_ao, ncol=n_window, &
2200 0 : s_firstrow=1, s_firstcol=mo_index_start_2, t_firstrow=n_ao + 1, t_firstcol=n_window + 1)
2201 : CALL cp_fm_to_fm_submat(msource=fm_src_im, mtarget=fm_tgt_im, nrow=n_ao, ncol=n_window, &
2202 0 : s_firstrow=1, s_firstcol=mo_index_start_2, t_firstrow=n_ao + 1, t_firstcol=n_window + 1)
2203 :
2204 0 : CALL cp_fm_to_cfm(fm_tgt_re, fm_tgt_im, cfm_mos_ikp_spinor)
2205 :
2206 0 : CALL cp_fm_release(fm_src_re)
2207 0 : CALL cp_fm_release(fm_src_im)
2208 0 : CALL cp_fm_release(fm_tgt_re)
2209 0 : CALL cp_fm_release(fm_tgt_im)
2210 :
2211 : ! 2.2 work_nν,σσ' = sum_µ C^*_µn,σ(k_i) V^SOC_µν,σσ'(k_i)
2212 : CALL parallel_gemm('C', 'N', n_window2tot, 2*n_ao, 2*n_ao, z_one, &
2213 : cfm_mos_ikp_spinor, cfm_SOC_ikp_spinor, &
2214 0 : z_zero, cfm_work_ikp_spinor)
2215 : ! 2.3 V^SOC_nn',σσ'(k_i) = sum_ν work_nν,σσ' C_νn'(k_i)
2216 : CALL parallel_gemm('N', 'N', n_window2tot, n_window2tot, 2*n_ao, z_one, &
2217 : cfm_work_ikp_spinor, cfm_mos_ikp_spinor, &
2218 0 : z_zero, cfm_ks_ikp_spinor)
2219 :
2220 : ! 3. remove SOC outside of energy window: not applicable here -- the truncation window
2221 : ! itself already restricts SOC to the states around the Fermi level
2222 0 : eigenval_spinor_no_SOC(1:n_ao) = eigenval_no_SOC(1:n_ao, ikp, 1)
2223 0 : eigenval_spinor_no_SOC(n_ao + 1:) = eigenval_no_SOC(1:n_ao, ikp, bs_env%n_spin)
2224 :
2225 : ! 4. h^G0W0+SOC_nn',σσ'(k_i) = ε_nσ^G0W0(k_i) δ_nn' δ_σσ' + V^SOC_nn',σσ'(k_i)
2226 : CALL cfm_add_on_diag(cfm_ks_ikp_spinor, &
2227 : [eigenval_no_SOC(mo_index_start_1:mo_index_start_1 + n_window - 1, ikp, 1), &
2228 0 : eigenval_no_SOC(mo_index_start_2:mo_index_start_2 + n_window - 1, ikp, bs_env%n_spin)])
2229 :
2230 : ! 5. diagonalize h^G0W0+SOC_nn',σσ'(k_i) to get eigenvalues
2231 0 : ALLOCATE (eig_win_sorted(n_window2tot))
2232 0 : CALL cp_cfm_heevd(cfm_ks_ikp_spinor, cfm_eigenvec_ikp_spinor, eig_win_sorted)
2233 :
2234 : ! 6. DOS from spinors: not supported for the truncated window (CPASSERT'd above)
2235 :
2236 : ! 7. valence band max. (VBM), conduction band min. (CBM) and direct bandgap (DBG)
2237 0 : band_edges%VBM = MAX(band_edges%VBM, eig_win_sorted(homo_used))
2238 0 : band_edges%CBM = MIN(band_edges%CBM, eig_win_sorted(homo_used + 1))
2239 0 : band_edges%DBG = MIN(band_edges%DBG, eig_win_sorted(homo_used + 1) - eig_win_sorted(homo_used))
2240 :
2241 : CALL fill_truncated_eigenval_spinor(eigenval_no_SOC, eig_win_sorted, ikp, bs_env%n_spin, &
2242 : n_ao, mo_index_start_1, mo_index_start_2, n_window, &
2243 0 : n_window2tot, eigenval_spinor)
2244 :
2245 : ! 8. spinor wavefunctions:
2246 0 : CALL cp_cfm_set_all(cfm_spinor_wf_ikp, z_zero)
2247 0 : CPASSERT(.NOT. bs_env%do_ldos)
2248 : CALL parallel_gemm('N', 'N', 2*n_ao, n_window2tot, n_window2tot, z_one, &
2249 : cfm_mos_ikp_spinor, cfm_eigenvec_ikp_spinor, &
2250 0 : z_zero, cfm_spinor_wf_ikp)
2251 :
2252 0 : CALL cp_cfm_release(cfm_ks_ikp_spinor)
2253 0 : CALL cp_cfm_release(cfm_SOC_ikp_spinor)
2254 0 : CALL cp_cfm_release(cfm_work_ikp_spinor)
2255 0 : CALL cp_cfm_release(cfm_eigenvec_ikp_spinor)
2256 0 : CALL cp_cfm_release(cfm_mos_ikp_spinor)
2257 :
2258 0 : CALL cp_fm_struct_release(fst_ww)
2259 0 : CALL cp_fm_struct_release(fst_wa)
2260 0 : CALL cp_fm_struct_release(fst_mos)
2261 :
2262 0 : CALL timestop(handle)
2263 :
2264 0 : END SUBROUTINE SOC_ev_truncate_mos
2265 : ! **************************************************************************************************
2266 : !> \brief ...
2267 : !> \param eigenval_no_SOC non-SOC band energies (n_ao, n_kpoints, n_spin)
2268 : !> \param eig_win_sorted SOC-corrected eigenvalues of the window, ascending
2269 : !> \param ikp k-point index into eigenval_no_SOC
2270 : !> \param n_spin number of spin channels
2271 : !> \param n_ao number of AO basis functions (per spin)
2272 : !> \param mo_index_start_1 first retained state index for spin 1
2273 : !> \param mo_index_start_2 first retained state index for spin n_spin
2274 : !> \param n_window per-spin window size
2275 : !> \param n_window2tot total window size
2276 : !> \param eigenval_spinor output: full repacked spinor spectrum (2*n_ao)
2277 : ! **************************************************************************************************
2278 0 : SUBROUTINE fill_truncated_eigenval_spinor(eigenval_no_SOC, eig_win_sorted, ikp, n_spin, n_ao, &
2279 : mo_index_start_1, mo_index_start_2, n_window, &
2280 0 : n_window2tot, eigenval_spinor)
2281 : REAL(KIND=dp), DIMENSION(:, :, :) :: eigenval_no_SOC
2282 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: eig_win_sorted
2283 : INTEGER :: ikp, n_spin, n_ao, mo_index_start_1, &
2284 : mo_index_start_2, n_window, &
2285 : n_window2tot
2286 : REAL(KIND=dp), DIMENSION(:) :: eigenval_spinor
2287 :
2288 : CHARACTER(LEN=*), PARAMETER :: routineN = 'fill_truncated_eigenval_spinor'
2289 :
2290 : INTEGER :: handle, i, ia, ib, idx_end, idx_start, &
2291 : mo_index_start_1_m1, &
2292 : mo_index_start_2_m1
2293 :
2294 0 : CALL timeset(routineN, handle)
2295 :
2296 : ! verify the window was wide enough that SOC did not push a retained boundary state
2297 : ! past an excluded neighbor on either side -- this would invalidate the merge below
2298 0 : IF (mo_index_start_1 > 1) THEN
2299 0 : IF (eig_win_sorted(1) < eigenval_no_SOC(mo_index_start_1 - 1, ikp, 1)) THEN
2300 0 : CPABORT("SOC_NBANDS_OCC too small.")
2301 : END IF
2302 : END IF
2303 0 : IF (mo_index_start_2 > 1) THEN
2304 0 : IF (eig_win_sorted(1) < eigenval_no_SOC(mo_index_start_2 - 1, ikp, n_spin)) THEN
2305 0 : CPABORT("SOC_NBANDS_OCC too small.")
2306 : END IF
2307 : END IF
2308 0 : IF (mo_index_start_1 + n_window <= n_ao) THEN
2309 0 : IF (eig_win_sorted(n_window2tot) > eigenval_no_SOC(mo_index_start_1 + n_window, ikp, 1)) THEN
2310 0 : CPABORT("SOC_NBANDS_VIRT too small.")
2311 : END IF
2312 : END IF
2313 0 : IF (mo_index_start_2 + n_window <= n_ao) THEN
2314 0 : IF (eig_win_sorted(n_window2tot) > eigenval_no_SOC(mo_index_start_2 + n_window, ikp, n_spin)) THEN
2315 0 : CPABORT("SOC_NBANDS_VIRT too small.")
2316 : END IF
2317 : END IF
2318 :
2319 0 : mo_index_start_1_m1 = mo_index_start_1 - 1
2320 0 : mo_index_start_2_m1 = mo_index_start_2 - 1
2321 :
2322 0 : ia = 1
2323 0 : ib = 1
2324 0 : DO i = 1, mo_index_start_1_m1 + mo_index_start_2_m1
2325 0 : IF (ia <= mo_index_start_1_m1 .AND. ib <= mo_index_start_2_m1) THEN
2326 0 : IF (eigenval_no_SOC(ia, ikp, 1) <= eigenval_no_SOC(ib, ikp, n_spin)) THEN
2327 0 : eigenval_spinor(i) = eigenval_no_SOC(ia, ikp, 1)
2328 0 : ia = ia + 1
2329 : ELSE
2330 0 : eigenval_spinor(i) = eigenval_no_SOC(ib, ikp, n_spin)
2331 0 : ib = ib + 1
2332 : END IF
2333 0 : ELSE IF (ia <= mo_index_start_1_m1) THEN
2334 0 : eigenval_spinor(i) = eigenval_no_SOC(ia, ikp, 1)
2335 0 : ia = ia + 1
2336 : ELSE
2337 0 : eigenval_spinor(i) = eigenval_no_SOC(ib, ikp, n_spin)
2338 0 : ib = ib + 1
2339 : END IF
2340 : END DO
2341 :
2342 0 : idx_start = mo_index_start_1_m1 + mo_index_start_2_m1 + 1
2343 0 : idx_end = mo_index_start_1_m1 + mo_index_start_2_m1 + n_window2tot
2344 :
2345 0 : eigenval_spinor(idx_start:idx_end) = eig_win_sorted(:)
2346 :
2347 0 : ia = mo_index_start_1 + n_window
2348 0 : ib = mo_index_start_2 + n_window
2349 0 : DO i = mo_index_start_1_m1 + mo_index_start_2_m1 + n_window2tot + 1, 2*n_ao
2350 0 : IF (ia <= n_ao .AND. ib <= n_ao) THEN
2351 0 : IF (eigenval_no_SOC(ia, ikp, 1) <= eigenval_no_SOC(ib, ikp, n_spin)) THEN
2352 0 : eigenval_spinor(i) = eigenval_no_SOC(ia, ikp, 1)
2353 0 : ia = ia + 1
2354 : ELSE
2355 0 : eigenval_spinor(i) = eigenval_no_SOC(ib, ikp, n_spin)
2356 0 : ib = ib + 1
2357 : END IF
2358 0 : ELSE IF (ia <= n_ao) THEN
2359 0 : eigenval_spinor(i) = eigenval_no_SOC(ia, ikp, 1)
2360 0 : ia = ia + 1
2361 : ELSE
2362 0 : eigenval_spinor(i) = eigenval_no_SOC(ib, ikp, n_spin)
2363 0 : ib = ib + 1
2364 : END IF
2365 : END DO
2366 :
2367 0 : DEALLOCATE (eig_win_sorted)
2368 :
2369 0 : CALL timestop(handle)
2370 :
2371 0 : END SUBROUTINE fill_truncated_eigenval_spinor
2372 : ! **************************************************************************************************
2373 : !> \brief ...
2374 : !> \param DOS ...
2375 : !> \param PDOS ...
2376 : !> \param eigenval ...
2377 : !> \param ikp ...
2378 : !> \param bs_env ...
2379 : !> \param n_E ...
2380 : !> \param E_min ...
2381 : !> \param proj_mo_on_kind ...
2382 : ! **************************************************************************************************
2383 952 : SUBROUTINE add_to_DOS_PDOS(DOS, PDOS, eigenval, ikp, bs_env, n_E, E_min, proj_mo_on_kind)
2384 :
2385 : REAL(KIND=dp), DIMENSION(:) :: DOS
2386 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: PDOS
2387 : REAL(KIND=dp), DIMENSION(:) :: eigenval
2388 : INTEGER :: ikp
2389 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
2390 : INTEGER :: n_E
2391 : REAL(KIND=dp) :: E_min
2392 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: proj_mo_on_kind
2393 :
2394 : CHARACTER(LEN=*), PARAMETER :: routineN = 'add_to_DOS_PDOS'
2395 :
2396 : INTEGER :: handle, i_E, i_kind, i_mo, n_mo, nkind
2397 : REAL(KIND=dp) :: broadening, energy, energy_step_DOS, wkp
2398 :
2399 952 : CALL timeset(routineN, handle)
2400 :
2401 952 : energy_step_DOS = bs_env%energy_step_DOS
2402 952 : broadening = bs_env%broadening_DOS
2403 :
2404 952 : n_mo = SIZE(eigenval)
2405 952 : nkind = SIZE(proj_mo_on_kind, 2)
2406 :
2407 : ! normalize to closed-shell / open-shell
2408 952 : wkp = bs_env%kpoints_DOS%wkp(ikp)*bs_env%spin_degeneracy
2409 2147288 : DO i_E = 1, n_E
2410 2146336 : energy = E_min + i_E*energy_step_DOS
2411 47466732 : DO i_mo = 1, n_mo
2412 : ! DOS
2413 45319444 : DOS(i_E) = DOS(i_E) + wkp*Gaussian(energy - eigenval(i_mo), broadening)
2414 :
2415 : ! PDOS
2416 138104668 : DO i_kind = 1, nkind
2417 135958332 : IF (proj_mo_on_kind(i_mo, i_kind) > 0.0_dp) THEN
2418 : PDOS(i_E, i_kind) = PDOS(i_E, i_kind) + &
2419 : proj_mo_on_kind(i_mo, i_kind)*wkp* &
2420 30345484 : Gaussian(energy - eigenval(i_mo), broadening)
2421 : END IF
2422 : END DO
2423 : END DO
2424 : END DO
2425 :
2426 952 : CALL timestop(handle)
2427 :
2428 952 : END SUBROUTINE add_to_DOS_PDOS
2429 :
2430 : ! **************************************************************************************************
2431 : !> \brief ...
2432 : !> \param LDOS_2d ...
2433 : !> \param qs_env ...
2434 : !> \param ikp ...
2435 : !> \param bs_env ...
2436 : !> \param cfm_mos_ikp ...
2437 : !> \param eigenval ...
2438 : !> \param band_edges ...
2439 : !> \param do_spinor ...
2440 : !> \param cfm_non_spinor ...
2441 : ! **************************************************************************************************
2442 6 : SUBROUTINE add_to_LDOS_2d(LDOS_2d, qs_env, ikp, bs_env, cfm_mos_ikp, eigenval, &
2443 : band_edges, do_spinor, cfm_non_spinor)
2444 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: LDOS_2d
2445 : TYPE(qs_environment_type), POINTER :: qs_env
2446 : INTEGER :: ikp
2447 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
2448 : TYPE(cp_cfm_type) :: cfm_mos_ikp
2449 : REAL(KIND=dp), DIMENSION(:) :: eigenval
2450 : TYPE(band_edges_type) :: band_edges
2451 : LOGICAL, OPTIONAL :: do_spinor
2452 : TYPE(cp_cfm_type), OPTIONAL :: cfm_non_spinor
2453 :
2454 : CHARACTER(LEN=*), PARAMETER :: routineN = 'add_to_LDOS_2d'
2455 :
2456 : INTEGER :: handle, i_E, i_x_end, i_x_start, i_y_end, i_y_start, i_z, i_z_end, i_z_start, &
2457 : j_col, j_mo, n_E, n_mo, n_z, ncol_local, nimages, z_end_global, z_start_global
2458 6 : INTEGER, DIMENSION(:), POINTER :: col_indices
2459 : LOGICAL :: is_any_weight_non_zero, my_do_spinor
2460 : REAL(KIND=dp) :: broadening, E_max, E_min, &
2461 : E_total_window, energy, energy_step, &
2462 : energy_window, spin_degeneracy, weight
2463 : TYPE(cp_cfm_type) :: cfm_weighted_dm_ikp, cfm_work
2464 : TYPE(cp_fm_type) :: fm_non_spinor, fm_weighted_dm_MIC
2465 6 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: weighted_dm_MIC
2466 : TYPE(dft_control_type), POINTER :: dft_control
2467 : TYPE(pw_c1d_gs_type) :: rho_g
2468 : TYPE(pw_env_type), POINTER :: pw_env
2469 : TYPE(pw_pool_type), POINTER :: auxbas_pw_pool
2470 : TYPE(pw_r3d_rs_type) :: LDOS_3d
2471 : TYPE(qs_ks_env_type), POINTER :: ks_env
2472 :
2473 6 : CALL timeset(routineN, handle)
2474 :
2475 6 : my_do_spinor = .FALSE.
2476 6 : IF (PRESENT(do_spinor)) my_do_spinor = do_spinor
2477 :
2478 6 : CALL get_qs_env(qs_env, ks_env=ks_env, pw_env=pw_env, dft_control=dft_control)
2479 :
2480 : ! previously, dft_control%nimages set to # neighbor cells, revert for Γ-only KS matrix
2481 6 : nimages = dft_control%nimages
2482 6 : dft_control%nimages = bs_env%nimages_scf
2483 :
2484 6 : energy_window = bs_env%energy_window_DOS
2485 6 : energy_step = bs_env%energy_step_DOS
2486 6 : broadening = bs_env%broadening_DOS
2487 :
2488 6 : E_min = band_edges%VBM - 0.5_dp*energy_window
2489 6 : E_max = band_edges%CBM + 0.5_dp*energy_window
2490 6 : E_total_window = E_max - E_min
2491 :
2492 6 : n_E = INT(E_total_window/energy_step)
2493 :
2494 6 : CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool)
2495 :
2496 6 : CALL auxbas_pw_pool%create_pw(LDOS_3d)
2497 6 : CALL auxbas_pw_pool%create_pw(rho_g)
2498 :
2499 6 : i_x_start = LBOUND(LDOS_3d%array, 1)
2500 6 : i_x_end = UBOUND(LDOS_3d%array, 1)
2501 6 : i_y_start = LBOUND(LDOS_3d%array, 2)
2502 6 : i_y_end = UBOUND(LDOS_3d%array, 2)
2503 6 : i_z_start = LBOUND(LDOS_3d%array, 3)
2504 6 : i_z_end = UBOUND(LDOS_3d%array, 3)
2505 :
2506 6 : z_start_global = i_z_start
2507 6 : z_end_global = i_z_end
2508 :
2509 6 : CALL bs_env%para_env%min(z_start_global)
2510 6 : CALL bs_env%para_env%max(z_end_global)
2511 6 : n_z = z_end_global - z_start_global + 1
2512 :
2513 36 : IF (ANY(ABS(bs_env%hmat(1:2, 3)) > 1.0E-6_dp) .OR. ANY(ABS(bs_env%hmat(3, 1:2)) > 1.0E-6_dp)) THEN
2514 0 : CPABORT("Please choose a cell that has 90° angles to the z-direction.")
2515 : END IF
2516 : ! for integration, we need the dz and the conversion from H -> eV and a_Bohr -> Å
2517 6 : bs_env%unit_ldos_int_z_inv_Ang2_eV = bs_env%hmat(3, 3)/REAL(n_z, KIND=dp)/evolt/angstrom**2
2518 :
2519 6 : IF (ikp == 1) THEN
2520 30 : ALLOCATE (LDOS_2d(i_x_start:i_x_end, i_y_start:i_y_end, n_E))
2521 6 : LDOS_2d(:, :, :) = 0.0_dp
2522 : END IF
2523 :
2524 6 : CALL cp_cfm_create(cfm_work, cfm_mos_ikp%matrix_struct)
2525 6 : CALL cp_cfm_create(cfm_weighted_dm_ikp, cfm_mos_ikp%matrix_struct)
2526 6 : CALL cp_fm_create(fm_weighted_dm_MIC, cfm_mos_ikp%matrix_struct)
2527 6 : IF (my_do_spinor) THEN
2528 2 : CALL cp_fm_create(fm_non_spinor, cfm_non_spinor%matrix_struct)
2529 : END IF
2530 :
2531 : CALL cp_cfm_get_info(matrix=cfm_mos_ikp, &
2532 : ncol_global=n_mo, &
2533 : ncol_local=ncol_local, &
2534 6 : col_indices=col_indices)
2535 :
2536 6 : NULLIFY (weighted_dm_MIC)
2537 6 : CALL dbcsr_allocate_matrix_set(weighted_dm_MIC, 1)
2538 6 : ALLOCATE (weighted_dm_MIC(1)%matrix)
2539 : CALL dbcsr_create(weighted_dm_MIC(1)%matrix, template=bs_env%mat_ao_ao%matrix, &
2540 6 : matrix_type=dbcsr_type_symmetric)
2541 :
2542 1678 : DO i_E = 1, n_E
2543 :
2544 1672 : energy = E_min + i_E*energy_step
2545 :
2546 1672 : is_any_weight_non_zero = .FALSE.
2547 :
2548 20950 : DO j_col = 1, ncol_local
2549 :
2550 19278 : j_mo = col_indices(j_col)
2551 :
2552 19278 : IF (my_do_spinor) THEN
2553 : spin_degeneracy = 1.0_dp
2554 : ELSE
2555 10818 : spin_degeneracy = bs_env%spin_degeneracy
2556 : END IF
2557 :
2558 19278 : weight = Gaussian(energy - eigenval(j_mo), broadening)*spin_degeneracy
2559 :
2560 144099 : cfm_work%local_data(:, j_col) = cfm_mos_ikp%local_data(:, j_col)*weight
2561 :
2562 20950 : IF (weight > 1.0E-5_dp) is_any_weight_non_zero = .TRUE.
2563 :
2564 : END DO
2565 :
2566 1672 : CALL bs_env%para_env%sync()
2567 1672 : CALL bs_env%para_env%sum(is_any_weight_non_zero)
2568 1672 : CALL bs_env%para_env%sync()
2569 :
2570 : ! cycle if there are no states at the energy i_E
2571 1678 : IF (is_any_weight_non_zero) THEN
2572 :
2573 : CALL parallel_gemm('N', 'C', n_mo, n_mo, n_mo, z_one, &
2574 24 : cfm_mos_ikp, cfm_work, z_zero, cfm_weighted_dm_ikp)
2575 :
2576 24 : IF (my_do_spinor) THEN
2577 :
2578 : ! contribution from up,up to fm_non_spinor
2579 8 : CALL get_cfm_submat(cfm_non_spinor, cfm_weighted_dm_ikp, 1, 1)
2580 8 : CALL cp_fm_set_all(fm_non_spinor, 0.0_dp)
2581 : CALL MIC_contribution_from_ikp(bs_env, qs_env, fm_non_spinor, &
2582 : cfm_non_spinor, ikp, bs_env%kpoints_DOS, &
2583 8 : "ORB", bs_env%kpoints_DOS%wkp(ikp))
2584 :
2585 : ! add contribution from down,down to fm_non_spinor
2586 8 : CALL get_cfm_submat(cfm_non_spinor, cfm_weighted_dm_ikp, n_mo/2, n_mo/2)
2587 : CALL MIC_contribution_from_ikp(bs_env, qs_env, fm_non_spinor, &
2588 : cfm_non_spinor, ikp, bs_env%kpoints_DOS, &
2589 8 : "ORB", bs_env%kpoints_DOS%wkp(ikp))
2590 : CALL copy_fm_to_dbcsr(fm_non_spinor, weighted_dm_MIC(1)%matrix, &
2591 8 : keep_sparsity=.FALSE.)
2592 : ELSE
2593 16 : CALL cp_fm_set_all(fm_weighted_dm_MIC, 0.0_dp)
2594 : CALL MIC_contribution_from_ikp(bs_env, qs_env, fm_weighted_dm_MIC, &
2595 : cfm_weighted_dm_ikp, ikp, bs_env%kpoints_DOS, &
2596 16 : "ORB", bs_env%kpoints_DOS%wkp(ikp))
2597 : CALL copy_fm_to_dbcsr(fm_weighted_dm_MIC, weighted_dm_MIC(1)%matrix, &
2598 16 : keep_sparsity=.FALSE.)
2599 : END IF
2600 :
2601 338424 : LDOS_3d%array(:, :, :) = 0.0_dp
2602 :
2603 : CALL calculate_rho_elec(matrix_p_kp=weighted_dm_MIC, &
2604 : rho=LDOS_3d, &
2605 : rho_gspace=rho_g, &
2606 24 : ks_env=ks_env)
2607 :
2608 504 : DO i_z = i_z_start, i_z_end
2609 338424 : LDOS_2d(:, :, i_E) = LDOS_2d(:, :, i_E) + LDOS_3d%array(:, :, i_z)
2610 : END DO
2611 :
2612 : END IF
2613 :
2614 : END DO
2615 :
2616 : ! set back nimages
2617 6 : dft_control%nimages = nimages
2618 :
2619 6 : CALL auxbas_pw_pool%give_back_pw(LDOS_3d)
2620 6 : CALL auxbas_pw_pool%give_back_pw(rho_g)
2621 :
2622 6 : CALL cp_cfm_release(cfm_work)
2623 6 : CALL cp_cfm_release(cfm_weighted_dm_ikp)
2624 :
2625 6 : CALL cp_fm_release(fm_weighted_dm_MIC)
2626 :
2627 6 : CALL dbcsr_deallocate_matrix_set(weighted_dm_MIC)
2628 :
2629 6 : IF (my_do_spinor) THEN
2630 2 : CALL cp_fm_release(fm_non_spinor)
2631 : END IF
2632 :
2633 6 : CALL timestop(handle)
2634 :
2635 6 : END SUBROUTINE add_to_LDOS_2d
2636 :
2637 : ! **************************************************************************************************
2638 : !> \brief ...
2639 : !> \param eigenval_spinor ...
2640 : !> \param ikp_for_file ...
2641 : !> \param ikp ...
2642 : !> \param bs_env ...
2643 : !> \param eigenval_spinor_G0W0 ...
2644 : ! **************************************************************************************************
2645 296 : SUBROUTINE write_SOC_eigenvalues(eigenval_spinor, ikp_for_file, ikp, bs_env, eigenval_spinor_G0W0)
2646 :
2647 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: eigenval_spinor
2648 : INTEGER :: ikp_for_file, ikp
2649 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
2650 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), OPTIONAL :: eigenval_spinor_G0W0
2651 :
2652 : CHARACTER(LEN=*), PARAMETER :: routineN = 'write_SOC_eigenvalues'
2653 :
2654 : CHARACTER(len=3) :: occ_vir
2655 : CHARACTER(LEN=default_string_length) :: fname
2656 : INTEGER :: handle, i_mo, iunit, n_occ_spinor
2657 :
2658 296 : CALL timeset(routineN, handle)
2659 :
2660 296 : fname = "bandstructure_SCF_and_G0W0_plus_SOC"
2661 :
2662 296 : IF (bs_env%para_env%is_source()) THEN
2663 :
2664 148 : IF (ikp_for_file == 1) THEN
2665 : CALL open_file(TRIM(fname), unit_number=iunit, file_status="REPLACE", &
2666 11 : file_action="WRITE")
2667 : ELSE
2668 : CALL open_file(TRIM(fname), unit_number=iunit, file_status="OLD", &
2669 137 : file_action="WRITE", file_position="APPEND")
2670 : END IF
2671 :
2672 148 : WRITE (iunit, "(A)") " "
2673 148 : WRITE (iunit, "(A10,I7,A25,3F10.4)") "kpoint: ", ikp_for_file, "coordinate: ", &
2674 740 : bs_env%kpoints_DOS%xkp(:, ikp)
2675 148 : WRITE (iunit, "(A)") " "
2676 :
2677 148 : IF (PRESENT(eigenval_spinor_G0W0)) THEN
2678 : ! SCF+SOC and G0W0+SOC eigenvalues
2679 148 : WRITE (iunit, "(A5,A12,2A22)") "n", "k", "ϵ_nk^DFT+SOC (eV)", "ϵ_nk^G0W0+SOC (eV)"
2680 : ELSE
2681 : ! SCF+SOC eigenvalues only
2682 0 : WRITE (iunit, "(A5,A12,A22)") "n", "k", "ϵ_nk^DFT+SOC (eV)"
2683 : END IF
2684 :
2685 148 : n_occ_spinor = bs_env%n_occ(1) + bs_env%n_occ(bs_env%n_spin)
2686 :
2687 3932 : DO i_mo = 1, SIZE(eigenval_spinor)
2688 3784 : IF (i_mo <= n_occ_spinor) occ_vir = 'occ'
2689 3784 : IF (i_mo > n_occ_spinor) occ_vir = 'vir'
2690 3932 : IF (PRESENT(eigenval_spinor_G0W0)) THEN
2691 : ! SCF+SOC and G0W0+SOC eigenvalues
2692 3784 : WRITE (iunit, "(I5,3A,I5,4F16.3,2F17.3)") i_mo, ' (', occ_vir, ') ', &
2693 7568 : ikp_for_file, eigenval_spinor(i_mo)*evolt, eigenval_spinor_G0W0(i_mo)*evolt
2694 : ELSE
2695 : ! SCF+SOC eigenvalues only
2696 0 : WRITE (iunit, "(I5,3A,I5,4F16.3,F17.3)") i_mo, ' (', occ_vir, ') ', &
2697 0 : ikp_for_file, eigenval_spinor(i_mo)*evolt
2698 : END IF
2699 : END DO
2700 :
2701 148 : CALL close_file(iunit)
2702 :
2703 : END IF
2704 :
2705 296 : CALL timestop(handle)
2706 :
2707 296 : END SUBROUTINE write_SOC_eigenvalues
2708 :
2709 : ! **************************************************************************************************
2710 : !> \brief ...
2711 : !> \param int_number ...
2712 : !> \return ...
2713 : ! **************************************************************************************************
2714 0 : PURE FUNCTION count_digits(int_number)
2715 :
2716 : INTEGER, INTENT(IN) :: int_number
2717 : INTEGER :: count_digits
2718 :
2719 : INTEGER :: digitCount, tempInt
2720 :
2721 0 : digitCount = 0
2722 :
2723 0 : tempInt = int_number
2724 :
2725 0 : DO WHILE (tempInt /= 0)
2726 0 : tempInt = tempInt/10
2727 0 : digitCount = digitCount + 1
2728 : END DO
2729 :
2730 0 : count_digits = digitCount
2731 :
2732 0 : END FUNCTION count_digits
2733 :
2734 : ! **************************************************************************************************
2735 : !> \brief ...
2736 : !> \param band_edges ...
2737 : !> \param scf_gw_soc ...
2738 : !> \param bs_env ...
2739 : ! **************************************************************************************************
2740 460 : SUBROUTINE write_band_edges(band_edges, scf_gw_soc, bs_env)
2741 :
2742 : TYPE(band_edges_type) :: band_edges
2743 : CHARACTER(LEN=*) :: scf_gw_soc
2744 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
2745 :
2746 : CHARACTER(LEN=*), PARAMETER :: routineN = 'write_band_edges'
2747 :
2748 : CHARACTER(LEN=17) :: print_format
2749 : INTEGER :: handle, u
2750 :
2751 460 : CALL timeset(routineN, handle)
2752 :
2753 : ! print format
2754 460 : print_format = "(T2,2A,T61,F20.3)"
2755 :
2756 460 : u = bs_env%unit_nr
2757 460 : IF (u > 0) THEN
2758 230 : WRITE (u, '(T2,A)') ''
2759 230 : WRITE (u, print_format) scf_gw_soc, ' valence band maximum (eV):', band_edges%VBM*evolt
2760 230 : WRITE (u, print_format) scf_gw_soc, ' conduction band minimum (eV):', band_edges%CBM*evolt
2761 230 : WRITE (u, print_format) scf_gw_soc, ' indirect band gap (eV):', band_edges%IDBG*evolt
2762 230 : WRITE (u, print_format) scf_gw_soc, ' direct band gap (eV):', band_edges%DBG*evolt
2763 : END IF
2764 :
2765 460 : CALL timestop(handle)
2766 :
2767 460 : END SUBROUTINE write_band_edges
2768 :
2769 : ! **************************************************************************************************
2770 : !> \brief ...
2771 : !> \param DOS ...
2772 : !> \param PDOS ...
2773 : !> \param bs_env ...
2774 : !> \param qs_env ...
2775 : !> \param scf_gw_soc ...
2776 : !> \param E_min ...
2777 : !> \param E_VBM ...
2778 : ! **************************************************************************************************
2779 84 : SUBROUTINE write_dos_pdos(DOS, PDOS, bs_env, qs_env, scf_gw_soc, E_min, E_VBM)
2780 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: DOS
2781 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: PDOS
2782 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
2783 : TYPE(qs_environment_type), POINTER :: qs_env
2784 : CHARACTER(LEN=*) :: scf_gw_soc
2785 : REAL(KIND=dp) :: E_min, E_VBM
2786 :
2787 : CHARACTER(LEN=*), PARAMETER :: routineN = 'write_dos_pdos'
2788 :
2789 : CHARACTER(LEN=3), DIMENSION(100) :: elements
2790 : CHARACTER(LEN=default_string_length) :: atom_name, fname, output_string
2791 : INTEGER :: handle, i_E, i_kind, iatom, iunit, n_A, &
2792 : n_E, nkind
2793 : REAL(KIND=dp) :: energy
2794 84 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
2795 :
2796 84 : CALL timeset(routineN, handle)
2797 :
2798 84 : WRITE (fname, "(3A)") "DOS_PDOS_", scf_gw_soc, ".out"
2799 :
2800 84 : n_E = SIZE(PDOS, 1)
2801 84 : nkind = SIZE(PDOS, 2)
2802 84 : CALL get_qs_env(qs_env, particle_set=particle_set)
2803 :
2804 84 : IF (bs_env%para_env%is_source()) THEN
2805 :
2806 42 : CALL open_file(TRIM(fname), unit_number=iunit, file_status="REPLACE", file_action="WRITE")
2807 :
2808 42 : n_A = 2 + nkind
2809 :
2810 162 : DO iatom = 1, bs_env%n_atom
2811 : CALL get_atomic_kind(atomic_kind=particle_set(iatom)%atomic_kind, &
2812 120 : kind_number=i_kind, name=atom_name)
2813 162 : elements(i_kind) = atom_name(1:3)
2814 : END DO
2815 :
2816 42 : WRITE (output_string, "(A,I1,A)") "(", n_A, "A)"
2817 :
2818 42 : WRITE (iunit, TRIM(output_string)) "Energy-E_F (eV) DOS (1/eV) PDOS (1/eV) ", &
2819 84 : " of atom type ", elements(1:nkind)
2820 :
2821 42 : WRITE (output_string, "(A,I1,A)") "(", n_A, "F13.5)"
2822 :
2823 87510 : DO i_E = 1, n_E
2824 : ! energy is relative to valence band maximum => - E_VBM
2825 87468 : energy = E_min + i_E*bs_env%energy_step_DOS - E_VBM
2826 262446 : WRITE (iunit, TRIM(output_string)) energy*evolt, DOS(i_E)/evolt, PDOS(i_E, :)/evolt
2827 : END DO
2828 :
2829 42 : CALL close_file(iunit)
2830 :
2831 : END IF
2832 :
2833 84 : CALL timestop(handle)
2834 :
2835 84 : END SUBROUTINE write_dos_pdos
2836 :
2837 : ! **************************************************************************************************
2838 : !> \brief ...
2839 : !> \param energy ...
2840 : !> \param broadening ...
2841 : !> \return ...
2842 : ! **************************************************************************************************
2843 75684206 : PURE FUNCTION Gaussian(energy, broadening)
2844 :
2845 : REAL(KIND=dp), INTENT(IN) :: energy, broadening
2846 : REAL(KIND=dp) :: Gaussian
2847 :
2848 75684206 : IF (ABS(energy) < 5*broadening) THEN
2849 116164 : Gaussian = 1.0_dp/broadening/SQRT(twopi)*EXP(-0.5_dp*energy**2/broadening**2)
2850 : ELSE
2851 : Gaussian = 0.0_dp
2852 : END IF
2853 :
2854 75684206 : END FUNCTION Gaussian
2855 :
2856 : ! **************************************************************************************************
2857 : !> \brief ...
2858 : !> \param proj_mo_on_kind ...
2859 : !> \param qs_env ...
2860 : !> \param cfm_mos ...
2861 : !> \param cfm_s ...
2862 : ! **************************************************************************************************
2863 514 : SUBROUTINE compute_proj_mo_on_kind(proj_mo_on_kind, qs_env, cfm_mos, cfm_s)
2864 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: proj_mo_on_kind
2865 : TYPE(qs_environment_type), POINTER :: qs_env
2866 : TYPE(cp_cfm_type) :: cfm_mos, cfm_s
2867 :
2868 : CHARACTER(LEN=*), PARAMETER :: routineN = 'compute_proj_mo_on_kind'
2869 :
2870 : INTEGER :: handle, i_atom, i_global, i_kind, i_row, &
2871 : j_col, n_ao, n_mo, ncol_local, nkind, &
2872 : nrow_local
2873 514 : INTEGER, ALLOCATABLE, DIMENSION(:) :: atom_from_bf, kind_of
2874 514 : INTEGER, DIMENSION(:), POINTER :: col_indices, row_indices
2875 514 : TYPE(atomic_kind_type), DIMENSION(:), POINTER :: atomic_kind_set
2876 : TYPE(cp_cfm_type) :: cfm_proj, cfm_s_i_kind, cfm_work
2877 : TYPE(cp_fm_type) :: fm_proj_im, fm_proj_re
2878 :
2879 514 : CALL timeset(routineN, handle)
2880 :
2881 514 : CALL get_qs_env(qs_env, atomic_kind_set=atomic_kind_set, nkind=nkind)
2882 514 : CALL get_atomic_kind_set(atomic_kind_set, kind_of=kind_of)
2883 :
2884 : CALL cp_cfm_get_info(matrix=cfm_mos, &
2885 : nrow_global=n_mo, &
2886 : nrow_local=nrow_local, &
2887 : ncol_local=ncol_local, &
2888 : row_indices=row_indices, &
2889 514 : col_indices=col_indices)
2890 :
2891 514 : n_ao = qs_env%bs_env%n_ao
2892 :
2893 1542 : ALLOCATE (atom_from_bf(n_ao))
2894 514 : CALL get_atom_index_from_basis_function_index(qs_env, atom_from_bf, n_ao, "ORB")
2895 :
2896 514 : proj_mo_on_kind(:, :) = 0.0_dp
2897 :
2898 514 : CALL cp_cfm_create(cfm_s_i_kind, cfm_s%matrix_struct)
2899 514 : CALL cp_cfm_create(cfm_work, cfm_s%matrix_struct)
2900 514 : CALL cp_cfm_create(cfm_proj, cfm_s%matrix_struct)
2901 514 : CALL cp_fm_create(fm_proj_re, cfm_s%matrix_struct)
2902 514 : CALL cp_fm_create(fm_proj_im, cfm_s%matrix_struct)
2903 :
2904 1420 : DO i_kind = 1, nkind
2905 :
2906 906 : CALL cp_cfm_to_cfm(cfm_s, cfm_s_i_kind)
2907 :
2908 : ! set entries in overlap matrix to zero which do not belong to atoms of i_kind
2909 12198 : DO j_col = 1, ncol_local
2910 90134 : DO i_row = 1, nrow_local
2911 :
2912 77936 : i_global = row_indices(i_row)
2913 :
2914 77936 : IF (i_global <= n_ao) THEN
2915 77936 : i_atom = atom_from_bf(i_global)
2916 0 : ELSE IF (i_global <= 2*n_ao) THEN
2917 0 : i_atom = atom_from_bf(i_global - n_ao)
2918 : ELSE
2919 0 : CPABORT("Wrong indices.")
2920 : END IF
2921 :
2922 89228 : IF (i_kind /= kind_of(i_atom)) THEN
2923 35834 : cfm_s_i_kind%local_data(i_row, j_col) = z_zero
2924 : END IF
2925 :
2926 : END DO
2927 : END DO
2928 :
2929 : CALL parallel_gemm('N', 'N', n_mo, n_mo, n_mo, z_one, &
2930 906 : cfm_s_i_kind, cfm_mos, z_zero, cfm_work)
2931 : CALL parallel_gemm('C', 'N', n_mo, n_mo, n_mo, z_one, &
2932 906 : cfm_mos, cfm_work, z_zero, cfm_proj)
2933 :
2934 906 : CALL cp_cfm_to_fm(cfm_proj, fm_proj_re, fm_proj_im)
2935 :
2936 906 : CALL cp_fm_get_diag(fm_proj_im, proj_mo_on_kind(:, i_kind))
2937 1420 : CALL cp_fm_get_diag(fm_proj_re, proj_mo_on_kind(:, i_kind))
2938 :
2939 : END DO ! i_kind
2940 :
2941 514 : CALL cp_cfm_release(cfm_s_i_kind)
2942 514 : CALL cp_cfm_release(cfm_work)
2943 514 : CALL cp_cfm_release(cfm_proj)
2944 514 : CALL cp_fm_release(fm_proj_re)
2945 514 : CALL cp_fm_release(fm_proj_im)
2946 :
2947 514 : CALL timestop(handle)
2948 :
2949 2056 : END SUBROUTINE compute_proj_mo_on_kind
2950 :
2951 : ! **************************************************************************************************
2952 : !> \brief ...
2953 : !> \param cfm_spinor_ikp ...
2954 : !> \param cfm_spinor_Gamma ...
2955 : !> \param fm_struct_non_spinor ...
2956 : !> \param ikp ...
2957 : !> \param qs_env ...
2958 : !> \param kpoints ...
2959 : !> \param basis_type ...
2960 : ! **************************************************************************************************
2961 120 : SUBROUTINE cfm_ikp_from_cfm_spinor_Gamma(cfm_spinor_ikp, cfm_spinor_Gamma, fm_struct_non_spinor, &
2962 : ikp, qs_env, kpoints, basis_type)
2963 : TYPE(cp_cfm_type) :: cfm_spinor_ikp, cfm_spinor_Gamma
2964 : TYPE(cp_fm_struct_type), POINTER :: fm_struct_non_spinor
2965 : INTEGER :: ikp
2966 : TYPE(qs_environment_type), POINTER :: qs_env
2967 : TYPE(kpoint_type), POINTER :: kpoints
2968 : CHARACTER(LEN=*) :: basis_type
2969 :
2970 : CHARACTER(LEN=*), PARAMETER :: routineN = 'cfm_ikp_from_cfm_spinor_Gamma'
2971 :
2972 : INTEGER :: handle, i_block, i_offset, j_block, &
2973 : j_offset, n_ao
2974 : TYPE(cp_cfm_type) :: cfm_non_spinor_Gamma, cfm_non_spinor_ikp
2975 : TYPE(cp_fm_type) :: fm_non_spinor_Gamma_im, &
2976 : fm_non_spinor_Gamma_re
2977 :
2978 20 : CALL timeset(routineN, handle)
2979 :
2980 20 : CALL cp_cfm_create(cfm_non_spinor_Gamma, fm_struct_non_spinor)
2981 20 : CALL cp_cfm_create(cfm_non_spinor_ikp, fm_struct_non_spinor)
2982 20 : CALL cp_fm_create(fm_non_spinor_Gamma_re, fm_struct_non_spinor)
2983 20 : CALL cp_fm_create(fm_non_spinor_Gamma_im, fm_struct_non_spinor)
2984 :
2985 20 : CALL cp_cfm_get_info(cfm_non_spinor_Gamma, nrow_global=n_ao)
2986 :
2987 20 : CALL cp_cfm_set_all(cfm_spinor_ikp, z_zero)
2988 :
2989 60 : DO i_block = 0, 1
2990 140 : DO j_block = 0, 1
2991 80 : i_offset = i_block*n_ao + 1
2992 80 : j_offset = j_block*n_ao + 1
2993 80 : CALL get_cfm_submat(cfm_non_spinor_Gamma, cfm_spinor_Gamma, i_offset, j_offset)
2994 80 : CALL cp_cfm_to_fm(cfm_non_spinor_Gamma, fm_non_spinor_Gamma_re, fm_non_spinor_Gamma_im)
2995 :
2996 : ! transform real part of Gamma-point matrix to ikp
2997 : CALL cfm_ikp_from_fm_Gamma(cfm_non_spinor_ikp, fm_non_spinor_Gamma_re, &
2998 80 : ikp, qs_env, kpoints, basis_type)
2999 80 : CALL add_cfm_submat(cfm_spinor_ikp, cfm_non_spinor_ikp, i_offset, j_offset)
3000 :
3001 : ! transform imag part of Gamma-point matrix to ikp
3002 : CALL cfm_ikp_from_fm_Gamma(cfm_non_spinor_ikp, fm_non_spinor_Gamma_im, &
3003 80 : ikp, qs_env, kpoints, basis_type)
3004 120 : CALL add_cfm_submat(cfm_spinor_ikp, cfm_non_spinor_ikp, i_offset, j_offset, gaussi)
3005 :
3006 : END DO
3007 : END DO
3008 :
3009 20 : CALL cp_cfm_release(cfm_non_spinor_Gamma)
3010 20 : CALL cp_cfm_release(cfm_non_spinor_ikp)
3011 20 : CALL cp_fm_release(fm_non_spinor_Gamma_re)
3012 20 : CALL cp_fm_release(fm_non_spinor_Gamma_im)
3013 :
3014 20 : CALL timestop(handle)
3015 :
3016 20 : END SUBROUTINE cfm_ikp_from_cfm_spinor_Gamma
3017 :
3018 : ! **************************************************************************************************
3019 : !> \brief Reconstruct a k-point operator from a real Gamma matrix using one MIC phase.
3020 : !> \param cfm_ikp ...
3021 : !> \param fm_Gamma ...
3022 : !> \param ikp ...
3023 : !> \param qs_env ...
3024 : !> \param kpoints ...
3025 : !> \param basis_type ...
3026 : ! **************************************************************************************************
3027 7788 : SUBROUTINE cfm_ikp_from_fm_Gamma(cfm_ikp, fm_Gamma, ikp, qs_env, kpoints, basis_type)
3028 : TYPE(cp_cfm_type) :: cfm_ikp
3029 : TYPE(cp_fm_type) :: fm_Gamma
3030 : INTEGER :: ikp
3031 : TYPE(qs_environment_type), POINTER :: qs_env
3032 : TYPE(kpoint_type), POINTER :: kpoints
3033 : CHARACTER(LEN=*) :: basis_type
3034 :
3035 : CHARACTER(LEN=*), PARAMETER :: routineN = 'cfm_ikp_from_fm_Gamma'
3036 :
3037 : INTEGER :: handle
3038 7788 : INTEGER, ALLOCATABLE, DIMENSION(:) :: atom_from_bf
3039 : TYPE(cell_type), POINTER :: cell
3040 7788 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
3041 :
3042 7788 : CALL timeset(routineN, handle)
3043 :
3044 7788 : CPASSERT(basis_type == "ORB" .OR. basis_type == "RI_AUX")
3045 23364 : ALLOCATE (atom_from_bf(fm_Gamma%matrix_struct%nrow_global))
3046 7788 : CALL get_atom_index_from_basis_function_index(qs_env, atom_from_bf, SIZE(atom_from_bf), basis_type)
3047 7788 : NULLIFY (cell, particle_set)
3048 7788 : CALL get_qs_env(qs_env, cell=cell, particle_set=particle_set)
3049 : CALL fm_gamma_to_kp(cfm_ikp, fm_Gamma, cell, particle_set, atom_from_bf, &
3050 7788 : kpoints%index_to_cell, kpoints%xkp(:, ikp))
3051 :
3052 7788 : CALL timestop(handle)
3053 :
3054 15576 : END SUBROUTINE cfm_ikp_from_fm_Gamma
3055 :
3056 : ! **************************************************************************************************
3057 : !> \brief ...
3058 : !> \param bs_env ...
3059 : !> \param qs_env ...
3060 : !> \param fm_W_MIC_freq_j ...
3061 : !> \param cfm_W_ikp_freq_j ...
3062 : !> \param ikp ...
3063 : !> \param kpoints ...
3064 : !> \param basis_type ...
3065 : !> \param wkp_ext ...
3066 : ! **************************************************************************************************
3067 3410 : SUBROUTINE MIC_contribution_from_ikp(bs_env, qs_env, fm_W_MIC_freq_j, &
3068 : cfm_W_ikp_freq_j, ikp, kpoints, basis_type, wkp_ext)
3069 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
3070 : TYPE(qs_environment_type), POINTER :: qs_env
3071 : TYPE(cp_fm_type) :: fm_W_MIC_freq_j
3072 : TYPE(cp_cfm_type) :: cfm_W_ikp_freq_j
3073 : INTEGER, INTENT(IN) :: ikp
3074 : TYPE(kpoint_type), POINTER :: kpoints
3075 : CHARACTER(LEN=*) :: basis_type
3076 : REAL(KIND=dp), OPTIONAL :: wkp_ext
3077 :
3078 : CHARACTER(LEN=*), PARAMETER :: routineN = 'MIC_contribution_from_ikp'
3079 :
3080 : INTEGER :: handle, i_bf, iatom, iatom_old, irow, &
3081 : j_bf, jatom, jatom_old, jcol, n_bf, &
3082 : ncol_local, nrow_local, num_cells
3083 3410 : INTEGER, ALLOCATABLE, DIMENSION(:) :: atom_from_bf_index
3084 3410 : INTEGER, DIMENSION(:), POINTER :: col_indices, row_indices
3085 3410 : INTEGER, DIMENSION(:, :), POINTER :: index_to_cell
3086 : REAL(KIND=dp) :: contribution, weight_im, weight_re, &
3087 : wkp_of_ikp
3088 : REAL(KIND=dp), DIMENSION(3, 3) :: hmat
3089 3410 : REAL(KIND=dp), DIMENSION(:), POINTER :: wkp
3090 3410 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: xkp
3091 : TYPE(cell_type), POINTER :: cell
3092 3410 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
3093 :
3094 3410 : CALL timeset(routineN, handle)
3095 :
3096 : ! get number of basis functions (bf) for different basis sets
3097 3410 : IF (basis_type == "ORB") THEN
3098 32 : n_bf = qs_env%bs_env%n_ao
3099 3378 : ELSE IF (basis_type == "RI_AUX") THEN
3100 3378 : n_bf = qs_env%bs_env%n_RI
3101 : ELSE
3102 0 : CPABORT("Only ORB and RI_AUX basis implemented.")
3103 : END IF
3104 :
3105 10230 : ALLOCATE (atom_from_bf_index(n_bf))
3106 3410 : CALL get_atom_index_from_basis_function_index(qs_env, atom_from_bf_index, n_bf, basis_type)
3107 :
3108 3410 : NULLIFY (cell, particle_set)
3109 3410 : CALL get_qs_env(qs_env, cell=cell, particle_set=particle_set)
3110 3410 : CALL get_cell(cell=cell, h=hmat)
3111 :
3112 : CALL cp_cfm_get_info(matrix=cfm_W_ikp_freq_j, &
3113 : nrow_local=nrow_local, &
3114 : ncol_local=ncol_local, &
3115 : row_indices=row_indices, &
3116 3410 : col_indices=col_indices)
3117 :
3118 3410 : CALL get_kpoint_info(kpoints, xkp=xkp, wkp=wkp)
3119 3410 : index_to_cell => kpoints%index_to_cell
3120 3410 : num_cells = SIZE(index_to_cell, 2)
3121 :
3122 3410 : iatom_old = 0
3123 3410 : jatom_old = 0
3124 :
3125 73304 : DO jcol = 1, ncol_local
3126 1529527 : DO irow = 1, nrow_local
3127 :
3128 1456223 : i_bf = row_indices(irow)
3129 1456223 : j_bf = col_indices(jcol)
3130 :
3131 1456223 : iatom = atom_from_bf_index(i_bf)
3132 1456223 : jatom = atom_from_bf_index(j_bf)
3133 :
3134 1456223 : IF (PRESENT(wkp_ext)) THEN
3135 3496 : wkp_of_ikp = wkp_ext
3136 : ELSE
3137 1497526 : SELECT CASE (bs_env%l_RI(i_bf) + bs_env%l_RI(j_bf))
3138 : CASE (0)
3139 : ! both RI functions are s-functions, k-extrapolation for 2D and 3D
3140 44799 : wkp_of_ikp = wkp(ikp)
3141 : CASE (1)
3142 : ! one function is an s-function, the other a p-function, k-extrapolation for 3D
3143 193398 : wkp_of_ikp = bs_env%wkp_s_p(ikp)
3144 : CASE DEFAULT
3145 : ! for any other matrix element of W, there is no need for extrapolation
3146 1452727 : wkp_of_ikp = bs_env%wkp_no_extra(ikp)
3147 : END SELECT
3148 : END IF
3149 :
3150 1456223 : IF (iatom /= iatom_old .OR. jatom /= jatom_old) THEN
3151 :
3152 : CALL compute_weight_re_im(weight_re, weight_im, &
3153 : num_cells, iatom, jatom, xkp(1:3, ikp), wkp_of_ikp, &
3154 138140 : cell, index_to_cell, hmat, particle_set)
3155 :
3156 138140 : iatom_old = iatom
3157 138140 : jatom_old = jatom
3158 :
3159 : END IF
3160 :
3161 : contribution = weight_re*REAL(cfm_W_ikp_freq_j%local_data(irow, jcol)) + &
3162 1456223 : weight_im*AIMAG(cfm_W_ikp_freq_j%local_data(irow, jcol))
3163 :
3164 : fm_W_MIC_freq_j%local_data(irow, jcol) = fm_W_MIC_freq_j%local_data(irow, jcol) &
3165 1526117 : + contribution
3166 :
3167 : END DO
3168 : END DO
3169 :
3170 3410 : CALL timestop(handle)
3171 :
3172 10230 : END SUBROUTINE MIC_contribution_from_ikp
3173 :
3174 : ! **************************************************************************************************
3175 : !> \brief ...
3176 : !> \param xkp ...
3177 : !> \param ikp_start ...
3178 : !> \param ikp_end ...
3179 : !> \param grid ...
3180 : ! **************************************************************************************************
3181 140 : SUBROUTINE compute_xkp(xkp, ikp_start, ikp_end, grid)
3182 :
3183 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: xkp
3184 : INTEGER :: ikp_start, ikp_end
3185 : INTEGER, DIMENSION(3) :: grid
3186 :
3187 : CHARACTER(LEN=*), PARAMETER :: routineN = 'compute_xkp'
3188 :
3189 : INTEGER :: handle, i, ix, iy, iz
3190 :
3191 140 : CALL timeset(routineN, handle)
3192 :
3193 140 : i = ikp_start
3194 300 : DO ix = 1, grid(1)
3195 572 : DO iy = 1, grid(2)
3196 894 : DO iz = 1, grid(3)
3197 :
3198 462 : IF (i > ikp_end) CYCLE
3199 :
3200 428 : xkp(1, i) = REAL(2*ix - grid(1) - 1, KIND=dp)/(2._dp*REAL(grid(1), KIND=dp))
3201 428 : xkp(2, i) = REAL(2*iy - grid(2) - 1, KIND=dp)/(2._dp*REAL(grid(2), KIND=dp))
3202 428 : xkp(3, i) = REAL(2*iz - grid(3) - 1, KIND=dp)/(2._dp*REAL(grid(3), KIND=dp))
3203 734 : i = i + 1
3204 :
3205 : END DO
3206 : END DO
3207 : END DO
3208 :
3209 140 : CALL timestop(handle)
3210 :
3211 140 : END SUBROUTINE compute_xkp
3212 :
3213 : ! **************************************************************************************************
3214 : !> \brief ...
3215 : !> \param kpoints ...
3216 : !> \param qs_env ...
3217 : ! **************************************************************************************************
3218 244 : SUBROUTINE kpoint_init_cell_index_simple(kpoints, qs_env)
3219 :
3220 : TYPE(kpoint_type), POINTER :: kpoints
3221 : TYPE(qs_environment_type), POINTER :: qs_env
3222 :
3223 : CHARACTER(LEN=*), PARAMETER :: routineN = 'kpoint_init_cell_index_simple'
3224 :
3225 : INTEGER :: handle, nimages
3226 : TYPE(mp_para_env_type), POINTER :: para_env
3227 : TYPE(neighbor_list_set_p_type), DIMENSION(:), &
3228 122 : POINTER :: sab_orb
3229 :
3230 122 : CALL timeset(routineN, handle)
3231 :
3232 122 : NULLIFY (para_env, sab_orb)
3233 122 : CALL get_qs_env(qs_env=qs_env, para_env=para_env, sab_orb=sab_orb)
3234 122 : CALL kpoint_init_cell_index(kpoints, sab_orb, para_env, nimages)
3235 :
3236 122 : CALL timestop(handle)
3237 :
3238 122 : END SUBROUTINE kpoint_init_cell_index_simple
3239 :
3240 : ! **************************************************************************************************
3241 : !> \brief ...
3242 : !> \param qs_env ...
3243 : !> \param bs_env ...
3244 : ! **************************************************************************************************
3245 22 : SUBROUTINE soc(qs_env, bs_env)
3246 : TYPE(qs_environment_type), POINTER :: qs_env
3247 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
3248 :
3249 : CHARACTER(LEN=*), PARAMETER :: routineN = 'soc'
3250 :
3251 : INTEGER :: handle
3252 :
3253 22 : CALL timeset(routineN, handle)
3254 :
3255 : ! V^SOC_µν^(α),R = ħ/2 < ϕ_µ cell O | sum_ℓ ΔV_ℓ^SO(r,r') L^(α) | ϕ_ν cell R>, α = x,y,z
3256 : ! see Hartwigsen, Goedecker, Hutter, Eq.(18), (19) (doi.org/10.1103/PhysRevB.58.3641)
3257 22 : CALL V_SOC_xyz_from_pseudopotential(qs_env, bs_env%mat_V_SOC_xyz)
3258 :
3259 : ! Calculate H^SOC_µν,σσ'(k) = sum_α V^SOC_µν^(α)(k)*Pauli-matrix^(α)_σσ'
3260 : ! see Hartwigsen, Goedecker, Hutter, Eq.(18) (doi.org/10.1103/PhysRevB.58.3641)
3261 28 : SELECT CASE (bs_env%gw_implementation)
3262 : CASE (tensor_large_cell_Gamma, ri_rs_large_cell_Gamma, ri_rs_non_periodic, tensor_static_cohsex)
3263 :
3264 : ! H^SOC_µν,σσ' = sum_α V^SOC_µν^(α)*Pauli-matrix^(α)_σσ'
3265 6 : CALL H_KS_spinor_Gamma(bs_env)
3266 :
3267 : CASE (tensor_small_cell_full_kp)
3268 :
3269 : ! V^SOC_µν^(α),R -> V^SOC_µν^(α)(k); then calculate spinor H^SOC_µν,σσ'(k) (see above)
3270 22 : CALL H_KS_spinor_kp(qs_env, bs_env)
3271 :
3272 : END SELECT
3273 :
3274 22 : CALL timestop(handle)
3275 :
3276 22 : END SUBROUTINE soc
3277 :
3278 : ! **************************************************************************************************
3279 : !> \brief ...
3280 : !> \param bs_env ...
3281 : ! **************************************************************************************************
3282 6 : SUBROUTINE H_KS_spinor_Gamma(bs_env)
3283 :
3284 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
3285 :
3286 : CHARACTER(LEN=*), PARAMETER :: routineN = 'H_KS_spinor_Gamma'
3287 :
3288 : INTEGER :: handle, nao, s
3289 : TYPE(cp_fm_struct_type), POINTER :: str
3290 :
3291 6 : CALL timeset(routineN, handle)
3292 :
3293 6 : CALL cp_fm_get_info(bs_env%fm_ks_Gamma(1), nrow_global=nao)
3294 :
3295 12 : ALLOCATE (bs_env%cfm_SOC_spinor_ao(1))
3296 6 : CALL create_cfm_double(bs_env%cfm_SOC_spinor_ao(1), fm_orig=bs_env%fm_ks_Gamma(1))
3297 6 : CALL cp_cfm_set_all(bs_env%cfm_SOC_spinor_ao(1), z_zero)
3298 :
3299 6 : str => bs_env%fm_ks_Gamma(1)%matrix_struct
3300 :
3301 6 : s = nao + 1
3302 :
3303 : ! careful: inside add_dbcsr_submat, mat_V_SOC_xyz is multiplied by i because the real matrix
3304 : ! mat_V_SOC_xyz is antisymmetric as V_SOC matrix is purely imaginary and Hermitian
3305 : ! V_x * sigma_x: sigma_x = ((0,1),(1,0))
3306 : ! ud block (1,s): +i*V_x
3307 : CALL add_dbcsr_submat(bs_env%cfm_SOC_spinor_ao(1), bs_env%mat_V_SOC_xyz(1, 1)%matrix, &
3308 6 : str, 1, s, z_one, .FALSE.)
3309 : ! du block (s,1): +i*V_x
3310 : CALL add_dbcsr_submat(bs_env%cfm_SOC_spinor_ao(1), bs_env%mat_V_SOC_xyz(1, 1)%matrix, &
3311 6 : str, s, 1, z_one, .FALSE.)
3312 :
3313 : ! V_y * sigma_y: sigma_y = ((0,-i),(i,0))
3314 : ! ud block (1,s): i*(i*V_y) = -V_y (extra gaussi factor)
3315 : CALL add_dbcsr_submat(bs_env%cfm_SOC_spinor_ao(1), bs_env%mat_V_SOC_xyz(2, 1)%matrix, &
3316 6 : str, 1, s, gaussi, .FALSE.)
3317 : ! du block (s,1): -i*(i*V_y) = +V_y (extra -gaussi factor)
3318 : CALL add_dbcsr_submat(bs_env%cfm_SOC_spinor_ao(1), bs_env%mat_V_SOC_xyz(2, 1)%matrix, &
3319 6 : str, s, 1, -gaussi, .FALSE.)
3320 :
3321 : ! V_z * sigma_z: sigma_z = ((1,0),(0,-1))
3322 : ! uu block (1,1): +i*V_z
3323 : CALL add_dbcsr_submat(bs_env%cfm_SOC_spinor_ao(1), bs_env%mat_V_SOC_xyz(3, 1)%matrix, &
3324 6 : str, 1, 1, z_one, .FALSE.)
3325 : ! dd block (s,s): -i*V_z
3326 : CALL add_dbcsr_submat(bs_env%cfm_SOC_spinor_ao(1), bs_env%mat_V_SOC_xyz(3, 1)%matrix, &
3327 6 : str, s, s, -z_one, .FALSE.)
3328 :
3329 6 : CALL timestop(handle)
3330 :
3331 6 : END SUBROUTINE H_KS_spinor_Gamma
3332 :
3333 : ! **************************************************************************************************
3334 : !> \brief ...
3335 : !> \param qs_env ...
3336 : !> \param bs_env ...
3337 : ! **************************************************************************************************
3338 32 : SUBROUTINE H_KS_spinor_kp(qs_env, bs_env)
3339 : TYPE(qs_environment_type), POINTER :: qs_env
3340 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
3341 :
3342 : CHARACTER(LEN=*), PARAMETER :: routineN = 'H_KS_spinor_kp'
3343 :
3344 : INTEGER :: handle, i_dim, ikp, n_spin, &
3345 : nkp_bs_and_DOS, s
3346 16 : INTEGER, DIMENSION(:, :, :), POINTER :: cell_to_index_scf
3347 : REAL(KIND=dp), DIMENSION(3) :: xkp
3348 : TYPE(cp_cfm_type) :: cfm_V_SOC_xyz_ikp
3349 : TYPE(cp_fm_struct_type), POINTER :: str
3350 : TYPE(kpoint_type), POINTER :: kpoints_scf
3351 : TYPE(neighbor_list_set_p_type), DIMENSION(:), &
3352 16 : POINTER :: sab_nl
3353 :
3354 16 : CALL timeset(routineN, handle)
3355 :
3356 16 : nkp_bs_and_DOS = bs_env%nkp_bs_and_DOS
3357 16 : n_spin = bs_env%n_spin
3358 16 : s = bs_env%n_ao + 1
3359 16 : str => bs_env%cfm_ks_kp(1, 1)%matrix_struct
3360 :
3361 16 : CALL cp_cfm_create(cfm_V_SOC_xyz_ikp, bs_env%cfm_work_mo%matrix_struct)
3362 :
3363 16 : CALL alloc_cfm_double_array_1d(bs_env%cfm_SOC_spinor_ao, bs_env%cfm_ks_kp(1, 1), nkp_bs_and_DOS)
3364 :
3365 16 : CALL get_qs_env(qs_env, kpoints=kpoints_scf)
3366 :
3367 16 : NULLIFY (sab_nl)
3368 16 : CALL get_kpoint_info(kpoints_scf, sab_nl=sab_nl, cell_to_index=cell_to_index_scf)
3369 :
3370 64 : DO i_dim = 1, 3
3371 :
3372 1018 : DO ikp = 1, nkp_bs_and_DOS
3373 :
3374 3816 : xkp(1:3) = bs_env%kpoints_DOS%xkp(1:3, ikp)
3375 :
3376 954 : CALL cp_cfm_set_all(cfm_V_SOC_xyz_ikp, z_zero)
3377 :
3378 : CALL rsmat_to_kp(bs_env%mat_V_SOC_xyz, i_dim, xkp, cell_to_index_scf, &
3379 954 : sab_nl, bs_env, cfm_V_SOC_xyz_ikp, imag_rs_mat=.TRUE.)
3380 :
3381 : ! multiply V_SOC with i because bs_env%mat_V_SOC_xyz stores imag. part (real part = 0)
3382 954 : CALL cp_cfm_scale(gaussi, cfm_V_SOC_xyz_ikp)
3383 :
3384 48 : SELECT CASE (i_dim)
3385 : CASE (1)
3386 : ! add V^SOC_x * σ_x for σ_x = ( (0,1) (1,0) )
3387 318 : CALL add_cfm_submat(bs_env%cfm_SOC_spinor_ao(ikp), cfm_V_SOC_xyz_ikp, 1, s)
3388 318 : CALL add_cfm_submat(bs_env%cfm_SOC_spinor_ao(ikp), cfm_V_SOC_xyz_ikp, s, 1)
3389 : CASE (2)
3390 : ! add V^SOC_y * σ_y for σ_y = ( (0,-i) (i,0) )
3391 318 : CALL cp_cfm_scale(gaussi, cfm_V_SOC_xyz_ikp)
3392 318 : CALL add_cfm_submat(bs_env%cfm_SOC_spinor_ao(ikp), cfm_V_SOC_xyz_ikp, 1, s)
3393 318 : CALL cp_cfm_scale(-z_one, cfm_V_SOC_xyz_ikp)
3394 318 : CALL add_cfm_submat(bs_env%cfm_SOC_spinor_ao(ikp), cfm_V_SOC_xyz_ikp, s, 1)
3395 : CASE (3)
3396 : ! add V^SOC_z * σ_z for σ_z = ( (1,0) (0,1) )
3397 318 : CALL add_cfm_submat(bs_env%cfm_SOC_spinor_ao(ikp), cfm_V_SOC_xyz_ikp, 1, 1)
3398 318 : CALL cp_cfm_scale(-z_one, cfm_V_SOC_xyz_ikp)
3399 1272 : CALL add_cfm_submat(bs_env%cfm_SOC_spinor_ao(ikp), cfm_V_SOC_xyz_ikp, s, s)
3400 : END SELECT
3401 :
3402 : END DO
3403 :
3404 : END DO ! ikp
3405 :
3406 16 : CALL cp_cfm_release(cfm_V_SOC_xyz_ikp)
3407 :
3408 16 : CALL timestop(handle)
3409 :
3410 16 : END SUBROUTINE H_KS_spinor_kp
3411 :
3412 : ! **************************************************************************************************
3413 : !> \brief ...
3414 : !> \param cfm_array ...
3415 : !> \param cfm_template ...
3416 : !> \param n ...
3417 : ! **************************************************************************************************
3418 16 : SUBROUTINE alloc_cfm_double_array_1d(cfm_array, cfm_template, n)
3419 : TYPE(cp_cfm_type), ALLOCATABLE, DIMENSION(:) :: cfm_array
3420 : TYPE(cp_cfm_type) :: cfm_template
3421 : INTEGER :: n
3422 :
3423 : CHARACTER(LEN=*), PARAMETER :: routineN = 'alloc_cfm_double_array_1d'
3424 :
3425 : INTEGER :: handle, i
3426 :
3427 16 : CALL timeset(routineN, handle)
3428 :
3429 366 : ALLOCATE (cfm_array(n))
3430 334 : DO i = 1, n
3431 318 : CALL create_cfm_double(cfm_array(i), cfm_orig=cfm_template)
3432 334 : CALL cp_cfm_set_all(cfm_array(i), z_zero)
3433 : END DO
3434 :
3435 16 : CALL timestop(handle)
3436 :
3437 16 : END SUBROUTINE alloc_cfm_double_array_1d
3438 :
3439 : ! **************************************************************************************************
3440 : !> \brief ...
3441 : !> \param bs_env ...
3442 : ! **************************************************************************************************
3443 152 : SUBROUTINE get_all_VBM_CBM_bandgaps(bs_env)
3444 :
3445 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
3446 :
3447 : CHARACTER(LEN=*), PARAMETER :: routineN = 'get_all_VBM_CBM_bandgaps'
3448 :
3449 : INTEGER :: handle
3450 :
3451 152 : CALL timeset(routineN, handle)
3452 :
3453 152 : CALL get_VBM_CBM_bandgaps(bs_env%band_edges_scf, bs_env%eigenval_scf, bs_env)
3454 152 : CALL get_VBM_CBM_bandgaps(bs_env%band_edges_GW, bs_env%eigenval_GW, bs_env)
3455 152 : CALL get_VBM_CBM_bandgaps(bs_env%band_edges_HF, bs_env%eigenval_HF, bs_env)
3456 :
3457 152 : CALL check_qp_gap_sanity(bs_env)
3458 :
3459 152 : CALL check_scf_gw_level_ordering(bs_env)
3460 :
3461 152 : CALL timestop(handle)
3462 :
3463 152 : END SUBROUTINE get_all_VBM_CBM_bandgaps
3464 :
3465 : ! **************************************************************************************************
3466 : !> \brief Warn if the GW fundamental band gap is inverted or implausibly large, i.e. if the
3467 : !> quasiparticle solve has produced a spectrum that cannot be physical.
3468 : !> \param bs_env ...
3469 : ! **************************************************************************************************
3470 152 : SUBROUTINE check_qp_gap_sanity(bs_env)
3471 :
3472 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
3473 :
3474 : CHARACTER(LEN=default_string_length) :: gw_label
3475 : REAL(KIND=dp) :: gap, gap_scf
3476 :
3477 152 : gap = bs_env%band_edges_GW%IDBG
3478 152 : gap_scf = bs_env%band_edges_scf%IDBG
3479 152 : gw_label = gw_flavour_label(bs_env)
3480 :
3481 : ! requiring a healthy SCF gap keeps the inversion test from firing on a genuine metal
3482 152 : IF (gap < -eps_qp_gap .AND. gap_scf > eps_qp_gap) THEN
3483 : CALL cp_warn(__LOCATION__, &
3484 : TRIM(gw_label)//" band gap is negative ("// &
3485 : TRIM(ADJUSTL(cp_to_string(gap*evolt, '(F12.3)')))//" eV): the quasiparticle "// &
3486 0 : "spectrum is inverted. Check numerical parameters.")
3487 152 : ELSE IF (ABS(gap) > max_qp_gap) THEN
3488 : CALL cp_warn(__LOCATION__, &
3489 : TRIM(gw_label)//" band gap is implausibly large ("// &
3490 : TRIM(ADJUSTL(cp_to_string(gap*evolt, '(F12.3)')))//" eV): the quasiparticle "// &
3491 0 : "solve has likely diverged. Check numerical parameters.")
3492 : END IF
3493 :
3494 152 : END SUBROUTINE check_qp_gap_sanity
3495 :
3496 : ! **************************************************************************************************
3497 : !> \brief Check whether the GW correction reorders the frontier levels with respect to the SCF
3498 : !> eigenvalues, i.e. whether the SCF HOMO (LUMO) is a different level than the GW HOMO
3499 : !> (LUMO). If so, the SCF and GW band edges printed afterwards belong to different
3500 : !> orbitals, which is easily overlooked => warn.
3501 : !> Levels closer than eps_degeneracy in the SCF spectrum count as degenerate, i.e. their
3502 : !> reordering by GW is not reported.
3503 : !> \param bs_env ...
3504 : ! **************************************************************************************************
3505 152 : SUBROUTINE check_scf_gw_level_ordering(bs_env)
3506 :
3507 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
3508 :
3509 : CHARACTER(LEN=*), PARAMETER :: routineN = 'check_scf_gw_level_ordering'
3510 : REAL(KIND=dp), PARAMETER :: eps_degeneracy = 1.0E-05_dp
3511 :
3512 : CHARACTER(LEN=default_string_length) :: gw_label, level_gw, level_scf, &
3513 : spin_string
3514 : CHARACTER(LEN=max_line_length) :: msg
3515 : INTEGER :: handle, homo, ispin, n_mo
3516 : INTEGER, DIMENSION(2) :: loc_gw, loc_scf
3517 :
3518 152 : CALL timeset(routineN, handle)
3519 :
3520 152 : n_mo = bs_env%n_ao
3521 152 : gw_label = gw_flavour_label(bs_env)
3522 :
3523 328 : DO ispin = 1, bs_env%n_spin
3524 :
3525 176 : homo = bs_env%n_occ(ispin)
3526 :
3527 176 : IF (bs_env%n_spin == 2) THEN
3528 48 : WRITE (spin_string, '(A,I0,A)') " (spin ", ispin, ")"
3529 : ELSE
3530 128 : spin_string = ""
3531 : END IF
3532 :
3533 : ! occupied levels: level carrying the SCF VBM versus level carrying the GW VBM
3534 2876 : loc_scf(:) = MAXLOC(bs_env%eigenval_scf(1:homo, :, ispin))
3535 2876 : loc_gw(:) = MAXLOC(bs_env%eigenval_GW(1:homo, :, ispin))
3536 :
3537 : ! only report a genuine reordering, not a permutation within a degenerate SCF shell
3538 176 : IF (bs_env%eigenval_scf(loc_scf(1), loc_scf(2), ispin) - &
3539 : bs_env%eigenval_scf(loc_gw(1), loc_gw(2), ispin) > eps_degeneracy) THEN
3540 :
3541 2 : CALL level_string(level_scf, loc_scf, bs_env)
3542 2 : CALL level_string(level_gw, loc_gw, bs_env)
3543 :
3544 : msg = TRIM(gw_label)//" reorders the occupied levels"//TRIM(spin_string)// &
3545 : ": the SCF valence band maximum (SCF HOMO) is "//TRIM(level_scf)// &
3546 : ", whereas the "//TRIM(gw_label)//" valence band maximum ("// &
3547 : TRIM(gw_label)//" HOMO) is "//TRIM(level_gw)//". The SCF and "// &
3548 : TRIM(gw_label)//" band edges printed below therefore belong to different "// &
3549 2 : "orbitals; see the eigenvalues in the file bandstructure_SCF_and_G0W0."
3550 2 : CPWARN(TRIM(msg))
3551 :
3552 : END IF
3553 :
3554 : ! empty levels: level carrying the SCF CBM versus level carrying the GW CBM
3555 5316 : loc_scf(:) = MINLOC(bs_env%eigenval_scf(homo + 1:n_mo, :, ispin))
3556 5316 : loc_gw(:) = MINLOC(bs_env%eigenval_GW(homo + 1:n_mo, :, ispin))
3557 176 : loc_scf(1) = loc_scf(1) + homo
3558 176 : loc_gw(1) = loc_gw(1) + homo
3559 :
3560 176 : IF (bs_env%eigenval_scf(loc_gw(1), loc_gw(2), ispin) - &
3561 152 : bs_env%eigenval_scf(loc_scf(1), loc_scf(2), ispin) > eps_degeneracy) THEN
3562 :
3563 0 : CALL level_string(level_scf, loc_scf, bs_env)
3564 0 : CALL level_string(level_gw, loc_gw, bs_env)
3565 :
3566 : msg = TRIM(gw_label)//" reorders the empty levels"//TRIM(spin_string)// &
3567 : ": the SCF conduction band minimum (SCF LUMO) is "//TRIM(level_scf)// &
3568 : ", whereas the "//TRIM(gw_label)//" conduction band minimum ("// &
3569 : TRIM(gw_label)//" LUMO) is "//TRIM(level_gw)//". The SCF and "// &
3570 : TRIM(gw_label)//" band edges printed below therefore belong to different "// &
3571 0 : "orbitals; see the eigenvalues in the file bandstructure_SCF_and_G0W0."
3572 0 : CPWARN(TRIM(msg))
3573 :
3574 : END IF
3575 :
3576 : END DO
3577 :
3578 152 : CALL timestop(handle)
3579 :
3580 152 : END SUBROUTINE check_scf_gw_level_ordering
3581 :
3582 : ! **************************************************************************************************
3583 : !> \brief Human readable name of the level (i_mo, ikp) given as loc = [i_mo, ikp]
3584 : !> \param string ...
3585 : !> \param loc ...
3586 : !> \param bs_env ...
3587 : ! **************************************************************************************************
3588 4 : SUBROUTINE level_string(string, loc, bs_env)
3589 :
3590 : CHARACTER(LEN=*), INTENT(OUT) :: string
3591 : INTEGER, DIMENSION(2), INTENT(IN) :: loc
3592 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
3593 :
3594 4 : IF (bs_env%nkp_bs_and_DOS > 1) THEN
3595 4 : WRITE (string, '(A,I0,A,I0)') "level ", loc(1), " at k-point ", loc(2)
3596 : ELSE
3597 0 : WRITE (string, '(A,I0)') "level ", loc(1)
3598 : END IF
3599 :
3600 4 : END SUBROUTINE level_string
3601 :
3602 : ! **************************************************************************************************
3603 : !> \brief ...
3604 : !> \param band_edges ...
3605 : !> \param ev ...
3606 : !> \param bs_env ...
3607 : ! **************************************************************************************************
3608 474 : SUBROUTINE get_VBM_CBM_bandgaps(band_edges, ev, bs_env)
3609 : TYPE(band_edges_type) :: band_edges
3610 : REAL(KIND=dp), DIMENSION(:, :, :) :: ev
3611 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
3612 :
3613 : CHARACTER(LEN=*), PARAMETER :: routineN = 'get_VBM_CBM_bandgaps'
3614 :
3615 : INTEGER :: handle, homo, homo_1, homo_2, ikp, &
3616 : ispin, lumo, lumo_1, lumo_2, n_mo
3617 : REAL(KIND=dp) :: E_DBG_at_ikp
3618 :
3619 474 : CALL timeset(routineN, handle)
3620 :
3621 474 : n_mo = bs_env%n_ao
3622 :
3623 474 : band_edges%DBG = 1000.0_dp
3624 :
3625 876 : SELECT CASE (bs_env%n_spin)
3626 : CASE (1)
3627 402 : homo = bs_env%n_occ(1)
3628 402 : lumo = homo + 1
3629 8294 : band_edges%VBM = MAXVAL(ev(1:homo, :, 1))
3630 16656 : band_edges%CBM = MINVAL(ev(homo + 1:n_mo, :, 1))
3631 : CASE (2)
3632 72 : homo_1 = bs_env%n_occ(1)
3633 72 : lumo_1 = homo_1 + 1
3634 72 : homo_2 = bs_env%n_occ(2)
3635 72 : lumo_2 = homo_2 + 1
3636 984 : band_edges%VBM = MAX(MAXVAL(ev(1:homo_1, :, 1)), MAXVAL(ev(1:homo_2, :, 2)))
3637 1380 : band_edges%CBM = MIN(MINVAL(ev(homo_1 + 1:n_mo, :, 1)), MINVAL(ev(homo_2 + 1:n_mo, :, 2)))
3638 : CASE DEFAULT
3639 474 : CPABORT("Error with number of spins.")
3640 : END SELECT
3641 :
3642 474 : band_edges%IDBG = band_edges%CBM - band_edges%VBM
3643 :
3644 1020 : DO ispin = 1, bs_env%n_spin
3645 :
3646 546 : homo = bs_env%n_occ(ispin)
3647 :
3648 2872 : DO ikp = 1, bs_env%nkp_bs_and_DOS
3649 :
3650 24514 : E_DBG_at_ikp = -MAXVAL(ev(1:homo, ikp, ispin)) + MINVAL(ev(homo + 1:n_mo, ikp, ispin))
3651 :
3652 2398 : IF (E_DBG_at_ikp < band_edges%DBG) band_edges%DBG = E_DBG_at_ikp
3653 :
3654 : END DO
3655 :
3656 : END DO
3657 402 : SELECT CASE (bs_env%n_spin)
3658 : CASE (1)
3659 : CALL get_fermi_level_1c(bs_env, ev(:, :, 1), &
3660 : REAL(bs_env%n_electron(1), KIND=dp), &
3661 402 : bs_env%spin_degeneracy, band_edges%VBM, band_edges%CBM, band_edges%E_fermi)
3662 : CASE (2)
3663 : CALL get_fermi_level_2c(bs_env, ev(:, :, 1:2), &
3664 : REAL(bs_env%n_electron(1) + bs_env%n_electron(2), KIND=dp), &
3665 474 : band_edges%VBM, band_edges%CBM, band_edges%E_fermi)
3666 : END SELECT
3667 :
3668 474 : CALL timestop(handle)
3669 :
3670 474 : END SUBROUTINE get_VBM_CBM_bandgaps
3671 :
3672 : ! **************************************************************************************************
3673 : !> \brief Fermi level (chemical potential) for one set of band energies on the (weighted)
3674 : !> DOS k-point mesh bs_env%kpoints_DOS (band-structure-path k-points carry wkp=0 and
3675 : !> therefore do not contribute). Used both for a single spin-degenerate channel
3676 : !> (n_spin=1, maxocc=bs_env%spin_degeneracy=2) and for the spin-orbit-coupled spinor
3677 : !> space, where the two spins are already merged into one set of 2*n_ao states, each
3678 : !> holding at most one electron (maxocc=1).
3679 : !> IMPORTANT: Smearkp's T=0 bisection does *not* converge to the gap midpoint for a
3680 : !> real (flat) gap: N(mu) is exactly n_el for every mu in [VBM,CBM), so the bisection
3681 : !> exits on its very first probe, wherever that lands inside the gap, not at the
3682 : !> midpoint. Therefore Smearkp is only invoked when bs_env%do_smear is active (a
3683 : !> genuine metal, smeared with the ground-state SCF's &SMEAR settings); otherwise
3684 : !> E_fermi = VBM (highest occupied eigenvalue), matching the convention ABINIT uses
3685 : !> for its fixed-occupation-number case (occopt<3), rather than the gap midpoint.
3686 : !> \param bs_env ...
3687 : !> \param eigenval band energies (n_states, n_kpoints)
3688 : !> \param n_el target (weighted) number of occupied states
3689 : !> \param maxocc maximum occupation per state
3690 : !> \param VBM valence band maximum, used as E_fermi when bs_env%do_smear = .FALSE.
3691 : !> \param CBM conduction band minimum, used only to detect a wide gap
3692 : !> \param e_fermi ...
3693 : ! **************************************************************************************************
3694 568 : SUBROUTINE get_fermi_level_1c(bs_env, eigenval, n_el, maxocc, VBM, CBM, e_fermi)
3695 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
3696 : REAL(KIND=dp), DIMENSION(:, :) :: eigenval
3697 : REAL(KIND=dp) :: n_el, maxocc, VBM, CBM, e_fermi
3698 :
3699 : REAL(KIND=dp), PARAMETER :: gap_smear_ratio = 20.0_dp
3700 :
3701 : REAL(KIND=dp) :: kTS
3702 568 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: f_occ
3703 :
3704 568 : IF (bs_env%do_smear .AND. .NOT. (CBM > VBM .AND. &
3705 : CBM - VBM > gap_smear_ratio*bs_env%smear_width)) THEN
3706 16 : ALLOCATE (f_occ(SIZE(eigenval, 1), SIZE(eigenval, 2)))
3707 : CALL Smearkp(f_occ, e_fermi, kTS, eigenval, n_el, &
3708 : bs_env%kpoints_DOS%wkp(1:SIZE(eigenval, 2)), &
3709 4 : bs_env%smear_width, maxocc, bs_env%smear_method)
3710 4 : DEALLOCATE (f_occ)
3711 : ELSE
3712 564 : e_fermi = VBM
3713 : END IF
3714 :
3715 568 : END SUBROUTINE get_fermi_level_1c
3716 :
3717 : ! **************************************************************************************************
3718 : !> \brief Fermi level (chemical potential) shared across two spin channels with independent
3719 : !> band energies but the same chemical potential (standard spin-polarized DFT); see
3720 : !> get_fermi_level_1c for the k-point weighting and for why Smearkp2 is only used
3721 : !> when bs_env%do_smear is active (E_fermi = VBM otherwise).
3722 : !> \param bs_env ...
3723 : !> \param eigenval band energies (n_states, n_kpoints, 2)
3724 : !> \param n_el target (weighted) total number of occupied states, summed over both spins
3725 : !> \param VBM valence band maximum, used as E_fermi when bs_env%do_smear = .FALSE.
3726 : !> \param CBM conduction band minimum, used only to detect a wide gap
3727 : !> \param e_fermi ...
3728 : ! **************************************************************************************************
3729 90 : SUBROUTINE get_fermi_level_2c(bs_env, eigenval, n_el, VBM, CBM, e_fermi)
3730 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
3731 : REAL(KIND=dp), DIMENSION(:, :, :) :: eigenval
3732 : REAL(KIND=dp) :: n_el, VBM, CBM, e_fermi
3733 :
3734 : REAL(KIND=dp), PARAMETER :: gap_smear_ratio = 20.0_dp
3735 :
3736 : REAL(KIND=dp) :: kTS
3737 90 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: f_occ
3738 :
3739 90 : IF (bs_env%do_smear .AND. .NOT. (CBM > VBM .AND. &
3740 : CBM - VBM > gap_smear_ratio*bs_env%smear_width)) THEN
3741 0 : ALLOCATE (f_occ(SIZE(eigenval, 1), SIZE(eigenval, 2), 2))
3742 : CALL Smearkp2(f_occ, e_fermi, kTS, eigenval, n_el, &
3743 : bs_env%kpoints_DOS%wkp(1:SIZE(eigenval, 2)), &
3744 0 : bs_env%smear_width, bs_env%smear_method)
3745 0 : DEALLOCATE (f_occ)
3746 : ELSE
3747 90 : e_fermi = VBM
3748 : END IF
3749 :
3750 90 : END SUBROUTINE get_fermi_level_2c
3751 : END MODULE post_scf_bandstructure_utils
|