CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_6_1_2_SLHC2_patch1/src/JetMETCorrections/InterpolationTables/interface/LinInterpolatedTableND.h

Go to the documentation of this file.
00001 #ifndef NPSTAT_LININTERPOLATEDTABLEND_HH_
00002 #define NPSTAT_LININTERPOLATEDTABLEND_HH_
00003 
00014 #include <climits>
00015 #include <vector>
00016 #include <utility>
00017 
00018 #include "Alignment/Geners/interface/CPP11_auto_ptr.hh"
00019 
00020 #include "JetMETCorrections/InterpolationTables/interface/ArrayND.h"
00021 #include "JetMETCorrections/InterpolationTables/interface/UniformAxis.h"
00022 
00023 namespace npstat {
00030     template <class Numeric, class Axis=UniformAxis>
00031     class LinInterpolatedTableND
00032     {
00033         template <typename Num2, typename Axis2>
00034         friend class LinInterpolatedTableND;
00035 
00036     public:
00037         typedef Numeric value_type;
00038         typedef Axis axis_type;
00039 
00054         LinInterpolatedTableND(
00055             const std::vector<Axis>& axes,
00056             const std::vector<std::pair<bool,bool> >& extrapolationType,
00057             const char* functionLabel=0);
00058 
00060         LinInterpolatedTableND(const Axis& xAxis, bool leftX, bool rightX,
00061                                const char* functionLabel=0);
00062 
00064         LinInterpolatedTableND(const Axis& xAxis, bool leftX, bool rightX,
00065                                const Axis& yAxis, bool leftY, bool rightY,
00066                                const char* functionLabel=0);
00067 
00069         LinInterpolatedTableND(const Axis& xAxis, bool leftX, bool rightX,
00070                                const Axis& yAxis, bool leftY, bool rightY,
00071                                const Axis& zAxis, bool leftZ, bool rightZ,
00072                                const char* functionLabel=0);
00073 
00075         LinInterpolatedTableND(const Axis& xAxis, bool leftX, bool rightX,
00076                                const Axis& yAxis, bool leftY, bool rightY,
00077                                const Axis& zAxis, bool leftZ, bool rightZ,
00078                                const Axis& tAxis, bool leftT, bool rightT,
00079                                const char* functionLabel=0);
00080 
00082         LinInterpolatedTableND(const Axis& xAxis, bool leftX, bool rightX,
00083                                const Axis& yAxis, bool leftY, bool rightY,
00084                                const Axis& zAxis, bool leftZ, bool rightZ,
00085                                const Axis& tAxis, bool leftT, bool rightT,
00086                                const Axis& vAxis, bool leftV, bool rightV,
00087                                const char* functionLabel=0);
00088 
00093         template <class Num2>
00094         LinInterpolatedTableND(const LinInterpolatedTableND<Num2,Axis>&);
00095 
00100         Numeric operator()(const double* point, unsigned dim) const;
00101 
00103 
00104         Numeric operator()(const double& x0) const;
00105         Numeric operator()(const double& x0, const double& x1) const;
00106         Numeric operator()(const double& x0, const double& x1,
00107                            const double& x2) const;
00108         Numeric operator()(const double& x0, const double& x1,
00109                            const double& x2, const double& x3) const;
00110         Numeric operator()(const double& x0, const double& x1,
00111                            const double& x2, const double& x3,
00112                            const double& x4) const;
00114 
00116 
00117         inline unsigned dim() const {return dim_;}
00118         inline const std::vector<Axis>& axes() const {return axes_;}
00119         inline const Axis& axis(const unsigned i) const
00120             {return axes_.at(i);}
00121         inline unsigned long length() const {return data_.length();}
00122         bool leftInterpolationLinear(unsigned i) const;
00123         bool rightInterpolationLinear(unsigned i) const;
00124         std::vector<std::pair<bool,bool> > interpolationType() const;
00125         inline const std::string& functionLabel() const
00126             {return functionLabel_;}
00128 
00130 
00131         inline const ArrayND<Numeric>& table() const {return data_;}
00132         inline ArrayND<Numeric>& table() {return data_;}
00134 
00136         void getCoords(unsigned long linearIndex,
00137                        double* coords, unsigned coordsBufferSize) const;
00138 
00143         bool isUniformlyBinned() const;
00144 
00149         bool isWithinLimits(const double* point, unsigned dim) const;
00150 
00152         inline void setFunctionLabel(const char* newlabel)
00153             {functionLabel_ = newlabel ? newlabel : "";}
00154 
00161         template <typename ConvertibleToUnsigned>
00162         CPP11_auto_ptr<LinInterpolatedTableND> invertWRTAxis(
00163             ConvertibleToUnsigned axisNumber, const Axis& replacementAxis,
00164             bool newAxisLeftLinear, bool newAxisRightLinear,
00165             const char* functionLabel=0) const;
00166 
00189         template <class Functor1, class Functor2>
00190         CPP11_auto_ptr<LinInterpolatedTableND> invertRatioResponse(
00191             unsigned axisNumber, const Axis& replacementAxis,
00192             bool newAxisLeftLinear, bool newAxisRightLinear,
00193             Functor1 invg, Functor2 invh,
00194             const char* functionLabel=0) const;
00195 
00197         bool operator==(const LinInterpolatedTableND&) const;
00198 
00200         inline bool operator!=(const LinInterpolatedTableND& r) const
00201             {return !(*this == r);}
00202 
00204         // Method related to "geners" I/O
00205         inline gs::ClassId classId() const {return gs::ClassId(*this);}
00206         bool write(std::ostream& of) const;
00208 
00209         static const char* classname();
00210         static inline unsigned version() {return 1;}
00211         static LinInterpolatedTableND* read(
00212             const gs::ClassId& id, std::istream& in);
00213 
00214     private:
00215         LinInterpolatedTableND();
00216 
00217         LinInterpolatedTableND(
00218             const ArrayND<Numeric>& data,
00219             const std::vector<Axis>& axes,
00220             const char* leftInterpolation,
00221             const char* rightInterpolation,
00222             const std::string& label);
00223 
00224         bool allConstInterpolated() const;
00225 
00226         ArrayND<Numeric> data_;
00227         std::vector<Axis> axes_;
00228         std::string functionLabel_;
00229         char leftInterpolationLinear_[CHAR_BIT*sizeof(unsigned long)];
00230         char rightInterpolationLinear_[CHAR_BIT*sizeof(unsigned long)];
00231         unsigned dim_;
00232         bool allConstInterpolated_;
00233 
00234         template <class Functor1>
00235         static double solveForRatioArg(double xmin, double xmax,
00236                                        double rmin, double rmax,
00237                                        double fval, Functor1 invg);
00238 
00239         template <class Functor1>
00240         static void invert1DResponse(const ArrayND<Numeric>& fromSlice,
00241                                      const Axis& fromAxis, const Axis& toAxis,
00242                                      bool newLeftLinear, bool newRightLinear,
00243                                      Functor1 invg,
00244                                      const double* rawx, const double* rawf,
00245                                      double* workspace,
00246                                      ArrayND<Numeric>* toSlice);
00247     };
00248 }
00249 
00250 #include <cmath>
00251 #include <cfloat>
00252 #include <cassert>
00253 #include <algorithm>
00254 #include <functional>
00255 
00256 #include "Alignment/Geners/interface/binaryIO.hh"
00257 
00258 #include "JetMETCorrections/InterpolationTables/interface/ArrayNDScanner.h"
00259 #include "JetMETCorrections/InterpolationTables/interface/isMonotonous.h"
00260 
00261 namespace npstat {
00262     namespace Private {
00263         template <class Axis>
00264         ArrayShape makeTableShape(const std::vector<Axis>& axes)
00265         {
00266             const unsigned n = axes.size();
00267             ArrayShape result;
00268             result.reserve(n);
00269             for (unsigned i=0; i<n; ++i)
00270                 result.push_back(axes[i].nCoords());
00271             return result;
00272         }
00273 
00274         template <class Axis>
00275         ArrayShape makeTableShape(const Axis& xAxis)
00276         {
00277             ArrayShape result;
00278             result.reserve(1U);
00279             result.push_back(xAxis.nCoords());
00280             return result;
00281         }
00282 
00283         template <class Axis>
00284         ArrayShape makeTableShape(const Axis& xAxis, const Axis& yAxis)
00285         {
00286             ArrayShape result;
00287             result.reserve(2U);
00288             result.push_back(xAxis.nCoords());
00289             result.push_back(yAxis.nCoords());
00290             return result;
00291         }
00292 
00293         template <class Axis>
00294         ArrayShape makeTableShape(const Axis& xAxis,
00295                                   const Axis& yAxis,
00296                                   const Axis& zAxis)
00297         {
00298             ArrayShape result;
00299             result.reserve(3U);
00300             result.push_back(xAxis.nCoords());
00301             result.push_back(yAxis.nCoords());
00302             result.push_back(zAxis.nCoords());
00303             return result;
00304         }
00305 
00306         template <class Axis>
00307         ArrayShape makeTableShape(const Axis& xAxis, const Axis& yAxis,
00308                                   const Axis& zAxis, const Axis& tAxis)
00309         {
00310             ArrayShape result;
00311             result.reserve(4U);
00312             result.push_back(xAxis.nCoords());
00313             result.push_back(yAxis.nCoords());
00314             result.push_back(zAxis.nCoords());
00315             result.push_back(tAxis.nCoords());
00316             return result;
00317         }
00318 
00319         template <class Axis>
00320         ArrayShape makeTableShape(const Axis& xAxis, const Axis& yAxis,
00321                                   const Axis& zAxis, const Axis& tAxis,
00322                                   const Axis& vAxis)
00323         {
00324             ArrayShape result;
00325             result.reserve(5U);
00326             result.push_back(xAxis.nCoords());
00327             result.push_back(yAxis.nCoords());
00328             result.push_back(zAxis.nCoords());
00329             result.push_back(tAxis.nCoords());
00330             result.push_back(vAxis.nCoords());
00331             return result;
00332         }
00333 
00334         inline double lind_interpolateSimple(
00335             const double x0, const double x1,
00336             const double y0, const double y1,
00337             const double x)
00338         {
00339             return y0 + (y1 - y0)*((x - x0)/(x1 - x0));
00340         }
00341 
00342         template <typename Numeric, class Axis>
00343         void lind_invert1DSlice(
00344             const ArrayND<Numeric>& fromSlice,
00345             const Axis& fromAxis, const Axis& toAxis,
00346             const bool leftLinear, const bool rightLinear,
00347             ArrayND<Numeric>* toSlice)
00348         {
00349             assert(toSlice);
00350             assert(fromSlice.rank() == 1U);
00351             assert(toSlice->rank() == 1U);
00352 
00353             const Numeric* fromData = fromSlice.data();
00354             const unsigned fromLen = fromSlice.length();
00355             assert(fromLen > 1U);
00356             assert(fromLen == fromAxis.nCoords());
00357             const Numeric* fromDataEnd = fromData + fromLen;
00358             if (!isStrictlyMonotonous(fromData, fromDataEnd))
00359                 throw npstat::NpstatInvalidArgument(
00360                     "In npstat::Private::lind_invert1DSlice: "
00361                     "slice data is not monotonous and can not be inverted");
00362 
00363             const Numeric yfirst = fromData[0];
00364             const Numeric ylast = fromData[fromLen - 1U];
00365             const bool increasing = yfirst < ylast;
00366 
00367             Numeric* toD = const_cast<Numeric*>(toSlice->data());
00368             const unsigned nAxisPoints = toAxis.nCoords();
00369             assert(toSlice->length() == nAxisPoints);
00370 
00371             for (unsigned ipt=0; ipt<nAxisPoints; ++ipt)
00372             {
00373                 const Numeric y = static_cast<Numeric>(toAxis.coordinate(ipt));
00374                 if (increasing)
00375                 {
00376                     if (y <= yfirst)
00377                     {
00378                         if (leftLinear)
00379                             toD[ipt] = Private::lind_interpolateSimple(
00380                                 yfirst, fromData[1], fromAxis.coordinate(0),
00381                                 fromAxis.coordinate(1), y);
00382                         else
00383                             toD[ipt] = fromAxis.coordinate(0);
00384                     }
00385                     else if (y >= ylast)
00386                     {
00387                         if (rightLinear)
00388                             toD[ipt] = Private::lind_interpolateSimple(
00389                                 ylast, fromData[fromLen - 2U],
00390                                 fromAxis.coordinate(fromLen - 1U),
00391                                 fromAxis.coordinate(fromLen - 2U), y);
00392                         else
00393                             toD[ipt] = fromAxis.coordinate(fromLen - 1U);
00394                     }
00395                     else
00396                     {
00397                         const unsigned i = std::lower_bound(fromData,fromDataEnd,y)-
00398                             fromData;
00399                         toD[ipt] = Private::lind_interpolateSimple(
00400                             fromData[i-1U], fromData[i],
00401                             fromAxis.coordinate(i-1U),
00402                             fromAxis.coordinate(i), y);
00403                     }
00404                 }
00405                 else
00406                 {
00407                     // The role of left and right are exchanged
00408                     // with respect to first and last point
00409                     if (y <= ylast)
00410                     {
00411                         if (leftLinear)
00412                             toD[ipt] = Private::lind_interpolateSimple(
00413                                 ylast, fromData[fromLen - 2U],
00414                                 fromAxis.coordinate(fromLen - 1U),
00415                                 fromAxis.coordinate(fromLen - 2U), y);
00416                         else
00417                             toD[ipt] = fromAxis.coordinate(fromLen - 1U);
00418                     }
00419                     else if (y >= yfirst)
00420                     {
00421                         if (rightLinear)
00422                             toD[ipt] = Private::lind_interpolateSimple(
00423                                 yfirst, fromData[1],
00424                                 fromAxis.coordinate(0),
00425                                 fromAxis.coordinate(1), y);
00426                         else
00427                             toD[ipt] = fromAxis.coordinate(0);
00428                     }
00429                     else
00430                     {
00431                         const unsigned i = std::lower_bound(fromData,fromDataEnd,
00432                                              y,std::greater<Numeric>())-fromData;
00433                         toD[ipt] = Private::lind_interpolateSimple(
00434                             fromData[i-1U], fromData[i],
00435                             fromAxis.coordinate(i-1U),
00436                             fromAxis.coordinate(i), y);
00437                     }
00438                 }
00439             }
00440         }
00441     }
00442 
00443     template <class Numeric, class Axis>
00444     bool LinInterpolatedTableND<Numeric,Axis>::allConstInterpolated() const
00445     {
00446         for (unsigned i=0; i<dim_; ++i)
00447             if (leftInterpolationLinear_[i] || rightInterpolationLinear_[i])
00448                 return false;
00449         return true;
00450     }
00451 
00452     template <class Numeric, class Axis>
00453     bool LinInterpolatedTableND<Numeric,Axis>::operator==(
00454         const LinInterpolatedTableND& r) const
00455     {
00456         if (dim_ != r.dim_)
00457             return false;
00458         for (unsigned i=0; i<dim_; ++i)
00459         {
00460             if (leftInterpolationLinear_[i] != r.leftInterpolationLinear_[i])
00461                 return false;
00462             if (rightInterpolationLinear_[i] != r.rightInterpolationLinear_[i])
00463                 return false;
00464         }
00465         return data_ == r.data_ && 
00466                axes_ == r.axes_ &&
00467                functionLabel_ == r.functionLabel_;
00468     }
00469 
00470     template <typename Numeric, class Axis>
00471     const char* LinInterpolatedTableND<Numeric,Axis>::classname()
00472     {
00473         static const std::string myClass(gs::template_class_name<Numeric,Axis>(
00474                                            "npstat::LinInterpolatedTableND"));
00475         return myClass.c_str();
00476     }
00477 
00478     template<typename Numeric, class Axis>
00479     bool LinInterpolatedTableND<Numeric,Axis>::write(std::ostream& of) const
00480     {
00481         const bool status = data_.classId().write(of) &&
00482                             data_.write(of) &&
00483                             gs::write_obj_vector(of, axes_);
00484         if (status)
00485         {
00486             gs::write_pod_array(of, leftInterpolationLinear_, dim_);
00487             gs::write_pod_array(of, rightInterpolationLinear_, dim_);
00488             gs::write_pod(of, functionLabel_);
00489         }
00490         return status && !of.fail();
00491     }
00492 
00493     template<typename Numeric, class Axis>
00494     LinInterpolatedTableND<Numeric,Axis>*
00495     LinInterpolatedTableND<Numeric,Axis>::read(
00496         const gs::ClassId& id, std::istream& in)
00497     {
00498         static const gs::ClassId current(
00499             gs::ClassId::makeId<LinInterpolatedTableND<Numeric,Axis> >());
00500         current.ensureSameId(id);
00501 
00502         gs::ClassId ida(in, 1);
00503         ArrayND<Numeric> data;
00504         ArrayND<Numeric>::restore(ida, in, &data);
00505         std::vector<Axis> axes;
00506         gs::read_heap_obj_vector_as_placed(in, &axes);
00507         const unsigned dim = axes.size();
00508         if (dim > CHAR_BIT*sizeof(unsigned long) || data.rank() != dim)
00509             throw gs::IOInvalidData(
00510                 "In npstat::LinInterpolatedTableND::read: "
00511                 "read back invalid dimensionality");
00512         char leftInterpolation[CHAR_BIT*sizeof(unsigned long)];
00513         gs::read_pod_array(in, leftInterpolation, dim);
00514         char rightInterpolation[CHAR_BIT*sizeof(unsigned long)];
00515         gs::read_pod_array(in, rightInterpolation, dim);
00516         std::string label;
00517         gs::read_pod(in, &label);
00518         if (in.fail()) throw gs::IOReadFailure(
00519             "In npstat::LinInterpolatedTableND::read: input stream failure");
00520         return new LinInterpolatedTableND(
00521             data, axes, leftInterpolation, rightInterpolation, label);
00522     }
00523 
00524     template<typename Numeric, class Axis>
00525     bool LinInterpolatedTableND<Numeric,Axis>::leftInterpolationLinear(
00526         const unsigned i) const
00527     {
00528         if (i >= dim_) throw npstat::NpstatOutOfRange(
00529             "In npstat::LinInterpolatedTableND::leftInterpolationLinear: "
00530             "index out of range");
00531         return leftInterpolationLinear_[i];
00532     }
00533 
00534     template<typename Numeric, class Axis>
00535     bool LinInterpolatedTableND<Numeric,Axis>::rightInterpolationLinear(
00536         const unsigned i) const
00537     {
00538         if (i >= dim_) throw npstat::NpstatOutOfRange(
00539             "In npstat::LinInterpolatedTableND::rightInterpolationLinear: "
00540             "index out of range");
00541         return rightInterpolationLinear_[i];
00542     }
00543 
00544     template<typename Numeric, class Axis>
00545     bool LinInterpolatedTableND<Numeric,Axis>::isUniformlyBinned() const
00546     {
00547         for (unsigned i=0; i<dim_; ++i)
00548             if (!axes_[i].isUniform())
00549                 return false;
00550         return true;
00551     }
00552 
00553     template<typename Numeric, class Axis>
00554     std::vector<std::pair<bool,bool> >
00555     LinInterpolatedTableND<Numeric,Axis>::interpolationType() const
00556     {
00557         std::vector<std::pair<bool,bool> > vec;
00558         vec.reserve(dim_);
00559         for (unsigned i=0; i<dim_; ++i)
00560             vec.push_back(std::pair<bool, bool>(leftInterpolationLinear_[i],
00561                                                 rightInterpolationLinear_[i]));
00562         return vec;
00563     }
00564 
00565     template<typename Numeric, class Axis>
00566     LinInterpolatedTableND<Numeric,Axis>::LinInterpolatedTableND(
00567         const std::vector<Axis>& axes,
00568         const std::vector<std::pair<bool,bool> >& interpolationType,
00569         const char* label)
00570         : data_(Private::makeTableShape(axes)),
00571           axes_(axes),
00572           functionLabel_(label ? label : ""),
00573           dim_(axes.size())
00574     {
00575         if (dim_ == 0 || dim_ >= CHAR_BIT*sizeof(unsigned long))
00576             throw npstat::NpstatInvalidArgument(
00577                 "In npstat::LinInterpolatedTableND constructor: requested "
00578                 "table dimensionality is not supported");
00579         if (dim_ != interpolationType.size())
00580             throw npstat::NpstatInvalidArgument(
00581                 "In npstat::LinInterpolatedTableND constructor: "
00582                 "incompatible number of interpolation specifications");
00583         for (unsigned i=0; i<dim_; ++i)
00584         {
00585             const std::pair<bool,bool>& pair(interpolationType[i]);
00586             leftInterpolationLinear_[i] = pair.first;
00587             rightInterpolationLinear_[i] = pair.second;
00588         }
00589 
00590         allConstInterpolated_ = allConstInterpolated();
00591     }
00592 
00593     template<typename Numeric, class Axis>
00594     template <class Num2>
00595     LinInterpolatedTableND<Numeric,Axis>::LinInterpolatedTableND(
00596         const LinInterpolatedTableND<Num2,Axis>& r)
00597         : data_(r.data_),
00598           axes_(r.axes_),
00599           functionLabel_(r.functionLabel_),
00600           dim_(r.dim_),
00601           allConstInterpolated_(r.allConstInterpolated_)
00602     {
00603         for (unsigned i=0; i<dim_; ++i)
00604         {
00605             leftInterpolationLinear_[i] = r.leftInterpolationLinear_[i];
00606             rightInterpolationLinear_[i] = r.rightInterpolationLinear_[i];
00607         }
00608     }
00609 
00610     template<typename Numeric, class Axis>
00611     LinInterpolatedTableND<Numeric,Axis>::LinInterpolatedTableND(
00612         const ArrayND<Numeric>& data,
00613         const std::vector<Axis>& axes,
00614         const char* leftInterpolation,
00615         const char* rightInterpolation,
00616         const std::string& label)
00617         : data_(data),
00618           axes_(axes),
00619           functionLabel_(label),
00620           dim_(data.rank())
00621     {
00622         for (unsigned i=0; i<dim_; ++i)
00623         {
00624             leftInterpolationLinear_[i] = leftInterpolation[i];
00625             rightInterpolationLinear_[i] = rightInterpolation[i];
00626         }
00627         allConstInterpolated_ = allConstInterpolated();
00628     }
00629 
00630     template<typename Numeric, class Axis>
00631     LinInterpolatedTableND<Numeric,Axis>::LinInterpolatedTableND(
00632         const Axis& xAxis, bool leftX, bool rightX,
00633         const Axis& yAxis, bool leftY, bool rightY,
00634         const Axis& zAxis, bool leftZ, bool rightZ,
00635         const Axis& tAxis, bool leftT, bool rightT,
00636         const Axis& vAxis, bool leftV, bool rightV,
00637         const char* label)
00638         : data_(Private::makeTableShape(xAxis, yAxis, zAxis, tAxis, vAxis)),
00639           functionLabel_(label ? label : ""),
00640           dim_(5U)
00641     {
00642         axes_.reserve(dim_);
00643         axes_.push_back(xAxis);
00644         axes_.push_back(yAxis);
00645         axes_.push_back(zAxis);
00646         axes_.push_back(tAxis);
00647         axes_.push_back(vAxis);
00648 
00649         unsigned i = 0;
00650         leftInterpolationLinear_[i] = leftX;
00651         rightInterpolationLinear_[i++] = rightX;
00652         leftInterpolationLinear_[i] = leftY;
00653         rightInterpolationLinear_[i++] = rightY;
00654         leftInterpolationLinear_[i] = leftZ;
00655         rightInterpolationLinear_[i++] = rightZ;
00656         leftInterpolationLinear_[i] = leftT;
00657         rightInterpolationLinear_[i++] = rightT;
00658         leftInterpolationLinear_[i] = leftV;
00659         rightInterpolationLinear_[i++] = rightV;
00660         assert(i == dim_);
00661 
00662         allConstInterpolated_ = allConstInterpolated();
00663     }
00664 
00665     template<typename Numeric, class Axis>
00666     LinInterpolatedTableND<Numeric,Axis>::LinInterpolatedTableND(
00667         const Axis& xAxis, bool leftX, bool rightX,
00668         const Axis& yAxis, bool leftY, bool rightY,
00669         const Axis& zAxis, bool leftZ, bool rightZ,
00670         const Axis& tAxis, bool leftT, bool rightT,
00671         const char* label)
00672         : data_(Private::makeTableShape(xAxis, yAxis, zAxis, tAxis)),
00673           functionLabel_(label ? label : ""),
00674           dim_(4U)
00675     {
00676         axes_.reserve(dim_);
00677         axes_.push_back(xAxis);
00678         axes_.push_back(yAxis);
00679         axes_.push_back(zAxis);
00680         axes_.push_back(tAxis);
00681 
00682         unsigned i = 0;
00683         leftInterpolationLinear_[i] = leftX;
00684         rightInterpolationLinear_[i++] = rightX;
00685         leftInterpolationLinear_[i] = leftY;
00686         rightInterpolationLinear_[i++] = rightY;
00687         leftInterpolationLinear_[i] = leftZ;
00688         rightInterpolationLinear_[i++] = rightZ;
00689         leftInterpolationLinear_[i] = leftT;
00690         rightInterpolationLinear_[i++] = rightT;
00691         assert(i == dim_);
00692 
00693         allConstInterpolated_ = allConstInterpolated();
00694     }
00695 
00696     template<typename Numeric, class Axis>
00697     LinInterpolatedTableND<Numeric,Axis>::LinInterpolatedTableND(
00698         const Axis& xAxis, bool leftX, bool rightX,
00699         const Axis& yAxis, bool leftY, bool rightY,
00700         const Axis& zAxis, bool leftZ, bool rightZ,
00701         const char* label)
00702         : data_(Private::makeTableShape(xAxis, yAxis, zAxis)),
00703           functionLabel_(label ? label : ""),
00704           dim_(3U)
00705     {
00706         axes_.reserve(dim_);
00707         axes_.push_back(xAxis);
00708         axes_.push_back(yAxis);
00709         axes_.push_back(zAxis);
00710 
00711         unsigned i = 0;
00712         leftInterpolationLinear_[i] = leftX;
00713         rightInterpolationLinear_[i++] = rightX;
00714         leftInterpolationLinear_[i] = leftY;
00715         rightInterpolationLinear_[i++] = rightY;
00716         leftInterpolationLinear_[i] = leftZ;
00717         rightInterpolationLinear_[i++] = rightZ;
00718         assert(i == dim_);
00719 
00720         allConstInterpolated_ = allConstInterpolated();
00721     }
00722 
00723     template<typename Numeric, class Axis>
00724     LinInterpolatedTableND<Numeric,Axis>::LinInterpolatedTableND(
00725         const Axis& xAxis, bool leftX, bool rightX,
00726         const Axis& yAxis, bool leftY, bool rightY,
00727         const char* label)
00728         : data_(Private::makeTableShape(xAxis, yAxis)),
00729           functionLabel_(label ? label : ""),
00730           dim_(2U)
00731     {
00732         axes_.reserve(dim_);
00733         axes_.push_back(xAxis);
00734         axes_.push_back(yAxis);
00735 
00736         unsigned i = 0;
00737         leftInterpolationLinear_[i] = leftX;
00738         rightInterpolationLinear_[i++] = rightX;
00739         leftInterpolationLinear_[i] = leftY;
00740         rightInterpolationLinear_[i++] = rightY;
00741         assert(i == dim_);
00742 
00743         allConstInterpolated_ = allConstInterpolated();
00744     }
00745 
00746     template<typename Numeric, class Axis>
00747     LinInterpolatedTableND<Numeric,Axis>::LinInterpolatedTableND(
00748         const Axis& xAxis, bool leftX, bool rightX,
00749         const char* label)
00750         : data_(Private::makeTableShape(xAxis)),
00751           functionLabel_(label ? label : ""),
00752           dim_(1U)
00753     {
00754         axes_.reserve(dim_);
00755         axes_.push_back(xAxis);
00756 
00757         leftInterpolationLinear_[0] = leftX;
00758         rightInterpolationLinear_[0] = rightX;
00759 
00760         allConstInterpolated_ = allConstInterpolated();
00761     }
00762 
00763     template<typename Numeric, class Axis>
00764     template <typename ConvertibleToUnsigned>
00765     CPP11_auto_ptr<LinInterpolatedTableND<Numeric,Axis> > 
00766     LinInterpolatedTableND<Numeric,Axis>::invertWRTAxis(
00767         const ConvertibleToUnsigned axisNumC, const Axis& replacementAxis,
00768         const bool leftLinear, const bool rightLinear,
00769         const char* functionLabel) const
00770     {
00771         const unsigned axisNumber = static_cast<unsigned>(axisNumC);
00772 
00773         if (axisNumber >= dim_)
00774             throw npstat::NpstatOutOfRange(
00775                 "In npstat::LinInterpolatedTableND::invertAxis: "
00776                 "axis number is out of range");
00777 
00778         // Generate the new set of axes
00779         std::vector<Axis> newAxes(axes_);
00780         newAxes[axisNumber] = replacementAxis;
00781 
00782         std::vector<std::pair<bool,bool> > iType(interpolationType());
00783         iType[axisNumber] = std::pair<bool,bool>(leftLinear, rightLinear);
00784 
00785         // Create the new table
00786         CPP11_auto_ptr<LinInterpolatedTableND> pTable(
00787             new LinInterpolatedTableND(newAxes, iType, functionLabel));
00788 
00789         if (dim_ > 1U)
00790         {
00791             // Prepare array slices
00792             unsigned sliceIndex[CHAR_BIT*sizeof(unsigned long)];
00793             unsigned fixedIndices[CHAR_BIT*sizeof(unsigned long)];
00794             unsigned count = 0;
00795             for (unsigned i=0; i<dim_; ++i)
00796                 if (i != axisNumber)
00797                 {
00798                     sliceIndex[count] = data_.span(i);
00799                     fixedIndices[count++] = i;
00800                 }
00801             ArrayND<Numeric> parentSlice(data_, fixedIndices, count);
00802             ArrayND<Numeric> dauSlice(pTable->data_, fixedIndices, count);
00803 
00804             // Cycle over the slices
00805             for (ArrayNDScanner scan(sliceIndex,count); scan.isValid(); ++scan)
00806             {
00807                 scan.getIndex(sliceIndex, count);
00808                 data_.exportSlice(&parentSlice, fixedIndices,
00809                                   sliceIndex, count);
00810                 Private::lind_invert1DSlice(
00811                     parentSlice, axes_[axisNumber], replacementAxis,
00812                     leftLinear, rightLinear, &dauSlice);
00813                 pTable->data_.importSlice(dauSlice, fixedIndices,
00814                                           sliceIndex, count);
00815             }
00816         }
00817         else
00818             Private::lind_invert1DSlice(
00819                 data_, axes_[0], replacementAxis,
00820                 leftLinear, rightLinear, &pTable->data_);
00821         return pTable;
00822     }
00823 
00824     template<typename Numeric, class Axis>
00825     template <class Functor1, class Functor2>
00826     CPP11_auto_ptr<LinInterpolatedTableND<Numeric,Axis> > 
00827     LinInterpolatedTableND<Numeric,Axis>::invertRatioResponse(
00828         const unsigned axisNumber, const Axis& replacementAxis,
00829         const bool leftLinear, const bool rightLinear,
00830         Functor1 invg, Functor2 invh,
00831         const char* functionLabel) const
00832     {
00833         if (axisNumber >= dim_)
00834             throw npstat::NpstatOutOfRange(
00835                 "In npstat::LinInterpolatedTableND::invertRatioResponse: "
00836                 "axis number is out of range");
00837 
00838         // Generate the new set of axes
00839         std::vector<Axis> newAxes(axes_);
00840         newAxes[axisNumber] = replacementAxis;
00841 
00842         std::vector<std::pair<bool,bool> > iType(interpolationType());
00843         iType[axisNumber] = std::pair<bool,bool>(leftLinear, rightLinear);
00844 
00845         // Transform the original axis to the raw x values
00846         const Axis& oldAxis(axes_[axisNumber]);
00847         std::vector<double> rawx;
00848         const unsigned nCoords = oldAxis.nCoords();
00849         rawx.reserve(nCoords);
00850         for (unsigned i=0; i<nCoords; ++i)
00851         {
00852             const double x = invg(oldAxis.coordinate(i));
00853             if (x < 0.0)
00854                 throw npstat::NpstatInvalidArgument(
00855                     "In npstat::LinInterpolatedTableND::invertRatioResponse: "
00856                     "invalid original axis definition (negative transformed "
00857                     "coordinate)");
00858             rawx.push_back(x);
00859         }
00860 
00861         // Transform the new axis to the raw f(x) values
00862         std::vector<double> rawf;
00863         const unsigned nFuncs = replacementAxis.nCoords();
00864         rawf.reserve(nFuncs);
00865         for (unsigned i=0; i<nFuncs; ++i)
00866         {
00867             const double f = invh(replacementAxis.coordinate(i));
00868             if (f < 0.0)
00869                 throw npstat::NpstatInvalidArgument(
00870                     "In npstat::LinInterpolatedTableND::invertRatioResponse: "
00871                     "invalid new axis definition (negative transformed "
00872                     "coordinate)");
00873             rawf.push_back(f);
00874         }
00875 
00876         // Workspace needed for the inversion code
00877         std::vector<double> workspace(nCoords);
00878 
00879         // Create the new table
00880         CPP11_auto_ptr<LinInterpolatedTableND> pTable(
00881             new LinInterpolatedTableND(newAxes, iType, functionLabel));
00882 
00883         if (dim_ > 1U)
00884         {
00885             // Prepare array slices
00886             unsigned sliceIndex[CHAR_BIT*sizeof(unsigned long)];
00887             unsigned fixedIndices[CHAR_BIT*sizeof(unsigned long)];
00888             unsigned count = 0;
00889             for (unsigned i=0; i<dim_; ++i)
00890                 if (i != axisNumber)
00891                 {
00892                     sliceIndex[count] = data_.span(i);
00893                     fixedIndices[count++] = i;
00894                 }
00895             ArrayND<Numeric> parentSlice(data_, fixedIndices, count);
00896             ArrayND<Numeric> dauSlice(pTable->data_, fixedIndices, count);
00897 
00898             // Cycle over the slices
00899             for (ArrayNDScanner scan(sliceIndex,count); scan.isValid(); ++scan)
00900             {
00901                 scan.getIndex(sliceIndex, count);
00902                 data_.exportSlice(&parentSlice, fixedIndices,
00903                                   sliceIndex, count);
00904                 invert1DResponse(parentSlice, oldAxis,
00905                                  replacementAxis, leftLinear, rightLinear,
00906                                  invg, &rawx[0], &rawf[0], &workspace[0],
00907                                  &dauSlice);
00908                 pTable->data_.importSlice(dauSlice, fixedIndices,
00909                                           sliceIndex, count);
00910             }
00911         }
00912         else
00913             invert1DResponse(data_, oldAxis, replacementAxis, leftLinear,
00914                              rightLinear, invg, &rawx[0], &rawf[0],
00915                              &workspace[0], &pTable->data_);
00916         return pTable;
00917     }
00918 
00919     template<typename Numeric, class Axis>
00920     void LinInterpolatedTableND<Numeric,Axis>::getCoords(
00921         const unsigned long linearIndex,
00922         double* coords, const unsigned coordsBufferSize) const
00923     {
00924         if (coordsBufferSize < dim_) throw npstat::NpstatInvalidArgument(
00925             "In LinInterpolatedTableND::getCoords: "
00926             "insufficient buffer size");
00927         assert(coords);
00928         unsigned index[CHAR_BIT*sizeof(unsigned long)];
00929         data_.convertLinearIndex(linearIndex, index, dim_);
00930         for (unsigned i=0; i<dim_; ++i)
00931             coords[i] = axes_[i].coordinate(index[i]);
00932     }
00933 
00934     template<typename Numeric, class Axis>
00935     bool LinInterpolatedTableND<Numeric,Axis>::isWithinLimits(
00936         const double* point, const unsigned len) const
00937     {
00938         if (len != dim_)
00939             throw npstat::NpstatInvalidArgument(
00940                 "In npstat::LinInterpolatedTableND::isWithinLimits: "
00941                 "incompatible point dimensionality");
00942         assert(point);
00943 
00944         for (unsigned i=0; i<dim_; ++i)
00945             if (point[i] < axes_[i].min() || point[i] > axes_[i].max())
00946                 return false;
00947         return true;
00948     }
00949 
00950     template<typename Numeric, class Axis>
00951     Numeric LinInterpolatedTableND<Numeric,Axis>::operator()(
00952         const double* point, const unsigned len) const
00953     {
00954         typedef typename ProperDblFromCmpl<Numeric>::type proper_double;
00955 
00956         if (len != dim_)
00957             throw npstat::NpstatInvalidArgument(
00958                 "In npstat::LinInterpolatedTableND::operator(): "
00959                 "incompatible point dimensionality");
00960         assert(point);
00961 
00962         bool interpolateArray = true;
00963         if (!allConstInterpolated_)
00964             for (unsigned i=0; i<dim_; ++i)
00965                 if ((leftInterpolationLinear_[i] && point[i] < axes_[i].min()) ||
00966                     (rightInterpolationLinear_[i] && point[i] > axes_[i].max()))
00967                 {
00968                     interpolateArray = false;
00969                     break;
00970                 }
00971 
00972         if (interpolateArray)
00973         {
00974             // Translate coordinates into the array system and
00975             // simply use the ArrayND interpolation facilities
00976             double buf[CHAR_BIT*sizeof(unsigned long)];
00977             for (unsigned i=0; i<dim_; ++i)
00978             {
00979                 const std::pair<unsigned,double>& pair = 
00980                     axes_[i].getInterval(point[i]);
00981                 buf[i] = pair.first + 1U - pair.second;
00982             }
00983             return data_.interpolate1(buf, dim_);
00984         }
00985         else
00986         {
00987             unsigned ix[CHAR_BIT*sizeof(unsigned long)];
00988             double weight[CHAR_BIT*sizeof(unsigned long)];
00989             for (unsigned i=0; i<dim_; ++i)
00990             {
00991                 const bool linear = (leftInterpolationLinear_[i] && 
00992                                      point[i] < axes_[i].min()) ||
00993                                     (rightInterpolationLinear_[i] && 
00994                                      point[i] > axes_[i].max());
00995                 const std::pair<unsigned,double>& pair = linear ?
00996                     axes_[i].linearInterval(point[i]) :
00997                     axes_[i].getInterval(point[i]);
00998                 ix[i] = pair.first;
00999                 weight[i] = pair.second;
01000             }
01001 
01002             Numeric sum = Numeric();
01003             const unsigned long maxcycle = 1UL << dim_;
01004             const unsigned long* strides = data_.strides();
01005             const Numeric* dat = data_.data();
01006             for (unsigned long icycle=0UL; icycle<maxcycle; ++icycle)
01007             {
01008                 double w = 1.0;
01009                 unsigned long icell = 0UL;
01010                 for (unsigned i=0; i<dim_; ++i)
01011                 {
01012                     if (icycle & (1UL << i))
01013                     {
01014                         w *= (1.0 - weight[i]);
01015                         icell += strides[i]*(ix[i] + 1U);
01016                     }
01017                     else
01018                     {
01019                         w *= weight[i];
01020                         icell += strides[i]*ix[i];
01021                     }
01022                 }
01023                 sum += dat[icell]*static_cast<proper_double>(w);
01024             }
01025             return sum;
01026         }
01027     }
01028 
01029     template<typename Numeric, class Axis>
01030     Numeric LinInterpolatedTableND<Numeric,Axis>::operator()(
01031         const double& x0) const
01032     {
01033         const unsigned nArgs = 1U;
01034         if (dim_ != nArgs) throw npstat::NpstatInvalidArgument(
01035             "In npstat::LinInterpolatedTableND::operator(): number of "
01036             "arguments, 1, is incompatible with the interpolator dimensionality");
01037         double tmp[nArgs];
01038         tmp[0] = x0;
01039         return operator()(tmp, nArgs);
01040     }
01041 
01042     template<typename Numeric, class Axis>
01043     Numeric LinInterpolatedTableND<Numeric,Axis>::operator()(
01044         const double& x0, const double& x1) const
01045     {
01046         const unsigned nArgs = 2U;
01047         if (dim_ != nArgs) throw npstat::NpstatInvalidArgument(
01048             "In npstat::LinInterpolatedTableND::operator(): number of "
01049             "arguments, 2, is incompatible with the interpolator dimensionality");
01050         double tmp[nArgs];
01051         tmp[0] = x0;
01052         tmp[1] = x1;
01053         return operator()(tmp, nArgs);
01054     }
01055 
01056     template<typename Numeric, class Axis>
01057     Numeric LinInterpolatedTableND<Numeric,Axis>::operator()(
01058         const double& x0, const double& x1, const double& x2) const
01059     {
01060         const unsigned nArgs = 3U;
01061         if (dim_ != nArgs) throw npstat::NpstatInvalidArgument(
01062             "In npstat::LinInterpolatedTableND::operator(): number of "
01063             "arguments, 3, is incompatible with the interpolator dimensionality");
01064         double tmp[nArgs];
01065         tmp[0] = x0;
01066         tmp[1] = x1;
01067         tmp[2] = x2;
01068         return operator()(tmp, nArgs);
01069     }
01070 
01071     template<typename Numeric, class Axis>
01072     Numeric LinInterpolatedTableND<Numeric,Axis>::operator()(
01073         const double& x0, const double& x1,
01074         const double& x2, const double& x3) const
01075     {
01076         const unsigned nArgs = 4U;
01077         if (dim_ != nArgs) throw npstat::NpstatInvalidArgument(
01078             "In npstat::LinInterpolatedTableND::operator(): number of "
01079             "arguments, 4, is incompatible with the interpolator dimensionality");
01080         double tmp[nArgs];
01081         tmp[0] = x0;
01082         tmp[1] = x1;
01083         tmp[2] = x2;
01084         tmp[3] = x3;
01085         return operator()(tmp, nArgs);
01086     }
01087 
01088     template<typename Numeric, class Axis>
01089     Numeric LinInterpolatedTableND<Numeric,Axis>::operator()(
01090         const double& x0, const double& x1, const double& x2,
01091         const double& x3, const double& x4) const
01092     {
01093         const unsigned nArgs = 5U;
01094         if (dim_ != nArgs) throw npstat::NpstatInvalidArgument(
01095             "In npstat::LinInterpolatedTableND::operator(): number of "
01096             "arguments, 5, is incompatible with the interpolator dimensionality");
01097         double tmp[nArgs];
01098         tmp[0] = x0;
01099         tmp[1] = x1;
01100         tmp[2] = x2;
01101         tmp[3] = x3;
01102         tmp[4] = x4;
01103         return operator()(tmp, nArgs);
01104     }
01105 
01106     template<typename Numeric, class Axis>
01107     template <class Functor1>
01108     double LinInterpolatedTableND<Numeric,Axis>::solveForRatioArg(
01109         const double xmin, const double xmax,
01110         const double rmin, const double rmax,
01111         const double fval, Functor1 invg)
01112     {
01113         // Find two values of x so that f(x0) <= fval <= f(x1)
01114         double x0 = xmin;
01115         double x1 = xmax;
01116         double fmin = invg(xmin)*rmin;
01117         double fmax = invg(xmax)*rmax;
01118         const double step = xmax - xmin;
01119         assert(fmin < fmax);
01120         assert(step > 0.0);
01121 
01122         unsigned stepcount = 0;
01123         const unsigned maxSteps = 1000U;
01124         for (double stepfactor = 1.0; (fval < fmin || fval > fmax) &&
01125                  stepcount < maxSteps; stepfactor *= 2.0, ++stepcount)
01126             if (fval < fmin)
01127             {
01128                 x1 = x0;
01129                 fmax = fmin;
01130                 x0 -= stepfactor*step;
01131                 fmin = invg(x0)*Private::lind_interpolateSimple(
01132                     xmin, xmax, rmin, rmax, x0);
01133             }
01134             else
01135             {
01136                 x0 = x1;
01137                 fmin = fmax;
01138                 x1 += stepfactor*step;
01139                 fmax = invg(x1)*Private::lind_interpolateSimple(
01140                     xmin, xmax, rmin, rmax, x1);
01141             }
01142         if (stepcount == maxSteps) throw npstat::NpstatRuntimeError(
01143             "In LinInterpolatedTableND::solveForRatioArg: "
01144             "faled to bracket the root");
01145 
01146         assert(x1 >= x0);
01147         while ((x1 - x0)/(std::abs(x1) + std::abs(x0) + DBL_EPSILON) > 4.0*DBL_EPSILON)
01148         {
01149             const double xhalf = (x1 + x0)/2.0;
01150             const double fhalf = invg(xhalf)*Private::lind_interpolateSimple(
01151                 xmin, xmax, rmin, rmax, xhalf);
01152             if (fval < fhalf)
01153             {
01154                 x1 = xhalf;
01155                 fmax = fhalf;
01156             }
01157             else
01158             {
01159                 x0 = xhalf;
01160                 fmin = fhalf;
01161             }    
01162         }
01163         return (x1 + x0)/2.0;
01164     }
01165 
01166     template<typename Numeric, class Axis>
01167     template <class Functor1>
01168     void LinInterpolatedTableND<Numeric,Axis>::invert1DResponse(
01169         const ArrayND<Numeric>& fromSlice,
01170         const Axis& fromAxis, const Axis& toAxis,
01171         const bool newLeftLinear, const bool newRightLinear,
01172         Functor1 invg, const double* rawx, const double* rawf,
01173         double* workspace,
01174         ArrayND<Numeric>* toSlice)
01175     {
01176         assert(toSlice);
01177         assert(fromSlice.rank() == 1U);
01178         assert(toSlice->rank() == 1U);
01179 
01180         const Numeric zero = Numeric();
01181         const Numeric* fromData = fromSlice.data();
01182         const unsigned fromLen = fromSlice.length();
01183         assert(fromLen > 1U);
01184         assert(fromLen == fromAxis.nCoords());
01185         Numeric* toD = const_cast<Numeric*>(toSlice->data());
01186         const unsigned nAxisPoints = toAxis.nCoords();
01187         assert(toSlice->length() == nAxisPoints);
01188 
01189         for (unsigned i=0; i<fromLen; ++i)
01190         {
01191             if (fromData[i] <= zero) throw npstat::NpstatDomainError(
01192                 "In LinInterpolatedTableND::invert1DResponse: "
01193                 "non-positive response found. This ratio "
01194                 "response table is not invertible.");
01195             workspace[i] = rawx[i]*fromData[i];
01196         }
01197 
01198         const double yfirst = workspace[0];
01199         const double ylast = workspace[fromLen - 1U];
01200 
01201         bool adjustZero = false;
01202         unsigned nBelow = 0;
01203         for (unsigned ipt=0; ipt<nAxisPoints; ++ipt)
01204         {
01205             const double y = rawf[ipt];
01206             unsigned i0 = 0;
01207             bool solve = false;
01208             if (y == 0.0)
01209             {
01210                 assert(ipt == 0U);
01211                 if (newLeftLinear)
01212                     adjustZero = true;
01213             }
01214             else if (y <= yfirst)
01215             {
01216                 ++nBelow;
01217                 solve = newLeftLinear;
01218             }
01219             else if (y >= ylast)
01220             {
01221                 solve = newRightLinear;
01222                 i0 = solve ? fromLen-2 : fromLen-1;
01223             }
01224             else
01225             {
01226                 solve = true;
01227                 i0 = static_cast<unsigned>(std::lower_bound(
01228                          workspace,workspace+fromLen,y) - workspace) - 1U;
01229             }
01230             if (solve)
01231             {
01232                 const double x = solveForRatioArg(fromAxis.coordinate(i0),
01233                                                   fromAxis.coordinate(i0+1),
01234                                                   fromData[i0], fromData[i0+1],
01235                                                   y, invg);
01236                 toD[ipt] = invg(x)/y;
01237             }
01238             else
01239                 toD[ipt] = 1.0/fromData[i0];
01240         }
01241         if (adjustZero && nBelow)
01242             toD[0] = toD[1];
01243     }
01244 }
01245 
01246 
01247 #endif // NPSTAT_LININTERPOLATEDTABLEND_HH_
01248