LCOV - code coverage report
Current view: top level - src - qs_kubo_transport.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:06f838d) Lines: 90.7 % 355 322
Test Date: 2026-06-05 07:04:50 Functions: 89.5 % 19 17

            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: KuhneHeskeProdan2020,&
      13              :                                               cite_reference
      14              :    USE cell_types,                      ONLY: cell_type,&
      15              :                                               pbc
      16              :    USE cp_blacs_env,                    ONLY: cp_blacs_env_type
      17              :    USE cp_dbcsr_api,                    ONLY: dbcsr_get_info,&
      18              :                                               dbcsr_p_type,&
      19              :                                               dbcsr_type
      20              :    USE cp_dbcsr_operations,             ONLY: copy_dbcsr_to_fm
      21              :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      22              :                                               cp_fm_struct_release,&
      23              :                                               cp_fm_struct_type
      24              :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      25              :                                               cp_fm_get_submatrix,&
      26              :                                               cp_fm_release,&
      27              :                                               cp_fm_type
      28              :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      29              :                                               cp_logger_get_default_io_unit,&
      30              :                                               cp_logger_type
      31              :    USE input_section_types,             ONLY: section_vals_get_subs_vals,&
      32              :                                               section_vals_type,&
      33              :                                               section_vals_val_get
      34              :    USE kinds,                           ONLY: dp
      35              :    USE mathconstants,                   ONLY: pi
      36              :    USE message_passing,                 ONLY: mp_para_env_type
      37              :    USE particle_types,                  ONLY: particle_type
      38              :    USE physcon,                         ONLY: a_bohr,&
      39              :                                               angstrom,&
      40              :                                               e_charge,&
      41              :                                               evolt,&
      42              :                                               h_bar,&
      43              :                                               kelvin
      44              :    USE qs_environment_types,            ONLY: get_qs_env,&
      45              :                                               qs_environment_type
      46              :    USE qs_mo_types,                     ONLY: get_mo_set,&
      47              :                                               mo_set_type
      48              :    USE string_utilities,                ONLY: uppercase
      49              : #include "./base/base_uses.f90"
      50              : 
      51              :    IMPLICIT NONE
      52              : 
      53              :    PRIVATE
      54              : 
      55              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_kubo_transport'
      56              : 
      57              :    PUBLIC :: qs_scf_post_kubo_transport
      58              : 
      59              : CONTAINS
      60              : 
      61              : ! **************************************************************************************************
      62              : !> \brief Compute and print the finite-volume Kubo-Greenwood conductivity tensor.
      63              : !> \param qs_env Quickstep environment
      64              : ! **************************************************************************************************
      65        12667 :    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        12667 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: ao_atom
      79        12667 :       INTEGER, DIMENSION(:), POINTER                     :: row_blk_sizes
      80              :       LOGICAL                                            :: allow_mo_reuse, do_kpoints, kubo_active, &
      81              :                                                             neutral_mu_explicit, ot_active
      82        12667 :       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        12667 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: maxocc
      86        12667 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: eig, s_dense
      87        12667 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :, :)  :: dHH
      88              :       REAL(KIND=dp), DIMENSION(3, 3)                     :: projection, sigma, sigma_out
      89        12667 :       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        12667 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_ks, matrix_s
      94        12667 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
      95              :       TYPE(mp_para_env_type), POINTER                    :: para_env
      96        12667 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
      97              :       TYPE(section_vals_type), POINTER                   :: input_section, kubo_section, ot_section
      98              : 
      99        12667 :       CALL timeset(routineN, handle)
     100              : 
     101        12667 :       NULLIFY (blacs_env, cell, energy_range, input_section, kubo_section, logger, matrix_ks, matrix_s, &
     102        12667 :                mos, ot_section, para_env, particle_set, row_blk_sizes)
     103              : 
     104        12667 :       CALL get_qs_env(qs_env, input=input_section)
     105        12667 :       kubo_section => section_vals_get_subs_vals(input_section, "PROPERTIES%KUBO_TRANSPORT")
     106        12667 :       CALL section_vals_val_get(kubo_section, "_SECTION_PARAMETERS_", l_val=kubo_active)
     107        12667 :       IF (.NOT. kubo_active) THEN
     108        12657 :          CALL timestop(handle)
     109        12657 :          RETURN
     110              :       END IF
     111           10 :       CALL cite_reference(KuhneHeskeProdan2020)
     112              : 
     113           10 :       CALL section_vals_val_get(kubo_section, "METHOD", c_val=method)
     114           10 :       CALL uppercase(method)
     115           10 :       SELECT CASE (TRIM(method))
     116              :       CASE ("DIAGONALIZATION")
     117              :       CASE ("TD", "CHEBYSHEV")
     118            0 :          CPABORT("KUBO_TRANSPORT METHOD "//TRIM(method)//" is reserved but not implemented yet.")
     119              :       CASE DEFAULT
     120           10 :          CPABORT("Unknown KUBO_TRANSPORT METHOD: "//TRIM(method))
     121              :       END SELECT
     122           10 :       ot_section => section_vals_get_subs_vals(input_section, "DFT%SCF%OT")
     123           10 :       CALL section_vals_val_get(ot_section, "_SECTION_PARAMETERS_", l_val=ot_active)
     124           10 :       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           10 :                       nelectron_total=nelectron_total, para_env=para_env, particle_set=particle_set)
     129              : 
     130           10 :       IF (do_kpoints) CPABORT("KUBO_TRANSPORT currently expects a finite Gamma-point supercell.")
     131           10 :       CPASSERT(ASSOCIATED(matrix_s))
     132           10 :       CPASSERT(ASSOCIATED(matrix_ks))
     133           10 :       CPASSERT(ASSOCIATED(cell))
     134           10 :       CPASSERT(ASSOCIATED(particle_set))
     135              : 
     136           10 :       CALL section_vals_val_get(kubo_section, "TEMPERATURE", r_val=temperature)
     137           10 :       CALL section_vals_val_get(kubo_section, "DISSIPATION", r_val=dissipation)
     138           10 :       CALL section_vals_val_get(kubo_section, "ENERGY_RANGE", r_vals=energy_range)
     139           10 :       CALL section_vals_val_get(kubo_section, "NEUTRAL_MU", explicit=neutral_mu_explicit)
     140           10 :       IF (neutral_mu_explicit) CALL section_vals_val_get(kubo_section, "NEUTRAL_MU", r_val=mu0)
     141           10 :       CALL section_vals_val_get(kubo_section, "N_MU", i_val=nmu)
     142           10 :       CALL section_vals_val_get(kubo_section, "NEUTRAL_GRID", i_val=neutral_grid)
     143              : 
     144           10 :       IF (temperature <= 0.0_dp) CPABORT("KUBO_TRANSPORT TEMPERATURE must be positive.")
     145           10 :       IF (dissipation <= 0.0_dp) CPABORT("KUBO_TRANSPORT DISSIPATION must be positive.")
     146           10 :       IF (nmu < 1) CPABORT("KUBO_TRANSPORT N_MU must be at least one.")
     147           10 :       IF (neutral_grid < 10) CPABORT("KUBO_TRANSPORT NEUTRAL_GRID must be at least ten.")
     148              : 
     149           10 :       nspins = SIZE(matrix_ks)
     150           10 :       CALL dbcsr_get_info(matrix_s(1)%matrix, nfullrows_total=nao, row_blk_size=row_blk_sizes)
     151           10 :       CALL build_ao_atom_map(row_blk_sizes, natom, ao_atom)
     152           10 :       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           10 :                                     measure, measure_unit)
     155           10 :       CALL transport_unit_labels(transport_ndim, density_unit, sigma_iso_unit, sigma_tensor_unit)
     156              : 
     157          130 :       ALLOCATE (eig(nao, nspins), dHH(nao, nao, 3, nspins), maxocc(nspins), reused_mos(nspins))
     158              : 
     159           20 :       DO ispin = 1, nspins
     160           10 :          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           20 :                                    eig(:, ispin), dHH(:, :, :, ispin), reused_mos(ispin))
     164              :       END DO
     165              : 
     166          120 :       emin = MINVAL(eig)
     167          120 :       emax = MAXVAL(eig)
     168           10 :       IF (.NOT. neutral_mu_explicit) THEN
     169              :          CALL find_neutral_mu(eig, maxocc, temperature, REAL(nelectron_total, KIND=dp), neutral_grid, &
     170            0 :                               emin, emax, mu0)
     171              :       END IF
     172              : 
     173           10 :       IF (energy_range(1) < energy_range(2)) THEN
     174           10 :          emin = energy_range(1)
     175           10 :          emax = energy_range(2)
     176              :       END IF
     177              : 
     178           10 :       measure_m = measure*a_bohr**transport_ndim
     179           10 :       density_factor = 1.0_dp/measure_m
     180           10 :       CALL transport_output_factors(transport_ndim, iso_factor, tensor_factor)
     181              : 
     182           10 :       logger => cp_get_default_logger()
     183           10 :       output_unit = cp_logger_get_default_io_unit(logger)
     184              : 
     185           10 :       IF (output_unit > 0) THEN
     186            5 :          WRITE (output_unit, '(/,T2,A)') "Kubo-Greenwood finite-volume transport"
     187            5 :          WRITE (output_unit, '(T3,A,T38,A)') "Method:", TRIM(method)
     188            5 :          WRITE (output_unit, '(T3,A,T38,A)') "Cell periodicity:", TRIM(periodic_label)
     189            5 :          IF (nperiodic == 0) THEN
     190            3 :             WRITE (output_unit, '(T3,A,T38,A)') "Transport normalization:", "3D finite box"
     191              :          ELSE
     192            2 :             WRITE (output_unit, '(T3,A,T38,I12)') "Transport dimensionality:", transport_ndim
     193              :          END IF
     194            6 :          IF (ALL(reused_mos)) THEN
     195            1 :             WRITE (output_unit, '(T3,A,T38,A)') "Eigensystem source:", "CP2K canonical MOs"
     196            8 :          ELSEIF (ANY(reused_mos)) THEN
     197            0 :             WRITE (output_unit, '(T3,A,T38,A)') "Eigensystem source:", "mixed canonical/internal"
     198              :          ELSE
     199            4 :             WRITE (output_unit, '(T3,A,T38,A)') "Eigensystem source:", "internal diagonalization"
     200              :          END IF
     201            5 :          WRITE (output_unit, '(T3,A,T38,I12)') "Number of atoms:", natom
     202            5 :          WRITE (output_unit, '(T3,A,T38,I12)') "Number of AO functions:", nao
     203            5 :          WRITE (output_unit, '(T3,A,T38,F12.4)') "Temperature [K]:", temperature*kelvin
     204            5 :          WRITE (output_unit, '(T3,A,T38,F12.4)') "Dissipation [K]:", dissipation*kelvin
     205            5 :          WRITE (output_unit, '(T3,A,T38,F12.6)') "Dissipation [eV]:", dissipation*evolt
     206            5 :          WRITE (output_unit, '(T3,A,T38,F12.6)') "Neutral chemical potential [eV]:", mu0*evolt
     207            5 :          WRITE (output_unit, '(T3,A,T38,ES12.4,1X,A)') "Transport measure:", &
     208           10 :             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            5 :                   TRIM(sigma_tensor_unit)//"]     sigma_zz["//TRIM(sigma_tensor_unit)//"]"
     217            5 :          WRITE (output_unit, '(/,T3,A)') TRIM(header)
     218              :       END IF
     219              : 
     220           10 :       IF (nmu == 1) THEN
     221              :          mu_step = 0.0_dp
     222              :       ELSE
     223            0 :          mu_step = (emax - emin)/REAL(nmu - 1, KIND=dp)
     224              :       END IF
     225              : 
     226           20 :       DO imu = 1, nmu
     227           10 :          mu = emin + REAL(imu - 1, KIND=dp)*mu_step
     228           10 :          CALL electron_hole_density(eig, maxocc, mu, mu0, temperature, ne, nh)
     229              :          CALL conductivity_at_mu(eig, dHH, maxocc, mu, temperature, dissipation, measure, &
     230           10 :                                  transport_ndim, sigma)
     231           30 :          IF (output_unit > 0) THEN
     232              :             sigma_iso = (sigma(1, 1) + sigma(2, 2) + sigma(3, 3))/ &
     233            5 :                         REAL(transport_ndim, KIND=dp)*iso_factor
     234           65 :             sigma_out(:, :) = sigma(:, :)*tensor_factor
     235            5 :             WRITE (output_unit, '(T3,F12.6,F14.6,2ES16.7,10ES17.8)') mu, (mu - mu0)*evolt, &
     236            5 :                ne*density_factor, nh*density_factor, &
     237            5 :                sigma_iso, &
     238            5 :                sigma_out(1, 1), sigma_out(1, 2), sigma_out(1, 3), &
     239            5 :                sigma_out(2, 1), sigma_out(2, 2), sigma_out(2, 3), &
     240           10 :                sigma_out(3, 1), sigma_out(3, 2), sigma_out(3, 3)
     241            1 :             SELECT CASE (transport_ndim)
     242              :             CASE (1)
     243            1 :                WRITE (output_unit, '(T3,A,1X,ES17.8)') "KUBO_TRANSPORT| sigma_iso[S*m]", sigma_iso
     244              :             CASE (2)
     245            1 :                WRITE (output_unit, '(T3,A,1X,ES17.8)') "KUBO_TRANSPORT| sigma_iso[S]", sigma_iso
     246              :             CASE DEFAULT
     247            5 :                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           10 :       DEALLOCATE (ao_atom, dHH, eig, maxocc, reused_mos, s_dense)
     253              : 
     254           10 :       CALL timestop(handle)
     255              : 
     256        38071 :    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           10 :    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           30 :       nao = SUM(row_blk_sizes(1:natom))
     272           30 :       ALLOCATE (ao_atom(nao))
     273           10 :       iao = 0
     274           30 :       DO iatom = 1, natom
     275          130 :          DO u = 1, row_blk_sizes(iatom)
     276          100 :             iao = iao + 1
     277          120 :             ao_atom(iao) = iatom
     278              :          END DO
     279              :       END DO
     280              : 
     281           10 :    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           20 :    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           20 :       NULLIFY (fm_struct)
     302              : 
     303           20 :       CALL dbcsr_get_info(matrix, nfullrows_total=nrow, nfullcols_total=ncol)
     304           80 :       ALLOCATE (dense(nrow, ncol))
     305              :       CALL cp_fm_struct_create(fm_struct, context=blacs_env, para_env=para_env, &
     306           20 :                                nrow_global=nrow, ncol_global=ncol)
     307           20 :       CALL cp_fm_create(fm, fm_struct)
     308           20 :       CALL copy_dbcsr_to_fm(matrix, fm)
     309           20 :       CALL cp_fm_get_submatrix(fm, dense, n_rows=nrow, n_cols=ncol)
     310           20 :       CALL cp_fm_release(fm)
     311           20 :       CALL cp_fm_struct_release(fm_struct)
     312              : 
     313           40 :    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           10 :    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            0 :       CPASSERT(ASSOCIATED(cell))
     340              : 
     341           40 :       nperiodic = COUNT(cell%perd(1:3) == 1)
     342           10 :       CALL transport_periodicity_label(cell%perd, periodic_label)
     343           10 :       projection = 0.0_dp
     344              : 
     345           16 :       SELECT CASE (nperiodic)
     346              :       CASE (0)
     347            6 :          transport_ndim = 3
     348            6 :          measure = cell%deth
     349           24 :          DO idir = 1, 3
     350           24 :             projection(idir, idir) = 1.0_dp
     351              :          END DO
     352            6 :          measure_unit = "Angstrom^3"
     353              :       CASE (1)
     354            2 :          transport_ndim = 1
     355            2 :          kdir = 0
     356            8 :          DO idir = 1, 3
     357            8 :             IF (cell%perd(idir) == 1) kdir = idir
     358              :          END DO
     359            8 :          v1(:) = cell%hmat(:, kdir)
     360            8 :          norm2 = DOT_PRODUCT(v1, v1)
     361            2 :          IF (norm2 <= 0.0_dp) CPABORT("KUBO_TRANSPORT periodic cell vector has zero length.")
     362            2 :          measure = SQRT(norm2)
     363            8 :          DO jdir = 1, 3
     364           26 :             DO idir = 1, 3
     365           24 :                projection(idir, jdir) = v1(idir)*v1(jdir)/norm2
     366              :             END DO
     367              :          END DO
     368            2 :          measure_unit = "Angstrom"
     369              :       CASE (2)
     370            2 :          transport_ndim = 2
     371            2 :          kdir = 0
     372            8 :          DO idir = 1, 3
     373            8 :             IF (cell%perd(idir) == 1) THEN
     374            4 :                kdir = kdir + 1
     375           16 :                basis2(:, kdir) = cell%hmat(:, idir)
     376              :             END IF
     377              :          END DO
     378            8 :          v1(:) = basis2(:, 1)
     379            8 :          v2(:) = basis2(:, 2)
     380            8 :          norm2 = DOT_PRODUCT(v1, v1)
     381            8 :          invg22 = DOT_PRODUCT(v2, v2)
     382            8 :          invg12 = DOT_PRODUCT(v1, v2)
     383            2 :          detg = norm2*invg22 - invg12*invg12
     384            2 :          IF (detg <= 0.0_dp) CPABORT("KUBO_TRANSPORT periodic cell vectors are linearly dependent.")
     385            2 :          measure = SQRT(detg)
     386            2 :          invg11 = invg22/detg
     387            2 :          invg22 = norm2/detg
     388            2 :          invg12 = -invg12/detg
     389            8 :          DO jdir = 1, 3
     390           26 :             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           24 :                                         basis2(idir, 2)*invg22*basis2(jdir, 2)
     395              :             END DO
     396              :          END DO
     397            2 :          measure_unit = "Angstrom^2"
     398              :       CASE DEFAULT
     399            0 :          transport_ndim = 3
     400            0 :          measure = cell%deth
     401            0 :          DO idir = 1, 3
     402            0 :             projection(idir, idir) = 1.0_dp
     403              :          END DO
     404           10 :          measure_unit = "Angstrom^3"
     405              :       END SELECT
     406              : 
     407           10 :       IF (measure <= 0.0_dp) CPABORT("KUBO_TRANSPORT transport normalization measure is not positive.")
     408              : 
     409           10 :    END SUBROUTINE setup_transport_geometry
     410              : 
     411              : ! **************************************************************************************************
     412              : !> \brief Human-readable periodicity label.
     413              : !> \param perd ...
     414              : !> \param label ...
     415              : ! **************************************************************************************************
     416           10 :    SUBROUTINE transport_periodicity_label(perd, label)
     417              :       INTEGER, DIMENSION(3), INTENT(IN)                  :: perd
     418              :       CHARACTER(LEN=*), INTENT(OUT)                      :: label
     419              : 
     420           10 :       label = ""
     421           10 :       IF (perd(1) == 1) label = TRIM(label)//"X"
     422           10 :       IF (perd(2) == 1) label = TRIM(label)//"Y"
     423           10 :       IF (perd(3) == 1) label = TRIM(label)//"Z"
     424           10 :       IF (LEN_TRIM(label) == 0) label = "NONE"
     425              : 
     426           10 :    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           10 :    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           12 :       SELECT CASE (transport_ndim)
     441              :       CASE (1)
     442            2 :          density_unit = "m^-1"
     443            2 :          sigma_iso_unit = "S*m"
     444            2 :          sigma_tensor_unit = "S*m"
     445              :       CASE (2)
     446            2 :          density_unit = "m^-2"
     447            2 :          sigma_iso_unit = "S"
     448            2 :          sigma_tensor_unit = "S"
     449              :       CASE DEFAULT
     450            6 :          density_unit = "m^-3"
     451            6 :          sigma_iso_unit = "S/cm"
     452            6 :          sigma_tensor_unit = "S/m"
     453              :       END SELECT
     454              : 
     455           10 :    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           10 :    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           12 :       SELECT CASE (transport_ndim)
     468              :       CASE (1)
     469            2 :          iso_factor = 1.0E-10_dp
     470            2 :          tensor_factor = 1.0E-10_dp
     471              :       CASE (2)
     472            2 :          iso_factor = 1.0_dp
     473            2 :          tensor_factor = 1.0_dp
     474              :       CASE DEFAULT
     475            6 :          iso_factor = 1.0E8_dp
     476           10 :          tensor_factor = 1.0E10_dp
     477              :       END SELECT
     478              : 
     479           10 :    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           10 :    SUBROUTINE setup_spin_transport(ks_matrix, s_dense, blacs_env, para_env, particle_set, cell, &
     498           10 :                                    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           10 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: coeff_dense, gmat, h_dense, horth, op, &
     515           10 :                                                             op_orth, uvec, work
     516           10 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: mo_eigenvalues
     517              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
     518              : 
     519           10 :       NULLIFY (mo_coeff, mo_eigenvalues)
     520           10 :       nao = SIZE(s_dense, 1)
     521           10 :       reused_mos = .FALSE.
     522              : 
     523           10 :       CALL dbcsr_to_dense(ks_matrix, blacs_env, para_env, h_dense)
     524           60 :       ALLOCATE (op(nao, nao), work(nao, nao))
     525              : 
     526           10 :       IF (allow_mo_reuse) THEN
     527              :          CALL get_mo_set(mo_set=mo_set, nao=mo_nao, nmo=nmo, eigenvalues=mo_eigenvalues, &
     528            2 :                          mo_coeff=mo_coeff)
     529              :          reused_mos = mo_nao == nao .AND. nmo >= nao .AND. ASSOCIATED(mo_eigenvalues) .AND. &
     530            2 :                       ASSOCIATED(mo_coeff)
     531            2 :          IF (reused_mos) reused_mos = SIZE(mo_eigenvalues) >= nao
     532              :       END IF
     533              : 
     534           10 :       IF (reused_mos) THEN
     535            6 :          ALLOCATE (coeff_dense(nao, nao))
     536           22 :          eig(:) = mo_eigenvalues(1:nao)
     537            2 :          CALL cp_fm_get_submatrix(mo_coeff, coeff_dense, n_rows=nao, n_cols=nao)
     538            8 :          DO idir = 1, 3
     539            6 :             CALL build_commutator_kernel(h_dense, particle_set, cell, projection, ao_atom, idir, op)
     540            8 :             CALL transform_to_eigenbasis(op, coeff_dense, dHH(:, :, idir), work)
     541              :          END DO
     542            2 :          DEALLOCATE (coeff_dense)
     543              :       ELSE
     544           72 :          ALLOCATE (gmat(nao, nao), horth(nao, nao), op_orth(nao, nao), uvec(nao, nao))
     545            8 :          CALL inverse_sqrt_symmetric(s_dense, gmat)
     546              : 
     547        16888 :          work(:, :) = MATMUL(h_dense, gmat)
     548         8888 :          horth(:, :) = MATMUL(gmat, work)
     549            8 :          CALL symmetrize(horth)
     550              : 
     551          888 :          uvec(:, :) = horth
     552            8 :          CALL diagonalize_symmetric(uvec, eig)
     553              : 
     554           32 :          DO idir = 1, 3
     555           24 :             CALL build_commutator_kernel(h_dense, particle_set, cell, projection, ao_atom, idir, op)
     556        26664 :             work(:, :) = MATMUL(op, gmat)
     557        26664 :             op_orth(:, :) = MATMUL(gmat, work)
     558           32 :             CALL transform_to_eigenbasis(op_orth, uvec, dHH(:, :, idir), work)
     559              :          END DO
     560            8 :          DEALLOCATE (gmat, horth, op_orth, uvec)
     561              :       END IF
     562              : 
     563           10 :       DEALLOCATE (h_dense, op, work)
     564              : 
     565           20 :    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            8 :    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            8 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: eig, work
     578            8 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: scaled, vectors
     579              : 
     580            8 :       n = SIZE(matrix, 1)
     581            8 :       lwork = MAX(1, 8*n)
     582           80 :       ALLOCATE (eig(n), scaled(n, n), vectors(n, n), work(lwork))
     583              : 
     584          888 :       vectors(:, :) = matrix
     585            8 :       CALL dsyev("V", "L", n, vectors, n, eig, work, lwork, info)
     586            8 :       IF (info /= 0) CPABORT("Diagonalization of the overlap matrix failed.")
     587           88 :       IF (MINVAL(eig) <= 0.0_dp) CPABORT("Overlap matrix is not positive definite.")
     588              : 
     589          888 :       scaled(:, :) = vectors
     590           88 :       DO i = 1, n
     591          888 :          scaled(:, i) = scaled(:, i)/SQRT(eig(i))
     592              :       END DO
     593            8 :       CALL dgemm("N", "T", n, n, n, 1.0_dp, scaled, n, vectors, n, 0.0_dp, inverse_sqrt, n)
     594              : 
     595            8 :       DEALLOCATE (eig, scaled, vectors, work)
     596              : 
     597            8 :    END SUBROUTINE inverse_sqrt_symmetric
     598              : 
     599              : ! **************************************************************************************************
     600              : !> \brief Dense symmetric diagonalization.
     601              : !> \param matrix ...
     602              : !> \param eig ...
     603              : ! **************************************************************************************************
     604            8 :    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            8 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: work
     610              : 
     611            8 :       n = SIZE(matrix, 1)
     612            8 :       lwork = MAX(1, 8*n)
     613           24 :       ALLOCATE (work(lwork))
     614            8 :       CALL dsyev("V", "L", n, matrix, n, eig, work, lwork, info)
     615            8 :       IF (info /= 0) CPABORT("Diagonalization of the orthogonalized KS matrix failed.")
     616            8 :       DEALLOCATE (work)
     617              : 
     618            8 :    END SUBROUTINE diagonalize_symmetric
     619              : 
     620              : ! **************************************************************************************************
     621              : !> \brief Enforce exact symmetry after dense products.
     622              : !> \param matrix ...
     623              : ! **************************************************************************************************
     624            8 :    SUBROUTINE symmetrize(matrix)
     625              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT)      :: matrix
     626              : 
     627              :       INTEGER                                            :: i, j, n
     628              :       REAL(KIND=dp)                                      :: value
     629              : 
     630            8 :       n = SIZE(matrix, 1)
     631           88 :       DO j = 1, n
     632          448 :          DO i = j + 1, n
     633          360 :             value = 0.5_dp*(matrix(i, j) + matrix(j, i))
     634          360 :             matrix(i, j) = value
     635          440 :             matrix(j, i) = value
     636              :          END DO
     637              :       END DO
     638              : 
     639            8 :    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           30 :    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           30 :       n = SIZE(matrix, 1)
     664          330 :       DO j = 1, n
     665         3330 :          DO i = 1, n
     666        12000 :             dr(:) = pbc(particle_set(ao_atom(j))%r(:) - particle_set(ao_atom(i))%r(:), cell)
     667        39000 :             projected_dr(:) = MATMUL(projection, dr)
     668         3300 :             op(i, j) = projected_dr(idir)*matrix(i, j)
     669              :          END DO
     670              :       END DO
     671              : 
     672           30 :    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           30 :    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           30 :       n = SIZE(op, 1)
     689           30 :       CALL dgemm("N", "N", n, n, n, 1.0_dp, op, n, uvec, n, 0.0_dp, work, n)
     690           30 :       CALL dgemm("T", "N", n, n, n, 1.0_dp, uvec, n, work, n, 0.0_dp, transformed, n)
     691              : 
     692           30 :    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          200 :    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          200 :       x = (eig - mu)/kT
     709          200 :       IF (x > 80.0_dp) THEN
     710              :          occ = 0.0_dp
     711           20 :       ELSEIF (x < -80.0_dp) THEN
     712            0 :          occ = maxocc
     713              :       ELSE
     714           20 :          occ = maxocc/(1.0_dp + EXP(x))
     715              :       END IF
     716              : 
     717          200 :    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           10 :    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           10 :       hole = maxocc - fermi_occ(eig, mu, kT, maxocc)
     732              : 
     733           10 :    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            0 :    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            0 :       count = 0.0_dp
     752            0 :       DO ispin = 1, SIZE(eig, 2)
     753            0 :          DO n = 1, SIZE(eig, 1)
     754            0 :             count = count + fermi_occ(eig(n, ispin), mu, kT, maxocc(ispin))
     755              :          END DO
     756              :       END DO
     757              : 
     758            0 :    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            0 :    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            0 :       mup = 0.5_dp*(emin + emax)
     784            0 :       previous_count = electron_count(eig, maxocc, emin, kT)
     785            0 :       DO i = 1, neutral_grid
     786            0 :          mu = emin + (emax - emin)*REAL(i, KIND=dp)/REAL(neutral_grid, KIND=dp)
     787            0 :          count = electron_count(eig, maxocc, mu, kT)
     788            0 :          IF ((count - neutral_electrons)*(previous_count - neutral_electrons) <= 0.0_dp) mup = mu
     789            0 :          previous_count = count
     790              :       END DO
     791              : 
     792            0 :       mu0 = mup
     793            0 :       best = HUGE(1.0_dp)
     794            0 :       DO i = 1, neutral_grid
     795            0 :          mu = emin + (emax - emin)*REAL(i, KIND=dp)/REAL(neutral_grid, KIND=dp)
     796            0 :          CALL electron_hole_density(eig, maxocc, mu, mup, kT, ne, nh)
     797            0 :          IF (ABS(nh - ne) <= best) THEN
     798            0 :             mu0 = mu
     799            0 :             best = ABS(nh - ne)
     800              :          END IF
     801              :       END DO
     802              : 
     803            0 :    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           10 :    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           10 :       ne = 0.0_dp
     824           10 :       nh = 0.0_dp
     825           20 :       DO ispin = 1, SIZE(eig, 2)
     826          120 :          DO n = 1, SIZE(eig, 1)
     827          100 :             IF (eig(n, ispin) <= mu0) nh = nh + fermi_hole(eig(n, ispin), mu, kT, maxocc(ispin))
     828          110 :             IF (eig(n, ispin) >= mu0) ne = ne + fermi_occ(eig(n, ispin), mu, kT, maxocc(ispin))
     829              :          END DO
     830              :       END DO
     831              : 
     832           10 :    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           10 :    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           10 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: occ
     857              : 
     858           10 :       nao = SIZE(eig, 1)
     859           10 :       eps = 1.0E-12_dp
     860           10 :       g0 = e_charge**2/(pi*h_bar)
     861           10 :       sigma = 0.0_dp
     862              : 
     863           30 :       ALLOCATE (occ(nao))
     864              : 
     865           20 :       DO ispin = 1, SIZE(eig, 2)
     866          110 :          DO n = 1, nao
     867          110 :             occ(n) = fermi_occ(eig(n, ispin), mu, kT, maxocc(ispin))
     868              :          END DO
     869              : 
     870           50 :          DO idir = 1, 3
     871          130 :             DO jdir = 1, 3
     872         1020 :                DO n = 1, nao
     873         9990 :                   DO m = 1, nao
     874         9000 :                      delta = eig(n, ispin) - eig(m, ispin)
     875         9000 :                      factor = (occ(n) - occ(m))/(delta + eps)*dissipation/(dissipation**2 + delta**2)
     876              :                      sigma(jdir, idir) = sigma(jdir, idir) + &
     877         9900 :                                          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          130 :       sigma = pi*g0*sigma*angstrom**(2 - transport_ndim)/measure
     885              : 
     886           10 :       DEALLOCATE (occ)
     887              : 
     888           10 :    END SUBROUTINE conductivity_at_mu
     889              : 
     890              : END MODULE qs_kubo_transport
        

Generated by: LCOV version 2.0-1