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
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
00408
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
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
00786 CPP11_auto_ptr<LinInterpolatedTableND> pTable(
00787 new LinInterpolatedTableND(newAxes, iType, functionLabel));
00788
00789 if (dim_ > 1U)
00790 {
00791
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
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
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
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
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
00877 std::vector<double> workspace(nCoords);
00878
00879
00880 CPP11_auto_ptr<LinInterpolatedTableND> pTable(
00881 new LinInterpolatedTableND(newAxes, iType, functionLabel));
00882
00883 if (dim_ > 1U)
00884 {
00885
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
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
00975
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
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