File indexing completed on 2024-04-06 12:19:22
0001 #ifndef NPSTAT_LININTERPOLATEDTABLEND_HH_
0002 #define NPSTAT_LININTERPOLATEDTABLEND_HH_
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include <climits>
0015 #include <vector>
0016 #include <utility>
0017
0018 #include <memory>
0019
0020 #include "JetMETCorrections/InterpolationTables/interface/ArrayND.h"
0021 #include "JetMETCorrections/InterpolationTables/interface/UniformAxis.h"
0022
0023 namespace npstat {
0024
0025
0026
0027
0028
0029
0030 template <class Numeric, class Axis = UniformAxis>
0031 class LinInterpolatedTableND {
0032 template <typename Num2, typename Axis2>
0033 friend class LinInterpolatedTableND;
0034
0035 public:
0036 typedef Numeric value_type;
0037 typedef Axis axis_type;
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053 LinInterpolatedTableND(const std::vector<Axis>& axes,
0054 const std::vector<std::pair<bool, bool> >& extrapolationType,
0055 const char* functionLabel = nullptr);
0056
0057
0058 LinInterpolatedTableND(const Axis& xAxis, bool leftX, bool rightX, const char* functionLabel = nullptr);
0059
0060
0061 LinInterpolatedTableND(const Axis& xAxis,
0062 bool leftX,
0063 bool rightX,
0064 const Axis& yAxis,
0065 bool leftY,
0066 bool rightY,
0067 const char* functionLabel = nullptr);
0068
0069
0070 LinInterpolatedTableND(const Axis& xAxis,
0071 bool leftX,
0072 bool rightX,
0073 const Axis& yAxis,
0074 bool leftY,
0075 bool rightY,
0076 const Axis& zAxis,
0077 bool leftZ,
0078 bool rightZ,
0079 const char* functionLabel = nullptr);
0080
0081
0082 LinInterpolatedTableND(const Axis& xAxis,
0083 bool leftX,
0084 bool rightX,
0085 const Axis& yAxis,
0086 bool leftY,
0087 bool rightY,
0088 const Axis& zAxis,
0089 bool leftZ,
0090 bool rightZ,
0091 const Axis& tAxis,
0092 bool leftT,
0093 bool rightT,
0094 const char* functionLabel = nullptr);
0095
0096
0097 LinInterpolatedTableND(const Axis& xAxis,
0098 bool leftX,
0099 bool rightX,
0100 const Axis& yAxis,
0101 bool leftY,
0102 bool rightY,
0103 const Axis& zAxis,
0104 bool leftZ,
0105 bool rightZ,
0106 const Axis& tAxis,
0107 bool leftT,
0108 bool rightT,
0109 const Axis& vAxis,
0110 bool leftV,
0111 bool rightV,
0112 const char* functionLabel = nullptr);
0113
0114
0115
0116
0117
0118 template <class Num2>
0119 LinInterpolatedTableND(const LinInterpolatedTableND<Num2, Axis>&);
0120
0121
0122 LinInterpolatedTableND() = delete;
0123
0124
0125
0126
0127
0128 Numeric operator()(const double* point, unsigned dim) const;
0129
0130
0131
0132 Numeric operator()(const double& x0) const;
0133 Numeric operator()(const double& x0, const double& x1) const;
0134 Numeric operator()(const double& x0, const double& x1, const double& x2) const;
0135 Numeric operator()(const double& x0, const double& x1, const double& x2, const double& x3) const;
0136 Numeric operator()(const double& x0, const double& x1, const double& x2, const double& x3, const double& x4) const;
0137
0138
0139
0140
0141 inline unsigned dim() const { return dim_; }
0142 inline const std::vector<Axis>& axes() const { return axes_; }
0143 inline const Axis& axis(const unsigned i) const { return axes_.at(i); }
0144 inline unsigned long length() const { return data_.length(); }
0145 bool leftInterpolationLinear(unsigned i) const;
0146 bool rightInterpolationLinear(unsigned i) const;
0147 std::vector<std::pair<bool, bool> > interpolationType() const;
0148 inline const std::string& functionLabel() const { return functionLabel_; }
0149
0150
0151
0152
0153 inline const ArrayND<Numeric>& table() const { return data_; }
0154 inline ArrayND<Numeric>& table() { return data_; }
0155
0156
0157
0158 void getCoords(unsigned long linearIndex, double* coords, unsigned coordsBufferSize) const;
0159
0160
0161
0162
0163
0164 bool isUniformlyBinned() const;
0165
0166
0167
0168
0169
0170 bool isWithinLimits(const double* point, unsigned dim) const;
0171
0172
0173 inline void setFunctionLabel(const char* newlabel) { functionLabel_ = newlabel ? newlabel : ""; }
0174
0175
0176
0177
0178
0179
0180
0181 template <typename ConvertibleToUnsigned>
0182 std::unique_ptr<LinInterpolatedTableND> invertWRTAxis(ConvertibleToUnsigned axisNumber,
0183 const Axis& replacementAxis,
0184 bool newAxisLeftLinear,
0185 bool newAxisRightLinear,
0186 const char* functionLabel = nullptr) const;
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210 template <class Functor1, class Functor2>
0211 std::unique_ptr<LinInterpolatedTableND> invertRatioResponse(unsigned axisNumber,
0212 const Axis& replacementAxis,
0213 bool newAxisLeftLinear,
0214 bool newAxisRightLinear,
0215 Functor1 invg,
0216 Functor2 invh,
0217 const char* functionLabel = nullptr) const;
0218
0219
0220 bool operator==(const LinInterpolatedTableND&) const;
0221
0222
0223 inline bool operator!=(const LinInterpolatedTableND& r) const { return !(*this == r); }
0224
0225
0226
0227 inline gs::ClassId classId() const { return gs::ClassId(*this); }
0228 bool write(std::ostream& of) const;
0229
0230
0231 static const char* classname();
0232 static inline unsigned version() { return 1; }
0233 static LinInterpolatedTableND* read(const gs::ClassId& id, std::istream& in);
0234
0235 private:
0236 LinInterpolatedTableND(const ArrayND<Numeric>& data,
0237 const std::vector<Axis>& axes,
0238 const char* leftInterpolation,
0239 const char* rightInterpolation,
0240 const std::string& label);
0241
0242 bool allConstInterpolated() const;
0243
0244 ArrayND<Numeric> data_;
0245 std::vector<Axis> axes_;
0246 std::string functionLabel_;
0247 char leftInterpolationLinear_[CHAR_BIT * sizeof(unsigned long)];
0248 char rightInterpolationLinear_[CHAR_BIT * sizeof(unsigned long)];
0249 unsigned dim_;
0250 bool allConstInterpolated_;
0251
0252 template <class Functor1>
0253 static double solveForRatioArg(double xmin, double xmax, double rmin, double rmax, double fval, Functor1 invg);
0254
0255 template <class Functor1>
0256 static void invert1DResponse(const ArrayND<Numeric>& fromSlice,
0257 const Axis& fromAxis,
0258 const Axis& toAxis,
0259 bool newLeftLinear,
0260 bool newRightLinear,
0261 Functor1 invg,
0262 const double* rawx,
0263 const double* rawf,
0264 double* workspace,
0265 ArrayND<Numeric>* toSlice);
0266 };
0267 }
0268
0269 #include <cmath>
0270 #include <cfloat>
0271 #include <cassert>
0272 #include <algorithm>
0273 #include <functional>
0274
0275 #include "Alignment/Geners/interface/binaryIO.hh"
0276
0277 #include "JetMETCorrections/InterpolationTables/interface/ArrayNDScanner.h"
0278 #include "JetMETCorrections/InterpolationTables/interface/isMonotonous.h"
0279
0280 namespace npstat {
0281 namespace Private {
0282 template <class Axis>
0283 ArrayShape makeTableShape(const std::vector<Axis>& axes) {
0284 const unsigned n = axes.size();
0285 ArrayShape result;
0286 result.reserve(n);
0287 for (unsigned i = 0; i < n; ++i)
0288 result.push_back(axes[i].nCoords());
0289 return result;
0290 }
0291
0292 template <class Axis>
0293 ArrayShape makeTableShape(const Axis& xAxis) {
0294 ArrayShape result;
0295 result.reserve(1U);
0296 result.push_back(xAxis.nCoords());
0297 return result;
0298 }
0299
0300 template <class Axis>
0301 ArrayShape makeTableShape(const Axis& xAxis, const Axis& yAxis) {
0302 ArrayShape result;
0303 result.reserve(2U);
0304 result.push_back(xAxis.nCoords());
0305 result.push_back(yAxis.nCoords());
0306 return result;
0307 }
0308
0309 template <class Axis>
0310 ArrayShape makeTableShape(const Axis& xAxis, const Axis& yAxis, const Axis& zAxis) {
0311 ArrayShape result;
0312 result.reserve(3U);
0313 result.push_back(xAxis.nCoords());
0314 result.push_back(yAxis.nCoords());
0315 result.push_back(zAxis.nCoords());
0316 return result;
0317 }
0318
0319 template <class Axis>
0320 ArrayShape makeTableShape(const Axis& xAxis, const Axis& yAxis, const Axis& zAxis, const Axis& tAxis) {
0321 ArrayShape result;
0322 result.reserve(4U);
0323 result.push_back(xAxis.nCoords());
0324 result.push_back(yAxis.nCoords());
0325 result.push_back(zAxis.nCoords());
0326 result.push_back(tAxis.nCoords());
0327 return result;
0328 }
0329
0330 template <class Axis>
0331 ArrayShape makeTableShape(
0332 const Axis& xAxis, const Axis& yAxis, const Axis& zAxis, const Axis& tAxis, const Axis& vAxis) {
0333 ArrayShape result;
0334 result.reserve(5U);
0335 result.push_back(xAxis.nCoords());
0336 result.push_back(yAxis.nCoords());
0337 result.push_back(zAxis.nCoords());
0338 result.push_back(tAxis.nCoords());
0339 result.push_back(vAxis.nCoords());
0340 return result;
0341 }
0342
0343 inline double lind_interpolateSimple(
0344 const double x0, const double x1, const double y0, const double y1, const double x) {
0345 return y0 + (y1 - y0) * ((x - x0) / (x1 - x0));
0346 }
0347
0348 template <typename Numeric, class Axis>
0349 void lind_invert1DSlice(const ArrayND<Numeric>& fromSlice,
0350 const Axis& fromAxis,
0351 const Axis& toAxis,
0352 const bool leftLinear,
0353 const bool rightLinear,
0354 ArrayND<Numeric>* toSlice) {
0355 assert(toSlice);
0356 assert(fromSlice.rank() == 1U);
0357 assert(toSlice->rank() == 1U);
0358
0359 const Numeric* fromData = fromSlice.data();
0360 const unsigned fromLen = fromSlice.length();
0361 assert(fromLen > 1U);
0362 assert(fromLen == fromAxis.nCoords());
0363 const Numeric* fromDataEnd = fromData + fromLen;
0364 if (!isStrictlyMonotonous(fromData, fromDataEnd))
0365 throw npstat::NpstatInvalidArgument(
0366 "In npstat::Private::lind_invert1DSlice: "
0367 "slice data is not monotonous and can not be inverted");
0368
0369 const Numeric yfirst = fromData[0];
0370 const Numeric ylast = fromData[fromLen - 1U];
0371 const bool increasing = yfirst < ylast;
0372
0373 Numeric* toD = const_cast<Numeric*>(toSlice->data());
0374 const unsigned nAxisPoints = toAxis.nCoords();
0375 assert(toSlice->length() == nAxisPoints);
0376
0377 for (unsigned ipt = 0; ipt < nAxisPoints; ++ipt) {
0378 const Numeric y = static_cast<Numeric>(toAxis.coordinate(ipt));
0379 if (increasing) {
0380 if (y <= yfirst) {
0381 if (leftLinear)
0382 toD[ipt] = Private::lind_interpolateSimple(
0383 yfirst, fromData[1], fromAxis.coordinate(0), fromAxis.coordinate(1), y);
0384 else
0385 toD[ipt] = fromAxis.coordinate(0);
0386 } else if (y >= ylast) {
0387 if (rightLinear)
0388 toD[ipt] = Private::lind_interpolateSimple(ylast,
0389 fromData[fromLen - 2U],
0390 fromAxis.coordinate(fromLen - 1U),
0391 fromAxis.coordinate(fromLen - 2U),
0392 y);
0393 else
0394 toD[ipt] = fromAxis.coordinate(fromLen - 1U);
0395 } else {
0396 const unsigned i = std::lower_bound(fromData, fromDataEnd, y) - fromData;
0397 toD[ipt] = Private::lind_interpolateSimple(
0398 fromData[i - 1U], fromData[i], fromAxis.coordinate(i - 1U), fromAxis.coordinate(i), y);
0399 }
0400 } else {
0401
0402
0403 if (y <= ylast) {
0404 if (leftLinear)
0405 toD[ipt] = Private::lind_interpolateSimple(ylast,
0406 fromData[fromLen - 2U],
0407 fromAxis.coordinate(fromLen - 1U),
0408 fromAxis.coordinate(fromLen - 2U),
0409 y);
0410 else
0411 toD[ipt] = fromAxis.coordinate(fromLen - 1U);
0412 } else if (y >= yfirst) {
0413 if (rightLinear)
0414 toD[ipt] = Private::lind_interpolateSimple(
0415 yfirst, fromData[1], fromAxis.coordinate(0), fromAxis.coordinate(1), y);
0416 else
0417 toD[ipt] = fromAxis.coordinate(0);
0418 } else {
0419 const unsigned i = std::lower_bound(fromData, fromDataEnd, y, std::greater<Numeric>()) - fromData;
0420 toD[ipt] = Private::lind_interpolateSimple(
0421 fromData[i - 1U], fromData[i], fromAxis.coordinate(i - 1U), fromAxis.coordinate(i), y);
0422 }
0423 }
0424 }
0425 }
0426 }
0427
0428 template <class Numeric, class Axis>
0429 bool LinInterpolatedTableND<Numeric, Axis>::allConstInterpolated() const {
0430 for (unsigned i = 0; i < dim_; ++i)
0431 if (leftInterpolationLinear_[i] || rightInterpolationLinear_[i])
0432 return false;
0433 return true;
0434 }
0435
0436 template <class Numeric, class Axis>
0437 bool LinInterpolatedTableND<Numeric, Axis>::operator==(const LinInterpolatedTableND& r) const {
0438 if (dim_ != r.dim_)
0439 return false;
0440 for (unsigned i = 0; i < dim_; ++i) {
0441 if (leftInterpolationLinear_[i] != r.leftInterpolationLinear_[i])
0442 return false;
0443 if (rightInterpolationLinear_[i] != r.rightInterpolationLinear_[i])
0444 return false;
0445 }
0446 return data_ == r.data_ && axes_ == r.axes_ && functionLabel_ == r.functionLabel_;
0447 }
0448
0449 template <typename Numeric, class Axis>
0450 const char* LinInterpolatedTableND<Numeric, Axis>::classname() {
0451 static const std::string myClass(gs::template_class_name<Numeric, Axis>("npstat::LinInterpolatedTableND"));
0452 return myClass.c_str();
0453 }
0454
0455 template <typename Numeric, class Axis>
0456 bool LinInterpolatedTableND<Numeric, Axis>::write(std::ostream& of) const {
0457 const bool status = data_.classId().write(of) && data_.write(of) && gs::write_obj_vector(of, axes_);
0458 if (status) {
0459 gs::write_pod_array(of, leftInterpolationLinear_, dim_);
0460 gs::write_pod_array(of, rightInterpolationLinear_, dim_);
0461 gs::write_pod(of, functionLabel_);
0462 }
0463 return status && !of.fail();
0464 }
0465
0466 template <typename Numeric, class Axis>
0467 LinInterpolatedTableND<Numeric, Axis>* LinInterpolatedTableND<Numeric, Axis>::read(const gs::ClassId& id,
0468 std::istream& in) {
0469 static const gs::ClassId current(gs::ClassId::makeId<LinInterpolatedTableND<Numeric, Axis> >());
0470 current.ensureSameId(id);
0471
0472 gs::ClassId ida(in, 1);
0473 ArrayND<Numeric> data;
0474 ArrayND<Numeric>::restore(ida, in, &data);
0475 std::vector<Axis> axes;
0476 gs::read_heap_obj_vector_as_placed(in, &axes);
0477 const unsigned dim = axes.size();
0478 if (dim > CHAR_BIT * sizeof(unsigned long) || data.rank() != dim)
0479 throw gs::IOInvalidData(
0480 "In npstat::LinInterpolatedTableND::read: "
0481 "read back invalid dimensionality");
0482 char leftInterpolation[CHAR_BIT * sizeof(unsigned long)];
0483 gs::read_pod_array(in, leftInterpolation, dim);
0484 char rightInterpolation[CHAR_BIT * sizeof(unsigned long)];
0485 gs::read_pod_array(in, rightInterpolation, dim);
0486 std::string label;
0487 gs::read_pod(in, &label);
0488 if (in.fail())
0489 throw gs::IOReadFailure("In npstat::LinInterpolatedTableND::read: input stream failure");
0490 return new LinInterpolatedTableND(data, axes, leftInterpolation, rightInterpolation, label);
0491 }
0492
0493 template <typename Numeric, class Axis>
0494 bool LinInterpolatedTableND<Numeric, Axis>::leftInterpolationLinear(const unsigned i) const {
0495 if (i >= dim_)
0496 throw npstat::NpstatOutOfRange(
0497 "In npstat::LinInterpolatedTableND::leftInterpolationLinear: "
0498 "index out of range");
0499 return leftInterpolationLinear_[i];
0500 }
0501
0502 template <typename Numeric, class Axis>
0503 bool LinInterpolatedTableND<Numeric, Axis>::rightInterpolationLinear(const unsigned i) const {
0504 if (i >= dim_)
0505 throw npstat::NpstatOutOfRange(
0506 "In npstat::LinInterpolatedTableND::rightInterpolationLinear: "
0507 "index out of range");
0508 return rightInterpolationLinear_[i];
0509 }
0510
0511 template <typename Numeric, class Axis>
0512 bool LinInterpolatedTableND<Numeric, Axis>::isUniformlyBinned() const {
0513 for (unsigned i = 0; i < dim_; ++i)
0514 if (!axes_[i].isUniform())
0515 return false;
0516 return true;
0517 }
0518
0519 template <typename Numeric, class Axis>
0520 std::vector<std::pair<bool, bool> > LinInterpolatedTableND<Numeric, Axis>::interpolationType() const {
0521 std::vector<std::pair<bool, bool> > vec;
0522 vec.reserve(dim_);
0523 for (unsigned i = 0; i < dim_; ++i)
0524 vec.push_back(std::pair<bool, bool>(leftInterpolationLinear_[i], rightInterpolationLinear_[i]));
0525 return vec;
0526 }
0527
0528 template <typename Numeric, class Axis>
0529 LinInterpolatedTableND<Numeric, Axis>::LinInterpolatedTableND(
0530 const std::vector<Axis>& axes, const std::vector<std::pair<bool, bool> >& interpolationType, const char* label)
0531 : data_(Private::makeTableShape(axes)), axes_(axes), functionLabel_(label ? label : ""), dim_(axes.size()) {
0532 if (dim_ == 0 || dim_ >= CHAR_BIT * sizeof(unsigned long))
0533 throw npstat::NpstatInvalidArgument(
0534 "In npstat::LinInterpolatedTableND constructor: requested "
0535 "table dimensionality is not supported");
0536 if (dim_ != interpolationType.size())
0537 throw npstat::NpstatInvalidArgument(
0538 "In npstat::LinInterpolatedTableND constructor: "
0539 "incompatible number of interpolation specifications");
0540 for (unsigned i = 0; i < dim_; ++i) {
0541 const std::pair<bool, bool>& pair(interpolationType[i]);
0542 leftInterpolationLinear_[i] = pair.first;
0543 rightInterpolationLinear_[i] = pair.second;
0544 }
0545
0546 allConstInterpolated_ = allConstInterpolated();
0547 }
0548
0549 template <typename Numeric, class Axis>
0550 template <class Num2>
0551 LinInterpolatedTableND<Numeric, Axis>::LinInterpolatedTableND(const LinInterpolatedTableND<Num2, Axis>& r)
0552 : data_(r.data_),
0553 axes_(r.axes_),
0554 functionLabel_(r.functionLabel_),
0555 dim_(r.dim_),
0556 allConstInterpolated_(r.allConstInterpolated_) {
0557 for (unsigned i = 0; i < dim_; ++i) {
0558 leftInterpolationLinear_[i] = r.leftInterpolationLinear_[i];
0559 rightInterpolationLinear_[i] = r.rightInterpolationLinear_[i];
0560 }
0561 }
0562
0563 template <typename Numeric, class Axis>
0564 LinInterpolatedTableND<Numeric, Axis>::LinInterpolatedTableND(const ArrayND<Numeric>& data,
0565 const std::vector<Axis>& axes,
0566 const char* leftInterpolation,
0567 const char* rightInterpolation,
0568 const std::string& label)
0569 : data_(data), axes_(axes), functionLabel_(label), dim_(data.rank()) {
0570 for (unsigned i = 0; i < dim_; ++i) {
0571 leftInterpolationLinear_[i] = leftInterpolation[i];
0572 rightInterpolationLinear_[i] = rightInterpolation[i];
0573 }
0574 allConstInterpolated_ = allConstInterpolated();
0575 }
0576
0577 template <typename Numeric, class Axis>
0578 LinInterpolatedTableND<Numeric, Axis>::LinInterpolatedTableND(const Axis& xAxis,
0579 bool leftX,
0580 bool rightX,
0581 const Axis& yAxis,
0582 bool leftY,
0583 bool rightY,
0584 const Axis& zAxis,
0585 bool leftZ,
0586 bool rightZ,
0587 const Axis& tAxis,
0588 bool leftT,
0589 bool rightT,
0590 const Axis& vAxis,
0591 bool leftV,
0592 bool rightV,
0593 const char* label)
0594 : data_(Private::makeTableShape(xAxis, yAxis, zAxis, tAxis, vAxis)),
0595 functionLabel_(label ? label : ""),
0596 dim_(5U) {
0597 axes_.reserve(dim_);
0598 axes_.push_back(xAxis);
0599 axes_.push_back(yAxis);
0600 axes_.push_back(zAxis);
0601 axes_.push_back(tAxis);
0602 axes_.push_back(vAxis);
0603
0604 unsigned i = 0;
0605 leftInterpolationLinear_[i] = leftX;
0606 rightInterpolationLinear_[i++] = rightX;
0607 leftInterpolationLinear_[i] = leftY;
0608 rightInterpolationLinear_[i++] = rightY;
0609 leftInterpolationLinear_[i] = leftZ;
0610 rightInterpolationLinear_[i++] = rightZ;
0611 leftInterpolationLinear_[i] = leftT;
0612 rightInterpolationLinear_[i++] = rightT;
0613 leftInterpolationLinear_[i] = leftV;
0614 rightInterpolationLinear_[i++] = rightV;
0615 assert(i == dim_);
0616
0617 allConstInterpolated_ = allConstInterpolated();
0618 }
0619
0620 template <typename Numeric, class Axis>
0621 LinInterpolatedTableND<Numeric, Axis>::LinInterpolatedTableND(const Axis& xAxis,
0622 bool leftX,
0623 bool rightX,
0624 const Axis& yAxis,
0625 bool leftY,
0626 bool rightY,
0627 const Axis& zAxis,
0628 bool leftZ,
0629 bool rightZ,
0630 const Axis& tAxis,
0631 bool leftT,
0632 bool rightT,
0633 const char* label)
0634 : data_(Private::makeTableShape(xAxis, yAxis, zAxis, tAxis)), functionLabel_(label ? label : ""), dim_(4U) {
0635 axes_.reserve(dim_);
0636 axes_.push_back(xAxis);
0637 axes_.push_back(yAxis);
0638 axes_.push_back(zAxis);
0639 axes_.push_back(tAxis);
0640
0641 unsigned i = 0;
0642 leftInterpolationLinear_[i] = leftX;
0643 rightInterpolationLinear_[i++] = rightX;
0644 leftInterpolationLinear_[i] = leftY;
0645 rightInterpolationLinear_[i++] = rightY;
0646 leftInterpolationLinear_[i] = leftZ;
0647 rightInterpolationLinear_[i++] = rightZ;
0648 leftInterpolationLinear_[i] = leftT;
0649 rightInterpolationLinear_[i++] = rightT;
0650 assert(i == dim_);
0651
0652 allConstInterpolated_ = allConstInterpolated();
0653 }
0654
0655 template <typename Numeric, class Axis>
0656 LinInterpolatedTableND<Numeric, Axis>::LinInterpolatedTableND(const Axis& xAxis,
0657 bool leftX,
0658 bool rightX,
0659 const Axis& yAxis,
0660 bool leftY,
0661 bool rightY,
0662 const Axis& zAxis,
0663 bool leftZ,
0664 bool rightZ,
0665 const char* label)
0666 : data_(Private::makeTableShape(xAxis, yAxis, zAxis)), functionLabel_(label ? label : ""), dim_(3U) {
0667 axes_.reserve(dim_);
0668 axes_.push_back(xAxis);
0669 axes_.push_back(yAxis);
0670 axes_.push_back(zAxis);
0671
0672 unsigned i = 0;
0673 leftInterpolationLinear_[i] = leftX;
0674 rightInterpolationLinear_[i++] = rightX;
0675 leftInterpolationLinear_[i] = leftY;
0676 rightInterpolationLinear_[i++] = rightY;
0677 leftInterpolationLinear_[i] = leftZ;
0678 rightInterpolationLinear_[i++] = rightZ;
0679 assert(i == dim_);
0680
0681 allConstInterpolated_ = allConstInterpolated();
0682 }
0683
0684 template <typename Numeric, class Axis>
0685 LinInterpolatedTableND<Numeric, Axis>::LinInterpolatedTableND(
0686 const Axis& xAxis, bool leftX, bool rightX, const Axis& yAxis, bool leftY, bool rightY, const char* label)
0687 : data_(Private::makeTableShape(xAxis, yAxis)), functionLabel_(label ? label : ""), dim_(2U) {
0688 axes_.reserve(dim_);
0689 axes_.push_back(xAxis);
0690 axes_.push_back(yAxis);
0691
0692 unsigned i = 0;
0693 leftInterpolationLinear_[i] = leftX;
0694 rightInterpolationLinear_[i++] = rightX;
0695 leftInterpolationLinear_[i] = leftY;
0696 rightInterpolationLinear_[i++] = rightY;
0697 assert(i == dim_);
0698
0699 allConstInterpolated_ = allConstInterpolated();
0700 }
0701
0702 template <typename Numeric, class Axis>
0703 LinInterpolatedTableND<Numeric, Axis>::LinInterpolatedTableND(const Axis& xAxis,
0704 bool leftX,
0705 bool rightX,
0706 const char* label)
0707 : data_(Private::makeTableShape(xAxis)), functionLabel_(label ? label : ""), dim_(1U) {
0708 axes_.reserve(dim_);
0709 axes_.push_back(xAxis);
0710
0711 leftInterpolationLinear_[0] = leftX;
0712 rightInterpolationLinear_[0] = rightX;
0713
0714 allConstInterpolated_ = allConstInterpolated();
0715 }
0716
0717 template <typename Numeric, class Axis>
0718 template <typename ConvertibleToUnsigned>
0719 std::unique_ptr<LinInterpolatedTableND<Numeric, Axis> > LinInterpolatedTableND<Numeric, Axis>::invertWRTAxis(
0720 const ConvertibleToUnsigned axisNumC,
0721 const Axis& replacementAxis,
0722 const bool leftLinear,
0723 const bool rightLinear,
0724 const char* functionLabel) const {
0725 const unsigned axisNumber = static_cast<unsigned>(axisNumC);
0726
0727 if (axisNumber >= dim_)
0728 throw npstat::NpstatOutOfRange(
0729 "In npstat::LinInterpolatedTableND::invertAxis: "
0730 "axis number is out of range");
0731
0732
0733 std::vector<Axis> newAxes(axes_);
0734 newAxes[axisNumber] = replacementAxis;
0735
0736 std::vector<std::pair<bool, bool> > iType(interpolationType());
0737 iType[axisNumber] = std::pair<bool, bool>(leftLinear, rightLinear);
0738
0739
0740 std::unique_ptr<LinInterpolatedTableND> pTable(new LinInterpolatedTableND(newAxes, iType, functionLabel));
0741
0742 if (dim_ > 1U) {
0743
0744 unsigned sliceIndex[CHAR_BIT * sizeof(unsigned long)];
0745 unsigned fixedIndices[CHAR_BIT * sizeof(unsigned long)];
0746 unsigned count = 0;
0747 for (unsigned i = 0; i < dim_; ++i)
0748 if (i != axisNumber) {
0749 sliceIndex[count] = data_.span(i);
0750 fixedIndices[count++] = i;
0751 }
0752 ArrayND<Numeric> parentSlice(data_, fixedIndices, count);
0753 ArrayND<Numeric> dauSlice(pTable->data_, fixedIndices, count);
0754
0755
0756 for (ArrayNDScanner scan(sliceIndex, count); scan.isValid(); ++scan) {
0757 scan.getIndex(sliceIndex, count);
0758 data_.exportSlice(&parentSlice, fixedIndices, sliceIndex, count);
0759 Private::lind_invert1DSlice(
0760 parentSlice, axes_[axisNumber], replacementAxis, leftLinear, rightLinear, &dauSlice);
0761 pTable->data_.importSlice(dauSlice, fixedIndices, sliceIndex, count);
0762 }
0763 } else
0764 Private::lind_invert1DSlice(data_, axes_[0], replacementAxis, leftLinear, rightLinear, &pTable->data_);
0765 return pTable;
0766 }
0767
0768 template <typename Numeric, class Axis>
0769 template <class Functor1, class Functor2>
0770 std::unique_ptr<LinInterpolatedTableND<Numeric, Axis> > LinInterpolatedTableND<Numeric, Axis>::invertRatioResponse(
0771 const unsigned axisNumber,
0772 const Axis& replacementAxis,
0773 const bool leftLinear,
0774 const bool rightLinear,
0775 Functor1 invg,
0776 Functor2 invh,
0777 const char* functionLabel) const {
0778 if (axisNumber >= dim_)
0779 throw npstat::NpstatOutOfRange(
0780 "In npstat::LinInterpolatedTableND::invertRatioResponse: "
0781 "axis number is out of range");
0782
0783
0784 std::vector<Axis> newAxes(axes_);
0785 newAxes[axisNumber] = replacementAxis;
0786
0787 std::vector<std::pair<bool, bool> > iType(interpolationType());
0788 iType[axisNumber] = std::pair<bool, bool>(leftLinear, rightLinear);
0789
0790
0791 const Axis& oldAxis(axes_[axisNumber]);
0792 std::vector<double> rawx;
0793 const unsigned nCoords = oldAxis.nCoords();
0794 rawx.reserve(nCoords);
0795 for (unsigned i = 0; i < nCoords; ++i) {
0796 const double x = invg(oldAxis.coordinate(i));
0797 if (x < 0.0)
0798 throw npstat::NpstatInvalidArgument(
0799 "In npstat::LinInterpolatedTableND::invertRatioResponse: "
0800 "invalid original axis definition (negative transformed "
0801 "coordinate)");
0802 rawx.push_back(x);
0803 }
0804
0805
0806 std::vector<double> rawf;
0807 const unsigned nFuncs = replacementAxis.nCoords();
0808 rawf.reserve(nFuncs);
0809 for (unsigned i = 0; i < nFuncs; ++i) {
0810 const double f = invh(replacementAxis.coordinate(i));
0811 if (f < 0.0)
0812 throw npstat::NpstatInvalidArgument(
0813 "In npstat::LinInterpolatedTableND::invertRatioResponse: "
0814 "invalid new axis definition (negative transformed "
0815 "coordinate)");
0816 rawf.push_back(f);
0817 }
0818
0819
0820 std::vector<double> workspace(nCoords);
0821
0822
0823 std::unique_ptr<LinInterpolatedTableND> pTable(new LinInterpolatedTableND(newAxes, iType, functionLabel));
0824
0825 if (dim_ > 1U) {
0826
0827 unsigned sliceIndex[CHAR_BIT * sizeof(unsigned long)];
0828 unsigned fixedIndices[CHAR_BIT * sizeof(unsigned long)];
0829 unsigned count = 0;
0830 for (unsigned i = 0; i < dim_; ++i)
0831 if (i != axisNumber) {
0832 sliceIndex[count] = data_.span(i);
0833 fixedIndices[count++] = i;
0834 }
0835 ArrayND<Numeric> parentSlice(data_, fixedIndices, count);
0836 ArrayND<Numeric> dauSlice(pTable->data_, fixedIndices, count);
0837
0838
0839 for (ArrayNDScanner scan(sliceIndex, count); scan.isValid(); ++scan) {
0840 scan.getIndex(sliceIndex, count);
0841 data_.exportSlice(&parentSlice, fixedIndices, sliceIndex, count);
0842 invert1DResponse(parentSlice,
0843 oldAxis,
0844 replacementAxis,
0845 leftLinear,
0846 rightLinear,
0847 invg,
0848 &rawx[0],
0849 &rawf[0],
0850 &workspace[0],
0851 &dauSlice);
0852 pTable->data_.importSlice(dauSlice, fixedIndices, sliceIndex, count);
0853 }
0854 } else
0855 invert1DResponse(data_,
0856 oldAxis,
0857 replacementAxis,
0858 leftLinear,
0859 rightLinear,
0860 invg,
0861 &rawx[0],
0862 &rawf[0],
0863 &workspace[0],
0864 &pTable->data_);
0865 return pTable;
0866 }
0867
0868 template <typename Numeric, class Axis>
0869 void LinInterpolatedTableND<Numeric, Axis>::getCoords(const unsigned long linearIndex,
0870 double* coords,
0871 const unsigned coordsBufferSize) const {
0872 if (coordsBufferSize < dim_)
0873 throw npstat::NpstatInvalidArgument(
0874 "In LinInterpolatedTableND::getCoords: "
0875 "insufficient buffer size");
0876 assert(coords);
0877 unsigned index[CHAR_BIT * sizeof(unsigned long)];
0878 data_.convertLinearIndex(linearIndex, index, dim_);
0879 for (unsigned i = 0; i < dim_; ++i)
0880 coords[i] = axes_[i].coordinate(index[i]);
0881 }
0882
0883 template <typename Numeric, class Axis>
0884 bool LinInterpolatedTableND<Numeric, Axis>::isWithinLimits(const double* point, const unsigned len) const {
0885 if (len != dim_)
0886 throw npstat::NpstatInvalidArgument(
0887 "In npstat::LinInterpolatedTableND::isWithinLimits: "
0888 "incompatible point dimensionality");
0889 assert(point);
0890
0891 for (unsigned i = 0; i < dim_; ++i)
0892 if (point[i] < axes_[i].min() || point[i] > axes_[i].max())
0893 return false;
0894 return true;
0895 }
0896
0897 template <typename Numeric, class Axis>
0898 Numeric LinInterpolatedTableND<Numeric, Axis>::operator()(const double* point, const unsigned len) const {
0899 typedef typename ProperDblFromCmpl<Numeric>::type proper_double;
0900
0901 if (len != dim_)
0902 throw npstat::NpstatInvalidArgument(
0903 "In npstat::LinInterpolatedTableND::operator(): "
0904 "incompatible point dimensionality");
0905 assert(point);
0906
0907 bool interpolateArray = true;
0908 if (!allConstInterpolated_)
0909 for (unsigned i = 0; i < dim_; ++i)
0910 if ((leftInterpolationLinear_[i] && point[i] < axes_[i].min()) ||
0911 (rightInterpolationLinear_[i] && point[i] > axes_[i].max())) {
0912 interpolateArray = false;
0913 break;
0914 }
0915
0916 if (interpolateArray) {
0917
0918
0919 double buf[CHAR_BIT * sizeof(unsigned long)];
0920 for (unsigned i = 0; i < dim_; ++i) {
0921 const std::pair<unsigned, double>& pair = axes_[i].getInterval(point[i]);
0922 buf[i] = pair.first + 1U - pair.second;
0923 }
0924 return data_.interpolate1(buf, dim_);
0925 } else {
0926 unsigned ix[CHAR_BIT * sizeof(unsigned long)];
0927 double weight[CHAR_BIT * sizeof(unsigned long)];
0928 for (unsigned i = 0; i < dim_; ++i) {
0929 const bool linear = (leftInterpolationLinear_[i] && point[i] < axes_[i].min()) ||
0930 (rightInterpolationLinear_[i] && point[i] > axes_[i].max());
0931 const std::pair<unsigned, double>& pair =
0932 linear ? axes_[i].linearInterval(point[i]) : axes_[i].getInterval(point[i]);
0933 ix[i] = pair.first;
0934 weight[i] = pair.second;
0935 }
0936
0937 Numeric sum = Numeric();
0938 const unsigned long maxcycle = 1UL << dim_;
0939 const unsigned long* strides = data_.strides();
0940 const Numeric* dat = data_.data();
0941 for (unsigned long icycle = 0UL; icycle < maxcycle; ++icycle) {
0942 double w = 1.0;
0943 unsigned long icell = 0UL;
0944 for (unsigned i = 0; i < dim_; ++i) {
0945 if (icycle & (1UL << i)) {
0946 w *= (1.0 - weight[i]);
0947 icell += strides[i] * (ix[i] + 1U);
0948 } else {
0949 w *= weight[i];
0950 icell += strides[i] * ix[i];
0951 }
0952 }
0953 sum += dat[icell] * static_cast<proper_double>(w);
0954 }
0955 return sum;
0956 }
0957 }
0958
0959 template <typename Numeric, class Axis>
0960 Numeric LinInterpolatedTableND<Numeric, Axis>::operator()(const double& x0) const {
0961 const unsigned nArgs = 1U;
0962 if (dim_ != nArgs)
0963 throw npstat::NpstatInvalidArgument(
0964 "In npstat::LinInterpolatedTableND::operator(): number of "
0965 "arguments, 1, is incompatible with the interpolator dimensionality");
0966 double tmp[nArgs];
0967 tmp[0] = x0;
0968 return operator()(tmp, nArgs);
0969 }
0970
0971 template <typename Numeric, class Axis>
0972 Numeric LinInterpolatedTableND<Numeric, Axis>::operator()(const double& x0, const double& x1) const {
0973 const unsigned nArgs = 2U;
0974 if (dim_ != nArgs)
0975 throw npstat::NpstatInvalidArgument(
0976 "In npstat::LinInterpolatedTableND::operator(): number of "
0977 "arguments, 2, is incompatible with the interpolator dimensionality");
0978 double tmp[nArgs];
0979 tmp[0] = x0;
0980 tmp[1] = x1;
0981 return operator()(tmp, nArgs);
0982 }
0983
0984 template <typename Numeric, class Axis>
0985 Numeric LinInterpolatedTableND<Numeric, Axis>::operator()(const double& x0,
0986 const double& x1,
0987 const double& x2) const {
0988 const unsigned nArgs = 3U;
0989 if (dim_ != nArgs)
0990 throw npstat::NpstatInvalidArgument(
0991 "In npstat::LinInterpolatedTableND::operator(): number of "
0992 "arguments, 3, is incompatible with the interpolator dimensionality");
0993 double tmp[nArgs];
0994 tmp[0] = x0;
0995 tmp[1] = x1;
0996 tmp[2] = x2;
0997 return operator()(tmp, nArgs);
0998 }
0999
1000 template <typename Numeric, class Axis>
1001 Numeric LinInterpolatedTableND<Numeric, Axis>::operator()(const double& x0,
1002 const double& x1,
1003 const double& x2,
1004 const double& x3) const {
1005 const unsigned nArgs = 4U;
1006 if (dim_ != nArgs)
1007 throw npstat::NpstatInvalidArgument(
1008 "In npstat::LinInterpolatedTableND::operator(): number of "
1009 "arguments, 4, is incompatible with the interpolator dimensionality");
1010 double tmp[nArgs];
1011 tmp[0] = x0;
1012 tmp[1] = x1;
1013 tmp[2] = x2;
1014 tmp[3] = x3;
1015 return operator()(tmp, nArgs);
1016 }
1017
1018 template <typename Numeric, class Axis>
1019 Numeric LinInterpolatedTableND<Numeric, Axis>::operator()(
1020 const double& x0, const double& x1, const double& x2, const double& x3, const double& x4) const {
1021 const unsigned nArgs = 5U;
1022 if (dim_ != nArgs)
1023 throw npstat::NpstatInvalidArgument(
1024 "In npstat::LinInterpolatedTableND::operator(): number of "
1025 "arguments, 5, is incompatible with the interpolator dimensionality");
1026 double tmp[nArgs];
1027 tmp[0] = x0;
1028 tmp[1] = x1;
1029 tmp[2] = x2;
1030 tmp[3] = x3;
1031 tmp[4] = x4;
1032 return operator()(tmp, nArgs);
1033 }
1034
1035 template <typename Numeric, class Axis>
1036 template <class Functor1>
1037 double LinInterpolatedTableND<Numeric, Axis>::solveForRatioArg(
1038 const double xmin, const double xmax, const double rmin, const double rmax, const double fval, Functor1 invg) {
1039
1040 double x0 = xmin;
1041 double x1 = xmax;
1042 double fmin = invg(xmin) * rmin;
1043 double fmax = invg(xmax) * rmax;
1044 const double step = xmax - xmin;
1045 assert(fmin < fmax);
1046 assert(step > 0.0);
1047
1048 unsigned stepcount = 0;
1049 const unsigned maxSteps = 1000U;
1050 for (double stepfactor = 1.0; (fval < fmin || fval > fmax) && stepcount < maxSteps; stepfactor *= 2.0, ++stepcount)
1051 if (fval < fmin) {
1052 x1 = x0;
1053 fmax = fmin;
1054 x0 -= stepfactor * step;
1055 fmin = invg(x0) * Private::lind_interpolateSimple(xmin, xmax, rmin, rmax, x0);
1056 } else {
1057 x0 = x1;
1058 fmin = fmax;
1059 x1 += stepfactor * step;
1060 fmax = invg(x1) * Private::lind_interpolateSimple(xmin, xmax, rmin, rmax, x1);
1061 }
1062 if (stepcount == maxSteps)
1063 throw npstat::NpstatRuntimeError(
1064 "In LinInterpolatedTableND::solveForRatioArg: "
1065 "faled to bracket the root");
1066
1067 assert(x1 >= x0);
1068 while ((x1 - x0) / (std::abs(x1) + std::abs(x0) + DBL_EPSILON) > 4.0 * DBL_EPSILON) {
1069 const double xhalf = (x1 + x0) / 2.0;
1070 const double fhalf = invg(xhalf) * Private::lind_interpolateSimple(xmin, xmax, rmin, rmax, xhalf);
1071 if (fval < fhalf) {
1072 x1 = xhalf;
1073 fmax = fhalf;
1074 } else {
1075 x0 = xhalf;
1076 fmin = fhalf;
1077 }
1078 }
1079 return (x1 + x0) / 2.0;
1080 }
1081
1082 template <typename Numeric, class Axis>
1083 template <class Functor1>
1084 void LinInterpolatedTableND<Numeric, Axis>::invert1DResponse(const ArrayND<Numeric>& fromSlice,
1085 const Axis& fromAxis,
1086 const Axis& toAxis,
1087 const bool newLeftLinear,
1088 const bool newRightLinear,
1089 Functor1 invg,
1090 const double* rawx,
1091 const double* rawf,
1092 double* workspace,
1093 ArrayND<Numeric>* toSlice) {
1094 assert(toSlice);
1095 assert(fromSlice.rank() == 1U);
1096 assert(toSlice->rank() == 1U);
1097
1098 const Numeric zero = Numeric();
1099 const Numeric* fromData = fromSlice.data();
1100 const unsigned fromLen = fromSlice.length();
1101 assert(fromLen > 1U);
1102 assert(fromLen == fromAxis.nCoords());
1103 Numeric* toD = const_cast<Numeric*>(toSlice->data());
1104 const unsigned nAxisPoints = toAxis.nCoords();
1105 assert(toSlice->length() == nAxisPoints);
1106
1107 for (unsigned i = 0; i < fromLen; ++i) {
1108 if (fromData[i] <= zero)
1109 throw npstat::NpstatDomainError(
1110 "In LinInterpolatedTableND::invert1DResponse: "
1111 "non-positive response found. This ratio "
1112 "response table is not invertible.");
1113 workspace[i] = rawx[i] * fromData[i];
1114 }
1115
1116 const double yfirst = workspace[0];
1117 const double ylast = workspace[fromLen - 1U];
1118
1119 bool adjustZero = false;
1120 unsigned nBelow = 0;
1121 for (unsigned ipt = 0; ipt < nAxisPoints; ++ipt) {
1122 const double y = rawf[ipt];
1123 unsigned i0 = 0;
1124 bool solve = false;
1125 if (y == 0.0) {
1126 assert(ipt == 0U);
1127 if (newLeftLinear)
1128 adjustZero = true;
1129 } else if (y <= yfirst) {
1130 ++nBelow;
1131 solve = newLeftLinear;
1132 } else if (y >= ylast) {
1133 solve = newRightLinear;
1134 i0 = solve ? fromLen - 2 : fromLen - 1;
1135 } else {
1136 solve = true;
1137 i0 = static_cast<unsigned>(std::lower_bound(workspace, workspace + fromLen, y) - workspace) - 1U;
1138 }
1139 if (solve) {
1140 const double x = solveForRatioArg(
1141 fromAxis.coordinate(i0), fromAxis.coordinate(i0 + 1), fromData[i0], fromData[i0 + 1], y, invg);
1142 toD[ipt] = invg(x) / y;
1143 } else
1144 toD[ipt] = 1.0 / fromData[i0];
1145 }
1146 if (adjustZero && nBelow)
1147 toD[0] = toD[1];
1148 }
1149 }
1150
1151 #endif