LCOV - code coverage report
Current view: top level - src - pao_param_methods.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:936074a) Lines: 99.2 % 129 128
Test Date: 2025-12-04 06:27:48 Functions: 100.0 % 4 4

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2025 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief Common routines for PAO parametrizations.
      10              : !> \author Ole Schuett
      11              : ! **************************************************************************************************
      12              : MODULE pao_param_methods
      13              :    USE cp_control_types,                ONLY: dft_control_type
      14              :    USE cp_dbcsr_api,                    ONLY: &
      15              :         dbcsr_add, dbcsr_complete_redistribute, dbcsr_create, dbcsr_get_block_p, dbcsr_get_info, &
      16              :         dbcsr_iterator_blocks_left, dbcsr_iterator_next_block, dbcsr_iterator_start, &
      17              :         dbcsr_iterator_stop, dbcsr_iterator_type, dbcsr_multiply, dbcsr_p_type, dbcsr_release, &
      18              :         dbcsr_scale, dbcsr_type
      19              :    USE cp_dbcsr_contrib,                ONLY: dbcsr_reserve_diag_blocks
      20              :    USE cp_log_handling,                 ONLY: cp_to_string
      21              :    USE dm_ls_scf_qs,                    ONLY: matrix_decluster
      22              :    USE dm_ls_scf_types,                 ONLY: ls_mstruct_type,&
      23              :                                               ls_scf_env_type
      24              :    USE kinds,                           ONLY: dp
      25              :    USE message_passing,                 ONLY: mp_comm_type
      26              :    USE pao_types,                       ONLY: pao_env_type
      27              :    USE qs_environment_types,            ONLY: get_qs_env,&
      28              :                                               qs_environment_type
      29              :    USE qs_rho_types,                    ONLY: qs_rho_get,&
      30              :                                               qs_rho_type
      31              : #include "./base/base_uses.f90"
      32              : 
      33              :    IMPLICIT NONE
      34              : 
      35              :    PRIVATE
      36              : 
      37              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'pao_param_methods'
      38              : 
      39              :    PUBLIC :: pao_calc_grad_lnv_wrt_U, pao_calc_AB_from_U, pao_calc_grad_lnv_wrt_AB
      40              : 
      41              : CONTAINS
      42              : 
      43              : ! **************************************************************************************************
      44              : !> \brief Helper routine, calculates partial derivative dE/dU
      45              : !> \param qs_env ...
      46              : !> \param ls_scf_env ...
      47              : !> \param matrix_M_diag the derivate wrt U, matrix uses pao%diag_distribution
      48              : ! **************************************************************************************************
      49         2426 :    SUBROUTINE pao_calc_grad_lnv_wrt_U(qs_env, ls_scf_env, matrix_M_diag)
      50              :       TYPE(qs_environment_type), POINTER                 :: qs_env
      51              :       TYPE(ls_scf_env_type), TARGET                      :: ls_scf_env
      52              :       TYPE(dbcsr_type)                                   :: matrix_M_diag
      53              : 
      54              :       CHARACTER(len=*), PARAMETER :: routineN = 'pao_calc_grad_lnv_wrt_U'
      55              : 
      56              :       INTEGER                                            :: handle
      57              :       REAL(KIND=dp)                                      :: filter_eps
      58         2426 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s
      59              :       TYPE(dbcsr_type)                                   :: matrix_M, matrix_Ma, matrix_Mb, matrix_NM
      60              :       TYPE(ls_mstruct_type), POINTER                     :: ls_mstruct
      61              :       TYPE(pao_env_type), POINTER                        :: pao
      62              : 
      63         2426 :       CALL timeset(routineN, handle)
      64              : 
      65         2426 :       ls_mstruct => ls_scf_env%ls_mstruct
      66         2426 :       pao => ls_scf_env%pao_env
      67         2426 :       filter_eps = ls_scf_env%eps_filter
      68         2426 :       CALL get_qs_env(qs_env, matrix_s=matrix_s)
      69              : 
      70         2426 :       CALL pao_calc_grad_lnv_wrt_AB(qs_env, ls_scf_env, matrix_Ma, matrix_Mb)
      71              : 
      72              :       ! Calculation uses distr. of matrix_s, afterwards we redistribute to pao%diag_distribution.
      73         2426 :       CALL dbcsr_create(matrix_M, template=matrix_s(1)%matrix, matrix_type="N")
      74         2426 :       CALL dbcsr_reserve_diag_blocks(matrix_M)
      75              : 
      76         2426 :       CALL dbcsr_create(matrix_NM, template=ls_mstruct%matrix_A, matrix_type="N")
      77              : 
      78              :       CALL dbcsr_multiply("N", "N", 1.0_dp, pao%matrix_N_inv, matrix_Ma, &
      79         2426 :                           1.0_dp, matrix_NM, filter_eps=filter_eps)
      80              : 
      81              :       CALL dbcsr_multiply("N", "N", 1.0_dp, pao%matrix_N, matrix_Mb, &
      82         2426 :                           1.0_dp, matrix_NM, filter_eps=filter_eps)
      83              : 
      84              :       CALL dbcsr_multiply("N", "T", 1.0_dp, matrix_NM, pao%matrix_Y, &
      85         2426 :                           1.0_dp, matrix_M, filter_eps=filter_eps)
      86              : 
      87              :       !---------------------------------------------------------------------------
      88              :       ! redistribute using pao%diag_distribution
      89              :       CALL dbcsr_create(matrix_M_diag, &
      90              :                         name="PAO matrix_M", &
      91              :                         matrix_type="N", &
      92              :                         dist=pao%diag_distribution, &
      93         2426 :                         template=matrix_s(1)%matrix)
      94         2426 :       CALL dbcsr_reserve_diag_blocks(matrix_M_diag)
      95         2426 :       CALL dbcsr_complete_redistribute(matrix_M, matrix_M_diag)
      96              : 
      97              :       !---------------------------------------------------------------------------
      98              :       ! cleanup:
      99         2426 :       CALL dbcsr_release(matrix_M)
     100         2426 :       CALL dbcsr_release(matrix_Ma)
     101         2426 :       CALL dbcsr_release(matrix_Mb)
     102         2426 :       CALL dbcsr_release(matrix_NM)
     103              : 
     104         2426 :       CALL timestop(handle)
     105         2426 :    END SUBROUTINE pao_calc_grad_lnv_wrt_U
     106              : 
     107              : ! **************************************************************************************************
     108              : !> \brief Takes current matrix_X and calculates the matrices A and B.
     109              : !> \param pao ...
     110              : !> \param qs_env ...
     111              : !> \param ls_scf_env ...
     112              : !> \param matrix_U_diag ...
     113              : ! **************************************************************************************************
     114        13050 :    SUBROUTINE pao_calc_AB_from_U(pao, qs_env, ls_scf_env, matrix_U_diag)
     115              :       TYPE(pao_env_type), POINTER                        :: pao
     116              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     117              :       TYPE(ls_scf_env_type), TARGET                      :: ls_scf_env
     118              :       TYPE(dbcsr_type)                                   :: matrix_U_diag
     119              : 
     120              :       CHARACTER(len=*), PARAMETER :: routineN = 'pao_calc_AB_from_U'
     121              : 
     122              :       INTEGER                                            :: acol, arow, handle, iatom
     123              :       LOGICAL                                            :: found
     124        13050 :       REAL(dp), DIMENSION(:, :), POINTER                 :: block_A, block_B, block_N, block_N_inv, &
     125        13050 :                                                             block_U, block_Y
     126              :       TYPE(dbcsr_iterator_type)                          :: iter
     127        13050 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s
     128              :       TYPE(dbcsr_type)                                   :: matrix_U
     129              :       TYPE(ls_mstruct_type), POINTER                     :: ls_mstruct
     130              : 
     131        13050 :       CALL timeset(routineN, handle)
     132        13050 :       CALL get_qs_env(qs_env, matrix_s=matrix_s)
     133        13050 :       ls_mstruct => ls_scf_env%ls_mstruct
     134              : 
     135              :       ! --------------------------------------------------------------------------------------------
     136              :       ! sanity check matrix U
     137        13050 :       CALL pao_assert_unitary(pao, matrix_U_diag)
     138              : 
     139              :       ! --------------------------------------------------------------------------------------------
     140              :       ! redistribute matrix_U_diag from diag_distribution to distribution of matrix_s
     141        13050 :       CALL get_qs_env(qs_env, matrix_s=matrix_s)
     142        13050 :       CALL dbcsr_create(matrix_U, matrix_type="N", template=matrix_s(1)%matrix)
     143        13050 :       CALL dbcsr_reserve_diag_blocks(matrix_U)
     144        13050 :       CALL dbcsr_complete_redistribute(matrix_U_diag, matrix_U)
     145              : 
     146              :       ! --------------------------------------------------------------------------------------------
     147              :       ! calculate matrix A and B from matrix U
     148              :       ! Multiplying diagonal matrices is a local operation.
     149              :       ! To take advantage of this we're using an iterator instead of calling dbcsr_multiply().
     150              : !$OMP PARALLEL DEFAULT(NONE) SHARED(pao,ls_mstruct,matrix_U) &
     151        13050 : !$OMP PRIVATE(iter,arow,acol,iatom,block_U,block_Y,block_A,block_B,block_N,block_N_inv,found)
     152              :       CALL dbcsr_iterator_start(iter, matrix_U)
     153              :       DO WHILE (dbcsr_iterator_blocks_left(iter))
     154              :          CALL dbcsr_iterator_next_block(iter, arow, acol, block_U)
     155              :          iatom = arow; CPASSERT(arow == acol)
     156              : 
     157              :          CALL dbcsr_get_block_p(matrix=pao%matrix_Y, row=iatom, col=iatom, block=block_Y, found=found)
     158              :          CPASSERT(ASSOCIATED(block_Y))
     159              : 
     160              :          CALL dbcsr_get_block_p(matrix=ls_mstruct%matrix_A, row=iatom, col=iatom, block=block_A, found=found)
     161              :          CALL dbcsr_get_block_p(matrix=pao%matrix_N_inv, row=iatom, col=iatom, block=block_N_inv, found=found)
     162              :          CPASSERT(ASSOCIATED(block_A) .AND. ASSOCIATED(block_N_inv))
     163              : 
     164              :          CALL dbcsr_get_block_p(matrix=ls_mstruct%matrix_B, row=iatom, col=iatom, block=block_B, found=found)
     165              :          CALL dbcsr_get_block_p(matrix=pao%matrix_N, row=iatom, col=iatom, block=block_N, found=found)
     166              :          CPASSERT(ASSOCIATED(block_B) .AND. ASSOCIATED(block_N))
     167              : 
     168              :          block_A = MATMUL(MATMUL(block_N_inv, block_U), block_Y)
     169              :          block_B = MATMUL(MATMUL(block_N, block_U), block_Y)
     170              : 
     171              :       END DO
     172              :       CALL dbcsr_iterator_stop(iter)
     173              : !$OMP END PARALLEL
     174              : 
     175        13050 :       CALL dbcsr_release(matrix_U)
     176              : 
     177        13050 :       CALL timestop(handle)
     178        13050 :    END SUBROUTINE pao_calc_AB_from_U
     179              : 
     180              : ! **************************************************************************************************
     181              : !> \brief Debugging routine, check unitaryness of U
     182              : !> \param pao ...
     183              : !> \param matrix_U ...
     184              : ! **************************************************************************************************
     185        17950 :    SUBROUTINE pao_assert_unitary(pao, matrix_U)
     186              :       TYPE(pao_env_type), POINTER                        :: pao
     187              :       TYPE(dbcsr_type)                                   :: matrix_U
     188              : 
     189              :       CHARACTER(len=*), PARAMETER :: routineN = 'pao_assert_unitary'
     190              : 
     191              :       INTEGER                                            :: acol, arow, handle, i, iatom, M, N
     192        13050 :       INTEGER, DIMENSION(:), POINTER                     :: blk_sizes_pao, blk_sizes_pri
     193              :       REAL(dp)                                           :: delta_max
     194        13050 :       REAL(dp), DIMENSION(:, :), POINTER                 :: block_test, tmp1, tmp2
     195              :       TYPE(dbcsr_iterator_type)                          :: iter
     196              :       TYPE(mp_comm_type)                                 :: group
     197              : 
     198        10600 :       IF (pao%check_unitary_tol < 0.0_dp) RETURN ! no checking
     199              : 
     200         2450 :       CALL timeset(routineN, handle)
     201         2450 :       delta_max = 0.0_dp
     202              : 
     203         2450 :       CALL dbcsr_get_info(pao%matrix_Y, row_blk_size=blk_sizes_pri, col_blk_size=blk_sizes_pao)
     204              : 
     205              : !$OMP PARALLEL DEFAULT(NONE) SHARED(pao,matrix_U,blk_sizes_pri,blk_sizes_pao,delta_max) &
     206         2450 : !$OMP PRIVATE(iter,arow,acol,iatom,N,M,block_test,tmp1,tmp2)
     207              :       CALL dbcsr_iterator_start(iter, matrix_U)
     208              :       DO WHILE (dbcsr_iterator_blocks_left(iter))
     209              :          CALL dbcsr_iterator_next_block(iter, arow, acol, block_test)
     210              :          iatom = arow; CPASSERT(arow == acol)
     211              :          N = blk_sizes_pri(iatom) ! size of primary basis
     212              :          M = blk_sizes_pao(iatom) ! size of pao basis
     213              : 
     214              :          ! we only need the upper left "PAO-corner" to be unitary
     215              :          ALLOCATE (tmp1(N, M), tmp2(M, M))
     216              :          tmp1 = block_test(:, 1:M)
     217              :          tmp2 = MATMUL(TRANSPOSE(tmp1), tmp1)
     218              :          DO i = 1, M
     219              :             tmp2(i, i) = tmp2(i, i) - 1.0_dp
     220              :          END DO
     221              : 
     222              : !$OMP ATOMIC
     223              :          delta_max = MAX(delta_max, MAXVAL(ABS(tmp2)))
     224              : 
     225              :          DEALLOCATE (tmp1, tmp2)
     226              :       END DO
     227              :       CALL dbcsr_iterator_stop(iter)
     228              : !$OMP END PARALLEL
     229              : 
     230         2450 :       CALL dbcsr_get_info(matrix_U, group=group)
     231              : 
     232         2450 :       CALL group%max(delta_max)
     233         2450 :       IF (pao%iw > 0) WRITE (pao%iw, *) 'PAO| checked unitaryness, max delta:', delta_max
     234         2450 :       IF (delta_max > pao%check_unitary_tol) &
     235            0 :          CPABORT("Found bad unitaryness:"//cp_to_string(delta_max))
     236              : 
     237         2450 :       CALL timestop(handle)
     238        13050 :    END SUBROUTINE pao_assert_unitary
     239              : 
     240              : ! **************************************************************************************************
     241              : !> \brief Helper routine, calculates partial derivative dE/dA and dE/dB.
     242              : !>        As energy functional serves the definition by LNV (Li, Nunes, Vanderbilt).
     243              : !> \param qs_env ...
     244              : !> \param ls_scf_env ...
     245              : !> \param matrix_Ma the derivate wrt A, matrix uses s_matrix-distribution.
     246              : !> \param matrix_Mb the derivate wrt B, matrix uses s_matrix-distribution.
     247              : ! **************************************************************************************************
     248         2660 :    SUBROUTINE pao_calc_grad_lnv_wrt_AB(qs_env, ls_scf_env, matrix_Ma, matrix_Mb)
     249              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     250              :       TYPE(ls_scf_env_type), TARGET                      :: ls_scf_env
     251              :       TYPE(dbcsr_type)                                   :: matrix_Ma, matrix_Mb
     252              : 
     253              :       CHARACTER(len=*), PARAMETER :: routineN = 'pao_calc_grad_lnv_wrt_AB'
     254              : 
     255              :       INTEGER                                            :: handle, nspin
     256         2660 :       INTEGER, DIMENSION(:), POINTER                     :: pao_blk_sizes
     257              :       REAL(KIND=dp)                                      :: filter_eps
     258         2660 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_ks, matrix_s, rho_ao
     259              :       TYPE(dbcsr_type) :: matrix_HB, matrix_HPS, matrix_M, matrix_M1, matrix_M1_dc, matrix_M2, &
     260              :          matrix_M2_dc, matrix_M3, matrix_M3_dc, matrix_PA, matrix_PH, matrix_PHP, matrix_PSP, &
     261              :          matrix_SB, matrix_SP
     262              :       TYPE(dft_control_type), POINTER                    :: dft_control
     263              :       TYPE(ls_mstruct_type), POINTER                     :: ls_mstruct
     264              :       TYPE(pao_env_type), POINTER                        :: pao
     265              :       TYPE(qs_rho_type), POINTER                         :: rho
     266              : 
     267         2660 :       CALL timeset(routineN, handle)
     268              : 
     269         2660 :       ls_mstruct => ls_scf_env%ls_mstruct
     270         2660 :       pao => ls_scf_env%pao_env
     271              : 
     272              :       CALL get_qs_env(qs_env, &
     273              :                       rho=rho, &
     274              :                       matrix_ks=matrix_ks, &
     275              :                       matrix_s=matrix_s, &
     276         2660 :                       dft_control=dft_control)
     277         2660 :       CALL qs_rho_get(rho, rho_ao=rho_ao)
     278         2660 :       nspin = dft_control%nspins
     279         2660 :       filter_eps = ls_scf_env%eps_filter
     280              : 
     281         2660 :       CALL dbcsr_get_info(ls_mstruct%matrix_A, col_blk_size=pao_blk_sizes)
     282              : 
     283         2660 :       IF (nspin /= 1) CPABORT("open shell not yet implemented")
     284              :       !TODO: handle openshell case properly
     285              : 
     286              :       ! Notation according to equation (4.6) on page 50 from:
     287              :       ! https://dx.doi.org/10.3929%2Fethz-a-010819495
     288              : 
     289              :       !---------------------------------------------------------------------------
     290              :       ! calculate need products in pao basis
     291         2660 :       CALL dbcsr_create(matrix_PH, template=ls_scf_env%matrix_s, matrix_type="N")
     292              :       CALL dbcsr_multiply("N", "N", 1.0_dp, ls_scf_env%matrix_p(1), ls_scf_env%matrix_ks(1), &
     293         2660 :                           0.0_dp, matrix_PH, filter_eps=filter_eps)
     294              : 
     295         2660 :       CALL dbcsr_create(matrix_PHP, template=ls_scf_env%matrix_s, matrix_type="N")
     296              :       CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_PH, ls_scf_env%matrix_p(1), &
     297         2660 :                           0.0_dp, matrix_PHP, filter_eps=filter_eps)
     298              : 
     299         2660 :       CALL dbcsr_create(matrix_SP, template=ls_scf_env%matrix_s, matrix_type="N")
     300              :       CALL dbcsr_multiply("N", "N", 1.0_dp, ls_scf_env%matrix_s, ls_scf_env%matrix_p(1), &
     301         2660 :                           0.0_dp, matrix_SP, filter_eps=filter_eps)
     302              : 
     303         2660 :       IF (nspin == 1) CALL dbcsr_scale(matrix_SP, 0.5_dp)
     304              : 
     305         2660 :       CALL dbcsr_create(matrix_HPS, template=ls_scf_env%matrix_s, matrix_type="N")
     306              :       CALL dbcsr_multiply("N", "T", 1.0_dp, ls_scf_env%matrix_ks(1), matrix_SP, &
     307         2660 :                           0.0_dp, matrix_HPS, filter_eps=filter_eps)
     308              : 
     309         2660 :       CALL dbcsr_create(matrix_PSP, template=ls_scf_env%matrix_s, matrix_type="N")
     310              :       CALL dbcsr_multiply("N", "N", 1.0_dp, ls_scf_env%matrix_p(1), matrix_SP, &
     311         2660 :                           0.0_dp, matrix_PSP, filter_eps=filter_eps)
     312              : 
     313              :       !---------------------------------------------------------------------------
     314              :       ! M1 = dE_lnv / dP_pao
     315         2660 :       CALL dbcsr_create(matrix_M1, template=ls_scf_env%matrix_s, matrix_type="N")
     316              : 
     317              :       CALL dbcsr_multiply("N", "T", 3.0_dp, ls_scf_env%matrix_ks(1), matrix_SP, &
     318         2660 :                           1.0_dp, matrix_M1, filter_eps=filter_eps)
     319              : 
     320              :       CALL dbcsr_multiply("N", "N", 3.0_dp, matrix_SP, ls_scf_env%matrix_ks(1), &
     321         2660 :                           1.0_dp, matrix_M1, filter_eps=filter_eps)
     322              : 
     323              :       CALL dbcsr_multiply("N", "T", -2.0_dp, matrix_HPS, matrix_SP, &
     324         2660 :                           1.0_dp, matrix_M1, filter_eps=filter_eps)
     325              : 
     326              :       CALL dbcsr_multiply("N", "N", -2.0_dp, matrix_SP, matrix_HPS, &
     327         2660 :                           1.0_dp, matrix_M1, filter_eps=filter_eps)
     328              : 
     329              :       CALL dbcsr_multiply("N", "T", -2.0_dp, matrix_SP, matrix_HPS, &
     330         2660 :                           1.0_dp, matrix_M1, filter_eps=filter_eps)
     331              : 
     332              :       ! reverse possible molecular clustering
     333              :       CALL dbcsr_create(matrix_M1_dc, &
     334              :                         template=matrix_s(1)%matrix, &
     335              :                         row_blk_size=pao_blk_sizes, &
     336         2660 :                         col_blk_size=pao_blk_sizes)
     337         2660 :       CALL matrix_decluster(matrix_M1_dc, matrix_M1, ls_mstruct)
     338              : 
     339              :       !---------------------------------------------------------------------------
     340              :       ! M2 = dE_lnv / dH
     341         2660 :       CALL dbcsr_create(matrix_M2, template=ls_scf_env%matrix_s, matrix_type="N")
     342              : 
     343         2660 :       CALL dbcsr_add(matrix_M2, matrix_PSP, 1.0_dp, 3.0_dp)
     344              : 
     345              :       CALL dbcsr_multiply("N", "N", -2.0_dp, matrix_PSP, matrix_SP, &
     346         2660 :                           1.0_dp, matrix_M2, filter_eps=filter_eps)
     347              : 
     348              :       ! reverse possible molecular clustering
     349              :       CALL dbcsr_create(matrix_M2_dc, &
     350              :                         template=matrix_s(1)%matrix, &
     351              :                         row_blk_size=pao_blk_sizes, &
     352         2660 :                         col_blk_size=pao_blk_sizes)
     353         2660 :       CALL matrix_decluster(matrix_M2_dc, matrix_M2, ls_mstruct)
     354              : 
     355              :       !---------------------------------------------------------------------------
     356              :       ! M3 = dE_lnv / dS
     357         2660 :       CALL dbcsr_create(matrix_M3, template=ls_scf_env%matrix_s, matrix_type="N")
     358              : 
     359         2660 :       CALL dbcsr_add(matrix_M3, matrix_PHP, 1.0_dp, 3.0_dp)
     360              : 
     361              :       CALL dbcsr_multiply("N", "N", -2.0_dp, matrix_PHP, matrix_SP, &
     362         2660 :                           1.0_dp, matrix_M3, filter_eps=filter_eps)
     363              : 
     364              :       CALL dbcsr_multiply("N", "T", -2.0_dp, matrix_PSP, matrix_PH, &
     365         2660 :                           1.0_dp, matrix_M3, filter_eps=filter_eps)
     366              : 
     367              :       ! reverse possible molecular clustering
     368              :       CALL dbcsr_create(matrix_M3_dc, &
     369              :                         template=matrix_s(1)%matrix, &
     370              :                         row_blk_size=pao_blk_sizes, &
     371         2660 :                         col_blk_size=pao_blk_sizes)
     372         2660 :       CALL matrix_decluster(matrix_M3_dc, matrix_M3, ls_mstruct)
     373              : 
     374              :       !---------------------------------------------------------------------------
     375              :       ! assemble Ma and Mb
     376              :       ! matrix_Ma = dE_lnv / dA = P * A * M1
     377              :       ! matrix_Mb = dE_lnv / dB = H * B * M2  +  S * B * M3
     378         2660 :       CALL dbcsr_create(matrix_Ma, template=ls_mstruct%matrix_A, matrix_type="N")
     379         2660 :       CALL dbcsr_reserve_diag_blocks(matrix_Ma)
     380         2660 :       CALL dbcsr_create(matrix_Mb, template=ls_mstruct%matrix_B, matrix_type="N")
     381         2660 :       CALL dbcsr_reserve_diag_blocks(matrix_Mb)
     382              : 
     383              :       !---------------------------------------------------------------------------
     384              :       ! combine M1 with matrices from primary basis
     385         2660 :       CALL dbcsr_create(matrix_PA, template=ls_mstruct%matrix_A, matrix_type="N")
     386              :       CALL dbcsr_multiply("N", "N", 1.0_dp, rho_ao(1)%matrix, ls_mstruct%matrix_A, &
     387         2660 :                           0.0_dp, matrix_PA, filter_eps=filter_eps)
     388              : 
     389              :       ! matrix_Ma = P * A * M1
     390              :       CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_PA, matrix_M1_dc, &
     391         2660 :                           0.0_dp, matrix_Ma, filter_eps=filter_eps)
     392              : 
     393              :       !---------------------------------------------------------------------------
     394              :       ! combine M2 with matrices from primary basis
     395         2660 :       CALL dbcsr_create(matrix_HB, template=ls_mstruct%matrix_B, matrix_type="N")
     396              :       CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_ks(1)%matrix, ls_mstruct%matrix_B, &
     397         2660 :                           0.0_dp, matrix_HB, filter_eps=filter_eps)
     398              : 
     399              :       ! matrix_Mb = H * B * M2
     400              :       CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_HB, matrix_M2_dc, &
     401         2660 :                           0.0_dp, matrix_Mb, filter_eps=filter_eps)
     402              : 
     403              :       !---------------------------------------------------------------------------
     404              :       ! combine M3 with matrices from primary basis
     405         2660 :       CALL dbcsr_create(matrix_SB, template=ls_mstruct%matrix_B, matrix_type="N")
     406              :       CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_s(1)%matrix, ls_mstruct%matrix_B, &
     407         2660 :                           0.0_dp, matrix_SB, filter_eps=filter_eps)
     408              : 
     409         2660 :       IF (nspin == 1) CALL dbcsr_scale(matrix_SB, 0.5_dp)
     410              : 
     411              :       ! matrix_Mb += S * B * M3
     412              :       CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_SB, matrix_M3_dc, &
     413         2660 :                           1.0_dp, matrix_Mb, filter_eps=filter_eps)
     414              : 
     415         2660 :       IF (nspin == 1) CALL dbcsr_scale(matrix_Ma, 2.0_dp)
     416         2660 :       IF (nspin == 1) CALL dbcsr_scale(matrix_Mb, 2.0_dp)
     417              : 
     418              :       !---------------------------------------------------------------------------
     419              :       ! cleanup: TODO release matrices as early as possible
     420         2660 :       CALL dbcsr_release(matrix_PH)
     421         2660 :       CALL dbcsr_release(matrix_PHP)
     422         2660 :       CALL dbcsr_release(matrix_SP)
     423         2660 :       CALL dbcsr_release(matrix_HPS)
     424         2660 :       CALL dbcsr_release(matrix_PSP)
     425         2660 :       CALL dbcsr_release(matrix_M)
     426         2660 :       CALL dbcsr_release(matrix_M1)
     427         2660 :       CALL dbcsr_release(matrix_M2)
     428         2660 :       CALL dbcsr_release(matrix_M3)
     429         2660 :       CALL dbcsr_release(matrix_M1_dc)
     430         2660 :       CALL dbcsr_release(matrix_M2_dc)
     431         2660 :       CALL dbcsr_release(matrix_M3_dc)
     432         2660 :       CALL dbcsr_release(matrix_PA)
     433         2660 :       CALL dbcsr_release(matrix_HB)
     434         2660 :       CALL dbcsr_release(matrix_SB)
     435              : 
     436         2660 :       CALL timestop(handle)
     437         2660 :    END SUBROUTINE pao_calc_grad_lnv_wrt_AB
     438              : 
     439              : END MODULE pao_param_methods
        

Generated by: LCOV version 2.0-1