LCOV - code coverage report
Current view: top level - src - qs_kpoint_state.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:24d69ee) Lines: 95.1 % 225 214
Test Date: 2026-09-03 07:32:15 Functions: 100.0 % 6 6

            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 Methods for preparing and committing k-point orbital states to the QS environment.
      10              : ! **************************************************************************************************
      11              : MODULE qs_kpoint_state
      12              :    USE cp_cfm_basic_linalg,             ONLY: cp_cfm_gemm,&
      13              :                                               cp_cfm_scale
      14              :    USE cp_cfm_diag,                     ONLY: cp_cfm_geeig,&
      15              :                                               cp_cfm_heevd
      16              :    USE cp_cfm_types,                    ONLY: cp_cfm_create,&
      17              :                                               cp_cfm_release,&
      18              :                                               cp_cfm_to_cfm,&
      19              :                                               cp_cfm_to_fm,&
      20              :                                               cp_cfm_type,&
      21              :                                               cp_fm_to_cfm
      22              :    USE cp_dbcsr_api,                    ONLY: dbcsr_p_type
      23              :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      24              :                                               cp_fm_struct_release,&
      25              :                                               cp_fm_struct_type
      26              :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      27              :                                               cp_fm_get_info,&
      28              :                                               cp_fm_release,&
      29              :                                               cp_fm_set_all,&
      30              :                                               cp_fm_to_fm,&
      31              :                                               cp_fm_type,&
      32              :                                               cp_fm_vectorsnorm
      33              :    USE kinds,                           ONLY: dp
      34              :    USE kpoint_methods,                  ONLY: kpoint_density_matrices,&
      35              :                                               kpoint_density_transform,&
      36              :                                               kpoint_set_mo_occupation
      37              :    USE kpoint_types,                    ONLY: get_kpoint_info,&
      38              :                                               kpoint_env_type,&
      39              :                                               kpoint_type
      40              :    USE mathconstants,                   ONLY: z_one,&
      41              :                                               z_zero
      42              :    USE message_passing,                 ONLY: mp_para_env_type
      43              :    USE qs_energy_types,                 ONLY: qs_energy_type
      44              :    USE qs_environment_types,            ONLY: get_qs_env,&
      45              :                                               qs_environment_type
      46              :    USE qs_ks_types,                     ONLY: qs_ks_did_change
      47              :    USE qs_mo_types,                     ONLY: get_mo_set,&
      48              :                                               mo_set_type
      49              :    USE qs_neighbor_list_types,          ONLY: neighbor_list_set_p_type
      50              :    USE qs_rho_methods,                  ONLY: qs_rho_update_rho
      51              :    USE qs_rho_types,                    ONLY: qs_rho_get,&
      52              :                                               qs_rho_type
      53              :    USE qs_scf_types,                    ONLY: qs_scf_env_type
      54              :    USE scf_control_types,               ONLY: scf_control_type
      55              : #include "./base/base_uses.f90"
      56              : 
      57              :    IMPLICIT NONE
      58              :    PRIVATE
      59              : 
      60              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_kpoint_state'
      61              : 
      62              :    PUBLIC :: qs_kpoint_copy_spin_mos, qs_kpoint_mos_initialized, &
      63              :              qs_kpoint_state_canonicalize_fixed, qs_kpoint_state_commit, &
      64              :              qs_kpoint_state_prepare_fixed_density
      65              : 
      66              : CONTAINS
      67              : 
      68              : ! **************************************************************************************************
      69              : !> \brief Reconstructs fixed-rank complex k-point orbitals from a density kernel.
      70              : !>        The density and overlap must first be transferred to kp%ot_hmat and kp%ot_smat. The
      71              : !>        largest natural-orbital subspace gives a metric-defined fixed-rank projector without
      72              : !>        replacing the guess by the ground-state projector of its initial Hamiltonian.
      73              : !> \param kpoints K-point environment containing the transferred density and overlap matrices.
      74              : ! **************************************************************************************************
      75           44 :    SUBROUTINE qs_kpoint_state_prepare_fixed_density(kpoints)
      76              :       TYPE(kpoint_type), POINTER                         :: kpoints
      77              : 
      78              :       INTEGER                                            :: ikpoint_local, ispin, nao, nmo, nocc
      79              :       LOGICAL                                            :: use_real_wfn
      80           44 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: density_eigenvalues
      81              :       TYPE(cp_cfm_type)                                  :: density_metric, density_work, matrix_p, &
      82              :                                                             matrix_s, matrix_s_work, projected
      83              :       TYPE(cp_fm_struct_type), POINTER                   :: active_struct, square_struct
      84              :       TYPE(cp_fm_type)                                   :: active_im, active_re
      85              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff_im, mo_coeff_re
      86              :       TYPE(kpoint_env_type), POINTER                     :: kp
      87              : 
      88           44 :       NULLIFY (active_struct, kp, mo_coeff_im, mo_coeff_re, square_struct)
      89              : 
      90            0 :       CPASSERT(ASSOCIATED(kpoints))
      91           44 :       CPASSERT(ASSOCIATED(kpoints%kp_env))
      92           44 :       CALL get_kpoint_info(kpoints, use_real_wfn=use_real_wfn)
      93           44 :       IF (use_real_wfn) THEN
      94            0 :          CPABORT("Fixed-density k-point OT initialization requires complex wavefunctions.")
      95              :       END IF
      96              : 
      97          152 :       DO ikpoint_local = 1, SIZE(kpoints%kp_env)
      98          108 :          kp => kpoints%kp_env(ikpoint_local)%kpoint_env
      99          108 :          CPASSERT(ASSOCIATED(kp))
     100          108 :          CPASSERT(ASSOCIATED(kp%mos))
     101          108 :          CPASSERT(ASSOCIATED(kp%ot_hmat))
     102          108 :          CPASSERT(ASSOCIATED(kp%ot_smat))
     103          108 :          CPASSERT(SIZE(kp%ot_hmat, 1) >= 2)
     104          108 :          CPASSERT(SIZE(kp%ot_hmat, 2) >= SIZE(kp%mos, 2))
     105          108 :          CPASSERT(SIZE(kp%ot_smat) >= 2)
     106              : 
     107          108 :          CALL cp_fm_get_info(kp%ot_hmat(1, 1), matrix_struct=square_struct, nrow_global=nao)
     108          108 :          CALL cp_cfm_create(matrix_p, square_struct, name="natural-orbital density P(k)")
     109          108 :          CALL cp_cfm_create(matrix_s, square_struct, name="natural-orbital overlap S(k)")
     110          108 :          CALL cp_fm_to_cfm(kp%ot_smat(1), kp%ot_smat(2), matrix_s)
     111              : 
     112          236 :          DO ispin = 1, SIZE(kp%mos, 2)
     113          128 :             CALL get_mo_set(kp%mos(1, ispin), homo=nocc, mo_coeff=mo_coeff_re, nmo=nmo)
     114          128 :             CALL get_mo_set(kp%mos(2, ispin), mo_coeff=mo_coeff_im)
     115          128 :             CPASSERT(ASSOCIATED(mo_coeff_re))
     116          128 :             CPASSERT(ASSOCIATED(mo_coeff_im))
     117          128 :             CPASSERT(nocc >= 1 .AND. nocc <= nmo)
     118              : 
     119              :             CALL cp_fm_struct_create(active_struct, template_fmstruct=mo_coeff_re%matrix_struct, &
     120          128 :                                      ncol_global=nocc)
     121          128 :             CALL cp_fm_to_cfm(kp%ot_hmat(1, ispin), kp%ot_hmat(2, ispin), matrix_p)
     122          128 :             CALL cp_cfm_create(projected, active_struct, name="fixed-density natural orbitals")
     123          128 :             CALL cp_cfm_create(density_metric, square_struct, name="natural-orbital metric")
     124          128 :             CALL cp_cfm_create(density_work, square_struct, name="natural-orbital work")
     125          128 :             CALL cp_cfm_create(matrix_s_work, square_struct, name="natural-orbital overlap work")
     126              : 
     127              :             ! The largest eigenvectors of S*P*S*C = S*C*n are the natural orbitals of
     128              :             ! S**(1/2)*P*S**(1/2). Negating the left-hand side lets the generalized
     129              :             ! eigensolver request only its lowest nocc eigenpairs when supported.
     130              :             CALL cp_cfm_gemm('N', 'N', nao, nao, nao, z_one, matrix_p, matrix_s, &
     131          128 :                              z_zero, density_work)
     132              :             CALL cp_cfm_gemm('N', 'N', nao, nao, nao, z_one, matrix_s, density_work, &
     133          128 :                              z_zero, density_metric)
     134          128 :             CALL cp_cfm_scale(-z_one, density_metric)
     135          128 :             CALL cp_cfm_to_cfm(matrix_s, matrix_s_work)
     136          384 :             ALLOCATE (density_eigenvalues(nocc))
     137              :             CALL cp_cfm_geeig(density_metric, matrix_s_work, projected, &
     138          128 :                               density_eigenvalues, density_work, lowest_subset=.TRUE.)
     139          128 :             DEALLOCATE (density_eigenvalues)
     140              : 
     141          128 :             CALL cp_fm_create(active_re, active_struct, name="fixed-density orbitals real")
     142          128 :             CALL cp_fm_create(active_im, active_struct, name="fixed-density orbitals imaginary")
     143          128 :             CALL cp_cfm_to_fm(projected, active_re, active_im)
     144          128 :             CALL cp_fm_set_all(mo_coeff_re, 0.0_dp)
     145          128 :             CALL cp_fm_set_all(mo_coeff_im, 0.0_dp)
     146          128 :             CALL cp_fm_to_fm(active_re, mo_coeff_re, nocc)
     147          128 :             CALL cp_fm_to_fm(active_im, mo_coeff_im, nocc)
     148              : 
     149          128 :             CALL cp_fm_release(active_im)
     150          128 :             CALL cp_fm_release(active_re)
     151          128 :             CALL cp_cfm_release(matrix_s_work)
     152          128 :             CALL cp_cfm_release(density_work)
     153          128 :             CALL cp_cfm_release(density_metric)
     154          128 :             CALL cp_cfm_release(projected)
     155          620 :             CALL cp_fm_struct_release(active_struct)
     156              :          END DO
     157              : 
     158          108 :          CALL cp_cfm_release(matrix_s)
     159          260 :          CALL cp_cfm_release(matrix_p)
     160              :       END DO
     161              : 
     162           88 :    END SUBROUTINE qs_kpoint_state_prepare_fixed_density
     163              : 
     164              : ! **************************************************************************************************
     165              : !> \brief Rotates a uniformly occupied k-point subspace into Ritz states of the current
     166              : !>        Hamiltonian and stores their energy labels. The Hamiltonian must first be transferred
     167              : !>        to kp%ot_hmat. Since the rotation is internal to a uniformly occupied subspace, it does
     168              : !>        not change the density represented by the orbitals.
     169              : !> \param kpoints K-point environment containing the orbitals and transferred Hamiltonians.
     170              : ! **************************************************************************************************
     171           44 :    SUBROUTINE qs_kpoint_state_canonicalize_fixed(kpoints)
     172              :       TYPE(kpoint_type), POINTER                         :: kpoints
     173              : 
     174              :       INTEGER                                            :: ikpoint_local, ispin, nao, nmo, nocc
     175              :       LOGICAL                                            :: use_real_wfn
     176           44 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: ritz_values
     177           44 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: eigenvalues_im, eigenvalues_re
     178              :       TYPE(cp_cfm_type)                                  :: coeff, eigenvectors, hblock, hc, &
     179              :                                                             matrix_h, rotated
     180              :       TYPE(cp_fm_struct_type), POINTER                   :: active_struct, square_struct
     181              :       TYPE(cp_fm_type)                                   :: active_im, active_re
     182              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff_im, mo_coeff_re
     183              :       TYPE(kpoint_env_type), POINTER                     :: kp
     184              : 
     185           44 :       NULLIFY (active_struct, eigenvalues_im, eigenvalues_re, kp, mo_coeff_im, mo_coeff_re, &
     186           44 :                square_struct)
     187              : 
     188            0 :       CPASSERT(ASSOCIATED(kpoints))
     189           44 :       CPASSERT(ASSOCIATED(kpoints%kp_env))
     190           44 :       CALL get_kpoint_info(kpoints, use_real_wfn=use_real_wfn)
     191           44 :       IF (use_real_wfn) THEN
     192            0 :          CPABORT("Fixed-density k-point OT canonicalization requires complex wavefunctions.")
     193              :       END IF
     194              : 
     195          152 :       DO ikpoint_local = 1, SIZE(kpoints%kp_env)
     196          108 :          kp => kpoints%kp_env(ikpoint_local)%kpoint_env
     197          108 :          CPASSERT(ASSOCIATED(kp))
     198          108 :          CPASSERT(ASSOCIATED(kp%mos))
     199          108 :          CPASSERT(ASSOCIATED(kp%ot_hmat))
     200          108 :          CPASSERT(SIZE(kp%ot_hmat, 1) >= 2)
     201          108 :          CPASSERT(SIZE(kp%ot_hmat, 2) >= SIZE(kp%mos, 2))
     202              : 
     203          108 :          CALL cp_fm_get_info(kp%ot_hmat(1, 1), matrix_struct=square_struct, nrow_global=nao)
     204          108 :          CALL cp_cfm_create(matrix_h, square_struct, name="fixed-density Ritz Hamiltonian")
     205              : 
     206          236 :          DO ispin = 1, SIZE(kp%mos, 2)
     207              :             CALL get_mo_set(kp%mos(1, ispin), homo=nocc, mo_coeff=mo_coeff_re, nmo=nmo, &
     208          128 :                             eigenvalues=eigenvalues_re)
     209              :             CALL get_mo_set(kp%mos(2, ispin), mo_coeff=mo_coeff_im, &
     210          128 :                             eigenvalues=eigenvalues_im)
     211          128 :             CPASSERT(ASSOCIATED(mo_coeff_re))
     212          128 :             CPASSERT(ASSOCIATED(mo_coeff_im))
     213          128 :             CPASSERT(ASSOCIATED(eigenvalues_re))
     214          128 :             CPASSERT(ASSOCIATED(eigenvalues_im))
     215          128 :             CPASSERT(nocc >= 1 .AND. nocc <= nmo)
     216          128 :             CPASSERT(SIZE(eigenvalues_re) >= nocc)
     217          128 :             CPASSERT(SIZE(eigenvalues_im) >= nocc)
     218              : 
     219              :             CALL cp_fm_struct_create(active_struct, template_fmstruct=mo_coeff_re%matrix_struct, &
     220          128 :                                      ncol_global=nocc)
     221          128 :             CALL cp_fm_create(active_re, active_struct, name="fixed-density Ritz orbitals real")
     222          128 :             CALL cp_fm_create(active_im, active_struct, name="fixed-density Ritz orbitals imaginary")
     223          128 :             CALL cp_fm_to_fm(mo_coeff_re, active_re, nocc)
     224          128 :             CALL cp_fm_to_fm(mo_coeff_im, active_im, nocc)
     225              : 
     226          128 :             CALL cp_cfm_create(coeff, active_struct, name="fixed-density Ritz orbitals")
     227          128 :             CALL cp_cfm_create(hc, active_struct, name="fixed-density Ritz HC")
     228          128 :             CALL cp_cfm_create(rotated, active_struct, name="fixed-density Ritz rotated orbitals")
     229              :             CALL cp_cfm_create(hblock, active_struct, nrow=nocc, ncol=nocc, &
     230          128 :                                name="fixed-density projected Hamiltonian")
     231              :             CALL cp_cfm_create(eigenvectors, active_struct, nrow=nocc, ncol=nocc, &
     232          128 :                                name="fixed-density Ritz eigenvectors")
     233          128 :             CALL cp_fm_to_cfm(kp%ot_hmat(1, ispin), kp%ot_hmat(2, ispin), matrix_h)
     234          128 :             CALL cp_fm_to_cfm(active_re, active_im, coeff)
     235              : 
     236          128 :             CALL cp_cfm_gemm('N', 'N', nao, nocc, nao, z_one, matrix_h, coeff, z_zero, hc)
     237          128 :             CALL cp_cfm_gemm('C', 'N', nocc, nocc, nao, z_one, coeff, hc, z_zero, hblock)
     238          384 :             ALLOCATE (ritz_values(nocc))
     239          128 :             CALL cp_cfm_heevd(hblock, eigenvectors, ritz_values)
     240              :             CALL cp_cfm_gemm('N', 'N', nao, nocc, nocc, z_one, coeff, eigenvectors, &
     241          128 :                              z_zero, rotated)
     242          128 :             CALL cp_cfm_to_fm(rotated, active_re, active_im)
     243          128 :             CALL cp_fm_to_fm(active_re, mo_coeff_re, nocc)
     244          128 :             CALL cp_fm_to_fm(active_im, mo_coeff_im, nocc)
     245          488 :             eigenvalues_re(1:nocc) = ritz_values
     246          488 :             eigenvalues_im(1:nocc) = ritz_values
     247          128 :             DEALLOCATE (ritz_values)
     248              : 
     249          128 :             CALL cp_cfm_release(eigenvectors)
     250          128 :             CALL cp_cfm_release(hblock)
     251          128 :             CALL cp_cfm_release(rotated)
     252          128 :             CALL cp_cfm_release(hc)
     253          128 :             CALL cp_cfm_release(coeff)
     254          128 :             CALL cp_fm_release(active_im)
     255          128 :             CALL cp_fm_release(active_re)
     256          620 :             CALL cp_fm_struct_release(active_struct)
     257              :          END DO
     258              : 
     259          260 :          CALL cp_cfm_release(matrix_h)
     260              :       END DO
     261              : 
     262           88 :    END SUBROUTINE qs_kpoint_state_canonicalize_fixed
     263              : 
     264              : ! **************************************************************************************************
     265              : !> \brief Rebuilds the physical density from the current k-point orbitals and occupations.
     266              : !> \param qs_env QS environment containing the orbital state to commit.
     267              : !> \param update_occupations Recompute occupations from the current MO energies and SCF settings.
     268              : !> \param separate_spin_occupations Fill restricted energy channels independently.
     269              : !> \param fixed_occupations Restore the fixed occupied rank required by OT.
     270              : ! **************************************************************************************************
     271          592 :    SUBROUTINE qs_kpoint_state_commit(qs_env, update_occupations, &
     272              :                                      separate_spin_occupations, fixed_occupations)
     273              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     274              :       LOGICAL, INTENT(IN)                                :: update_occupations
     275              :       LOGICAL, INTENT(IN), OPTIONAL                      :: separate_spin_occupations, &
     276              :                                                             fixed_occupations
     277              : 
     278              :       INTEGER                                            :: ispin
     279              :       LOGICAL                                            :: fixed, separate_spins
     280          592 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: matrix_s_kp, rho_ao_kp
     281              :       TYPE(kpoint_type), POINTER                         :: kpoints
     282          592 :       TYPE(mo_set_type), DIMENSION(:, :), POINTER        :: mos
     283              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
     284          592 :          POINTER                                         :: sab_nl
     285              :       TYPE(qs_energy_type), POINTER                      :: energy
     286              :       TYPE(qs_rho_type), POINTER                         :: rho
     287              :       TYPE(qs_scf_env_type), POINTER                     :: scf_env
     288              :       TYPE(scf_control_type), POINTER                    :: scf_control
     289              : 
     290          592 :       NULLIFY (energy, kpoints, matrix_s_kp, mos, rho_ao_kp, sab_nl, rho, scf_env, scf_control)
     291              : 
     292          592 :       fixed = .FALSE.
     293          592 :       separate_spins = .FALSE.
     294          126 :       IF (PRESENT(fixed_occupations)) fixed = fixed_occupations
     295          592 :       IF (PRESENT(separate_spin_occupations)) separate_spins = separate_spin_occupations
     296          592 :       IF (fixed .AND. .NOT. update_occupations) THEN
     297            0 :          CPABORT("Fixed occupations can only be requested while updating occupations.")
     298              :       END IF
     299              : 
     300              :       CALL get_qs_env(qs_env, kpoints=kpoints, matrix_s_kp=matrix_s_kp, &
     301          592 :                       energy=energy, rho=rho, scf_env=scf_env, scf_control=scf_control)
     302          592 :       CALL get_kpoint_info(kpoints, sab_nl=sab_nl)
     303              : 
     304          592 :       IF (update_occupations) THEN
     305              :          CALL kpoint_set_mo_occupation( &
     306          566 :             kpoints, scf_control%smear, separate_spin_occupations=separate_spins)
     307          566 :          IF (fixed) CALL qs_kpoint_set_fixed_occupations(kpoints)
     308              :       END IF
     309          592 :       CALL kpoint_density_matrices(kpoints)
     310          592 :       CALL qs_rho_get(rho, rho_ao_kp=rho_ao_kp)
     311              :       CALL kpoint_density_transform(kpoints, rho_ao_kp, .FALSE., &
     312              :                                     matrix_s_kp(1, 1)%matrix, sab_nl, scf_env%scf_work1, &
     313          592 :                                     overlap_rs=matrix_s_kp)
     314          592 :       CALL qs_rho_update_rho(rho, qs_env=qs_env)
     315          592 :       CALL qs_ks_did_change(qs_env%ks_env, rho_changed=.TRUE.)
     316              : 
     317          592 :       energy%kTS = 0.0_dp
     318          592 :       energy%efermi = 0.0_dp
     319          592 :       mos => kpoints%kp_env(1)%kpoint_env%mos
     320          592 :       CPASSERT(ASSOCIATED(mos))
     321         1230 :       DO ispin = 1, SIZE(mos, 2)
     322          638 :          energy%kTS = energy%kTS + mos(1, ispin)%kTS
     323         1230 :          energy%efermi = energy%efermi + mos(1, ispin)%mu
     324              :       END DO
     325          592 :       energy%efermi = energy%efermi/REAL(SIZE(mos, 2), KIND=dp)
     326              : 
     327          592 :    END SUBROUTINE qs_kpoint_state_commit
     328              : 
     329              : ! **************************************************************************************************
     330              : !> \brief Checks whether every local k-point channel contains nonzero occupied orbitals.
     331              : !> \param kpoints K-point environment.
     332              : !> \param require_full_space Require every available orbital instead of the occupied block.
     333              : !> \return True if every channel contains a nonzero real or imaginary coefficient.
     334              : ! **************************************************************************************************
     335          140 :    FUNCTION qs_kpoint_mos_initialized(kpoints, require_full_space) RESULT(initialized)
     336              :       TYPE(kpoint_type), POINTER                         :: kpoints
     337              :       LOGICAL, INTENT(IN), OPTIONAL                      :: require_full_space
     338              :       LOGICAL                                            :: initialized
     339              : 
     340              :       INTEGER                                            :: icomponent, ikpoint_local, ispin, &
     341              :                                                             nactive, nmo, nocc
     342              :       LOGICAL                                            :: full_space
     343              :       REAL(KIND=dp)                                      :: coefficient_norm
     344          140 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: column_norm, component_norm
     345              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
     346              :       TYPE(kpoint_env_type), POINTER                     :: kp
     347              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     348              : 
     349          140 :       NULLIFY (kp, mo_coeff, para_env)
     350          140 :       CPASSERT(ASSOCIATED(kpoints))
     351          140 :       CPASSERT(ASSOCIATED(kpoints%kp_env))
     352              : 
     353          140 :       full_space = .FALSE.
     354          140 :       IF (PRESENT(require_full_space)) full_space = require_full_space
     355          140 :       coefficient_norm = HUGE(1.0_dp)
     356          374 :       DO ikpoint_local = 1, SIZE(kpoints%kp_env)
     357          234 :          kp => kpoints%kp_env(ikpoint_local)%kpoint_env
     358          234 :          CPASSERT(ASSOCIATED(kp))
     359          234 :          CPASSERT(ASSOCIATED(kp%mos))
     360          648 :          DO ispin = 1, SIZE(kp%mos, 2)
     361          274 :             CALL get_mo_set(kp%mos(1, ispin), homo=nocc, mo_coeff=mo_coeff, nmo=nmo)
     362          274 :             CPASSERT(ASSOCIATED(mo_coeff))
     363          274 :             nactive = MERGE(nmo, nocc, full_space)
     364          274 :             IF (nactive < 1 .OR. nactive > nmo) THEN
     365            0 :                coefficient_norm = 0.0_dp
     366            0 :                CYCLE
     367              :             END IF
     368         1096 :             ALLOCATE (column_norm(nmo), component_norm(nmo))
     369          274 :             column_norm(:) = 0.0_dp
     370          822 :             DO icomponent = 1, SIZE(kp%mos, 1)
     371          548 :                CALL get_mo_set(kp%mos(icomponent, ispin), mo_coeff=mo_coeff)
     372          548 :                CPASSERT(ASSOCIATED(mo_coeff))
     373          548 :                CALL cp_fm_vectorsnorm(mo_coeff, component_norm)
     374         3894 :                column_norm(:) = column_norm(:) + component_norm(:)**2
     375              :             END DO
     376         1790 :             coefficient_norm = MIN(coefficient_norm, SQRT(MINVAL(column_norm(1:nactive))))
     377          782 :             DEALLOCATE (column_norm, component_norm)
     378              :          END DO
     379              :       END DO
     380              : 
     381          140 :       CALL get_kpoint_info(kpoints, para_env=para_env)
     382          140 :       CPASSERT(ASSOCIATED(para_env))
     383          140 :       CALL para_env%min(coefficient_norm)
     384          140 :       initialized = coefficient_norm > 100.0_dp*EPSILON(1.0_dp)
     385              : 
     386          140 :    END FUNCTION qs_kpoint_mos_initialized
     387              : 
     388              : ! **************************************************************************************************
     389              : !> \brief Copies the first k-point spin channel into the remaining channels.
     390              : !> \param kpoints K-point environment.
     391              : !> \param nspin Number of spin channels to populate.
     392              : ! **************************************************************************************************
     393           10 :    SUBROUTINE qs_kpoint_copy_spin_mos(kpoints, nspin)
     394              :       TYPE(kpoint_type), POINTER                         :: kpoints
     395              :       INTEGER, INTENT(IN)                                :: nspin
     396              : 
     397              :       INTEGER                                            :: icomponent, ikpoint_local, ispin
     398           10 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: eigenvalues_source, eigenvalues_target
     399              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff_source, mo_coeff_target
     400              :       TYPE(kpoint_env_type), POINTER                     :: kp
     401              : 
     402           10 :       NULLIFY (eigenvalues_source, eigenvalues_target, kp, mo_coeff_source, mo_coeff_target)
     403            0 :       CPASSERT(ASSOCIATED(kpoints))
     404           10 :       CPASSERT(ASSOCIATED(kpoints%kp_env))
     405           10 :       CPASSERT(nspin >= 1)
     406              : 
     407           24 :       DO ikpoint_local = 1, SIZE(kpoints%kp_env)
     408           14 :          kp => kpoints%kp_env(ikpoint_local)%kpoint_env
     409           14 :          CPASSERT(ASSOCIATED(kp))
     410           14 :          CPASSERT(ASSOCIATED(kp%mos))
     411           14 :          CPASSERT(SIZE(kp%mos, 2) >= nspin)
     412           52 :          DO icomponent = 1, SIZE(kp%mos, 1)
     413              :             CALL get_mo_set(kp%mos(icomponent, 1), mo_coeff=mo_coeff_source, &
     414           28 :                             eigenvalues=eigenvalues_source)
     415           28 :             CPASSERT(ASSOCIATED(mo_coeff_source))
     416           28 :             CPASSERT(ASSOCIATED(eigenvalues_source))
     417           70 :             DO ispin = 2, nspin
     418              :                CALL get_mo_set(kp%mos(icomponent, ispin), mo_coeff=mo_coeff_target, &
     419           28 :                                eigenvalues=eigenvalues_target)
     420           28 :                CPASSERT(ASSOCIATED(mo_coeff_target))
     421           28 :                CPASSERT(ASSOCIATED(eigenvalues_target))
     422           28 :                CALL cp_fm_to_fm(mo_coeff_source, mo_coeff_target)
     423          388 :                eigenvalues_target(:) = eigenvalues_source(:)
     424              :             END DO
     425              :          END DO
     426              :       END DO
     427              : 
     428           10 :    END SUBROUTINE qs_kpoint_copy_spin_mos
     429              : 
     430              : ! **************************************************************************************************
     431              : !> \brief Restores the fixed occupied rank required by k-point OT.
     432              : !> \param kpoints K-point environment.
     433              : ! **************************************************************************************************
     434           44 :    SUBROUTINE qs_kpoint_set_fixed_occupations(kpoints)
     435              :       TYPE(kpoint_type), POINTER                         :: kpoints
     436              : 
     437              :       INTEGER                                            :: icomponent, ikpoint_local, ispin, &
     438              :                                                             nelectron, nmo, nocc
     439              :       REAL(KIND=dp)                                      :: maxocc
     440           44 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: occupation_numbers
     441              :       TYPE(kpoint_env_type), POINTER                     :: kp
     442              : 
     443           44 :       NULLIFY (kp, occupation_numbers)
     444            0 :       CPASSERT(ASSOCIATED(kpoints))
     445           44 :       CPASSERT(ASSOCIATED(kpoints%kp_env))
     446              : 
     447          152 :       DO ikpoint_local = 1, SIZE(kpoints%kp_env)
     448          108 :          kp => kpoints%kp_env(ikpoint_local)%kpoint_env
     449          108 :          CPASSERT(ASSOCIATED(kp))
     450          108 :          CPASSERT(ASSOCIATED(kp%mos))
     451          280 :          DO ispin = 1, SIZE(kp%mos, 2)
     452          492 :             DO icomponent = 1, SIZE(kp%mos, 1)
     453              :                CALL get_mo_set(kp%mos(icomponent, ispin), homo=nocc, maxocc=maxocc, &
     454          256 :                                nelectron=nelectron, nmo=nmo, occupation_numbers=occupation_numbers)
     455          256 :                CPASSERT(ASSOCIATED(occupation_numbers))
     456          256 :                IF (nocc < 1 .OR. nocc > nmo) THEN
     457            0 :                   CPABORT("Fixed-occupation k-point OT requires a nonempty occupied subspace.")
     458              :                END IF
     459          256 :                IF (ABS(maxocc*REAL(nocc, KIND=dp) - REAL(nelectron, KIND=dp)) > &
     460              :                    100.0_dp*EPSILON(1.0_dp)) THEN
     461            0 :                   CPABORT("Fixed-occupation k-point OT requires uniform integer occupations.")
     462              :                END IF
     463         1016 :                occupation_numbers(:) = 0.0_dp
     464          976 :                occupation_numbers(1:nocc) = maxocc
     465          640 :                kp%mos(icomponent, ispin)%kTS = 0.0_dp
     466              :             END DO
     467              :          END DO
     468              :       END DO
     469              : 
     470           44 :    END SUBROUTINE qs_kpoint_set_fixed_occupations
     471              : 
     472              : END MODULE qs_kpoint_state
        

Generated by: LCOV version 2.0-1