CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_7/src/PhysicsTools/MVAComputer/src/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.4 2009/06/03 09:50:14 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::deriv(double x) const
00034 {
00035         double tmp;
00036         double d = 0.0;
00037         d += coeffs[1];                 tmp = x;
00038         d += coeffs[2] * tmp * 2.0;     tmp *= x;
00039         d += coeffs[3] * tmp * 3.0;
00040         return d;
00041 }
00042 
00043 double Spline::Segment::integral(double x) const
00044 {
00045         double tmp = x;
00046         double area = this->area;
00047         area += coeffs[0] * tmp;               tmp *= x;
00048         area += coeffs[1] * tmp * (1.0 / 2.0); tmp *= x;
00049         area += coeffs[2] * tmp * (1.0 / 3.0); tmp *= x;
00050         area += coeffs[3] * tmp * (1.0 / 4.0);
00051         return area;
00052 }
00053 
00054 Spline::Spline() : n(0), segments(0), area(0.0)
00055 {}
00056 
00057 Spline::Spline(const Spline &orig) : n(orig.n), area(orig.area)
00058 {
00059         segments = new Segment[n];
00060         std::memcpy(segments, orig.segments, sizeof(Segment) * n);
00061 }
00062 
00063 Spline::Spline(unsigned int n_, const double *vals) :
00064         n(0), segments(0), area(0.0)
00065 { set(n_, vals); }
00066 
00067 void Spline::set(unsigned int n_, const double *vals)
00068 {
00069         n = n_ - 1;
00070         area = 0.0;
00071 
00072         delete[] segments;
00073         segments = new Segment[n];
00074 
00075         if (n == 1) {
00076                 Segment *seg = &segments[0];
00077                 seg->coeffs[0] = vals[0];
00078                 seg->coeffs[1] = vals[1] - vals[0];
00079                 seg->coeffs[2] = 0.0;
00080                 seg->coeffs[3] = 0.0;
00081                 seg->area = 0.0;
00082                 area = seg->integral(1.0);
00083                 return;
00084         }
00085 
00086         double m0, m1;
00087         Segment *seg = &segments[0];
00088         m0 = 0.0, m1 = 0.5 * (vals[2] - vals[0]);
00089         seg->coeffs[0] = vals[0];
00090         seg->coeffs[1] = -2.0 * vals[0] + 2.0 * vals[1] - m1;
00091         seg->coeffs[2] = vals[0] - vals[1] + m1;
00092         seg->coeffs[3] = 0.0;
00093         seg->area = 0.0;
00094         area = seg->integral(1.0);
00095         m0 = m1;
00096         seg++, vals++;
00097 
00098         for(unsigned int i = 1; i < n - 1; i++, seg++, vals++) {
00099                 m1 = 0.5 * (vals[2] - vals[0]);
00100                 seg->coeffs[0] = vals[0];
00101                 seg->coeffs[1] = m0;
00102                 seg->coeffs[2] = -3.0 * vals[0] - 2.0 * m0 + 3.0 * vals[1] - m1;
00103                 seg->coeffs[3] = 2.0 * vals[0] + m0 - 2.0 * vals[1] + m1;
00104                 seg->area = area;
00105                 area = seg->integral(1.0);
00106                 m0 = m1;
00107         }
00108 
00109         seg->coeffs[0] = vals[0];
00110         seg->coeffs[1] = m0;
00111         seg->coeffs[2] = - vals[0] - m0 + vals[1];
00112         seg->coeffs[3] = 0.0;
00113         seg->area = area;
00114         area = seg->integral(1.0);
00115 }
00116 
00117 Spline::~Spline()
00118 {
00119         delete[] segments;
00120 }
00121 
00122 Spline &Spline::operator = (const Spline &orig)
00123 {
00124         delete[] segments;
00125         n = orig.n;
00126         segments = new Segment[n];
00127         std::memcpy(segments, orig.segments, sizeof(Segment) * n);
00128         area = orig.area;
00129         return *this;
00130 }
00131 
00132 double Spline::eval(double x) const
00133 {
00134         if (x <= 0.0)
00135                 return segments[0].eval(0.0);
00136         if (x >= 1.0)
00137                 return segments[n - 1].eval(1.0);
00138 
00139         double total;
00140         double rest = std::modf(x * n, &total);
00141 
00142         return segments[(unsigned int)total].eval(rest);
00143 }
00144 
00145 double Spline::deriv(double x) const
00146 {
00147         if (x < 0.0 || x > 1.0)
00148                 return 0.0;
00149         else if (x == 0.0)
00150                 return segments[0].deriv(0.0);
00151         else if (x == 1.0)
00152                 return segments[n - 1].deriv(1.0);
00153 
00154         double total;
00155         double rest = std::modf(x * n, &total);
00156 
00157         return segments[(unsigned int)total].deriv(rest);
00158 }
00159 
00160 double Spline::integral(double x) const
00161 {
00162         if (x <= 0.0)
00163                 return 0.0;
00164         if (x >= 1.0)
00165                 return 1.0;
00166 
00167         if (area < 1.0e-9)
00168                 return 0.0;
00169 
00170         double total;
00171         double rest = std::modf(x * n, &total);
00172 
00173         return segments[(unsigned int)total].integral(rest) / area;
00174 }
00175 
00176 } // namespace PhysicsTools