LCOV - code coverage report
Current view: top level - src - qs_vcd.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:ba1d7ca) Lines: 99.2 % 385 382
Test Date: 2026-09-09 06:35:33 Functions: 100.0 % 5 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              : MODULE qs_vcd
       8              :    USE atomic_kind_types,               ONLY: get_atomic_kind
       9              :    USE cell_types,                      ONLY: cell_type
      10              :    USE commutator_rpnl,                 ONLY: build_com_mom_nl
      11              :    USE cp_control_types,                ONLY: dft_control_type
      12              :    USE cp_dbcsr_api,                    ONLY: dbcsr_add,&
      13              :                                               dbcsr_copy,&
      14              :                                               dbcsr_desymmetrize,&
      15              :                                               dbcsr_scale,&
      16              :                                               dbcsr_set
      17              :    USE cp_dbcsr_operations,             ONLY: cp_dbcsr_sm_fm_multiply
      18              :    USE cp_fm_basic_linalg,              ONLY: cp_fm_scale,&
      19              :                                               cp_fm_scale_and_add,&
      20              :                                               cp_fm_trace
      21              :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      22              :                                               cp_fm_release,&
      23              :                                               cp_fm_set_all,&
      24              :                                               cp_fm_to_fm,&
      25              :                                               cp_fm_type
      26              :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      27              :                                               cp_logger_type
      28              :    USE cp_output_handling,              ONLY: cp_print_key_finished_output,&
      29              :                                               cp_print_key_unit_nr
      30              :    USE input_section_types,             ONLY: section_vals_get_subs_vals,&
      31              :                                               section_vals_type
      32              :    USE kinds,                           ONLY: dp
      33              :    USE parallel_gemm_api,               ONLY: parallel_gemm
      34              :    USE particle_types,                  ONLY: particle_type
      35              :    USE qs_dcdr_ao,                      ONLY: hr_mult_by_delta_1d
      36              :    USE qs_environment_types,            ONLY: get_qs_env,&
      37              :                                               qs_environment_type
      38              :    USE qs_kind_types,                   ONLY: get_qs_kind,&
      39              :                                               qs_kind_type
      40              :    USE qs_linres_methods,               ONLY: linres_solver
      41              :    USE qs_linres_types,                 ONLY: linres_control_type,&
      42              :                                               vcd_env_type
      43              :    USE qs_mo_types,                     ONLY: mo_set_type
      44              :    USE qs_moments,                      ONLY: build_local_moments_der_matrix
      45              :    USE qs_neighbor_list_types,          ONLY: neighbor_list_set_p_type
      46              :    USE qs_p_env_types,                  ONLY: qs_p_env_type
      47              :    USE qs_vcd_ao,                       ONLY: build_dSdV_matrix,&
      48              :                                               build_dcom_rpnl,&
      49              :                                               build_matrix_hr_rh,&
      50              :                                               hr_mult_by_delta_3d
      51              :    USE qs_vcd_utils,                    ONLY: vcd_read_restart,&
      52              :                                               vcd_write_restart
      53              : #include "./base/base_uses.f90"
      54              : 
      55              :    IMPLICIT NONE
      56              : 
      57              :    PRIVATE
      58              :    PUBLIC :: prepare_per_atom_vcd
      59              :    PUBLIC :: vcd_build_op_dV
      60              :    PUBLIC :: vcd_response_dV
      61              :    PUBLIC :: apt_dV
      62              :    PUBLIC :: aat_dV
      63              : 
      64              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_vcd'
      65              : 
      66              :    REAL(dp), DIMENSION(3, 3, 3), PARAMETER  :: Levi_Civita = RESHAPE([ &
      67              :                                                           0.0_dp, 0.0_dp, 0.0_dp, 0.0_dp, 0.0_dp, -1.0_dp, 0.0_dp, 1.0_dp, 0.0_dp, &
      68              :                                                           0.0_dp, 0.0_dp, 1.0_dp, 0.0_dp, 0.0_dp, 0.0_dp, -1.0_dp, 0.0_dp, 0.0_dp, &
      69              :                                                          0.0_dp, -1.0_dp, 0.0_dp, 1.0_dp, 0.0_dp, 0.0_dp, 0.0_dp, 0.0_dp, 0.0_dp], &
      70              :                                                                      [3, 3, 3])
      71              :    INTEGER, DIMENSION(3, 3), PARAMETER :: multipole_2d_to_1d = RESHAPE([4, 5, 6, 5, 7, 8, 6, 8, 9], [3, 3])
      72              : CONTAINS
      73              : 
      74              : ! **************************************************************************************************
      75              : !> \brief Compute I_{alpha beta}^lambda = d/dV^lambda_beta <m_alpha> = d/dV^lambda_beta < r x \dot{r} >
      76              : !>        The directions alpha, beta are stored in vcd_env%dcdr_env
      77              : !> \param vcd_env ...
      78              : !> \param qs_env ...
      79              : !> \author Edward Ditler
      80              : ! **************************************************************************************************
      81           18 :    SUBROUTINE aat_dV(vcd_env, qs_env)
      82              :       TYPE(vcd_env_type)                                 :: vcd_env
      83              :       TYPE(qs_environment_type), POINTER                 :: qs_env
      84              : 
      85              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'aat_dV'
      86              :       INTEGER, PARAMETER                                 :: ispin = 1
      87              : 
      88              :       INTEGER                                            :: alpha, delta, gamma, handle, ikind, &
      89              :                                                             my_index, nao, nmo, nspins
      90              :       LOGICAL                                            :: ghost
      91              :       REAL(dp)                                           :: aat_prefactor, aat_tmp, charge, lc_tmp, &
      92              :                                                             tmp_trace
      93              :       REAL(dp), DIMENSION(3, 3)                          :: aat_tmp_33
      94              :       TYPE(cp_fm_type)                                   :: tmp_aomo
      95              :       TYPE(dft_control_type), POINTER                    :: dft_control
      96              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
      97           18 :          POINTER                                         :: sab_all, sab_orb, sap_ppnl
      98           18 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
      99           18 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     100              : 
     101           18 :       CALL timeset(routineN, handle)
     102              : 
     103              :       CALL get_qs_env(qs_env=qs_env, &
     104              :                       dft_control=dft_control, &
     105              :                       sap_ppnl=sap_ppnl, &
     106              :                       sab_orb=sab_orb, &
     107              :                       sab_all=sab_all, &
     108              :                       particle_set=particle_set, &
     109           18 :                       qs_kind_set=qs_kind_set)
     110              : 
     111           18 :       CALL cp_fm_create(tmp_aomo, vcd_env%dcdr_env%likemos_fm_struct(ispin)%struct)
     112              : 
     113           18 :       nspins = dft_control%nspins
     114           18 :       nmo = vcd_env%dcdr_env%nmo(ispin)
     115           18 :       nao = vcd_env%dcdr_env%nao
     116              :       ASSOCIATE (mo_coeff => vcd_env%dcdr_env%mo_coeff(ispin), aat_atom => vcd_env%aat_atom_nvpt)
     117              : 
     118              :          ! I_{alpha beta}^lambda = 1/2c \sum_j^occ ...
     119           18 :          aat_prefactor = 1.0_dp!/(c_light_au * 2._dp)
     120           18 :          IF (nspins == 1) aat_prefactor = aat_prefactor*2.0_dp
     121              : 
     122              :          ! The non-PP part of the AAT consists of four contributions:
     123              :          !  (A1):  + P^0 * ε_{alpha gamma delta} * < mu | r_beta r_gamma ∂_delta | nu > * (mu == lambda)
     124              :          !  (A2):  - P^0 * ε_{alpha gamma delta} * < mu | r_gamma r_beta ∂_delta | nu > * (nu == lambda)
     125              :          !  (B):   - P^0 * ε_{alpha gamma delta} * < mu | r_gamma | nu > * (delta == beta) * (nu == lambda)
     126              :          !  (C):   + iP^1 * ε_{alpha gamma delta} * < mu | r_gamma ∂_delta | nu >
     127              : 
     128              :          ! (A1) + P^0 * ε_{alpha gamma delta} * < mu | r_beta r_gamma ∂_delta | nu > * (mu == lambda)
     129              :          ! (A2) - P^0 * ε_{alpha gamma delta} * < mu | r_gamma r_beta ∂_delta | nu > * (nu == lambda)
     130              :          ! Conjecture : It doesn't matter that the beta and gamma are swapped around!
     131              :          !               We define o = | ∂_delta nu >
     132              :          !                 and then < a | r_beta r_gamma | o > = < a | r_gamma r_beta | o>
     133              :          ! (A) + P^0 * ε_{alpha gamma delta} * < mu | r_beta r_gamma ∂_delta | nu > * (mu == lambda - nu == lambda)
     134              :          ! We have built the matrices - < mu | r_beta r_gamma ∂_delta | nu > in vcd_env%moments_der
     135              :          ! moments_der(1:9; 1:3) = moments_der(x, y, z, xx, xy, xz, yy, yz, zz;
     136              :          !                                     x, y, z)
     137              : 
     138           18 :          aat_tmp_33 = 0._dp
     139           72 :          DO gamma = 1, 3
     140           54 :             my_index = multipole_2d_to_1d(vcd_env%dcdr_env%beta, gamma)
     141          234 :             DO delta = 1, 3
     142              :                ! moments_der(moment, delta) = - < a | moment \partial_\delta | b >
     143              :                ! matrix_nosym_temp = - < mu | r_beta r_gamma ∂_delta | nu > * (mu - nu)
     144              :                CALL dbcsr_copy(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, &
     145          162 :                                vcd_env%moments_der_right(my_index, delta)%matrix)
     146              :                CALL dbcsr_add(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, &
     147              :                               vcd_env%moments_der_left(my_index, delta)%matrix, &
     148          162 :                               1._dp, -1._dp)
     149              : 
     150          162 :                CALL cp_dbcsr_sm_fm_multiply(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, mo_coeff, tmp_aomo, ncol=nmo)
     151          216 :                CALL cp_fm_trace(mo_coeff, tmp_aomo, aat_tmp_33(gamma, delta))
     152              :             END DO
     153              :          END DO
     154              : 
     155           72 :          DO alpha = 1, 3
     156           54 :             aat_tmp = 0._dp
     157              : 
     158              :             ! There are two remaining combinations for gamma and delta.
     159          216 :             DO gamma = 1, 3
     160          702 :                DO delta = 1, 3
     161          486 :                   lc_tmp = Levi_Civita(alpha, gamma, delta)
     162          486 :                   IF (lc_tmp == 0._dp) CYCLE
     163              : 
     164              :                   ! moments_der(moment, delta) = - < a | moment \partial_\delta | b >
     165              :                   ! matrix_nosym_temp = - < mu | r_beta r_gamma ∂_delta | nu > * (mu - nu)
     166              :                   ! Because of the negative in moments_der, we need another negative sign here.
     167          648 :                   aat_tmp = aat_tmp + lc_tmp*aat_prefactor*aat_tmp_33(gamma, delta)
     168              :                END DO
     169              :             END DO
     170              : 
     171              :             aat_atom(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) &
     172           72 :                = aat_atom(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) + aat_tmp
     173              :          END DO
     174              : 
     175              :          !  (B):   - P^0 * ε_{alpha gamma delta} * < mu | r_gamma | nu > * (delta == beta) * (nu == lambda)
     176              :          !      =  - P^0 * ε_{alpha gamma beta} * < mu | r_gamma | nu > * (nu == lambda)
     177              : 
     178           72 :          DO alpha = 1, 3
     179           54 :             aat_tmp = 0._dp
     180              : 
     181          216 :             DO gamma = 1, 3
     182          162 :                lc_tmp = Levi_Civita(alpha, gamma, vcd_env%dcdr_env%beta)
     183          162 :                IF (lc_tmp == 0._dp) CYCLE
     184              : 
     185              :                ! matrix_nosym_temp = < mu | r_gamma | nu > * (nu == lambda)
     186              :                CALL dbcsr_desymmetrize(vcd_env%dcdr_env%moments(gamma)%matrix, &
     187           36 :                                        vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix)
     188              :                CALL hr_mult_by_delta_1d(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, qs_kind_set, "ORB", &
     189           36 :                                         sab_all, direction_Or=.TRUE., lambda=vcd_env%dcdr_env%lambda)
     190              : 
     191           36 :                CALL cp_dbcsr_sm_fm_multiply(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, mo_coeff, tmp_aomo, ncol=nmo)
     192           36 :                CALL cp_fm_trace(mo_coeff, tmp_aomo, tmp_trace)
     193          216 :                aat_tmp = aat_tmp - lc_tmp*aat_prefactor*tmp_trace
     194              :             END DO
     195              : 
     196              :             aat_atom(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) &
     197           72 :                = aat_atom(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) + aat_tmp
     198              :          END DO
     199              : 
     200              :          !  (C):   + iP^1 * ε_{alpha gamma delta} * < mu | r_gamma ∂_delta | nu >
     201           72 :          DO alpha = 1, 3
     202           54 :             aat_tmp = 0._dp
     203              : 
     204          216 :             DO gamma = 1, 3
     205          702 :                DO delta = 1, 3
     206          486 :                   lc_tmp = Levi_Civita(alpha, gamma, delta)
     207          486 :                   IF (lc_tmp == 0._dp) CYCLE
     208              : 
     209          108 :                   CALL cp_dbcsr_sm_fm_multiply(vcd_env%moments_der(gamma, delta)%matrix, mo_coeff, tmp_aomo, ncol=nmo)
     210          108 :                   CALL cp_fm_trace(tmp_aomo, vcd_env%dCV_prime(ispin), tmp_trace)
     211              : 
     212              :                   ! mo_coeff * dCV_prime = + iP1
     213              :                   ! moments_der(moment, delta) = - < a | moment \partial_\delta | b >
     214              :                   ! so we need the opposite sign.
     215          648 :                   aat_tmp = aat_tmp - 2._dp*aat_prefactor*tmp_trace*lc_tmp
     216              :                END DO
     217              :             END DO
     218              : 
     219              :             aat_atom(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) &
     220           72 :                = aat_atom(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) + aat_tmp
     221              :          END DO
     222              : 
     223              :          ! The PP part consists of four contributions
     224              :          !  (D):  - P^0 * ε_{alpha gamma delta} * < mu | r_beta r_gamma [V, r_delta] | nu > * (mu == lambda)
     225              :          !  (E):  + P^0 * ε_{alpha gamma delta} * < mu | r_gamma [V, r_delta] r_beta | nu > * (nu == lambda)
     226              :          !  (F):  - P^0 * ε_{alpha gamma delta} * < mu | r_gamma [[V, r_beta], r_delta] | nu > * (eta == lambda)
     227              :          !  (G):  - iP^1 * ε_{alpha gamma delta} * < mu | r_gamma [V, r_delta] | nu >
     228              : 
     229              :          !  (D):  - P^0 * ε_{alpha gamma delta} * < mu | r_beta r_gamma [V, r_delta] | nu > * (mu == lambda)
     230              :          !    The negative of this is in vcd_env%matrix_r_rxvr
     231           72 :          DO alpha = 1, 3
     232              :             CALL dbcsr_copy(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, &
     233           54 :                             vcd_env%matrix_r_rxvr(alpha, vcd_env%dcdr_env%beta)%matrix)
     234              :             CALL hr_mult_by_delta_1d(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, qs_kind_set, "ORB", &
     235           54 :                                      sab_all, direction_Or=.FALSE., lambda=vcd_env%dcdr_env%lambda)
     236              : 
     237           54 :             CALL cp_dbcsr_sm_fm_multiply(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, mo_coeff, tmp_aomo, ncol=nmo)
     238           54 :             CALL cp_fm_trace(mo_coeff, tmp_aomo, aat_tmp)
     239           54 :             aat_tmp = -aat_prefactor*aat_tmp
     240              : 
     241              :             aat_atom(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) &
     242           72 :                = aat_atom(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) + aat_tmp
     243              :          END DO
     244              : 
     245              :          !  (E):  + P^0 * ε_{alpha gamma delta} * < mu | r_gamma [V, r_delta] r_beta | nu > * (nu == lambda)
     246              :          !    This is in vcd_env%matrix_rxvr_r
     247           72 :          DO alpha = 1, 3
     248           54 :            CALL dbcsr_copy(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, vcd_env%matrix_rxvr_r(alpha, vcd_env%dcdr_env%beta)%matrix)
     249              :             CALL hr_mult_by_delta_1d(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, qs_kind_set, "ORB", &
     250           54 :                                      sab_all, direction_Or=.TRUE., lambda=vcd_env%dcdr_env%lambda)
     251              : 
     252           54 :             CALL cp_dbcsr_sm_fm_multiply(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, mo_coeff, tmp_aomo, ncol=nmo)
     253           54 :             CALL cp_fm_trace(mo_coeff, tmp_aomo, aat_tmp)
     254           54 :             aat_tmp = aat_prefactor*aat_tmp
     255              : 
     256              :             aat_atom(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) &
     257           72 :                = aat_atom(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) + aat_tmp
     258              :          END DO
     259              : 
     260              :          !  (F):  - P^0 * ε_{alpha gamma delta} * < mu | r_gamma [[V, r_beta], r_delta] | nu > * (eta == lambda)
     261              :          !        + P^0 * ε_{alpha gamma delta} * < mu | [[V, r_beta], r_delta] | nu > * (eta == lambda) * R_gamma
     262              :          !    The negative is in vcd_env%matrix_r_doublecom
     263           72 :          DO alpha = 1, 3
     264              :             CALL cp_dbcsr_sm_fm_multiply(vcd_env%matrix_r_doublecom(alpha, vcd_env%dcdr_env%beta)%matrix, &
     265           54 :                                          mo_coeff, tmp_aomo, ncol=nmo)
     266           54 :             CALL cp_fm_trace(mo_coeff, tmp_aomo, aat_tmp)
     267           54 :             aat_tmp = -aat_prefactor*aat_tmp
     268              : 
     269              :             aat_atom(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) &
     270           72 :                = aat_atom(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) + aat_tmp
     271              :          END DO
     272              : 
     273              :          !  (G):   - iP^1 * ε_{alpha gamma delta} * < mu | r_gamma [V, r_delta] | nu >
     274           72 :          DO alpha = 1, 3
     275           54 :             CALL cp_dbcsr_sm_fm_multiply(vcd_env%matrix_rxrv(alpha)%matrix, mo_coeff, tmp_aomo, ncol=nmo)
     276           54 :             CALL cp_fm_trace(tmp_aomo, vcd_env%dCV_prime(ispin), aat_tmp)
     277              : 
     278              :             !  I can take the positive, because build_com_mom_nl computes r x [r, V]
     279           54 :             aat_tmp = 2._dp*aat_prefactor*aat_tmp
     280              : 
     281              :             aat_atom(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) &
     282              :                = aat_atom(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) &
     283           72 :                  + aat_tmp
     284              :          END DO
     285              : 
     286              :          ! All the reference dependent stuff
     287              :          ! (C) iP^1 * ε_{alpha gamma delta} * < mu | ∂_delta | nu > * (- R_gamma)
     288           72 :          DO alpha = 1, 3
     289           54 :             aat_tmp = 0._dp
     290              : 
     291          216 :             DO gamma = 1, 3
     292          702 :                DO delta = 1, 3
     293          486 :                   lc_tmp = Levi_Civita(alpha, gamma, delta)
     294          486 :                   IF (lc_tmp == 0._dp) CYCLE
     295              :                   ! dipvel_ao = + < a | ∂ | b >
     296          108 :                   CALL cp_dbcsr_sm_fm_multiply(vcd_env%dipvel_ao(delta)%matrix, mo_coeff, tmp_aomo, ncol=nmo)
     297          108 :                   CALL cp_fm_trace(tmp_aomo, vcd_env%dCV_prime(ispin), tmp_trace)
     298              : 
     299              :                   ! The negative sign is due to (r - O^mag_gamma) and otherwise this is
     300              :                   !   exactly the APT dipvel(beta, delta) * (-O^mag_gamma)
     301          648 :                   aat_tmp = aat_tmp + 2._dp*aat_prefactor*tmp_trace*lc_tmp*(-vcd_env%magnetic_origin_atom(gamma))
     302              :                END DO
     303              :             END DO
     304              : 
     305              :             aat_atom(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) &
     306           72 :                = aat_atom(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) + aat_tmp
     307              :          END DO
     308              : 
     309              :          !  (G):  - iP^1 * ε_{alpha gamma delta} * < mu | [V, r_delta] | nu > * (- R_gamma)
     310           72 :          DO alpha = 1, 3
     311           54 :             aat_tmp = 0._dp
     312          216 :             DO gamma = 1, 3
     313          702 :                DO delta = 1, 3
     314          486 :                   lc_tmp = Levi_Civita(alpha, gamma, delta)
     315          486 :                   IF (lc_tmp == 0._dp) CYCLE
     316              :                   ! hcom = < a | [r, V] | b > = - < a | [V, r] | b >
     317              :                   ! mo_coeff * dCV_prime = + iP1
     318          108 :                   CALL cp_dbcsr_sm_fm_multiply(vcd_env%hcom(delta)%matrix, mo_coeff, tmp_aomo, ncol=nmo)
     319          108 :                   CALL cp_fm_trace(tmp_aomo, vcd_env%dCV_prime(ispin), tmp_trace)
     320              : 
     321              :                   ! This is exactly APT hcom(beta, delta)
     322          648 :                   aat_tmp = aat_tmp + 2._dp*aat_prefactor*tmp_trace*lc_tmp*(-vcd_env%magnetic_origin_atom(gamma))
     323              :                END DO
     324              :             END DO
     325              : 
     326              :             aat_atom(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) &
     327           72 :                = aat_atom(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) + aat_tmp
     328              :          END DO
     329              : 
     330              :          !  mag_vel, vel, mag
     331              :          ! matrix_difdip2 stores nuclear derivatives; the electronic-coordinate
     332              :          ! derivative contributions below therefore use a negative sign.
     333              :          ! Ai)   + ε_{alpha gamma delta} * R_beta R_gamma * < mu | ∂_delta | nu > * (mu - nu)
     334              :          ! Aii)  + ε_{alpha gamma delta} * (-R_beta) * < mu | r_gamma ∂_delta | nu > * (mu - nu)
     335              :          ! Aiii) + ε_{alpha gamma delta} * (-R_gamma) * < mu | r_beta ∂_delta | nu > * (mu - nu)
     336           72 :          DO alpha = 1, 3
     337           54 :             aat_tmp = 0._dp
     338          216 :             DO gamma = 1, 3
     339          702 :                DO delta = 1, 3
     340          486 :                   lc_tmp = Levi_Civita(alpha, gamma, delta)
     341          486 :                   IF (lc_tmp == 0._dp) CYCLE
     342              :                   ! iii) - R_gamma * < mu | r_beta ∂_delta | nu > * (mu - nu)
     343              :                   ! mag
     344              :                   ! matrix_difdip2(beta, alpha) = - < a | r_beta | ∂_alpha b >  * (mu - nu)
     345              :                   !   so I need matrix_difdip2(beta, delta)
     346              :                   ! Only this part correspond to the APT difdip(beta, alpha)
     347              :                   CALL cp_dbcsr_sm_fm_multiply(vcd_env%matrix_difdip2(vcd_env%dcdr_env%beta, delta)%matrix, mo_coeff, &
     348          108 :                                                tmp_aomo, ncol=nmo)
     349          108 :                   CALL cp_fm_trace(mo_coeff, tmp_aomo, tmp_trace)
     350              : 
     351          108 :                   aat_tmp = aat_tmp - lc_tmp*aat_prefactor*tmp_trace*(-vcd_env%magnetic_origin_atom(gamma))
     352              : 
     353              :                   ! This part doesn't appear in the APT
     354              :                   ! ii)  - R_beta * < mu | r_gamma ∂_delta | nu > * (mu - nu)
     355              :                   ! vel
     356              :                   ! matrix_difdip2(beta, alpha) = - < a | r_beta | ∂_alpha b > * (mu - nu)
     357              :                   !   so I need matrix_difdip2(gamma, delta)
     358              :                   CALL cp_dbcsr_sm_fm_multiply(vcd_env%matrix_difdip2(gamma, delta)%matrix, mo_coeff, &
     359          108 :                                                tmp_aomo, ncol=nmo)
     360          108 :                   CALL cp_fm_trace(mo_coeff, tmp_aomo, tmp_trace)
     361              : 
     362          108 :                   aat_tmp = aat_tmp - lc_tmp*aat_prefactor*tmp_trace*(-vcd_env%spatial_origin_atom(vcd_env%dcdr_env%beta))
     363              : 
     364              :                   ! i)   + R_beta R_gamma * < mu | ∂_delta | nu > * (mu - nu)
     365              :                   ! mag_vel
     366              :                   ! dipvel_ao = + < a | ∂ | b >
     367          108 :                   CALL dbcsr_desymmetrize(vcd_env%dipvel_ao(delta)%matrix, vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix)
     368          108 :                   CALL dbcsr_desymmetrize(vcd_env%dipvel_ao(delta)%matrix, vcd_env%dcdr_env%matrix_nosym_temp(2)%matrix)
     369              :                   CALL hr_mult_by_delta_1d(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, qs_kind_set, "ORB", &
     370          108 :                                            sab_all, direction_Or=.FALSE., lambda=vcd_env%dcdr_env%lambda)
     371              :                   CALL hr_mult_by_delta_1d(vcd_env%dcdr_env%matrix_nosym_temp(2)%matrix, qs_kind_set, "ORB", &
     372          108 :                                            sab_all, direction_Or=.TRUE., lambda=vcd_env%dcdr_env%lambda)
     373              :                   CALL dbcsr_add(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, vcd_env%dcdr_env%matrix_nosym_temp(2)%matrix, &
     374          108 :                                  1._dp, -1._dp)
     375              : 
     376          108 :                   CALL cp_dbcsr_sm_fm_multiply(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, mo_coeff, tmp_aomo, ncol=nmo)
     377          108 :                   CALL cp_fm_trace(mo_coeff, tmp_aomo, tmp_trace)
     378              :                   aat_tmp = aat_tmp + lc_tmp*aat_prefactor*tmp_trace* &
     379          864 :                             (vcd_env%spatial_origin_atom(vcd_env%dcdr_env%beta)*vcd_env%magnetic_origin_atom(gamma))
     380              : 
     381              :                END DO
     382              :             END DO
     383              : 
     384              :             aat_atom(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) &
     385           72 :                = aat_atom(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) + aat_tmp
     386              :          END DO
     387              : 
     388              :          ! (B):  P^0 * ε_{alpha gamma beta} * < mu | nu > * (nu == lambda) * R_gamma
     389           72 :          DO alpha = 1, 3
     390           54 :             aat_tmp = 0._dp
     391              : 
     392          216 :             DO gamma = 1, 3
     393          162 :                lc_tmp = Levi_Civita(alpha, gamma, vcd_env%dcdr_env%beta)
     394          162 :                IF (lc_tmp == 0._dp) CYCLE
     395           36 :                CALL dbcsr_set(vcd_env%dcdr_env%matrix_nosym_temp(vcd_env%dcdr_env%beta)%matrix, 0.0_dp)
     396           36 :                CALL dbcsr_desymmetrize(vcd_env%dcdr_env%matrix_s1(1)%matrix, vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix)
     397              :                CALL hr_mult_by_delta_1d(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, qs_kind_set, "ORB", sab_all, &
     398           36 :                                         vcd_env%dcdr_env%lambda, direction_Or=.TRUE.)
     399           36 :                CALL cp_dbcsr_sm_fm_multiply(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, mo_coeff, tmp_aomo, ncol=nmo)
     400           36 :                CALL cp_fm_trace(mo_coeff, tmp_aomo, tmp_trace)
     401              : 
     402              :                ! This is in total positive because we are calculating
     403              :                !  -1/2c * P * < a | b > * (delta == beta) * (nu == lambda) * (-R_gamma)
     404              :                ! The whole term corresponds to difdip_s
     405          216 :                aat_tmp = aat_tmp + lc_tmp*aat_prefactor*tmp_trace*vcd_env%magnetic_origin_atom(gamma)
     406              :             END DO
     407              : 
     408              :             aat_atom(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) &
     409           72 :                = aat_atom(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) + aat_tmp
     410              :          END DO
     411              : 
     412              :          !  (D):  - P^0 * ε_{alpha gamma delta} * < mu | r_gamma r_beta [V, r_delta] | nu > * (mu == lambda)
     413              :          !  mag, vel, mag_vel
     414              :          ! Di)   - ε_{alpha gamma delta} * (-R_gamma) * < mu | r_beta [V, r_delta] | nu > * (mu == lambda)
     415              :          ! Dii)  - ε_{alpha gamma delta} * (-R_beta) * < mu | r_gamma [V, r_delta] | nu > * (mu == lambda)
     416              :          ! Diii) - ε_{alpha gamma delta} * R_beta R_gamma * < mu | [V, r_delta] | nu > * (mu == lambda)
     417              : 
     418           72 :          DO alpha = 1, 3
     419           54 :             aat_tmp = 0._dp
     420           54 :             CALL dbcsr_set(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, 0._dp)
     421              : 
     422          216 :             DO gamma = 1, 3
     423          702 :                DO delta = 1, 3
     424          486 :                   lc_tmp = Levi_Civita(alpha, gamma, delta)
     425          486 :                   IF (lc_tmp == 0._dp) CYCLE
     426              :                   ! vcd_env%matrix_rrcom(alpha, beta) = r_beta * [V, r_alpha]
     427              : 
     428              :                   ! This corresponds to rcom
     429              :                   ! Di) mag
     430              :                   ! -(-R_gamma) * < mu | r_beta [V, r_delta] | nu > * (mu == lambda)
     431              :                   ! vcd_env%matrix_rrcom(alpha, beta) = r_beta * [V, r_alpha]
     432              :                   !  so I need vcd_env%matrix_rrcom(delta, beta)
     433              :                   !  The multiplication with delta was not done for all directions
     434              :                   CALL dbcsr_copy(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, &
     435          108 :                                   vcd_env%matrix_rrcom(delta, vcd_env%dcdr_env%beta)%matrix)
     436              :                   CALL hr_mult_by_delta_1d(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, qs_kind_set, "ORB", &
     437          108 :                                            sab_all, direction_Or=.FALSE., lambda=vcd_env%dcdr_env%lambda)
     438          108 :                   CALL cp_dbcsr_sm_fm_multiply(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, mo_coeff, tmp_aomo, ncol=nmo)
     439          108 :                   CALL cp_fm_trace(mo_coeff, tmp_aomo, tmp_trace)
     440              :                   ! The sign is positive in total, because we have the negative coordinate and the whole term was negative
     441          108 :                   aat_tmp = aat_tmp + aat_prefactor*tmp_trace*lc_tmp*vcd_env%magnetic_origin_atom(gamma)
     442              : 
     443              :                   ! This doesn't appear in the APT formula
     444              :                   ! Dii) vel
     445              :                   ! -(-R_beta) * < mu | r_gamma [V, r_delta] | nu > * (mu == lambda)
     446              :                   ! vcd_env%matrix_rrcom(alpha, beta) = r_beta * [V, r_alpha]
     447              :                   !  so I need vcd_env%matrix_rrcom(delta, gamma)
     448              :                   !  The multiplication with delta was already done in SUBROUTINE apt_dV
     449          108 :                   CALL dbcsr_copy(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, vcd_env%matrix_rrcom(delta, gamma)%matrix)
     450              :                   CALL hr_mult_by_delta_1d(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, qs_kind_set, "ORB", &
     451          108 :                                            sab_all, direction_Or=.FALSE., lambda=vcd_env%dcdr_env%lambda)
     452          108 :                   CALL cp_dbcsr_sm_fm_multiply(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, mo_coeff, tmp_aomo, ncol=nmo)
     453          108 :                   CALL cp_fm_trace(mo_coeff, tmp_aomo, tmp_trace)
     454          108 :                   aat_tmp = aat_tmp + aat_prefactor*tmp_trace*lc_tmp*vcd_env%spatial_origin_atom(vcd_env%dcdr_env%beta)
     455              : 
     456              :                   ! Diii) mag_vel
     457              :                   !  - R_beta R_gamma * < mu | [V, r_delta] | nu >
     458              :                   ! hcom(delta) = - [V, r_delta]
     459          108 :                   CALL dbcsr_desymmetrize(vcd_env%hcom(delta)%matrix, vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix)
     460              :                   CALL hr_mult_by_delta_1d(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, qs_kind_set, "ORB", &
     461          108 :                                            sab_all, direction_Or=.FALSE., lambda=vcd_env%dcdr_env%lambda)
     462          108 :                   CALL cp_dbcsr_sm_fm_multiply(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, mo_coeff, tmp_aomo, ncol=nmo)
     463          108 :                   CALL cp_fm_trace(mo_coeff, tmp_aomo, tmp_trace)
     464              :                   ! No need for a negative sign, because hcom already contains the negative sign.
     465              :                   aat_tmp = aat_tmp + &
     466              :                             aat_prefactor*tmp_trace*lc_tmp &
     467          864 :                             *(vcd_env%spatial_origin_atom(vcd_env%dcdr_env%beta)*vcd_env%magnetic_origin_atom(gamma))
     468              :                END DO
     469              :             END DO
     470              : 
     471              :             aat_atom(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) &
     472           72 :                = aat_atom(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) + aat_tmp
     473              :          END DO
     474              : 
     475              :          !  (E):  + P^0 * ε_{alpha gamma delta} * < mu | r_gamma [V, r_delta] r_beta | nu > * (nu == lambda)
     476              :          !  mag, vel, mag_vel
     477              :          ! Ei)   + ε_{alpha gamma delta} * (-R_gamma) * < mu | [V, r_delta] r_beta | nu > * (nu == lambda)
     478              :          ! Eii)  + ε_{alpha gamma delta} * (-R_beta) * < mu | r_gamma [V, r_delta] | nu > * (nu == lambda)
     479              :          ! Eiii) + ε_{alpha gamma delta} * R_beta R_gamma * < mu | [V, r_delta] | nu > * (nu == lambda)
     480           72 :          DO alpha = 1, 3
     481           54 :             aat_tmp = 0._dp
     482           54 :             CALL dbcsr_set(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, 0._dp)
     483              : 
     484          216 :             DO gamma = 1, 3
     485          702 :                DO delta = 1, 3
     486          486 :                   lc_tmp = Levi_Civita(alpha, gamma, delta)
     487          486 :                   IF (lc_tmp == 0._dp) CYCLE
     488              :                   ! vcd_env%matrix_rrcom(alpha, beta) = r_beta * [V, r_alpha]
     489              :                   ! vcd_env%matrix_rcomr(alpha, beta) = [V, r_alpha] * r_beta
     490              : 
     491              :                   ! This corresponds to rcom
     492              :                   ! Ei) mag
     493              :                   ! (-R_gamma) * < mu | [V, r_delta] r_beta | nu > * (nu == lambda)
     494              :                   ! vcd_env%matrix_rcomr(alpha, beta) = [V, r_alpha] * r_beta
     495              :                   !  so I need vcd_env%matrix_rcomr(delta, beta)
     496              :                   CALL dbcsr_copy(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, &
     497          108 :                                   vcd_env%matrix_rcomr(delta, vcd_env%dcdr_env%beta)%matrix)
     498              :                   CALL hr_mult_by_delta_1d(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, qs_kind_set, "ORB", &
     499          108 :                                            sab_all, direction_Or=.TRUE., lambda=vcd_env%dcdr_env%lambda)
     500              : 
     501          108 :                   CALL cp_dbcsr_sm_fm_multiply(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, mo_coeff, tmp_aomo, ncol=nmo)
     502          108 :                   CALL cp_fm_trace(mo_coeff, tmp_aomo, tmp_trace)
     503          108 :                   aat_tmp = aat_tmp + aat_prefactor*tmp_trace*lc_tmp*(-vcd_env%magnetic_origin_atom(gamma))
     504              : 
     505              :                   ! This doesn't appear in the APT formula
     506              :                   ! E2) vel
     507              :                   ! (-R_beta) * < mu | r_gamma [V, r_delta] | nu > * (nu == lambda)
     508              :                   ! vcd_env%matrix_rrcom(alpha, beta) = r_beta * [V, r_alpha]
     509              :                   !  so I need vcd_env%matrix_rrcom(delta, gamma)
     510          108 :                   CALL dbcsr_copy(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, vcd_env%matrix_rrcom(delta, gamma)%matrix)
     511              :                   CALL hr_mult_by_delta_1d(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, qs_kind_set, "ORB", &
     512          108 :                                            sab_all, direction_Or=.TRUE., lambda=vcd_env%dcdr_env%lambda)
     513              : 
     514          108 :                   CALL cp_dbcsr_sm_fm_multiply(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, mo_coeff, tmp_aomo, ncol=nmo)
     515          108 :                   CALL cp_fm_trace(mo_coeff, tmp_aomo, tmp_trace)
     516          108 :                   aat_tmp = aat_tmp + aat_prefactor*tmp_trace*lc_tmp*(-vcd_env%spatial_origin_atom(vcd_env%dcdr_env%beta))
     517              : 
     518              :                   ! E3) mag_vel
     519              :                   ! R_beta R_gamma * < mu | [V, r_delta] | nu > * (nu == lambda)
     520          108 :                   CALL dbcsr_desymmetrize(vcd_env%hcom(delta)%matrix, vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix)
     521              :                   CALL hr_mult_by_delta_1d(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, qs_kind_set, "ORB", &
     522          108 :                                            sab_all, direction_Or=.TRUE., lambda=vcd_env%dcdr_env%lambda)
     523              : 
     524          108 :                   CALL cp_dbcsr_sm_fm_multiply(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, mo_coeff, tmp_aomo, ncol=nmo)
     525          108 :                   CALL cp_fm_trace(mo_coeff, tmp_aomo, tmp_trace)
     526              :                   ! There has to be a minus here, because hcom = [r, V] = - [V, r]
     527              :                   aat_tmp = aat_tmp - &
     528              :                             aat_prefactor*tmp_trace*lc_tmp* &
     529          864 :                             (vcd_env%spatial_origin_atom(vcd_env%dcdr_env%beta)*vcd_env%magnetic_origin_atom(gamma))
     530              :                END DO
     531              :             END DO
     532              : 
     533              :             aat_atom(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) &
     534           72 :                = aat_atom(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) + aat_tmp
     535              :          END DO
     536              : 
     537              :          !  (F):  - P^0 * ε_{alpha gamma delta} * < mu | [[V, r_beta], r_delta] | nu > * (eta == lambda) * (-R_gamma)
     538              :          ! This corresponds to APT dcom
     539           72 :          DO alpha = 1, 3
     540           54 :             aat_tmp = 0._dp
     541              : 
     542          216 :             DO gamma = 1, 3
     543          702 :                DO delta = 1, 3
     544          486 :                   lc_tmp = Levi_Civita(alpha, gamma, delta)
     545          486 :                   IF (lc_tmp == 0._dp) CYCLE
     546              :                   ! vcd_env%matrix_dcom(alpha, vcd_env%dcdr_env%beta) = - < mu | [ [V, r_beta], r_alpha ] | nu >
     547              :                   !  so I need matrix_dcom(delta, vcd_env%dcdr_env%beta)
     548              :                   CALL cp_dbcsr_sm_fm_multiply(vcd_env%matrix_dcom(delta, vcd_env%dcdr_env%beta)%matrix, &
     549          108 :                                                mo_coeff, tmp_aomo, ncol=nmo)
     550          108 :                   CALL cp_fm_trace(mo_coeff, tmp_aomo, tmp_trace)
     551              :                   ! matrix_dcom has the negative sign and we include the negative sign of the coordinate
     552          648 :                   aat_tmp = aat_tmp + aat_prefactor*tmp_trace*lc_tmp*(-vcd_env%magnetic_origin_atom(gamma))
     553              :                END DO
     554              :             END DO
     555              : 
     556              :             aat_atom(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) &
     557           72 :                = aat_atom(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) + aat_tmp
     558              :          END DO
     559              : 
     560              :          ! Nuclear contribution
     561           18 :          CALL get_atomic_kind(particle_set(vcd_env%dcdr_env%lambda)%atomic_kind, kind_number=ikind)
     562           18 :          CALL get_qs_kind(qs_kind_set(ikind), core_charge=charge, ghost=ghost)
     563           36 :          IF (.NOT. ghost) THEN
     564           72 :             DO alpha = 1, 3
     565           54 :                aat_tmp = 0._dp
     566          234 :                DO gamma = 1, 3
     567          162 :                   IF (Levi_Civita(alpha, gamma, vcd_env%dcdr_env%beta) == 0._dp) CYCLE
     568              :                   aat_tmp = aat_tmp + charge &
     569              :                             *Levi_Civita(alpha, gamma, vcd_env%dcdr_env%beta) &
     570           36 :                             *(particle_set(vcd_env%dcdr_env%lambda)%r(gamma) - vcd_env%magnetic_origin_atom(gamma))
     571              : 
     572              :                   aat_atom(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) &
     573          216 :                      = aat_atom(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) + aat_tmp
     574              :                END DO
     575              :             END DO
     576              :          END IF
     577              :       END ASSOCIATE
     578              : 
     579           18 :       CALL cp_fm_release(tmp_aomo)
     580           18 :       CALL timestop(handle)
     581           54 :    END SUBROUTINE aat_dV
     582              : 
     583              : ! **************************************************************************************************
     584              : !> \brief Compute E_{alpha beta}^lambda = d/dV^lambda_beta <\mu_alpha> = d/dV^lambda_beta < \dot{r} >
     585              : !>        The directions alpha, beta are stored in vcd_env%dcdr_env
     586              : !> \param vcd_env ...
     587              : !> \param qs_env ...
     588              : !> \author Edward Ditler, Tomas Zimmermann
     589              : ! **************************************************************************************************
     590           18 :    SUBROUTINE apt_dV(vcd_env, qs_env)
     591              :       TYPE(vcd_env_type)                                 :: vcd_env
     592              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     593              : 
     594              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'apt_dV'
     595              :       INTEGER, PARAMETER                                 :: ispin = 1
     596              :       REAL(dp), PARAMETER                                :: f_spin = 2._dp
     597              : 
     598              :       INTEGER                                            :: alpha, handle, ikind, nao, nmo
     599              :       LOGICAL                                            :: ghost
     600              :       REAL(dp)                                           :: charge
     601              :       REAL(KIND=dp)                                      :: apt_dcom, apt_difdip, apt_dipvel, &
     602              :                                                             apt_hcom, apt_rcom
     603              :       TYPE(cp_fm_type)                                   :: buf, matrix_dSdV_mo
     604              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
     605           18 :          POINTER                                         :: sab_all
     606           18 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     607           18 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     608              : 
     609           18 :       CALL timeset(routineN, handle)
     610              : 
     611              :       CALL get_qs_env(qs_env=qs_env, &
     612              :                       sab_all=sab_all, &
     613              :                       particle_set=particle_set, &
     614           18 :                       qs_kind_set=qs_kind_set)
     615              : 
     616           18 :       nmo = vcd_env%dcdr_env%nmo(ispin)
     617           18 :       nao = vcd_env%dcdr_env%nao
     618              : 
     619              :       ASSOCIATE (apt_el => vcd_env%apt_el_nvpt, &
     620              :                  apt_nuc => vcd_env%apt_nuc_nvpt, &
     621              :                  apt_total => vcd_env%apt_total_nvpt, &
     622              :                  mo_coeff => vcd_env%dcdr_env%mo_coeff(ispin), &
     623              :                  deltaR => vcd_env%dcdr_env%deltaR)
     624              : 
     625              :          ! build the full matrices
     626           18 :          CALL cp_fm_create(buf, vcd_env%dcdr_env%likemos_fm_struct(ispin)%struct, set_zero=.TRUE.)
     627           18 :          CALL cp_fm_create(matrix_dSdV_mo, vcd_env%dcdr_env%momo_fm_struct(ispin)%struct)
     628              : 
     629              :          ! STEP 1: dCV contribution (dipvel + commutator)
     630              :          ! <mu|∂_alpha|nu> and <mu|[r_alpha, V]|nu> in AO basis
     631              :          ! We compute tr(c_1^* x ∂_munu x c_0) + tr(c_0 x ∂_munu x c_1)
     632              :          ! We compute tr(c_1^* x [,]_munu x c_0) + tr(c_0 x [,]_munu x c_1)
     633           18 :          CALL cp_fm_scale_and_add(0._dp, vcd_env%dCV_prime(ispin), -1._dp, vcd_env%dCV(ispin))
     634              : 
     635              :          ! Ref independent
     636              :          CALL cp_dbcsr_sm_fm_multiply(vcd_env%matrix_dSdV(vcd_env%dcdr_env%beta)%matrix, mo_coeff, &
     637           18 :                                       buf, ncol=nmo)
     638              :          CALL parallel_gemm("T", "N", nmo, nmo, nao, &
     639              :                             1.0_dp, mo_coeff, buf, &
     640           18 :                             0.0_dp, matrix_dSdV_mo)
     641              : 
     642              :          CALL parallel_gemm("N", "N", nao, nmo, nmo, &
     643              :                             -0.5_dp, mo_coeff, matrix_dSdV_mo, &
     644           18 :                             1.0_dp, vcd_env%dCV_prime(ispin))
     645              : 
     646              :          ! + i∂ - i[Vnl, r]
     647           72 :          DO alpha = 1, 3
     648           54 :             CALL cp_fm_set_all(buf, 0.0_dp)
     649              :             apt_dipvel = 0.0_dp
     650              : 
     651           54 :             CALL cp_dbcsr_sm_fm_multiply(vcd_env%dipvel_ao(alpha)%matrix, mo_coeff, buf, ncol=nmo)
     652           54 :             CALL cp_fm_trace(buf, vcd_env%dCV_prime(ispin), apt_dipvel)
     653              :             ! dipvel_ao = + < a | ∂ | b >
     654              :             ! mo_coeff * dCV_prime = + iP1
     655           54 :             apt_dipvel = 2._dp*apt_dipvel
     656              :             apt_el(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) &
     657           72 :                = apt_el(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) + f_spin*apt_dipvel
     658              :          END DO
     659              : 
     660           72 :          DO alpha = 1, 3
     661           54 :             CALL cp_fm_set_all(buf, 0.0_dp)
     662              :             apt_hcom = 0.0_dp
     663           54 :             CALL cp_dbcsr_sm_fm_multiply(vcd_env%hcom(alpha)%matrix, mo_coeff, buf, ncol=nmo)
     664           54 :             CALL cp_fm_trace(buf, vcd_env%dCV_prime(ispin), apt_hcom)
     665              : 
     666              :             ! hcom = < a | [r, V] | b > = - < a | [V, r] | b >
     667              :             ! mo_coeff * dCV_prime = + iP1
     668           54 :             apt_hcom = +2._dp*apt_hcom
     669              : 
     670              :             apt_el(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) &
     671           72 :                = apt_el(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) + f_spin*apt_hcom
     672              :          END DO  !x/y/z
     673              : 
     674              :          ! STEP 2: basis function derivative contribution
     675              :       !! difdip_s
     676           18 :          CALL dbcsr_set(vcd_env%dcdr_env%matrix_nosym_temp(vcd_env%dcdr_env%beta)%matrix, 0.0_dp)
     677              :          CALL dbcsr_desymmetrize(vcd_env%dcdr_env%matrix_s1(1)%matrix, &
     678           18 :                                  vcd_env%dcdr_env%matrix_nosym_temp(vcd_env%dcdr_env%beta)%matrix)
     679              :          CALL hr_mult_by_delta_1d(vcd_env%dcdr_env%matrix_nosym_temp(vcd_env%dcdr_env%beta)%matrix, qs_kind_set, "ORB", sab_all, &
     680           18 :                                   vcd_env%dcdr_env%lambda, direction_Or=.TRUE.)
     681              : 
     682              :          CALL cp_dbcsr_sm_fm_multiply(vcd_env%dcdr_env%matrix_nosym_temp(vcd_env%dcdr_env%beta)%matrix, mo_coeff, &
     683           18 :                                       buf, ncol=nmo, alpha=1._dp, beta=0._dp)
     684           18 :          CALL cp_fm_trace(mo_coeff, buf, apt_difdip)
     685              : 
     686           18 :          apt_difdip = -f_spin*apt_difdip
     687              :          apt_el(vcd_env%dcdr_env%beta, vcd_env%dcdr_env%beta, vcd_env%dcdr_env%lambda) &
     688           18 :             = apt_el(vcd_env%dcdr_env%beta, vcd_env%dcdr_env%beta, vcd_env%dcdr_env%lambda) + apt_difdip
     689              : 
     690              :       !! difdip(j, idir) = < a | r_j | ∂_idir b >
     691              :       !! matrix_difdip2(beta, alpha) = < a | r_beta | ∂_alpha b >
     692              :          ! matrix_difdip2 stores nuclear derivatives.
     693           72 :          DO alpha = 1, 3 ! x/y/z for differentiated AO
     694              :             CALL cp_dbcsr_sm_fm_multiply(vcd_env%matrix_difdip2(vcd_env%dcdr_env%beta, alpha)%matrix, mo_coeff, &
     695           54 :                                          buf, ncol=nmo, alpha=1._dp, beta=0._dp)
     696              : 
     697           54 :             CALL cp_fm_trace(mo_coeff, buf, apt_difdip)
     698           54 :             apt_difdip = -f_spin*apt_difdip
     699              :             apt_el(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) &
     700           72 :                = apt_el(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) + apt_difdip
     701              : 
     702              :          END DO !alpha
     703              : 
     704              :          ! STEP 3: The terms r * [V, r]
     705              :          ! vcd_env%matrix_rrcom(alpha, beta) = r_beta * [V, r_alpha]
     706              :          ! vcd_env%matrix_rcomr(alpha, beta) = [V, r_alpha] * r_beta
     707           72 :          DO alpha = 1, 3 ! x/y/z for differentiated AO
     708           54 :             CALL dbcsr_copy(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, vcd_env%matrix_rcomr(alpha, vcd_env%dcdr_env%beta)%matrix)
     709           54 :             CALL dbcsr_copy(vcd_env%dcdr_env%matrix_nosym_temp(2)%matrix, vcd_env%matrix_rrcom(alpha, vcd_env%dcdr_env%beta)%matrix)
     710              : 
     711              :             CALL hr_mult_by_delta_1d(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, qs_kind_set, "ORB", &
     712           54 :                                      sab_all, direction_Or=.TRUE., lambda=vcd_env%dcdr_env%lambda)
     713              :             CALL hr_mult_by_delta_1d(vcd_env%dcdr_env%matrix_nosym_temp(2)%matrix, qs_kind_set, "ORB", &
     714           54 :                                      sab_all, direction_Or=.FALSE., lambda=vcd_env%dcdr_env%lambda)
     715              : 
     716              :             CALL dbcsr_add(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, vcd_env%dcdr_env%matrix_nosym_temp(2)%matrix, &
     717           54 :                            1.0_dp, -1.0_dp)
     718              : 
     719           54 :             CALL cp_fm_set_all(buf, 0.0_dp)
     720           54 :             CALL cp_dbcsr_sm_fm_multiply(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, mo_coeff, buf, ncol=nmo)
     721           54 :             CALL cp_fm_trace(mo_coeff, buf, apt_rcom)
     722              : 
     723              :             apt_el(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) &
     724           72 :                = apt_el(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) + f_spin*apt_rcom
     725              :          END DO !alpha
     726              : 
     727              :          ! STEP 4: pseudopotential derivative contribution
     728              :          ! vcd_env%matrix_dcom(alpha, vcd_env%dcdr_env%beta) = - < mu | [ [V, r_beta], r_alpha ] | nu >
     729           72 :          DO alpha = 1, 3 !x/y/z for differentiated AO
     730           54 :             CALL cp_fm_set_all(buf, 0.0_dp)
     731           54 :             CALL cp_dbcsr_sm_fm_multiply(vcd_env%matrix_dcom(alpha, vcd_env%dcdr_env%beta)%matrix, mo_coeff, buf, ncol=nmo)
     732           54 :             CALL cp_fm_trace(mo_coeff, buf, apt_dcom)
     733              :             apt_el(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) &
     734           72 :                = apt_el(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) + f_spin*apt_dcom
     735              :          END DO !alpha
     736              : 
     737              :          ! The reference point dependent terms:
     738              :       !! difdip_munu
     739              :          ! The additional term here is < a | db/dr(alpha)> * (delta_a - delta_b) * ref_point(beta)
     740              :          ! in qs_env%matrix_s1(2:4) there is < da/dR | b > = - < da/dr | b > = < a | db/dr >
     741           72 :          DO alpha = 1, 3
     742           54 :             CALL dbcsr_set(vcd_env%dcdr_env%matrix_nosym_temp(alpha)%matrix, 0._dp)
     743           54 :             CALL dbcsr_set(vcd_env%dcdr_env%matrix_nosym_temp2(alpha)%matrix, 0._dp)
     744           54 :             CALL dbcsr_desymmetrize(vcd_env%dcdr_env%matrix_s(alpha + 1)%matrix, vcd_env%dcdr_env%matrix_nosym_temp(alpha)%matrix)
     745           54 :             CALL dbcsr_copy(vcd_env%dcdr_env%matrix_nosym_temp2(alpha)%matrix, vcd_env%dcdr_env%matrix_nosym_temp(alpha)%matrix)
     746              : 
     747              :             ! < a | db/dr(alpha) > * R^lambda_beta * delta^lambda_nu
     748              :             CALL hr_mult_by_delta_1d(vcd_env%dcdr_env%matrix_nosym_temp(alpha)%matrix, qs_kind_set, "ORB", sab_all, &
     749           54 :                                      vcd_env%dcdr_env%lambda, direction_Or=.TRUE.)
     750              :             ! < a | db/dr(alpha) > * R^lambda_beta * delta^lambda_mu
     751              :             CALL hr_mult_by_delta_1d(vcd_env%dcdr_env%matrix_nosym_temp2(alpha)%matrix, qs_kind_set, "ORB", sab_all, &
     752           54 :                                      vcd_env%dcdr_env%lambda, direction_Or=.FALSE.)
     753              : 
     754              :             ! < a | db/dr > * R^lambda_beta * ( delta^lambda_mu - delta^lambda_nu )
     755              :             CALL dbcsr_add(vcd_env%dcdr_env%matrix_nosym_temp2(alpha)%matrix, vcd_env%dcdr_env%matrix_nosym_temp(alpha)%matrix, &
     756           54 :                            1._dp, -1._dp)
     757              : 
     758           54 :             CALL cp_fm_set_all(buf, 0.0_dp)
     759           54 :             CALL cp_dbcsr_sm_fm_multiply(vcd_env%dcdr_env%matrix_nosym_temp2(alpha)%matrix, mo_coeff, buf, ncol=nmo)
     760           54 :             CALL cp_fm_trace(mo_coeff, buf, apt_difdip)
     761              : 
     762              :             ! And the whole contribution is
     763              :             ! - < a | db/dr > * (mu - nu) * ref_point
     764           54 :             apt_difdip = -apt_difdip*vcd_env%spatial_origin_atom(vcd_env%dcdr_env%beta)
     765              : 
     766              :             apt_el(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) &
     767           72 :                = apt_el(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) + f_spin*apt_difdip
     768              :          END DO
     769              : 
     770              :          ! And the additional factor to rcom
     771              :          ! < mu | [V, r] | nu > * R^lambda_beta * delta^lambda_mu
     772              :          ! - < mu | [V, r] | nu > * R^lambda_beta * delta^lambda_nu
     773              :          !
     774              :          !                  vcd_env%hcom(alpha) = - < mu | [V, r_alpha] | nu >
     775              :          ! particle_set(lambda)%r(vcd_env%dcdr_env%beta) = R^lambda_beta
     776              : 
     777           72 :          DO alpha = 1, 3
     778           54 :             CALL dbcsr_set(vcd_env%dcdr_env%matrix_nosym_temp(alpha)%matrix, 0._dp)
     779           54 :             CALL dbcsr_desymmetrize(vcd_env%hcom(alpha)%matrix, vcd_env%dcdr_env%matrix_nosym_temp(alpha)%matrix)
     780           54 :             CALL dbcsr_copy(vcd_env%dcdr_env%matrix_nosym_temp2(alpha)%matrix, vcd_env%dcdr_env%matrix_nosym_temp(alpha)%matrix)
     781              : 
     782              :             ! < mu | [V, r] | nu > * delta^lambda_nu
     783              :             CALL hr_mult_by_delta_1d(vcd_env%dcdr_env%matrix_nosym_temp(alpha)%matrix, qs_kind_set, "ORB", sab_all, &
     784           54 :                                      vcd_env%dcdr_env%lambda, direction_Or=.TRUE.)
     785              :             ! < mu | [V, r] | nu > * delta^lambda_mu
     786              :             CALL hr_mult_by_delta_1d(vcd_env%dcdr_env%matrix_nosym_temp2(alpha)%matrix, qs_kind_set, "ORB", sab_all, &
     787           54 :                                      vcd_env%dcdr_env%lambda, direction_Or=.FALSE.)
     788              : 
     789              :             CALL dbcsr_add(vcd_env%dcdr_env%matrix_nosym_temp(alpha)%matrix, &
     790           54 :                            vcd_env%dcdr_env%matrix_nosym_temp2(alpha)%matrix, -1._dp, +1._dp)
     791              : 
     792           54 :             CALL cp_fm_set_all(buf, 0.0_dp)
     793           54 :             CALL cp_dbcsr_sm_fm_multiply(vcd_env%dcdr_env%matrix_nosym_temp(alpha)%matrix, mo_coeff, buf, ncol=nmo)
     794           54 :             CALL cp_fm_trace(mo_coeff, buf, apt_rcom)
     795           54 :             apt_rcom = -vcd_env%spatial_origin_atom(vcd_env%dcdr_env%beta)*apt_rcom
     796              : 
     797              :             apt_el(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) &
     798           72 :                = apt_el(vcd_env%dcdr_env%beta, alpha, vcd_env%dcdr_env%lambda) + f_spin*apt_rcom
     799              :          END DO
     800              : 
     801              :          ! STEP 5: nuclear contribution
     802              :          ASSOCIATE (atomic_kind => particle_set(vcd_env%dcdr_env%lambda)%atomic_kind)
     803           18 :             CALL get_atomic_kind(atomic_kind, kind_number=ikind)
     804           18 :             CALL get_qs_kind(qs_kind_set(ikind), core_charge=charge, ghost=ghost)
     805           18 :             IF (.NOT. ghost) THEN
     806              :                apt_nuc(vcd_env%dcdr_env%beta, vcd_env%dcdr_env%beta, vcd_env%dcdr_env%lambda) = &
     807           18 :                   apt_nuc(vcd_env%dcdr_env%beta, vcd_env%dcdr_env%beta, vcd_env%dcdr_env%lambda) + charge
     808              :             END IF
     809              :          END ASSOCIATE
     810              : 
     811              :          ! STEP 6: deallocations
     812           18 :          CALL cp_fm_release(buf)
     813           72 :          CALL cp_fm_release(matrix_dSdV_mo)
     814              : 
     815              :       END ASSOCIATE
     816              : 
     817           18 :       CALL timestop(handle)
     818           18 :    END SUBROUTINE apt_dV
     819              : 
     820              : ! **************************************************************************************************
     821              : !> \brief Initialize the matrices for the NVPT calculation
     822              : !> \param vcd_env ...
     823              : !> \param qs_env ...
     824              : !> \author Edward Ditler
     825              : ! **************************************************************************************************
     826            6 :    SUBROUTINE prepare_per_atom_vcd(vcd_env, qs_env)
     827              :       TYPE(vcd_env_type)                                 :: vcd_env
     828              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     829              : 
     830              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'prepare_per_atom_vcd'
     831              : 
     832              :       INTEGER                                            :: handle, i, ispin, j
     833              :       TYPE(cell_type), POINTER                           :: cell
     834              :       TYPE(dft_control_type), POINTER                    :: dft_control
     835              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
     836            6 :          POINTER                                         :: sab_all, sab_orb, sap_ppnl
     837            6 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     838            6 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     839              : 
     840            6 :       CALL timeset(routineN, handle)
     841              : 
     842              :       CALL get_qs_env(qs_env=qs_env, dft_control=dft_control, &
     843              :                       sab_orb=sab_orb, sab_all=sab_all, sap_ppnl=sap_ppnl, &
     844            6 :                       qs_kind_set=qs_kind_set, particle_set=particle_set, cell=cell)
     845              : 
     846            6 :       IF (vcd_env%distributed_origin) THEN
     847            0 :          vcd_env%magnetic_origin_atom(:) = particle_set(vcd_env%dcdr_env%lambda)%r(:) - vcd_env%magnetic_origin(:)
     848            0 :          vcd_env%spatial_origin_atom = particle_set(vcd_env%dcdr_env%lambda)%r(:) - vcd_env%spatial_origin(:)
     849              :       END IF
     850              : 
     851              :       ! Reset the matrices
     852           12 :       DO ispin = 1, dft_control%nspins
     853           24 :          DO j = 1, 3
     854           18 :             CALL dbcsr_set(vcd_env%matrix_dSdV(j)%matrix, 0._dp)
     855           18 :             CALL dbcsr_set(vcd_env%matrix_drpnl(j)%matrix, 0._dp)
     856              : 
     857           78 :             DO i = 1, 3
     858           54 :                CALL dbcsr_set(vcd_env%matrix_dcom(i, j)%matrix, 0.0_dp)
     859           72 :                CALL dbcsr_set(vcd_env%matrix_difdip2(i, j)%matrix, 0._dp)
     860              :             END DO
     861              :          END DO
     862            6 :          CALL cp_fm_set_all(vcd_env%op_dV(ispin), 0._dp)
     863           12 :          CALL dbcsr_set(vcd_env%matrix_hxc_dsdv(ispin)%matrix, 0._dp)
     864              :       END DO
     865              : 
     866              :       ! operator dV
     867              :       ! <mu|d/dV_beta [V, r_alpha]|nu>
     868              :       CALL build_dcom_rpnl(vcd_env%matrix_dcom, qs_kind_set, sab_orb, sap_ppnl, &
     869            6 :                            dft_control%qs_control%eps_ppnl, particle_set, vcd_env%dcdr_env%lambda)
     870              : 
     871              :       ! PP derivative. build_com_mom_nl returns [r, Vnl], while matrix_drpnl
     872              :       ! historically stores [Vnl, r] = -[r, Vnl].
     873              :       CALL build_com_mom_nl(qs_kind_set, sab_all, sap_ppnl, dft_control%qs_control%eps_ppnl, &
     874              :                             particle_set, cell=cell, matrix_rv=vcd_env%matrix_drpnl, &
     875            6 :                             pseudoatom=vcd_env%dcdr_env%lambda)
     876           24 :       DO j = 1, 3
     877           24 :          CALL dbcsr_scale(vcd_env%matrix_drpnl(j)%matrix, alpha_scalar=-1._dp)
     878              :       END DO
     879              :       ! lin_mom
     880           24 :       DO i = 1, 3
     881           18 :          CALL dbcsr_set(vcd_env%dipvel_ao_delta(i)%matrix, 0._dp)
     882           24 :          CALL dbcsr_copy(vcd_env%dipvel_ao_delta(i)%matrix, vcd_env%dipvel_ao(i)%matrix)
     883              :       END DO
     884              : 
     885              :       CALL hr_mult_by_delta_3d(vcd_env%dipvel_ao_delta, qs_kind_set, "ORB", &
     886            6 :                                sab_all, vcd_env%dcdr_env%delta_basis_function, direction_Or=.TRUE.)
     887              : 
     888              :       ! dS/dV
     889              :       CALL build_dSdV_matrix(qs_env, vcd_env%matrix_dSdV, &
     890              :                              deltaR=vcd_env%dcdr_env%delta_basis_function, &
     891            6 :                              rcc=vcd_env%spatial_origin_atom)
     892              : 
     893              :       CALL build_local_moments_der_matrix(qs_env, vcd_env%matrix_difdip2, 1, 0, &
     894              :                                           ref_point=[0._dp, 0._dp, 0._dp], basis_type="ORB", &
     895            6 :                                           ordered=.TRUE., lambda=vcd_env%dcdr_env%lambda)
     896              :       ! AAT
     897              :       ! moments_throw: x, y, z, xx, xy, xz, yy, yz, zz
     898              :       ! moments_der:  (moment, xyz derivative)
     899              :       ! build_local_moments_der_matrix uses adbdr for calculating derivatives of the *primitive*
     900              :       !  on the right. So the resulting
     901              :       !  moments_der(moment, delta) = - < a | moment \partial_\delta | b >
     902           60 :       DO i = 1, 9 ! x, y, z, xx, xy, xz, yy, yz, zz
     903          222 :          DO j = 1, 3
     904          162 :             CALL dbcsr_set(vcd_env%moments_der_right(i, j)%matrix, 0.0_dp)
     905          216 :             CALL dbcsr_set(vcd_env%moments_der_left(i, j)%matrix, 0.0_dp)
     906              :          END DO
     907              :       END DO
     908              : 
     909           60 :       DO i = 1, 9
     910          222 :          DO j = 1, 3 ! derivatives
     911          162 :             CALL dbcsr_desymmetrize(vcd_env%moments_der(i, j)%matrix, vcd_env%moments_der_right(i, j)%matrix) ! A2
     912          162 :             CALL dbcsr_desymmetrize(vcd_env%moments_der(i, j)%matrix, vcd_env%moments_der_left(i, j)%matrix)  ! A1
     913              : 
     914              :             !  - < mu | r_beta r_gamma ∂_delta | nu > * (mu/nu == lambda)
     915              :             CALL hr_mult_by_delta_1d(vcd_env%moments_der_right(i, j)%matrix, qs_kind_set, "ORB", &
     916          162 :                                      sab_all, direction_Or=.TRUE., lambda=vcd_env%dcdr_env%lambda)
     917              :             CALL hr_mult_by_delta_1d(vcd_env%moments_der_left(i, j)%matrix, qs_kind_set, "ORB", &
     918          216 :                                      sab_all, direction_Or=.FALSE., lambda=vcd_env%dcdr_env%lambda)
     919              :          END DO
     920              :       END DO
     921              : 
     922           24 :       DO i = 1, 3
     923           78 :          DO j = 1, 3
     924           72 :             CALL dbcsr_set(vcd_env%matrix_r_doublecom(i, j)%matrix, 0._dp)
     925              :          END DO
     926              :       END DO
     927              : 
     928              :       CALL build_com_mom_nl(qs_kind_set, sab_all, sap_ppnl, dft_control%qs_control%eps_ppnl, &
     929              :                             particle_set, ref_point=[0._dp, 0._dp, 0._dp], cell=cell, &
     930              :                             matrix_r_doublecom=vcd_env%matrix_r_doublecom, &
     931            6 :                             pseudoatom=vcd_env%dcdr_env%lambda)
     932              : 
     933            6 :       CALL timestop(handle)
     934              : 
     935            6 :    END SUBROUTINE prepare_per_atom_vcd
     936              : 
     937              : ! **************************************************************************************************
     938              : !> \brief What we are building here is the operator for the NVPT response:
     939              : !>     H0 * C1 - S0 * E0 * C1  = - op_dV
     940              : !>     linres_solver           = - [ H1 * C0 - S1 * C0 * E0 ]
     941              : !>   with
     942              : !>     H1 * C0 =   dH/dV * C0
     943              : !>               + i[∂]δ * C0
     944              : !>               - i S0 * C^(1,R)
     945              : !>               + i S0 * C0 * (C0 * S^(1,R) * C0)
     946              : !>               - S1 * C0 * E0
     947              : !>
     948              : !>     H1 * C0 = + i (Hr - rH) * C0                    [STEP 1]
     949              : !>               + i[∂]δ * C0                          [STEP 2]
     950              : !>               - i[V, r]δ * C0                       [STEP 3]
     951              : !>               - i S0 * C^(1,R)                      [STEP 4]
     952              : !>               - S1 * C0 * E0                        [STEP 5]
     953              : !> \param vcd_env ...
     954              : !> \param qs_env ...
     955              : !> \author Edward Ditler, Tomas Zimmermann
     956              : ! **************************************************************************************************
     957           18 :    SUBROUTINE vcd_build_op_dV(vcd_env, qs_env)
     958              :       TYPE(vcd_env_type)                                 :: vcd_env
     959              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     960              : 
     961              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'vcd_build_op_dV'
     962              :       INTEGER, PARAMETER                                 :: ispin = 1
     963              : 
     964              :       INTEGER                                            :: handle, nao, nmo
     965              :       TYPE(cp_fm_type)                                   :: buf
     966              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
     967           18 :          POINTER                                         :: sab_all
     968           18 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     969              : 
     970           18 :       CALL timeset(routineN, handle)
     971              : 
     972              :       CALL get_qs_env(qs_env=qs_env, &
     973              :                       sab_all=sab_all, &
     974           18 :                       qs_kind_set=qs_kind_set)
     975              : 
     976           18 :       nmo = vcd_env%dcdr_env%nmo(1)
     977           18 :       nao = vcd_env%dcdr_env%nao
     978              : 
     979           18 :       CALL build_matrix_hr_rh(vcd_env, qs_env, vcd_env%spatial_origin_atom)
     980              : 
     981              :       ! STEP 1: hr-rh
     982           18 :       CALL dbcsr_copy(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, vcd_env%matrix_hr(ispin, vcd_env%dcdr_env%beta)%matrix)
     983           18 :       CALL dbcsr_copy(vcd_env%dcdr_env%matrix_nosym_temp(2)%matrix, vcd_env%matrix_rh(ispin, vcd_env%dcdr_env%beta)%matrix)
     984              : 
     985              :       CALL hr_mult_by_delta_1d(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, qs_kind_set, "ORB", &
     986           18 :                                sab_all, vcd_env%dcdr_env%lambda, direction_or=.TRUE.)
     987              :       CALL hr_mult_by_delta_1d(vcd_env%dcdr_env%matrix_nosym_temp(2)%matrix, qs_kind_set, "ORB", &
     988           18 :                                sab_all, vcd_env%dcdr_env%lambda, direction_or=.FALSE.)
     989              :       CALL dbcsr_add(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, &
     990              :                      vcd_env%dcdr_env%matrix_nosym_temp(2)%matrix, &
     991           18 :                      1.0_dp, -1.0_dp)
     992              : 
     993              :       ASSOCIATE (mo_coeff => vcd_env%dcdr_env%mo_coeff(ispin))
     994              :          CALL cp_dbcsr_sm_fm_multiply(vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix, mo_coeff, &
     995           18 :                                       vcd_env%op_dV(ispin), ncol=nmo, alpha=1.0_dp, beta=0.0_dp)
     996              : 
     997              :          ! STEP 2: electronic momentum operator contribution
     998              :          CALL cp_dbcsr_sm_fm_multiply(vcd_env%dipvel_ao_delta(vcd_env%dcdr_env%beta)%matrix, mo_coeff, &
     999              :                                       vcd_env%op_dV(ispin), &
    1000           18 :                                       ncol=nmo, alpha=1.0_dp, beta=1.0_dp)
    1001              : 
    1002              :          ! STEP 3: +dV_ppnl/dV, but matrix_drpnl stores the negative of dV_ppnl
    1003              :          ! The arguments (-1, 1) are swapped wrt to the hr-rh term, implying that
    1004              :          ! direction_Or and direction_hr do what they should.
    1005              :          CALL cp_dbcsr_sm_fm_multiply(vcd_env%matrix_drpnl(vcd_env%dcdr_env%beta)%matrix, mo_coeff, &
    1006              :                                       vcd_env%op_dV(ispin), &
    1007           18 :                                       ncol=nmo, alpha=-1.0_dp, beta=1.0_dp)
    1008              : 
    1009              :          ! STEP 4: - S0 * C^(1,R)
    1010           18 :          CALL cp_fm_create(buf, vcd_env%dcdr_env%likemos_fm_struct(ispin)%struct)
    1011              :          CALL cp_dbcsr_sm_fm_multiply(vcd_env%dcdr_env%matrix_s1(1)%matrix, vcd_env%dcdr_env%dCR_prime(ispin), &
    1012           18 :                                       vcd_env%op_dV(1), ncol=nmo, alpha=-1.0_dp, beta=1.0_dp)
    1013              : 
    1014              :          ! STEP 5: -S(1,V) * C0 * E0
    1015              :          CALL cp_dbcsr_sm_fm_multiply(vcd_env%matrix_dSdV(vcd_env%dcdr_env%beta)%matrix, mo_coeff, &
    1016           18 :                                       buf, nmo, alpha=1.0_dp, beta=0.0_dp)
    1017              :          CALL parallel_gemm('N', 'N', nao, nmo, nmo, &
    1018              :                             -1.0_dp, buf, vcd_env%dcdr_env%chc(ispin), &
    1019           18 :                             1.0_dp, vcd_env%op_dV(ispin))
    1020              : 
    1021           36 :          CALL cp_fm_release(buf)
    1022              :       END ASSOCIATE
    1023              : 
    1024              :       ! We have built op_dV but plug -op_dV into the linres_solver
    1025           18 :       CALL cp_fm_scale(-1.0_dp, vcd_env%op_dV(1))
    1026              : 
    1027              :       ! Revert the matrices
    1028           18 :       CALL build_matrix_hr_rh(vcd_env, qs_env, [0._dp, 0._dp, 0._dp])
    1029              : 
    1030           18 :       CALL timestop(handle)
    1031           36 :    END SUBROUTINE vcd_build_op_dV
    1032              : 
    1033              : ! *****************************************************************************
    1034              : !> \brief Get the dC/dV using the vcd_env%op_dV
    1035              : !> \param vcd_env ...
    1036              : !> \param p_env ...
    1037              : !> \param qs_env ...
    1038              : !> \author Edward Ditler, Tomas Zimmermann
    1039              : ! **************************************************************************************************
    1040           18 :    SUBROUTINE vcd_response_dV(vcd_env, p_env, qs_env)
    1041              : 
    1042              :       TYPE(vcd_env_type)                                 :: vcd_env
    1043              :       TYPE(qs_p_env_type)                                :: p_env
    1044              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1045              : 
    1046              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'vcd_response_dV'
    1047              :       INTEGER, PARAMETER                                 :: ispin = 1
    1048              : 
    1049              :       INTEGER                                            :: handle, output_unit
    1050              :       LOGICAL                                            :: failure, should_stop
    1051           72 :       TYPE(cp_fm_type), DIMENSION(1)                     :: h1_psi0, psi1
    1052              :       TYPE(cp_logger_type), POINTER                      :: logger
    1053              :       TYPE(linres_control_type), POINTER                 :: linres_control
    1054           18 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
    1055              :       TYPE(section_vals_type), POINTER                   :: lr_section, vcd_section
    1056              : 
    1057           18 :       CALL timeset(routineN, handle)
    1058           18 :       failure = .FALSE.
    1059              : 
    1060           18 :       NULLIFY (linres_control, lr_section, logger)
    1061              : 
    1062              :       CALL get_qs_env(qs_env=qs_env, &
    1063              :                       linres_control=linres_control, &
    1064           18 :                       mos=mos)
    1065              : 
    1066           18 :       logger => cp_get_default_logger()
    1067           18 :       lr_section => section_vals_get_subs_vals(qs_env%input, "PROPERTIES%LINRES")
    1068              :       vcd_section => section_vals_get_subs_vals(qs_env%input, &
    1069           18 :                                                 "PROPERTIES%LINRES%vcd")
    1070              : 
    1071              :       output_unit = cp_print_key_unit_nr(logger, lr_section, "PRINT%PROGRAM_RUN_INFO", &
    1072           18 :                                          extension=".linresLog")
    1073           18 :       IF (output_unit > 0) THEN
    1074              :          WRITE (UNIT=output_unit, FMT="(T10,A,/)") &
    1075            9 :             "*** Self consistent optimization of the response wavefunction ***"
    1076              :       END IF
    1077              : 
    1078              :       ASSOCIATE (psi0_order => vcd_env%dcdr_env%mo_coeff)
    1079           18 :          CALL cp_fm_create(psi1(ispin), vcd_env%dcdr_env%likemos_fm_struct(ispin)%struct, set_zero=.TRUE.)
    1080           18 :          CALL cp_fm_create(h1_psi0(ispin), vcd_env%dcdr_env%likemos_fm_struct(ispin)%struct)
    1081              : 
    1082              :          ! Restart
    1083           18 :          IF (linres_control%linres_restart) THEN
    1084           18 :             CALL vcd_read_restart(qs_env, lr_section, psi1, vcd_env%dcdr_env%lambda, vcd_env%dcdr_env%beta, "dCdV")
    1085              :          ELSE
    1086            0 :             CALL cp_fm_set_all(psi1(ispin), 0.0_dp)
    1087              :          END IF
    1088              : 
    1089           18 :          IF (output_unit > 0) THEN
    1090              :             WRITE (output_unit, *) &
    1091            9 :                "Response to the perturbation operator referring to the velocity of atom ", &
    1092           18 :                vcd_env%dcdr_env%lambda, " in "//ACHAR(vcd_env%dcdr_env%beta + 119)
    1093              :          END IF
    1094              : 
    1095              :          ! First response to get dCR
    1096              :          ! (H0-E0) psi1 = (H1-E1) psi0
    1097              :          ! psi1 = the perturbed wavefunction
    1098              :          ! h1_psi0 = (H1-E1)
    1099              :          ! psi0_order = the unperturbed wavefunction
    1100              :          ! Second response to get dCV
    1101           18 :          CALL cp_fm_set_all(vcd_env%dCV(ispin), 0.0_dp)
    1102           18 :          CALL cp_fm_set_all(h1_psi0(ispin), 0.0_dp)
    1103           18 :          CALL cp_fm_to_fm(vcd_env%op_dV(ispin), h1_psi0(ispin))
    1104              : 
    1105           18 :          linres_control%lr_triplet = .FALSE. ! we do singlet response
    1106           18 :          linres_control%do_kernel = .FALSE. ! no coupled response since imaginary perturbation
    1107           18 :          linres_control%converged = .FALSE.
    1108              :          CALL linres_solver(p_env, qs_env, psi1, h1_psi0, psi0_order, &
    1109           18 :                             output_unit, should_stop)
    1110           18 :          CALL cp_fm_to_fm(psi1(ispin), vcd_env%dCV(ispin))
    1111              : 
    1112              :          ! Write the new result to the restart file
    1113           36 :          IF (linres_control%linres_restart) THEN
    1114           18 :             CALL vcd_write_restart(qs_env, lr_section, psi1, vcd_env%dcdr_env%lambda, vcd_env%dcdr_env%beta, "dCdV")
    1115              :          END IF
    1116              : 
    1117              :       END ASSOCIATE
    1118              : 
    1119              :       ! clean up
    1120           18 :       CALL cp_fm_release(psi1(ispin))
    1121           18 :       CALL cp_fm_release(h1_psi0(ispin))
    1122              : 
    1123              :       CALL cp_print_key_finished_output(output_unit, logger, lr_section, &
    1124           18 :                                         "PRINT%PROGRAM_RUN_INFO")
    1125              : 
    1126           18 :       CALL timestop(handle)
    1127           36 :    END SUBROUTINE vcd_response_dV
    1128              : 
    1129              : END MODULE qs_vcd
        

Generated by: LCOV version 2.0-1