6161// / <parameter name="rmsVelocity" value="220"/>
6262// / <parameter name="escapeVelocity" value="544"/>
6363// / <parameter name="exposure" value="116.8"/>
64- // / <parameter name="backgroundLevel " value="1"/>
64+ // / <parameter name="background " value="1"/>
6565// / <parameter name="energySpectra" value="(0,2)"/>
6666// / <parameter name="energySpectraStep" value="0.01"/>
6767// / <parameter name="energyRange" value="(0.1,1.1)"/>
@@ -177,6 +177,7 @@ void TRestWimpSensitivity::ReadNuclei() {
177177// /////////////////////////////////////////////
178178// / \brief Get recoil spectra for a given WIMP
179179// / mass and cross section
180+ // / Better performance version
180181// /
181182std::map<std::string, TH1D*> TRestWimpSensitivity::GetRecoilSpectra (const double wimpMass,
182183 const double crossSection) {
@@ -188,16 +189,76 @@ std::map<std::string, TH1D*> TRestWimpSensitivity::GetRecoilSpectra(const double
188189 std::string histName = " RecoilSpc_" + std::string (nucl.fNucleusName );
189190 TH1D* recoilSpc =
190191 new TH1D (histName.c_str (), histName.c_str (), nBins, fEnergySpectra .X (), fEnergySpectra .Y ());
191- for (int i = 1 ; i < recoilSpc->GetNbinsX (); i++) {
192+
193+ // Build vector of tuples=(recoilEnergy, minimum velocity, rate) used in further calculations
194+ std::vector<std::tuple<double , double , double >> tEnergyVminRate;
195+ for (int i = 0 ; i < recoilSpc->GetNbinsX (); i++) {
196+ double E = recoilSpc->GetBinCenter (i);
197+ if (E <= 0 ) continue ;
198+ tEnergyVminRate.push_back (
199+ std::make_tuple (E, TRestWimpUtils::GetVMin (wimpMass, nucl.fAnum , E), 0 ));
200+ }
201+
202+ const double nNuclei =
203+ nucl.fAbundance * TRestWimpUtils::N_AVOGADRO * 1E3 / nucl.fAnum ; // Number of atoms
204+ const double vMin = std::get<1 >(
205+ tEnergyVminRate.at (0 )); // element 0 should be the lowest (positive) energy -> lowest vMin
206+ const double vMax = fEscapeVelocity + fLabVelocity ;
207+
208+ // calculation of the rate for each recoil energy
209+ double rate{0 }; // will contain integral from minimun vMin to vMax, idem integral_min(vMin)^vMax
210+ const double velStep = 0.1 ; // km/s
211+ int j = 0 ;
212+ double flux = 0 , diffRate = 0 , v = 0 ;
213+ // vMax+velStep to save the rate when v is in interval (vMax-velStep, vMax]
214+ for (v = vMin; v < vMax + velStep; v += velStep) {
215+ // save (in 3rd element of tEnergyVminRate tuples) the integral from minimun vMin to each vMin,
216+ // idem integral_min(vMin)^vMin
217+ while (j < (int )tEnergyVminRate.size ()) {
218+ const double vmin = std::get<1 >(tEnergyVminRate.at (j));
219+ if (vmin < v) {
220+ // std::get<2>(tEnergyVminRate.at(j)) = rate; //les precise
221+ std::get<2 >(tEnergyVminRate.at (j)) = rate - diffRate * (v - vmin); // more precise
222+ j++;
223+ } else
224+ break ;
225+ }
226+ flux = 1E5 * v * fWimpDensity / wimpMass;
227+ diffRate =
228+ flux *
229+ TRestWimpUtils::GetDifferentialCrossSectionNoHelmFormFactor (wimpMass, crossSection, v,
230+ nucl.fAnum ) *
231+ TRestWimpUtils::GetVelocityDistribution (v, fLabVelocity , fRmsVelocity , fEscapeVelocity );
232+ rate += diffRate * velStep;
233+ }
234+ rate -=
235+ diffRate * (v - vMax); // substract last diffRate*(v - vMax) to obtain the rate from vMin to vMax
236+
237+ /* obtain the rate (integral from each vMin to vMax) by substracting integral from minimun vMin to each
238+ vMin to the integral from minimun vMin to vMax
239+ idem: integral_vMin^vMax = integral_min(vMin)^vMax - integral_min(vMin)^vMin */
240+ for (auto & [E, vmin, r] : tEnergyVminRate) {
241+ if (vmin > vMax) continue ; // r=0
242+ const double formFactor = TRestWimpUtils::GetHelmFormFactor (E, nucl.fAnum );
243+ r = (rate - r) * formFactor * formFactor * TRestWimpUtils::SECONDS_PER_DAY * nNuclei;
244+ }
245+
246+ // copy results to recoilMap
247+ j = 0 ;
248+ for (int i = 0 ; i < recoilSpc->GetNbinsX (); i++) {
192249 const double recoilEnergy = recoilSpc->GetBinCenter (i);
193- const double recoilRate =
194- TRestWimpUtils::GetRecoilRate (wimpMass, crossSection, recoilEnergy, nucl.fAnum , fLabVelocity ,
195- fRmsVelocity , fEscapeVelocity , fWimpDensity , nucl.fAbundance );
196- recoilSpc->SetBinContent (i, recoilRate);
250+ // const double recoilRate = std::get<2> (tEnergyVminRate.at(i));
251+ while (j < (int )tEnergyVminRate.size ()) {
252+ if (recoilEnergy == std::get<0 >(tEnergyVminRate.at (j))) {
253+ recoilSpc->SetBinContent (i, std::get<2 >(tEnergyVminRate.at (j)));
254+ j++;
255+ } else
256+ break ;
257+ }
197258 }
259+
198260 recoilMap[std::string (nucl.fNucleusName )] = recoilSpc;
199261 }
200-
201262 return recoilMap;
202263}
203264
@@ -211,19 +272,48 @@ const Double_t TRestWimpSensitivity::GetSensitivity(const double wimpMass) {
211272
212273 if (fUseQuenchingFactor ) CalculateQuenchingFactor ();
213274
214- const int nBins = (fEnergySpectra .Y () - fEnergySpectra .X ()) / fEnergySpectraStep ;
275+ if (!isEnergySpectraWideEnough ()) {
276+ RESTError << " Energy spectra range is not wide enough to match the energy range given." << RESTendl;
277+ // return 0;
278+ }
279+
280+ double nMeas = 0 ;
215281
216- TH1D recoilSpc (" recoilSpc" , " recoilSpc" , nBins, fEnergySpectra .X (), fEnergySpectra .Y ());
282+ const double crossSection = 1E-45 ;
283+ auto rSpc = GetRecoilSpectra (wimpMass, crossSection);
284+
285+ for (auto & nucl : fNuclei ) {
286+ auto recoilSpc = rSpc[std::string (nucl.fNucleusName )];
287+
288+ for (int i = 1 ; i < recoilSpc->GetNbinsX (); i++) {
289+ double recoilEnergy = recoilSpc->GetBinCenter (i);
290+ const double recoilRate = recoilSpc->GetBinContent (i);
291+
292+ if (fUseQuenchingFactor )
293+ recoilEnergy *= quenchingFactor[std::string (nucl.fNucleusName )]->GetBinContent (i);
294+
295+ if (recoilEnergy < fEnergyRange .X () || recoilEnergy > fEnergyRange .Y ()) continue ;
296+ nMeas += recoilRate * fEnergySpectraStep ;
297+ }
298+ }
217299
218300 double bckCounts = 0 ;
219301
220- for (int i = 1 ; i < recoilSpc.GetNbinsX (); i++) {
221- const double en = recoilSpc.GetBinCenter (i);
302+ auto recSpc = rSpc[std::string (fNuclei .front ().fNucleusName )];
303+ for (int i = 1 ; i < recSpc->GetNbinsX (); i++) {
304+ const double en = recSpc->GetBinCenter (i);
222305 if (en < fEnergyRange .X () || en > fEnergyRange .Y ()) continue ;
223306 bckCounts += fBackground * fEnergySpectraStep ;
224307 }
225308 bckCounts *= fExposure ;
226309
310+ for (auto & [name, histo] : rSpc) delete histo;
311+ rSpc.clear ();
312+
313+ RESTExtreme << " nMeas = " << nMeas << " c/kg/day" << RESTendl;
314+ RESTExtreme << " bckCounts = " << bckCounts << RESTendl;
315+ if (nMeas == 0 ) return 0 ;
316+
227317 double signalCounts = 0 , prob = 0 ;
228318
229319 do {
@@ -237,35 +327,10 @@ const Double_t TRestWimpSensitivity::GetSensitivity(const double wimpMass) {
237327 signalCounts++;
238328 } while (fabs (prob - 0.1 ) > 0.01 && signalCounts < 1E6 );
239329
240- double nMeas = 0 ;
241- const double crossSection = 1E-45 ;
242-
243- for (auto & nucl : fNuclei ) {
244- recoilSpc.Reset ();
245-
246- for (int i = 1 ; i < recoilSpc.GetNbinsX (); i++) {
247- const double recoilEnergy = recoilSpc.GetBinCenter (i);
248- const double recoilRate =
249- TRestWimpUtils::GetRecoilRate (wimpMass, crossSection, recoilEnergy, nucl.fAnum , fLabVelocity ,
250- fRmsVelocity , fEscapeVelocity , fWimpDensity , nucl.fAbundance );
251- recoilSpc.SetBinContent (i, recoilRate);
252- }
253-
254- for (int i = 1 ; i < recoilSpc.GetNbinsX (); i++) {
255- double recoilEnergy = recoilSpc.GetBinCenter (i);
256- // const double recoilRate = recoilSpc.GetBinContent(i);
257- if (fUseQuenchingFactor )
258- recoilEnergy *= quenchingFactor[std::string (nucl.fNucleusName )]->GetBinContent (i);
259-
260- if (recoilEnergy < fEnergyRange .X () || recoilEnergy > fEnergyRange .Y ()) continue ;
261- nMeas += recoilSpc.GetBinContent (i) * fEnergySpectraStep ;
262- }
263- }
264-
265- if (nMeas == 0 ) return 0 ;
266-
267330 const double sensitivity = signalCounts * 1E-45 / (nMeas * fExposure );
268331
332+ RESTExtreme << " sigCounts = " << signalCounts << RESTendl;
333+
269334 return sensitivity;
270335}
271336
@@ -274,7 +339,17 @@ const Double_t TRestWimpSensitivity::GetSensitivity(const double wimpMass) {
274339// / stores in a map
275340// /
276341void TRestWimpSensitivity::CalculateQuenchingFactor () {
277- if (!quenchingFactor.empty ()) return ;
342+ // do not calculate if already calculated (with same energy spectra limits)
343+ if (!quenchingFactor.empty ()) {
344+ bool same = true ;
345+ for (auto & [name, histo] : quenchingFactor)
346+ if (histo->GetXaxis ()->GetXmin () != fEnergySpectra .X () ||
347+ histo->GetXaxis ()->GetXmax () != fEnergySpectra .Y ()) {
348+ same = false ;
349+ break ;
350+ }
351+ if (same) return ;
352+ }
278353
279354 std::cout << " Calculating quenching factor " << std::endl;
280355
@@ -296,6 +371,21 @@ void TRestWimpSensitivity::CalculateQuenchingFactor() {
296371 }
297372}
298373
374+ bool TRestWimpSensitivity::isEnergySpectraWideEnough () {
375+ if (!fUseQuenchingFactor )
376+ return fEnergySpectra .X () <= fEnergyRange .X () && fEnergySpectra .Y () >= fEnergyRange .Y ();
377+
378+ CalculateQuenchingFactor ();
379+ for (auto & nucl : fNuclei ) {
380+ auto qf = quenchingFactor[std::string (nucl.fNucleusName )];
381+ // assuming that Energy_nr * QF(Energy_nr) is a monotonically increasing function
382+ if (qf->GetBinContent (1 ) * qf->GetBinCenter (1 ) > fEnergyRange .X () ||
383+ qf->GetBinContent (qf->GetNbinsX () - 1 ) * qf->GetBinCenter (qf->GetNbinsX () - 1 ) < fEnergyRange .Y ())
384+ return false ;
385+ }
386+ return true ;
387+ }
388+
299389// /////////////////////////////////////////////
300390// / \brief Return output file format with different
301391// / parameters used in the calculation.
@@ -309,6 +399,7 @@ const std::string TRestWimpSensitivity::BuildOutputFileName(const std::string& e
309399 ss << " WD_" << fWimpDensity << " _" ;
310400 ss << " Vel_" << fLabVelocity << " _" << fRmsVelocity << " _" << fEscapeVelocity << " _" ;
311401 ss << " Bck_" << fBackground << " _" ;
402+ ss << " Exp_" << fExposure << " _" ;
312403 ss << " RecEn_" << fEnergySpectra .X () << " _" << fEnergySpectra .Y () << " _" << fEnergySpectraStep << " _" ;
313404 ss << " EnRange_" << fEnergyRange .X () << " _" << fEnergyRange .Y () << " _" ;
314405
@@ -366,6 +457,6 @@ void TRestWimpSensitivity::PrintMetadata() {
366457 << " ) Step: " << fEnergySpectraStep << " keV" << RESTendl;
367458 RESTMetadata << " Sensitivity energy range: (" << fEnergyRange .X () << " , " << fEnergyRange .Y () << " ) keV"
368459 << RESTendl;
369- RESTMetadata << " Use quenching factor: " << fUseQuenchingFactor << RESTendl;
460+ RESTMetadata << " Use quenching factor: " << ( fUseQuenchingFactor ? " true " : " false " ) << RESTendl;
370461 RESTMetadata << " +++++" << RESTendl;
371462}
0 commit comments