Cubic Splines Consider the function P

advertisement
Cubic Splines
Consider the function
 0
1  x  0.2

f ( x)  5 x  .2 0.2  x  0.2

0.2  x  1
 0
and fit with polynomials of degree 2, 4, 6, and 8 (P2, P4, P6, P8 respectively). Note that for an
even function that the coefficients of odd powers of x are zero. From the sketches a fit using P2
may be best.
If a piecewise cubic is used the points, slopes and curvatures (second derivatives) can be made
continuous between the splines (i.e., the lines drawn between neighboring points). This is the
way we draw using French curves.
In the interval i (which extends from xi to xi+1) use
y  fi ( x)  ai ( x  xi )3  bi ( x  xi ) 2  ci ( x  xi )  d i
Let hi  xi1  xi , since y  yi at x  xi then
di  yi .
At x  xi1 , x  xi  xi1  xi and y  yi1 then
(1)
yi1  ai hi3  bi hi2  ci hi  di
is a second equation. Also in xi , xi 1 
y  3ai ( x  xi ) 2  2bi x  xi   ci
and
y  6ai ( x  xi )  2bi .
We need to match slopes and curvatures at xi and xi 1 . Let the curvatures remain as the
unknowns for now, by setting
Si 
d2y
dx 2
.
x  xi
Then
Si  2bi and Si1  6ai hi  2bi .
Solving these for ai and bi
bi 
Si
S  Si
and ai  i 1
.
2
6hi
Substituting back in the equations for yi 1 to find ci , we get
 S  Si
yi 1   i 1
 6hi
Hence ci 
 3 Si 2
hi  hi  ci hi  yi.
2

yi1  yi Si1hi Si hi yi1  yi  2hi Si  hi Si1 




.
hi
6
3
hi
6


All the remains is to equate the slopes at the spline end points. The slopes are found from
y 
Then
Si 1  Si
x  xi 2  Si x  xi   yi1  yi  2hi Si  hi Si1 .
2hi
hi
6
At x  xi
yi 1  yi 2hi Si  hi Si1

hi
6
yi 
and
yi1 
S i 1  Si
y  yi 2hi S i  hi S i 1
hi  S i hi  i 1

2
hi
6
or
yi1 
2hi S i 1  hi S i yi 1  yi
.

6
hi
The slope of the spline from k to k+1 is equal to the slope of the spline from k-1 to k at x  xk .
The slope of the spline from k-1 to k at x  xk is
y k 1 
2hk 1 S k  S k 1hk 1 y k  y k 1
,

6
hk 1
and the slope of the spline from k to k+1 at x  xk is
yk  
2hk S k  S k 1hk yk 1  y k

.
6
hk
Since they are equal
hk 1
2h  2hk
h
y  yk yk  yk 1
S k 1  k 1
S k  k S k 1  k 1

6
6
6
hk
hk 1
and
 y  yk yk  yk 1 
 .
hk 1S k 1  2hk 1  hk S k  hk S k 1  6 k 1

h
h
k
k

1


These equations are valid for 2  k  N  1, but there are no equations for the end points k  1
and k  N . Then there are no equations for S1 and S N , and there are N  2 equations for N
unknowns. Three possibilities are commonly considered at each end:
1) S1  0 or S N  0 , (i.e., splines are linear at the ends),
2) S1  S 2 or S N  S N 1 , (i.e., splines are quadratic at the ends),
S  S N 1 S N 1  S N 2
S  S1 S 3  S 2


3) 2
or N
(i.e., at ends curvatures vary linear).
h1
h2
hN 1
hN 2
The central N-2 equations can be written in matrix form as
 S1 
 S 
2 
h2
0
...  
h1 2(h1  h2 )
 S 
0
h2
2(h2  h3 )
h3
...   3 

  S 4   6change in slope for 2  k  N  1
0
0
h3
2(h3  h4 ) ...  


  ... 
...
...
...
hN 
 ...
S N 1 
S 
 N 
