2 #ifndef RIVET_MathUtils_HH 3 #define RIVET_MathUtils_HH 5 #include "Rivet/Math/MathConstants.hh" 19 template <
typename NUM>
20 inline typename std::enable_if<std::is_floating_point<NUM>::value,
bool>::type
21 isZero(NUM val,
double tolerance=1e-8) {
22 return fabs(val) < tolerance;
29 template <
typename NUM>
30 inline typename std::enable_if<std::is_integral<NUM>::value,
bool>::type
36 template <
typename NUM>
37 inline typename std::enable_if<std::is_floating_point<NUM>::value,
bool>::type
38 isNaN(NUM val) {
return std::isnan(val); }
41 template <
typename NUM>
42 inline typename std::enable_if<std::is_floating_point<NUM>::value,
bool>::type
43 notNaN(NUM val) {
return !std::isnan(val); }
50 template <
typename N1,
typename N2>
51 inline typename std::enable_if<
52 std::is_arithmetic<N1>::value && std::is_arithmetic<N2>::value &&
53 (std::is_floating_point<N1>::value || std::is_floating_point<N2>::value),
bool>::type
55 const double absavg = (std::abs(a) + std::abs(b))/2.0;
56 const double absdiff = std::abs(a - b);
57 const bool rtn = (
isZero(a) &&
isZero(b)) || absdiff < tolerance*absavg;
65 template <
typename N1,
typename N2>
66 inline typename std::enable_if<
67 std::is_integral<N1>::value && std::is_integral<N2>::value,
bool>::type
76 template <
typename N1,
typename N2>
77 inline typename std::enable_if<
78 std::is_arithmetic<N1>::value && std::is_arithmetic<N2>::value,
bool>::type
87 template <
typename N1,
typename N2>
88 inline typename std::enable_if<
89 std::is_arithmetic<N1>::value && std::is_arithmetic<N2>::value,
bool>::type
109 template <
typename N1,
typename N2,
typename N3>
110 inline typename std::enable_if<
111 std::is_arithmetic<N1>::value && std::is_arithmetic<N2>::value && std::is_arithmetic<N3>::value,
bool>::type
114 if (lowbound == OPEN && highbound == OPEN) {
115 return (value > low && value < high);
116 }
else if (lowbound == OPEN && highbound == CLOSED) {
117 return (value > low && value <= high);
118 }
else if (lowbound == CLOSED && highbound == OPEN) {
119 return (value >= low && value < high);
121 return (value >= low && value <= high);
129 template <
typename N1,
typename N2,
typename N3>
130 inline typename std::enable_if<
131 std::is_arithmetic<N1>::value && std::is_arithmetic<N2>::value && std::is_arithmetic<N3>::value,
bool>::type
134 if (lowbound == OPEN && highbound == OPEN) {
135 return (value > low && value < high);
136 }
else if (lowbound == OPEN && highbound == CLOSED) {
138 }
else if (lowbound == CLOSED && highbound == OPEN) {
146 template <
typename N1,
typename N2,
typename N3>
147 inline typename std::enable_if<
148 std::is_arithmetic<N1>::value && std::is_arithmetic<N2>::value && std::is_arithmetic<N3>::value,
bool>::type
151 return inRange(value, lowhigh.first, lowhigh.second, lowbound, highbound);
160 template <
typename N1,
typename N2,
typename N3>
161 inline typename std::enable_if<
162 std::is_arithmetic<N1>::value && std::is_arithmetic<N2>::value && std::is_arithmetic<N3>::value,
bool>::type
164 return inRange(val, low, high, CLOSED, OPEN);
170 template <
typename N1,
typename N2,
typename N3>
171 inline typename std::enable_if<
172 std::is_arithmetic<N1>::value && std::is_arithmetic<N2>::value && std::is_arithmetic<N3>::value,
bool>::type
174 return inRange(val, low, high, CLOSED, CLOSED);
180 template <
typename N1,
typename N2,
typename N3>
181 inline typename std::enable_if<
182 std::is_arithmetic<N1>::value && std::is_arithmetic<N2>::value && std::is_arithmetic<N3>::value,
bool>::type
184 return inRange(val, low, high, OPEN, OPEN);
196 template <
typename NUM>
197 inline typename std::enable_if<std::is_arithmetic<NUM>::value, NUM>::type
207 template <
typename NUM>
208 inline typename std::enable_if<std::is_arithmetic<NUM>::value, NUM>::type
211 return sqrt(a*a + b*b);
219 template <
typename NUM>
220 inline typename std::enable_if<std::is_arithmetic<NUM>::value, NUM>::type
223 return sqrt(a*a + b*b + c*c);
228 inline double safediv(
double num,
double den,
double fail=0.0) {
229 return (!
isZero(den)) ? num/den : fail;
233 template <
typename NUM>
234 inline typename std::enable_if<std::is_arithmetic<NUM>::value, NUM>::type
237 if (exp == 0)
return (NUM) 1;
238 else if (exp == 1)
return val;
239 return val *
intpow(val, exp-1);
243 template <
typename NUM>
244 inline typename std::enable_if<std::is_arithmetic<NUM>::value,
int>::type
246 if (
isZero(val))
return ZERO;
247 const int valsign = (val > 0) ? PLUS : MINUS;
258 inline double cdfBW(
double x,
double mu,
double gamma) {
260 const double xn = (x - mu)/gamma;
261 return std::atan(xn)/M_PI + 0.5;
265 inline double invcdfBW(
double p,
double mu,
double gamma) {
266 const double xn = std::tan(M_PI*(p-0.5));
267 return gamma*xn + mu;
280 inline vector<double>
linspace(
size_t nbins,
double start,
double end,
bool include_end=
true) {
281 assert(end >= start);
284 const double interval = (end-start)/static_cast<double>(nbins);
285 for (
size_t i = 0; i < nbins; ++i) {
286 rtn.push_back(start + i*interval);
288 assert(rtn.size() == nbins);
289 if (include_end) rtn.push_back(end);
299 inline vector<double>
logspace(
size_t nbins,
double start,
double end,
bool include_end=
true) {
300 assert(end >= start);
303 const double logstart = std::log(start);
304 const double logend = std::log(end);
305 const vector<double> logvals =
linspace(nbins, logstart, logend,
false);
306 assert(logvals.size() == nbins);
307 vector<double> rtn; rtn.reserve(nbins+1);
308 rtn.push_back(start);
309 for (
size_t i = 1; i < logvals.size(); ++i) {
310 rtn.push_back(std::exp(logvals[i]));
312 assert(rtn.size() == nbins);
313 if (include_end) rtn.push_back(end);
328 inline vector<double>
bwspace(
size_t nbins,
double start,
double end,
double mu,
double gamma) {
329 assert(end >= start);
331 const double pmin =
cdfBW(start, mu, gamma);
332 const double pmax =
cdfBW(end, mu, gamma);
333 const vector<double> edges =
linspace(nbins, pmin, pmax);
334 assert(edges.size() == nbins+1);
336 for (
double edge : edges) {
337 rtn.push_back(
invcdfBW(edge, mu, gamma));
339 assert(rtn.size() == nbins+1);
345 template <
typename NUM,
typename CONTAINER>
346 inline typename std::enable_if<std::is_arithmetic<NUM>::value && std::is_arithmetic<typename CONTAINER::value_type>::value,
int>::type
347 _binIndex(NUM val,
const CONTAINER& binedges,
bool allow_overflow=
false) {
348 if (val < *begin(binedges))
return -1;
350 if (val >= *(end(binedges)-1))
return allow_overflow ? int(binedges.size())-1 : -1;
351 auto it = std::upper_bound(begin(binedges), end(binedges), val);
352 return std::distance(begin(binedges), --it);
363 template <
typename NUM1,
typename NUM2>
364 inline typename std::enable_if<std::is_arithmetic<NUM1>::value && std::is_arithmetic<NUM2>::value,
int>::type
365 binIndex(NUM1 val, std::initializer_list<NUM2> binedges,
bool allow_overflow=
false) {
366 return _binIndex(val, binedges, allow_overflow);
377 template <
typename NUM,
typename CONTAINER>
378 inline typename std::enable_if<std::is_arithmetic<NUM>::value && std::is_arithmetic<typename CONTAINER::value_type>::value,
int>::type
379 binIndex(NUM val,
const CONTAINER& binedges,
bool allow_overflow=
false) {
380 return _binIndex(val, binedges, allow_overflow);
391 template <
typename NUM>
392 inline typename std::enable_if<std::is_arithmetic<NUM>::value, NUM>::type
394 if (sample.empty())
throw RangeError(
"Can't compute median of an empty set");
395 vector<NUM> tmp = sample;
396 std::sort(tmp.begin(), tmp.end());
397 const size_t imid = tmp.size()/2;
398 if (sample.size() % 2 == 0)
return (tmp.at(imid-1) + tmp.at(imid)) / 2.0;
399 else return tmp.at(imid);
405 template <
typename NUM>
406 inline typename std::enable_if<std::is_arithmetic<NUM>::value,
double>::type
407 mean(
const vector<NUM>& sample) {
408 if (sample.empty())
throw RangeError(
"Can't compute mean of an empty set");
410 for (
size_t i = 0; i < sample.size(); ++i) {
413 return mean/sample.size();
418 template <
typename NUM>
419 inline typename std::enable_if<std::is_arithmetic<NUM>::value,
double>::type
421 if (sample.empty())
throw RangeError(
"Can't compute mean_err of an empty set");
423 for (
size_t i = 0; i < sample.size(); ++i) {
424 mean_e += sqrt(sample[i]);
426 return mean_e/sample.size();
432 template <
typename NUM>
433 inline typename std::enable_if<std::is_arithmetic<NUM>::value,
double>::type
434 covariance(
const vector<NUM>& sample1,
const vector<NUM>& sample2) {
435 if (sample1.empty() || sample2.empty())
throw RangeError(
"Can't compute covariance of an empty set");
436 if (sample1.size() != sample2.size())
throw RangeError(
"Sizes of samples must be equal for covariance calculation");
437 const double mean1 =
mean(sample1);
438 const double mean2 =
mean(sample2);
439 const size_t N = sample1.size();
441 for (
size_t i = 0; i < N; i++) {
442 const double cov_i = (sample1[i] - mean1)*(sample2[i] - mean2);
445 if (N > 1)
return cov/(N-1);
451 template <
typename NUM>
452 inline typename std::enable_if<std::is_arithmetic<NUM>::value,
double>::type
454 if (sample1.empty() || sample2.empty())
throw RangeError(
"Can't compute covariance_err of an empty set");
455 if (sample1.size() != sample2.size())
throw RangeError(
"Sizes of samples must be equal for covariance_err calculation");
456 const double mean1 =
mean(sample1);
457 const double mean2 =
mean(sample2);
458 const double mean1_e =
mean_err(sample1);
459 const double mean2_e =
mean_err(sample2);
460 const size_t N = sample1.size();
462 for (
size_t i = 0; i < N; i++) {
463 const double cov_i = (sqrt(sample1[i]) - mean1_e)*(sample2[i] - mean2) +
464 (sample1[i] - mean1)*(sqrt(sample2[i]) - mean2_e);
467 if (N > 1)
return cov_e/(N-1);
474 template <
typename NUM>
475 inline typename std::enable_if<std::is_arithmetic<NUM>::value,
double>::type
476 correlation(
const vector<NUM>& sample1,
const vector<NUM>& sample2) {
477 const double cov =
covariance(sample1, sample2);
478 const double var1 =
covariance(sample1, sample1);
479 const double var2 =
covariance(sample2, sample2);
481 const double corr_strength = correlation*sqrt(var2/var1);
482 return corr_strength;
487 template <
typename NUM>
488 inline typename std::enable_if<std::is_arithmetic<NUM>::value,
double>::type
490 const double cov =
covariance(sample1, sample2);
491 const double var1 =
covariance(sample1, sample1);
492 const double var2 =
covariance(sample2, sample2);
501 cov/(2*pow(3./2., var1*var2)) * (var1_e * var2 + var1 * var2_e);
504 const double corr_strength_err = correlation_err*sqrt(var2/var1) +
505 correlation/(2*sqrt(var2/var1)) * (var2_e/var1 - var2*var1_e/pow(2, var2));
507 return corr_strength_err;
520 inline double _mapAngleM2PITo2Pi(
double angle) {
521 double rtn = fmod(angle,
TWOPI);
522 if (
isZero(rtn))
return 0;
529 double rtn = _mapAngleM2PITo2Pi(angle);
530 if (
isZero(rtn))
return 0;
533 assert(rtn > -
PI && rtn <=
PI);
539 double rtn = _mapAngleM2PITo2Pi(angle);
540 if (
isZero(rtn))
return 0;
541 if (rtn < 0) rtn +=
TWOPI;
542 if (rtn ==
TWOPI) rtn = 0;
543 assert(rtn >= 0 && rtn <
TWOPI);
550 if (
isZero(rtn))
return 0;
551 assert(rtn > 0 && rtn <=
PI);
565 throw Rivet::UserError(
"The specified phi mapping scheme is not implemented");
580 return sign ? x : fabs(x);
587 const double x = eta1 - eta2;
588 return sign ? x : fabs(x);
595 const double x = y1 - y2;
596 return sign? x : fabs(x);
601 inline double deltaR2(
double rap1,
double phi1,
double rap2,
double phi2) {
602 const double dphi =
deltaPhi(phi1, phi2);
603 return sqr(rap1-rap2) +
sqr(dphi);
608 inline double deltaR(
double rap1,
double phi1,
double rap2,
double phi2) {
609 return sqrt(
deltaR2(rap1, phi1, rap2, phi2));
615 throw std::runtime_error(
"Divergent positive rapidity");
619 throw std::runtime_error(
"Divergent negative rapidity");
622 return 0.5*log((E+pz)/(E-pz));
630 inline double mT(
double pT1,
double pT2,
double dphi) {
631 return sqrt(2*pT1*pT2 * (1 - cos(dphi)) );
Definition: MC_Cent_pPb.hh:10
std::enable_if< std::is_floating_point< NUM >::value, bool >::type notNaN(NUM val)
Check if a number is non-NaN.
Definition: MathUtils.hh:43
std::enable_if< std::is_arithmetic< NUM1 >::value &&std::is_arithmetic< NUM2 >::value, int >::type binIndex(NUM1 val, std::initializer_list< NUM2 > binedges, bool allow_overflow=false)
Return the bin index of the given value, val, given a vector of bin edges.
Definition: MathUtils.hh:365
double rapidity(double E, double pz)
Calculate a rapidity value from the supplied energy E and longitudinal momentum pz.
Definition: MathUtils.hh:613
double mapAngleMPiToPi(double angle)
Map an angle into the range (-PI, PI].
Definition: MathUtils.hh:528
double safediv(double num, double den, double fail=0.0)
Definition: MathUtils.hh:228
std::enable_if< std::is_arithmetic< N1 >::value &&std::is_arithmetic< N2 >::value &&std::is_arithmetic< N3 >::value, bool >::type in_range(N1 val, N2 low, N3 high)
Boolean function to determine if value is within the given range.
Definition: MathUtils.hh:163
static const double PI
Definition: MathConstants.hh:13
Error specialisation for where the problem is between the chair and the computer. ...
Definition: Exceptions.hh:55
std::enable_if< std::is_floating_point< NUM >::value, bool >::type isNaN(NUM val)
Check if a number is NaN.
Definition: MathUtils.hh:38
double mapAngle(double angle, PhiMapping mapping)
Map an angle into the enum-specified range.
Definition: MathUtils.hh:556
std::enable_if< std::is_arithmetic< NUM >::value, NUM >::type add_quad(NUM a, NUM b)
Named number-type addition in quadrature operation.
Definition: MathUtils.hh:210
vector< double > linspace(size_t nbins, double start, double end, bool include_end=true)
Make a list of nbins + 1 values equally spaced between start and end inclusive.
Definition: MathUtils.hh:280
double cdfBW(double x, double mu, double gamma)
CDF for the Breit-Wigner distribution.
Definition: MathUtils.hh:258
vector< double > logspace(size_t nbins, double start, double end, bool include_end=true)
Make a list of nbins + 1 values exponentially spaced between start and end inclusive.
Definition: MathUtils.hh:299
double deltaEta(double eta1, double eta2, bool sign=false)
Definition: MathUtils.hh:586
std::enable_if< std::is_arithmetic< N1 >::value &&std::is_arithmetic< N2 >::value &&std::is_arithmetic< N3 >::value, bool >::type in_open_range(N1 val, N2 low, N3 high)
Boolean function to determine if value is within the given range.
Definition: MathUtils.hh:183
PhiMapping
Enum for range of to be mapped into.
Definition: MathConstants.hh:49
std::enable_if< std::is_arithmetic< NUM >::value, double >::type covariance(const vector< NUM > &sample1, const vector< NUM > &sample2)
Definition: MathUtils.hh:434
double deltaPhi(double phi1, double phi2, bool sign=false)
Calculate the difference between two angles in radians.
Definition: MathUtils.hh:578
std::enable_if< std::is_arithmetic< NUM >::value, double >::type mean_err(const vector< NUM > &sample)
Definition: MathUtils.hh:420
double angle(const Vector3 &a, const Vector3 &b)
Angle (in radians) between two 3-vectors.
Definition: Vector3.hh:294
std::enable_if< std::is_arithmetic< N1 >::value &&std::is_arithmetic< N2 >::value &&std::is_arithmetic< N3 >::value, bool >::type inRange(N1 value, N2 low, N3 high, RangeBoundary lowbound=CLOSED, RangeBoundary highbound=OPEN)
Determine if value is in the range low to high, for floating point numbers.
Definition: MathUtils.hh:112
std::enable_if< std::is_arithmetic< N1 >::value &&std::is_arithmetic< N2 >::value &&std::is_arithmetic< N3 >::value, bool >::type in_closed_range(N1 val, N2 low, N3 high)
Boolean function to determine if value is within the given range.
Definition: MathUtils.hh:173
double mT(double pT1, double pT2, double dphi)
Definition: MathUtils.hh:630
double invcdfBW(double p, double mu, double gamma)
Inverse CDF for the Breit-Wigner distribution.
Definition: MathUtils.hh:265
std::enable_if< std::is_arithmetic< N1 >::value &&std::is_arithmetic< N2 >::value &&(std::is_floating_point< N1 >::value||std::is_floating_point< N2 >::value), bool >::type fuzzyEquals(N1 a, N2 b, double tolerance=1e-5)
Compare two numbers for equality with a degree of fuzziness.
Definition: MathUtils.hh:54
static const double TWOPI
A pre-defined value of .
Definition: MathConstants.hh:16
double deltaRap(double y1, double y2, bool sign=false)
Definition: MathUtils.hh:594
double deltaR2(double rap1, double phi1, double rap2, double phi2)
Definition: MathUtils.hh:601
double deltaR(double rap1, double phi1, double rap2, double phi2)
Definition: MathUtils.hh:608
RangeBoundary
Definition: MathUtils.hh:104
double mapAngle0To2Pi(double angle)
Map an angle into the range [0, 2PI).
Definition: MathUtils.hh:538
double mapAngle0ToPi(double angle)
Map an angle into the range [0, PI].
Definition: MathUtils.hh:548
std::enable_if< std::is_arithmetic< NUM >::value, double >::type covariance_err(const vector< NUM > &sample1, const vector< NUM > &sample2)
Definition: MathUtils.hh:453
std::enable_if< std::is_floating_point< NUM >::value, bool >::type isZero(NUM val, double tolerance=1e-8)
Compare a number to zero.
Definition: MathUtils.hh:21
std::enable_if< std::is_arithmetic< NUM >::value, double >::type correlation_err(const vector< NUM > &sample1, const vector< NUM > &sample2)
Definition: MathUtils.hh:489
std::enable_if< std::is_arithmetic< NUM >::value, NUM >::type median(const vector< NUM > &sample)
Definition: MathUtils.hh:393
std::enable_if< std::is_arithmetic< NUM >::value, double >::type mean(const vector< NUM > &sample)
Definition: MathUtils.hh:407
std::enable_if< std::is_arithmetic< N1 >::value &&std::is_arithmetic< N2 >::value, bool >::type fuzzyGtrEquals(N1 a, N2 b, double tolerance=1e-5)
Compare two numbers for >= with a degree of fuzziness.
Definition: MathUtils.hh:79
std::enable_if< std::is_arithmetic< NUM >::value, NUM >::type sqr(NUM a)
Named number-type squaring operation.
Definition: MathUtils.hh:198
std::enable_if< std::is_arithmetic< NUM >::value, NUM >::type intpow(NUM val, unsigned int exp)
A more efficient version of pow for raising numbers to integer powers.
Definition: MathUtils.hh:235
Error for e.g. use of invalid bin ranges.
Definition: Exceptions.hh:22
vector< double > bwspace(size_t nbins, double start, double end, double mu, double gamma)
Make a list of nbins + 1 values spaced for equal area Breit-Wigner binning between start and end incl...
Definition: MathUtils.hh:328
std::enable_if< std::is_arithmetic< NUM >::value, int >::type sign(NUM val)
Find the sign of a number.
Definition: MathUtils.hh:245
std::enable_if< std::is_arithmetic< N1 >::value &&std::is_arithmetic< N2 >::value &&std::is_arithmetic< N3 >::value, bool >::type fuzzyInRange(N1 value, N2 low, N3 high, RangeBoundary lowbound=CLOSED, RangeBoundary highbound=OPEN)
Determine if value is in the range low to high, for floating point numbers.
Definition: MathUtils.hh:132
std::enable_if< std::is_arithmetic< N1 >::value &&std::is_arithmetic< N2 >::value, bool >::type fuzzyLessEquals(N1 a, N2 b, double tolerance=1e-5)
Compare two floating point numbers for <= with a degree of fuzziness.
Definition: MathUtils.hh:90
std::enable_if< std::is_arithmetic< NUM >::value, double >::type correlation(const vector< NUM > &sample1, const vector< NUM > &sample2)
Definition: MathUtils.hh:476