LCOV - code coverage report
Current view: top level - src - negf_control_types.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:2fce0f8) Lines: 178 230 77.4 %
Date: 2024-12-21 06:28:57 Functions: 4 8 50.0 %

          Line data    Source code
       1             : !--------------------------------------------------------------------------------------------------!
       2             : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3             : !   Copyright 2000-2024 CP2K developers group <https://cp2k.org>                                   !
       4             : !                                                                                                  !
       5             : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6             : !--------------------------------------------------------------------------------------------------!
       7             : 
       8             : ! **************************************************************************************************
       9             : !> \brief Input control types for NEGF based quantum transport calculations
      10             : ! **************************************************************************************************
      11             : 
      12             : MODULE negf_control_types
      13             :    USE cp_subsys_types,                 ONLY: cp_subsys_get,&
      14             :                                               cp_subsys_type
      15             :    USE input_constants,                 ONLY: negf_run
      16             :    USE input_section_types,             ONLY: section_vals_get,&
      17             :                                               section_vals_get_subs_vals,&
      18             :                                               section_vals_type,&
      19             :                                               section_vals_val_get
      20             :    USE kinds,                           ONLY: default_string_length,&
      21             :                                               dp
      22             :    USE mathconstants,                   ONLY: pi
      23             :    USE molecule_kind_types,             ONLY: get_molecule_kind,&
      24             :                                               molecule_kind_type
      25             :    USE molecule_types,                  ONLY: get_molecule,&
      26             :                                               molecule_type
      27             :    USE negf_alloc_types,                ONLY: negf_allocatable_ivector
      28             :    USE particle_types,                  ONLY: particle_type
      29             :    USE physcon,                         ONLY: kelvin
      30             :    USE string_utilities,                ONLY: integer_to_string
      31             :    USE util,                            ONLY: sort
      32             : #include "./base/base_uses.f90"
      33             : 
      34             :    IMPLICIT NONE
      35             :    PRIVATE
      36             : 
      37             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'negf_control_types'
      38             :    LOGICAL, PARAMETER, PRIVATE          :: debug_this_module = .TRUE.
      39             : 
      40             :    PUBLIC :: negf_control_type, negf_control_contact_type
      41             :    PUBLIC :: negf_control_create, negf_control_release, read_negf_control
      42             : 
      43             : ! **************************************************************************************************
      44             : !> \brief Input parameters related to a single contact.
      45             : !> \author Sergey Chulkov
      46             : ! **************************************************************************************************
      47             :    TYPE negf_control_contact_type
      48             :       !> atoms belonging to bulk and screening regions
      49             :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: atomlist_bulk, atomlist_screening
      50             :       !> atom belonging to the primary and secondary bulk unit cells
      51             :       TYPE(negf_allocatable_ivector), ALLOCATABLE, &
      52             :          DIMENSION(:)                                    :: atomlist_cell
      53             :       !> index of the sub_force_env which should be used for bulk calculation
      54             :       INTEGER                                            :: force_env_index = -1
      55             :       !> contact Fermi level needs to be computed prior NEGF run
      56             :       LOGICAL                                            :: compute_fermi_level = .FALSE.
      57             :       !> when computing contact Fermi level, use the energy given in 'fermi_level' (instead of HOMO)
      58             :       !> (instead of the HOMO energy) as a starting point
      59             :       LOGICAL                                            :: refine_fermi_level = .FALSE.
      60             :       !> Fermi level
      61             :       REAL(kind=dp)                                      :: fermi_level = -1.0_dp
      62             :       !> temperature [in a.u.]
      63             :       REAL(kind=dp)                                      :: temperature = -1.0_dp
      64             :       !> applied electric potential
      65             :       REAL(kind=dp)                                      :: v_external = 0.0_dp
      66             :    END TYPE negf_control_contact_type
      67             : 
      68             : ! **************************************************************************************************
      69             : !> \brief Input parameters related to the NEGF run.
      70             : !> \author Sergey Chulkov
      71             : ! **************************************************************************************************
      72             :    TYPE negf_control_type
      73             :       !> input options for every contact
      74             :       TYPE(negf_control_contact_type), ALLOCATABLE, &
      75             :          DIMENSION(:)                                    :: contacts
      76             :       !> atoms belonging to the scattering region
      77             :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: atomlist_S
      78             :       !> atoms belonging to the scattering region as well as atoms belonging to
      79             :       !> screening regions of all the contacts
      80             :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: atomlist_S_screening
      81             :       !> do not keep contact self-energy matrices
      82             :       LOGICAL                                            :: disable_cache = .FALSE.
      83             :       !> convergence criteria for adaptive integration methods
      84             :       REAL(kind=dp)                                      :: conv_density = -1.0_dp
      85             :       !> convergence criteria for iterative Lopez-Sancho algorithm
      86             :       REAL(kind=dp)                                      :: conv_green = -1.0_dp
      87             :       !> convergence criteria for self-consistent iterations
      88             :       REAL(kind=dp)                                      :: conv_scf = -1.0_dp
      89             :       !> accuracy in mapping atoms between different force environments
      90             :       REAL(kind=dp)                                      :: eps_geometry = -1.0_dp
      91             :       !> applied bias [in a.u.]
      92             :       REAL(kind=dp)                                      :: v_bias = -1.0_dp
      93             :       !> integration lower bound [in a.u.]
      94             :       REAL(kind=dp)                                      :: energy_lbound = -1.0_dp
      95             :       !> infinitesimal offset along the imaginary axis [in a.u.]
      96             :       REAL(kind=dp)                                      :: eta = -1.0_dp
      97             :       !> initial guess to determine the actual Fermi level of bulk contacts [in a.u.]
      98             :       REAL(kind=dp)                                      :: homo_lumo_gap = -1.0_dp
      99             :       !> number of residuals (poles of the Fermi function)
     100             :       INTEGER                                            :: delta_npoles = -1
     101             :       !> offset along the x-axis away from the poles of the Fermi function [in units of kT]
     102             :       INTEGER                                            :: gamma_kT = -1
     103             :       !> integration method
     104             :       INTEGER                                            :: integr_method = -1
     105             :       !> minimal number of grid points along the closed contour
     106             :       INTEGER                                            :: integr_min_points = -1
     107             :       !> maximal number of grid points along the closed contour
     108             :       INTEGER                                            :: integr_max_points = -1
     109             :       !> maximal number of SCF iterations
     110             :       INTEGER                                            :: max_scf = -1
     111             :       !> minimal number of MPI processes to be used to compute Green's function per energy point
     112             :       INTEGER                                            :: nprocs = -1
     113             :       !> shift in Hartree potential [in a.u.]
     114             :       REAL(kind=dp)                                      :: v_shift = -1.0_dp
     115             :       !> initial offset to determine the correct shift in Hartree potential [in a.u.]
     116             :       REAL(kind=dp)                                      :: v_shift_offset = -1.0_dp
     117             :       !> maximal number of iteration to determine the shift in Hartree potential
     118             :       INTEGER                                            :: v_shift_maxiters = -1
     119             :    END TYPE negf_control_type
     120             : 
     121             :    PRIVATE :: read_negf_atomlist
     122             : 
     123             : CONTAINS
     124             : 
     125             : ! **************************************************************************************************
     126             : !> \brief allocate control options for Non-equilibrium Green's Function calculation
     127             : !> \param negf_control an object to create
     128             : !> \par History
     129             : !>    * 02.2017 created [Sergey Chulkov]
     130             : ! **************************************************************************************************
     131           8 :    SUBROUTINE negf_control_create(negf_control)
     132             :       TYPE(negf_control_type), POINTER                   :: negf_control
     133             : 
     134             :       CHARACTER(len=*), PARAMETER :: routineN = 'negf_control_create'
     135             : 
     136             :       INTEGER                                            :: handle
     137             : 
     138           4 :       CPASSERT(.NOT. ASSOCIATED(negf_control))
     139           4 :       CALL timeset(routineN, handle)
     140             : 
     141           4 :       ALLOCATE (negf_control)
     142             : 
     143           4 :       CALL timestop(handle)
     144           4 :    END SUBROUTINE negf_control_create
     145             : 
     146             : ! **************************************************************************************************
     147             : !> \brief release memory allocated for NEGF control options
     148             : !> \param negf_control an object to release
     149             : !> \par History
     150             : !>    * 02.2017 created [Sergey Chulkov]
     151             : ! **************************************************************************************************
     152           4 :    SUBROUTINE negf_control_release(negf_control)
     153             :       TYPE(negf_control_type), POINTER                   :: negf_control
     154             : 
     155             :       CHARACTER(len=*), PARAMETER :: routineN = 'negf_control_release'
     156             : 
     157             :       INTEGER                                            :: handle, i, j
     158             : 
     159           4 :       CALL timeset(routineN, handle)
     160             : 
     161           4 :       IF (ASSOCIATED(negf_control)) THEN
     162           4 :          IF (ALLOCATED(negf_control%atomlist_S)) DEALLOCATE (negf_control%atomlist_S)
     163           4 :          IF (ALLOCATED(negf_control%atomlist_S_screening)) DEALLOCATE (negf_control%atomlist_S_screening)
     164             : 
     165           4 :          IF (ALLOCATED(negf_control%contacts)) THEN
     166          12 :             DO i = SIZE(negf_control%contacts), 1, -1
     167           8 :                IF (ALLOCATED(negf_control%contacts(i)%atomlist_bulk)) &
     168           8 :                   DEALLOCATE (negf_control%contacts(i)%atomlist_bulk)
     169             : 
     170           8 :                IF (ALLOCATED(negf_control%contacts(i)%atomlist_screening)) &
     171           8 :                   DEALLOCATE (negf_control%contacts(i)%atomlist_screening)
     172             : 
     173          12 :                IF (ALLOCATED(negf_control%contacts(i)%atomlist_cell)) THEN
     174          12 :                   DO j = SIZE(negf_control%contacts(i)%atomlist_cell), 1, -1
     175           8 :                      IF (ALLOCATED(negf_control%contacts(i)%atomlist_cell(j)%vector)) &
     176          12 :                         DEALLOCATE (negf_control%contacts(i)%atomlist_cell(j)%vector)
     177             :                   END DO
     178          12 :                   DEALLOCATE (negf_control%contacts(i)%atomlist_cell)
     179             :                END IF
     180             :             END DO
     181             : 
     182          12 :             DEALLOCATE (negf_control%contacts)
     183             :          END IF
     184             : 
     185           4 :          DEALLOCATE (negf_control)
     186             :       END IF
     187             : 
     188           4 :       CALL timestop(handle)
     189           4 :    END SUBROUTINE negf_control_release
     190             : 
     191             : ! **************************************************************************************************
     192             : !> \brief Read NEGF input parameters.
     193             : !> \param negf_control NEGF control parameters
     194             : !> \param input        root input section
     195             : !> \param subsys       subsystem environment
     196             : ! **************************************************************************************************
     197           4 :    SUBROUTINE read_negf_control(negf_control, input, subsys)
     198             :       TYPE(negf_control_type), POINTER                   :: negf_control
     199             :       TYPE(section_vals_type), POINTER                   :: input
     200             :       TYPE(cp_subsys_type), POINTER                      :: subsys
     201             : 
     202             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'read_negf_control'
     203             : 
     204             :       CHARACTER(len=default_string_length) :: contact_id_str, eta_current_str, eta_max_str, &
     205             :          npoles_current_str, npoles_min_str, temp_current_str, temp_min_str
     206             :       INTEGER                                            :: delta_npoles_min, handle, i2_rep, i_rep, &
     207             :                                                             n2_rep, n_rep, natoms_current, &
     208             :                                                             natoms_total, run_type
     209           4 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: inds
     210             :       LOGICAL                                            :: do_negf, is_explicit
     211             :       REAL(kind=dp)                                      :: eta_max, temp_current, temp_min
     212             :       TYPE(section_vals_type), POINTER                   :: cell_section, contact_section, &
     213             :                                                             negf_section, region_section
     214             : 
     215           4 :       CALL timeset(routineN, handle)
     216             : 
     217           4 :       CALL section_vals_val_get(input, "GLOBAL%RUN_TYPE", i_val=run_type)
     218           4 :       do_negf = run_type == negf_run
     219             : 
     220           4 :       negf_section => section_vals_get_subs_vals(input, "NEGF")
     221             : 
     222           4 :       contact_section => section_vals_get_subs_vals(negf_section, "CONTACT")
     223           4 :       CALL section_vals_get(contact_section, n_repetition=n_rep, explicit=is_explicit)
     224           4 :       IF ((.NOT. is_explicit) .AND. do_negf) THEN
     225             :          CALL cp_abort(__LOCATION__, &
     226           0 :                        "At least one contact is needed for NEGF calculation.")
     227             :       END IF
     228             : 
     229          20 :       ALLOCATE (negf_control%contacts(n_rep))
     230          12 :       DO i_rep = 1, n_rep
     231           8 :          region_section => section_vals_get_subs_vals(contact_section, "SCREENING_REGION", i_rep_section=i_rep)
     232           8 :          CALL section_vals_get(region_section, explicit=is_explicit)
     233             : 
     234           8 :          IF ((.NOT. is_explicit) .AND. do_negf) THEN
     235           0 :             WRITE (contact_id_str, '(I11)') i_rep
     236             :             CALL cp_abort(__LOCATION__, &
     237           0 :                           "The screening region must be defined for the contact "//TRIM(ADJUSTL(contact_id_str))//".")
     238             :          END IF
     239             : 
     240           8 :          IF (is_explicit) THEN
     241           8 :             CALL read_negf_atomlist(negf_control%contacts(i_rep)%atomlist_screening, region_section, 1, subsys)
     242             :          END IF
     243             : 
     244           8 :          region_section => section_vals_get_subs_vals(contact_section, "BULK_REGION", i_rep_section=i_rep)
     245             : 
     246           8 :          CALL section_vals_get(region_section, explicit=is_explicit)
     247             : 
     248           8 :          IF ((.NOT. is_explicit) .AND. do_negf) THEN
     249           0 :             WRITE (contact_id_str, '(I11)') i_rep
     250             :             CALL cp_abort(__LOCATION__, &
     251           0 :                           "The bulk region must be defined for the contact "//TRIM(ADJUSTL(contact_id_str))//".")
     252             :          END IF
     253             : 
     254           8 :          IF (is_explicit) THEN
     255           8 :             CALL read_negf_atomlist(negf_control%contacts(i_rep)%atomlist_bulk, region_section, 1, subsys)
     256             :          END IF
     257             : 
     258             :          CALL section_vals_val_get(contact_section, "FORCE_EVAL_SECTION", &
     259             :                                    i_val=negf_control%contacts(i_rep)%force_env_index, &
     260           8 :                                    i_rep_section=i_rep)
     261             : 
     262           8 :          cell_section => section_vals_get_subs_vals(region_section, "CELL")
     263           8 :          CALL section_vals_get(cell_section, n_repetition=n2_rep, explicit=is_explicit)
     264             : 
     265           8 :          IF (((.NOT. is_explicit) .OR. n2_rep /= 2) .AND. negf_control%contacts(i_rep)%force_env_index <= 0 .AND. do_negf) THEN
     266           0 :             WRITE (contact_id_str, '(I11)') i_rep
     267             :             CALL cp_abort(__LOCATION__, &
     268             :                           "You must either provide indices of atoms belonging to two adjacent bulk unit cells "// &
     269             :                           "(BULK_REGION/CELL) for the contact, or the index of the FORCE_EVAL section (FORCE_EVAL_SECTION) "// &
     270             :                           "which will be used to construct Kohn-Sham matrix for the bulk contact "// &
     271           0 :                           TRIM(ADJUSTL(contact_id_str))//".")
     272             :          END IF
     273             : 
     274           8 :          IF (is_explicit .AND. n2_rep > 0) THEN
     275          20 :             ALLOCATE (negf_control%contacts(i_rep)%atomlist_cell(n2_rep))
     276             : 
     277          12 :             DO i2_rep = 1, n2_rep
     278          12 :                CALL read_negf_atomlist(negf_control%contacts(i_rep)%atomlist_cell(i2_rep)%vector, cell_section, i2_rep, subsys)
     279             :             END DO
     280             :          END IF
     281             : 
     282             :          CALL section_vals_val_get(contact_section, "REFINE_FERMI_LEVEL", &
     283             :                                    l_val=negf_control%contacts(i_rep)%refine_fermi_level, &
     284           8 :                                    i_rep_section=i_rep)
     285             : 
     286             :          CALL section_vals_val_get(contact_section, "FERMI_LEVEL", &
     287             :                                    r_val=negf_control%contacts(i_rep)%fermi_level, &
     288           8 :                                    i_rep_section=i_rep, explicit=is_explicit)
     289             :          negf_control%contacts(i_rep)%compute_fermi_level = (.NOT. is_explicit) .OR. &
     290           8 :                                                             negf_control%contacts(i_rep)%refine_fermi_level
     291             : 
     292           8 :          IF (do_negf .AND. negf_control%contacts(i_rep)%force_env_index <= 0 .AND. &
     293             :              (.NOT. (is_explicit .OR. negf_control%contacts(i_rep)%refine_fermi_level))) THEN
     294           0 :             WRITE (contact_id_str, '(I11)') i_rep
     295             :             CALL cp_warn(__LOCATION__, &
     296             :                          "There is no way to reasonably guess the Fermi level for the bulk contact "// &
     297             :                          TRIM(ADJUSTL(contact_id_str))//" without running a separate bulk DFT calculation first. "// &
     298             :                          "Therefore, 0.0 Hartree will be used as an initial guess. It is strongly advised to enable "// &
     299             :                          "the REFINE_FERMI_LEVEL switch and to provide an initial guess using the FERMI_LEVEL keyword. "// &
     300           0 :                          "Alternatively, a bulk FORCE_EVAL_SECTION can be set up.")
     301             :          END IF
     302             : 
     303             :          CALL section_vals_val_get(contact_section, "TEMPERATURE", &
     304             :                                    r_val=negf_control%contacts(i_rep)%temperature, &
     305           8 :                                    i_rep_section=i_rep)
     306           8 :          IF (negf_control%contacts(i_rep)%temperature <= 0.0_dp) THEN
     307           0 :             CALL cp_abort(__LOCATION__, "Electronic temperature must be > 0")
     308             :          END IF
     309             : 
     310             :          CALL section_vals_val_get(contact_section, "ELECTRIC_POTENTIAL", &
     311             :                                    r_val=negf_control%contacts(i_rep)%v_external, &
     312          44 :                                    i_rep_section=i_rep)
     313             :       END DO
     314             : 
     315           4 :       region_section => section_vals_get_subs_vals(negf_section, "SCATTERING_REGION")
     316           4 :       CALL section_vals_get(region_section, explicit=is_explicit)
     317           4 :       IF (is_explicit) THEN
     318           4 :          CALL read_negf_atomlist(negf_control%atomlist_S, region_section, 1, subsys)
     319             :       END IF
     320             : 
     321           4 :       CALL section_vals_val_get(negf_section, "DISABLE_CACHE", l_val=negf_control%disable_cache)
     322             : 
     323           4 :       CALL section_vals_val_get(negf_section, "EPS_DENSITY", r_val=negf_control%conv_density)
     324           4 :       CALL section_vals_val_get(negf_section, "EPS_GREEN", r_val=negf_control%conv_green)
     325           4 :       CALL section_vals_val_get(negf_section, "EPS_SCF", r_val=negf_control%conv_scf)
     326             : 
     327           4 :       CALL section_vals_val_get(negf_section, "EPS_GEO", r_val=negf_control%eps_geometry)
     328             : 
     329           4 :       CALL section_vals_val_get(negf_section, "ENERGY_LBOUND", r_val=negf_control%energy_lbound)
     330           4 :       CALL section_vals_val_get(negf_section, "ETA", r_val=negf_control%eta)
     331           4 :       CALL section_vals_val_get(negf_section, "HOMO_LUMO_GAP", r_val=negf_control%homo_lumo_gap)
     332           4 :       CALL section_vals_val_get(negf_section, "DELTA_NPOLES", i_val=negf_control%delta_npoles)
     333           4 :       CALL section_vals_val_get(negf_section, "GAMMA_KT", i_val=negf_control%gamma_kT)
     334             : 
     335           4 :       CALL section_vals_val_get(negf_section, "INTEGRATION_METHOD", i_val=negf_control%integr_method)
     336           4 :       CALL section_vals_val_get(negf_section, "INTEGRATION_MIN_POINTS", i_val=negf_control%integr_min_points)
     337           4 :       CALL section_vals_val_get(negf_section, "INTEGRATION_MAX_POINTS", i_val=negf_control%integr_max_points)
     338             : 
     339           4 :       IF (negf_control%integr_max_points < negf_control%integr_min_points) &
     340           0 :          negf_control%integr_max_points = negf_control%integr_min_points
     341             : 
     342           4 :       CALL section_vals_val_get(negf_section, "MAX_SCF", i_val=negf_control%max_scf)
     343             : 
     344           4 :       CALL section_vals_val_get(negf_section, "NPROC_POINT", i_val=negf_control%nprocs)
     345             : 
     346           4 :       CALL section_vals_val_get(negf_section, "V_SHIFT", r_val=negf_control%v_shift)
     347           4 :       CALL section_vals_val_get(negf_section, "V_SHIFT_OFFSET", r_val=negf_control%v_shift_offset)
     348           4 :       CALL section_vals_val_get(negf_section, "V_SHIFT_MAX_ITERS", i_val=negf_control%v_shift_maxiters)
     349             : 
     350             :       ! check consistency
     351           4 :       IF (negf_control%eta < 0.0_dp) THEN
     352           0 :          CALL cp_abort(__LOCATION__, "ETA must be >= 0")
     353             :       END IF
     354             : 
     355           4 :       IF (n_rep > 0) THEN
     356          16 :          delta_npoles_min = NINT(0.5_dp*(negf_control%eta/(pi*MAXVAL(negf_control%contacts(:)%temperature)) + 1.0_dp))
     357             :       ELSE
     358           0 :          delta_npoles_min = 1
     359             :       END IF
     360             : 
     361           4 :       IF (negf_control%delta_npoles < delta_npoles_min) THEN
     362           0 :          IF (n_rep > 0) THEN
     363           0 :             eta_max = REAL(2*negf_control%delta_npoles - 1, kind=dp)*pi*MAXVAL(negf_control%contacts(:)%temperature)
     364           0 :             temp_current = MAXVAL(negf_control%contacts(:)%temperature)*kelvin
     365           0 :             temp_min = negf_control%eta/(pi*REAL(2*negf_control%delta_npoles - 1, kind=dp))*kelvin
     366             : 
     367           0 :             WRITE (eta_current_str, '(ES11.4E2)') negf_control%eta
     368           0 :             WRITE (eta_max_str, '(ES11.4E2)') eta_max
     369           0 :             WRITE (npoles_current_str, '(I11)') negf_control%delta_npoles
     370           0 :             WRITE (npoles_min_str, '(I11)') delta_npoles_min
     371           0 :             WRITE (temp_current_str, '(F11.3)') temp_current
     372           0 :             WRITE (temp_min_str, '(F11.3)') temp_min
     373             : 
     374             :             CALL cp_abort(__LOCATION__, &
     375             :                           "Parameter DELTA_NPOLES must be at least "//TRIM(ADJUSTL(npoles_min_str))// &
     376             :                           " (instead of "//TRIM(ADJUSTL(npoles_current_str))// &
     377             :                           ") for given TEMPERATURE ("//TRIM(ADJUSTL(temp_current_str))// &
     378             :                           " K) and ETA ("//TRIM(ADJUSTL(eta_current_str))// &
     379             :                           "). Alternatively you can increase TEMPERATURE above "//TRIM(ADJUSTL(temp_min_str))// &
     380             :                           " K, or decrease ETA below "//TRIM(ADJUSTL(eta_max_str))// &
     381             :                           ". Please keep in mind that very tight ETA may result in dramatical precision loss"// &
     382           0 :                           " due to inversion of ill-conditioned matrices.")
     383             :          ELSE
     384             :             ! no leads have been defined, so calculation will abort anyway
     385           0 :             negf_control%delta_npoles = delta_npoles_min
     386             :          END IF
     387             :       END IF
     388             : 
     389             :       ! expand scattering region by adding atoms from contact screening regions
     390           4 :       n_rep = SIZE(negf_control%contacts)
     391           4 :       IF (ALLOCATED(negf_control%atomlist_S)) THEN
     392           4 :          natoms_total = SIZE(negf_control%atomlist_S)
     393             :       ELSE
     394           0 :          natoms_total = 0
     395             :       END IF
     396             : 
     397          12 :       DO i_rep = 1, n_rep
     398          12 :          IF (ALLOCATED(negf_control%contacts(i_rep)%atomlist_screening)) THEN
     399             :             IF (ALLOCATED(negf_control%contacts(i_rep)%atomlist_screening)) &
     400           8 :                natoms_total = natoms_total + SIZE(negf_control%contacts(i_rep)%atomlist_screening)
     401             :          END IF
     402             :       END DO
     403             : 
     404           4 :       IF (natoms_total > 0) THEN
     405          12 :          ALLOCATE (negf_control%atomlist_S_screening(natoms_total))
     406           4 :          IF (ALLOCATED(negf_control%atomlist_S)) THEN
     407           4 :             natoms_total = SIZE(negf_control%atomlist_S)
     408          20 :             negf_control%atomlist_S_screening(1:natoms_total) = negf_control%atomlist_S(1:natoms_total)
     409             :          ELSE
     410           0 :             natoms_total = 0
     411             :          END IF
     412             : 
     413          12 :          DO i_rep = 1, n_rep
     414          12 :             IF (ALLOCATED(negf_control%contacts(i_rep)%atomlist_screening)) THEN
     415           8 :                natoms_current = SIZE(negf_control%contacts(i_rep)%atomlist_screening)
     416             : 
     417             :                negf_control%atomlist_S_screening(natoms_total + 1:natoms_total + natoms_current) = &
     418          40 :                   negf_control%contacts(i_rep)%atomlist_screening(1:natoms_current)
     419             : 
     420           8 :                natoms_total = natoms_total + natoms_current
     421             :             END IF
     422             :          END DO
     423             : 
     424             :          ! sort and remove duplicated atoms
     425          12 :          ALLOCATE (inds(natoms_total))
     426           4 :          CALL sort(negf_control%atomlist_S_screening, natoms_total, inds)
     427           4 :          DEALLOCATE (inds)
     428             : 
     429           4 :          natoms_current = 1
     430          48 :          DO i_rep = natoms_current + 1, natoms_total
     431          48 :             IF (negf_control%atomlist_S_screening(i_rep) /= negf_control%atomlist_S_screening(natoms_current)) THEN
     432          44 :                natoms_current = natoms_current + 1
     433          44 :                negf_control%atomlist_S_screening(natoms_current) = negf_control%atomlist_S_screening(i_rep)
     434             :             END IF
     435             :          END DO
     436             : 
     437           4 :          IF (natoms_current < natoms_total) THEN
     438           0 :             CALL MOVE_ALLOC(negf_control%atomlist_S_screening, inds)
     439             : 
     440           0 :             ALLOCATE (negf_control%atomlist_S_screening(natoms_current))
     441           0 :             negf_control%atomlist_S_screening(1:natoms_current) = inds(1:natoms_current)
     442           0 :             DEALLOCATE (inds)
     443             :          END IF
     444             :       END IF
     445             : 
     446           4 :       IF (do_negf .AND. SIZE(negf_control%contacts) > 2) THEN
     447             :          CALL cp_abort(__LOCATION__, &
     448           0 :                        "General case (> 2 contacts) has not been implemented yet")
     449             :       END IF
     450             : 
     451           4 :       CALL timestop(handle)
     452          12 :    END SUBROUTINE read_negf_control
     453             : 
     454             : ! **************************************************************************************************
     455             : !> \brief Read region-specific list of atoms.
     456             : !> \param atomlist        list of atoms
     457             : !> \param input_section   input section which contains 'LIST' and 'MOLNAME' keywords
     458             : !> \param i_rep_section   repetition index of the input_section
     459             : !> \param subsys          subsystem environment
     460             : ! **************************************************************************************************
     461          28 :    SUBROUTINE read_negf_atomlist(atomlist, input_section, i_rep_section, subsys)
     462             :       INTEGER, ALLOCATABLE, DIMENSION(:), INTENT(out)    :: atomlist
     463             :       TYPE(section_vals_type), POINTER                   :: input_section
     464             :       INTEGER, INTENT(in)                                :: i_rep_section
     465             :       TYPE(cp_subsys_type), POINTER                      :: subsys
     466             : 
     467             :       CHARACTER(len=*), PARAMETER :: routineN = 'read_negf_atomlist'
     468             : 
     469             :       CHARACTER(len=default_string_length)               :: index_str, natoms_str
     470             :       CHARACTER(len=default_string_length), &
     471          28 :          DIMENSION(:), POINTER                           :: cptr
     472             :       INTEGER :: first_atom, handle, iatom, ikind, imol, iname, irep, last_atom, natoms_current, &
     473             :          natoms_max, natoms_total, nkinds, nmols, nnames, nrep_list, nrep_molname
     474          28 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: inds
     475          28 :       INTEGER, DIMENSION(:), POINTER                     :: iptr
     476             :       LOGICAL                                            :: is_list, is_molname
     477          28 :       TYPE(molecule_kind_type), DIMENSION(:), POINTER    :: molecule_kind_set
     478             :       TYPE(molecule_kind_type), POINTER                  :: molecule_kind
     479          28 :       TYPE(molecule_type), DIMENSION(:), POINTER         :: molecule_set
     480             :       TYPE(molecule_type), POINTER                       :: molecule
     481          28 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     482             : 
     483          28 :       CALL timeset(routineN, handle)
     484             : 
     485             :       CALL cp_subsys_get(subsys, particle_set=particle_set, &
     486             :                          molecule_set=molecule_set, &
     487          28 :                          molecule_kind_set=molecule_kind_set)
     488          28 :       natoms_max = SIZE(particle_set)
     489          28 :       nkinds = SIZE(molecule_kind_set)
     490             : 
     491             :       CALL section_vals_val_get(input_section, "LIST", i_rep_section=i_rep_section, &
     492          28 :                                 n_rep_val=nrep_list, explicit=is_list)
     493             :       CALL section_vals_val_get(input_section, "MOLNAME", i_rep_section=i_rep_section, &
     494          28 :                                 n_rep_val=nrep_molname, explicit=is_molname)
     495             : 
     496             :       ! compute the number of atoms in the NEGF region, and check the validity of giben atomic indices
     497          28 :       natoms_total = 0
     498          28 :       IF (is_list .AND. nrep_list > 0) THEN
     499           0 :          DO irep = 1, nrep_list
     500           0 :             CALL section_vals_val_get(input_section, "LIST", i_rep_section=i_rep_section, i_rep_val=irep, i_vals=iptr)
     501             : 
     502           0 :             natoms_current = SIZE(iptr)
     503           0 :             DO iatom = 1, natoms_current
     504           0 :                IF (iptr(iatom) > natoms_max) THEN
     505           0 :                   CALL integer_to_string(iptr(iatom), index_str)
     506           0 :                   CALL integer_to_string(natoms_max, natoms_str)
     507             :                   CALL cp_abort(__LOCATION__, &
     508             :                                 "NEGF: Atomic index "//TRIM(index_str)//" given in section "// &
     509             :                                 TRIM(input_section%section%name)//" exceeds the maximum number of atoms ("// &
     510           0 :                                 TRIM(natoms_str)//").")
     511             :                END IF
     512             :             END DO
     513             : 
     514           0 :             natoms_total = natoms_total + natoms_current
     515             :          END DO
     516             :       END IF
     517             : 
     518          28 :       IF (is_molname .AND. nrep_molname > 0) THEN
     519          56 :          DO irep = 1, nrep_molname
     520          28 :             CALL section_vals_val_get(input_section, "MOLNAME", i_rep_section=i_rep_section, i_rep_val=irep, c_vals=cptr)
     521          28 :             nnames = SIZE(cptr)
     522             : 
     523          92 :             DO iname = 1, nnames
     524         144 :                DO ikind = 1, nkinds
     525         144 :                   IF (molecule_kind_set(ikind)%name .EQ. cptr(iname)) EXIT
     526             :                END DO
     527             : 
     528          64 :                IF (ikind <= nkinds) THEN
     529          36 :                   molecule_kind => molecule_kind_set(ikind)
     530          36 :                   CALL get_molecule_kind(molecule_kind, nmolecule=nmols, molecule_list=iptr)
     531             : 
     532         180 :                   DO imol = 1, nmols
     533         144 :                      molecule => molecule_set(iptr(imol))
     534         144 :                      CALL get_molecule(molecule, first_atom=first_atom, last_atom=last_atom)
     535         144 :                      natoms_current = last_atom - first_atom + 1
     536         180 :                      natoms_total = natoms_total + natoms_current
     537             :                   END DO
     538             :                ELSE
     539             :                   CALL cp_abort(__LOCATION__, &
     540             :                                 "NEGF: A molecule with the name '"//TRIM(cptr(iname))//"' mentioned in section "// &
     541           0 :                                 TRIM(input_section%section%name)//" has not been defined. Note that names are case sensitive.")
     542             :                END IF
     543             :             END DO
     544             :          END DO
     545             :       END IF
     546             : 
     547             :       ! create a list of atomic indices
     548          28 :       IF (natoms_total > 0) THEN
     549          84 :          ALLOCATE (atomlist(natoms_total))
     550             : 
     551          28 :          natoms_total = 0
     552             : 
     553          28 :          IF (is_list .AND. nrep_list > 0) THEN
     554           0 :             DO irep = 1, nrep_list
     555           0 :                CALL section_vals_val_get(input_section, "LIST", i_rep_section=i_rep_section, i_rep_val=irep, i_vals=iptr)
     556             : 
     557           0 :                natoms_current = SIZE(iptr)
     558           0 :                atomlist(natoms_total + 1:natoms_total + natoms_current) = iptr(1:natoms_current)
     559           0 :                natoms_total = natoms_total + natoms_current
     560             :             END DO
     561             :          END IF
     562             : 
     563          28 :          IF (is_molname .AND. nrep_molname > 0) THEN
     564          56 :             DO irep = 1, nrep_molname
     565          28 :                CALL section_vals_val_get(input_section, "MOLNAME", i_rep_section=i_rep_section, i_rep_val=irep, c_vals=cptr)
     566          28 :                nnames = SIZE(cptr)
     567             : 
     568          92 :                DO iname = 1, nnames
     569         144 :                   DO ikind = 1, nkinds
     570         144 :                      IF (molecule_kind_set(ikind)%name .EQ. cptr(iname)) EXIT
     571             :                   END DO
     572             : 
     573          64 :                   IF (ikind <= nkinds) THEN
     574          36 :                      molecule_kind => molecule_kind_set(ikind)
     575          36 :                      CALL get_molecule_kind(molecule_kind, nmolecule=nmols, molecule_list=iptr)
     576             : 
     577         180 :                      DO imol = 1, nmols
     578         144 :                         molecule => molecule_set(iptr(imol))
     579         144 :                         CALL get_molecule(molecule, first_atom=first_atom, last_atom=last_atom)
     580             : 
     581         324 :                         DO natoms_current = first_atom, last_atom
     582         144 :                            natoms_total = natoms_total + 1
     583         288 :                            atomlist(natoms_total) = natoms_current
     584             :                         END DO
     585             :                      END DO
     586             :                   END IF
     587             :                END DO
     588             :             END DO
     589             :          END IF
     590             : 
     591             :          ! remove duplicated atoms
     592          84 :          ALLOCATE (inds(natoms_total))
     593          28 :          CALL sort(atomlist, natoms_total, inds)
     594          28 :          DEALLOCATE (inds)
     595             : 
     596          28 :          natoms_current = 1
     597         144 :          DO iatom = natoms_current + 1, natoms_total
     598         144 :             IF (atomlist(iatom) /= atomlist(natoms_current)) THEN
     599         116 :                natoms_current = natoms_current + 1
     600         116 :                atomlist(natoms_current) = atomlist(iatom)
     601             :             END IF
     602             :          END DO
     603             : 
     604          28 :          IF (natoms_current < natoms_total) THEN
     605           0 :             CALL MOVE_ALLOC(atomlist, inds)
     606             : 
     607           0 :             ALLOCATE (atomlist(natoms_current))
     608           0 :             atomlist(1:natoms_current) = inds(1:natoms_current)
     609           0 :             DEALLOCATE (inds)
     610             :          END IF
     611             :       END IF
     612             : 
     613          28 :       CALL timestop(handle)
     614          28 :    END SUBROUTINE read_negf_atomlist
     615           0 : END MODULE negf_control_types

Generated by: LCOV version 1.15