LCOV - code coverage report
Current view: top level - src - qs_mo_occupation.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:123285f) Lines: 81.5 % 417 340
Test Date: 2026-11-04 00:58:17 Functions: 100.0 % 3 3

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief Set occupation of molecular orbitals
      10              : !> \par History
      11              : !>      - set_mo_occupation subroutines moved from qs_mo_types (11.12.2014 MI)
      12              : !> \author  MI
      13              : ! **************************************************************************************************
      14              : 
      15              : MODULE qs_mo_occupation
      16              : 
      17              :    USE cp_control_types,                ONLY: hairy_probes_type
      18              :    USE cp_log_handling,                 ONLY: cp_to_string
      19              :    USE hairy_probes,                    ONLY: probe_occupancy
      20              :    USE input_constants,                 ONLY: smear_energy_window,&
      21              :                                               smear_fermi_dirac,&
      22              :                                               smear_gaussian,&
      23              :                                               smear_list,&
      24              :                                               smear_mp,&
      25              :                                               smear_mv
      26              :    USE kahan_sum,                       ONLY: accurate_sum
      27              :    USE kinds,                           ONLY: dp
      28              :    USE qs_mo_types,                     ONLY: get_mo_set,&
      29              :                                               has_uniform_occupation,&
      30              :                                               mo_set_type,&
      31              :                                               set_mo_set
      32              :    USE scf_control_types,               ONLY: gce_type,&
      33              :                                               smear_type
      34              :    USE smearing_utils,                  ONLY: SmearFixed,&
      35              :                                               SmearFixedDerivMV,&
      36              :                                               SmearOcc
      37              :    USE util,                            ONLY: sort
      38              :    USE xas_env_types,                   ONLY: get_xas_env,&
      39              :                                               xas_environment_type
      40              : #include "./base/base_uses.f90"
      41              : 
      42              :    IMPLICIT NONE
      43              : 
      44              :    PRIVATE
      45              : 
      46              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_mo_occupation'
      47              : 
      48              :    PUBLIC :: set_mo_occupation
      49              : 
      50              :    INTERFACE set_mo_occupation
      51              :       MODULE PROCEDURE set_mo_occupation_1, set_mo_occupation_2
      52              :    END INTERFACE
      53              : 
      54              : CONTAINS
      55              : 
      56              : ! **************************************************************************************************
      57              : !> \brief  Occupation for smeared spin polarized electronic structures
      58              : !>         with relaxed multiplicity
      59              : !>
      60              : !> \param mo_array ...
      61              : !> \param smear ...
      62              : !> \param gce ...
      63              : !> \date    10.03.2011 (MI)
      64              : !> \author  MI
      65              : !> \version 1.0
      66              : ! **************************************************************************************************
      67         2680 :    SUBROUTINE set_mo_occupation_3(mo_array, smear, gce)
      68              : 
      69              :       TYPE(mo_set_type), DIMENSION(2), INTENT(INOUT)     :: mo_array
      70              :       TYPE(smear_type)                                   :: smear
      71              :       TYPE(gce_type), OPTIONAL, POINTER                  :: gce
      72              : 
      73              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'set_mo_occupation_3'
      74              : 
      75              :       CHARACTER(LEN=32)                                  :: method_label
      76              :       INTEGER                                            :: all_nmo, handle, homo_a, homo_b, i, &
      77              :                                                             lfomo_a, lfomo_b, nmo_a, nmo_b, &
      78              :                                                             xas_estate
      79         2680 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: all_index
      80              :       LOGICAL                                            :: do_gce, is_large
      81              :       REAL(KIND=dp)                                      :: all_nelec, kTS, mu, nelec_a, nelec_b, &
      82              :                                                             occ_estate, smear_width
      83              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: all_eigval, all_occ
      84         2680 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: eigval_a, eigval_b, occ_a, occ_b
      85              : 
      86         2680 :       CALL timeset(routineN, handle)
      87              : 
      88         2680 :       NULLIFY (eigval_a, eigval_b, occ_a, occ_b)
      89              :       CALL get_mo_set(mo_set=mo_array(1), nmo=nmo_a, eigenvalues=eigval_a, &
      90         2680 :                       occupation_numbers=occ_a)
      91              :       CALL get_mo_set(mo_set=mo_array(2), nmo=nmo_b, eigenvalues=eigval_b, &
      92         2680 :                       occupation_numbers=occ_b)
      93         2680 :       all_nmo = nmo_a + nmo_b
      94         8040 :       ALLOCATE (all_eigval(all_nmo))
      95         5360 :       ALLOCATE (all_occ(all_nmo))
      96         8040 :       ALLOCATE (all_index(all_nmo))
      97              : 
      98        37540 :       all_eigval(1:nmo_a) = eigval_a(1:nmo_a)
      99        35562 :       all_eigval(nmo_a + 1:all_nmo) = eigval_b(1:nmo_b)
     100              : 
     101         2680 :       CALL sort(all_eigval, all_nmo, all_index)
     102              : 
     103         2680 :       IF (PRESENT(gce)) THEN
     104          172 :          do_gce = gce%do_gce
     105              :       ELSE
     106              :          do_gce = .FALSE.
     107              :       END IF
     108              : 
     109         5088 :       SELECT CASE (smear%method)
     110              :       CASE (smear_fermi_dirac)
     111         2408 :          smear_width = smear%electronic_temperature
     112         2408 :          method_label = "Fermi-Dirac"
     113              :       CASE (smear_gaussian)
     114          164 :          smear_width = smear%smearing_width
     115          164 :          method_label = "Gaussian"
     116              :       CASE (smear_mp)
     117            0 :          smear_width = smear%smearing_width
     118            0 :          method_label = "Methfessel-Paxton"
     119              :       CASE (smear_mv)
     120          108 :          smear_width = smear%smearing_width
     121          108 :          method_label = "Marzari-Vanderbilt"
     122              :       CASE DEFAULT
     123         2680 :          CPABORT("set_mo_occupation_3: unsupported smearing method")
     124              :       END SELECT
     125              : 
     126         2680 :       IF (.NOT. do_gce) THEN
     127         2508 :          xas_estate = -1
     128         2508 :          occ_estate = 0.0_dp
     129              : 
     130              :          nelec_a = 0.0_dp
     131              :          nelec_b = 0.0_dp
     132              :          all_nelec = 0.0_dp
     133         2508 :          nelec_a = accurate_sum(occ_a(:))
     134         2508 :          nelec_b = accurate_sum(occ_b(:))
     135         2508 :          all_nelec = nelec_a + nelec_b
     136              : 
     137        63714 :          DO i = 1, all_nmo
     138        63714 :             IF (all_index(i) <= nmo_a) THEN
     139        31592 :                all_occ(i) = occ_a(all_index(i))
     140              :             ELSE
     141        29614 :                all_occ(i) = occ_b(all_index(i) - nmo_a)
     142              :             END IF
     143              :          END DO
     144              : 
     145              :          CALL SmearFixed(all_occ, mu, kTS, all_eigval, all_nelec, &
     146         2508 :                          smear_width, 1._dp, smear%method, xas_estate, occ_estate)
     147              :       ELSE
     148          172 :          gce%prev_workfunction = gce%ref_esp - mo_array(1)%mu
     149          172 :          mu = gce%ref_esp - ((1.0_dp - gce%mixing_coef)*gce%prev_workfunction + gce%mixing_coef*gce%target_workfunction)
     150          172 :          CALL SmearOcc(all_occ, all_nelec, kTS, all_eigval, mu, smear_width, 1._dp, smear%method)
     151              :       END IF
     152              : 
     153         2680 :       is_large = ABS(all_occ(1) - 1.0_dp) > smear%eps_fermi_dirac
     154              :       ! this is not a real problem, but the smearing width might be a bit large
     155         2680 :       CPWARN_IF(is_large, TRIM(method_label)//" smearing includes the first MO")
     156              : 
     157         2680 :       is_large = ABS(all_occ(all_nmo)) > smear%eps_fermi_dirac
     158         2680 :       IF (is_large) THEN
     159              :          CALL cp_warn(__LOCATION__, &
     160              :                       TRIM(method_label)//" smearing includes the last MO => "// &
     161           20 :                       "Add more MOs for proper smearing.")
     162              :       END IF
     163         2680 :       IF (.NOT. do_gce) THEN
     164              :          ! check that the total electron count is accurate
     165         2508 :          is_large = (ABS(all_nelec - accurate_sum(all_occ(:))) > smear%eps_fermi_dirac*all_nelec)
     166         2508 :          CPWARN_IF(is_large, "Total number of electrons is not accurate")
     167              :       END IF
     168              : 
     169        70422 :       DO i = 1, all_nmo
     170        70422 :          IF (all_index(i) <= nmo_a) THEN
     171        34860 :             occ_a(all_index(i)) = all_occ(i)
     172        34860 :             eigval_a(all_index(i)) = all_eigval(i)
     173              :          ELSE
     174        32882 :             occ_b(all_index(i) - nmo_a) = all_occ(i)
     175        32882 :             eigval_b(all_index(i) - nmo_a) = all_eigval(i)
     176              :          END IF
     177              :       END DO
     178              : 
     179         2680 :       nelec_a = accurate_sum(occ_a(:))
     180         2680 :       nelec_b = accurate_sum(occ_b(:))
     181              : 
     182         2680 :       lfomo_a = nmo_a + 1
     183         2680 :       lfomo_b = nmo_b + 1
     184              :       homo_a = 0
     185              :       homo_b = 0
     186              : 
     187        22286 :       DO i = 1, nmo_a
     188        22286 :          IF (occ_a(i) < 1.0_dp) THEN
     189         2680 :             lfomo_a = i
     190         2680 :             EXIT
     191              :          END IF
     192              :       END DO
     193        21914 :       DO i = 1, nmo_b
     194        21914 :          IF (occ_b(i) < 1.0_dp) THEN
     195         2680 :             lfomo_b = i
     196         2680 :             EXIT
     197              :          END IF
     198              :       END DO
     199         2680 :       homo_a = lfomo_a - 1
     200        14304 :       DO i = nmo_a, lfomo_a, -1
     201        14304 :          IF (ABS(occ_a(i)) > smear%eps_fermi_dirac) THEN
     202         1980 :             homo_a = i
     203         1980 :             EXIT
     204              :          END IF
     205              :       END DO
     206         2680 :       homo_b = lfomo_b - 1
     207        14198 :       DO i = nmo_b, lfomo_b, -1
     208        14198 :          IF (ABS(occ_b(i)) > smear%eps_fermi_dirac) THEN
     209         1224 :             homo_b = i
     210         1224 :             EXIT
     211              :          END IF
     212              :       END DO
     213              : 
     214              :       CALL set_mo_set(mo_set=mo_array(1), kTS=kTS/2.0_dp, mu=mu, n_el_f=nelec_a, &
     215         2680 :                       lfomo=lfomo_a, homo=homo_a, uniform_occupation=.FALSE.)
     216              :       CALL set_mo_set(mo_set=mo_array(2), kTS=kTS/2.0_dp, mu=mu, n_el_f=nelec_b, &
     217         2680 :                       lfomo=lfomo_b, homo=homo_b, uniform_occupation=.FALSE.)
     218              : 
     219         2680 :       CALL timestop(handle)
     220              : 
     221         5360 :    END SUBROUTINE set_mo_occupation_3
     222              : 
     223              : ! **************************************************************************************************
     224              : !> \brief   Prepare an occupation of alpha and beta MOs following an Aufbau
     225              : !>          principle, i.e. allowing a change in multiplicity.
     226              : !> \param mo_array ...
     227              : !> \param smear ...
     228              : !> \param eval_deriv ...
     229              : !> \param tot_zeff_corr ...
     230              : !> \param probe ...
     231              : !> \param gce ...
     232              : !> \date    25.01.2010 (MK)
     233              : !> \par   History
     234              : !>        10.2019 Added functionality to adjust mo occupation if the core
     235              : !>                charges are changed via CORE_CORRECTION during surface dipole
     236              : !>                calculation. Total number of electrons matches the total core
     237              : !>                charges if tot_zeff_corr is non-zero. Not yet implemented for
     238              : !>                OT type method. [Soumya Ghosh]
     239              : !> \author  Matthias Krack (MK)
     240              : !> \version 1.0
     241              : ! **************************************************************************************************
     242       121003 :    SUBROUTINE set_mo_occupation_2(mo_array, smear, eval_deriv, tot_zeff_corr, probe, gce)
     243              : 
     244              :       TYPE(mo_set_type), DIMENSION(:), INTENT(INOUT)     :: mo_array
     245              :       TYPE(smear_type)                                   :: smear
     246              :       REAL(KIND=dp), DIMENSION(:), OPTIONAL, POINTER     :: eval_deriv
     247              :       REAL(KIND=dp), OPTIONAL                            :: tot_zeff_corr
     248              :       TYPE(hairy_probes_type), DIMENSION(:), OPTIONAL, &
     249              :          POINTER                                         :: probe
     250              :       TYPE(gce_type), OPTIONAL, POINTER                  :: gce
     251              : 
     252              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'set_mo_occupation_2'
     253              : 
     254              :       INTEGER                                            :: handle, i, lumo_a, lumo_b, &
     255              :                                                             multiplicity_new, multiplicity_old, &
     256              :                                                             nelec
     257              :       REAL(KIND=dp)                                      :: nelec_f, threshold
     258       121003 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: eigval_a, eigval_b
     259              : 
     260       121003 :       CALL timeset(routineN, handle)
     261              : 
     262              :       ! Fall back for the case that we have only one MO set
     263       121003 :       IF (SIZE(mo_array) == 1) THEN
     264       102143 :          IF (PRESENT(probe)) THEN
     265           14 :             CALL set_mo_occupation_1(mo_array(1), smear=smear, probe=probe)
     266       102129 :          ELSE IF (PRESENT(eval_deriv)) THEN
     267              : ! Change of MO occupancy to account for CORE_CORRECTION is not yet implemented
     268            0 :             IF (PRESENT(gce)) THEN
     269            0 :                CALL set_mo_occupation_1(mo_array(1), smear=smear, eval_deriv=eval_deriv, gce=gce)
     270              :             ELSE
     271            0 :                CALL set_mo_occupation_1(mo_array(1), smear=smear, eval_deriv=eval_deriv)
     272              :             END IF
     273              :          ELSE
     274       102129 :             IF (PRESENT(tot_zeff_corr)) THEN
     275           20 :                CALL set_mo_occupation_1(mo_array(1), smear=smear, tot_zeff_corr=tot_zeff_corr)
     276              :             ELSE
     277       102109 :                IF (PRESENT(gce)) THEN
     278          196 :                   CALL set_mo_occupation_1(mo_array(1), smear=smear, gce=gce)
     279              :                ELSE
     280       101913 :                   CALL set_mo_occupation_1(mo_array(1), smear=smear)
     281              :                END IF
     282              :             END IF
     283              :          END IF
     284       102143 :          CALL timestop(handle)
     285              :          RETURN
     286              :       END IF
     287              : 
     288        18860 :       IF (PRESENT(probe)) THEN
     289            0 :          CALL set_mo_occupation_1(mo_array(1), smear=smear, probe=probe)
     290            0 :          CALL set_mo_occupation_1(mo_array(2), smear=smear, probe=probe)
     291              :       END IF
     292              : 
     293        18860 :       IF (smear%do_smear) THEN
     294         4596 :          IF (smear%fixed_mag_mom < 0.0_dp) THEN
     295         3034 :             IF (PRESENT(tot_zeff_corr)) THEN
     296              :                CALL cp_warn(__LOCATION__, &
     297              :                             "CORE_CORRECTION /= 0.0 might cause the cell to charge up "// &
     298              :                             "that will lead to application of different background "// &
     299              :                             "correction compared to the reference system. "// &
     300              :                             "Use FIXED_MAGNETIC_MOMENT >= 0.0 if using SMEAR keyword "// &
     301            0 :                             "to correct the electron density")
     302              :             END IF
     303         3034 :             IF (smear%fixed_mag_mom /= -1.0_dp) THEN
     304         2680 :                CPASSERT(.NOT. (PRESENT(eval_deriv)))
     305         2680 :                CALL set_mo_occupation_3(mo_array, smear=smear, gce=gce)
     306         2680 :                CALL timestop(handle)
     307         2680 :                RETURN
     308              :             END IF
     309              :          ELSE
     310         1562 :             nelec_f = mo_array(1)%n_el_f + mo_array(2)%n_el_f
     311         1562 :             IF (ABS((mo_array(1)%n_el_f - mo_array(2)%n_el_f) - smear%fixed_mag_mom) > smear%eps_fermi_dirac*nelec_f) THEN
     312            2 :                mo_array(1)%n_el_f = nelec_f/2.0_dp + smear%fixed_mag_mom/2.0_dp
     313            2 :                mo_array(2)%n_el_f = nelec_f/2.0_dp - smear%fixed_mag_mom/2.0_dp
     314              :             END IF
     315         1562 :             CPASSERT(.NOT. (PRESENT(eval_deriv)))
     316         1562 :             IF (PRESENT(tot_zeff_corr)) THEN
     317           20 :                CALL set_mo_occupation_1(mo_array(1), smear=smear, tot_zeff_corr=tot_zeff_corr)
     318           20 :                CALL set_mo_occupation_1(mo_array(2), smear=smear, tot_zeff_corr=tot_zeff_corr)
     319              :             ELSE
     320         1542 :                CALL set_mo_occupation_1(mo_array(1), smear=smear)
     321         1542 :                CALL set_mo_occupation_1(mo_array(2), smear=smear)
     322              :             END IF
     323              :          END IF
     324              :       END IF
     325              : 
     326        16180 :       IF (.NOT. ((mo_array(1)%flexible_electron_count > 0.0_dp) .AND. &
     327              :                  (mo_array(2)%flexible_electron_count > 0.0_dp))) THEN
     328        15994 :          IF (PRESENT(probe)) THEN
     329            0 :             CALL set_mo_occupation_1(mo_array(1), smear=smear, probe=probe)
     330            0 :             CALL set_mo_occupation_1(mo_array(2), smear=smear, probe=probe)
     331        15994 :          ELSE IF (PRESENT(eval_deriv)) THEN
     332            0 :             CALL set_mo_occupation_1(mo_array(1), smear=smear, eval_deriv=eval_deriv)
     333            0 :             CALL set_mo_occupation_1(mo_array(2), smear=smear, eval_deriv=eval_deriv)
     334              :          ELSE
     335        15994 :             IF (PRESENT(tot_zeff_corr)) THEN
     336           20 :                CALL set_mo_occupation_1(mo_array(1), smear=smear, tot_zeff_corr=tot_zeff_corr)
     337           20 :                CALL set_mo_occupation_1(mo_array(2), smear=smear, tot_zeff_corr=tot_zeff_corr)
     338              :             ELSE
     339        15974 :                CALL set_mo_occupation_1(mo_array(1), smear=smear)
     340        15974 :                CALL set_mo_occupation_1(mo_array(2), smear=smear)
     341              :             END IF
     342              :          END IF
     343        15994 :          CALL timestop(handle)
     344        15994 :          RETURN
     345              :       END IF
     346              : 
     347          186 :       nelec = mo_array(1)%nelectron + mo_array(2)%nelectron
     348              : 
     349          186 :       multiplicity_old = mo_array(1)%nelectron - mo_array(2)%nelectron + 1
     350              : 
     351          186 :       IF (mo_array(1)%nelectron >= mo_array(1)%nmo) THEN
     352              :          CALL cp_warn(__LOCATION__, &
     353              :                       "All alpha MOs are occupied. Add more alpha MOs to "// &
     354            0 :                       "allow for a higher multiplicity")
     355              :       END IF
     356          186 :       IF ((mo_array(2)%nelectron >= mo_array(2)%nmo) .AND. (mo_array(2)%nelectron /= mo_array(1)%nelectron)) THEN
     357              :          CALL cp_warn(__LOCATION__, "All beta MOs are occupied. Add more beta MOs to "// &
     358            0 :                       "allow for a lower multiplicity")
     359              :       END IF
     360              : 
     361          186 :       eigval_a => mo_array(1)%eigenvalues
     362          186 :       eigval_b => mo_array(2)%eigenvalues
     363              : 
     364          186 :       lumo_a = 1
     365          186 :       lumo_b = 1
     366              : 
     367              :       ! Apply Aufbau principle
     368         2306 :       DO i = 1, nelec
     369              :          ! Threshold is needed to ensure a preference for alpha occupation in the case
     370              :          ! of degeneracy
     371         2120 :          threshold = MAX(mo_array(1)%flexible_electron_count, mo_array(2)%flexible_electron_count)
     372         2120 :          IF ((eigval_a(lumo_a) - threshold) < eigval_b(lumo_b)) THEN
     373         1212 :             lumo_a = lumo_a + 1
     374              :          ELSE
     375          908 :             lumo_b = lumo_b + 1
     376              :          END IF
     377         2120 :          IF (lumo_a > mo_array(1)%nmo) THEN
     378            0 :             IF (i /= nelec) THEN
     379              :                CALL cp_warn(__LOCATION__, &
     380              :                             "All alpha MOs are occupied. Add more alpha MOs to "// &
     381            0 :                             "allow for a higher multiplicity")
     382              :             END IF
     383            0 :             IF (i < nelec) THEN
     384            0 :                lumo_a = lumo_a - 1
     385            0 :                lumo_b = lumo_b + 1
     386              :             END IF
     387              :          END IF
     388         2306 :          IF (lumo_b > mo_array(2)%nmo) THEN
     389           34 :             IF (lumo_b < lumo_a) THEN
     390              :                CALL cp_warn(__LOCATION__, &
     391              :                             "All beta MOs are occupied. Add more beta MOs to "// &
     392            0 :                             "allow for a lower multiplicity")
     393              :             END IF
     394           34 :             IF (i < nelec) THEN
     395            6 :                lumo_a = lumo_a + 1
     396            6 :                lumo_b = lumo_b - 1
     397              :             END IF
     398              :          END IF
     399              :       END DO
     400              : 
     401          186 :       mo_array(1)%homo = lumo_a - 1
     402          186 :       mo_array(2)%homo = lumo_b - 1
     403              : 
     404          186 :       IF (mo_array(2)%homo > mo_array(1)%homo) THEN
     405              :          CALL cp_warn(__LOCATION__, &
     406              :                       "More beta ("// &
     407              :                       TRIM(ADJUSTL(cp_to_string(mo_array(2)%homo)))// &
     408              :                       ") than alpha ("// &
     409              :                       TRIM(ADJUSTL(cp_to_string(mo_array(1)%homo)))// &
     410            0 :                       ") MOs are occupied. Resorting to low spin state")
     411            0 :          mo_array(1)%homo = nelec/2 + MODULO(nelec, 2)
     412            0 :          mo_array(2)%homo = nelec/2
     413              :       END IF
     414              : 
     415          186 :       mo_array(1)%nelectron = mo_array(1)%homo
     416          186 :       mo_array(2)%nelectron = mo_array(2)%homo
     417          186 :       multiplicity_new = mo_array(1)%nelectron - mo_array(2)%nelectron + 1
     418              : 
     419          186 :       IF (multiplicity_new /= multiplicity_old) THEN
     420              :          CALL cp_warn(__LOCATION__, &
     421              :                       "Multiplicity changed from "// &
     422              :                       TRIM(ADJUSTL(cp_to_string(multiplicity_old)))//" to "// &
     423            8 :                       TRIM(ADJUSTL(cp_to_string(multiplicity_new))))
     424              :       END IF
     425              : 
     426          186 :       IF (PRESENT(probe)) THEN
     427            0 :          CALL set_mo_occupation_1(mo_array(1), smear=smear, probe=probe)
     428            0 :          CALL set_mo_occupation_1(mo_array(2), smear=smear, probe=probe)
     429          186 :       ELSE IF (PRESENT(eval_deriv)) THEN
     430            0 :          CALL set_mo_occupation_1(mo_array(1), smear=smear, eval_deriv=eval_deriv)
     431            0 :          CALL set_mo_occupation_1(mo_array(2), smear=smear, eval_deriv=eval_deriv)
     432              :       ELSE
     433          186 :          IF (PRESENT(tot_zeff_corr)) THEN
     434            0 :             CALL set_mo_occupation_1(mo_array(1), smear=smear, tot_zeff_corr=tot_zeff_corr)
     435            0 :             CALL set_mo_occupation_1(mo_array(2), smear=smear, tot_zeff_corr=tot_zeff_corr)
     436              :          ELSE
     437          186 :             CALL set_mo_occupation_1(mo_array(1), smear=smear)
     438          186 :             CALL set_mo_occupation_1(mo_array(2), smear=smear)
     439              :          END IF
     440              :       END IF
     441              : 
     442          186 :       CALL timestop(handle)
     443              : 
     444       121003 :    END SUBROUTINE set_mo_occupation_2
     445              : 
     446              : ! **************************************************************************************************
     447              : !> \brief   Smearing of the MO occupation with all kind of occupation numbers
     448              : !> \param   mo_set MO dataset structure
     449              : !> \param   smear optional smearing information
     450              : !> \param   eval_deriv on entry the derivative of the KS energy wrt to the occupation number
     451              : !>                     on exit  the derivative of the full free energy (i.e. KS and entropy) wrt to the eigenvalue
     452              : !> \param xas_env ...
     453              : !> \param tot_zeff_corr ...
     454              : !> \param probe ...
     455              : !> \param gce ...
     456              : !> \param emit_warnings emit first/last-MO and electron-count warnings
     457              : !> \date    17.04.2002 (v1.0), 26.08.2008 (v1.1)
     458              : !> \par   History
     459              : !>        10.2019 Added functionality to adjust mo occupation if the core
     460              : !>                charges are changed via CORE_CORRECTION during surface dipole
     461              : !>                calculation. Total number of electrons matches the total core
     462              : !>                charges if tot_zeff_corr is non-zero. Not yet implemented for
     463              : !>                OT type method. [Soumya Ghosh]
     464              : !> \author  Matthias Krack
     465              : !> \version 1.1
     466              : ! **************************************************************************************************
     467       272850 :    SUBROUTINE set_mo_occupation_1(mo_set, smear, eval_deriv, xas_env, tot_zeff_corr, probe, gce, &
     468              :                                   emit_warnings)
     469              : 
     470              :       TYPE(mo_set_type), INTENT(INOUT)                   :: mo_set
     471              :       TYPE(smear_type), OPTIONAL                         :: smear
     472              :       REAL(KIND=dp), DIMENSION(:), OPTIONAL, POINTER     :: eval_deriv
     473              :       TYPE(xas_environment_type), OPTIONAL, POINTER      :: xas_env
     474              :       REAL(KIND=dp), OPTIONAL                            :: tot_zeff_corr
     475              :       TYPE(hairy_probes_type), DIMENSION(:), OPTIONAL, &
     476              :          POINTER                                         :: probe
     477              :       TYPE(gce_type), OPTIONAL, POINTER                  :: gce
     478              :       LOGICAL, INTENT(IN), OPTIONAL                      :: emit_warnings
     479              : 
     480              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'set_mo_occupation_1'
     481              : 
     482              :       CHARACTER(LEN=20)                                  :: method_label
     483              :       INTEGER                                            :: handle, i, i_first, imo, ir, irmo, nmo, &
     484              :                                                             nomo, xas_estate
     485              :       LOGICAL                                            :: do_gce, equal_size, is_large, &
     486              :                                                             my_emit_warnings
     487              :       REAL(KIND=dp) :: delectron, e1, e2, edelta, edist, el_count, gce_mu, my_nelec, nelec, &
     488              :          occ_estate, smear_width, total_zeff_corr, xas_nelectron
     489       272850 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: tmp_v
     490              : 
     491       272850 :       CALL timeset(routineN, handle)
     492              : 
     493       272850 :       my_emit_warnings = .TRUE.
     494       272850 :       IF (PRESENT(emit_warnings)) my_emit_warnings = emit_warnings
     495              : 
     496       272850 :       CPASSERT(ASSOCIATED(mo_set%eigenvalues))
     497       272850 :       CPASSERT(ASSOCIATED(mo_set%occupation_numbers))
     498      3033233 :       mo_set%occupation_numbers(:) = 0.0_dp
     499              : 
     500              :       ! Quick return, if no electrons are available
     501       272850 :       IF (mo_set%nelectron == 0) THEN
     502         3754 :          CALL timestop(handle)
     503         3754 :          RETURN
     504              :       END IF
     505              : 
     506       269096 :       xas_estate = -1
     507       269096 :       occ_estate = 0.0_dp
     508       269096 :       IF (PRESENT(xas_env)) THEN
     509          798 :          CALL get_xas_env(xas_env=xas_env, xas_nelectron=xas_nelectron, occ_estate=occ_estate, xas_estate=xas_estate)
     510          798 :          nomo = CEILING(xas_nelectron + 1.0_dp - occ_estate - EPSILON(0.0_dp))
     511              : 
     512         8102 :          mo_set%occupation_numbers(1:nomo) = mo_set%maxocc
     513          798 :          IF (xas_estate > 0) mo_set%occupation_numbers(xas_estate) = occ_estate
     514         8102 :          el_count = SUM(mo_set%occupation_numbers(1:nomo))
     515          798 :          IF (el_count > xas_nelectron) THEN
     516           98 :             mo_set%occupation_numbers(nomo) = mo_set%occupation_numbers(nomo) - (el_count - xas_nelectron)
     517              :          END IF
     518         8102 :          el_count = SUM(mo_set%occupation_numbers(1:nomo))
     519          798 :          is_large = ABS(el_count - xas_nelectron) > xas_nelectron*EPSILON(el_count)
     520          798 :          CPASSERT(.NOT. is_large)
     521              :       ELSE
     522       268298 :          IF (PRESENT(gce)) THEN
     523          208 :             do_gce = gce%do_gce
     524              :          ELSE
     525              :             do_gce = .FALSE.
     526              :          END IF
     527              :          ! GCE workfunction (Fermi energy) mixing
     528          208 :          IF (do_gce) THEN
     529          208 :             smear_width = smear%smearing_width
     530          208 :             IF (smear%method == smear_fermi_dirac) smear_width = smear%electronic_temperature
     531          208 :             IF (gce%prev_workfunction < -1000.0_dp) THEN
     532            8 :                my_nelec = REAL(mo_set%nelectron, dp)
     533              :                CALL SmearFixed(mo_set%occupation_numbers, mo_set%mu, mo_set%kTS, mo_set%eigenvalues, my_nelec, &
     534            8 :                                smear_width, mo_set%maxocc, smear%method)
     535            8 :                gce%prev_workfunction = -501.0_dp
     536          200 :             ELSE IF (gce%prev_workfunction < -500.0_dp) THEN
     537            8 :                my_nelec = REAL(mo_set%nelectron, dp)
     538              :                CALL SmearFixed(mo_set%occupation_numbers, mo_set%mu, mo_set%kTS, mo_set%eigenvalues, my_nelec, &
     539            8 :                                smear_width, mo_set%maxocc, smear%method)
     540            8 :                gce%prev_workfunction = gce%ref_esp - mo_set%mu
     541              :             ELSE
     542              :                gce_mu = gce%ref_esp - ((1.0_dp - gce%mixing_coef)*gce%prev_workfunction &
     543          192 :                                        + gce%mixing_coef*gce%target_workfunction)
     544              :                CALL SmearOcc(mo_set%occupation_numbers, my_nelec, mo_set%kTS, mo_set%eigenvalues, gce_mu, &
     545          192 :                              smear_width, mo_set%maxocc, smear%method)
     546          192 :                mo_set%mu = gce_mu
     547          192 :                gce%prev_workfunction = gce%ref_esp - mo_set%mu
     548          192 :                is_large = ABS(mo_set%occupation_numbers(1) - mo_set%maxocc) > smear%eps_fermi_dirac
     549          192 :                CPWARN_IF(is_large .AND. my_emit_warnings, "Fermi-Dirac smearing includes the first MO")
     550              :             END IF
     551         1600 :             DO i = 1, SIZE(mo_set%occupation_numbers)
     552         1600 :                IF (mo_set%occupation_numbers(i) < mo_set%maxocc) THEN
     553          208 :                   mo_set%lfomo = i
     554          208 :                   EXIT
     555              :                END IF
     556              :             END DO
     557         2168 :             DO i = SIZE(mo_set%occupation_numbers), 1, -1
     558         2168 :                IF (ABS(mo_set%occupation_numbers(i)) > smear%eps_fermi_dirac) THEN
     559          208 :                   mo_set%homo = i
     560          208 :                   EXIT
     561              :                END IF
     562              :             END DO
     563          208 :             mo_set%uniform_occupation = .FALSE.
     564          208 :             mo_set%n_el_f = my_nelec
     565          208 :             CALL timestop(handle)
     566          208 :             RETURN
     567              :          END IF
     568              : 
     569       268090 :          IF (MODULO(mo_set%nelectron, INT(mo_set%maxocc)) == 0) THEN
     570       266994 :             nomo = NINT(mo_set%nelectron/mo_set%maxocc)
     571              :             ! Initialize MO occupations
     572      2426087 :             mo_set%occupation_numbers(1:nomo) = mo_set%maxocc
     573              :          ELSE
     574         1096 :             nomo = INT(mo_set%nelectron/mo_set%maxocc) + 1
     575              :             ! Initialize MO occupations
     576         6652 :             mo_set%occupation_numbers(1:nomo - 1) = mo_set%maxocc
     577         1096 :             mo_set%occupation_numbers(nomo) = mo_set%nelectron - (nomo - 1)*mo_set%maxocc
     578              :          END IF
     579              : ! introduce applied potential correction here
     580              : ! electron density is adjusted according to applied core correction
     581              : ! ref: SS, MT, MWF, JN PRL, 2018, 120, 246801
     582              : ! see whether both surface dipole correction and core correction is present in
     583              : ! the inputfile
     584       268090 :          IF (PRESENT(tot_zeff_corr)) THEN
     585              : ! find the additional core charges
     586          106 :             total_zeff_corr = tot_zeff_corr
     587          106 :             IF (INT(mo_set%maxocc) == 1) total_zeff_corr = total_zeff_corr/2.0_dp
     588          106 :             delectron = 0.0_dp
     589          106 :             IF (total_zeff_corr < 0.0_dp) THEN
     590              : ! remove electron density from the mos
     591          106 :                delectron = ABS(total_zeff_corr) - REAL(mo_set%maxocc, KIND=dp)
     592          106 :                IF (delectron > 0.0_dp) THEN
     593            0 :                   mo_set%occupation_numbers(nomo) = 0.0_dp
     594            0 :                   irmo = CEILING(delectron/REAL(mo_set%maxocc, KIND=dp))
     595            0 :                   DO ir = 1, irmo
     596            0 :                      delectron = delectron - REAL(mo_set%maxocc, KIND=dp)
     597            0 :                      IF (delectron < 0.0_dp) THEN
     598            0 :                         mo_set%occupation_numbers(nomo - ir) = -delectron
     599              :                      ELSE
     600            0 :                         mo_set%occupation_numbers(nomo - ir) = 0.0_dp
     601              :                      END IF
     602              :                   END DO
     603            0 :                   nomo = nomo - irmo
     604            0 :                   IF (mo_set%occupation_numbers(nomo) == 0.0_dp) nomo = nomo - 1
     605          106 :                ELSE IF (delectron < 0.0_dp) THEN
     606          106 :                   mo_set%occupation_numbers(nomo) = -delectron
     607              :                ELSE
     608            0 :                   mo_set%occupation_numbers(nomo) = 0.0_dp
     609            0 :                   nomo = nomo - 1
     610              :                END IF
     611            0 :             ELSE IF (total_zeff_corr > 0.0_dp) THEN
     612              : ! add electron density to the mos
     613            0 :                delectron = total_zeff_corr - REAL(mo_set%maxocc, KIND=dp)
     614            0 :                IF (delectron > 0.0_dp) THEN
     615            0 :                   mo_set%occupation_numbers(nomo + 1) = REAL(mo_set%maxocc, KIND=dp)
     616            0 :                   nomo = nomo + 1
     617            0 :                   irmo = CEILING(delectron/REAL(mo_set%maxocc, KIND=dp))
     618            0 :                   DO ir = 1, irmo
     619            0 :                      delectron = delectron - REAL(mo_set%maxocc, KIND=dp)
     620            0 :                      IF (delectron < 0.0_dp) THEN
     621            0 :                         mo_set%occupation_numbers(nomo + ir) = delectron + REAL(mo_set%maxocc, KIND=dp)
     622              :                      ELSE
     623            0 :                         mo_set%occupation_numbers(nomo + ir) = REAL(mo_set%maxocc, KIND=dp)
     624              :                      END IF
     625              :                   END DO
     626            0 :                   nomo = nomo + irmo
     627              :                ELSE
     628            0 :                   mo_set%occupation_numbers(nomo + 1) = total_zeff_corr
     629            0 :                   nomo = nomo + 1
     630              :                END IF
     631              :             END IF
     632              :          END IF
     633              :       END IF
     634       268888 :       nmo = SIZE(mo_set%eigenvalues)
     635              : 
     636       268888 :       CPASSERT(nmo >= nomo)
     637       268888 :       CPASSERT((SIZE(mo_set%occupation_numbers) == nmo))
     638              : 
     639       268888 :       mo_set%homo = nomo
     640       268888 :       mo_set%lfomo = nomo + 1
     641       268888 :       mo_set%mu = mo_set%eigenvalues(nomo)
     642              : 
     643              :       ! Check consistency of the array lengths
     644       268888 :       IF (PRESENT(eval_deriv)) THEN
     645            0 :          equal_size = (SIZE(mo_set%occupation_numbers, 1) == SIZE(eval_deriv, 1))
     646            0 :          CPASSERT(equal_size)
     647              :       END IF
     648              : 
     649              : !calling of HP module HERE, before smear
     650       268888 :       IF (PRESENT(probe)) THEN
     651           14 :          i_first = 1
     652           14 :          IF (smear%fixed_mag_mom == -1.0_dp) THEN
     653            0 :             nelec = REAL(mo_set%nelectron, dp)
     654              :          ELSE
     655           14 :             nelec = mo_set%n_el_f
     656              :          END IF
     657              : 
     658          294 :          mo_set%occupation_numbers(:) = 0.0_dp
     659              : 
     660              :          CALL probe_occupancy(mo_set%occupation_numbers, mo_set%mu, mo_set%kTS, &
     661              :                               mo_set%eigenvalues, mo_set%mo_coeff, mo_set%maxocc, &
     662           14 :                               probe, N=nelec)
     663              :          !NB: mu and T are taken from the hairy_probe type (defined in cp_control_types.F); these values are set in the input
     664              : 
     665              :          ! Find the lowest fractional occupied MO (LFOMO)
     666          198 :          DO imo = i_first, nmo
     667          198 :             IF (mo_set%occupation_numbers(imo) < mo_set%maxocc) THEN
     668           14 :                mo_set%lfomo = imo
     669           14 :                EXIT
     670              :             END IF
     671              :          END DO
     672          294 :          is_large = ABS(MAXVAL(mo_set%occupation_numbers) - mo_set%maxocc) > probe(1)%eps_hp
     673              :          ! this is not a real problem, but the temperature might be a bit large
     674           14 :          IF (is_large .AND. my_emit_warnings) THEN
     675            0 :             CPWARN("Hair-probes occupancy distribution includes the first MO")
     676              :          END IF
     677              : 
     678              :          ! Find the highest (fractional) occupied MO which will be now the HOMO
     679           22 :          DO imo = nmo, mo_set%lfomo, -1
     680           22 :             IF (mo_set%occupation_numbers(imo) > probe(1)%eps_hp) THEN
     681           14 :                mo_set%homo = imo
     682           14 :                EXIT
     683              :             END IF
     684              :          END DO
     685          294 :          is_large = ABS(MINVAL(mo_set%occupation_numbers)) > probe(1)%eps_hp
     686           14 :          IF (is_large .AND. my_emit_warnings) THEN
     687              :             CALL cp_warn(__LOCATION__, &
     688              :                          "Hair-probes occupancy distribution includes the last MO => "// &
     689            6 :                          "Add more MOs for proper smearing.")
     690              :          END IF
     691              : 
     692              :          ! check that the total electron count is accurate
     693           14 :          is_large = (ABS(nelec - accurate_sum(mo_set%occupation_numbers(:))) > probe(1)%eps_hp*nelec)
     694           14 :          IF (is_large .AND. my_emit_warnings) THEN
     695            0 :             CPWARN("Total number of electrons is not accurate")
     696              :          END IF
     697              : 
     698              :       END IF
     699              : 
     700              :       ! Quick return, if no smearing information is supplied (TO BE FIXED, smear should become non-optional...)
     701       268888 :       IF (.NOT. PRESENT(smear)) THEN
     702              :          ! there is no dependence of the energy on the eigenvalues
     703          230 :          mo_set%uniform_occupation = .TRUE.
     704          230 :          IF (PRESENT(eval_deriv)) THEN
     705            0 :             eval_deriv = 0.0_dp
     706              :          END IF
     707          230 :          CALL timestop(handle)
     708          230 :          RETURN
     709              :       END IF
     710              : 
     711              :       ! Check if proper eigenvalues are already available
     712       268658 :       IF (smear%method /= smear_list) THEN
     713       268658 :          IF ((ABS(mo_set%eigenvalues(1)) < 1.0E-12_dp) .AND. &
     714              :              (ABS(mo_set%eigenvalues(nmo)) < 1.0E-12_dp)) THEN
     715        60924 :             CALL timestop(handle)
     716        60924 :             RETURN
     717              :          END IF
     718              :       END IF
     719              : 
     720              :       ! Perform smearing
     721       207734 :       IF (smear%do_smear) THEN
     722        24450 :          IF (PRESENT(xas_env)) THEN
     723           30 :             i_first = xas_estate + 1
     724           30 :             nelec = xas_nelectron
     725              :          ELSE
     726        24420 :             i_first = 1
     727        24420 :             IF (smear%fixed_mag_mom == -1.0_dp) THEN
     728          782 :                nelec = REAL(mo_set%nelectron, dp)
     729              :             ELSE
     730        23638 :                nelec = mo_set%n_el_f
     731              :             END IF
     732              :          END IF
     733        22896 :          SELECT CASE (smear%method)
     734              :          CASE (smear_fermi_dirac)
     735        22896 :             IF (.NOT. PRESENT(eval_deriv)) THEN
     736              :                CALL SmearFixed(mo_set%occupation_numbers(1:mo_set%nmo), mo_set%mu, mo_set%kTS, &
     737              :                                mo_set%eigenvalues(1:mo_set%nmo), Nelec, &
     738              :                                smear%electronic_temperature, mo_set%maxocc, smear_fermi_dirac, &
     739        22896 :                                xas_estate, occ_estate)
     740              :             ELSE
     741            0 :                IF (.NOT. ALLOCATED(tmp_v)) ALLOCATE (tmp_v(SIZE(eval_deriv)))
     742            0 :                tmp_v(:) = eval_deriv - mo_set%eigenvalues + mo_set%mu
     743              :                CALL SmearFixedDerivMV(eval_deriv, mo_set%occupation_numbers(1:mo_set%nmo), mo_set%mu, &
     744              :                                       mo_set%kTS, mo_set%eigenvalues(1:mo_set%nmo), Nelec, &
     745              :                                       smear%electronic_temperature, mo_set%maxocc, smear_fermi_dirac, &
     746            0 :                                       tmp_v, xas_estate, occ_estate)
     747              :             END IF
     748              : 
     749              :             ! Find the lowest fractional occupied MO (LFOMO)
     750       209632 :             DO imo = i_first, nmo
     751       209632 :                IF (mo_set%occupation_numbers(imo) < mo_set%maxocc) THEN
     752        22896 :                   mo_set%lfomo = imo
     753        22896 :                   EXIT
     754              :                END IF
     755              :             END DO
     756        22896 :             IF (i_first <= nmo) THEN
     757        22896 :                is_large = ABS(mo_set%occupation_numbers(i_first) - mo_set%maxocc) > smear%eps_fermi_dirac
     758              :             ELSE
     759              :                is_large = .FALSE.
     760              :             END IF
     761              :             ! this is not a real problem, but the temperature might be a bit large
     762        22896 :             CPWARN_IF(is_large .AND. my_emit_warnings, "Fermi-Dirac smearing includes the first MO")
     763              : 
     764              :             ! Find the highest (fractional) occupied MO which will be now the HOMO
     765       423970 :             DO imo = nmo, mo_set%lfomo, -1
     766       423970 :                IF (mo_set%occupation_numbers(imo) > smear%eps_fermi_dirac) THEN
     767        14964 :                   mo_set%homo = imo
     768        14964 :                   EXIT
     769              :                END IF
     770              :             END DO
     771       674006 :             is_large = ABS(MINVAL(mo_set%occupation_numbers)) > smear%eps_fermi_dirac
     772        22896 :             IF (is_large .AND. my_emit_warnings) THEN
     773              :                CALL cp_warn(__LOCATION__, &
     774              :                             "Fermi-Dirac smearing includes the last MO => "// &
     775          684 :                             "Add more MOs for proper smearing.")
     776              :             END IF
     777              : 
     778              :             ! check that the total electron count is accurate
     779        22896 :             is_large = (ABS(nelec - accurate_sum(mo_set%occupation_numbers(:))) > smear%eps_fermi_dirac*nelec)
     780        22896 :             CPWARN_IF(is_large .AND. my_emit_warnings, "Total number of electrons is not accurate")
     781              : 
     782              :          CASE (smear_gaussian, smear_mp, smear_mv)
     783         1396 :             IF (.NOT. PRESENT(eval_deriv)) THEN
     784              :                CALL SmearFixed(mo_set%occupation_numbers(1:mo_set%nmo), mo_set%mu, mo_set%kTS, &
     785              :                                mo_set%eigenvalues(1:mo_set%nmo), Nelec, &
     786              :                                smear%smearing_width, mo_set%maxocc, smear%method, &
     787         1396 :                                xas_estate, occ_estate)
     788              :             ELSE
     789            0 :                IF (.NOT. ALLOCATED(tmp_v)) ALLOCATE (tmp_v(SIZE(eval_deriv)))
     790            0 :                tmp_v(:) = eval_deriv - mo_set%eigenvalues + mo_set%mu
     791              :                CALL SmearFixedDerivMV(eval_deriv, mo_set%occupation_numbers(1:mo_set%nmo), mo_set%mu, &
     792              :                                       mo_set%kTS, mo_set%eigenvalues(1:mo_set%nmo), Nelec, &
     793              :                                       smear%smearing_width, mo_set%maxocc, smear%method, &
     794            0 :                                       tmp_v, xas_estate, occ_estate)
     795              :             END IF
     796              : 
     797              :             ! Method label for warnings
     798         2792 :             SELECT CASE (smear%method)
     799              :             CASE (smear_gaussian)
     800         1396 :                method_label = "Gaussian"
     801              :             CASE (smear_mp)
     802            0 :                method_label = "Methfessel-Paxton"
     803              :             CASE (smear_mv)
     804         1396 :                method_label = "Marzari-Vanderbilt"
     805              :             END SELECT
     806              : 
     807              :             ! Find the lowest fractional occupied MO (LFOMO)
     808        18004 :             DO imo = i_first, nmo
     809        18004 :                IF (ABS(mo_set%occupation_numbers(imo) - mo_set%maxocc) > smear%eps_fermi_dirac) THEN
     810         1396 :                   mo_set%lfomo = imo
     811         1396 :                   EXIT
     812              :                END IF
     813              :             END DO
     814         1396 :             IF (i_first <= nmo) THEN
     815         1396 :                is_large = ABS(mo_set%occupation_numbers(i_first) - mo_set%maxocc) > smear%eps_fermi_dirac
     816              :             ELSE
     817              :                is_large = .FALSE.
     818              :             END IF
     819         1396 :             IF (is_large .AND. my_emit_warnings) THEN
     820            0 :                CPWARN(TRIM(method_label)//" smearing includes the first MO")
     821              :             END IF
     822              : 
     823              :             ! Find the highest (fractional) occupied MO which will be now the HOMO
     824        17210 :             DO imo = nmo, mo_set%lfomo, -1
     825        17210 :                IF (ABS(mo_set%occupation_numbers(imo)) > smear%eps_fermi_dirac) THEN
     826          964 :                   mo_set%homo = imo
     827          964 :                   EXIT
     828              :                END IF
     829              :             END DO
     830         1396 :             is_large = ABS(mo_set%occupation_numbers(nmo)) > smear%eps_fermi_dirac
     831         1396 :             IF (is_large .AND. my_emit_warnings) THEN
     832              :                CALL cp_warn(__LOCATION__, &
     833              :                             TRIM(method_label)//" smearing includes the last MO => "// &
     834            0 :                             "Add more MOs for proper smearing.")
     835              :             END IF
     836              : 
     837              :             ! Check that the total electron count is accurate
     838         1396 :             is_large = (ABS(nelec - accurate_sum(mo_set%occupation_numbers(:))) > smear%eps_fermi_dirac*nelec)
     839         1396 :             CPWARN_IF(is_large .AND. my_emit_warnings, "Total number of electrons is not accurate")
     840              : 
     841              :          CASE (smear_energy_window)
     842              :             ! not implemented
     843          158 :             CPASSERT(.NOT. PRESENT(eval_deriv))
     844              : 
     845              :             ! Define the energy window for the eigenvalues
     846          158 :             e1 = mo_set%eigenvalues(mo_set%homo) - 0.5_dp*smear%window_size
     847          158 :             IF (e1 <= mo_set%eigenvalues(1) .AND. my_emit_warnings) THEN
     848            0 :                CPWARN("Energy window for smearing includes the first MO")
     849              :             END IF
     850              : 
     851          158 :             e2 = mo_set%eigenvalues(mo_set%homo) + 0.5_dp*smear%window_size
     852          158 :             IF (e2 >= mo_set%eigenvalues(nmo) .AND. my_emit_warnings) THEN
     853              :                CALL cp_warn(__LOCATION__, &
     854              :                             "Energy window for smearing includes the last MO => "// &
     855            0 :                             "Add more MOs for proper smearing.")
     856              :             END IF
     857              : 
     858              :             ! Find the lowest fractional occupied MO (LFOMO)
     859         2636 :             DO imo = i_first, nomo
     860         2636 :                IF (mo_set%eigenvalues(imo) > e1) THEN
     861          158 :                   mo_set%lfomo = imo
     862          158 :                   EXIT
     863              :                END IF
     864              :             END DO
     865              : 
     866              :             ! Find the highest fractional occupied (non-zero) MO which will be the HOMO
     867         1344 :             DO imo = nmo, nomo, -1
     868         1344 :                IF (mo_set%eigenvalues(imo) < e2) THEN
     869          158 :                   mo_set%homo = imo
     870          158 :                   EXIT
     871              :                END IF
     872              :             END DO
     873              : 
     874              :             ! Get the number of electrons to be smeared
     875          158 :             edist = 0.0_dp
     876          158 :             nelec = 0.0_dp
     877              : 
     878          390 :             DO imo = mo_set%lfomo, mo_set%homo
     879          232 :                nelec = nelec + mo_set%occupation_numbers(imo)
     880          390 :                edist = edist + ABS(e2 - mo_set%eigenvalues(imo))
     881              :             END DO
     882              : 
     883              :             ! Smear electrons inside the energy window
     884          390 :             DO imo = mo_set%lfomo, mo_set%homo
     885          232 :                edelta = ABS(e2 - mo_set%eigenvalues(imo))
     886          232 :                mo_set%occupation_numbers(imo) = MIN(mo_set%maxocc, nelec*edelta/edist)
     887          232 :                nelec = nelec - mo_set%occupation_numbers(imo)
     888          390 :                edist = edist - edelta
     889              :             END DO
     890              : 
     891              :          CASE (smear_list)
     892            0 :             equal_size = SIZE(mo_set%occupation_numbers, 1) == SIZE(smear%list, 1)
     893            0 :             CPASSERT(equal_size)
     894            0 :             mo_set%occupation_numbers = smear%list
     895              :             ! there is no dependence of the energy on the eigenvalues
     896            0 :             IF (PRESENT(eval_deriv)) THEN
     897            0 :                eval_deriv = 0.0_dp
     898              :             END IF
     899              :             ! most general case
     900            0 :             mo_set%lfomo = 1
     901        24450 :             mo_set%homo = nmo
     902              :          END SELECT
     903              : 
     904              :          ! Check, if the smearing involves more than one MO
     905        24450 :          IF (mo_set%lfomo == mo_set%homo) THEN
     906         1578 :             mo_set%homo = nomo
     907         1578 :             mo_set%lfomo = nomo + 1
     908              :          ELSE
     909        22872 :             mo_set%uniform_occupation = .FALSE.
     910              :          END IF
     911              : 
     912              :       END IF ! do smear
     913              : 
     914              :       ! zeros don't count as uniform
     915       207734 :       mo_set%uniform_occupation = has_uniform_occupation(mo_set=mo_set)
     916              : 
     917       207734 :       IF (ALLOCATED(tmp_v)) DEALLOCATE (tmp_v)
     918       207734 :       CALL timestop(handle)
     919              : 
     920       207734 :    END SUBROUTINE set_mo_occupation_1
     921              : 
     922              : END MODULE qs_mo_occupation
        

Generated by: LCOV version 2.0-1