REST-for-Physics  v2.3
Rare Event Searches ToolKit for Physics
TRestSensitivity.cxx
1/*************************************************************************
2 * This file is part of the REST software framework. *
3 * *
4 * Copyright (C) 2016 GIFNA/TREX (University of Zaragoza) *
5 * For more information see https://gifna.unizar.es/trex *
6 * *
7 * REST is free software: you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation, either version 3 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * REST is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have a copy of the GNU General Public License along with *
18 * REST in $REST_PATH/LICENSE. *
19 * If not, see https://www.gnu.org/licenses/. *
20 * For the list of contributors see $REST_PATH/CREDITS. *
21 *************************************************************************/
22
41#include <TRestExperimentList.h>
42#include <TRestSensitivity.h>
43
44ClassImp(TRestSensitivity);
45
50
55
70TRestSensitivity::TRestSensitivity(const char* cfgFileName, const std::string& name)
71 : TRestMetadata(cfgFileName) {
73}
74
79void TRestSensitivity::Initialize() { SetSectionName(this->ClassName()); }
80
86Double_t TRestSensitivity::ApproachByFactor(Double_t node, Double_t g4, Double_t chi0, Double_t target,
87 Double_t factor) {
88 if (factor == 1) {
89 return 0;
90 }
91
93 Double_t Chi2 = 0;
94 do {
95 Chi2 = 0;
96 for (const auto& exp : fExperiments) Chi2 += -2 * UnbinnedLogLikelihood(exp, node, g4);
97
98 g4 = factor * g4;
99 } while (Chi2 - chi0 < target);
100 g4 = g4 / factor;
101
103 do {
104 Chi2 = 0;
105 for (const auto& exp : fExperiments) Chi2 += -2 * UnbinnedLogLikelihood(exp, node, g4);
106
107 g4 = g4 / factor;
108 } while (Chi2 - chi0 > target);
109
110 return g4 * factor;
111}
112
113void TRestSensitivity::GenerateCurve() {
115
116 if (GetNumberOfCurves() > 0)
117 for (const auto& exp : fExperiments) {
118 exp->GenerateMockDataSet();
119 }
120
121 RESTInfo << "Generating sensitivity curve" << RESTendl;
122 std::vector<Double_t> curve;
123 for (const auto& node : fParameterizationNodes) {
124 RESTInfo << "Generating node : " << node << RESTendl;
125 curve.push_back(GetCoupling(node));
126 }
127 fCurves.push_back(curve);
128
129 RESTInfo << "Curve has been generated. You may use now TRestSensitivity::ExportCurve( fname.txt )."
130 << RESTendl;
131}
132
133void TRestSensitivity::GenerateCurves(Int_t N) {
134 for (int n = 0; n < N; n++) GenerateCurve();
135}
136
137std::vector<Double_t> TRestSensitivity::GetCurve(size_t n) {
138 if (n >= GetNumberOfCurves()) {
139 RESTWarning << "Requested curve number : " << n << " but only " << GetNumberOfCurves() << " generated"
140 << RESTendl;
141 return std::vector<Double_t>();
142 }
143 return fCurves[n];
144}
145
146std::vector<Double_t> TRestSensitivity::GetAveragedCurve() {
147 if (GetNumberOfCurves() <= 0) return std::vector<Double_t>();
148
149 std::vector<double> averagedCurve(fCurves[0].size(), 0.0); // Initialize with zeros
150
151 for (const auto& row : fCurves) {
152 for (size_t i = 0; i < row.size(); ++i) {
153 averagedCurve[i] += row[i];
154 }
155 }
156
157 for (double& avg : averagedCurve) {
158 avg /= static_cast<double>(fCurves.size());
159 }
160
161 return averagedCurve;
162}
163
164void TRestSensitivity::ExportAveragedCurve(std::string fname) {
165 std::vector<Double_t> curve = GetAveragedCurve();
166 if (curve.empty()) std::cout << "Curve is empty" << std::endl;
167 if (curve.empty()) return;
168
169 // Open a file for writing
170 std::ofstream outputFile(fname);
171
172 // Check if the file is opened successfully
173 if (!outputFile) {
174 RESTError << "TRestSensitivity::ExportCurve. Error opening file for writing!" << RESTendl;
175 return;
176 }
177
178 if (fParameterizationNodes.size() != curve.size()) {
179 RESTError << "TRestSensitivity::ExportCurve. Curve has not been properly generated" << RESTendl;
180 RESTError << "Parameterization nodes: " << fParameterizationNodes.size() << RESTendl;
181 RESTError << "Try invoking TRestSensitivity::GenerateCurve" << RESTendl;
182 return;
183 }
184
185 int m = 0;
186 for (const auto& node : fParameterizationNodes) {
187 outputFile << node << " " << curve[m] << std::endl;
188 m++;
189 }
190
191 outputFile.close();
192
193 RESTInfo << "TRestSensitivity::ExportCurve. File has been written successfully!" << RESTendl;
194}
195
196void TRestSensitivity::ExportCurve(std::string fname, int n = 0) {
197 std::vector<Double_t> curve = GetCurve(n);
198 if (curve.empty()) return;
199
200 // Open a file for writing
201 std::ofstream outputFile(fname);
202
203 // Check if the file is opened successfully
204 if (!outputFile) {
205 RESTError << "TRestSensitivity::ExportCurve. Error opening file for writing!" << RESTendl;
206 return;
207 }
208
209 if (fParameterizationNodes.size() != curve.size()) {
210 RESTError << "TRestSensitivity::ExportCurve. Curve has not been properly generated" << RESTendl;
211 RESTError << "Try invoking TRestSensitivity::GenerateCurve" << RESTendl;
212 return;
213 }
214
215 int m = 0;
216 for (const auto& node : fParameterizationNodes) {
217 outputFile << node << " " << curve[m] << std::endl;
218 m++;
219 }
220
221 outputFile.close();
222
223 RESTInfo << "TRestSensitivity::ExportCurve. File has been written successfully!" << RESTendl;
224}
225
229Double_t TRestSensitivity::GetCoupling(Double_t node, Double_t sigma, Double_t precision) {
230 Double_t Chi2_0 = 0;
231 for (const auto& exp : fExperiments) {
232 Chi2_0 += -2 * UnbinnedLogLikelihood(exp, node, 0);
233 }
234
235 Double_t target = sigma * sigma;
236
237 Double_t g4 = 0.5;
238
239 g4 = ApproachByFactor(node, g4, Chi2_0, target, 2);
240 g4 = ApproachByFactor(node, g4, Chi2_0, target, 1.2);
241 g4 = ApproachByFactor(node, g4, Chi2_0, target, 1.02);
242 g4 = ApproachByFactor(node, g4, Chi2_0, target, 1.0002);
243
244 return g4;
245}
246
250Double_t TRestSensitivity::UnbinnedLogLikelihood(const TRestExperiment* experiment, Double_t node,
251 Double_t g4) {
252 Double_t lhood = 0;
253 if (!experiment->IsDataReady()) {
254 RESTError << "TRestSensitivity::UnbinnedLogLikelihood. Experiment " << experiment->GetName()
255 << " is not ready!" << RESTendl;
256 return lhood;
257 }
258
261 Int_t nd = experiment->GetSignal()->FindActiveNode(node);
262 if (nd >= 0)
263 experiment->GetSignal()->SetActiveNode(nd);
264 else
265 return 0.0;
266
271
272 if (experiment->GetBackground()->HasNodes()) {
273 RESTWarning
274 << "TRestSensitivity::UnbinnedLogLikelihood is not ready to have background parameter nodes!"
275 << RESTendl;
276 return 0.0;
277 }
278
279 Double_t signal = g4 * experiment->GetSignal()->GetTotalRate() * experiment->GetExposureInSeconds();
280
281 lhood = -signal;
282
283 if (experiment->GetExperimentalCounts() == 0) return lhood;
284
285 if (ROOT::IsImplicitMTEnabled()) ROOT::DisableImplicitMT();
286
287 std::vector<std::vector<Double_t>> trackingData;
288 for (const auto& var : experiment->GetSignal()->GetVariables()) {
289 auto values = experiment->GetExperimentalDataFrame().Take<Double_t>(var);
290 std::vector<Double_t> vDbl = std::move(*values);
291 trackingData.push_back(vDbl);
292 }
293
294 for (size_t n = 0; n < trackingData[0].size(); n++) {
295 std::vector<Double_t> point;
296 for (size_t m = 0; m < trackingData.size(); m++) point.push_back(trackingData[m][n]);
297
298 Double_t bckRate = experiment->GetBackground()->GetRate(point);
299 Double_t sgnlRate = experiment->GetSignal()->GetRate(point);
300
301 Double_t expectedRate = bckRate + g4 * sgnlRate;
302 lhood += TMath::Log(expectedRate);
303 }
304
305 return lhood;
306}
307
311TH1D* TRestSensitivity::SignalStatisticalTest(Double_t node, Int_t N) {
312 std::vector<Double_t> couplings;
313 for (int n = 0; n < N; n++) {
314 for (const auto& exp : fExperiments) exp->GetSignal()->RegenerateActiveNodeDensity();
315
316 Double_t coupling = TMath::Sqrt(TMath::Sqrt(GetCoupling(node)));
317 couplings.push_back(coupling);
318 }
319
320 // Directly assign the minimum and maximum values
321 double min_value = *std::min_element(couplings.begin(), couplings.end());
322 double max_value = *std::max_element(couplings.begin(), couplings.end());
323
324 if (fSignalTest) delete fSignalTest;
325 fSignalTest = new TH1D("SignalTest", "A signal test", 100, 0.9 * min_value, 1.1 * max_value);
326 for (const auto& coup : couplings) fSignalTest->Fill(coup);
327
328 return fSignalTest;
329}
330
336
337 int cont = 0;
338 TRestMetadata* metadata = (TRestMetadata*)this->InstantiateChildMetadata(cont, "Experiment");
339 while (metadata != nullptr) {
340 cont++;
341 if (metadata->InheritsFrom("TRestExperimentList")) {
342 TRestExperimentList* experimentsList = (TRestExperimentList*)metadata;
343 std::vector<TRestExperiment*> exList = experimentsList->GetExperiments();
344 fExperiments.insert(fExperiments.end(), exList.begin(), exList.end());
345 } else if (metadata->InheritsFrom("TRestExperiment")) {
346 fExperiments.push_back((TRestExperiment*)metadata);
347 }
348
349 metadata = (TRestMetadata*)this->InstantiateChildMetadata(cont, "Experiment");
350 }
351
352 Initialize();
353}
354
359//
366std::vector<std::vector<Double_t>> TRestSensitivity::GetLevelCurves(const std::vector<Double_t>& levels) {
367 std::vector<std::vector<Double_t>> curves(levels.size());
368
369 for (const auto& l : levels) {
370 if (l >= 1 || l <= 0) {
371 RESTError << "The level value should be between 0 and 1" << RESTendl;
372 return curves;
373 }
374 }
375
376 std::vector<int> intLevels;
377 for (const auto& l : levels) {
378 int val = (int)round(l * fCurves.size());
379 if (val >= (int)fCurves.size()) val = fCurves.size() - 1;
380 if (val < 0) val = 0;
381
382 intLevels.push_back(val);
383 }
384
385 for (size_t m = 0; m < fCurves[0].size(); m++) {
386 std::vector<Double_t> v;
387 for (size_t n = 0; n < fCurves.size(); n++) v.push_back(fCurves[n][m]);
388
389 std::sort(v.begin(), v.begin() + v.size());
390
391 for (size_t n = 0; n < intLevels.size(); n++) curves[n].push_back(v[intLevels[n]]);
392 }
393
394 return curves;
395}
396
397TCanvas* TRestSensitivity::DrawCurves() {
398 if (fCanvas != NULL) {
399 delete fCanvas;
400 fCanvas = NULL;
401 }
402 fCanvas = new TCanvas("canv", "This is the canvas title", 600, 450);
403 fCanvas->Draw();
404
405 TPad* pad1 = new TPad("pad1", "This is pad1", 0.01, 0.02, 0.99, 0.97);
406 // pad1->Divide(2, 2);
407 pad1->Draw();
408
410 // pad1->cd()->SetLogx();
411 pad1->cd()->SetRightMargin(0.09);
412 pad1->cd()->SetLeftMargin(0.15);
413 pad1->cd()->SetBottomMargin(0.15);
414
415 std::vector<TGraph*> graphs;
416
417 for (size_t n = 0; n < 20; n++) {
418 std::string grname = "gr" + IntegerToString(n);
419 TGraph* gr = new TGraph();
420 gr->SetName(grname.c_str());
421 for (size_t m = 0; m < this->GetCurve(n).size(); m++)
422 gr->SetPoint(gr->GetN(), fParameterizationNodes[m],
423 TMath::Sqrt(TMath::Sqrt(this->GetCurve(n)[m])));
424
425 gr->SetLineColorAlpha(kBlue + n, 0.3);
426 gr->SetLineWidth(1);
427 graphs.push_back(gr);
428 }
429
430 TGraph* avGr = new TGraph();
431 std::vector<Double_t> avCurve = GetAveragedCurve();
432 for (size_t m = 0; m < avCurve.size(); m++)
433 avGr->SetPoint(avGr->GetN(), fParameterizationNodes[m], TMath::Sqrt(TMath::Sqrt(avCurve[m])));
434 avGr->SetLineColor(kBlack);
435 avGr->SetLineWidth(2);
436
437 graphs[0]->GetXaxis()->SetLimits(0, 0.25);
438 // graphs[0]->GetHistogram()->SetMaximum(1);
439 // graphs[0]->GetHistogram()->SetMinimum(lowRange);
440
441 graphs[0]->GetXaxis()->SetTitle("mass [eV]");
442 graphs[0]->GetXaxis()->SetTitleSize(0.05);
443 graphs[0]->GetXaxis()->SetLabelSize(0.05);
444 graphs[0]->GetYaxis()->SetTitle("g_{a#gamma} [10^{-10} GeV^{-1}]");
445 graphs[0]->GetYaxis()->SetTitleOffset(1.5);
446 graphs[0]->GetYaxis()->SetTitleSize(0.05);
447 // graphs[0]->GetYaxis()->SetLabelSize(0.05);
448 // graphs[0]->GetYaxis()->SetLabelOffset(0.0);
449 // pad1->cd()->SetLogy();
450 graphs[0]->Draw("AL");
451 for (unsigned int n = 1; n < graphs.size(); n++) graphs[n]->Draw("L");
452 avGr->Draw("L");
453
454 /*
455Double_t lx1 = 0.6, ly1 = 0.75, lx2 = 0.9, ly2 = 0.95;
456if (eLegendCoords.size() > 0) {
457 lx1 = eLegendCoords[0];
458 ly1 = eLegendCoords[1];
459 lx2 = eLegendCoords[2];
460 ly2 = eLegendCoords[3];
461}
462TLegend* legend = new TLegend(lx1, ly1, lx2, ly2);
463
464legend->SetTextSize(0.03);
465legend->SetHeader("Energies", "C"); // option "C" allows to center the header
466for (unsigned int n = 0; n < energies.size(); n++) {
467 std::string lname = "gr" + IntegerToString(n);
468 std::string ltitle = DoubleToString(energies[n]) + " keV";
469
470 legend->AddEntry(lname.c_str(), ltitle.c_str(), "l");
471}
472legend->Draw();
473 */
474
475 return fCanvas;
476}
477
478TCanvas* TRestSensitivity::DrawLevelCurves() {
479 if (fCanvas != NULL) {
480 delete fCanvas;
481 fCanvas = NULL;
482 }
483 fCanvas = new TCanvas("canv", "This is the canvas title", 500, 400);
484 fCanvas->Draw();
485 fCanvas->SetLeftMargin(0.15);
486 fCanvas->SetRightMargin(0.04);
487 fCanvas->SetLogx();
488
489 std::vector<std::vector<Double_t>> levelCurves = GetLevelCurves({0.025, 0.16, 0.375, 0.625, 0.84, 0.975});
490
491 std::vector<TGraph*> graphs;
492 for (size_t n = 0; n < levelCurves.size(); n++) {
493 std::string grname = "gr" + IntegerToString(n);
494 TGraph* gr = new TGraph();
495 gr->SetName(grname.c_str());
496 for (size_t m = 0; m < levelCurves[n].size(); m++)
497 gr->SetPoint(gr->GetN(), fParameterizationNodes[m], TMath::Sqrt(TMath::Sqrt(levelCurves[n][m])));
498
499 gr->SetLineColor(kBlack);
500 gr->SetLineWidth(1);
501 graphs.push_back(gr);
502 }
503
504 TGraph* centralGr = new TGraph();
505 std::vector<Double_t> centralCurve = GetLevelCurves({0.5})[0];
506 for (size_t m = 0; m < centralCurve.size(); m++)
507 centralGr->SetPoint(centralGr->GetN(), fParameterizationNodes[m],
508 TMath::Sqrt(TMath::Sqrt(centralCurve[m])));
509 centralGr->SetLineColor(kBlack);
510 centralGr->SetLineWidth(2);
511 centralGr->SetMarkerSize(0.1);
512
513 graphs[0]->GetYaxis()->SetRangeUser(0, 0.5);
514 graphs[0]->GetXaxis()->SetRangeUser(0.001, 0.25);
515 graphs[0]->GetXaxis()->SetLimits(0.0001, 0.25);
516 graphs[0]->GetXaxis()->SetTitle("mass [eV]");
517 graphs[0]->GetXaxis()->SetTitleSize(0.04);
518 graphs[0]->GetXaxis()->SetTitleOffset(1.15);
519 graphs[0]->GetXaxis()->SetLabelSize(0.04);
520
521 // graphs[0]->GetYaxis()->SetLabelFont(43);
522 graphs[0]->GetYaxis()->SetTitle("g_{a#gamma} [10^{-10} GeV^{-1}]");
523 graphs[0]->GetYaxis()->SetTitleOffset(1.5);
524 graphs[0]->GetYaxis()->SetTitleSize(0.04);
525 graphs[0]->GetYaxis()->SetLabelSize(0.04);
526 // graphs[0]->GetYaxis()->SetLabelOffset(0);
527 // graphs[0]->GetYaxis()->SetLabelFont(43);
528 graphs[0]->Draw("AL");
529
530 TGraph* randomGr = new TGraph();
531 std::vector<Double_t> randomCurve = fCurves[13];
532 for (size_t m = 0; m < randomCurve.size(); m++)
533 randomGr->SetPoint(randomGr->GetN(), fParameterizationNodes[m],
534 TMath::Sqrt(TMath::Sqrt(randomCurve[m])));
535 randomGr->SetLineColor(kBlack);
536 randomGr->SetLineWidth(1);
537 randomGr->SetMarkerSize(0.3);
538 randomGr->SetMarkerStyle(4);
539
540 std::vector<TGraph*> shadeGraphs;
541
542 int M = (int)levelCurves.size();
543 for (int x = 0; x < M / 2; x++) {
544 TGraph* shade = new TGraph();
545 int N = levelCurves[0].size();
546 for (size_t m = 0; m < levelCurves[0].size(); m++)
547 shade->SetPoint(shade->GetN(), fParameterizationNodes[m],
548 TMath::Sqrt(TMath::Sqrt(levelCurves[x][m])));
549 for (int m = N - 1; m >= 0; --m)
550 shade->SetPoint(shade->GetN(), fParameterizationNodes[m],
551 TMath::Sqrt(TMath::Sqrt(levelCurves[M - 1 - x][m])));
552 shade->SetFillColorAlpha(kRed, 0.25);
553 shade->Draw("f");
554 shadeGraphs.push_back(shade);
555 }
556
557 for (unsigned int n = 1; n < graphs.size(); n++) graphs[n]->Draw("Lsame");
558 randomGr->Draw("LPsame");
559 // centralGr->Draw("Lsame");
560
561 return fCanvas;
562}
563
572 if (fParameterizationNodes.empty() || rescan) {
574
575 for (const auto& experiment : fExperiments) {
576 std::vector<Double_t> nodes = experiment->GetSignal()->GetParameterizationNodes();
577 fParameterizationNodes.insert(fParameterizationNodes.end(), nodes.begin(), nodes.end());
578
579 std::sort(fParameterizationNodes.begin(), fParameterizationNodes.end());
580 auto last = std::unique(fParameterizationNodes.begin(), fParameterizationNodes.end());
582 }
583 }
584}
585
586void TRestSensitivity::PrintParameterizationNodes() {
587 std::cout << "Curve sensitivity nodes: ";
588 for (const auto& node : fParameterizationNodes) std::cout << node << "\t";
589 std::cout << std::endl;
590}
591
597
598 RESTMetadata << " - Number of parameterization nodes : " << GetNumberOfNodes() << RESTendl;
599 RESTMetadata << " - Number of experiments loaded : " << GetNumberOfExperiments() << RESTendl;
600 RESTMetadata << " - Number of sensitivity curves generated : " << GetNumberOfCurves() << RESTendl;
601 RESTMetadata << " " << RESTendl;
602 RESTMetadata << " You may access experiment info using TRestSensitivity::GetExperiment(n)" << RESTendl;
603
604 RESTMetadata << "----" << RESTendl;
605}
Int_t FindActiveNode(Double_t node)
It returns the position of the fParameterizationNodes element for the variable name given by argument...
Double_t GetTotalRate()
This method integrates the rate to all the parameter space defined in the density function....
Bool_t HasNodes()
It returns true if any nodes have been defined.
Double_t GetRate(std::vector< Double_t > point)
It returns the intensity/rate (in seconds) corresponding to the generated distribution or formula eva...
Int_t SetActiveNode(Double_t node)
It returns the position of the fParameterizationNodes element for the variable name given by argument...
A helper metadata class to create a list of TRestExperiment instances.
It includes a model definition and experimental data used to obtain a final experimental sensitivity.
A base class for any REST metadata class.
Definition: TRestMetadata.h:70
virtual void PrintMetadata()
Implemented it in the derived metadata class to print out specific metadata information.
endl_t RESTendl
Termination flag object for TRestStringOutput.
Int_t LoadConfigFromFile(const std::string &configFilename, const std::string &sectionName="")
Give the file name, find out the corresponding section. Then call the main starter.
TRestMetadata * InstantiateChildMetadata(int index, std::string pattern="")
This method will retrieve a new TRestMetadata instance of a child element of the present TRestMetadat...
virtual void InitFromConfigFile()
To make settings from rml file. This method must be implemented in the derived class.
void SetSectionName(std::string sName)
set the section name, clear the section content
std::string fConfigFileName
Full name of the rml file.
It combines a number of experimental conditions allowing to calculate a combined experimental sensiti...
void Initialize() override
It will initialize the data frame with the filelist and column names (or observables) that have been ...
~TRestSensitivity()
Default destructor.
std::vector< std::vector< Double_t > > fCurves
A vector of calculated sensitivity curves defined as a funtion of the parametric node.
std::vector< TRestExperiment * > fExperiments
A list of experimental conditions included to get a final sensitivity plot.
void InitFromConfigFile() override
It customizes the retrieval of XML data values of this class.
TCanvas * fCanvas
A canvas to draw.
void PrintMetadata() override
Prints on screen the information about the metadata members of TRestAxionSolarFlux.
TH1D * fSignalTest
It is used to generate a histogram with the signal distribution produced with different signal sample...
void ExtractExperimentParameterizationNodes(Bool_t rescan=false)
It scans all the experiment signals parametric nodes to build a complete list of nodes used to build ...
TRestSensitivity()
Default constructor.
std::vector< std::vector< Double_t > > GetLevelCurves(const std::vector< Double_t > &levels)
This method is used to obtain the list of curves that satisfy that each value inside the curve is pla...
Double_t GetCoupling(Double_t node, Double_t sigma=2, Double_t precision=0.01)
It will return the coupling value for which Chi=sigma.
Double_t UnbinnedLogLikelihood(const TRestExperiment *experiment, Double_t node, Double_t g4=0)
It returns the Log(L) for the experiment and coupling given by argument.
std::vector< Double_t > fParameterizationNodes
The fusioned list of parameterization nodes found at each experiment signal.
Double_t ApproachByFactor(Double_t node, Double_t g4, Double_t chi0, Double_t target, Double_t factor)
It will return a value of the coupling, g4, such that (chi-chi0) gets closer to the target value give...
std::string IntegerToString(Int_t n, std::string format="%d")
Gets a string from an integer.