GRSISort "v4.1.1.0"
An extension of the ROOT analysis Framework
Loading...
Searching...
No Matches
SimulationAngularCorrelation.cxx
Go to the documentation of this file.
1#include <iostream>
2#include <iomanip>
3
4#include "TChain.h"
5#include "TFile.h"
6#include "TGraphErrors.h"
7#include "TH2D.h"
8
9#include "Globals.h"
10#include "TRedirect.h"
11#include "TUserSettings.h"
12#include "TGriffin.h"
13#include "TGriffinBgo.h"
14#include "TGriffinAngles.h"
15
16int main(int argc, char** argv)
17{
18 bool printUsage = (argc == 1);
19
20 std::array<std::vector<std::string>, 3> inputFilenames;
21 std::string outputFilename = "SimulatedAngularCorrelation.root";
22 double gateEnergy = 0.;
23 double fitEnergy = 0.;
24 bool addback = false;
25 bool singleCrystal = false;
26 double distance = 145.;
27 int bins = 2000;
28 double minEnergy = 0.;
29 double maxEnergy = 2000.;
30 std::vector<int> excludedDetectors;
31 int verboseLevel = 0;
32 std::string settingsFile;
33
34 // read command line arguments
35 for(int i = 1; i < argc; ++i) {
36 if(strncmp(argv[i], "-if", 2) == 0) {
37 // check which coefficent this is for
38 int coefficent = -1;
39 if(strcmp(&argv[i][3], "000") == 0) {
40 coefficent = 0;
41 } else if(strcmp(&argv[i][3], "010") == 0) {
42 coefficent = 1;
43 } else if(strcmp(&argv[i][3], "100") == 0) {
44 coefficent = 2;
45 } else {
46 std::cerr << "Unknown -if* command line flag " << argv[i] << ", should be -if000, -if010, or -if100!" << std::endl;
47 printUsage = true;
48 break;
49 }
50 // if we have another argument, check if it starts with '-'
51 while(i + 1 < argc) {
52 if(argv[i + 1][0] == '-') {
53 break;
54 }
55 // if we get here we can add the next argument to the list of file names
56 inputFilenames[coefficent].emplace_back(argv[++i]);
57 }
58 } else if(strcmp(argv[i], "-of") == 0) {
59 if(i + 1 < argc) {
60 outputFilename = argv[++i];
61 } else {
62 std::cout << "Error, -of flag needs an argument!" << std::endl;
63 printUsage = true;
64 }
65 } else if(strcmp(argv[i], "-g") == 0) {
66 if(i + 1 < argc) {
67 gateEnergy = std::atof(argv[++i]);
68 } else {
69 std::cout << "Error, -g flag needs an argument!" << std::endl;
70 printUsage = true;
71 }
72 } else if(strcmp(argv[i], "-f") == 0) {
73 if(i + 1 < argc) {
74 fitEnergy = std::atof(argv[++i]);
75 } else {
76 std::cout << "Error, -f flag needs an argument!" << std::endl;
77 printUsage = true;
78 }
79 } else if(strcmp(argv[i], "-ab") == 0) {
80 addback = true;
81 } else if(strcmp(argv[i], "-sc") == 0) {
82 singleCrystal = true;
83 } else if(strcmp(argv[i], "-d") == 0) {
84 if(i + 1 < argc) {
85 distance = std::atof(argv[++i]);
86 } else {
87 std::cout << "Error, -d flag needs an argument!" << std::endl;
88 printUsage = true;
89 }
90 } else if(strcmp(argv[i], "-ed") == 0) {
91 if(!excludedDetectors.empty()) {
92 std::cerr << "Warning, already got " << excludedDetectors.size() << " excluded detectors (?, this should not happen):";
93 for(auto bin : excludedDetectors) { std::cerr << " " << bin; }
94 std::cerr << std::endl;
95 std::cerr << "What is read from command line will not overwrite these but be added to them!" << std::endl;
96 }
97 // if we have a next argument, check if it starts with '-'
98 while(i + 1 < argc) {
99 if(argv[i + 1][0] == '-') {
100 break;
101 }
102 // if we get here we can add the next argument to the list of energies
103 excludedDetectors.push_back(std::atoi(argv[++i]));
104 }
105 } else if(strcmp(argv[i], "-vl") == 0) {
106 if(i + 1 < argc) {
107 verboseLevel = std::atoi(argv[++i]);
108 } else {
109 std::cout << "Error, -vl flag needs an argument!" << std::endl;
110 printUsage = true;
111 }
112 } else if(strcmp(argv[i], "-sf") == 0) {
113 if(i + 1 < argc) {
114 settingsFile = argv[++i];
115 } else {
116 std::cout << "Error, -sf flag needs an argument!" << std::endl;
117 printUsage = true;
118 }
119 } else {
120 std::cerr << "Error, unknown flag \"" << argv[i] << "\"!" << std::endl;
121 printUsage = true;
122 }
123 }
124
125 // try to read user settings
126 TUserSettings settings;
127 if(!settingsFile.empty()) {
128 settings.ReadSettings(settingsFile);
129
130 if(inputFilenames[0].empty()) {
131 inputFilenames[0] = settings.GetStringVector("Coefficient.000.Files");
132 }
133 if(inputFilenames[1].empty()) {
134 inputFilenames[1] = settings.GetStringVector("Coefficient.010.Files");
135 }
136 if(inputFilenames[2].empty()) {
137 inputFilenames[2] = settings.GetStringVector("Coefficient.100.Files");
138 }
139 if(outputFilename == "SimulatedAngularCorrelation.root") {
140 outputFilename = settings.GetString("OutputFilename", "SimulatedAngularCorrelation.root");
141 } else {
142 std::cout << "Output filename has already been set to \"" << outputFilename << "\" via command line, ignoring settings file for this." << std::endl;
143 }
144 if(gateEnergy != 0.) {
145 std::cerr << "Warning, already got gate energy " << gateEnergy << ", this could be overwritten by the settings file!" << std::endl;
146 }
147 gateEnergy = settings.GetDouble("Energy.Gate", gateEnergy);
148 if(fitEnergy != 0.) {
149 std::cerr << "Warning, already got fit energy " << fitEnergy << ", this could be overwritten by the settings file!" << std::endl;
150 }
151 fitEnergy = settings.GetDouble("Energy.Fit", fitEnergy);
152 // GetBool doesn't have a default version, so catch any errors
153 try {
154 addback = settings.GetBool("Addback", true);
155 } catch(std::out_of_range&) {}
156 try {
157 singleCrystal = settings.GetBool("SingleCrystal", true);
158 } catch(std::out_of_range&) {}
159 distance = settings.GetDouble("Distance", distance);
160 bins = settings.GetInt("Bins", bins);
161 minEnergy = settings.GetDouble("Energy.Minimum", minEnergy);
162 maxEnergy = settings.GetDouble("Energy.Minimum", maxEnergy);
163 if(!excludedDetectors.empty()) {
164 std::cerr << "Warning, already got " << excludedDetectors.size() << " excluded detectors from command line, not going to try and read them from settings file!" << std::endl;
165 } else {
166 try {
167 excludedDetectors = settings.GetIntVector("ExcludedBins", true);
168 } catch(std::out_of_range&) {}
169 }
170 verboseLevel = settings.GetInt("Verbosity", verboseLevel);
171 }
172
173 if(!printUsage && (inputFilenames[0].empty() || inputFilenames[1].empty() || inputFilenames[2].empty())) {
174 std::cerr << "Error, need input files for all three !" << std::endl;
175 printUsage = true;
176 }
177
178 if(!printUsage && (gateEnergy <= 0. || fitEnergy <= 0.)) {
179 std::cerr << "Error, need energies for the gate (" << gateEnergy << ") and the fit (" << fitEnergy << ")!" << std::endl;
180 printUsage = true;
181 }
182
183 if(!printUsage && singleCrystal && !addback) {
184 std::cerr << "Error, can't have single crystal method without using addback!" << std::endl;
185 printUsage = true;
186 }
187
188 if(printUsage) {
189 std::cerr << "Arguments for " << argv[0] << ":" << std::endl
190 << "-if000 <input files> (required, geant4 simulation files for parameters 000)" << std::endl
191 << "-if010 <input files> (required, geant4 simulation files for parameters 010)" << std::endl
192 << "-if100 <input files> (required, geant4 simulation files for parameters 100)" << std::endl
193 << "-g <gate energy> (required)" << std::endl
194 << "-f <fit energy> (required)" << std::endl
195 << "-of <output filename> (optional, default = \"SimulatedAngularCorrelation.root\")" << std::endl
196 << "-ab (optional, enables addback)" << std::endl
197 << "-sc (optional, enables single crystal method, needs addback to be enabled!)" << std::endl
198 << "-d <GRIFFIN distance (110. or 145.)> (optional, default = 145.)" << std::endl
199 << "-vl <verbose level> (optional)" << std::endl;
200
201 return 1;
202 }
203
204 if(distance != 145. && distance != 110.) {
205 std::cout << "Warning, distance is set to non-standard " << distance << " mm, are you sure this is correct?" << std::endl
206 << "Nominal distances are 145 mm in full suppression mode, and 110 mm in forward/high efficiency mode." << std::endl;
207 }
208
209 // open the output file
210 TFile output(outputFilename.c_str(), "recreate");
211 if(!output.IsOpen()) {
212 std::cerr << "Failed to open file " << outputFilename << ", maybe check permissions and disk space?" << std::endl;
213 return 1;
214 }
215
216 // create angle map, never use folding and/or grouping, that is done in the AngularCorrelations program
217 if(verboseLevel > 0) { TGriffinAngles::Verbosity(EVerbosity::kAll); }
218 TGriffinAngles angles(distance, false, false, addback);
219 for(auto& det : excludedDetectors) {
220 angles.ExcludeDetector(det);
221 }
222 // intermediate storage of hits
223 std::map<uint32_t, TFragment> fragments;
224 TGriffin griffin;
225 TGriffinBgo grifBgo;
226
227 // output histograms and graphs
228 std::string conditions = addback ? "using addback" : "without addback";
229 conditions += singleCrystal ? " single crystal" : "";
230
231 std::array<std::vector<TH2D*>, 3> hists;
232 std::array<TGraphErrors, 3> graph;
233
234 graph[0].SetName("graph000");
235 graph[0].SetTitle(Form("Simulated angular correlation coeff. 000, using %s;angle [#circ]", conditions.c_str()));
236
237 graph[1].SetName("graph010");
238 graph[1].SetTitle(Form("Simulated angular correlation coeff. 010, using %s;angle [#circ]", conditions.c_str()));
239
240 graph[2].SetName("graph100");
241 graph[2].SetTitle(Form("Simulated angular correlation coeff. 100, using %s;angle [#circ]", conditions.c_str()));
242
243 // loop over the three coefficents
244 for(int c = 0; c < 3; ++c) {
245 // resize and allocate histograms and graphs
246 hists[c].resize(angles.NumberOfAngles());
247 for(auto angle = angles.begin(); angle != angles.end(); ++angle) {
248 int i = std::distance(angles.begin(), angle);
249 hists[c][i] = new TH2D(Form("AngularCorrelation%d_%d", c, i), Form("%.1f^{o}: Simulated suppressed #gamma-#gamma %s", *angle, conditions.c_str()), bins, minEnergy, maxEnergy, bins, minEnergy, maxEnergy);
250 }
251 graph[c].Set(angles.NumberOfAngles());
252
253 // add all input files to the chain and set the branch addresses
254 TChain chain("ntuple");
255
256 for(const auto& filename : inputFilenames[c]) {
257 chain.Add(filename.c_str());
258 }
259
260 Int_t eventNumber = 0;
261 chain.SetBranchAddress("eventNumber", &eventNumber);
262 Int_t systemID = 0;
263 chain.SetBranchAddress("systemID", &systemID);
264 Int_t detNumber = 0;
265 chain.SetBranchAddress("detNumber", &detNumber);
266 Int_t cryNumber = 0;
267 chain.SetBranchAddress("cryNumber", &cryNumber);
268 Double_t depEnergy = 0.;
269 chain.SetBranchAddress("depEnergy", &depEnergy);
270 Double_t time = 0.;
271 chain.SetBranchAddress("time", &time);
272
273 // main loop over entries of the simulation tree
274 int oldEventNumber = 0;
275 uint32_t address = 0xdead;
276 std::string mnemonic;
277 std::string crystalColor = "BGRW";
278 TChannel* channel = nullptr;
279 int64_t nEntries = chain.GetEntries();
280 if(verboseLevel > 1) {
281 std::cout << "Starting loop over " << nEntries << " entries, using angles:" << std::endl;
282 angles.Print();
283 }
284 std::map<double, int> unknownAngles;
285 for(int64_t e = 0; e < nEntries; ++e) {
286 int status = chain.GetEntry(e);
287 if(status == -1) {
288 std::cerr << "Error occured, couldn't read entry " << e << " from tree " << chain.GetName() << " in file " << chain.GetFile()->GetName() << std::endl;
289 continue;
290 }
291 if(status == 0) {
292 std::cerr << "Error occured, entry " << e << " in tree " << chain.GetName() << " in file " << chain.GetFile()->GetName() << " doesn't exist" << std::endl;
293 break;
294 }
295 if(eventNumber != oldEventNumber) {
296 // new event number, use the current data to create detectors and fill histograms
297
298 // We want to fill the detectors time ordered. We can't sort the map by the time,
299 // but at this stage we don't need the key (address) anymore, so we can just
300 // copy everything into a vector and sort it.
301 std::vector<TFragment> fragmentCopy;
302 std::transform(fragments.begin(), fragments.end(), std::back_inserter(fragmentCopy), [](std::pair<const uint32_t, TFragment>& kv) { return kv.second; });
303 std::sort(fragmentCopy.begin(), fragmentCopy.end()); //uses the default < operator of TFragment (sorts by timestamp)
304
305 for(auto& frag : fragmentCopy) {
306 channel = TChannel::GetChannel(frag.GetAddress());
307 if(std::any_of(excludedDetectors.begin(), excludedDetectors.end(), [&channel](int det) { return channel->GetDetectorNumber() == det; })) {
308 continue;
309 }
310 switch(frag.GetAddress() / 1000) {
311 case 0: // Griffin
312 griffin.AddFragment(std::make_shared<TFragment>(frag), channel);
313 break;
314 case 1: // Griffin BGO
315 grifBgo.AddFragment(std::make_shared<TFragment>(frag), channel);
316 break;
317 default:
318 break;
319 }
320 }
321
322 if((verboseLevel > 2 && (addback ? griffin.GetSuppressedAddbackMultiplicity(&grifBgo) : griffin.GetSuppressedMultiplicity(&grifBgo)) > 1) || verboseLevel > 3) {
323 std::cout << "New event number is " << eventNumber << ", processing old event " << oldEventNumber << std::endl;
324 std::cout << "From " << fragments.size() << " fragments in the map, we got " << fragmentCopy.size() << " time sorted fragments, and " << griffin.GetMultiplicity() << " griffin hits, " << grifBgo.GetMultiplicity() << " BGO hits, " << griffin.GetSuppressedMultiplicity(&grifBgo) << " suppressed griffin hits, and " << griffin.GetSuppressedAddbackMultiplicity(&grifBgo) << " suppressed addback hits" << std::endl;
325 }
326 // now we have the detectors filled so we can simply loop over the suppressed hits we want (addback or not)
327 // we've already excluded the detectors we don't want when filling this, so we don't need to check here
328 for(int g1 = 0; g1 < (addback ? griffin.GetSuppressedAddbackMultiplicity(&grifBgo) : griffin.GetSuppressedMultiplicity(&grifBgo)); ++g1) {
329 if(singleCrystal && griffin.GetNSuppressedAddbackFrags(g1) > 1) { continue; }
330 auto* grif1 = (addback ? griffin.GetSuppressedAddbackHit(g1) : griffin.GetSuppressedHit(g1));
331 for(int g2 = g1 + 1; g2 < (addback ? griffin.GetSuppressedAddbackMultiplicity(&grifBgo) : griffin.GetSuppressedMultiplicity(&grifBgo)); ++g2) {
332 if(singleCrystal && griffin.GetNSuppressedAddbackFrags(g2) > 1) { continue; }
333 auto* grif2 = (addback ? griffin.GetSuppressedAddbackHit(g2) : griffin.GetSuppressedHit(g2));
334 // calculate the angle
335 double angle = grif1->GetPosition(distance).Angle(grif2->GetPosition(distance)) * 180. / TMath::Pi();
336 if(verboseLevel > 4) {
337 std::cout << "det,/cry. " << grif1->GetDetector() << "/" << grif1->GetCrystal() << " with " << grif2->GetDetector() << "/" << grif2->GetCrystal() << " = " << angle << std::endl;
338 }
339 int angleIndex = 0;
340 if(verboseLevel < 3) {
341 TRedirect r("/dev/null");
342 angleIndex = angles.Index(angle);
343 } else {
344 angleIndex = angles.Index(angle);
345 }
346 if(verboseLevel > 4) {
347 std::cout << "Filling histograms at index " << angleIndex << " = " << angle << " degree, with " << grif1->GetEnergy() << ", " << grif2->GetEnergy() << std::endl;
348 }
349 if(angleIndex >= 0) {
350 hists[c].at(angleIndex)->Fill(grif1->GetEnergy(), grif2->GetEnergy());
351 hists[c].at(angleIndex)->Fill(grif2->GetEnergy(), grif1->GetEnergy());
352 } else {
353 unknownAngles[angle]++;
354 if(verboseLevel > 4) {
355 std::cout << "Not filling histogram for griffin hits:" << std::endl;
356 grif1->Print();
357 grif2->Print();
358 }
359 }
360 }
361 }
362
363 griffin.Clear("a");
364 grifBgo.Clear("a");
365 fragments.clear();
366 }
367 switch(systemID) {
368 case 1000:
369 address = 4 * detNumber + cryNumber;
370 break;
371 case 1010: //left extension suppressor
372 case 1020: //right extension suppressor
373 case 1030: //left casing suppressor
374 case 1040: //right casing suppressor
375 case 1050: //back suppressor
376 address = 1000 + 10 * detNumber + cryNumber;
377 break;
378 default:
379 address = 0xdead;
380 break;
381 }
382 if(fragments.count(address) == 1) {
383 if(verboseLevel > 3) {
384 std::cout << "Found second hit for address " << address << ", updating time and energy from " << fragments[address].GetTime() << ", " << fragments[address].GetCharge();
385 }
386 // only update the time if the energy deposited is larger
387 if(depEnergy > fragments[address].GetCharge()) {
388 // timestamp is in 10 ns units, cfd is 10/16th of a nanosecond units and replaces the lowest 18 bits of the timestamp
389 // so we multiply the time by 16e8, and use only the lowest 22 bits
390 fragments[address].SetTimeStamp(static_cast<Long64_t>(time * 1e8));
391 fragments[address].SetCfd(static_cast<int>(time * 16e8) & 0x3fffff);
392 }
393 fragments[address].SetCharge(fragments[address].GetCharge() + static_cast<float>(depEnergy));
394 if(verboseLevel > 3) {
395 std::cout << " to " << fragments[address].GetTime() << ", " << fragments[address].GetCharge() << std::endl;
396 }
397 } else {
398 fragments[address].SetAddress(address);
399 fragments[address].SetTimeStamp(static_cast<Long64_t>(time * 1e8));
400 fragments[address].SetCfd(static_cast<int>(time * 16e8) & 0x3fffff);
401 fragments[address].SetCharge(static_cast<float>(depEnergy));
402 channel = TChannel::GetChannel(address);
403 if(channel == nullptr) {
404 switch(systemID) {
405 case 1000:
406 mnemonic = Form("GRG%02d%cN00A", detNumber, crystalColor[cryNumber]);
407 break;
408 case 1010: //left extension suppressor
409 case 1020: //right extension suppressor
410 case 1030: //left casing suppressor
411 case 1040: //right casing suppressor
412 case 1050: //back suppressor
413 mnemonic = Form("GRS%02d%cN%02d", detNumber, crystalColor[cryNumber], cryNumber); // third argument should be 1-5, not sure how to set this properly
414 break;
415 default:
416 break;
417 }
418 channel = new TChannel;
419 channel->SetAddress(address);
420 channel->SetName(mnemonic.c_str());
421 channel->SetDetectorNumber(detNumber + 1);
422 channel->SetCrystalNumber(cryNumber);
424 TChannel::AddChannel(channel);
425 }
426 }
427
428 oldEventNumber = eventNumber;
429
430 if(e % 1000 == 0) {
431 std::cout << std::setw(3) << (100 * e) / nEntries << "% done\r" << std::flush;
432 }
433 } // end of entry loop
434
435 std::cout << "100% done" << std::endl;
436
437 if(verboseLevel > 0) {
438 std::cout << "coeff. " << c << ": done looping over the tree and creating histograms" << std::endl;
439 }
440
441 if(!unknownAngles.empty()) {
442 std::cout << unknownAngles.size() << " unknown angles:" << std::endl;
443 for(auto& angle : unknownAngles) {
444 std::cout << std::setw(10) << angle.first << " found " << std::setw(8) << angle.second << " times" << std::endl;
445 }
446 }
447
448 // create the graphs by getting the bin contents of the 2D matrix
449 for(size_t i = 0; i < hists[c].size(); ++i) {
450 auto counts = hists[c][i]->GetBinContent(hists[c][i]->GetXaxis()->FindBin(gateEnergy), hists[c][i]->GetYaxis()->FindBin(fitEnergy));
451 graph[c].SetPoint(i, angles.Angle(i), counts / angles.Count(angles.Angle(i)));
452 graph[c].SetPointError(i, 0., TMath::Sqrt(counts) / angles.Count(angles.Angle(i)));
453 }
454
455 // write histograms and graph
456 for(auto* hist : hists[c]) {
457 hist->Write();
458 delete hist;
459 }
460
461 graph[c].Write();
462
463 if(verboseLevel > 0) {
464 std::cout << c << ": done writing histograms and graph" << std::endl;
465 }
466 } // end of coeff. loop
467
468 settings.Write();
469
470 output.Close();
471
472 std::cout << "done, wrote results to " << outputFilename << std::endl;
473
474 return 0;
475}
int main(int argc, char **argv)
TH1D * hist
Definition UserFillObj.h:3
void Clear(Option_t *opt="all") override
!
Definition TBgo.cxx:134
void AddFragment(const std::shared_ptr< const TFragment > &frag, TChannel *chan) override
!
Definition TBgo.cxx:153
void SetAddress(unsigned int tmpadd)
Definition TChannel.cxx:557
static TChannel * GetChannel(unsigned int temp_address, bool warn=false)
Definition TChannel.cxx:476
void SetName(const char *tmpName) override
Definition TChannel.cxx:253
void SetCrystalNumber(int tempint)
Definition TChannel.h:156
void SetDetectorNumber(int tempint)
Definition TChannel.h:154
static void AddChannel(TChannel *, Option_t *opt="")
Definition TChannel.cxx:294
void SetDigitizerType(const TPriorityValue< std::string > &tmp)
virtual Short_t GetMultiplicity() const
Definition TDetector.h:70
bool ExcludeDetector(int detector) const
std::set< double >::iterator end() const
void Print(Option_t *="") const override
int NumberOfAngles() const
double Angle(int index) const
int Index(double angle)
static EVerbosity Verbosity()
std::set< double >::iterator begin() const
int Count(double angle)
void Clear(Option_t *opt="all") override
!
Definition TGriffin.cxx:164
UShort_t GetNSuppressedAddbackFrags(const size_t &idx)
Definition TGriffin.cxx:593
TGriffinHit * GetSuppressedAddbackHit(const int &i)
Definition TGriffin.cxx:538
Short_t GetSuppressedMultiplicity(const TBgo *bgo)
Definition TGriffin.cxx:501
Short_t GetSuppressedAddbackMultiplicity(const TBgo *bgo)
Definition TGriffin.cxx:554
void AddFragment(const std::shared_ptr< const TFragment > &, TChannel *) override
!
Definition TGriffin.cxx:298
TGriffinHit * GetSuppressedHit(const int &i)
!
Definition TGriffin.cxx:485
std::string GetString(const std::string &parameter, bool quiet=false) const
std::vector< std::string > GetStringVector(const std::string &parameter, bool quiet=false) const
bool GetBool(const std::string &parameter, bool quiet=false) const
std::vector< int > GetIntVector(const std::string &parameter, bool quiet=false) const
int GetInt(const std::string &parameter, bool quiet=false) const
double GetDouble(const std::string &parameter, bool quiet=false) const
bool ReadSettings(const std::string &settingsFile)