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