LCOV - code coverage report
Current view: top level - src - negf_env_types.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:ca6acae) Lines: 70.4 % 570 401
Test Date: 2026-01-02 06:29:53 Functions: 63.2 % 19 12

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief Environment for NEGF based quantum transport calculations
      10              : ! **************************************************************************************************
      11              : MODULE negf_env_types
      12              :    USE cell_types,                      ONLY: cell_type,&
      13              :                                               real_to_scaled
      14              :    USE cp_blacs_env,                    ONLY: cp_blacs_env_type
      15              :    USE cp_control_types,                ONLY: dft_control_type
      16              :    USE cp_dbcsr_api,                    ONLY: dbcsr_copy,&
      17              :                                               dbcsr_deallocate_matrix,&
      18              :                                               dbcsr_init_p,&
      19              :                                               dbcsr_p_type,&
      20              :                                               dbcsr_set
      21              :    USE cp_files,                        ONLY: close_file,&
      22              :                                               open_file
      23              :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      24              :                                               cp_fm_struct_release,&
      25              :                                               cp_fm_struct_type
      26              :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      27              :                                               cp_fm_get_info,&
      28              :                                               cp_fm_get_submatrix,&
      29              :                                               cp_fm_release,&
      30              :                                               cp_fm_set_submatrix,&
      31              :                                               cp_fm_type
      32              :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      33              :                                               cp_logger_type
      34              :    USE force_env_types,                 ONLY: force_env_get,&
      35              :                                               force_env_p_type,&
      36              :                                               force_env_type,&
      37              :                                               use_qs_force
      38              :    USE input_section_types,             ONLY: section_vals_get_subs_vals,&
      39              :                                               section_vals_type,&
      40              :                                               section_vals_val_get
      41              :    USE kinds,                           ONLY: default_path_length,&
      42              :                                               default_string_length,&
      43              :                                               dp
      44              :    USE kpoint_types,                    ONLY: get_kpoint_env,&
      45              :                                               get_kpoint_info,&
      46              :                                               kpoint_env_p_type,&
      47              :                                               kpoint_type
      48              :    USE message_passing,                 ONLY: mp_para_env_type
      49              :    USE negf_atom_map,                   ONLY: negf_atom_map_type,&
      50              :                                               negf_map_atomic_indices
      51              :    USE negf_control_types,              ONLY: negf_control_contact_type,&
      52              :                                               negf_control_type
      53              :    USE negf_io,                         ONLY: negf_print_matrix_to_file,&
      54              :                                               negf_read_matrix_from_file,&
      55              :                                               negf_restart_file_name
      56              :    USE negf_matrix_utils,               ONLY: invert_cell_to_index,&
      57              :                                               negf_copy_contact_matrix,&
      58              :                                               negf_copy_sym_dbcsr_to_fm_submat,&
      59              :                                               number_of_atomic_orbitals
      60              :    USE negf_subgroup_types,             ONLY: negf_subgroup_env_type
      61              :    USE negf_vectors,                    ONLY: contact_direction_vector,&
      62              :                                               projection_on_direction_vector
      63              :    USE particle_types,                  ONLY: particle_type
      64              :    USE pw_env_types,                    ONLY: pw_env_get,&
      65              :                                               pw_env_type
      66              :    USE pw_pool_types,                   ONLY: pw_pool_type
      67              :    USE pw_types,                        ONLY: pw_r3d_rs_type
      68              :    USE qs_density_mixing_types,         ONLY: mixing_storage_create,&
      69              :                                               mixing_storage_release,&
      70              :                                               mixing_storage_type
      71              :    USE qs_energy,                       ONLY: qs_energies
      72              :    USE qs_energy_init,                  ONLY: qs_energies_init
      73              :    USE qs_environment_types,            ONLY: get_qs_env,&
      74              :                                               qs_environment_type
      75              :    USE qs_integrate_potential,          ONLY: integrate_v_rspace
      76              :    USE qs_mo_types,                     ONLY: get_mo_set,&
      77              :                                               mo_set_type
      78              :    USE qs_rho_types,                    ONLY: qs_rho_get,&
      79              :                                               qs_rho_type
      80              :    USE qs_subsys_types,                 ONLY: qs_subsys_get,&
      81              :                                               qs_subsys_type
      82              : #include "./base/base_uses.f90"
      83              : 
      84              :    IMPLICIT NONE
      85              :    PRIVATE
      86              : 
      87              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'negf_env_types'
      88              :    LOGICAL, PARAMETER, PRIVATE          :: debug_this_module = .TRUE.
      89              : 
      90              :    PUBLIC :: negf_env_type, negf_env_contact_type
      91              :    PUBLIC :: negf_env_create, negf_env_release
      92              : 
      93              : ! **************************************************************************************************
      94              : !> \brief  Contact-specific NEGF environment.
      95              : !> \author Sergey Chulkov
      96              : ! **************************************************************************************************
      97              :    TYPE negf_env_contact_type
      98              :       REAL(kind=dp), DIMENSION(3)                        :: direction_vector = -1.0_dp, origin = -1.0_dp
      99              :       REAL(kind=dp), DIMENSION(3)                        :: direction_vector_bias = -1.0_dp, origin_bias = -1.0_dp
     100              :       !> an axis towards the secondary contact unit cell which coincides with the transport direction
     101              :       !> 0 (undefined), 1 (+x), 2 (+y), 3 (+z), -1 (-x), -2 (-y), -3 (-z)
     102              :       INTEGER                                            :: direction_axis = -1
     103              :       !> atoms belonging to a primary contact unit cell
     104              :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: atomlist_cell0
     105              :       !> atoms belonging to a secondary contact unit cell (will be removed one day ...)
     106              :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: atomlist_cell1
     107              :       !> list of equivalent atoms in an appropriate contact force environment
     108              :       TYPE(negf_atom_map_type), ALLOCATABLE, &
     109              :          DIMENSION(:)                                    :: atom_map_cell0, atom_map_cell1
     110              :       !> energy of the HOMO
     111              :       REAL(kind=dp)                                      :: homo_energy = -1.0_dp
     112              :       !> diagonal (h_00) and off-diagonal (h_01) blocks of the contact Kohn-Sham matrix ([number_of_spins]).
     113              :       !> The matrix h_01 is of the shape [nao_cell0 x nao_cell1]
     114              :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:)      :: h_00, h_01
     115              :       !> diagonal and off-diagonal blocks of the density matrix
     116              :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:)      :: rho_00, rho_01
     117              :       !> diagonal and off-diagonal blocks of the overlap matrix
     118              :       TYPE(cp_fm_type), POINTER                          :: s_00 => null(), s_01 => null()
     119              :    END TYPE negf_env_contact_type
     120              : 
     121              : ! **************************************************************************************************
     122              : !> \brief  NEGF environment.
     123              : !> \author Sergey Chulkov
     124              : ! **************************************************************************************************
     125              :    TYPE negf_env_type
     126              :       !> contact-specific NEGF environments
     127              :       TYPE(negf_env_contact_type), ALLOCATABLE, &
     128              :          DIMENSION(:)                                     :: contacts
     129              :       !> Kohn-Sham matrix of the scattering region
     130              :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:)       :: h_s
     131              :       !> Kohn-Sham matrix of the scattering region -- contact interface ([nspins, ncontacts])
     132              :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:, :)    :: h_sc
     133              :       !> overlap matrix of the scattering region
     134              :       TYPE(cp_fm_type), POINTER                           :: s_s => null()
     135              :       !> an external Hartree potential in atomic basis set representation
     136              :       TYPE(cp_fm_type), POINTER                           :: v_hartree_s => null()
     137              :       !> overlap matrix of the scattering region -- contact interface for every contact ([ncontacts])
     138              :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:)       :: s_sc
     139              :       !> structure needed for density mixing
     140              :       TYPE(mixing_storage_type), POINTER                  :: mixing_storage => NULL()
     141              :       !> density mixing method
     142              :       INTEGER                                             :: mixing_method = -1
     143              :    END TYPE negf_env_type
     144              : 
     145              : ! **************************************************************************************************
     146              : !> \brief  Allocatable list of the type 'negf_atom_map_type'.
     147              : !> \author Sergey Chulkov
     148              : ! **************************************************************************************************
     149              :    TYPE negf_atom_map_contact_type
     150              :       TYPE(negf_atom_map_type), ALLOCATABLE, DIMENSION(:) :: atom_map
     151              :    END TYPE negf_atom_map_contact_type
     152              : 
     153              : CONTAINS
     154              : 
     155              : ! **************************************************************************************************
     156              : !> \brief Create a new NEGF environment and compute the relevant Kohn-Sham matrices.
     157              : !> \param negf_env            NEGF environment to create
     158              : !> \param sub_env             NEGF parallel (sub)group environment
     159              : !> \param negf_control        NEGF control
     160              : !> \param force_env           the primary force environment
     161              : !> \param negf_mixing_section pointer to a mixing section within the NEGF input section
     162              : !> \param log_unit            output unit number
     163              : !> \par History
     164              : !>   * 01.2017 created [Sergey Chulkov]
     165              : ! **************************************************************************************************
     166            4 :    SUBROUTINE negf_env_create(negf_env, sub_env, negf_control, force_env, negf_mixing_section, log_unit)
     167              :       TYPE(negf_env_type), INTENT(inout)                 :: negf_env
     168              :       TYPE(negf_subgroup_env_type), INTENT(in)           :: sub_env
     169              :       TYPE(negf_control_type), POINTER                   :: negf_control
     170              :       TYPE(force_env_type), POINTER                      :: force_env
     171              :       TYPE(section_vals_type), POINTER                   :: negf_mixing_section
     172              :       INTEGER, INTENT(in)                                :: log_unit
     173              : 
     174              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'negf_env_create'
     175              : 
     176              :       CHARACTER(len=default_string_length)               :: contact_str, force_env_str, &
     177              :                                                             n_force_env_str
     178              :       INTEGER                                            :: handle, icontact, in_use, n_force_env, &
     179              :                                                             ncontacts
     180              :       LOGICAL                                            :: do_kpoints
     181              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
     182            4 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: matrix_ks_kp, matrix_s_kp
     183              :       TYPE(dft_control_type), POINTER                    :: dft_control
     184            4 :       TYPE(force_env_p_type), DIMENSION(:), POINTER      :: sub_force_env
     185              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     186              :       TYPE(negf_atom_map_contact_type), ALLOCATABLE, &
     187            4 :          DIMENSION(:)                                    :: map_contact
     188              :       TYPE(pw_r3d_rs_type), POINTER                      :: v_hartree_rspace
     189              :       TYPE(qs_environment_type), POINTER                 :: qs_env, qs_env_contact
     190              :       TYPE(qs_subsys_type), POINTER                      :: subsys, subsys_contact
     191              :       TYPE(section_vals_type), POINTER                   :: negf_section, root_section
     192              : 
     193            4 :       CALL timeset(routineN, handle)
     194              : 
     195              :       ! ensure we have Quickstep enabled for all force_env
     196            4 :       NULLIFY (sub_force_env)
     197              :       CALL force_env_get(force_env, in_use=in_use, qs_env=qs_env, root_section=root_section, &
     198            4 :                          sub_force_env=sub_force_env)
     199              : 
     200            4 :       IF (ASSOCIATED(sub_force_env)) THEN
     201            2 :          n_force_env = SIZE(sub_force_env)
     202              :       ELSE
     203            2 :          n_force_env = 0
     204              :       END IF
     205              : 
     206            4 :       IF (in_use == use_qs_force) THEN
     207            8 :          DO icontact = 1, n_force_env
     208            4 :             CALL force_env_get(sub_force_env(icontact)%force_env, in_use=in_use)
     209            8 :             IF (in_use /= use_qs_force) EXIT
     210              :          END DO
     211              :       END IF
     212              : 
     213            4 :       IF (in_use /= use_qs_force) THEN
     214            0 :          CPABORT("Quickstep is required for NEGF run.")
     215              :       END IF
     216              : 
     217              :       ! check that all mentioned FORCE_EVAL sections are actually present
     218            4 :       ncontacts = SIZE(negf_control%contacts)
     219              : 
     220           12 :       DO icontact = 1, ncontacts
     221           12 :          IF (negf_control%contacts(icontact)%force_env_index > n_force_env) THEN
     222            0 :             WRITE (contact_str, '(I11)') icontact
     223            0 :             WRITE (force_env_str, '(I11)') negf_control%contacts(icontact)%force_env_index
     224            0 :             WRITE (n_force_env_str, '(I11)') n_force_env
     225              : 
     226              :             CALL cp_abort(__LOCATION__, &
     227              :                           "Contact number "//TRIM(ADJUSTL(contact_str))//" is linked with the FORCE_EVAL section number "// &
     228              :                           TRIM(ADJUSTL(force_env_str))//", however only "//TRIM(ADJUSTL(n_force_env_str))// &
     229              :                           " FORCE_EVAL sections have been found. Note that FORCE_EVAL sections are enumerated from 0"// &
     230            0 :                           " and that the primary (0-th) section must contain all the atoms.")
     231              :          END IF
     232              :       END DO
     233              : 
     234              :       ! create basic matrices and neighbour lists for the primary force_env,
     235              :       ! so we know how matrix elements are actually distributed across CPUs.
     236            4 :       CALL qs_energies_init(qs_env, calc_forces=.FALSE.)
     237              :       CALL get_qs_env(qs_env, blacs_env=blacs_env, do_kpoints=do_kpoints, &
     238              :                       matrix_s_kp=matrix_s_kp, matrix_ks_kp=matrix_ks_kp, &
     239            4 :                       para_env=para_env, subsys=subsys, v_hartree_rspace=v_hartree_rspace)
     240              : 
     241            4 :       negf_section => section_vals_get_subs_vals(root_section, "NEGF")
     242              : 
     243            4 :       IF (do_kpoints) THEN
     244            0 :          CPABORT("k-points are currently not supported for device FORCE_EVAL")
     245              :       END IF
     246              : 
     247              :       ! stage 1: map the atoms between the device force_env and all contact force_env-s
     248           80 :       ALLOCATE (negf_env%contacts(ncontacts))
     249           20 :       ALLOCATE (map_contact(ncontacts))
     250              : 
     251           12 :       DO icontact = 1, ncontacts
     252           12 :          IF (negf_control%contacts(icontact)%force_env_index > 0) THEN
     253            4 :             CALL force_env_get(sub_force_env(negf_control%contacts(icontact)%force_env_index)%force_env, qs_env=qs_env_contact)
     254            4 :             CALL get_qs_env(qs_env_contact, subsys=subsys_contact)
     255              : 
     256              :             CALL negf_env_contact_init_maps(contact_env=negf_env%contacts(icontact), &
     257              :                                             contact_control=negf_control%contacts(icontact), &
     258              :                                             atom_map=map_contact(icontact)%atom_map, &
     259              :                                             eps_geometry=negf_control%eps_geometry, &
     260              :                                             subsys_device=subsys, &
     261            4 :                                             subsys_contact=subsys_contact)
     262              : 
     263            4 :             IF (negf_env%contacts(icontact)%direction_axis == 0) THEN
     264            0 :                WRITE (contact_str, '(I11)') icontact
     265            0 :                WRITE (force_env_str, '(I11)') negf_control%contacts(icontact)%force_env_index
     266              :                CALL cp_abort(__LOCATION__, &
     267              :                              "One lattice vector of the contact unit cell (FORCE_EVAL section "// &
     268              :                              TRIM(ADJUSTL(force_env_str))//") must be parallel to the direction of the contact "// &
     269            0 :                              TRIM(ADJUSTL(contact_str))//".")
     270              :             END IF
     271              :          END IF
     272              :       END DO
     273              : 
     274              :       ! stage 2: obtain relevant Kohn-Sham matrix blocks for each contact (separate bulk DFT calculation)
     275           12 :       DO icontact = 1, ncontacts
     276           12 :          IF (negf_control%contacts(icontact)%force_env_index > 0) THEN
     277            4 :             IF (log_unit > 0) &
     278            2 :                WRITE (log_unit, '(/,T2,A,T70,I11)') "NEGF| Construct the Kohn-Sham matrix for the contact", icontact
     279            4 :             IF (negf_control%contacts(icontact)%read_write_HS) THEN
     280              :                CALL negf_env_contact_read_write_hs &
     281              :                   (icontact, sub_force_env(negf_control%contacts(icontact)%force_env_index)%force_env, &
     282            0 :                    para_env, negf_env, sub_env, negf_control, negf_section, log_unit, is_separate=.TRUE.)
     283              :             ELSE
     284            4 :                CALL force_env_get(sub_force_env(negf_control%contacts(icontact)%force_env_index)%force_env, qs_env=qs_env_contact)
     285            4 :                CALL qs_energies(qs_env_contact, consistent_energies=.FALSE., calc_forces=.FALSE.)
     286              :                CALL negf_env_contact_init_matrices(contact_env=negf_env%contacts(icontact), sub_env=sub_env, &
     287            4 :                                                    qs_env_contact=qs_env_contact)
     288              :             END IF
     289            4 :             IF (log_unit > 0) WRITE (log_unit, '(/,T2,79("-"))')
     290              :          END IF
     291              :       END DO
     292              : 
     293              :       ! obtain an initial KS-matrix for the scattering region
     294            4 :       IF (log_unit > 0) &
     295            2 :          WRITE (log_unit, '(/,T2,A,T70)') "NEGF| Construct the Kohn-Sham matrix for the entire system"
     296            4 :       CALL qs_energies(qs_env, consistent_energies=.FALSE., calc_forces=.FALSE.)
     297            4 :       IF (log_unit > 0) WRITE (log_unit, '(/,T2,79("-"))')
     298              : 
     299              :       ! *** obtain relevant Kohn-Sham matrix blocks for each contact with no separate FORCE_ENV ***
     300           12 :       DO icontact = 1, ncontacts
     301           12 :          IF (negf_control%contacts(icontact)%force_env_index <= 0) THEN
     302              :             CALL negf_env_contact_init_matrices_gamma(contact_env=negf_env%contacts(icontact), &
     303              :                                                       contact_control=negf_control%contacts(icontact), &
     304              :                                                       sub_env=sub_env, qs_env=qs_env, &
     305            4 :                                                       eps_geometry=negf_control%eps_geometry)
     306            4 :             IF (negf_control%contacts(icontact)%read_write_HS) THEN
     307              :                CALL negf_env_contact_read_write_hs(icontact, force_env, para_env, &
     308            0 :                                                    negf_env, sub_env, negf_control, negf_section, log_unit, is_separate=.FALSE.)
     309              :             END IF
     310              :          END IF
     311              :       END DO
     312              : 
     313              :       ! extract device-related matrix blocks
     314            4 :       CALL negf_env_device_init_matrices(negf_env, negf_control, sub_env, qs_env)
     315              : 
     316              :       ! electron density mixing;
     317              :       ! the input section below should be consistent with the subroutine create_negf_section()
     318            4 :       NULLIFY (negf_env%mixing_storage)
     319            4 :       CALL section_vals_val_get(negf_mixing_section, "METHOD", i_val=negf_env%mixing_method)
     320              : 
     321            4 :       CALL get_qs_env(qs_env, dft_control=dft_control)
     322           16 :       ALLOCATE (negf_env%mixing_storage)
     323              :       CALL mixing_storage_create(negf_env%mixing_storage, negf_mixing_section, &
     324            4 :                                  negf_env%mixing_method, dft_control%qs_control%cutoff)
     325              : 
     326            4 :       CALL timestop(handle)
     327           16 :    END SUBROUTINE negf_env_create
     328              : 
     329              : ! **************************************************************************************************
     330              : !> \brief Establish mapping between the primary and the contact force environments
     331              : !> \param contact_env         NEGF environment for the given contact (modified on exit)
     332              : !> \param contact_control     NEGF control
     333              : !> \param atom_map            atomic map
     334              : !> \param eps_geometry        accuracy in mapping atoms between different force environments
     335              : !> \param subsys_device       QuickStep subsystem of the device force environment
     336              : !> \param subsys_contact      QuickStep subsystem of the contact force environment
     337              : !> \author Sergey Chulkov
     338              : ! **************************************************************************************************
     339            4 :    SUBROUTINE negf_env_contact_init_maps(contact_env, contact_control, atom_map, &
     340              :                                          eps_geometry, subsys_device, subsys_contact)
     341              :       TYPE(negf_env_contact_type), INTENT(inout)         :: contact_env
     342              :       TYPE(negf_control_contact_type), INTENT(in)        :: contact_control
     343              :       TYPE(negf_atom_map_type), ALLOCATABLE, &
     344              :          DIMENSION(:), INTENT(inout)                     :: atom_map
     345              :       REAL(kind=dp), INTENT(in)                          :: eps_geometry
     346              :       TYPE(qs_subsys_type), POINTER                      :: subsys_device, subsys_contact
     347              : 
     348              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'negf_env_contact_init_maps'
     349              : 
     350              :       INTEGER                                            :: handle, natoms
     351              : 
     352            4 :       CALL timeset(routineN, handle)
     353              : 
     354              :       CALL contact_direction_vector(contact_env%origin, &
     355              :                                     contact_env%direction_vector, &
     356              :                                     contact_env%origin_bias, &
     357              :                                     contact_env%direction_vector_bias, &
     358              :                                     contact_control%atomlist_screening, &
     359              :                                     contact_control%atomlist_bulk, &
     360            4 :                                     subsys_device)
     361              : 
     362            4 :       contact_env%direction_axis = contact_direction_axis(contact_env%direction_vector, subsys_contact, eps_geometry)
     363              : 
     364            4 :       IF (contact_env%direction_axis /= 0) THEN
     365            4 :          natoms = SIZE(contact_control%atomlist_bulk)
     366           56 :          ALLOCATE (atom_map(natoms))
     367              : 
     368              :          ! map atom listed in 'contact_control%atomlist_bulk' to the corresponding atom/cell replica from the contact force_env
     369              :          CALL negf_map_atomic_indices(atom_map=atom_map, &
     370              :                                       atom_list=contact_control%atomlist_bulk, &
     371              :                                       subsys_device=subsys_device, &
     372              :                                       subsys_contact=subsys_contact, &
     373            4 :                                       eps_geometry=eps_geometry)
     374              : 
     375              :          ! list atoms from 'contact_control%atomlist_bulk' which belong to
     376              :          ! the primary unit cell of the bulk region for the given contact
     377              :          CALL list_atoms_in_bulk_primary_unit_cell(atomlist_cell0=contact_env%atomlist_cell0, &
     378              :                                                    atom_map_cell0=contact_env%atom_map_cell0, &
     379              :                                                    atomlist_bulk=contact_control%atomlist_bulk, &
     380              :                                                    atom_map=atom_map, &
     381              :                                                    origin=contact_env%origin, &
     382              :                                                    direction_vector=contact_env%direction_vector, &
     383              :                                                    direction_axis=contact_env%direction_axis, &
     384            4 :                                                    subsys_device=subsys_device)
     385              : 
     386              :          ! secondary unit cell
     387              :          CALL list_atoms_in_bulk_secondary_unit_cell(atomlist_cell1=contact_env%atomlist_cell1, &
     388              :                                                      atom_map_cell1=contact_env%atom_map_cell1, &
     389              :                                                      atomlist_bulk=contact_control%atomlist_bulk, &
     390              :                                                      atom_map=atom_map, &
     391              :                                                      origin=contact_env%origin, &
     392              :                                                      direction_vector=contact_env%direction_vector, &
     393              :                                                      direction_axis=contact_env%direction_axis, &
     394            4 :                                                      subsys_device=subsys_device)
     395              :       END IF
     396              : 
     397            4 :       CALL timestop(handle)
     398            4 :    END SUBROUTINE negf_env_contact_init_maps
     399              : 
     400              : ! **************************************************************************************************
     401              : !> \brief Reading and writing of the electrode Hamiltonian and overlap matrices from/to a file.
     402              : !> \param icontact     ...
     403              : !> \param el_force_env ...
     404              : !> \param para_env     ...
     405              : !> \param negf_env     ...
     406              : !> \param sub_env      ...
     407              : !> \param negf_control ...
     408              : !> \param negf_section ...
     409              : !> \param log_unit     ...
     410              : !> \param is_separate  ...
     411              : !> \par History
     412              : !>    * 12.2025 created  [Dmitry Ryndyk]
     413              : ! **************************************************************************************************
     414            0 :    SUBROUTINE negf_env_contact_read_write_hs(icontact, el_force_env, para_env, negf_env, &
     415              :                                              sub_env, negf_control, negf_section, log_unit, is_separate)
     416              :       INTEGER                                            :: icontact
     417              :       TYPE(force_env_type), POINTER                      :: el_force_env
     418              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     419              :       TYPE(negf_env_type), INTENT(inout)                 :: negf_env
     420              :       TYPE(negf_subgroup_env_type), INTENT(in)           :: sub_env
     421              :       TYPE(negf_control_type), POINTER                   :: negf_control
     422              :       TYPE(section_vals_type), POINTER                   :: negf_section
     423              :       INTEGER, INTENT(in)                                :: log_unit
     424              :       LOGICAL, INTENT(in)                                :: is_separate
     425              : 
     426              :       CHARACTER(len=*), PARAMETER :: routineN = 'negf_env_contact_read_write_hs'
     427              : 
     428              :       CHARACTER(len=default_path_length)                 :: filename_h00_1, filename_h00_2, &
     429              :                                                             filename_h01_1, filename_h01_2, &
     430              :                                                             filename_s00, filename_s01
     431              :       INTEGER                                            :: handle, ispin, ncol, nrow, nspins, &
     432              :                                                             print_unit
     433              :       LOGICAL                                            :: exist, exist_all
     434            0 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: target_m
     435              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
     436              :       TYPE(cp_logger_type), POINTER                      :: logger
     437              :       TYPE(dft_control_type), POINTER                    :: dft_control
     438              :       TYPE(qs_environment_type), POINTER                 :: qs_env_contact
     439              :       TYPE(qs_subsys_type), POINTER                      :: subsys
     440              : 
     441            0 :       CALL timeset(routineN, handle)
     442            0 :       logger => cp_get_default_logger()
     443              : 
     444            0 :       CALL force_env_get(el_force_env, qs_env=qs_env_contact)
     445            0 :       CALL get_qs_env(qs_env_contact, dft_control=dft_control, subsys=subsys)
     446            0 :       nspins = dft_control%nspins
     447              : 
     448            0 :       IF (.NOT. is_separate .AND. log_unit > 0) WRITE (log_unit, '(/,T2,A,T70,I11)') &
     449            0 :          "NEGF| Construct the Kohn-Sham matrix for the contact", icontact
     450              : 
     451              :       ! Check that the files exist.
     452              :       ! ispin=0 is used to show nspins=1
     453            0 :       exist_all = .TRUE.
     454            0 :       IF (para_env%is_source()) THEN
     455            0 :          CALL negf_restart_file_name(filename_s00, exist, negf_section, logger, icontact, s00=.TRUE.)
     456            0 :          IF (.NOT. exist) THEN
     457              :             CALL cp_warn(__LOCATION__, &
     458              :                          "User requested to read the Hamiltonian and overlap matrices from the file named: "// &
     459            0 :                          TRIM(filename_s00)//". This file does not exist. The file will be created.")
     460            0 :             exist_all = .FALSE.
     461              :          END IF
     462            0 :          CALL negf_restart_file_name(filename_s01, exist, negf_section, logger, icontact, s01=.TRUE.)
     463            0 :          IF (.NOT. exist) THEN
     464              :             CALL cp_warn(__LOCATION__, &
     465              :                          "User requested to read the Hamiltonian and overlap matrices from the file named: "// &
     466            0 :                          TRIM(filename_s01)//". This file does not exist. The file will be created.")
     467            0 :             exist_all = .FALSE.
     468              :          END IF
     469            0 :          IF (nspins == 1) THEN
     470            0 :             CALL negf_restart_file_name(filename_h00_1, exist, negf_section, logger, icontact, ispin=0, h00=.TRUE.)
     471            0 :             IF (.NOT. exist) THEN
     472              :                CALL cp_warn(__LOCATION__, &
     473              :                             "User requested to read the Hamiltonian and overlap matrices from the file named: "// &
     474            0 :                             TRIM(filename_h00_1)//". This file does not exist. The file will be created.")
     475            0 :                exist_all = .FALSE.
     476              :             END IF
     477            0 :             CALL negf_restart_file_name(filename_h01_1, exist, negf_section, logger, icontact, ispin=0, h01=.TRUE.)
     478            0 :             IF (.NOT. exist) THEN
     479              :                CALL cp_warn(__LOCATION__, &
     480              :                             "User requested to read the Hamiltonian and overlap matrices from the file named: "// &
     481            0 :                             TRIM(filename_h01_1)//". This file does not exist. The file will be created.")
     482            0 :                exist_all = .FALSE.
     483              :             END IF
     484              :          END IF
     485            0 :          IF (nspins == 2) THEN
     486            0 :             CALL negf_restart_file_name(filename_h00_1, exist, negf_section, logger, icontact, ispin=1, h00=.TRUE.)
     487            0 :             IF (.NOT. exist) THEN
     488              :                CALL cp_warn(__LOCATION__, &
     489              :                             "User requested to read the Hamiltonian and overlap matrices from the file named: "// &
     490            0 :                             TRIM(filename_h00_1)//". This file does not exist. The file will be created.")
     491            0 :                exist_all = .FALSE.
     492              :             END IF
     493            0 :             CALL negf_restart_file_name(filename_h01_1, exist, negf_section, logger, icontact, ispin=1, h01=.TRUE.)
     494            0 :             IF (.NOT. exist) THEN
     495              :                CALL cp_warn(__LOCATION__, &
     496              :                             "User requested to read the Hamiltonian and overlap matrices from the file named: "// &
     497            0 :                             TRIM(filename_h01_1)//". This file does not exist. The file will be created.")
     498            0 :                exist_all = .FALSE.
     499              :             END IF
     500            0 :             CALL negf_restart_file_name(filename_h00_2, exist, negf_section, logger, icontact, ispin=2, h00=.TRUE.)
     501            0 :             IF (.NOT. exist) THEN
     502              :                CALL cp_warn(__LOCATION__, &
     503              :                             "User requested to read the Hamiltonian and overlap matrices from the file named: "// &
     504            0 :                             TRIM(filename_h00_2)//". This file does not exist. The file will be created.")
     505            0 :                exist_all = .FALSE.
     506              :             END IF
     507            0 :             CALL negf_restart_file_name(filename_h01_2, exist, negf_section, logger, icontact, ispin=2, h01=.TRUE.)
     508            0 :             IF (.NOT. exist) THEN
     509              :                CALL cp_warn(__LOCATION__, &
     510              :                             "User requested to read the Hamiltonian and overlap matrices from the file named: "// &
     511            0 :                             TRIM(filename_h01_2)//". This file does not exist. The file will be created.")
     512            0 :                exist_all = .FALSE.
     513              :             END IF
     514              :          END IF
     515              :       END IF
     516            0 :       CALL para_env%bcast(exist_all)
     517              : 
     518            0 :       IF (exist_all) THEN
     519              : 
     520            0 :          IF (log_unit > 0) WRITE (log_unit, '(/,T2,A)') "All restart files exist."
     521              : 
     522              :          ! ++ create matrices: s_00, s_01, h_00, h_01
     523            0 :          IF (para_env%is_source()) THEN
     524              :             CALL open_file(file_name=filename_s00, file_status="OLD", &
     525              :                            file_form="FORMATTED", file_action="READ", &
     526            0 :                            file_position="REWIND", unit_number=print_unit)
     527            0 :             READ (print_unit, *) nrow, ncol
     528            0 :             CALL close_file(print_unit)
     529              :          END IF
     530            0 :          CALL para_env%bcast(nrow)
     531            0 :          CALL para_env%bcast(ncol)
     532            0 :          NULLIFY (fm_struct)
     533            0 :          CALL cp_fm_struct_create(fm_struct, nrow_global=nrow, ncol_global=ncol, context=sub_env%blacs_env)
     534            0 :          ALLOCATE (negf_env%contacts(icontact)%s_00, negf_env%contacts(icontact)%s_01)
     535            0 :          CALL cp_fm_create(negf_env%contacts(icontact)%s_00, fm_struct)
     536            0 :          CALL cp_fm_create(negf_env%contacts(icontact)%s_01, fm_struct)
     537            0 :          ALLOCATE (negf_env%contacts(icontact)%h_00(nspins), negf_env%contacts(icontact)%h_01(nspins))
     538            0 :          DO ispin = 1, nspins
     539            0 :             CALL cp_fm_create(negf_env%contacts(icontact)%h_00(ispin), fm_struct)
     540            0 :             CALL cp_fm_create(negf_env%contacts(icontact)%h_01(ispin), fm_struct)
     541              :          END DO
     542            0 :          CALL cp_fm_struct_release(fm_struct)
     543              : 
     544            0 :          ALLOCATE (target_m(nrow, ncol))
     545            0 :          IF (para_env%is_source()) CALL negf_read_matrix_from_file(filename_s00, target_m)
     546            0 :          CALL para_env%bcast(target_m)
     547            0 :          CALL cp_fm_set_submatrix(negf_env%contacts(icontact)%s_00, target_m)
     548            0 :          IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "S_00 is read from "//TRIM(filename_s00)
     549            0 :          IF (para_env%is_source()) CALL negf_read_matrix_from_file(filename_s01, target_m)
     550            0 :          CALL para_env%bcast(target_m)
     551            0 :          CALL cp_fm_set_submatrix(negf_env%contacts(icontact)%s_01, target_m)
     552            0 :          IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "S_01 is read from "//TRIM(filename_s01)
     553            0 :          IF (nspins == 1) THEN
     554            0 :             IF (para_env%is_source()) CALL negf_read_matrix_from_file(filename_h00_1, target_m)
     555            0 :             CALL para_env%bcast(target_m)
     556            0 :             CALL cp_fm_set_submatrix(negf_env%contacts(icontact)%h_00(1), target_m)
     557            0 :             IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "H_00 is read from "//TRIM(filename_h00_1)
     558            0 :             IF (para_env%is_source()) CALL negf_read_matrix_from_file(filename_h01_1, target_m)
     559            0 :             CALL para_env%bcast(target_m)
     560            0 :             CALL cp_fm_set_submatrix(negf_env%contacts(icontact)%h_01(1), target_m)
     561            0 :             IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "H_01 is read from "//TRIM(filename_H01_1)
     562              :          END IF
     563            0 :          IF (nspins == 2) THEN
     564            0 :             IF (para_env%is_source()) CALL negf_read_matrix_from_file(filename_h00_1, target_m)
     565            0 :             CALL para_env%bcast(target_m)
     566            0 :             CALL cp_fm_set_submatrix(negf_env%contacts(icontact)%h_00(1), target_m)
     567            0 :             IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "H_00 is read from "//TRIM(filename_h00_1)//" for spin 1"
     568            0 :             IF (para_env%is_source()) CALL negf_read_matrix_from_file(filename_h01_1, target_m)
     569            0 :             CALL para_env%bcast(target_m)
     570            0 :             CALL cp_fm_set_submatrix(negf_env%contacts(icontact)%h_01(1), target_m)
     571            0 :             IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "H_01 is read from "//TRIM(filename_H01_1)//" for spin 1"
     572            0 :             IF (para_env%is_source()) CALL negf_read_matrix_from_file(filename_h00_2, target_m)
     573            0 :             CALL para_env%bcast(target_m)
     574            0 :             CALL cp_fm_set_submatrix(negf_env%contacts(icontact)%h_00(2), target_m)
     575            0 :             IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "H_00 is read from "//TRIM(filename_h00_2)//" for spin 2"
     576            0 :             IF (para_env%is_source()) CALL negf_read_matrix_from_file(filename_h01_2, target_m)
     577            0 :             CALL para_env%bcast(target_m)
     578            0 :             CALL cp_fm_set_submatrix(negf_env%contacts(icontact)%h_01(2), target_m)
     579            0 :             IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "H_01 is read from "//TRIM(filename_H01_2)//" for spin 2"
     580              :          END IF
     581            0 :          DEALLOCATE (target_m)
     582              : 
     583              :       ELSE
     584              : 
     585            0 :          IF (log_unit > 0) WRITE (log_unit, '(T2,A)') &
     586            0 :             "Some restart files do not exist. ALL restart files will be recalculated!"
     587              : 
     588            0 :          IF (is_separate) THEN
     589            0 :             CALL qs_energies(qs_env_contact, consistent_energies=.FALSE., calc_forces=.FALSE.)
     590              :             CALL negf_env_contact_init_matrices(contact_env=negf_env%contacts(icontact), sub_env=sub_env, &
     591            0 :                                                 qs_env_contact=qs_env_contact)
     592              :          ELSE
     593            0 :             negf_control%contacts(icontact)%read_write_HS = .FALSE.
     594              :             CALL negf_env_contact_init_matrices_gamma(contact_env=negf_env%contacts(icontact), &
     595              :                                                       contact_control=negf_control%contacts(icontact), &
     596              :                                                       sub_env=sub_env, qs_env=qs_env_contact, &
     597            0 :                                                       eps_geometry=negf_control%eps_geometry)
     598            0 :             negf_control%contacts(icontact)%read_write_HS = .TRUE.
     599              :          END IF
     600              : 
     601            0 :          CALL cp_fm_get_info(negf_env%contacts(icontact)%s_00, nrow_global=nrow)
     602            0 :          ALLOCATE (target_m(nrow, nrow))
     603            0 :          CALL cp_fm_get_submatrix(negf_env%contacts(icontact)%s_00, target_m)
     604            0 :          IF (para_env%is_source()) CALL negf_print_matrix_to_file(filename_s00, target_m)
     605            0 :          IF (log_unit > 0) WRITE (log_unit, '(/,T2,A)') "S_00 is saved to "//TRIM(filename_s00)
     606            0 :          CALL cp_fm_get_submatrix(negf_env%contacts(icontact)%s_01, target_m)
     607            0 :          IF (para_env%is_source()) CALL negf_print_matrix_to_file(filename_s01, target_m)
     608            0 :          IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "S_01 is saved to "//TRIM(filename_s01)
     609            0 :          IF (nspins == 1) THEN
     610            0 :             CALL cp_fm_get_submatrix(negf_env%contacts(icontact)%h_00(1), target_m)
     611            0 :             IF (para_env%is_source()) CALL negf_print_matrix_to_file(filename_h00_1, target_m)
     612            0 :             IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "H_00 is saved to "//TRIM(filename_h00_1)
     613            0 :             CALL cp_fm_get_submatrix(negf_env%contacts(icontact)%h_01(1), target_m)
     614            0 :             IF (para_env%is_source()) CALL negf_print_matrix_to_file(filename_h01_1, target_m)
     615            0 :             IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "H_01 is saved to "//TRIM(filename_h01_1)
     616              :          END IF
     617            0 :          IF (nspins == 2) THEN
     618            0 :             CALL cp_fm_get_submatrix(negf_env%contacts(icontact)%h_00(1), target_m)
     619            0 :             IF (para_env%is_source()) CALL negf_print_matrix_to_file(filename_h00_1, target_m)
     620            0 :             IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "H_00 is saved to "//TRIM(filename_h00_1)//" for spin 1"
     621            0 :             CALL cp_fm_get_submatrix(negf_env%contacts(icontact)%h_01(1), target_m)
     622            0 :             IF (para_env%is_source()) CALL negf_print_matrix_to_file(filename_h01_1, target_m)
     623            0 :             IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "H_01 is saved to "//TRIM(filename_h01_1)//" for spin 1"
     624            0 :             CALL cp_fm_get_submatrix(negf_env%contacts(icontact)%h_00(2), target_m)
     625            0 :             IF (para_env%is_source()) CALL negf_print_matrix_to_file(filename_h00_2, target_m)
     626            0 :             IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "H_00 is saved to "//TRIM(filename_h00_2)//" for spin 2"
     627            0 :             CALL cp_fm_get_submatrix(negf_env%contacts(icontact)%h_01(2), target_m)
     628            0 :             IF (para_env%is_source()) CALL negf_print_matrix_to_file(filename_h01_2, target_m)
     629            0 :             IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "H_01 is saved to "//TRIM(filename_h01_2)//" for spin 2"
     630              :          END IF
     631            0 :          DEALLOCATE (target_m)
     632              : 
     633              :       END IF
     634              : 
     635            0 :       IF (.NOT. is_separate .AND. log_unit > 0) WRITE (log_unit, '(/,T2,79("-"))')
     636              : 
     637            0 :       CALL timestop(handle)
     638            0 :    END SUBROUTINE negf_env_contact_read_write_hs
     639              : 
     640              : ! **************************************************************************************************
     641              : !> \brief Extract relevant matrix blocks for the given contact.
     642              : !> \param contact_env         NEGF environment for the contact (modified on exit)
     643              : !> \param sub_env             NEGF parallel (sub)group environment
     644              : !> \param qs_env_contact      QuickStep environment for the contact force environment
     645              : !> \par History
     646              : !>   * 10.2017 created [Sergey Chulkov]
     647              : !>   * 10.2025 The subroutine is essentially modified. New functionality of negf_copy_contact_matrix.
     648              : !>             [Dmitry Ryndyk]
     649              : ! **************************************************************************************************
     650            4 :    SUBROUTINE negf_env_contact_init_matrices(contact_env, sub_env, qs_env_contact)
     651              :       TYPE(negf_env_contact_type), INTENT(inout)         :: contact_env
     652              :       TYPE(negf_subgroup_env_type), INTENT(in)           :: sub_env
     653              :       TYPE(qs_environment_type), POINTER                 :: qs_env_contact
     654              : 
     655              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'negf_env_contact_init_matrices'
     656              : 
     657              :       INTEGER                                            :: handle, iatom, ispin, nao, natoms, &
     658              :                                                             nimages, nspins
     659            4 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: atom_list0, atom_list1
     660            4 :       INTEGER, ALLOCATABLE, DIMENSION(:, :)              :: index_to_cell
     661            4 :       INTEGER, DIMENSION(:, :, :), POINTER               :: cell_to_index
     662              :       LOGICAL                                            :: do_kpoints
     663              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
     664            4 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matkp
     665            4 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: matrix_ks_kp, matrix_s_kp, rho_ao_kp
     666              :       TYPE(dft_control_type), POINTER                    :: dft_control
     667              :       TYPE(kpoint_type), POINTER                         :: kpoints
     668              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     669              :       TYPE(qs_rho_type), POINTER                         :: rho_struct
     670              :       TYPE(qs_subsys_type), POINTER                      :: subsys
     671              : 
     672            4 :       CALL timeset(routineN, handle)
     673              : 
     674              :       CALL get_qs_env(qs_env_contact, &
     675              :                       dft_control=dft_control, &
     676              :                       do_kpoints=do_kpoints, &
     677              :                       kpoints=kpoints, &
     678              :                       matrix_ks_kp=matrix_ks_kp, &
     679              :                       matrix_s_kp=matrix_s_kp, &
     680              :                       para_env=para_env, &
     681              :                       rho=rho_struct, &
     682            4 :                       subsys=subsys)
     683            4 :       CALL qs_rho_get(rho_struct, rho_ao_kp=rho_ao_kp)
     684              : 
     685            4 :       CALL negf_homo_energy_estimate(contact_env%homo_energy, qs_env_contact)
     686              : 
     687            4 :       natoms = SIZE(contact_env%atomlist_cell0)
     688           12 :       ALLOCATE (atom_list0(natoms))
     689           20 :       DO iatom = 1, natoms
     690           16 :          atom_list0(iatom) = contact_env%atom_map_cell0(iatom)%iatom
     691              : 
     692              :          ! with no k-points there is one-to-one correspondence between the primary unit cell
     693              :          ! of the contact force_env and the first contact unit cell of the device force_env
     694           68 :          IF (SUM(ABS(contact_env%atom_map_cell0(iatom)%cell(:))) > 0) THEN
     695            0 :             CPABORT("NEGF K-points are not currently supported")
     696              :          END IF
     697              :       END DO
     698              : 
     699            4 :       CPASSERT(SIZE(contact_env%atomlist_cell1) == natoms)
     700            8 :       ALLOCATE (atom_list1(natoms))
     701           20 :       DO iatom = 1, natoms
     702           20 :          atom_list1(iatom) = contact_env%atom_map_cell1(iatom)%iatom
     703              :       END DO
     704              : 
     705            4 :       nspins = dft_control%nspins
     706            4 :       nimages = dft_control%nimages
     707              : 
     708            4 :       IF (do_kpoints) THEN
     709            4 :          CALL get_kpoint_info(kpoints, cell_to_index=cell_to_index)
     710              :       ELSE
     711            0 :          ALLOCATE (cell_to_index(0:0, 0:0, 0:0))
     712            0 :          cell_to_index(0, 0, 0) = 1
     713              :       END IF
     714              : 
     715           12 :       ALLOCATE (index_to_cell(3, nimages))
     716            4 :       CALL invert_cell_to_index(cell_to_index, nimages, index_to_cell)
     717            4 :       IF (.NOT. do_kpoints) DEALLOCATE (cell_to_index)
     718              : 
     719            4 :       NULLIFY (fm_struct)
     720            4 :       nao = number_of_atomic_orbitals(subsys, atom_list0)
     721            4 :       CALL cp_fm_struct_create(fm_struct, nrow_global=nao, ncol_global=nao, context=sub_env%blacs_env)
     722              : 
     723              :       ! ++ create matrices: s_00, s_01
     724            4 :       ALLOCATE (contact_env%s_00, contact_env%s_01)
     725            4 :       CALL cp_fm_create(contact_env%s_00, fm_struct)
     726            4 :       CALL cp_fm_create(contact_env%s_01, fm_struct)
     727              : 
     728              :       ! ++ create matrices: h_00, h_01, rho_00, rho_01
     729           24 :       ALLOCATE (contact_env%h_00(nspins), contact_env%h_01(nspins))
     730           20 :       ALLOCATE (contact_env%rho_00(nspins), contact_env%rho_01(nspins))
     731            8 :       DO ispin = 1, nspins
     732            4 :          CALL cp_fm_create(contact_env%h_00(ispin), fm_struct)
     733            4 :          CALL cp_fm_create(contact_env%h_01(ispin), fm_struct)
     734            4 :          CALL cp_fm_create(contact_env%rho_00(ispin), fm_struct)
     735            8 :          CALL cp_fm_create(contact_env%rho_01(ispin), fm_struct)
     736              :       END DO
     737              : 
     738            4 :       CALL cp_fm_struct_release(fm_struct)
     739              : 
     740              :       ! extract matrices: s_00, s_01
     741            4 :       matkp => matrix_s_kp(1, :)
     742              :       CALL negf_copy_contact_matrix(fm_cell0=contact_env%s_00, &
     743              :                                     fm_cell1=contact_env%s_01, &
     744              :                                     direction_axis=contact_env%direction_axis, &
     745              :                                     matrix_kp=matkp, &
     746              :                                     atom_list0=atom_list0, atom_list1=atom_list1, &
     747              :                                     subsys=subsys, mpi_comm_global=para_env, &
     748            4 :                                     kpoints=kpoints)
     749              : 
     750              :       ! extract matrices: h_00, h_01, rho_00, rho_01
     751            8 :       DO ispin = 1, nspins
     752            4 :          matkp => matrix_ks_kp(ispin, :)
     753              :          CALL negf_copy_contact_matrix(fm_cell0=contact_env%h_00(ispin), &
     754              :                                        fm_cell1=contact_env%h_01(ispin), &
     755              :                                        direction_axis=contact_env%direction_axis, &
     756              :                                        matrix_kp=matkp, &
     757              :                                        atom_list0=atom_list0, atom_list1=atom_list1, &
     758              :                                        subsys=subsys, mpi_comm_global=para_env, &
     759            4 :                                        kpoints=kpoints)
     760              : 
     761            4 :          matkp => rho_ao_kp(ispin, :)
     762              :          CALL negf_copy_contact_matrix(fm_cell0=contact_env%rho_00(ispin), &
     763              :                                        fm_cell1=contact_env%rho_01(ispin), &
     764              :                                        direction_axis=contact_env%direction_axis, &
     765              :                                        matrix_kp=matkp, &
     766              :                                        atom_list0=atom_list0, atom_list1=atom_list1, &
     767              :                                        subsys=subsys, mpi_comm_global=para_env, &
     768            8 :                                        kpoints=kpoints)
     769              :       END DO
     770              : 
     771            4 :       DEALLOCATE (atom_list0, atom_list1)
     772              : 
     773            4 :       CALL timestop(handle)
     774            8 :    END SUBROUTINE negf_env_contact_init_matrices
     775              : 
     776              : ! **************************************************************************************************
     777              : !> \brief Extract relevant matrix blocks for the given contact using the device's force environment.
     778              : !> \param contact_env         NEGF environment for the contact (modified on exit)
     779              : !> \param contact_control     NEGF control for the contact
     780              : !> \param sub_env             NEGF parallel (sub)group environment
     781              : !> \param qs_env              QuickStep environment for the device force environment
     782              : !> \param eps_geometry        accuracy in Cartesian coordinates
     783              : !> \author Sergey Chulkov
     784              : ! **************************************************************************************************
     785            4 :    SUBROUTINE negf_env_contact_init_matrices_gamma(contact_env, contact_control, sub_env, qs_env, eps_geometry)
     786              :       TYPE(negf_env_contact_type), INTENT(inout)         :: contact_env
     787              :       TYPE(negf_control_contact_type), INTENT(in)        :: contact_control
     788              :       TYPE(negf_subgroup_env_type), INTENT(in)           :: sub_env
     789              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     790              :       REAL(kind=dp), INTENT(in)                          :: eps_geometry
     791              : 
     792              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'negf_env_contact_init_matrices_gamma'
     793              : 
     794              :       INTEGER                                            :: handle, iatom, icell, ispin, nao_c, &
     795              :                                                             nspins
     796              :       LOGICAL                                            :: do_kpoints
     797              :       REAL(kind=dp), DIMENSION(2)                        :: r2_origin_cell
     798              :       REAL(kind=dp), DIMENSION(3)                        :: direction_vector, origin
     799              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
     800            4 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: matrix_ks_kp, matrix_s_kp, rho_ao_kp
     801              :       TYPE(dft_control_type), POINTER                    :: dft_control
     802              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     803            4 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     804              :       TYPE(qs_rho_type), POINTER                         :: rho_struct
     805              :       TYPE(qs_subsys_type), POINTER                      :: subsys
     806              : 
     807            4 :       CALL timeset(routineN, handle)
     808              : 
     809              :       CALL get_qs_env(qs_env, &
     810              :                       dft_control=dft_control, &
     811              :                       do_kpoints=do_kpoints, &
     812              :                       matrix_ks_kp=matrix_ks_kp, &
     813              :                       matrix_s_kp=matrix_s_kp, &
     814              :                       para_env=para_env, &
     815              :                       rho=rho_struct, &
     816            4 :                       subsys=subsys)
     817            4 :       CALL qs_rho_get(rho_struct, rho_ao_kp=rho_ao_kp)
     818              : 
     819            4 :       IF (do_kpoints) THEN
     820              :          CALL cp_abort(__LOCATION__, &
     821            0 :                        "K-points in device region have not been implemented yet.")
     822              :       END IF
     823              : 
     824            4 :       nspins = dft_control%nspins
     825              : 
     826            4 :       nao_c = number_of_atomic_orbitals(subsys, contact_control%atomlist_cell(1)%vector)
     827            4 :       IF (number_of_atomic_orbitals(subsys, contact_control%atomlist_cell(2)%vector) /= nao_c) THEN
     828              :          CALL cp_abort(__LOCATION__, &
     829              :                        "Primary and secondary bulk contact cells should be identical "// &
     830              :                        "in terms of the number of atoms of each kind, and their basis sets. "// &
     831            0 :                        "No single atom, however, can be shared between these two cells.")
     832              :       END IF
     833              : 
     834            4 :       contact_env%homo_energy = 0.0_dp
     835              : 
     836              :       CALL contact_direction_vector(contact_env%origin, &
     837              :                                     contact_env%direction_vector, &
     838              :                                     contact_env%origin_bias, &
     839              :                                     contact_env%direction_vector_bias, &
     840              :                                     contact_control%atomlist_screening, &
     841              :                                     contact_control%atomlist_bulk, &
     842            4 :                                     subsys)
     843              : 
     844            4 :       contact_env%direction_axis = contact_direction_axis(contact_env%direction_vector, subsys, eps_geometry)
     845              : 
     846              :       ! choose the primary and secondary contact unit cells
     847            4 :       CALL qs_subsys_get(subsys, particle_set=particle_set)
     848              : 
     849           16 :       origin = particle_set(contact_control%atomlist_screening(1))%r
     850           16 :       DO iatom = 2, SIZE(contact_control%atomlist_screening)
     851           52 :          origin = origin + particle_set(contact_control%atomlist_screening(iatom))%r
     852              :       END DO
     853           16 :       origin = origin/REAL(SIZE(contact_control%atomlist_screening), kind=dp)
     854              : 
     855           12 :       DO icell = 1, 2
     856           32 :          direction_vector = particle_set(contact_control%atomlist_cell(icell)%vector(1))%r
     857           32 :          DO iatom = 2, SIZE(contact_control%atomlist_cell(icell)%vector)
     858          104 :             direction_vector = direction_vector + particle_set(contact_control%atomlist_cell(icell)%vector(iatom))%r
     859              :          END DO
     860           32 :          direction_vector = direction_vector/REAL(SIZE(contact_control%atomlist_cell(icell)%vector), kind=dp)
     861           32 :          direction_vector = direction_vector - origin
     862           36 :          r2_origin_cell(icell) = DOT_PRODUCT(direction_vector, direction_vector)
     863              :       END DO
     864              : 
     865            4 :       IF (ABS(r2_origin_cell(1) - r2_origin_cell(2)) < (eps_geometry*eps_geometry)) THEN
     866              :          ! primary and secondary bulk unit cells should not overlap;
     867              :          ! currently we check that they are different by at least one atom that is, indeed, not sufficient.
     868              :          CALL cp_abort(__LOCATION__, &
     869            0 :                        "Primary and secondary bulk contact cells should not overlap ")
     870            4 :       ELSE IF (r2_origin_cell(1) < r2_origin_cell(2)) THEN
     871            2 :          IF (.NOT. ALLOCATED(contact_env%atomlist_cell0)) &
     872            6 :             ALLOCATE (contact_env%atomlist_cell0(SIZE(contact_control%atomlist_cell(1)%vector)))
     873           10 :          contact_env%atomlist_cell0(:) = contact_control%atomlist_cell(1)%vector(:)
     874            2 :          IF (.NOT. ALLOCATED(contact_env%atomlist_cell1)) &
     875            6 :             ALLOCATE (contact_env%atomlist_cell1(SIZE(contact_control%atomlist_cell(2)%vector)))
     876           10 :          contact_env%atomlist_cell1(:) = contact_control%atomlist_cell(2)%vector(:)
     877              :       ELSE
     878            2 :          IF (.NOT. ALLOCATED(contact_env%atomlist_cell0)) &
     879            6 :             ALLOCATE (contact_env%atomlist_cell0(SIZE(contact_control%atomlist_cell(2)%vector)))
     880           10 :          contact_env%atomlist_cell0(:) = contact_control%atomlist_cell(2)%vector(:)
     881            2 :          IF (.NOT. ALLOCATED(contact_env%atomlist_cell1)) &
     882            6 :             ALLOCATE (contact_env%atomlist_cell1(SIZE(contact_control%atomlist_cell(1)%vector)))
     883           10 :          contact_env%atomlist_cell1(:) = contact_control%atomlist_cell(1)%vector(:)
     884              :       END IF
     885            4 :       IF (.NOT. contact_control%read_write_HS) THEN
     886            4 :          NULLIFY (fm_struct)
     887            4 :          CALL cp_fm_struct_create(fm_struct, nrow_global=nao_c, ncol_global=nao_c, context=sub_env%blacs_env)
     888           28 :          ALLOCATE (contact_env%h_00(nspins), contact_env%h_01(nspins))
     889           28 :          ALLOCATE (contact_env%rho_00(nspins), contact_env%rho_01(nspins))
     890            8 :          DO ispin = 1, nspins
     891            4 :             CALL cp_fm_create(contact_env%h_00(ispin), fm_struct)
     892            4 :             CALL cp_fm_create(contact_env%h_01(ispin), fm_struct)
     893            4 :             CALL cp_fm_create(contact_env%rho_00(ispin), fm_struct)
     894            8 :             CALL cp_fm_create(contact_env%rho_01(ispin), fm_struct)
     895              :          END DO
     896            4 :          ALLOCATE (contact_env%s_00, contact_env%s_01)
     897            4 :          CALL cp_fm_create(contact_env%s_00, fm_struct)
     898            4 :          CALL cp_fm_create(contact_env%s_01, fm_struct)
     899            4 :          CALL cp_fm_struct_release(fm_struct)
     900              : 
     901            8 :          DO ispin = 1, nspins
     902              :             CALL negf_copy_sym_dbcsr_to_fm_submat(matrix=matrix_ks_kp(ispin, 1)%matrix, &
     903              :                                                   fm=contact_env%h_00(ispin), &
     904              :                                                   atomlist_row=contact_env%atomlist_cell0, &
     905              :                                                   atomlist_col=contact_env%atomlist_cell0, &
     906              :                                                   subsys=subsys, mpi_comm_global=para_env, &
     907            4 :                                                   do_upper_diag=.TRUE., do_lower=.TRUE.)
     908              :             CALL negf_copy_sym_dbcsr_to_fm_submat(matrix=matrix_ks_kp(ispin, 1)%matrix, &
     909              :                                                   fm=contact_env%h_01(ispin), &
     910              :                                                   atomlist_row=contact_env%atomlist_cell0, &
     911              :                                                   atomlist_col=contact_env%atomlist_cell1, &
     912              :                                                   subsys=subsys, mpi_comm_global=para_env, &
     913            4 :                                                   do_upper_diag=.TRUE., do_lower=.TRUE.)
     914              : 
     915              :             CALL negf_copy_sym_dbcsr_to_fm_submat(matrix=rho_ao_kp(ispin, 1)%matrix, &
     916              :                                                   fm=contact_env%rho_00(ispin), &
     917              :                                                   atomlist_row=contact_env%atomlist_cell0, &
     918              :                                                   atomlist_col=contact_env%atomlist_cell0, &
     919              :                                                   subsys=subsys, mpi_comm_global=para_env, &
     920            4 :                                                   do_upper_diag=.TRUE., do_lower=.TRUE.)
     921              :             CALL negf_copy_sym_dbcsr_to_fm_submat(matrix=rho_ao_kp(ispin, 1)%matrix, &
     922              :                                                   fm=contact_env%rho_01(ispin), &
     923              :                                                   atomlist_row=contact_env%atomlist_cell0, &
     924              :                                                   atomlist_col=contact_env%atomlist_cell1, &
     925              :                                                   subsys=subsys, mpi_comm_global=para_env, &
     926            8 :                                                   do_upper_diag=.TRUE., do_lower=.TRUE.)
     927              :          END DO
     928              : 
     929              :          CALL negf_copy_sym_dbcsr_to_fm_submat(matrix=matrix_s_kp(1, 1)%matrix, &
     930              :                                                fm=contact_env%s_00, &
     931              :                                                atomlist_row=contact_env%atomlist_cell0, &
     932              :                                                atomlist_col=contact_env%atomlist_cell0, &
     933              :                                                subsys=subsys, mpi_comm_global=para_env, &
     934            4 :                                                do_upper_diag=.TRUE., do_lower=.TRUE.)
     935              :          CALL negf_copy_sym_dbcsr_to_fm_submat(matrix=matrix_s_kp(1, 1)%matrix, &
     936              :                                                fm=contact_env%s_01, &
     937              :                                                atomlist_row=contact_env%atomlist_cell0, &
     938              :                                                atomlist_col=contact_env%atomlist_cell1, &
     939              :                                                subsys=subsys, mpi_comm_global=para_env, &
     940            4 :                                                do_upper_diag=.TRUE., do_lower=.TRUE.)
     941              :       END IF
     942            4 :       CALL timestop(handle)
     943            4 :    END SUBROUTINE negf_env_contact_init_matrices_gamma
     944              : 
     945              : ! **************************************************************************************************
     946              : !> \brief Extract relevant matrix blocks for the scattering region as well as
     947              : !>        all the scattering -- contact interface regions.
     948              : !> \param negf_env            NEGF environment (modified on exit)
     949              : !> \param negf_control        NEGF control
     950              : !> \param sub_env             NEGF parallel (sub)group environment
     951              : !> \param qs_env              Primary QuickStep environment
     952              : !> \author Sergey Chulkov
     953              : ! **************************************************************************************************
     954            4 :    SUBROUTINE negf_env_device_init_matrices(negf_env, negf_control, sub_env, qs_env)
     955              :       TYPE(negf_env_type), INTENT(inout)                 :: negf_env
     956              :       TYPE(negf_control_type), POINTER                   :: negf_control
     957              :       TYPE(negf_subgroup_env_type), INTENT(in)           :: sub_env
     958              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     959              : 
     960              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'negf_env_device_init_matrices'
     961              : 
     962              :       INTEGER                                            :: handle, icontact, ispin, nao_c, nao_s, &
     963              :                                                             ncontacts, nspins
     964              :       LOGICAL                                            :: do_kpoints
     965              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
     966              :       TYPE(dbcsr_p_type)                                 :: hmat
     967            4 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: matrix_ks_kp, matrix_s_kp
     968              :       TYPE(dft_control_type), POINTER                    :: dft_control
     969              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     970              :       TYPE(pw_env_type), POINTER                         :: pw_env
     971              :       TYPE(pw_pool_type), POINTER                        :: pw_pool
     972              :       TYPE(pw_r3d_rs_type)                               :: v_hartree
     973              :       TYPE(qs_subsys_type), POINTER                      :: subsys
     974              : 
     975            4 :       CALL timeset(routineN, handle)
     976              : 
     977            4 :       IF (ALLOCATED(negf_control%atomlist_S_screening)) THEN
     978              :          CALL get_qs_env(qs_env, &
     979              :                          dft_control=dft_control, &
     980              :                          do_kpoints=do_kpoints, &
     981              :                          matrix_ks_kp=matrix_ks_kp, &
     982              :                          matrix_s_kp=matrix_s_kp, &
     983              :                          para_env=para_env, &
     984              :                          pw_env=pw_env, &
     985            4 :                          subsys=subsys)
     986            4 :          CALL pw_env_get(pw_env, auxbas_pw_pool=pw_pool)
     987              : 
     988            4 :          IF (do_kpoints) THEN
     989              :             CALL cp_abort(__LOCATION__, &
     990            0 :                           "K-points in device region have not been implemented yet.")
     991              :          END IF
     992              : 
     993            4 :          ncontacts = SIZE(negf_control%contacts)
     994            4 :          nspins = dft_control%nspins
     995              : 
     996            4 :          NULLIFY (fm_struct)
     997            4 :          nao_s = number_of_atomic_orbitals(subsys, negf_control%atomlist_S_screening)
     998              : 
     999              :          ! ++ create matrices: h_s, s_s
    1000            4 :          NULLIFY (negf_env%s_s, negf_env%v_hartree_s, fm_struct)
    1001           16 :          ALLOCATE (negf_env%h_s(nspins))
    1002              : 
    1003            4 :          CALL cp_fm_struct_create(fm_struct, nrow_global=nao_s, ncol_global=nao_s, context=sub_env%blacs_env)
    1004            4 :          ALLOCATE (negf_env%s_s)
    1005            4 :          CALL cp_fm_create(negf_env%s_s, fm_struct)
    1006            8 :          DO ispin = 1, nspins
    1007            8 :             CALL cp_fm_create(negf_env%h_s(ispin), fm_struct)
    1008              :          END DO
    1009            4 :          ALLOCATE (negf_env%v_hartree_s)
    1010            4 :          CALL cp_fm_create(negf_env%v_hartree_s, fm_struct)
    1011            4 :          CALL cp_fm_struct_release(fm_struct)
    1012              : 
    1013              :          ! ++ create matrices: h_sc, s_sc
    1014           48 :          ALLOCATE (negf_env%h_sc(nspins, ncontacts), negf_env%s_sc(ncontacts))
    1015           12 :          DO icontact = 1, ncontacts
    1016            8 :             nao_c = number_of_atomic_orbitals(subsys, negf_env%contacts(icontact)%atomlist_cell0)
    1017            8 :             CALL cp_fm_struct_create(fm_struct, nrow_global=nao_s, ncol_global=nao_c, context=sub_env%blacs_env)
    1018              : 
    1019            8 :             CALL cp_fm_create(negf_env%s_sc(icontact), fm_struct)
    1020              : 
    1021           16 :             DO ispin = 1, nspins
    1022           16 :                CALL cp_fm_create(negf_env%h_sc(ispin, icontact), fm_struct)
    1023              :             END DO
    1024              : 
    1025           12 :             CALL cp_fm_struct_release(fm_struct)
    1026              :          END DO
    1027              : 
    1028              :          ! extract matrices: h_s, s_s
    1029            8 :          DO ispin = 1, nspins
    1030              :             CALL negf_copy_sym_dbcsr_to_fm_submat(matrix=matrix_ks_kp(ispin, 1)%matrix, &
    1031              :                                                   fm=negf_env%h_s(ispin), &
    1032              :                                                   atomlist_row=negf_control%atomlist_S_screening, &
    1033              :                                                   atomlist_col=negf_control%atomlist_S_screening, &
    1034              :                                                   subsys=subsys, mpi_comm_global=para_env, &
    1035            8 :                                                   do_upper_diag=.TRUE., do_lower=.TRUE.)
    1036              :          END DO
    1037              : 
    1038              :          CALL negf_copy_sym_dbcsr_to_fm_submat(matrix=matrix_s_kp(1, 1)%matrix, &
    1039              :                                                fm=negf_env%s_s, &
    1040              :                                                atomlist_row=negf_control%atomlist_S_screening, &
    1041              :                                                atomlist_col=negf_control%atomlist_S_screening, &
    1042              :                                                subsys=subsys, mpi_comm_global=para_env, &
    1043            4 :                                                do_upper_diag=.TRUE., do_lower=.TRUE.)
    1044              : 
    1045              :          ! v_hartree_s
    1046            4 :          NULLIFY (hmat%matrix)
    1047            4 :          CALL dbcsr_init_p(hmat%matrix)
    1048            4 :          CALL dbcsr_copy(matrix_b=hmat%matrix, matrix_a=matrix_s_kp(1, 1)%matrix)
    1049            4 :          CALL dbcsr_set(hmat%matrix, 0.0_dp)
    1050              : 
    1051            4 :          CALL pw_pool%create_pw(v_hartree)
    1052            4 :          CALL negf_env_init_v_hartree(v_hartree, negf_env%contacts, negf_control%contacts)
    1053              : 
    1054              :          CALL integrate_v_rspace(v_rspace=v_hartree, hmat=hmat, qs_env=qs_env, &
    1055            4 :                                  calculate_forces=.FALSE., compute_tau=.FALSE., gapw=.FALSE.)
    1056              : 
    1057            4 :          CALL pw_pool%give_back_pw(v_hartree)
    1058              : 
    1059              :          CALL negf_copy_sym_dbcsr_to_fm_submat(matrix=hmat%matrix, &
    1060              :                                                fm=negf_env%v_hartree_s, &
    1061              :                                                atomlist_row=negf_control%atomlist_S_screening, &
    1062              :                                                atomlist_col=negf_control%atomlist_S_screening, &
    1063              :                                                subsys=subsys, mpi_comm_global=para_env, &
    1064            4 :                                                do_upper_diag=.TRUE., do_lower=.TRUE.)
    1065              : 
    1066            4 :          CALL dbcsr_deallocate_matrix(hmat%matrix)
    1067              : 
    1068              :          ! extract matrices: h_sc, s_sc
    1069           12 :          DO icontact = 1, ncontacts
    1070           16 :             DO ispin = 1, nspins
    1071              :                CALL negf_copy_sym_dbcsr_to_fm_submat(matrix=matrix_ks_kp(ispin, 1)%matrix, &
    1072              :                                                      fm=negf_env%h_sc(ispin, icontact), &
    1073              :                                                      atomlist_row=negf_control%atomlist_S_screening, &
    1074              :                                                      atomlist_col=negf_env%contacts(icontact)%atomlist_cell0, &
    1075              :                                                      subsys=subsys, mpi_comm_global=para_env, &
    1076           16 :                                                      do_upper_diag=.TRUE., do_lower=.TRUE.)
    1077              :             END DO
    1078              : 
    1079              :             CALL negf_copy_sym_dbcsr_to_fm_submat(matrix=matrix_s_kp(1, 1)%matrix, &
    1080              :                                                   fm=negf_env%s_sc(icontact), &
    1081              :                                                   atomlist_row=negf_control%atomlist_S_screening, &
    1082              :                                                   atomlist_col=negf_env%contacts(icontact)%atomlist_cell0, &
    1083              :                                                   subsys=subsys, mpi_comm_global=para_env, &
    1084           12 :                                                   do_upper_diag=.TRUE., do_lower=.TRUE.)
    1085              :          END DO
    1086              :       END IF
    1087              : 
    1088            4 :       CALL timestop(handle)
    1089            4 :    END SUBROUTINE negf_env_device_init_matrices
    1090              : 
    1091              : ! **************************************************************************************************
    1092              : !> \brief Contribution to the Hartree potential related to the external bias voltage.
    1093              : !> \param v_hartree        Hartree potential (modified on exit)
    1094              : !> \param contact_env      NEGF environment for every contact
    1095              : !> \param contact_control  NEGF control for every contact
    1096              : !> \author Sergey Chulkov
    1097              : ! **************************************************************************************************
    1098            4 :    SUBROUTINE negf_env_init_v_hartree(v_hartree, contact_env, contact_control)
    1099              :       TYPE(pw_r3d_rs_type), INTENT(IN)                   :: v_hartree
    1100              :       TYPE(negf_env_contact_type), DIMENSION(:), &
    1101              :          INTENT(in)                                      :: contact_env
    1102              :       TYPE(negf_control_contact_type), DIMENSION(:), &
    1103              :          INTENT(in)                                      :: contact_control
    1104              : 
    1105              :       CHARACTER(len=*), PARAMETER :: routineN = 'negf_env_init_v_hartree'
    1106              :       REAL(kind=dp), PARAMETER :: threshold = 16.0_dp*EPSILON(0.0_dp)
    1107              : 
    1108              :       INTEGER                                            :: dx, dy, dz, handle, icontact, ix, iy, &
    1109              :                                                             iz, lx, ly, lz, ncontacts, ux, uy, uz
    1110              :       REAL(kind=dp)                                      :: dvol, pot, proj, v1, v2
    1111              :       REAL(kind=dp), DIMENSION(3)                        :: dirvector_bias, point_coord, &
    1112              :                                                             point_indices, vector
    1113              : 
    1114            4 :       CALL timeset(routineN, handle)
    1115              : 
    1116            4 :       ncontacts = SIZE(contact_env)
    1117            4 :       CPASSERT(SIZE(contact_control) == ncontacts)
    1118            4 :       CPASSERT(ncontacts == 2)
    1119              : 
    1120           16 :       dirvector_bias = contact_env(2)%origin_bias - contact_env(1)%origin_bias
    1121            4 :       v1 = contact_control(1)%v_external
    1122            4 :       v2 = contact_control(2)%v_external
    1123              : 
    1124            4 :       lx = v_hartree%pw_grid%bounds_local(1, 1)
    1125            4 :       ux = v_hartree%pw_grid%bounds_local(2, 1)
    1126            4 :       ly = v_hartree%pw_grid%bounds_local(1, 2)
    1127            4 :       uy = v_hartree%pw_grid%bounds_local(2, 2)
    1128            4 :       lz = v_hartree%pw_grid%bounds_local(1, 3)
    1129            4 :       uz = v_hartree%pw_grid%bounds_local(2, 3)
    1130              : 
    1131            4 :       dx = v_hartree%pw_grid%npts(1)/2
    1132            4 :       dy = v_hartree%pw_grid%npts(2)/2
    1133            4 :       dz = v_hartree%pw_grid%npts(3)/2
    1134              : 
    1135            4 :       dvol = v_hartree%pw_grid%dvol
    1136              : 
    1137         1764 :       DO iz = lz, uz
    1138         1760 :          point_indices(3) = REAL(iz + dz, kind=dp)
    1139       112644 :          DO iy = ly, uy
    1140       110880 :             point_indices(2) = REAL(iy + dy, kind=dp)
    1141              : 
    1142      3605360 :             DO ix = lx, ux
    1143      3492720 :                point_indices(1) = REAL(ix + dx, kind=dp)
    1144     45405360 :                point_coord(:) = MATMUL(v_hartree%pw_grid%dh, point_indices)
    1145              : 
    1146     13970880 :                vector = point_coord - contact_env(1)%origin_bias
    1147      3492720 :                proj = projection_on_direction_vector(vector, dirvector_bias)
    1148      3492720 :                IF (proj + threshold >= 0.0_dp .AND. proj - threshold <= 1.0_dp) THEN
    1149              :                   ! scattering region
    1150              :                   ! proj == 0   we are at the first contact boundary
    1151              :                   ! proj == 1   we are at the second contact boundary
    1152      1373274 :                   IF (proj < 0.0_dp) THEN
    1153              :                      proj = 0.0_dp
    1154      1373274 :                   ELSE IF (proj > 1.0_dp) THEN
    1155            0 :                      proj = 1.0_dp
    1156              :                   END IF
    1157      1373274 :                   pot = v1 + (v2 - v1)*proj
    1158              :                ELSE
    1159      3357774 :                   pot = 0.0_dp
    1160      3357774 :                   DO icontact = 1, ncontacts
    1161     12954816 :                      vector = point_coord - contact_env(icontact)%origin_bias
    1162      3238704 :                      proj = projection_on_direction_vector(vector, contact_env(icontact)%direction_vector_bias)
    1163              : 
    1164      3357774 :                      IF (proj + threshold >= 0.0_dp .AND. proj - threshold <= 1.0_dp) THEN
    1165      2000376 :                         pot = contact_control(icontact)%v_external
    1166      2000376 :                         EXIT
    1167              :                      END IF
    1168              :                   END DO
    1169              :                END IF
    1170              : 
    1171      3603600 :                v_hartree%array(ix, iy, iz) = pot*dvol
    1172              :             END DO
    1173              :          END DO
    1174              :       END DO
    1175              : 
    1176            4 :       CALL timestop(handle)
    1177            4 :    END SUBROUTINE negf_env_init_v_hartree
    1178              : 
    1179              : ! **************************************************************************************************
    1180              : !> \brief Detect the axis towards secondary unit cell.
    1181              : !> \param direction_vector    direction vector
    1182              : !> \param subsys_contact      QuickStep subsystem of the contact force environment
    1183              : !> \param eps_geometry        accuracy in mapping atoms between different force environments
    1184              : !> \return direction axis: 0 (undefined), 1 (x), 2(y), 3 (z)
    1185              : !> \par History
    1186              : !>   * 08.2017 created [Sergey Chulkov]
    1187              : ! **************************************************************************************************
    1188            8 :    FUNCTION contact_direction_axis(direction_vector, subsys_contact, eps_geometry) RESULT(direction_axis)
    1189              :       REAL(kind=dp), DIMENSION(3), INTENT(in)            :: direction_vector
    1190              :       TYPE(qs_subsys_type), POINTER                      :: subsys_contact
    1191              :       REAL(kind=dp), INTENT(in)                          :: eps_geometry
    1192              :       INTEGER                                            :: direction_axis
    1193              : 
    1194              :       INTEGER                                            :: i, naxes
    1195              :       REAL(kind=dp), DIMENSION(3)                        :: scaled
    1196              :       TYPE(cell_type), POINTER                           :: cell
    1197              : 
    1198            8 :       CALL qs_subsys_get(subsys_contact, cell=cell)
    1199            8 :       CALL real_to_scaled(scaled, direction_vector, cell)
    1200              : 
    1201            8 :       naxes = 0
    1202            8 :       direction_axis = 0 ! initialize to make GCC<=6 happy
    1203              : 
    1204           32 :       DO i = 1, 3
    1205           32 :          IF (ABS(scaled(i)) > eps_geometry) THEN
    1206            8 :             IF (scaled(i) > 0.0_dp) THEN
    1207              :                direction_axis = i
    1208              :             ELSE
    1209            4 :                direction_axis = -i
    1210              :             END IF
    1211            8 :             naxes = naxes + 1
    1212              :          END IF
    1213              :       END DO
    1214              : 
    1215              :       ! direction_vector is not parallel to one of the unit cell's axis
    1216            8 :       IF (naxes /= 1) direction_axis = 0
    1217            8 :    END FUNCTION contact_direction_axis
    1218              : 
    1219              : ! **************************************************************************************************
    1220              : !> \brief Estimate energy of the highest spin-alpha occupied molecular orbital.
    1221              : !> \param homo_energy  HOMO energy (initialised on exit)
    1222              : !> \param qs_env       QuickStep environment
    1223              : !> \par History
    1224              : !>   * 01.2017 created [Sergey Chulkov]
    1225              : ! **************************************************************************************************
    1226            4 :    SUBROUTINE negf_homo_energy_estimate(homo_energy, qs_env)
    1227              :       REAL(kind=dp), INTENT(out)                         :: homo_energy
    1228              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1229              : 
    1230              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'negf_homo_energy_estimate'
    1231              :       INTEGER, PARAMETER                                 :: gamma_point = 1
    1232              : 
    1233              :       INTEGER                                            :: handle, homo, ikpgr, ikpoint, imo, &
    1234              :                                                             ispin, kplocal, nmo, nspins
    1235              :       INTEGER, DIMENSION(2)                              :: kp_range
    1236              :       LOGICAL                                            :: do_kpoints
    1237              :       REAL(kind=dp)                                      :: my_homo_energy
    1238            4 :       REAL(kind=dp), DIMENSION(:), POINTER               :: eigenvalues
    1239            4 :       TYPE(kpoint_env_p_type), DIMENSION(:), POINTER     :: kp_env
    1240              :       TYPE(kpoint_type), POINTER                         :: kpoints
    1241            4 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
    1242            4 :       TYPE(mo_set_type), DIMENSION(:, :), POINTER        :: mos_kp
    1243              :       TYPE(mp_para_env_type), POINTER                    :: para_env, para_env_kp
    1244              : 
    1245            4 :       CALL timeset(routineN, handle)
    1246            4 :       my_homo_energy = 0.0_dp
    1247              : 
    1248            4 :       CALL get_qs_env(qs_env, para_env=para_env, mos=mos, kpoints=kpoints, do_kpoints=do_kpoints)
    1249              : 
    1250            4 :       IF (do_kpoints) THEN
    1251            4 :          CALL get_kpoint_info(kpoints, kp_env=kp_env, kp_range=kp_range, para_env_kp=para_env_kp)
    1252              : 
    1253              :          ! looking for a processor that holds the gamma point
    1254            4 :          IF (para_env_kp%mepos == 0 .AND. kp_range(1) <= gamma_point .AND. kp_range(2) >= gamma_point) THEN
    1255            2 :             kplocal = kp_range(2) - kp_range(1) + 1
    1256              : 
    1257            2 :             DO ikpgr = 1, kplocal
    1258            2 :                CALL get_kpoint_env(kp_env(ikpgr)%kpoint_env, nkpoint=ikpoint, mos=mos_kp)
    1259              : 
    1260            2 :                IF (ikpoint == gamma_point) THEN
    1261              :                   ! mos_kp(component, spin), where component = 1 (real), or 2 (imaginary)
    1262            2 :                   CALL get_mo_set(mos_kp(1, 1), homo=homo, eigenvalues=eigenvalues) ! mu=fermi_level
    1263              : 
    1264            2 :                   my_homo_energy = eigenvalues(homo)
    1265            2 :                   EXIT
    1266              :                END IF
    1267              :             END DO
    1268              :          END IF
    1269              : 
    1270            4 :          CALL para_env%sum(my_homo_energy)
    1271              :       ELSE
    1272              :          ! Hamiltonian of the bulk contact region has been computed without k-points.
    1273              :          ! Try to obtain the HOMO energy assuming there is no OT. We probably should abort here
    1274              :          ! as we do need a second replica of the bulk contact unit cell along transport
    1275              :          ! direction anyway which is not available without k-points.
    1276              : 
    1277              :          CALL cp_abort(__LOCATION__, &
    1278              :                        "It is necessary to use k-points along the transport direction "// &
    1279            0 :                        "for all contact FORCE_EVAL-s")
    1280              :          !      It is necessary to use k-points along the transport direction within all contact FORCE_EVAL-s
    1281              : 
    1282            0 :          nspins = SIZE(mos)
    1283              : 
    1284            0 :          spin_loop: DO ispin = 1, nspins
    1285            0 :             CALL get_mo_set(mos(ispin), homo=homo, nmo=nmo, eigenvalues=eigenvalues)
    1286              : 
    1287            0 :             DO imo = nmo, 1, -1
    1288            0 :                IF (eigenvalues(imo) /= 0.0_dp) EXIT spin_loop
    1289              :             END DO
    1290              :          END DO spin_loop
    1291              : 
    1292            0 :          IF (imo == 0) THEN
    1293            0 :             CPABORT("Orbital transformation (OT) for contact FORCE_EVAL-s is not supported")
    1294              :          END IF
    1295              : 
    1296            0 :          my_homo_energy = eigenvalues(homo)
    1297              :       END IF
    1298              : 
    1299            4 :       homo_energy = my_homo_energy
    1300            4 :       CALL timestop(handle)
    1301            4 :    END SUBROUTINE negf_homo_energy_estimate
    1302              : 
    1303              : ! **************************************************************************************************
    1304              : !> \brief List atoms from the contact's primary unit cell.
    1305              : !> \param atomlist_cell0    list of atoms belonging to the contact's primary unit cell
    1306              : !>                          (allocate and initialised on exit)
    1307              : !> \param atom_map_cell0    atomic map of atoms from 'atomlist_cell0' (allocate and initialised on exit)
    1308              : !> \param atomlist_bulk     list of atoms belonging to the bulk contact region
    1309              : !> \param atom_map          atomic map of atoms from 'atomlist_bulk'
    1310              : !> \param origin            origin of the contact
    1311              : !> \param direction_vector  direction vector of the contact
    1312              : !> \param direction_axis    axis towards secondary unit cell
    1313              : !> \param subsys_device     QuickStep subsystem of the device force environment
    1314              : !> \par History
    1315              : !>   * 08.2017 created [Sergey Chulkov]
    1316              : ! **************************************************************************************************
    1317            4 :    SUBROUTINE list_atoms_in_bulk_primary_unit_cell(atomlist_cell0, atom_map_cell0, atomlist_bulk, atom_map, &
    1318              :                                                    origin, direction_vector, direction_axis, subsys_device)
    1319              :       INTEGER, ALLOCATABLE, DIMENSION(:), INTENT(inout)  :: atomlist_cell0
    1320              :       TYPE(negf_atom_map_type), ALLOCATABLE, &
    1321              :          DIMENSION(:), INTENT(inout)                     :: atom_map_cell0
    1322              :       INTEGER, DIMENSION(:), INTENT(in)                  :: atomlist_bulk
    1323              :       TYPE(negf_atom_map_type), DIMENSION(:), INTENT(in) :: atom_map
    1324              :       REAL(kind=dp), DIMENSION(3), INTENT(in)            :: origin, direction_vector
    1325              :       INTEGER, INTENT(in)                                :: direction_axis
    1326              :       TYPE(qs_subsys_type), POINTER                      :: subsys_device
    1327              : 
    1328              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'list_atoms_in_bulk_primary_unit_cell'
    1329              : 
    1330              :       INTEGER                                            :: atom_min, dir_axis_min, &
    1331              :                                                             direction_axis_abs, handle, iatom, &
    1332              :                                                             natoms_bulk, natoms_cell0
    1333              :       REAL(kind=dp)                                      :: proj, proj_min
    1334              :       REAL(kind=dp), DIMENSION(3)                        :: vector
    1335            4 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    1336              : 
    1337            4 :       CALL timeset(routineN, handle)
    1338            4 :       CALL qs_subsys_get(subsys_device, particle_set=particle_set)
    1339              : 
    1340            4 :       natoms_bulk = SIZE(atomlist_bulk)
    1341            4 :       CPASSERT(SIZE(atom_map, 1) == natoms_bulk)
    1342            4 :       direction_axis_abs = ABS(direction_axis)
    1343              : 
    1344              :       ! looking for the nearest atom from the scattering region
    1345            4 :       proj_min = 1.0_dp
    1346            4 :       atom_min = 1
    1347           36 :       DO iatom = 1, natoms_bulk
    1348          128 :          vector = particle_set(atomlist_bulk(iatom))%r - origin
    1349           32 :          proj = projection_on_direction_vector(vector, direction_vector)
    1350              : 
    1351           36 :          IF (proj < proj_min) THEN
    1352           16 :             proj_min = proj
    1353           16 :             atom_min = iatom
    1354              :          END IF
    1355              :       END DO
    1356              : 
    1357            4 :       dir_axis_min = atom_map(atom_min)%cell(direction_axis_abs)
    1358              : 
    1359            4 :       natoms_cell0 = 0
    1360           36 :       DO iatom = 1, natoms_bulk
    1361           32 :          IF (atom_map(iatom)%cell(direction_axis_abs) == dir_axis_min) &
    1362           20 :             natoms_cell0 = natoms_cell0 + 1
    1363              :       END DO
    1364              : 
    1365           12 :       ALLOCATE (atomlist_cell0(natoms_cell0))
    1366           40 :       ALLOCATE (atom_map_cell0(natoms_cell0))
    1367              : 
    1368            4 :       natoms_cell0 = 0
    1369           36 :       DO iatom = 1, natoms_bulk
    1370           36 :          IF (atom_map(iatom)%cell(direction_axis_abs) == dir_axis_min) THEN
    1371           16 :             natoms_cell0 = natoms_cell0 + 1
    1372           16 :             atomlist_cell0(natoms_cell0) = atomlist_bulk(iatom)
    1373           16 :             atom_map_cell0(natoms_cell0) = atom_map(iatom)
    1374              :          END IF
    1375              :       END DO
    1376              : 
    1377            4 :       CALL timestop(handle)
    1378            4 :    END SUBROUTINE list_atoms_in_bulk_primary_unit_cell
    1379              : 
    1380              : ! **************************************************************************************************
    1381              : !> \brief List atoms from the contact's secondary unit cell.
    1382              : !> \param atomlist_cell1    list of atoms belonging to the contact's secondary unit cell
    1383              : !>                          (allocate and initialised on exit)
    1384              : !> \param atom_map_cell1    atomic map of atoms from 'atomlist_cell1'
    1385              : !>                          (allocate and initialised on exit)
    1386              : !> \param atomlist_bulk     list of atoms belonging to the bulk contact region
    1387              : !> \param atom_map          atomic map of atoms from 'atomlist_bulk'
    1388              : !> \param origin            origin of the contact
    1389              : !> \param direction_vector  direction vector of the contact
    1390              : !> \param direction_axis    axis towards the secondary unit cell
    1391              : !> \param subsys_device     QuickStep subsystem of the device force environment
    1392              : !> \par History
    1393              : !>   * 11.2017 created [Sergey Chulkov]
    1394              : !> \note Cloned from list_atoms_in_bulk_primary_unit_cell. Will be removed once we can managed to
    1395              : !>        maintain consistency between real-space matrices from different force_eval sections.
    1396              : ! **************************************************************************************************
    1397            4 :    SUBROUTINE list_atoms_in_bulk_secondary_unit_cell(atomlist_cell1, atom_map_cell1, atomlist_bulk, atom_map, &
    1398              :                                                      origin, direction_vector, direction_axis, subsys_device)
    1399              :       INTEGER, ALLOCATABLE, DIMENSION(:), INTENT(inout)  :: atomlist_cell1
    1400              :       TYPE(negf_atom_map_type), ALLOCATABLE, &
    1401              :          DIMENSION(:), INTENT(inout)                     :: atom_map_cell1
    1402              :       INTEGER, DIMENSION(:), INTENT(in)                  :: atomlist_bulk
    1403              :       TYPE(negf_atom_map_type), DIMENSION(:), INTENT(in) :: atom_map
    1404              :       REAL(kind=dp), DIMENSION(3), INTENT(in)            :: origin, direction_vector
    1405              :       INTEGER, INTENT(in)                                :: direction_axis
    1406              :       TYPE(qs_subsys_type), POINTER                      :: subsys_device
    1407              : 
    1408              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'list_atoms_in_bulk_secondary_unit_cell'
    1409              : 
    1410              :       INTEGER                                            :: atom_min, dir_axis_min, &
    1411              :                                                             direction_axis_abs, handle, iatom, &
    1412              :                                                             natoms_bulk, natoms_cell1, offset
    1413              :       REAL(kind=dp)                                      :: proj, proj_min
    1414              :       REAL(kind=dp), DIMENSION(3)                        :: vector
    1415            4 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    1416              : 
    1417            4 :       CALL timeset(routineN, handle)
    1418            4 :       CALL qs_subsys_get(subsys_device, particle_set=particle_set)
    1419              : 
    1420            4 :       natoms_bulk = SIZE(atomlist_bulk)
    1421            4 :       CPASSERT(SIZE(atom_map, 1) == natoms_bulk)
    1422            4 :       direction_axis_abs = ABS(direction_axis)
    1423            4 :       offset = SIGN(1, direction_axis)
    1424              : 
    1425              :       ! looking for the nearest atom from the scattering region
    1426            4 :       proj_min = 1.0_dp
    1427            4 :       atom_min = 1
    1428           36 :       DO iatom = 1, natoms_bulk
    1429          128 :          vector = particle_set(atomlist_bulk(iatom))%r - origin
    1430           32 :          proj = projection_on_direction_vector(vector, direction_vector)
    1431              : 
    1432           36 :          IF (proj < proj_min) THEN
    1433           16 :             proj_min = proj
    1434           16 :             atom_min = iatom
    1435              :          END IF
    1436              :       END DO
    1437              : 
    1438            4 :       dir_axis_min = atom_map(atom_min)%cell(direction_axis_abs)
    1439              : 
    1440            4 :       natoms_cell1 = 0
    1441           36 :       DO iatom = 1, natoms_bulk
    1442           32 :          IF (atom_map(iatom)%cell(direction_axis_abs) == dir_axis_min + offset) &
    1443           20 :             natoms_cell1 = natoms_cell1 + 1
    1444              :       END DO
    1445              : 
    1446           12 :       ALLOCATE (atomlist_cell1(natoms_cell1))
    1447           40 :       ALLOCATE (atom_map_cell1(natoms_cell1))
    1448              : 
    1449            4 :       natoms_cell1 = 0
    1450           36 :       DO iatom = 1, natoms_bulk
    1451           36 :          IF (atom_map(iatom)%cell(direction_axis_abs) == dir_axis_min + offset) THEN
    1452           16 :             natoms_cell1 = natoms_cell1 + 1
    1453           16 :             atomlist_cell1(natoms_cell1) = atomlist_bulk(iatom)
    1454           16 :             atom_map_cell1(natoms_cell1) = atom_map(iatom)
    1455           16 :             atom_map_cell1(natoms_cell1)%cell(direction_axis_abs) = dir_axis_min
    1456              :          END IF
    1457              :       END DO
    1458              : 
    1459            4 :       CALL timestop(handle)
    1460            4 :    END SUBROUTINE list_atoms_in_bulk_secondary_unit_cell
    1461              : 
    1462              : ! **************************************************************************************************
    1463              : !> \brief Release a NEGF environment variable.
    1464              : !> \param negf_env  NEGF environment to release
    1465              : !> \par History
    1466              : !>   * 01.2017 created [Sergey Chulkov]
    1467              : ! **************************************************************************************************
    1468            4 :    SUBROUTINE negf_env_release(negf_env)
    1469              :       TYPE(negf_env_type), INTENT(inout)                 :: negf_env
    1470              : 
    1471              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'negf_env_release'
    1472              : 
    1473              :       INTEGER                                            :: handle, icontact
    1474              : 
    1475            4 :       CALL timeset(routineN, handle)
    1476              : 
    1477            4 :       IF (ALLOCATED(negf_env%contacts)) THEN
    1478           12 :          DO icontact = SIZE(negf_env%contacts), 1, -1
    1479           12 :             CALL negf_env_contact_release(negf_env%contacts(icontact))
    1480              :          END DO
    1481              : 
    1482           12 :          DEALLOCATE (negf_env%contacts)
    1483              :       END IF
    1484              : 
    1485              :       ! h_s
    1486            4 :       CALL cp_fm_release(negf_env%h_s)
    1487              : 
    1488              :       ! h_sc
    1489            4 :       CALL cp_fm_release(negf_env%h_sc)
    1490              : 
    1491              :       ! s_s
    1492            4 :       IF (ASSOCIATED(negf_env%s_s)) THEN
    1493            4 :          CALL cp_fm_release(negf_env%s_s)
    1494            4 :          DEALLOCATE (negf_env%s_s)
    1495              :          NULLIFY (negf_env%s_s)
    1496              :       END IF
    1497              : 
    1498              :       ! s_sc
    1499            4 :       CALL cp_fm_release(negf_env%s_sc)
    1500              : 
    1501              :       ! v_hartree_s
    1502            4 :       IF (ASSOCIATED(negf_env%v_hartree_s)) THEN
    1503            4 :          CALL cp_fm_release(negf_env%v_hartree_s)
    1504            4 :          DEALLOCATE (negf_env%v_hartree_s)
    1505              :          NULLIFY (negf_env%v_hartree_s)
    1506              :       END IF
    1507              : 
    1508              :       ! density mixing
    1509            4 :       IF (ASSOCIATED(negf_env%mixing_storage)) THEN
    1510            4 :          CALL mixing_storage_release(negf_env%mixing_storage)
    1511            4 :          DEALLOCATE (negf_env%mixing_storage)
    1512              :       END IF
    1513              : 
    1514            4 :       CALL timestop(handle)
    1515            4 :    END SUBROUTINE negf_env_release
    1516              : 
    1517              : ! **************************************************************************************************
    1518              : !> \brief Release a NEGF contact environment variable.
    1519              : !> \param contact_env  NEGF contact environment to release
    1520              : ! **************************************************************************************************
    1521            8 :    SUBROUTINE negf_env_contact_release(contact_env)
    1522              :       TYPE(negf_env_contact_type), INTENT(inout)         :: contact_env
    1523              : 
    1524              :       CHARACTER(len=*), PARAMETER :: routineN = 'negf_env_contact_release'
    1525              : 
    1526              :       INTEGER                                            :: handle
    1527              : 
    1528            8 :       CALL timeset(routineN, handle)
    1529              : 
    1530              :       ! h_00
    1531            8 :       CALL cp_fm_release(contact_env%h_00)
    1532              : 
    1533              :       ! h_01
    1534            8 :       CALL cp_fm_release(contact_env%h_01)
    1535              : 
    1536              :       ! rho_00
    1537            8 :       CALL cp_fm_release(contact_env%rho_00)
    1538              : 
    1539              :       ! rho_01
    1540            8 :       CALL cp_fm_release(contact_env%rho_01)
    1541              : 
    1542              :       ! s_00
    1543            8 :       IF (ASSOCIATED(contact_env%s_00)) THEN
    1544            8 :          CALL cp_fm_release(contact_env%s_00)
    1545            8 :          DEALLOCATE (contact_env%s_00)
    1546              :          NULLIFY (contact_env%s_00)
    1547              :       END IF
    1548              : 
    1549              :       ! s_01
    1550            8 :       IF (ASSOCIATED(contact_env%s_01)) THEN
    1551            8 :          CALL cp_fm_release(contact_env%s_01)
    1552            8 :          DEALLOCATE (contact_env%s_01)
    1553              :          NULLIFY (contact_env%s_01)
    1554              :       END IF
    1555              : 
    1556            8 :       IF (ALLOCATED(contact_env%atomlist_cell0)) DEALLOCATE (contact_env%atomlist_cell0)
    1557            8 :       IF (ALLOCATED(contact_env%atomlist_cell1)) DEALLOCATE (contact_env%atomlist_cell1)
    1558            8 :       IF (ALLOCATED(contact_env%atom_map_cell0)) DEALLOCATE (contact_env%atom_map_cell0)
    1559              : 
    1560            8 :       CALL timestop(handle)
    1561            8 :    END SUBROUTINE negf_env_contact_release
    1562              : 
    1563            0 : END MODULE negf_env_types
        

Generated by: LCOV version 2.0-1