LCOV - code coverage report
Current view: top level - src - post_scf_bandstructure_utils.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:d1f8d1b) Lines: 1073 1139 94.2 %
Date: 2024-11-29 06:42:44 Functions: 36 37 97.3 %

          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             : ! **************************************************************************************************
       9             : !> \brief
      10             : !> \author Jan Wilhelm
      11             : !> \date 07.2023
      12             : ! **************************************************************************************************
      13             : MODULE post_scf_bandstructure_utils
      14             :    USE atomic_kind_types,               ONLY: atomic_kind_type,&
      15             :                                               get_atomic_kind,&
      16             :                                               get_atomic_kind_set
      17             :    USE cell_types,                      ONLY: cell_type,&
      18             :                                               get_cell,&
      19             :                                               pbc
      20             :    USE cp_blacs_env,                    ONLY: cp_blacs_env_type
      21             :    USE cp_cfm_basic_linalg,             ONLY: cp_cfm_cholesky_decompose,&
      22             :                                               cp_cfm_scale
      23             :    USE cp_cfm_diag,                     ONLY: cp_cfm_geeig,&
      24             :                                               cp_cfm_geeig_canon,&
      25             :                                               cp_cfm_heevd
      26             :    USE cp_cfm_types,                    ONLY: cp_cfm_create,&
      27             :                                               cp_cfm_get_info,&
      28             :                                               cp_cfm_release,&
      29             :                                               cp_cfm_set_all,&
      30             :                                               cp_cfm_to_cfm,&
      31             :                                               cp_cfm_to_fm,&
      32             :                                               cp_cfm_type,&
      33             :                                               cp_fm_to_cfm
      34             :    USE cp_control_types,                ONLY: dft_control_type
      35             :    USE cp_dbcsr_api,                    ONLY: &
      36             :         dbcsr_create, dbcsr_deallocate_matrix, dbcsr_desymmetrize, dbcsr_p_type, dbcsr_set, &
      37             :         dbcsr_type, dbcsr_type_antisymmetric, dbcsr_type_no_symmetry, dbcsr_type_symmetric
      38             :    USE cp_dbcsr_cp2k_link,              ONLY: cp_dbcsr_alloc_block_from_nbl
      39             :    USE cp_dbcsr_operations,             ONLY: copy_dbcsr_to_fm,&
      40             :                                               copy_fm_to_dbcsr,&
      41             :                                               dbcsr_allocate_matrix_set,&
      42             :                                               dbcsr_deallocate_matrix_set
      43             :    USE cp_files,                        ONLY: close_file,&
      44             :                                               open_file
      45             :    USE cp_fm_diag,                      ONLY: cp_fm_geeig_canon
      46             :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      47             :                                               cp_fm_struct_release,&
      48             :                                               cp_fm_struct_type
      49             :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      50             :                                               cp_fm_get_diag,&
      51             :                                               cp_fm_get_info,&
      52             :                                               cp_fm_release,&
      53             :                                               cp_fm_set_all,&
      54             :                                               cp_fm_to_fm,&
      55             :                                               cp_fm_type
      56             :    USE cp_log_handling,                 ONLY: cp_logger_get_default_io_unit
      57             :    USE cp_parser_methods,               ONLY: read_float_object
      58             :    USE input_constants,                 ONLY: int_ldos_z,&
      59             :                                               large_cell_Gamma,&
      60             :                                               small_cell_full_kp
      61             :    USE input_section_types,             ONLY: section_vals_get,&
      62             :                                               section_vals_get_subs_vals,&
      63             :                                               section_vals_type,&
      64             :                                               section_vals_val_get
      65             :    USE kinds,                           ONLY: default_string_length,&
      66             :                                               dp,&
      67             :                                               max_line_length
      68             :    USE kpoint_methods,                  ONLY: kpoint_init_cell_index,&
      69             :                                               rskp_transform
      70             :    USE kpoint_types,                    ONLY: get_kpoint_info,&
      71             :                                               kpoint_create,&
      72             :                                               kpoint_type
      73             :    USE machine,                         ONLY: m_walltime
      74             :    USE mathconstants,                   ONLY: gaussi,&
      75             :                                               twopi,&
      76             :                                               z_one,&
      77             :                                               z_zero
      78             :    USE message_passing,                 ONLY: mp_para_env_type
      79             :    USE parallel_gemm_api,               ONLY: parallel_gemm
      80             :    USE particle_types,                  ONLY: particle_type
      81             :    USE physcon,                         ONLY: angstrom,&
      82             :                                               evolt
      83             :    USE post_scf_bandstructure_types,    ONLY: band_edges_type,&
      84             :                                               post_scf_bandstructure_type
      85             :    USE pw_env_types,                    ONLY: pw_env_get,&
      86             :                                               pw_env_type
      87             :    USE pw_pool_types,                   ONLY: pw_pool_type
      88             :    USE pw_types,                        ONLY: pw_c1d_gs_type,&
      89             :                                               pw_r3d_rs_type
      90             :    USE qs_collocate_density,            ONLY: calculate_rho_elec
      91             :    USE qs_environment_types,            ONLY: get_qs_env,&
      92             :                                               qs_environment_type
      93             :    USE qs_ks_types,                     ONLY: qs_ks_env_type
      94             :    USE qs_mo_types,                     ONLY: get_mo_set,&
      95             :                                               mo_set_type
      96             :    USE qs_neighbor_list_types,          ONLY: neighbor_list_set_p_type
      97             :    USE rpa_gw_im_time_util,             ONLY: compute_weight_re_im,&
      98             :                                               get_atom_index_from_basis_function_index
      99             :    USE scf_control_types,               ONLY: scf_control_type
     100             :    USE soc_pseudopotential_methods,     ONLY: V_SOC_xyz_from_pseudopotential,&
     101             :                                               remove_soc_outside_energy_window_mo
     102             :    USE soc_pseudopotential_utils,       ONLY: add_cfm_submat,&
     103             :                                               add_dbcsr_submat,&
     104             :                                               cfm_add_on_diag,&
     105             :                                               create_cfm_double,&
     106             :                                               get_cfm_submat
     107             : #include "base/base_uses.f90"
     108             : 
     109             :    IMPLICIT NONE
     110             : 
     111             :    PRIVATE
     112             : 
     113             :    PUBLIC :: create_and_init_bs_env, &
     114             :              dos_pdos_ldos, cfm_ikp_from_fm_Gamma, MIC_contribution_from_ikp, &
     115             :              compute_xkp, kpoint_init_cell_index_simple, rsmat_to_kp, soc, &
     116             :              get_VBM_CBM_bandgaps, get_all_VBM_CBM_bandgaps
     117             : 
     118             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'post_scf_bandstructure_utils'
     119             : 
     120             : CONTAINS
     121             : 
     122             : ! **************************************************************************************************
     123             : !> \brief ...
     124             : !> \param qs_env ...
     125             : !> \param bs_env ...
     126             : !> \param post_scf_bandstructure_section ...
     127             : ! **************************************************************************************************
     128          34 :    SUBROUTINE create_and_init_bs_env(qs_env, bs_env, post_scf_bandstructure_section)
     129             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     130             :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
     131             :       TYPE(section_vals_type), POINTER                   :: post_scf_bandstructure_section
     132             : 
     133             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'create_and_init_bs_env'
     134             : 
     135             :       INTEGER                                            :: handle
     136             : 
     137          34 :       CALL timeset(routineN, handle)
     138             : 
     139        3400 :       ALLOCATE (bs_env)
     140             : 
     141          34 :       CALL print_header(bs_env)
     142             : 
     143          34 :       CALL read_bandstructure_input_parameters(bs_env, post_scf_bandstructure_section)
     144             : 
     145          34 :       CALL get_parameters_from_qs_env(qs_env, bs_env)
     146             : 
     147          34 :       CALL set_heuristic_parameters(bs_env)
     148             : 
     149          62 :       SELECT CASE (bs_env%small_cell_full_kp_or_large_cell_Gamma)
     150             :       CASE (large_cell_Gamma)
     151             : 
     152          28 :          CALL setup_kpoints_DOS_large_cell_Gamma(qs_env, bs_env, bs_env%kpoints_DOS)
     153             : 
     154          28 :          CALL allocate_and_fill_fm_ks_fm_s(qs_env, bs_env)
     155             : 
     156          28 :          CALL diagonalize_ks_matrix(bs_env)
     157             : 
     158          28 :          CALL check_positive_definite_overlap_mat(bs_env, qs_env)
     159             : 
     160             :       CASE (small_cell_full_kp)
     161             : 
     162           6 :          CALL setup_kpoints_scf_desymm(qs_env, bs_env, bs_env%kpoints_scf_desymm, .TRUE.)
     163           6 :          CALL setup_kpoints_scf_desymm(qs_env, bs_env, bs_env%kpoints_scf_desymm_2, .FALSE.)
     164             : 
     165           6 :          CALL setup_kpoints_DOS_small_cell_full_kp(bs_env, bs_env%kpoints_DOS)
     166             : 
     167           6 :          CALL allocate_and_fill_fm_ks_fm_s(qs_env, bs_env)
     168             : 
     169          40 :          CALL compute_cfm_mo_coeff_kp_and_eigenval_scf_kp(qs_env, bs_env)
     170             : 
     171             :       END SELECT
     172             : 
     173          34 :       CALL timestop(handle)
     174             : 
     175          34 :    END SUBROUTINE create_and_init_bs_env
     176             : 
     177             : ! **************************************************************************************************
     178             : !> \brief ...
     179             : !> \param bs_env ...
     180             : !> \param bs_sec ...
     181             : ! **************************************************************************************************
     182          34 :    SUBROUTINE read_bandstructure_input_parameters(bs_env, bs_sec)
     183             :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
     184             :       TYPE(section_vals_type), POINTER                   :: bs_sec
     185             : 
     186             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'read_bandstructure_input_parameters'
     187             : 
     188             :       CHARACTER(LEN=default_string_length), &
     189          34 :          DIMENSION(:), POINTER                           :: string_ptr
     190             :       CHARACTER(LEN=max_line_length)                     :: error_msg
     191             :       INTEGER                                            :: handle, i, ikp
     192             :       TYPE(section_vals_type), POINTER                   :: gw_sec, kp_bs_sec, ldos_sec, soc_sec
     193             : 
     194          34 :       CALL timeset(routineN, handle)
     195             : 
     196          34 :       NULLIFY (gw_sec)
     197          34 :       gw_sec => section_vals_get_subs_vals(bs_sec, "GW")
     198          34 :       CALL section_vals_get(gw_sec, explicit=bs_env%do_gw)
     199             : 
     200          34 :       NULLIFY (soc_sec)
     201          34 :       soc_sec => section_vals_get_subs_vals(bs_sec, "SOC")
     202          34 :       CALL section_vals_get(soc_sec, explicit=bs_env%do_soc)
     203             : 
     204          34 :       CALL section_vals_val_get(soc_sec, "ENERGY_WINDOW", r_val=bs_env%energy_window_soc)
     205             : 
     206          34 :       CALL section_vals_val_get(bs_sec, "DOS%KPOINTS", i_vals=bs_env%nkp_grid_DOS_input)
     207          34 :       CALL section_vals_val_get(bs_sec, "DOS%ENERGY_WINDOW", r_val=bs_env%energy_window_DOS)
     208          34 :       CALL section_vals_val_get(bs_sec, "DOS%ENERGY_STEP", r_val=bs_env%energy_step_DOS)
     209          34 :       CALL section_vals_val_get(bs_sec, "DOS%BROADENING", r_val=bs_env%broadening_DOS)
     210             : 
     211          34 :       NULLIFY (ldos_sec)
     212          34 :       ldos_sec => section_vals_get_subs_vals(bs_sec, "DOS%LDOS")
     213          34 :       CALL section_vals_get(ldos_sec, explicit=bs_env%do_ldos)
     214             : 
     215          34 :       CALL section_vals_val_get(ldos_sec, "INTEGRATION", i_val=bs_env%int_ldos_xyz)
     216          34 :       CALL section_vals_val_get(ldos_sec, "BIN_MESH", i_vals=bs_env%bin_mesh)
     217             : 
     218          34 :       NULLIFY (kp_bs_sec)
     219          34 :       kp_bs_sec => section_vals_get_subs_vals(bs_sec, "BANDSTRUCTURE_PATH")
     220          34 :       CALL section_vals_val_get(kp_bs_sec, "NPOINTS", i_val=bs_env%input_kp_bs_npoints)
     221          34 :       CALL section_vals_val_get(kp_bs_sec, "SPECIAL_POINT", n_rep_val=bs_env%input_kp_bs_n_sp_pts)
     222             : 
     223             :       ! read special points for band structure
     224          72 :       ALLOCATE (bs_env%xkp_special(3, bs_env%input_kp_bs_n_sp_pts))
     225          50 :       DO ikp = 1, bs_env%input_kp_bs_n_sp_pts
     226          16 :          CALL section_vals_val_get(kp_bs_sec, "SPECIAL_POINT", i_rep_val=ikp, c_vals=string_ptr)
     227          16 :          CPASSERT(SIZE(string_ptr(:), 1) == 4)
     228          98 :          DO i = 1, 3
     229          48 :             CALL read_float_object(string_ptr(i + 1), bs_env%xkp_special(i, ikp), error_msg)
     230          64 :             IF (LEN_TRIM(error_msg) > 0) CPABORT(TRIM(error_msg))
     231             :          END DO
     232             :       END DO
     233             : 
     234          34 :       CALL timestop(handle)
     235             : 
     236          34 :    END SUBROUTINE read_bandstructure_input_parameters
     237             : 
     238             : ! **************************************************************************************************
     239             : !> \brief ...
     240             : !> \param bs_env ...
     241             : ! **************************************************************************************************
     242          34 :    SUBROUTINE print_header(bs_env)
     243             : 
     244             :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
     245             : 
     246             :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'print_header'
     247             : 
     248             :       INTEGER                                            :: handle, u
     249             : 
     250          34 :       CALL timeset(routineN, handle)
     251             : 
     252          34 :       bs_env%unit_nr = cp_logger_get_default_io_unit()
     253             : 
     254          34 :       u = bs_env%unit_nr
     255             : 
     256          34 :       IF (u > 0) THEN
     257          17 :          WRITE (u, *) ' '
     258          17 :          WRITE (u, '(T2,2A)') '-------------------------------------------------', &
     259          34 :             '------------------------------'
     260          17 :          WRITE (u, '(T2,2A)') '-                                                ', &
     261          34 :             '                             -'
     262          17 :          WRITE (u, '(T2,2A)') '-                          BANDSTRUCTURE CALCULATION', &
     263          34 :             '                          -'
     264          17 :          WRITE (u, '(T2,2A)') '-                                                ', &
     265          34 :             '                             -'
     266          17 :          WRITE (u, '(T2,2A)') '--------------------------------------------------', &
     267          34 :             '-----------------------------'
     268          17 :          WRITE (u, '(T2,A)') ' '
     269             :       END IF
     270             : 
     271          34 :       CALL timestop(handle)
     272             : 
     273          34 :    END SUBROUTINE print_header
     274             : 
     275             : ! **************************************************************************************************
     276             : !> \brief ...
     277             : !> \param qs_env ...
     278             : !> \param bs_env ...
     279             : !> \param kpoints ...
     280             : ! **************************************************************************************************
     281          28 :    SUBROUTINE setup_kpoints_DOS_large_cell_Gamma(qs_env, bs_env, kpoints)
     282             : 
     283             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     284             :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
     285             :       TYPE(kpoint_type), POINTER                         :: kpoints
     286             : 
     287             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'setup_kpoints_DOS_large_cell_Gamma'
     288             : 
     289             :       INTEGER                                            :: handle, i_dim, i_kp_in_line, &
     290             :                                                             i_special_kp, ikk, n_kp_in_line, &
     291             :                                                             n_special_kp, nkp, nkp_only_bs, &
     292             :                                                             nkp_only_DOS, u
     293             :       INTEGER, DIMENSION(3)                              :: nkp_grid, periodic
     294             : 
     295          28 :       CALL timeset(routineN, handle)
     296             : 
     297             :       ! routine adapted from mp2_integrals.F
     298          28 :       NULLIFY (kpoints)
     299          28 :       CALL kpoint_create(kpoints)
     300             : 
     301          28 :       kpoints%kp_scheme = "GENERAL"
     302             : 
     303          28 :       n_special_kp = bs_env%input_kp_bs_n_sp_pts
     304          28 :       n_kp_in_line = bs_env%input_kp_bs_npoints
     305             : 
     306         112 :       periodic(1:3) = bs_env%periodic(1:3)
     307             : 
     308         112 :       DO i_dim = 1, 3
     309             : 
     310          84 :          CPASSERT(periodic(i_dim) == 0 .OR. periodic(i_dim) == 1)
     311             : 
     312         112 :          IF (bs_env%nkp_grid_DOS_input(i_dim) < 0) THEN
     313          60 :             IF (periodic(i_dim) == 1) nkp_grid(i_dim) = 2
     314          60 :             IF (periodic(i_dim) == 0) nkp_grid(i_dim) = 1
     315             :          ELSE
     316          24 :             nkp_grid(i_dim) = bs_env%nkp_grid_DOS_input(i_dim)
     317             :          END IF
     318             : 
     319             :       END DO
     320             : 
     321             :       ! use the k <-> -k symmetry to reduce the number of kpoints
     322          28 :       IF (nkp_grid(1) > 1) THEN
     323           8 :          nkp_only_DOS = (nkp_grid(1) + 1)/2*nkp_grid(2)*nkp_grid(3)
     324          20 :       ELSE IF (nkp_grid(2) > 1) THEN
     325           4 :          nkp_only_DOS = nkp_grid(1)*(nkp_grid(2) + 1)/2*nkp_grid(3)
     326          16 :       ELSE IF (nkp_grid(3) > 1) THEN
     327           4 :          nkp_only_DOS = nkp_grid(1)*nkp_grid(2)*(nkp_grid(3) + 1)/2
     328             :       ELSE
     329          12 :          nkp_only_DOS = 1
     330             :       END IF
     331             : 
     332             :       ! we will compute the GW QP levels for all k's in the bandstructure path but also
     333             :       ! for all k-points from the SCF (e.g. for DOS or for self-consistent GW)
     334          28 :       IF (n_special_kp > 0) THEN
     335           0 :          nkp_only_bs = n_kp_in_line*(n_special_kp - 1) + 1
     336             :       ELSE
     337             :          nkp_only_bs = 0
     338             :       END IF
     339             : 
     340          28 :       nkp = nkp_only_DOS + nkp_only_bs
     341             : 
     342         112 :       kpoints%nkp_grid(1:3) = nkp_grid(1:3)
     343          28 :       kpoints%nkp = nkp
     344             : 
     345          28 :       bs_env%nkp_bs_and_DOS = nkp
     346          28 :       bs_env%nkp_only_bs = nkp_only_bs
     347          28 :       bs_env%nkp_only_DOS = nkp_only_DOS
     348             : 
     349         140 :       ALLOCATE (kpoints%xkp(3, nkp), kpoints%wkp(nkp))
     350          68 :       kpoints%wkp(1:nkp_only_DOS) = 1.0_dp/REAL(nkp_only_DOS, KIND=dp)
     351             : 
     352          28 :       CALL compute_xkp(kpoints%xkp, 1, nkp_only_DOS, nkp_grid)
     353             : 
     354          28 :       IF (n_special_kp > 0) THEN
     355           0 :          kpoints%xkp(1:3, nkp_only_DOS + 1) = bs_env%xkp_special(1:3, 1)
     356           0 :          ikk = nkp_only_DOS + 1
     357           0 :          DO i_special_kp = 2, n_special_kp
     358           0 :             DO i_kp_in_line = 1, n_kp_in_line
     359           0 :                ikk = ikk + 1
     360             :                kpoints%xkp(1:3, ikk) = bs_env%xkp_special(1:3, i_special_kp - 1) + &
     361             :                                        REAL(i_kp_in_line, KIND=dp)/REAL(n_kp_in_line, KIND=dp)* &
     362             :                                        (bs_env%xkp_special(1:3, i_special_kp) - &
     363           0 :                                         bs_env%xkp_special(1:3, i_special_kp - 1))
     364           0 :                kpoints%wkp(ikk) = 0.0_dp
     365             :             END DO
     366             :          END DO
     367             :       END IF
     368             : 
     369          28 :       CALL kpoint_init_cell_index_simple(kpoints, qs_env)
     370             : 
     371          28 :       u = bs_env%unit_nr
     372             : 
     373          28 :       IF (u > 0) THEN
     374          14 :          IF (nkp_only_bs > 0) THEN
     375             :             WRITE (u, FMT="(T2,1A,T77,I4)") &
     376           0 :                "Number of special k-points for the bandstructure", n_special_kp
     377           0 :             WRITE (u, FMT="(T2,1A,T77,I4)") "Number of k-points for the bandstructure", nkp
     378             :             WRITE (u, FMT="(T2,1A,T69,3I4)") &
     379           0 :                "K-point mesh for the density of states (DOS)", nkp_grid(1:3)
     380             :          ELSE
     381             :             WRITE (u, FMT="(T2,1A,T69,3I4)") &
     382          14 :                "K-point mesh for the density of states (DOS) and the self-energy", nkp_grid(1:3)
     383             :          END IF
     384             :       END IF
     385             : 
     386          28 :       CALL timestop(handle)
     387             : 
     388          28 :    END SUBROUTINE setup_kpoints_DOS_large_cell_Gamma
     389             : 
     390             : ! **************************************************************************************************
     391             : !> \brief ...
     392             : !> \param qs_env ...
     393             : !> \param bs_env ...
     394             : !> \param kpoints ...
     395             : !> \param do_print ...
     396             : ! **************************************************************************************************
     397          12 :    SUBROUTINE setup_kpoints_scf_desymm(qs_env, bs_env, kpoints, do_print)
     398             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     399             :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
     400             :       TYPE(kpoint_type), POINTER                         :: kpoints
     401             : 
     402             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'setup_kpoints_scf_desymm'
     403             : 
     404             :       INTEGER                                            :: handle, i_cell_x, i_dim, img, j_cell_y, &
     405             :                                                             k_cell_z, nimages, nkp, u
     406             :       INTEGER, DIMENSION(3)                              :: cell_grid, cixd, nkp_grid
     407             :       TYPE(kpoint_type), POINTER                         :: kpoints_scf
     408             : 
     409             :       LOGICAL:: do_print
     410             : 
     411          12 :       CALL timeset(routineN, handle)
     412             : 
     413          12 :       NULLIFY (kpoints)
     414          12 :       CALL kpoint_create(kpoints)
     415             : 
     416          12 :       CALL get_qs_env(qs_env=qs_env, kpoints=kpoints_scf)
     417             : 
     418          48 :       nkp_grid(1:3) = kpoints_scf%nkp_grid(1:3)
     419          12 :       nkp = nkp_grid(1)*nkp_grid(2)*nkp_grid(3)
     420             : 
     421             :       ! we need in periodic directions at least 4 k-points in the SCF
     422          48 :       DO i_dim = 1, 3
     423          48 :          IF (bs_env%periodic(i_dim) == 1) THEN
     424          24 :             CPASSERT(nkp_grid(i_dim) .GE. 4)
     425             :          END IF
     426             :       END DO
     427             : 
     428          12 :       kpoints%kp_scheme = "GENERAL"
     429          48 :       kpoints%nkp_grid(1:3) = nkp_grid(1:3)
     430          12 :       kpoints%nkp = nkp
     431          12 :       bs_env%nkp_scf_desymm = nkp
     432             : 
     433          36 :       ALLOCATE (kpoints%xkp(1:3, nkp))
     434          12 :       CALL compute_xkp(kpoints%xkp, 1, nkp, nkp_grid)
     435             : 
     436          36 :       ALLOCATE (kpoints%wkp(nkp))
     437         204 :       kpoints%wkp(:) = 1.0_dp/REAL(nkp, KIND=dp)
     438             : 
     439             :       ! for example 4x3x6 kpoint grid -> 3x3x5 cell grid because we need the same number of
     440             :       ! neighbor cells on both sides of the unit cell
     441          48 :       cell_grid(1:3) = nkp_grid(1:3) - MODULO(nkp_grid(1:3) + 1, 2)
     442             : 
     443             :       ! cell index: for example for x: from -n_x/2 to +n_x/2, n_x: number of cells in x direction
     444          48 :       cixd(1:3) = cell_grid(1:3)/2
     445             : 
     446          12 :       nimages = cell_grid(1)*cell_grid(2)*cell_grid(3)
     447             : 
     448          12 :       bs_env%nimages_scf_desymm = nimages
     449          48 :       bs_env%cell_grid_scf_desymm(1:3) = cell_grid(1:3)
     450             : 
     451          12 :       IF (ASSOCIATED(kpoints%index_to_cell)) DEALLOCATE (kpoints%index_to_cell)
     452          12 :       IF (ASSOCIATED(kpoints%cell_to_index)) DEALLOCATE (kpoints%cell_to_index)
     453             : 
     454          60 :       ALLOCATE (kpoints%cell_to_index(-cixd(1):cixd(1), -cixd(2):cixd(2), -cixd(3):cixd(3)))
     455          36 :       ALLOCATE (kpoints%index_to_cell(nimages, 3))
     456             : 
     457          12 :       img = 0
     458          40 :       DO i_cell_x = -cixd(1), cixd(1)
     459         124 :          DO j_cell_y = -cixd(2), cixd(2)
     460         220 :             DO k_cell_z = -cixd(3), cixd(3)
     461         108 :                img = img + 1
     462         108 :                kpoints%cell_to_index(i_cell_x, j_cell_y, k_cell_z) = img
     463         516 :                kpoints%index_to_cell(img, 1:3) = (/i_cell_x, j_cell_y, k_cell_z/)
     464             :             END DO
     465             :          END DO
     466             :       END DO
     467             : 
     468          12 :       u = bs_env%unit_nr
     469          12 :       IF (u > 0 .AND. do_print) THEN
     470           3 :          WRITE (u, FMT="(T2,A,I49)") "Number of cells for G, χ, W, Σ", nimages
     471             :       END IF
     472             : 
     473          12 :       CALL timestop(handle)
     474             : 
     475          12 :    END SUBROUTINE setup_kpoints_scf_desymm
     476             : 
     477             : ! **************************************************************************************************
     478             : !> \brief ...
     479             : !> \param bs_env ...
     480             : !> \param kpoints ...
     481             : ! **************************************************************************************************
     482           6 :    SUBROUTINE setup_kpoints_DOS_small_cell_full_kp(bs_env, kpoints)
     483             : 
     484             :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
     485             :       TYPE(kpoint_type), POINTER                         :: kpoints
     486             : 
     487             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'setup_kpoints_DOS_small_cell_full_kp'
     488             : 
     489             :       INTEGER                                            :: handle, i_kp_in_line, i_special_kp, ikk, &
     490             :                                                             n_kp_in_line, n_special_kp, nkp, &
     491             :                                                             nkp_only_bs, nkp_scf_desymm, u
     492             : 
     493           6 :       CALL timeset(routineN, handle)
     494             : 
     495             :       ! routine adapted from mp2_integrals.F
     496           6 :       NULLIFY (kpoints)
     497           6 :       CALL kpoint_create(kpoints)
     498             : 
     499           6 :       n_special_kp = bs_env%input_kp_bs_n_sp_pts
     500           6 :       n_kp_in_line = bs_env%input_kp_bs_npoints
     501           6 :       nkp_scf_desymm = bs_env%nkp_scf_desymm
     502             : 
     503             :       ! we will compute the GW QP levels for all k's in the bandstructure path but also
     504             :       ! for all k-points from the SCF (e.g. for DOS or for self-consistent GW)
     505           6 :       IF (n_special_kp > 0) THEN
     506           4 :          nkp_only_bs = n_kp_in_line*(n_special_kp - 1) + 1
     507             :       ELSE
     508             :          nkp_only_bs = 0
     509             :       END IF
     510           6 :       nkp = nkp_only_bs + nkp_scf_desymm
     511             : 
     512          18 :       ALLOCATE (kpoints%xkp(3, nkp))
     513          18 :       ALLOCATE (kpoints%wkp(nkp))
     514             : 
     515           6 :       kpoints%nkp = nkp
     516             : 
     517           6 :       bs_env%nkp_bs_and_DOS = nkp
     518           6 :       bs_env%nkp_only_bs = nkp_only_bs
     519           6 :       bs_env%nkp_only_DOS = nkp_scf_desymm
     520             : 
     521         780 :       kpoints%xkp(1:3, 1:nkp_scf_desymm) = bs_env%kpoints_scf_desymm%xkp(1:3, 1:nkp_scf_desymm)
     522         102 :       kpoints%wkp(1:nkp_scf_desymm) = 1.0_dp/REAL(nkp_scf_desymm, KIND=dp)
     523             : 
     524           6 :       IF (n_special_kp > 0) THEN
     525          32 :          kpoints%xkp(1:3, nkp_scf_desymm + 1) = bs_env%xkp_special(1:3, 1)
     526           4 :          ikk = nkp_scf_desymm + 1
     527          16 :          DO i_special_kp = 2, n_special_kp
     528         136 :             DO i_kp_in_line = 1, n_kp_in_line
     529         120 :                ikk = ikk + 1
     530             :                kpoints%xkp(1:3, ikk) = bs_env%xkp_special(1:3, i_special_kp - 1) + &
     531             :                                        REAL(i_kp_in_line, KIND=dp)/REAL(n_kp_in_line, KIND=dp)* &
     532             :                                        (bs_env%xkp_special(1:3, i_special_kp) - &
     533         960 :                                         bs_env%xkp_special(1:3, i_special_kp - 1))
     534         132 :                kpoints%wkp(ikk) = 0.0_dp
     535             :             END DO
     536             :          END DO
     537             :       END IF
     538             : 
     539           6 :       IF (ASSOCIATED(kpoints%index_to_cell)) DEALLOCATE (kpoints%index_to_cell)
     540             : 
     541          18 :       ALLOCATE (kpoints%index_to_cell(bs_env%nimages_scf_desymm, 3))
     542         372 :       kpoints%index_to_cell(:, :) = bs_env%kpoints_scf_desymm%index_to_cell(:, :)
     543             : 
     544           6 :       u = bs_env%unit_nr
     545             : 
     546           6 :       IF (u > 0) THEN
     547           3 :          WRITE (u, FMT="(T2,1A,T77,I4)") "Number of special k-points for the bandstructure", &
     548           6 :             n_special_kp
     549           3 :          WRITE (u, FMT="(T2,1A,T77,I4)") "Number of k-points for the bandstructure", nkp
     550             :       END IF
     551             : 
     552           6 :       CALL timestop(handle)
     553             : 
     554           6 :    END SUBROUTINE setup_kpoints_DOS_small_cell_full_kp
     555             : 
     556             : ! **************************************************************************************************
     557             : !> \brief ...
     558             : !> \param qs_env ...
     559             : !> \param bs_env ...
     560             : ! **************************************************************************************************
     561           6 :    SUBROUTINE compute_cfm_mo_coeff_kp_and_eigenval_scf_kp(qs_env, bs_env)
     562             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     563             :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
     564             : 
     565             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'compute_cfm_mo_coeff_kp_and_eigenval_scf_kp'
     566             : 
     567             :       INTEGER                                            :: handle, ikp, ispin, nkp_bs_and_DOS
     568           6 :       INTEGER, DIMENSION(:, :, :), POINTER               :: cell_to_index_scf
     569             :       REAL(KIND=dp)                                      :: CBM, VBM
     570             :       REAL(KIND=dp), DIMENSION(3)                        :: xkp
     571             :       TYPE(cp_cfm_type)                                  :: cfm_ks, cfm_mos, cfm_s
     572           6 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: matrix_ks, matrix_s
     573             :       TYPE(kpoint_type), POINTER                         :: kpoints_scf
     574             :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
     575           6 :          POINTER                                         :: sab_nl
     576             : 
     577           6 :       CALL timeset(routineN, handle)
     578             : 
     579             :       CALL get_qs_env(qs_env, &
     580             :                       matrix_ks_kp=matrix_ks, &
     581             :                       matrix_s_kp=matrix_s, &
     582           6 :                       kpoints=kpoints_scf)
     583             : 
     584           6 :       NULLIFY (sab_nl)
     585           6 :       CALL get_kpoint_info(kpoints_scf, sab_nl=sab_nl, cell_to_index=cell_to_index_scf)
     586             : 
     587           6 :       CALL cp_cfm_create(cfm_ks, bs_env%cfm_work_mo%matrix_struct)
     588           6 :       CALL cp_cfm_create(cfm_s, bs_env%cfm_work_mo%matrix_struct)
     589           6 :       CALL cp_cfm_create(cfm_mos, bs_env%cfm_work_mo%matrix_struct)
     590             : 
     591             :       ! nkp_bs_and_DOS contains desymmetrized k-point mesh from SCF and k-points from GW bandstructure
     592           6 :       nkp_bs_and_DOS = bs_env%nkp_bs_and_DOS
     593             : 
     594          30 :       ALLOCATE (bs_env%eigenval_G0W0(bs_env%n_ao, nkp_bs_and_DOS, bs_env%n_spin))
     595          30 :       ALLOCATE (bs_env%eigenval_HF(bs_env%n_ao, nkp_bs_and_DOS, bs_env%n_spin))
     596         250 :       ALLOCATE (bs_env%cfm_mo_coeff_kp(nkp_bs_and_DOS, bs_env%n_spin))
     597         250 :       ALLOCATE (bs_env%cfm_ks_kp(nkp_bs_and_DOS, bs_env%n_spin))
     598         238 :       ALLOCATE (bs_env%cfm_s_kp(nkp_bs_and_DOS))
     599         226 :       DO ikp = 1, nkp_bs_and_DOS
     600         440 :       DO ispin = 1, bs_env%n_spin
     601         220 :          CALL cp_cfm_create(bs_env%cfm_mo_coeff_kp(ikp, ispin), bs_env%cfm_work_mo%matrix_struct)
     602         440 :          CALL cp_cfm_create(bs_env%cfm_ks_kp(ikp, ispin), bs_env%cfm_work_mo%matrix_struct)
     603             :       END DO
     604         226 :       CALL cp_cfm_create(bs_env%cfm_s_kp(ikp), bs_env%cfm_work_mo%matrix_struct)
     605             :       END DO
     606             : 
     607          12 :       DO ispin = 1, bs_env%n_spin
     608         226 :          DO ikp = 1, nkp_bs_and_DOS
     609             : 
     610         880 :             xkp(1:3) = bs_env%kpoints_DOS%xkp(1:3, ikp)
     611             : 
     612             :             ! h^KS^R -> h^KS(k)
     613         220 :             CALL rsmat_to_kp(matrix_ks, ispin, xkp, cell_to_index_scf, sab_nl, bs_env, cfm_ks)
     614             : 
     615             :             ! S^R -> S(k)
     616         220 :             CALL rsmat_to_kp(matrix_s, 1, xkp, cell_to_index_scf, sab_nl, bs_env, cfm_s)
     617             : 
     618             :             ! we store the complex KS matrix as fm matrix because the infrastructure for fm is
     619             :             ! much nicer compared to cfm
     620         220 :             CALL cp_cfm_to_cfm(cfm_ks, bs_env%cfm_ks_kp(ikp, ispin))
     621         220 :             CALL cp_cfm_to_cfm(cfm_s, bs_env%cfm_s_kp(ikp))
     622             : 
     623             :             ! Diagonalize KS-matrix via Rothaan-Hall equation:
     624             :             ! H^KS(k) C(k) = S(k) C(k) ε(k)
     625             :             CALL cp_cfm_geeig_canon(cfm_ks, cfm_s, cfm_mos, &
     626             :                                     bs_env%eigenval_scf(:, ikp, ispin), &
     627         220 :                                     bs_env%cfm_work_mo, bs_env%eps_eigval_mat_s)
     628             : 
     629             :             ! we store the complex MO coeff as fm matrix because the infrastructure for fm is
     630             :             ! much nicer compared to cfm
     631         226 :             CALL cp_cfm_to_cfm(cfm_mos, bs_env%cfm_mo_coeff_kp(ikp, ispin))
     632             : 
     633             :          END DO
     634             : 
     635         232 :          VBM = MAXVAL(bs_env%eigenval_scf(bs_env%n_occ(ispin), :, ispin))
     636         232 :          CBM = MINVAL(bs_env%eigenval_scf(bs_env%n_occ(ispin) + 1, :, ispin))
     637             : 
     638          12 :          bs_env%e_fermi(ispin) = 0.5_dp*(VBM + CBM)
     639             : 
     640             :       END DO
     641             : 
     642           6 :       CALL get_VBM_CBM_bandgaps(bs_env%band_edges_scf, bs_env%eigenval_scf, bs_env)
     643             : 
     644           6 :       CALL cp_cfm_release(cfm_ks)
     645           6 :       CALL cp_cfm_release(cfm_s)
     646           6 :       CALL cp_cfm_release(cfm_mos)
     647             : 
     648           6 :       CALL timestop(handle)
     649             : 
     650          12 :    END SUBROUTINE compute_cfm_mo_coeff_kp_and_eigenval_scf_kp
     651             : 
     652             : ! **************************************************************************************************
     653             : !> \brief ...
     654             : !> \param mat_rs ...
     655             : !> \param ispin ...
     656             : !> \param xkp ...
     657             : !> \param cell_to_index_scf ...
     658             : !> \param sab_nl ...
     659             : !> \param bs_env ...
     660             : !> \param cfm_kp ...
     661             : !> \param imag_rs_mat ...
     662             : ! **************************************************************************************************
     663        1320 :    SUBROUTINE rsmat_to_kp(mat_rs, ispin, xkp, cell_to_index_scf, sab_nl, bs_env, cfm_kp, imag_rs_mat)
     664             :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: mat_rs
     665             :       INTEGER                                            :: ispin
     666             :       REAL(KIND=dp), DIMENSION(3)                        :: xkp
     667             :       INTEGER, DIMENSION(:, :, :), POINTER               :: cell_to_index_scf
     668             :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
     669             :          POINTER                                         :: sab_nl
     670             :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
     671             :       TYPE(cp_cfm_type)                                  :: cfm_kp
     672             :       LOGICAL, OPTIONAL                                  :: imag_rs_mat
     673             : 
     674             :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'rsmat_to_kp'
     675             : 
     676             :       INTEGER                                            :: handle
     677             :       LOGICAL                                            :: imag_rs_mat_private
     678             :       TYPE(dbcsr_type), POINTER                          :: cmat, nsmat, rmat
     679             : 
     680        1320 :       CALL timeset(routineN, handle)
     681             : 
     682        1320 :       ALLOCATE (rmat, cmat, nsmat)
     683             : 
     684        1320 :       imag_rs_mat_private = .FALSE.
     685        1320 :       IF (PRESENT(imag_rs_mat)) imag_rs_mat_private = imag_rs_mat
     686             : 
     687         660 :       IF (imag_rs_mat_private) THEN
     688         660 :          CALL dbcsr_create(rmat, template=mat_rs(1, 1)%matrix, matrix_type=dbcsr_type_antisymmetric)
     689         660 :          CALL dbcsr_create(cmat, template=mat_rs(1, 1)%matrix, matrix_type=dbcsr_type_symmetric)
     690             :       ELSE
     691         660 :          CALL dbcsr_create(rmat, template=mat_rs(1, 1)%matrix, matrix_type=dbcsr_type_symmetric)
     692         660 :          CALL dbcsr_create(cmat, template=mat_rs(1, 1)%matrix, matrix_type=dbcsr_type_antisymmetric)
     693             :       END IF
     694        1320 :       CALL dbcsr_create(nsmat, template=mat_rs(1, 1)%matrix, matrix_type=dbcsr_type_no_symmetry)
     695        1320 :       CALL cp_dbcsr_alloc_block_from_nbl(rmat, sab_nl)
     696        1320 :       CALL cp_dbcsr_alloc_block_from_nbl(cmat, sab_nl)
     697             : 
     698        1320 :       CALL dbcsr_set(rmat, 0.0_dp)
     699        1320 :       CALL dbcsr_set(cmat, 0.0_dp)
     700             :       CALL rskp_transform(rmatrix=rmat, cmatrix=cmat, rsmat=mat_rs, ispin=ispin, &
     701        1320 :                           xkp=xkp, cell_to_index=cell_to_index_scf, sab_nl=sab_nl)
     702             : 
     703        1320 :       CALL dbcsr_desymmetrize(rmat, nsmat)
     704        1320 :       CALL copy_dbcsr_to_fm(nsmat, bs_env%fm_work_mo(1))
     705        1320 :       CALL dbcsr_desymmetrize(cmat, nsmat)
     706        1320 :       CALL copy_dbcsr_to_fm(nsmat, bs_env%fm_work_mo(2))
     707        1320 :       CALL cp_fm_to_cfm(bs_env%fm_work_mo(1), bs_env%fm_work_mo(2), cfm_kp)
     708             : 
     709        1320 :       CALL dbcsr_deallocate_matrix(rmat)
     710        1320 :       CALL dbcsr_deallocate_matrix(cmat)
     711        1320 :       CALL dbcsr_deallocate_matrix(nsmat)
     712             : 
     713        1320 :       CALL timestop(handle)
     714             : 
     715        1320 :    END SUBROUTINE rsmat_to_kp
     716             : 
     717             : ! **************************************************************************************************
     718             : !> \brief ...
     719             : !> \param bs_env ...
     720             : ! **************************************************************************************************
     721          28 :    SUBROUTINE diagonalize_ks_matrix(bs_env)
     722             :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
     723             : 
     724             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'diagonalize_ks_matrix'
     725             : 
     726             :       INTEGER                                            :: handle, ispin
     727             :       REAL(KIND=dp)                                      :: CBM, VBM
     728             : 
     729          28 :       CALL timeset(routineN, handle)
     730             : 
     731         112 :       ALLOCATE (bs_env%eigenval_scf_Gamma(bs_env%n_ao, bs_env%n_spin))
     732             : 
     733          64 :       DO ispin = 1, bs_env%n_spin
     734             : 
     735             :          ! use work matrices because the matrices are overwritten in cp_fm_geeig_canon
     736          36 :          CALL cp_fm_to_fm(bs_env%fm_ks_Gamma(ispin), bs_env%fm_work_mo(1))
     737          36 :          CALL cp_fm_to_fm(bs_env%fm_s_Gamma, bs_env%fm_work_mo(2))
     738             : 
     739             :          ! diagonalize the Kohn-Sham matrix to obtain MO coefficients and SCF eigenvalues
     740             :          ! (at the Gamma-point)
     741             :          CALL cp_fm_geeig_canon(bs_env%fm_work_mo(1), &
     742             :                                 bs_env%fm_work_mo(2), &
     743             :                                 bs_env%fm_mo_coeff_Gamma(ispin), &
     744             :                                 bs_env%eigenval_scf_Gamma(:, ispin), &
     745             :                                 bs_env%fm_work_mo(3), &
     746          36 :                                 bs_env%eps_eigval_mat_s)
     747             : 
     748          36 :          VBM = bs_env%eigenval_scf_Gamma(bs_env%n_occ(ispin), ispin)
     749          36 :          CBM = bs_env%eigenval_scf_Gamma(bs_env%n_occ(ispin) + 1, ispin)
     750             : 
     751          36 :          bs_env%band_edges_scf_Gamma(ispin)%VBM = VBM
     752          36 :          bs_env%band_edges_scf_Gamma(ispin)%CBM = CBM
     753          64 :          bs_env%e_fermi(ispin) = 0.5_dp*(VBM + CBM)
     754             : 
     755             :       END DO
     756             : 
     757          28 :       CALL timestop(handle)
     758             : 
     759          28 :    END SUBROUTINE diagonalize_ks_matrix
     760             : 
     761             : ! **************************************************************************************************
     762             : !> \brief ...
     763             : !> \param bs_env ...
     764             : !> \param qs_env ...
     765             : ! **************************************************************************************************
     766          28 :    SUBROUTINE check_positive_definite_overlap_mat(bs_env, qs_env)
     767             :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
     768             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     769             : 
     770             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'check_positive_definite_overlap_mat'
     771             : 
     772             :       INTEGER                                            :: handle, ikp, info, u
     773             :       TYPE(cp_cfm_type)                                  :: cfm_s_ikp
     774             : 
     775          28 :       CALL timeset(routineN, handle)
     776             : 
     777          68 :       DO ikp = 1, bs_env%kpoints_DOS%nkp
     778             : 
     779             :          ! get S_µν(k_i) from S_µν(k=0)
     780             :          CALL cfm_ikp_from_fm_Gamma(cfm_s_ikp, bs_env%fm_s_Gamma, &
     781          40 :                                     ikp, qs_env, bs_env%kpoints_DOS, "ORB")
     782             : 
     783             :          ! check whether S_µν(k_i) is positive definite
     784          40 :          CALL cp_cfm_cholesky_decompose(matrix=cfm_s_ikp, n=bs_env%n_ao, info_out=info)
     785             : 
     786             :          ! check if Cholesky decomposition failed (Cholesky decomposition only works for
     787             :          ! positive definite matrices
     788          68 :          IF (info .NE. 0) THEN
     789           0 :             u = bs_env%unit_nr
     790             : 
     791           0 :             IF (u > 0) THEN
     792           0 :                WRITE (u, FMT="(T2,A)") ""
     793             :                WRITE (u, FMT="(T2,A)") "ERROR: The Cholesky decomposition "// &
     794           0 :                   "of the k-point overlap matrix failed. This is"
     795             :                WRITE (u, FMT="(T2,A)") "because the algorithm is "// &
     796           0 :                   "only correct in the limit of large cells. The cell of "
     797             :                WRITE (u, FMT="(T2,A)") "the calculation is too small. "// &
     798           0 :                   "Use MULTIPLE_UNIT_CELL to create a larger cell "
     799           0 :                WRITE (u, FMT="(T2,A)") "and to prevent this error."
     800             :             END IF
     801             : 
     802           0 :             CALL bs_env%para_env%sync()
     803           0 :             CPABORT("Please see information on the error above.")
     804             : 
     805             :          END IF ! Cholesky decomposition failed
     806             : 
     807             :       END DO ! ikp
     808             : 
     809          28 :       CALL cp_cfm_release(cfm_s_ikp)
     810             : 
     811          28 :       CALL timestop(handle)
     812             : 
     813          28 :    END SUBROUTINE check_positive_definite_overlap_mat
     814             : 
     815             : ! **************************************************************************************************
     816             : !> \brief ...
     817             : !> \param qs_env ...
     818             : !> \param bs_env ...
     819             : ! **************************************************************************************************
     820          68 :    SUBROUTINE get_parameters_from_qs_env(qs_env, bs_env)
     821             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     822             :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
     823             : 
     824             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'get_parameters_from_qs_env'
     825             : 
     826             :       INTEGER                                            :: color_sub, handle, homo, n_ao, n_atom, u
     827             :       INTEGER, DIMENSION(3)                              :: periodic
     828             :       REAL(KIND=dp), DIMENSION(3, 3)                     :: hmat
     829             :       TYPE(cell_type), POINTER                           :: cell
     830             :       TYPE(dft_control_type), POINTER                    :: dft_control
     831          34 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     832             :       TYPE(mp_para_env_type), POINTER                    :: para_env
     833          34 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     834             :       TYPE(scf_control_type), POINTER                    :: scf_control
     835             :       TYPE(section_vals_type), POINTER                   :: input
     836             : 
     837          34 :       CALL timeset(routineN, handle)
     838             : 
     839             :       CALL get_qs_env(qs_env, &
     840             :                       dft_control=dft_control, &
     841             :                       scf_control=scf_control, &
     842          34 :                       mos=mos)
     843             : 
     844          34 :       bs_env%n_spin = dft_control%nspins
     845          34 :       IF (bs_env%n_spin == 1) bs_env%spin_degeneracy = 2.0_dp
     846          34 :       IF (bs_env%n_spin == 2) bs_env%spin_degeneracy = 1.0_dp
     847             : 
     848          34 :       CALL get_mo_set(mo_set=mos(1), nao=n_ao, homo=homo)
     849          34 :       bs_env%n_ao = n_ao
     850         102 :       bs_env%n_occ(1:2) = homo
     851         102 :       bs_env%n_vir(1:2) = n_ao - homo
     852             : 
     853          34 :       IF (bs_env%n_spin == 2) THEN
     854           8 :          CALL get_mo_set(mo_set=mos(2), homo=homo)
     855           8 :          bs_env%n_occ(2) = homo
     856           8 :          bs_env%n_vir(2) = n_ao - homo
     857             :       END IF
     858             : 
     859          34 :       bs_env%eps_eigval_mat_s = scf_control%eps_eigval
     860             : 
     861             :       ! get para_env from qs_env (bs_env%para_env is identical to para_env in qs_env)
     862          34 :       CALL get_qs_env(qs_env, para_env=para_env)
     863          34 :       color_sub = 0
     864          34 :       ALLOCATE (bs_env%para_env)
     865          34 :       CALL bs_env%para_env%from_split(para_env, color_sub)
     866             : 
     867          34 :       CALL get_qs_env(qs_env, particle_set=particle_set)
     868             : 
     869          34 :       n_atom = SIZE(particle_set)
     870          34 :       bs_env%n_atom = n_atom
     871             : 
     872          34 :       CALL get_qs_env(qs_env=qs_env, cell=cell)
     873          34 :       CALL get_cell(cell=cell, periodic=periodic, h=hmat)
     874         136 :       bs_env%periodic(1:3) = periodic(1:3)
     875         442 :       bs_env%hmat(1:3, 1:3) = hmat
     876          34 :       bs_env%nimages_scf = dft_control%nimages
     877          34 :       IF (dft_control%nimages == 1) THEN
     878          28 :          bs_env%small_cell_full_kp_or_large_cell_Gamma = large_cell_Gamma
     879           6 :       ELSE IF (dft_control%nimages > 1) THEN
     880           6 :          bs_env%small_cell_full_kp_or_large_cell_Gamma = small_cell_full_kp
     881             :       ELSE
     882           0 :          CPABORT("Wrong number of cells from DFT calculation.")
     883             :       END IF
     884             : 
     885          34 :       u = bs_env%unit_nr
     886             : 
     887             :       ! Marek : Get and save the rtp method
     888          34 :       CALL get_qs_env(qs_env=qs_env, input=input)
     889          34 :       CALL section_vals_val_get(input, "DFT%REAL_TIME_PROPAGATION%RTP_METHOD", i_val=bs_env%rtp_method)
     890             : 
     891          34 :       IF (u > 0) THEN
     892          17 :          WRITE (u, FMT="(T2,2A,T73,I8)") "Number of occupied molecular orbitals (MOs) ", &
     893          34 :             "= Number of occupied bands", homo
     894          17 :          WRITE (u, FMT="(T2,2A,T73,I8)") "Number of unoccupied (= virtual) MOs ", &
     895          34 :             "= Number of unoccupied bands", n_ao - homo
     896          17 :          WRITE (u, FMT="(T2,A,T73,I8)") "Number of Gaussian basis functions for MOs", n_ao
     897          17 :          IF (bs_env%small_cell_full_kp_or_large_cell_Gamma == small_cell_full_kp) THEN
     898           3 :             WRITE (u, FMT="(T2,2A,T73,I8)") "Number of cells considered in the DFT ", &
     899           6 :                "calculation", bs_env%nimages_scf
     900             :          END IF
     901             :       END IF
     902             : 
     903          34 :       CALL timestop(handle)
     904             : 
     905          34 :    END SUBROUTINE get_parameters_from_qs_env
     906             : 
     907             : ! **************************************************************************************************
     908             : !> \brief ...
     909             : !> \param bs_env ...
     910             : ! **************************************************************************************************
     911          34 :    SUBROUTINE set_heuristic_parameters(bs_env)
     912             :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
     913             : 
     914             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'set_heuristic_parameters'
     915             : 
     916             :       INTEGER                                            :: handle
     917             : 
     918          34 :       CALL timeset(routineN, handle)
     919             : 
     920          34 :       bs_env%n_bins_max_for_printing = 5000
     921             : 
     922          34 :       CALL timestop(handle)
     923             : 
     924          34 :    END SUBROUTINE set_heuristic_parameters
     925             : 
     926             : ! **************************************************************************************************
     927             : !> \brief ...
     928             : !> \param qs_env ...
     929             : !> \param bs_env ...
     930             : ! **************************************************************************************************
     931          34 :    SUBROUTINE allocate_and_fill_fm_ks_fm_s(qs_env, bs_env)
     932             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     933             :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
     934             : 
     935             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'allocate_and_fill_fm_ks_fm_s'
     936             : 
     937             :       INTEGER                                            :: handle, i_work, ispin
     938             :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
     939             :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
     940          34 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: matrix_ks, matrix_s
     941             :       TYPE(mp_para_env_type), POINTER                    :: para_env
     942             : 
     943          34 :       CALL timeset(routineN, handle)
     944             : 
     945             :       CALL get_qs_env(qs_env, &
     946             :                       para_env=para_env, &
     947             :                       blacs_env=blacs_env, &
     948             :                       matrix_ks_kp=matrix_ks, &
     949          34 :                       matrix_s_kp=matrix_s)
     950             : 
     951          34 :       NULLIFY (fm_struct)
     952             :       CALL cp_fm_struct_create(fm_struct, context=blacs_env, nrow_global=bs_env%n_ao, &
     953          34 :                                ncol_global=bs_env%n_ao, para_env=para_env)
     954             : 
     955         170 :       DO i_work = 1, SIZE(bs_env%fm_work_mo)
     956         170 :          CALL cp_fm_create(bs_env%fm_work_mo(i_work), fm_struct)
     957             :       END DO
     958             : 
     959          34 :       CALL cp_cfm_create(bs_env%cfm_work_mo, fm_struct)
     960          34 :       CALL cp_cfm_create(bs_env%cfm_work_mo_2, fm_struct)
     961             : 
     962          34 :       CALL cp_fm_create(bs_env%fm_s_Gamma, fm_struct)
     963          34 :       CALL copy_dbcsr_to_fm(matrix_s(1, 1)%matrix, bs_env%fm_s_Gamma)
     964             : 
     965          76 :       DO ispin = 1, bs_env%n_spin
     966          42 :          CALL cp_fm_create(bs_env%fm_ks_Gamma(ispin), fm_struct)
     967          42 :          CALL copy_dbcsr_to_fm(matrix_ks(ispin, 1)%matrix, bs_env%fm_ks_Gamma(ispin))
     968          76 :          CALL cp_fm_create(bs_env%fm_mo_coeff_Gamma(ispin), fm_struct)
     969             :       END DO
     970             : 
     971          34 :       CALL cp_fm_struct_release(fm_struct)
     972             : 
     973          34 :       NULLIFY (bs_env%mat_ao_ao%matrix)
     974          34 :       ALLOCATE (bs_env%mat_ao_ao%matrix)
     975             :       CALL dbcsr_create(bs_env%mat_ao_ao%matrix, template=matrix_s(1, 1)%matrix, &
     976          34 :                         matrix_type=dbcsr_type_no_symmetry)
     977             : 
     978         170 :       ALLOCATE (bs_env%eigenval_scf(bs_env%n_ao, bs_env%nkp_bs_and_DOS, bs_env%n_spin))
     979             : 
     980          34 :       CALL timestop(handle)
     981             : 
     982          34 :    END SUBROUTINE allocate_and_fill_fm_ks_fm_s
     983             : 
     984             : ! **************************************************************************************************
     985             : !> \brief ...
     986             : !> \param qs_env ...
     987             : !> \param bs_env ...
     988             : ! **************************************************************************************************
     989          34 :    SUBROUTINE dos_pdos_ldos(qs_env, bs_env)
     990             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     991             :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
     992             : 
     993             :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'dos_pdos_ldos'
     994             : 
     995             :       INTEGER                                            :: handle, homo, homo_1, homo_2, &
     996             :                                                             homo_spinor, ikp, ikp_for_file, ispin, &
     997             :                                                             n_ao, n_E, nkind, nkp
     998             :       LOGICAL                                            :: is_bandstruc_kpoint, print_DOS_kpoints, &
     999             :                                                             print_ikp
    1000             :       REAL(KIND=dp)                                      :: broadening, E_max, E_max_G0W0, E_min, &
    1001             :                                                             E_min_G0W0, E_total_window, &
    1002             :                                                             energy_step_DOS, energy_window_DOS, t1
    1003          34 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: DOS_G0W0, DOS_G0W0_SOC, DOS_scf, DOS_scf_SOC, &
    1004          34 :          eigenval, eigenval_spinor, eigenval_spinor_G0W0, eigenval_spinor_no_SOC
    1005          34 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: PDOS_G0W0, PDOS_G0W0_SOC, PDOS_scf, &
    1006          34 :                                                             PDOS_scf_SOC, proj_mo_on_kind
    1007          34 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: LDOS_G0W0_2d, LDOS_scf_2d, &
    1008          34 :                                                             LDOS_scf_2d_SOC
    1009             :       TYPE(band_edges_type)                              :: band_edges_G0W0, band_edges_G0W0_SOC, &
    1010             :                                                             band_edges_scf, band_edges_scf_guess, &
    1011             :                                                             band_edges_scf_SOC
    1012             :       TYPE(cp_cfm_type) :: cfm_ks_ikp, cfm_ks_ikp_spinor, cfm_mos_ikp_spinor, cfm_s_ikp, &
    1013             :          cfm_s_ikp_copy, cfm_s_ikp_spinor, cfm_s_ikp_spinor_copy, cfm_SOC_ikp_spinor, &
    1014             :          cfm_spinor_wf_ikp, cfm_work_ikp, cfm_work_ikp_spinor
    1015         102 :       TYPE(cp_cfm_type), DIMENSION(2)                    :: cfm_mos_ikp
    1016             : 
    1017          34 :       CALL timeset(routineN, handle)
    1018             : 
    1019          34 :       n_ao = bs_env%n_ao
    1020             : 
    1021          34 :       energy_window_DOS = bs_env%energy_window_DOS
    1022          34 :       energy_step_DOS = bs_env%energy_step_DOS
    1023          34 :       broadening = bs_env%broadening_DOS
    1024             : 
    1025             :       ! if we have done GW or a full kpoint SCF, we already have the band edges
    1026          34 :       IF (bs_env%do_gw .OR. &
    1027             :           bs_env%small_cell_full_kp_or_large_cell_Gamma == small_cell_full_kp) THEN
    1028          34 :          band_edges_scf = bs_env%band_edges_scf
    1029          34 :          band_edges_scf_guess = band_edges_scf
    1030             :       ELSE
    1031             : 
    1032           0 :          IF (bs_env%n_spin == 1) THEN
    1033           0 :             homo = bs_env%n_occ(1)
    1034           0 :             band_edges_scf_guess%VBM = bs_env%eigenval_scf_Gamma(homo, 1)
    1035           0 :             band_edges_scf_guess%CBM = bs_env%eigenval_scf_Gamma(homo + 1, 1)
    1036             :          ELSE
    1037           0 :             homo_1 = bs_env%n_occ(1)
    1038           0 :             homo_2 = bs_env%n_occ(2)
    1039             :             band_edges_scf_guess%VBM = MAX(bs_env%eigenval_scf_Gamma(homo_1, 1), &
    1040           0 :                                            bs_env%eigenval_scf_Gamma(homo_2, 2))
    1041             :             band_edges_scf_guess%CBM = MIN(bs_env%eigenval_scf_Gamma(homo_1 + 1, 1), &
    1042           0 :                                            bs_env%eigenval_scf_Gamma(homo_2 + 1, 2))
    1043             :          END IF
    1044             : 
    1045             :          ! initialization
    1046           0 :          band_edges_scf%VBM = -1000.0_dp
    1047           0 :          band_edges_scf%CBM = 1000.0_dp
    1048           0 :          band_edges_scf%DBG = 1000.0_dp
    1049             :       END IF
    1050             : 
    1051          34 :       E_min = band_edges_scf_guess%VBM - 0.5_dp*energy_window_DOS
    1052          34 :       E_max = band_edges_scf_guess%CBM + 0.5_dp*energy_window_DOS
    1053             : 
    1054          34 :       IF (bs_env%do_gw) THEN
    1055          34 :          band_edges_G0W0 = bs_env%band_edges_G0W0
    1056          34 :          E_min_G0W0 = band_edges_G0W0%VBM - 0.5_dp*energy_window_DOS
    1057          34 :          E_max_G0W0 = band_edges_G0W0%CBM + 0.5_dp*energy_window_DOS
    1058          34 :          E_min = MIN(E_min, E_min_G0W0)
    1059          34 :          E_max = MAX(E_max, E_max_G0W0)
    1060             :       END IF
    1061             : 
    1062          34 :       E_total_window = E_max - E_min
    1063             : 
    1064          34 :       n_E = INT(E_total_window/energy_step_DOS)
    1065             : 
    1066         102 :       ALLOCATE (DOS_scf(n_E))
    1067      101188 :       DOS_scf(:) = 0.0_dp
    1068          68 :       ALLOCATE (DOS_scf_SOC(n_E))
    1069      101188 :       DOS_scf_SOC(:) = 0.0_dp
    1070             : 
    1071          34 :       CALL get_qs_env(qs_env, nkind=nkind)
    1072             : 
    1073         136 :       ALLOCATE (PDOS_scf(n_E, nkind))
    1074      143250 :       PDOS_scf(:, :) = 0.0_dp
    1075         102 :       ALLOCATE (PDOS_scf_SOC(n_E, nkind))
    1076      143250 :       PDOS_scf_SOC(:, :) = 0.0_dp
    1077             : 
    1078         136 :       ALLOCATE (proj_mo_on_kind(n_ao, nkind))
    1079         642 :       proj_mo_on_kind(:, :) = 0.0_dp
    1080             : 
    1081         102 :       ALLOCATE (eigenval(n_ao))
    1082         102 :       ALLOCATE (eigenval_spinor(2*n_ao))
    1083          68 :       ALLOCATE (eigenval_spinor_no_SOC(2*n_ao))
    1084          68 :       ALLOCATE (eigenval_spinor_G0W0(2*n_ao))
    1085             : 
    1086          34 :       IF (bs_env%do_gw) THEN
    1087             : 
    1088          68 :          ALLOCATE (DOS_G0W0(n_E))
    1089      101188 :          DOS_G0W0(:) = 0.0_dp
    1090          68 :          ALLOCATE (DOS_G0W0_SOC(n_E))
    1091      101188 :          DOS_G0W0_SOC(:) = 0.0_dp
    1092             : 
    1093         102 :          ALLOCATE (PDOS_G0W0(n_E, nkind))
    1094      143250 :          PDOS_G0W0(:, :) = 0.0_dp
    1095         102 :          ALLOCATE (PDOS_G0W0_SOC(n_E, nkind))
    1096      143250 :          PDOS_G0W0_SOC(:, :) = 0.0_dp
    1097             : 
    1098             :       END IF
    1099             : 
    1100          34 :       CALL cp_cfm_create(cfm_mos_ikp(1), bs_env%fm_ks_Gamma(1)%matrix_struct)
    1101          34 :       CALL cp_cfm_create(cfm_mos_ikp(2), bs_env%fm_ks_Gamma(1)%matrix_struct)
    1102          34 :       CALL cp_cfm_create(cfm_work_ikp, bs_env%fm_ks_Gamma(1)%matrix_struct)
    1103          34 :       CALL cp_cfm_create(cfm_s_ikp_copy, bs_env%fm_ks_Gamma(1)%matrix_struct)
    1104             : 
    1105          34 :       IF (bs_env%do_soc) THEN
    1106             : 
    1107          18 :          CALL cp_cfm_create(cfm_mos_ikp_spinor, bs_env%cfm_SOC_spinor_ao(1)%matrix_struct)
    1108          18 :          CALL cp_cfm_create(cfm_work_ikp_spinor, bs_env%cfm_SOC_spinor_ao(1)%matrix_struct)
    1109          18 :          CALL cp_cfm_create(cfm_s_ikp_spinor_copy, bs_env%cfm_SOC_spinor_ao(1)%matrix_struct)
    1110          18 :          CALL cp_cfm_create(cfm_ks_ikp_spinor, bs_env%cfm_SOC_spinor_ao(1)%matrix_struct)
    1111          18 :          CALL cp_cfm_create(cfm_SOC_ikp_spinor, bs_env%cfm_SOC_spinor_ao(1)%matrix_struct)
    1112          18 :          CALL cp_cfm_create(cfm_s_ikp_spinor, bs_env%cfm_SOC_spinor_ao(1)%matrix_struct)
    1113          18 :          CALL cp_cfm_create(cfm_spinor_wf_ikp, bs_env%cfm_SOC_spinor_ao(1)%matrix_struct)
    1114             : 
    1115          18 :          homo_spinor = bs_env%n_occ(1) + bs_env%n_occ(bs_env%n_spin)
    1116             : 
    1117          18 :          band_edges_scf_SOC%VBM = -1000.0_dp
    1118          18 :          band_edges_scf_SOC%CBM = 1000.0_dp
    1119          18 :          band_edges_scf_SOC%DBG = 1000.0_dp
    1120             : 
    1121          18 :          IF (bs_env%do_gw) THEN
    1122          18 :             band_edges_G0W0_SOC%VBM = -1000.0_dp
    1123          18 :             band_edges_G0W0_SOC%CBM = 1000.0_dp
    1124          18 :             band_edges_G0W0_SOC%DBG = 1000.0_dp
    1125             :          END IF
    1126             : 
    1127          18 :          IF (bs_env%unit_nr > 0) THEN
    1128           9 :             WRITE (bs_env%unit_nr, '(A)') ''
    1129           9 :             WRITE (bs_env%unit_nr, '(T2,A,F43.1,A)') 'SOC requested, SOC energy window:', &
    1130          18 :                bs_env%energy_window_soc*evolt, ' eV'
    1131             :          END IF
    1132             : 
    1133             :       END IF
    1134             : 
    1135          34 :       IF (bs_env%do_ldos) THEN
    1136           4 :          CPASSERT(bs_env%int_ldos_xyz == int_ldos_z)
    1137             :       END IF
    1138             : 
    1139          34 :       IF (bs_env%unit_nr > 0) THEN
    1140          17 :          WRITE (bs_env%unit_nr, '(A)') ''
    1141             :       END IF
    1142             : 
    1143          34 :       IF (bs_env%small_cell_full_kp_or_large_cell_Gamma == small_cell_full_kp) THEN
    1144           6 :          CALL cp_cfm_create(cfm_ks_ikp, bs_env%cfm_ks_kp(1, 1)%matrix_struct)
    1145           6 :          CALL cp_cfm_create(cfm_s_ikp, bs_env%cfm_ks_kp(1, 1)%matrix_struct)
    1146             :       END IF
    1147             : 
    1148         294 :       DO ikp = 1, bs_env%nkp_bs_and_DOS
    1149             : 
    1150         260 :          t1 = m_walltime()
    1151             : 
    1152         536 :          DO ispin = 1, bs_env%n_spin
    1153             : 
    1154         332 :             SELECT CASE (bs_env%small_cell_full_kp_or_large_cell_Gamma)
    1155             :             CASE (large_cell_Gamma)
    1156             : 
    1157             :                ! 1. get H^KS_µν(k_i) from H^KS_µν(k=0)
    1158             :                CALL cfm_ikp_from_fm_Gamma(cfm_ks_ikp, bs_env%fm_ks_Gamma(ispin), &
    1159          56 :                                           ikp, qs_env, bs_env%kpoints_DOS, "ORB")
    1160             : 
    1161             :                ! 2. get S_µν(k_i) from S_µν(k=0)
    1162             :                CALL cfm_ikp_from_fm_Gamma(cfm_s_ikp, bs_env%fm_s_Gamma, &
    1163          56 :                                           ikp, qs_env, bs_env%kpoints_DOS, "ORB")
    1164          56 :                CALL cp_cfm_to_cfm(cfm_s_ikp, cfm_s_ikp_copy)
    1165             : 
    1166             :                ! 3. Diagonalize (Roothaan-Hall): H_KS(k_i)*C(k_i) = S(k_i)*C(k_i)*ϵ(k_i)
    1167             :                CALL cp_cfm_geeig(cfm_ks_ikp, cfm_s_ikp_copy, cfm_mos_ikp(ispin), &
    1168          56 :                                  eigenval, cfm_work_ikp)
    1169             : 
    1170             :             CASE (small_cell_full_kp)
    1171             : 
    1172             :                ! 1. get H^KS_µν(k_i)
    1173         220 :                CALL cp_cfm_to_cfm(bs_env%cfm_ks_kp(ikp, ispin), cfm_ks_ikp)
    1174             : 
    1175             :                ! 2. get S_µν(k_i)
    1176         220 :                CALL cp_cfm_to_cfm(bs_env%cfm_s_kp(ikp), cfm_s_ikp)
    1177             : 
    1178             :                ! 3. get C_µn(k_i) and ϵ_n(k_i)
    1179         220 :                CALL cp_cfm_to_cfm(bs_env%cfm_mo_coeff_kp(ikp, ispin), cfm_mos_ikp(ispin))
    1180        2636 :                eigenval(:) = bs_env%eigenval_scf(:, ikp, ispin)
    1181             : 
    1182             :             END SELECT
    1183             : 
    1184             :             ! 4. Projection p_nk^A of MO ψ_nk(r) on atom type A (inspired by Mulliken charge)
    1185             :             !    p_nk^A = sum_µ^A,ν C*_µ^A,n(k) S_µ^A,ν(k) C_ν,n(k)
    1186         276 :             CALL compute_proj_mo_on_kind(proj_mo_on_kind, qs_env, cfm_mos_ikp(ispin), cfm_s_ikp)
    1187             : 
    1188             :             ! 5. DOS and PDOS
    1189             :             CALL add_to_DOS_PDOS(DOS_scf, PDOS_scf, eigenval, ikp, bs_env, n_E, E_min, &
    1190         276 :                                  proj_mo_on_kind)
    1191         276 :             IF (bs_env%do_gw) THEN
    1192             :                CALL add_to_DOS_PDOS(DOS_G0W0, PDOS_G0W0, bs_env%eigenval_G0W0(:, ikp, ispin), &
    1193         276 :                                     ikp, bs_env, n_E, E_min, proj_mo_on_kind)
    1194             :             END IF
    1195             : 
    1196         276 :             IF (bs_env%do_ldos) THEN
    1197             :                CALL add_to_LDOS_2d(LDOS_scf_2d, qs_env, ikp, bs_env, cfm_mos_ikp(ispin), &
    1198           4 :                                    eigenval(:), band_edges_scf_guess)
    1199             : 
    1200           4 :                IF (bs_env%do_gw) THEN
    1201             :                   CALL add_to_LDOS_2d(LDOS_G0W0_2d, qs_env, ikp, bs_env, cfm_mos_ikp(ispin), &
    1202           4 :                                       bs_env%eigenval_G0W0(:, ikp, 1), band_edges_G0W0)
    1203             :                END IF
    1204             : 
    1205             :             END IF
    1206             : 
    1207         276 :             homo = bs_env%n_occ(ispin)
    1208             : 
    1209         276 :             band_edges_scf%VBM = MAX(band_edges_scf%VBM, eigenval(homo))
    1210         276 :             band_edges_scf%CBM = MIN(band_edges_scf%CBM, eigenval(homo + 1))
    1211         536 :             band_edges_scf%DBG = MIN(band_edges_scf%DBG, eigenval(homo + 1) - eigenval(homo))
    1212             : 
    1213             :          END DO ! spin
    1214             : 
    1215             :          ! now the same with spin-orbit coupling
    1216         260 :          IF (bs_env%do_soc) THEN
    1217             : 
    1218             :             ! only print eigenvalues of DOS k-points in case no bandstructure path has been given
    1219         240 :             print_DOS_kpoints = (bs_env%nkp_only_bs .LE. 0)
    1220             :             ! in kpoints_DOS, the last nkp_only_bs are bandstructure k-points
    1221         240 :             is_bandstruc_kpoint = (ikp > bs_env%nkp_only_DOS)
    1222         240 :             print_ikp = print_DOS_kpoints .OR. is_bandstruc_kpoint
    1223             : 
    1224         240 :             IF (print_DOS_kpoints) THEN
    1225          52 :                nkp = bs_env%nkp_only_DOS
    1226          52 :                ikp_for_file = ikp
    1227             :             ELSE
    1228         188 :                nkp = bs_env%nkp_only_bs
    1229         188 :                ikp_for_file = ikp - bs_env%nkp_only_DOS
    1230             :             END IF
    1231             : 
    1232             :             ! compute DFT+SOC eigenvalues; based on these, compute band edges, DOS and LDOS
    1233             :             CALL SOC_ev(bs_env, qs_env, ikp, bs_env%eigenval_scf, band_edges_scf, &
    1234             :                         E_min, cfm_mos_ikp, DOS_scf_SOC, PDOS_scf_SOC, &
    1235         240 :                         band_edges_scf_SOC, eigenval_spinor, cfm_spinor_wf_ikp)
    1236             : 
    1237         240 :             IF (.NOT. bs_env%do_gw .AND. print_ikp) THEN
    1238           0 :                CALL write_SOC_eigenvalues(eigenval_spinor, ikp_for_file, ikp, bs_env)
    1239             :             END IF
    1240             : 
    1241         240 :             IF (bs_env%do_ldos) THEN
    1242             :                CALL add_to_LDOS_2d(LDOS_scf_2d_SOC, qs_env, ikp, bs_env, cfm_spinor_wf_ikp, &
    1243           4 :                                    eigenval_spinor, band_edges_scf_guess, .TRUE., cfm_work_ikp)
    1244             :             END IF
    1245             : 
    1246         240 :             IF (bs_env%do_gw) THEN
    1247             : 
    1248             :                ! compute G0W0+SOC eigenvalues; based on these, compute band edges, DOS and LDOS
    1249             :                CALL SOC_ev(bs_env, qs_env, ikp, bs_env%eigenval_G0W0, band_edges_G0W0, &
    1250             :                            E_min, cfm_mos_ikp, DOS_G0W0_SOC, PDOS_G0W0_SOC, &
    1251         240 :                            band_edges_G0W0_SOC, eigenval_spinor_G0W0, cfm_spinor_wf_ikp)
    1252             : 
    1253         240 :                IF (print_ikp) THEN
    1254             :                   ! write SCF+SOC and G0W0+SOC eigenvalues to file
    1255             :                   ! SCF_and_G0W0_band_structure_for_kpoint_<ikp>_+_SOC
    1256             :                   CALL write_SOC_eigenvalues(eigenval_spinor, ikp_for_file, ikp, bs_env, &
    1257         176 :                                              eigenval_spinor_G0W0)
    1258             :                END IF
    1259             : 
    1260             :             END IF ! do_gw
    1261             : 
    1262             :          END IF ! do_soc
    1263             : 
    1264         294 :          IF (bs_env%unit_nr > 0 .AND. m_walltime() - t1 > 20.0_dp) THEN
    1265             :             WRITE (bs_env%unit_nr, '(T2,A,T43,I5,A,I3,A,F7.1,A)') &
    1266           0 :                'Compute DOS, LDOS for k-point ', ikp, ' /', bs_env%nkp_bs_and_DOS, &
    1267           0 :                ',    Execution time', m_walltime() - t1, ' s'
    1268             :          END IF
    1269             : 
    1270             :       END DO ! ikp_DOS
    1271             : 
    1272          34 :       band_edges_scf%IDBG = band_edges_scf%CBM - band_edges_scf%VBM
    1273          34 :       IF (bs_env%do_soc) THEN
    1274          18 :          band_edges_scf_SOC%IDBG = band_edges_scf_SOC%CBM - band_edges_scf_SOC%VBM
    1275          18 :          IF (bs_env%do_gw) THEN
    1276          18 :             band_edges_G0W0_SOC%IDBG = band_edges_G0W0_SOC%CBM - band_edges_G0W0_SOC%VBM
    1277             :          END IF
    1278             :       END IF
    1279             : 
    1280          34 :       CALL write_band_edges(band_edges_scf, "SCF", bs_env)
    1281          34 :       CALL write_dos_pdos(DOS_scf, PDOS_scf, bs_env, qs_env, "SCF", E_min, band_edges_scf%VBM)
    1282          34 :       IF (bs_env%do_ldos) THEN
    1283           4 :          CALL print_LDOS_main(LDOS_scf_2d, bs_env, band_edges_scf, "SCF")
    1284             :       END IF
    1285             : 
    1286          34 :       IF (bs_env%do_soc) THEN
    1287          18 :          CALL write_band_edges(band_edges_scf_SOC, "SCF+SOC", bs_env)
    1288             :          CALL write_dos_pdos(DOS_scf_SOC, PDOS_scf_SOC, bs_env, qs_env, "SCF_SOC", &
    1289          18 :                              E_min, band_edges_scf_SOC%VBM)
    1290          18 :          IF (bs_env%do_ldos) THEN
    1291             :             ! argument band_edges_scf is actually correct because the non-SOC band edges
    1292             :             ! have been used as reference in add_to_LDOS_2d
    1293             :             CALL print_LDOS_main(LDOS_scf_2d_SOC, bs_env, band_edges_scf, &
    1294           4 :                                  "SCF_SOC")
    1295             :          END IF
    1296             :       END IF
    1297             : 
    1298          34 :       IF (bs_env%do_gw) THEN
    1299          34 :          CALL write_band_edges(band_edges_G0W0, "G0W0", bs_env)
    1300          34 :          CALL write_band_edges(bs_env%band_edges_HF, "Hartree-Fock with SCF orbitals", bs_env)
    1301             :          CALL write_dos_pdos(DOS_G0W0, PDOS_G0W0, bs_env, qs_env, "G0W0", E_min, &
    1302          34 :                              band_edges_G0W0%VBM)
    1303          34 :          IF (bs_env%do_ldos) THEN
    1304           4 :             CALL print_LDOS_main(LDOS_G0W0_2d, bs_env, band_edges_G0W0, "G0W0")
    1305             :          END IF
    1306             :       END IF
    1307             : 
    1308          34 :       IF (bs_env%do_soc .AND. bs_env%do_gw) THEN
    1309          18 :          CALL write_band_edges(band_edges_G0W0_SOC, "G0W0+SOC", bs_env)
    1310             :          CALL write_dos_pdos(DOS_G0W0_SOC, PDOS_G0W0_SOC, bs_env, qs_env, "G0W0_SOC", E_min, &
    1311          18 :                              band_edges_G0W0_SOC%VBM)
    1312             :       END IF
    1313             : 
    1314          34 :       CALL cp_cfm_release(cfm_s_ikp)
    1315          34 :       CALL cp_cfm_release(cfm_ks_ikp)
    1316          34 :       CALL cp_cfm_release(cfm_mos_ikp(1))
    1317          34 :       CALL cp_cfm_release(cfm_mos_ikp(2))
    1318          34 :       CALL cp_cfm_release(cfm_work_ikp)
    1319          34 :       CALL cp_cfm_release(cfm_s_ikp_copy)
    1320             : 
    1321          34 :       CALL cp_cfm_release(cfm_s_ikp_spinor)
    1322          34 :       CALL cp_cfm_release(cfm_ks_ikp_spinor)
    1323          34 :       CALL cp_cfm_release(cfm_SOC_ikp_spinor)
    1324          34 :       CALL cp_cfm_release(cfm_mos_ikp_spinor)
    1325          34 :       CALL cp_cfm_release(cfm_work_ikp_spinor)
    1326          34 :       CALL cp_cfm_release(cfm_s_ikp_spinor_copy)
    1327          34 :       CALL cp_cfm_release(cfm_spinor_wf_ikp)
    1328             : 
    1329          34 :       CALL timestop(handle)
    1330             : 
    1331         136 :    END SUBROUTINE dos_pdos_ldos
    1332             : 
    1333             : ! **************************************************************************************************
    1334             : !> \brief ...
    1335             : !> \param LDOS_2d ...
    1336             : !> \param bs_env ...
    1337             : !> \param band_edges ...
    1338             : !> \param scf_gw_soc ...
    1339             : ! **************************************************************************************************
    1340          12 :    SUBROUTINE print_LDOS_main(LDOS_2d, bs_env, band_edges, scf_gw_soc)
    1341             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: LDOS_2d
    1342             :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
    1343             :       TYPE(band_edges_type)                              :: band_edges
    1344             :       CHARACTER(LEN=*)                                   :: scf_gw_soc
    1345             : 
    1346             :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'print_LDOS_main'
    1347             : 
    1348             :       INTEGER :: handle, i_x, i_x_bin, i_x_end, i_x_end_bin, i_x_end_glob, i_x_start, &
    1349             :          i_x_start_bin, i_x_start_glob, i_y, i_y_bin, i_y_end, i_y_end_bin, i_y_end_glob, &
    1350             :          i_y_start, i_y_start_bin, i_y_start_glob, n_E
    1351          12 :       INTEGER, ALLOCATABLE, DIMENSION(:, :)              :: n_sum_for_bins
    1352             :       INTEGER, DIMENSION(2)                              :: bin_mesh
    1353             :       LOGICAL                                            :: do_xy_bins
    1354             :       REAL(KIND=dp)                                      :: E_min, energy_step, energy_window
    1355             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: LDOS_2d_bins
    1356             : 
    1357          12 :       CALL timeset(routineN, handle)
    1358             : 
    1359          12 :       n_E = SIZE(LDOS_2d, 3)
    1360             : 
    1361          12 :       energy_window = bs_env%energy_window_DOS
    1362          12 :       energy_step = bs_env%energy_step_DOS
    1363          12 :       E_min = band_edges%VBM - 0.5_dp*energy_window
    1364             : 
    1365          36 :       bin_mesh(1:2) = bs_env%bin_mesh(1:2)
    1366          12 :       do_xy_bins = (bin_mesh(1) > 0 .AND. bin_mesh(2) > 0)
    1367             : 
    1368          12 :       i_x_start = LBOUND(LDOS_2d, 1)
    1369          12 :       i_x_end = UBOUND(LDOS_2d, 1)
    1370          12 :       i_y_start = LBOUND(LDOS_2d, 2)
    1371          12 :       i_y_end = UBOUND(LDOS_2d, 2)
    1372             : 
    1373          12 :       IF (do_xy_bins) THEN
    1374          12 :          i_x_start_bin = 1
    1375          12 :          i_x_end_bin = bin_mesh(1)
    1376          12 :          i_y_start_bin = 1
    1377          12 :          i_y_end_bin = bin_mesh(2)
    1378             :       ELSE
    1379             :          i_x_start_bin = i_x_start
    1380             :          i_x_end_bin = i_x_end
    1381             :          i_y_start_bin = i_y_start
    1382             :          i_y_end_bin = i_y_end
    1383             :       END IF
    1384             : 
    1385          60 :       ALLOCATE (LDOS_2d_bins(i_x_start_bin:i_x_end_bin, i_y_start_bin:i_y_end_bin, n_E))
    1386       70236 :       LDOS_2d_bins(:, :, :) = 0.0_dp
    1387             : 
    1388          12 :       IF (do_xy_bins) THEN
    1389             : 
    1390          12 :          i_x_start_glob = i_x_start
    1391          12 :          i_x_end_glob = i_x_end
    1392          12 :          i_y_start_glob = i_y_start
    1393          12 :          i_y_end_glob = i_y_end
    1394             : 
    1395          12 :          CALL bs_env%para_env%min(i_x_start_glob)
    1396          12 :          CALL bs_env%para_env%max(i_x_end_glob)
    1397          12 :          CALL bs_env%para_env%min(i_y_start_glob)
    1398          12 :          CALL bs_env%para_env%max(i_y_end_glob)
    1399             : 
    1400          48 :          ALLOCATE (n_sum_for_bins(bin_mesh(1), bin_mesh(2)))
    1401         252 :          n_sum_for_bins(:, :) = 0
    1402             : 
    1403             :          ! transform interval [i_x_start, i_x_end] to [1, bin_mesh(1)] (and same for y)
    1404         132 :          DO i_x = i_x_start, i_x_end
    1405        7812 :             DO i_y = i_y_start, i_y_end
    1406        7680 :                i_x_bin = bin_mesh(1)*(i_x - i_x_start_glob)/(i_x_end_glob - i_x_start_glob + 1) + 1
    1407        7680 :                i_y_bin = bin_mesh(2)*(i_y - i_y_start_glob)/(i_y_end_glob - i_y_start_glob + 1) + 1
    1408             :                LDOS_2d_bins(i_x_bin, i_y_bin, :) = LDOS_2d_bins(i_x_bin, i_y_bin, :) + &
    1409     2147840 :                                                    LDOS_2d(i_x, i_y, :)
    1410        7800 :                n_sum_for_bins(i_x_bin, i_y_bin) = n_sum_for_bins(i_x_bin, i_y_bin) + 1
    1411             :             END DO
    1412             :          END DO
    1413             : 
    1414          12 :          CALL bs_env%para_env%sum(LDOS_2d_bins)
    1415          12 :          CALL bs_env%para_env%sum(n_sum_for_bins)
    1416             : 
    1417             :          ! divide by number of terms in the sum so we have the average LDOS(x,y,E)
    1418          60 :          DO i_x_bin = 1, bin_mesh(1)
    1419         252 :             DO i_y_bin = 1, bin_mesh(2)
    1420             :                LDOS_2d_bins(i_x_bin, i_y_bin, :) = LDOS_2d_bins(i_x_bin, i_y_bin, :)/ &
    1421       53744 :                                                    REAL(n_sum_for_bins(i_x_bin, i_y_bin), KIND=dp)
    1422             :             END DO
    1423             :          END DO
    1424             : 
    1425             :       ELSE
    1426             : 
    1427           0 :          LDOS_2d_bins(:, :, :) = LDOS_2d(:, :, :)
    1428             : 
    1429             :       END IF
    1430             : 
    1431          12 :       IF (bin_mesh(1)*bin_mesh(2) < bs_env%n_bins_max_for_printing) THEN
    1432          12 :          CALL print_LDOS_2d_bins(LDOS_2d_bins, bs_env, E_min, scf_gw_soc)
    1433             :       ELSE
    1434           0 :          CPWARN("The number of bins for the LDOS is too large. Decrease BIN_MESH.")
    1435             :       END IF
    1436             : 
    1437          12 :       CALL timestop(handle)
    1438             : 
    1439          24 :    END SUBROUTINE print_LDOS_main
    1440             : 
    1441             : ! **************************************************************************************************
    1442             : !> \brief ...
    1443             : !> \param LDOS_2d_bins ...
    1444             : !> \param bs_env ...
    1445             : !> \param E_min ...
    1446             : !> \param scf_gw_soc ...
    1447             : ! **************************************************************************************************
    1448          12 :    SUBROUTINE print_LDOS_2d_bins(LDOS_2d_bins, bs_env, E_min, scf_gw_soc)
    1449             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: LDOS_2d_bins
    1450             :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
    1451             :       REAL(KIND=dp)                                      :: E_min
    1452             :       CHARACTER(LEN=*)                                   :: scf_gw_soc
    1453             : 
    1454             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'print_LDOS_2d_bins'
    1455             : 
    1456             :       CHARACTER(LEN=18)                                  :: print_format
    1457             :       CHARACTER(LEN=4)                                   :: print_format_1, print_format_2
    1458             :       CHARACTER(len=default_string_length)               :: fname
    1459             :       INTEGER                                            :: handle, i_E, i_x, i_x_end, i_x_start, &
    1460             :                                                             i_y, i_y_end, i_y_start, iunit, n_E, &
    1461             :                                                             n_x, n_y
    1462             :       REAL(KIND=dp)                                      :: energy
    1463             :       REAL(KIND=dp), DIMENSION(3)                        :: coord, idx
    1464             : 
    1465          12 :       CALL timeset(routineN, handle)
    1466             : 
    1467          12 :       i_x_start = LBOUND(LDOS_2d_bins, 1)
    1468          12 :       i_x_end = UBOUND(LDOS_2d_bins, 1)
    1469          12 :       i_y_start = LBOUND(LDOS_2d_bins, 2)
    1470          12 :       i_y_end = UBOUND(LDOS_2d_bins, 2)
    1471          12 :       n_E = SIZE(LDOS_2d_bins, 3)
    1472             : 
    1473          12 :       n_x = i_x_end - i_x_start + 1
    1474          12 :       n_y = i_y_end - i_y_start + 1
    1475             : 
    1476          12 :       IF (bs_env%para_env%is_source()) THEN
    1477             : 
    1478          30 :          DO i_x = i_x_start, i_x_end
    1479         126 :             DO i_y = i_y_start, i_y_end
    1480             : 
    1481          96 :                idx(1) = (REAL(i_x, KIND=dp) - 0.5_dp)/REAL(n_x, KIND=dp)
    1482          96 :                idx(2) = (REAL(i_y, KIND=dp) - 0.5_dp)/REAL(n_y, KIND=dp)
    1483          96 :                idx(3) = 0.0_dp
    1484        1248 :                coord(1:3) = MATMUL(bs_env%hmat, idx)
    1485             : 
    1486          96 :                CALL get_print_format(coord(1), print_format_1)
    1487          96 :                CALL get_print_format(coord(2), print_format_2)
    1488             : 
    1489          96 :                print_format = "(3A,"//print_format_1//",A,"//print_format_2//",A)"
    1490             : 
    1491          96 :                WRITE (fname, print_format) "LDOS_", scf_gw_soc, &
    1492         192 :                   "_at_x_", coord(1)*angstrom, '_A_and_y_', coord(2)*angstrom, '_A'
    1493             : 
    1494             :                CALL open_file(TRIM(fname), unit_number=iunit, file_status="REPLACE", &
    1495          96 :                               file_action="WRITE")
    1496             : 
    1497          96 :                WRITE (iunit, "(2A)") "        Energy E (eV)    average LDOS(x,y,E) (1/(eV*Å^2), ", &
    1498         192 :                   "integrated over z, averaged inside bin)"
    1499             : 
    1500       26848 :                DO i_E = 1, n_E
    1501       26752 :                   energy = E_min + i_E*bs_env%energy_step_DOS
    1502       26752 :                   WRITE (iunit, "(2F17.3)") energy*evolt, &
    1503             :                      LDOS_2d_bins(i_x, i_y, i_E)* &
    1504       53600 :                      bs_env%unit_ldos_int_z_inv_Ang2_eV
    1505             :                END DO
    1506             : 
    1507         120 :                CALL close_file(iunit)
    1508             : 
    1509             :             END DO
    1510             :          END DO
    1511             : 
    1512             :       END IF
    1513             : 
    1514          12 :       CALL timestop(handle)
    1515             : 
    1516          12 :    END SUBROUTINE print_LDOS_2d_bins
    1517             : 
    1518             : ! **************************************************************************************************
    1519             : !> \brief ...
    1520             : !> \param coord ...
    1521             : !> \param print_format ...
    1522             : ! **************************************************************************************************
    1523         192 :    SUBROUTINE get_print_format(coord, print_format)
    1524             :       REAL(KIND=dp)                                      :: coord
    1525             :       CHARACTER(LEN=4)                                   :: print_format
    1526             : 
    1527             :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'get_print_format'
    1528             : 
    1529             :       INTEGER                                            :: handle
    1530             : 
    1531         192 :       CALL timeset(routineN, handle)
    1532             : 
    1533         192 :       IF (coord < -10000/angstrom) THEN
    1534           0 :          print_format = "F9.2"
    1535         192 :       ELSE IF (coord < -1000/angstrom) THEN
    1536           0 :          print_format = "F8.2"
    1537         192 :       ELSE IF (coord < -100/angstrom) THEN
    1538           0 :          print_format = "F7.2"
    1539         192 :       ELSE IF (coord < -10/angstrom) THEN
    1540           0 :          print_format = "F6.2"
    1541         192 :       ELSE IF (coord < -1/angstrom) THEN
    1542           0 :          print_format = "F5.2"
    1543         192 :       ELSE IF (coord < 10/angstrom) THEN
    1544         192 :          print_format = "F4.2"
    1545           0 :       ELSE IF (coord < 100/angstrom) THEN
    1546           0 :          print_format = "F5.2"
    1547           0 :       ELSE IF (coord < 1000/angstrom) THEN
    1548           0 :          print_format = "F6.2"
    1549           0 :       ELSE IF (coord < 10000/angstrom) THEN
    1550           0 :          print_format = "F7.2"
    1551             :       ELSE
    1552           0 :          print_format = "F8.2"
    1553             :       END IF
    1554             : 
    1555         192 :       CALL timestop(handle)
    1556             : 
    1557         192 :    END SUBROUTINE get_print_format
    1558             : 
    1559             : ! **************************************************************************************************
    1560             : !> \brief ...
    1561             : !> \param bs_env ...
    1562             : !> \param qs_env ...
    1563             : !> \param ikp ...
    1564             : !> \param eigenval_no_SOC ...
    1565             : !> \param band_edges_no_SOC ...
    1566             : !> \param E_min ...
    1567             : !> \param cfm_mos_ikp ...
    1568             : !> \param DOS ...
    1569             : !> \param PDOS ...
    1570             : !> \param band_edges ...
    1571             : !> \param eigenval_spinor ...
    1572             : !> \param cfm_spinor_wf_ikp ...
    1573             : ! **************************************************************************************************
    1574         480 :    SUBROUTINE SOC_ev(bs_env, qs_env, ikp, eigenval_no_SOC, band_edges_no_SOC, E_min, cfm_mos_ikp, &
    1575             :                      DOS, PDOS, band_edges, eigenval_spinor, cfm_spinor_wf_ikp)
    1576             : 
    1577             :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
    1578             :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1579             :       INTEGER                                            :: ikp
    1580             :       REAL(KIND=dp), DIMENSION(:, :, :)                  :: eigenval_no_SOC
    1581             :       TYPE(band_edges_type)                              :: band_edges_no_SOC
    1582             :       REAL(KIND=dp)                                      :: E_min
    1583             :       TYPE(cp_cfm_type), DIMENSION(2)                    :: cfm_mos_ikp
    1584             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: DOS
    1585             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: PDOS
    1586             :       TYPE(band_edges_type)                              :: band_edges
    1587             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: eigenval_spinor
    1588             :       TYPE(cp_cfm_type)                                  :: cfm_spinor_wf_ikp
    1589             : 
    1590             :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'SOC_ev'
    1591             : 
    1592             :       INTEGER                                            :: handle, homo_spinor, n_ao, n_E, nkind
    1593             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: eigenval_spinor_no_SOC
    1594             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: proj_mo_on_kind_spinor
    1595             :       TYPE(cp_cfm_type)                                  :: cfm_eigenvec_ikp_spinor, &
    1596             :                                                             cfm_ks_ikp_spinor, cfm_mos_ikp_spinor, &
    1597             :                                                             cfm_SOC_ikp_spinor, cfm_work_ikp_spinor
    1598             : 
    1599         480 :       CALL timeset(routineN, handle)
    1600             : 
    1601         480 :       n_ao = bs_env%n_ao
    1602         480 :       homo_spinor = bs_env%n_occ(1) + bs_env%n_occ(bs_env%n_spin)
    1603         480 :       n_E = SIZE(DOS)
    1604         480 :       nkind = SIZE(PDOS, 2)
    1605             : 
    1606         480 :       CALL cp_cfm_create(cfm_ks_ikp_spinor, bs_env%cfm_SOC_spinor_ao(1)%matrix_struct)
    1607         480 :       CALL cp_cfm_create(cfm_SOC_ikp_spinor, bs_env%cfm_SOC_spinor_ao(1)%matrix_struct)
    1608         480 :       CALL cp_cfm_create(cfm_mos_ikp_spinor, bs_env%cfm_SOC_spinor_ao(1)%matrix_struct)
    1609         480 :       CALL cp_cfm_create(cfm_work_ikp_spinor, bs_env%cfm_SOC_spinor_ao(1)%matrix_struct)
    1610         480 :       CALL cp_cfm_create(cfm_eigenvec_ikp_spinor, bs_env%cfm_SOC_spinor_ao(1)%matrix_struct)
    1611             : 
    1612        1440 :       ALLOCATE (eigenval_spinor_no_SOC(2*n_ao))
    1613        1920 :       ALLOCATE (proj_mo_on_kind_spinor(2*n_ao, nkind))
    1614             :       ! PDOS not yet implemented -> projection is just zero -> PDOS is zero
    1615       20000 :       proj_mo_on_kind_spinor(:, :) = 0.0_dp
    1616             : 
    1617             :       ! 1. get V^SOC_µν,σσ'(k_i)
    1618         520 :       SELECT CASE (bs_env%small_cell_full_kp_or_large_cell_Gamma)
    1619             :       CASE (large_cell_Gamma)
    1620             : 
    1621             :          ! 1. get V^SOC_µν,σσ'(k_i) from V^SOC_µν,σσ'(k=0)
    1622             :          CALL cfm_ikp_from_cfm_spinor_Gamma(cfm_SOC_ikp_spinor, &
    1623             :                                             bs_env%cfm_SOC_spinor_ao(1), &
    1624             :                                             bs_env%fm_s_Gamma%matrix_struct, &
    1625          40 :                                             ikp, qs_env, bs_env%kpoints_DOS, "ORB")
    1626             : 
    1627             :       CASE (small_cell_full_kp)
    1628             : 
    1629             :          ! 1. V^SOC_µν,σσ'(k_i) already there
    1630         480 :          CALL cp_cfm_to_cfm(bs_env%cfm_SOC_spinor_ao(ikp), cfm_SOC_ikp_spinor)
    1631             : 
    1632             :       END SELECT
    1633             : 
    1634             :       ! 2. V^SOC_nn',σσ'(k_i) = sum_µν C^*_µn,σ(k_i) V^SOC_µν,σσ'(k_i) C_νn'(k_i),
    1635             :       !    C_µn,σ(k_i): MO coefficiencts from diagonalizing KS-matrix h^KS_nn',σσ'(k_i)
    1636             : 
    1637             :       ! 2.1 build matrix C_µn,σ(k_i)
    1638         480 :       CALL cp_cfm_set_all(cfm_mos_ikp_spinor, z_zero)
    1639         480 :       CALL add_cfm_submat(cfm_mos_ikp_spinor, cfm_mos_ikp(1), 1, 1)
    1640         480 :       CALL add_cfm_submat(cfm_mos_ikp_spinor, cfm_mos_ikp(bs_env%n_spin), n_ao + 1, n_ao + 1)
    1641             : 
    1642             :       ! 2.2 work_nν,σσ' = sum_µ C^*_µn,σ(k_i) V^SOC_µν,σσ'(k_i)
    1643             :       CALL parallel_gemm('C', 'N', 2*n_ao, 2*n_ao, 2*n_ao, z_one, &
    1644             :                          cfm_mos_ikp_spinor, cfm_SOC_ikp_spinor, &
    1645         480 :                          z_zero, cfm_work_ikp_spinor)
    1646             : 
    1647             :       ! 2.3 V^SOC_nn',σσ'(k_i) = sum_ν work_nν,σσ' C_νn'(k_i)
    1648             :       CALL parallel_gemm('N', 'N', 2*n_ao, 2*n_ao, 2*n_ao, z_one, &
    1649             :                          cfm_work_ikp_spinor, cfm_mos_ikp_spinor, &
    1650         480 :                          z_zero, cfm_ks_ikp_spinor)
    1651             : 
    1652             :       ! 3. remove SOC outside of energy window (otherwise, numerical problems arise
    1653             :       !    because energetically low semicore states and energetically very high
    1654             :       !    unbound states couple to the states around the Fermi level)
    1655        5120 :       eigenval_spinor_no_SOC(1:n_ao) = eigenval_no_SOC(1:n_ao, ikp, 1)
    1656        5120 :       eigenval_spinor_no_SOC(n_ao + 1:) = eigenval_no_SOC(1:n_ao, ikp, bs_env%n_spin)
    1657         480 :       IF (bs_env%energy_window_soc > 0.0_dp) THEN
    1658             :          CALL remove_soc_outside_energy_window_mo(cfm_ks_ikp_spinor, &
    1659             :                                                   bs_env%energy_window_soc, &
    1660             :                                                   eigenval_spinor_no_SOC, &
    1661             :                                                   band_edges_no_SOC%VBM, &
    1662         480 :                                                   band_edges_no_SOC%CBM)
    1663             :       END IF
    1664             : 
    1665             :       ! 4. h^G0W0+SOC_nn',σσ'(k_i) = ε_nσ^G0W0(k_i) δ_nn' δ_σσ' + V^SOC_nn',σσ'(k_i)
    1666         480 :       CALL cfm_add_on_diag(cfm_ks_ikp_spinor, eigenval_spinor_no_SOC)
    1667             : 
    1668             :       ! 5. diagonalize h^G0W0+SOC_nn',σσ'(k_i) to get eigenvalues
    1669         480 :       CALL cp_cfm_heevd(cfm_ks_ikp_spinor, cfm_eigenvec_ikp_spinor, eigenval_spinor)
    1670             : 
    1671             :       ! 6. DOS from spinors, no PDOS
    1672             :       CALL add_to_DOS_PDOS(DOS, PDOS, eigenval_spinor, &
    1673         480 :                            ikp, bs_env, n_E, E_min, proj_mo_on_kind_spinor)
    1674             : 
    1675             :       ! 7. valence band max. (VBM), conduction band min. (CBM) and direct bandgap (DBG)
    1676         480 :       band_edges%VBM = MAX(band_edges%VBM, eigenval_spinor(homo_spinor))
    1677         480 :       band_edges%CBM = MIN(band_edges%CBM, eigenval_spinor(homo_spinor + 1))
    1678             :       band_edges%DBG = MIN(band_edges%DBG, eigenval_spinor(homo_spinor + 1) &
    1679         480 :                            - eigenval_spinor(homo_spinor))
    1680             : 
    1681             :       ! 8. spinor wavefunctions:
    1682             :       CALL parallel_gemm('N', 'N', 2*n_ao, 2*n_ao, 2*n_ao, z_one, &
    1683             :                          cfm_mos_ikp_spinor, cfm_eigenvec_ikp_spinor, &
    1684         480 :                          z_zero, cfm_spinor_wf_ikp)
    1685             : 
    1686         480 :       CALL cp_cfm_release(cfm_ks_ikp_spinor)
    1687         480 :       CALL cp_cfm_release(cfm_SOC_ikp_spinor)
    1688         480 :       CALL cp_cfm_release(cfm_work_ikp_spinor)
    1689         480 :       CALL cp_cfm_release(cfm_eigenvec_ikp_spinor)
    1690         480 :       CALL cp_cfm_release(cfm_mos_ikp_spinor)
    1691             : 
    1692         480 :       CALL timestop(handle)
    1693             : 
    1694         960 :    END SUBROUTINE SOC_ev
    1695             : 
    1696             : ! **************************************************************************************************
    1697             : !> \brief ...
    1698             : !> \param DOS ...
    1699             : !> \param PDOS ...
    1700             : !> \param eigenval ...
    1701             : !> \param ikp ...
    1702             : !> \param bs_env ...
    1703             : !> \param n_E ...
    1704             : !> \param E_min ...
    1705             : !> \param proj_mo_on_kind ...
    1706             : ! **************************************************************************************************
    1707        1032 :    SUBROUTINE add_to_DOS_PDOS(DOS, PDOS, eigenval, ikp, bs_env, n_E, E_min, proj_mo_on_kind)
    1708             : 
    1709             :       REAL(KIND=dp), DIMENSION(:)                        :: DOS
    1710             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: PDOS
    1711             :       REAL(KIND=dp), DIMENSION(:)                        :: eigenval
    1712             :       INTEGER                                            :: ikp
    1713             :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
    1714             :       INTEGER                                            :: n_E
    1715             :       REAL(KIND=dp)                                      :: E_min
    1716             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: proj_mo_on_kind
    1717             : 
    1718             :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'add_to_DOS_PDOS'
    1719             : 
    1720             :       INTEGER                                            :: handle, i_E, i_kind, i_mo, n_mo, nkind
    1721             :       REAL(KIND=dp)                                      :: broadening, energy, energy_step_DOS, wkp
    1722             : 
    1723        1032 :       CALL timeset(routineN, handle)
    1724             : 
    1725        1032 :       energy_step_DOS = bs_env%energy_step_DOS
    1726        1032 :       broadening = bs_env%broadening_DOS
    1727             : 
    1728        1032 :       n_mo = SIZE(eigenval)
    1729        1032 :       nkind = SIZE(proj_mo_on_kind, 2)
    1730             : 
    1731             :       ! normalize to closed-shell / open-shell
    1732        1032 :       wkp = bs_env%kpoints_DOS%wkp(ikp)*bs_env%spin_degeneracy
    1733     3181752 :       DO i_E = 1, n_E
    1734     3180720 :          energy = E_min + i_E*energy_step_DOS
    1735    47010808 :          DO i_mo = 1, n_mo
    1736             :             ! DOS
    1737    43829056 :             DOS(i_E) = DOS(i_E) + wkp*Gaussian(energy - eigenval(i_mo), broadening)
    1738             : 
    1739             :             ! PDOS
    1740   134431296 :             DO i_kind = 1, nkind
    1741   131250576 :                IF (proj_mo_on_kind(i_mo, i_kind) > 0.0_dp) THEN
    1742             :                   PDOS(i_E, i_kind) = PDOS(i_E, i_kind) + &
    1743             :                                       proj_mo_on_kind(i_mo, i_kind)*wkp* &
    1744    30345880 :                                       Gaussian(energy - eigenval(i_mo), broadening)
    1745             :                END IF
    1746             :             END DO
    1747             :          END DO
    1748             :       END DO
    1749             : 
    1750        1032 :       CALL timestop(handle)
    1751             : 
    1752        1032 :    END SUBROUTINE add_to_DOS_PDOS
    1753             : 
    1754             : ! **************************************************************************************************
    1755             : !> \brief ...
    1756             : !> \param LDOS_2d ...
    1757             : !> \param qs_env ...
    1758             : !> \param ikp ...
    1759             : !> \param bs_env ...
    1760             : !> \param cfm_mos_ikp ...
    1761             : !> \param eigenval ...
    1762             : !> \param band_edges ...
    1763             : !> \param do_spinor ...
    1764             : !> \param cfm_non_spinor ...
    1765             : ! **************************************************************************************************
    1766          12 :    SUBROUTINE add_to_LDOS_2d(LDOS_2d, qs_env, ikp, bs_env, cfm_mos_ikp, eigenval, &
    1767             :                              band_edges, do_spinor, cfm_non_spinor)
    1768             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: LDOS_2d
    1769             :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1770             :       INTEGER                                            :: ikp
    1771             :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
    1772             :       TYPE(cp_cfm_type)                                  :: cfm_mos_ikp
    1773             :       REAL(KIND=dp), DIMENSION(:)                        :: eigenval
    1774             :       TYPE(band_edges_type)                              :: band_edges
    1775             :       LOGICAL, OPTIONAL                                  :: do_spinor
    1776             :       TYPE(cp_cfm_type), OPTIONAL                        :: cfm_non_spinor
    1777             : 
    1778             :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'add_to_LDOS_2d'
    1779             : 
    1780             :       INTEGER :: handle, i_E, i_x_end, i_x_start, i_y_end, i_y_start, i_z, i_z_end, i_z_start, &
    1781             :          j_col, j_mo, n_E, n_mo, n_z, ncol_local, nimages, z_end_global, z_start_global
    1782          12 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices
    1783             :       LOGICAL                                            :: is_any_weight_non_zero, my_do_spinor
    1784             :       REAL(KIND=dp)                                      :: broadening, E_max, E_min, &
    1785             :                                                             E_total_window, energy, energy_step, &
    1786             :                                                             energy_window, spin_degeneracy, weight
    1787             :       TYPE(cp_cfm_type)                                  :: cfm_weighted_dm_ikp, cfm_work
    1788             :       TYPE(cp_fm_type)                                   :: fm_non_spinor, fm_weighted_dm_MIC
    1789          12 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: weighted_dm_MIC
    1790             :       TYPE(dft_control_type), POINTER                    :: dft_control
    1791             :       TYPE(pw_c1d_gs_type)                               :: rho_g
    1792             :       TYPE(pw_env_type), POINTER                         :: pw_env
    1793             :       TYPE(pw_pool_type), POINTER                        :: auxbas_pw_pool
    1794             :       TYPE(pw_r3d_rs_type)                               :: LDOS_3d
    1795             :       TYPE(qs_ks_env_type), POINTER                      :: ks_env
    1796             : 
    1797          12 :       CALL timeset(routineN, handle)
    1798             : 
    1799          12 :       my_do_spinor = .FALSE.
    1800          12 :       IF (PRESENT(do_spinor)) my_do_spinor = do_spinor
    1801             : 
    1802          12 :       CALL get_qs_env(qs_env, ks_env=ks_env, pw_env=pw_env, dft_control=dft_control)
    1803             : 
    1804             :       ! previously, dft_control%nimages set to # neighbor cells, revert for Γ-only KS matrix
    1805          12 :       nimages = dft_control%nimages
    1806          12 :       dft_control%nimages = bs_env%nimages_scf
    1807             : 
    1808          12 :       energy_window = bs_env%energy_window_DOS
    1809          12 :       energy_step = bs_env%energy_step_DOS
    1810          12 :       broadening = bs_env%broadening_DOS
    1811             : 
    1812          12 :       E_min = band_edges%VBM - 0.5_dp*energy_window
    1813          12 :       E_max = band_edges%CBM + 0.5_dp*energy_window
    1814          12 :       E_total_window = E_max - E_min
    1815             : 
    1816          12 :       n_E = INT(E_total_window/energy_step)
    1817             : 
    1818          12 :       CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool)
    1819             : 
    1820          12 :       CALL auxbas_pw_pool%create_pw(LDOS_3d)
    1821          12 :       CALL auxbas_pw_pool%create_pw(rho_g)
    1822             : 
    1823          12 :       i_x_start = LBOUND(LDOS_3d%array, 1)
    1824          12 :       i_x_end = UBOUND(LDOS_3d%array, 1)
    1825          12 :       i_y_start = LBOUND(LDOS_3d%array, 2)
    1826          12 :       i_y_end = UBOUND(LDOS_3d%array, 2)
    1827          12 :       i_z_start = LBOUND(LDOS_3d%array, 3)
    1828          12 :       i_z_end = UBOUND(LDOS_3d%array, 3)
    1829             : 
    1830          12 :       z_start_global = i_z_start
    1831          12 :       z_end_global = i_z_end
    1832             : 
    1833          12 :       CALL bs_env%para_env%min(z_start_global)
    1834          12 :       CALL bs_env%para_env%max(z_end_global)
    1835          12 :       n_z = z_end_global - z_start_global + 1
    1836             : 
    1837          72 :       IF (ANY(ABS(bs_env%hmat(1:2, 3)) > 1.0E-6_dp) .OR. ANY(ABS(bs_env%hmat(3, 1:2)) > 1.0E-6_dp)) &
    1838           0 :          CPABORT("Please choose a cell that has 90° angles to the z-direction.")
    1839             :       ! for integration, we need the dz and the conversion from H -> eV and a_Bohr -> Å
    1840          12 :       bs_env%unit_ldos_int_z_inv_Ang2_eV = bs_env%hmat(3, 3)/REAL(n_z, KIND=dp)/evolt/angstrom**2
    1841             : 
    1842          12 :       IF (ikp == 1) THEN
    1843          60 :          ALLOCATE (LDOS_2d(i_x_start:i_x_end, i_y_start:i_y_end, n_E))
    1844     2357532 :          LDOS_2d(:, :, :) = 0.0_dp
    1845             :       END IF
    1846             : 
    1847          12 :       CALL cp_cfm_create(cfm_work, cfm_mos_ikp%matrix_struct)
    1848          12 :       CALL cp_cfm_create(cfm_weighted_dm_ikp, cfm_mos_ikp%matrix_struct)
    1849          12 :       CALL cp_fm_create(fm_weighted_dm_MIC, cfm_mos_ikp%matrix_struct)
    1850          12 :       IF (my_do_spinor) THEN
    1851           4 :          CALL cp_fm_create(fm_non_spinor, cfm_non_spinor%matrix_struct)
    1852             :       END IF
    1853             : 
    1854             :       CALL cp_cfm_get_info(matrix=cfm_mos_ikp, &
    1855             :                            ncol_global=n_mo, &
    1856             :                            ncol_local=ncol_local, &
    1857          12 :                            col_indices=col_indices)
    1858             : 
    1859          12 :       NULLIFY (weighted_dm_MIC)
    1860          12 :       CALL dbcsr_allocate_matrix_set(weighted_dm_MIC, 1)
    1861          12 :       ALLOCATE (weighted_dm_MIC(1)%matrix)
    1862             :       CALL dbcsr_create(weighted_dm_MIC(1)%matrix, template=bs_env%mat_ao_ao%matrix, &
    1863          12 :                         matrix_type=dbcsr_type_symmetric)
    1864             : 
    1865        3356 :       DO i_E = 1, n_E
    1866             : 
    1867        3344 :          energy = E_min + i_E*energy_step
    1868             : 
    1869        3344 :          is_any_weight_non_zero = .FALSE.
    1870             : 
    1871       41900 :          DO j_col = 1, ncol_local
    1872             : 
    1873       38556 :             j_mo = col_indices(j_col)
    1874             : 
    1875       38556 :             IF (my_do_spinor) THEN
    1876             :                spin_degeneracy = 1.0_dp
    1877             :             ELSE
    1878       21636 :                spin_degeneracy = bs_env%spin_degeneracy
    1879             :             END IF
    1880             : 
    1881       38556 :             weight = Gaussian(energy - eigenval(j_mo), broadening)*spin_degeneracy
    1882             : 
    1883      288198 :             cfm_work%local_data(:, j_col) = cfm_mos_ikp%local_data(:, j_col)*weight
    1884             : 
    1885       41900 :             IF (weight > 1.0E-5_dp) is_any_weight_non_zero = .TRUE.
    1886             : 
    1887             :          END DO
    1888             : 
    1889        3344 :          CALL bs_env%para_env%sync()
    1890        3344 :          CALL bs_env%para_env%sum(is_any_weight_non_zero)
    1891        3344 :          CALL bs_env%para_env%sync()
    1892             : 
    1893             :          ! cycle if there are no states at the energy i_E
    1894        3356 :          IF (is_any_weight_non_zero) THEN
    1895             : 
    1896             :             CALL parallel_gemm('N', 'C', n_mo, n_mo, n_mo, z_one, &
    1897          48 :                                cfm_mos_ikp, cfm_work, z_zero, cfm_weighted_dm_ikp)
    1898             : 
    1899          48 :             IF (my_do_spinor) THEN
    1900             : 
    1901             :                ! contribution from up,up to fm_non_spinor
    1902          16 :                CALL get_cfm_submat(cfm_non_spinor, cfm_weighted_dm_ikp, 1, 1)
    1903          16 :                CALL cp_fm_set_all(fm_non_spinor, 0.0_dp)
    1904             :                CALL MIC_contribution_from_ikp(bs_env, qs_env, fm_non_spinor, &
    1905             :                                               cfm_non_spinor, ikp, bs_env%kpoints_DOS, &
    1906          16 :                                               "ORB", bs_env%kpoints_DOS%wkp(ikp))
    1907             : 
    1908             :                ! add contribution from down,down to fm_non_spinor
    1909          16 :                CALL get_cfm_submat(cfm_non_spinor, cfm_weighted_dm_ikp, n_mo/2, n_mo/2)
    1910             :                CALL MIC_contribution_from_ikp(bs_env, qs_env, fm_non_spinor, &
    1911             :                                               cfm_non_spinor, ikp, bs_env%kpoints_DOS, &
    1912          16 :                                               "ORB", bs_env%kpoints_DOS%wkp(ikp))
    1913             :                CALL copy_fm_to_dbcsr(fm_non_spinor, weighted_dm_MIC(1)%matrix, &
    1914          16 :                                      keep_sparsity=.FALSE.)
    1915             :             ELSE
    1916          32 :                CALL cp_fm_set_all(fm_weighted_dm_MIC, 0.0_dp)
    1917             :                CALL MIC_contribution_from_ikp(bs_env, qs_env, fm_weighted_dm_MIC, &
    1918             :                                               cfm_weighted_dm_ikp, ikp, bs_env%kpoints_DOS, &
    1919          32 :                                               "ORB", bs_env%kpoints_DOS%wkp(ikp))
    1920             :                CALL copy_fm_to_dbcsr(fm_weighted_dm_MIC, weighted_dm_MIC(1)%matrix, &
    1921          32 :                                      keep_sparsity=.FALSE.)
    1922             :             END IF
    1923             : 
    1924      676848 :             LDOS_3d%array(:, :, :) = 0.0_dp
    1925             : 
    1926             :             CALL calculate_rho_elec(matrix_p_kp=weighted_dm_MIC, &
    1927             :                                     rho=LDOS_3d, &
    1928             :                                     rho_gspace=rho_g, &
    1929          48 :                                     ks_env=ks_env)
    1930             : 
    1931        1008 :             DO i_z = i_z_start, i_z_end
    1932      676848 :                LDOS_2d(:, :, i_E) = LDOS_2d(:, :, i_E) + LDOS_3d%array(:, :, i_z)
    1933             :             END DO
    1934             : 
    1935             :          END IF
    1936             : 
    1937             :       END DO
    1938             : 
    1939             :       ! set back nimages
    1940          12 :       dft_control%nimages = nimages
    1941             : 
    1942          12 :       CALL auxbas_pw_pool%give_back_pw(LDOS_3d)
    1943          12 :       CALL auxbas_pw_pool%give_back_pw(rho_g)
    1944             : 
    1945          12 :       CALL cp_cfm_release(cfm_work)
    1946          12 :       CALL cp_cfm_release(cfm_weighted_dm_ikp)
    1947             : 
    1948          12 :       CALL cp_fm_release(fm_weighted_dm_MIC)
    1949             : 
    1950          12 :       CALL dbcsr_deallocate_matrix_set(weighted_dm_MIC)
    1951             : 
    1952          12 :       IF (my_do_spinor) THEN
    1953           4 :          CALL cp_fm_release(fm_non_spinor)
    1954             :       END IF
    1955             : 
    1956          12 :       CALL timestop(handle)
    1957             : 
    1958          12 :    END SUBROUTINE add_to_LDOS_2d
    1959             : 
    1960             : ! **************************************************************************************************
    1961             : !> \brief ...
    1962             : !> \param eigenval_spinor ...
    1963             : !> \param ikp_for_file ...
    1964             : !> \param ikp ...
    1965             : !> \param bs_env ...
    1966             : !> \param eigenval_spinor_G0W0 ...
    1967             : ! **************************************************************************************************
    1968         176 :    SUBROUTINE write_SOC_eigenvalues(eigenval_spinor, ikp_for_file, ikp, bs_env, eigenval_spinor_G0W0)
    1969             : 
    1970             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: eigenval_spinor
    1971             :       INTEGER                                            :: ikp_for_file, ikp
    1972             :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
    1973             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), OPTIONAL :: eigenval_spinor_G0W0
    1974             : 
    1975             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'write_SOC_eigenvalues'
    1976             : 
    1977             :       CHARACTER(len=3)                                   :: occ_vir
    1978             :       CHARACTER(LEN=default_string_length)               :: fname
    1979             :       INTEGER                                            :: handle, i_mo, iunit, n_occ_spinor
    1980             : 
    1981         176 :       CALL timeset(routineN, handle)
    1982             : 
    1983         176 :       fname = "bandstructure_SCF_and_G0W0_plus_SOC"
    1984             : 
    1985         176 :       IF (bs_env%para_env%is_source()) THEN
    1986             : 
    1987          88 :          IF (ikp_for_file == 1) THEN
    1988             :             CALL open_file(TRIM(fname), unit_number=iunit, file_status="REPLACE", &
    1989           9 :                            file_action="WRITE")
    1990             :          ELSE
    1991             :             CALL open_file(TRIM(fname), unit_number=iunit, file_status="OLD", &
    1992          79 :                            file_action="WRITE", file_position="APPEND")
    1993             :          END IF
    1994             : 
    1995          88 :          WRITE (iunit, "(A)") " "
    1996          88 :          WRITE (iunit, "(A10,I7,A25,3F10.4)") "kpoint: ", ikp_for_file, "coordinate: ", &
    1997         176 :             bs_env%kpoints_DOS%xkp(:, ikp)
    1998          88 :          WRITE (iunit, "(A)") " "
    1999             : 
    2000          88 :          IF (PRESENT(eigenval_spinor_G0W0)) THEN
    2001             :             ! SCF+SOC and G0W0+SOC eigenvalues
    2002          88 :             WRITE (iunit, "(A5,A12,2A22)") "n", "k", "ϵ_nk^DFT+SOC (eV)", "ϵ_nk^G0W0+SOC (eV)"
    2003             :          ELSE
    2004             :             ! SCF+SOC eigenvalues only
    2005           0 :             WRITE (iunit, "(A5,A12,A22)") "n", "k", "ϵ_nk^DFT+SOC (eV)"
    2006             :          END IF
    2007             : 
    2008          88 :          n_occ_spinor = bs_env%n_occ(1) + bs_env%n_occ(bs_env%n_spin)
    2009             : 
    2010        1832 :          DO i_mo = 1, SIZE(eigenval_spinor)
    2011        1744 :             IF (i_mo .LE. n_occ_spinor) occ_vir = 'occ'
    2012        1744 :             IF (i_mo > n_occ_spinor) occ_vir = 'vir'
    2013        1832 :             IF (PRESENT(eigenval_spinor_G0W0)) THEN
    2014             :                ! SCF+SOC and G0W0+SOC eigenvalues
    2015        1744 :                WRITE (iunit, "(I5,3A,I5,4F16.3,2F17.3)") i_mo, ' (', occ_vir, ') ', &
    2016        3488 :                   ikp_for_file, eigenval_spinor(i_mo)*evolt, eigenval_spinor_G0W0(i_mo)*evolt
    2017             :             ELSE
    2018             :                ! SCF+SOC eigenvalues only
    2019           0 :                WRITE (iunit, "(I5,3A,I5,4F16.3,F17.3)") i_mo, ' (', occ_vir, ') ', &
    2020           0 :                   ikp_for_file, eigenval_spinor(i_mo)*evolt
    2021             :             END IF
    2022             :          END DO
    2023             : 
    2024          88 :          CALL close_file(iunit)
    2025             : 
    2026             :       END IF
    2027             : 
    2028         176 :       CALL timestop(handle)
    2029             : 
    2030         176 :    END SUBROUTINE write_SOC_eigenvalues
    2031             : 
    2032             : ! **************************************************************************************************
    2033             : !> \brief ...
    2034             : !> \param int_number ...
    2035             : !> \return ...
    2036             : ! **************************************************************************************************
    2037           0 :    PURE FUNCTION count_digits(int_number)
    2038             : 
    2039             :       INTEGER, INTENT(IN)                                :: int_number
    2040             :       INTEGER                                            :: count_digits
    2041             : 
    2042             :       INTEGER                                            :: digitCount, tempInt
    2043             : 
    2044           0 :       digitCount = 0
    2045             : 
    2046           0 :       tempInt = int_number
    2047             : 
    2048           0 :       DO WHILE (tempInt /= 0)
    2049           0 :          tempInt = tempInt/10
    2050           0 :          digitCount = digitCount + 1
    2051             :       END DO
    2052             : 
    2053           0 :       count_digits = digitCount
    2054             : 
    2055           0 :    END FUNCTION count_digits
    2056             : 
    2057             : ! **************************************************************************************************
    2058             : !> \brief ...
    2059             : !> \param band_edges ...
    2060             : !> \param scf_gw_soc ...
    2061             : !> \param bs_env ...
    2062             : ! **************************************************************************************************
    2063         138 :    SUBROUTINE write_band_edges(band_edges, scf_gw_soc, bs_env)
    2064             : 
    2065             :       TYPE(band_edges_type)                              :: band_edges
    2066             :       CHARACTER(LEN=*)                                   :: scf_gw_soc
    2067             :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
    2068             : 
    2069             :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'write_band_edges'
    2070             : 
    2071             :       CHARACTER(LEN=17)                                  :: print_format
    2072             :       INTEGER                                            :: handle, u
    2073             : 
    2074         138 :       CALL timeset(routineN, handle)
    2075             : 
    2076             :       ! print format
    2077         138 :       print_format = "(T2,2A,T61,F20.3)"
    2078             : 
    2079         138 :       u = bs_env%unit_nr
    2080         138 :       IF (u > 0) THEN
    2081          69 :          WRITE (u, '(T2,A)') ''
    2082          69 :          WRITE (u, print_format) scf_gw_soc, ' valence band maximum (eV):', band_edges%VBM*evolt
    2083          69 :          WRITE (u, print_format) scf_gw_soc, ' conduction band minimum (eV):', band_edges%CBM*evolt
    2084          69 :          WRITE (u, print_format) scf_gw_soc, ' indirect band gap (eV):', band_edges%IDBG*evolt
    2085          69 :          WRITE (u, print_format) scf_gw_soc, ' direct band gap (eV):', band_edges%DBG*evolt
    2086             :       END IF
    2087             : 
    2088         138 :       CALL timestop(handle)
    2089             : 
    2090         138 :    END SUBROUTINE write_band_edges
    2091             : 
    2092             : ! **************************************************************************************************
    2093             : !> \brief ...
    2094             : !> \param DOS ...
    2095             : !> \param PDOS ...
    2096             : !> \param bs_env ...
    2097             : !> \param qs_env ...
    2098             : !> \param scf_gw_soc ...
    2099             : !> \param E_min ...
    2100             : !> \param E_VBM ...
    2101             : ! **************************************************************************************************
    2102         104 :    SUBROUTINE write_dos_pdos(DOS, PDOS, bs_env, qs_env, scf_gw_soc, E_min, E_VBM)
    2103             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: DOS
    2104             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: PDOS
    2105             :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
    2106             :       TYPE(qs_environment_type), POINTER                 :: qs_env
    2107             :       CHARACTER(LEN=*)                                   :: scf_gw_soc
    2108             :       REAL(KIND=dp)                                      :: E_min, E_VBM
    2109             : 
    2110             :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'write_dos_pdos'
    2111             : 
    2112             :       CHARACTER(LEN=3), DIMENSION(100)                   :: elements
    2113             :       CHARACTER(LEN=default_string_length)               :: atom_name, fname, output_string
    2114             :       INTEGER                                            :: handle, i_E, i_kind, iatom, iunit, n_A, &
    2115             :                                                             n_E, nkind
    2116             :       REAL(KIND=dp)                                      :: energy
    2117         104 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    2118             : 
    2119         104 :       CALL timeset(routineN, handle)
    2120             : 
    2121         104 :       WRITE (fname, "(3A)") "DOS_PDOS_", scf_gw_soc, ".out"
    2122             : 
    2123         104 :       n_E = SIZE(PDOS, 1)
    2124         104 :       nkind = SIZE(PDOS, 2)
    2125         104 :       CALL get_qs_env(qs_env, particle_set=particle_set)
    2126             : 
    2127         104 :       IF (bs_env%para_env%is_source()) THEN
    2128             : 
    2129          52 :          CALL open_file(TRIM(fname), unit_number=iunit, file_status="REPLACE", file_action="WRITE")
    2130             : 
    2131          52 :          n_A = 2 + nkind
    2132             : 
    2133         164 :          DO iatom = 1, bs_env%n_atom
    2134             :             CALL get_atomic_kind(atomic_kind=particle_set(iatom)%atomic_kind, &
    2135         112 :                                  kind_number=i_kind, name=atom_name)
    2136         164 :             elements(i_kind) = atom_name
    2137             :          END DO
    2138             : 
    2139          52 :          WRITE (output_string, "(A,I1,A)") "(", n_A, "A)"
    2140             : 
    2141          52 :          WRITE (iunit, TRIM(output_string)) "Energy-E_F (eV)    DOS (1/eV)    PDOS (1/eV) ", &
    2142         104 :             " of atom type ", elements(1:nkind)
    2143             : 
    2144          52 :          WRITE (output_string, "(A,I1,A)") "(", n_A, "F13.5)"
    2145             : 
    2146      134690 :          DO i_E = 1, n_E
    2147             :             ! energy is relative to valence band maximum => - E_VBM
    2148      134638 :             energy = E_min + i_E*bs_env%energy_step_DOS - E_VBM
    2149      344818 :             WRITE (iunit, TRIM(output_string)) energy*evolt, DOS(i_E)/evolt, PDOS(i_E, :)/evolt
    2150             :          END DO
    2151             : 
    2152          52 :          CALL close_file(iunit)
    2153             : 
    2154             :       END IF
    2155             : 
    2156         104 :       CALL timestop(handle)
    2157             : 
    2158         104 :    END SUBROUTINE write_dos_pdos
    2159             : 
    2160             : ! **************************************************************************************************
    2161             : !> \brief ...
    2162             : !> \param energy ...
    2163             : !> \param broadening ...
    2164             : !> \return ...
    2165             : ! **************************************************************************************************
    2166    74213492 :    PURE FUNCTION Gaussian(energy, broadening)
    2167             : 
    2168             :       REAL(KIND=dp), INTENT(IN)                          :: energy, broadening
    2169             :       REAL(KIND=dp)                                      :: Gaussian
    2170             : 
    2171    74213492 :       IF (ABS(energy) < 5*broadening) THEN
    2172      121084 :          Gaussian = 1.0_dp/broadening/SQRT(twopi)*EXP(-0.5_dp*energy**2/broadening**2)
    2173             :       ELSE
    2174             :          Gaussian = 0.0_dp
    2175             :       END IF
    2176             : 
    2177    74213492 :    END FUNCTION
    2178             : 
    2179             : ! **************************************************************************************************
    2180             : !> \brief ...
    2181             : !> \param proj_mo_on_kind ...
    2182             : !> \param qs_env ...
    2183             : !> \param cfm_mos ...
    2184             : !> \param cfm_s ...
    2185             : ! **************************************************************************************************
    2186         276 :    SUBROUTINE compute_proj_mo_on_kind(proj_mo_on_kind, qs_env, cfm_mos, cfm_s)
    2187             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: proj_mo_on_kind
    2188             :       TYPE(qs_environment_type), POINTER                 :: qs_env
    2189             :       TYPE(cp_cfm_type)                                  :: cfm_mos, cfm_s
    2190             : 
    2191             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'compute_proj_mo_on_kind'
    2192             : 
    2193             :       INTEGER                                            :: handle, i_atom, i_global, i_kind, i_row, &
    2194             :                                                             j_col, n_ao, n_mo, ncol_local, nkind, &
    2195             :                                                             nrow_local
    2196         276 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: atom_from_bf, kind_of
    2197         276 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices, row_indices
    2198         276 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
    2199             :       TYPE(cp_cfm_type)                                  :: cfm_proj, cfm_s_i_kind, cfm_work
    2200             :       TYPE(cp_fm_type)                                   :: fm_proj_im, fm_proj_re
    2201             : 
    2202         276 :       CALL timeset(routineN, handle)
    2203             : 
    2204         276 :       CALL get_qs_env(qs_env, atomic_kind_set=atomic_kind_set, nkind=nkind)
    2205         276 :       CALL get_atomic_kind_set(atomic_kind_set, kind_of=kind_of)
    2206             : 
    2207             :       CALL cp_cfm_get_info(matrix=cfm_mos, &
    2208             :                            nrow_global=n_mo, &
    2209             :                            nrow_local=nrow_local, &
    2210             :                            ncol_local=ncol_local, &
    2211             :                            row_indices=row_indices, &
    2212         276 :                            col_indices=col_indices)
    2213             : 
    2214         276 :       n_ao = qs_env%bs_env%n_ao
    2215             : 
    2216         828 :       ALLOCATE (atom_from_bf(n_ao))
    2217         276 :       CALL get_atom_index_from_basis_function_index(qs_env, atom_from_bf, n_ao, "ORB")
    2218             : 
    2219        6136 :       proj_mo_on_kind(:, :) = 0.0_dp
    2220             : 
    2221         276 :       CALL cp_cfm_create(cfm_s_i_kind, cfm_s%matrix_struct)
    2222         276 :       CALL cp_cfm_create(cfm_work, cfm_s%matrix_struct)
    2223         276 :       CALL cp_cfm_create(cfm_proj, cfm_s%matrix_struct)
    2224         276 :       CALL cp_fm_create(fm_proj_re, cfm_s%matrix_struct)
    2225         276 :       CALL cp_fm_create(fm_proj_im, cfm_s%matrix_struct)
    2226             : 
    2227         816 :       DO i_kind = 1, nkind
    2228             : 
    2229         540 :          CALL cp_cfm_to_cfm(cfm_s, cfm_s_i_kind)
    2230             : 
    2231             :          ! set entries in overlap matrix to zero which do not belong to atoms of i_kind
    2232        3200 :          DO i_row = 1, nrow_local
    2233       31872 :             DO j_col = 1, ncol_local
    2234             : 
    2235       28672 :                i_global = row_indices(i_row)
    2236             : 
    2237       28672 :                IF (i_global .LE. n_ao) THEN
    2238       28672 :                   i_atom = atom_from_bf(i_global)
    2239           0 :                ELSE IF (i_global .LE. 2*n_ao) THEN
    2240           0 :                   i_atom = atom_from_bf(i_global - n_ao)
    2241             :                ELSE
    2242           0 :                   CPABORT("Wrong indices.")
    2243             :                END IF
    2244             : 
    2245       31332 :                IF (i_kind .NE. kind_of(i_atom)) THEN
    2246       14324 :                   cfm_s_i_kind%local_data(i_row, j_col) = z_zero
    2247             :                END IF
    2248             : 
    2249             :             END DO
    2250             :          END DO
    2251             : 
    2252             :          CALL parallel_gemm('N', 'N', n_mo, n_mo, n_mo, z_one, &
    2253         540 :                             cfm_s_i_kind, cfm_mos, z_zero, cfm_work)
    2254             :          CALL parallel_gemm('C', 'N', n_mo, n_mo, n_mo, z_one, &
    2255         540 :                             cfm_mos, cfm_work, z_zero, cfm_proj)
    2256             : 
    2257         540 :          CALL cp_cfm_to_fm(cfm_proj, fm_proj_re, fm_proj_im)
    2258             : 
    2259         540 :          CALL cp_fm_get_diag(fm_proj_im, proj_mo_on_kind(:, i_kind))
    2260         816 :          CALL cp_fm_get_diag(fm_proj_re, proj_mo_on_kind(:, i_kind))
    2261             : 
    2262             :       END DO ! i_kind
    2263             : 
    2264         276 :       CALL cp_cfm_release(cfm_s_i_kind)
    2265         276 :       CALL cp_cfm_release(cfm_work)
    2266         276 :       CALL cp_cfm_release(cfm_proj)
    2267         276 :       CALL cp_fm_release(fm_proj_re)
    2268         276 :       CALL cp_fm_release(fm_proj_im)
    2269             : 
    2270         276 :       CALL timestop(handle)
    2271             : 
    2272        1104 :    END SUBROUTINE compute_proj_mo_on_kind
    2273             : 
    2274             : ! **************************************************************************************************
    2275             : !> \brief ...
    2276             : !> \param cfm_spinor_ikp ...
    2277             : !> \param cfm_spinor_Gamma ...
    2278             : !> \param fm_struct_non_spinor ...
    2279             : !> \param ikp ...
    2280             : !> \param qs_env ...
    2281             : !> \param kpoints ...
    2282             : !> \param basis_type ...
    2283             : ! **************************************************************************************************
    2284         240 :    SUBROUTINE cfm_ikp_from_cfm_spinor_Gamma(cfm_spinor_ikp, cfm_spinor_Gamma, fm_struct_non_spinor, &
    2285             :                                             ikp, qs_env, kpoints, basis_type)
    2286             :       TYPE(cp_cfm_type)                                  :: cfm_spinor_ikp, cfm_spinor_Gamma
    2287             :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_non_spinor
    2288             :       INTEGER                                            :: ikp
    2289             :       TYPE(qs_environment_type), POINTER                 :: qs_env
    2290             :       TYPE(kpoint_type), POINTER                         :: kpoints
    2291             :       CHARACTER(LEN=*)                                   :: basis_type
    2292             : 
    2293             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'cfm_ikp_from_cfm_spinor_Gamma'
    2294             : 
    2295             :       INTEGER                                            :: handle, i_block, i_offset, j_block, &
    2296             :                                                             j_offset, n_ao
    2297             :       TYPE(cp_cfm_type)                                  :: cfm_non_spinor_Gamma, cfm_non_spinor_ikp
    2298             :       TYPE(cp_fm_type)                                   :: fm_non_spinor_Gamma_im, &
    2299             :                                                             fm_non_spinor_Gamma_re
    2300             : 
    2301          40 :       CALL timeset(routineN, handle)
    2302             : 
    2303          40 :       CALL cp_cfm_create(cfm_non_spinor_Gamma, fm_struct_non_spinor)
    2304          40 :       CALL cp_cfm_create(cfm_non_spinor_ikp, fm_struct_non_spinor)
    2305          40 :       CALL cp_fm_create(fm_non_spinor_Gamma_re, fm_struct_non_spinor)
    2306          40 :       CALL cp_fm_create(fm_non_spinor_Gamma_im, fm_struct_non_spinor)
    2307             : 
    2308          40 :       CALL cp_cfm_get_info(cfm_non_spinor_Gamma, nrow_global=n_ao)
    2309             : 
    2310          40 :       CALL cp_cfm_set_all(cfm_spinor_ikp, z_zero)
    2311             : 
    2312         120 :       DO i_block = 0, 1
    2313         280 :          DO j_block = 0, 1
    2314         160 :             i_offset = i_block*n_ao + 1
    2315         160 :             j_offset = j_block*n_ao + 1
    2316         160 :             CALL get_cfm_submat(cfm_non_spinor_Gamma, cfm_spinor_Gamma, i_offset, j_offset)
    2317         160 :             CALL cp_cfm_to_fm(cfm_non_spinor_Gamma, fm_non_spinor_Gamma_re, fm_non_spinor_Gamma_im)
    2318             : 
    2319             :             ! transform real part of Gamma-point matrix to ikp
    2320             :             CALL cfm_ikp_from_fm_Gamma(cfm_non_spinor_ikp, fm_non_spinor_Gamma_re, &
    2321         160 :                                        ikp, qs_env, kpoints, basis_type)
    2322         160 :             CALL add_cfm_submat(cfm_spinor_ikp, cfm_non_spinor_ikp, i_offset, j_offset)
    2323             : 
    2324             :             ! transform imag part of Gamma-point matrix to ikp
    2325             :             CALL cfm_ikp_from_fm_Gamma(cfm_non_spinor_ikp, fm_non_spinor_Gamma_im, &
    2326         160 :                                        ikp, qs_env, kpoints, basis_type)
    2327         240 :             CALL add_cfm_submat(cfm_spinor_ikp, cfm_non_spinor_ikp, i_offset, j_offset, gaussi)
    2328             : 
    2329             :          END DO
    2330             :       END DO
    2331             : 
    2332          40 :       CALL cp_cfm_release(cfm_non_spinor_Gamma)
    2333          40 :       CALL cp_cfm_release(cfm_non_spinor_ikp)
    2334          40 :       CALL cp_fm_release(fm_non_spinor_Gamma_re)
    2335          40 :       CALL cp_fm_release(fm_non_spinor_Gamma_im)
    2336             : 
    2337          40 :       CALL timestop(handle)
    2338             : 
    2339          40 :    END SUBROUTINE cfm_ikp_from_cfm_spinor_Gamma
    2340             : 
    2341             : ! **************************************************************************************************
    2342             : !> \brief ...
    2343             : !> \param cfm_ikp ...
    2344             : !> \param fm_Gamma ...
    2345             : !> \param ikp ...
    2346             : !> \param qs_env ...
    2347             : !> \param kpoints ...
    2348             : !> \param basis_type ...
    2349             : ! **************************************************************************************************
    2350        3972 :    SUBROUTINE cfm_ikp_from_fm_Gamma(cfm_ikp, fm_Gamma, ikp, qs_env, kpoints, basis_type)
    2351             :       TYPE(cp_cfm_type)                                  :: cfm_ikp
    2352             :       TYPE(cp_fm_type)                                   :: fm_Gamma
    2353             :       INTEGER                                            :: ikp
    2354             :       TYPE(qs_environment_type), POINTER                 :: qs_env
    2355             :       TYPE(kpoint_type), POINTER                         :: kpoints
    2356             :       CHARACTER(LEN=*)                                   :: basis_type
    2357             : 
    2358             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'cfm_ikp_from_fm_Gamma'
    2359             : 
    2360             :       INTEGER :: col_global, handle, i, i_atom, i_atom_old, i_cell, i_mic_cell, i_row, j, j_atom, &
    2361             :          j_atom_old, j_cell, j_col, n_bf, ncol_local, nrow_local, num_cells, row_global
    2362        3972 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: atom_from_bf
    2363        3972 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices, row_indices
    2364        3972 :       INTEGER, DIMENSION(:, :), POINTER                  :: index_to_cell
    2365             :       LOGICAL :: i_cell_is_the_minimum_image_cell
    2366             :       REAL(KIND=dp)                                      :: abs_rab_cell_i, abs_rab_cell_j, arg
    2367             :       REAL(KIND=dp), DIMENSION(3)                        :: cell_vector, cell_vector_j, rab_cell_i, &
    2368             :                                                             rab_cell_j
    2369             :       REAL(KIND=dp), DIMENSION(3, 3)                     :: hmat
    2370             :       TYPE(cell_type), POINTER                           :: cell
    2371        3972 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    2372             : 
    2373        3972 :       CALL timeset(routineN, handle)
    2374             : 
    2375        3972 :       IF (.NOT. ASSOCIATED(cfm_ikp%local_data)) THEN
    2376        2120 :          CALL cp_cfm_create(cfm_ikp, fm_Gamma%matrix_struct)
    2377             :       END IF
    2378        3972 :       CALL cp_cfm_set_all(cfm_ikp, z_zero)
    2379             : 
    2380             :       CALL cp_fm_get_info(matrix=fm_Gamma, &
    2381             :                           nrow_local=nrow_local, &
    2382             :                           ncol_local=ncol_local, &
    2383             :                           row_indices=row_indices, &
    2384        3972 :                           col_indices=col_indices)
    2385             : 
    2386             :       ! get number of basis functions (bf) for different basis sets
    2387        3972 :       IF (basis_type == "ORB") THEN
    2388        1992 :          n_bf = qs_env%bs_env%n_ao
    2389        1980 :       ELSE IF (basis_type == "RI_AUX") THEN
    2390        1980 :          n_bf = qs_env%bs_env%n_RI
    2391             :       ELSE
    2392           0 :          CPABORT("Only ORB and RI_AUX basis implemented.")
    2393             :       END IF
    2394             : 
    2395       11916 :       ALLOCATE (atom_from_bf(n_bf))
    2396        3972 :       CALL get_atom_index_from_basis_function_index(qs_env, atom_from_bf, n_bf, basis_type)
    2397             : 
    2398        3972 :       NULLIFY (cell, particle_set)
    2399        3972 :       CALL get_qs_env(qs_env, cell=cell, particle_set=particle_set)
    2400        3972 :       CALL get_cell(cell=cell, h=hmat)
    2401             : 
    2402        3972 :       index_to_cell => kpoints%index_to_cell
    2403             : 
    2404        3972 :       num_cells = SIZE(index_to_cell, 2)
    2405        3972 :       i_atom_old = 0
    2406        3972 :       j_atom_old = 0
    2407             : 
    2408       18932 :       DO i_row = 1, nrow_local
    2409      176400 :          DO j_col = 1, ncol_local
    2410             : 
    2411      157468 :             row_global = row_indices(i_row)
    2412      157468 :             col_global = col_indices(j_col)
    2413             : 
    2414      157468 :             i_atom = atom_from_bf(row_global)
    2415      157468 :             j_atom = atom_from_bf(col_global)
    2416             : 
    2417             :             ! we only need to check for new MIC cell for new i_atom-j_atom pair
    2418      157468 :             IF (i_atom .NE. i_atom_old .OR. j_atom .NE. j_atom_old) THEN
    2419      443216 :                DO i_cell = 1, num_cells
    2420             : 
    2421             :                   ! only check nearest neigbors
    2422     1235640 :                   IF (ANY(ABS(index_to_cell(1:3, i_cell)) > 1)) CYCLE
    2423             : 
    2424     3244992 :                   cell_vector(1:3) = MATMUL(hmat, REAL(index_to_cell(1:3, i_cell), dp))
    2425             : 
    2426             :                   rab_cell_i(1:3) = pbc(particle_set(i_atom)%r(1:3), cell) - &
    2427      811248 :                                     (pbc(particle_set(j_atom)%r(1:3), cell) + cell_vector(1:3))
    2428      202812 :                   abs_rab_cell_i = SQRT(rab_cell_i(1)**2 + rab_cell_i(2)**2 + rab_cell_i(3)**2)
    2429             : 
    2430             :                   ! minimum image convention
    2431      202812 :                   i_cell_is_the_minimum_image_cell = .TRUE.
    2432     3530736 :                   DO j_cell = 1, num_cells
    2433    53246784 :                      cell_vector_j(1:3) = MATMUL(hmat, REAL(index_to_cell(1:3, j_cell), dp))
    2434             :                      rab_cell_j(1:3) = pbc(particle_set(i_atom)%r(1:3), cell) - &
    2435    13311696 :                                        (pbc(particle_set(j_atom)%r(1:3), cell) + cell_vector_j(1:3))
    2436     3327924 :                      abs_rab_cell_j = SQRT(rab_cell_j(1)**2 + rab_cell_j(2)**2 + rab_cell_j(3)**2)
    2437             : 
    2438     3530736 :                      IF (abs_rab_cell_i > abs_rab_cell_j + 1.0E-6_dp) THEN
    2439      654032 :                         i_cell_is_the_minimum_image_cell = .FALSE.
    2440             :                      END IF
    2441             :                   END DO
    2442             : 
    2443      236976 :                   IF (i_cell_is_the_minimum_image_cell) THEN
    2444       34164 :                      i_mic_cell = i_cell
    2445             :                   END IF
    2446             : 
    2447             :                END DO ! i_cell
    2448             :             END IF
    2449             : 
    2450             :             arg = REAL(index_to_cell(1, i_mic_cell), dp)*kpoints%xkp(1, ikp) + &
    2451             :                   REAL(index_to_cell(2, i_mic_cell), dp)*kpoints%xkp(2, ikp) + &
    2452      157468 :                   REAL(index_to_cell(3, i_mic_cell), dp)*kpoints%xkp(3, ikp)
    2453             : 
    2454      157468 :             i = i_row
    2455      157468 :             j = j_col
    2456             : 
    2457             :             cfm_ikp%local_data(i, j) = COS(twopi*arg)*fm_Gamma%local_data(i, j)*z_one + &
    2458      157468 :                                        SIN(twopi*arg)*fm_Gamma%local_data(i, j)*gaussi
    2459             : 
    2460      157468 :             j_atom_old = j_atom
    2461      172428 :             i_atom_old = i_atom
    2462             : 
    2463             :          END DO ! j_col
    2464             :       END DO ! i_row
    2465             : 
    2466        3972 :       CALL timestop(handle)
    2467             : 
    2468       11916 :    END SUBROUTINE cfm_ikp_from_fm_Gamma
    2469             : 
    2470             : ! **************************************************************************************************
    2471             : !> \brief ...
    2472             : !> \param bs_env ...
    2473             : !> \param qs_env ...
    2474             : !> \param fm_W_MIC_freq_j ...
    2475             : !> \param cfm_W_ikp_freq_j ...
    2476             : !> \param ikp ...
    2477             : !> \param kpoints ...
    2478             : !> \param basis_type ...
    2479             : !> \param wkp_ext ...
    2480             : ! **************************************************************************************************
    2481        2076 :    SUBROUTINE MIC_contribution_from_ikp(bs_env, qs_env, fm_W_MIC_freq_j, &
    2482             :                                         cfm_W_ikp_freq_j, ikp, kpoints, basis_type, wkp_ext)
    2483             :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
    2484             :       TYPE(qs_environment_type), POINTER                 :: qs_env
    2485             :       TYPE(cp_fm_type)                                   :: fm_W_MIC_freq_j
    2486             :       TYPE(cp_cfm_type)                                  :: cfm_W_ikp_freq_j
    2487             :       INTEGER                                            :: ikp
    2488             :       TYPE(kpoint_type), POINTER                         :: kpoints
    2489             :       CHARACTER(LEN=*)                                   :: basis_type
    2490             :       REAL(KIND=dp), OPTIONAL                            :: wkp_ext
    2491             : 
    2492             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'MIC_contribution_from_ikp'
    2493             : 
    2494             :       INTEGER                                            :: handle, i_bf, iatom, iatom_old, irow, &
    2495             :                                                             j_bf, jatom, jatom_old, jcol, n_bf, &
    2496             :                                                             ncol_local, nrow_local, num_cells
    2497        2076 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: atom_from_bf_index
    2498        2076 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices, row_indices
    2499        2076 :       INTEGER, DIMENSION(:, :), POINTER                  :: index_to_cell
    2500             :       REAL(KIND=dp)                                      :: contribution, weight_im, weight_re, &
    2501             :                                                             wkp_of_ikp
    2502             :       REAL(KIND=dp), DIMENSION(3, 3)                     :: hmat
    2503        2076 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: wkp
    2504        2076 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: xkp
    2505             :       TYPE(cell_type), POINTER                           :: cell
    2506        2076 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    2507             : 
    2508        2076 :       CALL timeset(routineN, handle)
    2509             : 
    2510             :       ! get number of basis functions (bf) for different basis sets
    2511        2076 :       IF (basis_type == "ORB") THEN
    2512          64 :          n_bf = qs_env%bs_env%n_ao
    2513        2012 :       ELSE IF (basis_type == "RI_AUX") THEN
    2514        2012 :          n_bf = qs_env%bs_env%n_RI
    2515             :       ELSE
    2516           0 :          CPABORT("Only ORB and RI_AUX basis implemented.")
    2517             :       END IF
    2518             : 
    2519        6228 :       ALLOCATE (atom_from_bf_index(n_bf))
    2520        2076 :       CALL get_atom_index_from_basis_function_index(qs_env, atom_from_bf_index, n_bf, basis_type)
    2521             : 
    2522        2076 :       NULLIFY (cell, particle_set)
    2523        2076 :       CALL get_qs_env(qs_env, cell=cell, particle_set=particle_set)
    2524        2076 :       CALL get_cell(cell=cell, h=hmat)
    2525             : 
    2526             :       CALL cp_cfm_get_info(matrix=cfm_W_ikp_freq_j, &
    2527             :                            nrow_local=nrow_local, &
    2528             :                            ncol_local=ncol_local, &
    2529             :                            row_indices=row_indices, &
    2530        2076 :                            col_indices=col_indices)
    2531             : 
    2532        2076 :       CALL get_kpoint_info(kpoints, xkp=xkp, wkp=wkp)
    2533        2076 :       index_to_cell => kpoints%index_to_cell
    2534        2076 :       num_cells = SIZE(index_to_cell, 2)
    2535             : 
    2536        2076 :       iatom_old = 0
    2537        2076 :       jatom_old = 0
    2538             : 
    2539        9350 :       DO irow = 1, nrow_local
    2540       76800 :          DO jcol = 1, ncol_local
    2541             : 
    2542       67450 :             i_bf = row_indices(irow)
    2543       67450 :             j_bf = col_indices(jcol)
    2544             : 
    2545       67450 :             iatom = atom_from_bf_index(i_bf)
    2546       67450 :             jatom = atom_from_bf_index(j_bf)
    2547             : 
    2548       67450 :             IF (PRESENT(wkp_ext)) THEN
    2549        4792 :                wkp_of_ikp = wkp_ext
    2550             :             ELSE
    2551       68610 :                SELECT CASE (bs_env%l_RI(i_bf) + bs_env%l_RI(j_bf))
    2552             :                CASE (0)
    2553             :                   ! both RI functions are s-functions, k-extrapolation for 2D and 3D
    2554        5952 :                   wkp_of_ikp = wkp(ikp)
    2555             :                CASE (1)
    2556             :                   ! one function is an s-function, the other a p-function, k-extrapolation for 3D
    2557       15192 :                   wkp_of_ikp = bs_env%wkp_s_p(ikp)
    2558             :                CASE DEFAULT
    2559             :                   ! for any other matrix element of W, there is no need for extrapolation
    2560       62658 :                   wkp_of_ikp = bs_env%wkp_no_extra(ikp)
    2561             :                END SELECT
    2562             :             END IF
    2563             : 
    2564       67450 :             IF (iatom .NE. iatom_old .OR. jatom .NE. jatom_old) THEN
    2565             : 
    2566             :                CALL compute_weight_re_im(weight_re, weight_im, &
    2567             :                                          num_cells, iatom, jatom, xkp(1:3, ikp), wkp_of_ikp, &
    2568       17044 :                                          cell, index_to_cell, hmat, particle_set)
    2569             : 
    2570       17044 :                iatom_old = iatom
    2571       17044 :                jatom_old = jatom
    2572             : 
    2573             :             END IF
    2574             : 
    2575             :             contribution = weight_re*REAL(cfm_W_ikp_freq_j%local_data(irow, jcol)) + &
    2576       67450 :                            weight_im*AIMAG(cfm_W_ikp_freq_j%local_data(irow, jcol))
    2577             : 
    2578             :             fm_W_MIC_freq_j%local_data(irow, jcol) = fm_W_MIC_freq_j%local_data(irow, jcol) &
    2579       74724 :                                                      + contribution
    2580             : 
    2581             :          END DO
    2582             :       END DO
    2583             : 
    2584        2076 :       CALL timestop(handle)
    2585             : 
    2586        6228 :    END SUBROUTINE MIC_contribution_from_ikp
    2587             : 
    2588             : ! **************************************************************************************************
    2589             : !> \brief ...
    2590             : !> \param xkp ...
    2591             : !> \param ikp_start ...
    2592             : !> \param ikp_end ...
    2593             : !> \param grid ...
    2594             : ! **************************************************************************************************
    2595          40 :    SUBROUTINE compute_xkp(xkp, ikp_start, ikp_end, grid)
    2596             : 
    2597             :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: xkp
    2598             :       INTEGER                                            :: ikp_start, ikp_end
    2599             :       INTEGER, DIMENSION(3)                              :: grid
    2600             : 
    2601             :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'compute_xkp'
    2602             : 
    2603             :       INTEGER                                            :: handle, i, ix, iy, iz
    2604             : 
    2605          40 :       CALL timeset(routineN, handle)
    2606             : 
    2607          40 :       i = ikp_start
    2608         112 :       DO ix = 1, grid(1)
    2609         312 :          DO iy = 1, grid(2)
    2610         532 :             DO iz = 1, grid(3)
    2611             : 
    2612         260 :                IF (i > ikp_end) CYCLE
    2613             : 
    2614         232 :                xkp(1, i) = REAL(2*ix - grid(1) - 1, KIND=dp)/(2._dp*REAL(grid(1), KIND=dp))
    2615         232 :                xkp(2, i) = REAL(2*iy - grid(2) - 1, KIND=dp)/(2._dp*REAL(grid(2), KIND=dp))
    2616         232 :                xkp(3, i) = REAL(2*iz - grid(3) - 1, KIND=dp)/(2._dp*REAL(grid(3), KIND=dp))
    2617         460 :                i = i + 1
    2618             : 
    2619             :             END DO
    2620             :          END DO
    2621             :       END DO
    2622             : 
    2623          40 :       CALL timestop(handle)
    2624             : 
    2625          40 :    END SUBROUTINE compute_xkp
    2626             : 
    2627             : ! **************************************************************************************************
    2628             : !> \brief ...
    2629             : !> \param kpoints ...
    2630             : !> \param qs_env ...
    2631             : ! **************************************************************************************************
    2632          28 :    SUBROUTINE kpoint_init_cell_index_simple(kpoints, qs_env)
    2633             : 
    2634             :       TYPE(kpoint_type), POINTER                         :: kpoints
    2635             :       TYPE(qs_environment_type), POINTER                 :: qs_env
    2636             : 
    2637             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'kpoint_init_cell_index_simple'
    2638             : 
    2639             :       INTEGER                                            :: handle, nimages
    2640             :       TYPE(dft_control_type), POINTER                    :: dft_control
    2641             :       TYPE(mp_para_env_type), POINTER                    :: para_env
    2642             :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
    2643          28 :          POINTER                                         :: sab_orb
    2644             : 
    2645          28 :       CALL timeset(routineN, handle)
    2646             : 
    2647          28 :       NULLIFY (dft_control, para_env, sab_orb)
    2648          28 :       CALL get_qs_env(qs_env=qs_env, para_env=para_env, dft_control=dft_control, sab_orb=sab_orb)
    2649          28 :       nimages = dft_control%nimages
    2650          28 :       CALL kpoint_init_cell_index(kpoints, sab_orb, para_env, dft_control)
    2651             : 
    2652             :       ! set back dft_control%nimages
    2653          28 :       dft_control%nimages = nimages
    2654             : 
    2655          28 :       CALL timestop(handle)
    2656             : 
    2657          28 :    END SUBROUTINE kpoint_init_cell_index_simple
    2658             : 
    2659             : ! **************************************************************************************************
    2660             : !> \brief ...
    2661             : !> \param qs_env ...
    2662             : !> \param bs_env ...
    2663             : ! **************************************************************************************************
    2664          18 :    SUBROUTINE soc(qs_env, bs_env)
    2665             :       TYPE(qs_environment_type), POINTER                 :: qs_env
    2666             :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
    2667             : 
    2668             :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'soc'
    2669             : 
    2670             :       INTEGER                                            :: handle
    2671             : 
    2672          18 :       CALL timeset(routineN, handle)
    2673             : 
    2674             :       ! V^SOC_µν^(α),R = ħ/2 < ϕ_µ cell O | sum_ℓ ΔV_ℓ^SO(r,r') L^(α) | ϕ_ν cell R>, α = x,y,z
    2675             :       ! see Hartwigsen, Goedecker, Hutter, Eq.(18), (19) (doi.org/10.1103/PhysRevB.58.3641)
    2676          18 :       CALL V_SOC_xyz_from_pseudopotential(qs_env, bs_env%mat_V_SOC_xyz)
    2677             : 
    2678             :       ! Calculate H^SOC_µν,σσ'(k) = sum_α V^SOC_µν^(α)(k)*Pauli-matrix^(α)_σσ'
    2679             :       ! see Hartwigsen, Goedecker, Hutter, Eq.(18) (doi.org/10.1103/PhysRevB.58.3641)
    2680          30 :       SELECT CASE (bs_env%small_cell_full_kp_or_large_cell_Gamma)
    2681             :       CASE (large_cell_Gamma)
    2682             : 
    2683             :          ! H^SOC_µν,σσ' = sum_α V^SOC_µν^(α)*Pauli-matrix^(α)_σσ'
    2684          12 :          CALL H_KS_spinor_Gamma(bs_env)
    2685             : 
    2686             :       CASE (small_cell_full_kp)
    2687             : 
    2688             :          ! V^SOC_µν^(α),R -> V^SOC_µν^(α)(k); then calculate spinor H^SOC_µν,σσ'(k) (see above)
    2689          18 :          CALL H_KS_spinor_kp(qs_env, bs_env)
    2690             : 
    2691             :       END SELECT
    2692             : 
    2693          18 :       CALL timestop(handle)
    2694             : 
    2695          18 :    END SUBROUTINE soc
    2696             : 
    2697             : ! **************************************************************************************************
    2698             : !> \brief ...
    2699             : !> \param bs_env ...
    2700             : ! **************************************************************************************************
    2701          12 :    SUBROUTINE H_KS_spinor_Gamma(bs_env)
    2702             : 
    2703             :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
    2704             : 
    2705             :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'H_KS_spinor_Gamma'
    2706             : 
    2707             :       INTEGER                                            :: handle, nao, s
    2708             :       TYPE(cp_fm_struct_type), POINTER                   :: str
    2709             : 
    2710          12 :       CALL timeset(routineN, handle)
    2711             : 
    2712          12 :       CALL cp_fm_get_info(bs_env%fm_ks_Gamma(1), nrow_global=nao)
    2713             : 
    2714          24 :       ALLOCATE (bs_env%cfm_SOC_spinor_ao(1))
    2715          12 :       CALL create_cfm_double(bs_env%cfm_SOC_spinor_ao(1), fm_orig=bs_env%fm_ks_Gamma(1))
    2716          12 :       CALL cp_cfm_set_all(bs_env%cfm_SOC_spinor_ao(1), z_zero)
    2717             : 
    2718          12 :       str => bs_env%fm_ks_Gamma(1)%matrix_struct
    2719             : 
    2720          12 :       s = nao + 1
    2721             : 
    2722             :       ! careful: inside add_dbcsr_submat, mat_V_SOC_xyz is multiplied by i because the real matrix
    2723             :       !          mat_V_SOC_xyz is antisymmetric as V_SOC matrix is purely imaginary and Hermitian
    2724             :       CALL add_dbcsr_submat(bs_env%cfm_SOC_spinor_ao(1), bs_env%mat_V_SOC_xyz(1, 1)%matrix, &
    2725          12 :                             str, s, 1, z_one, .TRUE.)
    2726             :       CALL add_dbcsr_submat(bs_env%cfm_SOC_spinor_ao(1), bs_env%mat_V_SOC_xyz(2, 1)%matrix, &
    2727          12 :                             str, s, 1, gaussi, .TRUE.)
    2728             :       CALL add_dbcsr_submat(bs_env%cfm_SOC_spinor_ao(1), bs_env%mat_V_SOC_xyz(3, 1)%matrix, &
    2729          12 :                             str, 1, 1, z_one, .FALSE.)
    2730             :       CALL add_dbcsr_submat(bs_env%cfm_SOC_spinor_ao(1), bs_env%mat_V_SOC_xyz(3, 1)%matrix, &
    2731          12 :                             str, s, s, -z_one, .FALSE.)
    2732             : 
    2733          12 :       CALL timestop(handle)
    2734             : 
    2735          12 :    END SUBROUTINE H_KS_spinor_Gamma
    2736             : 
    2737             : ! **************************************************************************************************
    2738             : !> \brief ...
    2739             : !> \param qs_env ...
    2740             : !> \param bs_env ...
    2741             : ! **************************************************************************************************
    2742          12 :    SUBROUTINE H_KS_spinor_kp(qs_env, bs_env)
    2743             :       TYPE(qs_environment_type), POINTER                 :: qs_env
    2744             :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
    2745             : 
    2746             :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'H_KS_spinor_kp'
    2747             : 
    2748             :       INTEGER                                            :: handle, i_dim, ikp, n_spin, &
    2749             :                                                             nkp_bs_and_DOS, s
    2750           6 :       INTEGER, DIMENSION(:, :, :), POINTER               :: cell_to_index_scf
    2751             :       REAL(KIND=dp), DIMENSION(3)                        :: xkp
    2752             :       TYPE(cp_cfm_type)                                  :: cfm_V_SOC_xyz_ikp
    2753             :       TYPE(cp_fm_struct_type), POINTER                   :: str
    2754             :       TYPE(kpoint_type), POINTER                         :: kpoints_scf
    2755             :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
    2756           6 :          POINTER                                         :: sab_nl
    2757             : 
    2758           6 :       CALL timeset(routineN, handle)
    2759             : 
    2760           6 :       nkp_bs_and_DOS = bs_env%nkp_bs_and_DOS
    2761           6 :       n_spin = bs_env%n_spin
    2762           6 :       s = bs_env%n_ao + 1
    2763           6 :       str => bs_env%cfm_ks_kp(1, 1)%matrix_struct
    2764             : 
    2765           6 :       CALL cp_cfm_create(cfm_V_SOC_xyz_ikp, bs_env%cfm_work_mo%matrix_struct)
    2766             : 
    2767           6 :       CALL alloc_cfm_double_array_1d(bs_env%cfm_SOC_spinor_ao, bs_env%cfm_ks_kp(1, 1), nkp_bs_and_DOS)
    2768             : 
    2769           6 :       CALL get_qs_env(qs_env, kpoints=kpoints_scf)
    2770             : 
    2771           6 :       NULLIFY (sab_nl)
    2772           6 :       CALL get_kpoint_info(kpoints_scf, sab_nl=sab_nl, cell_to_index=cell_to_index_scf)
    2773             : 
    2774          24 :       DO i_dim = 1, 3
    2775             : 
    2776         684 :          DO ikp = 1, nkp_bs_and_DOS
    2777             : 
    2778        2640 :             xkp(1:3) = bs_env%kpoints_DOS%xkp(1:3, ikp)
    2779             : 
    2780         660 :             CALL cp_cfm_set_all(cfm_V_SOC_xyz_ikp, z_zero)
    2781             : 
    2782             :             CALL rsmat_to_kp(bs_env%mat_V_SOC_xyz, i_dim, xkp, cell_to_index_scf, &
    2783         660 :                              sab_nl, bs_env, cfm_V_SOC_xyz_ikp, imag_rs_mat=.TRUE.)
    2784             : 
    2785             :             ! multiply V_SOC with i because bs_env%mat_V_SOC_xyz stores imag. part (real part = 0)
    2786         660 :             CALL cp_cfm_scale(gaussi, cfm_V_SOC_xyz_ikp)
    2787             : 
    2788          18 :             SELECT CASE (i_dim)
    2789             :             CASE (1)
    2790             :                ! add V^SOC_x * σ_x for σ_x = ( (0,1) (1,0) )
    2791         220 :                CALL add_cfm_submat(bs_env%cfm_SOC_spinor_ao(ikp), cfm_V_SOC_xyz_ikp, 1, s)
    2792         220 :                CALL add_cfm_submat(bs_env%cfm_SOC_spinor_ao(ikp), cfm_V_SOC_xyz_ikp, s, 1)
    2793             :             CASE (2)
    2794             :                ! add V^SOC_y * σ_y for σ_y = ( (0,-i) (i,0) )
    2795         220 :                CALL cp_cfm_scale(gaussi, cfm_V_SOC_xyz_ikp)
    2796         220 :                CALL add_cfm_submat(bs_env%cfm_SOC_spinor_ao(ikp), cfm_V_SOC_xyz_ikp, 1, s)
    2797         220 :                CALL cp_cfm_scale(-z_one, cfm_V_SOC_xyz_ikp)
    2798         220 :                CALL add_cfm_submat(bs_env%cfm_SOC_spinor_ao(ikp), cfm_V_SOC_xyz_ikp, s, 1)
    2799             :             CASE (3)
    2800             :                ! add V^SOC_z * σ_z for σ_z = ( (1,0) (0,1) )
    2801         220 :                CALL add_cfm_submat(bs_env%cfm_SOC_spinor_ao(ikp), cfm_V_SOC_xyz_ikp, 1, 1)
    2802         220 :                CALL cp_cfm_scale(-z_one, cfm_V_SOC_xyz_ikp)
    2803         880 :                CALL add_cfm_submat(bs_env%cfm_SOC_spinor_ao(ikp), cfm_V_SOC_xyz_ikp, s, s)
    2804             :             END SELECT
    2805             : 
    2806             :          END DO
    2807             : 
    2808             :       END DO ! ikp
    2809             : 
    2810           6 :       CALL cp_cfm_release(cfm_V_SOC_xyz_ikp)
    2811             : 
    2812           6 :       CALL timestop(handle)
    2813             : 
    2814           6 :    END SUBROUTINE H_KS_spinor_kp
    2815             : 
    2816             : ! **************************************************************************************************
    2817             : !> \brief ...
    2818             : !> \param cfm_array ...
    2819             : !> \param cfm_template ...
    2820             : !> \param n ...
    2821             : ! **************************************************************************************************
    2822           6 :    SUBROUTINE alloc_cfm_double_array_1d(cfm_array, cfm_template, n)
    2823             :       TYPE(cp_cfm_type), ALLOCATABLE, DIMENSION(:)       :: cfm_array
    2824             :       TYPE(cp_cfm_type)                                  :: cfm_template
    2825             :       INTEGER                                            :: n
    2826             : 
    2827             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'alloc_cfm_double_array_1d'
    2828             : 
    2829             :       INTEGER                                            :: handle, i
    2830             : 
    2831           6 :       CALL timeset(routineN, handle)
    2832             : 
    2833         238 :       ALLOCATE (cfm_array(n))
    2834         226 :       DO i = 1, n
    2835         220 :          CALL create_cfm_double(cfm_array(i), cfm_orig=cfm_template)
    2836         226 :          CALL cp_cfm_set_all(cfm_array(i), z_zero)
    2837             :       END DO
    2838             : 
    2839           6 :       CALL timestop(handle)
    2840             : 
    2841           6 :    END SUBROUTINE alloc_cfm_double_array_1d
    2842             : 
    2843             : ! **************************************************************************************************
    2844             : !> \brief ...
    2845             : !> \param bs_env ...
    2846             : ! **************************************************************************************************
    2847          34 :    SUBROUTINE get_all_VBM_CBM_bandgaps(bs_env)
    2848             : 
    2849             :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
    2850             : 
    2851             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'get_all_VBM_CBM_bandgaps'
    2852             : 
    2853             :       INTEGER                                            :: handle
    2854             : 
    2855          34 :       CALL timeset(routineN, handle)
    2856             : 
    2857          34 :       CALL get_VBM_CBM_bandgaps(bs_env%band_edges_scf, bs_env%eigenval_scf, bs_env)
    2858          34 :       CALL get_VBM_CBM_bandgaps(bs_env%band_edges_G0W0, bs_env%eigenval_G0W0, bs_env)
    2859          34 :       CALL get_VBM_CBM_bandgaps(bs_env%band_edges_HF, bs_env%eigenval_HF, bs_env)
    2860             : 
    2861          34 :       CALL timestop(handle)
    2862             : 
    2863          34 :    END SUBROUTINE get_all_VBM_CBM_bandgaps
    2864             : 
    2865             : ! **************************************************************************************************
    2866             : !> \brief ...
    2867             : !> \param band_edges ...
    2868             : !> \param ev ...
    2869             : !> \param bs_env ...
    2870             : ! **************************************************************************************************
    2871         108 :    SUBROUTINE get_VBM_CBM_bandgaps(band_edges, ev, bs_env)
    2872             :       TYPE(band_edges_type)                              :: band_edges
    2873             :       REAL(KIND=dp), DIMENSION(:, :, :)                  :: ev
    2874             :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
    2875             : 
    2876             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'get_VBM_CBM_bandgaps'
    2877             : 
    2878             :       INTEGER                                            :: handle, homo, homo_1, homo_2, ikp, &
    2879             :                                                             ispin, lumo, lumo_1, lumo_2, n_mo
    2880             :       REAL(KIND=dp)                                      :: E_DBG_at_ikp
    2881             : 
    2882         108 :       CALL timeset(routineN, handle)
    2883             : 
    2884         108 :       n_mo = bs_env%n_ao
    2885             : 
    2886         108 :       band_edges%DBG = 1000.0_dp
    2887             : 
    2888         192 :       SELECT CASE (bs_env%n_spin)
    2889             :       CASE (1)
    2890          84 :          homo = bs_env%n_occ(1)
    2891          84 :          lumo = homo + 1
    2892        4736 :          band_edges%VBM = MAXVAL(ev(1:homo, :, 1))
    2893        6628 :          band_edges%CBM = MINVAL(ev(homo + 1:n_mo, :, 1))
    2894             :       CASE (2)
    2895          24 :          homo_1 = bs_env%n_occ(1)
    2896          24 :          lumo_1 = homo_1 + 1
    2897          24 :          homo_2 = bs_env%n_occ(2)
    2898          24 :          lumo_2 = homo_2 + 1
    2899         456 :          band_edges%VBM = MAX(MAXVAL(ev(1:homo_1, :, 1)), MAXVAL(ev(1:homo_2, :, 2)))
    2900         648 :          band_edges%CBM = MIN(MINVAL(ev(homo_1 + 1:n_mo, :, 1)), MINVAL(ev(homo_2 + 1:n_mo, :, 2)))
    2901             :       CASE DEFAULT
    2902         108 :          CPABORT("Error with number of spins.")
    2903             :       END SELECT
    2904             : 
    2905         108 :       band_edges%IDBG = band_edges%CBM - band_edges%VBM
    2906             : 
    2907         240 :       DO ispin = 1, bs_env%n_spin
    2908             : 
    2909         132 :          homo = bs_env%n_occ(ispin)
    2910             : 
    2911        1288 :          DO ikp = 1, bs_env%nkp_bs_and_DOS
    2912             : 
    2913       13300 :             E_DBG_at_ikp = -MAXVAL(ev(1:homo, ikp, ispin)) + MINVAL(ev(homo + 1:n_mo, ikp, ispin))
    2914             : 
    2915        1180 :             IF (E_DBG_at_ikp < band_edges%DBG) band_edges%DBG = E_DBG_at_ikp
    2916             : 
    2917             :          END DO
    2918             : 
    2919             :       END DO
    2920             : 
    2921         108 :       CALL timestop(handle)
    2922             : 
    2923         108 :    END SUBROUTINE get_VBM_CBM_bandgaps
    2924             : 
    2925             : END MODULE post_scf_bandstructure_utils

Generated by: LCOV version 1.15