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 "Rivet/Tools/RivetBoost.hh" 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 boost::enable_if_c<boost::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 boost::enable_if_c<boost::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 boost::enable_if_c< 00043 boost::is_arithmetic<N1>::value && boost::is_arithmetic<N2>::value && 00044 (boost::is_floating_point<N1>::value || boost::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 boost::enable_if_c< 00058 boost::is_integral<N1>::value && boost::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 boost::enable_if_c< 00069 boost::is_arithmetic<N1>::value && boost::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 boost::enable_if_c< 00080 boost::is_arithmetic<N1>::value && boost::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 boost::enable_if_c< 00102 boost::is_arithmetic<N1>::value && boost::is_arithmetic<N2>::value && boost::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 boost::enable_if_c< 00122 boost::is_arithmetic<N1>::value && boost::is_arithmetic<N2>::value && boost::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 boost::enable_if_c< 00139 boost::is_arithmetic<N1>::value && boost::is_arithmetic<N2>::value && boost::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 boost::enable_if_c< 00153 boost::is_arithmetic<N1>::value && boost::is_arithmetic<N2>::value && boost::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 boost::enable_if_c< 00163 boost::is_arithmetic<N1>::value && boost::is_arithmetic<N2>::value && boost::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 boost::enable_if_c< 00173 boost::is_arithmetic<N1>::value && boost::is_arithmetic<N2>::value && boost::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 boost::enable_if_c<boost::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 boost::enable_if_c<boost::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 boost::enable_if_c<boost::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 boost::enable_if_c<boost::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 boost::enable_if_c<boost::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 double edge = start; 00277 for (size_t i = 0; i < nbins; ++i) { 00278 rtn.push_back(edge); 00279 edge += interval; 00280 } 00281 assert(rtn.size() == nbins); 00282 if (include_end) rtn.push_back(end); // exact end, not result of n * interval 00283 return rtn; 00284 } 00285 00286 00287 /// @brief Make a list of @a nbins + 1 values exponentially spaced between @a start and @a end inclusive. 00288 /// 00289 /// NB. The arg ordering and the meaning of the nbins variable is "histogram-like", 00290 /// as opposed to the Numpy/Matlab version, and the start and end arguments are expressed 00291 /// in "normal" space, rather than as the logarithms of the start/end values as in Numpy/Matlab. 00292 inline vector<double> logspace(size_t nbins, double start, double end, bool include_end=true) { 00293 assert(end >= start); 00294 assert(start > 0); 00295 assert(nbins > 0); 00296 const double logstart = std::log(start); 00297 const double logend = std::log(end); 00298 const vector<double> logvals = linspace(nbins, logstart, logend); 00299 assert(logvals.size() == nbins+1); 00300 vector<double> rtn; rtn.reserve(logvals.size()); 00301 rtn.push_back(start); 00302 for (size_t i = 1; i < logvals.size()-1; ++i) { 00303 rtn.push_back(std::exp(logvals[i])); 00304 } 00305 assert(rtn.size() == nbins); 00306 if (include_end) rtn.push_back(end); 00307 return rtn; 00308 } 00309 00310 00311 /// @brief Make a list of @a nbins + 1 values spaced for equal area 00312 /// Breit-Wigner binning between @a start and @a end inclusive. @a 00313 /// mu and @a gamma are the Breit-Wigner parameters. 00314 /// 00315 /// @note The arg ordering and the meaning of the nbins variable is "histogram-like", 00316 /// as opposed to the Numpy/Matlab version, and the start and end arguments are expressed 00317 /// in "normal" space. 00318 inline vector<double> bwspace(size_t nbins, double start, double end, double mu, double gamma) { 00319 assert(end >= start); 00320 assert(nbins > 0); 00321 const double pmin = cdfBW(start, mu, gamma); 00322 const double pmax = cdfBW(end, mu, gamma); 00323 const vector<double> edges = linspace(nbins, pmin, pmax); 00324 assert(edges.size() == nbins+1); 00325 vector<double> rtn; 00326 foreach (double edge, edges) { 00327 rtn.push_back(invcdfBW(edge, mu, gamma)); 00328 } 00329 assert(rtn.size() == nbins+1); 00330 return rtn; 00331 } 00332 00333 00334 /// @brief Return the bin index of the given value, @a val, given a vector of bin edges 00335 /// 00336 /// NB. The @a binedges vector must be sorted 00337 template <typename NUM1, typename NUM2> 00338 inline typename boost::enable_if_c<boost::is_arithmetic<NUM1>::value && boost::is_floating_point<NUM2>::value, int>::type 00339 binIndex(NUM1 val, const vector<NUM2>& binedges) { 00340 /// @todo Use std::common_type<NUM1, NUM2>::type x = val; ? 00341 /// @todo Add linear & log guesses, and binary split via upper_bound for large binnings 00342 if (!inRange(val, binedges.front(), binedges.back())) return -1; ///< Out of histo range 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 template <typename NUM> 00362 inline typename boost::enable_if_c<boost::is_arithmetic<NUM>::value, NUM>::type 00363 median(const vector<NUM>& sample) { 00364 vector<NUM> tmp = sample; 00365 std::sort(tmp.begin(), tmp.end()); 00366 const size_t imid = tmp.size()/2; // len1->idx0, len2->idx1, len3->idx1, len4->idx2, ... 00367 if (sample.size() % 2 == 0) return (tmp.at(imid-1) + tmp.at(imid)) / 2.0; 00368 else return tmp.at(imid); 00369 } 00370 00371 00372 /// Calculate the mean of a sample 00373 template <typename NUM> 00374 inline typename boost::enable_if_c<boost::is_arithmetic<NUM>::value, double>::type 00375 mean(const vector<NUM>& sample) { 00376 double mean = 0.0; 00377 for (size_t i = 0; i < sample.size(); ++i) { 00378 mean += sample[i]; 00379 } 00380 return mean/sample.size(); 00381 } 00382 00383 // Calculate the error on the mean, assuming Poissonian errors 00384 template <typename NUM> 00385 inline typename boost::enable_if_c<boost::is_arithmetic<NUM>::value, double>::type 00386 mean_err(const vector<NUM>& sample) { 00387 double mean_e = 0.0; 00388 for (size_t i = 0; i < sample.size(); ++i) { 00389 mean_e += sqrt(sample[i]); 00390 } 00391 return mean_e/sample.size(); 00392 } 00393 00394 00395 /// Calculate the covariance (variance) between two samples 00396 template <typename NUM> 00397 inline typename boost::enable_if_c<boost::is_arithmetic<NUM>::value, double>::type 00398 covariance(const vector<NUM>& sample1, const vector<NUM>& sample2) { 00399 const double mean1 = mean(sample1); 00400 const double mean2 = mean(sample2); 00401 const size_t N = sample1.size(); 00402 double cov = 0.0; 00403 for (size_t i = 0; i < N; i++) { 00404 const double cov_i = (sample1[i] - mean1)*(sample2[i] - mean2); 00405 cov += cov_i; 00406 } 00407 if (N > 1) return cov/(N-1); 00408 else return 0.0; 00409 } 00410 00411 /// Calculate the error on the covariance (variance) of two samples, assuming poissonian errors 00412 template <typename NUM> 00413 inline typename boost::enable_if_c<boost::is_arithmetic<NUM>::value, double>::type 00414 covariance_err(const vector<NUM>& sample1, const vector<NUM>& sample2) { 00415 const double mean1 = mean(sample1); 00416 const double mean2 = mean(sample2); 00417 const double mean1_e = mean_err(sample1); 00418 const double mean2_e = mean_err(sample2); 00419 const size_t N = sample1.size(); 00420 double cov_e = 0.0; 00421 for (size_t i = 0; i < N; i++) { 00422 const double cov_i = (sqrt(sample1[i]) - mean1_e)*(sample2[i] - mean2) + 00423 (sample1[i] - mean1)*(sqrt(sample2[i]) - mean2_e); 00424 cov_e += cov_i; 00425 } 00426 if (N > 1) return cov_e/(N-1); 00427 else return 0.0; 00428 } 00429 00430 00431 /// Calculate the correlation strength between two samples 00432 template <typename NUM> 00433 inline typename boost::enable_if_c<boost::is_arithmetic<NUM>::value, double>::type 00434 correlation(const vector<NUM>& sample1, const vector<NUM>& sample2) { 00435 const double cov = covariance(sample1, sample2); 00436 const double var1 = covariance(sample1, sample1); 00437 const double var2 = covariance(sample2, sample2); 00438 const double correlation = cov/sqrt(var1*var2); 00439 const double corr_strength = correlation*sqrt(var2/var1); 00440 return corr_strength; 00441 } 00442 00443 /// Calculate the error of the correlation strength between two samples assuming Poissonian errors 00444 template <typename NUM> 00445 inline typename boost::enable_if_c<boost::is_arithmetic<NUM>::value, double>::type 00446 correlation_err(const vector<NUM>& sample1, const vector<NUM>& sample2) { 00447 const double cov = covariance(sample1, sample2); 00448 const double var1 = covariance(sample1, sample1); 00449 const double var2 = covariance(sample2, sample2); 00450 const double cov_e = covariance_err(sample1, sample2); 00451 const double var1_e = covariance_err(sample1, sample1); 00452 const double var2_e = covariance_err(sample2, sample2); 00453 00454 // Calculate the correlation 00455 const double correlation = cov/sqrt(var1*var2); 00456 // Calculate the error on the correlation 00457 const double correlation_err = cov_e/sqrt(var1*var2) - 00458 cov/(2*pow(3./2., var1*var2)) * (var1_e * var2 + var1 * var2_e); 00459 00460 // Calculate the error on the correlation strength 00461 const double corr_strength_err = correlation_err*sqrt(var2/var1) + 00462 correlation/(2*sqrt(var2/var1)) * (var2_e/var1 - var2*var1_e/pow(2, var2)); 00463 00464 return corr_strength_err; 00465 } 00466 00467 //@} 00468 00469 00470 /// @name Angle range mappings 00471 //@{ 00472 00473 /// @brief Reduce any number to the range [-2PI, 2PI] 00474 /// 00475 /// Achieved by repeated addition or subtraction of 2PI as required. Used to 00476 /// normalise angular measures. 00477 inline double _mapAngleM2PITo2Pi(double angle) { 00478 double rtn = fmod(angle, TWOPI); 00479 if (isZero(rtn)) return 0; 00480 assert(rtn >= -TWOPI && rtn <= TWOPI); 00481 return rtn; 00482 } 00483 00484 /// Map an angle into the range (-PI, PI]. 00485 inline double mapAngleMPiToPi(double angle) { 00486 double rtn = _mapAngleM2PITo2Pi(angle); 00487 if (isZero(rtn)) return 0; 00488 if (rtn > PI) rtn -= TWOPI; 00489 if (rtn <= -PI) rtn += TWOPI; 00490 assert(rtn > -PI && rtn <= PI); 00491 return rtn; 00492 } 00493 00494 /// Map an angle into the range [0, 2PI). 00495 inline double mapAngle0To2Pi(double angle) { 00496 double rtn = _mapAngleM2PITo2Pi(angle); 00497 if (isZero(rtn)) return 0; 00498 if (rtn < 0) rtn += TWOPI; 00499 if (rtn == TWOPI) rtn = 0; 00500 assert(rtn >= 0 && rtn < TWOPI); 00501 return rtn; 00502 } 00503 00504 /// Map an angle into the range [0, PI]. 00505 inline double mapAngle0ToPi(double angle) { 00506 double rtn = fabs(mapAngleMPiToPi(angle)); 00507 if (isZero(rtn)) return 0; 00508 assert(rtn > 0 && rtn <= PI); 00509 return rtn; 00510 } 00511 00512 /// Map an angle into the enum-specified range. 00513 inline double mapAngle(double angle, PhiMapping mapping) { 00514 switch (mapping) { 00515 case MINUSPI_PLUSPI: 00516 return mapAngleMPiToPi(angle); 00517 case ZERO_2PI: 00518 return mapAngle0To2Pi(angle); 00519 case ZERO_PI: 00520 return mapAngle0To2Pi(angle); 00521 default: 00522 throw Rivet::UserError("The specified phi mapping scheme is not implemented"); 00523 } 00524 } 00525 00526 //@} 00527 00528 00529 /// @name Phase space measure helpers 00530 //@{ 00531 00532 /// @brief Calculate the difference between two angles in radians 00533 /// 00534 /// Returns in the range [0, PI]. 00535 inline double deltaPhi(double phi1, double phi2) { 00536 return mapAngle0ToPi(phi1 - phi2); 00537 } 00538 00539 /// Calculate the abs difference between two pseudorapidities 00540 /// 00541 /// @note Just a cosmetic name for analysis code clarity. 00542 inline double deltaEta(double eta1, double eta2) { 00543 return fabs(eta1 - eta2); 00544 } 00545 00546 /// Calculate the abs difference between two rapidities 00547 /// 00548 /// @note Just a cosmetic name for analysis code clarity. 00549 inline double deltaRap(double y1, double y2) { 00550 return fabs(y1 - y2); 00551 } 00552 00553 /// Calculate the distance between two points in 2D rapidity-azimuthal 00554 /// ("\f$ \eta-\phi \f$") space. The phi values are given in radians. 00555 inline double deltaR(double rap1, double phi1, double rap2, double phi2) { 00556 const double dphi = deltaPhi(phi1, phi2); 00557 return sqrt( sqr(rap1-rap2) + sqr(dphi) ); 00558 } 00559 00560 /// Calculate a rapidity value from the supplied energy @a E and longitudinal momentum @a pz. 00561 inline double rapidity(double E, double pz) { 00562 if (isZero(E - pz)) { 00563 throw std::runtime_error("Divergent positive rapidity"); 00564 return MAXDOUBLE; 00565 } 00566 if (isZero(E + pz)) { 00567 throw std::runtime_error("Divergent negative rapidity"); 00568 return -MAXDOUBLE; 00569 } 00570 return 0.5*log((E+pz)/(E-pz)); 00571 } 00572 00573 //@} 00574 00575 00576 } 00577 00578 00579 #endif Generated on Thu Mar 10 2016 08:29:51 for The Rivet MC analysis system by ![]() |