• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

dspline.c

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2009 Alan W. Irwin
00003 //
00004 // This file is part of PLplot.
00005 //
00006 // PLplot is free software; you can redistribute it and/or modify
00007 // it under the terms of the GNU Library General Public License as published
00008 // by the Free Software Foundation; either version 2 of the License, or
00009 // (at your option) any later version.
00010 //
00011 // PLplot is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 // GNU Library General Public License for more details.
00015 //
00016 // You should have received a copy of the GNU Library General Public License
00017 // along with PLplot; if not, write to the Free Software
00018 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00019 //
00020 // Provenance: This code was originally developed under the GPL as part of
00021 // the FreeEOS project (revision 121).  This code has been converted from
00022 // Fortran to C with the aid of f2c and relicensed for PLplot under the LGPL
00023 // with the permission of the FreeEOS copyright holder (Alan W. Irwin).
00024 //
00025 int dspline( double *x, double *y, int n,
00026              int if1, double cond1, int ifn, double condn, double *y2 )
00027 {
00028     int    i__1, i__, k;
00029     double p, u[2000], qn, un, sig;
00030 
00031 //      input parameters:
00032 //      x(n) are the spline knot points
00033 //      y(n) are the function values at the knot points
00034 //      if1 = 1 specifies cond1 is the first derivative at the
00035 //        first knot point.
00036 //      if1 = 2 specifies cond1 is the second derivative at the
00037 //        first knot point.
00038 //      ifn = 1 specifies condn is the first derivative at the
00039 //        nth knot point.
00040 //      ifn = 2 specifies condn is the second derivative at the
00041 //        nth knot point.
00042 //      output values:
00043 //      y2(n) is the second derivative of the spline evaluated at
00044 //        the knot points.
00045     // Parameter adjustments
00046     --y2;
00047     --y;
00048     --x;
00049 
00050     // Function Body
00051     if ( n > 2000 )
00052     {
00053         return 1;
00054     }
00055 //      y2(i) = u(i) + d(i)*y2(i+1), where
00056 //      d(i) is temporarily stored in y2(i) (see below).
00057     if ( if1 == 2 )
00058     {
00059 //        cond1 is second derivative at first point.
00060 //        these two values assure that for above equation with d(i) temporarily
00061 //        stored in y2(i)
00062         y2[1] = 0.;
00063         u[0]  = cond1;
00064     }
00065     else if ( if1 == 1 )
00066     {
00067 //        cond1 is first derivative at first point.
00068 //        special case (Press et al 3.3.5 with A = 1, and B=0)
00069 //        of equations below where
00070 //        a_j = 0
00071 //        b_j = -(x_j+1 - x_j)/3
00072 //        c_j = -(x_j+1 - x_j)/6
00073 //        r_j = cond1 - (y_j+1 - y_j)/(x_j+1 - x_j)
00074 //        u(i) = r(i)/b(i)
00075 //        d(i) = -c(i)/b(i)
00076 //        N.B. d(i) is temporarily stored in y2.
00077         y2[1] = -.5;
00078         u[0]  = 3. / ( x[2] - x[1] ) * ( ( y[2] - y[1] ) / ( x[2] - x[1] ) - cond1 );
00079     }
00080     else
00081     {
00082         return 2;
00083     }
00084 //      if original tri-diagonal system is characterized as
00085 //      a_j y2_j-1 + b_j y2_j + c_j y2_j+1 = r_j
00086 //      Then from Press et al. 3.3.7, we have the unscaled result:
00087 //      a_j = (x_j - x_j-1)/6
00088 //      b_j = (x_j+1 - x_j-1)/3
00089 //      c_j = (x_j+1 - x_j)/6
00090 //      r_j = (y_j+1 - y_j)/(x_j+1 - x_j) - (y_j - y_j-1)/(x_j - x_j-1)
00091 //      In practice, all these values are divided through by b_j/2 to scale
00092 //      them, and from now on we will use these scaled values.
00093 
00094 //      forward elimination step: assume y2(i-1) = u(i-1) + d(i-1)*y2(i).
00095 //      When this is substituted into above tridiagonal equation ==>
00096 //      y2(i) = u(i) + d(i)*y2(i+1), where
00097 //      u(i) = [r(i) - a(i) u(i-1)]/[b(i) + a(i) d(i-1)]
00098 //      d(i) = -c(i)/[b(i) + a(i) d(i-1)]
00099 //      N.B. d(i) is temporarily stored in y2.
00100     i__1 = n - 1;
00101     for ( i__ = 2; i__ <= i__1; ++i__ )
00102     {
00103 //        sig is scaled a(i)
00104         sig = ( x[i__] - x[i__ - 1] ) / ( x[i__ + 1] - x[i__ - 1] );
00105 //        p is denominator = scaled a(i) d(i-1) + scaled  b(i), where scaled
00106 //        b(i) is 2.
00107         p = sig * y2[i__ - 1] + 2.;
00108 //        propagate d(i) equation above.  Note sig-1 = -c(i)
00109         y2[i__] = ( sig - 1. ) / p;
00110 //        propagate scaled u(i) equation above
00111         u[i__ - 1] = ( ( ( y[i__ + 1] - y[i__] ) / ( x[i__ + 1] - x[i__] ) - ( y[i__]
00112                                                                                - y[i__ - 1] ) / ( x[i__] - x[i__ - 1] ) ) * 6. / ( x[i__ + 1] -
00113                                                                                                                                    x[i__ - 1] ) - sig * u[i__ - 2] ) / p;
00114     }
00115     if ( ifn == 2 )
00116     {
00117 //        condn is second derivative at nth point.
00118 //        These two values assure that in the equation below.
00119         qn = 0.;
00120         un = condn;
00121     }
00122     else if ( ifn == 1 )
00123     {
00124 //        specify condn is first derivative at nth point.
00125 //        special case (Press et al 3.3.5 with A = 0, and B=1)
00126 //        implies a_n y2(n-1) + b_n y2(n) = r_n, where
00127 //        a_n = (x_n - x_n-1)/6
00128 //        b_n = (x_n - x_n-1)/3
00129 //        r_n = cond1 - (y_n - y_n-1)/(x_n - x_n-1)
00130 //        use same propagation equation as above, only with c_n = 0
00131 //        ==> d_n = 0 ==> y2(n) = u(n) =>
00132 //        y(n) = [r(n) - a(n) u(n-1)]/[b(n) + a(n) d(n-1)]
00133 //        qn is scaled a_n
00134         qn = .5;
00135 //        un is scaled r_n (N.B. un is not u(n))!  Sorry for the mixed notation.
00136         un = 3. / ( x[n] - x[n - 1] ) * ( condn - ( y[n] - y[n - 1] ) / ( x[n]
00137                                                                           - x[n - 1] ) );
00138     }
00139     else
00140     {
00141         return 3;
00142     }
00143 //      N.B. d(i) is temporarily stored in y2, and everything is
00144 //      scaled by b_n.
00145 //     qn is scaled a_n, 1.d0 is scaled b_n, and un is scaled r_n.
00146     y2[n] = ( un - qn * u[n - 2] ) / ( qn * y2[n - 1] + 1. );
00147 //      back substitution.
00148     for ( k = n - 1; k >= 1; --k )
00149     {
00150         y2[k] = y2[k] * y2[k + 1] + u[k - 1];
00151     }
00152     return 0;
00153 }
00154 

Generated on Wed Oct 12 2011 20:42:21 for PLplot by  doxygen 1.7.1