Branch data Line data Source code
1 : : !!****m* ABINIT/m_brentq
2 : : !! NAME
3 : : !! m_brentq
4 : : !!
5 : : !! FUNCTION
6 : : !! This module contains Brent's root-finding method.
7 : : !! This was translated from scipy.
8 : : !! Originally written by Charles Harris charles.harris@sdl.usu.edu
9 : : !!
10 : : !! COPYRIGHT
11 : : !! Copyright (c) 2001-2002 Enthought, Inc. 2003-2024, SciPy Developers.
12 : : !! All rights reserved.
13 : : !!
14 : : !! Redistribution and use in source and binary forms, with or without
15 : : !! modification, are permitted provided that the following conditions
16 : : !! are met:
17 : : !!
18 : : !! 1. Redistributions of source code must retain the above copyright
19 : : !! notice, this list of conditions and the following disclaimer.
20 : : !!
21 : : !! 2. Redistributions in binary form must reproduce the above
22 : : !! copyright notice, this list of conditions and the following
23 : : !! disclaimer in the documentation and/or other materials provided
24 : : !! with the distribution.
25 : : !!
26 : : !! 3. Neither the name of the copyright holder nor the names of its
27 : : !! contributors may be used to endorse or promote products derived
28 : : !! from this software without specific prior written permission.
29 : : !!
30 : : !! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
31 : : !! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
32 : : !! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
33 : : !! A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
34 : : !! OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35 : : !! SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
36 : : !! LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
37 : : !! DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
38 : : !! THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39 : : !! (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
40 : : !! OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 : : !!
42 : : !! This file is distributed under the terms of the
43 : : !! GNU General Public License, see ~abinit/COPYING
44 : : !! or http://www.gnu.org/copyleft/gpl.txt .
45 : : !!
46 : : !! SOURCE
47 : :
48 : : #if defined HAVE_CONFIG_H
49 : : #include "config.h"
50 : : #endif
51 : :
52 : : #include "abi_common.h"
53 : :
54 : : MODULE m_brentq
55 : :
56 : : use defs_basis
57 : : use m_errors
58 : :
59 : : implicit none
60 : :
61 : : private
62 : :
63 : : public :: brentq
64 : :
65 : : CONTAINS !========================================================================================
66 : : !!***
67 : :
68 : : !!****f* m_brentq/brentq
69 : : !! NAME
70 : : !! brentq
71 : : !!
72 : : !! FUNCTION
73 : : !!
74 : : !! Brent's root finding method (taken from scipy).
75 : : !!
76 : : !! INPUTS
77 : : !! f= subroutine corresponding to the function for which the optimization is to be done, of the form subroutine f(x,fx)
78 : : !! xa,xb= interval on which to perform the optimization
79 : : !! xtol,rtol=tolerance criterion, the output root x0 will satisfy the criterion
80 : : !! abs(x-x0) < xtol + rtol * x0 with x the true root, default value on scipy are
81 : : !! 2e-12 and 4*machine_precision respectively
82 : : !! iter= maximum number of iterations, default value on scipy is 100
83 : : !!
84 : : !! OUTPUT
85 : : !! xcur= root
86 : : !! ierr= 1 if the algorithm converged, 0 otherwise
87 : : !!
88 : : !! SOURCE
89 : :
90 : 0 : subroutine brentq(f,xa,xb,xtol,rtol,iter,xcur,ierr)
91 : :
92 : : ! Written by Charles Harris charles.harris@sdl.usu.edu
93 : :
94 : : !Arguments ------------------------------------
95 : : interface
96 : : subroutine f(x,fx)
97 : : use defs_basis
98 : : real(dp), intent(in) :: x
99 : : real(dp), intent(out) :: fx
100 : : end subroutine f
101 : : end interface
102 : : real(dp), intent(in) :: xa,xb,xtol,rtol
103 : : integer, intent(in) :: iter
104 : : real(dp), intent(out) :: xcur
105 : : integer, intent(out) :: ierr
106 : : !Local variables ------------------------------
107 : : integer :: i
108 : : real(dp) :: dblk,delta,dpre,fblk,fcur,fpre,sbis,scur,spre,stry,xblk,xpre
109 : : character(len=200) :: msg
110 : : !************************************************************************
111 : :
112 : 0 : xpre = xa
113 : 0 : xcur = xb
114 : 0 : xblk = zero
115 : 0 : fblk = zero
116 : 0 : spre = zero
117 : 0 : scur = zero
118 : 0 : ierr = 0
119 : :
120 : : ! the tolerance is 2*delta
121 : 0 : call f(xpre,fpre)
122 : 0 : call f(xcur,fcur)
123 : :
124 [ # # ]: 0 : if (fpre == zero) then
125 : 0 : ierr = 1
126 : 0 : xcur = xpre
127 : 0 : return
128 : : end if
129 : :
130 [ # # ]: 0 : if (fcur == zero) then
131 : 0 : ierr = 1
132 : 0 : return
133 : : end if
134 : :
135 [ # # ]: 0 : if (sign(one,fpre) == sign(one,fcur)) then
136 : 0 : msg = 'Sign error in brentq'
137 : 0 : ABI_ERROR(msg)
138 : : end if
139 : :
140 [ # # ]: 0 : do i=1,iter
141 : :
142 [ # # # # : 0 : if ((fpre /= zero) .and. (fcur /= zero) .and. (sign(one,fpre) /= sign(one,fcur))) then
# # ]
143 : 0 : xblk = xpre
144 : 0 : fblk = fpre
145 : 0 : spre = xcur - xpre
146 : 0 : scur = xcur - xpre
147 : : end if
148 : :
149 [ # # ]: 0 : if (abs(fblk) < abs(fcur)) then
150 : 0 : xpre = xcur
151 : 0 : xcur = xblk
152 : 0 : xblk = xpre
153 : 0 : fpre = fcur
154 : 0 : fcur = fblk
155 : 0 : fblk = fpre
156 : : end if
157 : :
158 : 0 : delta = (xtol+rtol*abs(xcur)) * half
159 : 0 : sbis = (xblk - xcur) * half
160 [ # # # # ]: 0 : if ((fcur == zero) .or. (abs(sbis) < delta)) then
161 : 0 : ierr = 1
162 : 0 : return
163 : : end if
164 : :
165 [ # # # # ]: 0 : if ((abs(spre) > delta) .and. (abs(fcur) < abs(fpre))) then
166 [ # # ]: 0 : if (xpre == xblk) then
167 : : ! interpolate
168 : 0 : stry = -fcur * (xcur-xpre) / (fcur-fpre)
169 : : else
170 : : ! extrapolate
171 : 0 : dpre = (fpre-fcur) / (xpre-xcur)
172 : 0 : dblk = (fblk-fcur) / (xblk-xcur)
173 : 0 : stry = -fcur * (fblk*dblk-fpre*dpre) / (dblk*dpre*(fblk-fpre))
174 : : end if
175 : :
176 [ # # ]: 0 : if (two*abs(stry) < min(abs(spre),three*abs(sbis)-delta)) then
177 : : ! good short step
178 : : spre = scur
179 : : scur = stry
180 : : else
181 : : ! bisect
182 : 0 : spre = sbis
183 : 0 : scur = sbis
184 : : end if
185 : : else
186 : : ! bisect
187 : : spre = sbis
188 : : scur = sbis
189 : : end if
190 : :
191 : 0 : xpre = xcur
192 : 0 : fpre = fcur
193 : :
194 [ # # ]: 0 : if (abs(scur) > delta) then
195 : 0 : xcur = xcur + scur
196 : : else
197 [ # # ]: 0 : if (sbis > zero) then
198 : 0 : xcur = xcur + delta
199 : : else
200 : 0 : xcur = xcur - delta
201 : : end if
202 : : end if
203 : :
204 : 0 : call f(xcur,fcur)
205 : :
206 : : end do ! i
207 : :
208 : : end subroutine brentq
209 : : !!***
210 : :
211 : : !----------------------------------------------------------------------
212 : :
213 : : END MODULE m_brentq
214 : : !!***
215 : :
|