V3FIT
f1dim_mod.f90
1 
3  MODULE f1dim_mod
4  USE stel_kinds, ONLY: dp
5  INTEGER :: ncom
6  REAL(dp), DIMENSION(:), POINTER :: pcom,xicom
7 ! INTERFACE
8 ! FUNCTION func(p)
9 ! USE stel_kinds, ONLY: dp
10 ! IMPLICIT NONE
11 ! REAL(dp), DIMENSION(:), INTENT(IN) :: p
12 ! REAL(dp) :: func
13 ! END FUNCTION func
14 ! END INTERFACE
15 
16  CONTAINS
17 
19  FUNCTION f1dim(x)
20  IMPLICIT NONE
21  REAL(dp), INTENT(IN) :: x
22  REAL(dp) :: f1dim
23 !Used by linmin as the one-dimensional function passed to mnbrak and brent.
24  REAL(dp), DIMENSION(:), ALLOCATABLE :: xt
25  ALLOCATE(xt(ncom))
26  xt(:)=pcom(:)+x*xicom(:)
27  f1dim=wfunc(xt)
28  DEALLOCATE(xt)
29  END FUNCTION f1dim
30 
32  SUBROUTINE fletcher_reeves (p,ftol,iter,fret,n)
33  USE stel_kinds, ONLY: dp
34  IMPLICIT NONE
35  INTEGER, INTENT(IN) :: n
36  INTEGER, INTENT(OUT) :: iter
37  REAL(dp), INTENT(IN) :: ftol
38  REAL(dp), INTENT(OUT) :: fret
39  REAL(dp), DIMENSION(n), INTENT(INOUT) :: p
40 
41  INTEGER, PARAMETER :: itmax=50
42  REAL(dp), PARAMETER :: eps=1.0e-10_dp
43 
44 !Given a starting point p that is a vector of length N, Fletcher-Reeves-Polak-Ribiere minimization
45 !is performed on a function func, using its gradient as calculated by a routine
46 !dfunc. The convergence tolerance on the function value is input as ftol. Returned quantities
47 !are p (the location of the minimum), iter (the number of iterations that were
48 !performed), and fret (the minimum value of the function). The routine linmin is called
49 !to perform line minimizations.
50 !Parameters: ITMAX is the maximum allowed number of iterations; EPS is a small number
51 !to rectify the special case of converging to exactly zero function value.
52  INTEGER :: its
53  REAL(dp) :: dgg,fp,gam,gg
54  REAL(dp), ALLOCATABLE, DIMENSION(:) :: g, h, xi
55 ! REAL(dp), DIMENSION(SIZE(p)) :: g,h,xi
56 
57  ALLOCATE (g(SIZE(p)), h(SIZE(p)), xi(SIZE(p)))
58  fp=wfunc(p) !Initializations.
59  xi=dfunc(p)
60  g=-xi
61  h=g
62  xi=h
63  DO its=1,itmax !Loop over iterations.
64  iter=its
65  CALL linmin(p,xi,fret) !Next statement is the normal return:
66  IF (2*abs(fret-fp) <= ftol*(abs(fret)+abs(fp)+eps)) RETURN
67  fp=fret
68  xi=dfunc(p)
69  gg=dot_product(g,g)
70 ! dgg=DOT_PRODUCT(xi,xi) !This statement for Fletcher-Reeves.
71  dgg=dot_product(xi+g,xi) !This statement for Polak-Ribiere.
72  IF (gg == 0._dp) RETURN !Unlikely. If gradient is exactly zero then we are
73  gam=dgg/gg !already done.
74  g=-xi
75  h=g+gam*h
76  xi=h
77  END DO
78 
79  DEALLOCATE (g, h, xi)
80 
81  END SUBROUTINE fletcher_reeves
82 
84  FUNCTION wfunc(p)
85  USE stel_kinds, ONLY: dp
86  USE shared_functions, ONLY: getwmhd
87 ! USE diagnostics_mod, ONLY: getbgradp2
88  IMPLICIT NONE
89  REAL(dp), DIMENSION(:), INTENT(IN) :: p
90  REAL(dp) :: wfunc
91 
92  wfunc = getwmhd(p)
93 
94  END FUNCTION wfunc
95 
97  FUNCTION dfunc(p)
98  USE stel_kinds, ONLY: dp
99  USE shared_functions, ONLY: funct_island
100  USE shared_data, ONLY: xc, gc
101 ! USE diagnostics_mod, ONLY: funct_fgradp, xc, gc
102  IMPLICIT NONE
103  REAL(dp), DIMENSION(:), INTENT(IN) :: p
104  REAL(dp), DIMENSION(SIZE(p)) :: dfunc
105 
106  xc = p
107  CALL funct_island
108  dfunc = gc
109 
110  END FUNCTION dfunc
111 
113  SUBROUTINE linmin(p,xi,fret)
114  IMPLICIT NONE
115  REAL(dp), INTENT(OUT) :: fret
116  REAL(dp), DIMENSION(:), TARGET, INTENT(INOUT) :: p,xi
117  REAL(dp), PARAMETER :: tol=1.0e-4_dp
118 !Given an N-dimensional point p and an N-dimensional direction xi, both vectors of length
119 !N, moves and resets p to where the fixed-name function func takes on a minimum along
120 !the direction xi from p, and replaces xi by the actual vector displacement that p was
121 !moved. Also returns as fret the value of func at the returned location p. This is actually
122 !all accomplished by calling the routines mnbrak and brent.
123 !Parameter TOL: Tolerance passed to brent.
124  REAL(dp) :: ax,bx,fa,fb,fx,xmin,xx
125 ! REAL(dp), EXTERNAL :: brent
126 
127  ncom=SIZE(p)
128  pcom=>p !Communicate the global variables to f1dim.
129  xicom=>xi
130  ax=0 !Initial guess for brackets.
131  xx=1
132  CALL mnbrak(ax,xx,bx,fa,fx,fb,f1dim)
133  fret=brent(ax,xx,bx,f1dim,tol,xmin)
134  xi=xmin*xi !Construct the vector results to return.
135  p=p+xi
136  END SUBROUTINE linmin
137 
139  SUBROUTINE mnbrak(ax,bx,cx,fa,fb,fc,func)
140  USE stel_kinds, ONLY: dp
141  IMPLICIT NONE
142  REAL(dp), INTENT(INOUT) :: ax,bx
143  REAL(dp), INTENT(OUT) :: cx,fa,fb,fc
144  INTERFACE
145  FUNCTION func(x)
146  USE stel_kinds, ONLY: dp
147  IMPLICIT NONE
148  REAL(dp), INTENT(IN) :: x
149  REAL(dp) :: func
150  END FUNCTION func
151  END INTERFACE
152  REAL(dp), PARAMETER :: GOLD=1.618034_dp,glimit=100.0_dp,tiny=1.0e-20_dp, zero=0
153 !Given a function func, and given distinct initial points ax and bx, this routine searches
154 !in the downhill direction (defined by the function as evaluated at the initial points) and
155 !returns new points ax, bx, cx that bracket a minimum of the function. Also returned are
156 !the function values at the three points, fa, fb, and fc.
157 !Parameters: GOLD is the default ratio by which successive intervals are magnified; GLIMIT
158 !is the maximum magnification allowed for a parabolic-fit step.
159  REAL(dp) :: fu,q,r,u,ulim
160  fa=func(ax)
161  100 fb=func(bx)
162  if (fb > fa) then !Switch roles of a and b so that we
163  !can go downhill in the direction from a to b.
164 ! bx = bx/4; goto 100
165  call swap(ax,bx)
166  call swap(fa,fb)
167  end if
168  cx=bx+gold*(bx-ax) !First guess for c.
169  fc=func(cx)
170  do !Do-while-loop: Keep returning here
171  if (fb < fc) RETURN !until we bracket.
172 !Compute u by parabolic extrapolation from a, b, c. TINY is used to prevent any possible division by zero.
173  r=(bx-ax)*(fb-fc)
174  q=(bx-cx)*(fb-fa)
175  u=bx-((bx-cx)*q-(bx-ax)*r)/(2*sign(max(abs(q-r),tiny),q-r))
176  ulim=bx+glimit*(cx-bx)
177 !We won\92t go farther than this. Test various possibilities:
178  if ((bx-u)*(u-cx) > zero) then !Parabolic u is between b and c: try it.
179  fu=func(u)
180  if (fu < fc) then !Got a minimum between b and c.
181  ax=bx
182  fa=fb
183  bx=u
184  fb=fu
185  RETURN
186  else if (fu > fb) then !Got a minimum between a and u.
187  cx=u
188  fc=fu
189  RETURN
190  end if
191  u=cx+gold*(cx-bx) !Parabolic fit was no use. Use default magnification.
192  fu=func(u)
193  else if ((cx-u)*(u-ulim) > zero) then !Parabolic fit is between c and its allowed limit.
194  fu=func(u)
195  if (fu < fc) then
196  bx=cx
197  cx=u
198  u=cx+gold*(cx-bx)
199  call shft(fb,fc,fu,func(u))
200  end if
201  else if ((u-ulim)*(ulim-cx) >= zero) then !Limit parabolic u to maximum allowed value.
202  u=ulim
203  fu=func(u)
204  else !Reject parabolic u, use default magnification.
205  u=cx+gold*(cx-bx)
206  fu=func(u)
207  end if
208  call shft(ax,bx,cx,u)
209  call shft(fa,fb,fc,fu) !Eliminate oldest point and continue.
210 
211  end do
212 
213  END SUBROUTINE mnbrak
214 
216  FUNCTION brent(ax,bx,cx,func,tol,xmin)
217  USE stel_kinds, ONLY: dp
218  IMPLICIT NONE
219  REAL(dp), INTENT(IN) :: ax,bx,cx,tol
220  REAL(dp), INTENT(OUT) :: xmin
221  REAL(dp) :: brent
222  REAL(dp), EXTERNAL :: func
223 
224  INTEGER, PARAMETER :: itmax=100
225  REAL(dp), PARAMETER :: cgold=0.3819660_dp,zeps=1.0e-3_dp*epsilon(ax)
226 !Given a function func, and given a bracketing triplet of abscissas ax, bx, cx (such that bx
227 !is between ax and cx, and func(bx) is less than both func(ax) and func(cx)), this
228 !routine isolates the minimum to a fractional precision of about tol using Brent\92s method.
229 !The abscissa of the minimum is returned as xmin, and the minimum function value is
230 !returned as brent, the returned function value.
231 !Parameters: ITMAX, Maximum allowed number of iterations;gol den ratio; and a small number that
232 !protects against trying to achieve fractional accuracy for a minimum that happens to be
233 !exactly zero.
234  INTEGER :: iter
235  REAL(dp) :: a,b,d,e,etemp,fu,fv,fw,fx,p,q,r,tol1,tol2,u,v,w,x,xm
236 
237  a=min(ax,cx) !a and b must be in ascending order, though
238  b=max(ax,cx) !the input abscissas need not be.
239  v=bx !Initializations...
240  w=v
241  x=v
242  e=0 !This will be the distance moved on the step before last.
243  fx=func(x)
244  fv=fx
245  fw=fx
246  do iter=1,itmax !Main program loop.
247  xm=0.5_dp*(a+b)
248  tol1=tol*abs(x)+zeps
249  tol2=2*tol1
250  if (abs(x-xm) <= (tol2-0.5_dp*(b-a))) then !Test for done here.
251  xmin=x !Arrive here ready to exit with best values.
252  brent=fx
253  RETURN
254  end if
255  if (abs(e) > tol1) then !Construct a trial parabolic fit.
256  r=(x-w)*(fx-fv)
257  q=(x-v)*(fx-fw)
258  p=(x-v)*q-(x-w)*r
259  q=2*(q-r)
260  if (q > 0.0_dp) p=-p
261  q=abs(q)
262  etemp=e
263  e=d
264  if (abs(p) >= abs(0.5_dp*q*etemp) .or. &
265  p <= q*(a-x) .or. p >= q*(b-x)) then
266 !The above conditions determine the acceptability of the parabolic fit. Here it is
267 !not o.k., so we take the golden section step into the larger of the two segments.
268  e=merge(a-x,b-x, x >= xm)
269  d=cgold*e
270  else !Take the parabolic step.
271  d=p/q
272  u=x+d
273  if (u-a < tol2 .or. b-u < tol2) d=sign(tol1,xm-x)
274  end if
275  else !Take the golden section step into the larger
276  e=merge(a-x,b-x, x >= xm ) !of the two segments.
277  d=cgold*e
278  end if
279  u=merge(x+d,x+sign(tol1,d), abs(d) >= tol1 )
280 !Arrive here with d computed either from parabolic fit, or else from golden section.
281  fu=func(u)
282 !This is the one function evaluation per iteration.
283  if (fu <= fx) then !Now we have to decide what to do with our
284  if (u >= x) then !function evaluation. Housekeeping follows:
285  a=x
286  else
287  b=x
288  end if
289  call shft(v,w,x,u)
290  call shft(fv,fw,fx,fu)
291  else
292  if (u < x) then
293  a=u
294  else
295  b=u
296  end if
297  if (fu <= fw .or. w == x) then
298  v=w
299  fv=fw
300  w=u
301  fw=fu
302  else if (fu <= fv .or. v == x .or. v == w) then
303  v=u
304  fv=fu
305  end if
306  end if
307  end do !Done with housekeeping. Back for another iteration
308 
309  END FUNCTION brent
310 
312  SUBROUTINE swap(a,b)
313  USE stel_kinds, ONLY: dp
314  REAL(dp), INTENT(INOUT) :: a,b
315  REAL(dp) :: dum
316 
317  dum=a
318  a=b
319  b=dum
320  END SUBROUTINE swap
321 
323  SUBROUTINE shft(a,b,c,d)
324  USE stel_kinds, ONLY: dp
325  REAL(dp), INTENT(OUT) :: a
326  REAL(dp), INTENT(INOUT) :: b,c
327  REAL(dp), INTENT(IN) :: d
328 
329  a=b
330  b=c
331  c=d
332  END SUBROUTINE shft
333 
334  END MODULE f1dim_mod
shared_functions
Module contained subroutines and functions updating MHD forces and Wmhd.
Definition: shared_functions.f90:4
shared_data::xc
real(dp), dimension(:), allocatable xc
1D array of Fourier mode displacement components.
Definition: shared_data.f90:97
f1dim_mod
Module containing Fletcher-Reeves (non-linear Conjugate Gradient) routines including linear search al...
Definition: f1dim_mod.f90:3
shared_data::gc
real(dp), dimension(:), allocatable, target gc
1D Array of Fourier mode MHD force components
Definition: shared_data.f90:99
shared_data
This file contains variables and parameters used by many modules in SIESTA.
Definition: shared_data.f90:10