12 #include <boost/math/special_functions/ellint_1.hpp>
13 #include <boost/math/special_functions/ellint_2.hpp>
14 #include <boost/math/special_functions/ellint_3.hpp>
27 return([parentMass, masses, j](
const vector<double>& vals) -> pair<double, double> {
28 size_t N = masses.size();
32 for(
size_t idx = 0; idx < j; ++idx){
37 MjMax = vals[N-2-j] - masses[j];
40 MjMax = parentMass - masses[j];
43 return make_pair(MjMin, MjMax);
47 static double kStar(
double mParent,
double mk,
double mSibling){
48 double EStar = (mParent*mParent - mSibling*mSibling + mk*mk)/(2.* mParent);
49 return sqrt(EStar*EStar - mk*mk);
52 double phaseSpaceNBody(
const double parentMass,
const vector<double>& daughterMasses) {
53 size_t N = daughterMasses.size();
57 throw Error(
"Implementing a 1->1 decay is perhaps a poor idea.");
60 res +=
kStar(parentMass, daughterMasses[1], daughterMasses[0])/(4.*
pi*parentMass);
66 for(
size_t j = 2; j < N; ++j){
67 boundaries.push_back(
makeMjFunction(parentMass, daughterMasses, N+1-j));
73 for (
size_t i = 0; i < points.size(); ++i) {
74 double respart =
kStar(parentMass, daughterMasses[N-1], points[i][0])*weights[i]/(4.*
pi*parentMass);
75 for(
size_t j = 0; j < N-3; ++j){
76 respart *=
kStar(points[i][j], daughterMasses[N-2-j], points[i][j+1])/(4.*
pi2);
78 respart *=
kStar(points[i][N-3], daughterMasses[1], daughterMasses[0])/(4.*
pi2);
86 static double phaseSpace2(
const double m0,
const double m1,
const double m2) {
87 const double coeff = 1./(8.*
pi);
88 const double m0sq = m0*m0;
89 const double m1sq = m1*m1;
90 const double m2sq = m2*m2;
91 const double kallen = m0sq*m0sq + m1sq*m1sq + m2sq*m2sq - 2.*(m0sq*m1sq + m1sq*m2sq + m0sq*m2sq);
92 const double result = coeff * sqrt(kallen) / m0sq;
98 static double phaseSpace3(
const double m0,
const double m1,
const double m2,
const double m3) {
99 const double coeff = 1./(128.*
pi3);
101 const double m0sq = m0*m0;
102 const double m1sq = m1*m1;
103 const double m2sq = m2*m2;
104 const double m3sq = m3*m3;
106 const double sq0p3 = pow(m0 + m3, 2.);
107 const double sq0m3 = pow(m0 - m3, 2.);
108 const double sq1p2 = pow(m1 + m2, 2.);
109 const double sq1m2 = pow(m1 - m2, 2.);
111 const double qpp = sq0p3 - sq1p2;
112 const double qpm = sq0p3 - sq1m2;
113 const double qmp = sq0m3 - sq1p2;
114 const double qmm = sq0m3 - sq1m2;
116 const double Qplus = qpp * qmm;
117 const double Qminus = qmp * qpm;
119 double k =
regularize(sqrt(Qminus / Qplus), 1., 1.e-10, -1);
121 const double alpha1sq =
isZero(m1 + m2) ? 1. :
regularize(qmp / qmm, 1., 1.e-10, -1);
122 const double alpha2sq =
isZero(m1 + m2) ? 1. : sq1m2 / sq1p2 * alpha1sq;
126 const double ellipticE = boost::math::ellint_2(k);
127 const double ellipticK = boost::math::ellint_1(k);
128 const double ellipticPi1 = boost::math::ellint_3(k, alpha1sq);
129 const double ellipticPi2 = boost::math::ellint_3(k, alpha2sq);
131 const double expr = 0.5 * Qplus * (m1sq + m2sq + m3sq + m0sq) * ellipticE +
132 4. * m1 * m2 * ((sq0m3 - sq1m2) * (sq0p3 - m3 * m0 + m1 * m2) * ellipticK +
133 2. * ((m1sq + m2sq) * (m3sq + m0sq) - 2. * (m1sq * m2sq + m3sq * m0sq)) * ellipticPi1 -
134 2. * pow(m0sq - m3sq, 2.) * ellipticPi2);
136 const double result = coeff * expr / m0sq / sqrt(Qplus);
142 double phaseSpaceN(
const double parentMass,
const vector<double>& daughterMasses) {
143 switch(daughterMasses.size()) {
145 return phaseSpace2(parentMass, daughterMasses[0], daughterMasses[1]);
148 return phaseSpace3(parentMass, daughterMasses[0], daughterMasses[1], daughterMasses[2]);
151 function<double(double)> f = [parentMass, daughterMasses](
double m) ->
double {
const double f1 =
phaseSpace3(m, daughterMasses[0], daughterMasses[1], daughterMasses[2]);
152 const double f2 =
phaseSpace2(parentMass, m, daughterMasses[3]);
153 return 2*m*f1*f2/(2*
pi);
155 return integrate(f, daughterMasses[0] + daughterMasses[1] + daughterMasses[2], parentMass - daughterMasses[3]);
158 function<double(double)> f = [parentMass, daughterMasses](
double m) ->
double {
const double f1 =
phaseSpace3(m, daughterMasses[0], daughterMasses[1], daughterMasses[2]);
159 const double f2 =
phaseSpace3(parentMass, m, daughterMasses[3], daughterMasses[4]);
160 return 2*m*f1*f2/(2*
pi);
162 return integrate(f, daughterMasses[0] + daughterMasses[1] + daughterMasses[2], parentMass - daughterMasses[3] - daughterMasses[4]);
166 throw Error(
"Unimplemented phase space integral: n>5");
double integrate(std::function< double(double)> &func, double low, double high)
integration function based on gaussian method
const EvaluationWeights & getEvaluationWeights() const
static constexpr double pi2
const EvaluationGrid & getEvaluationPoints() const
returns the position of the evaluation points given an integration range
std::function< std::pair< double, double >(const std::vector< double > &)> BoundaryFunction
double phaseSpaceNBody(const double parentMass, const vector< double > &daughterMasses)
static constexpr double pi3
std::vector< BoundaryFunction > IntegrationBoundaries
static double phaseSpace2(const double m0, const double m1, const double m2)
Hammer exception definitions.
static double phaseSpace3(const double m0, const double m1, const double m2, const double m3)
static double kStar(double mParent, double mk, double mSibling)
double phaseSpaceN(const double parentMass, const vector< double > &daughterMasses)
double regularize(const double regularVal, const double problematicValue, const double delta=std::numeric_limits< double >::min(), int direction=0)
bool isZero(const std::complex< double > val)
Various numerical constants.
Hammer numerical integration classes.
static BoundaryFunction makeMjFunction(double parentMass, vector< double > masses, size_t j)
void applyRange(const IntegrationBoundaries &boundaries)
apply rescaling factor for the size of the interval from the canonical [-1,1] interval to the actual ...
std::vector< double > EvaluationWeights
std::vector< std::vector< double >> EvaluationGrid
Tensor integration class.
static constexpr double pi