LCOV - code coverage report
Current view: top level - src - dm_ls_scf_curvy.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:21ef868) Lines: 97.4 % 349 340
Test Date: 2026-08-14 07:04:57 Functions: 100.0 % 13 13

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief density matrix optimization using exponential transformations
      10              : !> \par History
      11              : !>       2012.05 created [Florian Schiffmann]
      12              : !> \author Florian Schiffmann
      13              : ! **************************************************************************************************
      14              : 
      15              : MODULE dm_ls_scf_curvy
      16              :    USE bibliography,                    ONLY: Shao2003,&
      17              :                                               cite_reference
      18              :    USE cp_dbcsr_api,                    ONLY: &
      19              :         dbcsr_add, dbcsr_copy, dbcsr_create, dbcsr_filter, dbcsr_multiply, dbcsr_release, &
      20              :         dbcsr_scale, dbcsr_set, dbcsr_transposed, dbcsr_type, dbcsr_type_no_symmetry
      21              :    USE cp_dbcsr_contrib,                ONLY: dbcsr_dot,&
      22              :                                               dbcsr_frobenius_norm
      23              :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      24              :                                               cp_logger_get_default_unit_nr,&
      25              :                                               cp_logger_type
      26              :    USE dm_ls_scf_types,                 ONLY: ls_scf_curvy_type,&
      27              :                                               ls_scf_env_type
      28              :    USE input_constants,                 ONLY: ls_scf_line_search_3point,&
      29              :                                               ls_scf_line_search_3point_2d
      30              :    USE iterate_matrix,                  ONLY: purify_mcweeny
      31              :    USE kinds,                           ONLY: dp
      32              :    USE machine,                         ONLY: m_flush
      33              :    USE mathconstants,                   ONLY: ifac
      34              :    USE mathlib,                         ONLY: invmat
      35              : #include "./base/base_uses.f90"
      36              : 
      37              :    IMPLICIT NONE
      38              : 
      39              :    PRIVATE
      40              : 
      41              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'dm_ls_scf_curvy'
      42              : 
      43              :    PUBLIC :: dm_ls_curvy_optimization, deallocate_curvy_data
      44              : 
      45              : CONTAINS
      46              : 
      47              : ! **************************************************************************************************
      48              : !> \brief driver routine for Head-Gordon curvy step approach
      49              : !> \param ls_scf_env ...
      50              : !> \param energy ...
      51              : !> \param check_conv ...
      52              : !> \par History
      53              : !>       2012.05 created [Florian Schiffmann]
      54              : !> \author Florian Schiffmann
      55              : ! **************************************************************************************************
      56              : 
      57           90 :    SUBROUTINE dm_ls_curvy_optimization(ls_scf_env, energy, check_conv)
      58              :       TYPE(ls_scf_env_type)                              :: ls_scf_env
      59              :       REAL(KIND=dp)                                      :: energy
      60              :       LOGICAL                                            :: check_conv
      61              : 
      62              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'dm_ls_curvy_optimization'
      63              : 
      64              :       INTEGER                                            :: handle, i, lsstep
      65              : 
      66           90 :       CALL timeset(routineN, handle)
      67              : 
      68           90 :       CALL cite_reference(Shao2003)
      69              : 
      70              : ! Upon first call initialize all matrices needed curing optimization
      71              : ! In addition transform P into orthonormal basis. Will be scaled by 0.5 in closed shell case
      72              : ! Only to be done once as it will be stored and reused afterwards
      73              : ! TRS4 might yield a non-idempotent P therefore McWeeny purification is applied on initial P
      74              : 
      75           90 :       IF (.NOT. ALLOCATED(ls_scf_env%curvy_data%matrix_dp)) THEN
      76           18 :          CALL init_curvy(ls_scf_env%curvy_data, ls_scf_env%matrix_s, ls_scf_env%nspins)
      77           18 :          ls_scf_env%curvy_data%line_search_step = 1
      78              : 
      79           18 :          IF (ls_scf_env%curvy_data%line_search_type == ls_scf_line_search_3point_2d) THEN
      80            6 :             DO i = 1, ls_scf_env%nspins
      81              :                CALL dbcsr_copy(ls_scf_env%curvy_data%matrix_psave(i, 1), &
      82            6 :                                ls_scf_env%matrix_p(i))
      83              :             END DO
      84              :          END IF
      85           18 :          IF (ls_scf_env%nspins == 1) CALL dbcsr_scale(ls_scf_env%matrix_p(1), 0.5_dp)
      86              :          CALL transform_matrix_orth(ls_scf_env%matrix_p, ls_scf_env%matrix_s_sqrt, &
      87           18 :                                     ls_scf_env%eps_filter)
      88           18 :          CALL purify_mcweeny(ls_scf_env%matrix_p, ls_scf_env%eps_filter, 3)
      89           38 :          DO i = 1, ls_scf_env%nspins
      90           38 :             CALL dbcsr_copy(ls_scf_env%curvy_data%matrix_p(i), ls_scf_env%matrix_p(i))
      91              :          END DO
      92              :       END IF
      93              : 
      94           90 :       lsstep = ls_scf_env%curvy_data%line_search_step
      95              : 
      96              : ! If new search direction has to be computed transform H into the orthnormal basis
      97              : 
      98           90 :       IF (ls_scf_env%curvy_data%line_search_step == 1) THEN
      99              :          CALL transform_matrix_orth(ls_scf_env%matrix_ks, ls_scf_env%matrix_s_sqrt_inv, &
     100           28 :                                     ls_scf_env%eps_filter)
     101              :       END IF
     102              : 
     103              : ! Set the energies for the line search and make sure to give the correct energy back to scf_main
     104           90 :       ls_scf_env%curvy_data%energies(lsstep) = energy
     105           90 :       IF (lsstep /= 1) energy = ls_scf_env%curvy_data%energies(1)
     106              : 
     107              : ! start the optimization by calling the driver routine or simply combine saved P(2D line search)
     108           90 :       IF (lsstep <= 2) THEN
     109           56 :          CALL optimization_step(ls_scf_env%curvy_data, ls_scf_env)
     110           34 :       ELSE IF (lsstep == ls_scf_env%curvy_data%line_search_type) THEN
     111              : ! line_search type has the value appropriate to the number of energy calculations needed
     112           28 :          CALL optimization_step(ls_scf_env%curvy_data, ls_scf_env)
     113              :       ELSE
     114              :          CALL new_p_from_save(ls_scf_env%matrix_p, ls_scf_env%curvy_data%matrix_psave, lsstep, &
     115            6 :                               ls_scf_env%curvy_data%double_step_size)
     116            6 :          ls_scf_env%curvy_data%line_search_step = ls_scf_env%curvy_data%line_search_step + 1
     117            6 :          CALL timestop(handle)
     118            6 :          RETURN
     119              :       END IF
     120           84 :       lsstep = ls_scf_env%curvy_data%line_search_step
     121              : 
     122              : ! transform new density matrix back into nonorthonormal basis (again scaling might apply)
     123              : 
     124              :       CALL transform_matrix_orth(ls_scf_env%matrix_p, ls_scf_env%matrix_s_sqrt_inv, &
     125           84 :                                  ls_scf_env%eps_filter)
     126           84 :       IF (ls_scf_env%nspins == 1) CALL dbcsr_scale(ls_scf_env%matrix_p(1), 2.0_dp)
     127              : 
     128              : ! P-matrices only need to be stored in case of 2D line search
     129           84 :       IF (lsstep <= 3 .AND. ls_scf_env%curvy_data%line_search_type == ls_scf_line_search_3point_2d) THEN
     130           18 :          DO i = 1, ls_scf_env%nspins
     131              :             CALL dbcsr_copy(ls_scf_env%curvy_data%matrix_psave(i, lsstep), &
     132           18 :                             ls_scf_env%matrix_p(i))
     133              :          END DO
     134              :       END IF
     135           84 :       check_conv = lsstep == 1
     136              : 
     137           84 :       CALL timestop(handle)
     138              : 
     139              :    END SUBROUTINE dm_ls_curvy_optimization
     140              : 
     141              : ! **************************************************************************************************
     142              : !> \brief low level routine for Head-Gordons curvy step approach
     143              : !>        computes gradients, performs a cg and line search,
     144              : !>        and evaluates the BCH series to obtain the new P matrix
     145              : !> \param curvy_data ...
     146              : !> \param ls_scf_env ...
     147              : !> \par History
     148              : !>       2012.05 created [Florian Schiffmann]
     149              : !> \author Florian Schiffmann
     150              : ! **************************************************************************************************
     151              : 
     152           84 :    SUBROUTINE optimization_step(curvy_data, ls_scf_env)
     153              :       TYPE(ls_scf_curvy_type)                            :: curvy_data
     154              :       TYPE(ls_scf_env_type)                              :: ls_scf_env
     155              : 
     156              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'optimization_step'
     157              : 
     158              :       INTEGER                                            :: handle, ispin
     159              :       REAL(KIND=dp)                                      :: filter, step_size(2)
     160              : 
     161              : ! Upon first line search step compute new search direction and apply CG if required
     162              : 
     163           84 :       CALL timeset(routineN, handle)
     164              : 
     165           84 :       IF (curvy_data%line_search_step == 1) THEN
     166          168 :          curvy_data%step_size = MAXVAL(curvy_data%step_size)
     167           84 :          curvy_data%step_size = MIN(MAX(0.10_dp, 0.5_dp*ABS(curvy_data%step_size(1))), 0.5_dp)
     168              : ! Dynamic eps_filter for newton steps
     169              :          filter = MAX(ls_scf_env%eps_filter*curvy_data%min_filter, &
     170           28 :                       ls_scf_env%eps_filter*curvy_data%filter_factor)
     171              :          CALL compute_direction_newton(curvy_data%matrix_p, ls_scf_env%matrix_ks, &
     172              :                                        curvy_data%matrix_dp, filter, curvy_data%fix_shift, curvy_data%shift, &
     173           28 :                                        curvy_data%cg_numer, curvy_data%cg_denom, curvy_data%min_shift)
     174           28 :          curvy_data%filter_factor = curvy_data%scale_filter*curvy_data%filter_factor
     175           84 :          step_size = curvy_data%step_size
     176           84 :          curvy_data%BCH_saved = 0
     177           56 :       ELSE IF (curvy_data%line_search_step == 2) THEN
     178           84 :          step_size = curvy_data%step_size
     179           28 :          IF (curvy_data%energies(1) - curvy_data%energies(2) > 0.0_dp) THEN
     180           72 :             curvy_data%step_size = curvy_data%step_size*2.0_dp
     181           24 :             curvy_data%double_step_size = .TRUE.
     182              :          ELSE
     183           12 :             curvy_data%step_size = curvy_data%step_size*0.5_dp
     184            4 :             curvy_data%double_step_size = .FALSE.
     185              :          END IF
     186           84 :          step_size = curvy_data%step_size
     187           28 :       ELSE IF (curvy_data%line_search_step == ls_scf_line_search_3point_2d) THEN
     188            2 :          CALL line_search_2d(curvy_data%energies, curvy_data%step_size)
     189            6 :          step_size = curvy_data%step_size
     190           26 :       ELSE IF (curvy_data%line_search_step == ls_scf_line_search_3point) THEN
     191           26 :          CALL line_search_3pnt(curvy_data%energies, curvy_data%step_size)
     192           78 :          step_size = curvy_data%step_size
     193              :       END IF
     194              : 
     195              :       CALL update_p_exp(curvy_data%matrix_p, ls_scf_env%matrix_p, curvy_data%matrix_dp, &
     196              :                         curvy_data%matrix_BCH, ls_scf_env%eps_filter, step_size, curvy_data%BCH_saved, &
     197           84 :                         curvy_data%n_bch_hist)
     198              : 
     199              : ! line_search type has the value appropriate to the numeber of energy calculations needed
     200           84 :       curvy_data%line_search_step = MOD(curvy_data%line_search_step, curvy_data%line_search_type) + 1
     201           84 :       IF (curvy_data%line_search_step == 1) THEN
     202           58 :          DO ispin = 1, SIZE(curvy_data%matrix_p)
     203           58 :             CALL dbcsr_copy(curvy_data%matrix_p(ispin), ls_scf_env%matrix_p(ispin))
     204              :          END DO
     205              :       END IF
     206           84 :       CALL timestop(handle)
     207              : 
     208           84 :    END SUBROUTINE optimization_step
     209              : 
     210              : ! **************************************************************************************************
     211              : !> \brief Perform a 6pnt-2D line search for spin polarized calculations.
     212              : !>        Fit a 2D parabolic function to 6 points
     213              : !> \param energies ...
     214              : !> \param step_size ...
     215              : !> \par History
     216              : !>       2012.05 created [Florian Schiffmann]
     217              : !> \author Florian Schiffmann
     218              : ! **************************************************************************************************
     219              : 
     220            2 :    SUBROUTINE line_search_2d(energies, step_size)
     221              :       REAL(KIND=dp)                                      :: energies(6), step_size(2)
     222              : 
     223              :       INTEGER                                            :: info, unit_nr
     224              :       REAL(KIND=dp)                                      :: e_pred, param(6), s1, s1sq, s2, s2sq, &
     225              :                                                             sys_lin_eq(6, 6), tmp_e, v1, v2
     226              :       TYPE(cp_logger_type), POINTER                      :: logger
     227              : 
     228            2 :       logger => cp_get_default_logger()
     229            2 :       IF (energies(1) - energies(2) < 0._dp) THEN
     230            0 :          tmp_e = energies(2); energies(2) = energies(3); energies(3) = tmp_e
     231            0 :          step_size = step_size*2.0_dp
     232              :       END IF
     233            2 :       IF (logger%para_env%is_source()) THEN
     234            1 :          unit_nr = cp_logger_get_default_unit_nr(logger, local=.TRUE.)
     235              :       ELSE
     236              :          unit_nr = -1
     237              :       END IF
     238            2 :       s1 = 0.5_dp*step_size(1); s2 = step_size(1); s1sq = s1**2; s2sq = s2**2
     239           14 :       sys_lin_eq = 0.0_dp; sys_lin_eq(:, 6) = 1.0_dp
     240            2 :       sys_lin_eq(2, 1) = s1sq; sys_lin_eq(2, 2) = s1sq; sys_lin_eq(2, 3) = s1sq; sys_lin_eq(2, 4) = s1; sys_lin_eq(2, 5) = s1
     241            2 :       sys_lin_eq(3, 1) = s2sq; sys_lin_eq(3, 2) = s2sq; sys_lin_eq(3, 3) = s2sq; sys_lin_eq(3, 4) = s2; sys_lin_eq(3, 5) = s2
     242            2 :       sys_lin_eq(4, 3) = s1sq; sys_lin_eq(4, 5) = s1
     243            2 :       sys_lin_eq(5, 1) = s1sq; sys_lin_eq(5, 4) = s1
     244            2 :       sys_lin_eq(6, 3) = s2sq; sys_lin_eq(6, 5) = s2
     245              : 
     246            2 :       CALL invmat(sys_lin_eq, info)
     247           86 :       param = MATMUL(sys_lin_eq, energies)
     248            2 :       v1 = (param(2)*param(4))/(2.0_dp*param(1)) - param(5)
     249            2 :       v2 = -(param(2)**2)/(2.0_dp*param(1)) + 2.0_dp*param(3)
     250            2 :       step_size(2) = v1/v2
     251            2 :       step_size(1) = (-param(2)*step_size(2) - param(4))/(2.0_dp*param(1))
     252            2 :       IF (step_size(1) < 0.0_dp) step_size(1) = 1.0_dp
     253            2 :       IF (step_size(2) < 0.0_dp) step_size(2) = 1.0_dp
     254              : !    step_size(1)=MIN(step_size(1),2.0_dp)
     255              : !    step_size(2)=MIN(step_size(2),2.0_dp)
     256              :       e_pred = param(1)*step_size(1)**2 + param(2)*step_size(1)*step_size(2) + &
     257            2 :                param(3)*step_size(2)**2 + param(4)*step_size(1) + param(5)*step_size(2) + param(6)
     258            2 :       IF (unit_nr > 0) WRITE (unit_nr, "(t3,a,F10.5,F10.5,A,F20.9)") &
     259            1 :          " Line Search: Step Size", step_size, " Predicted energy", e_pred
     260              :       e_pred = param(1)*s1**2 + param(2)*s2*s1*0.0_dp + &
     261              :                param(3)*s1**2*0.0_dp + param(4)*s1 + param(5)*s1*0.0_dp + param(6)
     262              : 
     263            2 :    END SUBROUTINE line_search_2d
     264              : 
     265              : ! **************************************************************************************************
     266              : !> \brief Perform a 3pnt line search
     267              : !> \param energies ...
     268              : !> \param step_size ...
     269              : !> \par History
     270              : !>       2012.05 created [Florian Schiffmann]
     271              : !> \author Florian Schiffmann
     272              : ! **************************************************************************************************
     273              : 
     274           26 :    SUBROUTINE line_search_3pnt(energies, step_size)
     275              :       REAL(KIND=dp)                                      :: energies(3), step_size(2)
     276              : 
     277              :       INTEGER                                            :: unit_nr
     278              :       REAL(KIND=dp)                                      :: a, b, c, e_pred, min_val, step1, tmp, &
     279              :                                                             tmp_e
     280              :       TYPE(cp_logger_type), POINTER                      :: logger
     281              : 
     282           26 :       logger => cp_get_default_logger()
     283           26 :       IF (energies(1) - energies(2) < 0._dp) THEN
     284            2 :          tmp_e = energies(2); energies(2) = energies(3); energies(3) = tmp_e
     285            6 :          step_size = step_size*2.0_dp
     286              :       END IF
     287           26 :       IF (logger%para_env%is_source()) THEN
     288           13 :          unit_nr = cp_logger_get_default_unit_nr(logger, local=.TRUE.)
     289              :       ELSE
     290           13 :          unit_nr = -1
     291              :       END IF
     292           26 :       step1 = 0.5_dp*step_size(1)
     293           26 :       c = energies(1)
     294           26 :       a = (energies(3) + c - 2.0_dp*energies(2))/(2.0_dp*step1**2)
     295           26 :       b = (energies(2) - c - a*step1**2)/step1
     296           26 :       IF (a < 1.0E-12_dp) a = -1.0E-12_dp
     297           26 :       min_val = -b/(2.0_dp*a)
     298           26 :       e_pred = a*min_val**2 + b*min_val + c
     299           26 :       tmp = step_size(1)
     300           26 :       IF (e_pred < energies(1) .AND. e_pred < energies(2)) THEN
     301              :          step_size = MAX(-1.0_dp, &
     302           54 :                          MIN(min_val, 10_dp*step_size))
     303              :       ELSE
     304           24 :          step_size = 1.0_dp
     305              :       END IF
     306           26 :       e_pred = a*(step_size(1))**2 + b*(step_size(1)) + c
     307           26 :       IF (unit_nr > 0) THEN
     308           13 :          WRITE (unit_nr, "(t3,a,f16.8,a,F20.9)") "Line Search: Step Size", step_size(1), " Predicted energy", e_pred
     309           13 :          CALL m_flush(unit_nr)
     310              :       END IF
     311           26 :    END SUBROUTINE line_search_3pnt
     312              : 
     313              : ! **************************************************************************************************
     314              : !> \brief Get a new search direction. Iterate to obtain a Newton like step
     315              : !>        Refine with a CG update of the search direction
     316              : !> \param matrix_p ...
     317              : !> \param matrix_ks ...
     318              : !> \param matrix_dp ...
     319              : !> \param eps_filter ...
     320              : !> \param fix_shift ...
     321              : !> \param curvy_shift ...
     322              : !> \param cg_numer ...
     323              : !> \param cg_denom ...
     324              : !> \param min_shift ...
     325              : !> \par History
     326              : !>       2012.05 created [Florian Schiffmann]
     327              : !> \author Florian Schiffmann
     328              : ! **************************************************************************************************
     329              : 
     330           28 :    SUBROUTINE compute_direction_newton(matrix_p, matrix_ks, matrix_dp, eps_filter, fix_shift, &
     331              :                                        curvy_shift, cg_numer, cg_denom, min_shift)
     332              :       TYPE(dbcsr_type), DIMENSION(:)                     :: matrix_p, matrix_ks, matrix_dp
     333              :       REAL(KIND=dp)                                      :: eps_filter
     334              :       LOGICAL                                            :: fix_shift(2)
     335              :       REAL(KIND=dp)                                      :: curvy_shift(2), cg_numer(2), &
     336              :                                                             cg_denom(2), min_shift
     337              : 
     338              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'compute_direction_newton'
     339              : 
     340              :       INTEGER                                            :: handle, i, ispin, ncyc, nspin, unit_nr
     341              :       LOGICAL                                            :: at_limit
     342              :       REAL(KIND=dp)                                      :: beta, conv_val, maxel, old_conv, shift
     343              :       TYPE(cp_logger_type), POINTER                      :: logger
     344              :       TYPE(dbcsr_type)                                   :: matrix_Ax, matrix_b, matrix_cg, &
     345              :                                                             matrix_dp_old, matrix_PKs, matrix_res, &
     346              :                                                             matrix_tmp, matrix_tmp1
     347              : 
     348           56 :       logger => cp_get_default_logger()
     349              : 
     350           28 :       IF (logger%para_env%is_source()) THEN
     351           14 :          unit_nr = cp_logger_get_default_unit_nr(logger, local=.TRUE.)
     352              :       ELSE
     353           14 :          unit_nr = -1
     354              :       END IF
     355           28 :       CALL timeset(routineN, handle)
     356           28 :       nspin = SIZE(matrix_p)
     357              : 
     358           28 :       CALL dbcsr_create(matrix_PKs, template=matrix_dp(1), matrix_type=dbcsr_type_no_symmetry)
     359           28 :       CALL dbcsr_create(matrix_Ax, template=matrix_dp(1), matrix_type=dbcsr_type_no_symmetry)
     360           28 :       CALL dbcsr_create(matrix_tmp, template=matrix_dp(1), matrix_type=dbcsr_type_no_symmetry)
     361           28 :       CALL dbcsr_create(matrix_tmp1, template=matrix_dp(1), matrix_type=dbcsr_type_no_symmetry)
     362           28 :       CALL dbcsr_create(matrix_res, template=matrix_dp(1), matrix_type=dbcsr_type_no_symmetry)
     363           28 :       CALL dbcsr_create(matrix_cg, template=matrix_dp(1), matrix_type=dbcsr_type_no_symmetry)
     364           28 :       CALL dbcsr_create(matrix_b, template=matrix_dp(1), matrix_type=dbcsr_type_no_symmetry)
     365           28 :       CALL dbcsr_create(matrix_dp_old, template=matrix_dp(1), matrix_type=dbcsr_type_no_symmetry)
     366              : 
     367           58 :       DO ispin = 1, nspin
     368           30 :          CALL dbcsr_copy(matrix_dp_old, matrix_dp(ispin))
     369              : 
     370              : ! Precompute some matrices to save work during iterations
     371              :          CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_p(ispin), matrix_ks(ispin), &
     372           30 :                              0.0_dp, matrix_PKs, filter_eps=eps_filter)
     373           30 :          CALL dbcsr_transposed(matrix_b, matrix_PKs)
     374           30 :          CALL dbcsr_copy(matrix_cg, matrix_b)
     375              : 
     376              : ! Starting CG with guess 0-matrix gives -2*gradient=[Ks*P-(Ks*P)T] for cg_matrix in second step
     377           30 :          CALL dbcsr_add(matrix_cg, matrix_PKs, 2.0_dp, -2.0_dp)
     378              : 
     379              : ! Residual matrix in first step=cg matrix. Keep Pks for later use in CG!
     380           30 :          CALL dbcsr_copy(matrix_res, matrix_cg)
     381              : 
     382              : ! Precompute -FP-[FP]T which will be used throughout the CG iterations
     383           30 :          CALL dbcsr_add(matrix_b, matrix_PKs, -1.0_dp, -1.0_dp)
     384              : 
     385              : ! Setup some values to check convergence and safety checks for eigenvalue shifting
     386           30 :          old_conv = dbcsr_frobenius_norm(matrix_res)
     387           30 :          shift = MIN(10.0_dp, MAX(min_shift, 0.05_dp*old_conv))
     388           30 :          conv_val = MAX(0.010_dp*old_conv, 100.0_dp*eps_filter)
     389           30 :          old_conv = 100.0_dp
     390           30 :          IF (fix_shift(ispin)) THEN
     391            0 :             shift = MAX(min_shift, MIN(10.0_dp, MAX(shift, curvy_shift(ispin) - 0.5_dp*curvy_shift(ispin))))
     392            0 :             curvy_shift(ispin) = shift
     393              :          END IF
     394              : 
     395              : ! Begin the real optimization loop
     396           30 :          CALL dbcsr_set(matrix_dp(ispin), 0.0_dp)
     397           30 :          ncyc = 10
     398          104 :          DO i = 1, ncyc
     399              : 
     400              : ! One step to compute: -FPD-DPF-DFP-PFD (not obvious but symmetry allows for some tricks)
     401          104 :             CALL commutator_symm(matrix_b, matrix_cg, matrix_Ax, eps_filter, 1.0_dp)
     402              : 
     403              : ! Compute the missing bits 2*(FDP+PDF) (again use symmetry to compute as a commutator)
     404              :             CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_cg, matrix_p(ispin), &
     405          104 :                                 0.0_dp, matrix_tmp, filter_eps=eps_filter)
     406          104 :             CALL commutator_symm(matrix_ks(ispin), matrix_tmp, matrix_tmp1, eps_filter, 2.0_dp)
     407          104 :             CALL dbcsr_add(matrix_Ax, matrix_tmp1, 1.0_dp, 1.0_dp)
     408              : 
     409              : ! Apply the shift and hope it's enough to stabilize the CG iterations
     410          104 :             CALL dbcsr_add(matrix_Ax, matrix_cg, 1.0_dp, shift)
     411              : 
     412              :             CALL compute_cg_matrices(matrix_Ax, matrix_res, matrix_cg, matrix_dp(ispin), &
     413          104 :                                      matrix_tmp, eps_filter, at_limit)
     414          104 :             CALL dbcsr_filter(matrix_cg, eps_filter)
     415              : 
     416              : ! check for convergence of the newton step
     417          104 :             maxel = dbcsr_frobenius_norm(matrix_res)
     418          104 :             IF (unit_nr > 0) THEN
     419           52 :                WRITE (unit_nr, "(T3,A,F12.6)") "Convergence of Newton iteration ", maxel
     420           52 :                CALL m_flush(unit_nr)
     421              :             END IF
     422          104 :             at_limit = at_limit .OR. (old_conv/maxel < 1.01_dp)
     423          104 :             old_conv = maxel
     424          104 :             IF (i == ncyc .AND. maxel/conv_val > 5.0_dp) THEN
     425            0 :                fix_shift(ispin) = .TRUE.
     426            0 :                curvy_shift(ispin) = 4.0_dp*shift
     427              :             END IF
     428          104 :             IF (maxel < conv_val .OR. at_limit) EXIT
     429              :          END DO
     430              : 
     431              : ! Refine the Newton like search direction with a preconditioned cg update
     432           30 :          CALL dbcsr_transposed(matrix_b, matrix_PKs)
     433              :          !compute b= -2*KsP+2*PKs=-(2*gradient)
     434           30 :          CALL dbcsr_copy(matrix_cg, matrix_b)
     435           30 :          CALL dbcsr_add(matrix_cg, matrix_PKs, 1.0_dp, -1.0_dp)
     436           30 :          cg_denom(ispin) = cg_numer(ispin)
     437           30 :          CALL dbcsr_dot(matrix_cg, matrix_dp(ispin), cg_numer(ispin))
     438           30 :          beta = cg_numer(ispin)/MAX(cg_denom(ispin), 1.0E-6_dp)
     439           30 :          IF (beta < 1.0_dp) THEN
     440           28 :             beta = MAX(0.0_dp, beta)
     441           28 :             CALL dbcsr_add(matrix_dp(ispin), matrix_dp_old, 1.0_dp, beta)
     442              :          END IF
     443           58 :          IF (unit_nr > 0) WRITE (unit_nr, "(A)") " "
     444              :       END DO
     445              : 
     446           28 :       CALL dbcsr_release(matrix_PKs)
     447           28 :       CALL dbcsr_release(matrix_dp_old)
     448           28 :       CALL dbcsr_release(matrix_b)
     449           28 :       CALL dbcsr_release(matrix_Ax)
     450           28 :       CALL dbcsr_release(matrix_tmp)
     451           28 :       CALL dbcsr_release(matrix_tmp1)
     452           28 :       CALL dbcsr_release(matrix_b)
     453           28 :       CALL dbcsr_release(matrix_res)
     454           28 :       CALL dbcsr_release(matrix_cg)
     455              : 
     456           28 :       IF (unit_nr > 0) CALL m_flush(unit_nr)
     457           28 :       CALL timestop(handle)
     458           28 :    END SUBROUTINE compute_direction_newton
     459              : 
     460              : ! **************************************************************************************************
     461              : !> \brief compute the optimal step size of the current cycle and update the
     462              : !>        matrices needed to solve the system of linear equations
     463              : !> \param Ax ...
     464              : !> \param res ...
     465              : !> \param cg ...
     466              : !> \param deltp ...
     467              : !> \param tmp ...
     468              : !> \param eps_filter ...
     469              : !> \param at_limit ...
     470              : !> \par History
     471              : !>       2012.05 created [Florian Schiffmann]
     472              : !> \author Florian Schiffmann
     473              : ! **************************************************************************************************
     474              : 
     475          104 :    SUBROUTINE compute_cg_matrices(Ax, res, cg, deltp, tmp, eps_filter, at_limit)
     476              :       TYPE(dbcsr_type)                                   :: Ax, res, cg, deltp, tmp
     477              :       REAL(KIND=dp)                                      :: eps_filter
     478              :       LOGICAL                                            :: at_limit
     479              : 
     480              :       INTEGER                                            :: i, info
     481              :       REAL(KIND=dp)                                      :: alpha, beta, devi(3), fac, fac1, &
     482              :                                                             lin_eq(3, 3), new_norm, norm_cA, &
     483              :                                                             norm_rr, vec(3)
     484              : 
     485          104 :       at_limit = .FALSE.
     486          104 :       CALL dbcsr_dot(res, res, norm_rr)
     487          104 :       CALL dbcsr_dot(cg, Ax, norm_cA)
     488          104 :       lin_eq = 0.0_dp
     489          104 :       fac = norm_rr/norm_cA
     490          104 :       fac1 = fac
     491              : ! Use a 3point line search and a fit to a quadratic function to determine optimal step size
     492          416 :       DO i = 1, 3
     493          312 :          CALL dbcsr_copy(tmp, res)
     494          312 :          CALL dbcsr_add(tmp, Ax, 1.0_dp, -fac)
     495          312 :          devi(i) = dbcsr_frobenius_norm(tmp)
     496         1248 :          lin_eq(i, :) = [fac**2, fac, 1.0_dp]
     497          416 :          fac = fac1 + fac1*((-1)**i)*0.5_dp
     498              :       END DO
     499          104 :       CALL invmat(lin_eq, info)
     500         1352 :       vec = MATMUL(lin_eq, devi)
     501          104 :       alpha = -vec(2)/(2.0_dp*vec(1))
     502          104 :       fac = SQRT(norm_rr/(norm_cA*alpha))
     503              : !scale the previous matrices to match the step size
     504          104 :       CALL dbcsr_scale(Ax, fac)
     505          104 :       CALL dbcsr_scale(cg, fac)
     506          104 :       norm_cA = norm_cA*fac**2
     507              : 
     508              : ! USe CG to get the new matrices
     509          104 :       alpha = norm_rr/norm_cA
     510          104 :       CALL dbcsr_add(res, Ax, 1.0_dp, -alpha)
     511          104 :       CALL dbcsr_dot(res, res, new_norm)
     512          104 :       IF (norm_rr < eps_filter*0.001_dp .OR. new_norm < eps_filter*0.001_dp) THEN
     513              :          beta = 0.0_dp
     514           22 :          at_limit = .TRUE.
     515              :       ELSE
     516              :          beta = new_norm/norm_rr
     517           82 :          CALL dbcsr_add(deltp, cg, 1.0_dp, alpha)
     518              :       END IF
     519          104 :       beta = new_norm/norm_rr
     520          104 :       CALL dbcsr_add(cg, res, beta, 1.0_dp)
     521              : 
     522          208 :    END SUBROUTINE compute_cg_matrices
     523              : 
     524              : ! **************************************************************************************************
     525              : !> \brief Only for 2D line search. Use saved P-components to construct new
     526              : !>        test density matrix. Takes care as well, whether step_size
     527              : !>        increased or decreased during 2nd step and combines matrices accordingly
     528              : !> \param matrix_p ...
     529              : !> \param matrix_psave ...
     530              : !> \param lsstep ...
     531              : !> \param DOUBLE ...
     532              : !> \par History
     533              : !>       2012.05 created [Florian Schiffmann]
     534              : !> \author Florian Schiffmann
     535              : ! **************************************************************************************************
     536              : 
     537            6 :    SUBROUTINE new_p_from_save(matrix_p, matrix_psave, lsstep, DOUBLE)
     538              :       TYPE(dbcsr_type), DIMENSION(:)                     :: matrix_p
     539              :       TYPE(dbcsr_type), DIMENSION(:, :)                  :: matrix_psave
     540              :       INTEGER                                            :: lsstep
     541              :       LOGICAL                                            :: DOUBLE
     542              : 
     543            8 :       SELECT CASE (lsstep)
     544              :       CASE (3)
     545            2 :          CALL dbcsr_copy(matrix_p(1), matrix_psave(1, 1))
     546            2 :          IF (DOUBLE) THEN
     547            2 :             CALL dbcsr_copy(matrix_p(2), matrix_psave(2, 2))
     548              :          ELSE
     549            0 :             CALL dbcsr_copy(matrix_p(2), matrix_psave(2, 3))
     550              :          END IF
     551              :       CASE (4)
     552            2 :          IF (DOUBLE) THEN
     553            2 :             CALL dbcsr_copy(matrix_p(1), matrix_psave(1, 2))
     554              :          ELSE
     555            0 :             CALL dbcsr_copy(matrix_p(1), matrix_psave(1, 3))
     556              :          END IF
     557            2 :          CALL dbcsr_copy(matrix_p(2), matrix_psave(2, 1))
     558              :       CASE (5)
     559            2 :          CALL dbcsr_copy(matrix_p(1), matrix_psave(1, 1))
     560            8 :          IF (DOUBLE) THEN
     561            2 :             CALL dbcsr_copy(matrix_p(2), matrix_psave(2, 3))
     562              :          ELSE
     563            0 :             CALL dbcsr_copy(matrix_p(2), matrix_psave(2, 2))
     564              :          END IF
     565              :       END SELECT
     566              : 
     567            6 :    END SUBROUTINE new_p_from_save
     568              : 
     569              : ! **************************************************************************************************
     570              : !> \brief computes a commutator exploiting symmetry RES=k*[A,B]=k*[AB-(AB)T]
     571              : !> \param a ...
     572              : !> \param b ...
     573              : !> \param res ...
     574              : !> \param eps_filter   filtering threshold for sparse matrices
     575              : !> \param prefac      prefactor k in above equation
     576              : !> \par History
     577              : !>       2012.05 created [Florian Schiffmann]
     578              : !> \author Florian Schiffmann
     579              : ! **************************************************************************************************
     580              : 
     581          208 :    SUBROUTINE commutator_symm(a, b, res, eps_filter, prefac)
     582              :       TYPE(dbcsr_type)                                   :: a, b, res
     583              :       REAL(KIND=dp)                                      :: eps_filter, prefac
     584              : 
     585              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'commutator_symm'
     586              : 
     587              :       INTEGER                                            :: handle
     588              :       TYPE(dbcsr_type)                                   :: work
     589              : 
     590          208 :       CALL timeset(routineN, handle)
     591              : 
     592          208 :       CALL dbcsr_create(work, template=a, matrix_type=dbcsr_type_no_symmetry)
     593              : 
     594          208 :       CALL dbcsr_multiply("N", "N", prefac, a, b, 0.0_dp, res, filter_eps=eps_filter)
     595          208 :       CALL dbcsr_transposed(work, res)
     596          208 :       CALL dbcsr_add(res, work, 1.0_dp, -1.0_dp)
     597              : 
     598          208 :       CALL dbcsr_release(work)
     599              : 
     600          208 :       CALL timestop(handle)
     601          208 :    END SUBROUTINE commutator_symm
     602              : 
     603              : ! **************************************************************************************************
     604              : !> \brief Use the BCH update to get the new idempotent P
     605              : !>        Numerics don't allow for perfect idempotency, therefore a mc weeny
     606              : !>        step is used to make sure we stay close to the idempotent surface
     607              : !> \param matrix_p_in ...
     608              : !> \param matrix_p_out ...
     609              : !> \param matrix_dp ...
     610              : !> \param matrix_BCH ...
     611              : !> \param threshold ...
     612              : !> \param step_size ...
     613              : !> \param BCH_saved ...
     614              : !> \param n_bch_hist ...
     615              : !> \par History
     616              : !>       2012.05 created [Florian Schiffmann]
     617              : !> \author Florian Schiffmann
     618              : ! **************************************************************************************************
     619              : 
     620           84 :    SUBROUTINE update_p_exp(matrix_p_in, matrix_p_out, matrix_dp, matrix_BCH, threshold, step_size, &
     621              :                            BCH_saved, n_bch_hist)
     622              :       TYPE(dbcsr_type), DIMENSION(:)                     :: matrix_p_in, matrix_p_out, matrix_dp
     623              :       TYPE(dbcsr_type), DIMENSION(:, :)                  :: matrix_BCH
     624              :       REAL(KIND=dp)                                      :: threshold, step_size(2)
     625              :       INTEGER                                            :: BCH_saved(2), n_bch_hist
     626              : 
     627              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'update_p_exp'
     628              : 
     629              :       INTEGER                                            :: handle, i, ispin, nsave, nspin, unit_nr
     630              :       LOGICAL                                            :: save_BCH
     631              :       REAL(KIND=dp)                                      :: frob_norm, step_fac
     632              :       TYPE(cp_logger_type), POINTER                      :: logger
     633              :       TYPE(dbcsr_type)                                   :: matrix, matrix_tmp
     634              : 
     635           84 :       CALL timeset(routineN, handle)
     636              : 
     637           84 :       logger => cp_get_default_logger()
     638           84 :       IF (logger%para_env%is_source()) THEN
     639           42 :          unit_nr = cp_logger_get_default_unit_nr(logger, local=.TRUE.)
     640              :       ELSE
     641           42 :          unit_nr = -1
     642              :       END IF
     643              : 
     644           84 :       CALL dbcsr_create(matrix, template=matrix_p_in(1), matrix_type=dbcsr_type_no_symmetry)
     645           84 :       CALL dbcsr_create(matrix_tmp, template=matrix_p_in(1), matrix_type=dbcsr_type_no_symmetry)
     646           84 :       nspin = SIZE(matrix_p_in)
     647              : 
     648          174 :       DO ispin = 1, nspin
     649           90 :          step_fac = 1.0_dp
     650           90 :          frob_norm = 1.0_dp
     651           90 :          nsave = 0
     652              : 
     653           90 :          CALL dbcsr_copy(matrix_tmp, matrix_p_in(ispin))
     654           90 :          CALL dbcsr_copy(matrix_p_out(ispin), matrix_p_in(ispin))
     655              : ! If a BCH history is used make good use of it and do a few steps as a copy and scale update of P
     656              : ! else BCH_saved will be 0 and loop is skipped
     657          130 :          DO i = 1, BCH_saved(ispin)
     658           86 :             step_fac = step_fac*step_size(ispin)
     659           86 :             CALL dbcsr_copy(matrix_tmp, matrix_p_out(ispin))
     660           86 :             CALL dbcsr_add(matrix_p_out(ispin), matrix_BCH(ispin, i), 1.0_dp, ifac(i)*step_fac)
     661           86 :             CALL dbcsr_add(matrix_tmp, matrix_p_out(ispin), 1.0_dp, -1.0_dp)
     662           86 :             frob_norm = dbcsr_frobenius_norm(matrix_tmp)
     663           86 :             IF (unit_nr > 0) WRITE (unit_nr, "(t3,a,i3,a,f16.8)") "BCH: step", i, " Norm of P_old-Pnew:", frob_norm
     664          130 :             IF (frob_norm < threshold) EXIT
     665              :          END DO
     666           90 :          IF (frob_norm < threshold) CYCLE
     667              : 
     668              : ! If the copy and scale isn't enough compute a few more BCH steps. 20 seems high but except of the first step it will never be close
     669           44 :          save_BCH = BCH_saved(ispin) == 0 .AND. n_bch_hist > 0
     670           86 :          DO i = BCH_saved(ispin) + 1, 20
     671           86 :             step_fac = step_fac*step_size(ispin)
     672              :             !allow for a bit of matrix magic here by exploiting matrix and matrix_tmp
     673              :             !matrix_tmp is alway the previous order of the BCH series
     674              :             CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_tmp, matrix_dp(ispin), &
     675           86 :                                 0.0_dp, matrix, filter_eps=threshold)
     676              : 
     677              :             !(anti)symmetry allows to sum the transposed instead of the full commutator, matrix becomes the latest result
     678              : 
     679           86 :             CALL dbcsr_transposed(matrix_tmp, matrix)
     680           86 :             CALL dbcsr_add(matrix, matrix_tmp, 1.0_dp, 1.0_dp)
     681              : 
     682              :             !Finally, add the new BCH order to P, but store the previous one for a convergence check
     683           86 :             CALL dbcsr_copy(matrix_tmp, matrix_p_out(ispin))
     684           86 :             CALL dbcsr_add(matrix_p_out(ispin), matrix, 1.0_dp, ifac(i)*step_fac)
     685           86 :             IF (save_BCH .AND. i <= n_bch_hist) THEN
     686           78 :                CALL dbcsr_copy(matrix_BCH(ispin, i), matrix)
     687           78 :                nsave = i
     688              :             END IF
     689              : 
     690           86 :             CALL dbcsr_add(matrix_tmp, matrix_p_out(ispin), 1.0_dp, -1.0_dp)
     691              : 
     692              :             !Stop the BCH-series if two successive P's differ by less the threshold
     693           86 :             frob_norm = dbcsr_frobenius_norm(matrix_tmp)
     694           86 :             IF (unit_nr > 0) WRITE (unit_nr, "(t3,a,i3,a,f16.8)") "BCH: step", i, " Norm of P_old-Pnew:", frob_norm
     695           86 :             IF (frob_norm < threshold) EXIT
     696              : 
     697              :             !Copy the latest BCH-matrix on matrix tmp, so we can cycle with all matrices in place
     698           42 :             CALL dbcsr_copy(matrix_tmp, matrix)
     699           86 :             CALL dbcsr_filter(matrix_tmp, threshold)
     700              :          END DO
     701           44 :          BCH_saved(ispin) = nsave
     702          128 :          IF (unit_nr > 0) WRITE (unit_nr, "(A)") " "
     703              :       END DO
     704              : 
     705           84 :       CALL purify_mcweeny(matrix_p_out, threshold, 1)
     706           84 :       IF (unit_nr > 0) CALL m_flush(unit_nr)
     707           84 :       CALL dbcsr_release(matrix_tmp)
     708           84 :       CALL dbcsr_release(matrix)
     709           84 :       CALL timestop(handle)
     710           84 :    END SUBROUTINE update_p_exp
     711              : 
     712              : ! **************************************************************************************************
     713              : !> \brief performs a transformation of a matrix back to/into orthonormal basis
     714              : !>        in case of P a scaling of 0.5 has to be applied for closed shell case
     715              : !> \param matrix       matrix to be transformed
     716              : !> \param matrix_trafo transformation matrix
     717              : !> \param eps_filter   filtering threshold for sparse matrices
     718              : !> \par History
     719              : !>       2012.05 created [Florian Schiffmann]
     720              : !> \author Florian Schiffmann
     721              : ! **************************************************************************************************
     722              : 
     723          130 :    SUBROUTINE transform_matrix_orth(matrix, matrix_trafo, eps_filter)
     724              :       TYPE(dbcsr_type), DIMENSION(:)                     :: matrix
     725              :       TYPE(dbcsr_type)                                   :: matrix_trafo
     726              :       REAL(KIND=dp)                                      :: eps_filter
     727              : 
     728              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'transform_matrix_orth'
     729              : 
     730              :       INTEGER                                            :: handle, ispin
     731              :       TYPE(dbcsr_type)                                   :: matrix_tmp, matrix_work
     732              : 
     733          130 :       CALL timeset(routineN, handle)
     734              : 
     735          130 :       CALL dbcsr_create(matrix_work, template=matrix(1), matrix_type=dbcsr_type_no_symmetry)
     736          130 :       CALL dbcsr_create(matrix_tmp, template=matrix(1), matrix_type=dbcsr_type_no_symmetry)
     737              : 
     738          270 :       DO ispin = 1, SIZE(matrix)
     739              :          CALL dbcsr_multiply("N", "N", 1.0_dp, matrix(ispin), matrix_trafo, &
     740          140 :                              0.0_dp, matrix_work, filter_eps=eps_filter)
     741              :          CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_trafo, matrix_work, &
     742          140 :                              0.0_dp, matrix_tmp, filter_eps=eps_filter)
     743              :          ! symmetrize results (this is again needed to make sure everything is stable)
     744          140 :          CALL dbcsr_transposed(matrix_work, matrix_tmp)
     745          140 :          CALL dbcsr_add(matrix_tmp, matrix_work, 0.5_dp, 0.5_dp)
     746          270 :          CALL dbcsr_copy(matrix(ispin), matrix_tmp)
     747              :       END DO
     748              : 
     749          130 :       CALL dbcsr_release(matrix_tmp)
     750          130 :       CALL dbcsr_release(matrix_work)
     751          130 :       CALL timestop(handle)
     752              : 
     753          130 :    END SUBROUTINE transform_matrix_orth
     754              : 
     755              : ! **************************************************************************************************
     756              : !> \brief ...
     757              : !> \param curvy_data ...
     758              : ! **************************************************************************************************
     759          982 :    SUBROUTINE deallocate_curvy_data(curvy_data)
     760              :       TYPE(ls_scf_curvy_type)                            :: curvy_data
     761              : 
     762              :       INTEGER                                            :: i, j
     763              : 
     764          982 :       CALL release_dbcsr_array(curvy_data%matrix_dp)
     765          982 :       CALL release_dbcsr_array(curvy_data%matrix_p)
     766              : 
     767          982 :       IF (ALLOCATED(curvy_data%matrix_psave)) THEN
     768            6 :          DO i = 1, SIZE(curvy_data%matrix_psave, 1)
     769           18 :             DO j = 1, 3
     770           16 :                CALL dbcsr_release(curvy_data%matrix_psave(i, j))
     771              :             END DO
     772              :          END DO
     773            2 :          DEALLOCATE (curvy_data%matrix_psave)
     774              :       END IF
     775          982 :       IF (ALLOCATED(curvy_data%matrix_BCH)) THEN
     776           38 :          DO i = 1, SIZE(curvy_data%matrix_BCH, 1)
     777          178 :             DO j = 1, 7
     778          160 :                CALL dbcsr_release(curvy_data%matrix_BCH(i, j))
     779              :             END DO
     780              :          END DO
     781           18 :          DEALLOCATE (curvy_data%matrix_BCH)
     782              :       END IF
     783          982 :    END SUBROUTINE deallocate_curvy_data
     784              : 
     785              : ! **************************************************************************************************
     786              : !> \brief ...
     787              : !> \param matrix ...
     788              : ! **************************************************************************************************
     789         1964 :    SUBROUTINE release_dbcsr_array(matrix)
     790              :       TYPE(dbcsr_type), ALLOCATABLE, DIMENSION(:)        :: matrix
     791              : 
     792              :       INTEGER                                            :: i
     793              : 
     794         1964 :       IF (ALLOCATED(matrix)) THEN
     795           76 :          DO i = 1, SIZE(matrix)
     796           76 :             CALL dbcsr_release(matrix(i))
     797              :          END DO
     798           36 :          DEALLOCATE (matrix)
     799              :       END IF
     800         1964 :    END SUBROUTINE release_dbcsr_array
     801              : 
     802              : ! **************************************************************************************************
     803              : !> \brief ...
     804              : !> \param curvy_data ...
     805              : !> \param matrix_s ...
     806              : !> \param nspins ...
     807              : ! **************************************************************************************************
     808           18 :    SUBROUTINE init_curvy(curvy_data, matrix_s, nspins)
     809              :       TYPE(ls_scf_curvy_type)                            :: curvy_data
     810              :       TYPE(dbcsr_type)                                   :: matrix_s
     811              :       INTEGER                                            :: nspins
     812              : 
     813              :       INTEGER                                            :: ispin, j
     814              : 
     815           74 :       ALLOCATE (curvy_data%matrix_dp(nspins))
     816           56 :       ALLOCATE (curvy_data%matrix_p(nspins))
     817           38 :       DO ispin = 1, nspins
     818              :          CALL dbcsr_create(curvy_data%matrix_dp(ispin), template=matrix_s, &
     819           20 :                            matrix_type=dbcsr_type_no_symmetry)
     820           20 :          CALL dbcsr_set(curvy_data%matrix_dp(ispin), 0.0_dp)
     821              :          CALL dbcsr_create(curvy_data%matrix_p(ispin), template=matrix_s, &
     822           20 :                            matrix_type=dbcsr_type_no_symmetry)
     823           60 :          curvy_data%fix_shift = .FALSE.
     824           20 :          curvy_data%double_step_size = .TRUE.
     825           60 :          curvy_data%shift = 1.0_dp
     826           60 :          curvy_data%BCH_saved = 0
     827           60 :          curvy_data%step_size = 0.60_dp
     828           60 :          curvy_data%cg_numer = 0.00_dp
     829           78 :          curvy_data%cg_denom = 0.00_dp
     830              :       END DO
     831           18 :       IF (curvy_data%line_search_type == ls_scf_line_search_3point_2d) THEN
     832           24 :          ALLOCATE (curvy_data%matrix_psave(nspins, 3))
     833            6 :          DO ispin = 1, nspins
     834           18 :             DO j = 1, 3
     835              :                CALL dbcsr_create(curvy_data%matrix_psave(ispin, j), template=matrix_s, &
     836           16 :                                  matrix_type=dbcsr_type_no_symmetry)
     837              :             END DO
     838              :          END DO
     839              :       END IF
     840           18 :       IF (curvy_data%n_bch_hist > 0) THEN
     841          338 :          ALLOCATE (curvy_data%matrix_BCH(nspins, curvy_data%n_bch_hist))
     842           38 :          DO ispin = 1, nspins
     843          178 :             DO j = 1, curvy_data%n_bch_hist
     844              :                CALL dbcsr_create(curvy_data%matrix_BCH(ispin, j), template=matrix_s, &
     845          160 :                                  matrix_type=dbcsr_type_no_symmetry)
     846              :             END DO
     847              :          END DO
     848              :       END IF
     849              : 
     850           18 :    END SUBROUTINE init_curvy
     851              : 
     852              : END MODULE dm_ls_scf_curvy
        

Generated by: LCOV version 2.0-1