rootstest.f90
Go to the documentation of this file.
1 !#############################################################################
2 !# #
3 !# fosite - 3D hydrodynamical simulation program #
4 !# module: rootstest.f90 #
5 !# #
6 !# Copyright (C) 2016 #
7 !# Tobias Illenseer <tillense@astrophysik.uni-kiel.de> #
8 !# #
9 !# This program is free software; you can redistribute it and/or modify #
10 !# it under the terms of the GNU General Public License as published by #
11 !# the Free Software Foundation; either version 2 of the License, or (at #
12 !# your option) any later version. #
13 !# #
14 !# This program is distributed in the hope that it will be useful, but #
15 !# WITHOUT ANY WARRANTY; without even the implied warranty of #
16 !# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or #
17 !# NON INFRINGEMENT. See the GNU General Public License for more #
18 !# details. #
19 !# #
20 !# You should have received a copy of the GNU General Public License #
21 !# along with this program; if not, write to the Free Software #
22 !# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #
23 !# #
24 !#############################################################################
25 
26 !----------------------------------------------------------------------------!
31 !----------------------------------------------------------------------------!
32 PROGRAM rootstest
33  USE roots
34 #include "tap.h"
35  IMPLICIT NONE
36  !--------------------------------------------------------------------------!
37  INTERFACE
38  PURE SUBROUTINE func(x,fx,plist)
39  IMPLICIT NONE
40  REAL, INTENT(IN) :: x
41  REAL, INTENT(IN), DIMENSION(:), OPTIONAL :: plist
42  REAL, INTENT(OUT) :: fx
43  END SUBROUTINE func
44  END INTERFACE
45  INTERFACE
46  PURE SUBROUTINE funcd(x,fx,dfx,plist)
47  IMPLICIT NONE
48  REAL, INTENT(IN) :: x
49  REAL, INTENT(IN), DIMENSION(:), OPTIONAL :: plist
50  REAL, INTENT(OUT) :: fx,dfx
51  END SUBROUTINE funcd
52  END INTERFACE
53  COMMON /test_num/ k
54  !--------------------------------------------------------------------------!
55  INTEGER, PARAMETER :: num_tests = 13
56  INTEGER, PARAMETER :: num_methods = 8
57  CHARACTER(LEN=16), PARAMETER, DIMENSION(NUM_METHODS) :: method_name = (/ &
58  " Bisection", &
59  " Regula Falsi", &
60  " Pegasus", &
61  " King", &
62  " Anderson Bjoerk", &
63  " Ridder", &
64  " Brent Dekker", &
65  " Newton" /)
66  REAL, PARAMETER, DIMENSION(2,NUM_TESTS) :: bounds = reshape((/ 0.0, 1.2, &
67  0.4, 1.6, &
68  -0.5, 1.9, &
69  -0.5, 0.7, &
70  -1.4, 1.0, &
71  -0.8, 1.6, &
72  -0.5, 1.9, &
73  0.001, 1.201, &
74  -0.9, 1.5, &
75  0.4, 1.0, &
76  -1.2, 0.0, &
77  1.0, 3.4, &
78  0.0, 5.0 /), &
79  (/2,num_tests/))
80  DOUBLE PRECISION, PARAMETER, DIMENSION(NUM_TESTS) :: ref_roots = &
81  (/ 3.9942229171096819451d-01, 8.0413309750366432374d-01, 9.0340766319186021294d-01, &
82  7.7014241346192677110d-02, 2.5920449372984746773d-01, 5.3674166257799978186d-01, &
83  4.4754176206055907112d-01, 1.1111111111111111111d-01, 5.0000003403025908310d-01, &
84  6.7980892150470050192d-01, -3.5938136638046273022d-01, 1.6487212707001281468d-00, &
85  1.0000000000000000000d-00 &
86  /)
87  !--------------------------------------------------------------------------!
88  REAL :: root, xm, dx_rel, dx_acc, plist(1)
89  INTEGER :: i,k, iter, error
90  CHARACTER(LEN=64) :: tap_message
91  LOGICAL :: verbose_results = .false.
92  !--------------------------------------------------------------------------!
93  ! some information
94  WRITE (*,"(A)") "========================================================="
95  WRITE (*,"(A)") " << Testing root finding algorithms >> "
96  WRITE (*,"(A)") "========================================================="
97 
98 
99  tap_plan((num_methods-1)*num_tests)
100 
101  DO k=1,num_tests
102  ! plist is an array of real parameters that can be passed to the function func
103  ! so far just a dummy, but it can be used if necessary;
104  plist(1) = 1.0
105  ! reset error code; if GetRoot returns error .ne. 0 something bad happend
106  error = 0
107  ! initial guess: arithmetic mean of boundary values
108  xm = 0.5*(bounds(1,k)+bounds(2,k))
109  print '(A,I2,A,2(ES10.2))', "Test #",k," Search Interval: ",bounds(1,k),bounds(2,k)
110  print '(A)', "---------------------------------------------------------"
111  IF (verbose_results) print '(A20,ES27.19)', "reference result", ref_roots(k)
112  DO i=1,num_methods
113  SELECT CASE(i)
114  CASE(1)
115  CALL getroot_bisection(func,bounds(1,k),bounds(2,k),root,error,plist,xm,iter)
116  CASE(2)
117  ! don't use Regula Falsi because of slow convergence in some cases
118  CALL getroot_regulafalsi(func,bounds(1,k),bounds(2,k),root,error,plist,xm,iter)
119  CASE(3)
120  CALL getroot_pegasus(func,bounds(1,k),bounds(2,k),root,error,plist,xm,iter)
121  CASE(4)
122  CALL getroot_king(func,bounds(1,k),bounds(2,k),root,error,plist,xm,iter)
123  CASE(5)
124  CALL getroot_andersonbjoerk(func,bounds(1,k),bounds(2,k),root,error,plist,xm,iter)
125  CASE(6)
126  CALL getroot_ridder(func,bounds(1,k),bounds(2,k),root,error,plist,xm,iter)
127  CASE(7)
128  CALL getroot_brentdekker(func,bounds(1,k),bounds(2,k),root,error,plist,xm,iter)
129  CASE(8)
130  CALL getroot_newton(funcd,bounds(1,k),bounds(2,k),root,error,plist,xm,iter)
131  END SELECT
132 
133  ! compute the relative error using reference root
134  dx_rel = abs(1.0-root/ref_roots(k))
135  IF (verbose_results) CALL printresults(method_name(i),root,ref_roots(k),error,iter)
136  ! exclude Regular Falsi from check
137  IF (i.NE.2) THEN
138 
139  dx_acc = default_accuracy
140  IF (k.EQ.12) THEN
141  ! this test never yields the required accuracy, see \cite engeln2011
142  dx_acc = 1.0e-5
143  END IF
144  WRITE (tap_message,'(A16,A11,ES9.2,A3,ES9.2)') method_name(i), ": dx_rel = ", dx_rel, " < ", dx_acc
145  tap_check(dx_rel.LE.dx_acc,tap_message)
146 
147  END IF
148  END DO
149  print '(A)', "---------------------------------------------------------"
150  END DO
151 
152  tap_done
153 
154 CONTAINS
155 
156 
157  SUBROUTINE printresults(method,root,ref_root,error,iter)
158  IMPLICIT NONE
159  CHARACTER(LEN=*), INTENT(IN) :: method
160  REAL, INTENT(IN) :: root
161  DOUBLE PRECISION, INTENT(IN) :: ref_root
162  INTEGER, INTENT(IN) :: error,iter
163  IF (error.NE.0) THEN
164  print *,trim(geterrormessage(error))
165  ELSE
166  print '(A20,ES23.15,ES9.1,I4)',trim(method),root,abs(1.0-root/ref_root),iter
167  END IF
168  END SUBROUTINE printresults
169 
170 
171 ! TAP_PLAN(7)
172 !
173 !
174 !
175 ! ! Check if the random numbers are in (0,1)
176 ! ! and if the average is near 0.5
177 ! TAP_CHECK_CLOSE(r/imax,0.5,1.E-4,"Average close to 0.5.")
178 ! TAP_CHECK_GE(rmin,0.,"All are bigger (or equal) than 0.")
179 ! TAP_CHECK_LE(root,1.,"All are smaller (or equal) than 1.")
180 ! TAP_CHECK_CLOSE(rmin,0.,1.E-4,"Lower limit is close to 0.")
181 ! TAP_CHECK_CLOSE(rmax,1.,1.E-4,"Upper limit is close to 1.")
182 !
183 ! TAP_CHECK(x.EQ.x0,"SuperKiss64")
184 !
185 
186 END PROGRAM rootstest
187 
188 
189 ! function definitions
190 PURE SUBROUTINE func(x,fx,plist)
191 IMPLICIT NONE
192  COMMON /test_num/ k
193  REAL, INTENT(IN) :: x
194  REAL, INTENT(IN), DIMENSION(:), OPTIONAL :: plist
195  REAL, INTENT(OUT) :: fx
196  INTEGER :: k
197  SELECT CASE(k)
198  CASE(1)
199  fx = x*x*(x*x/3. + sqrt(2.)*sin(x)) - sqrt(3.)/18.
200  CASE(2)
201  fx = 11*x**11 - 1.0
202  CASE(3)
203  fx = 35*x**35 - 1.0
204  CASE(4)
205  fx = 2*(x*exp(-9.)-exp(-9*x)) + 1.
206  CASE(5)
207  fx = x*x - (1.-x)**9
208  CASE(6)
209  fx = (x-1.)*exp(-9*x) + x**9
210  CASE(7)
211  fx = x*x + sin(x/9.) - 0.25
212  CASE(8)
213  fx = 0.125*(9.-1./x)
214  CASE(9)
215  fx = tan(x) - x - 0.0463025
216  CASE(10)
217  fx = x*(x+sin(sqrt(75.)*x)) - 0.2
218  CASE(11)
219  fx = x**9 + 1e-4
220  CASE(12)
221  fx = log(x) + 0.5*x*x/exp(1.) -2*x/sqrt(exp(1.)) + 1.
222  CASE DEFAULT
223  fx = x - 1.0
224  END SELECT
225 END SUBROUTINE func
226 
227 
228 PURE SUBROUTINE funcd(x,fx,dfx,plist)
229  IMPLICIT NONE
230  COMMON /test_num/ k
231  REAL, INTENT(IN) :: x
232  REAL, INTENT(IN), DIMENSION(:), OPTIONAL :: plist
233  REAL, INTENT(OUT) :: fx,dfx
234  INTEGER :: k
235  SELECT CASE(k)
236  CASE(1)
237  fx = x*x*(x*x/3. + sqrt(2.)*sin(x)) - sqrt(3.)/18.
238  dfx= 2*x*(sqrt(2.)*sin(x)+x*x/3.)+x*x*(sqrt(2.)*cos(x)+(2*x)/3.)
239  CASE(2)
240  fx = 11*x**11 - 1.0
241  dfx = 121*x**10
242  CASE(3)
243  fx = 35*x**35 - 1.0
244  dfx= 35*35*x**34 - 1.0
245  CASE(4)
246  fx = 2*(x*exp(-9.)-exp(-9*x)) + 1.
247  dfx= 2*(9*exp(-9*x)+exp(-9.))
248  CASE(5)
249  fx = x*x - (1.-x)**9
250  dfx= 2*x + 9*(1.-x)**8
251  CASE(6)
252  fx = (x-1.)*exp(-9*x) + x**9
253  dfx= (10.-9*x)*exp(-9*x) + 9*x**8
254  CASE(7)
255  fx = x*x + sin(x/9.) - 0.25
256  dfx= 2*x + cos(x/9.)/9.
257  CASE(8)
258  fx = 0.125*(9.-1./x)
259  dfx= 0.125/x**2
260  CASE(9)
261  fx = tan(x) - x - 0.0463025
262  dfx= 1./cos(x)**2 - 1.
263  CASE(10)
264  fx = x*(x+sin(sqrt(75.)*x)) - 0.2
265  dfx= sin(sqrt(75.)*x) + x*(2. + sqrt(75.)*cos(sqrt(75.)*x))
266  CASE(11)
267  fx = x**9 + 1e-4
268  dfx= 9*x**8
269  CASE(12)
270  fx = log(x) + 0.5*x*x/exp(1.) - 2*x/sqrt(exp(1.)) + 1.
271  dfx= 1./x + x/exp(1.) - 2./sqrt(exp(1.))
272  CASE DEFAULT
273  fx = x - 1.0
274  dfx= 1.
275  END SELECT
276 END SUBROUTINE funcd
277 
pure subroutine funcd(y, fy, dfy, plist)
Definition: bondi2d.f90:416
subroutine, public getroot_newton(funcd, x1, x2, root, error, plist, xm, iterations)
Definition: roots.f90:247
program rootstest
Definition: rootstest.f90:32
subroutine, public getroot_pegasus(func, x1, x2, root, error, plist, xm, iterations)
Definition: roots.f90:349
subroutine, public getroot_bisection(func, x1, x2, root, error, plist, xm, iterations)
Definition: roots.f90:519
subroutine, public getroot_brentdekker(func, x1, x2, root, error, plist, xm, iterations)
Definition: roots.f90:485
subroutine printresults(method, root, ref_root, error, iter)
Definition: rootstest.f90:158
pure subroutine func(x, fx, plist)
Definition: rootstest.f90:191
subroutine, public getroot_andersonbjoerk(func, x1, x2, root, error, plist, xm, iterations)
Definition: roots.f90:417
real, parameter, public default_accuracy
Definition: roots.f90:67
root finding subroutines
Definition: roots.f90:45
subroutine, public getroot_regulafalsi(func, x1, x2, root, error, plist, xm, iterations)
Definition: roots.f90:315
subroutine, public getroot_ridder(func, x1, x2, root, error, plist, xm, iterations)
Definition: roots.f90:451
character(len=64) function, public geterrormessage(error)
Definition: roots.f90:160
subroutine, public getroot_king(func, x1, x2, root, error, plist, xm, iterations)
Definition: roots.f90:383