LCOV - code coverage report
Current view: top level - src - soc_pseudopotential_methods.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:2fce0f8) Lines: 79 112 70.5 %
Date: 2024-12-21 06:28:57 Functions: 2 3 66.7 %

          Line data    Source code
       1             : !--------------------------------------------------------------------------------------------------!
       2             : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3             : !   Copyright 2000-2024 CP2K developers group <https://cp2k.org>                                   !
       4             : !                                                                                                  !
       5             : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6             : !--------------------------------------------------------------------------------------------------!
       7             : 
       8             : MODULE soc_pseudopotential_methods
       9             :    USE atomic_kind_types,               ONLY: atomic_kind_type
      10             :    USE core_ppnl,                       ONLY: build_core_ppnl
      11             :    USE cp_cfm_types,                    ONLY: cp_cfm_get_info,&
      12             :                                               cp_cfm_type
      13             :    USE cp_control_types,                ONLY: dft_control_type
      14             :    USE cp_dbcsr_api,                    ONLY: dbcsr_add,&
      15             :                                               dbcsr_copy,&
      16             :                                               dbcsr_create,&
      17             :                                               dbcsr_desymmetrize,&
      18             :                                               dbcsr_p_type,&
      19             :                                               dbcsr_set,&
      20             :                                               dbcsr_type_antisymmetric,&
      21             :                                               dbcsr_type_no_symmetry
      22             :    USE cp_dbcsr_cp2k_link,              ONLY: cp_dbcsr_alloc_block_from_nbl
      23             :    USE cp_dbcsr_operations,             ONLY: copy_dbcsr_to_fm,&
      24             :                                               copy_fm_to_dbcsr,&
      25             :                                               dbcsr_allocate_matrix_set,&
      26             :                                               dbcsr_deallocate_matrix_set
      27             :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      28             :                                               cp_fm_get_info,&
      29             :                                               cp_fm_release,&
      30             :                                               cp_fm_type
      31             :    USE kinds,                           ONLY: dp
      32             :    USE kpoint_types,                    ONLY: get_kpoint_info,&
      33             :                                               kpoint_type
      34             :    USE parallel_gemm_api,               ONLY: parallel_gemm
      35             :    USE particle_types,                  ONLY: particle_type
      36             :    USE qs_environment_types,            ONLY: get_qs_env,&
      37             :                                               qs_environment_type
      38             :    USE qs_force_types,                  ONLY: qs_force_type
      39             :    USE qs_kind_types,                   ONLY: qs_kind_type
      40             :    USE qs_neighbor_list_types,          ONLY: get_neighbor_list_set_p,&
      41             :                                               neighbor_list_set_p_type
      42             :    USE virial_types,                    ONLY: virial_type
      43             : #include "./base/base_uses.f90"
      44             : 
      45             :    IMPLICIT NONE
      46             : 
      47             :    PRIVATE
      48             : 
      49             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'soc_pseudopotential_methods'
      50             : 
      51             :    PUBLIC :: V_SOC_xyz_from_pseudopotential, &
      52             :              remove_soc_outside_energy_window_ao, &
      53             :              remove_soc_outside_energy_window_mo
      54             : 
      55             : CONTAINS
      56             : 
      57             : ! **************************************************************************************************
      58             : !> \brief V^SOC_µν^(α),R = ħ/2 < ϕ_µ cell O | sum_ℓ ΔV_ℓ^SO(r,r') L^(α) | ϕ_ν cell R>, α = x,y,z
      59             : !>        see Hartwigsen, Goedecker, Hutter, Eq.(18), (19) (doi.org/10.1103/PhysRevB.58.3641)
      60             : !>        Caution: V^SOC_µν^(α) is purely imaginary and Hermitian; V^SOC_µν^(α) is stored as real
      61             : !>                 dbcsr matrix mat_V_SOC_xyz without symmetry; V^SOC_µν^(α) is stored without
      62             : !>                 the imaginary unit, i.e. mat_V_SOC_xyz is real and antisymmetric
      63             : !> \param qs_env ...
      64             : !> \param mat_V_SOC_xyz ...
      65             : !> \par History
      66             : !>    * 09.2023 created
      67             : !> \author Jan Wilhelm
      68             : ! **************************************************************************************************
      69          40 :    SUBROUTINE V_SOC_xyz_from_pseudopotential(qs_env, mat_V_SOC_xyz)
      70             :       TYPE(qs_environment_type), POINTER                 :: qs_env
      71             :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: mat_V_SOC_xyz
      72             : 
      73             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'V_SOC_xyz_from_pseudopotential'
      74             : 
      75             :       INTEGER                                            :: handle, img, nder, nimages, xyz
      76          20 :       INTEGER, DIMENSION(:, :, :), POINTER               :: cell_to_index
      77             :       LOGICAL                                            :: calculate_forces, do_kp, do_symmetric, &
      78             :                                                             use_virial
      79             :       REAL(KIND=dp)                                      :: eps_ppnl
      80          20 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
      81          20 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: mat_l, mat_l_nosym, mat_pot_dummy, &
      82          20 :                                                             matrix_dummy, matrix_s
      83             :       TYPE(dft_control_type), POINTER                    :: dft_control
      84             :       TYPE(kpoint_type), POINTER                         :: kpoints
      85             :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
      86          20 :          POINTER                                         :: sab_orb, sap_ppnl
      87          20 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
      88          20 :       TYPE(qs_force_type), DIMENSION(:), POINTER         :: force
      89          20 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
      90             :       TYPE(virial_type), POINTER                         :: virial
      91             : 
      92          20 :       CALL timeset(routineN, handle)
      93             : 
      94          20 :       NULLIFY (qs_kind_set, dft_control, sab_orb, sap_ppnl, particle_set, atomic_kind_set, &
      95          20 :                cell_to_index)
      96             :       CALL get_qs_env(qs_env=qs_env, qs_kind_set=qs_kind_set, dft_control=dft_control, &
      97             :                       matrix_s_kp=matrix_s, kpoints=kpoints, atomic_kind_set=atomic_kind_set, &
      98          20 :                       particle_set=particle_set, sab_orb=sab_orb, sap_ppnl=sap_ppnl)
      99             : 
     100          20 :       eps_ppnl = dft_control%qs_control%eps_ppnl
     101          20 :       nimages = dft_control%nimages
     102          20 :       do_kp = (nimages > 1)
     103          20 :       CALL get_neighbor_list_set_p(neighbor_list_sets=sab_orb, symmetric=do_symmetric)
     104          20 :       CALL get_kpoint_info(kpoint=kpoints, cell_to_index=cell_to_index)
     105             : 
     106          20 :       NULLIFY (mat_l, mat_pot_dummy)
     107          20 :       CALL dbcsr_allocate_matrix_set(mat_l, 3, nimages)
     108          80 :       DO xyz = 1, 3
     109         560 :          DO img = 1, nimages
     110         480 :             ALLOCATE (mat_l(xyz, img)%matrix)
     111             :             CALL dbcsr_create(mat_l(xyz, img)%matrix, template=matrix_s(1, 1)%matrix, &
     112         480 :                               matrix_type=dbcsr_type_antisymmetric)
     113         480 :             CALL cp_dbcsr_alloc_block_from_nbl(mat_l(xyz, img)%matrix, sab_orb)
     114         540 :             CALL dbcsr_set(mat_l(xyz, img)%matrix, 0.0_dp)
     115             :          END DO
     116             :       END DO
     117             : 
     118             :       ! get mat_l; the next CPASSERT fails if the atoms do not have any SOC parameters, i.e.
     119             :       ! SOC is zero and one should not activate the SOC section
     120          20 :       CPASSERT(ASSOCIATED(sap_ppnl))
     121          20 :       nder = 0
     122          20 :       use_virial = .FALSE.
     123          20 :       calculate_forces = .FALSE.
     124             : 
     125          20 :       NULLIFY (mat_pot_dummy)
     126          20 :       CALL dbcsr_allocate_matrix_set(mat_pot_dummy, 1, nimages)
     127         180 :       DO img = 1, nimages
     128         160 :          ALLOCATE (mat_pot_dummy(1, img)%matrix)
     129         160 :          CALL dbcsr_create(mat_pot_dummy(1, img)%matrix, template=matrix_s(1, 1)%matrix)
     130         160 :          CALL cp_dbcsr_alloc_block_from_nbl(mat_pot_dummy(1, img)%matrix, sab_orb)
     131         180 :          CALL dbcsr_set(mat_pot_dummy(1, img)%matrix, 0.0_dp)
     132             :       END DO
     133             : 
     134             :       CALL build_core_ppnl(mat_pot_dummy, matrix_dummy, force, virial, &
     135             :                            calculate_forces, use_virial, nder, &
     136             :                            qs_kind_set, atomic_kind_set, particle_set, sab_orb, sap_ppnl, &
     137             :                            eps_ppnl, nimages=nimages, cell_to_index=cell_to_index, &
     138          20 :                            basis_type="ORB", matrix_l=mat_l)
     139             : 
     140          20 :       NULLIFY (mat_l_nosym)
     141          20 :       CALL dbcsr_allocate_matrix_set(mat_l_nosym, 3, nimages)
     142          80 :       DO xyz = 1, 3
     143         560 :          DO img = 1, nimages
     144             : 
     145         480 :             ALLOCATE (mat_l_nosym(xyz, img)%matrix)
     146         540 :             IF (do_kp) THEN
     147             :                CALL dbcsr_create(mat_l_nosym(xyz, img)%matrix, template=matrix_s(1, 1)%matrix, &
     148         438 :                                  matrix_type=dbcsr_type_antisymmetric)
     149         438 :                CALL dbcsr_copy(mat_l_nosym(xyz, img)%matrix, mat_l(xyz, img)%matrix)
     150             :             ELSE
     151             :                CALL dbcsr_create(mat_l_nosym(xyz, img)%matrix, template=matrix_s(1, 1)%matrix, &
     152          42 :                                  matrix_type=dbcsr_type_no_symmetry)
     153          42 :                CALL dbcsr_desymmetrize(mat_l(xyz, img)%matrix, mat_l_nosym(xyz, img)%matrix)
     154             :             END IF
     155             : 
     156             :          END DO
     157             :       END DO
     158             : 
     159          20 :       NULLIFY (mat_V_SOC_xyz)
     160          20 :       CALL dbcsr_allocate_matrix_set(mat_V_SOC_xyz, 3, nimages)
     161          80 :       DO xyz = 1, 3
     162         560 :          DO img = 1, nimages
     163         480 :             ALLOCATE (mat_V_SOC_xyz(xyz, img)%matrix)
     164         480 :             IF (do_kp) THEN
     165             :                ! mat_V_SOC_xyz^R with neighbor cell R actually has no symmetry
     166             :                ! mat_V_SOC_xyz^R_µν = mat_V_SOC_xyz^R_νµ* (the actual symmetry is
     167             :                ! mat_V_SOC_xyz^R_µν = mat_V_SOC_xyz^-R_νµ* )  but rskp_transform
     168             :                ! for mat_V_SOC_xyz^R -> mat_V_SOC_xyz(k) requires symmetry...
     169             :                CALL dbcsr_create(mat_V_SOC_xyz(xyz, img)%matrix, template=matrix_s(1, 1)%matrix, &
     170         438 :                                  matrix_type=dbcsr_type_antisymmetric)
     171             :             ELSE
     172             :                CALL dbcsr_create(mat_V_SOC_xyz(xyz, img)%matrix, template=matrix_s(1, 1)%matrix, &
     173          42 :                                  matrix_type=dbcsr_type_no_symmetry)
     174             :             END IF
     175         480 :             CALL cp_dbcsr_alloc_block_from_nbl(mat_V_SOC_xyz(xyz, img)%matrix, sab_orb)
     176             :             ! factor 0.5 from ħ/2 prefactor
     177             :             CALL dbcsr_add(mat_V_SOC_xyz(xyz, img)%matrix, mat_l_nosym(xyz, img)%matrix, &
     178         540 :                            0.0_dp, 0.5_dp)
     179             :          END DO
     180             :       END DO
     181             : 
     182          20 :       CALL dbcsr_deallocate_matrix_set(mat_pot_dummy)
     183          20 :       CALL dbcsr_deallocate_matrix_set(mat_l_nosym)
     184          20 :       CALL dbcsr_deallocate_matrix_set(mat_l)
     185             : 
     186          20 :       CALL timestop(handle)
     187             : 
     188          20 :    END SUBROUTINE V_SOC_xyz_from_pseudopotential
     189             : 
     190             : ! **************************************************************************************************
     191             : !> \brief Remove SOC outside of energy window (otherwise, numerical problems arise
     192             : !>        because energetically low semicore states and energetically very high
     193             : !>        unbound states couple to the states around the Fermi level).
     194             : !>        This routine is for mat_V_SOC_xyz being in the atomic-orbital (ao) basis.
     195             : !> \param mat_V_SOC_xyz ...
     196             : !> \param e_win ...
     197             : !> \param fm_mo_coeff ...
     198             : !> \param homo ...
     199             : !> \param eigenval ...
     200             : !> \param fm_s ...
     201             : ! **************************************************************************************************
     202           0 :    SUBROUTINE remove_soc_outside_energy_window_ao(mat_V_SOC_xyz, e_win, fm_mo_coeff, homo, &
     203           0 :                                                   eigenval, fm_s)
     204             :       TYPE(dbcsr_p_type), DIMENSION(:)                   :: mat_V_SOC_xyz
     205             :       REAL(KIND=dp)                                      :: e_win
     206             :       TYPE(cp_fm_type)                                   :: fm_mo_coeff
     207             :       INTEGER                                            :: homo
     208             :       REAL(KIND=dp), DIMENSION(:)                        :: eigenval
     209             :       TYPE(cp_fm_type)                                   :: fm_s
     210             : 
     211             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'remove_soc_outside_energy_window_ao'
     212             : 
     213             :       INTEGER                                            :: handle, i_glob, iiB, j_glob, jjB, nao, &
     214             :                                                             ncol_local, nrow_local, xyz
     215           0 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices, row_indices
     216             :       REAL(KIND=dp)                                      :: E_HOMO, E_i, E_j, E_LUMO
     217             :       TYPE(cp_fm_type)                                   :: fm_V_ao, fm_V_mo, fm_work
     218             : 
     219           0 :       CALL timeset(routineN, handle)
     220             : 
     221           0 :       CALL cp_fm_create(fm_work, fm_s%matrix_struct)
     222           0 :       CALL cp_fm_create(fm_V_ao, fm_s%matrix_struct)
     223           0 :       CALL cp_fm_create(fm_V_mo, fm_s%matrix_struct)
     224             : 
     225             :       CALL cp_fm_get_info(matrix=fm_s, &
     226             :                           nrow_local=nrow_local, &
     227             :                           ncol_local=ncol_local, &
     228             :                           row_indices=row_indices, &
     229           0 :                           col_indices=col_indices)
     230             : 
     231           0 :       nao = SIZE(eigenval)
     232             : 
     233           0 :       E_HOMO = eigenval(homo)
     234           0 :       E_LUMO = eigenval(homo + 1)
     235             : 
     236           0 :       DO xyz = 1, 3
     237             : 
     238           0 :          CALL copy_dbcsr_to_fm(mat_V_SOC_xyz(xyz)%matrix, fm_V_ao)
     239             : 
     240             :          ! V_MO = C^T*V_AO*C
     241             :          CALL parallel_gemm(transa="N", transb="N", m=nao, n=nao, k=nao, alpha=1.0_dp, &
     242           0 :                             matrix_a=fm_V_ao, matrix_b=fm_mo_coeff, beta=0.0_dp, matrix_c=fm_work)
     243             : 
     244             :          CALL parallel_gemm(transa="T", transb="N", m=nao, n=nao, k=nao, alpha=1.0_dp, &
     245           0 :                             matrix_a=fm_mo_coeff, matrix_b=fm_work, beta=0.0_dp, matrix_c=fm_V_mo)
     246             : 
     247           0 :          DO jjB = 1, ncol_local
     248           0 :             j_glob = col_indices(jjB)
     249           0 :             DO iiB = 1, nrow_local
     250           0 :                i_glob = row_indices(iiB)
     251             : 
     252           0 :                E_i = eigenval(i_glob)
     253           0 :                E_j = eigenval(j_glob)
     254             : 
     255             :                IF (E_i < E_HOMO - 0.5_dp*e_win .OR. E_i > E_LUMO + 0.5_dp*e_win .OR. &
     256           0 :                    E_j < E_HOMO - 0.5_dp*e_win .OR. E_j > E_LUMO + 0.5_dp*e_win) THEN
     257           0 :                   fm_V_mo%local_data(iiB, jjB) = 0.0_dp
     258             :                END IF
     259             : 
     260             :             END DO
     261             :          END DO
     262             : 
     263             :          ! V_AO = S*C*V_MO*C^T*S
     264             :          CALL parallel_gemm(transa="N", transb="T", m=nao, n=nao, k=nao, alpha=1.0_dp, &
     265           0 :                             matrix_a=fm_V_mo, matrix_b=fm_mo_coeff, beta=0.0_dp, matrix_c=fm_work)
     266             : 
     267             :          CALL parallel_gemm(transa="N", transb="N", m=nao, n=nao, k=nao, alpha=1.0_dp, &
     268           0 :                             matrix_a=fm_mo_coeff, matrix_b=fm_work, beta=0.0_dp, matrix_c=fm_V_ao)
     269             : 
     270             :          CALL parallel_gemm(transa="N", transb="N", m=nao, n=nao, k=nao, alpha=1.0_dp, &
     271           0 :                             matrix_a=fm_s, matrix_b=fm_V_ao, beta=0.0_dp, matrix_c=fm_work)
     272             : 
     273             :          CALL parallel_gemm(transa="N", transb="N", m=nao, n=nao, k=nao, alpha=1.0_dp, &
     274           0 :                             matrix_a=fm_work, matrix_b=fm_s, beta=0.0_dp, matrix_c=fm_V_ao)
     275             : 
     276           0 :          CALL copy_fm_to_dbcsr(fm_V_ao, mat_V_SOC_xyz(xyz)%matrix)
     277             : 
     278             :       END DO
     279             : 
     280           0 :       CALL cp_fm_release(fm_work)
     281           0 :       CALL cp_fm_release(fm_V_ao)
     282           0 :       CALL cp_fm_release(fm_V_mo)
     283             : 
     284           0 :       CALL timestop(handle)
     285             : 
     286           0 :    END SUBROUTINE remove_soc_outside_energy_window_ao
     287             : 
     288             : ! **************************************************************************************************
     289             : !> \brief ...
     290             : !> \param cfm_ks_spinor ...
     291             : !> \param e_win ...
     292             : !> \param eigenval ...
     293             : !> \param E_HOMO ...
     294             : !> \param E_LUMO ...
     295             : ! **************************************************************************************************
     296         480 :    SUBROUTINE remove_soc_outside_energy_window_mo(cfm_ks_spinor, e_win, eigenval, E_HOMO, E_LUMO)
     297             :       TYPE(cp_cfm_type)                                  :: cfm_ks_spinor
     298             :       REAL(KIND=dp)                                      :: e_win
     299             :       REAL(KIND=dp), DIMENSION(:)                        :: eigenval
     300             :       REAL(KIND=dp)                                      :: E_HOMO, E_LUMO
     301             : 
     302             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'remove_soc_outside_energy_window_mo'
     303             : 
     304             :       INTEGER                                            :: handle, i_glob, iiB, j_glob, jjB, &
     305             :                                                             ncol_global, ncol_local, nrow_global, &
     306             :                                                             nrow_local
     307         480 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices, row_indices
     308             :       REAL(KIND=dp)                                      :: E_i, E_j
     309             : 
     310             :       ! Remove SOC outside of energy window (otherwise, numerical problems arise
     311             :       ! because energetically low semicore states and energetically very high
     312             :       ! unbound states couple to the states around the Fermi level).
     313             :       ! This routine is for cfm_ks_spinor being in the molecular-orbital (mo) with
     314             :       ! corresponding eigenvalues "eigenval".
     315             : 
     316         480 :       CALL timeset(routineN, handle)
     317             : 
     318             :       CALL cp_cfm_get_info(matrix=cfm_ks_spinor, &
     319             :                            nrow_global=nrow_global, &
     320             :                            ncol_global=ncol_global, &
     321             :                            nrow_local=nrow_local, &
     322             :                            ncol_local=ncol_local, &
     323             :                            row_indices=row_indices, &
     324         480 :                            col_indices=col_indices)
     325             : 
     326         480 :       CPASSERT(nrow_global == SIZE(eigenval))
     327         480 :       CPASSERT(ncol_global == SIZE(eigenval))
     328             : 
     329        9760 :       DO jjB = 1, ncol_local
     330        9280 :          j_glob = col_indices(jjB)
     331      102240 :          DO iiB = 1, nrow_local
     332       92480 :             i_glob = row_indices(iiB)
     333             : 
     334       92480 :             E_i = eigenval(i_glob)
     335       92480 :             E_j = eigenval(j_glob)
     336             : 
     337             :             IF (E_i < E_HOMO - 0.5_dp*e_win .OR. E_i > E_LUMO + 0.5_dp*e_win .OR. &
     338      101760 :                 E_j < E_HOMO - 0.5_dp*e_win .OR. E_j > E_LUMO + 0.5_dp*e_win) THEN
     339       71992 :                cfm_ks_spinor%local_data(iiB, jjB) = 0.0_dp
     340             :             END IF
     341             : 
     342             :          END DO
     343             :       END DO
     344             : 
     345         480 :       CALL timestop(handle)
     346             : 
     347         480 :    END SUBROUTINE remove_soc_outside_energy_window_mo
     348             : 
     349             : END MODULE soc_pseudopotential_methods

Generated by: LCOV version 1.15