LCOV - code coverage report
Current view: top level - src - rtp_admm_methods.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:24d69ee) Lines: 92.4 % 158 146
Test Date: 2026-09-03 07:32:15 Functions: 100.0 % 7 7

            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 Utilities for rtp in combination with admm methods
      10              : !>        adapted routines from admm_method (author Manuel Guidon)
      11              : !>
      12              : !> \par History    Use new "force only" overlap routine [07.2014,JGH]
      13              : !> \author Florian Schiffmann
      14              : ! **************************************************************************************************
      15              : MODULE rtp_admm_methods
      16              :    USE admm_types,                      ONLY: admm_env_create,&
      17              :                                               admm_type,&
      18              :                                               get_admm_env
      19              :    USE cp_control_types,                ONLY: admm_control_type,&
      20              :                                               dft_control_type
      21              :    USE cp_dbcsr_api,                    ONLY: &
      22              :         dbcsr_add, dbcsr_copy, dbcsr_create, dbcsr_deallocate_matrix, dbcsr_desymmetrize, &
      23              :         dbcsr_get_info, dbcsr_p_type, dbcsr_release, dbcsr_set, dbcsr_type, dbcsr_type_no_symmetry
      24              :    USE cp_dbcsr_operations,             ONLY: copy_dbcsr_to_fm,&
      25              :                                               copy_fm_to_dbcsr,&
      26              :                                               cp_dbcsr_plus_fm_fm_t
      27              :    USE cp_fm_basic_linalg,              ONLY: cp_fm_column_scale,&
      28              :                                               cp_fm_uplo_to_full
      29              :    USE cp_fm_cholesky,                  ONLY: cp_fm_cholesky_decompose,&
      30              :                                               cp_fm_cholesky_invert
      31              :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      32              :                                               cp_fm_get_info,&
      33              :                                               cp_fm_release,&
      34              :                                               cp_fm_to_fm,&
      35              :                                               cp_fm_type
      36              :    USE hfx_admm_utils,                  ONLY: create_admm_xc_section
      37              :    USE input_constants,                 ONLY: do_admm_basis_projection,&
      38              :                                               do_admm_purify_none
      39              :    USE input_section_types,             ONLY: section_vals_get_subs_vals,&
      40              :                                               section_vals_type
      41              :    USE kinds,                           ONLY: default_string_length,&
      42              :                                               dp
      43              :    USE mathconstants,                   ONLY: zero
      44              :    USE message_passing,                 ONLY: mp_para_env_type
      45              :    USE parallel_gemm_api,               ONLY: parallel_gemm
      46              :    USE pw_types,                        ONLY: pw_c1d_gs_type,&
      47              :                                               pw_r3d_rs_type
      48              :    USE qs_collocate_density,            ONLY: calculate_rho_elec
      49              :    USE qs_environment_types,            ONLY: get_qs_env,&
      50              :                                               qs_environment_type,&
      51              :                                               set_qs_env
      52              :    USE qs_gapw_densities,               ONLY: prepare_gapw_den
      53              :    USE qs_kind_types,                   ONLY: get_qs_kind_set,&
      54              :                                               qs_kind_type
      55              :    USE qs_ks_types,                     ONLY: qs_ks_env_type
      56              :    USE qs_mo_types,                     ONLY: get_mo_set,&
      57              :                                               mo_set_type
      58              :    USE qs_rho_atom_methods,             ONLY: calculate_rho_atom_coeff
      59              :    USE qs_rho_types,                    ONLY: qs_rho_get,&
      60              :                                               qs_rho_set,&
      61              :                                               qs_rho_type
      62              :    USE rt_propagation_types,            ONLY: get_rtp,&
      63              :                                               rt_prop_type
      64              :    USE task_list_types,                 ONLY: task_list_type
      65              : #include "./base/base_uses.f90"
      66              : 
      67              :    IMPLICIT NONE
      68              : 
      69              :    PRIVATE
      70              : 
      71              :    ! *** Public subroutines ***
      72              :    PUBLIC :: rtp_admm_calc_rho_aux, rtp_admm_merge_ks_matrix
      73              : 
      74              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'rtp_admm_methods'
      75              : 
      76              : CONTAINS
      77              : 
      78              : ! **************************************************************************************************
      79              : !> \brief  Compute the ADMM density matrix in case of rtp (complex MO's)
      80              : !>
      81              : !> \param qs_env ...
      82              : !> \par History
      83              : ! **************************************************************************************************
      84          114 :    SUBROUTINE rtp_admm_calc_rho_aux(qs_env)
      85              : 
      86              :       TYPE(qs_environment_type), POINTER                 :: qs_env
      87              : 
      88              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'rtp_admm_calc_rho_aux'
      89              : 
      90              :       CHARACTER(LEN=default_string_length)               :: basis_type
      91              :       INTEGER                                            :: handle, ispin, nmo_aux, nspins
      92              :       LOGICAL                                            :: gapw, s_mstruct_changed
      93          114 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: occ_num_aux, tot_rho_r_aux
      94              :       TYPE(admm_type), POINTER                           :: admm_env
      95          114 :       TYPE(cp_fm_type), DIMENSION(:), POINTER            :: rtp_coeff_aux_fit
      96          114 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_p_aux, matrix_p_aux_im, &
      97          114 :                                                             matrix_s_aux_fit, &
      98          114 :                                                             matrix_s_aux_fit_vs_orb
      99              :       TYPE(dft_control_type), POINTER                    :: dft_control
     100          114 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos, mos_aux_fit
     101              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     102          114 :       TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER        :: rho_g_aux
     103          114 :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER        :: rho_r_aux
     104              :       TYPE(qs_ks_env_type), POINTER                      :: ks_env
     105              :       TYPE(qs_rho_type), POINTER                         :: rho, rho_aux_fit
     106              :       TYPE(rt_prop_type), POINTER                        :: rtp
     107              :       TYPE(task_list_type), POINTER                      :: task_list_aux_fit
     108              : 
     109          114 :       CALL timeset(routineN, handle)
     110          114 :       NULLIFY (admm_env, matrix_p_aux, matrix_p_aux_im, mos, &
     111          114 :                mos_aux_fit, para_env, matrix_s_aux_fit, matrix_s_aux_fit_vs_orb, rho, &
     112          114 :                ks_env, dft_control, tot_rho_r_aux, rho_r_aux, rho_g_aux, task_list_aux_fit)
     113              : 
     114              :       CALL get_qs_env(qs_env, &
     115              :                       admm_env=admm_env, &
     116              :                       ks_env=ks_env, &
     117              :                       dft_control=dft_control, &
     118              :                       para_env=para_env, &
     119              :                       mos=mos, &
     120              :                       rtp=rtp, &
     121              :                       rho=rho, &
     122          114 :                       s_mstruct_changed=s_mstruct_changed)
     123              :       CALL get_admm_env(admm_env, matrix_s_aux_fit=matrix_s_aux_fit, task_list_aux_fit=task_list_aux_fit, &
     124              :                         matrix_s_aux_fit_vs_orb=matrix_s_aux_fit_vs_orb, mos_aux_fit=mos_aux_fit, &
     125          114 :                         rho_aux_fit=rho_aux_fit)
     126          114 :       gapw = admm_env%do_gapw
     127              : 
     128          114 :       nspins = dft_control%nspins
     129              : 
     130          114 :       CALL get_rtp(rtp=rtp, admm_mos=rtp_coeff_aux_fit)
     131              :       CALL rtp_admm_fit_mo_coeffs(qs_env, admm_env, dft_control%admm_control, para_env, &
     132              :                                   matrix_s_aux_fit, matrix_s_aux_fit_vs_orb, &
     133              :                                   mos, mos_aux_fit, rtp, rtp_coeff_aux_fit, &
     134          114 :                                   s_mstruct_changed)
     135              : 
     136          266 :       DO ispin = 1, nspins
     137              :          CALL qs_rho_get(rho_aux_fit, &
     138              :                          rho_ao=matrix_p_aux, &
     139              :                          rho_ao_im=matrix_p_aux_im, &
     140              :                          rho_r=rho_r_aux, &
     141              :                          rho_g=rho_g_aux, &
     142          152 :                          tot_rho_r=tot_rho_r_aux)
     143              : 
     144          152 :          CALL get_mo_set(mos_aux_fit(ispin), occupation_numbers=occ_num_aux, nmo=nmo_aux)
     145              : 
     146              :          CALL rtp_admm_calculate_dm(admm_env, rtp_coeff_aux_fit, &
     147              :                                     matrix_p_aux(ispin)%matrix, &
     148              :                                     matrix_p_aux_im(ispin)%matrix, &
     149          152 :                                     occ_num_aux, ispin)
     150              : 
     151              :          !IF GAPW, only do the soft basis with PW
     152              :          basis_type = "AUX_FIT"
     153          152 :          IF (gapw) THEN
     154              :             basis_type = "AUX_FIT_SOFT"
     155           60 :             task_list_aux_fit => admm_env%admm_gapw_env%task_list
     156              :          END IF
     157              : 
     158              :          CALL calculate_rho_elec(matrix_p=matrix_p_aux(ispin)%matrix, &
     159              :                                  rho=rho_r_aux(ispin), &
     160              :                                  rho_gspace=rho_g_aux(ispin), &
     161              :                                  total_rho=tot_rho_r_aux(ispin), &
     162              :                                  ks_env=ks_env, soft_valid=.FALSE., &
     163              :                                  basis_type="AUX_FIT", &
     164          152 :                                  task_list_external=task_list_aux_fit)
     165              : 
     166              :          !IF GAPW, also need to atomic densities
     167          418 :          IF (gapw) THEN
     168              :             CALL calculate_rho_atom_coeff(qs_env, matrix_p_aux, &
     169              :                                           rho_atom_set=admm_env%admm_gapw_env%local_rho_set%rho_atom_set, &
     170              :                                           qs_kind_set=admm_env%admm_gapw_env%admm_kind_set, &
     171              :                                           oce=admm_env%admm_gapw_env%oce, sab=admm_env%sab_aux_fit, &
     172           60 :                                           para_env=para_env)
     173              : 
     174              :             CALL prepare_gapw_den(qs_env, local_rho_set=admm_env%admm_gapw_env%local_rho_set, &
     175           60 :                                   do_rho0=.FALSE., kind_set_external=admm_env%admm_gapw_env%admm_kind_set)
     176              :          END IF
     177              :       END DO
     178          114 :       CALL set_qs_env(qs_env, admm_env=admm_env)
     179          114 :       CALL qs_rho_set(rho_aux_fit, rho_r_valid=.TRUE., rho_g_valid=.TRUE.)
     180              : 
     181          114 :       CALL timestop(handle)
     182              : 
     183          114 :    END SUBROUTINE rtp_admm_calc_rho_aux
     184              : 
     185              : ! **************************************************************************************************
     186              : !> \brief ...
     187              : !> \param admm_env ...
     188              : !> \param rtp_coeff_aux_fit ...
     189              : !> \param density_matrix_aux ...
     190              : !> \param density_matrix_aux_im ...
     191              : !> \param occupation ...
     192              : !> \param ispin ...
     193              : ! **************************************************************************************************
     194          304 :    SUBROUTINE rtp_admm_calculate_dm(admm_env, rtp_coeff_aux_fit, density_matrix_aux, &
     195          152 :                                     density_matrix_aux_im, occupation, ispin)
     196              :       TYPE(admm_type), POINTER                           :: admm_env
     197              :       TYPE(cp_fm_type), DIMENSION(:), POINTER            :: rtp_coeff_aux_fit
     198              :       TYPE(dbcsr_type), POINTER                          :: density_matrix_aux, density_matrix_aux_im
     199              :       REAL(KIND=dp), DIMENSION(:), INTENT(in)            :: occupation
     200              :       INTEGER, INTENT(in)                                :: ispin
     201              : 
     202              :       CHARACTER(len=*), PARAMETER :: routineN = 'rtp_admm_calculate_dm'
     203              : 
     204              :       INTEGER                                            :: handle
     205              : 
     206          152 :       CALL timeset(routineN, handle)
     207              : 
     208          304 :       SELECT CASE (admm_env%purification_method)
     209              :       CASE (do_admm_purify_none)
     210              :          CALL calculate_rtp_admm_density(density_matrix_aux, density_matrix_aux_im, &
     211          152 :                                          rtp_coeff_aux_fit, occupation, ispin)
     212              :       CASE DEFAULT
     213          152 :          CPWARN("only purification NONE possible with RTP/EMD at the moment")
     214              :       END SELECT
     215              : 
     216          152 :       CALL timestop(handle)
     217              : 
     218          152 :    END SUBROUTINE rtp_admm_calculate_dm
     219              : 
     220              : ! **************************************************************************************************
     221              : !> \brief ...
     222              : !> \param qs_env ...
     223              : !> \param admm_env ...
     224              : !> \param admm_control ...
     225              : !> \param para_env ...
     226              : !> \param matrix_s_aux_fit ...
     227              : !> \param matrix_s_mixed ...
     228              : !> \param mos ...
     229              : !> \param mos_aux_fit ...
     230              : !> \param rtp ...
     231              : !> \param rtp_coeff_aux_fit ...
     232              : !> \param geometry_did_change ...
     233              : ! **************************************************************************************************
     234          228 :    SUBROUTINE rtp_admm_fit_mo_coeffs(qs_env, admm_env, admm_control, para_env, matrix_s_aux_fit, matrix_s_mixed, &
     235          114 :                                      mos, mos_aux_fit, rtp, rtp_coeff_aux_fit, geometry_did_change)
     236              : 
     237              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     238              :       TYPE(admm_type), POINTER                           :: admm_env
     239              :       TYPE(admm_control_type), POINTER                   :: admm_control
     240              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     241              :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s_aux_fit, matrix_s_mixed
     242              :       TYPE(mo_set_type), DIMENSION(:), INTENT(IN)        :: mos, mos_aux_fit
     243              :       TYPE(rt_prop_type), POINTER                        :: rtp
     244              :       TYPE(cp_fm_type), DIMENSION(:), POINTER            :: rtp_coeff_aux_fit
     245              :       LOGICAL, INTENT(IN)                                :: geometry_did_change
     246              : 
     247              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'rtp_admm_fit_mo_coeffs'
     248              : 
     249              :       INTEGER                                            :: handle, nao_aux_fit, natoms
     250              :       LOGICAL                                            :: recalc_S
     251          114 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     252              :       TYPE(section_vals_type), POINTER                   :: input, xc_section
     253              : 
     254          114 :       CALL timeset(routineN, handle)
     255              : 
     256          114 :       NULLIFY (xc_section, qs_kind_set)
     257              : 
     258          114 :       IF (.NOT. (ASSOCIATED(admm_env))) THEN
     259              :          ! setup admm environment
     260            0 :          CALL get_qs_env(qs_env, input=input, natom=natoms, qs_kind_set=qs_kind_set)
     261            0 :          CALL get_qs_kind_set(qs_kind_set, nsgf=nao_aux_fit, basis_type="AUX_FIT")
     262            0 :          CALL admm_env_create(admm_env, admm_control, mos, para_env, natoms, nao_aux_fit)
     263            0 :          xc_section => section_vals_get_subs_vals(input, "DFT%XC")
     264              :          CALL create_admm_xc_section(x_data=qs_env%x_data, xc_section=xc_section, &
     265            0 :                                      admm_env=admm_env)
     266              : 
     267            0 :          IF (admm_control%method /= do_admm_basis_projection) THEN
     268            0 :             CPWARN("RTP requires BASIS_PROJECTION.")
     269              :          END IF
     270              :       END IF
     271              : 
     272          114 :       recalc_S = geometry_did_change .OR. (rtp%iter == 0 .AND. (rtp%istep == rtp%i_start))
     273              : 
     274          228 :       SELECT CASE (admm_env%purification_method)
     275              :       CASE (do_admm_purify_none)
     276              :          CALL rtp_fit_mo_coeffs_none(qs_env, admm_env, para_env, matrix_s_aux_fit, matrix_s_mixed, &
     277          114 :                                      mos, mos_aux_fit, rtp, rtp_coeff_aux_fit, recalc_S)
     278              :       CASE DEFAULT
     279          114 :          CPWARN("Purification method not implemented in combination with RTP")
     280              :       END SELECT
     281              : 
     282          114 :       CALL timestop(handle)
     283              : 
     284          114 :    END SUBROUTINE rtp_admm_fit_mo_coeffs
     285              : ! **************************************************************************************************
     286              : !> \brief Calculates the MO coefficients for the auxiliary fitting basis set
     287              : !>        by minimizing int (psi_i - psi_aux_i)^2 using Lagrangian Multipliers
     288              : !>
     289              : !> \param qs_env ...
     290              : !> \param admm_env The ADMM env
     291              : !> \param para_env The parallel env
     292              : !> \param matrix_s_aux_fit the overlap matrix of the auxiliary fitting basis set
     293              : !> \param matrix_s_mixed the mixed overlap matrix of the auxiliary fitting basis
     294              : !>        set and the orbital basis set
     295              : !> \param mos the MO's of the orbital basis set
     296              : !> \param mos_aux_fit the MO's of the auxiliary fitting basis set
     297              : !> \param rtp ...
     298              : !> \param rtp_coeff_aux_fit ...
     299              : !> \param geometry_did_change flag to indicate if the geomtry changed
     300              : !> \par History
     301              : !>      05.2008 created [Manuel Guidon]
     302              : !> \author Manuel Guidon
     303              : ! **************************************************************************************************
     304          228 :    SUBROUTINE rtp_fit_mo_coeffs_none(qs_env, admm_env, para_env, matrix_s_aux_fit, matrix_s_mixed, &
     305          114 :                                      mos, mos_aux_fit, rtp, rtp_coeff_aux_fit, geometry_did_change)
     306              : 
     307              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     308              :       TYPE(admm_type), POINTER                           :: admm_env
     309              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     310              :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s_aux_fit, matrix_s_mixed
     311              :       TYPE(mo_set_type), DIMENSION(:), INTENT(IN)        :: mos, mos_aux_fit
     312              :       TYPE(rt_prop_type), POINTER                        :: rtp
     313              :       TYPE(cp_fm_type), DIMENSION(:), POINTER            :: rtp_coeff_aux_fit
     314              :       LOGICAL, INTENT(IN)                                :: geometry_did_change
     315              : 
     316              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'rtp_fit_mo_coeffs_none'
     317              : 
     318              :       INTEGER                                            :: handle, ispin, nao_aux_fit, nao_orb, &
     319              :                                                             natoms, nmo, nmo_mos, nspins
     320          114 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: occ_num, occ_num_aux
     321          114 :       TYPE(cp_fm_type), DIMENSION(:), POINTER            :: mos_new
     322              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff, mo_coeff_aux_fit
     323              :       TYPE(dft_control_type), POINTER                    :: dft_control
     324          114 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     325              :       TYPE(section_vals_type), POINTER                   :: input, xc_section
     326              : 
     327          114 :       CALL timeset(routineN, handle)
     328              : 
     329          114 :       NULLIFY (dft_control, qs_kind_set)
     330              : 
     331          114 :       IF (.NOT. (ASSOCIATED(admm_env))) THEN
     332            0 :          CALL get_qs_env(qs_env, input=input, natom=natoms, dft_control=dft_control, qs_kind_set=qs_kind_set)
     333            0 :          CALL get_qs_kind_set(qs_kind_set, nsgf=nao_aux_fit, basis_type="AUX_FIT")
     334            0 :          CALL admm_env_create(admm_env, dft_control%admm_control, mos, para_env, natoms, nao_aux_fit)
     335            0 :          xc_section => section_vals_get_subs_vals(input, "DFT%XC")
     336              :          CALL create_admm_xc_section(x_data=qs_env%x_data, xc_section=xc_section, &
     337            0 :                                      admm_env=admm_env)
     338              :       END IF
     339              : 
     340          114 :       nao_aux_fit = admm_env%nao_aux_fit
     341          114 :       nao_orb = admm_env%nao_orb
     342          114 :       nspins = SIZE(mos)
     343              : 
     344              :       ! *** This part only depends on overlap matrices ==> needs only to be calculated if the geometry changed
     345              : 
     346          114 :       IF (geometry_did_change) THEN
     347           30 :          CALL copy_dbcsr_to_fm(matrix_s_aux_fit(1)%matrix, admm_env%S_inv)
     348           30 :          CALL cp_fm_uplo_to_full(admm_env%S_inv, admm_env%work_aux_aux)
     349           30 :          CALL cp_fm_to_fm(admm_env%S_inv, admm_env%S)
     350              : 
     351           30 :          CALL copy_dbcsr_to_fm(matrix_s_mixed(1)%matrix, admm_env%Q)
     352              : 
     353              :          !! Calculate S'_inverse
     354           30 :          CALL cp_fm_cholesky_decompose(admm_env%S_inv)
     355           30 :          CALL cp_fm_cholesky_invert(admm_env%S_inv)
     356              :          !! Symmetrize the guy
     357           30 :          CALL cp_fm_uplo_to_full(admm_env%S_inv, admm_env%work_aux_aux)
     358              :          !! Calculate A=S'^(-1)*P
     359              :          CALL parallel_gemm('N', 'N', nao_aux_fit, nao_orb, nao_aux_fit, &
     360              :                             1.0_dp, admm_env%S_inv, admm_env%Q, 0.0_dp, &
     361           30 :                             admm_env%A)
     362              :       END IF
     363              : 
     364              :       ! *** Calculate the mo_coeffs for the fitting basis
     365          266 :       DO ispin = 1, nspins
     366          152 :          nmo = admm_env%nmo(ispin)
     367          152 :          IF (nmo == 0) CYCLE
     368              :          !! Lambda = C^(T)*B*C
     369          152 :          CALL get_rtp(rtp=rtp, mos_new=mos_new)
     370          152 :          CALL get_mo_set(mos(ispin), mo_coeff=mo_coeff, occupation_numbers=occ_num, nmo=nmo_mos)
     371              :          CALL get_mo_set(mos_aux_fit(ispin), mo_coeff=mo_coeff_aux_fit, &
     372          152 :                          occupation_numbers=occ_num_aux)
     373              : 
     374              :          CALL parallel_gemm('N', 'N', nao_aux_fit, nmo, nao_orb, &
     375              :                             1.0_dp, admm_env%A, mos_new(2*ispin - 1), 0.0_dp, &
     376          152 :                             rtp_coeff_aux_fit(2*ispin - 1))
     377              :          CALL parallel_gemm('N', 'N', nao_aux_fit, nmo, nao_orb, &
     378              :                             1.0_dp, admm_env%A, mos_new(2*ispin), 0.0_dp, &
     379          152 :                             rtp_coeff_aux_fit(2*ispin))
     380              : 
     381          418 :          CALL cp_fm_to_fm(rtp_coeff_aux_fit(2*ispin - 1), mo_coeff_aux_fit)
     382              :       END DO
     383              : 
     384          114 :       CALL timestop(handle)
     385              : 
     386          114 :    END SUBROUTINE rtp_fit_mo_coeffs_none
     387              : 
     388              : ! **************************************************************************************************
     389              : !> \brief ...
     390              : !> \param density_matrix_aux ...
     391              : !> \param density_matrix_aux_im ...
     392              : !> \param rtp_coeff_aux_fit ...
     393              : !> \param occupation ...
     394              : !> \param ispin ...
     395              : ! **************************************************************************************************
     396          456 :    SUBROUTINE calculate_rtp_admm_density(density_matrix_aux, density_matrix_aux_im, &
     397          152 :                                          rtp_coeff_aux_fit, occupation, ispin)
     398              : 
     399              :       TYPE(dbcsr_type), POINTER                          :: density_matrix_aux, density_matrix_aux_im
     400              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: rtp_coeff_aux_fit
     401              :       REAL(KIND=dp), DIMENSION(:), INTENT(in)            :: occupation
     402              :       INTEGER, INTENT(in)                                :: ispin
     403              : 
     404              :       CHARACTER(len=*), PARAMETER :: routineN = 'calculate_rtp_admm_density'
     405              :       REAL(KIND=dp), PARAMETER                           :: zero = 0.0_dp
     406              : 
     407              :       INTEGER                                            :: handle, im, ncol, re
     408              :       REAL(KIND=dp)                                      :: alpha
     409              :       TYPE(cp_fm_type)                                   :: fm_tmp
     410              : 
     411          152 :       CALL timeset(routineN, handle)
     412              : 
     413          152 :       re = 2*ispin - 1; im = 2*ispin
     414              : 
     415          152 :       CALL dbcsr_set(density_matrix_aux, zero)
     416          152 :       CALL cp_fm_get_info(rtp_coeff_aux_fit(re), ncol_global=ncol)
     417          152 :       alpha = occupation(1)
     418          628 :       IF (ALL(occupation == alpha)) THEN
     419              :          CALL cp_dbcsr_plus_fm_fm_t(sparse_matrix=density_matrix_aux, &
     420              :                                     matrix_v=rtp_coeff_aux_fit(re), &
     421              :                                     ncol=ncol, &
     422          108 :                                     alpha=alpha)
     423              : 
     424              :          ! It is actually complex conjugate but i*i=-1 therefore it must be added
     425              :          CALL cp_dbcsr_plus_fm_fm_t(sparse_matrix=density_matrix_aux, &
     426              :                                     matrix_v=rtp_coeff_aux_fit(im), &
     427              :                                     ncol=ncol, &
     428          108 :                                     alpha=alpha)
     429              : 
     430              :          !   compute the imaginary part of the dm
     431          108 :          CALL dbcsr_set(density_matrix_aux_im, zero)
     432              :          CALL cp_dbcsr_plus_fm_fm_t(sparse_matrix=density_matrix_aux_im, &
     433              :                                     matrix_v=rtp_coeff_aux_fit(im), &
     434              :                                     matrix_g=rtp_coeff_aux_fit(re), &
     435              :                                     ncol=ncol, &
     436              :                                     alpha=2.0_dp*alpha, &
     437          108 :                                     symmetry_mode=-1)
     438              :       ELSE
     439           44 :          CALL cp_fm_create(fm_tmp, rtp_coeff_aux_fit(1)%matrix_struct)
     440           44 :          CALL cp_fm_to_fm(rtp_coeff_aux_fit(re), fm_tmp)
     441           44 :          CALL cp_fm_column_scale(fm_tmp, occupation(1:ncol))
     442           44 :          alpha = 1.0_dp
     443              :          CALL cp_dbcsr_plus_fm_fm_t(sparse_matrix=density_matrix_aux, &
     444              :                                     matrix_v=rtp_coeff_aux_fit(re), &
     445              :                                     matrix_g=fm_tmp, &
     446           44 :                                     ncol=ncol, alpha=alpha)
     447              :          ! It is actually complex conjugate but i*i=-1 therefore it must be added
     448           44 :          CALL cp_fm_to_fm(rtp_coeff_aux_fit(im), fm_tmp)
     449           44 :          CALL cp_fm_column_scale(fm_tmp, occupation(1:ncol))
     450              :          CALL cp_dbcsr_plus_fm_fm_t(sparse_matrix=density_matrix_aux, &
     451              :                                     matrix_v=rtp_coeff_aux_fit(im), &
     452              :                                     matrix_g=fm_tmp, &
     453           44 :                                     ncol=ncol, alpha=alpha)
     454              :          !   compute the imaginary part of the dm
     455           44 :          CALL dbcsr_set(density_matrix_aux_im, zero)
     456              :          CALL cp_dbcsr_plus_fm_fm_t(sparse_matrix=density_matrix_aux_im, &
     457              :                                     matrix_v=fm_tmp, &
     458              :                                     matrix_g=rtp_coeff_aux_fit(re), &
     459              :                                     ncol=ncol, alpha=2.0_dp*alpha, &
     460           44 :                                     symmetry_mode=-1)
     461           44 :          CALL cp_fm_release(fm_tmp)
     462              :       END IF
     463              : 
     464          152 :       CALL timestop(handle)
     465              : 
     466          152 :    END SUBROUTINE calculate_rtp_admm_density
     467              : 
     468              : ! **************************************************************************************************
     469              : !> \brief ...
     470              : !> \param qs_env ...
     471              : ! **************************************************************************************************
     472          114 :    SUBROUTINE rtp_admm_merge_ks_matrix(qs_env)
     473              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     474              : 
     475              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'rtp_admm_merge_ks_matrix'
     476              : 
     477              :       INTEGER                                            :: handle, ispin
     478              :       TYPE(admm_type), POINTER                           :: admm_env
     479          114 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_ks, matrix_ks_aux_fit, &
     480          114 :                                                             matrix_ks_aux_fit_im, matrix_ks_im
     481              :       TYPE(dft_control_type), POINTER                    :: dft_control
     482              : 
     483          114 :       NULLIFY (admm_env, dft_control, matrix_ks, matrix_ks_im, matrix_ks_aux_fit, matrix_ks_aux_fit_im)
     484          114 :       CALL timeset(routineN, handle)
     485              : 
     486              :       CALL get_qs_env(qs_env, &
     487              :                       admm_env=admm_env, &
     488              :                       dft_control=dft_control, &
     489              :                       matrix_ks=matrix_ks, &
     490          114 :                       matrix_ks_im=matrix_ks_im)
     491          114 :       CALL get_admm_env(admm_env, matrix_ks_aux_fit=matrix_ks_aux_fit, matrix_ks_aux_fit_im=matrix_ks_aux_fit_im)
     492              : 
     493              :       !note: the GAPW contribution to ks_aux_fit taken care of in qs_ks_methods.F/update_admm_ks_atom
     494              : 
     495          266 :       DO ispin = 1, dft_control%nspins
     496              : 
     497          114 :          SELECT CASE (admm_env%purification_method)
     498              :          CASE (do_admm_purify_none)
     499              :             CALL rt_merge_ks_matrix_none(ispin, admm_env, &
     500          152 :                                          matrix_ks, matrix_ks_aux_fit)
     501              :             CALL rt_merge_ks_matrix_none(ispin, admm_env, &
     502          152 :                                          matrix_ks_im, matrix_ks_aux_fit_im)
     503              :          CASE DEFAULT
     504          152 :             CPWARN("only purification NONE possible with RTP/EMD at the moment")
     505              :          END SELECT
     506              : 
     507              :       END DO !spin loop
     508          114 :       CALL timestop(handle)
     509              : 
     510          114 :    END SUBROUTINE rtp_admm_merge_ks_matrix
     511              : 
     512              : ! **************************************************************************************************
     513              : !> \brief ...
     514              : !> \param ispin ...
     515              : !> \param admm_env ...
     516              : !> \param matrix_ks ...
     517              : !> \param matrix_ks_aux_fit ...
     518              : ! **************************************************************************************************
     519          304 :    SUBROUTINE rt_merge_ks_matrix_none(ispin, admm_env, &
     520              :                                       matrix_ks, matrix_ks_aux_fit)
     521              :       INTEGER, INTENT(IN)                                :: ispin
     522              :       TYPE(admm_type), POINTER                           :: admm_env
     523              :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_ks, matrix_ks_aux_fit
     524              : 
     525              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'rt_merge_ks_matrix_none'
     526              : 
     527              :       CHARACTER                                          :: matrix_type_fit
     528              :       INTEGER                                            :: handle, nao_aux_fit, nao_orb, nmo
     529              :       INTEGER, SAVE                                      :: counter = 0
     530              :       TYPE(dbcsr_type)                                   :: matrix_ks_nosym
     531              :       TYPE(dbcsr_type), POINTER                          :: matrix_k_tilde
     532              : 
     533          304 :       CALL timeset(routineN, handle)
     534              : 
     535          304 :       counter = counter + 1
     536          304 :       nao_aux_fit = admm_env%nao_aux_fit
     537          304 :       nao_orb = admm_env%nao_orb
     538          304 :       nmo = admm_env%nmo(ispin)
     539              :       CALL dbcsr_create(matrix_ks_nosym, template=matrix_ks_aux_fit(ispin)%matrix, &
     540          304 :                         matrix_type=dbcsr_type_no_symmetry)
     541          304 :       CALL dbcsr_set(matrix_ks_nosym, 0.0_dp)
     542          304 :       CALL dbcsr_desymmetrize(matrix_ks_aux_fit(ispin)%matrix, matrix_ks_nosym)
     543              : 
     544          304 :       CALL copy_dbcsr_to_fm(matrix_ks_nosym, admm_env%K(ispin))
     545              : 
     546              :       !! K*A
     547              :       CALL parallel_gemm('N', 'N', nao_aux_fit, nao_orb, nao_aux_fit, &
     548              :                          1.0_dp, admm_env%K(ispin), admm_env%A, 0.0_dp, &
     549          304 :                          admm_env%work_aux_orb)
     550              :       !! A^T*K*A
     551              :       CALL parallel_gemm('T', 'N', nao_orb, nao_orb, nao_aux_fit, &
     552              :                          1.0_dp, admm_env%A, admm_env%work_aux_orb, 0.0_dp, &
     553          304 :                          admm_env%work_orb_orb)
     554              : 
     555          304 :       CALL dbcsr_get_info(matrix_ks_aux_fit(ispin)%matrix, matrix_type=matrix_type_fit)
     556              : 
     557              :       NULLIFY (matrix_k_tilde)
     558          304 :       ALLOCATE (matrix_k_tilde)
     559              :       CALL dbcsr_create(matrix_k_tilde, template=matrix_ks(ispin)%matrix, &
     560          304 :                         name='MATRIX K_tilde', matrix_type=matrix_type_fit)
     561              : 
     562          304 :       CALL dbcsr_copy(matrix_k_tilde, matrix_ks(ispin)%matrix)
     563          304 :       CALL dbcsr_set(matrix_k_tilde, 0.0_dp)
     564          304 :       CALL copy_fm_to_dbcsr(admm_env%work_orb_orb, matrix_k_tilde, keep_sparsity=.TRUE.)
     565              : 
     566          304 :       CALL dbcsr_add(matrix_ks(ispin)%matrix, matrix_k_tilde, 1.0_dp, 1.0_dp)
     567              : 
     568          304 :       CALL dbcsr_deallocate_matrix(matrix_k_tilde)
     569          304 :       CALL dbcsr_release(matrix_ks_nosym)
     570              : 
     571          304 :       CALL timestop(handle)
     572              : 
     573          304 :    END SUBROUTINE rt_merge_ks_matrix_none
     574              : 
     575              : END MODULE rtp_admm_methods
        

Generated by: LCOV version 2.0-1