138#include "TRestDataSetGainMap.h"
181 TiXmlElement* moduleDefinition =
GetElement(
"module");
182 while (moduleDefinition !=
nullptr) {
184 fModulesCal.back().LoadConfigFromTiXmlElement(moduleDefinition);
199 RESTInfo <<
"Generating gain map of plane " << mod.GetPlaneId() <<
" module " << mod.GetModuleId()
201 mod.GenerateGainMap();
204 mod.DrawFullSpectrum();
223 std::vector<std::string> excludeColumns) {
225 RESTError <<
"TRestDataSetGainMap::CalibrateDataSet: No modules defined." <<
RESTendl;
230 dataSet.EnableMultiThreading(
true);
231 dataSet.
Import(dataSetFileName);
235 std::string pmIDname = (std::string)GetName() +
"_pmID";
236 std::string modCut =
fModulesCal[0].GetModuleDefinitionCut();
239 auto columnList = dataFrame.GetColumnNames();
240 if (std::find(columnList.begin(), columnList.end(), pmIDname) == columnList.end())
241 dataFrame = dataFrame.Define(pmIDname, modCut +
" ? " + std::to_string(pmID) +
" : -1");
243 dataFrame = dataFrame.Redefine(pmIDname, modCut +
" ? " + std::to_string(pmID) +
" : -1");
248 dataFrame = dataFrame.Redefine(pmIDname, (modCut +
" ? " + std::to_string(pmID) +
" : " + pmIDname));
252 auto calibrate = [
this](
double val,
double x,
double y,
int pmID) {
254 if (pmID == m.GetPlaneId() * 10 + m.GetModuleId())
255 return m.GetSlope(x, y) * val + m.GetIntercept(x, y);
259 return std::numeric_limits<double>::quiet_NaN();
261 std::string calibObsName = (std::string)GetName() +
"_";
262 calibObsName += GetObservable().erase(0, GetObservable().find(
"_") + 1);
263 dataFrame = dataFrame.Define(calibObsName, calibrate,
267 auto calibrateFullSpc = [
this](
double val,
int pmID) {
269 if (pmID == m.GetPlaneId() * 10 + m.GetModuleId())
270 return m.GetSlopeFullSpc() * val + m.GetInterceptFullSpc();
274 return std::numeric_limits<double>::quiet_NaN();
276 std::string calibObsNameFullSpc = (std::string)GetName() +
"_";
277 calibObsNameFullSpc +=
278 GetObservable().erase(0, GetObservable().find(
"_") + 1);
279 calibObsNameFullSpc +=
"_NoSegmentation";
280 dataFrame = dataFrame.Define(calibObsNameFullSpc, calibrateFullSpc, {
fObservable, pmIDname});
282 dataSet.SetDataFrame(dataFrame);
285 if (outputFileName.empty()) outputFileName = dataSetFileName;
286 if (outputFileName == dataSetFileName) {
287 std::string gmName = GetName();
288 outputFileName = outputFileName.substr(0, outputFileName.find_last_of(
"."));
289 outputFileName +=
"_" + gmName;
294 std::set<std::string> excludeCol;
297 for (
auto& eC : excludeColumns) {
298 if (eC.find(
"*") != std::string::npos || eC.find(
"?") != std::string::npos) {
299 for (
auto& c : columns)
301 }
else if (std::find(columns.begin(), columns.end(), eC) != columns.end())
302 excludeCol.insert(eC);
305 excludeCol.erase(calibObsName);
306 excludeCol.erase(calibObsNameFullSpc);
307 excludeCol.erase(pmIDname);
309 RESTDebug <<
"Excluding columns: ";
310 for (
auto& c : excludeCol) RESTDebug << c <<
", ";
313 dataSet.
Export(outputFileName, std::vector<std::string>(excludeCol.begin(), excludeCol.end()));
316 TFile* f = TFile::Open(outputFileName.c_str(),
"UPDATE");
329 RESTError <<
"No ModuleCalibration with index " << index;
331 RESTError <<
". There are no modules defined." <<
RESTendl;
343 if (i.GetPlaneId() == planeID && i.GetModuleId() == moduleID)
return &i;
345 RESTError <<
"No ModuleCalibration with planeID " << planeID <<
" and moduleID " << moduleID <<
RESTendl;
357 if (moduleCal ==
nullptr)
return 0;
367 if (moduleCal ==
nullptr)
return 0;
368 return moduleCal->GetSlopeFullSpc();
379 if (moduleCal ==
nullptr)
return 0;
389 if (moduleCal ==
nullptr)
return 0;
390 return moduleCal->GetInterceptFullSpc();
398 std::set<int> planeIDs;
399 for (
const auto& mc :
fModulesCal) planeIDs.insert(mc.GetPlaneId());
408 std::set<int> moduleIDs;
410 if (mc.GetPlaneId() == planeId) moduleIDs.insert(mc.GetModuleId());
418 std::map<int, std::set<int>> moduleIds;
420 moduleIds.insert(std::pair<
int, std::set<int>>(planeId,
GetModuleIDs(planeId)));
425 SetName(src.GetName());
443 if (i.GetPlaneId() == moduleCal.GetPlaneId() && i.GetModuleId() == moduleCal.GetModuleId()) {
456 if (fileName.empty()) {
457 RESTError <<
"No input calibration file defined" <<
RESTendl;
462 RESTInfo <<
"Opening " << fileName <<
RESTendl;
463 TFile* f = TFile::Open(fileName.c_str(),
"READ");
465 RESTError <<
"Cannot open calibration file " << fileName <<
RESTendl;
471 TIter nextkey(f->GetListOfKeys());
473 while ((key = (TKey*)nextkey())) {
474 std::string kName = key->GetClassName();
483 RESTError <<
"File extension not supported for " << fileName <<
RESTendl;
496 RESTError <<
"No output file defined" <<
RESTendl;
502 this->
Write(GetName());
517 RESTMetadata <<
" Cuts applied: ";
520 for (
const auto& cut :
fCut->GetCutStrings()) RESTMetadata << cut <<
", " <<
RESTendl;
521 for (
const auto& cut :
fCut->GetParamCut())
522 RESTMetadata << cut.first <<
" " << cut.second <<
", " <<
RESTendl;
526 RESTMetadata <<
" Number of planes: " << GetNumberOfPlanes() <<
RESTendl;
527 RESTMetadata <<
" Number of modules: " << GetNumberOfModules() <<
RESTendl;
531 RESTMetadata <<
"-----------------------------------------------" <<
RESTendl;
533 RESTMetadata <<
"***********************************************" <<
RESTendl;
545 int index_x = -1, index_y = -1;
548 index_x = std::distance(
fSplitX.begin(),
fSplitX.upper_bound(x)) - 1;
550 RESTWarning <<
"index_x < 0 for x = " << x <<
" and fSplitX[0]=" << *
fSplitX.begin()
555 RESTWarning <<
"x is out of split for x = " << x <<
p->
RESTendl;
560 index_y = std::distance(
fSplitY.begin(),
fSplitY.upper_bound(y)) - 1;
562 RESTWarning <<
"index_y < 0 for y = " << y <<
" and fSplitY[0]=" << *
fSplitY.begin()
567 RESTWarning <<
"y is out of split for y = " << y <<
p->
RESTendl;
571 return std::make_pair(index_x, index_y);
581 auto [index_x, index_y] = GetIndexMatrix(x, y);
582 if (fSlope.empty()) {
583 RESTError <<
"Calibration slope matrix is empty. Returning 0" << p->RESTendl;
587 if (index_x > (
int)fSlope.size() || index_y > (
int)fSlope.at(0).size()) {
588 RESTError <<
"Index out of range. Returning 0" << p->RESTendl;
592 return fSlope[index_x][index_y];
603 auto [index_x, index_y] = GetIndexMatrix(x, y);
604 if (fIntercept.empty()) {
605 RESTError <<
"Calibration constant matrix is empty. Returning 0" << p->RESTendl;
609 if (index_x > (
int)fIntercept.size() || index_y > (
int)fIntercept.at(0).size()) {
610 RESTError <<
"Index out of range. Returning 0" << p->RESTendl;
614 return fIntercept[index_x][index_y];
631 if (fNumberOfSegmentsX < 1) {
632 RESTError <<
"SetSplitX: fNumberOfSegmentsX must be >=1." << p->RESTendl;
635 std::set<double> split;
636 for (
int i = 0; i <= fNumberOfSegmentsX; i++) {
638 fReadoutRange.X() + ((fReadoutRange.Y() - fReadoutRange.X()) / (
float)fNumberOfSegmentsX) * i;
645 if (splitX.size() < 2) {
646 RESTError <<
"SetSplitX: split size must be >=2 (start and end of range must be included)."
651 RESTWarning <<
"SetSplitX: changing split but current gain map and calibration paremeters correspond "
652 "to previous splitting. Use GenerateGainMap() to update them."
655 fNumberOfSegmentsX = fSplitX.size() - 1;
664 if (fNumberOfSegmentsY < 1) {
665 RESTError <<
"SetSplitY: fNumberOfSegmentsY must be >=1." << p->RESTendl;
668 std::set<double> split;
669 for (
int i = 0; i <= fNumberOfSegmentsY; i++) {
671 fReadoutRange.X() + ((fReadoutRange.Y() - fReadoutRange.X()) / (
float)fNumberOfSegmentsY) * i;
678 if (splitY.size() < 2) {
679 RESTError <<
"SetSplitY: split size must be >=2 (start and end of range must be included)."
684 RESTWarning <<
"SetSplitY: changing split but current gain map and calibration paremeters correspond "
685 "to previous splitting. Use GenerateGainMap() to update them."
688 fNumberOfSegmentsY = fSplitY.size() - 1;
709 std::string dsFileName = fDataSetFileName;
710 if (dsFileName.empty()) dsFileName = p->GetCalibrationFileName();
711 if (dsFileName.empty()) {
712 RESTError <<
"No calibration file defined" << p->RESTendl;
717 RESTError <<
"Calibration file " << dsFileName <<
" does not exist." << p->RESTendl;
720 if (!
TRestTools::isDataSet(dsFileName)) RESTWarning << dsFileName <<
" is not a dataset." << p->RESTendl;
722 dataSet.EnableMultiThreading(
true);
723 dataSet.
Import(dsFileName);
724 fDataSetFileName = dsFileName;
726 dataSet.SetDataFrame(dataSet.
MakeCut(p->GetCut()));
728 if (fSplitX.empty()) SetSplitX();
729 if (fSplitY.empty()) SetSplitY();
732 if (fCalibRange.X() >= fCalibRange.Y()) {
734 std::string cut = fDefinitionCut;
735 if (cut.empty()) cut =
"1";
736 auto histo = dataSet.
GetDataFrame().Filter(cut).Histo1D({
"temp",
"", fNBins, 0, 0}, GetObservable());
737 std::unique_ptr<TH1F> hpunt = std::unique_ptr<TH1F>(
static_cast<TH1F*
>(histo->Clone()));
739 double xMax = hpunt->GetXaxis()->GetXmax();
742 double fraction = 1, nAtEndSpc = 0, step = 0.66;
743 while (nAtEndSpc * 1. / hpunt->Integral() < 0.01 && fraction > 0.001) {
745 nAtEndSpc = hpunt->Integral(hpunt->FindFixBin(hpunt->GetXaxis()->GetXmax() * fraction),
746 hpunt->FindFixBin(hpunt->GetXaxis()->GetXmax()));
748 xMax = hpunt->GetXaxis()->GetXmax() * fraction /
752 fCalibRange.SetY(xMax);
754 RESTDebug <<
"Calibration range (auto)set to (" << fCalibRange.X() <<
"," << fCalibRange.Y() <<
")"
759 std::string hModuleName =
"hSpc_" + std::to_string(fPlaneId) +
"_" + std::to_string(fModuleId);
760 delete fFullSpectrum;
761 fFullSpectrum =
new TH1F(hModuleName.c_str(),
"", fNBins, fCalibRange.X(), fCalibRange.Y());
764 std::string cut = fDefinitionCut;
765 if (cut.empty()) cut =
"1";
766 auto histoMod = dataSet.
GetDataFrame().Filter(cut).Histo1D(
767 {
"tempMod",
"", fNBins, fCalibRange.X(), fCalibRange.Y()}, GetObservable());
768 std::unique_ptr<TH1F> hpuntMod = std::unique_ptr<TH1F>(
static_cast<TH1F*
>(histoMod->Clone()));
769 fFullSpectrum->Add(hpuntMod.get());
772 std::vector<std::vector<TH1F*>> h(fNumberOfSegmentsX, std::vector<TH1F*>(fNumberOfSegmentsY,
nullptr));
773 for (
size_t i = 0; i < h.size(); i++) {
774 for (
size_t j = 0; j < h.at(0).size(); j++) {
775 std::string name = hModuleName +
"_" + std::to_string(i) +
"_" + std::to_string(j);
776 h[i][j] =
new TH1F(name.c_str(),
"", fNBins, fCalibRange.X(),
782 auto itX = fSplitX.begin();
783 for (
size_t i = 0; i < h.size(); i++) {
784 auto itY = fSplitY.begin();
785 for (
size_t j = 0; j < h.at(0).size(); j++) {
788 auto xUpper = *std::next(itX);
790 auto yUpper = *std::next(itY);
792 std::string segment_cut =
"";
793 if (!GetSpatialObservableX().empty())
794 segment_cut += GetSpatialObservableX() +
">=" + std::to_string(xLower) +
"&&" +
795 GetSpatialObservableX() +
"<" + std::to_string(xUpper);
796 if (!GetSpatialObservableY().empty())
797 segment_cut +=
"&&" + GetSpatialObservableY() +
">=" + std::to_string(yLower) +
"&&" +
798 GetSpatialObservableY() +
"<" + std::to_string(yUpper);
799 if (!fDefinitionCut.empty()) segment_cut +=
"&&" + fDefinitionCut;
800 if (segment_cut.empty()) segment_cut =
"1";
801 RESTExtreme <<
"Segment[" << i <<
"][" << j <<
"] cut: " << segment_cut << p->RESTendl;
804 .Histo1D({
"temp",
"", h[i][j]->GetNbinsX(), h[i][j]->GetXaxis()->GetXmin(),
805 h[i][j]->GetXaxis()->GetXmax()},
807 std::unique_ptr<TH1F> hpunt = std::unique_ptr<TH1F>(
static_cast<TH1F*
>(histo->Clone()));
808 h[i][j]->Add(hpunt.get());
816 std::vector<std::vector<double>> calParSlope(fNumberOfSegmentsX,
817 std::vector<double>(fNumberOfSegmentsY, 0));
818 std::vector<std::vector<double>> calParIntercept(fNumberOfSegmentsX,
819 std::vector<double>(fNumberOfSegmentsY, 0));
820 fSegLinearFit = std::vector(h.size(), std::vector<TGraph*>(h.at(0).size(),
nullptr));
821 for (
size_t i = 0; i < h.size(); i++)
822 for (
int j = 0; j < (int)h.at(0).size(); j++) {
823 fSegLinearFit[i][j] =
new TGraph();
824 auto [intercept, slope] = FitPeaks(h[i][j], fSegLinearFit[i][j]);
825 calParSlope[i][j] = slope;
826 calParIntercept[i][j] = intercept;
828 fSlope = calParSlope;
829 fIntercept = calParIntercept;
833 delete fFullLinearFit;
834 fFullLinearFit =
new TGraph();
835 auto [intercept, slope] = FitPeaks(fFullSpectrum, fFullLinearFit);
837 fFullIntercept = intercept;
840std::pair<double, double> TRestDataSetGainMap::Module::FitPeaks(TH1F* hSeg, TGraph* gr) {
842 RESTError <<
"No histogram for fitting" << p->RESTendl;
843 return std::make_pair(0, 0);
845 if (hSeg->Integral() == 0) {
846 RESTError <<
"Empty spectrum " << hSeg->GetName() << p->RESTendl;
847 return std::make_pair(0, 0);
849 std::shared_ptr<TGraph> graph = std::shared_ptr<TGraph>(
new TGraph());
850 RESTExtreme <<
"Fitting peaks for " << hSeg->GetName() << p->RESTendl;
853 std::unique_ptr<TSpectrum> s(
new TSpectrum(2 * fEnergyPeaks.size() + 1));
854 std::vector<double> peakPos;
855 s->Search(hSeg, 2,
"goff", 0.1);
856 for (
int k = 0; k < s->GetNPeaks(); k++) peakPos.push_back(s->GetPositionX()[k]);
857 std::sort(peakPos.begin(), peakPos.end(), std::greater<double>());
859 peakPos.size() == 0 ? 1 : peakPos.front() / fEnergyPeaks.front();
862 graph->SetName(
"grFit");
863 graph->SetTitle((
";" + GetObservable() +
";energy").c_str());
868 for (
const auto& energy : fEnergyPeaks) {
869 RESTExtreme <<
"\t fitting energy " <<
DoubleToString(energy,
"%g") << p->RESTendl;
871 double pos = energy * ratio;
872 double start = pos * 0.8;
873 double end = pos * 1.2;
874 if (fRangePeaks.at(c).X() < fRangePeaks.at(c).Y()) {
875 start = fRangePeaks.at(c).X();
876 end = fRangePeaks.at(c).Y();
880 if (fAutoRangePeaks) {
881 if (peakPos.size() > 0) {
884 while (!(start < pos && pos < end)) {
887 if (pos == peakPos.back()) {
891 pos = *std::next(std::find(peakPos.begin(), peakPos.end(),
894 peakPos.erase(std::find(peakPos.begin(), peakPos.end(),
900 const double relDist = peakPos.size() > 0 ? (pos - peakPos.front()) / pos : 999;
902 start = pos * (1 - relDist / 2);
903 end = pos * (1 + relDist / 2);
908 std::string name =
"g" + std::to_string(c);
909 TF1* g =
new TF1(name.c_str(),
"gaus", start, end);
910 RESTExtreme <<
"\t\tat " <<
DoubleToString(pos,
"%.3g") <<
". Range("
914 if (hSeg->GetFunction(name.c_str()))
915 hSeg->GetListOfFunctions()->Remove(hSeg->GetFunction(name.c_str()));
917 hSeg->Fit(g,
"R+Q0");
918 mu = g->GetParameter(1);
919 RESTExtreme <<
"\t\tgaus mean " <<
DoubleToString(mu,
"%g") << p->RESTendl;
920 }
while (fAutoRangePeaks && peakPos.size() > 0 &&
921 !(start < mu && mu < end));
922 graph->SetPoint(c++, mu, energy);
926 if (fZeroPoint) graph->SetPoint(c++, 0, 0);
927 while (graph->GetN() < 2) {
928 graph->SetPoint(c++, 0, 0);
930 RESTDebug <<
"Not enough points for linear fit. Adding and setting zero point to true" << p->RESTendl;
934 std::unique_ptr<TF1> linearFit;
935 linearFit = std::unique_ptr<TF1>(
new TF1(
"linearFit",
"pol1"));
936 graph->Fit(
"linearFit",
"SQ");
938 if (gr) *gr = *(TGraph*)graph->Clone();
939 return std::make_pair(linearFit->GetParameter(0), linearFit->GetParameter(1));
950 const TVector2& range) {
951 auto [index_x, index_y] = GetIndexMatrix(position.X(), position.Y());
953 for (
size_t i = 0; i < fEnergyPeaks.size(); i++)
954 if (fEnergyPeaks.at(i) == energyPeak) {
958 if (peakNumber == -1) {
959 RESTError <<
"Energy " << energyPeak <<
" not found in the list of energy peaks" << p->RESTendl;
962 Refit((
size_t)index_x, (
size_t)index_y, (
size_t)peakNumber, range);
975 const TVector2& range) {
976 if (fSegSpectra.empty()) {
977 RESTError <<
"No gain map found. Use GenerateGainMap() first." << p->RESTendl;
980 if (x >= fSegSpectra.size() || y >= fSegSpectra.at(0).size()) {
981 RESTError <<
"Segment with index (" << x <<
", " << y <<
") not found" << p->RESTendl;
984 if (peakNumber >= fEnergyPeaks.size()) {
985 RESTError <<
"Peak with index " << peakNumber <<
" not found" << p->RESTendl;
990 std::string name =
"g" + std::to_string(peakNumber);
991 TF1* g =
new TF1(name.c_str(),
"gaus", range.X(), range.Y());
992 TH1F* h = fSegSpectra.at(x).at(y);
993 while (h->GetFunction(name.c_str()))
994 h->GetListOfFunctions()->Remove(h->GetFunction(name.c_str()));
998 UpdateCalibrationFits(x, y);
1009 int peakNumber = -1;
1010 for (
size_t i = 0; i < fEnergyPeaks.size(); i++)
1011 if (fEnergyPeaks.at(i) == energyPeak) {
1015 if (peakNumber == -1) {
1016 RESTError <<
"Energy " << energyPeak <<
" not found in the list of energy peaks" << p->RESTendl;
1019 RefitFullSpc((
size_t)peakNumber, range);
1030 if (!fFullSpectrum) {
1031 RESTError <<
"No gain map found. Use GenerateGainMap() first." << p->RESTendl;
1034 if (peakNumber >= fEnergyPeaks.size()) {
1035 RESTError <<
"Peak with index " << peakNumber <<
" not found" << p->RESTendl;
1040 std::string name =
"g" + std::to_string(peakNumber);
1041 TF1* g =
new TF1(name.c_str(),
"gaus", range.X(), range.Y());
1042 while (fFullSpectrum->GetFunction(name.c_str()))
1043 fFullSpectrum->GetListOfFunctions()->Remove(fFullSpectrum->GetFunction(name.c_str()));
1044 fFullSpectrum->Fit(g,
"R+Q0");
1047 UpdateCalibrationFitsFullSpc();
1058void TRestDataSetGainMap::Module::UpdateCalibrationFits(
const size_t x,
const size_t y) {
1059 if (fSegSpectra.empty()) {
1060 RESTError <<
"No gain map found. Use GenerateGainMap() first." << p->RESTendl;
1063 if (x >= fSegSpectra.size() || y >= fSegSpectra.at(0).size()) {
1064 RESTError <<
"Segment with index (" << x <<
", " << y <<
") not found" << p->RESTendl;
1068 TH1F* h = fSegSpectra.at(x).at(y);
1069 TGraph* gr = fSegLinearFit.at(x).at(y);
1071 auto [intercept, slope] = UpdateCalibrationFits(h, gr);
1072 fSlope[x][y] = slope;
1073 fIntercept[x][y] = intercept;
1076std::pair<double, double> TRestDataSetGainMap::Module::UpdateCalibrationFits(TH1F* h, TGraph* gr) {
1078 RESTError <<
"No histogram for updating fits" << p->RESTendl;
1079 return std::make_pair(0, 0);
1082 RESTError <<
"No graph for updating fits" << p->RESTendl;
1083 return std::make_pair(0, 0);
1085 if (h->Integral() == 0) {
1086 RESTError <<
"Empty spectrum " << h->GetName() << p->RESTendl;
1087 return std::make_pair(0, 0);
1091 for (
size_t i = 0; i < fEnergyPeaks.size(); i++) gr->RemovePoint(i);
1094 for (
size_t i = 0; i < fEnergyPeaks.size(); i++) {
1095 std::string fitName = (std::string)
"g" + std::to_string(i);
1096 TF1* g = h->GetFunction(fitName.c_str());
1098 RESTWarning <<
"No fit ( " << fitName <<
" ) found for energy peak " << fEnergyPeaks[i]
1099 <<
" in histogram " << h->GetName() << p->RESTendl;
1102 gr->SetPoint(c++, g->GetParameter(1), fEnergyPeaks[i]);
1106 while (gr->GetN() < 2) {
1107 gr->SetPoint(c++, 0, 0);
1112 if (gr->GetFunction(
"linearFit"))
1113 lf = gr->GetFunction(
"linearFit");
1115 lf =
new TF1(
"linearFit",
"pol1");
1118 return std::make_pair(lf->GetParameter(0), lf->GetParameter(1));
1127 auto [intercept, slope] = UpdateCalibrationFits(fFullSpectrum, fFullLinearFit);
1129 fFullIntercept = intercept;
1147 if (module ==
nullptr) {
1148 RESTError <<
"TRestDataSetGainMap::Module::LoadConfigFromTiXmlElement: module is nullptr"
1153 std::string el = !module->Attribute(
"planeId") ?
"Not defined" : module->Attribute(
"planeId");
1154 if (!(el.empty() || el ==
"Not defined")) this->SetPlaneId(
StringToInteger(el));
1155 el = !module->Attribute(
"moduleId") ?
"Not defined" : module->Attribute(
"moduleId");
1156 if (!(el.empty() || el ==
"Not defined")) this->SetModuleId(
StringToInteger(el));
1158 el = !module->Attribute(
"moduleDefinitionCut") ?
"Not defined" : module->Attribute(
"moduleDefinitionCut");
1159 if (!(el.empty() || el ==
"Not defined")) this->SetModuleDefinitionCut(el);
1161 el = !module->Attribute(
"numberOfSegmentsX") ?
"Not defined" : module->Attribute(
"numberOfSegmentsX");
1162 if (!(el.empty() || el ==
"Not defined")) this->SetNumberOfSegmentsX(
StringToInteger(el));
1163 el = !module->Attribute(
"numberOfSegmentsY") ?
"Not defined" : module->Attribute(
"numberOfSegmentsY");
1164 if (!(el.empty() || el ==
"Not defined")) this->SetNumberOfSegmentsY(
StringToInteger(el));
1165 el = !module->Attribute(
"readoutRange") ?
"Not defined" : module->Attribute(
"readoutRange");
1166 if (!(el.empty() || el ==
"Not defined")) this->SetReadoutRange(
StringTo2DVector(el));
1168 el = !module->Attribute(
"calibRange") ?
"Not defined" : module->Attribute(
"calibRange");
1169 if (!(el.empty() || el ==
"Not defined")) this->SetCalibrationRange(
StringTo2DVector(el));
1170 el = !module->Attribute(
"nBins") ?
"Not defined" : module->Attribute(
"nBins");
1171 if (!(el.empty() || el ==
"Not defined")) this->SetNBins(
StringToInteger(el));
1173 el = !module->Attribute(
"dataSetFileName") ?
"Not defined" : module->Attribute(
"dataSetFileName");
1174 if (!(el.empty() || el ==
"Not defined")) this->SetDataSetFileName(el);
1176 el = !module->Attribute(
"zeroPoint") ?
"Not defined" : module->Attribute(
"zeroPoint");
1177 if (!(el.empty() || el ==
"Not defined")) this->SetZeroPoint(
ToLower(el) ==
"true");
1178 el = !module->Attribute(
"autoRangePeaks") ?
"Not defined" : module->Attribute(
"autoRangePeaks");
1179 if (!(el.empty() || el ==
"Not defined")) this->SetAutoRangePeaks(
ToLower(el) ==
"true");
1182 TiXmlElement* peakDefinition = (TiXmlElement*)module->FirstChildElement(
"peak");
1183 while (peakDefinition !=
nullptr) {
1185 TVector2 range = TVector2(0, 0);
1188 !peakDefinition->Attribute(
"energy") ?
"Not defined" : peakDefinition->Attribute(
"energy");
1189 if (ell.empty() || ell ==
"Not defined") {
1190 RESTError <<
"< peak variable key does not contain energy!" << p->RESTendl;
1195 ell = !peakDefinition->Attribute(
"range") ?
"Not defined" : peakDefinition->Attribute(
"range");
1198 this->AddPeak(energy, range);
1199 peakDefinition = (TiXmlElement*)peakDefinition->NextSiblingElement();
1205 std::pair<size_t, size_t> index = GetIndexMatrix(position.X(), position.Y());
1206 DrawSpectrum(index.first, index.second, drawFits, color, c);
1211 if (fSegSpectra.size() == 0) {
1212 RESTError <<
"Spectra matrix is empty." << p->RESTendl;
1215 if (index_x < 0 || index_y < 0 || index_x >= (
int)fSegSpectra.size() ||
1216 index_y >= (
int)fSegSpectra.at(index_x).size()) {
1217 RESTError <<
"Index out of range." << p->RESTendl;
1220 if (!fSegSpectra[index_x][index_y]) {
1221 RESTError <<
"No Spectrum for segment (" << index_x <<
", " << index_y <<
")." << p->RESTendl;
1226 std::string t =
"spectrum_" + std::to_string(fPlaneId) +
"_" + std::to_string(fModuleId) +
"_" +
1227 std::to_string(index_x) +
"_" + std::to_string(index_y);
1228 c =
new TCanvas(t.c_str(), t.c_str());
1231 auto xLower = *std::next(fSplitX.begin(), index_x);
1232 auto xUpper = *std::next(fSplitX.begin(), index_x + 1);
1233 auto yLower = *std::next(fSplitY.begin(), index_y);
1234 auto yUpper = *std::next(fSplitY.begin(), index_y + 1);
1237 GetObservable() +
";counts";
1238 fSegSpectra[index_x][index_y]->SetTitle(tH.c_str());
1240 if (color > 0) fSegSpectra[index_x][index_y]->SetLineColor(color);
1241 size_t colorT = fSegSpectra[index_x][index_y]->GetLineColor();
1242 fSegSpectra[index_x][index_y]->Draw(
"same");
1245 for (
size_t c = 0; c < fEnergyPeaks.size(); c++) {
1246 auto fit = fSegSpectra[index_x][index_y]->GetFunction((
"g" + std::to_string(c)).c_str());
1248 RESTWarning <<
"Fit for energy peak " << fEnergyPeaks[c] <<
" not found." << p->RESTendl;
1250 fit->SetLineColor(c + 2 != colorT ? c + 2 : ++colorT);
1278 if (fSegSpectra.size() == 0) {
1279 RESTError <<
"Spectra matrix is empty." << p->RESTendl;
1283 std::string t =
"spectrum_" + std::to_string(fPlaneId) +
"_" + std::to_string(fModuleId);
1284 c =
new TCanvas(t.c_str(), t.c_str());
1288 for (
const auto&
object : *c->GetListOfPrimitives())
1289 if (object->InheritsFrom(TVirtualPad::Class())) ++nPads;
1290 if (nPads != 0 && nPads != fSegSpectra.size() * fSegSpectra.at(0).size()) {
1291 RESTError <<
"Canvas " << c->GetName() <<
" has " << nPads <<
" pads, but "
1292 << fSegSpectra.size() * fSegSpectra.at(0).size() <<
" are needed." << p->RESTendl;
1294 }
else if (nPads == 0)
1295 c->Divide(fSegSpectra.size(), fSegSpectra.at(0).size());
1297 for (
size_t i = 0; i < fSegSpectra.size(); i++) {
1298 for (
size_t j = 0; j < fSegSpectra[i].size(); j++) {
1299 int pad = fSegSpectra.size() * (fSegSpectra[i].size() - 1) + 1 + i - fSegSpectra.size() * j;
1301 DrawSpectrum(i, j, drawFits, color, c);
1305void TRestDataSetGainMap::Module::DrawFullSpectrum(
const bool drawFits,
const int color, TCanvas* c) {
1306 if (!fFullSpectrum) {
1307 RESTError <<
"Spectrum is empty." << p->RESTendl;
1312 std::string t =
"fullSpc_" + std::to_string(fPlaneId) +
"_" + std::to_string(fModuleId);
1313 c =
new TCanvas(t.c_str(), t.c_str());
1317 fFullSpectrum->SetTitle((
"Full spectrum;" + GetObservable() +
";counts").c_str());
1319 if (color > 0) fFullSpectrum->SetLineColor(color);
1320 size_t colorT = fFullSpectrum->GetLineColor();
1321 fFullSpectrum->Draw(
"same");
1324 for (
size_t c = 0; c < fEnergyPeaks.size(); c++) {
1325 auto fit = fFullSpectrum->GetFunction((
"g" + std::to_string(c)).c_str());
1326 if (!fit) RESTWarning <<
"Fit for energy peak" << fEnergyPeaks[c] <<
" not found." << p->RESTendl;
1328 fit->SetLineColor(c + 2 != colorT ? c + 2 : ++colorT);
1336void TRestDataSetGainMap::Module::DrawLinearFit(
const TVector2& position, TCanvas* c) {
1337 std::pair<size_t, size_t> index = GetIndexMatrix(position.X(), position.Y());
1338 DrawLinearFit(index.first, index.second, c);
1341void TRestDataSetGainMap::Module::DrawLinearFit(
const int index_x,
const int index_y, TCanvas* c) {
1342 if (fSegLinearFit.size() == 0) {
1343 RESTError <<
"Spectra matrix is empty." << p->RESTendl;
1346 if (index_x < 0 || index_y < 0 || index_x >= (
int)fSegLinearFit.size() ||
1347 index_y >= (
int)fSegLinearFit.at(index_x).size()) {
1348 RESTError <<
"Index out of range." << p->RESTendl;
1351 if (!fSegLinearFit[index_x][index_y]) {
1352 RESTError <<
"No linear fit for segment (" << index_x <<
", " << index_y <<
")." << p->RESTendl;
1357 std::string t =
"linearFit_" + std::to_string(fPlaneId) +
"_" + std::to_string(fModuleId) +
"_" +
1358 std::to_string(index_x) +
"_" + std::to_string(index_y);
1359 c =
new TCanvas(t.c_str(), t.c_str());
1361 auto xLower = *std::next(fSplitX.begin(), index_x);
1362 auto xUpper = *std::next(fSplitX.begin(), index_x + 1);
1363 auto yLower = *std::next(fSplitY.begin(), index_y);
1364 auto yUpper = *std::next(fSplitY.begin(), index_y + 1);
1367 GetObservable() +
";energy";
1368 fSegLinearFit[index_x][index_y]->SetTitle(tH.c_str());
1369 fSegLinearFit[index_x][index_y]->Draw(
"AL*");
1372void TRestDataSetGainMap::Module::DrawLinearFit(TCanvas* c) {
1373 if (fSegLinearFit.size() == 0) {
1374 RESTError <<
"Spectra matrix is empty." << p->RESTendl;
1378 std::string t =
"linearFits_" + std::to_string(fPlaneId) +
"_" + std::to_string(fModuleId);
1379 c =
new TCanvas(t.c_str(), t.c_str());
1383 for (
const auto&
object : *c->GetListOfPrimitives())
1384 if (object->InheritsFrom(TVirtualPad::Class())) ++nPads;
1385 if (nPads != 0 && nPads != fSegLinearFit.size() * fSegLinearFit.at(0).size()) {
1386 RESTError <<
"Canvas " << c->GetName() <<
" has " << nPads <<
" pads, but "
1387 << fSegLinearFit.size() * fSegLinearFit.at(0).size() <<
" are needed." << p->RESTendl;
1389 }
else if (nPads == 0)
1390 c->Divide(fSegLinearFit.size(), fSegLinearFit.at(0).size());
1392 for (
size_t i = 0; i < fSegLinearFit.size(); i++) {
1393 for (
size_t j = 0; j < fSegLinearFit[i].size(); j++) {
1394 int pad = fSegLinearFit.size() * (fSegLinearFit[i].size() - 1) + 1 + i - fSegLinearFit.size() * j;
1396 DrawLinearFit(i, j, c);
1410 if (peakNumber < 0 || peakNumber >= (
int)fEnergyPeaks.size()) {
1411 RESTError <<
"Peak number out of range (peakNumber should be between 0 and "
1412 << fEnergyPeaks.size() - 1 <<
" )" << p->RESTendl;
1415 if (fSegLinearFit.size() == 0) {
1416 RESTError <<
"Linear fit matrix is empty." << p->RESTendl;
1419 if (!fFullLinearFit) {
1420 RESTError <<
"Full linear fit is empty." << p->RESTendl;
1424 double peakEnergy = fEnergyPeaks[peakNumber];
1425 std::string title =
"Gain map for energy " +
DoubleToString(peakEnergy,
"%g") +
";" +
1426 GetSpatialObservableX() +
";" + GetSpatialObservableY();
1427 std::string t =
"gainMap" + std::to_string(peakNumber) +
"_" + std::to_string(fPlaneId) +
"_" +
1428 std::to_string(fModuleId);
1429 TCanvas* gainMap =
new TCanvas(t.c_str(), t.c_str());
1431 TH2F* hGainMap =
new TH2F((
"h" + t).c_str(), title.c_str(), fNumberOfSegmentsX, fReadoutRange.X(),
1432 fReadoutRange.Y(), fNumberOfSegmentsY, fReadoutRange.X(), fReadoutRange.Y());
1434 double peakPosRef = fFullLinearFit->GetPointX(peakNumber);
1435 if (!fullModuleAsRef) {
1436 int index_x = fNumberOfSegmentsX > 0 ? (fNumberOfSegmentsX - 1) / 2 : 0;
1437 int index_y = fNumberOfSegmentsY > 0 ? (fNumberOfSegmentsY - 1) / 2 : 0;
1438 peakPosRef = fSegLinearFit[index_x][index_y]->GetPointX(peakNumber);
1441 auto itX = fSplitX.begin();
1442 for (
size_t i = 0; i < fSegLinearFit.size(); i++) {
1443 auto itY = fSplitY.begin();
1444 for (
size_t j = 0; j < fSegLinearFit.at(0).size(); j++) {
1446 auto xUpper = *std::next(itX);
1448 auto yUpper = *std::next(itY);
1449 float xMean = (xUpper + xLower) / 2.;
1450 float yMean = (yUpper + yLower) / 2.;
1451 auto [index_x, index_y] = GetIndexMatrix(xMean, yMean);
1452 if (!fSegLinearFit[index_x][index_y])
continue;
1453 hGainMap->Fill(xMean, yMean, fSegLinearFit[index_x][index_y]->GetPointX(peakNumber) / peakPosRef);
1458 hGainMap->SetStats(0);
1459 hGainMap->Draw(
"colz");
1460 hGainMap->SetBarOffset(0.2);
1461 hGainMap->Draw(
"TEXT SAME");
1469 RESTMetadata <<
"-----------------------------------------------" << p->RESTendl;
1470 RESTMetadata <<
" Plane ID: " << fPlaneId << p->RESTendl;
1471 RESTMetadata <<
" Module ID: " << fModuleId << p->RESTendl;
1472 RESTMetadata <<
" Definition cut: " << fDefinitionCut << p->RESTendl;
1473 RESTMetadata << p->RESTendl;
1475 RESTMetadata <<
" Calibration dataset: " << fDataSetFileName << p->RESTendl;
1476 RESTMetadata << p->RESTendl;
1478 RESTMetadata <<
" Energy peaks: ";
1479 for (
const auto& peak : fEnergyPeaks) RESTMetadata << peak <<
", ";
1480 RESTMetadata << p->RESTendl;
1481 bool anyRange =
false;
1482 for (
const auto& r : fRangePeaks)
1483 if (r.X() < r.Y()) {
1484 RESTMetadata <<
" Range peaks: ";
1489 for (
const auto& r : fRangePeaks) RESTMetadata <<
"(" << r.X() <<
", " << r.Y() <<
") ";
1490 if (anyRange) RESTMetadata << p->RESTendl;
1491 RESTMetadata <<
" Auto range peaks: " << (fAutoRangePeaks ?
"true" :
"false") << p->RESTendl;
1492 RESTMetadata <<
" Zero point: " << (fZeroPoint ?
"true" :
"false") << p->RESTendl;
1493 RESTMetadata <<
" Calibration range: (" << fCalibRange.X() <<
", " << fCalibRange.Y() <<
" )"
1495 RESTMetadata <<
" Number of bins: " << fNBins << p->RESTendl;
1496 RESTMetadata << p->RESTendl;
1498 RESTMetadata <<
" Number of segments X: " << fNumberOfSegmentsX << p->RESTendl;
1499 RESTMetadata <<
" Number of segments Y: " << fNumberOfSegmentsY << p->RESTendl;
1501 RESTMetadata <<
" Readout range (" << fReadoutRange.X() <<
", " << fReadoutRange.Y() <<
" )"
1503 RESTMetadata <<
"SplitX: ";
1504 for (
auto& i : fSplitX) {
1505 RESTMetadata <<
" " << i;
1507 RESTMetadata << p->RESTendl;
1508 RESTMetadata <<
"SplitY: ";
1509 for (
auto& i : fSplitY) {
1510 RESTMetadata <<
" " << i;
1512 RESTMetadata << p->RESTendl;
1513 RESTMetadata << p->RESTendl;
1515 RESTMetadata <<
" Slope: " << p->RESTendl;
1517 for (
auto& x : fSlope)
1518 if (maxSize < x.size()) maxSize = x.size();
1519 for (
size_t j = 0; j < maxSize; j++) {
1520 for (
size_t k = 0; k < fSlope.size(); k++) {
1521 if (j < fSlope[k].size())
1522 RESTMetadata <<
DoubleToString(fSlope[k][fSlope[k].size() - 1 - j],
"%.3e") <<
" ";
1524 RESTMetadata <<
" ";
1526 RESTMetadata << p->RESTendl;
1528 RESTMetadata <<
" Intercept: " << p->RESTendl;
1530 for (
auto& x : fIntercept)
1531 if (maxSize < x.size()) maxSize = x.size();
1532 for (
size_t j = 0; j < maxSize; j++) {
1533 for (
size_t k = 0; k < fIntercept.size(); k++) {
1534 if (j < fIntercept[k].size())
1535 RESTMetadata <<
DoubleToString(fIntercept[k][fIntercept[k].size() - 1 - j],
"%+.3e") <<
" ";
1537 RESTMetadata <<
" ";
1539 RESTMetadata << p->RESTendl;
1541 RESTMetadata << p->RESTendl;
1542 RESTMetadata <<
" Full slope: " <<
DoubleToString(fFullSlope,
"%.3e") << p->RESTendl;
1543 RESTMetadata <<
" Full intercept: " <<
DoubleToString(fFullIntercept,
"%+.3e") << p->RESTendl;
1545 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...
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...
void DrawGainMap(const int peakNumber=0, const bool fullModuleAsRef=true)
Function to draw the relative gain map for a given energy peak of the module.
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.
std::set< int > GetModuleIDs(const int planeId) const
Function to get a list (set) of the module IDs of the plane with planeID.
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.
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::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 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(std::string type)
Bool_t MatchString(std::string str, std::string matcher)
This method matches a string with certain matcher. Returns true if matched. Supports wildcard charact...
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.