CMS 3D CMS Logo

Spline.cc

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 //
00003 // Package:     MVAComputer
00004 // Class  :     Spline
00005 // 
00006 
00007 // Implementation:
00008 //     Simple cubic spline implementation for equidistant points in x.
00009 //
00010 // Author:      Christophe Saout
00011 // Created:     Sat Apr 24 15:18 CEST 2007
00012 // $Id: Spline.cc,v 1.3 2007/12/07 15:04:44 saout Exp $
00013 //
00014 
00015 #include <cstring>
00016 #include <cmath>
00017 
00018 #include "PhysicsTools/MVAComputer/interface/Spline.h"
00019 
00020 namespace PhysicsTools {
00021 
00022 double Spline::Segment::eval(double x) const
00023 {
00024         double tmp;
00025         double y = 0.0;
00026         y += coeffs[0];         tmp = x;
00027         y += coeffs[1] * tmp;   tmp *= x;
00028         y += coeffs[2] * tmp;   tmp *= x;
00029         y += coeffs[3] * tmp;
00030         return y;
00031 }
00032 
00033 double Spline::Segment::integral(double x) const
00034 {
00035         double tmp = x;
00036         double area = this->area;
00037         area += coeffs[0] * tmp;               tmp *= x;
00038         area += coeffs[1] * tmp * (1.0 / 2.0); tmp *= x;
00039         area += coeffs[2] * tmp * (1.0 / 3.0); tmp *= x;
00040         area += coeffs[3] * tmp * (1.0 / 4.0);
00041         return area;
00042 }
00043 
00044 Spline::Spline() : n(0), segments(0), area(0.0)
00045 {}
00046 
00047 Spline::Spline(const Spline &orig) : n(orig.n), area(orig.area)
00048 {
00049         segments = new Segment[n];
00050         std::memcpy(segments, orig.segments, sizeof(Segment) * n);
00051 }
00052 
00053 Spline::Spline(unsigned int n_, const double *vals) :
00054         n(0), segments(0), area(0.0)
00055 { set(n_, vals); }
00056 
00057 void Spline::set(unsigned int n_, const double *vals)
00058 {
00059         n = n_ - 1;
00060         area = 0.0;
00061 
00062         delete[] segments;
00063         segments = new Segment[n];
00064 
00065         if (n == 1) {
00066                 Segment *seg = &segments[0];
00067                 seg->coeffs[0] = vals[0];
00068                 seg->coeffs[1] = vals[1] - vals[0];
00069                 seg->coeffs[2] = 0.0;
00070                 seg->coeffs[3] = 0.0;
00071                 seg->area = 0.0;
00072                 area = seg->integral(1.0);
00073                 return;
00074         }
00075 
00076         double m0, m1;
00077         Segment *seg = &segments[0];
00078         m0 = 0.0, m1 = 0.5 * (vals[2] - vals[0]);
00079         seg->coeffs[0] = vals[0];
00080         seg->coeffs[1] = -2.0 * vals[0] + 2.0 * vals[1] - m1;
00081         seg->coeffs[2] = vals[0] - vals[1] + m1;
00082         seg->coeffs[3] = 0.0;
00083         seg->area = 0.0;
00084         area = seg->integral(1.0);
00085         m0 = m1;
00086         seg++, vals++;
00087 
00088         for(unsigned int i = 1; i < n - 1; i++, seg++, vals++) {
00089                 m1 = 0.5 * (vals[2] - vals[0]);
00090                 seg->coeffs[0] = vals[0];
00091                 seg->coeffs[1] = m0;
00092                 seg->coeffs[2] = -3.0 * vals[0] - 2.0 * m0 + 3.0 * vals[1] - m1;
00093                 seg->coeffs[3] = 2.0 * vals[0] + m0 - 2.0 * vals[1] + m1;
00094                 seg->area = area;
00095                 area = seg->integral(1.0);
00096                 m0 = m1;
00097         }
00098 
00099         seg->coeffs[0] = vals[0];
00100         seg->coeffs[1] = m0;
00101         seg->coeffs[2] = - vals[0] - m0 + vals[1];
00102         seg->coeffs[3] = 0.0;
00103         seg->area = area;
00104         area = seg->integral(1.0);
00105 }
00106 
00107 Spline::~Spline()
00108 {
00109         delete[] segments;
00110 }
00111 
00112 Spline &Spline::operator = (const Spline &orig)
00113 {
00114         delete[] segments;
00115         n = orig.n;
00116         segments = new Segment[n];
00117         std::memcpy(segments, orig.segments, sizeof(Segment) * n);
00118         area = orig.area;
00119         return *this;
00120 }
00121 
00122 double Spline::eval(double x) const
00123 {
00124         if (x <= 0.0)
00125                 return segments[0].eval(0.0);
00126         if (x >= 1.0)
00127                 return segments[n - 1].eval(1.0);
00128 
00129         double total;
00130         double rest = std::modf(x * n, &total);
00131 
00132         return segments[(unsigned int)total].eval(rest);
00133 }
00134 
00135 double Spline::integral(double x) const
00136 {
00137         if (x <= 0.0)
00138                 return 0.0;
00139         if (x >= 1.0)
00140                 return 1.0;
00141 
00142         if (area < 1.0e-9)
00143                 return 0.0;
00144 
00145         double total;
00146         double rest = std::modf(x * n, &total);
00147 
00148         return segments[(unsigned int)total].integral(rest) / area;
00149 }
00150 
00151 } // namespace PhysicsTools

Generated on Tue Jun 9 17:41:31 2009 for CMSSW by  doxygen 1.5.4