LCOV - code coverage report
Current view: top level - src - pexsi_methods.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:b4bd748) Lines: 0 190 0.0 %
Date: 2025-03-09 07:56:22 Functions: 0 6 0.0 %

          Line data    Source code
       1             : !--------------------------------------------------------------------------------------------------!
       2             : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3             : !   Copyright 2000-2025 CP2K developers group <https://cp2k.org>                                   !
       4             : !                                                                                                  !
       5             : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6             : !--------------------------------------------------------------------------------------------------!
       7             : 
       8             : ! **************************************************************************************************
       9             : !> \brief Methods using the PEXSI library to calculate the density matrix and
      10             : !>        related quantities using the Kohn-Sham and overlap matrices from the
      11             : !>        linear scaling quickstep SCF environment.
      12             : !> \par History
      13             : !>       2014.11 created [Patrick Seewald]
      14             : !> \author Patrick Seewald
      15             : ! **************************************************************************************************
      16             : 
      17             : MODULE pexsi_methods
      18             :    USE arnoldi_api,                     ONLY: arnoldi_env_type,&
      19             :                                               arnoldi_ev,&
      20             :                                               deallocate_arnoldi_env,&
      21             :                                               get_selected_ritz_val,&
      22             :                                               get_selected_ritz_vector,&
      23             :                                               set_arnoldi_initial_vector,&
      24             :                                               setup_arnoldi_env
      25             :    USE cp_dbcsr_api,                    ONLY: &
      26             :         dbcsr_convert_csr_to_dbcsr, dbcsr_convert_dbcsr_to_csr, dbcsr_copy, dbcsr_create, &
      27             :         dbcsr_csr_create, dbcsr_csr_create_from_dbcsr, dbcsr_csr_destroy, &
      28             :         dbcsr_csr_eqrow_floor_dist, dbcsr_csr_print_sparsity, dbcsr_csr_type_real_8, &
      29             :         dbcsr_desymmetrize, dbcsr_distribution_get, dbcsr_distribution_type, dbcsr_get_info, &
      30             :         dbcsr_has_symmetry, dbcsr_p_type, dbcsr_release, dbcsr_scale, dbcsr_set, dbcsr_type, &
      31             :         dbcsr_type_no_symmetry
      32             :    USE cp_dbcsr_cp2k_link,              ONLY: cp_dbcsr_to_csr_screening
      33             :    USE cp_dbcsr_operations,             ONLY: dbcsr_allocate_matrix_set
      34             :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      35             :                                               cp_logger_get_default_unit_nr,&
      36             :                                               cp_logger_type
      37             :    USE dm_ls_scf_qs,                    ONLY: matrix_ls_to_qs
      38             :    USE dm_ls_scf_types,                 ONLY: ls_scf_env_type
      39             :    USE input_section_types,             ONLY: section_vals_type,&
      40             :                                               section_vals_val_get
      41             :    USE kinds,                           ONLY: dp,&
      42             :                                               int_4,&
      43             :                                               int_8
      44             :    USE pexsi_interface,                 ONLY: cp_pexsi_dft_driver,&
      45             :                                               cp_pexsi_get_options,&
      46             :                                               cp_pexsi_load_real_hs_matrix,&
      47             :                                               cp_pexsi_retrieve_real_dft_matrix,&
      48             :                                               cp_pexsi_set_default_options,&
      49             :                                               cp_pexsi_set_options
      50             :    USE pexsi_types,                     ONLY: convert_nspin_cp2k_pexsi,&
      51             :                                               cp2k_to_pexsi,&
      52             :                                               lib_pexsi_env,&
      53             :                                               pexsi_to_cp2k
      54             :    USE qs_energy_types,                 ONLY: qs_energy_type
      55             :    USE qs_environment_types,            ONLY: get_qs_env,&
      56             :                                               qs_environment_type
      57             :    USE qs_ks_types,                     ONLY: qs_ks_env_type
      58             : #include "./base/base_uses.f90"
      59             : 
      60             :    IMPLICIT NONE
      61             :    PRIVATE
      62             : 
      63             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'pexsi_methods'
      64             : 
      65             :    LOGICAL, PARAMETER, PRIVATE          :: careful_mod = .FALSE.
      66             : 
      67             :    PUBLIC :: density_matrix_pexsi, pexsi_init_read_input, pexsi_to_qs, pexsi_init_scf, pexsi_finalize_scf, &
      68             :              pexsi_set_convergence_tolerance
      69             : 
      70             : CONTAINS
      71             : 
      72             : ! **************************************************************************************************
      73             : !> \brief Read CP2K input section PEXSI and pass it to the PEXSI environment
      74             : !> \param pexsi_section ...
      75             : !> \param pexsi_env ...
      76             : !> \par History
      77             : !>      11.2014 created [Patrick Seewald]
      78             : !> \author Patrick Seewald
      79             : ! **************************************************************************************************
      80           0 :    SUBROUTINE pexsi_init_read_input(pexsi_section, pexsi_env)
      81             :       TYPE(section_vals_type), INTENT(IN), POINTER       :: pexsi_section
      82             :       TYPE(lib_pexsi_env), INTENT(INOUT)                 :: pexsi_env
      83             : 
      84             :       INTEGER                                            :: isInertiaCount_int, maxPEXSIIter, &
      85             :                                                             min_ranks_per_pole, npSymbFact, &
      86             :                                                             numPole, ordering, rowOrdering, &
      87             :                                                             verbosity
      88             :       LOGICAL                                            :: csr_screening, isInertiaCount
      89             :       REAL(KIND=dp) :: gap, muInertiaExpansion, muInertiaTolerance, muMax0, muMin0, &
      90             :          muPEXSISafeGuard, numElectronInitialTolerance, numElectronTargetTolerance, temperature
      91             : 
      92             : ! Note: omitting the following PEXSI options: deltaE (estimated by Arnoldi
      93             : ! before invoking PEXSI), mu0 (taken from previous SCF step), matrixType
      94             : ! (not implemented in PEXSI yet), isSymbolicFactorize (not needed because
      95             : ! of fixed sparsity pattern)
      96             : 
      97             :       CALL section_vals_val_get(pexsi_section, "TEMPERATURE", &
      98           0 :                                 r_val=temperature)
      99             :       CALL section_vals_val_get(pexsi_section, "GAP", &
     100           0 :                                 r_val=gap)
     101             :       CALL section_vals_val_get(pexsi_section, "NUM_POLE", &
     102           0 :                                 i_val=numPole)
     103             :       CALL section_vals_val_get(pexsi_section, "IS_INERTIA_COUNT", &
     104           0 :                                 l_val=isInertiaCount)
     105             :       CALL section_vals_val_get(pexsi_section, "MAX_PEXSI_ITER", &
     106           0 :                                 i_val=maxPEXSIIter)
     107             :       CALL section_vals_val_get(pexsi_section, "MU_MIN_0", &
     108           0 :                                 r_val=muMin0)
     109             :       CALL section_vals_val_get(pexsi_section, "MU_MAX_0", &
     110           0 :                                 r_val=muMax0)
     111             :       CALL section_vals_val_get(pexsi_section, "MU_INERTIA_TOLERANCE", &
     112           0 :                                 r_val=muInertiaTolerance)
     113             :       CALL section_vals_val_get(pexsi_section, "MU_INERTIA_EXPANSION", &
     114           0 :                                 r_val=muInertiaExpansion)
     115             :       CALL section_vals_val_get(pexsi_section, "MU_PEXSI_SAFE_GUARD", &
     116           0 :                                 r_val=muPEXSISafeGuard)
     117             :       CALL section_vals_val_get(pexsi_section, "NUM_ELECTRON_INITIAL_TOLERANCE", &
     118           0 :                                 r_val=numElectronInitialTolerance)
     119             :       CALL section_vals_val_get(pexsi_section, "NUM_ELECTRON_PEXSI_TOLERANCE", &
     120           0 :                                 r_val=numElectronTargetTolerance)
     121             :       CALL section_vals_val_get(pexsi_section, "ORDERING", &
     122           0 :                                 i_val=ordering)
     123             :       CALL section_vals_val_get(pexsi_section, "ROW_ORDERING", &
     124           0 :                                 i_val=rowOrdering)
     125             :       CALL section_vals_val_get(pexsi_section, "NP_SYMB_FACT", &
     126           0 :                                 i_val=npSymbFact)
     127             :       CALL section_vals_val_get(pexsi_section, "VERBOSITY", &
     128           0 :                                 i_val=verbosity)
     129             :       CALL section_vals_val_get(pexsi_section, "MIN_RANKS_PER_POLE", &
     130           0 :                                 i_val=min_ranks_per_pole)
     131             :       CALL section_vals_val_get(pexsi_section, "CSR_SCREENING", &
     132           0 :                                 l_val=csr_screening)
     133             : 
     134           0 :       isInertiaCount_int = MERGE(1, 0, isInertiaCount) ! is integer in PEXSI
     135             : 
     136             :       ! Set default options inside PEXSI
     137           0 :       CALL cp_pexsi_set_default_options(pexsi_env%options)
     138             : 
     139             :       ! Pass CP2K input to PEXSI options
     140             :       CALL cp_pexsi_set_options(pexsi_env%options, temperature=temperature, gap=gap, &
     141             :                                 numPole=numPole, isInertiaCount=isInertiaCount_int, maxPEXSIIter=maxPEXSIIter, &
     142             :                                 muMin0=muMin0, muMax0=muMax0, muInertiaTolerance=muInertiaTolerance, &
     143             :                                 muInertiaExpansion=muInertiaExpansion, muPEXSISafeGuard=muPEXSISafeGuard, &
     144           0 :                                 ordering=ordering, rowOrdering=rowOrdering, npSymbFact=npSymbFact, verbosity=verbosity)
     145             : 
     146           0 :       pexsi_env%num_ranks_per_pole = min_ranks_per_pole ! not a PEXSI option
     147           0 :       pexsi_env%csr_screening = csr_screening
     148             : 
     149           0 :       IF (numElectronInitialTolerance .LT. numElectronTargetTolerance) &
     150           0 :          numElectronInitialTolerance = numElectronTargetTolerance
     151             : 
     152           0 :       pexsi_env%tol_nel_initial = numElectronInitialTolerance
     153           0 :       pexsi_env%tol_nel_target = numElectronTargetTolerance
     154             : 
     155           0 :    END SUBROUTINE pexsi_init_read_input
     156             : 
     157             : ! **************************************************************************************************
     158             : !> \brief Initializations needed before SCF
     159             : !> \param ks_env ...
     160             : !> \param pexsi_env ...
     161             : !> \param template_matrix DBCSR matrix that defines the block structure and
     162             : !>        sparsity pattern of all matrices that are sent to PEXSI
     163             : ! **************************************************************************************************
     164           0 :    SUBROUTINE pexsi_init_scf(ks_env, pexsi_env, template_matrix)
     165             :       TYPE(qs_ks_env_type), POINTER                      :: ks_env
     166             :       TYPE(lib_pexsi_env), INTENT(INOUT)                 :: pexsi_env
     167             :       TYPE(dbcsr_type), INTENT(IN)                       :: template_matrix
     168             : 
     169             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'pexsi_init_scf'
     170             : 
     171             :       INTEGER                                            :: handle, ispin, unit_nr
     172             :       TYPE(cp_logger_type), POINTER                      :: logger
     173             : 
     174           0 :       CALL timeset(routineN, handle)
     175             : 
     176           0 :       logger => cp_get_default_logger()
     177           0 :       IF (logger%para_env%is_source()) THEN
     178           0 :          unit_nr = cp_logger_get_default_unit_nr(logger, local=.TRUE.)
     179             :       ELSE
     180           0 :          unit_nr = -1
     181             :       END IF
     182             : 
     183             :       ! Create template matrices fixing sparsity pattern for PEXSI
     184             : 
     185           0 :       IF (dbcsr_has_symmetry(template_matrix)) THEN
     186             :          CALL dbcsr_copy(pexsi_env%dbcsr_template_matrix_sym, template_matrix, &
     187           0 :                          "symmetric template matrix for CSR conversion")
     188             :          CALL dbcsr_desymmetrize(pexsi_env%dbcsr_template_matrix_sym, &
     189           0 :                                  pexsi_env%dbcsr_template_matrix_nonsym)
     190             :       ELSE
     191             :          CALL dbcsr_copy(pexsi_env%dbcsr_template_matrix_nonsym, template_matrix, &
     192           0 :                          "non-symmetric template matrix for CSR conversion")
     193             :          CALL dbcsr_copy(pexsi_env%dbcsr_template_matrix_sym, template_matrix, &
     194           0 :                          "symmetric template matrix for CSR conversion")
     195             :       END IF
     196             : 
     197             :       CALL dbcsr_create(pexsi_env%csr_sparsity, "CSR sparsity", &
     198           0 :                         template=pexsi_env%dbcsr_template_matrix_sym)
     199           0 :       CALL dbcsr_copy(pexsi_env%csr_sparsity, pexsi_env%dbcsr_template_matrix_sym)
     200             : 
     201           0 :       CALL cp_dbcsr_to_csr_screening(ks_env, pexsi_env%csr_sparsity)
     202             : 
     203           0 :       IF (.NOT. pexsi_env%csr_screening) CALL dbcsr_set(pexsi_env%csr_sparsity, 1.0_dp)
     204             :       CALL dbcsr_csr_create_from_dbcsr(pexsi_env%dbcsr_template_matrix_nonsym, &
     205             :                                        pexsi_env%csr_mat_s, &
     206             :                                        dbcsr_csr_eqrow_floor_dist, &
     207             :                                        csr_sparsity=pexsi_env%csr_sparsity, &
     208           0 :                                        numnodes=pexsi_env%num_ranks_per_pole)
     209             : 
     210           0 :       IF (unit_nr > 0) WRITE (unit_nr, "(/T2,A)") "SPARSITY OF THE OVERLAP MATRIX IN CSR FORMAT"
     211           0 :       CALL dbcsr_csr_print_sparsity(pexsi_env%csr_mat_s, unit_nr)
     212             : 
     213           0 :       CALL dbcsr_convert_dbcsr_to_csr(pexsi_env%dbcsr_template_matrix_nonsym, pexsi_env%csr_mat_s)
     214             : 
     215           0 :       CALL dbcsr_csr_create(pexsi_env%csr_mat_ks, pexsi_env%csr_mat_s)
     216           0 :       CALL dbcsr_csr_create(pexsi_env%csr_mat_p, pexsi_env%csr_mat_s)
     217           0 :       CALL dbcsr_csr_create(pexsi_env%csr_mat_E, pexsi_env%csr_mat_s)
     218           0 :       CALL dbcsr_csr_create(pexsi_env%csr_mat_F, pexsi_env%csr_mat_s)
     219             : 
     220           0 :       DO ispin = 1, pexsi_env%nspin
     221             :          ! max_ev_vector only initialised to avoid warning in case max_scf==0
     222             :          CALL dbcsr_create(pexsi_env%matrix_w(ispin)%matrix, "W matrix", &
     223           0 :                            template=template_matrix, matrix_type=dbcsr_type_no_symmetry)
     224             :       END DO
     225             : 
     226           0 :       CALL cp_pexsi_set_options(pexsi_env%options, numElectronPEXSITolerance=pexsi_env%tol_nel_initial)
     227             : 
     228           0 :       CALL timestop(handle)
     229             : 
     230           0 :    END SUBROUTINE pexsi_init_scf
     231             : 
     232             : ! **************************************************************************************************
     233             : !> \brief Deallocations and post-processing after SCF
     234             : !> \param pexsi_env ...
     235             : !> \param mu_spin ...
     236             : ! **************************************************************************************************
     237           0 :    SUBROUTINE pexsi_finalize_scf(pexsi_env, mu_spin)
     238             :       TYPE(lib_pexsi_env), INTENT(INOUT)                 :: pexsi_env
     239             :       REAL(KIND=dp), DIMENSION(2), INTENT(IN)            :: mu_spin
     240             : 
     241             :       CHARACTER(len=*), PARAMETER :: routineN = 'pexsi_finalize_scf'
     242             : 
     243             :       INTEGER                                            :: handle, ispin, unit_nr
     244             :       REAL(KIND=dp)                                      :: kTS_total, mu_total
     245             :       TYPE(cp_logger_type), POINTER                      :: logger
     246             : 
     247           0 :       CALL timeset(routineN, handle)
     248             : 
     249           0 :       logger => cp_get_default_logger()
     250           0 :       IF (logger%para_env%is_source()) THEN
     251           0 :          unit_nr = cp_logger_get_default_unit_nr(logger, local=.TRUE.)
     252             :       ELSE
     253             :          unit_nr = -1
     254             :       END IF
     255             : 
     256           0 :       mu_total = SUM(mu_spin(1:pexsi_env%nspin))/REAL(pexsi_env%nspin, KIND=dp)
     257           0 :       kTS_total = SUM(pexsi_env%kTS)
     258           0 :       IF (pexsi_env%nspin .EQ. 1) kTS_total = kTS_total*2.0_dp
     259             : 
     260           0 :       IF (unit_nr > 0) THEN
     261             :          WRITE (unit_nr, "(/A,T55,F26.15)") &
     262           0 :             " PEXSI| Electronic entropic energy (a.u.):", kTS_total
     263             :          WRITE (unit_nr, "(A,T55,F26.15)") &
     264           0 :             " PEXSI| Chemical potential (a.u.):", mu_total
     265             :       END IF
     266             : 
     267           0 :       CALL dbcsr_release(pexsi_env%dbcsr_template_matrix_sym)
     268           0 :       CALL dbcsr_release(pexsi_env%dbcsr_template_matrix_nonsym)
     269           0 :       CALL dbcsr_release(pexsi_env%csr_sparsity)
     270           0 :       CALL dbcsr_csr_destroy(pexsi_env%csr_mat_p)
     271           0 :       CALL dbcsr_csr_destroy(pexsi_env%csr_mat_ks)
     272           0 :       CALL dbcsr_csr_destroy(pexsi_env%csr_mat_s)
     273           0 :       CALL dbcsr_csr_destroy(pexsi_env%csr_mat_E)
     274           0 :       CALL dbcsr_csr_destroy(pexsi_env%csr_mat_F)
     275           0 :       DO ispin = 1, pexsi_env%nspin
     276           0 :          CALL dbcsr_release(pexsi_env%max_ev_vector(ispin))
     277           0 :          CALL dbcsr_release(pexsi_env%matrix_w(ispin)%matrix)
     278             :       END DO
     279           0 :       CALL timestop(handle)
     280           0 :       pexsi_env%tol_nel_initial = pexsi_env%tol_nel_target ! Turn off adaptive threshold for subsequent SCF cycles
     281           0 :    END SUBROUTINE pexsi_finalize_scf
     282             : 
     283             : ! **************************************************************************************************
     284             : !> \brief Calculate density matrix, energy-weighted density matrix and entropic
     285             : !>        energy contribution with the DFT driver of the PEXSI library.
     286             : !> \param[in,out] pexsi_env     PEXSI environment
     287             : !> \param[in,out] matrix_p      density matrix returned by PEXSI
     288             : !> \param[in,out] matrix_w      energy-weighted density matrix returned by PEXSI
     289             : !> \param[out] kTS              entropic energy contribution returned by PEXSI
     290             : !> \param[in] matrix_ks         Kohn-Sham matrix from linear scaling QS environment
     291             : !> \param[in] matrix_s          overlap matrix from linear scaling QS environment
     292             : !> \param[in] nelectron_exact   exact number of electrons
     293             : !> \param[out] mu               chemical potential calculated by PEXSI
     294             : !> \param[in] iscf              SCF step
     295             : !> \param[in] ispin             Number of spin
     296             : !> \par History
     297             : !>      11.2014 created [Patrick Seewald]
     298             : !> \author Patrick Seewald
     299             : ! **************************************************************************************************
     300           0 :    SUBROUTINE density_matrix_pexsi(pexsi_env, matrix_p, matrix_w, kTS, matrix_ks, matrix_s, &
     301             :                                    nelectron_exact, mu, iscf, ispin)
     302             :       TYPE(lib_pexsi_env), INTENT(INOUT)                 :: pexsi_env
     303             :       TYPE(dbcsr_type), INTENT(INOUT)                    :: matrix_p
     304             :       TYPE(dbcsr_p_type), INTENT(INOUT)                  :: matrix_w
     305             :       REAL(KIND=dp), INTENT(OUT)                         :: kTS
     306             :       TYPE(dbcsr_type), INTENT(IN), TARGET               :: matrix_ks, matrix_s
     307             :       INTEGER, INTENT(IN)                                :: nelectron_exact
     308             :       REAL(KIND=dp), INTENT(OUT)                         :: mu
     309             :       INTEGER, INTENT(IN)                                :: iscf, ispin
     310             : 
     311             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'density_matrix_pexsi'
     312             :       INTEGER, PARAMETER                                 :: S_not_identity = 0
     313             : 
     314             :       INTEGER :: handle, is_symbolic_factorize, isInertiaCount, isInertiaCount_out, mynode, &
     315             :          n_total_inertia_iter, n_total_pexsi_iter, unit_nr
     316             :       LOGICAL                                            :: first_call, pexsi_convergence
     317             :       REAL(KIND=dp) :: delta_E, energy_H, energy_S, free_energy, mu_max_in, mu_max_out, mu_min_in, &
     318             :          mu_min_out, nel_tol, nelectron_diff, nelectron_exact_pexsi, nelectron_out
     319             :       TYPE(arnoldi_env_type)                             :: arnoldi_env
     320             :       TYPE(cp_logger_type), POINTER                      :: logger
     321             :       TYPE(dbcsr_distribution_type)                      :: dist
     322           0 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: arnoldi_matrices
     323             : 
     324           0 :       CALL timeset(routineN, handle)
     325             : 
     326             :       ! get a useful output_unit
     327           0 :       logger => cp_get_default_logger()
     328           0 :       IF (logger%para_env%is_source()) THEN
     329           0 :          unit_nr = cp_logger_get_default_unit_nr(logger, local=.TRUE.)
     330             :       ELSE
     331             :          unit_nr = -1
     332             :       END IF
     333             : 
     334           0 :       first_call = (iscf .EQ. 1) .AND. (ispin .EQ. 1)
     335             : 
     336             :       ! Assert a few things the first time PEXSI is called
     337             :       IF (first_call) THEN
     338             :          ! Assertion that matrices have the expected symmetry (both should be symmetric if no
     339             :          ! S preconditioning and no molecular clustering)
     340           0 :          IF (.NOT. dbcsr_has_symmetry(matrix_ks)) &
     341           0 :             CPABORT("PEXSI interface expects a non-symmetric DBCSR Kohn-Sham matrix")
     342           0 :          IF (.NOT. dbcsr_has_symmetry(matrix_s)) &
     343           0 :             CPABORT("PEXSI interface expects a non-symmetric DBCSR overlap matrix")
     344             : 
     345             :          ! Assertion on datatype
     346             :          IF ((pexsi_env%csr_mat_s%nzval_local%data_type .NE. dbcsr_csr_type_real_8) &
     347           0 :              .OR. (pexsi_env%csr_mat_ks%nzval_local%data_type .NE. dbcsr_csr_type_real_8)) &
     348           0 :             CPABORT("Complex data type not supported by PEXSI")
     349             : 
     350             :          ! Assertion on number of non-zero elements
     351             :          !(TODO: update when PEXSI changes to Long Int)
     352           0 :          IF (pexsi_env%csr_mat_s%nze_total .GE. INT(2, kind=int_8)**31) &
     353           0 :             CPABORT("Total number of non-zero elements of CSR matrix is too large to be handled by PEXSI")
     354             :       END IF
     355             : 
     356           0 :       CALL dbcsr_get_info(matrix_ks, distribution=dist)
     357           0 :       CALL dbcsr_distribution_get(dist, mynode=mynode)
     358             : 
     359             :       ! Convert DBCSR matrices to PEXSI CSR format. Intermediate step to template matrix
     360             :       ! needed in order to retain the initial sparsity pattern that is required for the
     361             :       ! conversion to CSR format.
     362           0 :       CALL dbcsr_copy(pexsi_env%dbcsr_template_matrix_sym, matrix_s, keep_sparsity=.TRUE.)
     363             :       CALL dbcsr_convert_dbcsr_to_csr(pexsi_env%dbcsr_template_matrix_sym, &
     364           0 :                                       pexsi_env%csr_mat_s)
     365             : 
     366           0 :       CALL dbcsr_copy(pexsi_env%dbcsr_template_matrix_sym, matrix_ks, keep_sparsity=.TRUE.)
     367             :       CALL dbcsr_convert_dbcsr_to_csr(pexsi_env%dbcsr_template_matrix_sym, &
     368           0 :                                       pexsi_env%csr_mat_ks)
     369             : 
     370             :       ! Get PEXSI input delta_E (upper bound for largest eigenvalue) using Arnoldi
     371           0 :       NULLIFY (arnoldi_matrices)
     372           0 :       CALL dbcsr_allocate_matrix_set(arnoldi_matrices, 2)
     373           0 :       arnoldi_matrices(1)%matrix => matrix_ks
     374           0 :       arnoldi_matrices(2)%matrix => matrix_s
     375             :       CALL setup_arnoldi_env(arnoldi_env, arnoldi_matrices, max_iter=20, &
     376             :                              threshold=1.0E-2_dp, selection_crit=2, nval_request=1, nrestarts=21, &
     377           0 :                              generalized_ev=.TRUE., iram=.FALSE.)
     378           0 :       IF (iscf .GT. 1) CALL set_arnoldi_initial_vector(arnoldi_env, pexsi_env%max_ev_vector(ispin))
     379           0 :       CALL arnoldi_ev(arnoldi_matrices, arnoldi_env)
     380           0 :       delta_E = REAL(get_selected_ritz_val(arnoldi_env, 1), dp)
     381             :       ! increase delta_E a bit to make sure that it really is an upper bound
     382           0 :       delta_E = delta_E + 1.0E-2_dp*ABS(delta_E)
     383             :       CALL get_selected_ritz_vector(arnoldi_env, 1, arnoldi_matrices(1)%matrix, &
     384           0 :                                     pexsi_env%max_ev_vector(ispin))
     385           0 :       CALL deallocate_arnoldi_env(arnoldi_env)
     386           0 :       DEALLOCATE (arnoldi_matrices)
     387             : 
     388           0 :       nelectron_exact_pexsi = nelectron_exact
     389             : 
     390           0 :       CALL cp_pexsi_set_options(pexsi_env%options, deltaE=delta_E)
     391             : 
     392             :       ! Set PEXSI options appropriately for first SCF iteration
     393           0 :       IF (iscf .EQ. 1) THEN
     394             :          ! Get option isInertiaCount to reset it later on and set it to 1 for first SCF iteration
     395           0 :          CALL cp_pexsi_get_options(pexsi_env%options, isInertiaCount=isInertiaCount)
     396             :          CALL cp_pexsi_set_options(pexsi_env%options, isInertiaCount=1, &
     397           0 :                                    isSymbolicFactorize=1)
     398             :       END IF
     399             : 
     400             :       ! Write PEXSI options to output
     401             :       CALL cp_pexsi_get_options(pexsi_env%options, isInertiaCount=isInertiaCount_out, &
     402             :                                 isSymbolicFactorize=is_symbolic_factorize, &
     403             :                                 muMin0=mu_min_in, muMax0=mu_max_in, &
     404           0 :                                 NumElectronPEXSITolerance=nel_tol)
     405             : 
     406             : !    IF(unit_nr>0) WRITE(unit_nr,'(/A,I4,A,I4)') " PEXSI| SCF", iscf, &
     407             : !                                                ", spin component", ispin
     408             : 
     409           0 :       IF (unit_nr > 0) WRITE (unit_nr, '(/A,T41,L20)') " PEXSI| Do inertia counting?", &
     410           0 :          isInertiaCount_out .EQ. 1
     411             :       IF (unit_nr > 0) WRITE (unit_nr, '(A,T50,F5.2,T56,F5.2)') &
     412           0 :          " PEXSI| Guess for min mu, max mu", mu_min_in, mu_max_in
     413             : 
     414             :       IF (unit_nr > 0) WRITE (unit_nr, '(A,T41,E20.3)') &
     415           0 :          " PEXSI| Tolerance in number of electrons", nel_tol
     416             : 
     417             : !    IF(unit_nr>0) WRITE(unit_nr,'(A,T41,L20)') &
     418             : !                  " PEXSI|   Do symbolic factorization?", is_symbolic_factorize.EQ.1
     419             : 
     420             :       IF (unit_nr > 0) WRITE (unit_nr, '(A,T41,F20.2)') &
     421           0 :          " PEXSI| Arnoldi est. spectral radius", delta_E
     422             : 
     423             :       ! Load data into PEXSI
     424             :       CALL cp_pexsi_load_real_hs_matrix( &
     425             :          pexsi_env%plan, &
     426             :          pexsi_env%options, &
     427             :          pexsi_env%csr_mat_ks%nrows_total, &
     428             :          INT(pexsi_env%csr_mat_ks%nze_total, kind=int_4), & ! TODO: update when PEXSI changes to Long Int
     429             :          pexsi_env%csr_mat_ks%nze_local, &
     430             :          pexsi_env%csr_mat_ks%nrows_local, &
     431             :          pexsi_env%csr_mat_ks%rowptr_local, &
     432             :          pexsi_env%csr_mat_ks%colind_local, &
     433             :          pexsi_env%csr_mat_ks%nzval_local%r_dp, &
     434             :          S_not_identity, &
     435           0 :          pexsi_env%csr_mat_s%nzval_local%r_dp)
     436             : 
     437             :       ! convert to spin restricted before passing number of electrons to PEXSI
     438             :       CALL convert_nspin_cp2k_pexsi(cp2k_to_pexsi, &
     439           0 :                                     numElectron=nelectron_exact_pexsi)
     440             : 
     441             :       ! Call DFT driver of PEXSI doing the actual calculation
     442             :       CALL cp_pexsi_dft_driver(pexsi_env%plan, pexsi_env%options, &
     443             :                                nelectron_exact_pexsi, mu, nelectron_out, mu_min_out, mu_max_out, &
     444           0 :                                n_total_inertia_iter, n_total_pexsi_iter)
     445             : 
     446             :       ! Check convergence
     447           0 :       nelectron_diff = nelectron_out - nelectron_exact_pexsi
     448           0 :       pexsi_convergence = ABS(nelectron_diff) .LT. nel_tol
     449             : 
     450           0 :       IF (unit_nr > 0) THEN
     451           0 :          IF (pexsi_convergence) THEN
     452           0 :             WRITE (unit_nr, '(/A)') " PEXSI| Converged"
     453             :          ELSE
     454           0 :             WRITE (unit_nr, '(/A)') " PEXSI| PEXSI did not converge!"
     455             :          END IF
     456             : 
     457             : !      WRITE(unit_nr,'(A,T41,F20.10,T61,F20.10)') " PEXSI|   Number of electrons", &
     458             : !                      nelectron_out/pexsi_env%nspin, nelectron_diff/pexsi_env%nspin
     459             : 
     460           0 :          WRITE (unit_nr, '(A,T41,F20.6)') " PEXSI|   Chemical potential", mu
     461             : 
     462           0 :          WRITE (unit_nr, '(A,T41,I20)') " PEXSI|   PEXSI iterations", n_total_pexsi_iter
     463           0 :          WRITE (unit_nr, '(A,T41,I20/)') " PEXSI|   Inertia counting iterations", &
     464           0 :             n_total_inertia_iter
     465             :       END IF
     466             : 
     467           0 :       IF (.NOT. pexsi_convergence) &
     468           0 :          CPABORT("PEXSI did not converge. Consider logPEXSI0 for more information.")
     469             : 
     470             :       ! Retrieve results from PEXSI
     471           0 :       IF (mynode < pexsi_env%mp_dims(1)*pexsi_env%mp_dims(2)) THEN
     472             :          CALL cp_pexsi_retrieve_real_dft_matrix( &
     473             :             pexsi_env%plan, &
     474             :             pexsi_env%csr_mat_p%nzval_local%r_dp, &
     475             :             pexsi_env%csr_mat_E%nzval_local%r_dp, &
     476             :             pexsi_env%csr_mat_F%nzval_local%r_dp, &
     477           0 :             energy_H, energy_S, free_energy)
     478             :          ! calculate entropic energy contribution -TS = A - U
     479           0 :          kTS = (free_energy - energy_H)
     480             :       END IF
     481             : 
     482             :       ! send kTS to all nodes:
     483           0 :       CALL pexsi_env%mp_group%bcast(kTS, 0)
     484             : 
     485             :       ! Convert PEXSI CSR matrices to DBCSR matrices
     486             :       CALL dbcsr_convert_csr_to_dbcsr(pexsi_env%dbcsr_template_matrix_nonsym, &
     487           0 :                                       pexsi_env%csr_mat_p)
     488           0 :       CALL dbcsr_copy(matrix_p, pexsi_env%dbcsr_template_matrix_nonsym)
     489             :       CALL dbcsr_convert_csr_to_dbcsr(pexsi_env%dbcsr_template_matrix_nonsym, &
     490           0 :                                       pexsi_env%csr_mat_E)
     491           0 :       CALL dbcsr_copy(matrix_w%matrix, pexsi_env%dbcsr_template_matrix_nonsym)
     492             : 
     493             :       ! Convert to spin unrestricted
     494             :       CALL convert_nspin_cp2k_pexsi(pexsi_to_cp2k, matrix_p=matrix_p, &
     495           0 :                                     matrix_w=matrix_w, kTS=kTS)
     496             : 
     497             :       ! Pass resulting mu as initial guess for next SCF to PEXSI
     498             :       CALL cp_pexsi_set_options(pexsi_env%options, mu0=mu, muMin0=mu_min_out, &
     499           0 :                                 muMax0=mu_max_out)
     500             : 
     501             :       ! Reset isInertiaCount according to user input
     502           0 :       IF (iscf .EQ. 1) THEN
     503             :          CALL cp_pexsi_set_options(pexsi_env%options, isInertiaCount= &
     504           0 :                                    isInertiaCount)
     505             :       END IF
     506             : 
     507             :       ! Turn off symbolic factorization for subsequent calls
     508           0 :       IF (first_call) THEN
     509           0 :          CALL cp_pexsi_set_options(pexsi_env%options, isSymbolicFactorize=0)
     510             :       END IF
     511             : 
     512           0 :       CALL timestop(handle)
     513           0 :    END SUBROUTINE density_matrix_pexsi
     514             : 
     515             : ! **************************************************************************************************
     516             : !> \brief Set PEXSI convergence tolerance (numElectronPEXSITolerance), adapted
     517             : !>        to the convergence error of the previous SCF step. The tolerance is
     518             : !>        calculated using an initial convergence threshold (tol_nel_initial)
     519             : !>        and a target convergence threshold (tol_nel_target):
     520             : !>        numElectronPEXSITolerance(delta_scf) = alpha*delta_scf+beta
     521             : !>        where alpha and beta are chosen such that
     522             : !>        numElectronPEXSITolerance(delta_scf_0) = tol_nel_initial
     523             : !>        numElectronPEXSITolerance(eps_scf) = tol_nel_target
     524             : !>        and delta_scf_0 is the initial SCF convergence error.
     525             : !> \param pexsi_env ...
     526             : !> \param delta_scf convergence error of previous SCF step
     527             : !> \param eps_scf SCF convergence criterion
     528             : !> \param initialize whether or not adaptive thresholing should be initialized
     529             : !>        with delta_scf as initial convergence error
     530             : !> \param check_convergence is set to .FALSE. if convergence in number of electrons
     531             : !>        will not be achieved in next SCF step
     532             : ! **************************************************************************************************
     533           0 :    SUBROUTINE pexsi_set_convergence_tolerance(pexsi_env, delta_scf, eps_scf, initialize, &
     534             :                                               check_convergence)
     535             :       TYPE(lib_pexsi_env), INTENT(INOUT)                 :: pexsi_env
     536             :       REAL(KIND=dp), INTENT(IN)                          :: delta_scf, eps_scf
     537             :       LOGICAL, INTENT(IN)                                :: initialize
     538             :       LOGICAL, INTENT(OUT)                               :: check_convergence
     539             : 
     540             :       CHARACTER(len=*), PARAMETER :: routineN = 'pexsi_set_convergence_tolerance'
     541             : 
     542             :       INTEGER                                            :: handle
     543             :       REAL(KIND=dp)                                      :: tol_nel
     544             : 
     545           0 :       CALL timeset(routineN, handle)
     546             : 
     547           0 :       tol_nel = pexsi_env%tol_nel_initial
     548             : 
     549           0 :       IF (initialize) THEN
     550             :          pexsi_env%adaptive_nel_alpha = &
     551           0 :             (pexsi_env%tol_nel_initial - pexsi_env%tol_nel_target)/(ABS(delta_scf) - eps_scf)
     552             :          pexsi_env%adaptive_nel_beta = &
     553           0 :             pexsi_env%tol_nel_initial - pexsi_env%adaptive_nel_alpha*ABS(delta_scf)
     554           0 :          pexsi_env%do_adaptive_tol_nel = .TRUE.
     555             :       END IF
     556           0 :       IF (pexsi_env%do_adaptive_tol_nel) THEN
     557           0 :          tol_nel = pexsi_env%adaptive_nel_alpha*ABS(delta_scf) + pexsi_env%adaptive_nel_beta
     558           0 :          tol_nel = MAX(tol_nel, pexsi_env%tol_nel_target)
     559           0 :          tol_nel = MIN(tol_nel, pexsi_env%tol_nel_initial)
     560             :       END IF
     561             : 
     562           0 :       check_convergence = (tol_nel .LE. pexsi_env%tol_nel_target)
     563             : 
     564           0 :       CALL cp_pexsi_set_options(pexsi_env%options, numElectronPEXSITolerance=tol_nel)
     565           0 :       CALL timestop(handle)
     566           0 :    END SUBROUTINE
     567             : 
     568             : ! **************************************************************************************************
     569             : !> \brief Pass energy weighted density matrix and entropic energy contribution
     570             : !>        to QS environment
     571             : !> \param ls_scf_env ...
     572             : !> \param qs_env ...
     573             : !> \param kTS ...
     574             : !> \param matrix_w ...
     575             : !> \par History
     576             : !>      12.2014 created [Patrick Seewald]
     577             : !> \author Patrick Seewald
     578             : ! **************************************************************************************************
     579           0 :    SUBROUTINE pexsi_to_qs(ls_scf_env, qs_env, kTS, matrix_w)
     580             :       TYPE(ls_scf_env_type)                              :: ls_scf_env
     581             :       TYPE(qs_environment_type), INTENT(INOUT), POINTER  :: qs_env
     582             :       REAL(KIND=dp), DIMENSION(:), INTENT(IN), OPTIONAL  :: kTS
     583             :       TYPE(dbcsr_p_type), DIMENSION(:), INTENT(IN), &
     584             :          OPTIONAL                                        :: matrix_w
     585             : 
     586             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'pexsi_to_qs'
     587             : 
     588             :       INTEGER                                            :: handle, ispin, unit_nr
     589             :       REAL(KIND=dp)                                      :: kTS_total
     590             :       TYPE(cp_logger_type), POINTER                      :: logger
     591           0 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_w_qs
     592             :       TYPE(qs_energy_type), POINTER                      :: energy
     593             : 
     594           0 :       CALL timeset(routineN, handle)
     595             : 
     596           0 :       NULLIFY (energy)
     597             : 
     598             :       ! get a useful output_unit
     599           0 :       logger => cp_get_default_logger()
     600           0 :       IF (logger%para_env%is_source()) THEN
     601           0 :          unit_nr = cp_logger_get_default_unit_nr(logger, local=.TRUE.)
     602             :       ELSE
     603             :          unit_nr = -1
     604             :       END IF
     605             : 
     606           0 :       CALL get_qs_env(qs_env, energy=energy, matrix_w=matrix_w_qs)
     607             : 
     608           0 :       IF (PRESENT(matrix_w)) THEN
     609           0 :          DO ispin = 1, ls_scf_env%nspins
     610             :             CALL matrix_ls_to_qs(matrix_w_qs(ispin)%matrix, matrix_w(ispin)%matrix, &
     611           0 :                                  ls_scf_env%ls_mstruct, covariant=.FALSE.)
     612           0 :             IF (ls_scf_env%nspins .EQ. 1) CALL dbcsr_scale(matrix_w_qs(ispin)%matrix, 2.0_dp)
     613             :          END DO
     614             :       END IF
     615             : 
     616           0 :       IF (PRESENT(kTS)) THEN
     617           0 :          kTS_total = SUM(kTS)
     618           0 :          IF (ls_scf_env%nspins .EQ. 1) kTS_total = kTS_total*2.0_dp
     619           0 :          energy%kTS = kTS_total
     620             :       END IF
     621             : 
     622           0 :       CALL timestop(handle)
     623           0 :    END SUBROUTINE pexsi_to_qs
     624             : 
     625             : END MODULE pexsi_methods

Generated by: LCOV version 1.15