Line data Source code
1 : ! ***********************************************************************
2 : !
3 : ! Copyright (C) 2012 The MESA Team
4 : !
5 : ! This program is free software: you can redistribute it and/or modify
6 : ! it under the terms of the GNU Lesser General Public License
7 : ! as published by the Free Software Foundation,
8 : ! either version 3 of the License, or (at your option) any later version.
9 : !
10 : ! This program is distributed in the hope that it will be useful,
11 : ! but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : ! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 : ! See the GNU Lesser General Public License for more details.
14 : !
15 : ! You should have received a copy of the GNU Lesser General Public License
16 : ! along with this program. If not, see <https://www.gnu.org/licenses/>.
17 : !
18 : ! ***********************************************************************
19 :
20 : module bicub_sg
21 :
22 : !implicit none
23 :
24 : contains
25 : ! from PSPLINE by Doug McCune (version as of February, 2004)
26 :
27 :
28 : ! PSPLINE Home Page:
29 : ! http://w3.pppl.gov/NTCC/PSPLINE
30 :
31 : ! Doug McCune, Princeton University
32 : ! dmccune@pppl.gov
33 :
34 :
35 : ! bcspeval -- eval bicubic spline function and/or derivatives
36 :
37 0 : subroutine bcspeval(xget,yget,iselect,fval,x,nx,y,ny,ilinx,iliny,f,inf3,ier)
38 :
39 : integer iselect(6)
40 : integer ilinx,iliny,nx,ny,inf3,ier
41 :
42 : real xget,yget
43 : real fval(6)
44 : !real x(nx),y(ny),f(4,4,inf3,ny)
45 : real x(:),y(:),f(:,:,:,:)
46 :
47 : ! modification -- dmc 11 Jan 1999 -- remove SAVE stmts; break routine
48 : ! into these parts:
49 :
50 : ! bcspevxy -- find grid cell of target pt.
51 : ! bcspevfn -- evaluate function using output of bcpsevxy
52 :
53 : ! in cases where multiple functions are defined on the same grid,
54 : ! time can be saved by using bcspevxy once and then bcspevfn
55 : ! multiple times.
56 :
57 : ! input:
58 : ! (xget,yget) location where interpolated value is desired
59 : ! x(1) <= xget <= x(nx) expected
60 : ! y(1) <= yget <= y(ny) expected
61 :
62 : ! iselect select desired output
63 :
64 : ! iselect(1)=1 -- want function value (f) itself
65 : ! iselect(2)=1 -- want df/dx
66 : ! iselect(3)=1 -- want df/dy
67 : ! iselect(4)=1 -- want d2f/dx2
68 : ! iselect(5)=1 -- want d2f/dy2
69 : ! iselect(6)=1 -- want d2f/dxdy
70 :
71 : ! example: iselect(1)=iselect(2)=iselect(3)=1
72 : ! f, df/dx, and df/dy all evaluated
73 : ! iselect(4)=iselect(5)=iselect(6)=0
74 : ! 2nd derivatives not evaluated.
75 :
76 : ! the number of non zero values iselect(1:6)
77 : ! determines the number of outputs...
78 : ! see fval (output) description.
79 :
80 : ! new dmc December 2005 -- access to higher derivatives (even if not
81 : ! continuous-- but can only go up to 3rd derivatives on any one coordinate.
82 : ! if iselect(1)=3 -- want 3rd derivatives
83 : ! iselect(2)=1 for d3f/dx3
84 : ! iselect(3)=1 for d3f/dx2dy
85 : ! iselect(4)=1 for d3f/dxdy2
86 : ! iselect(5)=1 for d3f/dy3
87 : ! number of non-zero values iselect(2:5) gives no. of outputs
88 : ! if iselect(1)=4 -- want 4th derivatives
89 : ! iselect(2)=1 for d4f/dx3dy
90 : ! iselect(3)=1 for d4f/dx2dy2
91 : ! iselect(4)=1 for d4f/dxdy3
92 : ! number of non-zero values iselect(2:4) gives no. of outputs
93 : ! if iselect(1)=5 -- want 5th derivatives
94 : ! iselect(2)=1 for d5f/dx3dy2
95 : ! iselect(3)=1 for d5f/dx2dy3
96 : ! number of non-zero values iselect(2:3) gives no. of outputs
97 : ! if iselect(1)=6 -- want 6th derivatives
98 : ! d6f/dx3dy3 -- one value is returned.
99 :
100 : ! x(1...nx) independent coordinate x, strict ascending
101 : ! y(1...ny) independent coordinate y, strict ascending
102 :
103 : ! ilinx -- =1: flag that x is linearly spaced (avoid search for speed)
104 : ! iliny -- =1: flag that y is linearly spaced (avoid search for speed)
105 :
106 : ! **CAUTION** actual even spacing of x, y is NOT CHECKED HERE!
107 :
108 : !
109 : ! f the function values (at grid points) and spline coefs
110 :
111 : ! evaluation formula: for point x btw x(i) and x(i+1), dx=x-x(i)
112 : ! and y btw y(j) and y(j+1), dy=y-y(j),
113 :
114 : ! spline value =
115 : ! f(1,1,i,j) + dx*f(2,1,i,j) + dx**2*f(3,1,i,j) + dx**3*f(4,1,i,j)
116 : ! +dy*(f(1,2,i,j) + dx*f(2,2,i,j) + dx**2*f(3,2,i,j) + dx**3*f(4,2,i,j))
117 : ! +d2*(f(1,3,i,j) + dx*f(2,3,i,j) + dx**2*f(3,3,i,j) + dx**3*f(4,3,i,j))
118 : ! +d3*(f(1,4,i,j) + dx*f(2,4,i,j) + dx**2*f(3,4,i,j) + dx**3*f(4,4,i,j))
119 :
120 : ! where d2=dy**2 and d3=dy**3.
121 :
122 : ! output:
123 : ! up to 6 elements of fval, ordered as follows:
124 : ! fval(1)=function value or lowest order derivative requested
125 : ! fval(2)=next order derivative
126 : ! etc
127 : ! the ordering is a subset of the sequence given under the "iselect"
128 : ! description.
129 :
130 : ! ier = 0 -- successful completion; = 1 -- an error occurred.
131 :
132 : !-------------------------------------------------------------------
133 : ! local
134 :
135 0 : real dx,dy
136 : integer ia(1), ja(1)
137 :
138 : !--------------------------
139 :
140 0 : ia(1) = 0
141 0 : ja(1) = 0
142 : call bcspevxy(xget,yget,x,nx,y,ny,ilinx,iliny,
143 0 : & 0,0,dx,dy,ier)
144 0 : if(ier /= 0) return
145 :
146 : call bcspevfn(iselect,1,1,fval,ia,ja,
147 0 : & (/dx/),(/dy/),f,inf3,ny)
148 :
149 0 : return
150 : end subroutine bcspeval
151 :
152 : !-------------------------------------------------------------------------
153 :
154 :
155 : ! bcspevxy -- look up x-y zone
156 :
157 : ! this is the "first part" of bcspeval, see comments, above.
158 :
159 0 : subroutine bcspevxy(xget,yget,x,nx,y,ny,ilinx,iliny,
160 : & i,j,dx,dy,ier)
161 :
162 : integer nx,ny ! array dimensions
163 :
164 : real xget,yget ! target point
165 : !real x(nx),y(ny) ! indep. coords.
166 : real x(:),y(:) ! indep. coords.
167 :
168 : integer ilinx ! =1: assume x evenly spaced
169 : integer iliny ! =1: assume y evenly spaced
170 :
171 : ! output of bcspevxy
172 :
173 : integer i,j ! index to cell containing target pt
174 : real dx,dy ! displacement of target pt w/in cell
175 : ! dx=x-x(i) dy=y-y(j)
176 :
177 : integer ier ! return ier /= 0 on error
178 :
179 : !------------------------------------
180 0 : real zxget, zyget, zxtol, zytol
181 : integer nxm, nym, ii, jj
182 :
183 0 : ier=0
184 :
185 : ! range check
186 :
187 0 : zxget=xget
188 0 : zyget=yget
189 :
190 0 : if((xget < x(1)).or.(xget > x(nx))) then
191 0 : zxtol=4.0e-7*max(abs(x(1)),abs(x(nx)))
192 0 : if((xget < x(1)-zxtol).or.(xget > x(nx)+zxtol)) then
193 0 : ier=1
194 : ! write(6,1001) xget,x(1),x(nx)
195 : ! 1001 format(' ?bcspeval: xget=',1pe11.4,' out of range ', 1pe11.4,' to ',1pe11.4)
196 : else
197 : ! if((xget < x(1)-0.5*zxtol).or. (xget > x(nx)+0.5*zxtol)) write(6,1011) xget,x(1),x(nx)
198 : ! 1011 format(' %bcspeval: xget=',1pe15.8,' beyond range ', 1pe15.8,' to ',1pe15.8,' (fixup applied)')
199 0 : if(xget < x(1)) then
200 0 : zxget=x(1)
201 : else
202 0 : zxget=x(nx)
203 : end if
204 : end if
205 : end if
206 0 : if((yget < y(1)).or.(yget > y(ny))) then
207 0 : zytol=4.0e-7*max(abs(y(1)),abs(y(ny)))
208 0 : if((yget < y(1)-zytol).or.(yget > y(ny)+zytol)) then
209 0 : ier=1
210 : ! write(6,1002) yget,y(1),y(ny)
211 : ! 1002 format(' ?bcspeval: yget=',1pe11.4,' out of range ', 1pe11.4,' to ',1pe11.4)
212 : else
213 : ! if((yget < y(1)-0.5*zytol).or.(yget > y(ny)+0.5*zytol)) write(6,1012) yget,y(1),y(ny)
214 : ! 1012 format(' %bcspeval: yget=',1pe15.8,' beyond range ', 1pe15.8,' to ',1pe15.8,' (fixup applied)')
215 0 : if(yget < y(1)) then
216 0 : zyget=y(1)
217 : else
218 0 : zyget=y(ny)
219 : end if
220 : end if
221 : end if
222 0 : if(ier /= 0) return
223 :
224 : ! now find interval in which target point lies..
225 :
226 0 : nxm=nx-1
227 0 : nym=ny-1
228 :
229 0 : if(ilinx == 1) then
230 0 : ii=1+nxm*(zxget-x(1))/(x(nx)-x(1))
231 0 : i=min(nxm, ii)
232 0 : if(zxget < x(i)) then
233 0 : i=i-1
234 0 : else if(zxget > x(i+1)) then
235 0 : i=i+1
236 : end if
237 : else
238 0 : if((1 <= i).and.(i < nxm)) then
239 0 : if((x(i) <= zxget).and.(zxget <= x(i+1))) then
240 : continue ! already have the zone
241 : else
242 0 : call zonfind(x,nx,zxget,i)
243 : end if
244 : else
245 0 : call zonfind(x,nx,zxget,i)
246 : end if
247 : end if
248 :
249 0 : if(iliny == 1) then
250 0 : jj=1+nym*(zyget-y(1))/(y(ny)-y(1))
251 0 : j=min(nym, jj)
252 0 : if(zyget < y(j)) then
253 0 : j=j-1
254 0 : else if(zyget > y(j+1)) then
255 0 : j=j+1
256 : end if
257 : else
258 0 : if((1 <= j).and.(j < nym)) then
259 0 : if((y(j) <= zyget).and.(zyget <= y(j+1))) then
260 : continue ! already have the zone
261 : else
262 0 : call zonfind(y,ny,zyget,j)
263 : end if
264 : else
265 0 : call zonfind(y,ny,zyget,j)
266 : end if
267 : end if
268 :
269 0 : dx=zxget-x(i)
270 0 : dy=zyget-y(j)
271 :
272 0 : return
273 : end subroutine bcspevxy
274 :
275 :
276 : !------------------------------------------------------------------------
277 : ! bcspevfn -- OK now evaluate the bicubic spline
278 :
279 0 : subroutine bcspevfn(ict,ivec,ivd,fval,iv,jv,dxv,dyv,f,inf3,ny)
280 :
281 : ! input:
282 : integer ny
283 : integer ict(6) ! selector:
284 : ! ict(1)=1 for f (don't evaluate f if ict(1)=0)
285 : ! ict(2)=1 for df/dx ""
286 : ! ict(3)=1 for df/dy ""
287 : ! ict(4)=1 for d2f/dx2
288 : ! ict(5)=1 for d2f/dy2
289 : ! ict(6)=1 for d2f/dxdy
290 :
291 : ! note: if ict(1)=-1, evaluate f,d2f/dx2,d2f/dy2,d4f/dx2dy2
292 :
293 : ! the number of non zero values ict(1:6)
294 : ! determines the number of outputs...
295 :
296 : ! new dmc December 2005 -- access to higher derivatives (even if not
297 : ! continuous-- but can only go up to 3rd derivatives on any one coordinate.
298 : ! if ict(1)=3 -- want 3rd derivatives
299 : ! ict(2)=1 for d3f/dx3
300 : ! ict(3)=1 for d3f/dx2dy
301 : ! ict(4)=1 for d3f/dxdy2
302 : ! ict(5)=1 for d3f/dy3
303 : ! number of non-zero values ict(2:5) gives no. of outputs
304 : ! if ict(1)=4 -- want 4th derivatives
305 : ! ict(2)=1 for d4f/dx3dy
306 : ! ict(3)=1 for d4f/dx2dy2
307 : ! ict(4)=1 for d4f/dxdy3
308 : ! number of non-zero values ict(2:4) gives no. of outputs
309 : ! if ict(1)=5 -- want 5th derivatives
310 : ! ict(2)=1 for d5f/dx3dy2
311 : ! ict(3)=1 for d5f/dx2dy3
312 : ! number of non-zero values ict(2:3) gives no. of outputs
313 : ! if ict(1)=6 -- want 6th derivatives
314 : ! d6f/dx3dy3 -- one value is returned.
315 :
316 : integer ivec,ivd ! vector dimensioning
317 :
318 : ! ivec-- number of vector pts (spline values to look up)
319 : ! ivd -- 1st dimension of fval, >= ivec
320 :
321 : ! output:
322 : real fval(ivd,6) ! output array
323 :
324 : ! v = index to element in vector;
325 : ! fval(v,1) = first item requested by ict(...),
326 : ! fval(v,2) = 2nd item requested, ...etc...
327 :
328 : ! input:
329 : !integer iv(ivec),jv(ivec) ! grid cell indices -- vectors
330 : !real dxv(ivec),dyv(ivec) ! displacements w/in cell -- vectors
331 : integer iv(:),jv(:) ! grid cell indices -- vectors
332 : real dxv(:),dyv(:) ! displacements w/in cell -- vectors
333 :
334 : integer inf3 ! 3rd dimension of f -- >= nx
335 : real f(:,:,:,:) ! (4,4,inf3,ny) ! bicubic fcn spline coeffs array
336 :
337 : ! usage example:
338 :
339 : ! 1. for each element (xx(v),yy(v)) in a vector of (x,y) pairs,
340 : ! find the x and y zone indices and displacements with respect
341 : ! to the "lower left corner" of the zone; store these in vectors
342 : ! iv,jv and dxv,dyv.
343 :
344 : ! 2. set ict(1)=0, ict(2)=1, ict(3)=1, the rest zero -- get only
345 : ! the 1st derivatives.
346 :
347 : ! 3. ivec is the length of the vector; ivd is the 1st dimension
348 : ! of the array fval to receive the output
349 :
350 : ! real fval(ivd,6)
351 : ! real xv(ivd),yv(ivd)
352 : ! integer iv(ivd),jv(ivd)
353 : ! real dxv(ivd),dyv(ivd)
354 : ! integer ict(6)
355 :
356 : ! real fspline(4,4,nx,ny) ! spline coeffs
357 : ! data ict/0,1,1,0,0,0/ ! this call: want 1st derivatives
358 : ! ! only ... these will be output to
359 : ! ! fval(*,1) fval(*,2)
360 : ! ...
361 : ! do iv=1,ivec
362 : ! ... ! find indices and displacements
363 : ! end do
364 : ! call bcspevfn(ict,ivec,ivd,fval,iv,jv,dxv,dyv,fspline,nx,ny)
365 :
366 : !-------------------------------------------------------------------
367 : ! local:
368 :
369 : integer v ! vector element index
370 : integer iaval, i, j
371 0 : real dx, dy
372 :
373 : ! OK can now do evaluations
374 :
375 0 : iaval=0 ! fval addressing
376 :
377 0 : if(ict(1) <= 2) then
378 0 : if((ict(1) > 0).or.(ict(1) == -1)) then
379 : ! evaluate f
380 0 : iaval=iaval+1
381 0 : do v=1,ivec
382 0 : i=iv(v)
383 0 : j=jv(v)
384 0 : dx=dxv(v)
385 0 : dy=dyv(v)
386 : fval(v,iaval)=
387 : & f(1,1,i,j)+dy*(f(1,2,i,j)+dy*(f(1,3,i,j)+dy*f(1,4,i,j)))
388 : & +dx*(f(2,1,i,j)+dy*(f(2,2,i,j)+dy*(f(2,3,i,j)+dy*f(2,4,i,j)))
389 : & +dx*(f(3,1,i,j)+dy*(f(3,2,i,j)+dy*(f(3,3,i,j)+dy*f(3,4,i,j)))
390 0 : & +dx*(f(4,1,i,j)+dy*(f(4,2,i,j)+dy*(f(4,3,i,j)+dy*f(4,4,i,j))))))
391 : end do
392 : end if
393 :
394 0 : if((ict(2) > 0).and.(ict(1) /= -1)) then
395 : ! evaluate df/dx
396 0 : iaval=iaval+1
397 0 : do v=1,ivec
398 0 : i=iv(v)
399 0 : j=jv(v)
400 0 : dx=dxv(v)
401 0 : dy=dyv(v)
402 : fval(v,iaval)=
403 : & f(2,1,i,j)+dy*(f(2,2,i,j)+dy*(f(2,3,i,j)+dy*f(2,4,i,j)))
404 : & +2.0*dx*(
405 : & f(3,1,i,j)+dy*(f(3,2,i,j)+dy*(f(3,3,i,j)+dy*f(3,4,i,j)))
406 : & +1.5*dx*(
407 : & f(4,1,i,j)+dy*(f(4,2,i,j)+dy*(f(4,3,i,j)+dy*f(4,4,i,j)))
408 0 : & ))
409 : end do
410 : end if
411 :
412 0 : if((ict(3) > 0).and.(ict(1) /= -1)) then
413 : ! evaluate df/dy
414 0 : iaval=iaval+1
415 0 : do v=1,ivec
416 0 : i=iv(v)
417 0 : j=jv(v)
418 0 : dx=dxv(v)
419 0 : dy=dyv(v)
420 : fval(v,iaval)=
421 : & f(1,2,i,j)+dy*(2.0*f(1,3,i,j)+dy*3.0*f(1,4,i,j))
422 : & +dx*(f(2,2,i,j)+dy*(2.0*f(2,3,i,j)+dy*3.0*f(2,4,i,j))
423 : & +dx*(f(3,2,i,j)+dy*(2.0*f(3,3,i,j)+dy*3.0*f(3,4,i,j))
424 : & +dx*(f(4,2,i,j)+dy*(2.0*f(4,3,i,j)+dy*3.0*f(4,4,i,j))
425 0 : & )))
426 : end do
427 : end if
428 :
429 0 : if((ict(4) > 0).or.(ict(1) == -1)) then
430 : ! evaluate d2f/dx2
431 0 : iaval=iaval+1
432 0 : do v=1,ivec
433 0 : i=iv(v)
434 0 : j=jv(v)
435 0 : dx=dxv(v)
436 0 : dy=dyv(v)
437 : fval(v,iaval)=
438 : & 2.0*(
439 : & f(3,1,i,j)+dy*(f(3,2,i,j)+dy*(f(3,3,i,j)+dy*f(3,4,i,j))))
440 : & +6.0*dx*(
441 0 : & f(4,1,i,j)+dy*(f(4,2,i,j)+dy*(f(4,3,i,j)+dy*f(4,4,i,j))))
442 : end do
443 : end if
444 :
445 0 : if((ict(5) > 0).or.(ict(1) == -1)) then
446 : ! evaluate d2f/dy2
447 0 : iaval=iaval+1
448 0 : do v=1,ivec
449 0 : i=iv(v)
450 0 : j=jv(v)
451 0 : dx=dxv(v)
452 0 : dy=dyv(v)
453 : fval(v,iaval)=
454 : & 2.0*f(1,3,i,j)+6.0*dy*f(1,4,i,j)
455 : & +dx*(2.0*f(2,3,i,j)+6.0*dy*f(2,4,i,j)
456 : & +dx*(2.0*f(3,3,i,j)+6.0*dy*f(3,4,i,j)
457 0 : & +dx*(2.0*f(4,3,i,j)+6.0*dy*f(4,4,i,j))))
458 : end do
459 : end if
460 :
461 0 : if((ict(6) > 0).and.(ict(1) /= -1)) then
462 : ! evaluate d2f/dxdy
463 0 : iaval=iaval+1
464 0 : do v=1,ivec
465 0 : i=iv(v)
466 0 : j=jv(v)
467 0 : dx=dxv(v)
468 0 : dy=dyv(v)
469 : fval(v,iaval)=
470 : & f(2,2,i,j)+dy*(2.0*f(2,3,i,j)+dy*3.0*f(2,4,i,j))
471 : & +2.*dx*(f(3,2,i,j)+dy*(2.0*f(3,3,i,j)+dy*3.0*f(3,4,i,j))
472 : &+1.5*dx*(f(4,2,i,j)+dy*(2.0*f(4,3,i,j)+dy*3.0*f(4,4,i,j))
473 0 : & ))
474 : end do
475 : end if
476 :
477 0 : if(ict(1) == -1) then
478 0 : iaval=iaval+1
479 0 : do v=1,ivec
480 0 : i=iv(v)
481 0 : j=jv(v)
482 0 : dx=dxv(v)
483 0 : dy=dyv(v)
484 : fval(v,iaval)=
485 : & 4.0*f(3,3,i,j)+12.0*dy*f(3,4,i,j)
486 0 : & +dx*(12.0*f(4,3,i,j)+36.0*dy*f(4,4,i,j))
487 : end do
488 : end if
489 :
490 : !-----------------------------------
491 : ! access to 3rd derivatives
492 :
493 0 : else if(ict(1) == 3) then
494 0 : if(ict(2) == 1) then
495 : ! evaluate d3f/dx3 (not continuous)
496 0 : iaval=iaval+1
497 0 : do v=1,ivec
498 0 : i=iv(v)
499 0 : j=jv(v)
500 0 : dy=dyv(v)
501 : fval(v,iaval)=
502 : & +6.0*(
503 0 : & f(4,1,i,j)+dy*(f(4,2,i,j)+dy*(f(4,3,i,j)+dy*f(4,4,i,j))))
504 : end do
505 : end if
506 :
507 0 : if(ict(3) == 1) then
508 : ! evaluate d3f/dx2dy
509 0 : iaval=iaval+1
510 0 : do v=1,ivec
511 0 : i=iv(v)
512 0 : j=jv(v)
513 0 : dx=dxv(v)
514 0 : dy=dyv(v)
515 : fval(v,iaval)=
516 : & 2.0*(
517 : & f(3,2,i,j)+dy*(2.0*f(3,3,i,j)+dy*3.0*f(3,4,i,j)))
518 : & +6.0*dx*(
519 0 : & f(4,2,i,j)+dy*(2.0*f(4,3,i,j)+dy*3.0*f(4,4,i,j)))
520 : end do
521 : end if
522 :
523 0 : if(ict(4) == 1) then
524 : ! evaluate d3f/dxdy2
525 0 : iaval=iaval+1
526 0 : do v=1,ivec
527 0 : i=iv(v)
528 0 : j=jv(v)
529 0 : dx=dxv(v)
530 0 : dy=dyv(v)
531 : fval(v,iaval)=
532 : & (2.0*f(2,3,i,j)+6.0*dy*f(2,4,i,j)
533 : & +2.0*dx*(2.0*f(3,3,i,j)+6.0*dy*f(3,4,i,j)
534 : & +1.5*dx*(2.0*f(4,3,i,j)+6.0*dy*f(4,4,i,j))
535 0 : & ))
536 : end do
537 : end if
538 :
539 0 : if(ict(5) == 1) then
540 : ! evaluate d3f/dy3 (not continuous)
541 0 : iaval=iaval+1
542 0 : do v=1,ivec
543 0 : i=iv(v)
544 0 : j=jv(v)
545 0 : dx=dxv(v)
546 : fval(v,iaval)=6.0*(f(1,4,i,j)+
547 0 : & dx*(f(2,4,i,j)+dx*(f(3,4,i,j)+dx*f(4,4,i,j))))
548 : end do
549 : end if
550 :
551 : !-----------------------------------
552 : ! access to 4th derivatives
553 :
554 0 : else if(ict(1) == 4) then
555 0 : if(ict(2) == 1) then
556 : ! evaluate d4f/dx3dy (not continuous)
557 0 : iaval=iaval+1
558 0 : do v=1,ivec
559 0 : i=iv(v)
560 0 : j=jv(v)
561 0 : dy=dyv(v)
562 : fval(v,iaval)=
563 : & +6.0*(
564 0 : & f(4,2,i,j)+dy*2.0*(f(4,3,i,j)+dy*1.5*f(4,4,i,j)))
565 : end do
566 : end if
567 :
568 0 : if(ict(3) == 1) then
569 : ! evaluate d4f/dx2dy2
570 0 : iaval=iaval+1
571 0 : do v=1,ivec
572 0 : i=iv(v)
573 0 : j=jv(v)
574 0 : dx=dxv(v)
575 0 : dy=dyv(v)
576 : fval(v,iaval)=
577 : & 4.0*f(3,3,i,j)+12.0*dy*f(3,4,i,j)
578 0 : & +dx*(12.0*f(4,3,i,j)+36.0*dy*f(4,4,i,j))
579 : end do
580 : end if
581 :
582 0 : if(ict(4) == 1) then
583 : ! evaluate d4f/dxdy3 (not continuous)
584 0 : iaval=iaval+1
585 0 : do v=1,ivec
586 0 : i=iv(v)
587 0 : j=jv(v)
588 0 : dx=dxv(v)
589 : fval(v,iaval)=
590 : & 6.0*(f(2,4,i,j)
591 0 : & +2.0*dx*(f(3,4,i,j)+1.5*dx*f(4,4,i,j)))
592 : end do
593 : end if
594 :
595 : !-----------------------------------
596 : ! access to 5th derivatives
597 :
598 0 : else if(ict(1) == 5) then
599 0 : if(ict(2) == 1) then
600 : ! evaluate d5f/dx3dy2 (not continuous)
601 0 : iaval=iaval+1
602 0 : do v=1,ivec
603 0 : i=iv(v)
604 0 : j=jv(v)
605 0 : dy=dyv(v)
606 : fval(v,iaval)=
607 0 : & +12.0*(f(4,3,i,j)+dy*3.0*f(4,4,i,j))
608 : end do
609 : end if
610 :
611 0 : if(ict(3) == 1) then
612 : ! evaluate d5f/dx3dy2 (not continuous)
613 0 : iaval=iaval+1
614 0 : do v=1,ivec
615 0 : i=iv(v)
616 0 : j=jv(v)
617 0 : dx=dxv(v)
618 : fval(v,iaval)=
619 0 : & 12.0*(f(3,4,i,j)+dx*3.0*f(4,4,i,j))
620 : end do
621 : end if
622 :
623 : !-----------------------------------
624 : ! access to 6th derivatives
625 :
626 0 : else if(ict(1) == 6) then
627 : ! evaluate d6f/dx3dy3 (not continuous)
628 0 : iaval=iaval+1
629 0 : do v=1,ivec
630 0 : i=iv(v)
631 0 : j=jv(v)
632 0 : fval(v,iaval) = 36.0*f(4,4,i,j)
633 : end do
634 : end if
635 :
636 0 : return
637 : end subroutine bcspevfn
638 : !----------------------
639 :
640 :
641 : ! cspline -- dmc 15 Feb 1999
642 :
643 : ! a standard interface to the 1d spline setup routine
644 : ! modified dmc 3 Mar 2000 -- to use Wayne Houlberg's v_spline code.
645 : ! new BC options added.
646 :
647 97 : subroutine cspline(x,nx,fspl,ibcxmin,bcxmin,ibcxmax,bcxmax,wk,iwk,ilinx,ier)
648 :
649 : integer nx, iwk
650 : real x(nx) ! x axis (in)
651 : real fspl(4,nx) ! spline data (in/out)
652 : integer ibcxmin ! x(1) BC flag (in, see comments)
653 : real bcxmin ! x(1) BC data (in, see comments)
654 : integer ibcxmax ! x(nx) BC flag (in, see comments)
655 : real bcxmax ! x(nx) BC data (in, see comments)
656 : real wk(iwk) ! workspace of size at least nx
657 : integer ilinx ! even spacing flag (out)
658 : integer ier ! output, =0 means OK
659 :
660 : ! ** note wk(...) array is not used unless ibcxmin=-1 (periodic spline
661 : ! evaluation)
662 :
663 : ! this routine computes spline coefficients for a 1d spline --
664 : ! evaluation of the spline can be done by cspeval.for subroutines
665 : ! or directly by inline code.
666 :
667 : ! the input x axis x(1...nx) must be strictly ascending, i.e.
668 : ! x(i+1) > x(i) is required for i=1 to nx-1. This is checked and
669 : ! ier=1 is set and the routine exits if the test is not satisfied.
670 :
671 : ! on output, ilinx=1 is set if, to a reasonably close tolerance,
672 : ! all grid spacings x(i+1)-x(i) are equal. This allows a speedier
673 : ! grid lookup algorithm on evaluation of the spline. If on output
674 : ! ilinx=2, this means the spline x axis is not evenly spaced.
675 :
676 : ! the input data for the spline are given in f[j] = fspl(1,j). The
677 : ! output data are the spline coefficients fspl(2,j),fspl(3,j), and
678 : ! fspl(4,j), j=1 to nx. The result is a spline s(x) satisfying the
679 : ! boundary conditions and with the properties
680 :
681 : ! s(x(j)) = fspl(1,j)
682 : ! s'(x) is continuous even at the grid points x(j)
683 : ! s''(x) is continuous even at the grid points x(j)
684 :
685 : ! the formula for evaluation of s(x) is:
686 :
687 : ! let dx = x-x(i), where x(i) <= x <= x(i+1). Then,
688 : ! s(x)=fspl(1,i) + dx*(fspl(2,i) +dx*(fspl(3,i) + dx*fspl(4,i)))
689 :
690 : ! ==>boundary conditions. Complete specification of a 1d spline
691 : ! requires specification of boundary conditions at x(1) and x(nx).
692 :
693 : ! this routine provides 4 options:
694 :
695 : ! -1 ***** PERIODIC BC
696 : ! ibcxmin=-1 -- periodic boundary condition. This means the
697 : ! boundary conditions s'(x(1))=s'(x(nx)) and s''(x(1))=s''(x(nx))
698 : ! are imposed. Note that s(x(1))=s(x(nx)) (i.e. fspl(1,1)=fspl(1,nx))
699 : ! is not required -- that is determined by the fspl array input data.
700 : ! The periodic boundary condition is to be preferred for periodic
701 : ! data. When splining periodic data f(x) with period P, the relation
702 : ! x(nx)=x(1)+n*P, n = the number of periods (usually 1), should hold.
703 : ! (ibcxmax, bcxmin, bcxmax are ignored).
704 :
705 : ! if a periodic boundary condition is set, this covers both boundaries.
706 : ! for the other types of boundary conditions, the type of condition
707 : ! chosen for the x(1) boundary need not be the same as the type chosen
708 : ! for the x(nx) boundary.
709 :
710 : ! 0 ***** NOT A KNOT BC
711 : ! ibcxmin=0 | ibcxmax=0 -- this specifies a "not a knot" boundary
712 : ! condition -- see cubsplb.for. This is a common way for inferring
713 : ! a "good" spline boundary condition automatically from data in the
714 : ! vicinity of the boundary. (bcxmin | bcxmax are ignored).
715 :
716 : ! 1 ***** BC: SPECIFIED SLOPE
717 : ! ibcxmin=1 | ibcxmax=1 -- boundary condition is to have s'(x(1)) |
718 : ! s'(x(nx)) match the passed value (bcxmin | bcxmax).
719 :
720 : ! 2 ***** BC: SPECIFIED 2nd DERIVATIVE
721 : ! ibcxmin=2 | ibcxmax=2 -- boundary condition is to have s''(x(1)) |
722 : ! s''(x(nx)) match the passed value (bcxmin | bcxmax).
723 :
724 : ! 3 ***** BC: SPECIFIED SLOPE = 0.0
725 : ! ibcxmin=3 | ibcxmax=3 -- boundary condition is to have s'(x(1)) |
726 : ! s'(x(nx)) equal to ZERO.
727 :
728 : ! 4 ***** BC: SPECIFIED 2nd DERIVATIVE = 0.0
729 : ! ibcxmin=4 | ibcxmax=4 -- boundary condition is to have s''(x(1)) |
730 : ! s''(x(nx)) equal to ZERO.
731 :
732 : ! 5 ***** BC: 1st DIVIDED DIFFERENCE
733 : ! ibcxmin=5 | ibcxmax=5 -- boundary condition is to have s'(x(1)) |
734 : ! s'(x(nx)) equal to the slope from the 1st|last 2 points
735 :
736 : ! 6 ***** BC: 2nd DIVIDED DIFFERENCE
737 : ! ibcxmin=6 | ibcxmax=6 -- boundary condition is to have s''(x(1)) |
738 : ! s''(x(nx)) equal to the 2nd derivative from the 1st|last 3 points
739 :
740 : ! 7 ***** BC: 3rd DIVIDED DIFFERENCE
741 : ! ibcxmin=7 | ibcxmax=7 -- boundary condition is to have s'''(x(1)) |
742 : ! s'''(x(nx)) equal to the 3rd derivative from the 1st|last 4 points
743 :
744 : !---------------------------------------------------------------------
745 : real, parameter :: half = 0.5
746 : real, parameter :: sixth = 1.0/6.0
747 : integer::ierx,inum,i
748 :
749 : ! error checks
750 :
751 97 : ier = 0
752 97 : if(nx < 4) then
753 0 : write(6,'('' ?cspline: at least 4 x points required.'')')
754 0 : ier=1
755 : end if
756 97 : call ibc_ck(ibcxmin,'cspline','xmin',-1,7,ier)
757 97 : if(ibcxmin >= 0) call ibc_ck(ibcxmax,'cspline','xmax',0,7,ier)
758 :
759 : ! x axis check
760 :
761 97 : call splinck(x,nx,ilinx,1.0e-3,ierx)
762 97 : if(ierx /= 0) ier=2
763 :
764 97 : if(ier == 2) then
765 0 : write(6,'('' ?cspline: x axis not strict ascending'')')
766 : end if
767 :
768 97 : if(ibcxmin == -1) then
769 0 : inum=nx
770 0 : if(iwk < inum) then
771 0 : write(6,1009) inum,iwk,nx
772 : 1009 format(
773 : & ' ?cspline: workspace too small. need: ',i6,' got: ',i6/
774 : & ' (need = nx, nx=',i6)
775 0 : ier=3
776 : end if
777 : end if
778 :
779 97 : if(ier /= 0) return
780 :
781 : ! OK -- evaluate spline
782 :
783 97 : if(ibcxmin == 1) then
784 0 : fspl(2,1)=bcxmin
785 97 : else if(ibcxmin == 2) then
786 0 : fspl(3,1)=bcxmin
787 : end if
788 :
789 97 : if(ibcxmax == 1) then
790 0 : fspl(2,nx)=bcxmax
791 97 : else if(ibcxmax == 2) then
792 0 : fspl(3,nx)=bcxmax
793 : end if
794 :
795 97 : call v_spline(ibcxmin,ibcxmax,nx,x,fspl,wk)
796 :
797 3352 : do i=1,nx
798 3255 : fspl(3,i)=half*fspl(3,i)
799 3352 : fspl(4,i)=sixth*fspl(4,i)
800 : end do
801 :
802 : return
803 : end subroutine cspline
804 :
805 0 : subroutine evbicub(xget,yget,x,nx,y,ny,ilinx,iliny,f1,inf2,ict,fval,ier)
806 :
807 : ! use mkbicub to set up spline coefficients!
808 :
809 : ! evaluate a 2d cubic Spline interpolant on a rectilinear
810 : ! grid -- this is C2 in both directions.
811 :
812 : ! this subroutine calls two subroutines:
813 : ! herm2xy -- find cell containing (xget,yget)
814 : ! fvbicub -- evaluate interpolant function and (optionally) derivatives
815 :
816 : ! input arguments:
817 : ! ================
818 :
819 : integer nx,ny ! grid sizes
820 : real xget,yget ! target of this interpolation
821 : real x(nx) ! ordered x grid
822 : real y(ny) ! ordered y grid
823 : integer ilinx ! ilinx=1 => assume x evenly spaced
824 : integer iliny ! iliny=1 => assume y evenly spaced
825 :
826 : integer inf2
827 : real, pointer :: f1(:) ! =(0:3,inf2,ny) interpolant data (cf "evbicub")
828 :
829 : ! f 2nd dimension inf2 must be >= nx
830 : ! contents of f:
831 :
832 : ! f(0,i,j) = f @ x(i),y(j)
833 : ! f(1,i,j) = d2f/dx2 @ x(i),y(j)
834 : ! f(2,i,j) = d2f/dy2 @ x(i),y(j)
835 : ! f(3,i,j) = d4f/dx2dy2 @ x(i),y(j)
836 :
837 : ! (these are spline coefficients selected for continuous 2-
838 : ! diffentiability, see mkbicub[w].for)
839 :
840 : integer ict(6) ! code specifying output desired
841 :
842 : ! ict(1)=1 -- return f (0, don't)
843 : ! ict(2)=1 -- return df/dx (0, don't)
844 : ! ict(3)=1 -- return df/dy (0, don't)
845 : ! ict(4)=1 -- return d2f/dx2 (0, don't)
846 : ! ict(5)=1 -- return d2f/dy2 (0, don't)
847 : ! ict(6)=1 -- return d2f/dxdy (0, don't)
848 : ! the number of non zero values ict(1:6)
849 : ! determines the number of outputs...
850 :
851 : ! new dmc December 2005 -- access to higher derivatives (even if not
852 : ! continuous-- but can only go up to 3rd derivatives on any one coordinate.
853 : ! if ict(1)=3 -- want 3rd derivatives
854 : ! ict(2)=1 for d3f/dx3
855 : ! ict(3)=1 for d3f/dx2dy
856 : ! ict(4)=1 for d3f/dxdy2
857 : ! ict(5)=1 for d3f/dy3
858 : ! number of non-zero values ict(2:5) gives no. of outputs
859 : ! if ict(1)=4 -- want 4th derivatives
860 : ! ict(2)=1 for d4f/dx3dy
861 : ! ict(3)=1 for d4f/dx2dy2
862 : ! ict(4)=1 for d4f/dxdy3
863 : ! number of non-zero values ict(2:4) gives no. of outputs
864 : ! if ict(1)=5 -- want 5th derivatives
865 : ! ict(2)=1 for d5f/dx3dy2
866 : ! ict(3)=1 for d5f/dx2dy3
867 : ! number of non-zero values ict(2:3) gives no. of outputs
868 : ! if ict(1)=6 -- want 6th derivatives
869 : ! d6f/dx3dy3 -- one value is returned.
870 :
871 : ! output arguments:
872 : ! =================
873 :
874 : real fval(6) ! output data
875 : integer ier ! error code =0 ==> no error
876 :
877 : ! fval(1) receives the first output (depends on ict(...) spec)
878 : ! fval(2) receives the second output (depends on ict(...) spec)
879 : ! fval(3) receives the third output (depends on ict(...) spec)
880 : ! fval(4) receives the fourth output (depends on ict(...) spec)
881 : ! fval(5) receives the fourth output (depends on ict(...) spec)
882 : ! fval(6) receives the fourth output (depends on ict(...) spec)
883 :
884 : ! examples:
885 : ! on input ict = [1,1,1,0,0,1]
886 : ! on output fval= [f,df/dx,df/dy,d2f/dxdy], elements 5 & 6 not referenced.
887 :
888 : ! on input ict = [1,0,0,0,0,0]
889 : ! on output fval= [f] ... elements 2 -- 6 never referenced.
890 :
891 : ! on input ict = [0,0,0,1,1,0]
892 : ! on output fval= [d2f/dx2,d2f/dy2] ... elements 3 -- 6 never referenced.
893 :
894 : ! on input ict = [0,0,1,0,0,0]
895 : ! on output fval= [df/dy] ... elements 2 -- 6 never referenced.
896 :
897 : ! ier -- completion code: 0 means OK
898 : !-------------------
899 : ! local:
900 :
901 : integer i,j ! cell indices
902 :
903 : ! normalized displacement from (x(i),y(j)) corner of cell.
904 : ! xparam=0 @x(i) xparam=1 @x(i+1)
905 : ! yparam=0 @y(j) yparam=1 @y(j+1)
906 :
907 0 : real xparam,yparam
908 :
909 : ! cell dimensions and
910 : ! inverse cell dimensions hxi = 1/(x(i+1)-x(i)), hyi = 1/(y(j+1)-y(j))
911 :
912 0 : real hx,hy
913 0 : real hxi,hyi
914 :
915 : ! 0 <= xparam <= 1
916 : ! 0 <= yparam <= 1
917 :
918 : ! ** the interface is very similar to herm2ev.for; can use herm2xy **
919 : !---------------------------------------------------------------------
920 :
921 : call herm2xy(xget,yget,x,nx,y,ny,ilinx,iliny,
922 0 : & i,j,xparam,yparam,hx,hxi,hy,hyi,ier)
923 0 : if(ier /= 0) return
924 :
925 : call fvbicub(ict,1,1,
926 : & fval,(/i/),(/j/),(/xparam/),(/yparam/),
927 0 : & (/hx/),(/hxi/),(/hy/),(/hyi/),f1,inf2,ny)
928 :
929 0 : return
930 : end subroutine evbicub
931 :
932 : !---------------------------------------------------------------------
933 : ! evaluate C1 cubic Hermite function interpolation -- 2d fcn
934 : ! --vectorized-- dmc 10 Feb 1999
935 :
936 : ! use mkbicub to set up spline coefficients!
937 :
938 6 : subroutine fvbicub(ict,ivec,ivecd,
939 6 : & fval,ii,jj,xparam,yparam,hx,hxi,hy,hyi,
940 : & f1,inf2,ny)
941 :
942 : integer ny
943 : integer ict(6) ! requested output control
944 : integer ivec ! vector length
945 : integer ivecd ! vector dimension (1st dim of fval)
946 :
947 : integer ii(ivec),jj(ivec) ! target cells (i,j)
948 : real xparam(ivec),yparam(ivec)
949 : ! normalized displacements from (i,j) corners
950 :
951 : real hx(ivec),hy(ivec) ! grid spacing, and
952 : real hxi(ivec),hyi(ivec) ! inverse grid spacing 1/(x(i+1)-x(i))
953 : ! & 1/(y(j+1)-y(j))
954 :
955 : integer inf2
956 : real, pointer :: f1(:) ! =(0:3,inf2,ny) interpolant data (cf "evbicub")
957 :
958 : real fval(ivecd,6) ! output returned
959 :
960 : ! for detailed description of fin, ict and fval see subroutine
961 : ! evbicub comments. Note ict is not vectorized; the same output
962 : ! is expected to be returned for all input vector data points.
963 :
964 : ! note that the index inputs ii,jj and parameter inputs
965 : ! xparam,yparam,hx,hxi,hy,hyi are vectorized, and the
966 : ! output array fval has a vector ** 1st dimension ** whose
967 : ! size must be given as a separate argument
968 :
969 : ! to use this routine in scalar mode, pass in ivec=ivecd=1
970 :
971 : !---------------
972 : ! Spline evaluation consists of a "mixing" of the interpolant
973 : ! data using the linear functionals xparam, xpi = 1-xparam,
974 : ! yparam, ypi = 1-yparam, and the cubic functionals
975 : ! xparam**3-xparam, xpi**3-xpi, yparam**3-yparam, ypi**3-ypi ...
976 : ! and their derivatives as needed.
977 :
978 : integer v,z36th,iadr,i,j
979 6 : real sum,xp,yp,xpi,ypi,xp2,yp2,xpi2,ypi2
980 6 : real cx,cy,cyd,cxi,cyi,cydi,hx2,hy2,cxd,cxdi
981 :
982 : real, parameter :: sixth = 0.166666666666666667
983 :
984 6 : real, pointer :: fin(:,:,:)
985 6 : fin(0:3,1:inf2,1:ny) => f1(1:4*inf2*ny)
986 :
987 :
988 : !---------------
989 : ! ...in x direction
990 :
991 6 : z36th=sixth*sixth
992 6 : iadr=0
993 :
994 6 : if(ict(1) <= 2) then
995 :
996 : ! get desired values:
997 :
998 6 : if(ict(1) == 1) then
999 :
1000 : ! function value:
1001 :
1002 12 : iadr=iadr+1
1003 12 : do v=1,ivec
1004 6 : i=ii(v)
1005 6 : j=jj(v)
1006 :
1007 : ! in x direction...
1008 :
1009 6 : xp=xparam(v)
1010 6 : xpi=1.0-xp
1011 6 : xp2=xp*xp
1012 6 : xpi2=xpi*xpi
1013 :
1014 6 : cx=xp*(xp2-1.0)
1015 6 : cxi=xpi*(xpi2-1.0)
1016 6 : hx2=hx(v)*hx(v)
1017 :
1018 : ! ...and in y direction
1019 :
1020 6 : yp=yparam(v)
1021 6 : ypi=1.0-yp
1022 6 : yp2=yp*yp
1023 6 : ypi2=ypi*ypi
1024 :
1025 6 : cy=yp*(yp2-1.0)
1026 6 : cyi=ypi*(ypi2-1.0)
1027 6 : hy2=hy(v)*hy(v)
1028 :
1029 : sum=xpi*(ypi*fin(0,i,j) +yp*fin(0,i,j+1))+
1030 6 : & xp*(ypi*fin(0,i+1,j)+yp*fin(0,i+1,j+1))
1031 :
1032 : sum=sum+sixth*hx2*(
1033 : & cxi*(ypi*fin(1,i,j) +yp*fin(1,i,j+1))+
1034 6 : & cx*(ypi*fin(1,i+1,j)+yp*fin(1,i+1,j+1)))
1035 :
1036 : sum=sum+sixth*hy2*(
1037 : & xpi*(cyi*fin(2,i,j) +cy*fin(2,i,j+1))+
1038 6 : & xp*(cyi*fin(2,i+1,j)+cy*fin(2,i+1,j+1)))
1039 :
1040 : sum=sum+z36th*hx2*hy2*(
1041 : & cxi*(cyi*fin(3,i,j) +cy*fin(3,i,j+1))+
1042 6 : & cx*(cyi*fin(3,i+1,j)+cy*fin(3,i+1,j+1)))
1043 :
1044 12 : fval(v,iadr)=sum
1045 : end do
1046 : end if
1047 :
1048 6 : if(ict(2) == 1) then
1049 :
1050 : ! df/dx:
1051 :
1052 6 : iadr=iadr+1
1053 12 : do v=1,ivec
1054 6 : i=ii(v)
1055 6 : j=jj(v)
1056 :
1057 : ! in x direction...
1058 :
1059 6 : xp=xparam(v)
1060 6 : xpi=1.0-xp
1061 6 : xp2=xp*xp
1062 6 : xpi2=xpi*xpi
1063 :
1064 6 : cxd=3.0*xp2-1.0
1065 6 : cxdi=-3.0*xpi2+1.0
1066 :
1067 : ! ...and in y direction
1068 :
1069 6 : yp=yparam(v)
1070 6 : ypi=1.0-yp
1071 6 : yp2=yp*yp
1072 6 : ypi2=ypi*ypi
1073 :
1074 6 : cy=yp*(yp2-1.0)
1075 6 : cyi=ypi*(ypi2-1.0)
1076 6 : hy2=hy(v)*hy(v)
1077 :
1078 : sum=hxi(v)*(
1079 : & -(ypi*fin(0,i,j) +yp*fin(0,i,j+1))
1080 6 : & +(ypi*fin(0,i+1,j)+yp*fin(0,i+1,j+1)))
1081 :
1082 : sum=sum+sixth*hx(v)*(
1083 : & cxdi*(ypi*fin(1,i,j) +yp*fin(1,i,j+1))+
1084 6 : & cxd*(ypi*fin(1,i+1,j)+yp*fin(1,i+1,j+1)))
1085 :
1086 : sum=sum+sixth*hxi(v)*hy2*(
1087 : & -(cyi*fin(2,i,j) +cy*fin(2,i,j+1))
1088 6 : & +(cyi*fin(2,i+1,j)+cy*fin(2,i+1,j+1)))
1089 :
1090 : sum=sum+z36th*hx(v)*hy2*(
1091 : & cxdi*(cyi*fin(3,i,j) +cy*fin(3,i,j+1))+
1092 6 : & cxd*(cyi*fin(3,i+1,j)+cy*fin(3,i+1,j+1)))
1093 :
1094 12 : fval(v,iadr)=sum
1095 : end do
1096 : end if
1097 :
1098 6 : if(ict(3) == 1) then
1099 :
1100 : ! df/dy:
1101 :
1102 6 : iadr=iadr+1
1103 12 : do v=1,ivec
1104 6 : i=ii(v)
1105 6 : j=jj(v)
1106 :
1107 : ! in x direction...
1108 :
1109 6 : xp=xparam(v)
1110 6 : xpi=1.0-xp
1111 6 : xp2=xp*xp
1112 6 : xpi2=xpi*xpi
1113 :
1114 6 : cx=xp*(xp2-1.0)
1115 6 : cxi=xpi*(xpi2-1.0)
1116 6 : hx2=hx(v)*hx(v)
1117 :
1118 : ! ...and in y direction
1119 :
1120 6 : yp=yparam(v)
1121 6 : ypi=1.0-yp
1122 6 : yp2=yp*yp
1123 6 : ypi2=ypi*ypi
1124 :
1125 6 : cyd=3.0*yp2-1.0
1126 6 : cydi=-3.0*ypi2+1.0
1127 :
1128 : sum=hyi(v)*(
1129 : & xpi*(-fin(0,i,j) +fin(0,i,j+1))+
1130 6 : & xp*(-fin(0,i+1,j)+fin(0,i+1,j+1)))
1131 :
1132 : sum=sum+sixth*hx2*hyi(v)*(
1133 : & cxi*(-fin(1,i,j) +fin(1,i,j+1))+
1134 6 : & cx*(-fin(1,i+1,j)+fin(1,i+1,j+1)))
1135 :
1136 : sum=sum+sixth*hy(v)*(
1137 : & xpi*(cydi*fin(2,i,j) +cyd*fin(2,i,j+1))+
1138 6 : & xp*(cydi*fin(2,i+1,j)+cyd*fin(2,i+1,j+1)))
1139 :
1140 : sum=sum+z36th*hx2*hy(v)*(
1141 : & cxi*(cydi*fin(3,i,j) +cyd*fin(3,i,j+1))+
1142 6 : & cx*(cydi*fin(3,i+1,j)+cyd*fin(3,i+1,j+1)))
1143 :
1144 12 : fval(v,iadr)=sum
1145 : end do
1146 : end if
1147 :
1148 6 : if(ict(4) == 1) then
1149 :
1150 : ! d2f/dx2:
1151 :
1152 0 : iadr=iadr+1
1153 0 : do v=1,ivec
1154 0 : i=ii(v)
1155 0 : j=jj(v)
1156 :
1157 : ! in x direction...
1158 :
1159 0 : xp=xparam(v)
1160 0 : xpi=1.0-xp
1161 :
1162 : ! ...and in y direction
1163 :
1164 0 : yp=yparam(v)
1165 0 : ypi=1.0-yp
1166 0 : yp2=yp*yp
1167 0 : ypi2=ypi*ypi
1168 :
1169 0 : cy=yp*(yp2-1.0)
1170 0 : cyi=ypi*(ypi2-1.0)
1171 0 : hy2=hy(v)*hy(v)
1172 :
1173 : sum=(
1174 : & xpi*(ypi*fin(1,i,j) +yp*fin(1,i,j+1))+
1175 0 : & xp*(ypi*fin(1,i+1,j)+yp*fin(1,i+1,j+1)))
1176 :
1177 : sum=sum+sixth*hy2*(
1178 : & xpi*(cyi*fin(3,i,j) +cy*fin(3,i,j+1))+
1179 0 : & xp*(cyi*fin(3,i+1,j)+cy*fin(3,i+1,j+1)))
1180 :
1181 0 : fval(v,iadr)=sum
1182 : end do
1183 : end if
1184 :
1185 6 : if(ict(5) == 1) then
1186 :
1187 : ! d2f/dy2:
1188 :
1189 0 : iadr=iadr+1
1190 0 : do v=1,ivec
1191 0 : i=ii(v)
1192 0 : j=jj(v)
1193 :
1194 : ! in x direction...
1195 :
1196 0 : xp=xparam(v)
1197 0 : xpi=1.0-xp
1198 0 : xp2=xp*xp
1199 0 : xpi2=xpi*xpi
1200 :
1201 0 : cx=xp*(xp2-1.0)
1202 0 : cxi=xpi*(xpi2-1.0)
1203 0 : hx2=hx(v)*hx(v)
1204 :
1205 : ! ...and in y direction
1206 :
1207 0 : yp=yparam(v)
1208 0 : ypi=1.0-yp
1209 :
1210 : sum=(
1211 : & xpi*(ypi*fin(2,i,j) +yp*fin(2,i,j+1))+
1212 0 : & xp*(ypi*fin(2,i+1,j)+yp*fin(2,i+1,j+1)))
1213 :
1214 : sum=sum+sixth*hx2*(
1215 : & cxi*(ypi*fin(3,i,j) +yp*fin(3,i,j+1))+
1216 0 : & cx*(ypi*fin(3,i+1,j)+yp*fin(3,i+1,j+1)))
1217 :
1218 0 : fval(v,iadr)=sum
1219 : end do
1220 : end if
1221 :
1222 6 : if(ict(6) == 1) then
1223 :
1224 : ! d2f/dxdy:
1225 :
1226 0 : iadr=iadr+1
1227 0 : do v=1,ivec
1228 0 : i=ii(v)
1229 0 : j=jj(v)
1230 :
1231 : ! in x direction...
1232 :
1233 0 : xp=xparam(v)
1234 0 : xpi=1.0-xp
1235 0 : xp2=xp*xp
1236 0 : xpi2=xpi*xpi
1237 :
1238 0 : cxd=3.0*xp2-1.0
1239 0 : cxdi=-3.0*xpi2+1.0
1240 :
1241 : ! ...and in y direction
1242 :
1243 0 : yp=yparam(v)
1244 0 : ypi=1.0-yp
1245 0 : yp2=yp*yp
1246 0 : ypi2=ypi*ypi
1247 :
1248 0 : cyd=3.0*yp2-1.0
1249 0 : cydi=-3.0*ypi2+1.0
1250 :
1251 : sum=hxi(v)*hyi(v)*(
1252 : & fin(0,i,j) -fin(0,i,j+1)
1253 0 : & -fin(0,i+1,j)+fin(0,i+1,j+1))
1254 :
1255 : sum=sum+sixth*hx(v)*hyi(v)*(
1256 : & cxdi*(-fin(1,i,j) +fin(1,i,j+1))+
1257 0 : & cxd*(-fin(1,i+1,j)+fin(1,i+1,j+1)))
1258 :
1259 : sum=sum+sixth*hxi(v)*hy(v)*(
1260 : & -(cydi*fin(2,i,j) +cyd*fin(2,i,j+1))
1261 0 : & +(cydi*fin(2,i+1,j)+cyd*fin(2,i+1,j+1)))
1262 :
1263 : sum=sum+z36th*hx(v)*hy(v)*(
1264 : & cxdi*(cydi*fin(3,i,j) +cyd*fin(3,i,j+1))+
1265 0 : & cxd*(cydi*fin(3,i+1,j)+cyd*fin(3,i+1,j+1)))
1266 :
1267 0 : fval(v,iadr)=sum
1268 : end do
1269 : end if
1270 :
1271 : !-------------------------------------------------
1272 :
1273 0 : else if(ict(1) == 3) then
1274 0 : if(ict(2) == 1) then
1275 : ! evaluate d3f/dx3 (not continuous)
1276 0 : iadr=iadr+1
1277 0 : do v=1,ivec
1278 0 : i=ii(v)
1279 0 : j=jj(v)
1280 0 : yp=yparam(v)
1281 0 : ypi=1.0-yp
1282 0 : yp2=yp*yp
1283 0 : ypi2=ypi*ypi
1284 0 : cy=yp*(yp2-1.0)
1285 0 : cyi=ypi*(ypi2-1.0)
1286 0 : hy2=hy(v)*hy(v)
1287 : sum=hxi(v)*(
1288 : & -(ypi*fin(1,i,j) +yp*fin(1,i,j+1))
1289 0 : & +(ypi*fin(1,i+1,j)+yp*fin(1,i+1,j+1)))
1290 :
1291 : sum=sum+sixth*hy2*hxi(v)*(
1292 : & -(cyi*fin(3,i,j) +cy*fin(3,i,j+1))
1293 0 : & +(cyi*fin(3,i+1,j)+cy*fin(3,i+1,j+1)))
1294 :
1295 0 : fval(v,iadr)=sum
1296 : end do
1297 : end if
1298 :
1299 0 : if(ict(3) == 1) then
1300 : ! evaluate d3f/dx2dy
1301 0 : iadr=iadr+1
1302 0 : do v=1,ivec
1303 0 : i=ii(v)
1304 0 : j=jj(v)
1305 0 : xp=xparam(v)
1306 0 : xpi=1.0-xp
1307 0 : yp=yparam(v)
1308 0 : ypi=1.0-yp
1309 0 : yp2=yp*yp
1310 0 : ypi2=ypi*ypi
1311 0 : cyd=3.0*yp2-1.0
1312 0 : cydi=-3.0*ypi2+1.0
1313 :
1314 : sum=hyi(v)*(
1315 : & xpi*(-fin(1,i,j) +fin(1,i,j+1))+
1316 0 : & xp*(-fin(1,i+1,j) +fin(1,i+1,j+1)))
1317 :
1318 : sum=sum+sixth*hy(v)*(
1319 : & xpi*(cydi*fin(3,i,j) +cyd*fin(3,i,j+1))+
1320 0 : & xp*(cydi*fin(3,i+1,j)+cyd*fin(3,i+1,j+1)))
1321 :
1322 0 : fval(v,iadr)=sum
1323 : end do
1324 : end if
1325 :
1326 0 : if(ict(4) == 1) then
1327 : ! evaluate d3f/dxdy2
1328 0 : iadr=iadr+1
1329 0 : do v=1,ivec
1330 0 : i=ii(v)
1331 0 : j=jj(v)
1332 0 : xp=xparam(v)
1333 0 : xpi=1.0-xp
1334 0 : xp2=xp*xp
1335 0 : xpi2=xpi*xpi
1336 0 : cxd=3.0*xp2-1.0
1337 0 : cxdi=-3.0*xpi2+1.0
1338 0 : yp=yparam(v)
1339 0 : ypi=1.0-yp
1340 :
1341 : sum=hxi(v)*(
1342 : & -(ypi*fin(2,i,j) +yp*fin(2,i,j+1))
1343 0 : & +(ypi*fin(2,i+1,j)+yp*fin(2,i+1,j+1)))
1344 :
1345 : sum=sum+sixth*hx(v)*(
1346 : & cxdi*(ypi*fin(3,i,j) +yp*fin(3,i,j+1))+
1347 0 : & cxd*(ypi*fin(3,i+1,j)+yp*fin(3,i+1,j+1)))
1348 :
1349 0 : fval(v,iadr)=sum
1350 : end do
1351 : end if
1352 :
1353 0 : if(ict(5) == 1) then
1354 : ! evaluate d3f/dy3 (not continuous)
1355 0 : iadr=iadr+1
1356 0 : do v=1,ivec
1357 0 : i=ii(v)
1358 0 : j=jj(v)
1359 :
1360 0 : xp=xparam(v)
1361 0 : xpi=1.0-xp
1362 0 : xp2=xp*xp
1363 0 : xpi2=xpi*xpi
1364 :
1365 0 : cx=xp*(xp2-1.0)
1366 0 : cxi=xpi*(xpi2-1.0)
1367 0 : hx2=hx(v)*hx(v)
1368 :
1369 : sum=hyi(v)*(
1370 : & xpi*(-fin(2,i,j) +fin(2,i,j+1))+
1371 0 : & xp*(-fin(2,i+1,j) +fin(2,i+1,j+1)))
1372 :
1373 : sum=sum+sixth*hx2*hyi(v)*(
1374 : & cxi*(-fin(3,i,j) +fin(3,i,j+1))+
1375 0 : & cx*(-fin(3,i+1,j) +fin(3,i+1,j+1)))
1376 :
1377 0 : fval(v,iadr)=sum
1378 : end do
1379 : end if
1380 :
1381 : !-----------------------------------
1382 : ! access to 4th derivatives
1383 :
1384 0 : else if(ict(1) == 4) then
1385 0 : if(ict(2) == 1) then
1386 : ! evaluate d4f/dx3dy (not continuous)
1387 0 : iadr=iadr+1
1388 0 : do v=1,ivec
1389 0 : i=ii(v)
1390 0 : j=jj(v)
1391 0 : yp=yparam(v)
1392 0 : ypi=1.0-yp
1393 0 : yp2=yp*yp
1394 0 : ypi2=ypi*ypi
1395 0 : cyd=3.0*yp2-1.0
1396 0 : cydi=-3.0*ypi2+1.0
1397 :
1398 : sum=hxi(v)*hyi(v)*(
1399 : & +( fin(1,i,j) -fin(1,i,j+1))
1400 0 : & +(-fin(1,i+1,j)+fin(1,i+1,j+1)))
1401 :
1402 : sum=sum+sixth*hy(v)*hxi(v)*(
1403 : & -(cydi*fin(3,i,j) +cyd*fin(3,i,j+1))
1404 0 : & +(cydi*fin(3,i+1,j)+cyd*fin(3,i+1,j+1)))
1405 :
1406 0 : fval(v,iadr)=sum
1407 : end do
1408 : end if
1409 :
1410 0 : if(ict(3) == 1) then
1411 : ! evaluate d4f/dx2dy2
1412 0 : iadr=iadr+1
1413 0 : do v=1,ivec
1414 0 : i=ii(v)
1415 0 : j=jj(v)
1416 :
1417 0 : xp=xparam(v)
1418 0 : xpi=1.0-xp
1419 0 : yp=yparam(v)
1420 0 : ypi=1.0-yp
1421 :
1422 : sum=xpi*(ypi*fin(3,i,j) +yp*fin(3,i,j+1))+
1423 0 : & xp*(ypi*fin(3,i+1,j)+yp*fin(3,i+1,j+1))
1424 :
1425 0 : fval(v,iadr)=sum
1426 : end do
1427 : end if
1428 :
1429 0 : if(ict(4) == 1) then
1430 : ! evaluate d4f/dxdy3 (not continuous)
1431 0 : iadr=iadr+1
1432 0 : do v=1,ivec
1433 0 : i=ii(v)
1434 0 : j=jj(v)
1435 :
1436 0 : xp=xparam(v)
1437 0 : xpi=1.0-xp
1438 0 : xp2=xp*xp
1439 0 : xpi2=xpi*xpi
1440 :
1441 0 : cxd=3.0*xp2-1.0
1442 0 : cxdi=-3.0*xpi2+1.0
1443 :
1444 : sum=hyi(v)*hxi(v)*(
1445 : & +( fin(2,i,j) -fin(2,i,j+1))
1446 0 : & +(-fin(2,i+1,j)+fin(2,i+1,j+1)))
1447 :
1448 : sum=sum+sixth*hx(v)*hyi(v)*(
1449 : & cxdi*(-fin(3,i,j) +fin(3,i,j+1))+
1450 0 : & cxd*(-fin(3,i+1,j) +fin(3,i+1,j+1)))
1451 :
1452 0 : fval(v,iadr)=sum
1453 : end do
1454 : end if
1455 :
1456 : !-----------------------------------
1457 : ! access to 5th derivatives
1458 :
1459 0 : else if(ict(1) == 5) then
1460 0 : if(ict(2) == 1) then
1461 : ! evaluate d5f/dx3dy2 (not continuous)
1462 0 : iadr=iadr+1
1463 0 : do v=1,ivec
1464 0 : i=ii(v)
1465 0 : j=jj(v)
1466 :
1467 0 : yp=yparam(v)
1468 0 : ypi=1.0-yp
1469 :
1470 : sum=hxi(v)*(
1471 : & -(ypi*fin(3,i,j) +yp*fin(3,i,j+1))
1472 0 : & +(ypi*fin(3,i+1,j)+yp*fin(3,i+1,j+1)))
1473 :
1474 0 : fval(v,iadr)=sum
1475 : end do
1476 : end if
1477 :
1478 0 : if(ict(3) == 1) then
1479 : ! evaluate d5f/dx2dy3 (not continuous)
1480 0 : iadr=iadr+1
1481 0 : do v=1,ivec
1482 0 : i=ii(v)
1483 0 : j=jj(v)
1484 :
1485 0 : xp=xparam(v)
1486 0 : xpi=1.0-xp
1487 :
1488 : sum=hyi(v)*(
1489 : & xpi*(-fin(3,i,j) +fin(3,i,j+1))+
1490 0 : & xp*(-fin(3,i+1,j)+fin(3,i+1,j+1)))
1491 :
1492 0 : fval(v,iadr)=sum
1493 : end do
1494 : end if
1495 :
1496 : !-----------------------------------
1497 : ! access to 6th derivatives
1498 :
1499 0 : else if(ict(1) == 6) then
1500 : ! evaluate d6f/dx3dy3 (not continuous)
1501 0 : iadr=iadr+1
1502 0 : do v=1,ivec
1503 0 : i=ii(v)
1504 0 : j=jj(v)
1505 : sum=hxi(v)*hyi(v)*(
1506 : & +( fin(3,i,j) -fin(3,i,j+1))
1507 0 : & +(-fin(3,i+1,j)+fin(3,i+1,j+1)))
1508 0 : fval(v,iadr)=sum
1509 : end do
1510 : end if
1511 :
1512 6 : return
1513 6 : end subroutine fvbicub
1514 :
1515 :
1516 : !---------------------------------------------------------------------
1517 : ! herm2xy -- look up x-y zone
1518 :
1519 : ! this is the "first part" of herm2ev, see comments, above.
1520 :
1521 6 : subroutine herm2xy(xget,yget,x,nx,y,ny,ilinx,iliny,
1522 : & i,j,xparam,yparam,hx,hxi,hy,hyi,ier)
1523 :
1524 : ! input of herm2xy
1525 : ! ================
1526 :
1527 : integer nx,ny ! array dimensions
1528 :
1529 : real xget,yget ! target point
1530 : real x(:) ! (nx) ! indep. coords., strict ascending
1531 : real y(:) ! (ny) ! indep. coords., strict ascending
1532 :
1533 : integer ilinx ! =1: x evenly spaced
1534 : integer iliny ! =1: y evenly spaced
1535 :
1536 : ! output of herm2xy
1537 : ! =================
1538 : integer i,j ! index to cell containing target pt
1539 : ! on exit: 1 <= i <= nx-1 1 <= j <= ny-1
1540 :
1541 : ! normalized position w/in (i,j) cell (btw 0 and 1):
1542 :
1543 : real xparam ! (xget-x(i))/(x(i+1)-x(i))
1544 : real yparam ! (yget-y(j))/(y(j+1)-y(j))
1545 :
1546 : ! grid spacing
1547 :
1548 : real hx ! hx = x(i+1)-x(i)
1549 : real hy ! hy = y(j+1)-y(j)
1550 :
1551 : ! inverse grid spacing:
1552 :
1553 : real hxi ! 1/hx = 1/(x(i+1)-x(i))
1554 : real hyi ! 1/hy = 1/(y(j+1)-y(j))
1555 :
1556 : integer ier ! return ier /= 0 on error
1557 6 : real zxget,zyget,zxtol,zytol
1558 : integer nxm,nym,ii,jj
1559 :
1560 : !------------------------------------
1561 :
1562 6 : ier=0
1563 :
1564 : ! range check
1565 :
1566 6 : zxget=xget
1567 6 : zyget=yget
1568 6 : if((xget < x(1)).or.(xget > x(nx))) then
1569 0 : zxtol=4.0e-7*max(abs(x(1)),abs(x(nx)))
1570 0 : if((xget < x(1)-zxtol).or.(xget > x(nx)+zxtol)) then
1571 0 : ier=1
1572 : ! write(6,1001) xget,x(1),x(nx)
1573 : ! 1001 format(' ?herm2ev: xget=',1pe11.4,' out of range ', 1pe11.4,' to ',1pe11.4)
1574 : else
1575 : ! if((xget < x(1)-0.5*zxtol).or. (xget > x(nx)+0.5*zxtol)) write(6,1011) xget,x(1),x(nx)
1576 : ! 1011 format(' %herm2ev: xget=',1pe15.8,' beyond range ', 1pe15.8,' to ',1pe15.8,' (fixup applied)')
1577 0 : if(xget < x(1)) then
1578 0 : zxget=x(1)
1579 : else
1580 0 : zxget=x(nx)
1581 : end if
1582 : end if
1583 : end if
1584 6 : if((yget < y(1)).or.(yget > y(ny))) then
1585 0 : zytol=4.0e-7*max(abs(y(1)),abs(y(ny)))
1586 0 : if((yget < y(1)-zytol).or.(yget > y(ny)+zytol)) then
1587 0 : ier=1
1588 : ! write(6,1002) yget,y(1),y(ny)
1589 : ! 1002 format(' ?herm2ev: yget=',1pe11.4,' out of range ', 1pe11.4,' to ',1pe11.4)
1590 : else
1591 : ! if((yget < y(1)-0.5*zytol).or. (yget > y(ny)+0.5*zytol)) write(6,1012) yget,y(1),y(ny)
1592 : ! 1012 format(' %herm2ev: yget=',1pe15.8,' beyond range ', 1pe15.8,' to ',1pe15.8,' (fixup applied)')
1593 0 : if(yget < y(1)) then
1594 0 : zyget=y(1)
1595 : else
1596 0 : zyget=y(ny)
1597 : end if
1598 : end if
1599 : end if
1600 6 : if(ier /= 0) return
1601 :
1602 : ! now find interval in which target point lies..
1603 :
1604 6 : nxm=nx-1
1605 6 : nym=ny-1
1606 :
1607 6 : if(ilinx == 1) then
1608 6 : ii=1+nxm*(zxget-x(1))/(x(nx)-x(1))
1609 6 : i=min(nxm, ii)
1610 6 : if(zxget < x(i)) then
1611 0 : i=i-1
1612 6 : else if(zxget > x(i+1)) then
1613 0 : i=i+1
1614 : end if
1615 : else
1616 0 : if((1 <= i).and.(i < nxm)) then
1617 0 : if((x(i) <= zxget).and.(zxget <= x(i+1))) then
1618 : continue ! already have the zone
1619 : else
1620 0 : call zonfind(x,nx,zxget,i)
1621 : end if
1622 : else
1623 0 : call zonfind(x,nx,zxget,i)
1624 : end if
1625 : end if
1626 :
1627 6 : if(iliny == 1) then
1628 6 : jj=1+nym*(zyget-y(1))/(y(ny)-y(1))
1629 6 : j=min(nym, jj)
1630 6 : if(zyget < y(j)) then
1631 0 : j=j-1
1632 6 : else if(zyget > y(j+1)) then
1633 0 : j=j+1
1634 : end if
1635 : else
1636 0 : if((1 <= j).and.(j < nym)) then
1637 0 : if((y(j) <= zyget).and.(zyget <= y(j+1))) then
1638 : continue ! already have the zone
1639 : else
1640 0 : call zonfind(y,ny,zyget,j)
1641 : end if
1642 : else
1643 0 : call zonfind(y,ny,zyget,j)
1644 : end if
1645 : end if
1646 :
1647 6 : hx=(x(i+1)-x(i))
1648 6 : hy=(y(j+1)-y(j))
1649 :
1650 6 : hxi=1.0/hx
1651 6 : hyi=1.0/hy
1652 :
1653 6 : xparam=(zxget-x(i))*hxi
1654 6 : yparam=(zyget-y(j))*hyi
1655 :
1656 6 : return
1657 : end subroutine herm2xy
1658 :
1659 0 : subroutine herm2fcn(ict,ivec,ivecd,
1660 0 : & fval,ii,jj,xparam,yparam,hx,hxi,hy,hyi,
1661 0 : & fin,inf2,ny)
1662 :
1663 : integer ny, inf2
1664 : integer ict(4) ! requested output control
1665 : integer ivec ! vector length
1666 : integer ivecd ! vector dimension (1st dim of fval)
1667 :
1668 : integer ii(ivec),jj(ivec) ! target cells (i,j)
1669 : real xparam(ivec),yparam(ivec)
1670 : ! normalized displacements from (i,j) corners
1671 :
1672 : real hx(ivec),hy(ivec) ! grid spacing, and
1673 : real hxi(ivec),hyi(ivec) ! inverse grid spacing 1/(x(i+1)-x(i))
1674 : ! & 1/(y(j+1)-y(j))
1675 :
1676 : real fin(0:3,inf2,ny) ! interpolant data (cf "herm2ev")
1677 :
1678 : real fval(ivecd,4) ! output returned
1679 :
1680 : ! for detailed description of fin, ict and fval see subroutine
1681 : ! herm2ev comments. Note ict is not vectorized; the same output
1682 : ! is expected to be returned for all input vector data points.
1683 :
1684 : ! note that the index inputs ii,jj and parameter inputs
1685 : ! xparam,yparam,hx,hxi,hy,hyi are vectorized, and the
1686 : ! output array fval has a vector ** 1st dimension ** whose
1687 : ! size must be given as a separate argument
1688 :
1689 : ! to use this routine in scalar mode, pass in ivec=ivecd=1
1690 :
1691 : !---------------
1692 : ! Hermite cubic basis functions
1693 : ! -->for function value matching
1694 : ! a(0)=0 a(1)=1 a'(0)=0 a'(1)=0
1695 : ! abar(0)=1 abar(1)=0 abar'(0)=0 abar'(1)=0
1696 :
1697 : ! a(x)=-2*x**3 + 3*x**2 = x*x*(-2.0*x+3.0)
1698 : ! abar(x)=1-a(x)
1699 : ! a'(x)=-abar'(x) = 6.0*x*(1.0-x)
1700 :
1701 : ! -->for derivative matching
1702 : ! b(0)=0 b(1)=0 b'(0)=0 b'(1)=1
1703 : ! bbar(0)=0 bbar(1)=0 bbar'(0)=1 bbar'(1)=0
1704 :
1705 : ! b(x)=x**3-x**2 b'(x)=3*x**2-2*x
1706 : ! bbar(x)=x**3-2*x**2+x bbar'(x)=3*x**2-4*x+1
1707 :
1708 0 : real sum
1709 : integer v,iadr,i,j
1710 0 : real xp,yp,xpi,ypi,xp2,yp2,xpi2,ypi2
1711 0 : real ax,bx,axbar,bxbar,ay,by,aybar,bybar
1712 0 : real axp,axbarp,bxp,bxbarp,ayp,aybarp,bybarp,byp
1713 :
1714 0 : do v=1,ivec
1715 0 : i=ii(v)
1716 0 : j=jj(v)
1717 :
1718 : ! ...in x direction
1719 :
1720 0 : xp=xparam(v)
1721 0 : xpi=1.0-xp
1722 0 : xp2=xp*xp
1723 0 : xpi2=xpi*xpi
1724 0 : ax=xp2*(3.0-2.0*xp)
1725 0 : axbar=1.0-ax
1726 0 : bx=-xp2*xpi
1727 0 : bxbar=xpi2*xp
1728 :
1729 : ! ...in y direction
1730 :
1731 0 : yp=yparam(v)
1732 0 : ypi=1.0-yp
1733 0 : yp2=yp*yp
1734 0 : ypi2=ypi*ypi
1735 0 : ay=yp2*(3.0-2.0*yp)
1736 0 : aybar=1.0-ay
1737 0 : by=-yp2*ypi
1738 0 : bybar=ypi2*yp
1739 :
1740 : ! ...derivatives...
1741 :
1742 0 : axp=6.0*xp*xpi
1743 0 : axbarp=-axp
1744 0 : bxp=xp*(3.0*xp-2.0)
1745 0 : bxbarp=xpi*(3.0*xpi-2.0)
1746 :
1747 0 : ayp=6.0*yp*ypi
1748 0 : aybarp=-ayp
1749 0 : byp=yp*(3.0*yp-2.0)
1750 0 : bybarp=ypi*(3.0*ypi-2.0)
1751 :
1752 0 : iadr=0
1753 :
1754 : ! get desired values:
1755 :
1756 0 : if(ict(1) == 1) then
1757 :
1758 : ! function value:
1759 :
1760 0 : iadr=iadr+1
1761 : sum=axbar*(aybar*fin(0,i,j) +ay*fin(0,i,j+1))+
1762 0 : & ax*(aybar*fin(0,i+1,j)+ay*fin(0,i+1,j+1))
1763 :
1764 : sum=sum+hx(v)*(
1765 : & bxbar*(aybar*fin(1,i,j) +ay*fin(1,i,j+1))+
1766 0 : & bx*(aybar*fin(1,i+1,j)+ay*fin(1,i+1,j+1)))
1767 :
1768 : sum=sum+hy(v)*(
1769 : & axbar*(bybar*fin(2,i,j) +by*fin(2,i,j+1))+
1770 0 : & ax*(bybar*fin(2,i+1,j)+by*fin(2,i+1,j+1)))
1771 :
1772 : sum=sum+hx(v)*hy(v)*(
1773 : & bxbar*(bybar*fin(3,i,j) +by*fin(3,i,j+1))+
1774 0 : & bx*(bybar*fin(3,i+1,j)+by*fin(3,i+1,j+1)))
1775 :
1776 0 : fval(v,iadr)=sum
1777 : end if
1778 :
1779 0 : if(ict(2) == 1) then
1780 :
1781 : ! df/dx:
1782 :
1783 0 : iadr=iadr+1
1784 :
1785 : sum=hxi(v)*(
1786 : & axbarp*(aybar*fin(0,i,j) +ay*fin(0,i,j+1))+
1787 0 : & axp*(aybar*fin(0,i+1,j)+ay*fin(0,i+1,j+1)))
1788 :
1789 : sum=sum+
1790 : & bxbarp*(aybar*fin(1,i,j) +ay*fin(1,i,j+1))+
1791 0 : & bxp*(aybar*fin(1,i+1,j)+ay*fin(1,i+1,j+1))
1792 :
1793 : sum=sum+hxi(v)*hy(v)*(
1794 : & axbarp*(bybar*fin(2,i,j) +by*fin(2,i,j+1))+
1795 0 : & axp*(bybar*fin(2,i+1,j)+by*fin(2,i+1,j+1)))
1796 :
1797 : sum=sum+hy(v)*(
1798 : & bxbarp*(bybar*fin(3,i,j) +by*fin(3,i,j+1))+
1799 0 : & bxp*(bybar*fin(3,i+1,j)+by*fin(3,i+1,j+1)))
1800 :
1801 0 : fval(v,iadr)=sum
1802 : end if
1803 :
1804 0 : if(ict(3) == 1) then
1805 :
1806 : ! df/dy:
1807 :
1808 0 : iadr=iadr+1
1809 :
1810 : sum=hyi(v)*(
1811 : & axbar*(aybarp*fin(0,i,j) +ayp*fin(0,i,j+1))+
1812 0 : & ax*(aybarp*fin(0,i+1,j)+ayp*fin(0,i+1,j+1)))
1813 :
1814 : sum=sum+hx(v)*hyi(v)*(
1815 : & bxbar*(aybarp*fin(1,i,j) +ayp*fin(1,i,j+1))+
1816 0 : & bx*(aybarp*fin(1,i+1,j)+ayp*fin(1,i+1,j+1)))
1817 :
1818 : sum=sum+
1819 : & axbar*(bybarp*fin(2,i,j) +byp*fin(2,i,j+1))+
1820 0 : & ax*(bybarp*fin(2,i+1,j)+byp*fin(2,i+1,j+1))
1821 :
1822 : sum=sum+hx(v)*(
1823 : & bxbar*(bybarp*fin(3,i,j) +byp*fin(3,i,j+1))+
1824 0 : & bx*(bybarp*fin(3,i+1,j)+byp*fin(3,i+1,j+1)))
1825 :
1826 0 : fval(v,iadr)=sum
1827 : end if
1828 :
1829 0 : if(ict(4) == 1) then
1830 :
1831 : ! d2f/dxdy:
1832 :
1833 0 : iadr=iadr+1
1834 :
1835 : sum=hxi(v)*hyi(v)*(
1836 : & axbarp*(aybarp*fin(0,i,j) +ayp*fin(0,i,j+1))+
1837 0 : & axp*(aybarp*fin(0,i+1,j)+ayp*fin(0,i+1,j+1)))
1838 :
1839 : sum=sum+hyi(v)*(
1840 : & bxbarp*(aybarp*fin(1,i,j) +ayp*fin(1,i,j+1))+
1841 0 : & bxp*(aybarp*fin(1,i+1,j)+ayp*fin(1,i+1,j+1)))
1842 :
1843 : sum=sum+hxi(v)*(
1844 : & axbarp*(bybarp*fin(2,i,j) +byp*fin(2,i,j+1))+
1845 0 : & axp*(bybarp*fin(2,i+1,j)+byp*fin(2,i+1,j+1)))
1846 :
1847 : sum=sum+
1848 : & bxbarp*(bybarp*fin(3,i,j) +byp*fin(3,i,j+1))+
1849 0 : & bxp*(bybarp*fin(3,i+1,j)+byp*fin(3,i+1,j+1))
1850 :
1851 0 : fval(v,iadr)=sum
1852 : end if
1853 :
1854 : end do ! vector loop
1855 :
1856 0 : return
1857 : end subroutine herm2fcn
1858 :
1859 :
1860 198 : subroutine ibc_ck(ibc,slbl,xlbl,imin,imax,ier)
1861 :
1862 : ! check that spline routine ibc flag is in range
1863 :
1864 : integer ibc ! input -- flag value
1865 : character*(*) slbl ! input -- subroutine name
1866 : character*(*) xlbl ! input -- axis label
1867 :
1868 : integer imin ! input -- min allowed value
1869 : integer imax ! input -- max allowed value
1870 :
1871 : integer ier ! output -- set =1 if error detected
1872 :
1873 : !----------------------
1874 :
1875 198 : if((ibc < imin).or.(ibc > imax)) then
1876 0 : ier=1
1877 : ! write(6,1001) slbl,xlbl,ibc,imin,imax
1878 : ! 1001 format(' ?',a,' -- ibc',a,' = ',i9,' out of range ', i2,' to ',i2)
1879 : end if
1880 :
1881 0 : return
1882 : end subroutine ibc_ck
1883 :
1884 :
1885 1 : subroutine do_mkbicub(x,nx,y,ny,f1,nf2,
1886 1 : & ibcxmin,bcxmin,ibcxmax,bcxmax,
1887 1 : & ibcymin,bcymin,ibcymax,bcymax,
1888 : & ilinx,iliny,ier)
1889 :
1890 : ! setup bicubic spline, dynamic allocation of workspace
1891 : ! fortran-90 fixed form source
1892 :
1893 : ! --NOTE-- dmc 22 Feb 2004 -- rewrite for direct calculation of
1894 : ! coefficients, to avoid large transient use of memory.
1895 :
1896 : !
1897 : implicit NONE
1898 :
1899 : ! input:
1900 : integer nx ! length of x vector
1901 : integer ny ! length of y vector
1902 : real x(:) ! (nx) ! x vector, strict ascending
1903 : real y(:) ! (ny) ! y vector, strict ascending
1904 :
1905 : integer nf2 ! 2nd dimension of f, nf2 >= nx
1906 : ! input/output:
1907 : real, pointer :: f1(:) ! =(4,nf2,ny) ! data & spline coefficients
1908 :
1909 : ! on input: f(1,i,j) = f(x(i),y(j))
1910 : ! on output: f(1,i,j) unchanged
1911 : ! f(2,i,j) = d2f/dx2(x(i),y(j))
1912 : ! f(3,i,j) = d2f/dy2(x(i),y(j))
1913 : ! f(4,i,j) = d4f/dx2dy2(x(i),y(j))
1914 :
1915 : ! and the interpolation formula for (x,y) in (x(i),x(i+1))^(y(j),y(j+1))
1916 : ! is:
1917 : ! hx = x(i+1)-x(i) hy = y(j+1)-y(j)
1918 : ! dxp= (x-x(i))/hx dxm= 1-dxp dxp,dxm in (0,1)
1919 : ! dyp= (x-x(i))/hx dym= 1-dyp dyp,dym in (0,1)
1920 : ! dx3p = dxp**3-dxp dx3m = dxm**3-dxm dxp3,dxm3 in (0,1)
1921 :
1922 : ! finterp = dxm*(dym*f(1,i,j)+dyp*f(1,i,j+1))
1923 : ! +dxp*(dym*f(1,i+1,j)+dyp*f(1,i+1,j+1))
1924 : ! +1/6*hx**2*
1925 : ! dx3m*(dym*f(2,i,j)+dyp*f(2,i,j+1))
1926 : ! +dx3p*(dym*f(2,i+1,j)+dyp*f(2,i+1,j+1))
1927 : ! +1/6*hy**2*
1928 : ! dxm*(dy3m*f(3,i,j)+dy3p*f(3,i,j+1))
1929 : ! +dxp*(dy3m*f(3,i+1,j)+dy3p*f(3,i+1,j+1))
1930 : ! +1/36*hx**2*hy**2*
1931 : ! dx3m*(dym*f(4,i,j)+dyp*f(4,i,j+1))
1932 : ! +dx3p*(dym*f(4,i+1,j)+dyp*f(4,i+1,j+1))
1933 :
1934 : ! where the f(2:4,*,*) are cleverly evaluated to assure
1935 : ! (a) finterp is continuous and twice differentiable across all
1936 : ! grid cell boundaries, and
1937 : ! (b) all boundary conditions are satisfied.
1938 :
1939 : ! input bdy condition data:
1940 : integer ibcxmin ! bc flag for x=xmin
1941 : real bcxmin(:) ! (ny) ! bc data vs. y at x=xmin
1942 : integer ibcxmax ! bc flag for x=xmax
1943 : real bcxmax(:) ! (ny) ! bc data vs. y at x=xmax
1944 :
1945 : integer ibcymin ! bc flag for y=ymin
1946 : real bcymin(:) ! (nx) ! bc data vs. x at y=ymin
1947 : integer ibcymax ! bc flag for y=ymax
1948 : real bcymax(:) ! (nx) ! bc data vs. x at y=ymax
1949 :
1950 : ! with interpretation:
1951 : ! ibcxmin -- indicator for boundary condition at x(1):
1952 : ! bcxmin(...) -- boundary condition data
1953 : ! =-1 -- periodic boundary condition
1954 : ! =0 -- use "not a knot"
1955 : ! =1 -- match slope, specified at x(1),th(ith) by bcxmin(ith)
1956 : ! =2 -- match 2nd derivative, specified at x(1),th(ith) by bcxmin(ith)
1957 : ! =3 -- boundary condition is slope=0 (df/dx=0) at x(1), all th(j)
1958 : ! =4 -- boundary condition is d2f/dx2=0 at x(1), all th(j)
1959 : ! =5 -- match 1st derivative to 1st divided difference
1960 : ! =6 -- match 2nd derivative to 2nd divided difference
1961 : ! =7 -- match 3rd derivative to 3rd divided difference
1962 : ! (for more detailed definition of BCs 5-7, see the
1963 : ! comments of subroutine mkspline)
1964 : ! NOTE bcxmin(...) referenced ONLY if ibcxmin=1 or ibcxmin=2
1965 :
1966 : ! ibcxmax -- indicator for boundary condition at x(nx):
1967 : ! bcxmax(...) -- boundary condition data
1968 : ! (interpretation as with ibcxmin, bcxmin)
1969 : ! NOTE: if ibcxmin=-1, ibcxmax is ignored! ...and the BC is periodic.
1970 :
1971 : ! and analogous interpretation for ibcymin,bcymin,ibcymax,bcymax
1972 : ! (df/dy or d2f/dy2 boundary conditions at y=ymin and y=ymax).
1973 :
1974 : ! output linear grid flags and completion code (ier=0 is normal):
1975 :
1976 : integer ilinx ! =1: x grid is "nearly" equally spaced
1977 : integer iliny ! =1: y grid is "nearly" equally spaced
1978 : ! ilinx and iliny are set to zero if corresponding grids are not equally
1979 : ! spaced
1980 :
1981 : integer ier ! =0 on exit if there is no error.
1982 :
1983 : ! if there is an error, ier is set and a message is output on unit 6.
1984 : ! these are considered programming errors in the calling routine.
1985 :
1986 : ! possible errors:
1987 : ! x(...) not strict ascending
1988 : ! y(...) not strict ascending
1989 : ! nx < 4
1990 : ! ny < 4
1991 : ! invalid boundary condition flag
1992 :
1993 : !-----------------------
1994 : integer ierx,iery
1995 :
1996 1 : real, dimension(:,:), allocatable :: fwk
1997 1 : real :: zbcmin,zbcmax
1998 : integer ix,iy,ibcmin,ibcmax
1999 :
2000 1 : real, dimension(:,:,:), allocatable :: fcorr
2001 : integer iflg2
2002 3 : real zdiff(2),hy
2003 :
2004 1 : real, pointer :: f(:,:,:)
2005 1 : f(1:4,1:nf2,1:ny) => f1(1:4*nf2*ny)
2006 :
2007 : !-----------------------
2008 :
2009 : ! see if 2nd pass is needed due to inhomogeneous d/dy bdy cond.
2010 :
2011 1 : iflg2=0
2012 1 : if(ibcymin /= -1) then
2013 1 : if((ibcymin == 1).or.(ibcymin == 2)) then
2014 0 : do ix=1,nx
2015 0 : if (bcymin(ix) /= 0.0) iflg2=1
2016 : end do
2017 : end if
2018 1 : if((ibcymax == 1).or.(ibcymax == 2)) then
2019 0 : do ix=1,nx
2020 0 : if (bcymax(ix) /= 0.0) iflg2=1
2021 : end do
2022 : end if
2023 : end if
2024 :
2025 : ! check boundary condition specifications
2026 :
2027 1 : ier=0
2028 :
2029 1 : call ibc_ck(ibcxmin,'bcspline','xmin',-1,7,ier)
2030 2 : if(ibcxmin >= 0) call ibc_ck(ibcxmax,'bcspline','xmax',0,7,ier)
2031 1 : call ibc_ck(ibcymin,'bcspline','ymin',-1,7,ier)
2032 1 : if(ibcymin >= 0) call ibc_ck(ibcymax,'bcspline','ymax',0,7,ier)
2033 :
2034 : ! check ilinx & x vector
2035 :
2036 1 : call splinck(x,nx,ilinx,1.0e-3,ierx)
2037 1 : if(ierx /= 0) ier=2
2038 :
2039 1 : if(ier == 2) then
2040 0 : write(6,'('' ?bcspline: x axis not strict ascending'')')
2041 : end if
2042 :
2043 : ! check iliny & y vector
2044 :
2045 1 : call splinck(y,ny,iliny,1.0e-3,iery)
2046 1 : if(iery /= 0) ier=3
2047 :
2048 1 : if(ier == 3) then
2049 0 : write(6,'('' ?bcspline: y axis not strict ascending'')')
2050 : end if
2051 :
2052 1 : if(ier /= 0) return
2053 :
2054 : !------------------------------------
2055 1 : allocate(fwk(2,max(nx,ny)))
2056 :
2057 : ! evaluate fxx (spline in x direction)
2058 :
2059 1 : zbcmin=0
2060 1 : zbcmax=0
2061 36 : do iy=1,ny
2062 1120 : fwk(1,1:nx) = f(1,1:nx,iy)
2063 35 : if((ibcxmin == 1).or.(ibcxmin == 2)) zbcmin=bcxmin(iy)
2064 35 : if((ibcxmax == 1).or.(ibcxmax == 2)) zbcmax=bcxmax(iy)
2065 35 : call mkspline(x,nx,fwk,ibcxmin,zbcmin,ibcxmax,zbcmax,ilinx,ier)
2066 35 : if(ier /= 0) then
2067 0 : deallocate(fwk)
2068 0 : return
2069 : end if
2070 1121 : f(2,1:nx,iy)=fwk(2,1:nx)
2071 : end do
2072 :
2073 : ! evaluate fyy (spline in y direction)
2074 : ! use homogeneous boundary condition; correction done later if necessary
2075 :
2076 1 : zbcmin=0
2077 1 : zbcmax=0
2078 1 : ibcmin=ibcymin
2079 1 : ibcmax=ibcymax
2080 32 : do ix=1,nx
2081 1116 : fwk(1,1:ny) = f(1,ix,1:ny)
2082 31 : if(iflg2 == 1) then
2083 0 : if((ibcymin == 1).or.(ibcymin == 2)) ibcmin=0
2084 0 : if((ibcymax == 1).or.(ibcymax == 2)) ibcmax=0
2085 : end if
2086 31 : call mkspline(y,ny,fwk,ibcmin,zbcmin,ibcmax,zbcmax,iliny,ier)
2087 31 : if(ier /= 0) then
2088 0 : deallocate(fwk)
2089 0 : return
2090 : end if
2091 1117 : f(3,ix,1:ny)=fwk(2,1:ny)
2092 : end do
2093 :
2094 : ! evaluate fxxyy (spline fxx in y direction; BC simplified; avg
2095 : ! d2(d2f/dx2)/dy2 and d2(df2/dy2)/dx2
2096 :
2097 : zbcmin=0
2098 : zbcmax=0
2099 1 : ibcmin=ibcymin
2100 1 : ibcmax=ibcymax
2101 32 : do ix=1,nx
2102 1116 : fwk(1,1:ny) = f(2,ix,1:ny)
2103 31 : if(iflg2 == 1) then
2104 0 : if((ibcymin == 1).or.(ibcymin == 2)) ibcmin=0
2105 0 : if((ibcymax == 1).or.(ibcymax == 2)) ibcmax=0
2106 : end if
2107 31 : call mkspline(y,ny,fwk,ibcmin,zbcmin,ibcmax,zbcmax,iliny,ier)
2108 31 : if(ier /= 0) then
2109 0 : deallocate(fwk)
2110 0 : return
2111 : end if
2112 1117 : f(4,ix,1:ny)= fwk(2,1:ny)
2113 : end do
2114 :
2115 1 : if(iflg2 == 1) then
2116 0 : allocate(fcorr(2,nx,ny))
2117 :
2118 : ! correct for inhomogeneous y boundary condition
2119 :
2120 0 : do ix=1,nx
2121 : ! the desired inhomogeneous BC is the difference btw the
2122 : ! requested derivative (1st or 2nd) and the current value
2123 :
2124 0 : zdiff(1)=0.0
2125 0 : if(ibcymin == 1) then
2126 0 : hy=y(2)-y(1)
2127 : zdiff(1)=(f(1,ix,2)-f(1,ix,1))/hy +
2128 0 : & hy*(-2*f(3,ix,1)-f(3,ix,2))/6
2129 0 : zdiff(1)=bcymin(ix)-zdiff(1)
2130 0 : else if(ibcymin == 2) then
2131 0 : zdiff(1)=bcymin(ix)-f(3,ix,1)
2132 : end if
2133 :
2134 0 : zdiff(2)=0.0
2135 0 : if(ibcymax == 1) then
2136 0 : hy=y(ny)-y(ny-1)
2137 : zdiff(2)=(f(1,ix,ny)-f(1,ix,ny-1))/hy +
2138 0 : & hy*(2*f(3,ix,ny)+f(3,ix,ny-1))/6
2139 0 : zdiff(2)=bcymax(ix)-zdiff(2)
2140 0 : else if(ibcymax == 2) then
2141 0 : zdiff(2)=bcymax(ix)-f(3,ix,ny)
2142 : end if
2143 :
2144 0 : fwk(1,1:ny)=0.0 ! values are zero; only BC is not
2145 0 : call mkspline(y,ny,fwk,ibcymin,zdiff(1),ibcymax,zdiff(2),iliny,ier)
2146 0 : if(ier /= 0) then
2147 0 : deallocate(fwk,fcorr)
2148 0 : return
2149 : end if
2150 0 : fcorr(1,ix,1:ny)=fwk(2,1:ny) ! fyy-correction
2151 : end do
2152 :
2153 : zbcmin=0
2154 : zbcmax=0
2155 0 : do iy=1,ny
2156 0 : fwk(1,1:nx)=fcorr(1,1:nx,iy)
2157 0 : call mkspline(x,nx,fwk,ibcxmin,zbcmin,ibcxmax,zbcmax,ilinx,ier)
2158 0 : if(ier /= 0) then
2159 0 : deallocate(fwk,fcorr)
2160 0 : return
2161 : end if
2162 0 : fcorr(2,1:nx,iy)=fwk(2,1:nx) ! fxxyy-correction
2163 : end do
2164 :
2165 0 : f(3:4,1:nx,1:ny)=f(3:4,1:nx,1:ny)+fcorr(1:2,1:nx,1:ny)
2166 :
2167 0 : deallocate(fcorr)
2168 : end if
2169 :
2170 : ! correction spline -- f=fxx=zero; fyy & fxxyy are affected
2171 :
2172 1 : deallocate(fwk)
2173 : !------------------------------------
2174 :
2175 : ! that's all
2176 :
2177 1 : return
2178 2 : end subroutine do_mkbicub
2179 :
2180 97 : subroutine mkspline(x,nx,fspl,ibcxmin,bcxmin,ibcxmax,bcxmax,ilinx,ier)
2181 :
2182 : ! make a 2-coefficient 1d spline
2183 :
2184 : ! only 2 coefficients, the data and its 2nd derivative, are needed to
2185 : ! fully specify a spline. See e.g. Numerical Recipes in Fortran-77
2186 : ! (2nd edition) chapter 3, section on cubic splines.
2187 :
2188 : ! input:
2189 : integer nx ! no. of data points
2190 : real x(:) ! (nx) ! x axis data, strict ascending order
2191 :
2192 : ! input/output:
2193 : real fspl(:,:) ! (2,nx) ! f(1,*): data in; f(2,*): coeffs out
2194 :
2195 : ! f(1,j) = f(x(j)) on input (unchanged on output)
2196 : ! f(2,j) = f''(x(j)) (of interpolating spline) (on output).
2197 :
2198 : ! ...boundary conditions...
2199 :
2200 : ! input:
2201 :
2202 : integer ibcxmin ! b.c. flag @ x=xmin=x(1)
2203 : real bcxmin ! b.c. data @xmin
2204 :
2205 : integer ibcxmax ! b.c. flag @ x=xmax=x(nx)
2206 : real bcxmax ! b.c. data @xmax
2207 :
2208 : ! ibcxmin=-1 -- periodic boundary condition
2209 : ! (bcxmin,ibcxmax,bcxmax are ignored)
2210 :
2211 : ! the output spline s satisfies
2212 : ! s'(x(1))=s'(x(nx)) ..and.. s''(x(1))=s''(x(nx))
2213 :
2214 : ! if non-periodic boundary conditions are used, then the xmin and xmax
2215 : ! boundary conditions can be specified independently:
2216 :
2217 : ! ibcxmin (ibcxmax) = 0 -- this specifies a "not a knot" boundary
2218 : ! condition, see "cubsplb.for". This is a common way
2219 : ! for inferring a "good" spline boundary condition
2220 : ! automatically from data in the vicinity of the
2221 : ! boundary. ... bcxmin (bcxmax) are ignored.
2222 :
2223 : ! ibcxmin (ibcxmax) = 1 -- boundary condition is to have s'(x(1))
2224 : ! ( s'(x(nx)) ) match the passed value bcxmin (bcxmax).
2225 :
2226 : ! ibcxmin (ibcxmax) = 2 -- boundary condition is to have s''(x(1))
2227 : ! ( s''(x(nx)) ) match the passed value bcxmin (bcxmax).
2228 :
2229 : ! ibcxmin (ibcxmax) = 3 -- boundary condition is to have s'(x(1))=0.0
2230 : ! ( s'(x(nx))=0.0 )
2231 :
2232 : ! ibcxmin (ibcxmax) = 4 -- boundary condition is to have s''(x(1))=0.0
2233 : ! ( s''(x(nx))=0.0 )
2234 :
2235 : ! ibcxmin (ibcxmax) = 5 -- boundary condition is to have s'(x(1))
2236 : ! ( s'(x(nx)) ) match the 1st divided difference
2237 : ! e.g. at x(1): d(1)/h(1), where
2238 : ! d(j)=f(1,j+1)-f(1,j)
2239 : ! h(j)=x(j+1)-x(j)
2240 :
2241 : ! ibcxmin (ibcxmax) = 6 -- BC is to have s''(x(1)) ( s''(x(nx)) )
2242 : ! match the 2nd divided difference
2243 : ! e.g. at x(1):
2244 : ! e(1) = [d(2)/h(2) - d(1)/h(1)]/(0.5*(h(1)+h(2)))
2245 :
2246 : ! ibcxmin (ibcxmax) = 7 -- BC is to have s'''(x(1)) ( s'''(x(nx)) )
2247 : ! match the 3rd divided difference
2248 : ! e.g. at x(1): [e(2)-e(1)]/(0.33333*(h(1)+h(2)+h(3)))
2249 :
2250 : ! output:
2251 :
2252 : integer ilinx ! =1: hint, x axis is ~evenly spaced
2253 :
2254 : ! let dx[avg] = (x(nx)-x(1))/(nx-1)
2255 : ! let dx[j] = x(j+1)-x(j), for all j satisfying 1 <= j < nx
2256 :
2257 : ! if for all such j, abs(dx[j]-dx[avg]) <= (1.0e-3*dx[avg]) then
2258 : ! ilinx=1 is returned, indicating the data is (at least nearly)
2259 : ! evenly spaced. Even spacing is useful, for speed of zone lookup,
2260 : ! when evaluating a spline.
2261 :
2262 : ! if the even spacing condition is not satisfied, ilinx=2 is returned.
2263 :
2264 : integer ier ! exit code, 0=OK
2265 :
2266 : ! an error code is returned if the x axis is not strict ascending,
2267 : ! or if nx < 4, or if an invalid boundary condition specification was
2268 : ! input.
2269 :
2270 : !------------------------------------
2271 :
2272 : ! this routine calls traditional 4 coefficient spline software, and
2273 : ! translates the result to 2 coefficient form.
2274 :
2275 : ! this could be done more efficiently but we decided out of conservatism
2276 : ! to use the traditional software.
2277 :
2278 : !------------------------------------
2279 : ! workspaces -- f90 dynamically allocated
2280 :
2281 97 : real, dimension(:,:), allocatable :: fspl4 ! traditional 4-spline
2282 97 : real, dimension(:), allocatable :: wk ! cspline workspace
2283 : integer i,inwk
2284 :
2285 : !------------------------------------
2286 :
2287 97 : allocate(fspl4(4,nx),wk(nx))
2288 :
2289 : ! make the traditional call
2290 :
2291 3352 : do i=1,nx
2292 3255 : fspl4(1,i)=fspl(1,i)
2293 3352 : fspl(2,i)=0.0 ! for now
2294 : end do
2295 :
2296 97 : inwk=nx
2297 :
2298 : ! boundary conditions imposed by cspline...
2299 :
2300 : call cspline(x,nx,fspl4,ibcxmin,bcxmin,ibcxmax,bcxmax,
2301 97 : & wk,inwk,ilinx,ier)
2302 :
2303 97 : if(ier == 0) then
2304 :
2305 : ! copy the output -- careful of end point.
2306 :
2307 3255 : do i=1,nx-1
2308 3255 : fspl(2,i) = 2.0*fspl4(3,i)
2309 : end do
2310 97 : fspl(2,nx) = 2.0*fspl4(3,nx-1) + (x(nx)-x(nx-1))*6.0*fspl4(4,nx-1)
2311 : end if
2312 :
2313 97 : deallocate(fspl4,wk)
2314 :
2315 97 : return
2316 : end subroutine mkspline
2317 :
2318 99 : subroutine splinck(x,inx,ilinx,ztol,ier)
2319 :
2320 : ! check if a grid is strictly ascending and if it is evenly spaced
2321 : ! to w/in ztol
2322 :
2323 : integer inx
2324 : real x(:) ! (inx) ! input -- grid to check
2325 :
2326 : integer ilinx ! output -- =1 if evenly spaced =2 O.W.
2327 :
2328 : real ztol ! input -- spacing check tolerance
2329 :
2330 : integer ier ! output -- =0 if OK
2331 :
2332 : ! ier=1 is returned if x(1...inx) is NOT STRICTLY ASCENDING...
2333 99 : real dxavg,zeps,zdiffx,zdiff
2334 : integer ix
2335 :
2336 : !-------------------------------
2337 :
2338 99 : ier=0
2339 99 : ilinx=1
2340 99 : if(inx <= 1) return
2341 :
2342 99 : dxavg=(x(inx)-x(1))/(inx-1)
2343 99 : zeps=abs(ztol*dxavg)
2344 :
2345 3321 : do ix=2,inx
2346 3222 : zdiffx=(x(ix)-x(ix-1))
2347 3222 : if(zdiffx <= 0.0) ier=2
2348 3222 : zdiff=zdiffx-dxavg
2349 3321 : if(abs(zdiff) > zeps) then
2350 0 : ilinx=2
2351 : end if
2352 : end do
2353 : 10 continue
2354 :
2355 : return
2356 : end subroutine splinck
2357 :
2358 97 : subroutine V_SPLINE(k_bc1,k_bcn,n,x,f,wk)
2359 : !***********************************************************************
2360 : !V_SPLINE evaluates the coefficients for a 1d cubic interpolating spline
2361 : !References:
2362 : ! Forsythe, Malcolm, Moler, Computer Methods for Mathematical
2363 : ! Computations, Prentice-Hall, 1977, p.76
2364 : ! Engeln-Muellges, Uhlig, Numerical Algorithms with Fortran, Springer,
2365 : ! 1996, p.251
2366 : ! W.A.Houlberg, D.McCune 3/2000
2367 : !Input:
2368 : ! k_bc1-option for BC at x(1)
2369 : ! =-1 periodic, ignore k_bcn
2370 : ! =0 not-a-knot
2371 : ! =1 s'(x1) = input value of f(2,1)
2372 : ! =2 s''(x1) = input value of f(3,1)
2373 : ! =3 s'(x1) = 0.0
2374 : ! =4 s''(x1) = 0.0
2375 : ! =5 match first derivative to first 2 points
2376 : ! =6 match second derivative to first 3 points
2377 : ! =7 match third derivative to first 4 points
2378 : ! =else use not-a-knot
2379 : ! k_bcn-option for boundary condition at x(n)
2380 : ! =0 not-a-knot
2381 : ! =1 s'(x1) = input value of f(2,1)
2382 : ! =2 s''(x1) = input value of f(3,1)
2383 : ! =3 s'(x1) = 0.0
2384 : ! =4 s''(x1) = 0.0
2385 : ! =5 match first derivative to first 2 points
2386 : ! =6 match second derivative to first 3 points
2387 : ! =7 match third derivative to first 4 points
2388 : ! =else use knot-a-knot
2389 : ! n-number of data points or knots-(n >= 2)
2390 : ! x(n)-abscissas of the knots in strictly increasing order
2391 : ! f(1,i)-ordinates of the knots
2392 : ! f(2,1)-input value of s'(x1) for k_bc1=1
2393 : ! f(2,n)-input value of s'(xn) for k_bcn=1
2394 : ! f(3,1)-input value of s''(x1) for k_bc1=2
2395 : ! f(3,n)-input value of s''(xn) for k_bcn=2
2396 : ! wk(n)-scratch work area for periodic BC
2397 : !Output:
2398 : ! f(2,i)=s'(x(i))
2399 : ! f(3,i)=s''(x(i))
2400 : ! f(4,i)=s'''(x(i))
2401 : !Comments:
2402 : ! s(x)=f(1,i)+f(2,i)*(x-x(i))+f(3,i)*(x-x(i))**2/2!
2403 : ! +f(4,i)*(x-x(i))**3/3! for x(i) <= x <= x(i+1)
2404 : ! W_SPLINE can be used to evaluate the spline and its derivatives
2405 : ! The cubic spline is twice differentiable (C2)
2406 :
2407 : ! bugfixes -- dmc 24 Feb 2004:
2408 : ! (a) fixed logic for not-a-knot:
2409 : ! ! Set f(3,1) for not-a-knot
2410 : ! if (k_bc1 <= 0.or.k_bc1 > 7) then ...
2411 : ! instead of
2412 : ! ! Set f(3,1) for not-a-knot
2413 : ! if (k_bc1 <= 0.or.k_bc1 > 5) then ...
2414 : ! and similarly for logic after cmt
2415 : ! ! Set f(3,n) for not-a-knot
2416 : ! as required since k_bc*=6 and k_bc*=7 are NOT not-a-knot BCs.
2417 :
2418 : ! (b) the BCs to fix 2nd derivative at end points did not work if that
2419 : ! 2nd derivative were non-zero. The reason is that in those cases
2420 : ! the off-diagonal matrix elements nearest the corners are not
2421 : ! symmetric; i.e. elem(1,2) /= elem(2,1) and
2422 : ! elem(n-1,n) /= elem(n,n-1) where I use "elem" to refer to
2423 : ! the tridiagonal matrix elements. The correct values for the
2424 : ! elements is: elem(1,2)=0, elem(2,1)=x(2)-x(1)
2425 : ! elem(n,n-1)=0, elem(n-1,n)=x(n)-x(n-1)
2426 : ! the old code in effect had these as all zeroes. Since this
2427 : ! meant the wrong set of linear equations was solved, the
2428 : ! resulting spline had a discontinuity in its 1st derivative
2429 : ! at x(2) and x(n-1). Fixed by introducing elem21 and elemnn1
2430 : ! to represent the non-symmetric lower-diagonal values. Since
2431 : ! elem21 & elemnn1 are both on the lower diagonals, logic to
2432 : ! use them occurs in the non-periodic forward elimination loop
2433 : ! only. DMC 24 Feb 2004.
2434 : !***********************************************************************
2435 : implicit none
2436 : !Declaration of input variables
2437 : integer :: k_bc1, k_bcn, n
2438 : real :: x(*), wk(*), f(4,*)
2439 : !Declaration in local variables
2440 : integer :: i, ib, imax, imin
2441 97 : real :: a1, an, b1, bn, q, t, hn
2442 97 : real :: elem21, elemnn1 ! (dmc)
2443 :
2444 : !Set default range
2445 97 : imin=1
2446 97 : imax=n
2447 : !Set first and second BC values
2448 97 : a1=0.0
2449 97 : b1=0.0
2450 97 : an=0.0
2451 97 : bn=0.0
2452 97 : if (k_bc1 == 1) then
2453 0 : a1=f(2,1)
2454 97 : else if(k_bc1 == 2) then
2455 0 : b1=f(3,1)
2456 97 : else if(k_bc1 == 5) then
2457 0 : a1=(f(1,2)-f(1,1))/(x(2)-x(1))
2458 97 : else if(k_bc1 == 6) then
2459 : b1=2.0*((f(1,3)-f(1,2))/(x(3)-x(2))
2460 0 : & -(f(1,2)-f(1,1))/(x(2)-x(1)))/(x(3)-x(1))
2461 : end if
2462 97 : if (k_bcn == 1) then
2463 0 : an=f(2,n)
2464 97 : else if(k_bcn == 2) then
2465 0 : bn=f(3,n)
2466 97 : else if(k_bcn == 5) then
2467 0 : an=(f(1,n)-f(1,n-1))/(x(n)-x(n-1))
2468 97 : else if(k_bcn == 6) then
2469 : bn=2.0*((f(1,n)-f(1,n-1))/(x(n)-x(n-1))
2470 0 : & -(f(1,n-1)-f(1,n-2))/(x(n-1)-x(n-2)))/(x(n)-x(n-2))
2471 : end if
2472 : !Clear f(2:4,n)
2473 97 : f(2,n)=0.0
2474 97 : f(3,n)=0.0
2475 97 : f(4,n)=0.0
2476 97 : if (n == 2) then
2477 : !Coefficients for n=2
2478 0 : f(2,1)=(f(1,2)-f(1,1))/(x(2)-x(1))
2479 0 : f(3,1)=0.0
2480 0 : f(4,1)=0.0
2481 0 : f(2,2)=f(2,1)
2482 0 : f(3,2)=0.0
2483 0 : f(4,2)=0.0
2484 97 : else if(n > 2) then
2485 : !Set up tridiagonal system for A*y=B where y(i) are the second
2486 : ! derivatives at the knots
2487 : ! f(2,i) are the diagonal elements of A
2488 : ! f(4,i) are the off-diagonal elements of A
2489 : ! f(3,i) are the B elements/3, and will become c/3 upon solution
2490 97 : f(4,1)=x(2)-x(1)
2491 97 : f(3,2)=(f(1,2)-f(1,1))/f(4,1)
2492 3158 : do i=2,n-1
2493 3061 : f(4,i)=x(i+1)-x(i)
2494 3061 : f(2,i)=2.0*(f(4,i-1)+f(4,i))
2495 3061 : f(3,i+1)=(f(1,i+1)-f(1,i))/f(4,i)
2496 3158 : f(3,i)=f(3,i+1)-f(3,i)
2497 : end do
2498 :
2499 : ! (dmc): save now:
2500 :
2501 97 : elem21=f(4,1)
2502 97 : elemnn1=f(4,n-1)
2503 :
2504 : ! BC's
2505 : ! Left
2506 : if (k_bc1 == -1) then
2507 0 : f(2,1)=2.0*(f(4,1)+f(4,n-1))
2508 0 : f(3,1)=(f(1,2)-f(1,1))/f(4,1)-(f(1,n)-f(1,n-1))/f(4,n-1)
2509 0 : wk(1)=f(4,n-1)
2510 0 : do i=2,n-3
2511 0 : wk(i)=0.0
2512 : end do
2513 0 : wk(n-2)=f(4,n-2)
2514 0 : wk(n-1)=f(4,n-1)
2515 : else if(k_bc1 == 1.or.k_bc1 == 3.or.k_bc1 == 5) then
2516 0 : f(2,1)=2.0*f(4,1)
2517 0 : f(3,1)=(f(1,2)-f(1,1))/f(4,1)-a1
2518 : else if(k_bc1 == 2.or.k_bc1 == 4.or.k_bc1 == 6) then
2519 0 : f(2,1)=2.0*f(4,1)
2520 0 : f(3,1)=f(4,1)*b1/3.0
2521 0 : f(4,1)=0.0 ! upper diagonal only (dmc: cf elem21)
2522 : else if(k_bc1 == 7) then
2523 0 : f(2,1)=-f(4,1)
2524 0 : f(3,1)=f(3,3)/(x(4)-x(2))-f(3,2)/(x(3)-x(1))
2525 0 : f(3,1)=f(3,1)*f(4,1)**2/(x(4)-x(1))
2526 : else ! not a knot:
2527 97 : imin=2
2528 97 : f(2,2)=f(4,1)+2.0*f(4,2)
2529 97 : f(3,2)=f(3,2)*f(4,2)/(f(4,1)+f(4,2))
2530 : end if
2531 : ! Right
2532 97 : if (k_bcn == 1.or.k_bcn == 3.or.k_bcn == 5) then
2533 0 : f(2,n)=2.0*f(4,n-1)
2534 0 : f(3,n)=-(f(1,n)-f(1,n-1))/f(4,n-1)+an
2535 : else if(k_bcn == 2.or.k_bcn == 4.or.k_bcn == 6) then
2536 0 : f(2,n)=2.0*f(4,n-1)
2537 0 : f(3,n)=f(4,n-1)*bn/3.0
2538 : !xxx f(4,n-1)=0.0 ! dmc: preserve f(4,n-1) for back subst.
2539 0 : elemnn1=0.0 ! lower diagonal only (dmc)
2540 : else if(k_bcn == 7) then
2541 0 : f(2,n)=-f(4,n-1)
2542 0 : f(3,n)=f(3,n-1)/(x(n)-x(n-2))-f(3,n-2)/(x(n-1)-x(n-3))
2543 0 : f(3,n)=-f(3,n)*f(4,n-1)**2/(x(n)-x(n-3))
2544 97 : else if(k_bc1 /= -1) then ! not a knot:
2545 97 : imax=n-1
2546 97 : f(2,n-1)=2.0*f(4,n-2)+f(4,n-1)
2547 97 : f(3,n-1)=f(3,n-1)*f(4,n-2)/(f(4,n-1)+f(4,n-2))
2548 : end if
2549 : ! Limit solution for only three points in domain
2550 97 : if (n == 3) then
2551 0 : f(3,1)=0.0
2552 0 : f(3,n)=0.0
2553 : end if
2554 97 : if (k_bc1 == -1) then
2555 : !Solve system of equations for second derivatives at the knots
2556 : ! Periodic BC
2557 : ! Forward elimination
2558 0 : do i=2,n-2
2559 0 : t=f(4,i-1)/f(2,i-1)
2560 0 : f(2,i)=f(2,i)-t*f(4,i-1)
2561 0 : f(3,i)=f(3,i)-t*f(3,i-1)
2562 0 : wk(i)=wk(i)-t*wk(i-1)
2563 0 : q=wk(n-1)/f(2,i-1)
2564 0 : wk(n-1)=-q*f(4,i-1)
2565 0 : f(2,n-1)=f(2,n-1)-q*wk(i-1)
2566 0 : f(3,n-1)=f(3,n-1)-q*f(3,i-1)
2567 : end do
2568 : ! Correct the n-1 element
2569 0 : wk(n-1)=wk(n-1)+f(4,n-2)
2570 : ! Complete the forward elimination
2571 : ! wk(n-1) and wk(n-2) are the off-diag elements of the lower corner
2572 0 : t=wk(n-1)/f(2,n-2)
2573 0 : f(2,n-1)=f(2,n-1)-t*wk(n-2)
2574 0 : f(3,n-1)=f(3,n-1)-t*f(3,n-2)
2575 : ! Back substitution
2576 0 : f(3,n-1)=f(3,n-1)/f(2,n-1)
2577 0 : f(3,n-2)=(f(3,n-2)-wk(n-2)*f(3,n-1))/f(2,n-2)
2578 0 : do ib=3,n-1
2579 0 : i=n-ib
2580 0 : f(3,i)=(f(3,i)-f(4,i)*f(3,i+1)-wk(i)*f(3,n-1))/f(2,i)
2581 : end do
2582 0 : f(3,n)=f(3,1)
2583 : else
2584 : ! Non-periodic BC
2585 : ! Forward elimination
2586 : ! For Not-A-Knot BC the off-diagonal end elements are not equal
2587 3061 : do i=imin+1,imax
2588 2964 : if ((i == n-1).and.(imax == n-1)) then
2589 97 : t=(f(4,i-1)-f(4,i))/f(2,i-1)
2590 : else
2591 2867 : if(i == 2) then
2592 0 : t=elem21/f(2,i-1)
2593 2867 : else if(i == n) then
2594 0 : t=elemnn1/f(2,i-1)
2595 : else
2596 2867 : t=f(4,i-1)/f(2,i-1)
2597 : end if
2598 : end if
2599 2964 : if ((i == imin+1).and.(imin == 2)) then
2600 97 : f(2,i)=f(2,i)-t*(f(4,i-1)-f(4,i-2))
2601 : else
2602 2867 : f(2,i)=f(2,i)-t*f(4,i-1)
2603 : end if
2604 3061 : f(3,i)=f(3,i)-t*f(3,i-1)
2605 : end do
2606 : ! Back substitution
2607 97 : f(3,imax)=f(3,imax)/f(2,imax)
2608 3061 : do ib=1,imax-imin
2609 2964 : i=imax-ib
2610 3061 : if (abs(f(3,i)) > 1e20) then
2611 0 : f(3,i) = 0.0 ! protect against overflow
2612 2964 : else if((i == 2).and.(imin == 2)) then
2613 97 : f(3,i)=(f(3,i)-(f(4,i)-f(4,i-1))*f(3,i+1))/f(2,i)
2614 : else
2615 2867 : f(3,i)=(f(3,i)-f(4,i)*f(3,i+1))/f(2,i)
2616 : end if
2617 : end do
2618 : ! Reset d array to step size
2619 97 : f(4,1)=x(2)-x(1)
2620 97 : f(4,n-1)=x(n)-x(n-1)
2621 : ! Set f(3,1) for not-a-knot
2622 97 : if (k_bc1 <= 0.or.k_bc1 > 7) then
2623 97 : f(3,1)=(f(3,2)*(f(4,1)+f(4,2))-f(3,3)*f(4,1))/f(4,2)
2624 : end if
2625 : ! Set f(3,n) for not-a-knot
2626 97 : if (k_bcn <= 0.or.k_bcn > 7) then
2627 97 : f(3,n)=f(3,n-1)+(f(3,n-1)-f(3,n-2))*f(4,n-1)/f(4,n-2)
2628 : end if
2629 : end if
2630 : !f(3,i) is now the sigma(i) of the text and f(4,i) is the step size
2631 : !Compute polynomial coefficients
2632 3255 : do i=1,n-1
2633 : f(2,i)=
2634 3158 : & (f(1,i+1)-f(1,i))/f(4,i)-f(4,i)*(f(3,i+1)+2.0*f(3,i))
2635 3158 : f(4,i)=(f(3,i+1)-f(3,i))/f(4,i)
2636 3158 : f(3,i)=6.0*f(3,i)
2637 3255 : f(4,i)=6.0*f(4,i)
2638 : end do
2639 97 : if (k_bc1 == -1) then
2640 0 : f(2,n)=f(2,1)
2641 0 : f(3,n)=f(3,1)
2642 0 : f(4,n)=f(4,1)
2643 : else
2644 97 : hn=x(n)-x(n-1)
2645 97 : f(2,n)=f(2,n-1)+hn*(f(3,n-1)+0.5*hn*f(4,n-1))
2646 97 : f(3,n)=f(3,n-1)+hn*f(4,n-1)
2647 97 : f(4,n)=f(4,n-1)
2648 : if (k_bcn == 1.or.k_bcn == 3.or.k_bcn == 5) then
2649 0 : f(2,n)=an
2650 : else if(k_bcn == 2.or.k_bcn == 4.or.k_bcn == 6) then
2651 0 : f(3,n)=bn
2652 : end if
2653 : end if
2654 : end if
2655 97 : return
2656 : end subroutine V_SPLINE
2657 :
2658 :
2659 0 : subroutine zonfind(x,nx,zxget,i)
2660 :
2661 : integer nx
2662 : real zxget
2663 : real x(:) ! (nx)
2664 : integer i,nxm,i1,i2,ij,ii
2665 0 : real dx
2666 :
2667 : ! find index i such that x(i) <= zxget <= x(i+1)
2668 :
2669 : ! x(1...nx) is strict increasing and x(1) <= zxget <= x(nx)
2670 : ! (this is assumed to already have been checked -- no check here!)
2671 :
2672 0 : nxm=nx-1
2673 0 : if((i < 1).or.(i > nxm)) then
2674 : i1=1
2675 : i2=nx-1
2676 : GOTO 10
2677 : end if
2678 :
2679 0 : if(x(i) > zxget) then
2680 : ! look down
2681 0 : dx=x(i+1)-x(i)
2682 0 : if((x(i)-zxget) > 4*dx) then
2683 0 : i1=1
2684 0 : i2=i-1
2685 0 : GOTO 10
2686 : else
2687 0 : i2=i-1
2688 0 : do ij=i2,1,-1
2689 0 : if((x(ij) <= zxget).and.(zxget <= x(ij+1))) then
2690 0 : i=ij
2691 0 : return
2692 : end if
2693 : end do
2694 0 : i=1
2695 0 : return
2696 : end if
2697 0 : else if(x(i+1) < zxget) then
2698 : ! look up
2699 0 : dx=x(i+1)-x(i)
2700 0 : if((zxget-x(i+1)) > 4*dx) then
2701 : i1=i+1
2702 : i2=nxm
2703 : GOTO 10
2704 : else
2705 0 : i2=i+1
2706 0 : do ij=i2,nxm
2707 0 : if((x(ij) <= zxget).and.(zxget <= x(ij+1))) then
2708 0 : i=ij
2709 0 : return
2710 : end if
2711 : end do
2712 0 : ij=nxm
2713 : return
2714 : end if
2715 : else
2716 : ! already there...
2717 : return
2718 : end if
2719 :
2720 : !---------------------------
2721 : ! binary search
2722 :
2723 : 10 continue
2724 :
2725 0 : if(i1 == i2) then
2726 : ! found by proc. of elimination
2727 0 : i=i1
2728 0 : return
2729 : end if
2730 :
2731 0 : ii=(i1+i2)/2
2732 :
2733 0 : if(zxget < x(ii)) then
2734 0 : i2=ii-1
2735 0 : else if(zxget > x(ii+1)) then
2736 : i1=ii+1
2737 : else
2738 : ! found
2739 0 : i=ii
2740 0 : return
2741 : end if
2742 :
2743 : GOTO 10
2744 :
2745 : end subroutine zonfind
2746 :
2747 : end module bicub_sg
|