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 Finite-volume Kubo-Greenwood transport from converged Quickstep matrices.
10 : ! **************************************************************************************************
11 : MODULE qs_kubo_transport
12 : USE bibliography, ONLY: EsteveParedes2023,&
13 : KuhneHeskeProdan2020,&
14 : cite_reference
15 : USE cell_types, ONLY: cell_type,&
16 : pbc
17 : USE cp_blacs_env, ONLY: cp_blacs_env_type
18 : USE cp_dbcsr_api, ONLY: dbcsr_get_info,&
19 : dbcsr_p_type,&
20 : dbcsr_type
21 : USE cp_dbcsr_operations, ONLY: copy_dbcsr_to_fm,&
22 : dbcsr_deallocate_matrix_set
23 : USE cp_fm_struct, ONLY: cp_fm_struct_create,&
24 : cp_fm_struct_release,&
25 : cp_fm_struct_type
26 : USE cp_fm_types, ONLY: cp_fm_create,&
27 : cp_fm_get_submatrix,&
28 : cp_fm_release,&
29 : cp_fm_type
30 : USE cp_log_handling, ONLY: cp_get_default_logger,&
31 : cp_logger_get_default_io_unit,&
32 : cp_logger_type
33 : USE ieee_arithmetic, ONLY: ieee_is_finite
34 : USE input_section_types, ONLY: section_vals_get_subs_vals,&
35 : section_vals_type,&
36 : section_vals_val_get
37 : USE kinds, ONLY: dp
38 : USE kubo_bloch, ONLY: fermi_slope
39 : USE kubo_hall, ONLY: hall_response
40 : USE kubo_projected, ONLY: projected_current
41 : USE mathconstants, ONLY: pi
42 : USE message_passing, ONLY: mp_para_env_type
43 : USE particle_types, ONLY: particle_type
44 : USE physcon, ONLY: a_bohr,&
45 : angstrom,&
46 : e_charge,&
47 : evolt,&
48 : h_bar,&
49 : kelvin
50 : USE qs_environment_types, ONLY: get_qs_env,&
51 : qs_environment_type
52 : USE qs_finite_ao, ONLY: finite_ao_positions,&
53 : finite_ao_soc
54 : USE qs_kubo_bloch, ONLY: setup_bloch_transport
55 : USE qs_mo_types, ONLY: get_mo_set,&
56 : mo_set_type
57 : USE spectral_localizer_dbcsr, ONLY: localizer_ao_operators,&
58 : localizer_dbcsr_dense,&
59 : localizer_dbcsr_release,&
60 : localizer_matrix_type
61 : USE string_utilities, ONLY: uppercase
62 : #include "./base/base_uses.f90"
63 :
64 : IMPLICIT NONE
65 :
66 : PRIVATE
67 :
68 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_kubo_transport'
69 :
70 : PUBLIC :: qs_scf_post_kubo_transport
71 :
72 : CONTAINS
73 :
74 : ! **************************************************************************************************
75 : !> \brief Share full finite AO/SOC operators with the localizer, retaining complex matrix elements.
76 : !> \param qs_env Converged finite Quickstep environment
77 : !> \param spin Scalar spin channel, one for SOC
78 : !> \param do_soc Include GTH SOC
79 : !> \param energies Complete scalar/spinor eigenvalues
80 : !> \param current Three projected commutators in the eigenbasis
81 : ! **************************************************************************************************
82 8 : SUBROUTINE setup_projected_transport(qs_env, spin, do_soc, energies, current)
83 : TYPE(qs_environment_type), POINTER :: qs_env
84 : INTEGER, INTENT(IN) :: spin
85 : LOGICAL, INTENT(IN) :: do_soc
86 : REAL(dp), INTENT(OUT) :: energies(:)
87 : COMPLEX(dp), INTENT(OUT) :: current(:, :, :)
88 :
89 16 : COMPLEX(dp), ALLOCATABLE :: component(:, :), hd(:, :), sd(:, :), &
90 : xd(:, :, :)
91 : INTEGER :: axis, n, status
92 16 : TYPE(dbcsr_p_type), POINTER :: h(:), positions(:), s(:), soc(:, :)
93 40 : TYPE(localizer_matrix_type) :: metric, operators(4)
94 : TYPE(mp_para_env_type), POINTER :: para_env
95 :
96 8 : NULLIFY (positions, soc)
97 8 : CALL get_qs_env(qs_env, matrix_ks=h, matrix_s=s, para_env=para_env)
98 8 : CALL finite_ao_positions(qs_env, positions)
99 8 : IF (do_soc) THEN
100 2 : CALL finite_ao_soc(qs_env, soc)
101 2 : CALL localizer_ao_operators(h(spin)%matrix, s(1)%matrix, positions, operators, metric, soc)
102 : ELSE
103 6 : CALL localizer_ao_operators(h(spin)%matrix, s(1)%matrix, positions, operators, metric)
104 : END IF
105 8 : CALL localizer_dbcsr_dense(operators(1), para_env, hd)
106 8 : CALL localizer_dbcsr_dense(metric, para_env, sd)
107 8 : n = SIZE(hd, 1)
108 40 : ALLOCATE (xd(n, n, 3))
109 32 : DO axis = 1, 3
110 24 : CALL localizer_dbcsr_dense(operators(axis + 1), para_env, component)
111 6216 : xd(:, :, axis) = component
112 32 : DEALLOCATE (component)
113 : END DO
114 8 : status = 0
115 8 : IF (para_env%is_source()) CALL projected_current(hd, sd, xd, energies, current, status)
116 8 : CALL para_env%bcast(status, para_env%source)
117 8 : IF (status /= 0) THEN
118 0 : CPABORT("Kubo projected AO matrices or eigensystem invalid.")
119 : END IF
120 232 : CALL para_env%bcast(energies, para_env%source)
121 12440 : CALL para_env%bcast(current, para_env%source)
122 8 : CALL dbcsr_deallocate_matrix_set(positions)
123 8 : IF (do_soc) CALL dbcsr_deallocate_matrix_set(soc)
124 40 : DO axis = 1, 4
125 40 : CALL localizer_dbcsr_release(operators(axis))
126 : END DO
127 8 : CALL localizer_dbcsr_release(metric)
128 24 : END SUBROUTINE setup_projected_transport
129 :
130 : ! **************************************************************************************************
131 : !> \brief Compute and print the finite-volume Kubo-Greenwood conductivity tensor.
132 : !> \param qs_env Quickstep environment
133 : ! **************************************************************************************************
134 14227 : SUBROUTINE qs_scf_post_kubo_transport(qs_env)
135 : TYPE(qs_environment_type), POINTER :: qs_env
136 :
137 : CHARACTER(len=*), PARAMETER :: routineN = 'qs_scf_post_kubo_transport'
138 :
139 : CHARACTER(LEN=32) :: density_unit, measure_unit, method, &
140 : periodic_label, sigma_iso_unit, &
141 : sigma_tensor_unit
142 : CHARACTER(LEN=512) :: header
143 : COMPLEX(KIND=dp), ALLOCATABLE, &
144 14227 : DIMENSION(:, :, :, :) :: dHH
145 : INTEGER :: axis, current_operator, hall_status, handle, imu, ispin, max_ao, max_memory_mb, &
146 : nao, natom, nelectron_total, neutral_grid, nk, nmu, nperiodic, nspins, nstate, &
147 : output_unit, symmetry_backend, transport_ndim
148 14227 : INTEGER, ALLOCATABLE, DIMENSION(:) :: ao_atom
149 14227 : INTEGER, DIMENSION(:), POINTER :: row_blk_sizes
150 14227 : INTEGER, POINTER :: grid(:)
151 : LOGICAL :: allow_mo_reuse, do_hall, do_kpoints, &
152 : do_soc, kubo_active, &
153 : neutral_mu_explicit, ot_active, &
154 : property_symmetry
155 14227 : LOGICAL, ALLOCATABLE, DIMENSION(:) :: reused_mos
156 14227 : REAL(dp), ALLOCATABLE :: scalar_current(:, :, :)
157 : REAL(KIND=dp) :: density_factor, dissipation, emax, emin, eps_operators, eps_symmetry, &
158 : iso_factor, measure, measure_m, mu, mu0, mu_step, ne, nh, sigma_iso, temperature, &
159 : tensor_factor
160 14227 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: maxocc
161 14227 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: eig, s_dense
162 : REAL(KIND=dp), DIMENSION(3, 3) :: hall, hall_part, projection, sigma, &
163 : sigma_out
164 14227 : REAL(KIND=dp), DIMENSION(:), POINTER :: energy_range
165 : TYPE(cell_type), POINTER :: cell
166 : TYPE(cp_blacs_env_type), POINTER :: blacs_env
167 : TYPE(cp_logger_type), POINTER :: logger
168 14227 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_ks, matrix_s
169 14227 : TYPE(dbcsr_p_type), POINTER :: images(:, :)
170 14227 : TYPE(mo_set_type), DIMENSION(:), POINTER :: mos
171 : TYPE(mp_para_env_type), POINTER :: para_env
172 14227 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
173 : TYPE(section_vals_type), POINTER :: input_section, kubo_section, ot_section
174 :
175 14227 : CALL timeset(routineN, handle)
176 :
177 14227 : NULLIFY (blacs_env, cell, energy_range, input_section, kubo_section, logger, matrix_ks, matrix_s, &
178 14227 : mos, ot_section, para_env, particle_set, row_blk_sizes)
179 :
180 14227 : CALL get_qs_env(qs_env, input=input_section)
181 14227 : kubo_section => section_vals_get_subs_vals(input_section, "PROPERTIES%KUBO_TRANSPORT")
182 14227 : CALL section_vals_val_get(kubo_section, "_SECTION_PARAMETERS_", l_val=kubo_active)
183 14227 : IF (.NOT. kubo_active) THEN
184 14197 : CALL timestop(handle)
185 14197 : RETURN
186 : END IF
187 30 : CALL cite_reference(KuhneHeskeProdan2020)
188 :
189 30 : CALL section_vals_val_get(kubo_section, "METHOD", c_val=method)
190 30 : CALL uppercase(method)
191 30 : SELECT CASE (TRIM(method))
192 : CASE ("DIAGONALIZATION")
193 : CASE ("TD", "CHEBYSHEV")
194 0 : CPABORT("KUBO_TRANSPORT METHOD "//TRIM(method)//" is reserved but not implemented yet.")
195 : CASE DEFAULT
196 30 : CPABORT("Unknown KUBO_TRANSPORT METHOD: "//TRIM(method))
197 : END SELECT
198 30 : ot_section => section_vals_get_subs_vals(input_section, "DFT%SCF%OT")
199 30 : CALL section_vals_val_get(ot_section, "_SECTION_PARAMETERS_", l_val=ot_active)
200 30 : allow_mo_reuse = .NOT. ot_active
201 :
202 30 : CALL section_vals_val_get(kubo_section, "CURRENT_OPERATOR", i_val=current_operator)
203 30 : CALL section_vals_val_get(kubo_section, "SOC", l_val=do_soc)
204 30 : CALL section_vals_val_get(kubo_section, "HALL_RESPONSE", l_val=do_hall)
205 30 : IF (do_hall .AND. current_operator == 0) THEN
206 0 : CPABORT("Kubo HALL_RESPONSE requires CURRENT_OPERATOR PROJECTED_AO or BLOCH.")
207 : END IF
208 30 : CALL section_vals_val_get(kubo_section, "SYMMETRY", l_val=property_symmetry)
209 30 : IF (property_symmetry .AND. current_operator /= 2) THEN
210 0 : CPABORT('Kubo property SYMMETRY requires BLOCH.')
211 : END IF
212 30 : CALL get_qs_env(qs_env, do_kpoints=do_kpoints, cell=cell)
213 30 : IF (do_kpoints .AND. current_operator /= 2) THEN
214 0 : CPABORT("Kubo explicit k-points require CURRENT_OPERATOR BLOCH.")
215 : END IF
216 30 : IF (do_soc .AND. current_operator == 0) THEN
217 0 : CPABORT("Kubo SOC requires CURRENT_OPERATOR PROJECTED_AO or BLOCH.")
218 : END IF
219 66 : IF (current_operator == 1 .AND. ANY(cell%perd /= 0)) THEN
220 0 : CPABORT("Kubo PROJECTED_AO requires PERIODIC NONE.")
221 : END IF
222 : CALL get_qs_env(qs_env, blacs_env=blacs_env, cell=cell, mos=mos, natom=natom, &
223 30 : nelectron_total=nelectron_total, para_env=para_env, particle_set=particle_set)
224 30 : CALL get_qs_env(qs_env, matrix_ks_kp=images)
225 30 : matrix_ks => images(:, 1)
226 30 : CALL get_qs_env(qs_env, matrix_s_kp=images)
227 30 : matrix_s => images(:, 1)
228 30 : CPASSERT(ASSOCIATED(matrix_s))
229 30 : CPASSERT(ASSOCIATED(matrix_ks))
230 30 : CPASSERT(ASSOCIATED(cell))
231 30 : CPASSERT(ASSOCIATED(particle_set))
232 :
233 30 : CALL section_vals_val_get(kubo_section, "TEMPERATURE", r_val=temperature)
234 30 : CALL section_vals_val_get(kubo_section, "DISSIPATION", r_val=dissipation)
235 30 : CALL section_vals_val_get(kubo_section, "ENERGY_RANGE", r_vals=energy_range)
236 30 : CALL section_vals_val_get(kubo_section, "NEUTRAL_MU", explicit=neutral_mu_explicit)
237 30 : IF (neutral_mu_explicit) CALL section_vals_val_get(kubo_section, "NEUTRAL_MU", r_val=mu0)
238 30 : CALL section_vals_val_get(kubo_section, "N_MU", i_val=nmu)
239 30 : CALL section_vals_val_get(kubo_section, "NEUTRAL_GRID", i_val=neutral_grid)
240 :
241 30 : IF (temperature <= 0.0_dp) CPABORT("KUBO_TRANSPORT TEMPERATURE must be positive.")
242 30 : IF (dissipation <= 0.0_dp) CPABORT("KUBO_TRANSPORT DISSIPATION must be positive.")
243 30 : IF (nmu < 1) CPABORT("KUBO_TRANSPORT N_MU must be at least one.")
244 30 : IF (neutral_grid < 10) CPABORT("KUBO_TRANSPORT NEUTRAL_GRID must be at least ten.")
245 :
246 30 : nspins = SIZE(matrix_ks)
247 30 : CALL dbcsr_get_info(matrix_s(1)%matrix, nfullrows_total=nao, row_blk_size=row_blk_sizes)
248 30 : nstate = nao
249 30 : IF (current_operator /= 0) THEN
250 20 : CALL section_vals_val_get(kubo_section, "MAX_AO", i_val=max_ao)
251 20 : IF (max_ao < 1 .OR. nao > max_ao) CPABORT("Kubo AO current exceeds MAX_AO.")
252 20 : IF (.NOT. qs_env%scf_convergence_available .OR. .NOT. qs_env%scf_converged) THEN
253 0 : CPABORT("Kubo AO current requires a converged SCF.")
254 : END IF
255 : END IF
256 30 : IF (do_soc) THEN
257 12 : IF (nspins /= 1) CPABORT("Kubo SOC requires a restricted SCF.")
258 12 : nstate = 2*nao
259 : END IF
260 30 : CALL build_ao_atom_map(row_blk_sizes, natom, ao_atom)
261 30 : IF (current_operator == 0) CALL dbcsr_to_dense(matrix_s(1)%matrix, blacs_env, para_env, s_dense)
262 : CALL setup_transport_geometry(cell, transport_ndim, nperiodic, periodic_label, projection, &
263 30 : measure, measure_unit)
264 30 : CALL transport_unit_labels(transport_ndim, density_unit, sigma_iso_unit, sigma_tensor_unit)
265 :
266 30 : IF (current_operator == 2) THEN
267 14 : CALL cite_reference(EsteveParedes2023)
268 14 : CALL section_vals_val_get(kubo_section, "MP_GRID", i_vals=grid)
269 14 : CALL section_vals_val_get(kubo_section, "MAX_MEMORY_MB", i_val=max_memory_mb)
270 14 : CALL section_vals_val_get(kubo_section, "SYMMETRY_BACKEND", i_val=symmetry_backend)
271 14 : CALL section_vals_val_get(kubo_section, "EPS_SYMMETRY", r_val=eps_symmetry)
272 14 : CALL section_vals_val_get(kubo_section, "EPS_SYMMETRY_OPERATORS", r_val=eps_operators)
273 14 : IF (.NOT. ieee_is_finite(eps_symmetry) .OR. eps_symmetry <= 0.0_dp .OR. eps_symmetry >= 1.0_dp) THEN
274 0 : CPABORT('Invalid Kubo EPS_SYMMETRY.')
275 : END IF
276 14 : IF (.NOT. ieee_is_finite(eps_operators) .OR. eps_operators <= 0.0_dp .OR. eps_operators >= 1.0_dp) THEN
277 0 : CPABORT('Invalid Kubo EPS_SYMMETRY_OPERATORS.')
278 : END IF
279 56 : IF (COUNT(cell%perd /= 0) == 0) CPABORT("Kubo BLOCH requires a periodic cell.")
280 98 : IF (ANY(grid < 1) .OR. ANY(grid /= 1 .AND. cell%perd == 0)) CPABORT("Invalid Kubo MP_GRID.")
281 : nk = 1
282 56 : DO axis = 1, 3
283 42 : IF (grid(axis) > 1000000/nk) CPABORT("Kubo MP_GRID exceeds one million points.")
284 56 : nk = nk*grid(axis)
285 : END DO
286 : CALL setup_bloch_transport(qs_env, grid, do_soc, projection, max_memory_mb, eig, dHH, maxocc, &
287 14 : property_symmetry, symmetry_backend, eps_symmetry, eps_operators)
288 56 : ALLOCATE (reused_mos(SIZE(eig, 2)), SOURCE=.FALSE.)
289 : ELSE
290 208 : ALLOCATE (eig(nstate, nspins), dHH(nstate, nstate, 3, nspins), maxocc(nspins), reused_mos(nspins))
291 34 : DO ispin = 1, nspins
292 18 : maxocc(ispin) = mos(ispin)%maxocc
293 18 : IF (do_soc) maxocc(ispin) = 1.0_dp
294 34 : IF (current_operator == 1) THEN
295 8 : CALL setup_projected_transport(qs_env, ispin, do_soc, eig(:, ispin), dHH(:, :, :, ispin))
296 8 : reused_mos(ispin) = .FALSE.
297 : ELSE
298 50 : ALLOCATE (scalar_current(nao, nao, 3))
299 : CALL setup_spin_transport(matrix_ks(ispin)%matrix, s_dense, blacs_env, para_env, &
300 : particle_set, cell, projection, ao_atom, mos(ispin), allow_mo_reuse, &
301 10 : eig(:, ispin), scalar_current, reused_mos(ispin))
302 3340 : dHH(:, :, :, ispin) = CMPLX(scalar_current, 0.0_dp, dp)
303 10 : DEALLOCATE (scalar_current)
304 : END IF
305 : END DO
306 : END IF
307 :
308 3214 : emin = MINVAL(eig)
309 3214 : emax = MAXVAL(eig)
310 30 : IF (.NOT. neutral_mu_explicit) THEN
311 : CALL find_neutral_mu(eig, maxocc, temperature, REAL(nelectron_total, KIND=dp), neutral_grid, &
312 0 : emin, emax, mu0)
313 : END IF
314 :
315 30 : IF (energy_range(1) < energy_range(2)) THEN
316 30 : emin = energy_range(1)
317 30 : emax = energy_range(2)
318 : END IF
319 :
320 30 : measure_m = measure*a_bohr**transport_ndim
321 30 : density_factor = 1.0_dp/measure_m
322 30 : CALL transport_output_factors(transport_ndim, iso_factor, tensor_factor)
323 :
324 30 : logger => cp_get_default_logger()
325 30 : output_unit = cp_logger_get_default_io_unit(logger)
326 :
327 30 : IF (output_unit > 0) THEN
328 15 : WRITE (output_unit, '(/,T2,A)') "Kubo-Greenwood finite-volume transport"
329 15 : WRITE (output_unit, '(T3,A,T38,A)') "Method:", TRIM(method)
330 15 : IF (current_operator == 1) THEN
331 3 : WRITE (output_unit, '(T3,A)') "Current: metric-aware projected AO commutator, not continuum velocity."
332 3 : WRITE (output_unit, '(T3,A,L1)') "GTH SOC in the complete AO spinor space: ", do_soc
333 12 : ELSE IF (current_operator == 2) THEN
334 7 : WRITE (output_unit, '(T3,A)') "Current: Bloch H/S derivatives and analytic AO connection."
335 28 : WRITE (output_unit, '(T3,A,3I6)') "Full property mesh: ", grid
336 7 : WRITE (output_unit, '(T3,A,L1)') "GTH SOC in the complete AO spinor space: ", do_soc
337 : END IF
338 15 : IF (current_operator /= 0) THEN
339 10 : IF (do_hall) THEN
340 6 : WRITE (output_unit, '(T3,A)') "Dissipative and antisymmetric DC charge response; scalar relaxation rate."
341 6 : WRITE (output_unit, '(T3,A)') "Tensor convention: first index current, second index electric field."
342 : ELSE
343 4 : WRITE (output_unit, '(T3,A)') "Dissipative symmetric conductivity only; no Hall response."
344 : END IF
345 : END IF
346 15 : WRITE (output_unit, '(T3,A,T38,A)') "Cell periodicity:", TRIM(periodic_label)
347 15 : IF (nperiodic == 0) THEN
348 6 : WRITE (output_unit, '(T3,A,T38,A)') "Transport normalization:", "3D finite box"
349 : ELSE
350 9 : WRITE (output_unit, '(T3,A,T38,I12)') "Transport dimensionality:", transport_ndim
351 : END IF
352 16 : IF (ALL(reused_mos)) THEN
353 1 : WRITE (output_unit, '(T3,A,T38,A)') "Eigensystem source:", "CP2K canonical MOs"
354 69 : ELSE IF (ANY(reused_mos)) THEN
355 0 : WRITE (output_unit, '(T3,A,T38,A)') "Eigensystem source:", "mixed canonical/internal"
356 : ELSE
357 14 : WRITE (output_unit, '(T3,A,T38,A)') "Eigensystem source:", "internal diagonalization"
358 : END IF
359 15 : WRITE (output_unit, '(T3,A,T38,I12)') "Number of atoms:", natom
360 15 : WRITE (output_unit, '(T3,A,T38,I12)') "Number of AO functions:", nao
361 15 : WRITE (output_unit, '(T3,A,T38,F12.4)') "Temperature [K]:", temperature*kelvin
362 15 : WRITE (output_unit, '(T3,A,T38,F12.4)') "Dissipation [K]:", dissipation*kelvin
363 15 : WRITE (output_unit, '(T3,A,T38,F12.6)') "Dissipation [eV]:", dissipation*evolt
364 15 : WRITE (output_unit, '(T3,A,T38,F12.6)') "Neutral chemical potential [eV]:", mu0*evolt
365 15 : WRITE (output_unit, '(T3,A,T38,ES12.4,1X,A)') "Transport measure:", &
366 30 : measure*angstrom**transport_ndim, TRIM(measure_unit)
367 : header = "mu[Ha] mu-mu0[eV] Ne["//TRIM(density_unit)//"] "// &
368 : "Nh["//TRIM(density_unit)//"] sigma_iso["//TRIM(sigma_iso_unit)//"] "// &
369 : "sigma_xx["//TRIM(sigma_tensor_unit)//"] sigma_xy["// &
370 : TRIM(sigma_tensor_unit)//"] sigma_xz["//TRIM(sigma_tensor_unit)// &
371 : "] sigma_yx["//TRIM(sigma_tensor_unit)//"] sigma_yy["// &
372 : TRIM(sigma_tensor_unit)//"] sigma_yz["//TRIM(sigma_tensor_unit)// &
373 : "] sigma_zx["//TRIM(sigma_tensor_unit)//"] sigma_zy["// &
374 15 : TRIM(sigma_tensor_unit)//"] sigma_zz["//TRIM(sigma_tensor_unit)//"]"
375 15 : WRITE (output_unit, '(/,T3,A)') TRIM(header)
376 : END IF
377 :
378 30 : IF (nmu == 1) THEN
379 : mu_step = 0.0_dp
380 : ELSE
381 0 : mu_step = (emax - emin)/REAL(nmu - 1, KIND=dp)
382 : END IF
383 :
384 60 : DO imu = 1, nmu
385 30 : mu = emin + REAL(imu - 1, KIND=dp)*mu_step
386 30 : CALL electron_hole_density(eig, maxocc, mu, mu0, temperature, ne, nh)
387 : CALL conductivity_at_mu(eig, dHH, maxocc, mu, temperature, dissipation, measure, &
388 44 : transport_ndim, sigma, current_operator == 2 .OR. do_hall)
389 30 : IF (do_hall) THEN
390 12 : hall = 0.0_dp
391 76 : DO ispin = 1, SIZE(eig, 2)
392 : CALL hall_response(eig(:, ispin), dHH(:, :, :, ispin), mu, temperature, dissipation, &
393 64 : hall_part, hall_status)
394 64 : IF (hall_status /= 0) THEN
395 0 : CPABORT("Invalid Kubo Hall current, spectrum, or relaxation parameters.")
396 : END IF
397 844 : hall = hall + maxocc(ispin)*hall_part
398 : END DO
399 156 : hall = (e_charge**2/h_bar)*hall*angstrom**(2 - transport_ndim)/measure
400 156 : sigma = sigma + hall
401 : END IF
402 90 : IF (output_unit > 0) THEN
403 : sigma_iso = (sigma(1, 1) + sigma(2, 2) + sigma(3, 3))/ &
404 15 : REAL(transport_ndim, KIND=dp)*iso_factor
405 195 : sigma_out(:, :) = sigma(:, :)*tensor_factor
406 15 : WRITE (output_unit, '(T3,F12.6,F14.6,2ES16.7,10ES17.8)') mu, (mu - mu0)*evolt, &
407 15 : ne*density_factor, nh*density_factor, &
408 15 : sigma_iso, &
409 15 : sigma_out(1, 1), sigma_out(1, 2), sigma_out(1, 3), &
410 15 : sigma_out(2, 1), sigma_out(2, 2), sigma_out(2, 3), &
411 30 : sigma_out(3, 1), sigma_out(3, 2), sigma_out(3, 3)
412 2 : SELECT CASE (transport_ndim)
413 : CASE (1)
414 2 : WRITE (output_unit, '(T3,A,1X,ES17.8)') "KUBO_TRANSPORT| sigma_iso[S*m]", sigma_iso
415 : CASE (2)
416 3 : WRITE (output_unit, '(T3,A,1X,ES17.8)') "KUBO_TRANSPORT| sigma_iso[S]", sigma_iso
417 : CASE DEFAULT
418 15 : WRITE (output_unit, '(T3,A,1X,ES17.8)') "KUBO_TRANSPORT| sigma_iso[S/cm]", sigma_iso
419 : END SELECT
420 15 : IF (do_hall) THEN
421 6 : WRITE (output_unit, '(T3,A,1X,A,3ES17.8)') "KUBO_TRANSPORT| hall_xy_yz_zx", &
422 6 : "["//TRIM(sigma_tensor_unit)//"]", &
423 12 : tensor_factor*hall(1, 2), tensor_factor*hall(2, 3), tensor_factor*hall(3, 1)
424 6 : WRITE (output_unit, '(T3,A,1X,ES17.8)') "KUBO_TRANSPORT| hall_max", &
425 84 : tensor_factor*MAXVAL(ABS(hall))
426 : END IF
427 : END IF
428 : END DO
429 :
430 30 : DEALLOCATE (ao_atom, dHH, eig, maxocc, reused_mos)
431 30 : IF (ALLOCATED(s_dense)) DEALLOCATE (s_dense)
432 :
433 30 : CALL timestop(handle)
434 :
435 28454 : END SUBROUTINE qs_scf_post_kubo_transport
436 :
437 : ! **************************************************************************************************
438 : !> \brief Build a global AO -> atom map from DBCSR atomic block sizes.
439 : !> \param row_blk_sizes ...
440 : !> \param natom ...
441 : !> \param ao_atom ...
442 : ! **************************************************************************************************
443 30 : SUBROUTINE build_ao_atom_map(row_blk_sizes, natom, ao_atom)
444 : INTEGER, DIMENSION(:), INTENT(IN) :: row_blk_sizes
445 : INTEGER, INTENT(IN) :: natom
446 : INTEGER, ALLOCATABLE, DIMENSION(:), INTENT(OUT) :: ao_atom
447 :
448 : INTEGER :: iao, iatom, nao, u
449 :
450 78 : nao = SUM(row_blk_sizes(1:natom))
451 90 : ALLOCATE (ao_atom(nao))
452 30 : iao = 0
453 78 : DO iatom = 1, natom
454 478 : DO u = 1, row_blk_sizes(iatom)
455 400 : iao = iao + 1
456 448 : ao_atom(iao) = iatom
457 : END DO
458 : END DO
459 :
460 30 : END SUBROUTINE build_ao_atom_map
461 :
462 : ! **************************************************************************************************
463 : !> \brief Copy a DBCSR matrix to a replicated dense matrix.
464 : !> \param matrix ...
465 : !> \param blacs_env ...
466 : !> \param para_env ...
467 : !> \param dense ...
468 : ! **************************************************************************************************
469 20 : SUBROUTINE dbcsr_to_dense(matrix, blacs_env, para_env, dense)
470 : TYPE(dbcsr_type), INTENT(IN) :: matrix
471 : TYPE(cp_blacs_env_type), POINTER :: blacs_env
472 : TYPE(mp_para_env_type), POINTER :: para_env
473 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :), &
474 : INTENT(OUT) :: dense
475 :
476 : INTEGER :: ncol, nrow
477 : TYPE(cp_fm_struct_type), POINTER :: fm_struct
478 : TYPE(cp_fm_type) :: fm
479 :
480 20 : NULLIFY (fm_struct)
481 :
482 20 : CALL dbcsr_get_info(matrix, nfullrows_total=nrow, nfullcols_total=ncol)
483 80 : ALLOCATE (dense(nrow, ncol))
484 : CALL cp_fm_struct_create(fm_struct, context=blacs_env, para_env=para_env, &
485 20 : nrow_global=nrow, ncol_global=ncol)
486 20 : CALL cp_fm_create(fm, fm_struct)
487 20 : CALL copy_dbcsr_to_fm(matrix, fm)
488 20 : CALL cp_fm_get_submatrix(fm, dense, n_rows=nrow, n_cols=ncol)
489 20 : CALL cp_fm_release(fm)
490 20 : CALL cp_fm_struct_release(fm_struct)
491 :
492 40 : END SUBROUTINE dbcsr_to_dense
493 :
494 : ! **************************************************************************************************
495 : !> \brief Set up the periodic transport subspace and its normalization measure.
496 : !> \param cell ...
497 : !> \param transport_ndim ...
498 : !> \param nperiodic ...
499 : !> \param periodic_label ...
500 : !> \param projection ...
501 : !> \param measure ...
502 : !> \param measure_unit ...
503 : ! **************************************************************************************************
504 30 : SUBROUTINE setup_transport_geometry(cell, transport_ndim, nperiodic, periodic_label, projection, &
505 : measure, measure_unit)
506 : TYPE(cell_type), POINTER :: cell
507 : INTEGER, INTENT(OUT) :: transport_ndim, nperiodic
508 : CHARACTER(LEN=*), INTENT(OUT) :: periodic_label
509 : REAL(KIND=dp), DIMENSION(3, 3), INTENT(OUT) :: projection
510 : REAL(KIND=dp), INTENT(OUT) :: measure
511 : CHARACTER(LEN=*), INTENT(OUT) :: measure_unit
512 :
513 : INTEGER :: idir, jdir, kdir
514 : REAL(KIND=dp) :: detg, invg11, invg12, invg22, norm2
515 : REAL(KIND=dp), DIMENSION(3) :: v1, v2
516 : REAL(KIND=dp), DIMENSION(3, 2) :: basis2
517 :
518 0 : CPASSERT(ASSOCIATED(cell))
519 :
520 120 : nperiodic = COUNT(cell%perd(1:3) == 1)
521 30 : CALL transport_periodicity_label(cell%perd, periodic_label)
522 30 : projection = 0.0_dp
523 :
524 42 : SELECT CASE (nperiodic)
525 : CASE (0)
526 12 : transport_ndim = 3
527 12 : measure = cell%deth
528 48 : DO idir = 1, 3
529 48 : projection(idir, idir) = 1.0_dp
530 : END DO
531 12 : measure_unit = "Angstrom^3"
532 : CASE (1)
533 4 : transport_ndim = 1
534 4 : kdir = 0
535 16 : DO idir = 1, 3
536 16 : IF (cell%perd(idir) == 1) kdir = idir
537 : END DO
538 16 : v1(:) = cell%hmat(:, kdir)
539 16 : norm2 = DOT_PRODUCT(v1, v1)
540 4 : IF (norm2 <= 0.0_dp) CPABORT("KUBO_TRANSPORT periodic cell vector has zero length.")
541 4 : measure = SQRT(norm2)
542 16 : DO jdir = 1, 3
543 52 : DO idir = 1, 3
544 48 : projection(idir, jdir) = v1(idir)*v1(jdir)/norm2
545 : END DO
546 : END DO
547 4 : measure_unit = "Angstrom"
548 : CASE (2)
549 6 : transport_ndim = 2
550 6 : kdir = 0
551 24 : DO idir = 1, 3
552 24 : IF (cell%perd(idir) == 1) THEN
553 12 : kdir = kdir + 1
554 48 : basis2(:, kdir) = cell%hmat(:, idir)
555 : END IF
556 : END DO
557 24 : v1(:) = basis2(:, 1)
558 24 : v2(:) = basis2(:, 2)
559 24 : norm2 = DOT_PRODUCT(v1, v1)
560 24 : invg22 = DOT_PRODUCT(v2, v2)
561 24 : invg12 = DOT_PRODUCT(v1, v2)
562 6 : detg = norm2*invg22 - invg12*invg12
563 6 : IF (detg <= 0.0_dp) CPABORT("KUBO_TRANSPORT periodic cell vectors are linearly dependent.")
564 6 : measure = SQRT(detg)
565 6 : invg11 = invg22/detg
566 6 : invg22 = norm2/detg
567 6 : invg12 = -invg12/detg
568 24 : DO jdir = 1, 3
569 78 : DO idir = 1, 3
570 : projection(idir, jdir) = basis2(idir, 1)*invg11*basis2(jdir, 1) + &
571 : basis2(idir, 1)*invg12*basis2(jdir, 2) + &
572 : basis2(idir, 2)*invg12*basis2(jdir, 1) + &
573 72 : basis2(idir, 2)*invg22*basis2(jdir, 2)
574 : END DO
575 : END DO
576 6 : measure_unit = "Angstrom^2"
577 : CASE DEFAULT
578 8 : transport_ndim = 3
579 8 : measure = cell%deth
580 32 : DO idir = 1, 3
581 32 : projection(idir, idir) = 1.0_dp
582 : END DO
583 38 : measure_unit = "Angstrom^3"
584 : END SELECT
585 :
586 30 : IF (measure <= 0.0_dp) CPABORT("KUBO_TRANSPORT transport normalization measure is not positive.")
587 :
588 30 : END SUBROUTINE setup_transport_geometry
589 :
590 : ! **************************************************************************************************
591 : !> \brief Human-readable periodicity label.
592 : !> \param perd ...
593 : !> \param label ...
594 : ! **************************************************************************************************
595 30 : SUBROUTINE transport_periodicity_label(perd, label)
596 : INTEGER, DIMENSION(3), INTENT(IN) :: perd
597 : CHARACTER(LEN=*), INTENT(OUT) :: label
598 :
599 30 : label = ""
600 30 : IF (perd(1) == 1) label = TRIM(label)//"X"
601 30 : IF (perd(2) == 1) label = TRIM(label)//"Y"
602 30 : IF (perd(3) == 1) label = TRIM(label)//"Z"
603 30 : IF (LEN_TRIM(label) == 0) label = "NONE"
604 :
605 30 : END SUBROUTINE transport_periodicity_label
606 :
607 : ! **************************************************************************************************
608 : !> \brief Output unit labels for a transport dimensionality.
609 : !> \param transport_ndim ...
610 : !> \param density_unit ...
611 : !> \param sigma_iso_unit ...
612 : !> \param sigma_tensor_unit ...
613 : ! **************************************************************************************************
614 30 : SUBROUTINE transport_unit_labels(transport_ndim, density_unit, sigma_iso_unit, sigma_tensor_unit)
615 : INTEGER, INTENT(IN) :: transport_ndim
616 : CHARACTER(LEN=*), INTENT(OUT) :: density_unit, sigma_iso_unit, &
617 : sigma_tensor_unit
618 :
619 34 : SELECT CASE (transport_ndim)
620 : CASE (1)
621 4 : density_unit = "m^-1"
622 4 : sigma_iso_unit = "S*m"
623 4 : sigma_tensor_unit = "S*m"
624 : CASE (2)
625 6 : density_unit = "m^-2"
626 6 : sigma_iso_unit = "S"
627 6 : sigma_tensor_unit = "S"
628 : CASE DEFAULT
629 20 : density_unit = "m^-3"
630 20 : sigma_iso_unit = "S/cm"
631 20 : sigma_tensor_unit = "S/m"
632 : END SELECT
633 :
634 30 : END SUBROUTINE transport_unit_labels
635 :
636 : ! **************************************************************************************************
637 : !> \brief Output conversion factors from internal dimensional transport units.
638 : !> \param transport_ndim ...
639 : !> \param iso_factor ...
640 : !> \param tensor_factor ...
641 : ! **************************************************************************************************
642 30 : SUBROUTINE transport_output_factors(transport_ndim, iso_factor, tensor_factor)
643 : INTEGER, INTENT(IN) :: transport_ndim
644 : REAL(KIND=dp), INTENT(OUT) :: iso_factor, tensor_factor
645 :
646 34 : SELECT CASE (transport_ndim)
647 : CASE (1)
648 4 : iso_factor = 1.0E-10_dp
649 4 : tensor_factor = 1.0E-10_dp
650 : CASE (2)
651 6 : iso_factor = 1.0_dp
652 6 : tensor_factor = 1.0_dp
653 : CASE DEFAULT
654 20 : iso_factor = 1.0E8_dp
655 30 : tensor_factor = 1.0E10_dp
656 : END SELECT
657 :
658 30 : END SUBROUTINE transport_output_factors
659 :
660 : ! **************************************************************************************************
661 : !> \brief Prepare eigenvalues and the transformed [X,H] matrices for one spin channel.
662 : !> \param ks_matrix ...
663 : !> \param s_dense ...
664 : !> \param blacs_env ...
665 : !> \param para_env ...
666 : !> \param particle_set ...
667 : !> \param cell ...
668 : !> \param projection ...
669 : !> \param ao_atom ...
670 : !> \param mo_set ...
671 : !> \param allow_mo_reuse ...
672 : !> \param eig ...
673 : !> \param dHH ...
674 : !> \param reused_mos ...
675 : ! **************************************************************************************************
676 10 : SUBROUTINE setup_spin_transport(ks_matrix, s_dense, blacs_env, para_env, particle_set, cell, &
677 10 : projection, ao_atom, mo_set, allow_mo_reuse, eig, dHH, reused_mos)
678 : TYPE(dbcsr_type), INTENT(IN) :: ks_matrix
679 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: s_dense
680 : TYPE(cp_blacs_env_type), POINTER :: blacs_env
681 : TYPE(mp_para_env_type), POINTER :: para_env
682 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
683 : TYPE(cell_type), POINTER :: cell
684 : REAL(KIND=dp), DIMENSION(3, 3), INTENT(IN) :: projection
685 : INTEGER, DIMENSION(:), INTENT(IN) :: ao_atom
686 : TYPE(mo_set_type), INTENT(IN) :: mo_set
687 : LOGICAL, INTENT(IN) :: allow_mo_reuse
688 : REAL(KIND=dp), DIMENSION(:), INTENT(OUT) :: eig
689 : REAL(KIND=dp), DIMENSION(:, :, :), INTENT(OUT) :: dHH
690 : LOGICAL, INTENT(OUT) :: reused_mos
691 :
692 : INTEGER :: idir, mo_nao, nao, nmo
693 10 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: coeff_dense, gmat, h_dense, horth, op, &
694 10 : op_orth, uvec, work
695 10 : REAL(KIND=dp), DIMENSION(:), POINTER :: mo_eigenvalues
696 : TYPE(cp_fm_type), POINTER :: mo_coeff
697 :
698 10 : NULLIFY (mo_coeff, mo_eigenvalues)
699 10 : nao = SIZE(s_dense, 1)
700 10 : reused_mos = .FALSE.
701 :
702 10 : CALL dbcsr_to_dense(ks_matrix, blacs_env, para_env, h_dense)
703 60 : ALLOCATE (op(nao, nao), work(nao, nao))
704 :
705 10 : IF (allow_mo_reuse) THEN
706 : CALL get_mo_set(mo_set=mo_set, nao=mo_nao, nmo=nmo, eigenvalues=mo_eigenvalues, &
707 2 : mo_coeff=mo_coeff)
708 : reused_mos = mo_nao == nao .AND. nmo >= nao .AND. ASSOCIATED(mo_eigenvalues) .AND. &
709 2 : ASSOCIATED(mo_coeff)
710 2 : IF (reused_mos) reused_mos = SIZE(mo_eigenvalues) >= nao
711 : END IF
712 :
713 10 : IF (reused_mos) THEN
714 6 : ALLOCATE (coeff_dense(nao, nao))
715 22 : eig(:) = mo_eigenvalues(1:nao)
716 2 : CALL cp_fm_get_submatrix(mo_coeff, coeff_dense, n_rows=nao, n_cols=nao)
717 8 : DO idir = 1, 3
718 6 : CALL build_commutator_kernel(h_dense, particle_set, cell, projection, ao_atom, idir, op)
719 8 : CALL transform_to_eigenbasis(op, coeff_dense, dHH(:, :, idir), work)
720 : END DO
721 2 : DEALLOCATE (coeff_dense)
722 : ELSE
723 72 : ALLOCATE (gmat(nao, nao), horth(nao, nao), op_orth(nao, nao), uvec(nao, nao))
724 8 : CALL inverse_sqrt_symmetric(s_dense, gmat)
725 :
726 16888 : work(:, :) = MATMUL(h_dense, gmat)
727 8888 : horth(:, :) = MATMUL(gmat, work)
728 8 : CALL symmetrize(horth)
729 :
730 888 : uvec(:, :) = horth
731 8 : CALL diagonalize_symmetric(uvec, eig)
732 :
733 32 : DO idir = 1, 3
734 24 : CALL build_commutator_kernel(h_dense, particle_set, cell, projection, ao_atom, idir, op)
735 26664 : work(:, :) = MATMUL(op, gmat)
736 26664 : op_orth(:, :) = MATMUL(gmat, work)
737 32 : CALL transform_to_eigenbasis(op_orth, uvec, dHH(:, :, idir), work)
738 : END DO
739 8 : DEALLOCATE (gmat, horth, op_orth, uvec)
740 : END IF
741 :
742 10 : DEALLOCATE (h_dense, op, work)
743 :
744 20 : END SUBROUTINE setup_spin_transport
745 :
746 : ! **************************************************************************************************
747 : !> \brief Symmetric inverse square root via dense diagonalization.
748 : !> \param matrix ...
749 : !> \param inverse_sqrt ...
750 : ! **************************************************************************************************
751 8 : SUBROUTINE inverse_sqrt_symmetric(matrix, inverse_sqrt)
752 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: matrix
753 : REAL(KIND=dp), DIMENSION(:, :), INTENT(OUT) :: inverse_sqrt
754 :
755 : INTEGER :: i, info, lwork, n
756 8 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: eig, work
757 8 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: scaled, vectors
758 :
759 8 : n = SIZE(matrix, 1)
760 8 : lwork = MAX(1, 8*n)
761 80 : ALLOCATE (eig(n), scaled(n, n), vectors(n, n), work(lwork))
762 :
763 888 : vectors(:, :) = matrix
764 8 : CALL dsyev("V", "L", n, vectors, n, eig, work, lwork, info)
765 8 : IF (info /= 0) CPABORT("Diagonalization of the overlap matrix failed.")
766 88 : IF (MINVAL(eig) <= 0.0_dp) CPABORT("Overlap matrix is not positive definite.")
767 :
768 888 : scaled(:, :) = vectors
769 88 : DO i = 1, n
770 888 : scaled(:, i) = scaled(:, i)/SQRT(eig(i))
771 : END DO
772 8 : CALL dgemm("N", "T", n, n, n, 1.0_dp, scaled, n, vectors, n, 0.0_dp, inverse_sqrt, n)
773 :
774 8 : DEALLOCATE (eig, scaled, vectors, work)
775 :
776 8 : END SUBROUTINE inverse_sqrt_symmetric
777 :
778 : ! **************************************************************************************************
779 : !> \brief Dense symmetric diagonalization.
780 : !> \param matrix ...
781 : !> \param eig ...
782 : ! **************************************************************************************************
783 8 : SUBROUTINE diagonalize_symmetric(matrix, eig)
784 : REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT) :: matrix
785 : REAL(KIND=dp), DIMENSION(:), INTENT(OUT) :: eig
786 :
787 : INTEGER :: info, lwork, n
788 8 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: work
789 :
790 8 : n = SIZE(matrix, 1)
791 8 : lwork = MAX(1, 8*n)
792 24 : ALLOCATE (work(lwork))
793 8 : CALL dsyev("V", "L", n, matrix, n, eig, work, lwork, info)
794 8 : IF (info /= 0) CPABORT("Diagonalization of the orthogonalized KS matrix failed.")
795 8 : DEALLOCATE (work)
796 :
797 8 : END SUBROUTINE diagonalize_symmetric
798 :
799 : ! **************************************************************************************************
800 : !> \brief Enforce exact symmetry after dense products.
801 : !> \param matrix ...
802 : ! **************************************************************************************************
803 8 : SUBROUTINE symmetrize(matrix)
804 : REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT) :: matrix
805 :
806 : INTEGER :: i, j, n
807 : REAL(KIND=dp) :: value
808 :
809 8 : n = SIZE(matrix, 1)
810 88 : DO j = 1, n
811 448 : DO i = j + 1, n
812 360 : value = 0.5_dp*(matrix(i, j) + matrix(j, i))
813 360 : matrix(i, j) = value
814 440 : matrix(j, i) = value
815 : END DO
816 : END DO
817 :
818 8 : END SUBROUTINE symmetrize
819 :
820 : ! **************************************************************************************************
821 : !> \brief Build element-wise kernel (P*(r_col-r_row))_idir * matrix(row,col).
822 : !> \param matrix ...
823 : !> \param particle_set ...
824 : !> \param cell ...
825 : !> \param projection ...
826 : !> \param ao_atom ...
827 : !> \param idir ...
828 : !> \param op ...
829 : ! **************************************************************************************************
830 30 : SUBROUTINE build_commutator_kernel(matrix, particle_set, cell, projection, ao_atom, idir, op)
831 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: matrix
832 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
833 : TYPE(cell_type), POINTER :: cell
834 : REAL(KIND=dp), DIMENSION(3, 3), INTENT(IN) :: projection
835 : INTEGER, DIMENSION(:), INTENT(IN) :: ao_atom
836 : INTEGER, INTENT(IN) :: idir
837 : REAL(KIND=dp), DIMENSION(:, :), INTENT(OUT) :: op
838 :
839 : INTEGER :: i, j, n
840 : REAL(KIND=dp), DIMENSION(3) :: dr, projected_dr
841 :
842 30 : n = SIZE(matrix, 1)
843 330 : DO j = 1, n
844 3330 : DO i = 1, n
845 12000 : dr(:) = pbc(particle_set(ao_atom(j))%r(:) - particle_set(ao_atom(i))%r(:), cell)
846 39000 : projected_dr(:) = MATMUL(projection, dr)
847 3300 : op(i, j) = projected_dr(idir)*matrix(i, j)
848 : END DO
849 : END DO
850 :
851 30 : END SUBROUTINE build_commutator_kernel
852 :
853 : ! **************************************************************************************************
854 : !> \brief Transform an AO matrix to the eigenvector basis.
855 : !> \param op ...
856 : !> \param uvec ...
857 : !> \param transformed ...
858 : !> \param work ...
859 : ! **************************************************************************************************
860 30 : SUBROUTINE transform_to_eigenbasis(op, uvec, transformed, work)
861 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: op, uvec
862 : REAL(KIND=dp), DIMENSION(:, :), INTENT(OUT) :: transformed
863 : REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT) :: work
864 :
865 : INTEGER :: n
866 :
867 30 : n = SIZE(op, 1)
868 30 : CALL dgemm("N", "N", n, n, n, 1.0_dp, op, n, uvec, n, 0.0_dp, work, n)
869 30 : CALL dgemm("T", "N", n, n, n, 1.0_dp, uvec, n, work, n, 0.0_dp, transformed, n)
870 :
871 30 : END SUBROUTINE transform_to_eigenbasis
872 :
873 : ! **************************************************************************************************
874 : !> \brief Fermi occupation with overflow protection.
875 : !> \param eig ...
876 : !> \param mu ...
877 : !> \param kT ...
878 : !> \param maxocc ...
879 : !> \return ...
880 : ! **************************************************************************************************
881 6144 : PURE FUNCTION fermi_occ(eig, mu, kT, maxocc) RESULT(occ)
882 : REAL(KIND=dp), INTENT(IN) :: eig, mu, kT, maxocc
883 : REAL(KIND=dp) :: occ
884 :
885 : REAL(KIND=dp) :: x
886 :
887 6144 : x = (eig - mu)/kT
888 6144 : IF (x > 80.0_dp) THEN
889 : occ = 0.0_dp
890 1824 : ELSE IF (x < -80.0_dp) THEN
891 1036 : occ = maxocc
892 : ELSE
893 788 : occ = maxocc/(1.0_dp + EXP(x))
894 : END IF
895 :
896 6144 : END FUNCTION fermi_occ
897 :
898 : ! **************************************************************************************************
899 : !> \brief Fermi vacancy below the neutral point.
900 : !> \param eig ...
901 : !> \param mu ...
902 : !> \param kT ...
903 : !> \param maxocc ...
904 : !> \return ...
905 : ! **************************************************************************************************
906 912 : PURE FUNCTION fermi_hole(eig, mu, kT, maxocc) RESULT(hole)
907 : REAL(KIND=dp), INTENT(IN) :: eig, mu, kT, maxocc
908 : REAL(KIND=dp) :: hole
909 :
910 912 : hole = maxocc - fermi_occ(eig, mu, kT, maxocc)
911 :
912 912 : END FUNCTION fermi_hole
913 :
914 : ! **************************************************************************************************
915 : !> \brief Total electron count at a chemical potential.
916 : !> \param eig ...
917 : !> \param maxocc ...
918 : !> \param mu ...
919 : !> \param kT ...
920 : !> \return ...
921 : ! **************************************************************************************************
922 0 : PURE FUNCTION electron_count(eig, maxocc, mu, kT) RESULT(count)
923 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: eig
924 : REAL(KIND=dp), DIMENSION(:), INTENT(IN) :: maxocc
925 : REAL(KIND=dp), INTENT(IN) :: mu, kT
926 : REAL(KIND=dp) :: count
927 :
928 : INTEGER :: ispin, n
929 :
930 0 : count = 0.0_dp
931 0 : DO ispin = 1, SIZE(eig, 2)
932 0 : DO n = 1, SIZE(eig, 1)
933 0 : count = count + fermi_occ(eig(n, ispin), mu, kT, maxocc(ispin))
934 : END DO
935 : END DO
936 :
937 0 : END FUNCTION electron_count
938 :
939 : ! **************************************************************************************************
940 : !> \brief Determine the neutral chemical potential using the legacy two-step definition.
941 : !> \param eig ...
942 : !> \param maxocc ...
943 : !> \param kT ...
944 : !> \param neutral_electrons ...
945 : !> \param neutral_grid ...
946 : !> \param emin ...
947 : !> \param emax ...
948 : !> \param mu0 ...
949 : ! **************************************************************************************************
950 0 : SUBROUTINE find_neutral_mu(eig, maxocc, kT, neutral_electrons, neutral_grid, emin, emax, mu0)
951 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: eig
952 : REAL(KIND=dp), DIMENSION(:), INTENT(IN) :: maxocc
953 : REAL(KIND=dp), INTENT(IN) :: kT, neutral_electrons
954 : INTEGER, INTENT(IN) :: neutral_grid
955 : REAL(KIND=dp), INTENT(IN) :: emin, emax
956 : REAL(KIND=dp), INTENT(OUT) :: mu0
957 :
958 : INTEGER :: i
959 : REAL(KIND=dp) :: best, count, mu, mup, ne, nh, &
960 : previous_count
961 :
962 0 : mup = 0.5_dp*(emin + emax)
963 0 : previous_count = electron_count(eig, maxocc, emin, kT)
964 0 : DO i = 1, neutral_grid
965 0 : mu = emin + (emax - emin)*REAL(i, KIND=dp)/REAL(neutral_grid, KIND=dp)
966 0 : count = electron_count(eig, maxocc, mu, kT)
967 0 : IF ((count - neutral_electrons)*(previous_count - neutral_electrons) <= 0.0_dp) mup = mu
968 0 : previous_count = count
969 : END DO
970 :
971 0 : mu0 = mup
972 0 : best = HUGE(1.0_dp)
973 0 : DO i = 1, neutral_grid
974 0 : mu = emin + (emax - emin)*REAL(i, KIND=dp)/REAL(neutral_grid, KIND=dp)
975 0 : CALL electron_hole_density(eig, maxocc, mu, mup, kT, ne, nh)
976 0 : IF (ABS(nh - ne) <= best) THEN
977 0 : mu0 = mu
978 0 : best = ABS(nh - ne)
979 : END IF
980 : END DO
981 :
982 0 : END SUBROUTINE find_neutral_mu
983 :
984 : ! **************************************************************************************************
985 : !> \brief Electron and hole counts relative to a neutral point.
986 : !> \param eig ...
987 : !> \param maxocc ...
988 : !> \param mu ...
989 : !> \param mu0 ...
990 : !> \param kT ...
991 : !> \param ne ...
992 : !> \param nh ...
993 : ! **************************************************************************************************
994 30 : SUBROUTINE electron_hole_density(eig, maxocc, mu, mu0, kT, ne, nh)
995 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: eig
996 : REAL(KIND=dp), DIMENSION(:), INTENT(IN) :: maxocc
997 : REAL(KIND=dp), INTENT(IN) :: mu, mu0, kT
998 : REAL(KIND=dp), INTENT(OUT) :: ne, nh
999 :
1000 : INTEGER :: ispin, n
1001 :
1002 30 : ne = 0.0_dp
1003 30 : nh = 0.0_dp
1004 142 : DO ispin = 1, SIZE(eig, 2)
1005 3214 : DO n = 1, SIZE(eig, 1)
1006 3072 : IF (eig(n, ispin) <= mu0) nh = nh + fermi_hole(eig(n, ispin), mu, kT, maxocc(ispin))
1007 3184 : IF (eig(n, ispin) >= mu0) ne = ne + fermi_occ(eig(n, ispin), mu, kT, maxocc(ispin))
1008 : END DO
1009 : END DO
1010 :
1011 30 : END SUBROUTINE electron_hole_density
1012 :
1013 : ! **************************************************************************************************
1014 : !> \brief Conductivity tensor at one chemical potential.
1015 : !> \param eig ...
1016 : !> \param dHH ...
1017 : !> \param maxocc ...
1018 : !> \param mu ...
1019 : !> \param kT ...
1020 : !> \param dissipation ...
1021 : !> \param measure ...
1022 : !> \param transport_ndim ...
1023 : !> \param sigma ...
1024 : !> \param bloch Use the stable Fermi limit for Bloch currents or the complete DC tensor
1025 : ! **************************************************************************************************
1026 30 : SUBROUTINE conductivity_at_mu(eig, dHH, maxocc, mu, kT, dissipation, measure, transport_ndim, sigma, bloch)
1027 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: eig
1028 : COMPLEX(KIND=dp), DIMENSION(:, :, :, :), &
1029 : INTENT(IN) :: dHH
1030 : REAL(KIND=dp), DIMENSION(:), INTENT(IN) :: maxocc
1031 : REAL(KIND=dp), INTENT(IN) :: mu, kT, dissipation, measure
1032 : INTEGER, INTENT(IN) :: transport_ndim
1033 : REAL(KIND=dp), DIMENSION(3, 3), INTENT(OUT) :: sigma
1034 : LOGICAL, INTENT(IN) :: bloch
1035 :
1036 : INTEGER :: idir, ispin, jdir, m, n, nao
1037 : REAL(KIND=dp) :: delta, eps, factor, g0
1038 30 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: occ
1039 :
1040 30 : nao = SIZE(eig, 1)
1041 30 : eps = 1.0E-12_dp
1042 30 : g0 = e_charge**2/(pi*h_bar)
1043 30 : sigma = 0.0_dp
1044 :
1045 90 : ALLOCATE (occ(nao))
1046 :
1047 142 : DO ispin = 1, SIZE(eig, 2)
1048 3184 : DO n = 1, nao
1049 3184 : occ(n) = fermi_occ(eig(n, ispin), mu, kT, maxocc(ispin))
1050 : END DO
1051 :
1052 478 : DO idir = 1, 3
1053 1456 : DO jdir = 1, 3
1054 28992 : DO n = 1, nao
1055 1065168 : DO m = 1, nao
1056 1036512 : delta = eig(n, ispin) - eig(m, ispin)
1057 1036512 : IF (bloch) THEN
1058 : factor = maxocc(ispin)*fermi_slope(eig(n, ispin), eig(m, ispin), mu, kT)* &
1059 1022112 : dissipation/(dissipation**2 + delta**2)
1060 : ELSE
1061 14400 : factor = (occ(n) - occ(m))/(delta + eps)*dissipation/(dissipation**2 + delta**2)
1062 : END IF
1063 : sigma(jdir, idir) = sigma(jdir, idir) + &
1064 1064160 : REAL(dHH(m, n, jdir, ispin)*dHH(n, m, idir, ispin), dp)*factor
1065 : END DO
1066 : END DO
1067 : END DO
1068 : END DO
1069 : END DO
1070 :
1071 390 : sigma = pi*g0*sigma*angstrom**(2 - transport_ndim)/measure
1072 :
1073 30 : DEALLOCATE (occ)
1074 :
1075 30 : END SUBROUTINE conductivity_at_mu
1076 :
1077 : END MODULE qs_kubo_transport
|