LCOV - code coverage report
Current view: top level - src - qs_cdft_scf_utils.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:123285f) Lines: 86.7 % 188 163
Test Date: 2026-11-04 00:58:17 Functions: 100.0 % 6 6

            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 Auxiliary routines for performing a constrained DFT SCF run with Quickstep.
      10              : !> \par History
      11              : !>      - Separated some routines from qs_scf (03.2018) [Nico Holmberg]
      12              : !> \author Nico Holmberg (03.2018)
      13              : ! **************************************************************************************************
      14              : MODULE qs_cdft_scf_utils
      15              :    USE cp_control_types,                ONLY: dft_control_type
      16              :    USE cp_files,                        ONLY: close_file,&
      17              :                                               open_file
      18              :    USE cp_log_handling,                 ONLY: cp_logger_create,&
      19              :                                               cp_logger_type,&
      20              :                                               cp_to_string
      21              :    USE input_constants,                 ONLY: &
      22              :         broyden_type_1, broyden_type_1_explicit, broyden_type_1_explicit_ls, broyden_type_1_ls, &
      23              :         broyden_type_2, broyden_type_2_explicit, broyden_type_2_explicit_ls, broyden_type_2_ls, &
      24              :         jacobian_fd1, jacobian_fd1_backward, jacobian_fd1_central, jacobian_fd2, &
      25              :         jacobian_fd2_backward, outer_scf_optimizer_broyden, outer_scf_optimizer_newton, &
      26              :         outer_scf_optimizer_newton_ls
      27              :    USE kinds,                           ONLY: default_path_length,&
      28              :                                               dp
      29              :    USE mathlib,                         ONLY: invert_matrix
      30              :    USE message_passing,                 ONLY: mp_para_env_type
      31              :    USE qs_environment_types,            ONLY: get_qs_env,&
      32              :                                               qs_environment_type
      33              :    USE qs_scf_types,                    ONLY: qs_scf_env_type
      34              :    USE scf_control_types,               ONLY: scf_control_type
      35              : #include "./base/base_uses.f90"
      36              : 
      37              :    IMPLICIT NONE
      38              : 
      39              :    PRIVATE
      40              : 
      41              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_cdft_scf_utils'
      42              : 
      43              :    PUBLIC :: prepare_jacobian_stencil, build_diagonal_jacobian, &
      44              :              restart_inverse_jacobian, print_inverse_jacobian, &
      45              :              create_tmp_logger, initialize_inverse_jacobian
      46              : 
      47              : CONTAINS
      48              : 
      49              : ! **************************************************************************************************
      50              : !> \brief Prepares the finite difference stencil for computing the Jacobian. The constraints
      51              : !>        are re-evaluated by perturbing each constraint.
      52              : !> \param qs_env the qs_env where to build the Jacobian
      53              : !> \param output_unit the output unit number
      54              : !> \param nwork the number of perturbations to take in the negative direction
      55              : !> \param pwork the number of perturbations to take in the positive direction
      56              : !> \param coeff list of coefficients that determine how to sum up the various perturbations
      57              : !> \param step_multiplier list of values that determine how large steps to take for each perturbatio
      58              : !> \param dh total length of the interval to use for computing the finite difference derivatives
      59              : !> \par History
      60              : !>      03.2018 created [Nico Holmberg]
      61              : ! **************************************************************************************************
      62           66 :    SUBROUTINE prepare_jacobian_stencil(qs_env, output_unit, nwork, pwork, &
      63              :                                        coeff, step_multiplier, dh)
      64              :       TYPE(qs_environment_type), POINTER                 :: qs_env
      65              :       INTEGER                                            :: output_unit, nwork, pwork
      66              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: coeff, step_multiplier, dh
      67              : 
      68              :       CHARACTER(len=15)                                  :: fmt_code
      69              :       INTEGER                                            :: ivar
      70              :       TYPE(dft_control_type), POINTER                    :: dft_control
      71              :       TYPE(qs_scf_env_type), POINTER                     :: scf_env
      72              :       TYPE(scf_control_type), POINTER                    :: scf_control
      73              : 
      74           66 :       NULLIFY (scf_env, scf_control, dft_control)
      75              : 
      76           66 :       CPASSERT(ASSOCIATED(qs_env))
      77              :       CALL get_qs_env(qs_env, scf_env=scf_env, &
      78              :                       scf_control=scf_control, &
      79           66 :                       dft_control=dft_control)
      80              : 
      81            4 :       IF (SIZE(scf_control%outer_scf%cdft_opt_control%jacobian_step) /= 1 .AND. &
      82           66 :           SIZE(scf_control%outer_scf%cdft_opt_control%jacobian_step) /= SIZE(scf_env%outer_scf%variables, 1)) THEN
      83              :          CALL cp_abort(__LOCATION__, &
      84              :                        cp_to_string(SIZE(scf_control%outer_scf%cdft_opt_control%jacobian_step))// &
      85              :                        " values passed to keyword JACOBIAN_STEP, expected 1 or "// &
      86            0 :                        cp_to_string(SIZE(scf_env%outer_scf%variables, 1)))
      87              :       END IF
      88              : 
      89          198 :       ALLOCATE (dh(SIZE(scf_env%outer_scf%variables, 1)))
      90           66 :       IF (SIZE(dh) /= SIZE(scf_control%outer_scf%cdft_opt_control%jacobian_step)) THEN
      91           72 :          DO ivar = 1, SIZE(dh)
      92           72 :             dh(ivar) = scf_control%outer_scf%cdft_opt_control%jacobian_step(1)
      93              :          END DO
      94              :       ELSE
      95           88 :          dh(:) = scf_control%outer_scf%cdft_opt_control%jacobian_step
      96              :       END IF
      97              : 
      98           66 :       SELECT CASE (scf_control%outer_scf%cdft_opt_control%jacobian_type)
      99              :       CASE DEFAULT
     100              :          CALL cp_abort(__LOCATION__, &
     101              :                        "Unknown Jacobian type: "// &
     102            0 :                        cp_to_string(scf_control%outer_scf%cdft_opt_control%jacobian_type))
     103              :       CASE (jacobian_fd1)
     104              :          ! f'(x0) = [ f(x0+h) - f(x0) ] / h
     105           52 :          nwork = 0
     106           52 :          pwork = 1
     107           52 :          ALLOCATE (coeff(nwork:pwork), step_multiplier(nwork:pwork))
     108           52 :          coeff(nwork) = -1.0_dp
     109           52 :          coeff(pwork) = 1.0_dp
     110          156 :          step_multiplier = 1.0_dp
     111              :       CASE (jacobian_fd1_backward)
     112              :          ! f'(x0) = [ f(x0) - f(x0-h) ] / h
     113            2 :          nwork = -1
     114            2 :          pwork = 0
     115            2 :          ALLOCATE (coeff(nwork:pwork), step_multiplier(nwork:pwork))
     116            2 :          coeff(nwork) = -1.0_dp
     117            2 :          coeff(pwork) = 1.0_dp
     118            6 :          step_multiplier = -1.0_dp
     119              :       CASE (jacobian_fd2)
     120              :          ! f'(x0) = [ -f(x0+2h) + 4f(x0+h) - 3f(x0) ] / 2h
     121            2 :          nwork = 0
     122            2 :          pwork = 2
     123            2 :          ALLOCATE (coeff(nwork:pwork), step_multiplier(nwork:pwork))
     124            2 :          coeff(0) = -3.0_dp
     125            2 :          coeff(1) = 4.0_dp
     126            2 :          coeff(2) = -1.0_dp
     127            2 :          step_multiplier(0) = 0.0_dp
     128            2 :          step_multiplier(1) = 1.0_dp
     129            2 :          step_multiplier(2) = 2.0_dp
     130            4 :          dh(:) = 2.0_dp*dh(:)
     131              :       CASE (jacobian_fd2_backward)
     132              :          ! f'(x0) = [ 3f(x0) - 4f(x0-h) + f(x0-2h) ] / 2h
     133            8 :          nwork = -2
     134            8 :          pwork = 0
     135            8 :          ALLOCATE (coeff(nwork:pwork), step_multiplier(nwork:pwork))
     136            8 :          coeff(0) = 3.0_dp
     137            8 :          coeff(-1) = -4.0_dp
     138            8 :          coeff(-2) = 1.0_dp
     139            8 :          step_multiplier(0) = 0.0_dp
     140            8 :          step_multiplier(-1) = -1.0_dp
     141            8 :          step_multiplier(-2) = -2.0_dp
     142           16 :          dh(:) = 2.0_dp*dh(:)
     143              :       CASE (jacobian_fd1_central)
     144              :          ! f'(x0) = [ f(x0+h) - f(x0-h) ] / 2h
     145            2 :          nwork = -1
     146            2 :          pwork = 1
     147            2 :          ALLOCATE (coeff(nwork:pwork), step_multiplier(nwork:pwork))
     148            2 :          coeff(0) = 0.0_dp
     149            2 :          coeff(nwork) = -1.0_dp
     150            2 :          coeff(pwork) = 1.0_dp
     151            2 :          step_multiplier(0) = 0.0_dp
     152            2 :          step_multiplier(nwork) = -1.0_dp
     153            2 :          step_multiplier(pwork) = 1.0_dp
     154           70 :          dh(:) = 2.0_dp*dh(:)
     155              :       END SELECT
     156              :       ! Print some info
     157           66 :       IF (output_unit > 0) THEN
     158              :          WRITE (output_unit, FMT="(/,A)") &
     159           33 :             " ================================== JACOBIAN CALCULATION ================================="
     160              :          WRITE (output_unit, FMT="(A)") &
     161           33 :             " Evaluating inverse Jacobian using finite differences"
     162              :          WRITE (output_unit, '(A,I10,A,I10)') &
     163           33 :             " Energy evaluation: ", dft_control%qs_control%cdft_control%ienergy, &
     164           66 :             ", CDFT SCF iteration: ", scf_env%outer_scf%iter_count
     165           59 :          SELECT CASE (scf_control%outer_scf%cdft_opt_control%jacobian_type)
     166              :          CASE (jacobian_fd1)
     167           26 :             WRITE (output_unit, '(A)') " Type               : First order forward difference"
     168              :          CASE (jacobian_fd1_backward)
     169            1 :             WRITE (output_unit, '(A)') " Type               : First order backward difference"
     170              :          CASE (jacobian_fd2)
     171            1 :             WRITE (output_unit, '(A)') " Type               : Second order forward difference"
     172              :          CASE (jacobian_fd2_backward)
     173            4 :             WRITE (output_unit, '(A)') " Type               : Second order backward difference"
     174              :          CASE (jacobian_fd1_central)
     175            1 :             WRITE (output_unit, '(A)') " Type               : First order central difference"
     176              :          CASE DEFAULT
     177              :             CALL cp_abort(__LOCATION__, "Unknown Jacobian type: "// &
     178           33 :                           cp_to_string(scf_control%outer_scf%cdft_opt_control%jacobian_type))
     179              :          END SELECT
     180           33 :          IF (SIZE(scf_control%outer_scf%cdft_opt_control%jacobian_step) == 1) THEN
     181           62 :             WRITE (output_unit, '(A,ES12.4)') " Step size          : ", scf_control%outer_scf%cdft_opt_control%jacobian_step
     182              :          ELSE
     183              :             WRITE (output_unit, '(A,ES12.4,A)') &
     184            2 :                " Step sizes         : ", scf_control%outer_scf%cdft_opt_control%jacobian_step(1), ' (constraint 1)'
     185            2 :             IF (SIZE(scf_control%outer_scf%cdft_opt_control%jacobian_step) < 10) THEN
     186            2 :                fmt_code = '(ES34.4,A,I2,A)'
     187              :             ELSE
     188            0 :                fmt_code = '(ES34.4,A,I3,A)'
     189              :             END IF
     190            4 :             DO ivar = 2, SIZE(scf_control%outer_scf%cdft_opt_control%jacobian_step)
     191            4 :                WRITE (output_unit, fmt_code) scf_control%outer_scf%cdft_opt_control%jacobian_step(ivar), " (constraint", ivar, ")"
     192              :             END DO
     193              :          END IF
     194              :       END IF
     195              : 
     196           66 :    END SUBROUTINE prepare_jacobian_stencil
     197              : ! **************************************************************************************************
     198              : !> \brief Builds a strictly diagonal inverse Jacobian from MD/SCF history.
     199              : !> \param qs_env the qs_environment_type where to compute the Jacobian
     200              : !> \param used_history flag that determines if history was actually used to prepare the Jacobian
     201              : !> \par History
     202              : !>      03.2018 created [Nico Holmberg]
     203              : ! **************************************************************************************************
     204           20 :    SUBROUTINE build_diagonal_jacobian(qs_env, used_history)
     205              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     206              :       LOGICAL                                            :: used_history
     207              : 
     208              :       INTEGER                                            :: i, ihistory, nvar, outer_scf_ihistory
     209              :       LOGICAL                                            :: use_md_history
     210              :       REAL(KIND=dp)                                      :: inv_error
     211           20 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: jacobian
     212           20 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: gradient_history, inv_jacobian, &
     213           20 :                                                             variable_history
     214              :       TYPE(qs_scf_env_type), POINTER                     :: scf_env
     215              :       TYPE(scf_control_type), POINTER                    :: scf_control
     216              : 
     217           20 :       NULLIFY (scf_control, scf_env)
     218              : 
     219              :       CALL get_qs_env(qs_env, scf_env=scf_env, &
     220              :                       scf_control=scf_control, &
     221           20 :                       outer_scf_ihistory=outer_scf_ihistory)
     222           20 :       ihistory = scf_env%outer_scf%iter_count
     223              : 
     224           20 :       IF (outer_scf_ihistory >= 3 .AND. .NOT. used_history) THEN
     225              :          ! First, lets try using the history from previous energy evaluations
     226              :          CALL get_qs_env(qs_env, gradient_history=gradient_history, &
     227            0 :                          variable_history=variable_history)
     228            0 :          nvar = SIZE(scf_env%outer_scf%variables, 1)
     229            0 :          use_md_history = .TRUE.
     230              :          ! Check that none of the history values are identical in which case we should try something different
     231            0 :          DO i = 1, nvar
     232            0 :             IF (ABS(variable_history(i, 2) - variable_history(i, 1)) < 1.0E-12_dp) THEN
     233            0 :                use_md_history = .FALSE.
     234              :             END IF
     235              :          END DO
     236            0 :          IF (use_md_history) THEN
     237            0 :             ALLOCATE (jacobian(nvar, nvar))
     238            0 :             jacobian = 0.0_dp
     239            0 :             DO i = 1, nvar
     240              :                jacobian(i, i) = (gradient_history(i, 2) - gradient_history(i, 1))/ &
     241            0 :                                 (variable_history(i, 2) - variable_history(i, 1))
     242              :             END DO
     243            0 :             IF (.NOT. ASSOCIATED(scf_env%outer_scf%inv_jacobian)) THEN
     244            0 :                ALLOCATE (scf_env%outer_scf%inv_jacobian(nvar, nvar))
     245              :             END IF
     246            0 :             inv_jacobian => scf_env%outer_scf%inv_jacobian
     247            0 :             CALL invert_matrix(jacobian, inv_jacobian, inv_error)
     248            0 :             DEALLOCATE (jacobian)
     249              :             ! Mark that an inverse Jacobian was just built and the next outer_loop_optimize should not perform
     250              :             ! a Broyden update of it
     251            0 :             scf_control%outer_scf%cdft_opt_control%broyden_update = .FALSE.
     252              :             ! Mark that the MD history has been used and should not be reused anymore on this energy evaluation
     253            0 :             used_history = .TRUE.
     254              :          END IF
     255              :       END IF
     256           20 :       IF (ihistory >= 2 .AND. .NOT. ASSOCIATED(scf_env%outer_scf%inv_jacobian)) THEN
     257              :          ! Next, try history from current SCF procedure
     258           10 :          nvar = SIZE(scf_env%outer_scf%variables, 1)
     259           10 :          IF (SIZE(scf_env%outer_scf%gradient, 2) < 3) THEN
     260              :             CALL cp_abort(__LOCATION__, &
     261              :                           "Keyword EXTRAPOLATION_ORDER in section OUTER_SCF must be greater than or equal "// &
     262            0 :                           "to 3 for optimizers that build the Jacobian from SCF history.")
     263              :          END IF
     264           40 :          ALLOCATE (jacobian(nvar, nvar))
     265           10 :          jacobian = 0.0_dp
     266           22 :          DO i = 1, nvar
     267              :             jacobian(i, i) = (scf_env%outer_scf%gradient(i, ihistory) - scf_env%outer_scf%gradient(i, ihistory - 1))/ &
     268           22 :                              (scf_env%outer_scf%variables(i, ihistory) - scf_env%outer_scf%variables(i, ihistory - 1))
     269              :          END DO
     270           10 :          IF (.NOT. ASSOCIATED(scf_env%outer_scf%inv_jacobian)) THEN
     271           30 :             ALLOCATE (scf_env%outer_scf%inv_jacobian(nvar, nvar))
     272              :          END IF
     273           10 :          inv_jacobian => scf_env%outer_scf%inv_jacobian
     274           10 :          CALL invert_matrix(jacobian, inv_jacobian, inv_error)
     275           10 :          DEALLOCATE (jacobian)
     276           20 :          scf_control%outer_scf%cdft_opt_control%broyden_update = .FALSE.
     277              :       ELSE
     278              :          ! No history => will fall back to SD optimizer in outer_loop_optimize
     279              :       END IF
     280              : 
     281           40 :    END SUBROUTINE build_diagonal_jacobian
     282              : 
     283              : ! **************************************************************************************************
     284              : !> \brief Restarts the finite difference inverse Jacobian.
     285              : !> \param qs_env the qs_environment_type where to compute the Jacobian
     286              : !> \par History
     287              : !>      03.2018 created [Nico Holmberg]
     288              : ! **************************************************************************************************
     289            6 :    SUBROUTINE restart_inverse_jacobian(qs_env)
     290              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     291              : 
     292              :       INTEGER                                            :: i, iwork, j, nvar
     293            6 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: inv_jacobian
     294              :       TYPE(qs_scf_env_type), POINTER                     :: scf_env
     295              :       TYPE(scf_control_type), POINTER                    :: scf_control
     296              : 
     297            6 :       NULLIFY (scf_env, scf_control)
     298            0 :       CPASSERT(ASSOCIATED(qs_env))
     299            6 :       CALL get_qs_env(qs_env, scf_env=scf_env, scf_control=scf_control)
     300              : 
     301            6 :       CPASSERT(ASSOCIATED(scf_control%outer_scf%cdft_opt_control%jacobian_vector))
     302            6 :       nvar = SIZE(scf_env%outer_scf%variables, 1)
     303            6 :       IF (SIZE(scf_control%outer_scf%cdft_opt_control%jacobian_vector) /= nvar**2) THEN
     304              :          CALL cp_abort(__LOCATION__, &
     305            0 :                        "Too many or too few values defined for restarting inverse Jacobian.")
     306              :       END IF
     307            6 :       IF (.NOT. ASSOCIATED(scf_env%outer_scf%inv_jacobian)) THEN
     308           24 :          ALLOCATE (scf_env%outer_scf%inv_jacobian(nvar, nvar))
     309              :       END IF
     310            6 :       inv_jacobian => scf_env%outer_scf%inv_jacobian
     311            6 :       iwork = 1
     312           16 :       DO i = 1, nvar
     313           34 :          DO j = 1, nvar
     314           18 :             inv_jacobian(i, j) = scf_control%outer_scf%cdft_opt_control%jacobian_vector(iwork)
     315           28 :             iwork = iwork + 1
     316              :          END DO
     317              :       END DO
     318            6 :       DEALLOCATE (scf_control%outer_scf%cdft_opt_control%jacobian_vector)
     319            6 :       scf_control%outer_scf%cdft_opt_control%jacobian_restart = .FALSE.
     320            6 :       scf_control%outer_scf%cdft_opt_control%broyden_update = .FALSE.
     321            6 :       scf_env%outer_scf%deallocate_jacobian = .FALSE.
     322              : 
     323            6 :    END SUBROUTINE restart_inverse_jacobian
     324              : 
     325              : ! **************************************************************************************************
     326              : !> \brief Prints the finite difference inverse Jacobian to file
     327              : !> \param logger the default IO logger
     328              : !> \param inv_jacobian the inverse Jacobian matrix
     329              : !> \param iter_count the iteration number
     330              : !> \par History
     331              : !>      03.2018 created [Nico Holmberg]
     332              : ! **************************************************************************************************
     333          124 :    SUBROUTINE print_inverse_jacobian(logger, inv_jacobian, iter_count)
     334              :       TYPE(cp_logger_type), POINTER                      :: logger
     335              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN), &
     336              :          POINTER                                         :: inv_jacobian
     337              :       INTEGER                                            :: iter_count
     338              : 
     339              :       CHARACTER(len=default_path_length)                 :: project_name
     340              :       INTEGER                                            :: i, j, lp, nvar, output_unit
     341              : 
     342           62 :       nvar = SIZE(inv_jacobian, 1)
     343           62 :       project_name = logger%iter_info%project_name
     344           62 :       lp = LEN_TRIM(project_name)
     345           62 :       project_name(lp + 1:LEN(project_name)) = ".inverseJacobian"
     346              :       CALL open_file(file_name=project_name, &
     347              :                      file_status="UNKNOWN", &
     348              :                      file_action="WRITE", &
     349              :                      file_position="APPEND", &
     350           62 :                      unit_number=output_unit)
     351           62 :       WRITE (output_unit, FMT="(/,A)") "Inverse Jacobian matrix in row major order"
     352           62 :       WRITE (output_unit, FMT="(A,I10)") "Iteration: ", iter_count
     353          159 :       DO i = 1, nvar
     354          326 :          DO j = 1, nvar
     355          264 :             WRITE (output_unit, *) inv_jacobian(i, j)
     356              :          END DO
     357              :       END DO
     358           62 :       CALL close_file(unit_number=output_unit)
     359              : 
     360           62 :    END SUBROUTINE print_inverse_jacobian
     361              : 
     362              : ! **************************************************************************************************
     363              : !> \brief Creates a temporary logger for redirecting output to a new file
     364              : !> \param para_env the para_env
     365              : !> \param project_name the project basename
     366              : !> \param suffix the suffix
     367              : !> \param output_unit the default unit number for the newly created temporary logger
     368              : !> \param tmp_logger pointer to the newly created temporary logger
     369              : !> \par History
     370              : !>      03.2018 created [Nico Holmberg]
     371              : ! **************************************************************************************************
     372           74 :    SUBROUTINE create_tmp_logger(para_env, project_name, suffix, output_unit, tmp_logger)
     373              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     374              :       CHARACTER(len=*)                                   :: project_name, suffix
     375              :       INTEGER, INTENT(OUT)                               :: output_unit
     376              :       TYPE(cp_logger_type), INTENT(OUT), POINTER         :: tmp_logger
     377              : 
     378              :       INTEGER                                            :: lp
     379              : 
     380          111 :       IF (para_env%is_source()) THEN
     381           37 :          lp = LEN_TRIM(project_name)
     382           37 :          project_name(lp + 1:LEN(project_name)) = suffix
     383              :          CALL open_file(file_name=project_name, file_status="UNKNOWN", &
     384              :                         file_action="WRITE", file_position="APPEND", &
     385           37 :                         unit_number=output_unit)
     386              :       ELSE
     387           37 :          output_unit = -1
     388              :       END IF
     389              :       CALL cp_logger_create(tmp_logger, &
     390              :                             para_env=para_env, &
     391              :                             default_global_unit_nr=output_unit, &
     392           74 :                             close_global_unit_on_dealloc=.FALSE.)
     393              : 
     394           74 :    END SUBROUTINE create_tmp_logger
     395              : 
     396              : ! **************************************************************************************************
     397              : !> \brief Checks if the inverse Jacobian should be calculated and initializes the calculation
     398              : !> \param scf_control         the scf_control that holds the Jacobian settings
     399              : !> \param scf_env             the scf_env that holds the CDFT iteration information
     400              : !> \param explicit_jacobian   flag that determines if the finite difference Jacobian is needed
     401              : !> \param should_build        flag that determines if the Jacobian should be built
     402              : !> \param used_history        flag that determines if SCF history has been used to build a Jacobian
     403              : !> \par History
     404              : !>      03.2018 created [Nico Holmberg]
     405              : ! **************************************************************************************************
     406          134 :    SUBROUTINE initialize_inverse_jacobian(scf_control, scf_env, explicit_jacobian, &
     407              :                                           should_build, used_history)
     408              :       TYPE(scf_control_type), POINTER                    :: scf_control
     409              :       TYPE(qs_scf_env_type), POINTER                     :: scf_env
     410              :       LOGICAL                                            :: explicit_jacobian, should_build, &
     411              :                                                             used_history
     412              : 
     413          134 :       CPASSERT(ASSOCIATED(scf_control))
     414          134 :       CPASSERT(ASSOCIATED(scf_env))
     415              : 
     416          134 :       SELECT CASE (scf_control%outer_scf%optimizer)
     417              :       CASE DEFAULT
     418            0 :          CPABORT("Noncompatible optimizer requested.")
     419              :       CASE (outer_scf_optimizer_newton, outer_scf_optimizer_newton_ls)
     420          102 :          CPASSERT(ASSOCIATED(scf_control%outer_scf%cdft_opt_control))
     421          102 :          scf_control%outer_scf%cdft_opt_control%build_jacobian = .TRUE.
     422          102 :          explicit_jacobian = .TRUE.
     423              :       CASE (outer_scf_optimizer_broyden)
     424           32 :          CPASSERT(ASSOCIATED(scf_control%outer_scf%cdft_opt_control))
     425          134 :          SELECT CASE (scf_control%outer_scf%cdft_opt_control%broyden_type)
     426              :          CASE (broyden_type_1, broyden_type_2, broyden_type_1_ls, broyden_type_2_ls)
     427           28 :             scf_control%outer_scf%cdft_opt_control%build_jacobian = .TRUE.
     428           28 :             explicit_jacobian = .FALSE.
     429              :          CASE (broyden_type_1_explicit, broyden_type_2_explicit, broyden_type_1_explicit_ls, broyden_type_2_explicit_ls)
     430            4 :             scf_control%outer_scf%cdft_opt_control%build_jacobian = .TRUE.
     431           32 :             explicit_jacobian = .TRUE.
     432              :          END SELECT
     433              :       END SELECT
     434          134 :       IF (scf_control%outer_scf%cdft_opt_control%build_jacobian) THEN
     435              :          ! Reset counter
     436          134 :          IF (scf_env%outer_scf%iter_count == 1) scf_control%outer_scf%cdft_opt_control%ijacobian(1) = 0
     437              :          ! Check if an old Jacobian can be reused avoiding a rebuild
     438          134 :          IF (ASSOCIATED(scf_env%outer_scf%inv_jacobian)) THEN
     439              :             ! Rebuild if number of previous energy evaluations exceeds limit
     440              :             IF (scf_control%outer_scf%cdft_opt_control%ijacobian(2) >= &
     441           74 :                 scf_control%outer_scf%cdft_opt_control%jacobian_freq(2) .AND. .NOT. used_history .AND. &
     442              :                 scf_control%outer_scf%cdft_opt_control%jacobian_freq(2) > 0) THEN
     443            4 :                should_build = .TRUE.
     444              :                ! Zero the corresponding counters
     445           12 :                scf_control%outer_scf%cdft_opt_control%ijacobian(:) = 0
     446              :                ! Rebuild if number of previous SCF iterations exceeds limit (on this energy eval)
     447              :             ELSE IF (scf_control%outer_scf%cdft_opt_control%ijacobian(1) >= &
     448           70 :                      scf_control%outer_scf%cdft_opt_control%jacobian_freq(1) .AND. &
     449              :                      scf_control%outer_scf%cdft_opt_control%jacobian_freq(1) > 0) THEN
     450           28 :                should_build = .TRUE.
     451              :                ! Zero the corresponding counter
     452           28 :                scf_control%outer_scf%cdft_opt_control%ijacobian(1) = 0
     453              :             END IF
     454           74 :             IF (should_build) DEALLOCATE (scf_env%outer_scf%inv_jacobian)
     455              :          ELSE
     456           60 :             should_build = .TRUE.
     457              :             ! Zero the counter
     458          180 :             scf_control%outer_scf%cdft_opt_control%ijacobian(:) = 0
     459              :          END IF
     460              :       END IF
     461              : 
     462          134 :    END SUBROUTINE initialize_inverse_jacobian
     463              : 
     464              : END MODULE qs_cdft_scf_utils
        

Generated by: LCOV version 2.0-1