/home/bes3soft/bes3soft/Boss/7.0.2/dist/7.0.2/Generator/Mcgpj/Mcgpj-00-01-04/src/code/src/TRadSpline.C

Go to the documentation of this file.
00001 #include<cmath>
00002 #include<stdio.h>
00003 #include<string.h>
00004 
00005 #include<iostream>
00006 #include<fstream>
00007 
00008 #include "TRadSpline.h"
00009 
00010 using namespace std;
00011 
00013 //                                                                      //
00014 // TRadSpline3                                                          //
00015 //                                                                      //
00016 // Class to create third splines to interpolate knots                   //
00017 // Arbitrary conditions can be introduced for first and second          //
00018 // derivatives at beginning and ending points                           //
00019 //                                                                      //
00021 
00022 
00023 //____________________________________________________________________________
00024 TRadSpline3::TRadSpline3(const char *title,
00025                    double x[], double y[], int n, const char *opt,
00026                    double valbeg, double valend) :
00027   TRadSpline(title,-1,x[0],x[n-1],n,false),
00028   fValBeg(valbeg), fValEnd(valend), fBegCond(0), fEndCond(0)
00029 {
00030   //
00031   // Third spline creator given an array of
00032   // arbitrary knots in increasing abscissa order and
00033   // possibly end point conditions
00034   //
00035 
00036   //
00037   // Set endpoint conditions
00038   if(opt) SetCond(opt);
00039   //
00040   // Create the plynomial terms and fill
00041   // them with node information
00042   fPoly = new TRadSplinePoly3[n];
00043   for (int i=0; i<n; ++i) {
00044     fPoly[i].X() = x[i];
00045     fPoly[i].Y() = y[i];
00046   }
00047   //
00048   // Build the spline coefficients
00049   BuildCoeff();
00050 }
00051 
00052 //____________________________________________________________________________
00053 TRadSpline3::TRadSpline3(const char *title,
00054                    double xmin, double xmax,
00055                    double y[], int n, const char *opt,
00056                    double valbeg, double valend) :
00057   TRadSpline(title,(xmax-xmin)/(n-1), xmin, xmax, n, true),
00058   fValBeg(valbeg), fValEnd(valend),
00059   fBegCond(0), fEndCond(0)
00060 {
00061   //
00062   // Third spline creator given an array of
00063   // arbitrary function values on equidistant n abscissa
00064   // values from xmin to xmax and possibly end point conditions
00065   //
00066 
00067   //
00068   // Set endpoint conditions
00069   if(opt) SetCond(opt);
00070   //
00071   // Create the plynomial terms and fill
00072   // them with node information
00073   fPoly = new TRadSplinePoly3[n];
00074   for (int i=0; i<n; ++i) {
00075     fPoly[i].X() = fXmin+i*fDelta;
00076     fPoly[i].Y() = y[i];
00077   }
00078   //
00079   // Build the spline coefficients
00080   BuildCoeff();
00081 }
00082 
00083 TRadSpline3::TRadSpline3(const char *title,
00084                          double xmin, double xmax,
00085                          double (*func)(const double&), int n, const char *opt,
00086                          double valbeg, double valend) :
00087   TRadSpline(title,(xmax-xmin)/(n-1), xmin, xmax, n, true),
00088   fValBeg(valbeg), fValEnd(valend),
00089   fBegCond(0), fEndCond(0)
00090 {
00091   //
00092   // Third spline creator given a function to be
00093   // evaluated on n equidistand abscissa points between xmin
00094   // and xmax and possibly end point conditions
00095   //
00096 
00097   //
00098   // Set endpoint conditions
00099   if(opt) SetCond(opt);
00100   // Create the plynomial terms and fill
00101   // them with node information
00102   fPoly = new TRadSplinePoly3[n];
00103   for (int i=0; i<n; ++i) {
00104     double x=fXmin+i*fDelta;
00105     fPoly[i].X() = x;
00106     fPoly[i].Y() = func(x);
00107   }
00108   // Build the spline coefficients
00109   BuildCoeff();
00110 }
00111 
00112 void TRadSpline3::SetCond(const char *opt)
00113 {
00114   //
00115   // Check the boundary conditions
00116   //
00117   const char *b1 = strstr(opt,"b1");
00118   const char *e1 = strstr(opt,"e1");
00119   const char *b2 = strstr(opt,"b2");
00120   const char *e2 = strstr(opt,"e2");
00121   if (b1 && b2)
00122     printf("%s %s\n","SetCond","Cannot specify first and second derivative at first point");
00123   if (e1 && e2)
00124     printf("%s %s\n","SetCond","Cannot specify first and second derivative at last point");
00125   if (b1) fBegCond=1;
00126   else if (b2) fBegCond=2;
00127   if (e1) fEndCond=1;
00128   else if (e2) fEndCond=2;
00129 }
00130 
00131 //___________________________________________________________________________
00132 void TRadSpline3::Test()
00133 {
00134   //
00135   // Test method for TRadSpline5
00136   //
00137   //   n          number of data points.
00138   //   m          2*m-1 is order of spline.
00139   //                 m = 2 always for third spline.
00140   //   nn,nm1,mm,
00141   //   mm1,i,k,
00142   //   j,jj       temporary integer variables.
00143   //   z,p        temporary double precision variables.
00144   //   x[n]       the sequence of knots.
00145   //   y[n]       the prescribed function values at the knots.
00146   //   a[200][4]  two dimensional array whose columns are
00147   //                 the computed spline coefficients
00148   //   diff[3]    maximum values of differences of values and
00149   //                 derivatives to right and left of knots.
00150   //   com[3]     maximum values of coefficients.
00151   //
00152   //
00153   //   test of TRadSpline3 with nonequidistant knots and
00154   //      equidistant knots follows.
00155   //
00156   //
00157   double hx;
00158   double diff[3];
00159   double a[800], c[4];
00160   int i, j, k, m, n;
00161   double x[200], y[200], z;
00162   int jj, mm;
00163   int mm1, nm1;
00164   double com[3];
00165   printf("1         TEST OF TRadSpline3 WITH NONEQUIDISTANT KNOTS\n");
00166   n = 5;
00167   x[0] = -3;
00168   x[1] = -1;
00169   x[2] = 0;
00170   x[3] = 3;
00171   x[4] = 4;
00172   y[0] = 7;
00173   y[1] = 11;
00174   y[2] = 26;
00175   y[3] = 56;
00176   y[4] = 29;
00177   m = 2;
00178   mm = m << 1;
00179   mm1 = mm-1;
00180   printf("\n-N = %3d    M =%2d\n",n,m);
00181   TRadSpline3 *spline = new TRadSpline3("Test",x,y,n);
00182   for (i = 0; i < n; ++i)
00183     spline->GetCoeff(i,hx, a[i],a[i+200],a[i+400],a[i+600]);
00184   delete spline;
00185   for (i = 0; i < mm1; ++i) diff[i] = com[i] = 0;
00186   for (k = 0; k < n; ++k) {
00187     for (i = 0; i < mm; ++i) c[i] = a[k+i*200];
00188     printf(" ---------------------------------------%3d --------------------------------------------\n",k+1);
00189     printf("%12.8f\n",x[k]);
00190     if (k == n-1) {
00191       printf("%16.8f\n",c[0]);
00192     } else {
00193       for (i = 0; i < mm; ++i) printf("%16.8f",c[i]);
00194       printf("\n");
00195       for (i = 0; i < mm1; ++i)
00196         if ((z=fabs(a[k+i*200])) > com[i]) com[i] = z;
00197       z = x[k+1]-x[k];
00198       for (i = 1; i < mm; ++i)
00199         for (jj = i; jj < mm; ++jj) {
00200           j = mm+i-jj;
00201           c[j-2] = c[j-1]*z+c[j-2];
00202         }
00203       for (i = 0; i < mm; ++i) printf("%16.8f",c[i]);
00204       printf("\n");
00205       for (i = 0; i < mm1; ++i)
00206         if (!(k >= n-2 && i != 0))
00207           if((z = fabs(c[i]-a[k+1+i*200]))
00208              > diff[i]) diff[i] = z;
00209     }
00210   }
00211   printf("  MAXIMUM ABSOLUTE VALUES OF DIFFERENCES \n");
00212   for (i = 0; i < mm1; ++i) printf("%18.9E",diff[i]);
00213   printf("\n");
00214   printf("  MAXIMUM ABSOLUTE VALUES OF COEFFICIENTS \n");
00215   if (fabs(c[0]) > com[0])
00216     com[0] = fabs(c[0]);
00217   for (i = 0; i < mm1; ++i) printf("%16.8f",com[i]);
00218   printf("\n");
00219   m = 2;
00220   for (n = 10; n <= 100; n += 10) {
00221     mm = m << 1;
00222     mm1 = mm-1;
00223     nm1 = n-1;
00224     for (i = 0; i < nm1; i += 2) {
00225       x[i] = i+1;
00226       x[i+1] = i+2;
00227       y[i] = 1;
00228       y[i+1] = 0;
00229     }
00230     if (n % 2 != 0) {
00231       x[n-1] = n;
00232       y[n-1] = 1;
00233     }
00234     printf("\n-N = %3d    M =%2d\n",n,m);
00235     spline = new TRadSpline3("Test",x,y,n);
00236     for (i = 0; i < n; ++i)
00237       spline->GetCoeff(i,hx,a[i],a[i+200],a[i+400],a[i+600]);
00238     delete spline;
00239     for (i = 0; i < mm1; ++i)
00240       diff[i] = com[i] = 0;
00241     for (k = 0; k < n; ++k) {
00242       for (i = 0; i < mm; ++i)
00243         c[i] = a[k+i*200];
00244       if (n < 11) {
00245         printf(" ---------------------------------------%3d --------------------------------------------\n",k+1);
00246         printf("%12.8f\n",x[k]);
00247         if (k == n-1) printf("%16.8f\n",c[0]);
00248       }
00249       if (k == n-1) break;
00250       if (n <= 10) {
00251         for (i = 0; i < mm; ++i) printf("%16.8f",c[i]);
00252         printf("\n");
00253       }
00254       for (i = 0; i < mm1; ++i)
00255         if ((z=fabs(a[k+i*200])) > com[i])
00256           com[i] = z;
00257       z = x[k+1]-x[k];
00258       for (i = 1; i < mm; ++i)
00259         for (jj = i; jj < mm; ++jj) {
00260           j = mm+i-jj;
00261           c[j-2] = c[j-1]*z+c[j-2];
00262         }
00263       if (n <= 10) {
00264         for (i = 0; i < mm; ++i) printf("%16.8f",c[i]);
00265         printf("\n");
00266       }
00267       for (i = 0; i < mm1; ++i)
00268         if (!(k >= n-2 && i != 0))
00269           if ((z = fabs(c[i]-a[k+1+i*200]))
00270               > diff[i]) diff[i] = z;
00271     }
00272     printf("  MAXIMUM ABSOLUTE VALUES OF DIFFERENCES \n");
00273     for (i = 0; i < mm1; ++i) printf("%18.9E",diff[i]);
00274     printf("\n");
00275     printf("  MAXIMUM ABSOLUTE VALUES OF COEFFICIENTS \n");
00276     if (fabs(c[0]) > com[0])
00277       com[0] = fabs(c[0]);
00278     for (i = 0; i < mm1; ++i) printf("%16.8E",com[i]);
00279     printf("\n");
00280   }
00281 }
00282 
00283 //_____________________________________________________________________
00284 
00285 int TRadSpline3::FindX(double x) const
00286 {
00287   int klow=0;
00288   //
00289   // If out of boundaries, extrapolate
00290   // It may be badly wrong
00291   if(x<=fXmin) klow=0;
00292   else if(x>=fXmax) klow=fNp-1;
00293   else {
00294     if(fKstep) {
00295       //
00296       // Equidistant knots, use histogramming
00297       klow = (int((x-fXmin)/fDelta)<fNp-1)?int((x-fXmin)/fDelta):fNp-1;
00298     } else {
00299       int khig=fNp-1, khalf;
00300       //
00301       // Non equidistant knots, binary search
00302       while(khig-klow>1)
00303         if(x>fPoly[khalf=(klow+khig)/2].X())
00304           klow=khalf;
00305         else
00306           khig=khalf;
00307     }
00308     //
00309     // This could be removed, sanity check
00310     if(!(fPoly[klow].X()<=x && x<=fPoly[klow+1].X()))
00311       printf("Binary search failed x(%d) = %f < %f < x(%d) = %f\n",
00312              klow, fPoly[klow].X(), x, klow+1, fPoly[klow+1].X());
00313   }
00314   return klow;
00315 }
00316 
00317 //____________________________________________________________________________
00318 double TRadSpline3::Eval(double x) const
00319 {
00320   int klow=FindX(x);
00321   return fPoly[klow].Eval(x);
00322 }
00323 
00324 //____________________________________________________________________________
00325 double TRadSpline3::Derivative(double x) const
00326 {
00327   int klow=FindX(x);
00328   return fPoly[klow].Derivative(x);
00329 }
00330 
00331 //____________________________________________________________________________
00332 void TRadSpline3::SaveAs(const char *filename) const
00333 {
00334   // write this spline as a C++ function that can be executed without ROOT
00335   // the name of the function is the name of the file up to the "." if any
00336     
00337    //open the file
00338    ofstream *f = new ofstream(filename,ios::out);
00339    if (f == 0) {
00340       printf("Cannot open file:%s\n",filename);
00341       return;
00342    }
00343    
00344    //write the function name and the spline constants
00345    char buffer[512];
00346    int nch = strlen(filename);
00347    sprintf(buffer,"double %s",filename);
00348    char *dot = strstr(buffer,".");
00349    if (dot) *dot = 0;
00350    strcat(buffer,"(double x) {\n");
00351    nch = strlen(buffer); f->write(buffer,nch);
00352    sprintf(buffer,"   const int fNp = %d, fKstep = %d;\n",fNp,fKstep);
00353    nch = strlen(buffer); f->write(buffer,nch);
00354    sprintf(buffer,"   const double fDelta = %g, fXmin = %g, fXmax = %g;\n",fDelta,fXmin,fXmax);
00355    nch = strlen(buffer); f->write(buffer,nch);
00356 
00357    //write the spline coefficients
00358    //array fX
00359    sprintf(buffer,"   const double fX[%d] = {",fNp);   
00360    nch = strlen(buffer); f->write(buffer,nch);
00361    buffer[0] = 0;
00362    int i;
00363    char numb[20];
00364    for (i=0;i<fNp;i++) {
00365       sprintf(numb," %g,",fPoly[i].X());
00366       nch = strlen(numb);
00367       if (i == fNp-1) numb[nch-1]=0;
00368       strcat(buffer,numb);
00369       if (i%5 == 4 || i == fNp-1) {
00370          nch = strlen(buffer); f->write(buffer,nch);
00371          if (i != fNp-1) sprintf(buffer,"\n                       ");
00372       }
00373    }
00374    sprintf(buffer," };\n");
00375    nch = strlen(buffer); f->write(buffer,nch);
00376    //array fY
00377    sprintf(buffer,"   const double fY[%d] = {",fNp);   
00378    nch = strlen(buffer); f->write(buffer,nch);
00379    buffer[0] = 0;
00380    for (i=0;i<fNp;i++) {
00381       sprintf(numb," %g,",fPoly[i].Y());
00382       nch = strlen(numb);
00383       if (i == fNp-1) numb[nch-1]=0;
00384       strcat(buffer,numb);
00385       if (i%5 == 4 || i == fNp-1) {
00386          nch = strlen(buffer); f->write(buffer,nch);
00387          if (i != fNp-1) sprintf(buffer,"\n                       ");
00388       }
00389    }
00390    sprintf(buffer," };\n");
00391    nch = strlen(buffer); f->write(buffer,nch);
00392    //array fB
00393    sprintf(buffer,"   const double fB[%d] = {",fNp);   
00394    nch = strlen(buffer); f->write(buffer,nch);
00395    buffer[0] = 0;
00396    for (i=0;i<fNp;i++) {
00397       sprintf(numb," %g,",fPoly[i].B());
00398       nch = strlen(numb);
00399       if (i == fNp-1) numb[nch-1]=0;
00400       strcat(buffer,numb);
00401       if (i%5 == 4 || i == fNp-1) {
00402          nch = strlen(buffer); f->write(buffer,nch);
00403          if (i != fNp-1) sprintf(buffer,"\n                       ");
00404       }
00405    }
00406    sprintf(buffer," };\n");
00407    nch = strlen(buffer); f->write(buffer,nch);
00408    //array fC
00409    sprintf(buffer,"   const double fC[%d] = {",fNp);   
00410    nch = strlen(buffer); f->write(buffer,nch);
00411    buffer[0] = 0;
00412    for (i=0;i<fNp;i++) {
00413       sprintf(numb," %g,",fPoly[i].C());
00414       nch = strlen(numb);
00415       if (i == fNp-1) numb[nch-1]=0;
00416       strcat(buffer,numb);
00417       if (i%5 == 4 || i == fNp-1) {
00418          nch = strlen(buffer); f->write(buffer,nch);
00419          if (i != fNp-1) sprintf(buffer,"\n                       ");
00420       }
00421    }
00422    sprintf(buffer," };\n");
00423    nch = strlen(buffer); f->write(buffer,nch);
00424     //array fD
00425    sprintf(buffer,"   const double fD[%d] = {",fNp);   
00426    nch = strlen(buffer); f->write(buffer,nch);
00427    buffer[0] = 0;
00428    for (i=0;i<fNp;i++) {
00429       sprintf(numb," %g,",fPoly[i].D());
00430       nch = strlen(numb);
00431       if (i == fNp-1) numb[nch-1]=0;
00432       strcat(buffer,numb);
00433       if (i%5 == 4 || i == fNp-1) {
00434          nch = strlen(buffer); f->write(buffer,nch);
00435          if (i != fNp-1) sprintf(buffer,"\n                       ");
00436       }
00437    }
00438    sprintf(buffer," };\n");
00439    nch = strlen(buffer); f->write(buffer,nch);
00440     
00441    //generate code for the spline evaluation
00442    sprintf(buffer,"   int klow=0;\n");
00443    nch = strlen(buffer); f->write(buffer,nch);
00444 
00445    sprintf(buffer,"   // If out of boundaries, extrapolate. It may be badly wrong\n");
00446    sprintf(buffer,"   if(x<=fXmin) klow=0;\n");
00447    nch = strlen(buffer); f->write(buffer,nch);
00448    sprintf(buffer,"   else if(x>=fXmax) klow=fNp-1;\n");
00449    nch = strlen(buffer); f->write(buffer,nch);
00450    sprintf(buffer,"   else {\n");
00451    nch = strlen(buffer); f->write(buffer,nch);
00452    sprintf(buffer,"     if(fKstep) {\n");
00453    nch = strlen(buffer); f->write(buffer,nch);
00454 
00455    sprintf(buffer,"       // Equidistant knots, use histogramming\n");
00456    nch = strlen(buffer); f->write(buffer,nch);
00457    sprintf(buffer,"       klow = int((x-fXmin)/fDelta);\n");
00458    nch = strlen(buffer); f->write(buffer,nch);
00459    sprintf(buffer,"       if (klow < fNp-1) klow = fNp-1;\n");
00460    nch = strlen(buffer); f->write(buffer,nch);
00461    sprintf(buffer,"     } else {\n");
00462    nch = strlen(buffer); f->write(buffer,nch);
00463    sprintf(buffer,"       int khig=fNp-1, khalf;\n");
00464    nch = strlen(buffer); f->write(buffer,nch);
00465 
00466    sprintf(buffer,"       // Non equidistant knots, binary search\n");
00467    nch = strlen(buffer); f->write(buffer,nch);
00468    sprintf(buffer,"       while(khig-klow>1)\n");
00469    nch = strlen(buffer); f->write(buffer,nch);
00470    sprintf(buffer,"      if(x>fX[khalf=(klow+khig)/2]) klow=khalf;\n");
00471    nch = strlen(buffer); f->write(buffer,nch);
00472    sprintf(buffer,"      else khig=khalf;\n");
00473    nch = strlen(buffer); f->write(buffer,nch);
00474    sprintf(buffer,"     }\n");
00475    nch = strlen(buffer); f->write(buffer,nch);
00476    sprintf(buffer,"   }\n");
00477    nch = strlen(buffer); f->write(buffer,nch);
00478    sprintf(buffer,"   // Evaluate now\n");
00479    nch = strlen(buffer); f->write(buffer,nch);
00480    sprintf(buffer,"   double dx=x-fX[klow];\n");
00481    nch = strlen(buffer); f->write(buffer,nch);
00482    sprintf(buffer,"   return (fY[klow]+dx*(fB[klow]+dx*(fC[klow]+dx*fD[klow])));\n");
00483    nch = strlen(buffer); f->write(buffer,nch);
00484     
00485    //close file
00486    f->write("}\n",2);
00487       
00488    if (f) { f->close(); delete f;}
00489 }
00490 
00491 //____________________________________________________________________________
00492 void TRadSpline3::BuildCoeff()
00493 {
00494 //      subroutine cubspl ( tau, c, n, ibcbeg, ibcend )
00495 //  from  * a practical guide to splines *  by c. de boor
00496 //     ************************  input  ***************************
00497 //     n = number of data points. assumed to be .ge. 2.
00498 //     (tau(i), c(1,i), i=1,...,n) = abscissae and ordinates of the
00499 //        data points. tau is assumed to be strictly increasing.
00500 //     ibcbeg, ibcend = boundary condition indicators, and
00501 //     c(2,1), c(2,n) = boundary condition information. specifically,
00502 //        ibcbeg = 0  means no boundary condition at tau(1) is given.
00503 //           in this case, the not-a-knot condition is used, i.e. the
00504 //           jump in the third derivative across tau(2) is forced to
00505 //           zero, thus the first and the second cubic polynomial pieces
00506 //           are made to coincide.)
00507 //        ibcbeg = 1  means that the slope at tau(1) is made to equal
00508 //           c(2,1), supplied by input.
00509 //        ibcbeg = 2  means that the second derivative at tau(1) is
00510 //           made to equal c(2,1), supplied by input.
00511 //        ibcend = 0, 1, or 2 has analogous meaning concerning the
00512 //           boundary condition at tau(n), with the additional infor-
00513 //           mation taken from c(2,n).
00514 //     ***********************  output  **************************
00515 //     c(j,i), j=1,...,4; i=1,...,l (= n-1) = the polynomial coefficients
00516 //        of the cubic interpolating spline with interior knots (or
00517 //        joints) tau(2), ..., tau(n-1). precisely, in the interval
00518 //        (tau(i), tau(i+1)), the spline f is given by
00519 //           f(x) = c(1,i)+h*(c(2,i)+h*(c(3,i)+h*c(4,i)/3.)/2.)
00520 //        where h = x - tau(i). the function program *ppvalu* may be
00521 //        used to evaluate f or its derivatives from tau,c, l = n-1,
00522 //        and k=4.
00523 
00524   int i, j, l, m;
00525   double   divdf1,divdf3,dtau,g=0;
00526 //***** a tridiagonal linear system for the unknown slopes s(i) of
00527 //  f  at tau(i), i=1,...,n, is generated and then solved by gauss elim-
00528 //  ination, with s(i) ending up in c(2,i), all i.
00529 //     c(3,.) and c(4,.) are used initially for temporary storage.
00530   l = fNp-1;
00531 // compute first differences of x sequence and store in C also,
00532 // compute first divided difference of data and store in D.
00533   for (m=1; m<fNp ; ++m) {
00534     fPoly[m].C() = fPoly[m].X() - fPoly[m-1].X();
00535     fPoly[m].D() = (fPoly[m].Y() - fPoly[m-1].Y())/fPoly[m].C();
00536   }
00537 // construct first equation from the boundary condition, of the form
00538 //             D[0]*s[0] + C[0]*s[1] = B[0]
00539   if(fBegCond==0) {
00540     if(fNp == 2) {
00541 //     no condition at left end and n = 2.
00542       fPoly[0].D() = 1.;
00543       fPoly[0].C() = 1.;
00544       fPoly[0].B() = 2.*fPoly[1].D();
00545     } else {
00546 //     not-a-knot condition at left end and n .gt. 2.
00547       fPoly[0].D() = fPoly[2].C();
00548       fPoly[0].C() = fPoly[1].C() + fPoly[2].C();
00549       fPoly[0].B() =((fPoly[1].C()+2.*fPoly[0].C())*fPoly[1].D()*fPoly[2].C()+fPoly[1].C()*fPoly[1].C()*fPoly[2].D())/fPoly[0].C();
00550     }
00551   } else if (fBegCond==1) {
00552 //     slope prescribed at left end.
00553     fPoly[0].B() = fValBeg;
00554     fPoly[0].D() = 1.;
00555     fPoly[0].C() = 0.;
00556   } else if (fBegCond==2) {
00557 //     second derivative prescribed at left end.
00558     fPoly[0].D() = 2.;
00559     fPoly[0].C() = 1.;
00560     fPoly[0].B() = 3.*fPoly[1].D() - fPoly[1].C()/2.*fValBeg;
00561   }
00562   if(fNp > 2) {
00563 //  if there are interior knots, generate the corresp. equations and car-
00564 //  ry out the forward pass of gauss elimination, after which the m-th
00565 //  equation reads    D[m]*s[m] + C[m]*s[m+1] = B[m].
00566     for (m=1; m<l; ++m) {
00567       g = -fPoly[m+1].C()/fPoly[m-1].D();
00568       fPoly[m].B() = g*fPoly[m-1].B() + 3.*(fPoly[m].C()*fPoly[m+1].D()+fPoly[m+1].C()*fPoly[m].D());
00569       fPoly[m].D() = g*fPoly[m-1].C() + 2.*(fPoly[m].C() + fPoly[m+1].C());
00570     }
00571 // construct last equation from the second boundary condition, of the form
00572 //           (-g*D[n-2])*s[n-2] + D[n-1]*s[n-1] = B[n-1]
00573 //     if slope is prescribed at right end, one can go directly to back-
00574 //     substitution, since c array happens to be set up just right for it
00575 //     at this point.
00576     if(fEndCond == 0) {
00577       if (fNp > 3 || fBegCond != 0) {
00578 //     not-a-knot and n .ge. 3, and either n.gt.3 or  also not-a-knot at
00579 //     left end point.
00580         g = fPoly[fNp-2].C() + fPoly[fNp-1].C();
00581         fPoly[fNp-1].B() = ((fPoly[fNp-1].C()+2.*g)*fPoly[fNp-1].D()*fPoly[fNp-2].C()
00582                      + fPoly[fNp-1].C()*fPoly[fNp-1].C()*(fPoly[fNp-2].Y()-fPoly[fNp-3].Y())/fPoly[fNp-2].C())/g;
00583         g = -g/fPoly[fNp-2].D();
00584         fPoly[fNp-1].D() = fPoly[fNp-2].C();
00585       } else {
00586 //     either (n=3 and not-a-knot also at left) or (n=2 and not not-a-
00587 //     knot at left end point).
00588         fPoly[fNp-1].B() = 2.*fPoly[fNp-1].D();
00589         fPoly[fNp-1].D() = 1.;
00590         g = -1./fPoly[fNp-2].D();
00591       }
00592     } else if (fEndCond == 1) {
00593       fPoly[fNp-1].B() = fValEnd;
00594       goto L30;
00595     } else if (fEndCond == 2) {
00596 //     second derivative prescribed at right endpoint.
00597       fPoly[fNp-1].B() = 3.*fPoly[fNp-1].D() + fPoly[fNp-1].C()/2.*fValEnd;
00598       fPoly[fNp-1].D() = 2.;
00599       g = -1./fPoly[fNp-2].D();
00600     }
00601    } else {
00602      if(fEndCond == 0) {
00603        if (fBegCond > 0) {
00604 //     either (n=3 and not-a-knot also at left) or (n=2 and not not-a-
00605 //     knot at left end point).
00606          fPoly[fNp-1].B() = 2.*fPoly[fNp-1].D();
00607          fPoly[fNp-1].D() = 1.;
00608          g = -1./fPoly[fNp-2].D();
00609        } else {
00610 //     not-a-knot at right endpoint and at left endpoint and n = 2.
00611          fPoly[fNp-1].B() = fPoly[fNp-1].D();
00612          goto L30;
00613        }
00614      } else if(fEndCond == 1) {
00615        fPoly[fNp-1].B() = fValEnd;
00616        goto L30;
00617      } else if(fEndCond == 2) {
00618 //     second derivative prescribed at right endpoint.
00619        fPoly[fNp-1].B() = 3.*fPoly[fNp-1].D() + fPoly[fNp-1].C()/2.*fValEnd;
00620        fPoly[fNp-1].D() = 2.;
00621        g = -1./fPoly[fNp-2].D();
00622      }
00623    }
00624 // complete forward pass of gauss elimination.
00625   fPoly[fNp-1].D() = g*fPoly[fNp-2].C() + fPoly[fNp-1].D();
00626   fPoly[fNp-1].B() = (g*fPoly[fNp-2].B() + fPoly[fNp-1].B())/fPoly[fNp-1].D();
00627 // carry out back substitution
00628  L30: j = l-1;
00629   do {
00630     fPoly[j].B() = (fPoly[j].B() - fPoly[j].C()*fPoly[j+1].B())/fPoly[j].D();
00631     --j;
00632   }  while (j>=0);
00633 //****** generate cubic coefficients in each interval, i.e., the deriv.s
00634 //  at its left endpoint, from value and slope at its endpoints.
00635   for (i=1; i<fNp; ++i) {
00636     dtau = fPoly[i].C();
00637     divdf1 = (fPoly[i].Y() - fPoly[i-1].Y())/dtau;
00638     divdf3 = fPoly[i-1].B() + fPoly[i].B() - 2.*divdf1;
00639     fPoly[i-1].C() = (divdf1 - fPoly[i-1].B() - divdf3)/dtau;
00640     fPoly[i-1].D() = (divdf3/dtau)/dtau;
00641   }
00642 }
00643 
00645 //                                                                      //
00646 // TRadSpline5                                                             //
00647 //                                                                      //
00648 // Class to create quintic natural splines to interpolate knots         //
00649 // Arbitrary conditions can be introduced for first and second          //
00650 // derivatives using double knots (see BuildCoeff) for more on this.    //
00651 // Double knots are automatically introduced at ending points           //
00652 //                                                                      //
00654 
00655 
00656 //____________________________________________________________________________
00657 TRadSpline5::TRadSpline5(const char *title,
00658                    double x[], double y[], int n,
00659                    const char *opt, double b1, double e1,
00660                    double b2, double e2) :
00661   TRadSpline(title,-1, x[0], x[n-1], n, false)
00662 {
00663   //
00664   // Quintic natural spline creator given an array of
00665   // arbitrary knots in increasing abscissa order and
00666   // possibly end point conditions
00667   //
00668   int beg, end;
00669   const char *cb1, *ce1, *cb2, *ce2;
00670   //
00671   // Check endpoint conditions
00672   BoundaryConditions(opt,beg,end,cb1,ce1,cb2,ce2);
00673   //
00674   // Create the plynomial terms and fill
00675   // them with node information
00676   fPoly = new TRadSplinePoly5[fNp];
00677   for (int i=0; i<n; ++i) {
00678     fPoly[i+beg].X() = x[i];
00679     fPoly[i+beg].Y() = y[i];
00680   }
00681   //
00682   // Set the double knots at boundaries
00683   SetBoundaries(b1,e1,b2,e2,cb1,ce1,cb2,ce2);
00684   //
00685   // Build the spline coefficients
00686   BuildCoeff();
00687 }
00688 
00689 //____________________________________________________________________________
00690 TRadSpline5::TRadSpline5(const char *title,
00691                    double xmin, double xmax,
00692                    double y[], int n,
00693                    const char *opt, double b1, double e1,
00694                    double b2, double e2) :
00695   TRadSpline(title,(xmax-xmin)/(n-1), xmin, xmax, n, true)
00696 {
00697   //
00698   // Quintic natural spline creator given an array of
00699   // arbitrary function values on equidistant n abscissa
00700   // values from xmin to xmax and possibly end point conditions
00701   //
00702   int beg, end;
00703   const char *cb1, *ce1, *cb2, *ce2;
00704   //
00705   // Check endpoint conditions
00706   BoundaryConditions(opt,beg,end,cb1,ce1,cb2,ce2);
00707   //
00708   // Create the plynomial terms and fill
00709   // them with node information
00710   fPoly = new TRadSplinePoly5[fNp];
00711   for (int i=0; i<n; ++i) {
00712     fPoly[i+beg].X() = fXmin+i*fDelta;
00713     fPoly[i+beg].Y() = y[i];
00714   }
00715   //
00716   // Set the double knots at boundaries
00717   SetBoundaries(b1,e1,b2,e2,cb1,ce1,cb2,ce2);
00718   //
00719   // Build the spline coefficients
00720   BuildCoeff();
00721 }
00722 
00723 TRadSpline5::TRadSpline5(const char *title,
00724                          double xmin, double xmax,
00725                          double (*func)(const double&), int n,
00726                          const char *opt, double b1, double e1,
00727                          double b2, double e2) :
00728   TRadSpline(title,(xmax-xmin)/(n-1), xmin, xmax, n, true)
00729 {
00730   //
00731   // Quintic natural spline creator given a function to be
00732   // evaluated on n equidistand abscissa points between xmin
00733   // and xmax and possibly end point conditions
00734   //
00735   int beg, end;
00736   const char *cb1, *ce1, *cb2, *ce2;
00737 
00738   //
00739   // Check endpoint conditions
00740   BoundaryConditions(opt,beg,end,cb1,ce1,cb2,ce2);
00741   //
00742   // Create the plynomial terms and fill
00743   // them with node information
00744   fPoly = new TRadSplinePoly5[fNp];
00745   for (int i=0; i<n; ++i) {
00746     double x=fXmin+i*fDelta;
00747     fPoly[i+beg].X() = x;
00748     fPoly[i+beg].Y() = func(x);
00749   }
00750   //
00751   // Set the double knots at boundaries
00752   SetBoundaries(b1,e1,b2,e2,cb1,ce1,cb2,ce2);
00753   //
00754   // Build the spline coefficients
00755   BuildCoeff();
00756 }
00757 
00758 
00759 void TRadSpline5::BoundaryConditions(const char *opt,int &beg,int &end,
00760                                   const char *&cb1,const char *&ce1,
00761                                   const char *&cb2,const char *&ce2)
00762 {
00763   //
00764   // Check the boundary conditions and the
00765   // amount of extra double knots needed
00766   //
00767   cb1=ce1=cb2=ce2=0;
00768   beg=end=0;
00769   if(opt) {
00770     cb1 = strstr(opt,"b1");
00771     ce1 = strstr(opt,"e1");
00772     cb2 = strstr(opt,"b2");
00773     ce2 = strstr(opt,"e2");
00774     if(cb2) {
00775       fNp=fNp+2;
00776       beg=2;
00777     } else if(cb1) {
00778       fNp=fNp+1;
00779       beg=1;
00780     }
00781     if(ce2) {
00782       fNp=fNp+2;
00783       end=2;
00784     } else if(ce1) {
00785       fNp=fNp+1;
00786       end=1;
00787     }
00788   }
00789 }
00790 
00791 //____________________________________________________________________________
00792 void TRadSpline5::SetBoundaries(double b1, double e1, double b2, double e2,
00793                              const char *cb1, const char *ce1, const char *cb2,
00794                              const char *ce2)
00795 {
00796   //
00797   // Set the boundary conditions at double/triple knots
00798   //
00799   if(cb2) {
00800     //
00801     // Second derivative at the beginning
00802     fPoly[0].X() = fPoly[1].X() = fPoly[2].X();
00803     fPoly[0].Y() = fPoly[2].Y();
00804     fPoly[2].Y()=b2;
00805     //
00806     // If first derivative not given, we take the finite
00807     // difference from first and second point... not recommended
00808     if(cb1)
00809       fPoly[1].Y()=b1;
00810     else
00811       fPoly[1].Y()=(fPoly[3].Y()-fPoly[0].Y())/(fPoly[3].X()-fPoly[2].X());
00812   } else if(cb1) {
00813     //
00814     // First derivative at the end
00815     fPoly[0].X() = fPoly[1].X();
00816     fPoly[0].Y() = fPoly[1].Y();
00817     fPoly[1].Y()=b1;
00818   }
00819   if(ce2) {
00820     //
00821     // Second derivative at the end
00822     fPoly[fNp-1].X() = fPoly[fNp-2].X() = fPoly[fNp-3].X();
00823     fPoly[fNp-1].Y()=e2;
00824     //
00825     // If first derivative not given, we take the finite
00826     // difference from first and second point... not recommended
00827     if(ce1)
00828       fPoly[fNp-2].Y()=e1;
00829     else
00830       fPoly[fNp-2].Y()=
00831         (fPoly[fNp-3].Y()-fPoly[fNp-4].Y())
00832         /(fPoly[fNp-3].X()-fPoly[fNp-4].X());
00833   } else if(ce1) {
00834     //
00835     // First derivative at the end
00836     fPoly[fNp-1].X() = fPoly[fNp-2].X();
00837     fPoly[fNp-1].Y()=e1;
00838   }
00839 }
00840 //___________________________________________________________________________
00841 int TRadSpline5::FindX(double x) const
00842 {
00843 
00844   int klow=0;
00845   //
00846   // If out of boundaries, extrapolate
00847   // It may be badly wrong
00848   if(x<=fXmin) klow=0;
00849   else if(x>=fXmax) klow=fNp-1;
00850   else {
00851     if(fKstep) {
00852       //
00853       // Equidistant knots, use histogramming
00854       klow = (int((x-fXmin)/fDelta)<fNp-1)?int((x-fXmin)/fDelta):fNp-1;
00855     } else {
00856       int khig=fNp-1, khalf;
00857       //
00858       // Non equidistant knots, binary search
00859       while(khig-klow>1)
00860         if(x>fPoly[khalf=(klow+khig)/2].X())
00861           klow=khalf;
00862         else
00863           khig=khalf;
00864     }
00865     //
00866     // This could be removed, sanity check
00867     if(!(fPoly[klow].X()<=x && x<=fPoly[klow+1].X()))
00868       printf("Binary search failed x(%d) = %f < %f < x(%d) = %f\n",
00869              klow,fPoly[klow].X(),x,klow+1,fPoly[klow+1].X());
00870   }
00871   return klow;
00872 }
00873 
00874 //___________________________________________________________________________
00875 double TRadSpline5::Eval(double x) const
00876 {
00877   int klow=FindX(x);
00878   return fPoly[klow].Eval(x);
00879 }
00880 
00881 //____________________________________________________________________________
00882 double TRadSpline5::Derivative(double x) const
00883 {
00884   int klow=FindX(x);
00885   return fPoly[klow].Derivative(x);
00886 }
00887 
00888 //____________________________________________________________________________
00889 void TRadSpline5::SaveAs(const char *filename) const
00890 {
00891   // write this spline as a C++ function that can be executed without ROOT
00892   // the name of the function is the name of the file up to the "." if any
00893     
00894    //open the file
00895    ofstream *f = new ofstream(filename,ios::out);
00896    if (f == 0) {
00897       printf("Cannot open file:%s\n",filename);
00898       return;
00899    }
00900    
00901    //write the function name and the spline constants
00902    char buffer[512];
00903    int nch = strlen(filename);
00904    sprintf(buffer,"double %s",filename);
00905    char *dot = strstr(buffer,".");
00906    if (dot) *dot = 0;
00907    strcat(buffer,"(double x) {\n");
00908    nch = strlen(buffer); f->write(buffer,nch);
00909    sprintf(buffer,"   const int fNp = %d, fKstep = %d;\n",fNp,fKstep);
00910    nch = strlen(buffer); f->write(buffer,nch);
00911    sprintf(buffer,"   const double fDelta = %g, fXmin = %g, fXmax = %g;\n",fDelta,fXmin,fXmax);
00912    nch = strlen(buffer); f->write(buffer,nch);
00913 
00914    //write the spline coefficients
00915    //array fX
00916    sprintf(buffer,"   const double fX[%d] = {",fNp);   
00917    nch = strlen(buffer); f->write(buffer,nch);
00918    buffer[0] = 0;
00919    int i;
00920    char numb[20];
00921    for (i=0;i<fNp;i++) {
00922       sprintf(numb," %g,",fPoly[i].X());
00923       nch = strlen(numb);
00924       if (i == fNp-1) numb[nch-1]=0;
00925       strcat(buffer,numb);
00926       if (i%5 == 4 || i == fNp-1) {
00927          nch = strlen(buffer); f->write(buffer,nch);
00928          if (i != fNp-1) sprintf(buffer,"\n                       ");
00929       }
00930    }
00931    sprintf(buffer," };\n");
00932    nch = strlen(buffer); f->write(buffer,nch);
00933    //array fY
00934    sprintf(buffer,"   const double fY[%d] = {",fNp);   
00935    nch = strlen(buffer); f->write(buffer,nch);
00936    buffer[0] = 0;
00937    for (i=0;i<fNp;i++) {
00938       sprintf(numb," %g,",fPoly[i].Y());
00939       nch = strlen(numb);
00940       if (i == fNp-1) numb[nch-1]=0;
00941       strcat(buffer,numb);
00942       if (i%5 == 4 || i == fNp-1) {
00943          nch = strlen(buffer); f->write(buffer,nch);
00944          if (i != fNp-1) sprintf(buffer,"\n                       ");
00945       }
00946    }
00947    sprintf(buffer," };\n");
00948    nch = strlen(buffer); f->write(buffer,nch);
00949    //array fB
00950    sprintf(buffer,"   const double fB[%d] = {",fNp);   
00951    nch = strlen(buffer); f->write(buffer,nch);
00952    buffer[0] = 0;
00953    for (i=0;i<fNp;i++) {
00954       sprintf(numb," %g,",fPoly[i].B());
00955       nch = strlen(numb);
00956       if (i == fNp-1) numb[nch-1]=0;
00957       strcat(buffer,numb);
00958       if (i%5 == 4 || i == fNp-1) {
00959          nch = strlen(buffer); f->write(buffer,nch);
00960          if (i != fNp-1) sprintf(buffer,"\n                       ");
00961       }
00962    }
00963    sprintf(buffer," };\n");
00964    nch = strlen(buffer); f->write(buffer,nch);
00965    //array fC
00966    sprintf(buffer,"   const double fC[%d] = {",fNp);   
00967    nch = strlen(buffer); f->write(buffer,nch);
00968    buffer[0] = 0;
00969    for (i=0;i<fNp;i++) {
00970       sprintf(numb," %g,",fPoly[i].C());
00971       nch = strlen(numb);
00972       if (i == fNp-1) numb[nch-1]=0;
00973       strcat(buffer,numb);
00974       if (i%5 == 4 || i == fNp-1) {
00975          nch = strlen(buffer); f->write(buffer,nch);
00976          if (i != fNp-1) sprintf(buffer,"\n                       ");
00977       }
00978    }
00979    sprintf(buffer," };\n");
00980    nch = strlen(buffer); f->write(buffer,nch);
00981     //array fD
00982    sprintf(buffer,"   const double fD[%d] = {",fNp);   
00983    nch = strlen(buffer); f->write(buffer,nch);
00984    buffer[0] = 0;
00985    for (i=0;i<fNp;i++) {
00986       sprintf(numb," %g,",fPoly[i].D());
00987       nch = strlen(numb);
00988       if (i == fNp-1) numb[nch-1]=0;
00989       strcat(buffer,numb);
00990       if (i%5 == 4 || i == fNp-1) {
00991          nch = strlen(buffer); f->write(buffer,nch);
00992          if (i != fNp-1) sprintf(buffer,"\n                       ");
00993       }
00994    }
00995    sprintf(buffer," };\n");
00996    nch = strlen(buffer); f->write(buffer,nch);
00997     //array fE
00998    sprintf(buffer,"   const double fE[%d] = {",fNp);   
00999    nch = strlen(buffer); f->write(buffer,nch);
01000    buffer[0] = 0;
01001    for (i=0;i<fNp;i++) {
01002       sprintf(numb," %g,",fPoly[i].E());
01003       nch = strlen(numb);
01004       if (i == fNp-1) numb[nch-1]=0;
01005       strcat(buffer,numb);
01006       if (i%5 == 4 || i == fNp-1) {
01007          nch = strlen(buffer); f->write(buffer,nch);
01008          if (i != fNp-1) sprintf(buffer,"\n                       ");
01009       }
01010    }
01011    sprintf(buffer," };\n");
01012    nch = strlen(buffer); f->write(buffer,nch);
01013     //array fF
01014    sprintf(buffer,"   const double fF[%d] = {",fNp);   
01015    nch = strlen(buffer); f->write(buffer,nch);
01016    buffer[0] = 0;
01017    for (i=0;i<fNp;i++) {
01018       sprintf(numb," %g,",fPoly[i].F());
01019       nch = strlen(numb);
01020       if (i == fNp-1) numb[nch-1]=0;
01021       strcat(buffer,numb);
01022       if (i%5 == 4 || i == fNp-1) {
01023          nch = strlen(buffer); f->write(buffer,nch);
01024          if (i != fNp-1) sprintf(buffer,"\n                       ");
01025       }
01026    }
01027    sprintf(buffer," };\n");
01028    nch = strlen(buffer); f->write(buffer,nch);
01029     
01030    //generate code for the spline evaluation
01031    sprintf(buffer,"   int klow=0;\n");
01032    nch = strlen(buffer); f->write(buffer,nch);
01033 
01034    sprintf(buffer,"   // If out of boundaries, extrapolate. It may be badly wrong\n");
01035    sprintf(buffer,"   if(x<=fXmin) klow=0;\n");
01036    nch = strlen(buffer); f->write(buffer,nch);
01037    sprintf(buffer,"   else if(x>=fXmax) klow=fNp-1;\n");
01038    nch = strlen(buffer); f->write(buffer,nch);
01039    sprintf(buffer,"   else {\n");
01040    nch = strlen(buffer); f->write(buffer,nch);
01041    sprintf(buffer,"     if(fKstep) {\n");
01042    nch = strlen(buffer); f->write(buffer,nch);
01043 
01044    sprintf(buffer,"       // Equidistant knots, use histogramming\n");
01045    nch = strlen(buffer); f->write(buffer,nch);
01046    sprintf(buffer,"       klow = int((x-fXmin)/fDelta);\n");
01047    nch = strlen(buffer); f->write(buffer,nch);
01048    sprintf(buffer,"       if (klow < fNp-1) klow = fNp-1;\n");
01049    nch = strlen(buffer); f->write(buffer,nch);
01050    sprintf(buffer,"     } else {\n");
01051    nch = strlen(buffer); f->write(buffer,nch);
01052    sprintf(buffer,"       int khig=fNp-1, khalf;\n");
01053    nch = strlen(buffer); f->write(buffer,nch);
01054 
01055    sprintf(buffer,"       // Non equidistant knots, binary search\n");
01056    nch = strlen(buffer); f->write(buffer,nch);
01057    sprintf(buffer,"       while(khig-klow>1)\n");
01058    nch = strlen(buffer); f->write(buffer,nch);
01059    sprintf(buffer,"      if(x>fX[khalf=(klow+khig)/2]) klow=khalf;\n");
01060    nch = strlen(buffer); f->write(buffer,nch);
01061    sprintf(buffer,"      else khig=khalf;\n");
01062    nch = strlen(buffer); f->write(buffer,nch);
01063    sprintf(buffer,"     }\n");
01064    nch = strlen(buffer); f->write(buffer,nch);
01065    sprintf(buffer,"   }\n");
01066    nch = strlen(buffer); f->write(buffer,nch);
01067    sprintf(buffer,"   // Evaluate now\n");
01068    nch = strlen(buffer); f->write(buffer,nch);
01069    sprintf(buffer,"   double dx=x-fX[klow];\n");
01070    nch = strlen(buffer); f->write(buffer,nch);
01071    sprintf(buffer,"   return (fY[klow]+dx*(fB[klow]+dx*(fC[klow]+dx*(fD[klow]+dx*(fE[klow]+dx*fF[klow])))));\n");
01072    nch = strlen(buffer); f->write(buffer,nch);
01073     
01074    //close file
01075    f->write("}\n",2);
01076       
01077    if (f) { f->close(); delete f;}
01078 }
01079 
01080 //____________________________________________________________________________
01081 void TRadSpline5::BuildCoeff()
01082 {
01083   //
01084   //     algorithm 600, collected algorithms from acm.
01085   //     algorithm appeared in acm-trans. math. software, vol.9, no. 2,
01086   //     jun., 1983, p. 258-259.
01087   //
01088   //     TRadSpline5 computes the coefficients of a quintic natural quintic spli
01089   //     s(x) with knots x(i) interpolating there to given function values:
01090   //               s(x(i)) = y(i)  for i = 1,2, ..., n.
01091   //     in each interval (x(i),x(i+1)) the spline function s(xx) is a
01092   //     polynomial of fifth degree:
01093   //     s(xx) = ((((f(i)*p+e(i))*p+d(i))*p+c(i))*p+b(i))*p+y(i)    (*)
01094   //           = ((((-f(i)*q+e(i+1))*q-d(i+1))*q+c(i+1))*q-b(i+1))*q+y(i+1)
01095   //     where  p = xx - x(i)  and  q = x(i+1) - xx.
01096   //     (note the first subscript in the second expression.)
01097   //     the different polynomials are pieced together so that s(x) and
01098   //     its derivatives up to s"" are continuous.
01099   //
01100   //        input:
01101   //
01102   //     n          number of data points, (at least three, i.e. n > 2)
01103   //     x(1:n)     the strictly increasing or decreasing sequence of
01104   //                knots.  the spacing must be such that the fifth power
01105   //                of x(i+1) - x(i) can be formed without overflow or
01106   //                underflow of exponents.
01107   //     y(1:n)     the prescribed function values at the knots.
01108   //
01109   //        output:
01110   //
01111   //     b,c,d,e,f  the computed spline coefficients as in (*).
01112   //         (1:n)  specifically
01113   //                b(i) = s'(x(i)), c(i) = s"(x(i))/2, d(i) = s"'(x(i))/6,
01114   //                e(i) = s""(x(i))/24,  f(i) = s""'(x(i))/120.
01115   //                f(n) is neither used nor altered.  the five arrays
01116   //                b,c,d,e,f must always be distinct.
01117   //
01118   //        option:
01119   //
01120   //     it is possible to specify values for the first and second
01121   //     derivatives of the spline function at arbitrarily many knots.
01122   //     this is done by relaxing the requirement that the sequence of
01123   //     knots be strictly increasing or decreasing.  specifically:
01124   //
01125   //     if x(j) = x(j+1) then s(x(j)) = y(j) and s'(x(j)) = y(j+1),
01126   //     if x(j) = x(j+1) = x(j+2) then in addition s"(x(j)) = y(j+2).
01127   //
01128   //     note that s""(x) is discontinuous at a double knot and, in
01129   //     addition, s"'(x) is discontinuous at a triple knot.  the
01130   //     subroutine assigns y(i) to y(i+1) in these cases and also to
01131   //     y(i+2) at a triple knot.  the representation (*) remains
01132   //     valid in each open interval (x(i),x(i+1)).  at a double knot,
01133   //     x(j) = x(j+1), the output coefficients have the following values:
01134   //       y(j) = s(x(j))          = y(j+1)
01135   //       b(j) = s'(x(j))         = b(j+1)
01136   //       c(j) = s"(x(j))/2       = c(j+1)
01137   //       d(j) = s"'(x(j))/6      = d(j+1)
01138   //       e(j) = s""(x(j)-0)/24     e(j+1) = s""(x(j)+0)/24
01139   //       f(j) = s""'(x(j)-0)/120   f(j+1) = s""'(x(j)+0)/120
01140   //     at a triple knot, x(j) = x(j+1) = x(j+2), the output
01141   //     coefficients have the following values:
01142   //       y(j) = s(x(j))         = y(j+1)    = y(j+2)
01143   //       b(j) = s'(x(j))        = b(j+1)    = b(j+2)
01144   //       c(j) = s"(x(j))/2      = c(j+1)    = c(j+2)
01145   //       d(j) = s"'((x(j)-0)/6    d(j+1) = 0  d(j+2) = s"'(x(j)+0)/6
01146   //       e(j) = s""(x(j)-0)/24    e(j+1) = 0  e(j+2) = s""(x(j)+0)/24
01147   //       f(j) = s""'(x(j)-0)/120  f(j+1) = 0  f(j+2) = s""'(x(j)+0)/120
01148   //
01149   int i, m;
01150   double pqqr, p, q, r, s, t, u, v,
01151     b1, p2, p3, q2, q3, r2, pq, pr, qr;
01152 
01153   if (fNp <= 2) {
01154     return;
01155   }
01156   //
01157   //     coefficients of a positive definite, pentadiagonal matrix,
01158   //     stored in D, E, F from 1 to n-3.
01159   //
01160   m = fNp-2;
01161   q = fPoly[1].X()-fPoly[0].X();
01162   r = fPoly[2].X()-fPoly[1].X();
01163   q2 = q*q;
01164   r2 = r*r;
01165   qr = q+r;
01166   fPoly[0].D() = fPoly[0].E() = 0;
01167   if (q) fPoly[1].D() = q*6.*q2/(qr*qr);
01168   else fPoly[1].D() = 0;
01169 
01170   if (m > 1) {
01171     for (i = 1; i < m; ++i) {
01172       p = q;
01173       q = r;
01174       r = fPoly[i+2].X()-fPoly[i+1].X();
01175       p2 = q2;
01176       q2 = r2;
01177       r2 = r*r;
01178       pq = qr;
01179       qr = q+r;
01180       if (q) {
01181         q3 = q2*q;
01182         pr = p*r;
01183         pqqr = pq*qr;
01184         fPoly[i+1].D() = q3*6./(qr*qr);
01185         fPoly[i].D() += (q+q)*(pr*15.*pr+(p+r)*q
01186                                *(pr* 20.+q2*7.)+q2*
01187                                ((p2+r2)*8.+pr*21.+q2+q2))/(pqqr*pqqr);
01188         fPoly[i-1].D() += q3*6./(pq*pq);
01189         fPoly[i].E() = q2*(p*qr+pq*3.*(qr+r+r))/(pqqr*qr);
01190         fPoly[i-1].E() += q2*(r*pq+qr*3.*(pq+p+p))/(pqqr*pq);
01191         fPoly[i-1].F() = q3/pqqr;
01192       } else
01193         fPoly[i+1].D() = fPoly[i].E() = fPoly[i-1].F() = 0;
01194     }
01195   }
01196   if (r) fPoly[m-1].D() += r*6.*r2/(qr*qr);
01197   //
01198   //     First and second order divided differences of the given function
01199   //     values, stored in b from 2 to n and in c from 3 to n
01200   //     respectively. care is taken of double and triple knots.
01201   //
01202   for (i = 1; i < fNp; ++i) {
01203     if (fPoly[i].X() != fPoly[i-1].X()) {
01204       fPoly[i].B() =
01205         (fPoly[i].Y()-fPoly[i-1].Y())/(fPoly[i].X()-fPoly[i-1].X());
01206     } else {
01207       fPoly[i].B() = fPoly[i].Y();
01208       fPoly[i].Y() = fPoly[i-1].Y();
01209     }
01210   }
01211   for (i = 2; i < fNp; ++i) {
01212     if (fPoly[i].X() != fPoly[i-2].X()) {
01213       fPoly[i].C() =
01214         (fPoly[i].B()-fPoly[i-1].B())/(fPoly[i].X()-fPoly[i-2].X());
01215     } else {
01216       fPoly[i].C() = fPoly[i].B()*.5;
01217       fPoly[i].B() = fPoly[i-1].B();
01218     }
01219   }
01220   //
01221   //     Solve the linear system with c(i+2) - c(i+1) as right-hand side. */
01222   //
01223   if (m > 1) {
01224     p=fPoly[0].C()=fPoly[m-1].E()=fPoly[0].F()
01225       =fPoly[m-2].F()=fPoly[m-1].F()=0;
01226     fPoly[1].C() = fPoly[3].C()-fPoly[2].C();
01227     fPoly[1].D() = 1./fPoly[1].D();
01228 
01229     if (m > 2) {
01230       for (i = 2; i < m; ++i) {
01231         q = fPoly[i-1].D()*fPoly[i-1].E();
01232         fPoly[i].D() = 1./(fPoly[i].D()-p*fPoly[i-2].F()-q*fPoly[i-1].E());
01233         fPoly[i].E() -= q*fPoly[i-1].F();
01234         fPoly[i].C() = fPoly[i+2].C()-fPoly[i+1].C()-p*fPoly[i-2].C()
01235           -q*fPoly[i-1].C();
01236         p = fPoly[i-1].D()*fPoly[i-1].F();
01237       }
01238     }
01239   }
01240 
01241   fPoly[fNp-2].C() = fPoly[fNp-1].C() = 0;
01242   if (fNp > 3)
01243     for (i=fNp-3; i > 0; --i)
01244       fPoly[i].C() = (fPoly[i].C()-fPoly[i].E()*fPoly[i+1].C()
01245                       -fPoly[i].F()*fPoly[i+2].C())*fPoly[i].D();
01246   //
01247   //     Integrate the third derivative of s(x)
01248   //
01249   m = fNp-1;
01250   q = fPoly[1].X()-fPoly[0].X();
01251   r = fPoly[2].X()-fPoly[1].X();
01252   b1 = fPoly[1].B();
01253   q3 = q*q*q;
01254   qr = q+r;
01255   if (qr) {
01256     v = fPoly[1].C()/qr;
01257     t = v;
01258   } else
01259     v = t = 0;
01260   if (q) fPoly[0].F() = v/q;
01261   else fPoly[0].F() = 0;
01262   for (i = 1; i < m; ++i) {
01263     p = q;
01264     q = r;
01265     if (i != m-1) r = fPoly[i+2].X()-fPoly[i+1].X();
01266     else r = 0;
01267     p3 = q3;
01268     q3 = q*q*q;
01269     pq = qr;
01270     qr = q+r;
01271     s = t;
01272     if (qr) t = (fPoly[i+1].C()-fPoly[i].C())/qr;
01273     else t = 0;
01274     u = v;
01275     v = t-s;
01276     if (pq) {
01277       fPoly[i].F() = fPoly[i-1].F();
01278       if (q) fPoly[i].F() = v/q;
01279       fPoly[i].E() = s*5.;
01280       fPoly[i].D() = (fPoly[i].C()-q*s)*10;
01281       fPoly[i].C() =
01282         fPoly[i].D()*(p-q)+(fPoly[i+1].B()-fPoly[i].B()+(u-fPoly[i].E())*
01283                             p3-(v+fPoly[i].E())*q3)/pq;
01284       fPoly[i].B() = (p*(fPoly[i+1].B()-v*q3)+q*(fPoly[i].B()-u*p3))/pq-p
01285         *q*(fPoly[i].D()+fPoly[i].E()*(q-p));
01286     } else {
01287       fPoly[i].C() = fPoly[i-1].C();
01288       fPoly[i].D() = fPoly[i].E() = fPoly[i].F() = 0;
01289     }
01290   }
01291   //
01292   //     End points x(1) and x(n)
01293   //
01294   p = fPoly[1].X()-fPoly[0].X();
01295   s = fPoly[0].F()*p*p*p;
01296   fPoly[0].E() = fPoly[0].D() = 0;
01297   fPoly[0].C() = fPoly[1].C()-s*10;
01298   fPoly[0].B() = b1-(fPoly[0].C()+s)*p;
01299 
01300   q = fPoly[fNp-1].X()-fPoly[fNp-2].X();
01301   t = fPoly[fNp-2].F()*q*q*q;
01302   fPoly[fNp-1].E() = fPoly[fNp-1].D() = 0;
01303   fPoly[fNp-1].C() = fPoly[fNp-2].C()+t*10;
01304   fPoly[fNp-1].B() += (fPoly[fNp-1].C()-t)*q;
01305 }
01306 
01307 //___________________________________________________________________________
01308 void TRadSpline5::Test()
01309 {
01310   //
01311   // Test method for TRadSpline5
01312   //
01313   //
01314   //   n          number of data points.
01315   //   m          2*m-1 is order of spline.
01316   //                 m = 3 always for quintic spline.
01317   //   nn,nm1,mm,
01318   //   mm1,i,k,
01319   //   j,jj       temporary integer variables.
01320   //   z,p        temporary double precision variables.
01321   //   x[n]       the sequence of knots.
01322   //   y[n]       the prescribed function values at the knots.
01323   //   a[200][6]  two dimensional array whose columns are
01324   //                 the computed spline coefficients
01325   //   diff[5]    maximum values of differences of values and
01326   //                 derivatives to right and left of knots.
01327   //   com[5]     maximum values of coefficients.
01328   //
01329   //
01330   //   test of TRadSpline5 with nonequidistant knots and
01331   //      equidistant knots follows.
01332   //
01333   //
01334   double hx;
01335   double diff[5];
01336   double a[1200], c[6];
01337   int i, j, k, m, n;
01338   double p, x[200], y[200], z;
01339   int jj, mm, nn;
01340   int mm1, nm1;
01341   double com[5];
01342 
01343   printf("1         TEST OF TRadSpline5 WITH NONEQUIDISTANT KNOTS\n");
01344   n = 5;
01345   x[0] = -3;
01346   x[1] = -1;
01347   x[2] = 0;
01348   x[3] = 3;
01349   x[4] = 4;
01350   y[0] = 7;
01351   y[1] = 11;
01352   y[2] = 26;
01353   y[3] = 56;
01354   y[4] = 29;
01355   m = 3;
01356   mm = m << 1;
01357   mm1 = mm-1;
01358   printf("\n-N = %3d    M =%2d\n",n,m);
01359   TRadSpline5 *spline = new TRadSpline5("Test",x,y,n);
01360   for (i = 0; i < n; ++i)
01361     spline->GetCoeff(i,hx, a[i],a[i+200],a[i+400],
01362                      a[i+600],a[i+800],a[i+1000]);
01363   delete spline;
01364   for (i = 0; i < mm1; ++i) diff[i] = com[i] = 0;
01365   for (k = 0; k < n; ++k) {
01366     for (i = 0; i < mm; ++i) c[i] = a[k+i*200];
01367     printf(" ---------------------------------------%3d --------------------------------------------\n",k+1);
01368     printf("%12.8f\n",x[k]);
01369     if (k == n-1) {
01370       printf("%16.8f\n",c[0]);
01371     } else {
01372       for (i = 0; i < mm; ++i) printf("%16.8f",c[i]);
01373       printf("\n");
01374       for (i = 0; i < mm1; ++i)
01375         if ((z=fabs(a[k+i*200])) > com[i]) com[i] = z;
01376       z = x[k+1]-x[k];
01377       for (i = 1; i < mm; ++i)
01378         for (jj = i; jj < mm; ++jj) {
01379           j = mm+i-jj;
01380           c[j-2] = c[j-1]*z+c[j-2];
01381         }
01382       for (i = 0; i < mm; ++i) printf("%16.8f",c[i]);
01383       printf("\n");
01384       for (i = 0; i < mm1; ++i)
01385         if (!(k >= n-2 && i != 0))
01386           if((z = fabs(c[i]-a[k+1+i*200]))
01387              > diff[i]) diff[i] = z;
01388     }
01389   }
01390   printf("  MAXIMUM ABSOLUTE VALUES OF DIFFERENCES \n");
01391   for (i = 0; i < mm1; ++i) printf("%18.9E",diff[i]);
01392   printf("\n");
01393   printf("  MAXIMUM ABSOLUTE VALUES OF COEFFICIENTS \n");
01394   if (fabs(c[0]) > com[0])
01395     com[0] = fabs(c[0]);
01396   for (i = 0; i < mm1; ++i) printf("%16.8f",com[i]);
01397   printf("\n");
01398   m = 3;
01399   for (n = 10; n <= 100; n += 10) {
01400     mm = m << 1;
01401     mm1 = mm-1;
01402     nm1 = n-1;
01403     for (i = 0; i < nm1; i += 2) {
01404       x[i] = i+1;
01405       x[i+1] = i+2;
01406       y[i] = 1;
01407       y[i+1] = 0;
01408     }
01409     if (n % 2 != 0) {
01410       x[n-1] = n;
01411       y[n-1] = 1;
01412     }
01413     printf("\n-N = %3d    M =%2d\n",n,m);
01414     spline = new TRadSpline5("Test",x,y,n);
01415     for (i = 0; i < n; ++i)
01416       spline->GetCoeff(i,hx,a[i],a[i+200],a[i+400],
01417                        a[i+600],a[i+800],a[i+1000]);
01418     delete spline;
01419     for (i = 0; i < mm1; ++i)
01420       diff[i] = com[i] = 0;
01421     for (k = 0; k < n; ++k) {
01422       for (i = 0; i < mm; ++i)
01423         c[i] = a[k+i*200];
01424       if (n < 11) {
01425         printf(" ---------------------------------------%3d --------------------------------------------\n",k+1);
01426         printf("%12.8f\n",x[k]);
01427         if (k == n-1) printf("%16.8f\n",c[0]);
01428       }
01429       if (k == n-1) break;
01430       if (n <= 10) {
01431         for (i = 0; i < mm; ++i) printf("%16.8f",c[i]);
01432         printf("\n");
01433       }
01434       for (i = 0; i < mm1; ++i)
01435         if ((z=fabs(a[k+i*200])) > com[i])
01436           com[i] = z;
01437       z = x[k+1]-x[k];
01438       for (i = 1; i < mm; ++i)
01439         for (jj = i; jj < mm; ++jj) {
01440           j = mm+i-jj;
01441           c[j-2] = c[j-1]*z+c[j-2];
01442         }
01443       if (n <= 10) {
01444         for (i = 0; i < mm; ++i) printf("%16.8f",c[i]);
01445         printf("\n");
01446       }
01447       for (i = 0; i < mm1; ++i)
01448         if (!(k >= n-2 && i != 0))
01449           if ((z = fabs(c[i]-a[k+1+i*200]))
01450               > diff[i]) diff[i] = z;
01451     }
01452     printf("  MAXIMUM ABSOLUTE VALUES OF DIFFERENCES \n");
01453     for (i = 0; i < mm1; ++i) printf("%18.9E",diff[i]);
01454     printf("\n");
01455     printf("  MAXIMUM ABSOLUTE VALUES OF COEFFICIENTS \n");
01456     if (fabs(c[0]) > com[0])
01457       com[0] = fabs(c[0]);
01458     for (i = 0; i < mm1; ++i) printf("%16.8E",com[i]);
01459     printf("\n");
01460   }
01461   //
01462   //     Test of TRadSpline5 with nonequidistant double knots follows
01463   //
01464   printf("1  TEST OF TRadSpline5 WITH NONEQUIDISTANT DOUBLE KNOTS\n");
01465   n = 5;
01466   x[0] = -3;
01467   x[1] = -3;
01468   x[2] = -1;
01469   x[3] = -1;
01470   x[4] = 0;
01471   x[5] = 0;
01472   x[6] = 3;
01473   x[7] = 3;
01474   x[8] = 4;
01475   x[9] = 4;
01476   y[0] = 7;
01477   y[1] = 2;
01478   y[2] = 11;
01479   y[3] = 15;
01480   y[4] = 26;
01481   y[5] = 10;
01482   y[6] = 56;
01483   y[7] = -27;
01484   y[8] = 29;
01485   y[9] = -30;
01486   m = 3;
01487   nn = n << 1;
01488   mm = m << 1;
01489   mm1 = mm-1;
01490   printf("-N = %3d    M =%2d\n",n,m);
01491   spline = new TRadSpline5("Test",x,y,nn);
01492   for (i = 0; i < nn; ++i)
01493     spline->GetCoeff(i,hx,a[i],a[i+200],a[i+400],
01494                      a[i+600],a[i+800],a[i+1000]);
01495   delete spline;
01496   for (i = 0; i < mm1; ++i)
01497     diff[i] = com[i] = 0;
01498   for (k = 0; k < nn; ++k) {
01499     for (i = 0; i < mm; ++i)
01500       c[i] = a[k+i*200];
01501     printf(" ---------------------------------------%3d --------------------------------------------\n",k+1);
01502     printf("%12.8f\n",x[k]);
01503     if (k == nn-1) {
01504       printf("%16.8f\n",c[0]);
01505       break;
01506     }
01507     for (i = 0; i < mm; ++i) printf("%16.8f",c[i]);
01508     printf("\n");
01509     for (i = 0; i < mm1; ++i)
01510       if ((z=fabs(a[k+i*200])) > com[i]) com[i] = z;
01511     z = x[k+1]-x[k];
01512     for (i = 1; i < mm; ++i)
01513       for (jj = i; jj < mm; ++jj) {
01514         j = mm+i-jj;
01515         c[j-2] = c[j-1]*z+c[j-2];
01516       }
01517     for (i = 0; i < mm; ++i) printf("%16.8f",c[i]);
01518     printf("\n");
01519     for (i = 0; i < mm1; ++i)
01520       if (!(k >= nn-2 && i != 0))
01521         if ((z = fabs(c[i]-a[k+1+i*200]))
01522             > diff[i]) diff[i] = z;
01523   }
01524   printf("  MAXIMUM ABSOLUTE VALUES OF DIFFERENCES \n");
01525   for (i = 1; i <= mm1; ++i) {
01526     printf("%18.9E",diff[i-1]);
01527   }
01528   printf("\n");
01529   if (fabs(c[0]) > com[0])
01530     com[0] = fabs(c[0]);
01531   printf("  MAXIMUM ABSOLUTE VALUES OF COEFFICIENTS \n");
01532   for (i = 0; i < mm1; ++i) printf("%16.8f",com[i]);
01533   printf("\n");
01534   m = 3;
01535   for (n = 10; n <= 100; n += 10) {
01536     nn = n << 1;
01537     mm = m << 1;
01538     mm1 = mm-1;
01539     p = 0;
01540     for (i = 0; i < n; ++i) {
01541       p += fabs(sin(i+1));
01542       x[(i << 1)] = p;
01543       x[(i << 1)+1] = p;
01544       y[(i << 1)] = cos(i+1)-.5;
01545       y[(i << 1)+1] = cos((i << 1)+2)-.5;
01546     }
01547     printf("-N = %3d    M =%2d\n",n,m);
01548     spline = new TRadSpline5("Test",x,y,nn);
01549     for (i = 0; i < nn; ++i)
01550       spline->GetCoeff(i,hx,a[i],a[i+200],a[i+400],
01551                        a[i+600],a[i+800],a[i+1000]);
01552     delete spline;
01553     for (i = 0; i < mm1; ++i)
01554       diff[i] = com[i] = 0;
01555     for (k = 0; k < nn; ++k) {
01556       for (i = 0; i < mm; ++i)
01557         c[i] = a[k+i*200];
01558       if (n < 11) {
01559         printf(" ---------------------------------------%3d --------------------------------------------\n",k+1);
01560         printf("%12.8f\n",x[k]);
01561         if (k == nn-1) printf("%16.8f\n",c[0]);
01562       }
01563       if (k == nn-1) break;
01564       if (n <= 10) {
01565         for (i = 0; i < mm; ++i) printf("%16.8f",c[i]);
01566         printf("\n");
01567       }
01568       for (i = 0; i < mm1; ++i)
01569         if ((z=fabs(a[k+i*200])) > com[i]) com[i] = z;
01570       z = x[k+1]-x[k];
01571       for (i = 1; i < mm; ++i) {
01572         for (jj = i; jj < mm; ++jj) {
01573           j = mm+i-jj;
01574           c[j-2] = c[j-1]*z+c[j-2];
01575         }
01576       }
01577       if (n <= 10) {
01578         for (i = 0; i < mm; ++i) printf("%16.8f",c[i]);
01579         printf("\n");
01580       }
01581       for (i = 0; i < mm1; ++i)
01582         if (!(k >= nn-2 && i != 0))
01583           if ((z = fabs(c[i]-a[k+1+i*200]))
01584               > diff[i]) diff[i] = z;
01585     }
01586     printf("  MAXIMUM ABSOLUTE VALUES OF DIFFERENCES \n");
01587     for (i = 0; i < mm1; ++i) printf("%18.9E",diff[i]);
01588     printf("\n");
01589     printf("  MAXIMUM ABSOLUTE VALUES OF COEFFICIENTS \n");
01590     if (fabs(c[0]) > com[0])
01591       com[0] = fabs(c[0]);
01592     for (i = 0; i < mm1; ++i) printf("%18.9E",com[i]);
01593     printf("\n");
01594   }
01595   //
01596   //     test of TRadSpline5 with nonequidistant knots, one double knot,
01597   //        one triple knot, follows.
01598   //
01599   printf("1         TEST OF TRadSpline5 WITH NONEQUIDISTANT KNOTS,\n");
01600   printf("             ONE DOUBLE, ONE TRIPLE KNOT\n");
01601   n = 8;
01602   x[0] = -3;
01603   x[1] = -1;
01604   x[2] = -1;
01605   x[3] = 0;
01606   x[4] = 3;
01607   x[5] = 3;
01608   x[6] = 3;
01609   x[7] = 4;
01610   y[0] = 7;
01611   y[1] = 11;
01612   y[2] = 15;
01613   y[3] = 26;
01614   y[4] = 56;
01615   y[5] = -30;
01616   y[6] = -7;
01617   y[7] = 29;
01618   m = 3;
01619   mm = m << 1;
01620   mm1 = mm-1;
01621   printf("-N = %3d    M =%2d\n",n,m);
01622   spline=new TRadSpline5("Test",x,y,n);
01623   for (i = 0; i < n; ++i)
01624     spline->GetCoeff(i,hx,a[i],a[i+200],a[i+400],
01625                      a[i+600],a[i+800],a[i+1000]);
01626   delete spline;
01627   for (i = 0; i < mm1; ++i)
01628     diff[i] = com[i] = 0;
01629   for (k = 0; k < n; ++k) {
01630     for (i = 0; i < mm; ++i)
01631       c[i] = a[k+i*200];
01632     printf(" ---------------------------------------%3d --------------------------------------------\n",k+1);
01633     printf("%12.8f\n",x[k]);
01634     if (k == n-1) {
01635       printf("%16.8f\n",c[0]);
01636       break;
01637     }
01638     for (i = 0; i < mm; ++i) printf("%16.8f",c[i]);
01639     printf("\n");
01640     for (i = 0; i < mm1; ++i)
01641       if ((z=fabs(a[k+i*200])) > com[i]) com[i] = z;
01642     z = x[k+1]-x[k];
01643     for (i = 1; i < mm; ++i)
01644       for (jj = i; jj < mm; ++jj) {
01645         j = mm+i-jj;
01646         c[j-2] = c[j-1]*z+c[j-2];
01647       }
01648     for (i = 0; i < mm; ++i) printf("%16.8f",c[i]);
01649     printf("\n");
01650     for (i = 0; i < mm1; ++i)
01651       if (!(k >= n-2 && i != 0))
01652         if ((z = fabs(c[i]-a[k+1+i*200]))
01653             > diff[i]) diff[i] = z;
01654   }
01655   printf("  MAXIMUM ABSOLUTE VALUES OF DIFFERENCES \n");
01656   for (i = 0; i < mm1; ++i) printf("%18.9E",diff[i]);
01657   printf("\n");
01658   printf("  MAXIMUM ABSOLUTE VALUES OF COEFFICIENTS \n");
01659   if (fabs(c[0]) > com[0])
01660     com[0] = fabs(c[0]);
01661   for (i = 0; i < mm1; ++i) printf("%16.8f",com[i]);
01662   printf("\n");
01663   //
01664   //     Test of TRadSpline5 with nonequidistant knots, two double knots,
01665   //        one triple knot,follows.
01666   //
01667   printf("1         TEST OF TRadSpline5 WITH NONEQUIDISTANT KNOTS,\n");
01668   printf("             TWO DOUBLE, ONE TRIPLE KNOT\n");
01669   n = 10;
01670   x[0] = 0;
01671   x[1] = 2;
01672   x[2] = 2;
01673   x[3] = 3;
01674   x[4] = 3;
01675   x[5] = 3;
01676   x[6] = 5;
01677   x[7] = 8;
01678   x[8] = 9;
01679   x[9] = 9;
01680   y[0] = 163;
01681   y[1] = 237;
01682   y[2] = -127;
01683   y[3] = 119;
01684   y[4] = -65;
01685   y[5] = 192;
01686   y[6] = 293;
01687   y[7] = 326;
01688   y[8] = 0;
01689   y[9] = -414;
01690   m = 3;
01691   mm = m << 1;
01692   mm1 = mm-1;
01693   printf("-N = %3d    M =%2d\n",n,m);
01694   spline = new TRadSpline5("Test",x,y,n);
01695   for (i = 0; i < n; ++i)
01696     spline->GetCoeff(i,hx,a[i],a[i+200],a[i+400],
01697                      a[i+600],a[i+800],a[i+1000]);
01698   delete spline;
01699   for (i = 0; i < mm1; ++i)
01700     diff[i] = com[i] = 0;
01701   for (k = 0; k < n; ++k) {
01702     for (i = 0; i < mm; ++i)
01703       c[i] = a[k+i*200];
01704     printf(" ---------------------------------------%3d --------------------------------------------\n",k+1);
01705     printf("%12.8f\n",x[k]);
01706     if (k == n-1) {
01707       printf("%16.8f\n",c[0]);
01708       break;
01709     }
01710     for (i = 0; i < mm; ++i) printf("%16.8f",c[i]);
01711     printf("\n");
01712     for (i = 0; i < mm1; ++i)
01713       if ((z=fabs(a[k+i*200])) > com[i]) com[i] = z;
01714     z = x[k+1]-x[k];
01715     for (i = 1; i < mm; ++i)
01716       for (jj = i; jj < mm; ++jj) {
01717         j = mm+i-jj;
01718         c[j-2] = c[j-1]*z+c[j-2];
01719       }
01720     for (i = 0; i < mm; ++i) printf("%16.8f",c[i]);
01721     printf("\n");
01722     for (i = 0; i < mm1; ++i)
01723       if (!(k >= n-2 && i != 0))
01724         if((z = fabs(c[i]-a[k+1+i*200]))
01725            > diff[i]) diff[i] = z;
01726   }
01727   printf("  MAXIMUM ABSOLUTE VALUES OF DIFFERENCES \n");
01728   for (i = 0; i < mm1; ++i) printf("%18.9E",diff[i]);
01729   printf("\n");
01730   printf("  MAXIMUM ABSOLUTE VALUES OF COEFFICIENTS \n");
01731   if (fabs(c[0]) > com[0])
01732     com[0] = fabs(c[0]);
01733   for (i = 0; i < mm1; ++i) printf("%16.8f",com[i]);
01734   printf("\n");
01735 }

Generated on Tue Nov 29 23:12:42 2016 for BOSS_7.0.2 by  doxygen 1.4.7