GRSISort "v4.0.0.5"
An extension of the ROOT analysis Framework
Loading...
Searching...
No Matches
TAngularCorrelation.cxx
Go to the documentation of this file.
1/** \class TAngularCorrelation
2 * An angular correlation class
3 **/
4#include <cstdio>
5#include <map>
7#include "TVector3.h"
8#include <sys/stat.h>
9#include "TGriffin.h"
10#include "TMath.h"
11#include "TCanvas.h"
12
13////////////////////////////////////////////////////////////////////////////////
14/// Angular correlation default constructor
15///
17 : fIndexCorrelation(nullptr), fIndexMapSize(0), fFolded(kFALSE), fGrouped(kFALSE)
18{
19}
20
21////////////////////////////////////////////////////////////////////////////////
22/// Angular correlation default destructor
23///
28
29////////////////////////////////////////////////////////////////////////////////
30/// Create energy-gated 2D histogram of energy vs. angular index
31///
32/// \param[in] hst Three-dimensional histogram of angular index vs. energy vs. energy
33/// \param[in] min Minimum of energy gate
34/// \param[in] max Maximum of energy gate
35/// \param[in] fold Switch for turning folding on
36/// \param[in] group Switch for turning grouping on (not yet implemented)
37///
38/// Projects out the events with one energy between min and max
39/// X-axis of returned histogram is second energy
40/// Y-axis of returned histogram is angular index (or the group number if group = kTRUE)
41
42TH2D* TAngularCorrelation::Create2DSlice(THnSparse* hst, Double_t min, Double_t max, Bool_t fold = kFALSE,
43 Bool_t group = kFALSE)
44{
45 // identify the axes (angular index, energy, energy)
46 // we assume that the two axes with identical limits are the energy axes
47 Int_t indexaxis = 0;
48 Int_t energy1axis = 0;
49 Int_t energy2axis = 0;
50 std::array<Double_t, 3> xmin;
51 std::array<Double_t, 3> xmax;
52 for(int i = 0; i < 3; i++) { // goes through all three dimensions of THnSparse and finds the min and max values
53 xmin[i] = hst->GetAxis(i)->GetXmin();
54 xmax[i] = hst->GetAxis(i)->GetXmax();
55 } // then look for matching axis since energy axis should be the same
56 if(xmin[0] == xmin[1] && xmax[0] == xmax[1]) { // are 0 and 1 the same? then axis 2 is the index axis
57 indexaxis = 2;
58 energy1axis = 0;
59 energy2axis = 1;
60 } else if(xmin[1] == xmin[2] && xmax[1] == xmax[2]) { // are 1 and 2 the same? then axis 0 is the index axis
61 indexaxis = 0;
62 energy1axis = 1;
63 energy2axis = 2;
64 } else if(xmin[2] == xmin[0] && xmax[2] == xmax[0]) { // are 0 and 2 the same? then axis 1 is the index axis
65 indexaxis = 1;
66 energy1axis = 0;
67 energy2axis = 2;
68 } else {
69 std::cout << "Can't identify energy axes. Assuming index axis is axis 0." << std::endl; // no two axis are the same
70 indexaxis = 0;
71 energy1axis = 1;
72 energy2axis = 2;
73 }
74
75 // project the THnSparse
76 hst->GetAxis(energy1axis)->SetRangeUser(min, max);
77 TH2D* tempslice = hst->Projection(indexaxis, energy2axis, "eo"); // the "e" option pushes appropriate errors
78 tempslice->SetName(Form("%s_proj_%i", hst->GetName(), static_cast<Int_t>((max + min) / 2)));
79 tempslice->SetTitle(Form("%s: %i keV", hst->GetTitle(), static_cast<Int_t>((max + min) / 2)));
80
81 TH2D* slice2d = Modify2DSlice(tempslice, fold, group);
82
83 return slice2d;
84}
85
86////////////////////////////////////////////////////////////////////////////////
87/// Create energy-gated 2D histogram of energy vs. angular index
88///
89/// \param[in] hstarray TObjArray of TH2 energy vs. energy plots for each angular index
90/// \param[in] min Minimum of energy gate
91/// \param[in] max Maximum of energy gate
92/// \param[in] fold Switch for turning folding on
93/// \param[in] group Switch for turning grouping on (not yet implemented)
94///
95/// Assumes that the index of the TObjArray is the angular index
96///
97/// Projects out the events with one energy between min and max
98/// X-axis of returned histogram is second energy
99/// Y-axis of returned histogram is angular index
100
101TH2D* TAngularCorrelation::Create2DSlice(TObjArray* hstarray, Double_t min, Double_t max, Bool_t fold = kFALSE,
102 Bool_t group = kFALSE)
103{
104 // identify the type of histograms included in the array
105 // a TH2D will need to be projected differently than a THnSparse array
106
107 Bool_t sparse = kFALSE; // true if the array has THnSparse histograms
108 Bool_t hst2d = kFALSE; // true if the array has some kind of TH2 histogram
109 TIter next(hstarray);
110 TObject* obj = nullptr;
111 while((obj = next()) != nullptr) {
112 // TH2 loop
113 if(obj->InheritsFrom("TH2")) {
114 // if there have been no sparse histograms found
115 if(!sparse) {
116 hst2d = kTRUE;
117 } else {
118 std::cout << "found both THnSparse and TH2 in array." << std::endl;
119 std::cout << "currently, Create2DSlice only deals with one." << std::endl;
120 std::cout << "Bailing out." << std::endl;
121 return nullptr;
122 }
123 } else if(obj->InheritsFrom("THnSparse")) {
124 // if there have been no sparse histograms found
125 if(!hst2d) {
126 sparse = kTRUE;
127 } else {
128 std::cout << "found both THnSparse and TH2 in array." << std::endl;
129 std::cout << "currently, Create2DSlice only deals with one." << std::endl;
130 std::cout << "Bailing out." << std::endl;
131 return nullptr;
132 }
133 } else {
134 std::cout << "Element is neither THnSparse or TH2." << std::endl;
135 std::cout << "Bailing." << std::endl;
136 }
137 }
138
139 // if the array is neither, bail out
140 if(!sparse && !hst2d) {
141 std::cout << "Can't identify the type of object in the array." << std::endl;
142 std::cout << "Returning without slicing." << std::endl;
143 return nullptr;
144 }
145
146 // get axis properties
147 Int_t elements = hstarray->GetEntries();
148 Int_t bins = 0;
149 Double_t xmin = 0;
150 Double_t xmax = 0;
151 const Char_t* name = nullptr;
152 const Char_t* title = nullptr;
153 if(sparse) {
154 auto* firsthst = static_cast<THnSparse*>(hstarray->At(0));
155 bins = firsthst->GetAxis(0)->GetNbins();
156 xmin = firsthst->GetAxis(0)->GetBinLowEdge(1);
157 xmax = firsthst->GetAxis(0)->GetBinUpEdge(bins);
158 name = firsthst->GetName();
159 title = firsthst->GetTitle();
160 } else if(hst2d) {
161 auto* firsthst = static_cast<TH2*>(hstarray->At(0));
162 bins = firsthst->GetXaxis()->GetNbins();
163 xmin = firsthst->GetXaxis()->GetBinLowEdge(1);
164 xmax = firsthst->GetXaxis()->GetBinUpEdge(bins);
165 name = firsthst->GetName();
166 title = firsthst->GetTitle();
167 }
168 Int_t ybins = elements;
169
170 Int_t iteration = 0;
171 TH2D* newslice = nullptr;
172 if(gFile->Get(Form("%s_%i_%i", name, static_cast<Int_t>(min), static_cast<Int_t>(max))) == nullptr) {
173 newslice = new TH2D(Form("%s_%i_%i", name, static_cast<Int_t>(min), static_cast<Int_t>(max)),
174 Form("%s, E_{#gamma 1}=[%.1f,%.1f)", title, min, max), bins, xmin, xmax, ybins, 0, ybins);
175 } else {
176 while(iteration < 10) {
177 if(gFile->Get(Form("%s_%i_%i_%i", name, static_cast<Int_t>(min), static_cast<Int_t>(max), iteration)) == nullptr) {
178 break;
179 }
180 ++iteration;
181 }
182 newslice = new TH2D(Form("%s_%i_%i_%i", name, static_cast<Int_t>(min), static_cast<Int_t>(max), iteration),
183 Form("%s, E_{#gamma 1}=[%.1f,%.1f)", title, min, max), bins, xmin, xmax, ybins, 0, ybins);
184 }
185
186 // iterate over the array of 2D gamma-gamma matrices
187 for(Int_t i = 0; i < elements; i++) { // takes slice and itterates through all indexes
188 // slice this particular matrix
189 TH1D* tempslice = nullptr;
190 // sparse option
191 if(sparse) {
192 auto* thishst = static_cast<THnSparse*>(hstarray->At(i));
193 thishst->GetAxis(0)->SetRangeUser(min, max);
194 tempslice = thishst->Projection(
195 1, "oe"); // the "e" option pushes appropriate errors, the "o" makes the projection correct
196 } else if(hst2d) {
197 auto* thishst = static_cast<TH2*>(hstarray->At(i)); // itterating through all the indexes
198 thishst->GetXaxis()->SetRangeUser(min, max);
199 tempslice = thishst->ProjectionY(); // projecting result of gate into temporary slice
200 }
201
202 // iterate through the appropriate bins, transfer values, and take care of error appropriately
203 Double_t y = i;
204 for(Int_t j = 1; j <= bins; j++) {
205 Double_t x = tempslice->GetBinCenter(j); // energy
206 Int_t bin = newslice->FindBin(x, y);
207 Double_t newcontent = tempslice->GetBinContent(j); // number of counts
208 Double_t oldcontent = newslice->GetBinContent(bin);
209 Double_t newerror = tempslice->GetBinError(j);
210 Double_t olderror = newslice->GetBinError(bin);
211 newslice->SetBinContent(bin, oldcontent + newcontent);
212 newslice->SetBinError(bin, sqrt(pow(newerror, 2) + pow(olderror, 2)));
213 }
214
215 // cleanup
216 delete tempslice;
217 }
218
219 TH2D* finalslice = Modify2DSlice(newslice, fold, group);
220 if(fold || group) {
221 delete newslice;
222 }
223
224 return finalslice;
225}
226
227TH2D* TAngularCorrelation::Modify2DSlice(TH2* hst, Bool_t fold, Bool_t group)
228{
229 if(!fold && !group) {
230 std::cout << "No folding or grouping selected." << std::endl;
231 std::cout << "Returning unmodified 2D slice." << std::endl;
232 return static_cast<TH2D*>(hst);
233 }
234
235 // if desired settings are the same as current settings, then continue on
236 // else, change the settings and make new maps.
237 if(fold == fFolded && group == fGrouped) {
238 // do nothing
239 } else {
240 GenerateModifiedMaps(fold, group);
241 }
242
243 ////consistency check group assignments
244 if(group) {
245 Int_t group_numbers = fGroups.size();
246 Int_t angle_numbers = fAngleMap.size();
247
248 // check for index map
249 if(angle_numbers == 0) {
250 std::cout << "Angle Map has not been defined yet." << std::endl;
251 std::cout << "Need Angle Map to assign groups." << std::endl;
252 std::cout << "Bailing out." << std::endl;
253 return nullptr;
254 }
255 // check for group assignments
256 if(group_numbers == 0) {
257 std::cout << "Groups have not been assigned yet." << std::endl;
258 std::cout << "Cannot group Angular Indexes." << std::endl;
259 std::cout << "Bailing out." << std::endl;
260 return nullptr;
261 }
262 // consistency check
263 if(group_numbers != angle_numbers) {
264 if(group_numbers < angle_numbers) {
265 std::cout << "Not all angular indexes have been assigned a group." << std::endl;
266 std::cout << "Bailing out." << std::endl;
267 return nullptr;
268 }
269 if(group_numbers > angle_numbers) {
270 std::cout << "Too many groups have been assigned, not enough angular indexes." << std::endl;
271 std::cout << "Bailing out." << std::endl;
272 return nullptr;
273 }
274 }
275 }
276
277 // get x-axis parameters
278 Int_t bins = hst->GetNbinsX();
279 Double_t xmin = hst->GetXaxis()->GetBinLowEdge(1);
280 Double_t xmax = hst->GetXaxis()->GetBinUpEdge(bins);
281
282 // get histogram name and title
283 const Char_t* hst2dname = hst->GetName();
284 const Char_t* hst2dtitle = hst->GetTitle();
285
286 // get number of y-bins
287 Int_t ybins = hst->GetNbinsY();
288 Int_t newybins = GetNumModIndices();
289
290 // initialize the histogram
291 TH2D* modified_slice = nullptr;
292 if(static_cast<int>(static_cast<int>((group)) & static_cast<int>(!fold)) != 0) {
293 modified_slice = new TH2D(Form("%s_grouped", hst2dname), Form("%s_grouped", hst2dtitle), bins, xmin, xmax,
294 newybins, 0, newybins); // defines slice
295 } else if(static_cast<int>(static_cast<int>((fold)) & static_cast<int>(!group)) != 0) {
296 modified_slice = new TH2D(Form("%s_folded", hst2dname), Form("%s_folded", hst2dtitle), bins, xmin, xmax, newybins,
297 0, newybins); // defines slice
298 } else if(fold && group) {
299 modified_slice = new TH2D(Form("%s_grouped_folded", hst2dname), Form("%s_grouped_folded", hst2dtitle), bins, xmin,
300 xmax, newybins, 0, newybins); // defines slice
301 } else {
302 modified_slice = new TH2D(Form("%s_unknown", hst2dname), Form("%s_unknown", hst2dtitle), bins, xmin, xmax,
303 newybins, 0, newybins); // defines slice
304 }
305
306 // loop through the original 2D histograms y-axis...
307 for(Int_t i = 0; i < ybins; i++) { // y-axis bin loop
308 TH1D* tempslice = nullptr;
309 tempslice = hst->ProjectionX("", i + 1, i + 1);
310
311 // figure out the new index
312 Double_t y = GetModifiedIndex(i);
313 // now loop through the energy axis...
314 for(Int_t j = 1; j <= bins; j++) { // x-axis bin loop
315 Double_t x = tempslice->GetBinCenter(j);
316 Int_t bin = modified_slice->FindBin(x, y);
317 // pull out the new content / error
318 Double_t newcontent = tempslice->GetBinContent(j); // number of counts
319 Double_t newerror = tempslice->GetBinError(j);
320 // pull out the old content / error
321 Double_t oldcontent = modified_slice->GetBinContent(bin);
322 Double_t olderror = modified_slice->GetBinError(bin);
323 // re-set new 2D histogram bin with combined value
324 modified_slice->SetBinContent(bin, oldcontent + newcontent);
325 modified_slice->SetBinError(bin, sqrt(pow(newerror, 2) + pow(olderror, 2)));
326 } // end x-axis bin loop
327
328 // cleanup
329 delete tempslice;
330
331 } // end y-axis bin loop
332
333 return modified_slice;
334}
335
336////////////////////////////////////////////////////////////////////////////////
337/// Create 1D histogram of counts vs. angular index
338///
339/// \param[in] hst Two-dimensional histogram of angular index vs. energy
340/// \param[in] min Minimum of energy gate
341/// \param[in] max Maximum of energy gate
342///
343/// For each bin (angular index), projects out the total number of events within
344/// some energy range (given by min and max).
345
346TH1D* TAngularCorrelation::IntegralSlices(TH2* hst, Double_t min, Double_t max)
347{
348 // set the range on the energy axis (x)
349 hst->GetXaxis()->SetRangeUser(min, max);
350
351 // calculate errors (if not already calculated)
352 hst->Sumw2();
353
354 // project counts to angular index axis
355 fIndexCorrelation = hst->ProjectionY();
356
357 return fIndexCorrelation;
358}
359
360////////////////////////////////////////////////////////////////////////////////
361/// Create 1D histogram of counts vs. angular index
362///
363/// \param[in] hst Two-dimensional histogram of angular index vs. energy
364/// \param[in] peak TPeak template used to fit one dimensional histograms
365/// \param[in] visualization Boolean to select whether to draw on a canvas
366///
367/// For each bin (angular index), fits one-dimensional projection with given TPeak
368/// and returns a TH1D with x-axis of angular index and a y-axis of TPeak area for
369/// that angular index.
370
371TH1D* TAngularCorrelation::FitSlices(TH2* hst, TPeak* peak, Bool_t visualization = kTRUE)
372{
373 ///////////////////////////////////////////////////////
374 // Set-up histograms
375 // ////////////////////////////////////////////////////
376
377 // pull angular index limits from hst
378 // assumes that angular index is y-axis and energy is x-axis
379 auto indexmin = static_cast<Int_t>(hst->GetYaxis()->GetXmin());
380 auto indexmax = static_cast<Int_t>(hst->GetYaxis()->GetXmax());
381 const Int_t indexbins = indexmax - indexmin;
382
383 // pull name from hst, modify for 1D hst
384 const Char_t* hst2dname = hst->GetName();
385 const Char_t* hst2dtitle = hst->GetTitle();
386 const Char_t* hst1dname = Form("%s_%ikeV", hst2dname, static_cast<Int_t>(peak->GetCentroid()));
387 const Char_t* hst1dtitle = Form("%s-%ikeV", hst2dtitle, static_cast<Int_t>(peak->GetCentroid()));
388
389 // initialize histogram to return
390 auto* newhst = new TH1D(hst1dname, Form("%s;Angular index;Counts", hst1dtitle), indexbins, indexmin, indexmax);
391
392 // calculate errors on hst (if not already calculated)
393 hst->Sumw2();
394
395 // set the range on the energy axis (x)
396 // this isn't strictly necessary, but it will make the histograms smaller
397 // and visually, easier to see in the diagnostic.
398 Double_t minenergy = 0.;
399 Double_t maxenergy = 0.;
400 peak->GetRange(minenergy, maxenergy);
401 Double_t difference = maxenergy - minenergy;
402 minenergy = minenergy - 0.5 * difference;
403 maxenergy = maxenergy + 0.5 * difference;
404 hst->GetXaxis()->SetRangeUser(minenergy, maxenergy);
405 Double_t AvgFWHM = 0;
406 ///////////////////////////////////////////////////////
407 // Fitting and visualization
408 ///////////////////////////////////////////////////////
409
410 std::vector<TCanvas*> c;
411
412 TH1D* totalProjection =
413 hst->ProjectionX(Form("total_%sproj", hst2dname), hst->GetYaxis()->GetFirst(), hst->GetYaxis()->GetLast());
414
415 // Set initial parameters for peak
417 peak->SetParameter("centroid", peak->GetCentroid());
418 peak->InitParams(totalProjection);
419 std::cout << "initial parameters:" << std::endl;
420 for(int i = 0; i < peak->GetNpar(); i++) {
421 double min = 0.;
422 double max = 0.;
423 peak->GetParLimits(i, min, max);
424 std::cout << i << ": " << peak->GetParameter(i) << "; " << min << " - " << max << std::endl;
425 }
426 std::cout << "===========================" << std::endl;
427 peak->SetParameter(0, totalProjection->GetMaximum() / 2.);
428 peak->SetParLimits(0, 0., 2. * totalProjection->GetMaximum());
429 peak->SetParameter(1, peak->GetCentroid());
430 peak->SetParLimits(1, peak->GetCentroid() - 2., peak->GetCentroid() + 2.);
431 peak->SetParameter(2, 0.02 * peak->GetCentroid());
432 peak->SetParLimits(2, 0.001 * peak->GetCentroid(), 0.1 * peak->GetCentroid());
433 peak->SetParLimits(7, -0.1, 0.1);
434 peak->FixParameter(8, 0.);
435 peak->SetParameter(9, peak->GetCentroid());
436 peak->SetParLimits(9, peak->GetCentroid() - 2, peak->GetCentroid() + 2);
437 std::cout << "Our parameters:" << std::endl;
438 for(int i = 0; i < peak->GetNpar(); i++) {
439 double min = 0.;
440 double max = 0.;
441 peak->GetParLimits(i, min, max);
442 std::cout << i << ": " << peak->GetParameter(i) << "; " << min << " - " << max << std::endl;
443 }
444 std::cout << "==========================" << std::endl;
445 // bool fit = peak->Fit(totalProjection, "LL");
446 // if (!fit) continue;
447 std::cout << "Final parameters:" << std::endl;
448 for(int i = 0; i < peak->GetNpar(); i++) {
449 double min = 0.;
450 double max = 0.;
451 peak->GetParLimits(i, min, max);
452 std::cout << i << ": " << peak->GetParameter(i) << "; " << min << " - " << max << std::endl;
453 }
454 std::cout << "==========================" << std::endl;
455 std::cout << "Peak area = " << peak->GetArea() << " +/- " << peak->GetAreaErr() << std::endl;
456 double peakCentroid = peak->GetParameter(1);
457 double sigma = peak->GetParameter(2);
458 std::cout << "Fixing the centroid to " << peakCentroid << ", and sigma to " << sigma << " (FWHM = " << 2.355 * sigma
459 << ")" << std::endl;
460 // loop over the indices
461 auto* file = new TFile("Fit_singles.root", "recreate");
462 for(Int_t i = 1; i <= indexmax - indexmin; i++) {
463 auto index = static_cast<Int_t>(hst->GetYaxis()->GetBinLowEdge(i));
464 if(visualization) {
465 // find the correct pad
466 Int_t canvas = (i - 1) / 16;
467 Int_t pad = (i - 1) % 16;
468 if(pad == 0) {
469 auto* temp = new TCanvas(Form("c%i", canvas), Form("c%i", canvas), 800, 800);
470 temp->Divide(4, 4);
471 c.push_back(temp);
472 }
473 // go to canvas pad
474 c[canvas]->cd(pad + 1);
475 }
476
477 // pull individual slice
478 TH1D* temphst = hst->ProjectionX(Form("%s_proj%i", hst2dname, index), i, i);
479 temphst->SetStats(false);
480 temphst->SetTitle(Form("%s: angular index %i", hst->GetTitle(), index));
481 Set1DSlice(index, temphst);
482
483 // draw the slice to canvas
484 if(visualization) {
485 Get1DSlice(index)->Draw("pe1");
486 }
487
488 // if there are too few counts, continue on (you can fit it manually later)
489 if(temphst->Integral() < 50) {
490 continue;
491 }
492
493 // rename TPeak
494 peak->SetName(Form("%s_proj%i_peak", hst2dname, index));
495
496 // Fix FWHM and centroid and set other parameters for single projections rather than total
497 peak->InitParams(temphst);
498 peak->SetParameter(0, temphst->GetMaximum());
499 peak->FixParameter(1, peakCentroid);
500 peak->FixParameter(2, sigma);
501 peak->SetParLimits(7, -0.1, 0.1);
502 peak->FixParameter(8, 0.);
503 peak->SetParameter(9, peakCentroid);
504 peak->SetParLimits(9, peakCentroid - 2., peakCentroid + 2.);
505 peak->SetNpx(1000);
506 // fit peak
507 peak->Fit(temphst, "LL");
508 temphst->Write();
509
510 // fit TPeak
511 // Bool_t fitresult = peak->Fit(temphst,"Q");
512 // Bool_t fitresult = kFALSE;
513 bool fitresult = false;
514 if(visualization) {
515 fitresult = peak->Fit(temphst, "Q");
516 } else {
517 fitresult = peak->Fit(temphst, "Q0");
518 }
519 if(!fitresult) {
520 continue; // if fit failed, continue on to next index
521 }
522 if(visualization) {
523 static_cast<TPeak*>(temphst->GetListOfFunctions()->Last())->Background()->Draw("same");
524 }
525
526 Double_t FullWidthHM = peak->GetParameter(2);
527 AvgFWHM = AvgFWHM + FullWidthHM;
528 // assign TPeak to fPeaks array
529 SetPeak(index, static_cast<TPeak*>(temphst->GetFunction(Form("%s_proj%i_peak", hst2dname, index))));
530
531 // extract area
532 Double_t area = static_cast<TPeak*>(GetPeak(index))->GetArea();
533 Double_t area_err = static_cast<TPeak*>(GetPeak(index))->GetAreaErr();
534 Double_t chi2 = peak->GetChisquare();
535 Double_t ndf = peak->GetNDF();
536 Double_t scale = TMath::Max(1.0, TMath::Sqrt(chi2 / ndf));
537 if(area_err < scale * TMath::Sqrt(area)) {
538 std::cout << "Area error was less than the scaled square root of the area." << std::endl;
539 std::cout << "This means something is wrong; using scaled square root of area for area error." << std::endl;
540 area_err = TMath::Sqrt(area) * scale;
541 }
542
543 // fill histogram with area
544 newhst->SetBinContent(i, area);
545 newhst->SetBinError(i, area_err);
546 }
547
548 Double_t TrueFWHM = AvgFWHM / (indexmax - indexmin);
549 std::cout << "True sigma = " << TrueFWHM << std::endl;
550 ///////////////////////////////////////////////////////
551 // Create diagnostic window
552 ///////////////////////////////////////////////////////
553
554 // initialize canvas
555 auto* c_diag =
556 new TCanvas(Form("c_diag_%i", static_cast<Int_t>(peak->GetCentroid())),
557 Form("Diagnostics for fitting %i keV peak", static_cast<Int_t>(peak->GetCentroid())), 800, 800);
558
559 // create plots for chi^2, centroid, and fwhm
560 hst2dname = hst->GetName();
561 hst1dname = Form("%s_%ikeV", hst2dname, static_cast<Int_t>(peak->GetCentroid()));
562 auto* chi2hst =
563 new TH1D(Form("%s_chi2", hst1dname), Form("%s: #chi^{2};Angular index;#chi^{2}/NDF value", newhst->GetTitle()),
564 indexbins, indexmin, indexmax);
565 auto* centroidhst = new TH1D(Form("%s_centroid", hst1dname),
566 Form("%s: Peak centroid;Angular index;Peak centroid (keV)", newhst->GetTitle()),
567 indexbins, indexmin, indexmax);
568 auto* fwhmhst = new TH1D(Form("%s_fwhm", hst1dname), Form("%s: FWHM;Angular index;FWHM (keV)", newhst->GetTitle()),
569 indexbins, indexmin, indexmax);
570
571 // assign histogram to fIndexCorrelation
572 fIndexCorrelation = newhst;
573 fChi2 = chi2hst;
574 fCentroid = centroidhst;
575 fFWHM = fwhmhst;
576
578 DisplayDiagnostics(c_diag);
579
580 ///////////////////////////////////////////////////////
581 // Clean-up
582 ///////////////////////////////////////////////////////
583
584 file->Close();
585 delete file;
586 return fIndexCorrelation;
587}
588
589////////////////////////////////////////////////////////////////////////////////
590/// Creates graph of counts vs. cos(theta) from histogram of counts vs. angular index
591///
592/// \param[in] hst One-dimensional histogram of angular index vs. counts
593/// \param[in] fold boolean to select whether angles are folded at 90 degree
594/// \param[in] group boolean to select whether angles are grouped
595///
596
597TGraphAsymmErrors* TAngularCorrelation::CreateGraphFromHst(TH1* hst, Bool_t fold, Bool_t group)
598{
599 if(!fold && !group) {
600 Int_t check = fAngleMap.size();
601 if(check == 0) {
602 std::cout << "Angles have not been assigned." << std::endl;
603 std::cout << "Therefore cannot create graph." << std::endl;
604 return nullptr;
605 }
606 } else {
607 // compare fold and group
608 if(fold == fFolded && group == fGrouped) {
609 // do nothing
610 } else {
611 GenerateModifiedMaps(fold, group);
612 }
613
614 Int_t check = fModifiedAngles.size();
615 if(check == 0) {
616 std::cout << "Modified angles have not been assigned." << std::endl;
617 std::cout << "Therefore cannot create graph." << std::endl;
618 return nullptr;
619 }
620
621 if(CheckModifiedHistogram(hst)) {
622 // do nothing
623 } else {
624 return nullptr;
625 }
626 }
627
628 auto* graph = new TGraphAsymmErrors();
629 Int_t n = hst->GetNbinsX();
630
631 for(Int_t i = 1; i <= n; i++) { // bin number loop
632
633 // get index number
634 auto index = static_cast<Int_t>(hst->GetXaxis()->GetBinLowEdge(i));
635
636 // get associated angle
637 Double_t angle = 0;
638 if(!fold && !group) {
639 angle = fAngleMap[index];
640 } else {
641 angle = fModifiedAngles[index];
642 }
643
644 // get counts and error
645 Double_t y = hst->GetBinContent(i);
646 if(y == 0) {
647 continue;
648 }
649 Double_t yerr = hst->GetBinError(i);
650
651 // fill graph with point
652 Int_t graphn = graph->GetN();
653 graph->SetPoint(graphn, TMath::Cos(angle), y);
654 graph->SetPointError(graphn, 0, 0, yerr, yerr);
655 } // bin number loop end
656
657 // set title on graph
658 graph->SetTitle(Form("%s;cos(#theta);Counts", hst->GetTitle()));
659
660 return graph;
661}
662
663////////////////////////////////////////////////////////////////////////////////
664/// Get angular index from two array numbers
665///
666/// \param[in] arraynum1 first array number
667/// \param[in] arraynum2 second array number
668///
669
670Int_t TAngularCorrelation::GetAngularIndex(Int_t arraynum1, Int_t arraynum2)
671{
672 if(arraynum1 == 0 || arraynum2 == 0) {
673 std::cout << "Array numbers usually begin at 1 - unless you have programmed" << std::endl;
674 std::cout << "it differently explicitly, don't trust this output." << std::endl;
675 }
676 if(fIndexMap.count(arraynum1) == 0) {
677 std::cout << "Error: array number " << arraynum1 << " is not present in the index map." << std::endl;
678 return -1;
679 }
680 if(fIndexMap[arraynum1].count(arraynum2) == 0) {
681 std::cout << "Error: element [" << arraynum1 << "][" << arraynum2 << "] is not present in the index map." << std::endl;
682 return -1;
683 }
684 // Array numbers start counting at 1
685 // Indices of this array start at 0
686 return fIndexMap[arraynum1][arraynum2];
687}
688
689////////////////////////////////////////////////////////////////////////////////
690/// Checks that maps are consistent with each other
691/// need to input whether the angles are folded, grouped, or folded and grouped
692
693Bool_t TAngularCorrelation::CheckMaps(Bool_t fold, Bool_t group)
694{
695 Bool_t result = kTRUE; // result to return
696 if(!fold && !group) {
697 if(fAngleMap.size() != fWeights.size()) {
698 std::cout << "fAngleMap and fWeights do not have the same size." << std::endl;
699 std::cout << "fAngleMap size is: " << static_cast<Int_t>(fAngleMap.size()) << std::endl;
700 std::cout << "fWeights size is: " << static_cast<Int_t>(fWeights.size()) << std::endl;
701 result = kFALSE;
702 }
703 } else {
704 if(fModifiedAngles.size() != fModifiedWeights.size()) {
705 std::cout << "fModifiedAngles and fModifiedWeights do not have the same size." << std::endl;
706 std::cout << "fModifiedAngles size is: " << static_cast<Int_t>(fModifiedAngles.size()) << std::endl;
707 std::cout << "fModifiedWeights size is: " << static_cast<Int_t>(fModifiedWeights.size()) << std::endl;
708 result = kFALSE;
709 }
710 }
711 return result;
712}
713
714////////////////////////////////////////////////////////////////////////////////
715/// Prints map used to construct angular indices
716///
717
719{
720 Int_t size = fIndexMapSize;
721 if(size == 0) {
722 std::cout << "Indexes have not been assigned yet." << std::endl;
723 std::cout << "Therefore cannot print map." << std::endl;
724 return;
725 }
726
727 for(Int_t i = 1; i <= size; i++) {
728 std::cout << "-----------------------------------------------------" << std::endl;
729 std::cout << "|| Array number 1 | Array number 2 | Angular index ||" << std::endl;
730 std::cout << "-----------------------------------------------------" << std::endl;
731 for(Int_t j = 1; j <= size; j++) {
732 if(GetAngularIndex(i, j) == -1) {
733 continue;
734 }
735 std::cout << std::left << "|| " << std::setw(14) << i << " | " << std::setw(14) << j << " | " << std::setw(13) << GetAngularIndex(i, j) << " ||" << std::right << std::endl;
736 }
737 }
738 std::cout << "-----------------------------------------------------" << std::endl;
739}
740
741////////////////////////////////////////////////////////////////////////////////
742/// Prints map of angular index vs. opening angle vs. weight
743///
744
746{
747 Int_t size = fAngleMap.size();
748 Int_t weight_size = fWeights.size();
749 if(size == 0) {
750 std::cout << "The angle map hasn't been created yet." << std::endl;
751 std::cout << "Therefore, can't print." << std::endl;
752 return;
753 }
754
755 if(weight_size == 0) {
756 std::cout << "The weights haven't been calculated yet." << std::endl;
757 std::cout << "Therefore, can't print." << std::endl;
758 return;
759 }
760
761 std::cout << "--------------------------------------------------------" << std::endl;
762 std::cout << "|| Angular index | Opening angle (rad) | Weight ||" << std::endl;
763 std::cout << "--------------------------------------------------------" << std::endl;
764 for(Int_t i = 0; i < size; i++) {
765 std::cout << std::left << "|| " << std::setw(13) << i << " | " << std::setw(19) << GetAngleFromIndex(i) << " | " << std::setw(6) << GetWeightFromIndex(i) << " ||" << std::right << std::endl;
766 }
767 std::cout << "--------------------------------------------------------" << std::endl;
768}
769////////////////////////////////////////////////////////////////////////////////
770/// Prints map of angular index vs. opening angle vs. group
771///
772
774{
775 Int_t size = fAngleMap.size();
776 Int_t group_size = fGroups.size();
777 if(size == 0) {
778 std::cout << "The angle map hasn't been created yet." << std::endl;
779 std::cout << "Therefore, can't print." << std::endl;
780 return;
781 }
782 if(group_size == 0) {
783 std::cout << "The groups haven't been assigned yet." << std::endl;
784 std::cout << "Therefore, can't print." << std::endl;
785 return;
786 }
787
788 std::cout << "-------------------------------------" << std::endl;
789 std::cout << "|| Angular index | Group index ||" << std::endl;
790 std::cout << "-------------------------------------" << std::endl;
791 for(Int_t i = 0; i < size; i++) {
792 std::cout << "|| " << std::setw(13) << i << " | " << std::setw(11) << GetGroupFromIndex(i) << " ||" << std::endl;
793 }
794 std::cout << "-------------------------------------" << std::endl;
795}
796
797////////////////////////////////////////////////////////////////////////////////
798/// Prints map of group vs. group weight vs. average group angle
799///
800
802{
803 Int_t size = GetNumGroups();
804 Int_t angle_size = fGroupAngles.size();
805 if(size == 0) {
806 std::cout << "The number of groups haven't been determined yet." << std::endl;
807 std::cout << "Therefore, can't print." << std::endl;
808 return;
809 }
810 if(angle_size == 0) {
811 std::cout << "The angles haven't been assigned yet." << std::endl;
812 std::cout << "Therefore, can't print." << std::endl;
813 return;
814 }
815 std::cout << "-----------------------------------" << std::endl;
816 std::cout << "|| Group index | Angle (rad) ||" << std::endl;
817 std::cout << "-----------------------------------" << std::endl;
818 for(Int_t i = 0; i < size; i++) {
819 std::cout << "|| " << std::setw(11) << i << " | " << std::setw(12) << GetGroupAngleFromIndex(i) << " ||" << std::endl;
820 }
821 std::cout << "-----------------------------------" << std::endl;
822}
823
824////////////////////////////////////////////////////////////////////////////////
825/// Prints map of angular index vs. opening angle
826///
827
829{
830 Int_t size = fAngleMap.size();
831 if(size == 0) {
832 std::cout << "Folded angles have not been assigned yet." << std::endl;
833 std::cout << "Therefore cannot print map." << std::endl;
834 return;
835 }
836
837 std::cout << "---------------------------------------------" << std::endl;
838 std::cout << "|| Angular index | Opening angle (rad) ||" << std::endl;
839 std::cout << "---------------------------------------------" << std::endl;
840 for(Int_t i = 0; i < size; i++) {
841 std::cout << std::left << "|| " << std::setw(13) << i << " | " << std::setw(19) << GetAngleFromIndex(i) << " ||" << std::right << std::endl;
842 }
843 std::cout << "---------------------------------------------" << std::endl;
844}
845
846////////////////////////////////////////////////////////////////////////////////
847/// Prints map of Folded index vs. opening angle
848///
849
851{
852 Int_t size = fModifiedAngles.size();
853
854 if(size == 0) {
855 std::cout << "Folded angles have not been assigned yet." << std::endl;
856 std::cout << "Therefore cannot print map." << std::endl;
857 return;
858 }
859
860 std::cout << "--------------------------------------" << std::endl;
861 std::cout << "|| Modified index | Angle (rad) ||" << std::endl;
862 std::cout << "--------------------------------------" << std::endl;
863 for(Int_t i = 0; i < size; i++) {
864 std::cout << "|| " << std::setw(14) << i << " | " << std::setw(11) << GetModifiedAngleFromIndex(i) << " ||" << std::endl;
865 }
866 std::cout << "--------------------------------------" << std::endl;
867}
868
869////////////////////////////////////////////////////////////////////////////////
870/// Prints map of Folded index vs. opening angle
871///
872
874{
875 Int_t size = fModifiedAngles.size();
876 Int_t weight_size = fModifiedWeights.size();
877
878 if(size == 0) {
879 std::cout << "Modified angles have not been assigned yet." << std::endl;
880 std::cout << "Therefore cannot print map." << std::endl;
881 return;
882 }
883 if(weight_size == 0) {
884 std::cout << "Modified weights have not been generated yet." << std::endl;
885 std::cout << "Therefore cannot print map." << std::endl;
886 return;
887 }
888
889 std::cout << "-------------------------------------------------" << std::endl;
890 std::cout << "|| Modified index | Angle (rad) | Weight ||" << std::endl;
891 std::cout << "-------------------------------------------------" << std::endl;
892 for(Int_t i = 0; i < size; i++) {
893 std::cout << "|| " << std::setw(14) << i << " | " << std::setw(11) << GetModifiedAngleFromIndex(i) << " | " << GetModifiedWeight(i) << " ||" << std::endl;
894 }
895 std::cout << "-------------------------------------------------" << std::endl;
896}
897
898////////////////////////////////////////////////////////////////////////////////
899/// Prints map of angular index vs. Folded Index
900
902{
903 Int_t size = fModifiedIndices.size();
904 if(size == 0) {
905 std::cout << "Modified indices have not been assigned yet." << std::endl;
906 std::cout << "Therefore cannot print map." << std::endl;
907 return;
908 }
909
910 std::cout << "----------------------------------------" << std::endl;
911 std::cout << "|| Angular index | Modified index ||" << std::endl;
912 std::cout << "----------------------------------------" << std::endl;
913 for(Int_t i = 0; i < size; i++) {
914 std::cout << "|| " << std::setw(13) << i << " | " << std::setw(14) << GetModifiedIndex(i) << " ||" << std::endl;
915 }
916 std::cout << "----------------------------------------" << std::endl;
917}
918
919////////////////////////////////////////////////////////////////////////////////
920/// Creates map of angular index vs. opening angle.
921///
922/// \param[in] arraynumbers Vector of array numbers used in this experiment
923/// \param[in] distances Vector of detector distances for those array numbers
924///
925
926std::vector<Double_t> TAngularCorrelation::GenerateAngleMap(std::vector<Int_t>& arraynumbers,
927 std::vector<Int_t>& distances)
928{
929
930 std::vector<Double_t> map; // vector to return
931
932 // basic consistency check
933 const Int_t size = arraynumbers.size();
934 if(size != static_cast<Int_t>(distances.size())) {
935 std::cout << "Lengths of array number and distance vectors are inconsistent." << std::endl;
936 std::cout << "Array number vector size: " << size << std::endl;
937 std::cout << "Distance vector size: " << distances.size() << std::endl;
938 }
939
940 // loop through array numbers (a list of crystals in the array)
941 for(Int_t i = 0; i < size; i++) {
942 // identify detector and crystal numbers
943 Int_t detector1 = (arraynumbers[i] - 1) / 4 + 1;
944 Int_t crystal1 = (arraynumbers[i] - 1) % 4;
945 // now we will loop through all *unique* combinations
946 // we can start from j=i here, because j<i will only produce duplicates
947 for(Int_t j = i; j < size; j++) {
948 // identify detector and crystal numbers
949 Int_t detector2 = (arraynumbers[j] - 1) / 4 + 1;
950 Int_t crystal2 = (arraynumbers[j] - 1) % 4;
951 TVector3 positionone =
952 TGriffin::GetPosition(detector1, crystal1, distances[i]); // distance is in mm, usually 110, 145, or 160
953 TVector3 positiontwo =
954 TGriffin::GetPosition(detector2, crystal2, distances[j]); // distance is in mm, usually 110, 145, or 160
955 Double_t angle = positionone.Angle(positiontwo); // in radians
956 Bool_t alreadyclaimed = kFALSE;
957 for(double m : map) {
958 if(TMath::Abs(angle - m) < 0.00005) {
959 alreadyclaimed = kTRUE;
960 break;
961 }
962 }
963 if(!alreadyclaimed) {
964 map.push_back(angle);
965 }
966 }
967 }
968
969 // sort the map
970 std::sort(map.begin(), map.end());
971
972 return map;
973}
974
975////////////////////////////////////////////////////////////////////////////////
976/// Creates map of weights vs. angular index
977///
978/// \param[in] arraynumbers Vector of array numbers used in this experiment
979/// \param[in] distances Vector of detector distances for those array numbers
980/// \param[in] indexmap Index map (probably created with GenerateIndexMap)
981///
982/// The indices for the index map start from zero, so when using array numbers
983/// (which start from one) as input for those indices, you need to subtract one.
984///
985/// This function is called by GenerateMaps()
986
987std::vector<Int_t> TAngularCorrelation::GenerateWeights(std::vector<Int_t>& arraynumbers, std::vector<Int_t>&,
988 std::map<Int_t, std::map<Int_t, Int_t>>& indexmap)
989{
990 std::vector<Int_t> weights; // vector to return
991
992 // get array number size
993 Int_t size = arraynumbers.size();
994
995 // find maximum angular index
996 Int_t max = 0;
997 for(Int_t i = 0; i < size; i++) {
998 for(Int_t j = 0; j < size; j++) {
999 if(indexmap[i][j] > max) {
1000 max = indexmap[i][j];
1001 }
1002 }
1003 }
1004
1005 // initialize vector
1006 for(Int_t i = 0; i <= max; i++) {
1007 weights.push_back(0);
1008 }
1009
1010 // loop through array numbers (a list of crystals in the array)
1011 for(Int_t i = 0; i < size; i++) {
1012 if(arraynumbers[i] < 1 || arraynumbers[i] > 64) {
1013 std::cout << arraynumbers[i] << " is not a good array number." << std::endl;
1014 std::cout << "Skipping... you'll probably get some errors." << std::endl;
1015 continue;
1016 }
1017 // here, we want all combinations for the indices, so we start from j=0
1018 for(Int_t j = 0; j < size; j++) {
1019 Int_t index = indexmap[arraynumbers[i]][arraynumbers[j]];
1020 Int_t old_weight = weights[index];
1021 Int_t new_weight = old_weight + 1;
1022 weights[index] = new_weight;
1023 }
1024 }
1025
1026 return weights;
1027}
1028
1029////////////////////////////////////////////////////////////////////////////////
1030/// Creates map of modified weights vs. modified index
1031///
1032/// \param[in] modindices vector that converts angular index to modified index
1033/// \param[in] weights vector of weights for angular index
1034///
1035/// This function is called by GenerateMaps() and GenerateGroupMaps()
1036
1037std::vector<Int_t> TAngularCorrelation::GenerateModifiedWeights(std::vector<Int_t>& modindices,
1038 std::vector<Int_t>& weights)
1039{
1040 std::vector<Int_t> modifiedweights; // vector to return
1041
1042 // get weights size
1043 Int_t size = weights.size();
1044
1045 // find total number of modified indices
1046 Int_t max = 0;
1047 for(Int_t i = 0; i < size; i++) {
1048 if(modindices[i] > max) {
1049 max = modindices[i];
1050 }
1051 }
1052
1053 // fill modifiedweights with zeros
1054 for(Int_t i = 0; i <= max; i++) {
1055 modifiedweights.push_back(0);
1056 }
1057
1058 // iterate over angular modindices to look for same groups
1059 for(Int_t i = 0; i < size; i++) {
1060 Int_t thisIndex = modindices[i];
1061 modifiedweights[thisIndex] = modifiedweights[thisIndex] + weights[i];
1062 }
1063
1064 return modifiedweights;
1065}
1066
1067////////////////////////////////////////////////////////////////////////////////
1068/// Creates map of angle pair vs. angular index
1069///
1070/// \param[in] arraynumbers Vector of array numbers used in this experiment
1071/// \param[in] distances Vector of detector distances for those array numbers
1072/// \param[in] anglemap Angle map (probably created with GenerateAngleMap
1073///
1074/// This function is called by GenerateMaps()
1075///
1076std::map<Int_t, std::map<Int_t, Int_t>> TAngularCorrelation::GenerateIndexMap(std::vector<Int_t>& arraynumbers,
1077 std::vector<Int_t>& distances,
1078 std::vector<Double_t>& anglemap)
1079{
1080 // initialize map
1081 std::map<Int_t, std::map<Int_t, Int_t>> indexmap;
1082
1083 // get arraynumbers size
1084 Int_t size = arraynumbers.size();
1085
1086 // get angle map size
1087 Int_t mapsize = anglemap.size();
1088
1089 // loop through array numbers (a list of crystals in the array)
1090 for(Int_t i = 0; i < size; i++) {
1091 if(arraynumbers[i] < 1 || arraynumbers[i] > 64) {
1092 std::cout << arraynumbers[i] << " is not a good array number." << std::endl;
1093 std::cout << "Skipping... you'll probably get some errors." << std::endl;
1094 continue;
1095 }
1096
1097 // identify detector and crystal numbers
1098 Int_t detector1 = (arraynumbers[i] - 1) / 4 + 1;
1099 Int_t crystal1 = (arraynumbers[i] - 1) % 4;
1100 TVector3 positionone =
1101 TGriffin::GetPosition(detector1, crystal1, distances[i]); // distance is in mm, usually 110, 145, or 160
1102
1103 // here, we want all combinations for the indices, so we start from j=0
1104 for(Int_t j = 0; j < size; j++) {
1105 // identify detector and crystal numbers
1106 Int_t detector2 = (arraynumbers[j] - 1) / 4 + 1;
1107 Int_t crystal2 = (arraynumbers[j] - 1) % 4;
1108 TVector3 positiontwo =
1109 TGriffin::GetPosition(detector2, crystal2, distances[j]); // distance is in mm, usually 110, 145, or 160
1110 Double_t angle = positionone.Angle(positiontwo); // in radians
1111 for(Int_t m = 0; m < mapsize; m++) {
1112 if(TMath::Abs(angle - anglemap[m]) < 0.00005) {
1113 Int_t index1 = arraynumbers[i];
1114 Int_t index2 = arraynumbers[j];
1115 if(index1 == 0 || index2 == 0) {
1116 std::cout << "found array number of zero?" << std::endl;
1117 }
1118 indexmap[index1][index2] = m;
1119 break;
1120 }
1121 }
1122 }
1123 }
1124
1125 return indexmap;
1126}
1127
1128////////////////////////////////////////
1129/// Check Groups for Angular Indexes
1130///
1131/// \param[in] group vector of assigned groups for angular indexes (this is user input)
1132///
1133/// This function is called by GenerateGroupMaps()
1134///
1135
1136Bool_t TAngularCorrelation::CheckGroups(std::vector<Int_t>& group) const
1137{
1138
1139 // get number of group entries
1140 Int_t size = group.size();
1141
1142 // basic consistency check
1143 if(size != fNumIndices) {
1144 std::cout << "The group list is inconsistent with the number of angular indices." << std::endl;
1145 std::cout << "Number of groups: " << size << std::endl;
1146 std::cout << "Number of angular indices: " << fNumIndices << std::endl;
1147 return kFALSE;
1148 }
1149
1150 return kTRUE;
1151}
1152
1153////////////////////////////////////////
1154/// Returns the number of groups
1155///
1156
1158{
1159 Int_t max = 0;
1160 for(int fGroup : fGroups) {
1161 if(fGroup > max) {
1162 max = fGroup;
1163 }
1164 }
1165 return max + 1;
1166}
1167
1168////////////////////////////////////////
1169/// Returns the number of groups
1170///
1171
1173{
1174 Int_t max = 0;
1175 for(int fModifiedIndice : fModifiedIndices) {
1176 if(fModifiedIndice > max) {
1177 max = fModifiedIndice;
1178 }
1179 }
1180 return max + 1;
1181}
1182
1183////////////////////////////////////////
1184/// Check angles for groups
1185///
1186/// \param[in] groupangles vector (user input)
1187///
1188/// This function is called by GenerateGroupMaps()
1189///
1190
1191Bool_t TAngularCorrelation::CheckGroupAngles(std::vector<Double_t>& groupangles) const
1192{
1193 std::vector<Double_t> groupangle; // vector to return
1194
1195 // get number of group entries
1196 Int_t size = groupangles.size();
1197 Int_t numgroups = GetNumGroups();
1198
1199 // basic consistency check
1200 if(size != numgroups) {
1201 std::cout << "Not all groups have been assigned an angle." << std::endl;
1202 return kFALSE;
1203 }
1204
1205 return kTRUE;
1206}
1207
1208////////////////////////////////////////
1209/// Generate Folded Angles
1210/// gives angles out for each folded index in radians
1211///
1212/// \param[in] anglemap (can be for grouped or ungrouped anglular indexes)
1213///
1214/// This function is called by GenerateMaps() and GenerateGroupMaps()
1215///
1216
1217std::vector<Double_t> TAngularCorrelation::GenerateFoldedAngles(std::vector<Double_t>& anglemap)
1218{
1219 std::vector<Double_t> folds; // vector to return
1220
1221 // get size
1222 Int_t size = anglemap.size();
1223
1224 // consistancy check
1225 if(size == 0) {
1226 std::cout << "Angles have not been assigned yet. " << std::endl;
1227 std::cout << "Therefore cannot fold indexes. " << std::endl;
1228 return folds;
1229 }
1230
1231 // declare fold array and fill with zeros
1232 std::vector<Double_t> foldArray(size);
1233
1234 // fill fold array with angle values
1235 for(Int_t i = 0; i < size; i++) {
1236 foldArray[i] = anglemap[i];
1237 }
1238
1239 // Iterate through fold array
1240 for(Int_t i = 0; i < size; i++) {
1241 Double_t fold_angle = foldArray[i];
1242 Bool_t alreadyclaimed = kFALSE;
1243
1244 for(double fold : folds) {
1245 if(TMath::Abs(TMath::Sin(fold_angle) - TMath::Sin(fold)) <
1246 0.000005) { // look for duplicated angles in the fold array
1247 alreadyclaimed = kTRUE;
1248 break;
1249 }
1250 }
1251 if(!alreadyclaimed) {
1252 folds.push_back(fold_angle);
1253 }
1254 }
1255
1256 std::sort(folds.begin(), folds.end());
1257
1258 return folds;
1259}
1260
1261////////////////////////////////////////
1262/// Generated Folded Indexes
1263///
1264/// \param[in] folds vector of the folded angles
1265/// \param[in] anglemap vector of the unfolded angles
1266///
1267/// This function is called by GenerateMaps() and by GenerateGroupMaps()
1268///
1269
1270std::vector<Int_t> TAngularCorrelation::GenerateFoldedIndices(std::vector<Double_t>& folds,
1271 std::vector<Double_t>& anglemap)
1272{
1273 std::vector<Int_t> fold_indexes; // vector to return
1274
1275 // get sizes of fold and angle vectors
1276 Int_t fold_size = folds.size();
1277 Int_t angle_size = anglemap.size();
1278
1279 // itterate through angle map to find abs(cos(angle)
1280 for(Int_t i = 0; i < angle_size; i++) {
1281 Double_t angle = anglemap[i];
1282 Double_t sin_angle = TMath::Sin(angle);
1283
1284 // itterate through folds
1285 for(Int_t j = 0; j < fold_size; j++) {
1286 Double_t rad_angle = folds[j];
1287 Double_t fold_angle = TMath::Sin(rad_angle);
1288 if(TMath::Abs(fold_angle - sin_angle) < 0.000005) { // compare abs(cos(angle)) to fold_Angles to find matches
1289 fold_indexes.push_back(j); // assign folds
1290 break;
1291 }
1292 }
1293 }
1294
1295 return fold_indexes;
1296}
1297////////////////////////////////////////////////////////////////////////////////
1298/// Creates maps of angle pair vs. angular index and angular index vs. opening angle.
1299///
1300/// \param[in] arraynumbers Vector of array numbers used in this experiment
1301/// \param[in] distances Vector of detector distances for those array numbers
1302///
1303
1304Int_t TAngularCorrelation::GenerateMaps(std::vector<Int_t>& arraynumbers, std::vector<Int_t>& distances)
1305{
1306 // basic consistency check
1307 const Int_t size = arraynumbers.size();
1308 if(size != static_cast<Int_t>(distances.size())) {
1309 std::cout << "Lengths of array number and distance vectors are inconsistent." << std::endl;
1310 std::cout << "Array number vector size: " << size << std::endl;
1311 std::cout << "Distance vector size: " << distances.size() << std::endl;
1312 }
1313
1314 // clear vector map
1315 fAngleMap.clear();
1316
1317 // find maximum array number (which will be the index map size)
1318 fIndexMapSize = 0;
1319 for(Int_t i = 0; i < size; i++) {
1320 if(arraynumbers[i] > fIndexMapSize) {
1321 fIndexMapSize = arraynumbers[i];
1322 }
1323 }
1324
1325 // generate maps
1326 fAngleMap = GenerateAngleMap(arraynumbers, distances);
1327 fNumIndices = fAngleMap.size();
1328 fIndexMap = GenerateIndexMap(arraynumbers, distances, fAngleMap);
1329 fWeights = GenerateWeights(arraynumbers, distances, fIndexMap);
1330
1331 return fNumIndices;
1332}
1333
1334////////////////////////////////////////////////////////////////////////////////
1335/// Creates maps for modified indices with some combination of folding or grouping
1336///
1337/// \param[in] fold
1338/// \param[in] group
1339///
1340Int_t TAngularCorrelation::GenerateModifiedMaps(Bool_t fold, Bool_t group)
1341{
1342 if(group) {
1343 if(static_cast<Int_t>(fGroups.size()) != fNumIndices) {
1344 std::cout << "The groups are not set up properly." << std::endl;
1345 std::cout << "Cannot create grouped maps." << std::endl;
1346 std::cout << "Please use AssignGroupMaps first." << std::endl;
1347 return 0;
1348 }
1349 }
1351 Int_t size = fModifiedAngles.size();
1354
1355 return size;
1356}
1357
1358////////////////////////////////////////////////////////////////////////////////
1359/// Creates maps for Grouped Angular Indexes
1360/// Including group angle versus group index and angular index versus group index
1361///
1362/// \param[in] arraynumbers Vector of array numbers used in this experiment
1363/// \param[in] distances Vector of detector distances for those array numbers
1364/// \param[in] group Vector (user input)
1365/// \param[in] groupangles Vector (user input)
1366///
1367Int_t TAngularCorrelation::GenerateGroupMaps(std::vector<Int_t>& arraynumbers, std::vector<Int_t>& distances,
1368 std::vector<Int_t>& group, std::vector<Double_t>& groupangles)
1369{
1370 // basic consistency check
1371 const Int_t size = arraynumbers.size();
1372 if(size != static_cast<Int_t>(distances.size())) {
1373 std::cout << "Lengths of array number and distance vectors are inconsistent." << std::endl;
1374 std::cout << "Array number vector size: " << size << std::endl;
1375 std::cout << "Distance vector size: " << distances.size() << std::endl;
1376 }
1377
1378 // clear vector map
1379 fAngleMap.clear();
1380
1381 // find maximum array number (which will be the index map size)
1382 fIndexMapSize = 0;
1383 for(Int_t i = 0; i < size; i++) {
1384 if(arraynumbers[i] > fIndexMapSize) {
1385 fIndexMapSize = arraynumbers[i];
1386 }
1387 }
1388
1389 // generate maps
1390 fAngleMap = GenerateAngleMap(arraynumbers, distances);
1391 fNumIndices = fAngleMap.size();
1392 fIndexMap = GenerateIndexMap(arraynumbers, distances, fAngleMap);
1393 fWeights = GenerateWeights(arraynumbers, distances, fIndexMap);
1394 AssignGroupMaps(group, groupangles);
1395 // fGroupWeights = GenerateModifiedWeights(group, fWeights);
1396 // fFoldedGroupAngles = GenerateFoldedAngles(fGroupAngles);
1397 // fFoldedGroupIndexes = GenerateFoldedIndices(fFoldedGroupAngles, fGroupAngles);
1398 // fFoldedGroupWeights = GenerateModifiedWeights(fFoldedGroupIndexes, fGroupWeights);
1399 return fNumIndices;
1400}
1401
1402////////////////////////////////////////////////////////////////////////////////
1403/// Assigns maps for Grouped Angular Indexes
1404/// Including group angle versus group index and angular index versus group index
1405///
1406/// \param[in] group Vector (user input)
1407/// \param[in] groupangles Vector (user input)
1408///
1409
1410Int_t TAngularCorrelation::AssignGroupMaps(std::vector<Int_t>& group, std::vector<Double_t>& groupangles)
1411{
1412 // generate maps
1413 if(CheckGroups(group)) {
1414 fGroups = group;
1415 }
1416 if(CheckGroupAngles(groupangles)) {
1417 fGroupAngles = groupangles;
1418 }
1419 return GetNumGroups();
1420}
1421
1422////////////////////////////////////////////////////////////////////////////////
1423/// Creates maps for typical GRIFFIN configurations
1424///
1425/// \param[in] detectors number of detectors
1426/// \param[in] distance distance of detectors (in mm)
1427///
1428/// 16 detectors: full array
1429/// 15 detectors: full array less detector 13
1430/// 12 detectors: upstream lampshade and corona, detectors 5-16
1431/// 11 detectors: upstream lampshade and corona, less detector 13
1432/// 8 detectors: corona only
1433/// For more detailed configurations, please use GenerateMaps(std::vector<Int_t> &arraynumbers, std::vector<Int_t>
1434/// &distances)
1435///
1436
1437Int_t TAngularCorrelation::GenerateMaps(Int_t detectors, Int_t distance)
1438{
1439 std::vector<Int_t> array_numbers;
1440 std::vector<Int_t> distances;
1441
1442 if(detectors == 16) {
1443 std::cout << "Generating maps for full array setup." << std::endl;
1444 for(Int_t i = 1; i <= 64; i++) {
1445 array_numbers.push_back(i);
1446 distances.push_back(distance);
1447 }
1448 } else if(detectors == 15) {
1449 std::cout << "Generating maps for full array setup, less detector 13." << std::endl;
1450 for(Int_t i = 1; i <= 64; i++) {
1451 if(i >= 49 && i <= 52) {
1452 continue; // no detector 13
1453 }
1454 array_numbers.push_back(i);
1455 distances.push_back(distance);
1456 }
1457 } else if(detectors == 12) {
1458 std::cout << "Generating maps for detectors 5-16." << std::endl;
1459 for(Int_t i = 17; i <= 64; i++) {
1460 array_numbers.push_back(i);
1461 distances.push_back(distance);
1462 }
1463 } else if(detectors == 11) {
1464 std::cout << "Generating maps for detectors 5-16, less detector 13." << std::endl;
1465 for(Int_t i = 17; i <= 64; i++) {
1466 if(i >= 49 && i <= 52) {
1467 continue; // no detector 13
1468 }
1469 array_numbers.push_back(i);
1470 distances.push_back(distance);
1471 }
1472 } else if(detectors == 8) {
1473 std::cout << "Generating maps for the corona only, detectors 5-12." << std::endl;
1474 for(Int_t i = 17; i <= 48; i++) {
1475 array_numbers.push_back(i);
1476 distances.push_back(distance);
1477 }
1478 } else {
1479 std::cout << "This option isn't coded. Please use the more general GenerateMap(std::vector<Int_t> &arraynumbers, std::vector<Int_t> &distances)function." << std::endl;
1480 return 0;
1481 }
1482
1483 Int_t val = GenerateMaps(array_numbers, distances);
1484
1485 return val;
1486}
1487
1488////////////////////////////////////////////////////////////////////
1489/// Generates modified indices
1490///
1491/// \param[in] fold boolean indicating whether or not to fold the indices
1492/// \param[in] group boolean indicating whether or not to group the indices
1493
1494std::vector<Int_t> TAngularCorrelation::GenerateModifiedIndices(Bool_t fold, Bool_t group)
1495{
1496 std::vector<Int_t> modindices;
1497
1498 if(fNumIndices == 0) {
1499 std::cout << "You haven't set any angular indices yet." << std::endl;
1500 std::cout << "Returning empty vector from GenerateModifiedIndices." << std::endl;
1501 return modindices;
1502 }
1503 // make sure the modified angles are set appropriately
1504 if(fold != fFolded || group != fGrouped) {
1505 std::cout << "Please call GenerateModifiedAngles before calling GenerateModifiedIndices." << std::endl;
1506 std::cout << "Returning empty vector from GenerateModifiedIndices." << std::endl;
1507 return modindices;
1508 }
1509
1510 if(group) {
1511 if(static_cast<Int_t>(fGroups.size()) != fNumIndices) {
1512 std::cout << "The groups are not set up properly." << std::endl;
1513 std::cout << "Returning empty vector from GenerateModifiedIndices." << std::endl;
1514 return modindices;
1515 }
1516 }
1517
1518 if(!group && (!fold)) {
1519 // well then why are you doing this in the first place?
1520 // do nothing
1521 } else if(!fold && group) {
1522 modindices = fGroups;
1523 } else if(fold && group) {
1524 // group angles won't be directly comparable to the normal angle map
1525 // so we have to make another, temporary one.
1526 std::vector<Double_t> groupedangles;
1527 for(Int_t i = 0; i < fNumIndices; i++) {
1528 Int_t thisgroup = fGroups[i];
1529 Double_t thisangle = fGroupAngles[thisgroup];
1530 groupedangles.push_back(thisangle);
1531 }
1532 modindices = GenerateFoldedIndices(fModifiedAngles, groupedangles);
1533 } else if(fold) {
1535 }
1536
1537 return modindices;
1538}
1539
1540////////////////////////////////////////////////////////////////////
1541/// Clears the modified arrays
1542///
1543
1545{
1546 fModifiedIndices.clear();
1547 fModifiedAngles.clear();
1548 fModifiedWeights.clear();
1549}
1550
1551////////////////////////////////////////////////////////////////////
1552/// Generates modified angles
1553///
1554/// \param[in] fold boolean indicating whether or not to fold the indices
1555/// \param[in] group boolean indicating whether or not to group the indices
1556
1557std::vector<Double_t> TAngularCorrelation::GenerateModifiedAngles(Bool_t fold, Bool_t group)
1558{
1559 std::vector<Double_t> modangles;
1560
1561 // checking to see that we have regular indices
1562 if(fNumIndices == 0) {
1563 std::cout << "You haven't set any angular indices yet." << std::endl;
1564 std::cout << "Aborting." << std::endl;
1565 return modangles;
1566 }
1567
1568 // checking for groups set up
1569 if(static_cast<Int_t>(fGroups.size()) != fNumIndices) {
1570 std::cout << "The groups are not set up properly." << std::endl;
1571 std::cout << "Returning empty vector from GenerateModifiedAngles." << std::endl;
1572 return modangles;
1573 }
1574
1575 // checking for group angle setup
1576 if(group && static_cast<Int_t>(fGroupAngles.size()) != GetNumGroups()) {
1577 std::cout << "Group angles aren't set up properly." << std::endl;
1578 std::cout << "Returning empty vector from GenerateModifiedAngles." << std::endl;
1579 return modangles;
1580 }
1581
1583 std::cout << "Changing modification conditions to:" << std::endl;
1584 if(fold) {
1585 std::cout << "Folded: yes" << std::endl;
1586 } else {
1587 std::cout << "Folded: no" << std::endl;
1588 }
1589 if(group) {
1590 std::cout << "Grouped: yes" << std::endl;
1591 } else {
1592 std::cout << "Grouped: no" << std::endl;
1593 }
1594 fFolded = fold;
1595 fGrouped = group;
1596
1597 if(!group && (!fold)) {
1598 // well then why are you doing this in the first place?
1599 // do nothing
1600 } else if(!fold && group) {
1601 modangles = fGroupAngles;
1602 } else if(static_cast<int>(static_cast<int>((fold)) & static_cast<int>(!group)) != 0) {
1603 modangles = GenerateFoldedAngles(fAngleMap);
1604 } else if(fold && group) {
1606 }
1607
1608 return modangles;
1609}
1610
1611////////////////////////////////////////////////////////////////////
1612/// Updates index correlation based on peak array
1613///
1614
1616{
1617 // loop over quantities in map
1618 for(auto& fPeak : fPeaks) {
1619 Int_t index = fPeak.first;
1620 Int_t bin = (GetIndexCorrelation())->FindBin(index);
1621
1622 // extract area
1623 auto* peak = static_cast<TPeak*>(GetPeak(index));
1624 if(peak == nullptr) {
1625 return;
1626 }
1627 Double_t area = peak->GetArea();
1628 Double_t area_err = peak->GetAreaErr();
1629 Double_t chi2 = peak->GetChisquare();
1630 Double_t ndf = peak->GetNDF();
1631 Double_t scale = TMath::Max(1.0, TMath::Sqrt(chi2 / ndf));
1632 if(area_err < scale * TMath::Sqrt(area)) {
1633 std::cout << "Area error was less than the scaled square root of the area." << std::endl;
1634 std::cout << "This means something is wrong; using scaled square root of area for area error." << std::endl;
1635 area_err = TMath::Sqrt(area) * scale;
1636 }
1637
1638 // fill histogram with area
1639 static_cast<TH1D*>(GetIndexCorrelation())->SetBinContent(bin, area);
1640 static_cast<TH1D*>(GetIndexCorrelation())->SetBinError(bin, area_err);
1641 }
1642}
1643
1644////////////////////////////////////////////////////////////////////
1645/// Updates index correlation based on peak array
1646///
1647
1648void TAngularCorrelation::ScaleSingleIndex(TH1* hst, Int_t index, Double_t factor)
1649{
1650
1651 // get old values
1652 Double_t old_value = hst->GetBinContent(index + 1);
1653 Double_t old_error = hst->GetBinError(index + 1);
1654
1655 // set new values
1656 Double_t new_value = old_value * factor;
1657 std::cout << "old value is " << old_value << " multiplied by " << factor << " is " << new_value << std::endl;
1658 Double_t new_area_err = old_error * factor;
1659
1660 // fill histogram with new values
1661 hst->SetBinContent(index + 1, new_value);
1662 hst->SetBinError(index + 1, new_area_err);
1663}
1664////////////////////////////////////////////////////////////////////////////////
1665/// Updates diagnostics based on peak array
1666///
1667
1669{
1670 // loop over quantities in map
1671 for(auto& fPeak : fPeaks) {
1672 Int_t index = fPeak.first;
1673 Int_t bin = (GetIndexCorrelation())->FindBin(index);
1674
1675 // extract pertinent values from TPeaks
1676 auto* peak = static_cast<TPeak*>(GetPeak(index));
1677 if(peak == nullptr) {
1678 return;
1679 }
1680 Double_t chi2 = peak->GetChisquare();
1681 auto NDF = static_cast<Double_t>(peak->GetNDF());
1682 Double_t centroid = peak->GetCentroid();
1683 Double_t centroid_err = peak->GetCentroidErr();
1684 Double_t fwhm = peak->GetFWHM();
1685 Double_t fwhm_err = peak->GetFWHMErr();
1686
1687 // fill histogram with values
1688 static_cast<TH1D*>(GetChi2Hst())->SetBinContent(bin, chi2 / NDF);
1689 static_cast<TH1D*>(GetCentroidHst())->SetBinContent(bin, centroid);
1690 static_cast<TH1D*>(GetCentroidHst())->SetBinError(bin, centroid_err);
1691 static_cast<TH1D*>(GetFWHMHst())->SetBinContent(bin, fwhm);
1692 static_cast<TH1D*>(GetFWHMHst())->SetBinError(bin, fwhm_err);
1693 }
1694}
1695
1696////////////////////////////////////////////////////////////////////////////////
1697/// Fits slice with new peak and updates the index correlation
1698///
1699/// \param[in] index angular index
1700/// \param[in] peak Tpeak to be used for fitting
1701
1702void TAngularCorrelation::UpdatePeak(Int_t index, TPeak* peak) // sometimes this function will cause grsisort to crash
1703 // when I try to re-fit a bad peak, we should add in a
1704 // safe-gaurd to make the function return if the peak
1705 // cannot be re-fit
1706{
1707 // create canvas
1708 new TCanvas(Form("peak%iupdate", index), Form("Peak %i update", index), 400, 400);
1709
1710 // get histogram
1711 TH1D* temphst = Get1DSlice(index);
1712
1713 // adjust range
1714 Double_t minenergy = 0.;
1715 Double_t maxenergy = 0.;
1716 peak->GetRange(minenergy, maxenergy);
1717 Double_t difference = maxenergy - minenergy;
1718 minenergy = minenergy - 0.5 * difference;
1719 maxenergy = maxenergy + 0.5 * difference;
1720 temphst->GetXaxis()->SetRangeUser(minenergy, maxenergy);
1721
1722 // fit peak
1723 // peak->SetName(name);
1724 peak->Fit(Get1DSlice(index), "");
1725 auto* hstpeak = static_cast<TPeak*>(temphst->GetListOfFunctions()->Last());
1726
1727 // push new peak
1728 SetPeak(index, hstpeak);
1731}
1732
1733////////////////////////////////////////////////////////////////////////////////
1734/// Returns peak, if it exists
1735///
1736/// \param[in] index angular index
1737///
1738
1740{
1741 if(fPeaks[index] == nullptr) {
1742 std::cout << "No peak exists for index " << index << ". Returning nullptr." << std::endl;
1743 return nullptr;
1744 }
1745 return fPeaks[index];
1746}
1747
1748////////////////////////////////////////////////////////////////////////////////
1749/// Compares 1D histogram to current AC modified settings
1750///
1751/// \param[in] hst histogram
1752///
1754{
1755 Int_t hstbins = hst->GetNbinsX();
1756 Int_t modindices = GetNumModIndices();
1757
1758 if(hstbins != modindices) {
1759 std::cout << "The histogram " << hst->GetName() << " does not have the same number of bins as the current settings." << std::endl;
1760 std::cout << "Bins in the histogram: " << hstbins << std::endl;
1761 std::cout << "Number of modified indices: " << modindices << std::endl;
1763 return kFALSE;
1764 }
1765
1766 return kTRUE;
1767}
1768
1769////////////////////////////////////////////////////////////////////////////////
1770/// Prints current folding and grouping settings
1771///
1773{
1774 std::cout << "Current modification conditions:" << std::endl;
1775 if(fFolded) {
1776 std::cout << "Folded: yes" << std::endl;
1777 } else {
1778 std::cout << "Folded: no" << std::endl;
1779 }
1780 if(fGrouped) {
1781 std::cout << "Grouped: yes" << std::endl;
1782 } else {
1783 std::cout << "Grouped: no" << std::endl;
1784 }
1785}
1786
1787////////////////////////////////////////////////////////////////////////////////
1788/// Divides histogram by weights listed in weight array
1789///
1790/// \param[in] hst histogram
1791/// \param[in] fold boolean indicating whether or not to fold the indices
1792/// \param[in] group boolean indicating whether or not to group the indices
1793///
1794
1795TH1D* TAngularCorrelation::DivideByWeights(TH1* hst, Bool_t fold, Bool_t group)
1796{
1797
1798 if(!fold && !group) {
1799 Int_t size = GetWeightsSize();
1800
1801 // consistency/stability checks
1802 if(size == 0) {
1803 std::cout << "You haven't created the weights yet. Please use the GenerateMaps function to do so." << std::endl;
1804 return nullptr;
1805 }
1806 if(size != hst->GetNbinsX()) {
1807 std::cout << "Warning: size of weights array is different than number of bins in " << hst->GetName() << std::endl;
1808 }
1809 // this loop is just for checking to make sure all indices are in the weight vector
1810 for(Int_t i = 1; i <= hst->GetNbinsX(); i++) {
1811 auto index = static_cast<Int_t>(hst->GetXaxis()->GetBinLowEdge(i));
1812 if(index >= size) {
1813 std::cout << "Indices in histogram " << hst->GetName() << " go beyond size of weights array. Aborting." << std::endl;
1814 return nullptr;
1815 }
1816 }
1817 } else {
1818 // compare fold and group
1819 if(fold == fFolded && group == fGrouped) {
1820 // do nothing
1821 } else {
1822 GenerateModifiedMaps(fold, group);
1823 }
1824
1825 if(CheckModifiedHistogram(hst)) {
1826 // do nothing
1827 } else {
1828 return nullptr;
1829 }
1830
1831 // check that the weights array is the same size
1832 if(static_cast<Int_t>(fModifiedWeights.size()) == hst->GetNbinsX()) {
1833 // do nothing
1834 } else {
1835 std::cout << "Weights array size is not the same as the number of bins." << std::endl;
1836 std::cout << "Returning from DivideByWeights without dividing." << std::endl;
1837 return nullptr;
1838 }
1839 }
1840
1841 // now that we're satisified everything is kosher, divide the bins.
1842 for(Int_t i = 1; i <= hst->GetNbinsX(); i++) {
1843 std::cout << "\t" << i << std::endl;
1844 auto index = static_cast<Int_t>(hst->GetXaxis()->GetBinLowEdge(i));
1845 Double_t found_weight = 0;
1846 if(!fold && !group) {
1847 found_weight = GetWeightFromIndex(index);
1848 } else {
1849 found_weight = GetModifiedWeight(index);
1850 }
1851 Double_t content = hst->GetBinContent(i);
1852 Double_t error = hst->GetBinError(i);
1853 Double_t weight = found_weight;
1854 Double_t newcontent = content / weight;
1855 Double_t newerror = error / weight;
1856 hst->SetBinContent(i, newcontent);
1857 hst->SetBinError(i, newerror);
1858 }
1859
1860 return static_cast<TH1D*>(hst);
1861}
1862
1864{
1865 if(c_diag == nullptr) {
1866 c_diag = new TCanvas(Form("c_diag_%s", GetName()), Form("Diagnostics from %s", GetName()), 800, 800);
1867 }
1868
1869 // divide canvas
1870 c_diag->Divide(2, 2);
1871
1872 // pull plots for index correlation, chi^2, centroid, and fwhm
1873 TH1D* indexhst = GetIndexCorrelation();
1874 TH1D* chi2hst = GetChi2Hst();
1875 TH1D* centroidhst = GetCentroidHst();
1876 TH1D* fwhmhst = GetFWHMHst();
1877
1878 for(int i = 0; i < 52; i++) {
1879 std::cout << chi2hst->GetBinContent(i) << std::endl;
1880 }
1881
1882 // format the diagnostic plots
1883 indexhst->SetStats(false);
1884 chi2hst->SetStats(false);
1885 centroidhst->SetStats(false);
1886 fwhmhst->SetStats(false);
1887 chi2hst->SetMarkerStyle(4);
1888
1889 // plot chi^2, centroid, and FWHM
1890 c_diag->cd(1);
1891 indexhst->Draw();
1892 c_diag->cd(2);
1893 chi2hst->Draw("p");
1894 c_diag->cd(3);
1895 centroidhst->Draw();
1896 c_diag->cd(4);
1897 fwhmhst->Draw();
1898}
std::vector< Double_t > fGroupAngles
array correlating angular index with group assignment
TGraphAsymmErrors * CreateGraphFromHst()
void Set1DSlice(Int_t index, TH1D *slice)
Double_t GetWeightFromIndex(Int_t index)
Int_t GetAngularIndex(Int_t arraynum1, Int_t arraynum2)
TPeak * GetPeak(Int_t index)
TH1D * DivideByWeights(TH1 *hst, Bool_t fold, Bool_t group)
Bool_t CheckModifiedHistogram(TH1 *hst) const
std::vector< Double_t > fAngleMap
size of fIndexMap
Int_t GetModifiedWeight(Int_t modindex)
Int_t AssignGroupMaps(std::vector< Int_t > &group, std::vector< Double_t > &groupangles)
std::vector< Int_t > fGroups
array correlating angular index with weight (number of detector pairs at that index)
static std::vector< Int_t > GenerateFoldedIndices(std::vector< Double_t > &folds, std::vector< Double_t > &anglemap)
Bool_t CheckGroups(std::vector< Int_t > &group) const
std::vector< Double_t > GenerateModifiedAngles(Bool_t fold, Bool_t group)
Int_t GetGroupFromIndex(Int_t index)
TH2D * Create2DSlice(THnSparse *hst, Double_t min, Double_t max, Bool_t fold, Bool_t group)
std::vector< Int_t > GenerateModifiedWeights(std::vector< Int_t > &modindices, std::vector< Int_t > &weights)
Bool_t fGrouped
switch to indicate a folded correlation
void PrintModifiedIndexMap()
Prints map of angular index vs. Folded Index.
Int_t fIndexMapSize
number of angular indices
TH1D * fFWHM
1D plot of centroid vs. angular index
TH1D * IntegralSlices(TH2 *hst, Double_t min, Double_t max)
Bool_t CheckGroupAngles(std::vector< Double_t > &groupangles) const
static std::vector< Double_t > GenerateAngleMap(std::vector< Int_t > &arraynumbers, std::vector< Int_t > &distances)
std::vector< Int_t > fModifiedWeights
TH1D * FitSlices(TH2 *hst, TPeak *peak, Bool_t visualization)
static std::vector< Int_t > GenerateWeights(std::vector< Int_t > &arraynumbers, std::vector< Int_t > &distances, std::map< Int_t, std::map< Int_t, Int_t > > &indexmap)
Bool_t fFolded
array correlating group assignment with their average angles
void ScaleSingleIndex(TH1 *hst, Int_t index, Double_t factor)
Int_t GenerateGroupMaps(std::vector< Int_t > &arraynumbers, std::vector< Int_t > &distances, std::vector< Int_t > &group, std::vector< Double_t > &groupangles)
static std::map< Int_t, std::map< Int_t, Int_t > > GenerateIndexMap(std::vector< Int_t > &arraynumbers, std::vector< Int_t > &distances, std::vector< Double_t > &anglemap)
std::vector< Int_t > GenerateModifiedIndices(Bool_t fold, Bool_t group)
void SetPeak(Int_t index, TPeak *peak)
void UpdatePeak(Int_t index, TPeak *peak)
TH1D * fChi2
1D plot of counts vs. angular index
Double_t GetGroupAngleFromIndex(Int_t gindex)
Int_t fNumIndices
2D square array correlating array number pairs with angular index
Int_t GenerateMaps(std::vector< Int_t > &arraynumbers, std::vector< Int_t > &distances)
TH1D * Get1DSlice(Int_t index)
Double_t GetModifiedAngleFromIndex(Int_t modindex)
static std::vector< Double_t > GenerateFoldedAngles(std::vector< Double_t > &anglemap)
std::vector< Int_t > fWeights
array correlating angular index with opening angle
std::map< Int_t, TPeak * > fPeaks
1D plot of FWHM vs. angular index
void DisplayDiagnostics(TCanvas *c_diag)
Bool_t CheckMaps(Bool_t fold, Bool_t group)
std::vector< Int_t > fModifiedIndices
switch to indicate a grouped correlation
Int_t GetModifiedIndex(Int_t index)
std::vector< Double_t > fModifiedAngles
Int_t GenerateModifiedMaps(Bool_t fold, Bool_t group)
std::map< Int_t, std::map< Int_t, Int_t > > fIndexMap
array of 1D histograms used to create fIndexCorrelations
TH1D * fCentroid
1D plot of chi^2 vs. angular index
Double_t GetAngleFromIndex(Int_t index)
TH2D * Modify2DSlice(TH2 *hst, Bool_t fold, Bool_t group)
static TVector3 GetPosition(int DetNbr, int CryNbr=5, double dist=110.0)
!
Definition TGriffin.cxx:501
Definition TPeak.h:28
Bool_t Fit(TH1 *fitHist, Option_t *opt="")
Definition TPeak.cxx:191
TF1 * Background() const
Definition TPeak.h:96
Double_t GetAreaErr() const
Definition TPeak.h:54
static void SetLogLikelihoodFlag(Bool_t flag=true)
Definition TPeak.h:102
Bool_t InitParams(TH1 *fitHist=nullptr) override
Definition TPeak.cxx:131
Double_t GetArea() const
Definition TPeak.h:53
Double_t GetCentroid() const
Definition TPeak.h:51