(git:b76ce4e)
Loading...
Searching...
No Matches
qs_kubo_transport.F
Go to the documentation of this file.
1!--------------------------------------------------------------------------------------------------!
2! CP2K: A general program to perform molecular dynamics simulations !
3! Copyright 2000-2026 CP2K developers group <https://cp2k.org> !
4! !
5! SPDX-License-Identifier: GPL-2.0-or-later !
6!--------------------------------------------------------------------------------------------------!
7
8! **************************************************************************************************
9!> \brief Finite-volume Kubo-Greenwood transport from converged Quickstep matrices.
10! **************************************************************************************************
13 cite_reference
14 USE cell_types, ONLY: cell_type,&
15 pbc
17 USE cp_dbcsr_api, ONLY: dbcsr_get_info,&
24 USE cp_fm_types, ONLY: cp_fm_create,&
34 USE kinds, ONLY: dp
35 USE mathconstants, ONLY: pi
38 USE physcon, ONLY: a_bohr,&
39 angstrom,&
40 e_charge,&
41 evolt,&
42 h_bar,&
43 kelvin
46 USE qs_mo_types, ONLY: get_mo_set,&
49#include "./base/base_uses.f90"
50
51 IMPLICIT NONE
52
53 PRIVATE
54
55 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_kubo_transport'
56
58
59CONTAINS
60
61! **************************************************************************************************
62!> \brief Compute and print the finite-volume Kubo-Greenwood conductivity tensor.
63!> \param qs_env Quickstep environment
64! **************************************************************************************************
65 SUBROUTINE qs_scf_post_kubo_transport(qs_env)
66 TYPE(qs_environment_type), POINTER :: qs_env
67
68 CHARACTER(len=*), PARAMETER :: routinen = 'qs_scf_post_kubo_transport'
69
70 CHARACTER(LEN=32) :: density_unit, measure_unit, method, &
71 periodic_label, sigma_iso_unit, &
72 sigma_tensor_unit
73 CHARACTER(LEN=512) :: header
74 INTEGER :: handle, imu, ispin, nao, natom, &
75 nelectron_total, neutral_grid, nmu, &
76 nperiodic, nspins, output_unit, &
77 transport_ndim
78 INTEGER, ALLOCATABLE, DIMENSION(:) :: ao_atom
79 INTEGER, DIMENSION(:), POINTER :: row_blk_sizes
80 LOGICAL :: allow_mo_reuse, do_kpoints, kubo_active, &
81 neutral_mu_explicit, ot_active
82 LOGICAL, ALLOCATABLE, DIMENSION(:) :: reused_mos
83 REAL(kind=dp) :: density_factor, dissipation, emax, emin, iso_factor, measure, measure_m, &
84 mu, mu0, mu_step, ne, nh, sigma_iso, temperature, tensor_factor
85 REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: maxocc
86 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: eig, s_dense
87 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :, :, :) :: dhh
88 REAL(kind=dp), DIMENSION(3, 3) :: projection, sigma, sigma_out
89 REAL(kind=dp), DIMENSION(:), POINTER :: energy_range
90 TYPE(cell_type), POINTER :: cell
91 TYPE(cp_blacs_env_type), POINTER :: blacs_env
92 TYPE(cp_logger_type), POINTER :: logger
93 TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_ks, matrix_s
94 TYPE(mo_set_type), DIMENSION(:), POINTER :: mos
95 TYPE(mp_para_env_type), POINTER :: para_env
96 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
97 TYPE(section_vals_type), POINTER :: input_section, kubo_section, ot_section
98
99 CALL timeset(routinen, handle)
100
101 NULLIFY (blacs_env, cell, energy_range, input_section, kubo_section, logger, matrix_ks, matrix_s, &
102 mos, ot_section, para_env, particle_set, row_blk_sizes)
103
104 CALL get_qs_env(qs_env, input=input_section)
105 kubo_section => section_vals_get_subs_vals(input_section, "PROPERTIES%KUBO_TRANSPORT")
106 CALL section_vals_val_get(kubo_section, "_SECTION_PARAMETERS_", l_val=kubo_active)
107 IF (.NOT. kubo_active) THEN
108 CALL timestop(handle)
109 RETURN
110 END IF
111 CALL cite_reference(kuhneheskeprodan2020)
112
113 CALL section_vals_val_get(kubo_section, "METHOD", c_val=method)
114 CALL uppercase(method)
115 SELECT CASE (trim(method))
116 CASE ("DIAGONALIZATION")
117 CASE ("TD", "CHEBYSHEV")
118 cpabort("KUBO_TRANSPORT METHOD "//trim(method)//" is reserved but not implemented yet.")
119 CASE DEFAULT
120 cpabort("Unknown KUBO_TRANSPORT METHOD: "//trim(method))
121 END SELECT
122 ot_section => section_vals_get_subs_vals(input_section, "DFT%SCF%OT")
123 CALL section_vals_val_get(ot_section, "_SECTION_PARAMETERS_", l_val=ot_active)
124 allow_mo_reuse = .NOT. ot_active
125
126 CALL get_qs_env(qs_env, blacs_env=blacs_env, cell=cell, do_kpoints=do_kpoints, &
127 matrix_ks=matrix_ks, matrix_s=matrix_s, mos=mos, natom=natom, &
128 nelectron_total=nelectron_total, para_env=para_env, particle_set=particle_set)
129
130 IF (do_kpoints) cpabort("KUBO_TRANSPORT currently expects a finite Gamma-point supercell.")
131 cpassert(ASSOCIATED(matrix_s))
132 cpassert(ASSOCIATED(matrix_ks))
133 cpassert(ASSOCIATED(cell))
134 cpassert(ASSOCIATED(particle_set))
135
136 CALL section_vals_val_get(kubo_section, "TEMPERATURE", r_val=temperature)
137 CALL section_vals_val_get(kubo_section, "DISSIPATION", r_val=dissipation)
138 CALL section_vals_val_get(kubo_section, "ENERGY_RANGE", r_vals=energy_range)
139 CALL section_vals_val_get(kubo_section, "NEUTRAL_MU", explicit=neutral_mu_explicit)
140 IF (neutral_mu_explicit) CALL section_vals_val_get(kubo_section, "NEUTRAL_MU", r_val=mu0)
141 CALL section_vals_val_get(kubo_section, "N_MU", i_val=nmu)
142 CALL section_vals_val_get(kubo_section, "NEUTRAL_GRID", i_val=neutral_grid)
143
144 IF (temperature <= 0.0_dp) cpabort("KUBO_TRANSPORT TEMPERATURE must be positive.")
145 IF (dissipation <= 0.0_dp) cpabort("KUBO_TRANSPORT DISSIPATION must be positive.")
146 IF (nmu < 1) cpabort("KUBO_TRANSPORT N_MU must be at least one.")
147 IF (neutral_grid < 10) cpabort("KUBO_TRANSPORT NEUTRAL_GRID must be at least ten.")
148
149 nspins = SIZE(matrix_ks)
150 CALL dbcsr_get_info(matrix_s(1)%matrix, nfullrows_total=nao, row_blk_size=row_blk_sizes)
151 CALL build_ao_atom_map(row_blk_sizes, natom, ao_atom)
152 CALL dbcsr_to_dense(matrix_s(1)%matrix, blacs_env, para_env, s_dense)
153 CALL setup_transport_geometry(cell, transport_ndim, nperiodic, periodic_label, projection, &
154 measure, measure_unit)
155 CALL transport_unit_labels(transport_ndim, density_unit, sigma_iso_unit, sigma_tensor_unit)
156
157 ALLOCATE (eig(nao, nspins), dhh(nao, nao, 3, nspins), maxocc(nspins), reused_mos(nspins))
158
159 DO ispin = 1, nspins
160 maxocc(ispin) = mos(ispin)%maxocc
161 CALL setup_spin_transport(matrix_ks(ispin)%matrix, s_dense, blacs_env, para_env, &
162 particle_set, cell, projection, ao_atom, mos(ispin), allow_mo_reuse, &
163 eig(:, ispin), dhh(:, :, :, ispin), reused_mos(ispin))
164 END DO
165
166 emin = minval(eig)
167 emax = maxval(eig)
168 IF (.NOT. neutral_mu_explicit) THEN
169 CALL find_neutral_mu(eig, maxocc, temperature, real(nelectron_total, kind=dp), neutral_grid, &
170 emin, emax, mu0)
171 END IF
172
173 IF (energy_range(1) < energy_range(2)) THEN
174 emin = energy_range(1)
175 emax = energy_range(2)
176 END IF
177
178 measure_m = measure*a_bohr**transport_ndim
179 density_factor = 1.0_dp/measure_m
180 CALL transport_output_factors(transport_ndim, iso_factor, tensor_factor)
181
182 logger => cp_get_default_logger()
183 output_unit = cp_logger_get_default_io_unit(logger)
184
185 IF (output_unit > 0) THEN
186 WRITE (output_unit, '(/,T2,A)') "Kubo-Greenwood finite-volume transport"
187 WRITE (output_unit, '(T3,A,T38,A)') "Method:", trim(method)
188 WRITE (output_unit, '(T3,A,T38,A)') "Cell periodicity:", trim(periodic_label)
189 IF (nperiodic == 0) THEN
190 WRITE (output_unit, '(T3,A,T38,A)') "Transport normalization:", "3D finite box"
191 ELSE
192 WRITE (output_unit, '(T3,A,T38,I12)') "Transport dimensionality:", transport_ndim
193 END IF
194 IF (all(reused_mos)) THEN
195 WRITE (output_unit, '(T3,A,T38,A)') "Eigensystem source:", "CP2K canonical MOs"
196 ELSEIF (any(reused_mos)) THEN
197 WRITE (output_unit, '(T3,A,T38,A)') "Eigensystem source:", "mixed canonical/internal"
198 ELSE
199 WRITE (output_unit, '(T3,A,T38,A)') "Eigensystem source:", "internal diagonalization"
200 END IF
201 WRITE (output_unit, '(T3,A,T38,I12)') "Number of atoms:", natom
202 WRITE (output_unit, '(T3,A,T38,I12)') "Number of AO functions:", nao
203 WRITE (output_unit, '(T3,A,T38,F12.4)') "Temperature [K]:", temperature*kelvin
204 WRITE (output_unit, '(T3,A,T38,F12.4)') "Dissipation [K]:", dissipation*kelvin
205 WRITE (output_unit, '(T3,A,T38,F12.6)') "Dissipation [eV]:", dissipation*evolt
206 WRITE (output_unit, '(T3,A,T38,F12.6)') "Neutral chemical potential [eV]:", mu0*evolt
207 WRITE (output_unit, '(T3,A,T38,ES12.4,1X,A)') "Transport measure:", &
208 measure*angstrom**transport_ndim, trim(measure_unit)
209 header = "mu[Ha] mu-mu0[eV] Ne["//trim(density_unit)//"] "// &
210 "Nh["//trim(density_unit)//"] sigma_iso["//trim(sigma_iso_unit)//"] "// &
211 "sigma_xx["//trim(sigma_tensor_unit)//"] sigma_xy["// &
212 trim(sigma_tensor_unit)//"] sigma_xz["//trim(sigma_tensor_unit)// &
213 "] sigma_yx["//trim(sigma_tensor_unit)//"] sigma_yy["// &
214 trim(sigma_tensor_unit)//"] sigma_yz["//trim(sigma_tensor_unit)// &
215 "] sigma_zx["//trim(sigma_tensor_unit)//"] sigma_zy["// &
216 trim(sigma_tensor_unit)//"] sigma_zz["//trim(sigma_tensor_unit)//"]"
217 WRITE (output_unit, '(/,T3,A)') trim(header)
218 END IF
219
220 IF (nmu == 1) THEN
221 mu_step = 0.0_dp
222 ELSE
223 mu_step = (emax - emin)/real(nmu - 1, kind=dp)
224 END IF
225
226 DO imu = 1, nmu
227 mu = emin + real(imu - 1, kind=dp)*mu_step
228 CALL electron_hole_density(eig, maxocc, mu, mu0, temperature, ne, nh)
229 CALL conductivity_at_mu(eig, dhh, maxocc, mu, temperature, dissipation, measure, &
230 transport_ndim, sigma)
231 IF (output_unit > 0) THEN
232 sigma_iso = (sigma(1, 1) + sigma(2, 2) + sigma(3, 3))/ &
233 REAL(transport_ndim, kind=dp)*iso_factor
234 sigma_out(:, :) = sigma(:, :)*tensor_factor
235 WRITE (output_unit, '(T3,F12.6,F14.6,2ES16.7,10ES17.8)') mu, (mu - mu0)*evolt, &
236 ne*density_factor, nh*density_factor, &
237 sigma_iso, &
238 sigma_out(1, 1), sigma_out(1, 2), sigma_out(1, 3), &
239 sigma_out(2, 1), sigma_out(2, 2), sigma_out(2, 3), &
240 sigma_out(3, 1), sigma_out(3, 2), sigma_out(3, 3)
241 SELECT CASE (transport_ndim)
242 CASE (1)
243 WRITE (output_unit, '(T3,A,1X,ES17.8)') "KUBO_TRANSPORT| sigma_iso[S*m]", sigma_iso
244 CASE (2)
245 WRITE (output_unit, '(T3,A,1X,ES17.8)') "KUBO_TRANSPORT| sigma_iso[S]", sigma_iso
246 CASE DEFAULT
247 WRITE (output_unit, '(T3,A,1X,ES17.8)') "KUBO_TRANSPORT| sigma_iso[S/cm]", sigma_iso
248 END SELECT
249 END IF
250 END DO
251
252 DEALLOCATE (ao_atom, dhh, eig, maxocc, reused_mos, s_dense)
253
254 CALL timestop(handle)
255
256 END SUBROUTINE qs_scf_post_kubo_transport
257
258! **************************************************************************************************
259!> \brief Build a global AO -> atom map from DBCSR atomic block sizes.
260!> \param row_blk_sizes ...
261!> \param natom ...
262!> \param ao_atom ...
263! **************************************************************************************************
264 SUBROUTINE build_ao_atom_map(row_blk_sizes, natom, ao_atom)
265 INTEGER, DIMENSION(:), INTENT(IN) :: row_blk_sizes
266 INTEGER, INTENT(IN) :: natom
267 INTEGER, ALLOCATABLE, DIMENSION(:), INTENT(OUT) :: ao_atom
268
269 INTEGER :: iao, iatom, nao, u
270
271 nao = sum(row_blk_sizes(1:natom))
272 ALLOCATE (ao_atom(nao))
273 iao = 0
274 DO iatom = 1, natom
275 DO u = 1, row_blk_sizes(iatom)
276 iao = iao + 1
277 ao_atom(iao) = iatom
278 END DO
279 END DO
280
281 END SUBROUTINE build_ao_atom_map
282
283! **************************************************************************************************
284!> \brief Copy a DBCSR matrix to a replicated dense matrix.
285!> \param matrix ...
286!> \param blacs_env ...
287!> \param para_env ...
288!> \param dense ...
289! **************************************************************************************************
290 SUBROUTINE dbcsr_to_dense(matrix, blacs_env, para_env, dense)
291 TYPE(dbcsr_type), INTENT(IN) :: matrix
292 TYPE(cp_blacs_env_type), POINTER :: blacs_env
293 TYPE(mp_para_env_type), POINTER :: para_env
294 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :), &
295 INTENT(OUT) :: dense
296
297 INTEGER :: ncol, nrow
298 TYPE(cp_fm_struct_type), POINTER :: fm_struct
299 TYPE(cp_fm_type) :: fm
300
301 NULLIFY (fm_struct)
302
303 CALL dbcsr_get_info(matrix, nfullrows_total=nrow, nfullcols_total=ncol)
304 ALLOCATE (dense(nrow, ncol))
305 CALL cp_fm_struct_create(fm_struct, context=blacs_env, para_env=para_env, &
306 nrow_global=nrow, ncol_global=ncol)
307 CALL cp_fm_create(fm, fm_struct)
308 CALL copy_dbcsr_to_fm(matrix, fm)
309 CALL cp_fm_get_submatrix(fm, dense, n_rows=nrow, n_cols=ncol)
310 CALL cp_fm_release(fm)
311 CALL cp_fm_struct_release(fm_struct)
312
313 END SUBROUTINE dbcsr_to_dense
314
315! **************************************************************************************************
316!> \brief Set up the periodic transport subspace and its normalization measure.
317!> \param cell ...
318!> \param transport_ndim ...
319!> \param nperiodic ...
320!> \param periodic_label ...
321!> \param projection ...
322!> \param measure ...
323!> \param measure_unit ...
324! **************************************************************************************************
325 SUBROUTINE setup_transport_geometry(cell, transport_ndim, nperiodic, periodic_label, projection, &
326 measure, measure_unit)
327 TYPE(cell_type), POINTER :: cell
328 INTEGER, INTENT(OUT) :: transport_ndim, nperiodic
329 CHARACTER(LEN=*), INTENT(OUT) :: periodic_label
330 REAL(kind=dp), DIMENSION(3, 3), INTENT(OUT) :: projection
331 REAL(kind=dp), INTENT(OUT) :: measure
332 CHARACTER(LEN=*), INTENT(OUT) :: measure_unit
333
334 INTEGER :: idir, jdir, kdir
335 REAL(kind=dp) :: detg, invg11, invg12, invg22, norm2
336 REAL(kind=dp), DIMENSION(3) :: v1, v2
337 REAL(kind=dp), DIMENSION(3, 2) :: basis2
338
339 cpassert(ASSOCIATED(cell))
340
341 nperiodic = count(cell%perd(1:3) == 1)
342 CALL transport_periodicity_label(cell%perd, periodic_label)
343 projection = 0.0_dp
344
345 SELECT CASE (nperiodic)
346 CASE (0)
347 transport_ndim = 3
348 measure = cell%deth
349 DO idir = 1, 3
350 projection(idir, idir) = 1.0_dp
351 END DO
352 measure_unit = "Angstrom^3"
353 CASE (1)
354 transport_ndim = 1
355 kdir = 0
356 DO idir = 1, 3
357 IF (cell%perd(idir) == 1) kdir = idir
358 END DO
359 v1(:) = cell%hmat(:, kdir)
360 norm2 = dot_product(v1, v1)
361 IF (norm2 <= 0.0_dp) cpabort("KUBO_TRANSPORT periodic cell vector has zero length.")
362 measure = sqrt(norm2)
363 DO jdir = 1, 3
364 DO idir = 1, 3
365 projection(idir, jdir) = v1(idir)*v1(jdir)/norm2
366 END DO
367 END DO
368 measure_unit = "Angstrom"
369 CASE (2)
370 transport_ndim = 2
371 kdir = 0
372 DO idir = 1, 3
373 IF (cell%perd(idir) == 1) THEN
374 kdir = kdir + 1
375 basis2(:, kdir) = cell%hmat(:, idir)
376 END IF
377 END DO
378 v1(:) = basis2(:, 1)
379 v2(:) = basis2(:, 2)
380 norm2 = dot_product(v1, v1)
381 invg22 = dot_product(v2, v2)
382 invg12 = dot_product(v1, v2)
383 detg = norm2*invg22 - invg12*invg12
384 IF (detg <= 0.0_dp) cpabort("KUBO_TRANSPORT periodic cell vectors are linearly dependent.")
385 measure = sqrt(detg)
386 invg11 = invg22/detg
387 invg22 = norm2/detg
388 invg12 = -invg12/detg
389 DO jdir = 1, 3
390 DO idir = 1, 3
391 projection(idir, jdir) = basis2(idir, 1)*invg11*basis2(jdir, 1) + &
392 basis2(idir, 1)*invg12*basis2(jdir, 2) + &
393 basis2(idir, 2)*invg12*basis2(jdir, 1) + &
394 basis2(idir, 2)*invg22*basis2(jdir, 2)
395 END DO
396 END DO
397 measure_unit = "Angstrom^2"
398 CASE DEFAULT
399 transport_ndim = 3
400 measure = cell%deth
401 DO idir = 1, 3
402 projection(idir, idir) = 1.0_dp
403 END DO
404 measure_unit = "Angstrom^3"
405 END SELECT
406
407 IF (measure <= 0.0_dp) cpabort("KUBO_TRANSPORT transport normalization measure is not positive.")
408
409 END SUBROUTINE setup_transport_geometry
410
411! **************************************************************************************************
412!> \brief Human-readable periodicity label.
413!> \param perd ...
414!> \param label ...
415! **************************************************************************************************
416 SUBROUTINE transport_periodicity_label(perd, label)
417 INTEGER, DIMENSION(3), INTENT(IN) :: perd
418 CHARACTER(LEN=*), INTENT(OUT) :: label
419
420 label = ""
421 IF (perd(1) == 1) label = trim(label)//"X"
422 IF (perd(2) == 1) label = trim(label)//"Y"
423 IF (perd(3) == 1) label = trim(label)//"Z"
424 IF (len_trim(label) == 0) label = "NONE"
425
426 END SUBROUTINE transport_periodicity_label
427
428! **************************************************************************************************
429!> \brief Output unit labels for a transport dimensionality.
430!> \param transport_ndim ...
431!> \param density_unit ...
432!> \param sigma_iso_unit ...
433!> \param sigma_tensor_unit ...
434! **************************************************************************************************
435 SUBROUTINE transport_unit_labels(transport_ndim, density_unit, sigma_iso_unit, sigma_tensor_unit)
436 INTEGER, INTENT(IN) :: transport_ndim
437 CHARACTER(LEN=*), INTENT(OUT) :: density_unit, sigma_iso_unit, &
438 sigma_tensor_unit
439
440 SELECT CASE (transport_ndim)
441 CASE (1)
442 density_unit = "m^-1"
443 sigma_iso_unit = "S*m"
444 sigma_tensor_unit = "S*m"
445 CASE (2)
446 density_unit = "m^-2"
447 sigma_iso_unit = "S"
448 sigma_tensor_unit = "S"
449 CASE DEFAULT
450 density_unit = "m^-3"
451 sigma_iso_unit = "S/cm"
452 sigma_tensor_unit = "S/m"
453 END SELECT
454
455 END SUBROUTINE transport_unit_labels
456
457! **************************************************************************************************
458!> \brief Output conversion factors from internal dimensional transport units.
459!> \param transport_ndim ...
460!> \param iso_factor ...
461!> \param tensor_factor ...
462! **************************************************************************************************
463 SUBROUTINE transport_output_factors(transport_ndim, iso_factor, tensor_factor)
464 INTEGER, INTENT(IN) :: transport_ndim
465 REAL(kind=dp), INTENT(OUT) :: iso_factor, tensor_factor
466
467 SELECT CASE (transport_ndim)
468 CASE (1)
469 iso_factor = 1.0e-10_dp
470 tensor_factor = 1.0e-10_dp
471 CASE (2)
472 iso_factor = 1.0_dp
473 tensor_factor = 1.0_dp
474 CASE DEFAULT
475 iso_factor = 1.0e8_dp
476 tensor_factor = 1.0e10_dp
477 END SELECT
478
479 END SUBROUTINE transport_output_factors
480
481! **************************************************************************************************
482!> \brief Prepare eigenvalues and the transformed [X,H] matrices for one spin channel.
483!> \param ks_matrix ...
484!> \param s_dense ...
485!> \param blacs_env ...
486!> \param para_env ...
487!> \param particle_set ...
488!> \param cell ...
489!> \param projection ...
490!> \param ao_atom ...
491!> \param mo_set ...
492!> \param allow_mo_reuse ...
493!> \param eig ...
494!> \param dHH ...
495!> \param reused_mos ...
496! **************************************************************************************************
497 SUBROUTINE setup_spin_transport(ks_matrix, s_dense, blacs_env, para_env, particle_set, cell, &
498 projection, ao_atom, mo_set, allow_mo_reuse, eig, dHH, reused_mos)
499 TYPE(dbcsr_type), INTENT(IN) :: ks_matrix
500 REAL(kind=dp), DIMENSION(:, :), INTENT(IN) :: s_dense
501 TYPE(cp_blacs_env_type), POINTER :: blacs_env
502 TYPE(mp_para_env_type), POINTER :: para_env
503 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
504 TYPE(cell_type), POINTER :: cell
505 REAL(kind=dp), DIMENSION(3, 3), INTENT(IN) :: projection
506 INTEGER, DIMENSION(:), INTENT(IN) :: ao_atom
507 TYPE(mo_set_type), INTENT(IN) :: mo_set
508 LOGICAL, INTENT(IN) :: allow_mo_reuse
509 REAL(kind=dp), DIMENSION(:), INTENT(OUT) :: eig
510 REAL(kind=dp), DIMENSION(:, :, :), INTENT(OUT) :: dhh
511 LOGICAL, INTENT(OUT) :: reused_mos
512
513 INTEGER :: idir, mo_nao, nao, nmo
514 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: coeff_dense, gmat, h_dense, horth, op, &
515 op_orth, uvec, work
516 REAL(kind=dp), DIMENSION(:), POINTER :: mo_eigenvalues
517 TYPE(cp_fm_type), POINTER :: mo_coeff
518
519 NULLIFY (mo_coeff, mo_eigenvalues)
520 nao = SIZE(s_dense, 1)
521 reused_mos = .false.
522
523 CALL dbcsr_to_dense(ks_matrix, blacs_env, para_env, h_dense)
524 ALLOCATE (op(nao, nao), work(nao, nao))
525
526 IF (allow_mo_reuse) THEN
527 CALL get_mo_set(mo_set=mo_set, nao=mo_nao, nmo=nmo, eigenvalues=mo_eigenvalues, &
528 mo_coeff=mo_coeff)
529 reused_mos = mo_nao == nao .AND. nmo >= nao .AND. ASSOCIATED(mo_eigenvalues) .AND. &
530 ASSOCIATED(mo_coeff)
531 IF (reused_mos) reused_mos = SIZE(mo_eigenvalues) >= nao
532 END IF
533
534 IF (reused_mos) THEN
535 ALLOCATE (coeff_dense(nao, nao))
536 eig(:) = mo_eigenvalues(1:nao)
537 CALL cp_fm_get_submatrix(mo_coeff, coeff_dense, n_rows=nao, n_cols=nao)
538 DO idir = 1, 3
539 CALL build_commutator_kernel(h_dense, particle_set, cell, projection, ao_atom, idir, op)
540 CALL transform_to_eigenbasis(op, coeff_dense, dhh(:, :, idir), work)
541 END DO
542 DEALLOCATE (coeff_dense)
543 ELSE
544 ALLOCATE (gmat(nao, nao), horth(nao, nao), op_orth(nao, nao), uvec(nao, nao))
545 CALL inverse_sqrt_symmetric(s_dense, gmat)
546
547 work(:, :) = matmul(h_dense, gmat)
548 horth(:, :) = matmul(gmat, work)
549 CALL symmetrize(horth)
550
551 uvec(:, :) = horth
552 CALL diagonalize_symmetric(uvec, eig)
553
554 DO idir = 1, 3
555 CALL build_commutator_kernel(h_dense, particle_set, cell, projection, ao_atom, idir, op)
556 work(:, :) = matmul(op, gmat)
557 op_orth(:, :) = matmul(gmat, work)
558 CALL transform_to_eigenbasis(op_orth, uvec, dhh(:, :, idir), work)
559 END DO
560 DEALLOCATE (gmat, horth, op_orth, uvec)
561 END IF
562
563 DEALLOCATE (h_dense, op, work)
564
565 END SUBROUTINE setup_spin_transport
566
567! **************************************************************************************************
568!> \brief Symmetric inverse square root via dense diagonalization.
569!> \param matrix ...
570!> \param inverse_sqrt ...
571! **************************************************************************************************
572 SUBROUTINE inverse_sqrt_symmetric(matrix, inverse_sqrt)
573 REAL(kind=dp), DIMENSION(:, :), INTENT(IN) :: matrix
574 REAL(kind=dp), DIMENSION(:, :), INTENT(OUT) :: inverse_sqrt
575
576 INTEGER :: i, info, lwork, n
577 REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: eig, work
578 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: scaled, vectors
579
580 n = SIZE(matrix, 1)
581 lwork = max(1, 8*n)
582 ALLOCATE (eig(n), scaled(n, n), vectors(n, n), work(lwork))
583
584 vectors(:, :) = matrix
585 CALL dsyev("V", "L", n, vectors, n, eig, work, lwork, info)
586 IF (info /= 0) cpabort("Diagonalization of the overlap matrix failed.")
587 IF (minval(eig) <= 0.0_dp) cpabort("Overlap matrix is not positive definite.")
588
589 scaled(:, :) = vectors
590 DO i = 1, n
591 scaled(:, i) = scaled(:, i)/sqrt(eig(i))
592 END DO
593 CALL dgemm("N", "T", n, n, n, 1.0_dp, scaled, n, vectors, n, 0.0_dp, inverse_sqrt, n)
594
595 DEALLOCATE (eig, scaled, vectors, work)
596
597 END SUBROUTINE inverse_sqrt_symmetric
598
599! **************************************************************************************************
600!> \brief Dense symmetric diagonalization.
601!> \param matrix ...
602!> \param eig ...
603! **************************************************************************************************
604 SUBROUTINE diagonalize_symmetric(matrix, eig)
605 REAL(kind=dp), DIMENSION(:, :), INTENT(INOUT) :: matrix
606 REAL(kind=dp), DIMENSION(:), INTENT(OUT) :: eig
607
608 INTEGER :: info, lwork, n
609 REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: work
610
611 n = SIZE(matrix, 1)
612 lwork = max(1, 8*n)
613 ALLOCATE (work(lwork))
614 CALL dsyev("V", "L", n, matrix, n, eig, work, lwork, info)
615 IF (info /= 0) cpabort("Diagonalization of the orthogonalized KS matrix failed.")
616 DEALLOCATE (work)
617
618 END SUBROUTINE diagonalize_symmetric
619
620! **************************************************************************************************
621!> \brief Enforce exact symmetry after dense products.
622!> \param matrix ...
623! **************************************************************************************************
624 SUBROUTINE symmetrize(matrix)
625 REAL(kind=dp), DIMENSION(:, :), INTENT(INOUT) :: matrix
626
627 INTEGER :: i, j, n
628 REAL(kind=dp) :: value
629
630 n = SIZE(matrix, 1)
631 DO j = 1, n
632 DO i = j + 1, n
633 value = 0.5_dp*(matrix(i, j) + matrix(j, i))
634 matrix(i, j) = value
635 matrix(j, i) = value
636 END DO
637 END DO
638
639 END SUBROUTINE symmetrize
640
641! **************************************************************************************************
642!> \brief Build element-wise kernel (P*(r_col-r_row))_idir * matrix(row,col).
643!> \param matrix ...
644!> \param particle_set ...
645!> \param cell ...
646!> \param projection ...
647!> \param ao_atom ...
648!> \param idir ...
649!> \param op ...
650! **************************************************************************************************
651 SUBROUTINE build_commutator_kernel(matrix, particle_set, cell, projection, ao_atom, idir, op)
652 REAL(kind=dp), DIMENSION(:, :), INTENT(IN) :: matrix
653 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
654 TYPE(cell_type), POINTER :: cell
655 REAL(kind=dp), DIMENSION(3, 3), INTENT(IN) :: projection
656 INTEGER, DIMENSION(:), INTENT(IN) :: ao_atom
657 INTEGER, INTENT(IN) :: idir
658 REAL(kind=dp), DIMENSION(:, :), INTENT(OUT) :: op
659
660 INTEGER :: i, j, n
661 REAL(kind=dp), DIMENSION(3) :: dr, projected_dr
662
663 n = SIZE(matrix, 1)
664 DO j = 1, n
665 DO i = 1, n
666 dr(:) = pbc(particle_set(ao_atom(j))%r(:) - particle_set(ao_atom(i))%r(:), cell)
667 projected_dr(:) = matmul(projection, dr)
668 op(i, j) = projected_dr(idir)*matrix(i, j)
669 END DO
670 END DO
671
672 END SUBROUTINE build_commutator_kernel
673
674! **************************************************************************************************
675!> \brief Transform an AO matrix to the eigenvector basis.
676!> \param op ...
677!> \param uvec ...
678!> \param transformed ...
679!> \param work ...
680! **************************************************************************************************
681 SUBROUTINE transform_to_eigenbasis(op, uvec, transformed, work)
682 REAL(kind=dp), DIMENSION(:, :), INTENT(IN) :: op, uvec
683 REAL(kind=dp), DIMENSION(:, :), INTENT(OUT) :: transformed
684 REAL(kind=dp), DIMENSION(:, :), INTENT(INOUT) :: work
685
686 INTEGER :: n
687
688 n = SIZE(op, 1)
689 CALL dgemm("N", "N", n, n, n, 1.0_dp, op, n, uvec, n, 0.0_dp, work, n)
690 CALL dgemm("T", "N", n, n, n, 1.0_dp, uvec, n, work, n, 0.0_dp, transformed, n)
691
692 END SUBROUTINE transform_to_eigenbasis
693
694! **************************************************************************************************
695!> \brief Fermi occupation with overflow protection.
696!> \param eig ...
697!> \param mu ...
698!> \param kT ...
699!> \param maxocc ...
700!> \return ...
701! **************************************************************************************************
702 PURE FUNCTION fermi_occ(eig, mu, kT, maxocc) RESULT(occ)
703 REAL(kind=dp), INTENT(IN) :: eig, mu, kt, maxocc
704 REAL(kind=dp) :: occ
705
706 REAL(kind=dp) :: x
707
708 x = (eig - mu)/kt
709 IF (x > 80.0_dp) THEN
710 occ = 0.0_dp
711 ELSEIF (x < -80.0_dp) THEN
712 occ = maxocc
713 ELSE
714 occ = maxocc/(1.0_dp + exp(x))
715 END IF
716
717 END FUNCTION fermi_occ
718
719! **************************************************************************************************
720!> \brief Fermi vacancy below the neutral point.
721!> \param eig ...
722!> \param mu ...
723!> \param kT ...
724!> \param maxocc ...
725!> \return ...
726! **************************************************************************************************
727 PURE FUNCTION fermi_hole(eig, mu, kT, maxocc) RESULT(hole)
728 REAL(kind=dp), INTENT(IN) :: eig, mu, kt, maxocc
729 REAL(kind=dp) :: hole
730
731 hole = maxocc - fermi_occ(eig, mu, kt, maxocc)
732
733 END FUNCTION fermi_hole
734
735! **************************************************************************************************
736!> \brief Total electron count at a chemical potential.
737!> \param eig ...
738!> \param maxocc ...
739!> \param mu ...
740!> \param kT ...
741!> \return ...
742! **************************************************************************************************
743 PURE FUNCTION electron_count(eig, maxocc, mu, kT) RESULT(count)
744 REAL(kind=dp), DIMENSION(:, :), INTENT(IN) :: eig
745 REAL(kind=dp), DIMENSION(:), INTENT(IN) :: maxocc
746 REAL(kind=dp), INTENT(IN) :: mu, kt
747 REAL(kind=dp) :: count
748
749 INTEGER :: ispin, n
750
751 count = 0.0_dp
752 DO ispin = 1, SIZE(eig, 2)
753 DO n = 1, SIZE(eig, 1)
754 count = count + fermi_occ(eig(n, ispin), mu, kt, maxocc(ispin))
755 END DO
756 END DO
757
758 END FUNCTION electron_count
759
760! **************************************************************************************************
761!> \brief Determine the neutral chemical potential using the legacy two-step definition.
762!> \param eig ...
763!> \param maxocc ...
764!> \param kT ...
765!> \param neutral_electrons ...
766!> \param neutral_grid ...
767!> \param emin ...
768!> \param emax ...
769!> \param mu0 ...
770! **************************************************************************************************
771 SUBROUTINE find_neutral_mu(eig, maxocc, kT, neutral_electrons, neutral_grid, emin, emax, mu0)
772 REAL(kind=dp), DIMENSION(:, :), INTENT(IN) :: eig
773 REAL(kind=dp), DIMENSION(:), INTENT(IN) :: maxocc
774 REAL(kind=dp), INTENT(IN) :: kt, neutral_electrons
775 INTEGER, INTENT(IN) :: neutral_grid
776 REAL(kind=dp), INTENT(IN) :: emin, emax
777 REAL(kind=dp), INTENT(OUT) :: mu0
778
779 INTEGER :: i
780 REAL(kind=dp) :: best, count, mu, mup, ne, nh, &
781 previous_count
782
783 mup = 0.5_dp*(emin + emax)
784 previous_count = electron_count(eig, maxocc, emin, kt)
785 DO i = 1, neutral_grid
786 mu = emin + (emax - emin)*real(i, kind=dp)/real(neutral_grid, kind=dp)
787 count = electron_count(eig, maxocc, mu, kt)
788 IF ((count - neutral_electrons)*(previous_count - neutral_electrons) <= 0.0_dp) mup = mu
789 previous_count = count
790 END DO
791
792 mu0 = mup
793 best = huge(1.0_dp)
794 DO i = 1, neutral_grid
795 mu = emin + (emax - emin)*real(i, kind=dp)/real(neutral_grid, kind=dp)
796 CALL electron_hole_density(eig, maxocc, mu, mup, kt, ne, nh)
797 IF (abs(nh - ne) <= best) THEN
798 mu0 = mu
799 best = abs(nh - ne)
800 END IF
801 END DO
802
803 END SUBROUTINE find_neutral_mu
804
805! **************************************************************************************************
806!> \brief Electron and hole counts relative to a neutral point.
807!> \param eig ...
808!> \param maxocc ...
809!> \param mu ...
810!> \param mu0 ...
811!> \param kT ...
812!> \param ne ...
813!> \param nh ...
814! **************************************************************************************************
815 SUBROUTINE electron_hole_density(eig, maxocc, mu, mu0, kT, ne, nh)
816 REAL(kind=dp), DIMENSION(:, :), INTENT(IN) :: eig
817 REAL(kind=dp), DIMENSION(:), INTENT(IN) :: maxocc
818 REAL(kind=dp), INTENT(IN) :: mu, mu0, kt
819 REAL(kind=dp), INTENT(OUT) :: ne, nh
820
821 INTEGER :: ispin, n
822
823 ne = 0.0_dp
824 nh = 0.0_dp
825 DO ispin = 1, SIZE(eig, 2)
826 DO n = 1, SIZE(eig, 1)
827 IF (eig(n, ispin) <= mu0) nh = nh + fermi_hole(eig(n, ispin), mu, kt, maxocc(ispin))
828 IF (eig(n, ispin) >= mu0) ne = ne + fermi_occ(eig(n, ispin), mu, kt, maxocc(ispin))
829 END DO
830 END DO
831
832 END SUBROUTINE electron_hole_density
833
834! **************************************************************************************************
835!> \brief Conductivity tensor at one chemical potential.
836!> \param eig ...
837!> \param dHH ...
838!> \param maxocc ...
839!> \param mu ...
840!> \param kT ...
841!> \param dissipation ...
842!> \param measure ...
843!> \param transport_ndim ...
844!> \param sigma ...
845! **************************************************************************************************
846 SUBROUTINE conductivity_at_mu(eig, dHH, maxocc, mu, kT, dissipation, measure, transport_ndim, sigma)
847 REAL(kind=dp), DIMENSION(:, :), INTENT(IN) :: eig
848 REAL(kind=dp), DIMENSION(:, :, :, :), INTENT(IN) :: dhh
849 REAL(kind=dp), DIMENSION(:), INTENT(IN) :: maxocc
850 REAL(kind=dp), INTENT(IN) :: mu, kt, dissipation, measure
851 INTEGER, INTENT(IN) :: transport_ndim
852 REAL(kind=dp), DIMENSION(3, 3), INTENT(OUT) :: sigma
853
854 INTEGER :: idir, ispin, jdir, m, n, nao
855 REAL(kind=dp) :: delta, eps, factor, g0
856 REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: occ
857
858 nao = SIZE(eig, 1)
859 eps = 1.0e-12_dp
860 g0 = e_charge**2/(pi*h_bar)
861 sigma = 0.0_dp
862
863 ALLOCATE (occ(nao))
864
865 DO ispin = 1, SIZE(eig, 2)
866 DO n = 1, nao
867 occ(n) = fermi_occ(eig(n, ispin), mu, kt, maxocc(ispin))
868 END DO
869
870 DO idir = 1, 3
871 DO jdir = 1, 3
872 DO n = 1, nao
873 DO m = 1, nao
874 delta = eig(n, ispin) - eig(m, ispin)
875 factor = (occ(n) - occ(m))/(delta + eps)*dissipation/(dissipation**2 + delta**2)
876 sigma(jdir, idir) = sigma(jdir, idir) + &
877 dhh(m, n, jdir, ispin)*dhh(n, m, idir, ispin)*factor
878 END DO
879 END DO
880 END DO
881 END DO
882 END DO
883
884 sigma = pi*g0*sigma*angstrom**(2 - transport_ndim)/measure
885
886 DEALLOCATE (occ)
887
888 END SUBROUTINE conductivity_at_mu
889
890END MODULE qs_kubo_transport
static void dgemm(const char transa, const char transb, const int m, const int n, const int k, const double alpha, const double *a, const int lda, const double *b, const int ldb, const double beta, double *c, const int ldc)
Convenient wrapper to hide Fortran nature of dgemm_, swapping a and b.
collects all references to literature in CP2K as new algorithms / method are included from literature...
integer, save, public kuhneheskeprodan2020
Handles all functions related to the CELL.
Definition cell_types.F:15
methods related to the blacs parallel environment
subroutine, public dbcsr_get_info(matrix, nblkrows_total, nblkcols_total, nfullrows_total, nfullcols_total, nblkrows_local, nblkcols_local, nfullrows_local, nfullcols_local, my_prow, my_pcol, local_rows, local_cols, proc_row_dist, proc_col_dist, row_blk_size, col_blk_size, row_blk_offset, col_blk_offset, distribution, name, matrix_type, group)
...
DBCSR operations in CP2K.
subroutine, public copy_dbcsr_to_fm(matrix, fm)
Copy a DBCSR matrix to a BLACS matrix.
represent the structure of a full matrix
subroutine, public cp_fm_struct_create(fmstruct, para_env, context, nrow_global, ncol_global, nrow_block, ncol_block, descriptor, first_p_pos, local_leading_dimension, template_fmstruct, square_blocks, force_block)
allocates and initializes a full matrix structure
subroutine, public cp_fm_struct_release(fmstruct)
releases a full matrix structure
represent a full matrix distributed on many processors
Definition cp_fm_types.F:15
subroutine, public cp_fm_create(matrix, matrix_struct, name, nrow, ncol, set_zero)
creates a new full matrix with the given structure
subroutine, public cp_fm_get_submatrix(fm, target_m, start_row, start_col, n_rows, n_cols, transpose)
gets a submatrix of a full matrix op(target_m)(1:n_rows,1:n_cols) =fm(start_row:start_row+n_rows,...
various routines to log and control the output. The idea is that decisions about where to log should ...
integer function, public cp_logger_get_default_io_unit(logger)
returns the unit nr for the ionode (-1 on all other processors) skips as well checks if the procs cal...
type(cp_logger_type) function, pointer, public cp_get_default_logger()
returns the default logger
objects that represent the structure of input sections and the data contained in an input section
recursive type(section_vals_type) function, pointer, public section_vals_get_subs_vals(section_vals, subsection_name, i_rep_section, can_return_null)
returns the values of the requested subsection
subroutine, public section_vals_val_get(section_vals, keyword_name, i_rep_section, i_rep_val, n_rep_val, val, l_val, i_val, r_val, c_val, l_vals, i_vals, r_vals, c_vals, explicit)
returns the requested value
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34
Definition of mathematical constants and functions.
real(kind=dp), parameter, public pi
Interface to the message passing library MPI.
Define the data structure for the particle information.
Definition of physical constants:
Definition physcon.F:68
real(kind=dp), parameter, public a_bohr
Definition physcon.F:136
real(kind=dp), parameter, public e_charge
Definition physcon.F:106
real(kind=dp), parameter, public kelvin
Definition physcon.F:165
real(kind=dp), parameter, public h_bar
Definition physcon.F:103
real(kind=dp), parameter, public evolt
Definition physcon.F:183
real(kind=dp), parameter, public angstrom
Definition physcon.F:144
subroutine, public get_qs_env(qs_env, atomic_kind_set, qs_kind_set, cell, super_cell, cell_ref, use_ref_cell, kpoints, dft_control, mos, sab_orb, sab_all, qmmm, qmmm_periodic, mimic, sac_ae, sac_ppl, sac_lri, sap_ppnl, sab_vdw, sab_scp, sap_oce, sab_lrc, sab_se, sab_xtbe, sab_tbe, sab_core, sab_xb, sab_xtb_pp, sab_xtb_nonbond, sab_almo, sab_kp, sab_kp_nosym, sab_cneo, particle_set, energy, force, matrix_h, matrix_h_im, matrix_ks, matrix_ks_im, matrix_vxc, run_rtp, rtp, matrix_h_kp, matrix_h_im_kp, matrix_ks_kp, matrix_ks_im_kp, matrix_vxc_kp, kinetic_kp, matrix_s_kp, matrix_w_kp, matrix_s_ri_aux_kp, matrix_s, matrix_s_ri_aux, matrix_w, matrix_p_mp2, matrix_p_mp2_admm, rho, rho_xc, pw_env, ewald_env, ewald_pw, active_space, mpools, input, para_env, blacs_env, scf_control, rel_control, kinetic, qs_charges, vppl, xcint_weights, rho_core, rho_nlcc, rho_nlcc_g, ks_env, ks_qmmm_env, wf_history, scf_env, local_particles, local_molecules, distribution_2d, dbcsr_dist, molecule_kind_set, molecule_set, subsys, cp_subsys, oce, local_rho_set, rho_atom_set, task_list, task_list_soft, rho0_atom_set, rho0_mpole, rhoz_set, rhoz_cneo_set, ecoul_1c, rho0_s_rs, rho0_s_gs, rhoz_cneo_s_rs, rhoz_cneo_s_gs, do_kpoints, has_unit_metric, requires_mo_derivs, mo_derivs, mo_loc_history, nkind, natom, nelectron_total, nelectron_spin, efield, neighbor_list_id, linres_control, xas_env, virial, cp_ddapc_env, cp_ddapc_ewald, outer_scf_history, outer_scf_ihistory, x_data, et_coupling, dftb_potential, results, se_taper, se_store_int_env, se_nddo_mpole, se_nonbond_env, admm_env, lri_env, lri_density, exstate_env, ec_env, harris_env, dispersion_env, gcp_env, vee, rho_external, external_vxc, mask, mp2_env, bs_env, kg_env, wanniercentres, atprop, ls_scf_env, do_transport, transport_env, v_hartree_rspace, s_mstruct_changed, rho_changed, potential_changed, forces_up_to_date, mscfg_env, almo_scf_env, gradient_history, variable_history, embed_pot, spin_embed_pot, polar_env, mos_last_converged, eeq, rhs, do_rixs, tb_tblite)
Get the QUICKSTEP environment.
Finite-volume Kubo-Greenwood transport from converged Quickstep matrices.
subroutine, public qs_scf_post_kubo_transport(qs_env)
Compute and print the finite-volume Kubo-Greenwood conductivity tensor.
Definition and initialisation of the mo data type.
Definition qs_mo_types.F:22
subroutine, public get_mo_set(mo_set, maxocc, homo, lfomo, nao, nelectron, n_el_f, nmo, eigenvalues, occupation_numbers, mo_coeff, mo_coeff_b, uniform_occupation, kts, mu, flexible_electron_count)
Get the components of a MO set data structure.
Utilities for string manipulations.
elemental subroutine, public uppercase(string)
Convert all lower case characters in a string to upper case.
Type defining parameters related to the simulation cell.
Definition cell_types.F:60
represent a blacs multidimensional parallel environment (for the mpi corrispective see cp_paratypes/m...
keeps the information about the structure of a full matrix
represent a full matrix
type of a logger, at the moment it contains just a print level starting at which level it should be l...
stores all the informations relevant to an mpi environment