54int main(
int argc,
char** argv)
62 double projGateLow = -1.;
63 double projGateHigh = -1.;
64 double projBgLow = -1.;
65 double projBgHigh = -1.;
66 double timeRandomNorm = -1.;
69 double peakHigh = -1.;
70 std::string baseName =
"AngularCorrelation";
71 std::string inputFile;
72 std::string theoryFile;
73 std::string outputFile =
"AngularCorrelations.root";
74 std::string settingsFile;
78 parser.
option(
"h help ?", &help,
true).description(
"Show this help message.");
79 parser.
option(
"projection-low proj-low", &projGateLow,
true).description(
"Low edge of projection gate.");
80 parser.
option(
"projection-high proj-high", &projGateHigh,
true).description(
"High edge of projection gate.");
81 parser.
option(
"background-low bg-low", &projBgLow,
true).description(
"Low edge of background gate (for multiple gates use settings file).");
82 parser.
option(
"background-high bg-high", &projBgHigh,
true).description(
"High edge of background gate (for multiple gates use settings file).");
83 parser.
option(
"time-random-normalization", &timeRandomNorm,
true).description(
"Normalization factor for subtraction of time-random matrix. If negative (default) it will be calculated automatically.");
84 parser.
option(
"base-name", &baseName,
true).description(
"Base name of matrices.").default_value(
"AngularCorrelation");
85 parser.
option(
"peak-pos peak", &peakPos,
true).description(
"Peak position (for multiple peaks use settings file).");
86 parser.
option(
"peak-low", &peakLow,
true).description(
"Low edge of peak fit.");
87 parser.
option(
"peak-high", &peakHigh,
true).description(
"High edge of peak fit.");
88 parser.
option(
"settings", &settingsFile,
true).description(
"Settings file with user settings, these do not overwrite anything provided on command line!");
89 parser.
option(
"input", &inputFile,
true).description(
"Input file with gamma-gamma matrices for each angle (coincident, time-random, and event mixed).");
90 parser.
option(
"theory", &theoryFile,
true).description(
"File with simulated z0-, z2-, and z4-graphs.");
91 parser.
option(
"output", &outputFile,
true).description(
"Name of output file, default is \"AngularCorrelations.root\".");
93 parser.
parse(argc, argv,
true);
96 std::cout << parser << std::endl;
101 if(inputFile.empty()) {
102 std::cerr <<
"Need an input file!" << std::endl;
103 std::cout << parser << std::endl;
107 TFile input(inputFile.c_str());
109 if(!input.IsOpen()) {
110 std::cerr <<
"Failed to open input file " << inputFile << std::endl;
111 std::cout << parser << std::endl;
115 auto* settings =
static_cast<TUserSettings*
>(input.Get(
"UserSettings"));
119 if(!settingsFile.empty()) {
120 if(settings ==
nullptr) {
123 settings->ReadSettings(settingsFile);
128 if(settings ==
nullptr || settings->empty()) {
129 std::cerr <<
"Failed to get user settings from input file." << std::endl;
130 std::cout << parser << std::endl;
135 if(projGateLow == -1.) { projGateLow = settings->GetDouble(
"Projection.Low"); }
136 if(projGateHigh == -1.) { projGateHigh = settings->GetDouble(
"Projection.High"); }
137 if(timeRandomNorm == -1.) { timeRandomNorm = settings->GetDouble(
"TimeRandomNormalization"); }
138 if(peakPos == -1.) { peakPos = settings->GetDouble(
"Peak.Position"); }
139 if(peakLow == -1.) { peakLow = settings->GetDouble(
"Peak.Low"); }
140 if(peakHigh == -1.) { peakHigh = settings->GetDouble(
"Peak.High"); }
142 std::vector<double> bgPeakPos;
143 std::vector<double>
bgLow;
144 std::vector<double>
bgHigh;
146 if(projBgLow == -1. || projBgHigh == -1. || projBgLow >= projBgHigh) {
147 for(
int i = 1;; ++i) {
149 auto low = settings->GetDouble(Form(
"Background.%d.Low", i),
true);
150 auto high = settings->GetDouble(Form(
"Background.%d.High", i),
true);
152 std::cout << i <<
". background gate, low edge not lower than the high edge: " << low <<
" >= " << high << std::endl;
155 bgLow.push_back(low);
157 }
catch(std::out_of_range& e) {
162 bgLow.push_back(projBgLow);
163 bgHigh.push_back(projBgHigh);
167 for(
int i = 1;; ++i) {
169 auto pos = settings->GetDouble(Form(
"BackgroundPeak.Position.%d", i),
true);
170 if(pos <= peakLow || pos >= peakHigh) {
171 std::cout << i <<
". background peak outside of fit range: " << pos <<
" <= " << peakLow <<
" or " << pos <<
" >= " << peakHigh << std::endl;
174 bgPeakPos.push_back(pos);
175 }
catch(std::out_of_range& e) {
183 std::vector<double> peakParameter(6, -2.);
184 std::vector<double> peakParameterLow(6, 0.);
185 std::vector<double> peakParameterHigh(6, -1.);
186 std::vector<double> bgPeakParameter(6, -2.);
187 std::vector<double> bgPeakParameterLow(6, 0.);
188 std::vector<double> bgPeakParameterHigh(6, -1.);
189 for(
size_t i = 0; i < peakParameterLow.size(); ++i) {
190 peakParameter[i] = settings->GetDouble(Form(
"Peak.Parameter.%d",
static_cast<int>(i)), -2.);
191 peakParameterLow[i] = settings->GetDouble(Form(
"Peak.Parameter.%d.Low",
static_cast<int>(i)), 0.);
192 peakParameterHigh[i] = settings->GetDouble(Form(
"Peak.Parameter.%d.High",
static_cast<int>(i)), -1.);
193 bgPeakParameter[i] = settings->GetDouble(Form(
"BackgroundPeak.Parameter.%d",
static_cast<int>(i)), -2.);
194 bgPeakParameterLow[i] = settings->GetDouble(Form(
"BackgroundPeak.Parameter.%d.Low",
static_cast<int>(i)), 0.);
195 bgPeakParameterHigh[i] = settings->GetDouble(Form(
"BackgroundPeak.Parameter.%d.High",
static_cast<int>(i)), -1.);
198 if(peakParameterLow[i] <= peakParameterHigh[i] && (peakParameter[i] < peakParameterLow[i] || peakParameterHigh[i] < peakParameter[i])) {
199 bool output = peakParameter[i] != -2.;
200 if(output) { std::cout <<
"Warning, " << i <<
". peak parameter (" << peakParameter[i] <<
") is out of range " << peakParameterLow[i] <<
" - " << peakParameterHigh[i] <<
", resetting it to "; }
201 peakParameter[i] = (peakParameterHigh[i] + peakParameterLow[i]) / 2.;
202 if(output) { std::cout << peakParameter[i] << std::endl; }
204 if(bgPeakParameterLow[i] <= bgPeakParameterHigh[i] && (bgPeakParameter[i] < bgPeakParameterLow[i] || bgPeakParameterHigh[i] < bgPeakParameter[i])) {
205 bool output = bgPeakParameter[i] != -2.;
206 if(output) { std::cout <<
"Warning, " << i <<
". background peak parameter (" << bgPeakParameter[i] <<
") is out of range " << bgPeakParameterLow[i] <<
" - " << bgPeakParameterHigh[i] <<
", resetting it to "; }
207 bgPeakParameter[i] = (bgPeakParameterHigh[i] + bgPeakParameterLow[i]) / 2.;
208 if(output) { std::cout << bgPeakParameter[i] << std::endl; }
213 std::vector<double> backgroundParameter(4, -2.);
214 std::vector<double> backgroundParameterLow(4, 0.);
215 std::vector<double> backgroundParameterHigh(4, -1.);
216 backgroundParameter[0] = settings->GetDouble(
"Background.Offset", -2.);
217 backgroundParameterLow[0] = settings->GetDouble(
"Background.Offset.Low", 0.);
218 backgroundParameterHigh[0] = settings->GetDouble(
"Background.Offset.High", -1.);
219 backgroundParameter[1] = settings->GetDouble(
"Background.Linear", -2.);
220 backgroundParameterLow[1] = settings->GetDouble(
"Background.Linear.Low", 0.);
221 backgroundParameterHigh[1] = settings->GetDouble(
"Background.Linear.High", -1.);
222 backgroundParameter[2] = settings->GetDouble(
"Background.Quadratic", -2.);
223 backgroundParameterLow[2] = settings->GetDouble(
"Background.Quadratic.Low", 0.);
224 backgroundParameterHigh[2] = settings->GetDouble(
"Background.Quadratic.High", -1.);
225 backgroundParameter[3] = settings->GetDouble(
"Background.Xoffset", -2.);
226 backgroundParameterLow[3] = settings->GetDouble(
"Background.Xoffset.Low", 0.);
227 backgroundParameterHigh[3] = settings->GetDouble(
"Background.Xoffset.High", -1.);
228 for(
size_t i = 0; i < backgroundParameter.size(); ++i) {
229 if(backgroundParameterLow[i] <= backgroundParameterHigh[i] && (backgroundParameter[i] < backgroundParameterLow[i] || backgroundParameterHigh[i] < backgroundParameter[i])) {
230 bool output = backgroundParameter[i] != -2.;
231 if(output) { std::cout <<
"Warning, " << i <<
". background parameter (" << backgroundParameter[i] <<
") is out of range " << backgroundParameterLow[i] <<
" - " << backgroundParameterHigh[i] <<
", resetting it to "; }
232 backgroundParameter[i] = (backgroundParameterHigh[i] + backgroundParameterLow[i]) / 2.;
233 if(output) { std::cout << backgroundParameter[i] << std::endl; }
239 std::vector<int> twoJLow = settings->GetIntVector(
"TwoJ.Low");
240 std::vector<int> twoJMiddle = settings->GetIntVector(
"TwoJ.Middle");
241 std::vector<int> twoJHigh = settings->GetIntVector(
"TwoJ.High");
244 double confidenceLevel = settings->GetDouble(
"ConfidenceLevel", 1.535);
247 if(projGateLow >= projGateHigh) {
248 std::cerr <<
"Need a projection gate with a low edge that is smaller than the high edge, " << projGateLow <<
" >= " << projGateHigh << std::endl;
249 std::cout << parser << std::endl;
253 if(peakLow >= peakHigh) {
254 std::cerr <<
"Need a fit range with a low edge that is smaller than the high edge, " << peakLow <<
" >= " << peakHigh << std::endl;
255 std::cout << parser << std::endl;
259 if(peakPos >= peakHigh || peakPos <= peakLow) {
260 std::cerr <<
"Need a peak within the fit range, " << peakPos <<
" not within " << peakLow <<
" - " << peakHigh << std::endl;
261 std::cout << parser << std::endl;
265 if(timeRandomNorm <= 0.) {
266 std::cerr <<
"Need a positive normalization factor for time random subtraction" << std::endl;
267 std::cout << parser << std::endl;
274 std::cerr <<
"Background gate information missing, either no low/high edges or a mismatching amount of low and high edges: " <<
bgLow.size() <<
" low edges, and " <<
bgHigh.size() <<
" high edges" << std::endl;
275 std::cout << parser << std::endl;
280 auto* angles =
static_cast<TGriffinAngles*
>(input.Get(
"GriffinAngles"));
282 if(angles ==
nullptr) {
283 std::cerr <<
"Failed to find 'GriffinAngles' in '" << inputFile <<
"'" << std::endl;
284 std::cout << parser << std::endl;
293 TFile output(outputFile.c_str(),
"recreate");
295 auto* rawAngularDistribution =
new TGraphErrors(angles->NumberOfAngles());
296 rawAngularDistribution->SetName(
"RawAngularDistribution");
297 auto* angularDistribution =
new TGraphErrors(angles->NumberOfAngles());
298 angularDistribution->SetName(
"AngularDistribution");
299 auto* mixedAngularDistribution =
new TGraphErrors(angles->NumberOfAngles());
300 mixedAngularDistribution->SetName(
"MixedAngularDistribution");
301 auto* rawChiSquares =
new TGraph(angles->NumberOfAngles());
302 rawChiSquares->SetName(
"RawChiSquares");
303 auto* mixedChiSquares =
new TGraph(angles->NumberOfAngles());
304 mixedChiSquares->SetName(
"MixedChiSquares");
309#if ROOT_VERSION_CODE >= ROOT_VERSION(6, 20, 0)
310 auto* fitDir = output.mkdir(
"fits",
"Projections with fits",
true);
312 auto* fitDir = output.mkdir(
"fits",
"Projections with fits");
316 for(
int i = 0; i < angles->NumberOfAngles(); ++i) {
318 auto* prompt =
static_cast<TH2*
>(input.Get(Form(
"AngularCorrelation%d", i)));
319 if(prompt ==
nullptr) {
320 std::cerr <<
"Failed to find histogram '" << Form(
"AngularCorrelation%d", i) <<
"', should have " << angles->NumberOfAngles() <<
" angles in total!" << std::endl;
321 std::cout << parser << std::endl;
324 auto* bg =
static_cast<TH2*
>(input.Get(Form(
"AngularCorrelationBG%d", i)));
326 std::cerr <<
"Failed to find histogram '" << Form(
"AngularCorrelationBG%d", i) <<
"', should have " << angles->NumberOfAngles() <<
" angles in total!" << std::endl;
327 std::cout << parser << std::endl;
330 auto* mixed =
static_cast<TH2*
>(input.Get(Form(
"AngularCorrelationMixed%d", i)));
331 if(mixed ==
nullptr) {
332 std::cerr <<
"Failed to find histogram '" << Form(
"AngularCorrelationMixed%d", i) <<
"', should have " << angles->NumberOfAngles() <<
" angles in total!" << std::endl;
333 std::cout << parser << std::endl;
339 prompt->Add(bg, -timeRandomNorm);
343 auto* proj = prompt->ProjectionX(Form(
"proj%d", i), prompt->GetYaxis()->FindBin(projGateLow), prompt->GetYaxis()->FindBin(projGateHigh));
344 auto* projMixed = mixed->ProjectionX(Form(
"projMixed%d", i), mixed->GetYaxis()->FindBin(projGateLow), mixed->GetYaxis()->FindBin(projGateHigh));
346 auto* projBg = prompt->ProjectionX(Form(
"projBg%d", i), prompt->GetYaxis()->FindBin(
bgLow[0]), prompt->GetYaxis()->FindBin(
bgHigh[0]));
347 auto* projMixedBg = mixed->ProjectionX(Form(
"projMixedBg%d", i), mixed->GetYaxis()->FindBin(
bgLow[0]), mixed->GetYaxis()->FindBin(
bgHigh[0]));
348 double bgGateWidth = prompt->GetYaxis()->FindBin(
bgHigh[0]) - prompt->GetYaxis()->FindBin(
bgLow[0]) + 1;
349 double mixedBgGateWidth = mixed->GetYaxis()->FindBin(
bgHigh[0]) - mixed->GetYaxis()->FindBin(
bgLow[0]) + 1;
350 for(
size_t g = 1; g <
bgLow.size(); ++g) {
351 projBg->Add(prompt->ProjectionX(Form(
"projBg%d", i), prompt->GetYaxis()->FindBin(
bgLow[g]), prompt->GetYaxis()->FindBin(
bgHigh[g])));
352 projMixedBg->Add(mixed->ProjectionX(Form(
"projMixedBg%d", i), mixed->GetYaxis()->FindBin(
bgLow[g]), mixed->GetYaxis()->FindBin(
bgHigh[g])));
353 bgGateWidth += prompt->GetYaxis()->FindBin(
bgHigh[g]) - prompt->GetYaxis()->FindBin(
bgLow[g]) + 1;
354 mixedBgGateWidth += mixed->GetYaxis()->FindBin(
bgHigh[g]) - mixed->GetYaxis()->FindBin(
bgLow[g]) + 1;
358 proj->Add(projBg, -(prompt->GetYaxis()->FindBin(projGateHigh) - prompt->GetYaxis()->FindBin(projGateLow) + 1) / bgGateWidth);
359 projMixed->Add(projMixedBg, -(mixed->GetYaxis()->FindBin(projGateHigh) - mixed->GetYaxis()->FindBin(projGateLow) + 1) / mixedBgGateWidth);
364 for(
size_t p = 0; p < peakParameterLow.size(); ++p) {
365 if(peakParameterLow[p] == peakParameterHigh[p]) {
367 }
else if(peakParameterLow[p] < peakParameterHigh[p]) {
369 peak.
GetFitFunction()->SetParLimits(p, peakParameterLow[p], peakParameterHigh[p]);
373 for(
auto bgPeak : bgPeakPos) {
374 auto* bgP =
new TRWPeak(bgPeak);
375 for(
size_t p = 0; p < bgPeakParameterLow.size(); ++p) {
376 if(bgPeakParameterLow[p] == bgPeakParameterHigh[p]) {
377 bgP->GetFitFunction()->FixParameter(p, bgPeakParameter[p]);
378 }
else if(bgPeakParameterLow[p] < bgPeakParameterHigh[p]) {
379 bgP->GetFitFunction()->SetParameter(p, bgPeakParameter[p]);
380 bgP->GetFitFunction()->SetParLimits(p, bgPeakParameterLow[p], bgPeakParameterHigh[p]);
385 for(
size_t p = 0; p < backgroundParameterLow.size(); ++p) {
386 if(backgroundParameterLow[p] == backgroundParameterHigh[p]) {
388 }
else if(backgroundParameterLow[p] < backgroundParameterHigh[p]) {
390 pf.
GetBackground()->SetParLimits(p, backgroundParameterLow[p], backgroundParameterHigh[p]);
393 pf.
Fit(proj,
"qretryfit");
397 for(
size_t p = 0; p < peakParameterLow.size(); ++p) {
398 if(peakParameterLow[p] == peakParameterHigh[p]) {
400 }
else if(peakParameterLow[p] < peakParameterHigh[p]) {
402 peakMixed.
GetFitFunction()->SetParLimits(p, peakParameterLow[p], peakParameterHigh[p]);
406 for(
auto bgPeak : bgPeakPos) {
407 auto* bgP =
new TRWPeak(bgPeak);
408 for(
size_t p = 0; p < bgPeakParameterLow.size(); ++p) {
409 if(bgPeakParameterLow[p] == bgPeakParameterHigh[p]) {
410 bgP->GetFitFunction()->FixParameter(p, bgPeakParameter[p]);
411 }
else if(bgPeakParameterLow[p] < bgPeakParameterHigh[p]) {
412 bgP->GetFitFunction()->SetParameter(p, bgPeakParameter[p]);
413 bgP->GetFitFunction()->SetParLimits(p, bgPeakParameterLow[p], bgPeakParameterHigh[p]);
418 for(
size_t p = 0; p < backgroundParameterLow.size(); ++p) {
419 if(backgroundParameterLow[p] == backgroundParameterHigh[p]) {
420 pfMixed.
GetBackground()->FixParameter(p, backgroundParameter[p]);
421 }
else if(backgroundParameterLow[p] < backgroundParameterHigh[p]) {
422 pfMixed.
GetBackground()->SetParameter(p, backgroundParameter[p]);
423 pfMixed.
GetBackground()->SetParLimits(p, backgroundParameterLow[p], backgroundParameterHigh[p]);
426 pfMixed.
Fit(projMixed,
"qretryfit");
434 rawAngularDistribution->SetPoint(i, angles->AverageAngle(i), peak.
Area());
435 rawAngularDistribution->SetPointError(i, 0., peak.
AreaErr());
436 mixedAngularDistribution->SetPoint(i, angles->AverageAngle(i), peakMixed.
Area());
437 mixedAngularDistribution->SetPointError(i, 0., peakMixed.
AreaErr());
438 angularDistribution->SetPoint(i, angles->AverageAngle(i), peak.
Area() / peakMixed.
Area());
439 angularDistribution->SetPointError(i, 0., peak.
Area() / peakMixed.
Area() * TMath::Sqrt(TMath::Power(peak.
AreaErr() / peak.
Area(), 2) + TMath::Power(peakMixed.
AreaErr() / peakMixed.
Area(), 2)));
441 rawChiSquares->SetPoint(i, angles->AverageAngle(i), peak.
GetReducedChi2());
442 mixedChiSquares->SetPoint(i, angles->AverageAngle(i), peakMixed.
GetReducedChi2());
444 std::cout << std::setw(3) << i <<
" of " << angles->NumberOfAngles() <<
" done\r" << std::flush;
446 std::cout <<
"Fitting of projections done." << std::endl;
449 auto* rawAngularDistributionCorr =
static_cast<TGraphErrors*
>(rawAngularDistribution->Clone(
"RawAngularDistributionCorrected"));
450 for(
int i = 0; i < rawAngularDistributionCorr->GetN(); ++i) {
451#if ROOT_VERSION_CODE >= ROOT_VERSION(6, 20, 0)
452 if(angles->Count(rawAngularDistributionCorr->GetPointX(i)) != 0) {
453 rawAngularDistributionCorr->SetPointY(i, rawAngularDistributionCorr->GetPointY(i) / angles->Count(rawAngularDistributionCorr->GetPointX(i)));
454 rawAngularDistributionCorr->SetPointError(i, rawAngularDistributionCorr->GetErrorX(i), rawAngularDistributionCorr->GetErrorY(i) / angles->Count(rawAngularDistributionCorr->GetPointX(i)));
456 rawAngularDistributionCorr->SetPointY(i, 0);
460 rawAngularDistributionCorr->GetPoint(i, px, py);
461 if(angles->Count(px) != 0) {
462 rawAngularDistributionCorr->SetPoint(i, px, py / angles->Count(px));
463 rawAngularDistributionCorr->SetPointError(i, rawAngularDistributionCorr->GetErrorX(i), rawAngularDistributionCorr->GetErrorY(i) / angles->Count(px));
465 rawAngularDistributionCorr->SetPoint(i, px, 0);
469 auto* mixedAngularDistributionCorr =
static_cast<TGraphErrors*
>(mixedAngularDistribution->Clone(
"MixedAngularDistributionCorrected"));
470 for(
int i = 0; i < mixedAngularDistributionCorr->GetN(); ++i) {
471#if ROOT_VERSION_CODE >= ROOT_VERSION(6, 20, 0)
472 if(angles->Count(mixedAngularDistributionCorr->GetPointX(i)) != 0) {
473 mixedAngularDistributionCorr->SetPointY(i, mixedAngularDistributionCorr->GetPointY(i) / angles->Count(mixedAngularDistributionCorr->GetPointX(i)));
474 mixedAngularDistributionCorr->SetPointError(i, mixedAngularDistributionCorr->GetErrorX(i), mixedAngularDistributionCorr->GetErrorY(i) / angles->Count(mixedAngularDistributionCorr->GetPointX(i)));
476 mixedAngularDistributionCorr->SetPointY(i, 0);
480 mixedAngularDistributionCorr->GetPoint(i, px, py);
481 if(angles->Count(px) != 0) {
482 mixedAngularDistributionCorr->SetPoint(i, px, py / angles->Count(px));
483 mixedAngularDistributionCorr->SetPointError(i, mixedAngularDistributionCorr->GetErrorX(i), mixedAngularDistributionCorr->GetErrorY(i) / angles->Count(px));
485 mixedAngularDistributionCorr->SetPoint(i, px, 0);
496 if(!theoryFile.empty()) {
497 TFile theory(theoryFile.c_str());
499 if(theory.IsOpen()) {
501 auto* z0 =
static_cast<TGraphErrors*
>(theory.Get(
"graph000"));
502 auto* z2 =
static_cast<TGraphErrors*
>(theory.Get(
"graph010"));
503 auto* z4 =
static_cast<TGraphErrors*
>(theory.Get(
"graph100"));
505 if(z0 !=
nullptr && z2 !=
nullptr && z4 !=
nullptr && z0->GetN() == z2->GetN() && z0->GetN() == z4->GetN()) {
509 if(z0->GetN() == angularDistribution->GetN() || ((angles->Grouping() || angles->Folding()) && z0->GetN() == (angles->Addback() ? 49 : 51))) {
511 if(z0->GetN() != angularDistribution->GetN()) {
512 angles->FoldOrGroup(z0, z2, z4);
515 std::vector<TGraph*> spin;
516 std::vector<double> spinLabel;
517 std::vector<std::vector<double>> parameters;
519 if(twoJLow.size() > 1 && twoJMiddle.size() == 1 && twoJHigh.size() == 1) {
520 for(
auto twoJ : twoJLow) {
521 parameters.emplace_back();
522 spin.push_back(
MixingMethod(angularDistribution, z0, z2, z4, twoJHigh.at(0), twoJMiddle.at(0), twoJ, parameters.back()));
523 spinLabel.push_back(twoJ / 2.);
525 }
else if(twoJLow.size() == 1 && twoJMiddle.size() > 1 && twoJHigh.size() == 1) {
526 for(
auto twoJ : twoJMiddle) {
527 parameters.emplace_back();
528 spin.push_back(
MixingMethod(angularDistribution, z0, z2, z4, twoJHigh.at(0), twoJ, twoJLow.at(0), parameters.back()));
529 spinLabel.push_back(twoJ / 2.);
531 }
else if(twoJLow.size() == 1 && twoJMiddle.size() == 1 && twoJHigh.size() > 1) {
532 for(
auto twoJ : twoJHigh) {
533 parameters.emplace_back();
534 spin.push_back(
MixingMethod(angularDistribution, z0, z2, z4, twoJ, twoJMiddle.at(0), twoJLow.at(0), parameters.back()));
535 spinLabel.push_back(twoJ / 2.);
538 parameters.emplace_back();
539 spin.push_back(
MixingMethod(angularDistribution, z0, z2, z4, twoJHigh.at(0), twoJMiddle.at(0), twoJLow.at(0), parameters.back()));
540 spinLabel.push_back(twoJHigh.at(0) / 2.);
544 auto* canvas =
new TCanvas;
547 double min = TMath::MinElement(spin.at(0)->GetN(), spin.at(0)->GetY());
548 double max = TMath::MaxElement(spin.at(0)->GetN(), spin.at(0)->GetY());
549 for(
size_t i = 1; i < spin.size(); ++i) {
550 min = TMath::Min(min, TMath::MinElement(spin.at(i)->GetN(), spin.at(i)->GetY()));
551 max = TMath::Max(max, TMath::MaxElement(spin.at(i)->GetN(), spin.at(i)->GetY()));
553 min = TMath::Min(min, confidenceLevel);
557 for(first = 0; first < spin.size(); ++first) {
558 if(spin[first]->GetN() > 1) {
break; }
561 spin[first]->SetTitle(
"");
562 spin[first]->SetMinimum(0.9 * min);
563 spin[first]->SetMaximum(1.1 * max);
565 for(
size_t i = 0; i < spin.size(); ++i) {
566 spin[i]->SetLineColor(i + 1);
567 spin[i]->SetMarkerColor(i + 1);
568 spin[i]->SetLineWidth(2);
571 spin[first]->Draw(
"ac");
572 for(
size_t i = 0; i < spin.size(); ++i) {
573 if(i == first) {
continue; }
574 if(spin[i]->GetN() > 1) {
581 auto* confidenceLevelLine =
new TLine(-1.5, confidenceLevel, 1.5, confidenceLevel);
583 confidenceLevelLine->Draw();
585#if ROOT_VERSION_CODE >= ROOT_VERSION(6, 20, 0)
586 auto* legend =
new TLegend(0.1, 0.3);
588 auto* legend =
new TLegend(0.7, 0.6, 0.8, 0.9);
590 for(
size_t i = 0; i < spin.size(); ++i) {
591 if(spin[i]->GetN() == 1) {
592 legend->AddEntry(spin[i], Form(
"J = %.1f", spinLabel[i]),
"p");
594 legend->AddEntry(spin[i], Form(
"J = %.1f", spinLabel[i]),
"l");
602 spin[first]->GetHistogram()->GetXaxis()->SetRangeUser(-1.5, 1.5);
603 spin[first]->GetHistogram()->GetXaxis()->SetTitle(
"atan(#delta) [rad]");
604 spin[first]->GetHistogram()->GetXaxis()->CenterTitle();
605 spin[first]->GetHistogram()->GetYaxis()->SetTitle(
"red. #chi^{2}");
606 spin[first]->GetHistogram()->GetYaxis()->CenterTitle();
610 z0->Write(
"graph000");
611 z2->Write(
"graph010");
612 z4->Write(
"graph100");
613 for(
size_t i = 0; i < spin.size(); ++i) {
614 spin[i]->Write(Form(
"spin%d",
static_cast<int>(i)));
616 canvas->Write(
"MixingCanvas");
619 std::vector<TGraphErrors*> spinFit(spin.size(),
new TGraphErrors(angularDistribution->GetN()));
620 auto* x = angularDistribution->GetX();
621 for(
int p = 0; p < angularDistribution->GetN(); ++p) {
622 for(
size_t i = 0; i < spinFit.size(); ++i) {
623 spinFit[i]->SetPoint(p, x[p], parameters[i][0] * ((1. - parameters[i][1] - parameters[i][2]) * z0->Eval(x[p]) + parameters[i][1] * z2->Eval(x[p]) + parameters[i][2] * z4->Eval(x[p])));
624 spinFit[i]->SetPointError(p, 0., TMath::Sqrt(parameters[i][0] * (TMath::Power((1. - parameters[i][1] - parameters[i][2]) *
GetYError(z0, x[p]), 2) + TMath::Power(parameters[i][1] *
GetYError(z2, x[p]), 2) + TMath::Power(parameters[i][2] *
GetYError(z4, x[p]), 2))));
627 for(
size_t i = 0; i < spin.size(); ++i) {
628 spinFit[i]->SetLineColor(i + 1);
629 spinFit[i]->SetMarkerColor(i + 1);
630 spinFit[i]->SetLineWidth(2);
631 spinFit[i]->Write(Form(
"SpinFit%d",
static_cast<int>(i)));
632 output.WriteObject(¶meters[i], Form(
"Parameters%d",
static_cast<int>(i)));
635 auto a2a4Parameters =
A2a4Method(angularDistribution, z0, z2, z4);
636 output.WriteObject(&a2a4Parameters,
"ParametersA2a4Fit");
638 std::cerr <<
"Mismatch between theory and data (" << z0->GetN() <<
" != " << angularDistribution->GetN() <<
"?) or neither grouping and folding are enabled (" << std::boolalpha << angles->Grouping() <<
", " << angles->Folding() <<
") or the ungrouped/folded theory doesn't match the required size for " << (angles->Addback() ?
"addback" :
"singles") <<
" data (" << (angles->Addback() ? 49 : 51) <<
")" << std::endl;
641 std::cerr <<
"Failed to find z0 (" << z0 <<
", \"graph000\"), z2 (" << z2 <<
", \"graph010\"), or z4 (" << z4 <<
", \"graph100\") in " << theoryFile <<
", or they had mismatched sizes" << std::endl;
644 std::cerr <<
"Failed to open " << theoryFile << std::endl;
647 std::cout <<
"No file with simulation results (--theory flag), so we won't produce chi2 vs mixing angle plot." << std::endl;
651 rawAngularDistribution->Write();
652 angularDistribution->Write();
653 mixedAngularDistribution->Write();
654 rawChiSquares->Write();
655 mixedChiSquares->Write();
656 rawAngularDistributionCorr->Write();
657 mixedAngularDistributionCorr->Write();
836std::vector<double>
A2a4Method(TGraphErrors* data, TGraphErrors* z0, TGraphErrors* z2, TGraphErrors* z4)
838 assert(data->GetN() == z0->GetN());
839 assert(data->GetN() == z2->GetN());
840 assert(data->GetN() == z4->GetN());
843 auto* cosTheta =
new TGraphErrors(*data);
844 auto* x = cosTheta->GetX();
845 for(
int i = 0; i < cosTheta->GetN(); ++i) {
846 x[i] = TMath::Cos(x[i] / 180. * TMath::Pi());
851 legendre->SetParNames(
"a_{0}",
"a_{2}",
"a_{4}");
852 legendre->SetParameters(1., 0.5, 0.5);
853 cosTheta->Fit(legendre,
"QN0");
856 Ac ac(data, z0, z2, z4);
857 ROOT::Fit::Fitter fitter;
858 fitter.SetFCN(nPar, ac);
860 fitter.Config().ParSettings(0) = ROOT::Fit::ParameterSettings(
"a_{0}", data->GetMaximum() / z0->GetMaximum(), 0.0001, -10., 10.);
861 for(
int i = 1; i < nPar; ++i) {
863 fitter.Config().ParSettings(i) = ROOT::Fit::ParameterSettings(Form(
"a_{%d}", 2 * i), legendre->GetParameter(i), 0.0001, -10., 10.);
865 fitter.Config().MinimizerOptions().SetPrintLevel(0);
866 fitter.Config().SetMinimizer(
"Minuit2",
"Migrad");
867 if(!fitter.FitFCN()) {
868 std::cerr <<
"Fit failed" << std::endl;
873 auto fitResult = fitter.Result();
875 std::cout <<
"Reduced chi^2: " << fitResult.MinFcnValue() / (ac.
Np() - fitResult.NFreeParameters()) << std::endl;
876 std::vector<double> parameters(fitResult.GetParams(), fitResult.GetParams() + nPar);
877 const auto* errors = fitResult.GetErrors();
878 std::cout <<
"Parameters a_0: " << parameters[0] <<
" +- " << errors[0] <<
", a_2: " << parameters[1] <<
" +- " << errors[1] <<
", a_4: " << parameters[2] <<
" +- " << errors[2] << std::endl;
879 TMatrixD covariance(nPar, nPar);
880 fitResult.GetCovarianceMatrix(covariance);
883 auto* fit =
static_cast<TGraphErrors*
>(z0->Clone(
"fit"));
884 for(
int i = 0; i < fit->GetN(); ++i) {
885#if ROOT_VERSION_CODE >= ROOT_VERSION(6, 20, 0)
886 fit->SetPointY(i, parameters[0] * ((1. - parameters[1] - parameters[2]) * z0->GetPointY(i) + parameters[1] * z2->GetPointY(i) + parameters[2] * z4->GetPointY(i)));
888 fit->SetPoint(i, fit->GetX()[i], parameters[0] * ((1. - parameters[1] - parameters[2]) * z0->GetY()[i] + parameters[1] * z2->GetY()[i] + parameters[2] * z4->GetY()[i]));
890 fit->SetPointError(i, 0., std::abs(parameters[0]) * TMath::Sqrt(TMath::Power((1. - parameters[1] - parameters[2]) * z0->GetErrorY(i), 2) + TMath::Power(parameters[1] * z2->GetErrorY(i), 2) + TMath::Power(parameters[2] * z4->GetErrorY(i), 2)));
893 auto* residual =
static_cast<TGraphErrors*
>(data->Clone(
"residual"));
894 for(
int i = 0; i < residual->GetN(); ++i) {
895#if ROOT_VERSION_CODE >= ROOT_VERSION(6, 20, 0)
896 residual->SetPointY(i, data->GetPointY(i) - fit->GetPointY(i));
898 residual->SetPoint(i, residual->GetX()[i], data->GetY()[i] - fit->GetY()[i]);
900 residual->SetPointError(i, 0., TMath::Sqrt(TMath::Power(data->GetErrorY(i), 2) + TMath::Power(fit->GetErrorY(i), 2)));
905 auto* stats =
new TPaveText(0.35, 0.7, 0.75, 0.95,
"NDC");
906 stats->SetTextFont(133);
907 stats->SetTextSize(20);
908 stats->SetFillStyle(0);
909 stats->SetBorderSize(0);
910 stats->AddText(Form(
"a_{2} = %f #pm %f", parameters[1], errors[1]));
911 stats->AddText(Form(
"a_{4} = %f #pm %f", parameters[2], errors[2]));
912 stats->AddText(Form(
"#chi^{2}/NDF = %.2f", fitResult.MinFcnValue() / (ac.
Np() - fitResult.NFreeParameters())));
917 auto* canvas =
new TCanvas;
918 auto* resPad =
new TPad(
"resPad",
"resPad", 0., 0., 1., 0.3);
919 resPad->SetTopMargin(0.);
920 resPad->SetBottomMargin(0.22);
921 resPad->SetLeftMargin(0.1);
922 resPad->SetRightMargin(0.01);
924 auto* compPad =
new TPad(
"compPad",
"compPad", 0., 0.3, 1., 1.);
925 compPad->SetTopMargin(0.01);
926 compPad->SetBottomMargin(0.);
927 compPad->SetLeftMargin(0.1);
928 compPad->SetRightMargin(0.01);
934 auto* multiGraph =
new TMultiGraph;
935 fit->SetLineColor(kRed);
936 fit->SetFillColor(kRed);
937 fit->SetMarkerColor(kRed);
938 multiGraph->Add(fit,
"l3");
939 data->SetMarkerStyle(kFullDotLarge);
940 multiGraph->Add(data,
"p");
942 multiGraph->SetTitle(
";;Normalized Counts;");
944 multiGraph->GetXaxis()->SetRangeUser(0., 180.);
946 multiGraph->GetYaxis()->CenterTitle();
947 multiGraph->GetYaxis()->SetTitleSize(0.05);
948 multiGraph->GetYaxis()->SetTitleOffset(1.);
950 multiGraph->Draw(
"a");
956 residual->SetTitle(
";#vartheta [^{o}];Residual");
958 residual->GetXaxis()->CenterTitle();
959 residual->GetXaxis()->SetTitleSize(0.1);
960 residual->GetXaxis()->SetLabelSize(0.1);
961 residual->GetXaxis()->SetRangeUser(0., 180.);
963 residual->GetYaxis()->CenterTitle();
964 residual->GetYaxis()->SetTitleSize(0.1);
965 residual->GetYaxis()->SetTitleOffset(0.5);
966 residual->GetYaxis()->SetLabelSize(0.08);
968 residual->Draw(
"ap");
969 auto* zeroLine =
new TLine(0., 0., 180., 0.);
970 zeroLine->Draw(
"same");
972 fit->Write(
"A2a4Fit");
973 residual->Write(
"Residual");
974 multiGraph->Write(
"FitComparison");
975 canvas->Write(
"A2a4Canvas");