LCOV - code coverage report
Current view: top level - src - pao_param_linpot.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:e5b1968) Lines: 187 189 98.9 %
Date: 2025-06-05 07:00:53 Functions: 10 10 100.0 %

          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 framework for a linear parametrization of the potential.
      10             : !> \author Ole Schuett
      11             : ! **************************************************************************************************
      12             : MODULE pao_param_linpot
      13             :    USE atomic_kind_types,               ONLY: get_atomic_kind
      14             :    USE basis_set_types,                 ONLY: gto_basis_set_type
      15             :    USE cp_control_types,                ONLY: dft_control_type
      16             :    USE cp_dbcsr_api,                    ONLY: &
      17             :         dbcsr_create, dbcsr_get_block_p, dbcsr_get_info, dbcsr_iterator_blocks_left, &
      18             :         dbcsr_iterator_next_block, dbcsr_iterator_start, dbcsr_iterator_stop, dbcsr_iterator_type, &
      19             :         dbcsr_p_type, dbcsr_release, dbcsr_type
      20             :    USE cp_dbcsr_contrib,                ONLY: dbcsr_reserve_diag_blocks
      21             :    USE dm_ls_scf_types,                 ONLY: ls_scf_env_type
      22             :    USE kinds,                           ONLY: dp
      23             :    USE machine,                         ONLY: m_flush
      24             :    USE mathlib,                         ONLY: diamat_all
      25             :    USE message_passing,                 ONLY: mp_comm_type,&
      26             :                                               mp_para_env_type
      27             :    USE pao_input,                       ONLY: pao_fock_param,&
      28             :                                               pao_rotinv_param
      29             :    USE pao_linpot_full,                 ONLY: linpot_full_calc_terms,&
      30             :                                               linpot_full_count_terms
      31             :    USE pao_linpot_rotinv,               ONLY: linpot_rotinv_calc_forces,&
      32             :                                               linpot_rotinv_calc_terms,&
      33             :                                               linpot_rotinv_count_terms
      34             :    USE pao_param_fock,                  ONLY: pao_calc_U_block_fock
      35             :    USE pao_param_methods,               ONLY: pao_calc_AB_from_U,&
      36             :                                               pao_calc_grad_lnv_wrt_U
      37             :    USE pao_potentials,                  ONLY: pao_guess_initial_potential
      38             :    USE pao_types,                       ONLY: pao_env_type
      39             :    USE particle_types,                  ONLY: particle_type
      40             :    USE qs_environment_types,            ONLY: get_qs_env,&
      41             :                                               qs_environment_type
      42             :    USE qs_kind_types,                   ONLY: get_qs_kind,&
      43             :                                               qs_kind_type
      44             : #include "./base/base_uses.f90"
      45             : 
      46             :    IMPLICIT NONE
      47             : 
      48             :    PRIVATE
      49             : 
      50             :    PUBLIC :: pao_param_init_linpot, pao_param_finalize_linpot, pao_calc_AB_linpot
      51             :    PUBLIC :: pao_param_count_linpot, pao_param_initguess_linpot
      52             : 
      53             : CONTAINS
      54             : 
      55             : ! **************************************************************************************************
      56             : !> \brief Initialize the linear potential parametrization
      57             : !> \param pao ...
      58             : !> \param qs_env ...
      59             : ! **************************************************************************************************
      60         234 :    SUBROUTINE pao_param_init_linpot(pao, qs_env)
      61             :       TYPE(pao_env_type), POINTER                        :: pao
      62             :       TYPE(qs_environment_type), POINTER                 :: qs_env
      63             : 
      64             :       CHARACTER(len=*), PARAMETER :: routineN = 'pao_param_init_linpot'
      65             : 
      66             :       INTEGER                                            :: acol, arow, handle, iatom, ikind, N, &
      67             :                                                             natoms, nterms
      68         234 :       INTEGER, DIMENSION(:), POINTER                     :: blk_sizes_pri, col_blk_size, row_blk_size
      69         234 :       REAL(dp), DIMENSION(:, :), POINTER                 :: block_V_terms
      70         234 :       REAL(dp), DIMENSION(:, :, :), POINTER              :: V_blocks
      71             :       TYPE(dbcsr_iterator_type)                          :: iter
      72             :       TYPE(dft_control_type), POINTER                    :: dft_control
      73             :       TYPE(mp_para_env_type), POINTER                    :: para_env
      74         234 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
      75             : 
      76         234 :       CALL timeset(routineN, handle)
      77             : 
      78             :       CALL get_qs_env(qs_env, &
      79             :                       para_env=para_env, &
      80             :                       dft_control=dft_control, &
      81             :                       particle_set=particle_set, &
      82         234 :                       natom=natoms)
      83             : 
      84         234 :       IF (dft_control%nspins /= 1) CPABORT("open shell not yet implemented")
      85             : 
      86             :       ! figure out number of potential terms
      87         936 :       ALLOCATE (row_blk_size(natoms), col_blk_size(natoms))
      88         714 :       DO iatom = 1, natoms
      89         480 :          CALL get_atomic_kind(particle_set(iatom)%atomic_kind, kind_number=ikind)
      90         480 :          CALL pao_param_count_linpot(pao, qs_env, ikind, nterms)
      91         714 :          col_blk_size(iatom) = nterms
      92             :       END DO
      93             : 
      94             :       ! allocate matrix_V_terms
      95         234 :       CALL dbcsr_get_info(pao%matrix_Y, row_blk_size=blk_sizes_pri)
      96        1428 :       row_blk_size = blk_sizes_pri**2
      97             :       CALL dbcsr_create(pao%matrix_V_terms, &
      98             :                         name="PAO matrix_V_terms", &
      99             :                         dist=pao%diag_distribution, &
     100             :                         matrix_type="N", &
     101             :                         row_blk_size=row_blk_size, &
     102         234 :                         col_blk_size=col_blk_size)
     103         234 :       CALL dbcsr_reserve_diag_blocks(pao%matrix_V_terms)
     104         234 :       DEALLOCATE (row_blk_size, col_blk_size)
     105             : 
     106             :       ! calculate, normalize, and store potential terms as rows of block_V_terms
     107             : !$OMP PARALLEL DEFAULT(NONE) SHARED(pao,qs_env,blk_sizes_pri) &
     108         234 : !$OMP PRIVATE(iter,arow,acol,iatom,N,nterms,block_V_terms,V_blocks)
     109             :       CALL dbcsr_iterator_start(iter, pao%matrix_V_terms)
     110             :       DO WHILE (dbcsr_iterator_blocks_left(iter))
     111             :          CALL dbcsr_iterator_next_block(iter, arow, acol, block_V_terms)
     112             :          iatom = arow; CPASSERT(arow == acol)
     113             :          nterms = SIZE(block_V_terms, 2)
     114             :          IF (nterms == 0) CYCLE ! protect against corner-case of zero pao parameters
     115             :          N = blk_sizes_pri(iatom)
     116             :          CPASSERT(N*N == SIZE(block_V_terms, 1))
     117             :          ALLOCATE (V_blocks(N, N, nterms))
     118             :          CALL linpot_calc_terms(pao, qs_env, iatom, V_blocks)
     119             :          block_V_terms = RESHAPE(V_blocks, (/N*N, nterms/)) ! convert matrices into vectors
     120             :          DEALLOCATE (V_blocks)
     121             :       END DO
     122             :       CALL dbcsr_iterator_stop(iter)
     123             : !$OMP END PARALLEL
     124             : 
     125         234 :       CALL pao_param_linpot_regularizer(pao)
     126             : 
     127         234 :       IF (pao%precondition) &
     128          12 :          CALL pao_param_linpot_preconditioner(pao)
     129             : 
     130         234 :       CALL para_env%sync() ! ensure that timestop is not called too early
     131             : 
     132         234 :       CALL timestop(handle)
     133         234 :    END SUBROUTINE pao_param_init_linpot
     134             : 
     135             : ! **************************************************************************************************
     136             : !> \brief Builds the regularization metric matrix_R
     137             : !> \param pao ...
     138             : ! **************************************************************************************************
     139         234 :    SUBROUTINE pao_param_linpot_regularizer(pao)
     140             :       TYPE(pao_env_type), POINTER                        :: pao
     141             : 
     142             :       CHARACTER(len=*), PARAMETER :: routineN = 'pao_param_linpot_regularizer'
     143             : 
     144             :       INTEGER                                            :: acol, arow, handle, i, iatom, j, k, &
     145             :                                                             nterms
     146         234 :       INTEGER, DIMENSION(:), POINTER                     :: blk_sizes_nterms
     147             :       LOGICAL                                            :: found
     148             :       REAL(dp)                                           :: v, w
     149         234 :       REAL(dp), ALLOCATABLE, DIMENSION(:)                :: S_evals
     150         234 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: S, S_evecs
     151         234 :       REAL(dp), DIMENSION(:, :), POINTER                 :: block_R, V_terms
     152             :       TYPE(dbcsr_iterator_type)                          :: iter
     153             : 
     154         234 :       CALL timeset(routineN, handle)
     155             : 
     156         234 :       IF (pao%iw > 0) WRITE (pao%iw, *) "PAO| Building linpot regularizer"
     157             : 
     158         234 :       CALL dbcsr_get_info(pao%matrix_V_terms, col_blk_size=blk_sizes_nterms)
     159             : 
     160             :       ! build regularization metric
     161             :       CALL dbcsr_create(pao%matrix_R, &
     162             :                         template=pao%matrix_V_terms, &
     163             :                         matrix_type="N", &
     164             :                         row_blk_size=blk_sizes_nterms, &
     165             :                         col_blk_size=blk_sizes_nterms, &
     166         234 :                         name="PAO matrix_R")
     167         234 :       CALL dbcsr_reserve_diag_blocks(pao%matrix_R)
     168             : 
     169             :       ! fill matrix_R
     170             : !$OMP PARALLEL DEFAULT(NONE) SHARED(pao) &
     171         234 : !$OMP PRIVATE(iter,arow,acol,iatom,block_R,V_terms,found,nterms,S,S_evecs,S_evals,k,i,j,v,w)
     172             :       CALL dbcsr_iterator_start(iter, pao%matrix_R)
     173             :       DO WHILE (dbcsr_iterator_blocks_left(iter))
     174             :          CALL dbcsr_iterator_next_block(iter, arow, acol, block_R)
     175             :          iatom = arow; CPASSERT(arow == acol)
     176             :          CALL dbcsr_get_block_p(matrix=pao%matrix_V_terms, row=iatom, col=iatom, block=V_terms, found=found)
     177             :          CPASSERT(ASSOCIATED(V_terms))
     178             :          nterms = SIZE(V_terms, 2)
     179             :          IF (nterms == 0) CYCLE ! protect against corner-case of zero pao parameters
     180             : 
     181             :          ! build overlap matrix
     182             :          ALLOCATE (S(nterms, nterms))
     183             :          S(:, :) = MATMUL(TRANSPOSE(V_terms), V_terms)
     184             : 
     185             :          ! diagonalize S
     186             :          ALLOCATE (S_evals(nterms), S_evecs(nterms, nterms))
     187             :          S_evecs(:, :) = S
     188             :          CALL diamat_all(S_evecs, S_evals)
     189             : 
     190             :          block_R = 0.0_dp
     191             :          DO k = 1, nterms
     192             :             v = pao%linpot_regu_delta/S_evals(k)
     193             :             w = pao%linpot_regu_strength*MIN(1.0_dp, ABS(v))
     194             :             DO i = 1, nterms
     195             :             DO j = 1, nterms
     196             :                block_R(i, j) = block_R(i, j) + w*S_evecs(i, k)*S_evecs(j, k)
     197             :             END DO
     198             :             END DO
     199             :          END DO
     200             : 
     201             :          ! clean up
     202             :          DEALLOCATE (S, S_evals, S_evecs)
     203             :       END DO
     204             :       CALL dbcsr_iterator_stop(iter)
     205             : !$OMP END PARALLEL
     206             : 
     207         234 :       CALL timestop(handle)
     208         468 :    END SUBROUTINE pao_param_linpot_regularizer
     209             : 
     210             : ! **************************************************************************************************
     211             : !> \brief Builds the preconditioner matrix_precon and matrix_precon_inv
     212             : !> \param pao ...
     213             : ! **************************************************************************************************
     214          12 :    SUBROUTINE pao_param_linpot_preconditioner(pao)
     215             :       TYPE(pao_env_type), POINTER                        :: pao
     216             : 
     217             :       CHARACTER(len=*), PARAMETER :: routineN = 'pao_param_linpot_preconditioner'
     218             : 
     219             :       INTEGER                                            :: acol, arow, handle, i, iatom, j, k, &
     220             :                                                             nterms
     221          12 :       INTEGER, DIMENSION(:), POINTER                     :: blk_sizes_nterms
     222             :       LOGICAL                                            :: found
     223             :       REAL(dp)                                           :: eval_capped
     224          12 :       REAL(dp), ALLOCATABLE, DIMENSION(:)                :: S_evals
     225          12 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: S, S_evecs
     226          12 :       REAL(dp), DIMENSION(:, :), POINTER                 :: block_precon, block_precon_inv, &
     227          12 :                                                             block_V_terms
     228             :       TYPE(dbcsr_iterator_type)                          :: iter
     229             : 
     230          12 :       CALL timeset(routineN, handle)
     231             : 
     232          12 :       IF (pao%iw > 0) WRITE (pao%iw, *) "PAO| Building linpot preconditioner"
     233             : 
     234          12 :       CALL dbcsr_get_info(pao%matrix_V_terms, col_blk_size=blk_sizes_nterms)
     235             : 
     236             :       CALL dbcsr_create(pao%matrix_precon, &
     237             :                         template=pao%matrix_V_terms, &
     238             :                         matrix_type="N", &
     239             :                         row_blk_size=blk_sizes_nterms, &
     240             :                         col_blk_size=blk_sizes_nterms, &
     241          12 :                         name="PAO matrix_precon")
     242          12 :       CALL dbcsr_reserve_diag_blocks(pao%matrix_precon)
     243             : 
     244          12 :       CALL dbcsr_create(pao%matrix_precon_inv, template=pao%matrix_precon, name="PAO matrix_precon_inv")
     245          12 :       CALL dbcsr_reserve_diag_blocks(pao%matrix_precon_inv)
     246             : 
     247             : !$OMP PARALLEL DEFAULT(NONE) SHARED(pao) &
     248          12 : !$OMP PRIVATE(iter,arow,acol,iatom,block_V_terms,block_precon,block_precon_inv,found,nterms,S,S_evals,S_evecs,i,j,k,eval_capped)
     249             :       CALL dbcsr_iterator_start(iter, pao%matrix_V_terms)
     250             :       DO WHILE (dbcsr_iterator_blocks_left(iter))
     251             :          CALL dbcsr_iterator_next_block(iter, arow, acol, block_V_terms)
     252             :          iatom = arow; CPASSERT(arow == acol)
     253             :          nterms = SIZE(block_V_terms, 2)
     254             :          IF (nterms == 0) CYCLE ! protect against corner-case of zero pao parameters
     255             : 
     256             :          CALL dbcsr_get_block_p(matrix=pao%matrix_precon, row=iatom, col=iatom, block=block_precon, found=found)
     257             :          CALL dbcsr_get_block_p(matrix=pao%matrix_precon_inv, row=iatom, col=iatom, block=block_precon_inv, found=found)
     258             :          CPASSERT(ASSOCIATED(block_precon))
     259             :          CPASSERT(ASSOCIATED(block_precon_inv))
     260             : 
     261             :          ALLOCATE (S(nterms, nterms))
     262             :          S(:, :) = MATMUL(TRANSPOSE(block_V_terms), block_V_terms)
     263             : 
     264             :          ! diagonalize S
     265             :          ALLOCATE (S_evals(nterms), S_evecs(nterms, nterms))
     266             :          S_evecs(:, :) = S
     267             :          CALL diamat_all(S_evecs, S_evals)
     268             : 
     269             :          ! construct 1/Sqrt(S) and Sqrt(S)
     270             :          block_precon = 0.0_dp
     271             :          block_precon_inv = 0.0_dp
     272             :          DO k = 1, nterms
     273             :             eval_capped = MAX(pao%linpot_precon_delta, S_evals(k)) ! too small eigenvalues are hurtful
     274             :             DO i = 1, nterms
     275             :             DO j = 1, nterms
     276             :                block_precon(i, j) = block_precon(i, j) + S_evecs(i, k)*S_evecs(j, k)/SQRT(eval_capped)
     277             :                block_precon_inv(i, j) = block_precon_inv(i, j) + S_evecs(i, k)*S_evecs(j, k)*SQRT(eval_capped)
     278             :             END DO
     279             :             END DO
     280             :          END DO
     281             : 
     282             :          DEALLOCATE (S, S_evecs, S_evals)
     283             :       END DO
     284             :       CALL dbcsr_iterator_stop(iter)
     285             : !$OMP END PARALLEL
     286             : 
     287          12 :       CALL timestop(handle)
     288          24 :    END SUBROUTINE pao_param_linpot_preconditioner
     289             : 
     290             : ! **************************************************************************************************
     291             : !> \brief Finalize the linear potential parametrization
     292             : !> \param pao ...
     293             : ! **************************************************************************************************
     294         234 :    SUBROUTINE pao_param_finalize_linpot(pao)
     295             :       TYPE(pao_env_type), POINTER                        :: pao
     296             : 
     297         234 :       CALL dbcsr_release(pao%matrix_V_terms)
     298         234 :       CALL dbcsr_release(pao%matrix_R)
     299             : 
     300         234 :       IF (pao%precondition) THEN
     301          12 :          CALL dbcsr_release(pao%matrix_precon)
     302          12 :          CALL dbcsr_release(pao%matrix_precon_inv)
     303             :       END IF
     304             : 
     305         234 :    END SUBROUTINE pao_param_finalize_linpot
     306             : 
     307             : ! **************************************************************************************************
     308             : !> \brief Returns the number of potential terms for given atomic kind
     309             : !> \param pao ...
     310             : !> \param qs_env ...
     311             : !> \param ikind ...
     312             : !> \param nparams ...
     313             : ! **************************************************************************************************
     314        1344 :    SUBROUTINE pao_param_count_linpot(pao, qs_env, ikind, nparams)
     315             :       TYPE(pao_env_type), POINTER                        :: pao
     316             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     317             :       INTEGER, INTENT(IN)                                :: ikind
     318             :       INTEGER, INTENT(OUT)                               :: nparams
     319             : 
     320             :       INTEGER                                            :: pao_basis_size
     321             :       TYPE(gto_basis_set_type), POINTER                  :: basis_set
     322         672 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     323             : 
     324         672 :       CALL get_qs_env(qs_env, qs_kind_set=qs_kind_set)
     325             : 
     326             :       CALL get_qs_kind(qs_kind_set(ikind), &
     327             :                        basis_set=basis_set, &
     328         672 :                        pao_basis_size=pao_basis_size)
     329             : 
     330         672 :       IF (pao_basis_size == basis_set%nsgf) THEN
     331          26 :          nparams = 0 ! pao disabled for iatom
     332             : 
     333             :       ELSE
     334         754 :          SELECT CASE (pao%parameterization)
     335             :          CASE (pao_fock_param)
     336         646 :             CALL linpot_full_count_terms(qs_env, ikind, nterms=nparams)
     337             :          CASE (pao_rotinv_param)
     338         538 :             CALL linpot_rotinv_count_terms(qs_env, ikind, nterms=nparams)
     339             :          CASE DEFAULT
     340         646 :             CPABORT("unknown parameterization")
     341             :          END SELECT
     342             :       END IF
     343             : 
     344         672 :    END SUBROUTINE pao_param_count_linpot
     345             : 
     346             : ! **************************************************************************************************
     347             : !> \brief Takes current matrix_X and calculates the matrices A and B.
     348             : !> \param pao ...
     349             : !> \param qs_env ...
     350             : !> \param ls_scf_env ...
     351             : !> \param gradient ...
     352             : !> \param penalty ...
     353             : !> \param forces ...
     354             : ! **************************************************************************************************
     355        8192 :    SUBROUTINE pao_calc_AB_linpot(pao, qs_env, ls_scf_env, gradient, penalty, forces)
     356             :       TYPE(pao_env_type), POINTER                        :: pao
     357             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     358             :       TYPE(ls_scf_env_type), TARGET                      :: ls_scf_env
     359             :       LOGICAL, INTENT(IN)                                :: gradient
     360             :       REAL(dp), INTENT(INOUT), OPTIONAL                  :: penalty
     361             :       REAL(dp), DIMENSION(:, :), INTENT(INOUT), OPTIONAL :: forces
     362             : 
     363             :       CHARACTER(len=*), PARAMETER :: routineN = 'pao_calc_AB_linpot'
     364             : 
     365             :       INTEGER                                            :: handle
     366        8192 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s
     367             :       TYPE(dbcsr_type)                                   :: matrix_M, matrix_U
     368             : 
     369        8192 :       CALL timeset(routineN, handle)
     370        8192 :       CALL get_qs_env(qs_env, matrix_s=matrix_s)
     371        8192 :       CALL dbcsr_create(matrix_U, matrix_type="N", dist=pao%diag_distribution, template=matrix_s(1)%matrix)
     372        8192 :       CALL dbcsr_reserve_diag_blocks(matrix_U)
     373             : 
     374             :       !TODO: move this condition into pao_calc_U, use matrix_N as template
     375        8192 :       IF (gradient) THEN
     376        1616 :          CALL pao_calc_grad_lnv_wrt_U(qs_env, ls_scf_env, matrix_M)
     377        3198 :          CALL pao_calc_U_linpot(pao, qs_env, matrix_U, matrix_M, pao%matrix_G, penalty, forces)
     378        1616 :          CALL dbcsr_release(matrix_M)
     379             :       ELSE
     380        6576 :          CALL pao_calc_U_linpot(pao, qs_env, matrix_U, penalty=penalty)
     381             :       END IF
     382             : 
     383        8192 :       CALL pao_calc_AB_from_U(pao, qs_env, ls_scf_env, matrix_U)
     384        8192 :       CALL dbcsr_release(matrix_U)
     385        8192 :       CALL timestop(handle)
     386        8192 :    END SUBROUTINE pao_calc_AB_linpot
     387             : 
     388             : ! **************************************************************************************************
     389             : !> \brief Calculate new matrix U and optinally its gradient G
     390             : !> \param pao ...
     391             : !> \param qs_env ...
     392             : !> \param matrix_U ...
     393             : !> \param matrix_M ...
     394             : !> \param matrix_G ...
     395             : !> \param penalty ...
     396             : !> \param forces ...
     397             : ! **************************************************************************************************
     398        8192 :    SUBROUTINE pao_calc_U_linpot(pao, qs_env, matrix_U, matrix_M, matrix_G, penalty, forces)
     399             :       TYPE(pao_env_type), POINTER                        :: pao
     400             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     401             :       TYPE(dbcsr_type)                                   :: matrix_U
     402             :       TYPE(dbcsr_type), OPTIONAL                         :: matrix_M, matrix_G
     403             :       REAL(dp), INTENT(INOUT), OPTIONAL                  :: penalty
     404             :       REAL(dp), DIMENSION(:, :), INTENT(INOUT), OPTIONAL :: forces
     405             : 
     406             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'pao_calc_U_linpot'
     407             : 
     408             :       INTEGER                                            :: acol, arow, handle, iatom, kterm, n, &
     409             :                                                             natoms, nterms
     410             :       LOGICAL                                            :: found
     411             :       REAL(dp), ALLOCATABLE, DIMENSION(:)                :: gaps
     412             :       REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: evals
     413        8192 :       REAL(dp), DIMENSION(:), POINTER                    :: vec_M2, vec_V
     414        8192 :       REAL(dp), DIMENSION(:, :), POINTER                 :: block_G, block_M1, block_M2, block_R, &
     415        8192 :                                                             block_U, block_V, block_V_terms, &
     416        8192 :                                                             block_X
     417        8192 :       REAL(dp), DIMENSION(:, :, :), POINTER              :: M_blocks
     418             :       REAL(KIND=dp)                                      :: regu_energy
     419             :       TYPE(dbcsr_iterator_type)                          :: iter
     420             :       TYPE(mp_comm_type)                                 :: group
     421             : 
     422        8192 :       CALL timeset(routineN, handle)
     423             : 
     424        8192 :       CPASSERT(PRESENT(matrix_G) .EQV. PRESENT(matrix_M))
     425             : 
     426        8192 :       CALL get_qs_env(qs_env, natom=natoms)
     427       40960 :       ALLOCATE (gaps(natoms), evals(10, natoms)) ! printing 10 eigenvalues seems reasonable
     428      244604 :       evals(:, :) = 0.0_dp
     429       29684 :       gaps(:) = HUGE(1.0_dp)
     430        8192 :       regu_energy = 0.0_dp
     431        8192 :       CALL dbcsr_get_info(matrix_U, group=group)
     432             : 
     433        8192 :       CALL dbcsr_iterator_start(iter, pao%matrix_X)
     434       18938 :       DO WHILE (dbcsr_iterator_blocks_left(iter))
     435       10746 :          CALL dbcsr_iterator_next_block(iter, arow, acol, block_X)
     436       10746 :          iatom = arow; CPASSERT(arow == acol)
     437       10746 :          CALL dbcsr_get_block_p(matrix=pao%matrix_R, row=iatom, col=iatom, block=block_R, found=found)
     438       10746 :          CALL dbcsr_get_block_p(matrix=matrix_U, row=iatom, col=iatom, block=block_U, found=found)
     439       10746 :          CPASSERT(ASSOCIATED(block_R) .AND. ASSOCIATED(block_U))
     440       10746 :          n = SIZE(block_U, 1)
     441             : 
     442             :          ! calculate potential V
     443       32238 :          ALLOCATE (vec_V(n*n))
     444      647165 :          vec_V(:) = 0.0_dp
     445       10746 :          CALL dbcsr_get_block_p(matrix=pao%matrix_V_terms, row=iatom, col=iatom, block=block_V_terms, found=found)
     446       10746 :          CPASSERT(ASSOCIATED(block_V_terms))
     447       10746 :          nterms = SIZE(block_V_terms, 2)
     448       10746 :          IF (nterms > 0) & ! protect against corner-case of zero pao parameters
     449    71735320 :             vec_V = MATMUL(block_V_terms, block_X(:, 1))
     450       10746 :          block_V(1:n, 1:n) => vec_V(:) ! map vector into matrix
     451             : 
     452             :          ! symmetrize
     453     1431894 :          IF (MAXVAL(ABS(block_V - TRANSPOSE(block_V))/MAX(1.0_dp, MAXVAL(ABS(block_V)))) > 1e-12) &
     454           0 :             CPABORT("block_V not symmetric")
     455     1442640 :          block_V = 0.5_dp*(block_V + TRANSPOSE(block_V)) ! symmetrize exactly
     456             : 
     457             :          ! regularization energy
     458             :          ! protect against corner-case of zero pao parameters
     459       10746 :          IF (PRESENT(penalty) .AND. nterms > 0) &
     460    30347076 :             regu_energy = regu_energy + DOT_PRODUCT(block_X(:, 1), MATMUL(block_R, block_X(:, 1)))
     461             : 
     462             :          CALL pao_calc_U_block_fock(pao, iatom=iatom, penalty=penalty, V=block_V, U=block_U, &
     463       10746 :                                     gap=gaps(iatom), evals=evals(:, iatom))
     464             : 
     465       10746 :          IF (PRESENT(matrix_G)) THEN ! TURNING POINT (if calc grad) --------------------------------
     466        2132 :             CPASSERT(PRESENT(matrix_M))
     467        2132 :             CALL dbcsr_get_block_p(matrix=matrix_M, row=iatom, col=iatom, block=block_M1, found=found)
     468             : 
     469             :             ! corner-cases: block_M1 might have been filtered out or there might be zero pao parameters
     470        6396 :             IF (ASSOCIATED(block_M1) .AND. SIZE(block_V_terms) > 0) THEN
     471        4038 :                ALLOCATE (vec_M2(n*n))
     472        2019 :                block_M2(1:n, 1:n) => vec_M2(:) ! map vector into matrix
     473             :                !TODO: this 2nd call does double work. However, *sometimes* this branch is not taken.
     474             :                CALL pao_calc_U_block_fock(pao, iatom=iatom, penalty=penalty, V=block_V, U=block_U, &
     475        2019 :                                           M1=block_M1, G=block_M2, gap=gaps(iatom), evals=evals(:, iatom))
     476      124173 :                IF (MAXVAL(ABS(block_M2 - TRANSPOSE(block_M2))) > 1e-14_dp) &
     477           0 :                   CPABORT("matrix not symmetric")
     478             : 
     479             :                ! gradient dE/dX
     480        2019 :                IF (PRESENT(matrix_G)) THEN
     481        2019 :                   CALL dbcsr_get_block_p(matrix=matrix_G, row=iatom, col=iatom, block=block_G, found=found)
     482        2019 :                   CPASSERT(ASSOCIATED(block_G))
     483     6582106 :                   block_G(:, 1) = MATMUL(vec_M2, block_V_terms)
     484        2019 :                   IF (PRESENT(penalty)) &
     485    10731904 :                      block_G = block_G + 2.0_dp*MATMUL(block_R, block_X) ! regularization gradient
     486             :                END IF
     487             : 
     488             :                ! forced dE/dR
     489        2019 :                IF (PRESENT(forces)) THEN
     490         170 :                   ALLOCATE (M_blocks(n, n, nterms))
     491         296 :                   DO kterm = 1, nterms
     492       16806 :                      M_blocks(:, :, kterm) = block_M2*block_X(kterm, 1)
     493             :                   END DO
     494          34 :                   CALL linpot_calc_forces(pao, qs_env, iatom=iatom, M_blocks=M_blocks, forces=forces)
     495          34 :                   DEALLOCATE (M_blocks)
     496             :                END IF
     497             : 
     498        2019 :                DEALLOCATE (vec_M2)
     499             :             END IF
     500             :          END IF
     501       51176 :          DEALLOCATE (vec_V)
     502             :       END DO
     503        8192 :       CALL dbcsr_iterator_stop(iter)
     504             : 
     505        8192 :       IF (PRESENT(penalty)) THEN
     506             :          ! sum penalty energies across ranks
     507        7924 :          CALL group%sum(penalty)
     508        7924 :          CALL group%sum(regu_energy)
     509        7924 :          penalty = penalty + regu_energy
     510             :       END IF
     511             : 
     512             :       ! print stuff, but not during second invocation for forces
     513        8192 :       IF (.NOT. PRESENT(forces)) THEN
     514             :          ! print eigenvalues from fock-layer
     515        8158 :          CALL group%sum(evals)
     516        8158 :          IF (pao%iw_fockev > 0) THEN
     517        2000 :             DO iatom = 1, natoms
     518        2000 :                WRITE (pao%iw_fockev, *) "PAO| atom:", iatom, " fock evals around gap:", evals(:, iatom)
     519             :             END DO
     520         500 :             CALL m_flush(pao%iw_fockev)
     521             :          END IF
     522             :          ! print homo-lumo gap encountered by fock-layer
     523        8158 :          CALL group%min(gaps)
     524        8158 :          IF (pao%iw_gap > 0) THEN
     525        2000 :             DO iatom = 1, natoms
     526        2000 :                WRITE (pao%iw_gap, *) "PAO| atom:", iatom, " fock gap:", gaps(iatom)
     527             :             END DO
     528             :          END IF
     529             :          ! one-line summaries
     530        8158 :          IF (pao%iw > 0) WRITE (pao%iw, *) "PAO| linpot regularization energy:", regu_energy
     531       37738 :          IF (pao%iw > 0) WRITE (pao%iw, "(A,E20.10,A,T71,I10)") " PAO| min_gap:", MINVAL(gaps), " for atom:", MINLOC(gaps)
     532             :       END IF
     533             : 
     534        8192 :       DEALLOCATE (gaps, evals)
     535        8192 :       CALL timestop(handle)
     536             : 
     537       16384 :    END SUBROUTINE pao_calc_U_linpot
     538             : 
     539             : ! **************************************************************************************************
     540             : !> \brief Internal routine, calculates terms in potential parametrization
     541             : !> \param pao ...
     542             : !> \param qs_env ...
     543             : !> \param iatom ...
     544             : !> \param V_blocks ...
     545             : ! **************************************************************************************************
     546         234 :    SUBROUTINE linpot_calc_terms(pao, qs_env, iatom, V_blocks)
     547             :       TYPE(pao_env_type), POINTER                        :: pao
     548             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     549             :       INTEGER, INTENT(IN)                                :: iatom
     550             :       REAL(dp), DIMENSION(:, :, :), INTENT(OUT)          :: V_blocks
     551             : 
     552         273 :       SELECT CASE (pao%parameterization)
     553             :       CASE (pao_fock_param)
     554          39 :          CALL linpot_full_calc_terms(V_blocks)
     555             :       CASE (pao_rotinv_param)
     556         195 :          CALL linpot_rotinv_calc_terms(qs_env, iatom, V_blocks)
     557             :       CASE DEFAULT
     558         234 :          CPABORT("unknown parameterization")
     559             :       END SELECT
     560             : 
     561         234 :    END SUBROUTINE linpot_calc_terms
     562             : 
     563             : ! **************************************************************************************************
     564             : !> \brief Internal routine, calculates force contributions from potential parametrization
     565             : !> \param pao ...
     566             : !> \param qs_env ...
     567             : !> \param iatom ...
     568             : !> \param M_blocks ...
     569             : !> \param forces ...
     570             : ! **************************************************************************************************
     571          34 :    SUBROUTINE linpot_calc_forces(pao, qs_env, iatom, M_blocks, forces)
     572             :       TYPE(pao_env_type), POINTER                        :: pao
     573             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     574             :       INTEGER, INTENT(IN)                                :: iatom
     575             :       REAL(dp), DIMENSION(:, :, :), INTENT(IN)           :: M_blocks
     576             :       REAL(dp), DIMENSION(:, :), INTENT(INOUT)           :: forces
     577             : 
     578          66 :       SELECT CASE (pao%parameterization)
     579             :       CASE (pao_fock_param)
     580             :          ! no force contributions
     581             :       CASE (pao_rotinv_param)
     582          32 :          CALL linpot_rotinv_calc_forces(qs_env, iatom, M_blocks, forces)
     583             :       CASE DEFAULT
     584          34 :          CPABORT("unknown parameterization")
     585             :       END SELECT
     586             : 
     587          34 :    END SUBROUTINE linpot_calc_forces
     588             : 
     589             : ! **************************************************************************************************
     590             : !> \brief Calculate initial guess for matrix_X
     591             : !> \param pao ...
     592             : !> \param qs_env ...
     593             : ! **************************************************************************************************
     594          34 :    SUBROUTINE pao_param_initguess_linpot(pao, qs_env)
     595             :       TYPE(pao_env_type), POINTER                        :: pao
     596             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     597             : 
     598             :       CHARACTER(len=*), PARAMETER :: routineN = 'pao_param_initguess_linpot'
     599             : 
     600             :       INTEGER                                            :: acol, arow, handle, i, iatom, j, k, n, &
     601             :                                                             nterms
     602          34 :       INTEGER, DIMENSION(:), POINTER                     :: pri_basis_size
     603             :       LOGICAL                                            :: found
     604             :       REAL(dp)                                           :: w
     605          34 :       REAL(dp), ALLOCATABLE, DIMENSION(:)                :: S_evals
     606          34 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: S, S_evecs, S_inv
     607          34 :       REAL(dp), DIMENSION(:), POINTER                    :: V_guess_vec
     608          34 :       REAL(dp), DIMENSION(:, :), POINTER                 :: block_X, V_guess, V_terms
     609             :       TYPE(dbcsr_iterator_type)                          :: iter
     610             : 
     611          34 :       CALL timeset(routineN, handle)
     612             : 
     613          34 :       CALL dbcsr_get_info(pao%matrix_Y, row_blk_size=pri_basis_size)
     614             : 
     615             : !$OMP PARALLEL DEFAULT(NONE) SHARED(pao,qs_env,pri_basis_size) &
     616          34 : !$OMP PRIVATE(iter,arow,acol,iatom,block_X,N,nterms,V_terms,found,V_guess,V_guess_vec,S,S_evecs,S_evals,S_inv,k,i,j,w)
     617             :       CALL dbcsr_iterator_start(iter, pao%matrix_X)
     618             :       DO WHILE (dbcsr_iterator_blocks_left(iter))
     619             :          CALL dbcsr_iterator_next_block(iter, arow, acol, block_X)
     620             :          iatom = arow; CPASSERT(arow == acol)
     621             :          CALL dbcsr_get_block_p(matrix=pao%matrix_V_terms, row=iatom, col=iatom, block=V_terms, found=found)
     622             :          CPASSERT(ASSOCIATED(V_terms))
     623             :          nterms = SIZE(V_terms, 2)
     624             :          IF (nterms == 0) CYCLE ! protect against corner-case of zero pao parameters
     625             : 
     626             :          ! guess initial potential
     627             :          N = pri_basis_size(iatom)
     628             :          ALLOCATE (V_guess_vec(n*n))
     629             :          V_guess(1:n, 1:n) => V_guess_vec
     630             :          CALL pao_guess_initial_potential(qs_env, iatom, V_guess)
     631             : 
     632             :          ! build overlap matrix
     633             :          ALLOCATE (S(nterms, nterms))
     634             :          S(:, :) = MATMUL(TRANSPOSE(V_terms), V_terms)
     635             : 
     636             :          ! diagonalize S
     637             :          ALLOCATE (S_evals(nterms), S_evecs(nterms, nterms))
     638             :          S_evecs(:, :) = S
     639             :          CALL diamat_all(S_evecs, S_evals)
     640             : 
     641             :          ! calculate Tikhonov regularized inverse
     642             :          ALLOCATE (S_inv(nterms, nterms))
     643             :          S_inv(:, :) = 0.0_dp
     644             :          DO k = 1, nterms
     645             :             w = S_evals(k)/(S_evals(k)**2 + pao%linpot_init_delta)
     646             :             DO i = 1, nterms
     647             :             DO j = 1, nterms
     648             :                S_inv(i, j) = S_inv(i, j) + w*S_evecs(i, k)*S_evecs(j, k)
     649             :             END DO
     650             :             END DO
     651             :          END DO
     652             : 
     653             :          ! perform fit
     654             :          block_X(:, 1) = MATMUL(MATMUL(S_inv, TRANSPOSE(V_terms)), V_guess_vec)
     655             : 
     656             :          ! clean up
     657             :          DEALLOCATE (V_guess_vec, S, S_evecs, S_evals, S_inv)
     658             :       END DO
     659             :       CALL dbcsr_iterator_stop(iter)
     660             : !$OMP END PARALLEL
     661             : 
     662          34 :       CALL timestop(handle)
     663          68 :    END SUBROUTINE pao_param_initguess_linpot
     664             : 
     665       24204 : END MODULE pao_param_linpot

Generated by: LCOV version 1.15