61
61
// / <parameter name="rmsVelocity" value="220"/>
62
62
// / <parameter name="escapeVelocity" value="544"/>
63
63
// / <parameter name="exposure" value="116.8"/>
64
- // / <parameter name="backgroundLevel " value="1"/>
64
+ // / <parameter name="background " value="1"/>
65
65
// / <parameter name="energySpectra" value="(0,2)"/>
66
66
// / <parameter name="energySpectraStep" value="0.01"/>
67
67
// / <parameter name="energyRange" value="(0.1,1.1)"/>
@@ -177,6 +177,7 @@ void TRestWimpSensitivity::ReadNuclei() {
177
177
// /////////////////////////////////////////////
178
178
// / \brief Get recoil spectra for a given WIMP
179
179
// / mass and cross section
180
+ // / Better performance version
180
181
// /
181
182
std::map<std::string, TH1D*> TRestWimpSensitivity::GetRecoilSpectra (const double wimpMass,
182
183
const double crossSection) {
@@ -188,16 +189,76 @@ std::map<std::string, TH1D*> TRestWimpSensitivity::GetRecoilSpectra(const double
188
189
std::string histName = " RecoilSpc_" + std::string (nucl.fNucleusName );
189
190
TH1D* recoilSpc =
190
191
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++) {
192
249
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
+ }
197
258
}
259
+
198
260
recoilMap[std::string (nucl.fNucleusName )] = recoilSpc;
199
261
}
200
-
201
262
return recoilMap;
202
263
}
203
264
@@ -211,19 +272,48 @@ const Double_t TRestWimpSensitivity::GetSensitivity(const double wimpMass) {
211
272
212
273
if (fUseQuenchingFactor ) CalculateQuenchingFactor ();
213
274
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 ;
215
281
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
+ }
217
299
218
300
double bckCounts = 0 ;
219
301
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);
222
305
if (en < fEnergyRange .X () || en > fEnergyRange .Y ()) continue ;
223
306
bckCounts += fBackground * fEnergySpectraStep ;
224
307
}
225
308
bckCounts *= fExposure ;
226
309
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
+
227
317
double signalCounts = 0 , prob = 0 ;
228
318
229
319
do {
@@ -237,35 +327,10 @@ const Double_t TRestWimpSensitivity::GetSensitivity(const double wimpMass) {
237
327
signalCounts++;
238
328
} while (fabs (prob - 0.1 ) > 0.01 && signalCounts < 1E6 );
239
329
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
-
267
330
const double sensitivity = signalCounts * 1E-45 / (nMeas * fExposure );
268
331
332
+ RESTExtreme << " sigCounts = " << signalCounts << RESTendl;
333
+
269
334
return sensitivity;
270
335
}
271
336
@@ -274,7 +339,17 @@ const Double_t TRestWimpSensitivity::GetSensitivity(const double wimpMass) {
274
339
// / stores in a map
275
340
// /
276
341
void 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
+ }
278
353
279
354
std::cout << " Calculating quenching factor " << std::endl;
280
355
@@ -296,6 +371,21 @@ void TRestWimpSensitivity::CalculateQuenchingFactor() {
296
371
}
297
372
}
298
373
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
+
299
389
// /////////////////////////////////////////////
300
390
// / \brief Return output file format with different
301
391
// / parameters used in the calculation.
@@ -309,6 +399,7 @@ const std::string TRestWimpSensitivity::BuildOutputFileName(const std::string& e
309
399
ss << " WD_" << fWimpDensity << " _" ;
310
400
ss << " Vel_" << fLabVelocity << " _" << fRmsVelocity << " _" << fEscapeVelocity << " _" ;
311
401
ss << " Bck_" << fBackground << " _" ;
402
+ ss << " Exp_" << fExposure << " _" ;
312
403
ss << " RecEn_" << fEnergySpectra .X () << " _" << fEnergySpectra .Y () << " _" << fEnergySpectraStep << " _" ;
313
404
ss << " EnRange_" << fEnergyRange .X () << " _" << fEnergyRange .Y () << " _" ;
314
405
@@ -366,6 +457,6 @@ void TRestWimpSensitivity::PrintMetadata() {
366
457
<< " ) Step: " << fEnergySpectraStep << " keV" << RESTendl;
367
458
RESTMetadata << " Sensitivity energy range: (" << fEnergyRange .X () << " , " << fEnergyRange .Y () << " ) keV"
368
459
<< RESTendl;
369
- RESTMetadata << " Use quenching factor: " << fUseQuenchingFactor << RESTendl;
460
+ RESTMetadata << " Use quenching factor: " << ( fUseQuenchingFactor ? " true " : " false " ) << RESTendl;
370
461
RESTMetadata << " +++++" << RESTendl;
371
462
}
0 commit comments