122#include "TRestWimpSensitivity.h"
124#include "TRestWimpUtils.h"
172 bool anyAbundanceGivenInMol =
false;
175 TiXmlElement* ElementDef =
GetElement(
"addElement");
183 !ElementDef->Attribute(
"abundance") ?
"Not defined" : ElementDef->Attribute(
"abundance");
186 el = !ElementDef->Attribute(
"abundanceInMol") ?
"Not defined"
187 : ElementDef->Attribute(
"abundanceInMol");
188 if (!(el.empty() || el ==
"Not defined")) {
190 anyAbundanceGivenInMol =
true;
199 RESTError <<
"abundance or abundanceInMol not defined for nucleus " << nucleus.
fNucleusName
207 TiXmlElement* CompoundDef =
GetElement(
"addCompound");
208 while (CompoundDef) {
209 bool compoundAbundanceGivenInMol =
false;
210 std::string compoundName =
GetFieldValue(
"compoundName", CompoundDef);
211 double compoundAbundance = 0, compoundAbundanceInMol = 0;
212 double totalMolMass = 0;
215 !CompoundDef->Attribute(
"abundance") ?
"Not defined" : CompoundDef->Attribute(
"abundance");
216 if (!(el.empty() || el ==
"Not defined")) compoundAbundance =
StringToDouble(el);
218 el = !CompoundDef->Attribute(
"abundanceInMol") ?
"Not defined"
219 : CompoundDef->Attribute(
"abundanceInMol");
220 if (!(el.empty() || el ==
"Not defined")) {
222 compoundAbundanceGivenInMol =
true;
223 anyAbundanceGivenInMol =
true;
226 if (compoundAbundance == 0 && compoundAbundanceInMol == 0) {
227 RESTWarning <<
"abundance or abundanceInMol not defined for compound " << compoundName
228 <<
". Setting its abundanceInMol to 1 " <<
RESTendl;
229 compoundAbundanceInMol = 1;
233 TiXmlElement* ElementDef =
GetElement(
"addElement", CompoundDef);
246 if (compoundAbundanceGivenInMol)
247 compoundAbundance = compoundAbundanceInMol * totalMolMass;
249 compoundAbundanceInMol = compoundAbundance / totalMolMass;
253 int stechiometricFactor = nucleus.GetStechiometricFactorFromCompound(compoundName);
254 nucleus.fAbundanceMol = compoundAbundanceInMol * stechiometricFactor;
255 nucleus.fAbundance = nucleus.fAbundanceMol * nucleus.fAnum;
262 std::map<std::tuple<TString, Double_t, Int_t>,
TRestWimpNucleus> uniqueNucleiMap;
263 for (
const auto& nucleus :
fNuclei) {
264 auto key = std::make_tuple(nucleus.fNucleusName, nucleus.fAnum, nucleus.fZnum);
265 if (uniqueNucleiMap.find(key) != uniqueNucleiMap.end()) {
266 uniqueNucleiMap[key].fAbundance += nucleus.fAbundance;
267 uniqueNucleiMap[key].fAbundanceMol += nucleus.fAbundanceMol;
269 uniqueNucleiMap[key] = nucleus;
272 for (
const auto& entry : uniqueNucleiMap)
fNuclei.push_back(entry.second);
275 if (anyAbundanceGivenInMol) {
277 for (
auto& nucl :
fNuclei) sumMass += nucl.fAbundance;
278 for (
auto& nucl :
fNuclei) nucl.fAbundance /= sumMass;
281 for (
auto& nucl :
fNuclei) nucl.PrintNucleus();
291 const double crossSection) {
292 std::map<std::string, TH1D*> recoilMap;
297 std::string histName =
"RecoilSpc_" + std::string(nucl.fNucleusName);
302 std::vector<std::tuple<double, double, double>> tEnergyVminRate;
303 for (
int i = 0; i < recoilSpc->GetNbinsX(); i++) {
304 double E = recoilSpc->GetBinCenter(i);
305 if (E <= 0)
continue;
306 tEnergyVminRate.push_back(
307 std::make_tuple(E, TRestWimpUtils::GetVMin(wimpMass, nucl.fAnum, E), 0));
310 const double nNuclei =
311 nucl.fAbundance * TRestWimpUtils::N_AVOGADRO * 1E3 / nucl.fAnum;
312 const double vMin = std::get<1>(
313 tEnergyVminRate.at(0));
318 const double velStep = 0.1;
320 double flux = 0, diffRate = 0, v = 0;
322 for (v = vMin; v < vMax + velStep; v += velStep) {
325 while (j < (
int)tEnergyVminRate.size()) {
326 const double vmin = std::get<1>(tEnergyVminRate.at(j));
329 std::get<2>(tEnergyVminRate.at(j)) = rate - diffRate * (v - vmin);
337 TRestWimpUtils::GetDifferentialCrossSectionNoHelmFormFactor(wimpMass, crossSection, v,
340 rate += diffRate * velStep;
343 diffRate * (v - vMax);
348 for (
auto& [E, vmin, r] : tEnergyVminRate) {
349 if (vmin > vMax)
continue;
350 const double formFactor = TRestWimpUtils::GetHelmFormFactor(E, nucl.fAnum);
351 r = (rate - r) * formFactor * formFactor * TRestWimpUtils::SECONDS_PER_DAY * nNuclei;
356 for (
int i = 0; i < recoilSpc->GetNbinsX(); i++) {
357 const double recoilEnergy = recoilSpc->GetBinCenter(i);
359 while (j < (
int)tEnergyVminRate.size()) {
360 if (recoilEnergy == std::get<0>(tEnergyVminRate.at(j))) {
361 recoilSpc->SetBinContent(i, std::get<2>(tEnergyVminRate.at(j)));
368 recoilMap[std::string(nucl.fNucleusName)] = recoilSpc;
378 RESTError <<
"Please add at least one element to the rml file" <<
RESTendl;
383 if (!isEnergySpectraWideEnough()) {
384 RESTError <<
"Energy spectra range is not wide enough to match the energy range given." <<
RESTendl;
390 const double crossSection = 1E-45;
394 auto recoilSpc = rSpc[std::string(nucl.fNucleusName)];
396 for (
int i = 1; i < recoilSpc->GetNbinsX(); i++) {
397 double recoilEnergy = recoilSpc->GetBinCenter(i);
398 const double recoilRate = recoilSpc->GetBinContent(i);
401 recoilEnergy *=
quenchingFactor[std::string(nucl.fNucleusName)]->GetBinContent(i);
408 double bckCounts = 0;
410 auto recSpc = rSpc[std::string(
fNuclei.front().fNucleusName)];
411 for (
int i = 1; i < recSpc->GetNbinsX(); i++) {
412 const double en = recSpc->GetBinCenter(i);
418 for (
auto& [name, histo] : rSpc)
delete histo;
421 RESTExtreme <<
"nMeas = " << nMeas <<
" c/kg/day" <<
RESTendl;
422 RESTExtreme <<
"bckCounts = " << bckCounts <<
RESTendl;
423 if (nMeas == 0)
return 0;
425 double signalCounts = 0, prob = 0;
429 for (
int mu = signalCounts; mu < (signalCounts + bckCounts + 10000); mu++) {
430 if (bckCounts <= 1.e3)
431 prob += TMath::Poisson(mu + bckCounts, bckCounts);
432 else if (bckCounts > 1.e3)
433 prob += TMath::Gaus(mu + bckCounts, bckCounts, TMath::Sqrt(bckCounts),
true);
436 }
while (fabs(prob - 0.1) > 0.01 && signalCounts < 1E6);
438 const double sensitivity = signalCounts * 1E-45 / (nMeas *
fExposure);
440 RESTExtreme <<
"sigCounts = " << signalCounts <<
RESTendl;
462 std::cout <<
"Calculating quenching factor " << std::endl;
467 std::string histName =
"QF_" + std::string(nucl.fNucleusName);
470 for (
int i = 1; i < QF->GetNbinsX(); i++) {
471 const double recoilEnergy = QF->GetBinCenter(i);
472 const double qF = TRestWimpUtils::GetQuenchingFactor(recoilEnergy, nucl.fAnum, nucl.fZnum);
473 if (!isnan(qF) && qF > 0)
474 QF->SetBinContent(i, 1. / qF);
476 QF->SetBinContent(i, 0);
482bool TRestWimpSensitivity::isEnergySpectraWideEnough() {
490 if (qf->GetBinContent(1) * qf->GetBinCenter(1) >
fEnergyRange.X() ||
491 qf->GetBinContent(qf->GetNbinsX() - 1) * qf->GetBinCenter(qf->GetNbinsX() - 1) <
fEnergyRange.Y())
502 std::stringstream ss;
503 ss <<
"WimpSensitivity_";
505 for (
auto& nucl :
fNuclei) ss << nucl.fNucleusName <<
"_" << nucl.fAbundance <<
"_";
521 std::cout <<
"Output File " << ss.str() << std::endl;
531 std::map<std::string, TH1D*> formFactor;
536 std::string histName =
"FF_" + std::string(nucl.fNucleusName);
539 for (
int i = 1; i < FF->GetNbinsX(); i++) {
540 const double recoilEnergy = FF->GetBinCenter(i);
541 const double helmFF = TRestWimpUtils::GetHelmFormFactor(recoilEnergy, nucl.fAnum);
542 FF->SetBinContent(i, helmFF * helmFF);
544 formFactor[std::string(nucl.fNucleusName)] = FF;
557 for (
auto& nucl :
fNuclei) nucl.PrintNucleus();
569 RESTMetadata <<
"+++++" <<
RESTendl;
A class to store different nucleus parameters.
Double_t fAnum
Atomic number in amus.
int GetStechiometricFactorFromCompound(const std::string &compound)
Get the stechiometric factor of this nucleus in a given compound.
TString fNucleusName
Nucleus name.
Double_t fAbundance
Abundance, in mass percentage.
Int_t fZnum
Number of protons.
Double_t fAbundanceMol
Abundance, in mole (or volume)
void Initialize() override
Initialization of TRestWimpSensitivity members.
Double_t fExposure
Detector exposure in kg*day.
~TRestWimpSensitivity()
Default destructor.
void InitFromConfigFile() override
Initialization of TRestWimpSensitivity members through a RML file.
std::map< std::string, TH1D * > GetRecoilSpectra(const double wimpMass, const double crossSection)
Get recoil spectra for a given WIMP mass and cross section Better performance version (velocity integ...
Double_t fEscapeVelocity
WIMP escape velocity (km/s)
TVector2 fEnergySpectra
Energy range for the recoil spectra in keV.
Double_t fEnergySpectraStep
Energy step for the recoil spectra in keV.
void PrintMetadata() override
Prints on screen the details about WIMP parameters, stored in TRestWimpSensitivity.
const Double_t GetSensitivity(const double wimpMass)
Get sensitivity for a give WIMP mass.
TVector2 fEnergyRange
Energy range for the sensitivity prospects in keV.
Double_t fBackground
Detector background level in c/keV/day.
std::map< std::string, TH1D * > quenchingFactor
Map containing quenching factor for a nucleus.
void CalculateQuenchingFactor()
Calculate Quenching factor and stores in a map.
Bool_t fUseQuenchingFactor
Use or not quenching factor.
Double_t fRmsVelocity
WIMP RMS velocity (km/s)
Double_t fWimpDensity
WIMP density in GeV/cm3.
Double_t fLabVelocity
WIMP velocity in the lab (Earth) frame reference in km/s.
void ReadNuclei()
Initialization of TRestWimpSensitivity members through a RML file.
TRestWimpSensitivity(const char *configFilename, const std::string &name="")
Constructor loading data from a config file.
std::map< std::string, TH1D * > GetFormFactor()
Return a map of histograms with the Form Factor of the different elements.
const std::string BuildOutputFileName(const std::string &extension=".txt")
Return output file format with different parameters used in the calculation.
std::vector< TRestWimpNucleus > fNuclei
A vector containing TRestWimpNucleus with different nucleus parameters.
Double_t StringToDouble(std::string in)
Gets a double from a string.
Int_t StringToInteger(std::string in)
Gets an integer from a string.