The 2nd equation can be modified, for example, condition (1) make the first equation
2(h1  h2 ) S 2  h2 S3  6change in slope at x  x2 .
For condition (2) (3h1  2h2 ) S 2  h2 S3  6change in slope at x  x2 ,
and for condition (3),
(h1  h2 )( h1  2h2 )
h 2  h12
S2  2
S3  6change in slope at x  x2  .
h2
h2
There are similar relationships for k  N  1 end conditions. This leaves N-2 equations in N-2
unknowns.
Example: y  x 3  8 .
x
y
Note that hi  1 . Let  i 
0
-8
1
-7
2
0
3
19
4
56
yi 1  yi yi  yi 1

 yi 1  2 yi  yi 1 be the change in slope at
xi 1  xi xi  xi 1
x  xi  i  1 .
Therefore
2  0  14  8  6, 3  19  0  7  12, 4  56  38  0  18.
For condition (1) at both ends,
 S1   0 
S   6.4285 
4 1 0 S 2   36 
 2 

1 4 1  S    72  and  S   10.2857  .








3

 3







0 1 4 S 4  108
S
24.4285
 4 

 S 5   0 
For condition (2) at both ends,
 S1   4.8 
S   4.8 
5 1 0 S 2   36 
 2 

1 4 1  S    72  and  S   12.0 ,
 3 


 3   







0 1 5 S 4  108
S
19.2
 4 

 S5  19.2
and condition (3) at both ends,
 S1   0 
S   6 
6 0 0 S 2   36 
 2  
1 4 1  S    72  and  S 3   12  .

 3   
S  18 
0 0 6 S 4  108 
 4  
 S 5  24
Cubic splines can be used evaluate the function and its first and second derivatives. For
example, at x  xi
f ( xi )  di ,
f ( xi )  ci ,
and
f ( xi )  2bi .
Integrals can also be evaluated. Over the entire range x1  x  x N 1 ,
xN 1

x1
xi 1
bi
ci
 ai

4
3
2
f ( x)dx 
 4 ( x  xi )  3 ( x  xi )  2 ( x  xi )  d i ( x  xi )
 xi
i 1 
N

and
xN 1

x
f ( x)dx 
1
N
a

i 4
i 3
i 2

 4 hi  3 hi  2 hi  d i hi .

i 1 
b
c
If hi  h and all the intervals are equal
xN 1

x
1
f ( x)dx 
h4
4
N

i 1
ai 
h3
3
N

i 1
bi 
h2
2
N

i 1
ci  h
N
di .

