LCOV - code coverage report
Current view: top level - src - qs_p_env_methods.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:71c3ab0) Lines: 66.0 % 297 196
Test Date: 2026-07-25 06:35:44 Functions: 71.4 % 7 5

            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 Utility functions for the perturbation calculations.
      10              : !> \note
      11              : !>      - routines are programmed with spins in mind
      12              : !>        but are as of now not tested with them
      13              : !> \par History
      14              : !>      22-08-2002, TCH, started development
      15              : ! **************************************************************************************************
      16              : MODULE qs_p_env_methods
      17              :    USE admm_methods,                    ONLY: admm_aux_response_density
      18              :    USE admm_types,                      ONLY: admm_gapw_r3d_rs_type,&
      19              :                                               admm_type,&
      20              :                                               get_admm_env
      21              :    USE atomic_kind_types,               ONLY: atomic_kind_type
      22              :    USE cp_blacs_env,                    ONLY: cp_blacs_env_type
      23              :    USE cp_control_types,                ONLY: dft_control_type
      24              :    USE cp_dbcsr_api,                    ONLY: dbcsr_add,&
      25              :                                               dbcsr_copy,&
      26              :                                               dbcsr_p_type,&
      27              :                                               dbcsr_release,&
      28              :                                               dbcsr_scale,&
      29              :                                               dbcsr_set,&
      30              :                                               dbcsr_type
      31              :    USE cp_dbcsr_operations,             ONLY: copy_fm_to_dbcsr,&
      32              :                                               cp_dbcsr_plus_fm_fm_t,&
      33              :                                               cp_dbcsr_sm_fm_multiply,&
      34              :                                               dbcsr_allocate_matrix_set
      35              :    USE cp_fm_basic_linalg,              ONLY: cp_fm_triangular_multiply
      36              :    USE cp_fm_cholesky,                  ONLY: cp_fm_cholesky_decompose
      37              :    USE cp_fm_pool_types,                ONLY: cp_fm_pool_p_type,&
      38              :                                               cp_fm_pool_type,&
      39              :                                               fm_pool_create_fm,&
      40              :                                               fm_pool_get_el_struct,&
      41              :                                               fm_pool_give_back_fm,&
      42              :                                               fm_pools_create_fm_vect
      43              :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      44              :                                               cp_fm_struct_get,&
      45              :                                               cp_fm_struct_release,&
      46              :                                               cp_fm_struct_type
      47              :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      48              :                                               cp_fm_get_info,&
      49              :                                               cp_fm_release,&
      50              :                                               cp_fm_set_all,&
      51              :                                               cp_fm_to_fm,&
      52              :                                               cp_fm_type
      53              :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      54              :                                               cp_logger_type,&
      55              :                                               cp_to_string
      56              :    USE cp_output_handling,              ONLY: cp_print_key_finished_output,&
      57              :                                               cp_print_key_unit_nr
      58              :    USE hartree_local_methods,           ONLY: init_coulomb_local
      59              :    USE hartree_local_types,             ONLY: hartree_local_create
      60              :    USE input_constants,                 ONLY: do_admm_aux_exch_func_none,&
      61              :                                               ot_precond_none
      62              :    USE input_section_types,             ONLY: section_vals_get,&
      63              :                                               section_vals_get_subs_vals,&
      64              :                                               section_vals_type
      65              :    USE kinds,                           ONLY: default_string_length,&
      66              :                                               dp
      67              :    USE message_passing,                 ONLY: mp_para_env_type
      68              :    USE parallel_gemm_api,               ONLY: parallel_gemm
      69              :    USE preconditioner_types,            ONLY: init_preconditioner
      70              :    USE pw_env_types,                    ONLY: pw_env_type
      71              :    USE pw_types,                        ONLY: pw_c1d_gs_type,&
      72              :                                               pw_r3d_rs_type
      73              :    USE qs_collocate_density,            ONLY: calculate_rho_elec
      74              :    USE qs_energy_types,                 ONLY: qs_energy_type
      75              :    USE qs_environment_types,            ONLY: get_qs_env,&
      76              :                                               qs_environment_type
      77              :    USE qs_kind_types,                   ONLY: qs_kind_type
      78              :    USE qs_kpp1_env_methods,             ONLY: kpp1_create,&
      79              :                                               kpp1_did_change
      80              :    USE qs_ks_methods,                   ONLY: qs_ks_update_qs_env
      81              :    USE qs_ks_types,                     ONLY: qs_ks_did_change,&
      82              :                                               qs_ks_env_type
      83              :    USE qs_linres_types,                 ONLY: linres_control_type
      84              :    USE qs_local_rho_types,              ONLY: local_rho_set_create
      85              :    USE qs_matrix_pools,                 ONLY: mpools_get
      86              :    USE qs_mo_types,                     ONLY: get_mo_set,&
      87              :                                               mo_set_type
      88              :    USE qs_neighbor_list_types,          ONLY: neighbor_list_set_p_type
      89              :    USE qs_p_env_types,                  ONLY: qs_p_env_type
      90              :    USE qs_rho0_ggrid,                   ONLY: rho0_s_grid_create
      91              :    USE qs_rho0_methods,                 ONLY: init_rho0
      92              :    USE qs_rho_atom_methods,             ONLY: allocate_rho_atom_internals,&
      93              :                                               calculate_rho_atom_coeff
      94              :    USE qs_rho_methods,                  ONLY: qs_rho_rebuild,&
      95              :                                               qs_rho_update_rho
      96              :    USE qs_rho_types,                    ONLY: qs_rho_create,&
      97              :                                               qs_rho_get,&
      98              :                                               qs_rho_type
      99              :    USE string_utilities,                ONLY: compress
     100              :    USE task_list_types,                 ONLY: task_list_type
     101              : #include "./base/base_uses.f90"
     102              : 
     103              :    IMPLICIT NONE
     104              : 
     105              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_p_env_methods'
     106              :    LOGICAL, PRIVATE, PARAMETER :: debug_this_module = .FALSE.
     107              : 
     108              :    PRIVATE
     109              :    PUBLIC :: p_env_create, p_env_psi0_changed
     110              :    PUBLIC :: p_preortho, p_postortho
     111              :    PUBLIC :: p_env_check_i_alloc, p_env_update_rho
     112              :    PUBLIC :: p_env_finish_kpp1
     113              : 
     114              : CONTAINS
     115              : 
     116              : ! **************************************************************************************************
     117              : !> \brief allocates and initializes the perturbation environment (no setup)
     118              : !> \param p_env the environment to initialize
     119              : !> \param qs_env the qs_environment for the system
     120              : !> \param p1_option ...
     121              : !> \param p1_admm_option ...
     122              : !> \param orthogonal_orbitals if the orbitals are orthogonal
     123              : !> \param linres_control ...
     124              : !> \par History
     125              : !>      07.2002 created [fawzi]
     126              : !> \author Fawzi Mohamed
     127              : ! **************************************************************************************************
     128         1830 :    SUBROUTINE p_env_create(p_env, qs_env, p1_option, p1_admm_option, &
     129              :                            orthogonal_orbitals, linres_control)
     130              : 
     131              :       TYPE(qs_p_env_type)                                :: p_env
     132              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     133              :       TYPE(dbcsr_p_type), DIMENSION(:), OPTIONAL, &
     134              :          POINTER                                         :: p1_option, p1_admm_option
     135              :       LOGICAL, INTENT(in), OPTIONAL                      :: orthogonal_orbitals
     136              :       TYPE(linres_control_type), OPTIONAL, POINTER       :: linres_control
     137              : 
     138              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'p_env_create'
     139              : 
     140              :       INTEGER                                            :: handle, n_ao, n_mo, n_spins, natom, spin
     141              :       TYPE(admm_gapw_r3d_rs_type), POINTER               :: admm_gapw_env
     142              :       TYPE(admm_type), POINTER                           :: admm_env
     143         1830 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
     144              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
     145         1830 :       TYPE(cp_fm_pool_p_type), DIMENSION(:), POINTER     :: ao_mo_fm_pools, mo_mo_fm_pools
     146              :       TYPE(cp_fm_type), POINTER                          :: qs_env_c
     147         1830 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s, matrix_s_aux_fit
     148              :       TYPE(dft_control_type), POINTER                    :: dft_control
     149              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     150              :       TYPE(pw_env_type), POINTER                         :: pw_env
     151         1830 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     152              : 
     153         1830 :       CALL timeset(routineN, handle)
     154         1830 :       NULLIFY (ao_mo_fm_pools, mo_mo_fm_pools, matrix_s, dft_control, para_env, blacs_env)
     155              :       CALL get_qs_env(qs_env, &
     156              :                       matrix_s=matrix_s, &
     157              :                       dft_control=dft_control, &
     158              :                       para_env=para_env, &
     159         1830 :                       blacs_env=blacs_env)
     160              : 
     161         1830 :       n_spins = dft_control%nspins
     162              : 
     163         1830 :       p_env%new_preconditioner = .TRUE.
     164              : 
     165         1830 :       ALLOCATE (p_env%rho1)
     166         1830 :       CALL qs_rho_create(p_env%rho1)
     167         1830 :       ALLOCATE (p_env%rho1_xc)
     168         1830 :       CALL qs_rho_create(p_env%rho1_xc)
     169              : 
     170         1830 :       ALLOCATE (p_env%kpp1_env)
     171         1830 :       CALL kpp1_create(p_env%kpp1_env)
     172              : 
     173         1830 :       IF (PRESENT(p1_option)) THEN
     174          272 :          p_env%p1 => p1_option
     175              :       ELSE
     176         1558 :          CALL dbcsr_allocate_matrix_set(p_env%p1, n_spins)
     177         3342 :          DO spin = 1, n_spins
     178         1784 :             ALLOCATE (p_env%p1(spin)%matrix)
     179              :             CALL dbcsr_copy(p_env%p1(spin)%matrix, matrix_s(1)%matrix, &
     180         1784 :                             name="p_env%p1-"//TRIM(ADJUSTL(cp_to_string(spin))))
     181         3342 :             CALL dbcsr_set(p_env%p1(spin)%matrix, 0.0_dp)
     182              :          END DO
     183              :       END IF
     184              : 
     185         1830 :       IF (dft_control%do_admm) THEN
     186          340 :          CALL get_admm_env(qs_env%admm_env, matrix_s_aux_fit=matrix_s_aux_fit)
     187          340 :          IF (qs_env%admm_env%aux_exch_func /= do_admm_aux_exch_func_none) THEN
     188          206 :             ALLOCATE (p_env%rho1_admm)
     189          206 :             CALL qs_rho_create(p_env%rho1_admm)
     190              :          END IF
     191              : 
     192          340 :          IF (PRESENT(p1_admm_option)) THEN
     193            0 :             p_env%p1_admm => p1_admm_option
     194              :          ELSE
     195          340 :             CALL dbcsr_allocate_matrix_set(p_env%p1_admm, n_spins)
     196          726 :             DO spin = 1, n_spins
     197          386 :                ALLOCATE (p_env%p1_admm(spin)%matrix)
     198              :                CALL dbcsr_copy(p_env%p1_admm(spin)%matrix, matrix_s_aux_fit(1)%matrix, &
     199          386 :                                name="p_env%p1_admm-"//TRIM(ADJUSTL(cp_to_string(spin))))
     200          726 :                CALL dbcsr_set(p_env%p1_admm(spin)%matrix, 0.0_dp)
     201              :             END DO
     202              :          END IF
     203          340 :          CALL get_qs_env(qs_env, admm_env=admm_env)
     204          340 :          IF (admm_env%do_gapw) THEN
     205           54 :             CALL get_qs_env(qs_env, atomic_kind_set=atomic_kind_set)
     206           54 :             admm_gapw_env => admm_env%admm_gapw_env
     207           54 :             CALL local_rho_set_create(p_env%local_rho_set_admm)
     208              :             CALL allocate_rho_atom_internals(p_env%local_rho_set_admm%rho_atom_set, atomic_kind_set, &
     209           54 :                                              admm_gapw_env%admm_kind_set, dft_control, para_env)
     210              :          END IF
     211              :       END IF
     212              : 
     213              :       CALL mpools_get(qs_env%mpools, ao_mo_fm_pools=ao_mo_fm_pools, &
     214         1830 :                       mo_mo_fm_pools=mo_mo_fm_pools)
     215              : 
     216         5490 :       p_env%n_mo = 0
     217         5490 :       p_env%n_ao = 0
     218         3972 :       DO spin = 1, n_spins
     219         2142 :          CALL get_mo_set(qs_env%mos(spin), mo_coeff=qs_env_c)
     220              :          CALL cp_fm_get_info(qs_env_c, &
     221         2142 :                              ncol_global=n_mo, nrow_global=n_ao)
     222         2142 :          p_env%n_mo(spin) = n_mo
     223         3972 :          p_env%n_ao(spin) = n_ao
     224              :       END DO
     225              : 
     226         1830 :       p_env%orthogonal_orbitals = .FALSE.
     227         1830 :       IF (PRESENT(orthogonal_orbitals)) THEN
     228         1830 :          p_env%orthogonal_orbitals = orthogonal_orbitals
     229              :       END IF
     230              : 
     231              :       CALL fm_pools_create_fm_vect(ao_mo_fm_pools, elements=p_env%S_psi0, &
     232         1830 :                                    name="p_env%S_psi0")
     233              : 
     234              :       ! alloc m_epsilon
     235              :       CALL fm_pools_create_fm_vect(mo_mo_fm_pools, elements=p_env%m_epsilon, &
     236         1830 :                                    name="p_env%m_epsilon")
     237              : 
     238              :       ! alloc Smo_inv
     239         1830 :       IF (.NOT. p_env%orthogonal_orbitals) THEN
     240              :          CALL fm_pools_create_fm_vect(mo_mo_fm_pools, elements=p_env%Smo_inv, &
     241            0 :                                       name="p_env%Smo_inv")
     242              :       END IF
     243              : 
     244         1830 :       IF (.NOT. p_env%orthogonal_orbitals) THEN
     245              :          CALL fm_pools_create_fm_vect(ao_mo_fm_pools, &
     246              :                                       elements=p_env%psi0d, &
     247            0 :                                       name="p_env%psi0d")
     248              :       END IF
     249              : 
     250              :       !------------------------------!
     251              :       ! GAPW/GAPW_XC initializations !
     252              :       !------------------------------!
     253         1830 :       IF (dft_control%qs_control%gapw) THEN
     254              :          CALL get_qs_env(qs_env, &
     255              :                          atomic_kind_set=atomic_kind_set, &
     256              :                          natom=natom, &
     257              :                          pw_env=pw_env, &
     258          314 :                          qs_kind_set=qs_kind_set)
     259              : 
     260          314 :          CALL local_rho_set_create(p_env%local_rho_set)
     261              :          CALL allocate_rho_atom_internals(p_env%local_rho_set%rho_atom_set, atomic_kind_set, &
     262          314 :                                           qs_kind_set, dft_control, para_env)
     263              : 
     264              :          CALL init_rho0(p_env%local_rho_set, qs_env, dft_control%qs_control%gapw_control, &
     265          314 :                         zcore=0.0_dp)
     266          314 :          CALL rho0_s_grid_create(pw_env, p_env%local_rho_set%rho0_mpole)
     267          314 :          CALL hartree_local_create(p_env%hartree_local)
     268          314 :          CALL init_coulomb_local(p_env%hartree_local, natom)
     269         1516 :       ELSE IF (dft_control%qs_control%gapw_xc) THEN
     270              :          CALL get_qs_env(qs_env, &
     271              :                          atomic_kind_set=atomic_kind_set, &
     272           54 :                          qs_kind_set=qs_kind_set)
     273           54 :          CALL local_rho_set_create(p_env%local_rho_set)
     274              :          CALL allocate_rho_atom_internals(p_env%local_rho_set%rho_atom_set, atomic_kind_set, &
     275           54 :                                           qs_kind_set, dft_control, para_env)
     276              :       END IF
     277              : 
     278              :       !------------------------!
     279              :       ! LINRES initializations !
     280              :       !------------------------!
     281         1830 :       IF (PRESENT(linres_control)) THEN
     282              : 
     283         1830 :          IF (linres_control%preconditioner_type /= ot_precond_none) THEN
     284              :             ! Initialize the preconditioner matrix
     285         1826 :             IF (.NOT. ASSOCIATED(p_env%preconditioner)) THEN
     286              : 
     287         7616 :                ALLOCATE (p_env%preconditioner(n_spins))
     288         3964 :                DO spin = 1, n_spins
     289              :                   CALL init_preconditioner(p_env%preconditioner(spin), &
     290         3964 :                                            para_env=para_env, blacs_env=blacs_env)
     291              :                END DO
     292              : 
     293              :                CALL fm_pools_create_fm_vect(ao_mo_fm_pools, elements=p_env%PS_psi0, &
     294         1826 :                                             name="p_env%PS_psi0")
     295              :             END IF
     296              :          END IF
     297              : 
     298              :       END IF
     299              : 
     300         1830 :       CALL timestop(handle)
     301              : 
     302         1830 :    END SUBROUTINE p_env_create
     303              : 
     304              : ! **************************************************************************************************
     305              : !> \brief checks that the intenal storage is allocated, and allocs it if needed
     306              : !> \param p_env the environment to check
     307              : !> \param qs_env the qs environment this p_env lives in
     308              : !> \par History
     309              : !>      12.2002 created [fawzi]
     310              : !> \author Fawzi Mohamed
     311              : !> \note
     312              : !>      private routine
     313              : ! **************************************************************************************************
     314        10142 :    SUBROUTINE p_env_check_i_alloc(p_env, qs_env)
     315              :       TYPE(qs_p_env_type)                                :: p_env
     316              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     317              : 
     318              :       CHARACTER(len=*), PARAMETER :: routineN = 'p_env_check_i_alloc'
     319              : 
     320              :       CHARACTER(len=25)                                  :: name
     321              :       INTEGER                                            :: handle, ispin, nspins
     322              :       LOGICAL                                            :: gapw_xc
     323        10142 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s
     324              :       TYPE(dft_control_type), POINTER                    :: dft_control
     325              : 
     326        10142 :       CALL timeset(routineN, handle)
     327              : 
     328        10142 :       NULLIFY (dft_control, matrix_s)
     329              : 
     330        10142 :       CALL get_qs_env(qs_env, dft_control=dft_control)
     331        10142 :       gapw_xc = dft_control%qs_control%gapw_xc
     332        10142 :       IF (.NOT. ASSOCIATED(p_env%kpp1)) THEN
     333         1610 :          CALL get_qs_env(qs_env, matrix_s=matrix_s)
     334         1610 :          nspins = dft_control%nspins
     335              : 
     336         1610 :          CALL dbcsr_allocate_matrix_set(p_env%kpp1, nspins)
     337         1610 :          name = "p_env%kpp1-"
     338         1610 :          CALL compress(name, full=.TRUE.)
     339         3454 :          DO ispin = 1, nspins
     340         1844 :             ALLOCATE (p_env%kpp1(ispin)%matrix)
     341              :             CALL dbcsr_copy(p_env%kpp1(ispin)%matrix, matrix_s(1)%matrix, &
     342         1844 :                             name=TRIM(name)//ADJUSTL(cp_to_string(ispin)))
     343         3454 :             CALL dbcsr_set(p_env%kpp1(ispin)%matrix, 0.0_dp)
     344              :          END DO
     345              : 
     346         1610 :          CALL qs_rho_rebuild(p_env%rho1, qs_env=qs_env)
     347         1610 :          IF (gapw_xc) THEN
     348           52 :             CALL qs_rho_rebuild(p_env%rho1_xc, qs_env=qs_env)
     349              :          END IF
     350              : 
     351              :       END IF
     352              : 
     353        10142 :       IF (dft_control%do_admm .AND. .NOT. ASSOCIATED(p_env%kpp1_admm)) THEN
     354          340 :          CALL get_admm_env(qs_env%admm_env, matrix_s_aux_fit=matrix_s)
     355          340 :          nspins = dft_control%nspins
     356              : 
     357          340 :          CALL dbcsr_allocate_matrix_set(p_env%kpp1_admm, nspins)
     358          340 :          name = "p_env%kpp1_admm-"
     359          340 :          CALL compress(name, full=.TRUE.)
     360          726 :          DO ispin = 1, nspins
     361          386 :             ALLOCATE (p_env%kpp1_admm(ispin)%matrix)
     362              :             CALL dbcsr_copy(p_env%kpp1_admm(ispin)%matrix, matrix_s(1)%matrix, &
     363          386 :                             name=TRIM(name)//ADJUSTL(cp_to_string(ispin)))
     364          726 :             CALL dbcsr_set(p_env%kpp1_admm(ispin)%matrix, 0.0_dp)
     365              :          END DO
     366              : 
     367          340 :          IF (qs_env%admm_env%aux_exch_func /= do_admm_aux_exch_func_none) THEN
     368          206 :             CALL qs_rho_rebuild(p_env%rho1_admm, qs_env=qs_env, admm=.TRUE.)
     369              :          END IF
     370              : 
     371              :       END IF
     372              : 
     373        10142 :       IF (.NOT. ASSOCIATED(p_env%rho1)) THEN
     374            0 :          CALL qs_rho_rebuild(p_env%rho1, qs_env=qs_env)
     375            0 :          IF (gapw_xc) THEN
     376            0 :             CALL qs_rho_rebuild(p_env%rho1_xc, qs_env=qs_env)
     377              :          END IF
     378              : 
     379            0 :          IF (dft_control%do_admm) THEN
     380            0 :             IF (qs_env%admm_env%aux_exch_func /= do_admm_aux_exch_func_none) THEN
     381            0 :                CALL qs_rho_rebuild(p_env%rho1_admm, qs_env=qs_env, admm=.TRUE.)
     382              :             END IF
     383              :          END IF
     384              : 
     385              :       END IF
     386              : 
     387        10142 :       CALL timestop(handle)
     388        10142 :    END SUBROUTINE p_env_check_i_alloc
     389              : 
     390              : ! **************************************************************************************************
     391              : !> \brief ...
     392              : !> \param p_env ...
     393              : !> \param qs_env ...
     394              : ! **************************************************************************************************
     395        11654 :    SUBROUTINE p_env_update_rho(p_env, qs_env)
     396              :       TYPE(qs_p_env_type), INTENT(IN)                    :: p_env
     397              :       TYPE(qs_environment_type), INTENT(IN), POINTER     :: qs_env
     398              : 
     399              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'p_env_update_rho'
     400              : 
     401              :       CHARACTER(LEN=default_string_length)               :: basis_type
     402              :       INTEGER                                            :: handle, ispin
     403              :       TYPE(admm_type), POINTER                           :: admm_env
     404        11654 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: rho1_ao
     405              :       TYPE(dft_control_type), POINTER                    :: dft_control
     406              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     407              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
     408        11654 :          POINTER                                         :: sab_aux_fit
     409        11654 :       TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER        :: rho_g_aux
     410        11654 :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER        :: rho_r_aux
     411              :       TYPE(qs_ks_env_type), POINTER                      :: ks_env
     412              :       TYPE(task_list_type), POINTER                      :: task_list
     413              : 
     414        11654 :       CALL timeset(routineN, handle)
     415              : 
     416        11654 :       CALL get_qs_env(qs_env, dft_control=dft_control)
     417              : 
     418        11654 :       IF (dft_control%do_admm) CALL admm_aux_response_density(qs_env, p_env%p1, p_env%p1_admm)
     419              : 
     420        11654 :       CALL qs_rho_get(p_env%rho1, rho_ao=rho1_ao)
     421        24972 :       DO ispin = 1, SIZE(rho1_ao)
     422        24972 :          CALL dbcsr_copy(rho1_ao(ispin)%matrix, p_env%p1(ispin)%matrix)
     423              :       END DO
     424              : 
     425              :       CALL qs_rho_update_rho(rho_struct=p_env%rho1, &
     426              :                              rho_xc_external=p_env%rho1_xc, &
     427              :                              local_rho_set=p_env%local_rho_set, &
     428        11654 :                              qs_env=qs_env)
     429              : 
     430        11654 :       IF (dft_control%do_admm) THEN
     431         2426 :          IF (qs_env%admm_env%aux_exch_func /= do_admm_aux_exch_func_none) THEN
     432         1398 :             NULLIFY (ks_env, rho1_ao, rho_g_aux, rho_r_aux, task_list)
     433              : 
     434         1398 :             CALL get_qs_env(qs_env, ks_env=ks_env, admm_env=admm_env)
     435         1398 :             basis_type = "AUX_FIT"
     436         1398 :             CALL get_admm_env(qs_env%admm_env, task_list_aux_fit=task_list)
     437         1398 :             IF (admm_env%do_gapw) THEN
     438          396 :                basis_type = "AUX_FIT_SOFT"
     439          396 :                task_list => admm_env%admm_gapw_env%task_list
     440              :             END IF
     441              :             CALL qs_rho_get(p_env%rho1_admm, &
     442              :                             rho_ao=rho1_ao, &
     443              :                             rho_g=rho_g_aux, &
     444         1398 :                             rho_r=rho_r_aux)
     445         2958 :             DO ispin = 1, SIZE(rho1_ao)
     446         1560 :                CALL dbcsr_copy(rho1_ao(ispin)%matrix, p_env%p1_admm(ispin)%matrix)
     447              :                CALL calculate_rho_elec(ks_env=ks_env, &
     448              :                                        matrix_p=rho1_ao(ispin)%matrix, &
     449              :                                        rho=rho_r_aux(ispin), &
     450              :                                        rho_gspace=rho_g_aux(ispin), &
     451              :                                        soft_valid=.FALSE., &
     452              :                                        basis_type=basis_type, &
     453         2958 :                                        task_list_external=task_list)
     454              :             END DO
     455         1398 :             IF (admm_env%do_gapw) THEN
     456          396 :                CALL get_qs_env(qs_env, para_env=para_env)
     457          396 :                CALL get_admm_env(admm_env, sab_aux_fit=sab_aux_fit)
     458              :                CALL calculate_rho_atom_coeff(qs_env, rho1_ao, &
     459              :                                              rho_atom_set=p_env%local_rho_set_admm%rho_atom_set, &
     460              :                                              qs_kind_set=admm_env%admm_gapw_env%admm_kind_set, &
     461          396 :                                              oce=admm_env%admm_gapw_env%oce, sab=sab_aux_fit, para_env=para_env)
     462              :             END IF
     463              :          END IF
     464              :       END IF
     465              : 
     466        11654 :       CALL timestop(handle)
     467              : 
     468        11654 :    END SUBROUTINE p_env_update_rho
     469              : 
     470              : ! **************************************************************************************************
     471              : !> \brief To be called after the value of psi0 has changed.
     472              : !>      Recalculates the quantities S_psi0 and m_epsilon.
     473              : !> \param p_env the perturbation environment to set
     474              : !> \param qs_env ...
     475              : !> \par History
     476              : !>      07.2002 created [fawzi]
     477              : !> \author Fawzi Mohamed
     478              : ! **************************************************************************************************
     479         1830 :    SUBROUTINE p_env_psi0_changed(p_env, qs_env)
     480              : 
     481              :       TYPE(qs_p_env_type)                                :: p_env
     482              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     483              : 
     484              :       CHARACTER(len=*), PARAMETER :: routineN = 'p_env_psi0_changed'
     485              : 
     486              :       INTEGER                                            :: handle, iounit, lfomo, n_spins, nmo, spin
     487              :       LOGICAL                                            :: was_present
     488              :       REAL(KIND=dp)                                      :: maxocc
     489         1830 :       TYPE(cp_fm_pool_p_type), DIMENSION(:), POINTER     :: ao_mo_fm_pools
     490         1830 :       TYPE(cp_fm_type), DIMENSION(:), POINTER            :: psi0
     491              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
     492              :       TYPE(cp_logger_type), POINTER                      :: logger
     493         1830 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_ks, matrix_s, rho_ao
     494              :       TYPE(dft_control_type), POINTER                    :: dft_control
     495         1830 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     496              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     497              :       TYPE(qs_energy_type), POINTER                      :: energy
     498              :       TYPE(qs_ks_env_type), POINTER                      :: ks_env
     499              :       TYPE(qs_rho_type), POINTER                         :: rho
     500              :       TYPE(section_vals_type), POINTER                   :: input, lr_section
     501              : 
     502         1830 :       CALL timeset(routineN, handle)
     503              : 
     504         1830 :       NULLIFY (ao_mo_fm_pools, mos, psi0, matrix_s, mos, para_env, ks_env, rho, &
     505         1830 :                logger, input, lr_section, energy, matrix_ks, dft_control, rho_ao)
     506         1830 :       logger => cp_get_default_logger()
     507              : 
     508              :       CALL get_qs_env(qs_env, &
     509              :                       ks_env=ks_env, &
     510              :                       mos=mos, &
     511              :                       matrix_s=matrix_s, &
     512              :                       matrix_ks=matrix_ks, &
     513              :                       para_env=para_env, &
     514              :                       rho=rho, &
     515              :                       input=input, &
     516              :                       energy=energy, &
     517         1830 :                       dft_control=dft_control)
     518              : 
     519         1830 :       CALL qs_rho_get(rho, rho_ao=rho_ao)
     520              : 
     521         1830 :       n_spins = dft_control%nspins
     522              :       CALL mpools_get(qs_env%mpools, &
     523         1830 :                       ao_mo_fm_pools=ao_mo_fm_pools)
     524         7632 :       ALLOCATE (psi0(n_spins))
     525         3972 :       DO spin = 1, n_spins
     526         2142 :          CALL get_mo_set(mos(spin), mo_coeff=mo_coeff)
     527         2142 :          CALL cp_fm_create(psi0(spin), mo_coeff%matrix_struct)
     528         3972 :          CALL cp_fm_to_fm(mo_coeff, psi0(spin))
     529              :       END DO
     530              : 
     531         1830 :       lr_section => section_vals_get_subs_vals(input, "PROPERTIES%LINRES")
     532              :       ! def psi0d
     533         1830 :       IF (p_env%orthogonal_orbitals) THEN
     534         1830 :          IF (ASSOCIATED(p_env%psi0d)) THEN
     535            0 :             CALL cp_fm_release(p_env%psi0d)
     536              :          END IF
     537         1830 :          p_env%psi0d => psi0
     538              :       ELSE
     539              : 
     540            0 :          DO spin = 1, n_spins
     541              :             ! m_epsilon=cholesky_decomposition(psi0^T S psi0)^-1
     542              :             ! could be optimized by combining next two calls
     543              :             CALL cp_dbcsr_sm_fm_multiply(matrix_s(1)%matrix, &
     544              :                                          psi0(spin), &
     545              :                                          p_env%S_psi0(spin), &
     546            0 :                                          ncol=p_env%n_mo(spin), alpha=1.0_dp)
     547              :             CALL parallel_gemm(transa='T', transb='N', n=p_env%n_mo(spin), &
     548              :                                m=p_env%n_mo(spin), k=p_env%n_ao(spin), alpha=1.0_dp, &
     549              :                                matrix_a=psi0(spin), &
     550              :                                matrix_b=p_env%S_psi0(spin), &
     551            0 :                                beta=0.0_dp, matrix_c=p_env%m_epsilon(spin))
     552              :             CALL cp_fm_cholesky_decompose(p_env%m_epsilon(spin), &
     553            0 :                                           n=p_env%n_mo(spin))
     554              : 
     555              :             ! Smo_inv= (psi0^T S psi0)^-1
     556            0 :             CALL cp_fm_set_all(p_env%Smo_inv(spin), 0.0_dp, 1.0_dp)
     557              :             ! faster using cp_fm_cholesky_invert ?
     558              :             CALL cp_fm_triangular_multiply( &
     559              :                triangular_matrix=p_env%m_epsilon(spin), &
     560              :                matrix_b=p_env%Smo_inv(spin), side='R', &
     561              :                invert_tr=.TRUE., n_rows=p_env%n_mo(spin), &
     562            0 :                n_cols=p_env%n_mo(spin))
     563              :             CALL cp_fm_triangular_multiply( &
     564              :                triangular_matrix=p_env%m_epsilon(spin), &
     565              :                matrix_b=p_env%Smo_inv(spin), side='R', &
     566              :                transpose_tr=.TRUE., &
     567              :                invert_tr=.TRUE., n_rows=p_env%n_mo(spin), &
     568            0 :                n_cols=p_env%n_mo(spin))
     569              : 
     570              :             ! psi0d=psi0 (psi0^T S psi0)^-1
     571              :             ! faster using cp_fm_cholesky_invert ?
     572              :             CALL cp_fm_to_fm(psi0(spin), &
     573            0 :                              p_env%psi0d(spin))
     574              :             CALL cp_fm_triangular_multiply( &
     575              :                triangular_matrix=p_env%m_epsilon(spin), &
     576              :                matrix_b=p_env%psi0d(spin), side='R', &
     577              :                invert_tr=.TRUE., n_rows=p_env%n_ao(spin), &
     578            0 :                n_cols=p_env%n_mo(spin))
     579              :             CALL cp_fm_triangular_multiply( &
     580              :                triangular_matrix=p_env%m_epsilon(spin), &
     581              :                matrix_b=p_env%psi0d(spin), side='R', &
     582              :                transpose_tr=.TRUE., &
     583              :                invert_tr=.TRUE., n_rows=p_env%n_ao(spin), &
     584            0 :                n_cols=p_env%n_mo(spin))
     585              : 
     586              :             ! updates P
     587              :             CALL get_mo_set(mos(spin), lfomo=lfomo, &
     588            0 :                             nmo=nmo, maxocc=maxocc)
     589            0 :             IF (lfomo > nmo) THEN
     590            0 :                CALL dbcsr_set(rho_ao(spin)%matrix, 0.0_dp)
     591              :                CALL cp_dbcsr_plus_fm_fm_t(rho_ao(spin)%matrix, &
     592              :                                           matrix_v=psi0(spin), &
     593              :                                           matrix_g=p_env%psi0d(spin), &
     594            0 :                                           ncol=p_env%n_mo(spin))
     595            0 :                CALL dbcsr_scale(rho_ao(spin)%matrix, alpha_scalar=maxocc)
     596              :             ELSE
     597            0 :                CPABORT("symmetrized onesided smearing to do")
     598              :             END IF
     599              :          END DO
     600              : 
     601              :          ! updates rho
     602            0 :          CALL qs_rho_update_rho(rho_struct=rho, qs_env=qs_env)
     603              : 
     604              :          ! tells ks_env that p changed
     605            0 :          CALL qs_ks_did_change(ks_env=ks_env, rho_changed=.TRUE.)
     606              : 
     607              :       END IF
     608              : 
     609              :       ! updates K (if necessary)
     610         1830 :       CALL qs_ks_update_qs_env(qs_env)
     611              :       iounit = cp_print_key_unit_nr(logger, lr_section, "PRINT%PROGRAM_RUN_INFO", &
     612         1830 :                                     extension=".linresLog")
     613         1830 :       IF (iounit > 0) THEN
     614          890 :          CALL section_vals_get(lr_section, explicit=was_present)
     615          890 :          IF (was_present) THEN
     616              :             WRITE (UNIT=iounit, FMT="(/,(T3,A,T55,F25.14))") &
     617          168 :                "Total energy ground state:                     ", energy%total
     618              :          END IF
     619              :       END IF
     620              :       CALL cp_print_key_finished_output(iounit, logger, lr_section, &
     621         1830 :                                         "PRINT%PROGRAM_RUN_INFO")
     622              :       !-----------------------------------------------------------------------|
     623              :       ! calculates                                                            |
     624              :       ! m_epsilon = - psi0d^T times K times psi0d                             |
     625              :       !           = - [K times psi0d]^T times psi0d (because K is symmetric)  |
     626              :       !-----------------------------------------------------------------------|
     627         3972 :       DO spin = 1, n_spins
     628              :          ! S_psi0 = k times psi0d
     629              :          CALL cp_dbcsr_sm_fm_multiply(matrix_ks(spin)%matrix, &
     630              :                                       p_env%psi0d(spin), &
     631         2142 :                                       p_env%S_psi0(spin), p_env%n_mo(spin))
     632              :          ! m_epsilon = -1 times S_psi0^T times psi0d
     633              :          CALL parallel_gemm('T', 'N', &
     634              :                             p_env%n_mo(spin), p_env%n_mo(spin), p_env%n_ao(spin), &
     635              :                             -1.0_dp, p_env%S_psi0(spin), p_env%psi0d(spin), &
     636         3972 :                             0.0_dp, p_env%m_epsilon(spin))
     637              :       END DO
     638              : 
     639              :       !----------------------------------|
     640              :       ! calculates S_psi0 = S * psi0  |
     641              :       !----------------------------------|
     642              :       ! calculating this reduces the mat mult without storing a full aoxao
     643              :       ! matrix (for P). If nspin>1 you might consider calculating it on the
     644              :       ! fly to spare some memory
     645         1830 :       CALL get_qs_env(qs_env, matrix_s=matrix_s)
     646         3972 :       DO spin = 1, n_spins
     647              :          CALL cp_dbcsr_sm_fm_multiply(matrix_s(1)%matrix, &
     648              :                                       psi0(spin), &
     649              :                                       p_env%S_psi0(spin), &
     650         3972 :                                       p_env%n_mo(spin))
     651              :       END DO
     652              : 
     653              :       ! releases psi0
     654         1830 :       IF (p_env%orthogonal_orbitals) THEN
     655         1830 :          NULLIFY (psi0)
     656              :       ELSE
     657            0 :          CALL cp_fm_release(psi0)
     658              :       END IF
     659              : 
     660              :       ! tells kpp1_env about the change of psi0
     661         1830 :       CALL kpp1_did_change(p_env%kpp1_env)
     662              : 
     663         1830 :       CALL timestop(handle)
     664              : 
     665         1830 :    END SUBROUTINE p_env_psi0_changed
     666              : 
     667              : ! **************************************************************************************************
     668              : !> \brief does a preorthogonalization of the given matrix:
     669              : !>      v = (I-PS)v
     670              : !> \param p_env the perturbation environment
     671              : !> \param qs_env the qs_env that is perturbed by this p_env
     672              : !> \param v matrix to orthogonalize
     673              : !> \param n_cols the number of columns of C to multiply (defaults to size(v,2))
     674              : !> \par History
     675              : !>      02.09.2002 adapted for new qs_p_env_type (TC)
     676              : !> \author Fawzi Mohamed
     677              : ! **************************************************************************************************
     678            0 :    SUBROUTINE p_preortho(p_env, qs_env, v, n_cols)
     679              : 
     680              :       TYPE(qs_p_env_type)                                :: p_env
     681              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     682              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(inout)      :: v
     683              :       INTEGER, DIMENSION(:), INTENT(in), OPTIONAL        :: n_cols
     684              : 
     685              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'p_preortho'
     686              : 
     687              :       INTEGER                                            :: cols, handle, max_cols, maxnmo, n_spins, &
     688              :                                                             nmo2, spin, v_cols, v_rows
     689              :       TYPE(cp_fm_pool_type), POINTER                     :: maxmo_maxmo_fm_pool
     690              :       TYPE(cp_fm_struct_type), POINTER                   :: maxmo_maxmo_fmstruct, tmp_fmstruct
     691              :       TYPE(cp_fm_type)                                   :: tmp_matrix
     692              :       TYPE(dft_control_type), POINTER                    :: dft_control
     693              : 
     694            0 :       CALL timeset(routineN, handle)
     695              : 
     696            0 :       NULLIFY (maxmo_maxmo_fm_pool, maxmo_maxmo_fmstruct, tmp_fmstruct, &
     697            0 :                dft_control)
     698              : 
     699            0 :       CALL get_qs_env(qs_env, dft_control=dft_control)
     700            0 :       CALL mpools_get(qs_env%mpools, maxmo_maxmo_fm_pool=maxmo_maxmo_fm_pool)
     701            0 :       n_spins = dft_control%nspins
     702            0 :       maxmo_maxmo_fmstruct => fm_pool_get_el_struct(maxmo_maxmo_fm_pool)
     703            0 :       CALL cp_fm_struct_get(maxmo_maxmo_fmstruct, nrow_global=nmo2, ncol_global=maxnmo)
     704            0 :       CPASSERT(SIZE(v) >= n_spins)
     705              :       ! alloc tmp storage
     706            0 :       IF (PRESENT(n_cols)) THEN
     707            0 :          max_cols = MAXVAL(n_cols(1:n_spins))
     708              :       ELSE
     709            0 :          max_cols = 0
     710            0 :          DO spin = 1, n_spins
     711            0 :             CALL cp_fm_get_info(v(spin), ncol_global=v_cols)
     712            0 :             max_cols = MAX(max_cols, v_cols)
     713              :          END DO
     714              :       END IF
     715            0 :       IF (max_cols <= nmo2) THEN
     716            0 :          CALL fm_pool_create_fm(maxmo_maxmo_fm_pool, tmp_matrix)
     717              :       ELSE
     718              :          CALL cp_fm_struct_create(tmp_fmstruct, nrow_global=max_cols, &
     719            0 :                                   ncol_global=maxnmo, template_fmstruct=maxmo_maxmo_fmstruct)
     720            0 :          CALL cp_fm_create(tmp_matrix, matrix_struct=tmp_fmstruct)
     721            0 :          CALL cp_fm_struct_release(tmp_fmstruct)
     722              :       END IF
     723              : 
     724            0 :       DO spin = 1, n_spins
     725              : 
     726              :          CALL cp_fm_get_info(v(spin), &
     727            0 :                              nrow_global=v_rows, ncol_global=v_cols)
     728            0 :          CPASSERT(v_rows >= p_env%n_ao(spin))
     729            0 :          cols = v_cols
     730            0 :          IF (PRESENT(n_cols)) THEN
     731            0 :             CPASSERT(n_cols(spin) <= cols)
     732            0 :             cols = n_cols(spin)
     733              :          END IF
     734            0 :          CPASSERT(cols <= max_cols)
     735              : 
     736              :          ! tmp_matrix = v^T (S psi0)
     737              :          CALL parallel_gemm(transa='T', transb='N', m=cols, n=p_env%n_mo(spin), &
     738              :                             k=p_env%n_ao(spin), alpha=1.0_dp, matrix_a=v(spin), &
     739              :                             matrix_b=p_env%S_psi0(spin), beta=0.0_dp, &
     740            0 :                             matrix_c=tmp_matrix)
     741              :          ! v = v - psi0d tmp_matrix^T = v - psi0d psi0^T S v
     742              :          CALL parallel_gemm(transa='N', transb='T', m=p_env%n_ao(spin), n=cols, &
     743              :                             k=p_env%n_mo(spin), alpha=-1.0_dp, &
     744              :                             matrix_a=p_env%psi0d(spin), matrix_b=tmp_matrix, &
     745            0 :                             beta=1.0_dp, matrix_c=v(spin))
     746              : 
     747              :       END DO
     748              : 
     749            0 :       IF (max_cols <= nmo2) THEN
     750            0 :          CALL fm_pool_give_back_fm(maxmo_maxmo_fm_pool, tmp_matrix)
     751              :       ELSE
     752            0 :          CALL cp_fm_release(tmp_matrix)
     753              :       END IF
     754              : 
     755            0 :       CALL timestop(handle)
     756              : 
     757            0 :    END SUBROUTINE p_preortho
     758              : 
     759              : ! **************************************************************************************************
     760              : !> \brief does a postorthogonalization on the given matrix vector:
     761              : !>      v = (I-SP) v
     762              : !> \param p_env the perturbation environment
     763              : !> \param qs_env the qs_env that is perturbed by this p_env
     764              : !> \param v matrix to orthogonalize
     765              : !> \param n_cols the number of columns of C to multiply (defaults to size(v,2))
     766              : !> \par History
     767              : !>      07.2002 created [fawzi]
     768              : !> \author Fawzi Mohamed
     769              : ! **************************************************************************************************
     770            0 :    SUBROUTINE p_postortho(p_env, qs_env, v, n_cols)
     771              : 
     772              :       TYPE(qs_p_env_type)                                :: p_env
     773              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     774              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(inout)      :: v
     775              :       INTEGER, DIMENSION(:), INTENT(in), OPTIONAL        :: n_cols
     776              : 
     777              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'p_postortho'
     778              : 
     779              :       INTEGER                                            :: cols, handle, max_cols, maxnmo, n_spins, &
     780              :                                                             nmo2, spin, v_cols, v_rows
     781              :       TYPE(cp_fm_pool_type), POINTER                     :: maxmo_maxmo_fm_pool
     782              :       TYPE(cp_fm_struct_type), POINTER                   :: maxmo_maxmo_fmstruct, tmp_fmstruct
     783              :       TYPE(cp_fm_type)                                   :: tmp_matrix
     784              :       TYPE(dft_control_type), POINTER                    :: dft_control
     785              : 
     786            0 :       CALL timeset(routineN, handle)
     787              : 
     788            0 :       NULLIFY (maxmo_maxmo_fm_pool, maxmo_maxmo_fmstruct, tmp_fmstruct, &
     789            0 :                dft_control)
     790              : 
     791            0 :       CALL get_qs_env(qs_env, dft_control=dft_control)
     792            0 :       CALL mpools_get(qs_env%mpools, maxmo_maxmo_fm_pool=maxmo_maxmo_fm_pool)
     793            0 :       n_spins = dft_control%nspins
     794            0 :       maxmo_maxmo_fmstruct => fm_pool_get_el_struct(maxmo_maxmo_fm_pool)
     795            0 :       CALL cp_fm_struct_get(maxmo_maxmo_fmstruct, nrow_global=nmo2, ncol_global=maxnmo)
     796            0 :       CPASSERT(SIZE(v) >= n_spins)
     797              :       ! alloc tmp storage
     798            0 :       IF (PRESENT(n_cols)) THEN
     799            0 :          max_cols = MAXVAL(n_cols(1:n_spins))
     800              :       ELSE
     801            0 :          max_cols = 0
     802            0 :          DO spin = 1, n_spins
     803            0 :             CALL cp_fm_get_info(v(spin), ncol_global=v_cols)
     804            0 :             max_cols = MAX(max_cols, v_cols)
     805              :          END DO
     806              :       END IF
     807            0 :       IF (max_cols <= nmo2) THEN
     808            0 :          CALL fm_pool_create_fm(maxmo_maxmo_fm_pool, tmp_matrix)
     809              :       ELSE
     810              :          CALL cp_fm_struct_create(tmp_fmstruct, nrow_global=max_cols, &
     811            0 :                                   ncol_global=maxnmo, template_fmstruct=maxmo_maxmo_fmstruct)
     812            0 :          CALL cp_fm_create(tmp_matrix, matrix_struct=tmp_fmstruct)
     813            0 :          CALL cp_fm_struct_release(tmp_fmstruct)
     814              :       END IF
     815              : 
     816            0 :       DO spin = 1, n_spins
     817              : 
     818              :          CALL cp_fm_get_info(v(spin), &
     819            0 :                              nrow_global=v_rows, ncol_global=v_cols)
     820            0 :          CPASSERT(v_rows >= p_env%n_ao(spin))
     821            0 :          cols = v_cols
     822            0 :          IF (PRESENT(n_cols)) THEN
     823            0 :             CPASSERT(n_cols(spin) <= cols)
     824            0 :             cols = n_cols(spin)
     825              :          END IF
     826            0 :          CPASSERT(cols <= max_cols)
     827              : 
     828              :          ! tmp_matrix = v^T psi0d
     829              :          CALL parallel_gemm(transa='T', transb='N', m=cols, n=p_env%n_mo(spin), &
     830              :                             k=p_env%n_ao(spin), alpha=1.0_dp, matrix_a=v(spin), &
     831              :                             matrix_b=p_env%psi0d(spin), beta=0.0_dp, &
     832            0 :                             matrix_c=tmp_matrix)
     833              :          ! v = v - (S psi0) tmp_matrix^T = v - S psi0 psi0d^T v
     834              :          CALL parallel_gemm(transa='N', transb='T', m=p_env%n_ao(spin), n=cols, &
     835              :                             k=p_env%n_mo(spin), alpha=-1.0_dp, &
     836              :                             matrix_a=p_env%S_psi0(spin), matrix_b=tmp_matrix, &
     837            0 :                             beta=1.0_dp, matrix_c=v(spin))
     838              : 
     839              :       END DO
     840              : 
     841            0 :       IF (max_cols <= nmo2) THEN
     842            0 :          CALL fm_pool_give_back_fm(maxmo_maxmo_fm_pool, tmp_matrix)
     843              :       ELSE
     844            0 :          CALL cp_fm_release(tmp_matrix)
     845              :       END IF
     846              : 
     847            0 :       CALL timestop(handle)
     848              : 
     849            0 :    END SUBROUTINE p_postortho
     850              : 
     851              : ! **************************************************************************************************
     852              : !> \brief ...
     853              : !> \param qs_env ...
     854              : !> \param p_env ...
     855              : ! **************************************************************************************************
     856         2846 :    SUBROUTINE p_env_finish_kpp1(qs_env, p_env)
     857              :       TYPE(qs_environment_type), INTENT(IN), POINTER     :: qs_env
     858              :       TYPE(qs_p_env_type), INTENT(IN)                    :: p_env
     859              : 
     860              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'p_env_finish_kpp1'
     861              : 
     862              :       INTEGER                                            :: handle, ispin, nao, nao_aux
     863              :       TYPE(admm_type), POINTER                           :: admm_env
     864              :       TYPE(dbcsr_type)                                   :: work_hmat
     865              :       TYPE(dft_control_type), POINTER                    :: dft_control
     866              : 
     867         2846 :       CALL timeset(routineN, handle)
     868              : 
     869         2846 :       CALL get_qs_env(qs_env, dft_control=dft_control, admm_env=admm_env)
     870              : 
     871         2846 :       IF (dft_control%do_admm) THEN
     872         2402 :          CALL dbcsr_copy(work_hmat, p_env%kpp1(1)%matrix)
     873              : 
     874         2402 :          CALL cp_fm_get_info(admm_env%A, nrow_global=nao_aux, ncol_global=nao)
     875         5104 :          DO ispin = 1, SIZE(p_env%kpp1)
     876              :             CALL cp_dbcsr_sm_fm_multiply(p_env%kpp1_admm(ispin)%matrix, admm_env%A, admm_env%work_aux_orb, &
     877         2702 :                                          ncol=nao, alpha=1.0_dp, beta=0.0_dp)
     878              :             CALL parallel_gemm('T', 'N', nao, nao, nao_aux, 1.0_dp, admm_env%A, &
     879         2702 :                                admm_env%work_aux_orb, 0.0_dp, admm_env%work_orb_orb)
     880         2702 :             CALL dbcsr_set(work_hmat, 0.0_dp)
     881         2702 :             CALL copy_fm_to_dbcsr(admm_env%work_orb_orb, work_hmat, keep_sparsity=.TRUE.)
     882         5104 :             CALL dbcsr_add(p_env%kpp1(ispin)%matrix, work_hmat, 1.0_dp, 1.0_dp)
     883              :          END DO
     884              : 
     885         2402 :          CALL dbcsr_release(work_hmat)
     886              :       END IF
     887              : 
     888         2846 :       CALL timestop(handle)
     889              : 
     890         2846 :    END SUBROUTINE p_env_finish_kpp1
     891              : 
     892              : END MODULE qs_p_env_methods
        

Generated by: LCOV version 2.0-1