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 xi1 xi , since y yi at x xi then di yi . At x xi1 , x xi xi1 xi and y yi1 then (1) yi1 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 Si1 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 yi1 yi Si1hi Si hi yi1 yi 2hi Si hi Si1 . 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 yi1 yi 2hi Si hi Si1 . 2hi hi 6 At x xi yi 1 yi 2hi Si hi Si1 hi 6 yi and yi1 S i 1 Si y yi 2hi S i hi S i 1 hi S i hi i 1 2 hi 6 or yi1 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 2hk 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 6change 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 6change in slope at x x2 . For condition (2) (3h1 2h2 ) S 2 h2 S3 6change in slope at x x2 , and for condition (3), (h1 h2 )( h1 2h2 ) h 2 h12 S2 2 S3 6change 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