140#include "TRestDataSetGainMap.h"
183 TiXmlElement* moduleDefinition =
GetElement(
"module");
184 while (moduleDefinition !=
nullptr) {
186 fModulesCal.back().LoadConfigFromTiXmlElement(moduleDefinition);
201 RESTInfo <<
"Generating gain map of plane " << mod.GetPlaneId() <<
" module " << mod.GetModuleId()
203 mod.GenerateGainMap();
206 mod.DrawFullSpectrum();
227 std::vector<std::string> excludeColumns) {
229 RESTError <<
"TRestDataSetGainMap::CalibrateDataSet: No modules defined." <<
RESTendl;
234 dataSet.EnableMultiThreading(
true);
237 dataSet.
Import(dataSetFileName);
239 RESTWarning << dataSetFileName <<
" is not a dataset. Generating a temporal one..." <<
RESTendl;
241 dataSet.SetFilePattern(dataSetFileName);
242 dataSet.SetObservablesList({
"*"});
249 std::string pmIDname = (std::string)GetName() +
"_pmID";
250 std::string modCut =
fModulesCal[0].GetModuleDefinitionCut();
251 if (modCut.empty()) modCut =
"1";
254 auto columnList = dataFrame.GetColumnNames();
255 if (std::find(columnList.begin(), columnList.end(), pmIDname) == columnList.end())
256 dataFrame = dataFrame.Define(pmIDname, modCut +
" ? " + std::to_string(pmID) +
" : -1");
258 dataFrame = dataFrame.Redefine(pmIDname, modCut +
" ? " + std::to_string(pmID) +
" : -1");
262 if (modCut.empty()) modCut =
"1";
264 dataFrame = dataFrame.Redefine(pmIDname, (modCut +
" ? " + std::to_string(pmID) +
" : " + pmIDname));
268 auto calibrate = [
this](
double val,
double x,
double y,
int pmID) {
270 if (pmID == m.GetPlaneId() * 10 + m.GetModuleId())
271 return m.GetSlope(x, y) * val + m.GetIntercept(x, y);
275 return std::numeric_limits<double>::quiet_NaN();
277 std::string calibObsName = (std::string)GetName() +
"_";
278 calibObsName += GetObservable().erase(0, GetObservable().find(
"_") + 1);
279 dataFrame = dataFrame.Define(calibObsName, calibrate,
283 auto calibrateFullSpc = [
this](
double val,
int pmID) {
285 if (pmID == m.GetPlaneId() * 10 + m.GetModuleId())
286 return m.GetSlopeFullSpc() * val + m.GetInterceptFullSpc();
290 return std::numeric_limits<double>::quiet_NaN();
292 std::string calibObsNameFullSpc = (std::string)GetName() +
"_";
293 calibObsNameFullSpc +=
294 GetObservable().erase(0, GetObservable().find(
"_") + 1);
295 calibObsNameFullSpc +=
"_NoSegmentation";
296 dataFrame = dataFrame.Define(calibObsNameFullSpc, calibrateFullSpc, {
fObservable, pmIDname});
298 dataSet.SetDataFrame(dataFrame);
301 if (outputFileName.empty()) outputFileName = dataSetFileName;
302 if (outputFileName == dataSetFileName) {
303 std::string gmName = GetName();
304 outputFileName = outputFileName.substr(0, outputFileName.find_last_of(
"."));
312 excludeCol.erase(calibObsName);
313 excludeCol.erase(calibObsNameFullSpc);
314 excludeCol.erase(pmIDname);
316 RESTDebug <<
"Excluding columns: ";
317 for (
auto& c : excludeCol) RESTDebug << c <<
", ";
320 dataSet.
Export(outputFileName, std::vector<std::string>(excludeCol.begin(), excludeCol.end()));
323 TFile* f = TFile::Open(outputFileName.c_str(),
"UPDATE");
336 RESTError <<
"No ModuleCalibration with index " << index;
338 RESTError <<
". There are no modules defined." <<
RESTendl;
350 if (i.GetPlaneId() == planeID && i.GetModuleId() == moduleID)
return &i;
352 RESTError <<
"No ModuleCalibration with planeID " << planeID <<
" and moduleID " << moduleID <<
RESTendl;
364 if (moduleCal ==
nullptr)
return 0;
374 if (moduleCal ==
nullptr)
return 0;
375 return moduleCal->GetSlopeFullSpc();
386 if (moduleCal ==
nullptr)
return 0;
396 if (moduleCal ==
nullptr)
return 0;
397 return moduleCal->GetInterceptFullSpc();
405 std::set<int> planeIDs;
406 for (
const auto& mc :
fModulesCal) planeIDs.insert(mc.GetPlaneId());
415 std::set<int> moduleIDs;
417 if (mc.GetPlaneId() == planeId) moduleIDs.insert(mc.GetModuleId());
425 std::map<int, std::set<int>> moduleIds;
427 moduleIds.insert(std::pair<
int, std::set<int>>(planeId,
GetModuleIDs(planeId)));
432 SetName(src.GetName());
452 if (i.GetPlaneId() == moduleCal.GetPlaneId() && i.GetModuleId() == moduleCal.GetModuleId()) {
465 if (fileName.empty()) {
466 RESTError <<
"No input calibration file defined" <<
RESTendl;
471 RESTInfo <<
"Opening " << fileName <<
RESTendl;
472 TFile* f = TFile::Open(fileName.c_str(),
"READ");
474 RESTError <<
"Cannot open calibration file " << fileName <<
RESTendl;
480 TIter nextkey(f->GetListOfKeys());
482 while ((key = (TKey*)nextkey())) {
483 std::string kName = key->GetClassName();
492 RESTError <<
"File extension not supported for " << fileName <<
RESTendl;
505 RESTError <<
"No output file defined" <<
RESTendl;
511 this->
Write(GetName());
526 RESTMetadata <<
" Cuts applied: ";
529 for (
const auto& cut :
fCut->GetCutStrings()) RESTMetadata << cut <<
", " <<
RESTendl;
530 for (
const auto& cut :
fCut->GetParamCut())
531 RESTMetadata << cut.first <<
" " << cut.second <<
", " <<
RESTendl;
535 RESTMetadata <<
" Number of planes: " << GetNumberOfPlanes() <<
RESTendl;
536 RESTMetadata <<
" Number of modules: " << GetNumberOfModules() <<
RESTendl;
544 RESTMetadata <<
"-----------------------------------------------" <<
RESTendl;
546 RESTMetadata <<
"***********************************************" <<
RESTendl;
558 int index_x = -1, index_y = -1;
561 index_x = std::distance(
fSplitX.begin(),
fSplitX.upper_bound(x)) - 1;
563 RESTWarning <<
"index_x < 0 for x = " << x <<
" and fSplitX[0]=" << *
fSplitX.begin()
568 RESTWarning <<
"x is out of split for x = " << x <<
p->
RESTendl;
573 index_y = std::distance(
fSplitY.begin(),
fSplitY.upper_bound(y)) - 1;
575 RESTWarning <<
"index_y < 0 for y = " << y <<
" and fSplitY[0]=" << *
fSplitY.begin()
580 RESTWarning <<
"y is out of split for y = " << y <<
p->
RESTendl;
584 return std::make_pair(index_x, index_y);
594 auto [index_x, index_y] = GetIndexMatrix(x, y);
595 if (fSlope.empty()) {
596 RESTError <<
"Calibration slope matrix is empty. Returning 0" << p->RESTendl;
600 if (index_x > (
int)fSlope.size() || index_y > (
int)fSlope.at(0).size()) {
601 RESTError <<
"Index out of range. Returning 0" << p->RESTendl;
605 return fSlope[index_x][index_y];
616 auto [index_x, index_y] = GetIndexMatrix(x, y);
617 if (fIntercept.empty()) {
618 RESTError <<
"Calibration constant matrix is empty. Returning 0" << p->RESTendl;
622 if (index_x > (
int)fIntercept.size() || index_y > (
int)fIntercept.at(0).size()) {
623 RESTError <<
"Index out of range. Returning 0" << p->RESTendl;
627 return fIntercept[index_x][index_y];
644 if (fNumberOfSegmentsX < 1) {
645 RESTError <<
"SetSplitX: fNumberOfSegmentsX must be >=1." << p->RESTendl;
648 std::set<double> split;
649 for (
int i = 0; i <= fNumberOfSegmentsX; i++) {
651 fReadoutRange.X() + ((fReadoutRange.Y() - fReadoutRange.X()) / (
float)fNumberOfSegmentsX) * i;
658 if (splitX.size() < 2) {
659 RESTError <<
"SetSplitX: split size must be >=2 (start and end of range must be included)."
664 RESTWarning <<
"SetSplitX: changing split but current gain map and calibration paremeters correspond "
665 "to previous splitting. Use GenerateGainMap() to update them."
668 fNumberOfSegmentsX = fSplitX.size() - 1;
677 if (fNumberOfSegmentsY < 1) {
678 RESTError <<
"SetSplitY: fNumberOfSegmentsY must be >=1." << p->RESTendl;
681 std::set<double> split;
682 for (
int i = 0; i <= fNumberOfSegmentsY; i++) {
684 fReadoutRange.X() + ((fReadoutRange.Y() - fReadoutRange.X()) / (
float)fNumberOfSegmentsY) * i;
691 if (splitY.size() < 2) {
692 RESTError <<
"SetSplitY: split size must be >=2 (start and end of range must be included)."
697 RESTWarning <<
"SetSplitY: changing split but current gain map and calibration paremeters correspond "
698 "to previous splitting. Use GenerateGainMap() to update them."
701 fNumberOfSegmentsY = fSplitY.size() - 1;
722 std::string dsFileName = fDataSetFileName;
723 if (dsFileName.empty()) dsFileName = p->GetCalibrationFileName();
724 if (dsFileName.empty()) {
725 RESTError <<
"No calibration file defined" << p->RESTendl;
730 dataSet.EnableMultiThreading(
true);
732 dataSet.
Import(dsFileName);
733 fDataSetFileName = dsFileName;
735 RESTWarning << dsFileName <<
" is not a dataset. Generating a temporal one..." << p->RESTendl;
737 std::vector<std::string> obsList;
739 obsList.push_back(p->GetObservable());
740 obsList.push_back(p->GetSpatialObservableX());
741 obsList.push_back(p->GetSpatialObservableY());
742 if (!p->GetSpatialObservableXSecondary().empty())
743 obsList.push_back(p->GetSpatialObservableXSecondary());
744 if (!p->GetSpatialObservableYSecondary().empty())
745 obsList.push_back(p->GetSpatialObservableYSecondary());
749 obsList.insert(obsList.end(), modDefCutObs.begin(), modDefCutObs.end());
752 for (
const auto& cut : p->GetCut()->GetCutStrings()) {
754 obsList.insert(obsList.end(), cutObs.begin(), cutObs.end());
756 for (
const auto& [variable, condition] : p->GetCut()->GetParamCut()) {
758 obsList.insert(obsList.end(), cutObs.begin(), cutObs.end());
761 obsList.insert(obsList.end(), cutObs.begin(), cutObs.end());
765 std::sort(obsList.begin(), obsList.end());
766 obsList.erase(std::unique(obsList.begin(), obsList.end()), obsList.end());
769 dataSet.SetFilePattern(dsFileName);
770 dataSet.SetObservablesList(obsList);
772 fDataSetFileName = dsFileName;
775 dataSet.SetDataFrame(dataSet.
MakeCut(p->GetCut()));
777 if (fSplitX.empty()) SetSplitX();
778 if (fSplitY.empty()) SetSplitY();
781 if (fCalibRange.X() >= fCalibRange.Y()) {
783 std::string cut = fDefinitionCut;
784 if (cut.empty()) cut =
"1";
785 auto histo = dataSet.
GetDataFrame().Filter(cut).Histo1D({
"temp",
"", fNBins, 0, 0}, GetObservable());
786 std::unique_ptr<TH1F> hpunt = std::unique_ptr<TH1F>(
static_cast<TH1F*
>(histo->Clone()));
788 double xMax = hpunt->GetXaxis()->GetXmax();
791 double fraction = 1, nAtEndSpc = 0, step = 0.66;
792 while (nAtEndSpc * 1. / hpunt->Integral() < 0.01 && fraction > 0.001) {
794 nAtEndSpc = hpunt->Integral(hpunt->FindFixBin(hpunt->GetXaxis()->GetXmax() * fraction),
795 hpunt->FindFixBin(hpunt->GetXaxis()->GetXmax()));
797 xMax = hpunt->GetXaxis()->GetXmax() * fraction /
801 fCalibRange.SetY(xMax);
803 RESTDebug <<
"Calibration range (auto)set to (" << fCalibRange.X() <<
"," << fCalibRange.Y() <<
")"
808 std::string hModuleName =
"hSpc_" + std::to_string(fPlaneId) +
"_" + std::to_string(fModuleId);
809 delete fFullSpectrum;
810 fFullSpectrum =
new TH1F(hModuleName.c_str(),
"", fNBins, fCalibRange.X(), fCalibRange.Y());
813 std::string cut = fDefinitionCut;
814 if (cut.empty()) cut =
"1";
815 auto histoMod = dataSet.
GetDataFrame().Filter(cut).Histo1D(
816 {
"tempMod",
"", fNBins, fCalibRange.X(), fCalibRange.Y()}, GetObservable());
817 std::unique_ptr<TH1F> hpuntMod = std::unique_ptr<TH1F>(
static_cast<TH1F*
>(histoMod->Clone()));
818 fFullSpectrum->Add(hpuntMod.get());
821 std::vector<std::vector<TH1F*>> h(fNumberOfSegmentsX, std::vector<TH1F*>(fNumberOfSegmentsY,
nullptr));
822 for (
size_t i = 0; i < h.size(); i++) {
823 for (
size_t j = 0; j < h.at(0).size(); j++) {
824 std::string name = hModuleName +
"_" + std::to_string(i) +
"_" + std::to_string(j);
825 h[i][j] =
new TH1F(name.c_str(),
"", fNBins, fCalibRange.X(),
831 auto itX = fSplitX.begin();
832 for (
size_t i = 0; i < h.size(); i++) {
833 auto itY = fSplitY.begin();
834 for (
size_t j = 0; j < h.at(0).size(); j++) {
837 auto xUpper = *std::next(itX);
839 auto yUpper = *std::next(itY);
841 std::string segment_cut =
"";
842 if (!GetSpatialObservableX().empty())
843 segment_cut += GetSpatialObservableX() +
">=" + std::to_string(xLower) +
"&&" +
844 GetSpatialObservableX() +
"<" + std::to_string(xUpper);
845 if (!GetSpatialObservableY().empty())
846 segment_cut +=
"&&" + GetSpatialObservableY() +
">=" + std::to_string(yLower) +
"&&" +
847 GetSpatialObservableY() +
"<" + std::to_string(yUpper);
848 if (!GetSpatialObservableXSecondary().empty())
849 segment_cut +=
"&&" + GetSpatialObservableXSecondary() +
">=" + std::to_string(xLower) +
850 "&&" + GetSpatialObservableXSecondary() +
"<" + std::to_string(xUpper);
851 if (!GetSpatialObservableYSecondary().empty())
852 segment_cut +=
"&&" + GetSpatialObservableYSecondary() +
">=" + std::to_string(yLower) +
853 "&&" + GetSpatialObservableYSecondary() +
"<" + std::to_string(yUpper);
854 if (!fDefinitionCut.empty()) segment_cut +=
"&&" + fDefinitionCut;
855 if (segment_cut.empty()) segment_cut =
"1";
856 RESTExtreme <<
"Segment[" << i <<
"][" << j <<
"] cut: " << segment_cut << p->RESTendl;
859 .Histo1D({
"temp",
"", h[i][j]->GetNbinsX(), h[i][j]->GetXaxis()->GetXmin(),
860 h[i][j]->GetXaxis()->GetXmax()},
862 std::unique_ptr<TH1F> hpunt = std::unique_ptr<TH1F>(
static_cast<TH1F*
>(histo->Clone()));
863 h[i][j]->Add(hpunt.get());
871 std::vector<std::vector<double>> calParSlope(fNumberOfSegmentsX,
872 std::vector<double>(fNumberOfSegmentsY, 0));
873 std::vector<std::vector<double>> calParIntercept(fNumberOfSegmentsX,
874 std::vector<double>(fNumberOfSegmentsY, 0));
875 fSegLinearFit = std::vector(h.size(), std::vector<TGraph*>(h.at(0).size(),
nullptr));
876 for (
size_t i = 0; i < h.size(); i++)
877 for (
int j = 0; j < (int)h.at(0).size(); j++) {
878 fSegLinearFit[i][j] =
new TGraph();
879 auto [intercept, slope] = FitPeaks(h[i][j], fSegLinearFit[i][j]);
880 calParSlope[i][j] = slope;
881 calParIntercept[i][j] = intercept;
883 fSlope = calParSlope;
884 fIntercept = calParIntercept;
888 delete fFullLinearFit;
889 fFullLinearFit =
new TGraph();
890 auto [intercept, slope] = FitPeaks(fFullSpectrum, fFullLinearFit);
892 fFullIntercept = intercept;
895std::pair<double, double> TRestDataSetGainMap::Module::FitPeaks(TH1F* hSeg, TGraph* gr) {
897 RESTError <<
"No histogram for fitting" << p->RESTendl;
898 return std::make_pair(0, 0);
900 if (hSeg->Integral() == 0) {
901 RESTError <<
"Empty spectrum " << hSeg->GetName() << p->RESTendl;
902 return std::make_pair(0, 0);
904 std::shared_ptr<TGraph> graph = std::shared_ptr<TGraph>(
new TGraph());
905 RESTExtreme <<
"Fitting peaks for " << hSeg->GetName() << p->RESTendl;
908 std::unique_ptr<TSpectrum> s(
new TSpectrum(2 * fEnergyPeaks.size() + 1));
909 std::vector<double> peakPos;
910 s->Search(hSeg, 2,
"goff", 0.1);
911 for (
int k = 0; k < s->GetNPeaks(); k++) peakPos.push_back(s->GetPositionX()[k]);
912 std::sort(peakPos.begin(), peakPos.end(), std::greater<double>());
914 peakPos.size() == 0 ? 1 : peakPos.front() / fEnergyPeaks.front();
917 graph->SetName(
"grFit");
918 graph->SetTitle((
";" + GetObservable() +
";energy").c_str());
923 for (
const auto& energy : fEnergyPeaks) {
924 RESTExtreme <<
"\t fitting energy " <<
DoubleToString(energy,
"%g") << p->RESTendl;
926 double pos = energy * ratio;
927 double start = pos * 0.8;
928 double end = pos * 1.2;
929 if (fRangePeaks.at(c).X() < fRangePeaks.at(c).Y()) {
930 start = fRangePeaks.at(c).X();
931 end = fRangePeaks.at(c).Y();
935 if (fAutoRangePeaks) {
936 if (peakPos.size() > 0) {
939 while (!(start < pos && pos < end)) {
942 if (pos == peakPos.back()) {
946 pos = *std::next(std::find(peakPos.begin(), peakPos.end(),
949 peakPos.erase(std::find(peakPos.begin(), peakPos.end(),
955 const double relDist = peakPos.size() > 0 ? (pos - peakPos.front()) / pos : 999;
957 start = pos * (1 - relDist / 2);
958 end = pos * (1 + relDist / 2);
963 std::string name =
"g" + std::to_string(c);
964 TF1* g =
new TF1(name.c_str(),
"gaus", start, end);
965 RESTExtreme <<
"\t\tat " <<
DoubleToString(pos,
"%.3g") <<
". Range("
969 if (hSeg->GetFunction(name.c_str()))
970 hSeg->GetListOfFunctions()->Remove(hSeg->GetFunction(name.c_str()));
972 hSeg->Fit(g,
"R+Q0");
973 mu = g->GetParameter(1);
974 RESTExtreme <<
"\t\tgaus mean " <<
DoubleToString(mu,
"%g") << p->RESTendl;
975 }
while (fAutoRangePeaks && peakPos.size() > 0 &&
976 !(start < mu && mu < end));
977 graph->SetPoint(c++, mu, energy);
981 if (fZeroPoint) graph->SetPoint(c++, 0, 0);
982 while (graph->GetN() < 2) {
983 graph->SetPoint(c++, 0, 0);
985 RESTDebug <<
"Not enough points for linear fit. Adding and setting zero point to true" << p->RESTendl;
989 std::unique_ptr<TF1> linearFit;
990 linearFit = std::unique_ptr<TF1>(
new TF1(
"linearFit",
"pol1"));
991 graph->Fit(
"linearFit",
"SQ");
993 if (gr) *gr = *(TGraph*)graph->Clone();
994 return std::make_pair(linearFit->GetParameter(0), linearFit->GetParameter(1));
1005 const TVector2& range) {
1006 auto [index_x, index_y] = GetIndexMatrix(position.X(), position.Y());
1007 int peakNumber = -1;
1008 for (
size_t i = 0; i < fEnergyPeaks.size(); i++)
1009 if (fEnergyPeaks.at(i) == energyPeak) {
1013 if (peakNumber == -1) {
1014 RESTError <<
"Energy " << energyPeak <<
" not found in the list of energy peaks" << p->RESTendl;
1017 Refit((
size_t)index_x, (
size_t)index_y, (
size_t)peakNumber, range);
1030 const TVector2& range) {
1031 if (fSegSpectra.empty()) {
1032 RESTError <<
"No gain map found. Use GenerateGainMap() first." << p->RESTendl;
1035 if (x >= fSegSpectra.size() || y >= fSegSpectra.at(0).size()) {
1036 RESTError <<
"Segment with index (" << x <<
", " << y <<
") not found" << p->RESTendl;
1039 if (peakNumber >= fEnergyPeaks.size()) {
1040 RESTError <<
"Peak with index " << peakNumber <<
" not found" << p->RESTendl;
1045 std::string name =
"g" + std::to_string(peakNumber);
1046 TF1* g =
new TF1(name.c_str(),
"gaus", range.X(), range.Y());
1047 TH1F* h = fSegSpectra.at(x).at(y);
1048 while (h->GetFunction(name.c_str()))
1049 h->GetListOfFunctions()->Remove(h->GetFunction(name.c_str()));
1053 UpdateCalibrationFits(x, y);
1064 int peakNumber = -1;
1065 for (
size_t i = 0; i < fEnergyPeaks.size(); i++)
1066 if (fEnergyPeaks.at(i) == energyPeak) {
1070 if (peakNumber == -1) {
1071 RESTError <<
"Energy " << energyPeak <<
" not found in the list of energy peaks" << p->RESTendl;
1074 RefitFullSpc((
size_t)peakNumber, range);
1085 if (!fFullSpectrum) {
1086 RESTError <<
"No gain map found. Use GenerateGainMap() first." << p->RESTendl;
1089 if (peakNumber >= fEnergyPeaks.size()) {
1090 RESTError <<
"Peak with index " << peakNumber <<
" not found" << p->RESTendl;
1095 std::string name =
"g" + std::to_string(peakNumber);
1096 TF1* g =
new TF1(name.c_str(),
"gaus", range.X(), range.Y());
1097 while (fFullSpectrum->GetFunction(name.c_str()))
1098 fFullSpectrum->GetListOfFunctions()->Remove(fFullSpectrum->GetFunction(name.c_str()));
1099 fFullSpectrum->Fit(g,
"R+Q0");
1102 UpdateCalibrationFitsFullSpc();
1113void TRestDataSetGainMap::Module::UpdateCalibrationFits(
const size_t x,
const size_t y) {
1114 if (fSegSpectra.empty()) {
1115 RESTError <<
"No gain map found. Use GenerateGainMap() first." << p->RESTendl;
1118 if (x >= fSegSpectra.size() || y >= fSegSpectra.at(0).size()) {
1119 RESTError <<
"Segment with index (" << x <<
", " << y <<
") not found" << p->RESTendl;
1123 TH1F* h = fSegSpectra.at(x).at(y);
1124 TGraph* gr = fSegLinearFit.at(x).at(y);
1126 auto [intercept, slope] = UpdateCalibrationFits(h, gr);
1127 fSlope[x][y] = slope;
1128 fIntercept[x][y] = intercept;
1131std::pair<double, double> TRestDataSetGainMap::Module::UpdateCalibrationFits(TH1F* h, TGraph* gr) {
1133 RESTError <<
"No histogram for updating fits" << p->RESTendl;
1134 return std::make_pair(0, 0);
1137 RESTError <<
"No graph for updating fits" << p->RESTendl;
1138 return std::make_pair(0, 0);
1140 if (h->Integral() == 0) {
1141 RESTError <<
"Empty spectrum " << h->GetName() << p->RESTendl;
1142 return std::make_pair(0, 0);
1146 for (
size_t i = 0; i < fEnergyPeaks.size(); i++) gr->RemovePoint(i);
1149 for (
size_t i = 0; i < fEnergyPeaks.size(); i++) {
1150 std::string fitName = (std::string)
"g" + std::to_string(i);
1151 TF1* g = h->GetFunction(fitName.c_str());
1153 RESTWarning <<
"No fit ( " << fitName <<
" ) found for energy peak " << fEnergyPeaks[i]
1154 <<
" in histogram " << h->GetName() << p->RESTendl;
1157 gr->SetPoint(c++, g->GetParameter(1), fEnergyPeaks[i]);
1161 while (gr->GetN() < 2) {
1162 gr->SetPoint(c++, 0, 0);
1167 if (gr->GetFunction(
"linearFit"))
1168 lf = gr->GetFunction(
"linearFit");
1170 lf =
new TF1(
"linearFit",
"pol1");
1173 return std::make_pair(lf->GetParameter(0), lf->GetParameter(1));
1182 auto [intercept, slope] = UpdateCalibrationFits(fFullSpectrum, fFullLinearFit);
1184 fFullIntercept = intercept;
1202 if (module ==
nullptr) {
1203 RESTError <<
"TRestDataSetGainMap::Module::LoadConfigFromTiXmlElement: module is nullptr"
1208 std::string el = !
module->Attribute("planeId") ? "Not defined" : module->Attribute("planeId");
1209 if (!(el.empty() || el ==
"Not defined")) this->SetPlaneId(
StringToInteger(el));
1210 el = !
module->Attribute("moduleId") ? "Not defined" : module->Attribute("moduleId");
1211 if (!(el.empty() || el ==
"Not defined")) this->SetModuleId(
StringToInteger(el));
1213 el = !
module->Attribute("moduleDefinitionCut") ? "Not defined" : module->Attribute("moduleDefinitionCut");
1214 if (!(el.empty() || el ==
"Not defined")) this->SetModuleDefinitionCut(el);
1216 el = !
module->Attribute("numberOfSegmentsX") ? "Not defined" : module->Attribute("numberOfSegmentsX");
1217 if (!(el.empty() || el ==
"Not defined")) this->SetNumberOfSegmentsX(
StringToInteger(el));
1218 el = !
module->Attribute("numberOfSegmentsY") ? "Not defined" : module->Attribute("numberOfSegmentsY");
1219 if (!(el.empty() || el ==
"Not defined")) this->SetNumberOfSegmentsY(
StringToInteger(el));
1220 el = !
module->Attribute("readoutRange") ? "Not defined" : module->Attribute("readoutRange");
1221 if (!(el.empty() || el ==
"Not defined")) this->SetReadoutRange(
StringTo2DVector(el));
1223 el = !
module->Attribute("calibRange") ? "Not defined" : module->Attribute("calibRange");
1224 if (!(el.empty() || el ==
"Not defined")) this->SetCalibrationRange(
StringTo2DVector(el));
1225 el = !
module->Attribute("nBins") ? "Not defined" : module->Attribute("nBins");
1226 if (!(el.empty() || el ==
"Not defined")) this->SetNBins(
StringToInteger(el));
1228 el = !
module->Attribute("dataSetFileName") ? "Not defined" : module->Attribute("dataSetFileName");
1229 if (!(el.empty() || el ==
"Not defined")) this->SetDataSetFileName(el);
1231 el = !
module->Attribute("zeroPoint") ? "Not defined" : module->Attribute("zeroPoint");
1232 if (!(el.empty() || el ==
"Not defined")) this->SetZeroPoint(
ToLower(el) ==
"true");
1233 el = !
module->Attribute("autoRangePeaks") ? "Not defined" : module->Attribute("autoRangePeaks");
1234 if (!(el.empty() || el ==
"Not defined")) this->SetAutoRangePeaks(
ToLower(el) ==
"true");
1237 TiXmlElement* peakDefinition = (TiXmlElement*)module->FirstChildElement(
"peak");
1238 while (peakDefinition !=
nullptr) {
1240 TVector2 range = TVector2(0, 0);
1243 !peakDefinition->Attribute(
"energy") ?
"Not defined" : peakDefinition->Attribute(
"energy");
1244 if (ell.empty() || ell ==
"Not defined") {
1245 RESTError <<
"< peak variable key does not contain energy!" << p->RESTendl;
1250 ell = !peakDefinition->Attribute(
"range") ?
"Not defined" : peakDefinition->Attribute(
"range");
1253 this->AddPeak(energy, range);
1254 peakDefinition = (TiXmlElement*)peakDefinition->NextSiblingElement();
1260 std::pair<size_t, size_t> index = GetIndexMatrix(position.X(), position.Y());
1261 DrawSpectrum(index.first, index.second, drawFits, color, c);
1266 if (fSegSpectra.size() == 0) {
1267 RESTError <<
"Spectra matrix is empty." << p->RESTendl;
1270 if (index_x < 0 || index_y < 0 || index_x >= (
int)fSegSpectra.size() ||
1271 index_y >= (
int)fSegSpectra.at(index_x).size()) {
1272 RESTError <<
"Index out of range." << p->RESTendl;
1275 if (!fSegSpectra[index_x][index_y]) {
1276 RESTError <<
"No Spectrum for segment (" << index_x <<
", " << index_y <<
")." << p->RESTendl;
1281 std::string t =
"spectrum_" + std::to_string(fPlaneId) +
"_" + std::to_string(fModuleId) +
"_" +
1282 std::to_string(index_x) +
"_" + std::to_string(index_y);
1283 c =
new TCanvas(t.c_str(), t.c_str());
1286 auto xLower = *std::next(fSplitX.begin(), index_x);
1287 auto xUpper = *std::next(fSplitX.begin(), index_x + 1);
1288 auto yLower = *std::next(fSplitY.begin(), index_y);
1289 auto yUpper = *std::next(fSplitY.begin(), index_y + 1);
1292 GetObservable() +
";counts";
1293 fSegSpectra[index_x][index_y]->SetTitle(tH.c_str());
1295 if (color > 0) fSegSpectra[index_x][index_y]->SetLineColor(color);
1296 size_t colorT = fSegSpectra[index_x][index_y]->GetLineColor();
1297 fSegSpectra[index_x][index_y]->Draw(
"same");
1300 for (
size_t c = 0; c < fEnergyPeaks.size(); c++) {
1301 auto fit = fSegSpectra[index_x][index_y]->GetFunction((
"g" + std::to_string(c)).c_str());
1303 RESTWarning <<
"Fit for energy peak " << fEnergyPeaks[c] <<
" not found." << p->RESTendl;
1305 fit->SetLineColor(c + 2 != colorT ? c + 2 : ++colorT);
1333 if (fSegSpectra.size() == 0) {
1334 RESTError <<
"Spectra matrix is empty." << p->RESTendl;
1338 std::string t =
"spectrum_" + std::to_string(fPlaneId) +
"_" + std::to_string(fModuleId);
1339 c =
new TCanvas(t.c_str(), t.c_str());
1343 for (
const auto&
object : *c->GetListOfPrimitives())
1344 if (object->InheritsFrom(TVirtualPad::Class())) ++nPads;
1345 if (nPads != 0 && nPads != fSegSpectra.size() * fSegSpectra.at(0).size()) {
1346 RESTError <<
"Canvas " << c->GetName() <<
" has " << nPads <<
" pads, but "
1347 << fSegSpectra.size() * fSegSpectra.at(0).size() <<
" are needed." << p->RESTendl;
1349 }
else if (nPads == 0)
1350 c->Divide(fSegSpectra.size(), fSegSpectra.at(0).size());
1352 for (
size_t i = 0; i < fSegSpectra.size(); i++) {
1353 for (
size_t j = 0; j < fSegSpectra[i].size(); j++) {
1354 int pad = fSegSpectra.size() * (fSegSpectra[i].size() - 1) + 1 + i - fSegSpectra.size() * j;
1356 DrawSpectrum(i, j, drawFits, color, c);
1360void TRestDataSetGainMap::Module::DrawFullSpectrum(
const bool drawFits,
const int color, TCanvas* c) {
1361 if (!fFullSpectrum) {
1362 RESTError <<
"Spectrum is empty." << p->RESTendl;
1367 std::string t =
"fullSpc_" + std::to_string(fPlaneId) +
"_" + std::to_string(fModuleId);
1368 c =
new TCanvas(t.c_str(), t.c_str());
1372 fFullSpectrum->SetTitle((
"Full spectrum;" + GetObservable() +
";counts").c_str());
1374 if (color > 0) fFullSpectrum->SetLineColor(color);
1375 size_t colorT = fFullSpectrum->GetLineColor();
1376 fFullSpectrum->Draw(
"same");
1379 for (
size_t c = 0; c < fEnergyPeaks.size(); c++) {
1380 auto fit = fFullSpectrum->GetFunction((
"g" + std::to_string(c)).c_str());
1381 if (!fit) RESTWarning <<
"Fit for energy peak" << fEnergyPeaks[c] <<
" not found." << p->RESTendl;
1383 fit->SetLineColor(c + 2 != colorT ? c + 2 : ++colorT);
1391void TRestDataSetGainMap::Module::DrawLinearFit(
const TVector2& position, TCanvas* c) {
1392 std::pair<size_t, size_t> index = GetIndexMatrix(position.X(), position.Y());
1393 DrawLinearFit(index.first, index.second, c);
1396void TRestDataSetGainMap::Module::DrawLinearFit(
const int index_x,
const int index_y, TCanvas* c) {
1397 if (fSegLinearFit.size() == 0) {
1398 RESTError <<
"Spectra matrix is empty." << p->RESTendl;
1401 if (index_x < 0 || index_y < 0 || index_x >= (
int)fSegLinearFit.size() ||
1402 index_y >= (
int)fSegLinearFit.at(index_x).size()) {
1403 RESTError <<
"Index out of range." << p->RESTendl;
1406 if (!fSegLinearFit[index_x][index_y]) {
1407 RESTError <<
"No linear fit for segment (" << index_x <<
", " << index_y <<
")." << p->RESTendl;
1412 std::string t =
"linearFit_" + std::to_string(fPlaneId) +
"_" + std::to_string(fModuleId) +
"_" +
1413 std::to_string(index_x) +
"_" + std::to_string(index_y);
1414 c =
new TCanvas(t.c_str(), t.c_str());
1416 auto xLower = *std::next(fSplitX.begin(), index_x);
1417 auto xUpper = *std::next(fSplitX.begin(), index_x + 1);
1418 auto yLower = *std::next(fSplitY.begin(), index_y);
1419 auto yUpper = *std::next(fSplitY.begin(), index_y + 1);
1422 GetObservable() +
";energy";
1423 fSegLinearFit[index_x][index_y]->SetTitle(tH.c_str());
1424 fSegLinearFit[index_x][index_y]->Draw(
"AL*");
1427void TRestDataSetGainMap::Module::DrawLinearFit(TCanvas* c) {
1428 if (fSegLinearFit.size() == 0) {
1429 RESTError <<
"Spectra matrix is empty." << p->RESTendl;
1433 std::string t =
"linearFits_" + std::to_string(fPlaneId) +
"_" + std::to_string(fModuleId);
1434 c =
new TCanvas(t.c_str(), t.c_str());
1438 for (
const auto&
object : *c->GetListOfPrimitives())
1439 if (object->InheritsFrom(TVirtualPad::Class())) ++nPads;
1440 if (nPads != 0 && nPads != fSegLinearFit.size() * fSegLinearFit.at(0).size()) {
1441 RESTError <<
"Canvas " << c->GetName() <<
" has " << nPads <<
" pads, but "
1442 << fSegLinearFit.size() * fSegLinearFit.at(0).size() <<
" are needed." << p->RESTendl;
1444 }
else if (nPads == 0)
1445 c->Divide(fSegLinearFit.size(), fSegLinearFit.at(0).size());
1447 for (
size_t i = 0; i < fSegLinearFit.size(); i++) {
1448 for (
size_t j = 0; j < fSegLinearFit[i].size(); j++) {
1449 int pad = fSegLinearFit.size() * (fSegLinearFit[i].size() - 1) + 1 + i - fSegLinearFit.size() * j;
1451 DrawLinearFit(i, j, c);
1466 const bool showText) {
1467 if (peakNumber < 0 || peakNumber >= (
int)fEnergyPeaks.size()) {
1468 RESTError <<
"Peak number out of range (peakNumber should be between 0 and "
1469 << fEnergyPeaks.size() - 1 <<
" )" << p->RESTendl;
1472 if (fSegLinearFit.size() == 0) {
1473 RESTError <<
"Linear fit matrix is empty." << p->RESTendl;
1476 if (!fFullLinearFit) {
1477 RESTError <<
"Full linear fit is empty." << p->RESTendl;
1481 double peakEnergy = fEnergyPeaks[peakNumber];
1482 std::string title =
"Gain map for energy " +
DoubleToString(peakEnergy,
"%g") +
";" +
1483 GetSpatialObservableX() +
";" + GetSpatialObservableY();
1484 std::string t =
"gainMap" + std::to_string(peakNumber) +
"_" + std::to_string(fPlaneId) +
"_" +
1485 std::to_string(fModuleId);
1486 TCanvas* gainMap =
new TCanvas(t.c_str(), t.c_str());
1488 TH2F* hGainMap =
new TH2F((
"h" + t).c_str(), title.c_str(), fNumberOfSegmentsX, fReadoutRange.X(),
1489 fReadoutRange.Y(), fNumberOfSegmentsY, fReadoutRange.X(), fReadoutRange.Y());
1491 double peakPosRef = fFullLinearFit->GetPointX(peakNumber);
1492 if (!fullModuleAsRef) {
1493 int index_x = fNumberOfSegmentsX > 0 ? (fNumberOfSegmentsX - 1) / 2 : 0;
1494 int index_y = fNumberOfSegmentsY > 0 ? (fNumberOfSegmentsY - 1) / 2 : 0;
1495 peakPosRef = fSegLinearFit[index_x][index_y]->GetPointX(peakNumber);
1498 auto itX = fSplitX.begin();
1499 for (
size_t i = 0; i < fSegLinearFit.size(); i++) {
1500 auto itY = fSplitY.begin();
1501 for (
size_t j = 0; j < fSegLinearFit.at(0).size(); j++) {
1503 auto xUpper = *std::next(itX);
1505 auto yUpper = *std::next(itY);
1506 float xMean = (xUpper + xLower) / 2.;
1507 float yMean = (yUpper + yLower) / 2.;
1508 auto [index_x, index_y] = GetIndexMatrix(xMean, yMean);
1509 if (!fSegLinearFit[index_x][index_y])
continue;
1510 hGainMap->Fill(xMean, yMean, fSegLinearFit[index_x][index_y]->GetPointX(peakNumber) / peakPosRef);
1515 hGainMap->SetStats(0);
1516 hGainMap->Draw(
"colz");
1517 hGainMap->SetBarOffset(0.2);
1519 hGainMap->Draw(
"TEXT SAME");
1528 RESTMetadata <<
"-----------------------------------------------" << p->RESTendl;
1529 RESTMetadata <<
" Plane ID: " << fPlaneId << p->RESTendl;
1530 RESTMetadata <<
" Module ID: " << fModuleId << p->RESTendl;
1531 RESTMetadata <<
" Definition cut: " << fDefinitionCut << p->RESTendl;
1532 RESTMetadata << p->RESTendl;
1534 RESTMetadata <<
" Calibration dataset: " << fDataSetFileName << p->RESTendl;
1535 RESTMetadata << p->RESTendl;
1537 RESTMetadata <<
" Energy peaks: ";
1538 for (
const auto& peak : fEnergyPeaks) RESTMetadata << peak <<
", ";
1539 RESTMetadata << p->RESTendl;
1540 bool anyRange =
false;
1541 for (
const auto& r : fRangePeaks)
1542 if (r.X() < r.Y()) {
1543 RESTMetadata <<
" Range peaks: ";
1548 for (
const auto& r : fRangePeaks) RESTMetadata <<
"(" << r.X() <<
", " << r.Y() <<
") ";
1549 if (anyRange) RESTMetadata << p->RESTendl;
1550 RESTMetadata <<
" Auto range peaks: " << (fAutoRangePeaks ?
"true" :
"false") << p->RESTendl;
1551 RESTMetadata <<
" Zero point: " << (fZeroPoint ?
"true" :
"false") << p->RESTendl;
1552 RESTMetadata <<
" Calibration range: (" << fCalibRange.X() <<
", " << fCalibRange.Y() <<
" )"
1554 RESTMetadata <<
" Number of bins: " << fNBins << p->RESTendl;
1555 RESTMetadata << p->RESTendl;
1557 RESTMetadata <<
" Number of segments X: " << fNumberOfSegmentsX << p->RESTendl;
1558 RESTMetadata <<
" Number of segments Y: " << fNumberOfSegmentsY << p->RESTendl;
1560 RESTMetadata <<
" Readout range (" << fReadoutRange.X() <<
", " << fReadoutRange.Y() <<
" )"
1562 RESTMetadata <<
"SplitX: ";
1563 for (
auto& i : fSplitX) {
1564 RESTMetadata <<
" " << i;
1566 RESTMetadata << p->RESTendl;
1567 RESTMetadata <<
"SplitY: ";
1568 for (
auto& i : fSplitY) {
1569 RESTMetadata <<
" " << i;
1571 RESTMetadata << p->RESTendl;
1572 RESTMetadata << p->RESTendl;
1574 RESTMetadata <<
" Slope: " << p->RESTendl;
1576 for (
auto& x : fSlope)
1577 if (maxSize < x.size()) maxSize = x.size();
1578 for (
size_t j = 0; j < maxSize; j++) {
1579 for (
size_t k = 0; k < fSlope.size(); k++) {
1580 if (j < fSlope[k].size())
1581 RESTMetadata <<
DoubleToString(fSlope[k][fSlope[k].size() - 1 - j],
"%.3e") <<
" ";
1583 RESTMetadata <<
" ";
1585 RESTMetadata << p->RESTendl;
1587 RESTMetadata <<
" Intercept: " << p->RESTendl;
1589 for (
auto& x : fIntercept)
1590 if (maxSize < x.size()) maxSize = x.size();
1591 for (
size_t j = 0; j < maxSize; j++) {
1592 for (
size_t k = 0; k < fIntercept.size(); k++) {
1593 if (j < fIntercept[k].size())
1594 RESTMetadata <<
DoubleToString(fIntercept[k][fIntercept[k].size() - 1 - j],
"%+.3e") <<
" ";
1596 RESTMetadata <<
" ";
1598 RESTMetadata << p->RESTendl;
1600 RESTMetadata << p->RESTendl;
1601 RESTMetadata <<
" Full slope: " <<
DoubleToString(fFullSlope,
"%.3e") << p->RESTendl;
1602 RESTMetadata <<
" Full intercept: " <<
DoubleToString(fFullIntercept,
"%+.3e") << p->RESTendl;
1604 RESTMetadata <<
"-----------------------------------------------" << p->RESTendl;
A class to help on cuts definitions. To be used with TRestAnalysisTree.
void SetSplitY()
Function to set the class members for segmentation of the detector plane along the Y axis.
void SetSplits()
Function to set the class members for segmentation of the detector plane along the X and Y axis.
void SetSplitX()
Function to set the class members for segmentation of the detector plane along the X axis.
void DrawSpectrum(const bool drawFits=true, const int color=-1, TCanvas *c=nullptr)
Function to draw the spectrum for each segment of the module on the same canvas. The canvas is divide...
void LoadConfigFromTiXmlElement(const TiXmlElement *module)
Function to read the parameters from the RML element (TiXmlElement) and set those class members.
void GenerateGainMap()
Function that calculates the calibration parameters for each segment defined at fSplitX and fSplitY a...
void DrawGainMap(const int peakNumber=0, const bool fullModuleAsRef=true, const bool showText=true)
Function to draw the relative gain map for a given energy peak of the module.
double GetSlope(const double x, const double y) const
Function to get the calibration parameter slope for a given x and y position on the detector plane.
std::set< double > fSplitX
Split points in the x direction.
void Print() const
Prints on screen the information about the members of Module.
void Refit(const TVector2 &position, const double energy, const TVector2 &range)
Function to fit again manually a peak for a given segment of the module.
std::set< double > fSplitY
Split points in the y direction.
void RefitFullSpc(const double energy, const TVector2 &range)
Function to fit again manually a peak for the whole module spectrum. The calibration curve is updated...
const TRestDataSetGainMap * p
Pointer to the parent class.
void UpdateCalibrationFitsFullSpc()
Function to update the calibration curve for the whole module. The calibration curve is cleared and t...
double GetIntercept(const double x, const double y) const
Function to get the calibration parameter intercept for a given x and y position on the detector plan...
std::pair< int, int > GetIndexMatrix(const double x, const double y) const
Function to get the index of the matrix of calibration parameters for a given x and y position on the...
Metadata class to calculate,store and apply the gain corrected calibration of a group of detectors.
double GetInterceptParameter(const int planeID, const int moduleID, const double x, const double y)
Function to get the intercept parameter of the module with planeID and moduleID at physical position ...
double GetSlopeParameter(const int planeID, const int moduleID, const double x, const double y)
Function to get the slope parameter of the module with planeID and moduleID at physical position (x,...
std::string fObservable
Observable that will be used to calculate the gain map.
double GetInterceptParameterFullSpc(const int planeID, const int moduleID)
Function to get the intercept parameter of the whole module with planeID and moduleID.
void CalibrateDataSet(const std::string &dataSetFileName, std::string outputFileName="", std::vector< std::string > excludeColumns={})
Function to calibrate a dataset with this gain map.
~TRestDataSetGainMap()
Default destructor.
void GenerateGainMap()
Function to calculate the calibration parameters of all modules.
std::string fSpatialObservableXSecondary
Secondary observable that will be used to segmentize the gain map in the x direction (if needed)
TRestDataSetGainMap()
Default constructor.
void Initialize() override
Making default settings.
std::vector< Module > fModulesCal
List of modules.
void SetModule(const Module &moduleCal)
Function to set a module calibration. If the module calibration already exists (same planeId and modu...
void InitFromConfigFile() override
Initialization of TRestDataSetGainMap members through a RML file.
double GetSlopeParameterFullSpc(const int planeID, const int moduleID)
Function to get the slope parameter of the whole module with planeID and moduleID.
void Export(const std::string &fileName="")
Function to export the calibration to the file fileName.
void PrintMetadata() override
Prints on screen the information about the metadata members.
std::map< int, std::set< int > > GetModuleIDs() const
Function to get the map of the module IDs for each plane ID.
std::string fSpatialObservableY
Observable that will be used to segmentize the gain map in the y direction.
std::string fCalibFileName
Name of the file that contains the calibration data.
TRestCut * fCut
Cut to be applied to the calibration data.
std::string fOutputFileName
Name of the file where the gain map was (or will be) exported.
std::string fSpatialObservableYSecondary
Secondary observable that will be used to segmentize the gain map in the y direction (if needed)
std::set< int > GetPlaneIDs() const
Function to get a list (set) of the plane IDs.
std::string fSpatialObservableX
Observable that will be used to segmentize the gain map in the x direction.
Module * GetModule(const size_t index=0)
Function to retrieve the module calibration by index. Default is 0.
void Import(const std::string &fileName)
Function to import the calibration parameters from the root file fileName.
It allows to group a number of runs that satisfy given metadata conditions.
void Import(const std::string &fileName)
This function imports metadata from a root file it import metadata info from the previous dataSet whi...
ROOT::RDF::RNode GetDataFrame() const
Gives access to the RDataFrame.
ROOT::RDF::RNode MakeCut(const TRestCut *cut)
This function applies a TRestCut to the dataframe and returns a dataframe with the applied cuts....
void GenerateDataSet()
This function generates the data frame with the filelist and column names (or observables) that have ...
void Export(const std::string &filename, std::vector< std::string > excludeColumns={})
It will generate an output file with the dataset compilation. Only the selected branches and the file...
@ REST_Info
+show most of the information for each steps
@ REST_Debug
+show the defined debug messages
TClass * GetClassQuick()
Get the type of a "class" object, returning the wrapped type identifier "TClass".
Double_t StringToDouble(std::string in)
Gets a double from a string.
Int_t StringToInteger(std::string in)
Gets an integer from a string.
std::string DoubleToString(Double_t d, std::string format="%8.6e")
Gets a string from a double.
TVector2 StringTo2DVector(std::string in)
Gets a 2D-vector from a string.
std::string ToLower(std::string in)
Convert string to its lower case. Alternative of TString::ToLower.