i 1
program test_spline
C
C
C
Test the cubic spline program
implicit none
C
C
C
Declare variables
real xa(5001)
real ya(5001)
real a(5000)
real b(5000)
real c(5000)
real d(5000)
real x
real y
integer N
integer eval
real S1
real SN
character*40 jobname
integer Type1
integer TypeN
integer i
integer EOF
C
C
C
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
Array of x values for fit
Array of y values to fit
Cubic coefficient of x^3
Cubic coefficient of x^2
Cubic coefficient of x^1
Cubic coefficient of x^0
Point to find cubic spline value
Cubic spline value at x
Number of points
Zero to find coefficients,
Not zero to evaluate y at x only
First curvature
Last curvature
Name of job
First boundary condition type
Last boundary condition type
Counter
EOF
Get data input file from the user
write (6,'(A)') 'Note: jobname.inp is input file'
write (6,'(A)') '
jobname.out is output file'
write (6,'(A)') '
Each line of jobname.inp is x,y in pairs'
write (6,'("Please enter jobname: ",$)')
read (5,'(A)') jobname
C
C
C
Find first blank in jobname
i=1
do while (jobname(i:i).ne.' ')
i=i+1
end do
open (unit=10,file=jobname(1:i-1)//'.dat',status='unknown')
C
C
C
Get the first and last curvature boundary conditions from the user
write (6,'("Please enter the first curvature type (Type1): ",$)')
read (5,*) Type1
If (Type1.eq.0) then
write (6,'("Please enter the first curvature (S1): ",$)')
read (5,*) S1
end if
write (6,'("Please enter the last curvature type (TypeN): ",$)')
read (5,*) TypeN
If (TypeN.eq.0) then
write (6,'("Please enter the last curvature (SN): ",$)')
read (5,*) SN
end if
C
C
C
Read input file to end
EOF=0 ! Set flag for end of file
N=1
! Initialize counter to get number of points
C
C
C
Read the points
do while (EOF.eq.0)
read (10,*,iostat=EOF) xa(N),ya(N)
N=N+1
end do
N=N-2 ! Correct to number of intervals
C
C
C
Echo the input
write (6,'(///)')
write (6,'(A,I3)') 'N = ',N
write (6,'(/)')
write (6,'( A)') '
i
x(i)
y(i)'
write (6,'(I5,1P2E15.6)') (i,xa(i),ya(i),i=1,N)
write (6,'(//)')
write (6,'(A,I2)') 'Boundary Condition Type at 1 =
If (Type1.eq.0) write (6,'(A,1PE10.3)') 'Curvature
write (6,'(A,I2)') 'Boundary Condition Type at N =
If (TypeN.eq.0) write (6,'(A,1PE10.3)') 'Curvature
C
C
C
',Type1
at 1 = ',S1
',TypeN
at N = ',SN
Call the cubic spline program
call cubic_spline(xa,ya,a,b,c,d,N,x,y,0,Type1,TypeN,S1,SN)
C
C
C
Write the coefficients
write (6,'(//)')
write (6,*) '
i
a(i)
b(i)'
$
,'
c(i)
d(i)'
do i=1,N-1
write (6,'(I5,1P4E15.6)') i,a(i),b(i),c(i),d(i)
end do
C
C
C
C
C
C
C
Get a point to evaluate the spline
write (6,'(// A,1PE10.3,A,1PE10.3 /)')
$ 'Evaluation will occur while x is in ',xa(1),' to ',xa(N)
x=(xa(1)+xa(N))/2.
do while (x.ge.xa(1).and.x.le.xa(N))
do
write (6,'("Please enter an x to evaluate the spline: ",$)')
read (5,*) x
if (x.lt.xa(1).or.x.gt.xa(n)) stop
! Normal stop
Evaluate the spline at the point
call cubic_spline(xa,ya,a,b,c,d,N,x,y,1,Type1,TypeN,S1,SN)
C
C
Write the value
C
write (6,'(/)')
write (6,'(2(A,1PE10.4))') 'y(',x,') = ',y
write (6,'(/)')
end do
C
C
C
Program end
end
subroutine
$
C
C
C
cubic_spline(xa,ya,a,b,c,d,N,x,y,eval,Type1,TypeN,S1,SN)
Find the coefficients and/or the value for a cubic spline
implicit none
C
C
C
Declare parameters
integer NDIM
parameter (NDIM=500)
C
C
C
Declare input variables
real xa(N)
real ya(N)
real a(N-1)
real b(N-1)
real c(N-1)
real d(N-1)
real x
real y
integer N
integer Type1
integer TypeN
integer eval
real S1
real SN
C
C
C
Array of x values for fit
Array of y values to fit
Cubic coefficient of x^3
Cubic coefficient of x^2
Cubic coefficient of x^1
Cubic coefficient of x^0
Point to find cubic spline value
Cubic spline value at x
Number of points
First boundary condition type
Last boundary condition type
Zero to find coefficients,
Not zero to evaluate y at x only
First curvature
Last curvature
!
!
!
!
!
!
!
Slopes
Curvatures
Intervals
Coefficient matrix
Right hand side
Counter
Error message
Declare subroutine variables
real dydx(NDIM)
real S(N)
real h(N-1)
real AA(NDIM,NDIM)
real BB(NDIM)
integer i
character*72 error_mssg(4)
C
C
C
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
Set error message in data
error_mssg(1)='***************************************'
error_mssg(4)='* in NDIM in routine cubic_spline.f *'
C
C
C
C
Check to be sure number of points is less than NDIM+1
Write message and stop
if (N.gt.NDIM+1) then
write (error_mssg(2),'(A,I5,A)')
$
'* ERROR: Number of points N is ',N,' *'
write (error_mssg(3),'(A,I5,A)')
$
'* which is greater than ',NDIM,' stored *'
do i=1,4
write (6,'(A)') error_mssg(i)
end do
write (6,'(A)') error_mssg(1)
stop
end if
C
C
C
Find coefficients if eval equal 0
$
C
C
C
call find_cubic_spline_coeff(xa,ya,a,b,c,d,N,
Type1,TypeN,S1,SN,dydx,S,h,AA,BB,NDIM)
Evaluate polynomial if eval equal
call eval_cubic_spline(xa,a,b,c,d,N,x,y)
C
C
C
Normal return
return
end
$
C
C
C
subroutine find_cubic_spline_coeff(xa,ya,a,b,c,d,N,
Type1,TypeN,S1,SN,dydx,S,h,AA,BB,NDIM)
Find the coefficients for a cubic spline
implicit none
C
C
C
Declare input variables
real xa(N)
real ya(N)
real a(N-1)
real b(N-1)
real c(N-1)
real d(N-1)
real S1
real SN
integer N
integer Type1
integer TypeN
C
C
C
!
!
!
!
!
!
!
!
!
!
!
Array of x values for fit
Array of y values to fit
Cubic coefficient of x^3
Cubic coefficient of x^2
Cubic coefficient of x^1
Cubic coefficient of x^0
First curvature
Last curvature
Number of points
First boundary condition type
Last boundary condition type
Declare subroutine variables
integer NDIM
real dydx(N)
real S(N)
! Array dimensions
! Slopes
! Curvatures
real h(N)
real AA(NDIM,NDIM)
real BB(NDIM)
integer i,j
C
C
C
!
!
!
!
Intervals
Coefficient matrix
Right hand side
Counters
Find the interval and the slopes
do i=1,N-1
h(i)=xa(i+1)-xa(i)
dydx(i)=(ya(i+1)-ya(i))/h(i)
end do
C
C
C
Find the coefficient matrix
do i=1,N
do j=1,N
AA(i,j)=0.
end do
end do
if (type1.le.1) then
AA(1,1)=1.
else if (type1.eq.2) then
AA(1,1)=1.
AA(1,2)=-1.
else
AA(1,1)=1./h(1)
AA(1,2)=-1./h(1)-1./h(2)
AA(1,3)=1./h(2)
end if
do i=2,N-1
AA(i,i-1)=h(i-1)
AA(i,i)=2.*(h(i-1)+h(i))
AA(i,i+1)=h(i)
end do
if (typeN.le.1) then
AA(N,N)=1.
else if (typeN.eq.2) then
AA(N,N)=1.
AA(N,N-1)=-1.
else
AA(N,N)=1./h(N-1)
AA(N,N-1)=-1./h(N-1)-1./h(N-2)
AA(N,N-2)=1./h(N-2)
end if
C
C
C
Find the right hand side
If (Type1.eq.0) then
BB(1)=S1
else
BB(1)=0.
end if
do i=2,N-1
BB(i)=6.*(dydx(i)-dydx(i-1))
end do
If (TypeN.eq.0) then
BB(N)=SN
else
BB(N)=0.
end if
C
C
C
Solve the equations by AA decomposition
call matrix_solve(AA,BB,S,N,NDIM)
C
C
C
Find the spline coefficients
do i=1,N-1
a(i)=(S(i+1)-S(i))/(6.*h(i))
b(i)=S(i)/2.
c(i)=dydx(i)-(2.*h(i)*S(i)+h(i)*S(i+1))/6.
d(i)=ya(i)
end do
C
C
C
Normal return
return
end
subroutine matrix_solve(a,b,x,n,NDIM)
C
C
C
Solve a set of simultaneous equations by LU decomposition wo. pivoting
implicit none
C
C
C
Declare variables
real a(NDIM,NDIM)
real b(NDIM)
real x(NDIM)
integer n
integer NDIM
real*8 lu(1000000)
C
C
C
Decompose & back substitute
call ludecomp(a,lu,n,NDIM)
call solvelu(lu,b,x,n,NDIM)
C
C
C
Normal return
return
end
subroutine solvelu(lu,BB,XX,n,NDIM)
C
C
C
Solve lower*upper*x=b for x
implicit none
!
!
!
!
!
!
Coefficient matrix
Right hand side vector
Unknowns
Number of equations
Declared array size
LU decomposition of a
C
C
C
Declare variables
integer
NDIM
integer
n
real*8 lu(NDIM,NDIM)
real*8 b(1000)
real*8 x(1000)
real
BB(NDIM)
real
XX(NDIM)
real*8 sum
integer
i,k
do i=1,n
b(i)=BB(i)
end do
x(1)=b(1)/lu(1,1)
do i=2,n
sum=0.
do k=1,i-1
sum=sum+lu(i,k)*x(k)
end do
x(i)=(b(i)-sum)/lu(i,i)
end do
do i=n-1,1,-1
sum=0.
do k=i+1,n
sum=sum+lu(i,k)*x(k)
end do
x(i)=x(i)-sum
end do
do i=1,n
XX(i)=x(i)
end do
C
C
C
!
!
!
!
!
!
!
!
!
Declared size of arrays
Number of unknowns
LU decomposed matrix
Right hand side
Unknows
Single precision b
Single precision x
Running sum
Counters
Normal return
return
end
subroutine ludecomp(AA,lu,n,NDIM)
C
C
C
Decompose a into lower *upper
implicit none
integer
NDIM
real*8 lu(NDIM,NDIM)
real*8 a(1000,1000)
real AA(NDIM,NDIM)
integer
n
real*8 sum
integer
i,j,k
do i=1,n
do j=1,n
a(i,j)=AA(i,j)
!
!
!
!
!
!
!
Size of arrays
LU decomposition of matrix a
Input matrix a
Single precision a
Number of unknowns
Running sum
Counters
end do
end do
do i=1,n
lu(i,1)=a(i,1)
end do
do j=2,n
lu(1,j)=a(1,j)/lu(1,1)
end do
do j=2,n
do i=j,n
sum=0.
do k=1,j-1
sum=sum+lu(i,k)*lu(k,j)
end do
lu(i,j)=a(i,j)-sum
end do
do i=j+1,n
sum=0.
do k=1,j-1
sum=sum+lu(j,k)*lu(k,i)
end do
lu(j,i)=(a(j,i)-sum)/lu(j,j)
end do
end do
C
C
C
Normal return
return
end
subroutine eval_cubic_spline(xa,a,b,c,d,N,x,y)
C
C
C
Evaluate the spline at a point
implicit none
C
C
C
Declare variables
real xa(N)
real a(N-1)
real b(N-1)
real c(N-1)
real d(N-1)
real x
real y
integer N
integer i
C
C
C
!
!
!
!
!
!
!
!
!
Array of x values for fit
Cubic coefficient of x^3
Cubic coefficient of x^2
Cubic coefficient of x^1
Cubic coefficient of x^0
Point to find cubic spline value
Cubic spline value at x
Number of points
Counter
Find the interval
i=1
do while (x.gt.xa(i+1).and.i.lt.N)
i=i+1
end do
C
C
C
Evaluate the spline
y=a(i)*(x-xa(i))**3+b(i)*(x-xa(i))**2+c(i)*(x-xa(i))+d(i)
C
C
C
Normal return
return
end
File: test_spline.dat
0. 0.
1. 1.
2. 8.
3 27.
4 64.
Screen Output:
Note: jobname.inp is input file
jobname.out is output file
Each line of jobname.inp is x,y in pairs
Please enter jobname: test_spline
Please enter the first curvature type (Type1): 3
Please enter the last curvature type (TypeN): 3
N =
5
i
1
2
3
4
5
x(i)
0.000000E+00
1.000000E+00
2.000000E+00
3.000000E+00
4.000000E+00
y(i)
0.000000E+00
1.000000E+00
8.000000E+00
2.700000E+01
6.400000E+01
Boundary Condition Type at 1 =
Boundary Condition Type at N =
i
1
2
3
4
a(i)
1.000000E+00
1.000000E+00
1.000000E+00
1.000000E+00
3
3
b(i)
0.000000E+00
3.000000E+00
6.000000E+00
9.000000E+00
Evaluation will occur while x is in
c(i)
0.000000E+00
3.000000E+00
1.200000E+01
2.700000E+01
0.000E+00 to
Please enter an x to evaluate the spline: 2.5
y(2.5000E+00) = 1.5625E+01
Please enter an x to evaluate the spline: 0.5
y(5.0000E-01) = 1.2500E-01
Please enter an x to evaluate the spline: -1
d(i)
0.000000E+00
1.000000E+00
8.000000E+00
2.700000E+01
4.000E+00
Download