LCOV - code coverage report
Current view: top level - src - linesearch.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:42dac4a) Lines: 94.6 % 295 279
Test Date: 2025-07-25 12:55:17 Functions: 66.7 % 15 10

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2025 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief A generic framework to calculate step lengths for 1D line search
      10              : !> \author Ole Schuett
      11              : ! **************************************************************************************************
      12              : MODULE linesearch
      13              :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      14              :                                               cp_logger_type
      15              :    USE cp_output_handling,              ONLY: add_last_numeric,&
      16              :                                               cp_print_key_section_create,&
      17              :                                               cp_print_key_unit_nr,&
      18              :                                               low_print_level
      19              :    USE input_keyword_types,             ONLY: keyword_create,&
      20              :                                               keyword_release,&
      21              :                                               keyword_type
      22              :    USE input_section_types,             ONLY: section_add_keyword,&
      23              :                                               section_add_subsection,&
      24              :                                               section_create,&
      25              :                                               section_release,&
      26              :                                               section_type,&
      27              :                                               section_vals_type,&
      28              :                                               section_vals_val_get
      29              :    USE kinds,                           ONLY: dp
      30              :    USE string_utilities,                ONLY: s2a
      31              : #include "./base/base_uses.f90"
      32              : 
      33              :    IMPLICIT NONE
      34              : 
      35              :    PRIVATE
      36              : 
      37              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'linesearch'
      38              : 
      39              :    PUBLIC :: linesearch_type
      40              : 
      41              :    INTEGER, PARAMETER :: linesearch_method_adapt = 1
      42              :    INTEGER, PARAMETER :: linesearch_method_2pnt = 2
      43              :    INTEGER, PARAMETER :: linesearch_method_3pnt = 3
      44              :    INTEGER, PARAMETER :: linesearch_method_gold = 4
      45              :    INTEGER, PARAMETER :: linesearch_method_none = 5
      46              : 
      47              :    TYPE linesearch_2pnt_type
      48              :       REAL(KIND=dp), DIMENSION(2)                    :: energies = 0.0
      49              :       REAL(KIND=dp)                                  :: scan_step = 0.0
      50              :       REAL(KIND=dp)                                  :: last_step_size = 0.0
      51              :       REAL(KIND=dp)                                  :: max_step_size = 0.0
      52              :       INTEGER                                        :: count = 1
      53              :    END TYPE linesearch_2pnt_type
      54              : 
      55              :    TYPE linesearch_3pnt_type
      56              :       REAL(KIND=dp), DIMENSION(3)                    :: energies = 0.0
      57              :       REAL(KIND=dp), DIMENSION(3)                    :: scan_steps = 0.0
      58              :       REAL(KIND=dp)                                  :: last_step_size = 0.0
      59              :       REAL(KIND=dp)                                  :: max_step_size = 0.0
      60              :       REAL(KIND=dp)                                  :: tiny_step_size = 0.0
      61              :       INTEGER                                        :: count = 1
      62              :    END TYPE linesearch_3pnt_type
      63              : 
      64              :    TYPE linesearch_adapt_type
      65              :       REAL(KIND=dp)                                  :: last_step_size = 0.0
      66              :       REAL(KIND=dp)                                  :: left_x = 0.0
      67              :       REAL(KIND=dp)                                  :: middle_x = 0.0
      68              :       REAL(KIND=dp)                                  :: right_x = 0.0
      69              :       REAL(KIND=dp)                                  :: left_e = 0.0
      70              :       REAL(KIND=dp)                                  :: middle_e = 0.0
      71              :       REAL(KIND=dp)                                  :: right_e = 0.0
      72              :       LOGICAL                                        :: have_left = .FALSE.
      73              :       LOGICAL                                        :: have_middle = .FALSE.
      74              :       LOGICAL                                        :: have_right = .FALSE.
      75              :       INTEGER                                        :: count = 0
      76              :    END TYPE linesearch_adapt_type
      77              : 
      78              :    TYPE linesearch_gold_type
      79              :       REAL(KIND=dp)                                  :: scan_steps = 0.0
      80              :       REAL(KIND=dp)                                  :: last_step_size = 0.0
      81              :       REAL(KIND=dp)                                  :: eps_step_size = 0.0
      82              :       REAL(KIND=dp)                                  :: left_x = 0.0
      83              :       REAL(KIND=dp)                                  :: middle_x = 0.0
      84              :       REAL(KIND=dp)                                  :: right_x = 0.0
      85              :       REAL(KIND=dp)                                  :: left_e = 0.0
      86              :       REAL(KIND=dp)                                  :: middle_e = 0.0
      87              :       REAL(KIND=dp)                                  :: right_e = 0.0
      88              :       LOGICAL                                        :: have_left = .FALSE.
      89              :       LOGICAL                                        :: have_middle = .FALSE.
      90              :       LOGICAL                                        :: have_right = .FALSE.
      91              :       LOGICAL                                        :: gave_up = .FALSE.
      92              :    END TYPE linesearch_gold_type
      93              : 
      94              :    TYPE linesearch_type
      95              :       PRIVATE
      96              :       REAL(KIND=dp), PUBLIC                          :: step_size = 0.0_dp
      97              :       LOGICAL, PUBLIC                                :: starts = .FALSE.
      98              :       TYPE(linesearch_adapt_type), POINTER           :: state_adapt => Null()
      99              :       TYPE(linesearch_2pnt_type), POINTER            :: state_2pnt => Null()
     100              :       TYPE(linesearch_3pnt_type), POINTER            :: state_3pnt => Null()
     101              :       TYPE(linesearch_gold_type), POINTER            :: state_gold => Null()
     102              :       INTEGER                                        :: iw = -1
     103              :       INTEGER                                        :: method = -1
     104              :       CHARACTER(LEN=10)                              :: label = ""
     105              :       REAL(KIND=dp)                                  :: init_step_size = 0.0_dp
     106              :       REAL(dp)                                       :: eps_step_size = 0.0_dp
     107              :       REAL(dp)                                       :: max_step_size = 0.0_dp
     108              :       REAL(dp)                                       :: tiny_step_size = 0.0_dp
     109              :    END TYPE linesearch_type
     110              : 
     111              :    PUBLIC :: linesearch_create_section, linesearch_init, linesearch_finalize
     112              :    PUBLIC :: linesearch_step, linesearch_reset
     113              : 
     114              : CONTAINS
     115              : 
     116              : ! **************************************************************************************************
     117              : !> \brief Declare the line search input section.
     118              : !> \param section ...
     119              : !> \author Ole Schuett
     120              : ! **************************************************************************************************
     121         9254 :    SUBROUTINE linesearch_create_section(section)
     122              :       TYPE(section_type), POINTER                        :: section
     123              : 
     124              :       TYPE(keyword_type), POINTER                        :: keyword
     125              :       TYPE(section_type), POINTER                        :: print_section, printkey
     126              : 
     127         9254 :       NULLIFY (keyword, print_section, printkey)
     128              : 
     129         9254 :       CPASSERT(.NOT. ASSOCIATED(section))
     130              :       CALL section_create(section, __LOCATION__, name="LINE_SEARCH", repeats=.FALSE., &
     131         9254 :                           description="Detail settings or linesearch method.")
     132              : 
     133              :       CALL keyword_create( &
     134              :          keyword, __LOCATION__, name="METHOD", &
     135              :          description="Linesearch method.", &
     136              :          default_i_val=linesearch_method_adapt, &
     137              :          enum_c_vals=s2a("ADAPT", "3PNT", "2PNT", "GOLD", "NONE"), &
     138              :          enum_desc=s2a("extrapolates usually based on 3 points, uses additional points on demand, very robust.", &
     139              :                        "extrapolate based on 3 points", &
     140              :                        "extrapolate based on 2 points and the slope (super fast, but might get stuck at saddle points)", &
     141              :                        "perform 1D golden section search of the minimum (very expensive)", &
     142              :                        "always take steps of fixed INITIAL_STEP_SIZE"), &
     143              :          enum_i_vals=(/linesearch_method_adapt, linesearch_method_3pnt, linesearch_method_2pnt, &
     144         9254 :                        linesearch_method_gold, linesearch_method_none/))
     145         9254 :       CALL section_add_keyword(section, keyword)
     146         9254 :       CALL keyword_release(keyword)
     147              : 
     148              :       CALL keyword_create(keyword, __LOCATION__, name="INITIAL_STEP_SIZE", &
     149              :                           description="Initial step length", &
     150         9254 :                           default_r_val=0.1_dp)
     151         9254 :       CALL section_add_keyword(section, keyword)
     152         9254 :       CALL keyword_release(keyword)
     153              : 
     154              :       CALL keyword_create(keyword, __LOCATION__, name="MAX_STEP_SIZE", &
     155              :                           description="Maximum step length", &
     156         9254 :                           default_r_val=3.0_dp)
     157         9254 :       CALL section_add_keyword(section, keyword)
     158         9254 :       CALL keyword_release(keyword)
     159              : 
     160              :       CALL keyword_create(keyword, __LOCATION__, name="TINY_STEP_SIZE", &
     161              :                           description="Step length taken if negative step is suggested.", &
     162         9254 :                           default_r_val=0.002_dp)
     163         9254 :       CALL section_add_keyword(section, keyword)
     164         9254 :       CALL keyword_release(keyword)
     165              : 
     166              :       CALL keyword_create(keyword, __LOCATION__, name="EPS_STEP_SIZE", &
     167              :                           description="Convergence criterion of GOLD method.", &
     168         9254 :                           default_r_val=0.1_dp)
     169         9254 :       CALL section_add_keyword(section, keyword)
     170         9254 :       CALL keyword_release(keyword)
     171              : 
     172              :       CALL section_create(print_section, __LOCATION__, name="PRINT", &
     173              :                           description="Print section", &
     174         9254 :                           n_keywords=0, n_subsections=1, repeats=.TRUE.)
     175              : 
     176              :       CALL cp_print_key_section_create(printkey, __LOCATION__, "RUN_INFO", &
     177              :                                        description="General run information", &
     178         9254 :                                        print_level=low_print_level, add_last=add_last_numeric, filename="__STD_OUT__")
     179              : 
     180         9254 :       CALL section_add_subsection(print_section, printkey)
     181         9254 :       CALL section_release(printkey)
     182         9254 :       CALL section_add_subsection(section, print_section)
     183         9254 :       CALL section_release(print_section)
     184              : 
     185         9254 :    END SUBROUTINE linesearch_create_section
     186              : 
     187              : ! **************************************************************************************************
     188              : !> \brief Initialize linesearch from given input section
     189              : !> \param this ...
     190              : !> \param section ...
     191              : !> \param label ...
     192              : !> \author Ole Schuett
     193              : ! **************************************************************************************************
     194          294 :    SUBROUTINE linesearch_init(this, section, label)
     195              :       TYPE(linesearch_type), INTENT(INOUT)               :: this
     196              :       TYPE(section_vals_type), POINTER                   :: section
     197              :       CHARACTER(LEN=*)                                   :: label
     198              : 
     199              :       TYPE(cp_logger_type), POINTER                      :: logger
     200              : 
     201          294 :       CALL section_vals_val_get(section, "METHOD", i_val=this%method)
     202          294 :       CALL section_vals_val_get(section, "INITIAL_STEP_SIZE", r_val=this%init_step_size)
     203          294 :       CALL section_vals_val_get(section, "MAX_STEP_SIZE", r_val=this%max_step_size)
     204          294 :       CALL section_vals_val_get(section, "TINY_STEP_SIZE", r_val=this%tiny_step_size)
     205          294 :       CALL section_vals_val_get(section, "EPS_STEP_SIZE", r_val=this%eps_step_size)
     206              : 
     207          294 :       CPASSERT(LEN_TRIM(label) <= 10)
     208          294 :       this%label = label
     209          294 :       logger => cp_get_default_logger()
     210              :       this%iw = cp_print_key_unit_nr(logger, section, "PRINT%RUN_INFO", &
     211          294 :                                      extension=".linesearchlog")
     212              : 
     213          294 :       CALL linesearch_init_low(this)
     214              : 
     215          294 :    END SUBROUTINE linesearch_init
     216              : 
     217              : ! **************************************************************************************************
     218              : !> \brief Helper routine to (re)-initialize line search machinery
     219              : !> \param this ...
     220              : !> \author Ole Schuett
     221              : ! **************************************************************************************************
     222          540 :    SUBROUTINE linesearch_init_low(this)
     223              :       TYPE(linesearch_type), INTENT(INOUT)               :: this
     224              : 
     225          540 :       this%step_size = 0.0_dp
     226          540 :       this%starts = .TRUE.
     227              : 
     228          956 :       SELECT CASE (this%method)
     229              :       CASE (linesearch_method_adapt)
     230          416 :          ALLOCATE (this%state_adapt)
     231          416 :          this%state_adapt%last_step_size = this%init_step_size
     232              :       CASE (linesearch_method_2pnt)
     233           64 :          ALLOCATE (this%state_2pnt)
     234           16 :          this%state_2pnt%max_step_size = this%max_step_size
     235           16 :          this%state_2pnt%last_step_size = this%init_step_size
     236              :       CASE (linesearch_method_3pnt)
     237          540 :          ALLOCATE (this%state_3pnt)
     238           60 :          this%state_3pnt%last_step_size = this%init_step_size
     239           60 :          this%state_3pnt%max_step_size = this%max_step_size
     240           60 :          this%state_3pnt%tiny_step_size = this%tiny_step_size
     241              :       CASE (linesearch_method_gold)
     242           44 :          ALLOCATE (this%state_gold)
     243           44 :          this%state_gold%last_step_size = this%init_step_size
     244           44 :          this%state_gold%eps_step_size = this%eps_step_size
     245              :       CASE (linesearch_method_none)
     246              :          ! nothing todo
     247              :       CASE DEFAULT
     248          540 :          CPABORT("unknown method")
     249              :       END SELECT
     250              : 
     251          540 :    END SUBROUTINE linesearch_init_low
     252              : 
     253              : ! **************************************************************************************************
     254              : !> \brief Finzalize line search machinery
     255              : !> \param this ...
     256              : !> \author Ole Schuett
     257              : ! **************************************************************************************************
     258          540 :    SUBROUTINE linesearch_finalize(this)
     259              :       TYPE(linesearch_type), INTENT(INOUT)               :: this
     260              : 
     261          956 :       SELECT CASE (this%method)
     262              :       CASE (linesearch_method_adapt)
     263          416 :          DEALLOCATE (this%state_adapt)
     264              :       CASE (linesearch_method_2pnt)
     265           16 :          DEALLOCATE (this%state_2pnt)
     266              :       CASE (linesearch_method_3pnt)
     267           60 :          DEALLOCATE (this%state_3pnt)
     268              :       CASE (linesearch_method_gold)
     269           44 :          DEALLOCATE (this%state_gold)
     270              :       CASE (linesearch_method_none)
     271              :          ! nothing todo
     272              :       CASE DEFAULT
     273          540 :          CPABORT("unknown method")
     274              :       END SELECT
     275              : 
     276              :       !TODO: should finish printkey, but don't have the section here
     277          540 :    END SUBROUTINE linesearch_finalize
     278              : 
     279              : ! **************************************************************************************************
     280              : !> \brief Reset line search to initial state
     281              : !> \param this ...
     282              : !> \author Ole Schuett
     283              : ! **************************************************************************************************
     284          246 :    SUBROUTINE linesearch_reset(this)
     285              :       TYPE(linesearch_type), INTENT(INOUT)               :: this
     286              : 
     287          246 :       CALL linesearch_finalize(this)
     288          246 :       CALL linesearch_init_low(this)
     289          246 :    END SUBROUTINE linesearch_reset
     290              : 
     291              : ! **************************************************************************************************
     292              : !> \brief Calculate step length of next line search step.
     293              : !> \param this ...
     294              : !> \param energy ...
     295              : !> \param slope ...
     296              : !> \author Ole Schuett
     297              : ! **************************************************************************************************
     298         9880 :    SUBROUTINE linesearch_step(this, energy, slope)
     299              :       TYPE(linesearch_type), INTENT(INOUT)               :: this
     300              :       REAL(KIND=dp), INTENT(IN)                          :: energy, slope
     301              : 
     302              :       LOGICAL                                            :: is_done
     303              :       REAL(KIND=dp)                                      :: step_size
     304              : 
     305        17302 :       SELECT CASE (this%method)
     306              :       CASE (linesearch_method_adapt)
     307         7422 :          CALL linesearch_adapt(this%state_adapt, energy, step_size, is_done, this%iw, TRIM(this%label))
     308              :       CASE (linesearch_method_2pnt)
     309           68 :          CALL linesearch_2pnt(this%state_2pnt, energy, slope, step_size, is_done, this%iw, TRIM(this%label))
     310              :       CASE (linesearch_method_3pnt)
     311          756 :          CALL linesearch_3pnt(this%state_3pnt, energy, step_size, is_done, this%iw, TRIM(this%label))
     312              :       CASE (linesearch_method_gold)
     313         1634 :          CALL linesearch_gold(this%state_gold, energy, step_size, is_done, this%iw, TRIM(this%label))
     314              :       CASE (linesearch_method_none)
     315            0 :          step_size = this%init_step_size ! take steps of fixed length
     316            0 :          is_done = .TRUE.
     317              :       CASE DEFAULT
     318         9880 :          CPABORT("unknown method")
     319              :       END SELECT
     320              : 
     321         9880 :       this%step_size = step_size
     322         9880 :       this%starts = is_done
     323         9880 :    END SUBROUTINE linesearch_step
     324              : 
     325              : ! **************************************************************************************************
     326              : !> \brief Perform a 2pnt linesearch
     327              : !> \param this ...
     328              : !> \param energy ...
     329              : !> \param slope ...
     330              : !> \param step_size ...
     331              : !> \param is_done ...
     332              : !> \param unit_nr ...
     333              : !> \param label ...
     334              : !> \author Ole Schuett
     335              : ! **************************************************************************************************
     336           68 :    SUBROUTINE linesearch_2pnt(this, energy, slope, step_size, is_done, unit_nr, label)
     337              :       TYPE(linesearch_2pnt_type), INTENT(INOUT)          :: this
     338              :       REAL(KIND=dp), INTENT(IN)                          :: energy, slope
     339              :       REAL(KIND=dp), INTENT(OUT)                         :: step_size
     340              :       LOGICAL, INTENT(OUT)                               :: is_done
     341              :       INTEGER, INTENT(IN)                                :: unit_nr
     342              :       CHARACTER(len=*), INTENT(IN)                       :: label
     343              : 
     344              :       REAL(KIND=dp)                                      :: a, b, c, pred_energy, x2
     345              : 
     346           68 :       this%energies(this%count) = energy
     347           68 :       is_done = .FALSE.
     348              : 
     349           34 :       SELECT CASE (this%count)
     350              :       CASE (1)
     351           34 :          step_size = 2.0_dp*this%last_step_size
     352           34 :          this%scan_step = step_size
     353           34 :          this%count = 2
     354              :       CASE (2)
     355           34 :          c = this%energies(1)
     356           34 :          b = -slope
     357           34 :          x2 = this%scan_step
     358           34 :          a = (this%energies(2) - b*x2 - c)/(x2**2)
     359              : 
     360           34 :          IF (a < 0.0_dp) THEN
     361            0 :             IF (unit_nr > 0) WRITE (unit_nr, *) label, "LS| had to quench curvature"
     362              :             a = 1.0E-15_dp
     363              :          END IF
     364              : 
     365           34 :          step_size = -b/(2.0_dp*a)
     366           34 :          pred_energy = a*step_size**2 + b*step_size + c
     367              : 
     368           34 :          IF (unit_nr > 0) WRITE (unit_nr, *) label, "LS| 2pnt suggested step_size: ", step_size
     369           34 :          IF (unit_nr > 0) WRITE (unit_nr, *) label, "LS| 2pnt predicted energy", pred_energy
     370              : 
     371           34 :          IF (pred_energy > this%energies(1) .OR. pred_energy > this%energies(2)) THEN
     372            0 :             CPABORT(label//"LS| predicted energy not below test points")
     373              :          END IF
     374              : 
     375           34 :          IF (step_size > this%max_step_size) THEN
     376            0 :             step_size = this%max_step_size
     377            0 :             IF (unit_nr > 0) WRITE (unit_nr, *) label, "LS| limiting step_size to MAX_STEP_SIZE"
     378              :          END IF
     379              : 
     380           34 :          this%last_step_size = step_size
     381           34 :          this%count = 1
     382           34 :          is_done = .TRUE.
     383              :       CASE DEFAULT
     384           68 :          CPABORT("this should not happen")
     385              :       END SELECT
     386              : 
     387           68 :    END SUBROUTINE linesearch_2pnt
     388              : 
     389              : ! **************************************************************************************************
     390              : !> \brief Perform a 3pnt linesearch
     391              : !> \param this ...
     392              : !> \param energy ...
     393              : !> \param step_size ...
     394              : !> \param is_done ...
     395              : !> \param unit_nr ...
     396              : !> \param label ...
     397              : !> \author Ole Schuett
     398              : ! **************************************************************************************************
     399          756 :    SUBROUTINE linesearch_3pnt(this, energy, step_size, is_done, unit_nr, label)
     400              :       TYPE(linesearch_3pnt_type), INTENT(INOUT)          :: this
     401              :       REAL(KIND=dp), INTENT(IN)                          :: energy
     402              :       REAL(KIND=dp), INTENT(OUT)                         :: step_size
     403              :       LOGICAL, INTENT(OUT)                               :: is_done
     404              :       INTEGER, INTENT(IN)                                :: unit_nr
     405              :       CHARACTER(len=*), INTENT(IN)                       :: label
     406              : 
     407              :       REAL(KIND=dp)                                      :: a, b, c, denom, pred_energy, x1, x2, x3, &
     408              :                                                             y1, y2, y3
     409              : 
     410          756 :       this%energies(this%count) = energy
     411          756 :       is_done = .FALSE.
     412              : 
     413          252 :       SELECT CASE (this%count)
     414              :       CASE (1)
     415          252 :          step_size = (2.0_dp/3.0_dp)*this%last_step_size
     416          252 :          IF (step_size < this%tiny_step_size) THEN
     417            0 :             IF (unit_nr > 0) WRITE (unit_nr, *) label, "LS| initial step size too small, using TINY_STEP_SIZE"
     418            0 :             step_size = this%tiny_step_size
     419              :          END IF
     420          252 :          this%scan_steps(1) = 0.0_dp
     421          252 :          this%scan_steps(2) = step_size
     422          252 :          this%count = 2
     423              :       CASE (2)
     424          252 :          IF (this%energies(1) > this%energies(2)) THEN
     425          214 :             step_size = 2.0_dp*this%scan_steps(2)
     426              :          ELSE
     427           38 :             step_size = 0.5_dp*this%scan_steps(2)
     428              :          END IF
     429          252 :          this%scan_steps(3) = step_size
     430          252 :          this%count = 3
     431              :       CASE (3)
     432              :          ! fitting y = a*x^2 + b*x + c
     433          252 :          y1 = this%energies(1); y2 = this%energies(2); y3 = this%energies(3)
     434          252 :          x1 = this%scan_steps(1); x2 = this%scan_steps(2); x3 = this%scan_steps(3)
     435              : 
     436          252 :          IF (unit_nr > 0) WRITE (unit_nr, *) label, "LS| 3pnt scan_steps: ", this%scan_steps
     437          252 :          IF (unit_nr > 0) WRITE (unit_nr, *) label, "LS| 3pnt energies: ", this%energies
     438              : 
     439              :          ! Cramer's Rule
     440          252 :          denom = (x1 - x2)*(x1 - x3)*(x2 - x3)
     441          252 :          a = (x3*(y2 - y1) + x2*(y1 - y3) + x1*(y3 - y2))/denom
     442          252 :          b = (x3**2*(y1 - y2) + x2**2*(y3 - y1) + x1**2*(y2 - y3))/denom
     443          252 :          c = (x2*x3*(x2 - x3)*y1 + x3*x1*(x3 - x1)*y2 + x1*x2*(x1 - x2)*y3)/denom
     444              : 
     445          252 :          step_size = -b/(2.0_dp*a)
     446          252 :          pred_energy = a*step_size**2 + b*step_size + c
     447          252 :          IF (unit_nr > 0) WRITE (unit_nr, *) label, "LS| 3pnt suggested step_size: ", step_size
     448          252 :          IF (unit_nr > 0) WRITE (unit_nr, *) label, "LS| 3pnt predicted energy", pred_energy
     449              : 
     450          252 :          IF (a < 0) THEN
     451            0 :             step_size = -2.0_dp*step_size
     452            0 :             IF (unit_nr > 0) WRITE (unit_nr, *) label, "LS| inverting step size"
     453              :          END IF
     454              : 
     455          252 :          IF (step_size < 0) THEN
     456            0 :             step_size = this%tiny_step_size
     457            0 :             IF (unit_nr > 0) WRITE (unit_nr, *) label, "LS| makeing a step of size TINY_STEP_SIZE"
     458              :          END IF
     459              : 
     460          252 :          IF (step_size > this%max_step_size) THEN
     461            6 :             step_size = this%max_step_size
     462            6 :             IF (unit_nr > 0) WRITE (unit_nr, *) label, "LS| limiting step_size to MAX_STEP_SIZE"
     463              :          END IF
     464              : 
     465          252 :          this%last_step_size = step_size
     466          252 :          this%count = 1
     467          252 :          is_done = .TRUE.
     468              :       CASE DEFAULT
     469          756 :          CPABORT("this should not happen")
     470              :       END SELECT
     471              : 
     472          756 :    END SUBROUTINE linesearch_3pnt
     473              : 
     474              : ! **************************************************************************************************
     475              : !> \brief Perform an adaptive linesearch
     476              : !> \param this ...
     477              : !> \param energy ...
     478              : !> \param step_size ...
     479              : !> \param is_done ...
     480              : !> \param unit_nr ...
     481              : !> \param label ...
     482              : !> \author Ole Schuett
     483              : ! **************************************************************************************************
     484         7422 :    SUBROUTINE linesearch_adapt(this, energy, step_size, is_done, unit_nr, label)
     485              :       TYPE(linesearch_adapt_type), INTENT(INOUT)         :: this
     486              :       REAL(KIND=dp), INTENT(IN)                          :: energy
     487              :       REAL(KIND=dp), INTENT(OUT)                         :: step_size
     488              :       LOGICAL, INTENT(OUT)                               :: is_done
     489              :       INTEGER, INTENT(IN)                                :: unit_nr
     490              :       CHARACTER(len=*), INTENT(IN)                       :: label
     491              : 
     492              :       REAL(KIND=dp), PARAMETER                           :: grow_factor = 2.0_dp, &
     493              :                                                             shrink_factor = 0.5_dp
     494              : 
     495              :       REAL(KIND=dp)                                      :: a, b, c, denom, pred_energy, x1, x2, x3, &
     496              :                                                             y1, y2, y3
     497              : 
     498         7422 :       is_done = .FALSE.
     499         7422 :       this%count = this%count + 1
     500              : 
     501         7422 :       IF (.NOT. this%have_left) THEN
     502         1932 :          this%left_x = 0.0_dp
     503         1932 :          this%left_e = energy
     504         1932 :          this%have_left = .TRUE.
     505         1932 :          step_size = this%last_step_size
     506              : 
     507         5490 :       ELSE IF (.NOT. (this%have_middle .OR. this%have_right)) THEN
     508         1932 :          IF (energy < this%left_e) THEN
     509         1552 :             this%middle_e = energy
     510         1552 :             this%middle_x = this%last_step_size
     511         1552 :             this%have_middle = .TRUE.
     512         1552 :             step_size = this%middle_x*grow_factor
     513              :          ELSE
     514          380 :             this%right_e = energy
     515          380 :             this%right_x = this%last_step_size
     516          380 :             this%have_right = .TRUE.
     517          380 :             step_size = this%right_x*shrink_factor
     518              :          END IF
     519              : 
     520         3558 :       ELSE IF (.NOT. this%have_right) THEN
     521         2974 :          IF (energy < this%middle_e) THEN
     522         1424 :             this%middle_e = energy
     523         1424 :             this%middle_x = this%last_step_size
     524         1424 :             step_size = this%middle_x*grow_factor
     525              :          ELSE
     526         1550 :             this%right_e = energy
     527         1550 :             this%right_x = this%last_step_size
     528         1550 :             this%have_right = .TRUE.
     529              :          END IF
     530              : 
     531          584 :       ELSE IF (.NOT. this%have_middle) THEN
     532          584 :          IF (energy > this%left_e) THEN
     533          204 :             this%right_e = energy
     534          204 :             this%right_x = this%last_step_size
     535          204 :             step_size = this%right_x*shrink_factor
     536              :          ELSE
     537          380 :             this%middle_e = energy
     538          380 :             this%middle_x = this%last_step_size
     539          380 :             this%have_middle = .TRUE.
     540              :          END IF
     541              :       END IF
     542              : 
     543         7422 :       IF (this%count > 3) THEN
     544         1628 :          IF (unit_nr > 0) WRITE (unit_nr, *) label, "LS| Need extra step"
     545              :       END IF
     546         7422 :       IF (unit_nr > 0) WRITE (unit_nr, *) label, "LS| adapt: ", this%have_left, this%have_middle, this%have_right
     547         7422 :       IF (unit_nr > 0) WRITE (unit_nr, *) label, "LS| adapt: scan_steps: ", this%left_x, this%middle_x, this%right_x
     548         7422 :       IF (unit_nr > 0) WRITE (unit_nr, *) label, "LS| adapt: energies: ", this%left_e, this%middle_e, this%right_e
     549              : 
     550         7422 :       IF (this%have_left .AND. this%have_middle .AND. this%have_right) THEN
     551              :          ! fitting y = a*x^2 + b*x + c
     552         1930 :          y1 = this%left_e; y2 = this%middle_e; y3 = this%right_e
     553         1930 :          x1 = this%left_x; x2 = this%middle_x; x3 = this%right_x
     554              : 
     555              :          ! Cramer's rule
     556         1930 :          denom = (x1 - x2)*(x1 - x3)*(x2 - x3)
     557         1930 :          a = (x3*(y2 - y1) + x2*(y1 - y3) + x1*(y3 - y2))/denom
     558         1930 :          b = (x3**2*(y1 - y2) + x2**2*(y3 - y1) + x1**2*(y2 - y3))/denom
     559         1930 :          c = (x2*x3*(x2 - x3)*y1 + x3*x1*(x3 - x1)*y2 + x1*x2*(x1 - x2)*y3)/denom
     560              : 
     561         1930 :          IF (ABS(a) /= 0.0_dp) THEN
     562         1930 :             step_size = -b/(2.0_dp*a)
     563              :          ELSE
     564            0 :             step_size = 0.0_dp
     565              :          END IF
     566              : 
     567         1930 :          CPASSERT(step_size >= 0.0_dp)
     568         1930 :          pred_energy = a*step_size**2 + b*step_size + c
     569         1930 :          IF (unit_nr > 0) WRITE (unit_nr, *) label, "LS| adapt: suggested step_size: ", step_size
     570         1930 :          IF (unit_nr > 0) WRITE (unit_nr, *) label, "LS| adapt: predicted energy", pred_energy
     571              : 
     572              :          ! reset
     573         1930 :          is_done = .TRUE.
     574         1930 :          this%count = 0
     575         1930 :          this%have_left = .FALSE.
     576         1930 :          this%have_middle = .FALSE.
     577         1930 :          this%have_right = .FALSE.
     578         1930 :          this%left_e = 0.0
     579         1930 :          this%middle_e = 0.0
     580         1930 :          this%right_e = 0.0
     581         1930 :          this%left_x = 0.0
     582         1930 :          this%middle_x = 0.0
     583         1930 :          this%right_x = 0.0
     584              :       END IF
     585              : 
     586         7422 :       this%last_step_size = step_size
     587         7422 :    END SUBROUTINE linesearch_adapt
     588              : 
     589              : ! **************************************************************************************************
     590              : !> \brief Perform a gold linesearch
     591              : !> \param this ...
     592              : !> \param energy ...
     593              : !> \param step_size ...
     594              : !> \param is_done ...
     595              : !> \param unit_nr ...
     596              : !> \param label ...
     597              : !> \author Ole Schuett
     598              : ! **************************************************************************************************
     599         1634 :    SUBROUTINE linesearch_gold(this, energy, step_size, is_done, unit_nr, label)
     600              :       TYPE(linesearch_gold_type), INTENT(INOUT)          :: this
     601              :       REAL(KIND=dp), INTENT(IN)                          :: energy
     602              :       REAL(KIND=dp), INTENT(OUT)                         :: step_size
     603              :       LOGICAL, INTENT(OUT)                               :: is_done
     604              :       INTEGER, INTENT(IN)                                :: unit_nr
     605              :       CHARACTER(len=*), INTENT(IN)                       :: label
     606              : 
     607              :       REAL(KIND=dp), PARAMETER :: phi = (1.0_dp + SQRT(5.0_dp))/2.0_dp
     608              : 
     609              :       REAL(KIND=dp)                                      :: a, b, d
     610              : 
     611         1634 :       is_done = .FALSE.
     612              : 
     613         1634 :       IF (this%gave_up) &
     614            0 :          CPABORT("had to give up, should not be called again")
     615              : 
     616         1634 :       IF (.NOT. this%have_left) THEN
     617          154 :          this%left_x = 0.0_dp
     618          154 :          this%left_e = energy
     619          154 :          this%have_left = .TRUE.
     620          154 :          step_size = this%last_step_size
     621              : 
     622         1480 :       ELSE IF (.NOT. (this%have_middle .OR. this%have_right)) THEN
     623          154 :          IF (energy < this%left_e) THEN
     624          112 :             this%middle_e = energy
     625          112 :             this%middle_x = this%scan_steps
     626          112 :             this%have_middle = .TRUE.
     627          112 :             step_size = this%middle_x*phi
     628              :          ELSE
     629           42 :             this%right_e = energy
     630           42 :             this%right_x = this%scan_steps
     631           42 :             this%have_right = .TRUE.
     632           42 :             step_size = this%right_x/phi
     633              :          END IF
     634              : 
     635         1326 :       ELSE IF (.NOT. this%have_right) THEN
     636          418 :          IF (energy < this%middle_e) THEN
     637          306 :             this%middle_e = energy
     638          306 :             this%middle_x = this%scan_steps
     639          306 :             step_size = this%middle_x*phi
     640              :          ELSE
     641          112 :             this%right_e = energy
     642          112 :             this%right_x = this%scan_steps
     643          112 :             this%have_right = .TRUE.
     644              :          END IF
     645              : 
     646          908 :       ELSE IF (.NOT. this%have_middle) THEN
     647          112 :          IF (energy > this%left_e) THEN
     648           70 :             this%right_e = energy
     649           70 :             this%right_x = this%scan_steps
     650           70 :             step_size = this%right_x/phi
     651              :          ELSE
     652           42 :             this%middle_e = energy
     653           42 :             this%middle_x = this%scan_steps
     654           42 :             this%have_middle = .TRUE.
     655              :          END IF
     656              : 
     657              :       ELSE !up and running
     658          796 :          a = this%middle_x - this%left_x
     659          796 :          b = this%right_x - this%middle_x
     660          796 :          IF (energy < this%middle_e) THEN
     661          234 :             IF (a < b) THEN
     662           90 :                this%left_e = this%middle_e
     663           90 :                this%left_x = this%middle_x
     664              :             ELSE
     665          144 :                this%right_e = this%middle_e
     666          144 :                this%right_x = this%middle_x
     667              :             END IF
     668          234 :             this%middle_e = energy
     669          234 :             this%middle_x = this%scan_steps
     670              :          ELSE
     671          562 :             IF (a < b) THEN
     672          234 :                this%right_e = energy
     673          234 :                this%right_x = this%scan_steps
     674              :             ELSE
     675          328 :                this%left_e = energy
     676          328 :                this%left_x = this%scan_steps
     677              :             END IF
     678              :          END IF
     679              :       END IF
     680              : 
     681         1634 :       IF (unit_nr > 0) WRITE (unit_nr, *) label, "LS| gold: ", this%have_left, this%have_middle, this%have_right
     682         1634 :       IF (unit_nr > 0) WRITE (unit_nr, *) label, "LS| gold: ", this%left_x, this%middle_x, this%right_x
     683         1634 :       IF (unit_nr > 0) WRITE (unit_nr, *) label, "LS| gold: ", this%left_e, this%middle_e, this%right_e
     684              : 
     685         1634 :       IF (this%have_left .AND. this%have_middle .AND. this%have_right) THEN
     686          950 :          a = this%middle_x - this%left_x
     687          950 :          b = this%right_x - this%middle_x
     688          950 :          IF (ABS(MIN(a, b)*phi - MAX(a, b)) > 1.0E-10) &
     689            0 :             CPABORT("golden-ratio gone")
     690              : 
     691          950 :          IF (a < b) THEN
     692          418 :             step_size = this%middle_x + a/phi
     693              :          ELSE
     694          532 :             step_size = this%middle_x - b/phi
     695              :          END IF
     696              : 
     697          950 :          d = ABS(this%right_x - this%left_x)/(ABS(this%middle_x) + ABS(step_size))
     698          950 :          IF (d < this%eps_step_size) THEN
     699          154 :             step_size = this%middle_x
     700          154 :             this%last_step_size = step_size
     701          154 :             is_done = .TRUE.
     702              : 
     703          154 :             IF (unit_nr > 0) WRITE (unit_nr, *) label, "LS| gold done, step-size: ", step_size
     704              : 
     705          154 :             this%have_left = .FALSE.
     706          154 :             this%have_middle = .FALSE.
     707          154 :             this%have_right = .FALSE.
     708          154 :             this%left_e = 0.0
     709          154 :             this%middle_e = 0.0
     710          154 :             this%right_e = 0.0
     711          154 :             this%left_x = 0.0
     712          154 :             this%middle_x = 0.0
     713          154 :             this%right_x = 0.0
     714              :          END IF
     715              : 
     716              :       END IF
     717              : 
     718         1634 :       IF (step_size < 1E-10) CPABORT("linesearch failed / done")
     719              : 
     720         1634 :       this%scan_steps = step_size
     721         1634 :    END SUBROUTINE linesearch_gold
     722              : 
     723            0 : END MODULE linesearch
        

Generated by: LCOV version 2.0-1