46#include <TRestWimpUtils.h>
54 const double reducedMass = GetReducedMass(wimpMass, Anum);
55 const double reducedMassSingle = GetReducedMass(wimpMass, 1.);
56 return (Anum * reducedMass / reducedMassSingle) * (Anum * reducedMass / reducedMassSingle);
63const double TRestWimpUtils::GetReducedMass(
const double wimpMass,
const double Anum) {
73const double TRestWimpUtils::GetHelmFormFactor(
const double recoilEnergy,
const double Anum) {
75 const double q = sqrt(2. * Anum *
GEV_PER_UMA * 1E6 * recoilEnergy);
77 const double qs = q * s / HC_KEV_FM;
79 const double RN = sqrt(pow(1.23 * std::cbrt(Anum) - 0.60, 2) +
80 (7. / 3.) * pow(TMath::Pi(), 2) * 0.52 * 0.52 - 5. * s * s);
81 const double qR = q * RN / HC_KEV_FM;
83 const double bessel1 = sin(qR) / (qR * qR) - cos(qR) / qR;
85 double formFactor = 3. * bessel1 / qR * exp(-0.5 * qs * qs);
95const double TRestWimpUtils::GetVMin(
const double wimpMass,
const double Anum,
const double recoilEnergy) {
96 const double reducedMass = GetReducedMass(wimpMass, Anum);
97 return sqrt(Anum *
GEV_PER_UMA * recoilEnergy * 1E-6 / (2. * reducedMass * reducedMass)) * LIGHT_SPEED;
105const double TRestWimpUtils::GetVelocityDistribution(
const double v,
const double vLab,
const double vRMS,
106 const double vEscape) {
107 if (v > vLab + vEscape)
return 0;
109 const double vAdim = vEscape / vRMS;
111 erf(vAdim) - 2. / sqrt(TMath::Pi()) * vAdim *
116 std::max(-1., std::min(1., (vEscape * vEscape - vLab * vLab - v * v) / (2. * vLab * v)));
118 return v / Nesc / (vLab * vRMS * sqrt(TMath::Pi())) *
119 (exp(-(v - vLab) * (v - vLab) / (vRMS * vRMS)) -
120 exp(-(v * v + vLab * vLab + 2 * v * vLab * xMax) / (vRMS * vRMS)));
131const double TRestWimpUtils::GetDifferentialCrossSectionNoHelmFormFactor(
const double wimpMass,
132 const double crossSection,
133 const double velocity,
136 const double reducedMass = GetReducedMass(wimpMass, Anum);
137 const double Emax = 1E6 / LIGHT_SPEED / LIGHT_SPEED * 2. * reducedMass * reducedMass * velocity *
150const double TRestWimpUtils::GetDifferentialCrossSection(
const double wimpMass,
const double crossSection,
151 const double velocity,
const double recoilEnergy,
153 const double formFactor = GetHelmFormFactor(recoilEnergy, Anum);
155 return GetDifferentialCrossSectionNoHelmFormFactor(wimpMass, crossSection, velocity, Anum) * formFactor *
164const double TRestWimpUtils::GetRecoilRate(
const double wimpMass,
const double crossSection,
165 const double recoilEnergy,
const double Anum,
const double vLab,
166 const double vRMS,
const double vEscape,
const double wimpDensity,
167 const double abundance) {
168 const double vMin = GetVMin(wimpMass, Anum, recoilEnergy);
169 const double vMax = vEscape + vLab;
170 const double nNuclei = abundance * N_AVOGADRO * 1E3 / Anum;
172 if (vMin > vMax)
return 0;
175 const double velStep = 0.1;
177 for (
double v = vMin; v < vMax; v += velStep) {
178 const double flux = 1E5 * v * wimpDensity / wimpMass;
179 const double diffRate = flux *
180 GetDifferentialCrossSection(wimpMass, crossSection, v, recoilEnergy, Anum) *
181 GetVelocityDistribution(v, vLab, vRMS, vEscape);
182 rate += diffRate * velStep;
185 return rate * SECONDS_PER_DAY * nNuclei;
192const double TRestWimpUtils::GetQuenchingFactor(
const double recoilEnergy,
const double Anum,
194 const double deltaE = 0.0001, Emin = 0.1, resolution = 0.1;
195 double g, Er = recoilEnergy, Ev;
199 g = 0.66 * pow(Znum, 5. / 18.) / sqrt(Anum) * pow(recoilEnergy, 1. / 6.);
200 }
while ((Er / (1 + g) * g) > Emin);
204 g = 0.66 * pow(Znum, 5. / 18.) / sqrt(Anum) * pow(Er, 1. / 6.);
205 Ev = (Er / (1 + g) * g);
206 }
while (recoilEnergy > Ev);
223std::map<std::string, int> TRestWimpUtils::ParseChemicalCompound(
const std::string& compound) {
224 std::map<std::string, int> elementMap;
225 std::string elementName;
227 std::pair<int, int> parenthesisCount = {0, 0};
228 for (
size_t i = 0; i < compound.size();) {
229 if (compound[i] ==
'(') parenthesisCount.first++;
230 if (compound[i] ==
')') parenthesisCount.second++;
233 if (parenthesisCount.first != parenthesisCount.second) {
234 std::cout <<
"Error: Parentheses in compound " << compound <<
" do not match." << std::endl;
238 for (
size_t i = 0; i < compound.size();) {
241 if (std::isupper(compound[i])) {
242 elementName = compound[i];
246 while (i < compound.size() && std::islower(compound[i])) {
247 elementName += compound[i];
252 if (i < compound.size() && std::isdigit(compound[i])) {
254 while (i < compound.size() && std::isdigit(compound[i])) {
255 coefficient = coefficient * 10 + (compound[i] -
'0');
260 elementMap[elementName] += coefficient;
261 }
else if (compound[i] ==
'(') {
263 std::string subCompound;
264 while (i < compound.size()) {
265 if (compound[i] ==
')') {
266 if (parenthesisCount.second > 1)
267 parenthesisCount.second--;
271 subCompound += compound[i];
277 if (i < compound.size() && std::isdigit(compound[i])) {
279 while (i < compound.size() && std::isdigit(compound[i])) {
280 coefficient = coefficient * 10 + (compound[i] -
'0');
285 std::map<std::string, int> subElementMap = ParseChemicalCompound(subCompound);
286 for (
auto& pair : subElementMap) {
287 elementMap[pair.first] += pair.second * coefficient;
constexpr double GEV_PER_UMA
Physics constants.
const double GetRelativeNuclearCS(const double wimpMass, const double Anum)
Generic functions for different calculations.