V3FIT
akherm1.f
1  subroutine akherm1(x,nx,fherm,ilinx,ier)
2 C
3 C create a data set for Hermite interpolation, based on Akima's method
4 C [Hiroshi Akima, Communications of the ACM, Jan 1974, Vol. 17 No. 1]
5 C
6 C 1d routine -- default boundary condition (based on divided differences)
7 C
8 C input:
9 C
10  integer nx ! array dimensions
11  real x(nx) ! x coordinate array
12  real fherm(0:1,nx) ! data/Hermite array
13 C
14 C fherm(0,i) = function value f at x(i) **on input**
15 C
16 C fherm(1,i) = derivative df/dx at x(i) **on output**
17 C
18 C addl output:
19 C ilinx=1 if x is "evenly spaced" ier=0 if no errors
20 C
21 C ** x must be strict ascending **
22 C
23 C work by calling akherm1p; no periodic boundary condition
24 C
25  call akherm1p(x,nx,fherm,ilinx,0,ier)
26 C
27  return
28  end
29 C----------------------------
30  subroutine akherm1p(x,nx,fherm,ilinx,ipx,ier)
31 C
32 C Akima subroutine with boundary condition option:
33 C
34 C =>ipx=1 for periodic boundary condition
35 C
36 C =>ipx=2 for user specified boundary condition:
37 C in which case fherm(1,1) and fherm(1,nx) must contain
38 C the derivatives fx(x(1)) and fx(x(nx)), respectively, and these
39 C will not be modified on output.
40 C
41 C =>ipx=0: default boundary conditions
42 C
43 C other arguments as with akherm1.
44 C
45 C input:
46 C
47  integer nx ! array dimensions
48  real x(nx) ! x coordinate array
49  real fherm(0:1,nx) ! data/Hermite array
50  integer ipx ! =1: f' periodic in x
51 C
52 C----------------------------
53 C
54  real wx(2)
55 C
56 C error checks...
57 C
58  ztol=1.0e-3
59  ier=0
60 C
61  call splinck(x,nx,ilinx,ztol,ier)
62  if(ier.ne.0) then
63  write(6,*) '?akherm1: x axis not strict ascending.'
64  ier=ier+1
65  endif
66 C
67  ierbc=0
68  call ibc_ck(ipx,'akherm1','Bdy Cond',0,2,ierbc)
69  ier=ier+ierbc
70  if(ier.gt.0) return
71 C
72 C deal with boundary region. The boundary derivatives are set
73 C and "ghost" points are provided...
74 C
75 C all paths need the 1st div. diffs at the bdy...
76 C
77  cxp=(fherm(0,2)-fherm(0,1))/(x(2)-x(1))
78  cxm=(fherm(0,nx)-fherm(0,nx-1))/(x(nx)-x(nx-1))
79 C
80  if(ipx.eq.1) then
81 C
82 C periodic BC
83 C
84 C LHS/RHS
85 C
86  if(nx.gt.2) then
87  cxpp=(fherm(0,3)-fherm(0,2))/(x(3)-x(2))
88  cxmm=(fherm(0,nx-1)-fherm(0,nx-2))/(x(nx-1)-x(nx-2))
89 C
90  call akherm0(cxmm,cxm,cxp,cxpp,wx,fherm(1,1))
91  fherm(1,nx)=fherm(1,1)
92  else
93  ! nx=2
94  fherm(1,1)=cxp ! =cxm
95  fherm(1,nx)=cxm ! =cxp
96  endif
97 c
98  cxtrap0=cxm
99  cxtrap1=cxp
100 C
101  else if(ipx.eq.0) then
102 C
103 C default BC -- standard numeric extrapolation
104 C
105  if(nx.gt.2) then
106  cxpp=(fherm(0,3)-fherm(0,2))/(x(3)-x(2))
107  fherm(1,1)=1.5*cxp-0.5*cxpp
108 C
109  cxmm=(fherm(0,nx-1)-fherm(0,nx-2))/(x(nx-1)-x(nx-2))
110  fherm(1,nx)=1.5*cxm-0.5*cxmm
111 C
112  else
113  ! nx=2
114  fherm(1,1)=cxp ! =cxm
115  fherm(1,nx)=cxm ! =cxp
116  endif
117 C
118 C extrapolate to slope to ghost points just past bdy...
119 C
120  cxtrap0=2.0*fherm(1,1)-cxp
121  cxtrap1=2.0*fherm(1,nx)-cxm
122 C
123  else
124 C
125 C BC supplied by user. Also use this for extrapolation...
126 C extrapolate to slope to ghost points just past bdy...
127 C
128  cxtrap0=2.0*fherm(1,1)-cxp
129  cxtrap1=2.0*fherm(1,nx)-cxm
130 C
131  endif
132 C
133 C NOTE: this loop is inactive if nx=2
134 C
135  do ix=2,nx-1
136 c
137 c x div. diffs in vicinity
138 c
139  ixm2=ix
140  ixm1=ixm2-1
141  ixmm2=ixm1
142  ixmm1=ixm1-1
143 c
144  ixp2=ix+1
145  ixp1=ix
146  ixpp2=ix+2
147  ixpp1=ixp2
148 c
149  if(ix.eq.2) then
150  cxmm=cxtrap0
151  else
152  cxmm=(fherm(0,ixmm2)-fherm(0,ixmm1))/(x(ixmm2)-x(ixmm1))
153  endif
154 c
155  if(ix.eq.nx-1) then
156  cxpp=cxtrap1
157  else
158  cxpp=(fherm(0,ixpp2)-fherm(0,ixpp1))/(x(ixpp2)-x(ixpp1))
159  endif
160 c
161  cxm=(fherm(0,ixm2)-fherm(0,ixm1))/(x(ixm2)-x(ixm1))
162  cxp=(fherm(0,ixp2)-fherm(0,ixp1))/(x(ixp2)-x(ixp1))
163 C
164  call akherm0(cxmm,cxm,cxp,cxpp,wx,fherm(1,ix))
165 c
166  enddo
167 C
168  return
169  end
170 C--------------------------------------
171  subroutine akherm0(cxmm,cxm,cxp,cxpp,wx,result)
172 c
173 c basic akima formula for 1st derivative at pt p:
174 c
175 c cxmm = numerical slope 2 zones to left
176 c cxm = numerical slope 1 zone to left
177 c cxp = numerical slope 1 zone to right
178 c cxpp = numerical slope 2 zones to right
179 c
180 c return slope at point p and weighting factors
181 c
182  real cxmm,cxm,cxp,cxpp ! nearby slopes (in)
183  real wx(2) ! weights (out)
184  real result ! Akima nominal slope (out)
185 c
186  wx(2)=abs(cxm-cxmm)
187  wx(1)=abs(cxp-cxpp)
188  if(wx(1)+wx(2).eq.0.0) then
189  wx(1)=1.0
190  wx(2)=1.0
191  endif
192 c
193 c the derivative -- weighted average of neighbouring slopes
194 c
195  result=(wx(1)*cxm+wx(2)*cxp)/(wx(1)+wx(2))
196 c
197  return
198  end