18#include <TGraphErrors.h>
19#include <TMultiGraph.h>
23#include <Math/Functor.h>
24#include <Math/Factory.h>
25#include <Math/Minimizer.h>
26#include <Math/MinimizerOptions.h>
33#pragma GCC diagnostic ignored "-Wunused-parameter"
191 namespace Efficiency {
200 double x1 =
log(x[0]/100.0);
201 double x2 =
log(x[0]/1000.0);
204 double f1 = pars[0] + pars[1]*x1 + pars[2]*x1*x1;
205 double f2 = pars[3] + pars[4]*x2 + pars[5]*x2*x2;
207 double abs_scale = pars[7];
214 if (f1 < 0 && f2 < 0) {
215 if (x[0] > 50 && x[0] < 8192) {
216 std::cerr <<
"Warning! Both parabolic components of efficiency are < 0 for E_gamma = " << x[0] <<
" keV, consider decreasing normalization for data sets" << std::endl;
235 double retval = exp(f)*abs_scale;
241 double y = pow(pow(r, g) + 1.0, -1.0/g);
242 double retval = exp(y*f)*abs_scale;
253 fIntensities.clear();
254 fEfficiencies.clear();
255 fEfficiencyErrors.clear();
256 fNormalisation = 1.0;
262 SetData(fHist, fTransitionMap, fIntensityMap);
268 std::map<std::string, GamR::Nucleus::Transition > *fTransMap = fTransitionMap->
GetMap();
269 fNormalisation = 0.0;
271 for (
auto &intensity : fIntensityMap) {
273 if (fTransMap->find(intensity.first) != fTransMap->end()) {
274 double area = (*fTransMap)[intensity.first].Apply(fHist);
275 double areaerror = (*fTransMap)[intensity.first].ApplyError(fHist);
276 double energy = intensity.second.first;
277 double intens = intensity.second.second;
278 double eff = area/intens;
279 double efferr = areaerror/intens;
283 fKeys.push_back(intensity.first);
284 fPeakAreas.push_back(area);
285 fPeakErrors.push_back(areaerror);
286 fEnergies.push_back(energy);
287 fIntensities.push_back(intens);
288 fEfficiencies.push_back(eff);
289 fEfficiencyErrors.push_back(efferr);
297 fNormalisation = max/1000.0;
301 void DataSet::SetData(std::string areaFile, std::map<std::string, std::pair<double, double> > fIntensityMap)
304 std::map<std::string, std::pair<double, double> > areaMap;
305 std::ifstream area_file(areaFile);
307 double area,area_error;
308 while (area_file >> key >> area >> area_error) {
309 areaMap[key] = {area, area_error};
312 fNormalisation = 0.0;
314 for (
auto &intensity : fIntensityMap) {
316 if (areaMap.find(intensity.first) != areaMap.end()) {
317 double area = areaMap[intensity.first].first;
318 double areaerror = areaMap[intensity.first].second;
319 double energy = intensity.second.first;
320 double intens = intensity.second.second;
321 double eff = area/intens;
322 double efferr = areaerror/intens;
326 fKeys.push_back(intensity.first);
327 fPeakAreas.push_back(area);
328 fPeakErrors.push_back(areaerror);
329 fEnergies.push_back(energy);
330 fIntensities.push_back(intens);
331 fEfficiencies.push_back(eff);
332 fEfficiencyErrors.push_back(efferr);
340 fNormalisation = max/1000.0;
353 std::ifstream eff_file(effFile);
354 std::stringstream
ss;
355 if (!eff_file.is_open()) {
356 std::cerr <<
"Error opening " << effFile << std::endl;
358 while (getline(eff_file, line)) {
359 if (line.size()==0) {
continue; }
360 if (line[0]==
'#') {
continue; }
363 ss >> key >> energy >> intens >> area >> areaerror;
364 double eff = area/intens;
365 double efferr = areaerror/intens;
369 fKeys.push_back(key);
370 fPeakAreas.push_back(area);
371 fPeakErrors.push_back(areaerror);
372 fEnergies.push_back(energy);
373 fIntensities.push_back(intens);
374 fEfficiencies.push_back(eff);
375 fEfficiencyErrors.push_back(efferr);
382 fNormalisation = max/1000.0;
390 DataSet::DataSet(
const char *histFile,
const char *histName,
const char *gateFile,
const char *mapName,
const char *intensityFile)
392 TFile *hisFile =
new TFile(histFile);
393 TH1D *fHist = (TH1D*)hisFile->Get(histName);
395 TFile *gatFile =
new TFile(gateFile);
399 std::ifstream intFile(intensityFile);
404 std::map<std::string, std::pair<double, double> > fIntensityMap;
405 while(intFile >> key >> energy >> intensity) {
406 fIntensityMap[key] = std::pair<double, double>(energy, intensity);
409 SetData(fHist, fTransitionMap, fIntensityMap);
416 std::ifstream intFile(intensityFile);
421 std::map<std::string, std::pair<double, double> > fIntensityMap;
422 while(intFile >> key >> energy >> intensity) {
423 fIntensityMap[key] = std::pair<double, double>(energy, intensity);
426 SetData(areaFile, fIntensityMap);
433 if (fKeys[i].compare(key) == 0) {
439 std::cout <<
"Key " << key <<
" not found!" << std::endl;
450 fKeys.erase(fKeys.begin()+index);
451 fEnergies.erase(fEnergies.begin()+index);
452 fPeakAreas.erase(fPeakAreas.begin()+index);
453 fPeakErrors.erase(fPeakErrors.begin()+index);
454 fIntensities.erase(fIntensities.begin()+index);
455 fEfficiencies.erase(fEfficiencies.begin()+index);
456 fEfficiencyErrors.erase(fEfficiencyErrors.begin()+index);
463 file = fopen(fileName,
"wa");
465 fprintf(file,
"Key Energy Intensity PeakArea Error \n");
467 fprintf(file,
"%8s %11.2f %13.4f %12.2f %10.4f\n", fKeys[i].c_str(), fEnergies[i], fIntensities[i], fPeakAreas[i], fPeakErrors[i]);
475 int nPoints = fEnergies.size();
476 TGraphErrors *graph =
new TGraphErrors(nPoints);
478 for (
int i=0; i<nPoints; ++i)
480 double y = fEfficiencies[i]/fNormalisation;
481 double y_err = fEfficiencyErrors[i]/fNormalisation;
484 y_err = y_err * fAbsScale;
486 graph->SetPoint(i, fEnergies[i], y);
487 graph->SetPointError(i, 0, 0.01*fAbsScale);
494 int nPoints = fEnergies.size();
495 TGraphErrors *graph =
new TGraphErrors(nPoints);
497 for (
int i=0; i<nPoints; ++i)
499 double y = fEfficiencies[i]/fNormalisation;
500 double y_err = fEfficiencyErrors[i]/fNormalisation;
503 y_err = y_err * fAbsScale;
505 std::cout << fEnergies[i] <<
" " << fEfficiencies[i] <<
" " << fNormalisation <<
" " << y << std::endl;
506 graph->SetPoint(i, fEnergies[i], y);
507 graph->SetPointError(i, 0, y_err);
527 for (
int i=0; i<7; ++i)
529 double parmin, parmax;
530 EffFunc->GetParLimits(i, parmin, parmax);
531 EffFunc->SetParLimits(i, -1e4, 1e4);
534 EffFunc->SetParLimits(6, 1.0, 1e4);
536 EffFunc->SetParLimits(7, 0, 1.0);
556 p->EffFunc->SetParameter(0, par[0]);
557 p->EffFunc->SetParameter(1, par[1]);
558 p->EffFunc->SetParameter(2, par[2]);
559 p->EffFunc->SetParameter(3, par[3]);
560 p->EffFunc->SetParameter(4, par[4]);
561 p->EffFunc->SetParameter(5, par[5]);
562 p->EffFunc->SetParameter(6, par[6]);
563 p->EffFunc->SetParameter(7, par[7]);
565 int nDataSets = p->fDataSets.size();
566 for (
int i=0; i<8+nDataSets; ++i) {
567 std::cout << Form(
"%6.3f ", par[i]);
570 for (
int i=0; i<nDataSets; ++i) {
571 p->fDataSets[i].SetAbsScale(par[7]);
572 p->fDataSets[i].SetNorm(par[8+i]);
573 if (p->fDataSets[i].GetNData() > 0) {
575 if (p->EqualWeights) {
576 graph = p->fDataSets[i].GetGraph();
579 graph = p->fDataSets[i].GetGraphErrors();
581 if (p->fDataSets[i].GetAbsolute()) {
582 chisq += 100.0*graph->Chisquare(p->EffFunc);
585 chisq += graph->Chisquare(p->EffFunc);
591 std::cout << Form(
"chisq=%5.1f",chisq);
592 std::cout << std::endl;
633 EffFit *EffFit::GlobalChiSquare::p =
nullptr;
638 if (nDataSets == 0) {
return; }
639 Int_t npars = 8 + nDataSets;
641 ROOT::Math::Minimizer *min = NULL;
642 min=ROOT::Math::Factory::CreateMinimizer(
"Minuit2",
"Minimize");
644 if (min==NULL) { std::cerr <<
"Minimizer failed to create!" << std::endl; exit(1); }
647 ROOT::Math::Functor f_init(func,npars);
649 min->SetErrorDef(1.);
650 min->SetMaxFunctionCalls(100000);
651 min->SetMaxIterations(100000);
652 min->SetTolerance(1e-6);
653 min->SetPrecision(1e-8);
654 min->SetFunction(f_init);
658 std::cout <<
"Starting fit with guesses: " << std::endl;
659 std::vector< std::string > parnames = {
"A",
"B",
"C",
"D",
"E",
"F",
"G",
"AbsScale"};
660 for (
int i=0; i<8; ++i ) {
661 double parmin, parmax;
662 EffFunc->GetParLimits(i, parmin, parmax);
663 if (parmin==parmax) {
664 parmin =
EffFunc->GetParameter(i) - 1;
665 parmax =
EffFunc->GetParameter(i) + 1;
667 std::cout <<
" " << parnames[i] <<
" " <<
EffFunc->GetParameter(i) <<
" (" << parmin <<
"," << parmax <<
")" << std::endl;
668 min->SetLimitedVariable(parnum, parnames[i].c_str(),
EffFunc->GetParameter(i),
EffFunc->GetParError(i), parmin, parmax);
669 min->SetVariableStepSize(parnum, 0.1);
673 for (
int i=0; i<8; ++i) {
674 double parmin, parmax;
675 EffFunc->GetParLimits(i, parmin, parmax);
676 if (parmin*parmax != 0 && parmin >= parmax) {
681 for (
int i=0; i<nDataSets; ++i) {
682 std::cout <<
"Initial fNorm " << i <<
" = " <<
fDataSets[i].GetNorm() << std::endl;
685 min->FixVariable(parnum);
698 for (
int i=0; i<8; ++i) {
699 double parVal, parErr;
700 parVal = min->X()[i];
701 parErr = min->Errors()[i];
702 EffFunc->SetParameter(i, parVal);
703 EffFunc->SetParError(i, parErr);
709 std::cout <<
"Setting final normalizations" << std::endl;
710 for (
int i=0; i<nDataSets; ++i) {
711 double parVal, parErr;
712 parVal = min->X()[8+i];
714 std::cout <<
"Dataset " << i <<
": " << parVal << std::endl;
720 TCanvas *c1 =
new TCanvas(
"cEff",
"Efficiency Curve", 1280, 720);
825 for (
int i=0; i<params.
params.size(); ++i) {
827 EffFunc->GetParLimits(i, plow, phigh);
828 double parmin = params.
limlow[i].Eval(plow);
829 double parmax = params.
limhigh[i].Eval(phigh);
832 if (params.
fixed[i]==1) {
834 EffFunc->SetParLimits(i, parmin, parmax);
840 EffFunc->SetParLimits(i, parmin, parmax);
841 if (
EffFunc->GetParError(i) == 0) {
850 TMultiGraph*
EffFit::Draw(TCanvas *canvas,
int detID,
double xlow,
double xhigh,
bool log)
852 std::cout <<
"Drawing Detector " << detID << std::endl;
856 TMultiGraph *graph =
new TMultiGraph();
857 graph->SetTitle((
"Efficiency "+std::to_string(detID)).c_str());
858 std::vector<Color_t> colors = {kRed, kBlue, kGreen, kMagenta, kCyan, kBlack, kYellow};
859 for (
int i=0; i<nDataSets; ++i)
862 TGraphErrors *dsetgraph =
fDataSets[i].GetGraphErrors();
863 std::cout <<
" Data Set " << i <<
", nPoints " << dsetgraph->GetN() << std::endl;
864 dsetgraph->SetLineColor(colors[i]);
865 dsetgraph->SetMarkerColor(colors[i]);
866 graph->Add(dsetgraph);
869 graph->GetHistogram()->SetMinimum(0.01);
872 graph->GetHistogram()->SetMinimum(0.0);
876 graph->GetXaxis()->SetLimits(xlow, xhigh);
898 for (
int i=0; i<nDataSets; ++i)
900 std::string fname = outDir+
"/dset_"+std::to_string(i)+
".dat";
901 std::ofstream dset_file(fname);
902 TGraphErrors *dsetgraph =
fDataSets[i].GetGraphErrors();
903 std::cout <<
" Data Set " << i <<
", nPoints " << dsetgraph->GetN() << std::endl;
904 std::cout << fname << std::endl;
905 for (
int j=0; j<dsetgraph->GetN(); ++j) {
907 dsetgraph->GetPoint(j, x, y);
908 yerr = dsetgraph->GetErrorY(j);
909 dset_file << x <<
" " << y <<
" " << yerr << std::endl;
914 std::string fname = outDir+
"/efficiency.dat";
915 std::ofstream eff_file(fname);
916 for (
int i=1; i<=4096; ++i) {
917 eff_file << i <<
" " <<
EffFunc->Eval((
double)i) << std::endl;
924 std::cout <<
"Drawing Detector " << detID << std::endl;
928 TMultiGraph *graph =
new TMultiGraph();
929 graph->SetTitle((
"Efficiency "+std::to_string(detID)).c_str());
930 std::vector<Color_t> colors = {kRed, kBlue, kGreen, kMagenta, kCyan, kBlack, kYellow};
933 for (
int i=0; i<nDataSets; ++i)
935 TGraphErrors *dsetgraph =
fDataSets[i].GetGraphErrors();
936 std::cout <<
" Data Set " << i <<
", nPoints " << dsetgraph->GetN() << std::endl;
937 TGraphErrors *residuals =
new TGraphErrors();
938 for (
int j=0; j<dsetgraph->GetN(); ++j) {
941 dsetgraph->GetPoint(j, x, y);
944 residuals->SetPoint(j, x, y);
945 residuals->SetPointError(j, 0, dsetgraph->GetErrorY(j)/
EffFunc->Eval(x)*100.0);
948 residuals->SetLineColor(colors[i]);
949 residuals->SetMarkerColor(colors[i]);
950 graph->Add(residuals);
952 std_dev = std::sqrt(std_dev/(
double)nPoints);
953 std::cout <<
"Spread = " << std_dev << std::endl;
957 graph->GetXaxis()->SetLimits(xlow, xhigh);
960 TF1 *con =
new TF1(
"con",
"0", xlow, xhigh);
966 TCanvas *c1 =
new TCanvas();
967 c1->Print(((std::string)outFile+
"[").c_str());
968 TMultiGraph *graph =
Draw(c1, 0, xlow, xhigh,
log);
971 TMultiGraph *res =
DrawRes(c1, 0, xlow, xhigh);
974 c1->Print(((std::string)outFile+
"]").c_str());
981 TFile *hisFile =
new TFile(histFile);
982 TH2D *fHist = (TH2D*)hisFile->Get(histName);
984 TFile *gatFile =
new TFile(gateFile);
987 std::ifstream intFile(intensityFile);
992 std::map<std::string, std::pair<double, double> > fIntensityMap;
993 while(intFile >> key >> energy >> intensity) {
994 fIntensityMap[key] = std::pair<double, double>(energy, intensity);
997 for (
int i=1; i<fHist->GetYaxis()->GetNbins()+1; ++i) {
998 TH1D *proj = (TH1D*)fHist->ProjectionX(
"proj", i, i);
999 std::cout <<
"ADDING DETECTOR " << i <<
", " << proj->GetEntries() << std::endl;
1000 if (proj->GetEntries()>0) {
1001 fDataSets[i] =
DataSet(proj, fTransitionMap, fIntensityMap);
1012 void FitParams::SetParams(std::vector<std::string> sParams, std::vector<std::string> sFixed, std::vector<std::string> sLimLow, std::vector<std::string> sLimHigh)
1014 for (
int i=0; i<sParams.size(); ++i) {
1015 TFormula fval(
"fval", sParams[i].c_str());
1016 TFormula flow(
"flow", sLimLow[i].c_str());
1017 TFormula fhigh(
"fhigh", sLimHigh[i].c_str());
1018 double parlow, parhigh;
1023 if (atoi(sFixed[i].c_str())==1) {
1032 void MultiEffFit::AddData(
const char *histFile,
const char *histName,
const char *gateFile,
const char *mapName,
const char *intensityFile)
1034 MultiDataSet mdataset(histFile, histName, gateFile, mapName, intensityFile);
1037 AddData(dset.second, dset.first);
1042 if (fEffFits.find(ID) == fEffFits.end()) {
1046 fEffFits[ID].AddData(dataSet);
1047 std::cout <<
"Added Det " << ID <<
" with " << dataSet.
GetNData() <<
" efficiency calibration points" << std::endl;
1048 for (
int j=0; j<dataSet.
GetNData(); ++j) {
1055 fEffFits[ID].fDataSets[i].SetData(effFile);
1060 for (
auto &efffit : fEffFits) {
1061 efffit.second.SetParams(params);
1067 if (fEffFits.find(ID) == fEffFits.end()) {
return; }
1068 fEffFits[ID].SetParams(params);
1073 int index = fEffFits[ID].fDataSets[iDataSet].GetIndex(key);
1074 double normArea = fEffFits[ID].fDataSets[iDataSet].GetPeak(index);
1076 for (
auto &efffit : fEffFits) {
1077 if (efffit.first != ID) {
1078 index = efffit.second.fDataSets[iDataSet].GetIndex(key);
1079 fDetNorm[efffit.first] = efffit.second.fDataSets[iDataSet].GetPeak(index)/normArea;
1085 for (
auto &efffit : fEffFits) {
1086 double curNorm = efffit.second.fDataSets[iDataSet].GetNorm();
1087 efffit.second.fDataSets[iDataSet].SetNorm(curNorm*factor);
1092 double curNorm = fEffFits[ID].fDataSets[iDataSet].GetNorm();
1093 fEffFits[ID].fDataSets[iDataSet].SetNorm(curNorm*factor);
1097 for (
auto &efffit : fEffFits) {
1098 efffit.second.fDataSets[iDataSet].EraseData(key);
1103 for (
auto &efffit : fEffFits) {
1104 efffit.second.EqualWeights =
true;
1110 for (
auto &efffit : fEffFits) {
1111 std::cout <<
"=====================================================" << std::endl;
1112 std::cout <<
"FITTING DETECTOR " << efffit.first << std::endl;
1113 std::cout <<
"=====================================================" << std::endl;
1114 efffit.second.Fit(1);
1120 if (fEffFits.find(ID) == fEffFits.end()) {
return; }
1121 fEffFits[ID].Fit(1);
1126 std::vector<int> presentIDs;
1127 TCanvas *c1 =
new TCanvas(
"c1",
"c1", 1280, 720);
1128 c1->Print((outFile+std::string(
"[")).c_str());
1129 for (
auto &efffit : fEffFits) {
1130 int detID = efffit.first;
1131 std::cout <<
"Drawing Det " << detID << std::endl;
1133 TMultiGraph *graph = efffit.second.Draw(c1, detID, xlow, xhigh,
log);
1136 presentIDs.push_back(detID);
1140 c1->Print((outFile+std::string(
"]")).c_str());
1145 fEffFits[ID].fDataSets[i].Print(fileName);
1150 for (
auto &efffit : fEffFits) {
1151 std::string fileName((std::string(fileNameBase)+
"."+std::to_string(efffit.first)).c_str());
1152 efffit.second.fDataSets[i].Print(fileName.c_str());
1159 file = fopen(outFile,
"wa");
1160 fprintf(file,
" ID AbsScale RelNorm A Aerr B Berr C Cerr D Derr E Eerr F Ferr G Gerr\n");
1161 for (
auto &efffit : fEffFits) {
1162 int detID = efffit.first;
1163 fprintf(file,
"%4i", detID);
1164 fprintf(file,
" %8.7f ", efffit.second.EffFunc->GetParameter(7));
1165 fprintf(file,
" %10.3f", fDetNorm[efffit.first]);
1166 for (
int i=0; i<7; ++i) {
1167 fprintf(file,
" %5.4f %5.4f ", efffit.second.EffFunc->GetParameter(i), efffit.second.EffFunc->GetParError(i));
1176 for (
auto &det : fEffFits) {
1177 det.second.WriteGraph(outDir+
"/det"+std::to_string(det.first));
1183 file = fopen(outFile,
"wa");
1184 fprintf(file,
"AbsScale A Aerr B Berr C Cerr D Derr E Eerr F Ferr G Gerr\n");
1185 fprintf(file,
" %8.7f ",
EffFunc->GetParameter(7));
1186 for (
int i=0; i<7; ++i) {
1187 fprintf(file,
" %5.4f %5.4f ",
EffFunc->GetParameter(i),
EffFunc->GetParError(i));
void ss(std::vector< int > indexes, TCanvas *canvas, Option_t *option)
void log(TVirtualPad *canvas)
double GetEfficiency(int i)
TGraphErrors * GetGraph()
void SetData(const char *effFile)
void Print(const char *fileName)
void EraseData(std::string key)
TGraphErrors * GetGraphErrors()
int GetIndex(std::string key)
GlobalChiSquare(EffFit *parent)
double operator()(const double *par)
std::vector< DataSet > fDataSets
void PrintParams(const char *fileName)
void SetParams(FitParams params)
void WriteGraph(std::string outDir)
TMultiGraph * Draw(TCanvas *canvas, int detID=0, double xlow=-1, double xhigh=-1, bool log=false)
TMultiGraph * DrawRes(TCanvas *canvas, int detID=0, double xlow=-1, double xhigh=-1)
void SetParams(std::vector< std::string > sParams, std::vector< std::string > sFixed, std::vector< std::string > sLimLow, std::vector< std::string > sLimHigh)
std::vector< TFormula > params
std::vector< TFormula > limlow
std::vector< TFormula > limhigh
std::map< int, DataSet > * GetDataSets()
void SetParams(FitParams params)
void SetData(const char *effFile, int i, int ID)
void SetEqualWeights(bool eq)
void AddData(const char *histFile, const char *histName, const char *gateFile, const char *mapName, const char *intensityFile)
void Draw(const char *outFile, double xlow=-1, double xhigh=-1, bool log=false)
void PrintParams(const char *outFile)
void SetDetNorms(int ID, int iDataSet, std::string key)
void WriteGraphs(std::string outDir)
void SetNorm(int iDataSet, double factor)
void PrintDataSet(int i, const char *fileNameBase)
void EraseData(int ID, int iDataSet, std::string key)
std::map< std::string, Transition > * GetMap()
Library to calculate relative efficiencies for HPGe detectors.
double EffCFunc(double *x, double *pars)