LCOV - code coverage report
Current view: top level - src - atom_optimization.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:2fce0f8) Lines: 89 94 94.7 %
Date: 2024-12-21 06:28:57 Functions: 4 6 66.7 %

          Line data    Source code
       1             : !--------------------------------------------------------------------------------------------------!
       2             : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3             : !   Copyright 2000-2024 CP2K developers group <https://cp2k.org>                                   !
       4             : !                                                                                                  !
       5             : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6             : !--------------------------------------------------------------------------------------------------!
       7             : 
       8             : ! **************************************************************************************************
       9             : !> \brief Optimizer for the atomic code
      10             : ! **************************************************************************************************
      11             : MODULE atom_optimization
      12             :    USE atom_types,                      ONLY: atom_optimization_type
      13             :    USE kinds,                           ONLY: dp
      14             :    USE lapack,                          ONLY: lapack_sgelss
      15             : #include "./base/base_uses.f90"
      16             : 
      17             :    IMPLICIT NONE
      18             : 
      19             :    PRIVATE
      20             : 
      21             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'atom_optimization'
      22             : 
      23             :    TYPE hmat_type
      24             :       REAL(dp)                                  :: energy = 0.0_dp
      25             :       REAL(dp)                                  :: error = 0.0_dp
      26             :       REAL(dp), DIMENSION(:, :, :), POINTER     :: emat => NULL()
      27             :       REAL(dp), DIMENSION(:, :, :), POINTER     :: fmat => NULL()
      28             :       REAL(dp), DIMENSION(:, :, :), POINTER     :: pmat => NULL()
      29             :    END TYPE hmat_type
      30             : 
      31             :    TYPE atom_history_type
      32             :       INTEGER                                  :: max_history = 0
      33             :       INTEGER                                  :: hlen = 0
      34             :       INTEGER                                  :: hpos = 0
      35             :       REAL(dp)                                 :: damping = 0.0_dp
      36             :       REAL(dp)                                 :: eps_diis = 0.0_dp
      37             :       REAL(dp), DIMENSION(:, :), POINTER       :: dmat => NULL()
      38             :       TYPE(hmat_type), DIMENSION(:), POINTER   :: hmat => NULL()
      39             :    END TYPE atom_history_type
      40             : 
      41             :    PUBLIC :: atom_opt_fmat, &
      42             :              atom_history_type, atom_history_init, atom_history_update, atom_history_release
      43             : 
      44             : CONTAINS
      45             : 
      46             : ! **************************************************************************************************
      47             : !> \brief Initialise a circular buffer to keep Kohn-Sham and density matrices from previous iteration.
      48             : !> \param history       object to initialise
      49             : !> \param optimization  optimisation parameters
      50             : !> \param matrix        reference matrix. Historic matrices will have the same size as
      51             : !>                      this reference matrix
      52             : !> \par History
      53             : !>    * 08.2016 new structure element: density matrix [Juerg Hutter]
      54             : !>    * 08.2008 created [Juerg Hutter]
      55             : ! **************************************************************************************************
      56       11429 :    PURE SUBROUTINE atom_history_init(history, optimization, matrix)
      57             :       TYPE(atom_history_type), INTENT(INOUT)             :: history
      58             :       TYPE(atom_optimization_type), INTENT(IN)           :: optimization
      59             :       REAL(dp), DIMENSION(:, :, :), INTENT(IN)           :: matrix
      60             : 
      61             :       INTEGER                                            :: i, n1, n2, n3, ndiis
      62             :       REAL(dp)                                           :: damp, eps
      63             : 
      64       11429 :       ndiis = optimization%n_diis
      65       11429 :       eps = optimization%eps_diis
      66       11429 :       damp = optimization%damping
      67             : 
      68       11429 :       CALL atom_history_release(history)
      69             : 
      70       11429 :       history%max_history = ndiis
      71       11429 :       history%hlen = 0
      72       11429 :       history%hpos = 0
      73       11429 :       history%damping = damp
      74       11429 :       history%eps_diis = eps
      75       45716 :       ALLOCATE (history%dmat(ndiis + 1, ndiis + 1))
      76             : 
      77       91434 :       ALLOCATE (history%hmat(ndiis))
      78       11429 :       n1 = SIZE(matrix, 1)
      79       11429 :       n2 = SIZE(matrix, 2)
      80       11429 :       n3 = SIZE(matrix, 3)
      81       68576 :       DO i = 1, ndiis
      82       57147 :          history%hmat(i)%energy = 0.0_dp
      83       57147 :          history%hmat(i)%error = 0.0_dp
      84      285695 :          ALLOCATE (history%hmat(i)%emat(n1, n2, n3))
      85      228548 :          ALLOCATE (history%hmat(i)%fmat(n1, n2, n3))
      86      239977 :          ALLOCATE (history%hmat(i)%pmat(n1, n2, n3))
      87             :       END DO
      88             : 
      89       11429 :    END SUBROUTINE atom_history_init
      90             : 
      91             : ! **************************************************************************************************
      92             : !> \brief Add matrices from the current iteration into the circular buffer.
      93             : !> \param history  object to keep historic matrices
      94             : !> \param pmat     density matrix
      95             : !> \param fmat     Kohn-Sham matrix
      96             : !> \param emat     error matrix
      97             : !> \param energy   total energy
      98             : !> \param error    convergence
      99             : !> \par History
     100             : !>    * 08.2016 new formal argument: density matrix [Juerg Hutter]
     101             : !>    * 08.2008 created [Juerg Hutter]
     102             : ! **************************************************************************************************
     103       66822 :    PURE SUBROUTINE atom_history_update(history, pmat, fmat, emat, energy, error)
     104             :       TYPE(atom_history_type), INTENT(INOUT)             :: history
     105             :       REAL(dp), DIMENSION(:, :, :), INTENT(IN)           :: pmat, fmat, emat
     106             :       REAL(dp), INTENT(IN)                               :: energy, error
     107             : 
     108             :       INTEGER                                            :: nlen, nmax, nnow
     109             : 
     110       66822 :       nmax = history%max_history
     111       66822 :       nlen = MIN(history%hlen + 1, nmax)
     112       66822 :       nnow = history%hpos + 1
     113       66822 :       IF (nnow > nmax) nnow = 1
     114             : 
     115       66822 :       history%hmat(nnow)%energy = energy
     116       66822 :       history%hmat(nnow)%error = error
     117    34412646 :       history%hmat(nnow)%pmat = pmat
     118    34412646 :       history%hmat(nnow)%fmat = fmat
     119    34412646 :       history%hmat(nnow)%emat = emat
     120             : 
     121       66822 :       history%hlen = nlen
     122       66822 :       history%hpos = nnow
     123             : 
     124       66822 :    END SUBROUTINE atom_history_update
     125             : 
     126             : ! **************************************************************************************************
     127             : !> \brief Release circular buffer to keep historic matrices.
     128             : !> \param history  object to release
     129             : !> \par History
     130             : !>    * 08.2008 created [Juerg Hutter]
     131             : ! **************************************************************************************************
     132       22858 :    PURE SUBROUTINE atom_history_release(history)
     133             :       TYPE(atom_history_type), INTENT(INOUT)             :: history
     134             : 
     135             :       INTEGER                                            :: i
     136             : 
     137       22858 :       history%max_history = 0
     138       22858 :       history%hlen = 0
     139       22858 :       history%hpos = 0
     140       22858 :       history%damping = 0._dp
     141       22858 :       history%eps_diis = 0._dp
     142       22858 :       IF (ASSOCIATED(history%dmat)) THEN
     143       11429 :          DEALLOCATE (history%dmat)
     144             :       END IF
     145       22858 :       IF (ASSOCIATED(history%hmat)) THEN
     146       68576 :          DO i = 1, SIZE(history%hmat)
     147       57147 :             IF (ASSOCIATED(history%hmat(i)%emat)) THEN
     148       57147 :                DEALLOCATE (history%hmat(i)%emat)
     149             :             END IF
     150       57147 :             IF (ASSOCIATED(history%hmat(i)%fmat)) THEN
     151       57147 :                DEALLOCATE (history%hmat(i)%fmat)
     152             :             END IF
     153       68576 :             IF (ASSOCIATED(history%hmat(i)%pmat)) THEN
     154       57147 :                DEALLOCATE (history%hmat(i)%pmat)
     155             :             END IF
     156             :          END DO
     157       11429 :          DEALLOCATE (history%hmat)
     158             :       END IF
     159             : 
     160       22858 :    END SUBROUTINE atom_history_release
     161             : 
     162             : ! **************************************************************************************************
     163             : !> \brief Construct a Kohn-Sham matrix for the next iteration based on the historic data.
     164             : !> \param fmat     new Kohn-Sham matrix
     165             : !> \param history  historic matrices
     166             : !> \param err      convergence
     167             : !> \par History
     168             : !>    * 08.2016 renamed to atom_opt_fmat() [Juerg Hutter]
     169             : !>    * 08.2008 created as atom_opt() [Juerg Hutter]
     170             : ! **************************************************************************************************
     171       66822 :    SUBROUTINE atom_opt_fmat(fmat, history, err)
     172             :       REAL(dp), DIMENSION(:, :, :), INTENT(INOUT)        :: fmat
     173             :       TYPE(atom_history_type), INTENT(INOUT)             :: history
     174             :       REAL(dp), INTENT(IN)                               :: err
     175             : 
     176             :       INTEGER                                            :: i, info, j, lwork, na, nb, nlen, nm, &
     177             :                                                             nmax, nnow, rank
     178             :       REAL(dp)                                           :: a, rcond, t
     179       66822 :       REAL(dp), ALLOCATABLE, DIMENSION(:)                :: s, work
     180       66822 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: vec
     181             : 
     182       66822 :       nmax = history%max_history
     183       66822 :       nnow = history%hpos
     184       66822 :       a = history%damping
     185       66822 :       IF (history%hlen > 1) THEN
     186       57573 :          IF (err < history%eps_diis) THEN
     187             :             ! DIIS
     188       57573 :             rcond = 1.e-10_dp
     189       57573 :             lwork = 25*nmax
     190      460584 :             ALLOCATE (vec(nmax + 1, 2), s(nmax + 1), work(lwork))
     191             :             nlen = history%hlen
     192      863619 :             vec = 0._dp
     193       57573 :             vec(nlen + 1, 1) = 1._dp
     194      298790 :             history%dmat(1:nlen, nlen + 1) = 1._dp
     195      298790 :             history%dmat(nlen + 1, 1:nlen) = 1._dp
     196       57573 :             history%dmat(nlen + 1, nlen + 1) = 0._dp
     197      298790 :             DO i = 1, nlen
     198      241217 :                na = nnow + 1 - i
     199      241217 :                IF (na < 1) na = nmax + na
     200      963524 :                DO j = i, nlen
     201      664734 :                   nb = nnow + 1 - j
     202      664734 :                   IF (nb < 1) nb = nmax + nb
     203   374799306 :                   t = SUM(history%hmat(na)%emat*history%hmat(nb)%emat)
     204      664734 :                   history%dmat(i, j) = t
     205      905951 :                   history%dmat(j, i) = t
     206             :                END DO
     207             :             END DO
     208             :             CALL lapack_sgelss(nlen + 1, nlen + 1, 1, history%dmat, nmax + 1, vec, nmax + 1, s, &
     209       57573 :                                rcond, rank, work, lwork, info)
     210       57573 :             CPASSERT(info == 0)
     211    30910299 :             fmat = 0._dp
     212      298790 :             DO i = 1, nlen
     213      241217 :                na = nnow + 1 - i
     214      241217 :                IF (na < 1) na = nmax + na
     215   134058248 :                fmat = fmat + vec(i, 1)*history%hmat(na)%fmat
     216             :             END DO
     217             : 
     218       57573 :             DEALLOCATE (vec, s, work)
     219             :          ELSE
     220             :             ! damping
     221           0 :             nm = nnow - 1
     222           0 :             IF (nm < 1) nm = history%max_history
     223           0 :             fmat = a*history%hmat(nnow)%fmat + (1._dp - a)*history%hmat(nm)%fmat
     224             :          END IF
     225        9249 :       ELSEIF (history%hlen == 1) THEN
     226     3502347 :          fmat = history%hmat(nnow)%fmat
     227             :       ELSE
     228           0 :          CPABORT("")
     229             :       END IF
     230             : 
     231       66822 :    END SUBROUTINE atom_opt_fmat
     232             : 
     233           0 : END MODULE atom_optimization

Generated by: LCOV version 1.15