LCOV - code coverage report
Current view: top level - num/test/src - test_brent.f90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 93.4 % 183 171
Test Date: 2025-05-08 18:23:42 Functions: 95.5 % 22 21

            Line data    Source code
       1              : module test_brent
       2              : 
       3              :    use num_def
       4              :    use num_lib
       5              :    use math_lib
       6              :    use utils_lib, only: mesa_error
       7              :    use const_def, only: dp
       8              : 
       9              :    implicit none
      10              : 
      11              :    logical, parameter :: dbg = .false.
      12              : 
      13              : contains
      14              : 
      15            1 :    subroutine do_test_brent
      16            1 :       write (*, *) 'test brent'
      17              : 
      18            1 :       call test_global_min_all
      19            1 :       call test_local_min_all
      20            1 :       call test_brent_zero
      21              : 
      22            1 :    end subroutine do_test_brent
      23              : 
      24            1 :    subroutine test_global_min_all
      25              : 
      26              :       !*****************************************************************************80
      27              :       !
      28              :       !! TEST_GLOMIN_ALL tests the Brent global minimizer on all test functions.
      29              :       !
      30              :       !  Licensing:
      31              :       !
      32              :       !    This code is distributed under the GNU LGPL license.
      33              :       !
      34              :       !  Modified:
      35              :       !
      36              :       !    12 April 2008
      37              :       !
      38              :       !  Author:
      39              :       !
      40              :       !    John Burkardt
      41              :       !
      42              :       implicit none
      43              : 
      44              :       real(dp) :: a
      45              :       real(dp) :: b
      46              :       real(dp) :: c
      47              :       real(dp) :: e
      48              :       real(dp) :: m
      49              :       real(dp) :: machep
      50              :       real(dp) :: t
      51              : 
      52            1 :       write (*, '(a)') ' '
      53            1 :       write (*, '(a)') 'TEST_GLOMIN_ALL'
      54            1 :       write (*, '(a)') '  Test the Brent GLOMIN routine, which seeks'
      55            1 :       write (*, '(a)') '  a global minimizer of a function F(X)'
      56            1 :       write (*, '(a)') '  in an interval [A,B],'
      57            1 :       write (*, '(a)') '  given some upper bound M for F".'
      58              : 
      59            1 :       machep = epsilon(machep)
      60            1 :       e = sqrt(machep)
      61            1 :       t = sqrt(machep)
      62              : 
      63            1 :       a = 7.0D+00
      64            1 :       b = 9.0D+00
      65            1 :       c = (a + b)/2.0D+00
      66            1 :       m = 0.0D+00
      67              : 
      68              :       call test_glomin_one(a, b, c, m, machep, e, t, h_01, &
      69            1 :                            'h_01(x) = 2 - x')
      70              : 
      71              :       a = 7.0D+00
      72              :       b = 9.0D+00
      73              :       c = (a + b)/2.0D+00
      74            1 :       m = 100.0D+00
      75              : 
      76              :       call test_glomin_one(a, b, c, m, machep, e, t, h_01, &
      77            1 :                            'h_01(x) = 2 - x')
      78              : 
      79            1 :       a = -1.0D+00
      80            1 :       b = +2.0D+00
      81            1 :       c = (a + b)/2.0D+00
      82            1 :       m = 2.0D+00
      83              : 
      84              :       call test_glomin_one(a, b, c, m, machep, e, t, h_02, &
      85            1 :                            'h_02(x) = x * x')
      86              : 
      87              :       a = -1.0D+00
      88              :       b = +2.0D+00
      89              :       c = (a + b)/2.0D+00
      90            1 :       m = 2.1D+00
      91              : 
      92              :       call test_glomin_one(a, b, c, m, machep, e, t, h_02, &
      93            1 :                            'h_02(x) = x * x')
      94              : 
      95              :       a = -0.5D+00
      96              :       b = +2.0D+00
      97              :       c = (a + b)/2.0D+00
      98              :       m = 14.0D+00
      99              : 
     100              :       !call test_glomin_one ( a, b, c, m, machep, e, t, h_03, &
     101              :       !  'h_03(x) = x^3 + x^2' )
     102              : 
     103              :       a = -0.5D+00
     104              :       b = +2.0D+00
     105              :       c = (a + b)/2.0D+00
     106              :       m = 28.0D+00
     107              : 
     108              :       !call test_glomin_one ( a, b, c, m, machep, e, t, h_03, &
     109              :       !  'h_03(x) = x^3 + x^2' )
     110              : 
     111            1 :       a = -10.0D+00
     112            1 :       b = +10.0D+00
     113            1 :       c = (a + b)/2.0D+00
     114            1 :       m = 72.0D+00
     115              : 
     116              :       call test_glomin_one(a, b, c, m, machep, e, t, h_04, &
     117            1 :                            'h_04(x) = ( x + sin(x) ) * exp(-x*x)')
     118              : 
     119              :       a = -10.0D+00
     120              :       b = +10.0D+00
     121              :       c = (a + b)/2.0D+00
     122              :       m = 72.0D+00
     123              : 
     124              :       call test_glomin_one(a, b, c, m, machep, e, t, h_05, &
     125            1 :                            'h_05(x) = ( x - sin(x) ) * exp(-x*x)')
     126              : 
     127            1 :    end subroutine test_global_min_all
     128              : 
     129            6 :    subroutine test_glomin_one(a, b, c, m, machep, e, t, f, title)
     130              :       real(dp), intent(in) :: a, b, c, m, machep, e, t
     131              :       interface
     132              :          real(dp) function f(x)
     133              :             use const_def, only: dp
     134              :             implicit none
     135              :             real(dp), intent(in) :: x
     136              :          end function f
     137              :       end interface
     138              : 
     139            6 :       real(dp) :: fa
     140            6 :       real(dp) :: fb
     141            6 :       real(dp) :: fx
     142              :       character(len=*) :: title
     143              :       real(dp) :: x
     144              :       integer :: max_tries, ierr
     145              :       include 'formats'
     146              : 
     147            6 :       max_tries = 10000
     148              :       ierr = 0
     149            6 :       fx = brent_global_min(max_tries, a, b, c, m, machep, e, t, f, x, ierr)
     150            6 :       if (ierr /= 0) then
     151            0 :          write (*, *) 'failed in brent_global_min'
     152            0 :          call mesa_error(__FILE__, __LINE__)
     153              :       end if
     154            6 :       fa = f(a)
     155            6 :       fb = f(b)
     156              : 
     157            6 :       write (*, '(a)') ' '
     158            6 :       write (*, '(a)') trim(title)
     159            6 :       write (*, 1) 'a,  b', a, b
     160            6 :       write (*, 1) 'fa, fb', fa, fb
     161              : 
     162            6 :    end subroutine test_glomin_one
     163              : 
     164           31 :    real(dp) function h_01(x)
     165              :       real(dp), intent(in) :: x
     166           31 :       h_01 = 2.0D+00 - x
     167           31 :    end function h_01
     168              : 
     169           45 :    real(dp) function h_02(x)
     170              :       real(dp), intent(in) :: x
     171           45 :       h_02 = x*x
     172           45 :    end function h_02
     173              : 
     174            0 :    real(dp) function h_03(x)
     175              :       real(dp), intent(in) :: x
     176            0 :       h_03 = x*x*(x + 1.0D+00)
     177            0 :    end function h_03
     178              : 
     179          383 :    real(dp) function h_04(x)
     180              :       real(dp), intent(in) :: x
     181          383 :       h_04 = (x + sin(x))*exp(-x*x)
     182          383 :    end function h_04
     183              : 
     184         1135 :    real(dp) function h_05(x)
     185              :       real(dp), intent(in) :: x
     186         1135 :       h_05 = (x - sin(x))*exp(-x*x)
     187         1135 :    end function h_05
     188              : 
     189            1 :    subroutine test_local_min_all
     190              : 
     191              :       !*****************************************************************************80
     192              :       !
     193              :       !! TEST_LOCAL_MIN_ALL tests Brent's local minimizer on all test functions.
     194              :       !
     195              :       !  Licensing:
     196              :       !
     197              :       !    This code is distributed under the GNU LGPL license.
     198              :       !
     199              :       !  Modified:
     200              :       !
     201              :       !    12 April 2008
     202              :       !
     203              :       !  Author:
     204              :       !
     205              :       !    John Burkardt
     206              :       !
     207              :       implicit none
     208              : 
     209              :       real(dp) :: a
     210              :       real(dp) :: b
     211              :       real(dp) :: eps
     212              :       real(dp) :: t
     213              : 
     214            1 :       write (*, '(a)') ' '
     215            1 :       write (*, '(a)') 'TEST_LOCAL_MIN_ALL'
     216            1 :       write (*, '(a)') '  Test the Brent LOCAL_MIN routine, which seeks'
     217            1 :       write (*, '(a)') '  a local minimizer of a function F(X)'
     218            1 :       write (*, '(a)') '  in an interval [A,B].'
     219              : 
     220            1 :       eps = 10.0D+00*sqrt(epsilon(eps))
     221            1 :       t = eps
     222              : 
     223            1 :       a = 0.0D+00
     224            1 :       b = 3.141592653589793D+00
     225              : 
     226              :       call test_local_min_one(a, b, eps, t, g_01, &
     227            1 :                               'g_01(x) = ( x - 2 ) * ( x - 2 ) + 1')
     228              : 
     229              :       a = 0.0D+00
     230            1 :       b = 1.0D+00
     231              : 
     232              :       call test_local_min_one(a, b, eps, t, g_02, &
     233            1 :                               'g_02(x) = x * x + exp( - x )')
     234              : 
     235            1 :       a = -2.0D+00
     236            1 :       b = 2.0D+00
     237              : 
     238              :       call test_local_min_one(a, b, eps, t, g_03, &
     239            1 :                               'g_03(x) = x^4 + 2x^2 + x + 3')
     240              : 
     241            1 :       a = 0.0001D+00
     242            1 :       b = 1.0D+00
     243              : 
     244              :       call test_local_min_one(a, b, eps, t, g_04, &
     245            1 :                               'g_04(x) = exp( x ) + 1 / ( 100 x )')
     246              : 
     247            1 :       a = 0.0002D+00
     248            1 :       b = 2.0D+00
     249              : 
     250              :       call test_local_min_one(a, b, eps, t, g_05, &
     251            1 :                               'g_05(x) = exp( x ) - 2x + 1/(100x) - 1/(1000000x^2)')
     252              : 
     253            1 :    end subroutine test_local_min_all
     254              : 
     255            5 :    subroutine test_local_min_one(a, b, eps, t, f, title)
     256              : 
     257              :       !*****************************************************************************80
     258              :       !
     259              :       !! TEST_LOCAL_MIN_ONE tests Brent's local minimizer on one test function.
     260              :       !
     261              :       !  Licensing:
     262              :       !
     263              :       !    This code is distributed under the GNU LGPL license.
     264              :       !
     265              :       !  Modified:
     266              :       !
     267              :       !    12 April 2008
     268              :       !
     269              :       !  Author:
     270              :       !
     271              :       !    John Burkardt
     272              :       !
     273              :       !  Parameters:
     274              :       !
     275              :       !    Input, real(dp) A, B, the endpoints of the interval.
     276              :       !
     277              :       !    Input, real(dp) EPS, a positive relative error tolerance.
     278              :       !
     279              :       !    Input, real(dp) T, a positive absolute error tolerance.
     280              :       !
     281              :       !    Input, external real(dp) F, the name of a user-supplied
     282              :       !    function, of the form "FUNCTION F ( X )", which evaluates the
     283              :       !    function whose local minimum is being sought.
     284              :       !
     285              :       !    Input, character ( LEN = * ) TITLE, a title for the problem.
     286              :       !
     287              :       implicit none
     288              :       real(dp), intent(in) :: a, b, eps, t
     289              :       interface
     290              :          real(dp) function f(x)
     291              :             use const_def, only: dp
     292              :             implicit none
     293              :             real(dp), intent(in) :: x
     294              :          end function f
     295              :       end interface
     296              :       character(len=*) :: title
     297              : 
     298            5 :       real(dp) :: fa
     299            5 :       real(dp) :: fb
     300            5 :       real(dp) :: fx
     301              :       real(dp) :: x
     302              :       integer :: max_tries, ierr
     303              :       include 'formats'
     304              : 
     305            5 :       max_tries = 10000
     306              :       ierr = 0
     307            5 :       fx = brent_local_min(max_tries, a, b, eps, t, f, x, ierr)
     308            5 :       if (ierr /= 0) then
     309            0 :          write (*, *) 'failed in brent_local_min'
     310            0 :          call mesa_error(__FILE__, __LINE__)
     311              :       end if
     312            5 :       fa = f(a)
     313            5 :       fb = f(b)
     314              : 
     315            5 :       write (*, '(a)') ' '
     316            5 :       write (*, '(a)') trim(title)
     317            5 :       write (*, 1) 'a,  b', a, b
     318            5 :       write (*, 1) 'fa, fb', fa, fb
     319              : 
     320            5 :    end subroutine test_local_min_one
     321              : 
     322            8 :    real(dp) function g_01(x)
     323              :       real(dp), intent(in) :: x
     324            8 :       g_01 = (x - 2.0D+00)*(x - 2.0D+00) + 1.0D+00
     325            8 :    end function g_01
     326              : 
     327           11 :    real(dp) function g_02(x)
     328              :       real(dp), intent(in) :: x
     329           11 :       g_02 = x*x + exp(-x)
     330           11 :    end function g_02
     331              : 
     332           13 :    real(dp) function g_03(x)
     333              :       real(dp), intent(in) :: x
     334           13 :       g_03 = ((x*x + 2.0D+00)*x + 1.0D+00)*x + 3.0D+00
     335           13 :    end function g_03
     336              : 
     337           15 :    real(dp) function g_04(x)
     338              :       real(dp), intent(in) :: x
     339           15 :       g_04 = exp(x) + 0.01D+00/x
     340           15 :    end function g_04
     341              : 
     342           12 :    real(dp) function g_05(x)
     343              :       real(dp), intent(in) :: x
     344           12 :       g_05 = exp(x) - 2.0D+00*x + 0.01D+00/x - 0.000001D+00/x/x
     345           12 :    end function g_05
     346              : 
     347           29 :    real(dp) function f_01(x, dfdx, lrpar, rpar, lipar, ipar, ierr)
     348              :       integer, intent(in) :: lrpar, lipar
     349              :       real(dp), intent(in) :: x
     350              :       real(dp), intent(out) :: dfdx
     351              :       integer, intent(inout), pointer :: ipar(:)  ! (lipar)
     352              :       real(dp), intent(inout), pointer :: rpar(:)  ! (lrpar)
     353              :       integer, intent(out) :: ierr
     354           29 :       f_01 = sin(x) - 0.5D+00*x
     355           29 :       ierr = 0
     356           29 :       dfdx = 0
     357           29 :    end function f_01
     358              : 
     359           10 :    real(dp) function f_02(x, dfdx, lrpar, rpar, lipar, ipar, ierr)
     360              :       integer, intent(in) :: lrpar, lipar
     361              :       real(dp), intent(in) :: x
     362              :       real(dp), intent(out) :: dfdx
     363              :       integer, intent(inout), pointer :: ipar(:)  ! (lipar)
     364              :       real(dp), intent(inout), pointer :: rpar(:)  ! (lrpar)
     365              :       integer, intent(out) :: ierr
     366           10 :       f_02 = 2.0D+00*x - exp(-x)
     367           10 :       ierr = 0
     368           10 :       dfdx = 0
     369           10 :    end function f_02
     370              : 
     371           15 :    real(dp) function f_03(x, dfdx, lrpar, rpar, lipar, ipar, ierr)
     372              :       integer, intent(in) :: lrpar, lipar
     373              :       real(dp), intent(in) :: x
     374              :       real(dp), intent(out) :: dfdx
     375              :       integer, intent(inout), pointer :: ipar(:)  ! (lipar)
     376              :       real(dp), intent(inout), pointer :: rpar(:)  ! (lrpar)
     377              :       integer, intent(out) :: ierr
     378           15 :       f_03 = x*exp(-x)
     379           15 :       ierr = 0
     380           15 :       dfdx = 0
     381           15 :    end function f_03
     382              : 
     383           18 :    real(dp) function f_04(x, dfdx, lrpar, rpar, lipar, ipar, ierr)
     384              :       integer, intent(in) :: lrpar, lipar
     385              :       real(dp), intent(in) :: x
     386              :       real(dp), intent(out) :: dfdx
     387              :       integer, intent(inout), pointer :: ipar(:)  ! (lipar)
     388              :       real(dp), intent(inout), pointer :: rpar(:)  ! (lrpar)
     389              :       integer, intent(out) :: ierr
     390           18 :       f_04 = exp(x) - 1.0D+00/100.0D+00/x/x
     391           18 :       ierr = 0
     392           18 :       dfdx = 0
     393           18 :    end function f_04
     394              : 
     395           18 :    real(dp) function f_05(x, dfdx, lrpar, rpar, lipar, ipar, ierr)
     396              :       integer, intent(in) :: lrpar, lipar
     397              :       real(dp), intent(in) :: x
     398              :       real(dp), intent(out) :: dfdx
     399              :       integer, intent(inout), pointer :: ipar(:)  ! (lipar)
     400              :       real(dp), intent(inout), pointer :: rpar(:)  ! (lrpar)
     401              :       integer, intent(out) :: ierr
     402           18 :       f_05 = (x + 3.0D+00)*(x - 1.0D+00)*(x - 1.0D+00)
     403           18 :       ierr = 0
     404           18 :       dfdx = 0
     405           18 :    end function f_05
     406              : 
     407            1 :    subroutine test_brent_zero()
     408              : 
     409              :       !*****************************************************************************80
     410              :       !
     411              :       !! test_brent_zero tests Brent's zero finding routine on all test functions.
     412              :       !
     413              :       !  Licensing:
     414              :       !
     415              :       !    This code is distributed under the GNU LGPL license.
     416              :       !
     417              :       !  Modified:
     418              :       !
     419              :       !    12 April 2008
     420              :       !
     421              :       !  Author:
     422              :       !
     423              :       !    John Burkardt
     424              :       !
     425              :       implicit none
     426              : 
     427              :       real(dp) :: a
     428              :       real(dp) :: b
     429              :       real(dp) :: machep
     430              :       real(dp) :: t
     431              : 
     432            1 :       machep = epsilon(machep)
     433            1 :       t = machep
     434              : 
     435            1 :       a = 1.0D+00
     436            1 :       b = 2.0D+00
     437              : 
     438              :       call test_zero_one(a, b, machep, t, f_01, &
     439            1 :                          'f_01(x) = sin ( x ) - x / 2')
     440              : 
     441            1 :       a = 0.0D+00
     442            1 :       b = 1.0D+00
     443              : 
     444              :       call test_zero_one(a, b, machep, t, f_02, &
     445            1 :                          'f_02(x) = 2 * x - exp( - x )')
     446              : 
     447            1 :       a = -1.0D+00
     448            1 :       b = 0.5D+00
     449              : 
     450              :       call test_zero_one(a, b, machep, t, f_03, &
     451            1 :                          'f_03(x) = x * exp( - x )')
     452              : 
     453            1 :       a = 0.0001D+00
     454            1 :       b = 20.0D+00
     455              : 
     456              :       call test_zero_one(a, b, machep, t, f_04, &
     457            1 :                          'f_04(x) = exp( x ) - 1 / ( 100 * x * x )')
     458              : 
     459            1 :       a = -5.0D+00
     460            1 :       b = 2.0D+00
     461              : 
     462              :       call test_zero_one(a, b, machep, t, f_05, &
     463            1 :                          'f_05(x) = (x+3) * (x-1) * (x-1)')
     464              : 
     465            1 :    end subroutine test_brent_zero
     466              : 
     467            5 :    subroutine test_zero_one(a, b, machep, t, f, title)
     468              : 
     469              :       !*****************************************************************************80
     470              :       !
     471              :       !! TEST_ZERO_ONE tests Brent's zero finding routine on one test function.
     472              :       !
     473              :       !  Licensing:
     474              :       !
     475              :       !    This code is distributed under the GNU LGPL license.
     476              :       !
     477              :       !  Modified:
     478              :       !
     479              :       !    12 April 2008
     480              :       !
     481              :       !  Author:
     482              :       !
     483              :       !    John Burkardt
     484              :       !
     485              :       !  Parameters:
     486              :       !
     487              :       !    Input, real(dp) A, B, the two endpoints of the change of sign
     488              :       !    interval.
     489              :       !
     490              :       !    Input, real(dp) MACHEP, an estimate for the relative machine
     491              :       !    precision.
     492              :       !
     493              :       !    Input, real(dp) T, a positive error tolerance.
     494              :       !
     495              :       !    Input, external real(dp) F, the name of a user-supplied
     496              :       !    function, of the form "FUNCTION F ( X )", which evaluates the
     497              :       !    function whose zero is being sought.
     498              :       !
     499              :       !    Input, character ( LEN = * ) TITLE, a title for the problem.
     500              :       !
     501              :       implicit none
     502              : 
     503              :       interface
     504              :          include 'num_root_fcn.dek'  ! f provides function values
     505              :       end interface
     506              : 
     507              :       real(dp) :: a
     508              :       real(dp) :: b
     509              :       real(dp) :: fa
     510              :       real(dp) :: fb
     511              :       real(dp) :: fz
     512              :       real(dp) :: machep
     513              :       real(dp) :: t
     514              :       character(len=*) :: title
     515              :       real(dp) :: z
     516              :       real(dp) :: dfdx
     517              : 
     518              :       integer, parameter :: lrpar = 0, lipar = 0
     519              :       integer :: ierr
     520              :       real(dp), target :: rpar_ary(lrpar)
     521              :       integer, target :: ipar_ary(lipar)
     522              :       real(dp), pointer :: rpar(:)
     523              :       integer, pointer :: ipar(:)
     524              : 
     525              :       include 'formats'
     526              : 
     527            5 :       rpar => rpar_ary
     528            5 :       ipar => ipar_ary
     529              : 
     530              :       ierr = 0
     531            5 :       fa = f(a, dfdx, lrpar, rpar, lipar, ipar, ierr)
     532            5 :       if (ierr /= 0) call mesa_error(__FILE__, __LINE__)
     533            5 :       fb = f(b, dfdx, lrpar, rpar, lipar, ipar, ierr)
     534            5 :       if (ierr /= 0) call mesa_error(__FILE__, __LINE__)
     535            5 :       z = brent_safe_zero(a, b, machep, t, 0d0, f, fa, fb, lrpar, rpar, lipar, ipar, ierr)
     536            5 :       if (ierr /= 0) call mesa_error(__FILE__, __LINE__)
     537            5 :       fz = f(z, dfdx, lrpar, rpar, lipar, ipar, ierr)
     538            5 :       if (ierr /= 0) call mesa_error(__FILE__, __LINE__)
     539              : 
     540            5 :       if (abs(fz) < 1d-14) return
     541              : 
     542            0 :       write (*, '(a)') ' '
     543            0 :       write (*, '(a)') trim(title)
     544            0 :       write (*, 1) 'a,  z,  b', a, z, b
     545            0 :       write (*, 1) 'fa, fz, fb', fa, fz, fb
     546            0 :       write (*, '(a)') ' '
     547              : 
     548              :    end subroutine test_zero_one
     549              : 
     550              : end module test_brent
        

Generated by: LCOV version 2.0-1