MathUtils.hh
Go to the documentation of this file.
00001 // -*- C++ -*- 00002 #ifndef RIVET_MathUtils_HH 00003 #define RIVET_MathUtils_HH 00004 00005 #include "Rivet/Math/MathHeader.hh" 00006 #include <type_traits> 00007 #include <cassert> 00008 00009 namespace Rivet { 00010 00011 00012 /// @name Comparison functions for safe (floating point) equality tests 00013 //@{ 00014 00015 /// @brief Compare a number to zero 00016 /// 00017 /// This version for floating point types has a degree of fuzziness expressed 00018 /// by the absolute @a tolerance parameter, for floating point safety. 00019 template <typename NUM> 00020 inline typename std::enable_if<std::is_floating_point<NUM>::value, bool>::type 00021 isZero(NUM val, double tolerance=1e-8) { 00022 return fabs(val) < tolerance; 00023 } 00024 00025 /// @brief Compare a number to zero 00026 /// 00027 /// SFINAE template specialisation for integers, since there is no FP 00028 /// precision issue. 00029 template <typename NUM> 00030 inline typename std::enable_if<std::is_integral<NUM>::value, bool>::type 00031 isZero(NUM val, double UNUSED(tolerance)=1e-8) { 00032 return val == 0; 00033 } 00034 00035 00036 /// @brief Compare two numbers for equality with a degree of fuzziness 00037 /// 00038 /// This version for floating point types (if any argument is FP) has a degree 00039 /// of fuzziness expressed by the fractional @a tolerance parameter, for 00040 /// floating point safety. 00041 template <typename N1, typename N2> 00042 inline typename std::enable_if< 00043 std::is_arithmetic<N1>::value && std::is_arithmetic<N2>::value && 00044 (std::is_floating_point<N1>::value || std::is_floating_point<N2>::value), bool>::type 00045 fuzzyEquals(N1 a, N2 b, double tolerance=1e-5) { 00046 const double absavg = (std::abs(a) + std::abs(b))/2.0; 00047 const double absdiff = std::abs(a - b); 00048 const bool rtn = (isZero(a) && isZero(b)) || absdiff < tolerance*absavg; 00049 return rtn; 00050 } 00051 00052 /// @brief Compare two numbers for equality with a degree of fuzziness 00053 /// 00054 /// Simpler SFINAE template specialisation for integers, since there is no FP 00055 /// precision issue. 00056 template <typename N1, typename N2> 00057 inline typename std::enable_if< 00058 std::is_integral<N1>::value && std::is_integral<N2>::value, bool>::type 00059 fuzzyEquals(N1 a, N2 b, double UNUSED(tolerance)=1e-5) { 00060 return a == b; 00061 } 00062 00063 00064 /// @brief Compare two numbers for >= with a degree of fuzziness 00065 /// 00066 /// The @a tolerance parameter on the equality test is as for @c fuzzyEquals. 00067 template <typename N1, typename N2> 00068 inline typename std::enable_if< 00069 std::is_arithmetic<N1>::value && std::is_arithmetic<N2>::value, bool>::type 00070 fuzzyGtrEquals(N1 a, N2 b, double tolerance=1e-5) { 00071 return a > b || fuzzyEquals(a, b, tolerance); 00072 } 00073 00074 00075 /// @brief Compare two floating point numbers for <= with a degree of fuzziness 00076 /// 00077 /// The @a tolerance parameter on the equality test is as for @c fuzzyEquals. 00078 template <typename N1, typename N2> 00079 inline typename std::enable_if< 00080 std::is_arithmetic<N1>::value && std::is_arithmetic<N2>::value, bool>::type 00081 fuzzyLessEquals(N1 a, N2 b, double tolerance=1e-5) { 00082 return a < b || fuzzyEquals(a, b, tolerance); 00083 } 00084 00085 //@} 00086 00087 00088 /// @name Ranges and intervals 00089 //@{ 00090 00091 /// Represents whether an interval is open (non-inclusive) or closed (inclusive). 00092 /// 00093 /// For example, the interval \f$ [0, \pi) \f$ is closed (an inclusive 00094 /// boundary) at 0, and open (a non-inclusive boundary) at \f$ \pi \f$. 00095 enum RangeBoundary { OPEN=0, SOFT=0, CLOSED=1, HARD=1 }; 00096 00097 /// @brief Determine if @a value is in the range @a low to @a high, for floating point numbers 00098 /// 00099 /// Interval boundary types are defined by @a lowbound and @a highbound. 00100 template <typename N1, typename N2, typename N3> 00101 inline typename std::enable_if< 00102 std::is_arithmetic<N1>::value && std::is_arithmetic<N2>::value && std::is_arithmetic<N3>::value, bool>::type 00103 inRange(N1 value, N2 low, N3 high, 00104 RangeBoundary lowbound=CLOSED, RangeBoundary highbound=OPEN) { 00105 if (lowbound == OPEN && highbound == OPEN) { 00106 return (value > low && value < high); 00107 } else if (lowbound == OPEN && highbound == CLOSED) { 00108 return (value > low && value <= high); 00109 } else if (lowbound == CLOSED && highbound == OPEN) { 00110 return (value >= low && value < high); 00111 } else { // if (lowbound == CLOSED && highbound == CLOSED) { 00112 return (value >= low && value <= high); 00113 } 00114 } 00115 00116 /// @brief Determine if @a value is in the range @a low to @a high, for floating point numbers 00117 /// 00118 /// Interval boundary types are defined by @a lowbound and @a highbound. 00119 /// Closed intervals are compared fuzzily. 00120 template <typename N1, typename N2, typename N3> 00121 inline typename std::enable_if< 00122 std::is_arithmetic<N1>::value && std::is_arithmetic<N2>::value && std::is_arithmetic<N3>::value, bool>::type 00123 fuzzyInRange(N1 value, N2 low, N3 high, 00124 RangeBoundary lowbound=CLOSED, RangeBoundary highbound=OPEN) { 00125 if (lowbound == OPEN && highbound == OPEN) { 00126 return (value > low && value < high); 00127 } else if (lowbound == OPEN && highbound == CLOSED) { 00128 return (value > low && fuzzyLessEquals(value, high)); 00129 } else if (lowbound == CLOSED && highbound == OPEN) { 00130 return (fuzzyGtrEquals(value, low) && value < high); 00131 } else { // if (lowbound == CLOSED && highbound == CLOSED) { 00132 return (fuzzyGtrEquals(value, low) && fuzzyLessEquals(value, high)); 00133 } 00134 } 00135 00136 /// Alternative version of inRange which accepts a pair for the range arguments. 00137 template <typename N1, typename N2, typename N3> 00138 inline typename std::enable_if< 00139 std::is_arithmetic<N1>::value && std::is_arithmetic<N2>::value && std::is_arithmetic<N3>::value, bool>::type 00140 inRange(N1 value, pair<N2, N3> lowhigh, 00141 RangeBoundary lowbound=CLOSED, RangeBoundary highbound=OPEN) { 00142 return inRange(value, lowhigh.first, lowhigh.second, lowbound, highbound); 00143 } 00144 00145 00146 // Alternative forms, with snake_case names and boundary types in names rather than as args -- from MCUtils 00147 00148 /// @brief Boolean function to determine if @a value is within the given range 00149 /// 00150 /// @note The interval is closed (inclusive) at the low end, and open (exclusive) at the high end. 00151 template <typename N1, typename N2, typename N3> 00152 inline typename std::enable_if< 00153 std::is_arithmetic<N1>::value && std::is_arithmetic<N2>::value && std::is_arithmetic<N3>::value, bool>::type 00154 in_range(N1 val, N2 low, N3 high) { 00155 return inRange(val, low, high, CLOSED, OPEN); 00156 } 00157 00158 /// @brief Boolean function to determine if @a value is within the given range 00159 /// 00160 /// @note The interval is closed at both ends. 00161 template <typename N1, typename N2, typename N3> 00162 inline typename std::enable_if< 00163 std::is_arithmetic<N1>::value && std::is_arithmetic<N2>::value && std::is_arithmetic<N3>::value, bool>::type 00164 in_closed_range(N1 val, N2 low, N3 high) { 00165 return inRange(val, low, high, CLOSED, CLOSED); 00166 } 00167 00168 /// @brief Boolean function to determine if @a value is within the given range 00169 /// 00170 /// @note The interval is open at both ends. 00171 template <typename N1, typename N2, typename N3> 00172 inline typename std::enable_if< 00173 std::is_arithmetic<N1>::value && std::is_arithmetic<N2>::value && std::is_arithmetic<N3>::value, bool>::type 00174 in_open_range(N1 val, N2 low, N3 high) { 00175 return inRange(val, low, high, OPEN, OPEN); 00176 } 00177 00178 /// @todo Add pair-based versions of the named range-boundary functions 00179 00180 //@} 00181 00182 00183 /// @name Miscellaneous numerical helpers 00184 //@{ 00185 00186 /// Named number-type squaring operation. 00187 template <typename NUM> 00188 inline typename std::enable_if<std::is_arithmetic<NUM>::value, NUM>::type 00189 sqr(NUM a) { 00190 return a*a; 00191 } 00192 00193 /// @brief Named number-type addition in quadrature operation. 00194 /// 00195 /// @note Result has the sqrt operation applied. 00196 /// @todo When std::common_type can be used, generalise to multiple numeric types with appropriate return type. 00197 // template <typename N1, typename N2> 00198 template <typename NUM> 00199 inline typename std::enable_if<std::is_arithmetic<NUM>::value, NUM>::type 00200 //std::common_type<N1, N2>::type 00201 add_quad(NUM a, NUM b) { 00202 return sqrt(a*a + b*b); 00203 } 00204 00205 /// Named number-type addition in quadrature operation. 00206 /// 00207 /// @note Result has the sqrt operation applied. 00208 /// @todo When std::common_type can be used, generalise to multiple numeric types with appropriate return type. 00209 // template <typename N1, typename N2> 00210 template <typename NUM> 00211 inline typename std::enable_if<std::is_arithmetic<NUM>::value, NUM>::type 00212 //std::common_type<N1, N2, N3>::type 00213 add_quad(NUM a, NUM b, NUM c) { 00214 return sqrt(a*a + b*b + c*c); 00215 } 00216 00217 /// Return a/b, or @a fail if b = 0 00218 /// @todo When std::common_type can be used, generalise to multiple numeric types with appropriate return type. 00219 inline double safediv(double num, double den, double fail=0.0) { 00220 return (!isZero(den)) ? num/den : fail; 00221 } 00222 00223 /// A more efficient version of pow for raising numbers to integer powers. 00224 template <typename NUM> 00225 inline typename std::enable_if<std::is_arithmetic<NUM>::value, NUM>::type 00226 intpow(NUM val, unsigned int exp) { 00227 assert(exp >= 0); 00228 if (exp == 0) return (NUM) 1; 00229 else if (exp == 1) return val; 00230 return val * intpow(val, exp-1); 00231 } 00232 00233 /// Find the sign of a number 00234 template <typename NUM> 00235 inline typename std::enable_if<std::is_arithmetic<NUM>::value, int>::type 00236 sign(NUM val) { 00237 if (isZero(val)) return ZERO; 00238 const int valsign = (val > 0) ? PLUS : MINUS; 00239 return valsign; 00240 } 00241 00242 //@} 00243 00244 00245 /// @name Physics statistical distributions 00246 //@{ 00247 00248 /// @brief CDF for the Breit-Wigner distribution 00249 inline double cdfBW(double x, double mu, double gamma) { 00250 // normalize to (0;1) distribution 00251 const double xn = (x - mu)/gamma; 00252 return std::atan(xn)/M_PI + 0.5; 00253 } 00254 00255 /// @brief Inverse CDF for the Breit-Wigner distribution 00256 inline double invcdfBW(double p, double mu, double gamma) { 00257 const double xn = std::tan(M_PI*(p-0.5)); 00258 return gamma*xn + mu; 00259 } 00260 00261 //@} 00262 00263 00264 /// @name Binning helper functions 00265 //@{ 00266 00267 /// @brief Make a list of @a nbins + 1 values equally spaced between @a start and @a end inclusive. 00268 /// 00269 /// NB. The arg ordering and the meaning of the nbins variable is "histogram-like", 00270 /// as opposed to the Numpy/Matlab version. 00271 inline vector<double> linspace(size_t nbins, double start, double end, bool include_end=true) { 00272 assert(end >= start); 00273 assert(nbins > 0); 00274 vector<double> rtn; 00275 const double interval = (end-start)/static_cast<double>(nbins); 00276 for (size_t i = 0; i < nbins; ++i) { 00277 rtn.push_back(start + i*interval); 00278 } 00279 assert(rtn.size() == nbins); 00280 if (include_end) rtn.push_back(end); //< exact end, not result of n * interval 00281 return rtn; 00282 } 00283 00284 00285 /// @brief Make a list of @a nbins + 1 values exponentially spaced between @a start and @a end inclusive. 00286 /// 00287 /// NB. The arg ordering and the meaning of the nbins variable is "histogram-like", 00288 /// as opposed to the Numpy/Matlab version, and the start and end arguments are expressed 00289 /// in "normal" space, rather than as the logarithms of the start/end values as in Numpy/Matlab. 00290 inline vector<double> logspace(size_t nbins, double start, double end, bool include_end=true) { 00291 assert(end >= start); 00292 assert(start > 0); 00293 assert(nbins > 0); 00294 const double logstart = std::log(start); 00295 const double logend = std::log(end); 00296 const vector<double> logvals = linspace(nbins, logstart, logend, false); 00297 assert(logvals.size() == nbins); 00298 vector<double> rtn; rtn.reserve(nbins+1); 00299 rtn.push_back(start); //< exact start, not exp(log(start)) 00300 for (size_t i = 1; i < logvals.size(); ++i) { 00301 rtn.push_back(std::exp(logvals[i])); 00302 } 00303 assert(rtn.size() == nbins); 00304 if (include_end) rtn.push_back(end); //< exact end, not exp(n * loginterval) 00305 return rtn; 00306 } 00307 00308 00309 /// @brief Make a list of @a nbins + 1 values spaced for equal area 00310 /// Breit-Wigner binning between @a start and @a end inclusive. @a 00311 /// mu and @a gamma are the Breit-Wigner parameters. 00312 /// 00313 /// @note The arg ordering and the meaning of the nbins variable is "histogram-like", 00314 /// as opposed to the Numpy/Matlab version, and the start and end arguments are expressed 00315 /// in "normal" space. 00316 inline vector<double> bwspace(size_t nbins, double start, double end, double mu, double gamma) { 00317 assert(end >= start); 00318 assert(nbins > 0); 00319 const double pmin = cdfBW(start, mu, gamma); 00320 const double pmax = cdfBW(end, mu, gamma); 00321 const vector<double> edges = linspace(nbins, pmin, pmax); 00322 assert(edges.size() == nbins+1); 00323 vector<double> rtn; 00324 for (double edge : edges) { 00325 rtn.push_back(invcdfBW(edge, mu, gamma)); 00326 } 00327 assert(rtn.size() == nbins+1); 00328 return rtn; 00329 } 00330 00331 00332 /// @brief Return the bin index of the given value, @a val, given a vector of bin edges 00333 /// 00334 /// @note The @a binedges vector must be sorted 00335 /// @todo Use std::common_type<NUM1, NUM2>::type x = val; ? 00336 template <typename NUM1, typename NUM2> 00337 inline typename std::enable_if<std::is_arithmetic<NUM1>::value && std::is_floating_point<NUM2>::value, int>::type 00338 binIndex(NUM1 val, const vector<NUM2>& binedges, bool allow_overflow=false) { 00339 if (val < binedges.front()) return -1; ///< Below/out of histo range 00340 if (val >= binedges.back()) return allow_overflow ? int(binedges.size())-1 : -1; ///< Above/out of histo range 00341 return std::distance(binedges.begin(), --std::upper_bound(binedges.begin(), binedges.end(), val)); 00342 // 00343 // int index = -1; 00344 // for (size_t i = 1; i < binedges.size(); ++i) { 00345 // if (val < binedges[i]) { 00346 // index = i-1; 00347 // break; 00348 // } 00349 // } 00350 // assert(inRange(index, -1, int(binedges.size())-1)); 00351 // return index; 00352 } 00353 00354 //@} 00355 00356 00357 /// @name Discrete statistics functions 00358 //@{ 00359 00360 /// Calculate the median of a sample 00361 /// @todo Support multiple container types via SFINAE 00362 template <typename NUM> 00363 inline typename std::enable_if<std::is_arithmetic<NUM>::value, NUM>::type 00364 median(const vector<NUM>& sample) { 00365 if (sample.empty()) throw RangeError("Can't compute median of an empty set"); 00366 vector<NUM> tmp = sample; 00367 std::sort(tmp.begin(), tmp.end()); 00368 const size_t imid = tmp.size()/2; // len1->idx0, len2->idx1, len3->idx1, len4->idx2, ... 00369 if (sample.size() % 2 == 0) return (tmp.at(imid-1) + tmp.at(imid)) / 2.0; 00370 else return tmp.at(imid); 00371 } 00372 00373 00374 /// Calculate the mean of a sample 00375 /// @todo Support multiple container types via SFINAE 00376 template <typename NUM> 00377 inline typename std::enable_if<std::is_arithmetic<NUM>::value, double>::type 00378 mean(const vector<NUM>& sample) { 00379 if (sample.empty()) throw RangeError("Can't compute mean of an empty set"); 00380 double mean = 0.0; 00381 for (size_t i = 0; i < sample.size(); ++i) { 00382 mean += sample[i]; 00383 } 00384 return mean/sample.size(); 00385 } 00386 00387 // Calculate the error on the mean, assuming Poissonian errors 00388 /// @todo Support multiple container types via SFINAE 00389 template <typename NUM> 00390 inline typename std::enable_if<std::is_arithmetic<NUM>::value, double>::type 00391 mean_err(const vector<NUM>& sample) { 00392 if (sample.empty()) throw RangeError("Can't compute mean_err of an empty set"); 00393 double mean_e = 0.0; 00394 for (size_t i = 0; i < sample.size(); ++i) { 00395 mean_e += sqrt(sample[i]); 00396 } 00397 return mean_e/sample.size(); 00398 } 00399 00400 00401 /// Calculate the covariance (variance) between two samples 00402 /// @todo Support multiple container types via SFINAE 00403 template <typename NUM> 00404 inline typename std::enable_if<std::is_arithmetic<NUM>::value, double>::type 00405 covariance(const vector<NUM>& sample1, const vector<NUM>& sample2) { 00406 if (sample1.empty() || sample2.empty()) throw RangeError("Can't compute covariance of an empty set"); 00407 if (sample1.size() != sample2.size()) throw RangeError("Sizes of samples must be equal for covariance calculation"); 00408 const double mean1 = mean(sample1); 00409 const double mean2 = mean(sample2); 00410 const size_t N = sample1.size(); 00411 double cov = 0.0; 00412 for (size_t i = 0; i < N; i++) { 00413 const double cov_i = (sample1[i] - mean1)*(sample2[i] - mean2); 00414 cov += cov_i; 00415 } 00416 if (N > 1) return cov/(N-1); 00417 else return 0.0; 00418 } 00419 00420 /// Calculate the error on the covariance (variance) of two samples, assuming poissonian errors 00421 /// @todo Support multiple container types via SFINAE 00422 template <typename NUM> 00423 inline typename std::enable_if<std::is_arithmetic<NUM>::value, double>::type 00424 covariance_err(const vector<NUM>& sample1, const vector<NUM>& sample2) { 00425 if (sample1.empty() || sample2.empty()) throw RangeError("Can't compute covariance_err of an empty set"); 00426 if (sample1.size() != sample2.size()) throw RangeError("Sizes of samples must be equal for covariance_err calculation"); 00427 const double mean1 = mean(sample1); 00428 const double mean2 = mean(sample2); 00429 const double mean1_e = mean_err(sample1); 00430 const double mean2_e = mean_err(sample2); 00431 const size_t N = sample1.size(); 00432 double cov_e = 0.0; 00433 for (size_t i = 0; i < N; i++) { 00434 const double cov_i = (sqrt(sample1[i]) - mean1_e)*(sample2[i] - mean2) + 00435 (sample1[i] - mean1)*(sqrt(sample2[i]) - mean2_e); 00436 cov_e += cov_i; 00437 } 00438 if (N > 1) return cov_e/(N-1); 00439 else return 0.0; 00440 } 00441 00442 00443 /// Calculate the correlation strength between two samples 00444 /// @todo Support multiple container types via SFINAE 00445 template <typename NUM> 00446 inline typename std::enable_if<std::is_arithmetic<NUM>::value, double>::type 00447 correlation(const vector<NUM>& sample1, const vector<NUM>& sample2) { 00448 const double cov = covariance(sample1, sample2); 00449 const double var1 = covariance(sample1, sample1); 00450 const double var2 = covariance(sample2, sample2); 00451 const double correlation = cov/sqrt(var1*var2); 00452 const double corr_strength = correlation*sqrt(var2/var1); 00453 return corr_strength; 00454 } 00455 00456 /// Calculate the error of the correlation strength between two samples assuming Poissonian errors 00457 /// @todo Support multiple container types via SFINAE 00458 template <typename NUM> 00459 inline typename std::enable_if<std::is_arithmetic<NUM>::value, double>::type 00460 correlation_err(const vector<NUM>& sample1, const vector<NUM>& sample2) { 00461 const double cov = covariance(sample1, sample2); 00462 const double var1 = covariance(sample1, sample1); 00463 const double var2 = covariance(sample2, sample2); 00464 const double cov_e = covariance_err(sample1, sample2); 00465 const double var1_e = covariance_err(sample1, sample1); 00466 const double var2_e = covariance_err(sample2, sample2); 00467 00468 // Calculate the correlation 00469 const double correlation = cov/sqrt(var1*var2); 00470 // Calculate the error on the correlation 00471 const double correlation_err = cov_e/sqrt(var1*var2) - 00472 cov/(2*pow(3./2., var1*var2)) * (var1_e * var2 + var1 * var2_e); 00473 00474 // Calculate the error on the correlation strength 00475 const double corr_strength_err = correlation_err*sqrt(var2/var1) + 00476 correlation/(2*sqrt(var2/var1)) * (var2_e/var1 - var2*var1_e/pow(2, var2)); 00477 00478 return corr_strength_err; 00479 } 00480 00481 //@} 00482 00483 00484 /// @name Angle range mappings 00485 //@{ 00486 00487 /// @brief Reduce any number to the range [-2PI, 2PI] 00488 /// 00489 /// Achieved by repeated addition or subtraction of 2PI as required. Used to 00490 /// normalise angular measures. 00491 inline double _mapAngleM2PITo2Pi(double angle) { 00492 double rtn = fmod(angle, TWOPI); 00493 if (isZero(rtn)) return 0; 00494 assert(rtn >= -TWOPI && rtn <= TWOPI); 00495 return rtn; 00496 } 00497 00498 /// Map an angle into the range (-PI, PI]. 00499 inline double mapAngleMPiToPi(double angle) { 00500 double rtn = _mapAngleM2PITo2Pi(angle); 00501 if (isZero(rtn)) return 0; 00502 if (rtn > PI) rtn -= TWOPI; 00503 if (rtn <= -PI) rtn += TWOPI; 00504 assert(rtn > -PI && rtn <= PI); 00505 return rtn; 00506 } 00507 00508 /// Map an angle into the range [0, 2PI). 00509 inline double mapAngle0To2Pi(double angle) { 00510 double rtn = _mapAngleM2PITo2Pi(angle); 00511 if (isZero(rtn)) return 0; 00512 if (rtn < 0) rtn += TWOPI; 00513 if (rtn == TWOPI) rtn = 0; 00514 assert(rtn >= 0 && rtn < TWOPI); 00515 return rtn; 00516 } 00517 00518 /// Map an angle into the range [0, PI]. 00519 inline double mapAngle0ToPi(double angle) { 00520 double rtn = fabs(mapAngleMPiToPi(angle)); 00521 if (isZero(rtn)) return 0; 00522 assert(rtn > 0 && rtn <= PI); 00523 return rtn; 00524 } 00525 00526 /// Map an angle into the enum-specified range. 00527 inline double mapAngle(double angle, PhiMapping mapping) { 00528 switch (mapping) { 00529 case MINUSPI_PLUSPI: 00530 return mapAngleMPiToPi(angle); 00531 case ZERO_2PI: 00532 return mapAngle0To2Pi(angle); 00533 case ZERO_PI: 00534 return mapAngle0To2Pi(angle); 00535 default: 00536 throw Rivet::UserError("The specified phi mapping scheme is not implemented"); 00537 } 00538 } 00539 00540 //@} 00541 00542 00543 /// @name Phase space measure helpers 00544 //@{ 00545 00546 /// @brief Calculate the difference between two angles in radians 00547 /// 00548 /// Returns in the range [0, PI]. 00549 inline double deltaPhi(double phi1, double phi2) { 00550 return mapAngle0ToPi(phi1 - phi2); 00551 } 00552 00553 /// Calculate the abs difference between two pseudorapidities 00554 /// 00555 /// @note Just a cosmetic name for analysis code clarity. 00556 inline double deltaEta(double eta1, double eta2) { 00557 return fabs(eta1 - eta2); 00558 } 00559 00560 /// Calculate the abs difference between two rapidities 00561 /// 00562 /// @note Just a cosmetic name for analysis code clarity. 00563 inline double deltaRap(double y1, double y2) { 00564 return fabs(y1 - y2); 00565 } 00566 00567 /// Calculate the distance between two points in 2D rapidity-azimuthal 00568 /// ("\f$ \eta-\phi \f$") space. The phi values are given in radians. 00569 inline double deltaR(double rap1, double phi1, double rap2, double phi2) { 00570 const double dphi = deltaPhi(phi1, phi2); 00571 return sqrt( sqr(rap1-rap2) + sqr(dphi) ); 00572 } 00573 00574 /// Calculate a rapidity value from the supplied energy @a E and longitudinal momentum @a pz. 00575 inline double rapidity(double E, double pz) { 00576 if (isZero(E - pz)) { 00577 throw std::runtime_error("Divergent positive rapidity"); 00578 return MAXDOUBLE; 00579 } 00580 if (isZero(E + pz)) { 00581 throw std::runtime_error("Divergent negative rapidity"); 00582 return -MAXDOUBLE; 00583 } 00584 return 0.5*log((E+pz)/(E-pz)); 00585 } 00586 00587 //@} 00588 00589 00590 } 00591 00592 00593 #endif Generated on Tue Dec 13 2016 16:32:38 for The Rivet MC analysis system by ![]() |