REST-for-Physics  v2.3
Rare Event Searches ToolKit for Physics
TRestGeant4VetoAnalysisProcess.cxx
1/*************************************************************************
2 * This file is part of the REST software framework. *
3 * *
4 * Copyright (C) 2020 GIFNA/TREX (University of Zaragoza) *
5 * For more information see http://gifna.unizar.es/trex *
6 * *
7 * REST is free software: you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation, either version 3 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * REST is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have a copy of the GNU General Public License along with *
18 * REST in $REST_PATH/LICENSE. *
19 * If not, see http://www.gnu.org/licenses/. *
20 * For the list of contributors see $REST_PATH/CREDITS. *
21 *************************************************************************/
22
65
66#include "TRestGeant4VetoAnalysisProcess.h"
67
68#include <TObjArray.h>
69#include <TObjString.h>
70#include <TString.h>
71
72#include <iostream>
73#include <unordered_map>
74
75using namespace std;
76
78
79int findMostFrequent(const vector<int>& nums) {
80 if (nums.empty()) {
81 return 0;
82 }
83
84 unordered_map<int, int> freqMap;
85
86 // Count the frequency of each element
87 for (int num : nums) {
88 freqMap[num]++;
89 }
90
91 int mostFrequent = nums[0];
92 int maxFrequency = 0;
93
94 // Find the most frequent element
95 for (const auto& entry : freqMap) {
96 if (entry.second > maxFrequency) {
97 mostFrequent = entry.first;
98 maxFrequency = entry.second;
99 }
100 }
101
102 return mostFrequent;
103}
104
105Veto TRestGeant4VetoAnalysisProcess::GetVetoFromString(const string& input) {
106 // example input:
107 // VetoSystem_vetoSystemEast_vetoLayerEast2_assembly-13.veto2_scintillatorVolume-1500.0mm-f1a5df68
108
109 Veto veto;
110 veto.name = input;
111
112 TObjArray* parts = TString(input).Tokenize("_");
113
114 if (parts->GetEntries() >= 5) {
115 TString group = ((TObjString*)parts->At(1))->GetString();
116 // remove leading "vetoSystem" from group if present
117 if (group.Index("vetoSystem") == 0) {
118 group = group(10, group.Length() - 10);
119 }
120
121 TString layer = ((TObjString*)parts->At(2))->GetString();
122 // layer is last character of layer string
123 layer = layer(layer.Length() - 1, 1);
124
125 TString numberAndRest = ((TObjString*)parts->At(parts->GetEntries() - 2))->GetString();
126 Ssiz_t vetoPos = numberAndRest.Index("veto");
127 if (vetoPos != kNPOS) {
128 TString number = numberAndRest(vetoPos + 4, numberAndRest.Length() - vetoPos - 4);
129
130 TString lengthAndRest = ((TObjString*)parts->At(parts->GetEntries() - 1))->GetString();
131 Ssiz_t mmPos = lengthAndRest.Index("mm");
132 if (mmPos != kNPOS) {
133 TString length = lengthAndRest(0, mmPos);
134 // if "scintillatorVolume" is present, remove it
135 if (length.Index("scintillatorVolume") == 0) {
136 length = length(19, length.Length() - 19);
137 }
138
139 veto.group = group.Data();
140 veto.layer = layer.Atoi();
141 veto.number = number.Atoi();
142 veto.length = length.Atof();
143
144 } else {
145 cout << "No match found." << endl;
146 }
147 } else {
148 cout << "No match found." << endl;
149 }
150 } else {
151 cout << "No match found." << endl;
152 }
153
154 delete parts;
155
156 veto.alias = veto.group + "_L" + veto.layer + "_N" + veto.number;
157 return veto;
158}
159
160TRestGeant4VetoAnalysisProcess::TRestGeant4VetoAnalysisProcess() { Initialize(); }
161
162TRestGeant4VetoAnalysisProcess::TRestGeant4VetoAnalysisProcess(const char* configFilename) {
164 if (LoadConfigFromFile(configFilename)) {
166 }
167}
168
169TRestGeant4VetoAnalysisProcess::~TRestGeant4VetoAnalysisProcess() { delete fOutputEvent; }
170
174void TRestGeant4VetoAnalysisProcess::LoadDefaultConfig() { SetTitle("Default config"); }
175
181 SetSectionName(this->ClassName());
182 SetLibraryVersion(LIBRARY_VERSION);
183
184 fOutputEvent = new TRestGeant4Event();
185}
186
199void TRestGeant4VetoAnalysisProcess::LoadConfig(const string& configFilename, const string& name) {
200 if (LoadConfigFromFile(configFilename, name)) {
202 }
203}
204
209 // CAREFUL THIS METHOD IS CALLED TWICE!
210 fVetoVolumes.clear();
211
212 if (fGeant4Metadata == nullptr) {
213 // maybe it was manually initialized
214 fGeant4Metadata = GetMetadata<TRestGeant4Metadata>();
215 }
216 if (fGeant4Metadata == nullptr) {
217 cerr << "TRestGeant4VetoAnalysisProcess::InitProcess: Geant4 metadata not found" << endl;
218 exit(1);
219 }
220
221 RESTDebug << "Expression: " << fVetoVolumesExpression << RESTendl;
222 const auto& geometryInfo = fGeant4Metadata->GetGeant4GeometryInfo();
223
224 auto vetoVolumes = geometryInfo.GetAllPhysicalVolumesMatchingExpression(fVetoVolumesExpression);
225 if (vetoVolumes.empty()) {
226 const auto logicalVolumes =
227 geometryInfo.GetAllLogicalVolumesMatchingExpression(fVetoVolumesExpression);
228 for (const auto& logicalVolume : logicalVolumes) {
229 for (const auto& physicalVolume : geometryInfo.GetAllPhysicalVolumesFromLogical(logicalVolume)) {
230 const string name =
231 geometryInfo.GetAlternativeNameFromGeant4PhysicalName(physicalVolume).Data();
232 Veto veto = GetVetoFromString(name);
233 veto.position = geometryInfo.GetPosition(name);
234 fVetoVolumes.push_back(veto);
235 }
236 }
237 }
238
239 // PrintMetadata();
240}
241
246 fInputEvent = (TRestGeant4Event*)inputEvent;
247 *fOutputEvent = *((TRestGeant4Event*)inputEvent);
248
249 map<string, double> vetoEnergyMap;
250 map<string, double> vetoGroupEnergyMap;
251 map<pair<string, int>, double> vetoGroupLayerEnergyMap;
252 double totalVetoEnergy = 0;
253
254 for (const auto& veto : fVetoVolumes) {
255 const double energy = fInputEvent->GetEnergyInVolume(veto.name);
256
257 totalVetoEnergy += energy;
258 vetoEnergyMap[veto.name] = energy;
259 vetoGroupEnergyMap[veto.group] += energy;
260 vetoGroupLayerEnergyMap[make_pair(veto.group, veto.layer)] += energy;
261
262 SetObservableValue("EnergyVeto_" + veto.alias, energy);
263 }
264
265 for (const auto& [group, energy] : vetoGroupEnergyMap) {
266 SetObservableValue("EnergyGroup_" + group, energy);
267 }
268
269 for (const auto& [groupLayer, energy] : vetoGroupLayerEnergyMap) {
270 SetObservableValue("EnergyGroupLayer_" + groupLayer.first + "_" + to_string(groupLayer.second),
271 energy);
272 }
273
274 SetObservableValue("EnergyTotal", totalVetoEnergy);
275
276 // compute max energy
277 double maxEnergy = 0;
278 for (const auto& [name, energy] : vetoEnergyMap) {
279 if (energy > maxEnergy) {
280 maxEnergy = energy;
281 }
282 }
283 SetObservableValue("EnergyMax", maxEnergy);
284
285 // compute max energy for each group
286 map<string, double> vetoGroupMaxEnergyMap;
287 for (const auto& [name, energy] : vetoEnergyMap) {
288 const auto veto = GetVetoFromString(name);
289 if (vetoGroupMaxEnergyMap[veto.group] < energy) {
290 vetoGroupMaxEnergyMap[veto.group] = energy;
291 }
292 }
293 for (const auto& [group, energy] : vetoGroupMaxEnergyMap) {
294 SetObservableValue("EnergyGroupMax_" + group, energy);
295 }
296
297 // compute max energy for each group layer
298 map<pair<string, int>, double> vetoGroupLayerMaxEnergyMap;
299 for (const auto& [name, energy] : vetoEnergyMap) {
300 const auto veto = GetVetoFromString(name);
301 if (vetoGroupLayerMaxEnergyMap[make_pair(veto.group, veto.layer)] < energy) {
302 vetoGroupLayerMaxEnergyMap[make_pair(veto.group, veto.layer)] = energy;
303 }
304 }
305
306 for (const auto& [groupLayer, energy] : vetoGroupLayerMaxEnergyMap) {
307 SetObservableValue("EnergyGroupLayerMax_" + groupLayer.first + "_" + to_string(groupLayer.second),
308 energy);
309 }
310
311 // compute max energy for each layer (all groups)
312 map<int, double> vetoLayerMaxEnergyMap;
313 for (const auto& [name, energy] : vetoEnergyMap) {
314 const auto veto = GetVetoFromString(name);
315 if (vetoLayerMaxEnergyMap[veto.layer] < energy) {
316 vetoLayerMaxEnergyMap[veto.layer] = energy;
317 }
318 }
319 for (const auto& [layer, energy] : vetoLayerMaxEnergyMap) {
320 SetObservableValue("EnergyLayerMax_" + to_string(layer), energy);
321 }
322
323 // compute neutron capture observables
324 int nCaptures = 0;
325 int nCapturesInCaptureVolumes = 0;
326 int nCapturesInVetoVolumes = 0;
327
328 vector<float> nCapturesInCaptureVolumesTimes;
329 vector<vector<float>> nCapturesInCaptureVolumesChildGammaEnergies;
330 // for each child gamma, how much energy was deposited in all vetoes
331 vector<float> nCapturesInCaptureVolumesChildGammasEnergyInVetos;
332 vector<vector<float>> nCapturesInCaptureVolumesEnergyInVetoesForCapture;
333
334 set<int> nCapturesInCaptureVolumesNeutronTrackIds;
335
336 vector<float> nCapturesInCaptureVolumesPositionX;
337 vector<float> nCapturesInCaptureVolumesPositionY;
338 vector<float> nCapturesInCaptureVolumesPositionZ;
339
340 for (const auto& track : fInputEvent->GetTracks()) {
341 if (track.GetParticleName() == "neutron") {
342 const auto hits = track.GetHits();
343 for (size_t hitIndex = 0; hitIndex < hits.GetNumberOfHits(); hitIndex++) {
344 const auto processName = hits.GetProcessName(hitIndex);
345 if (processName != "nCapture") {
346 continue;
347 }
348 nCaptures++;
349 const string volumeName = hits.GetVolumeName(hitIndex).Data();
350 const double time = hits.GetTime(hitIndex);
351
352 if (volumeName.find("captureLayerVolume") != string::npos) {
353 nCapturesInCaptureVolumes++;
354 nCapturesInCaptureVolumesNeutronTrackIds.insert(track.GetTrackID());
355 nCapturesInCaptureVolumesTimes.push_back(time);
356 const TVector3& position = hits.GetPosition(hitIndex);
357 nCapturesInCaptureVolumesPositionX.push_back(position.X());
358 nCapturesInCaptureVolumesPositionY.push_back(position.Y());
359 nCapturesInCaptureVolumesPositionZ.push_back(position.Z());
360 vector<float> childrenEnergy;
361 const auto children = track.GetChildrenTracks();
362 for (const auto& child : children) {
363 if (child->GetParticleName() != "gamma") {
364 continue;
365 }
366 if (child->GetCreatorProcess() != "nCapture") {
367 continue;
368 }
369 childrenEnergy.push_back(child->GetInitialKineticEnergy());
370 double energyInVeto = 0;
371 for (const auto& veto : fVetoVolumes) {
372 energyInVeto += child->GetEnergyInVolume(veto.name, true);
373 }
374 nCapturesInCaptureVolumesChildGammasEnergyInVetos.push_back(energyInVeto);
375 }
376 nCapturesInCaptureVolumesChildGammaEnergies.push_back(childrenEnergy);
377
378 vector<float> energyInVetoesForCapture;
379 for (const auto& veto : fVetoVolumes) {
380 const double energyInVeto = track.GetEnergyInVolume(veto.name, true);
381 if (energyInVeto > 0) { // soft limit of 100 keV
382 energyInVetoesForCapture.push_back(energyInVeto);
383 }
384 }
385 nCapturesInCaptureVolumesEnergyInVetoesForCapture.push_back(energyInVetoesForCapture);
386 }
387 if (volumeName.find("scintillatorVolume") != string::npos) {
388 nCapturesInVetoVolumes++;
389 }
390 }
391 }
392 }
393
394 SetObservableValue("nCapturesInCaptureVolumesPositionX", nCapturesInCaptureVolumesPositionX);
395 SetObservableValue("nCapturesInCaptureVolumesPositionY", nCapturesInCaptureVolumesPositionY);
396 SetObservableValue("nCapturesInCaptureVolumesPositionZ", nCapturesInCaptureVolumesPositionZ);
397
398 vector<float> nCapturesInCaptureVolumesPositionOriginX;
399 vector<float> nCapturesInCaptureVolumesPositionOriginY;
400 vector<float> nCapturesInCaptureVolumesPositionOriginZ;
401
402 // compute observables for neutrons in capture volumes
403 vector<double> nCapturesInCaptureVolumesNeutronInitialEnergy;
404 vector<int> nCapturesInCaptureVolumesNeutronGeneration; // Number of inelastic interactions leading to
405 // neutron (primary neutron has generation 0)
406 for (const auto& neutronCaptureTrackId : nCapturesInCaptureVolumesNeutronTrackIds) {
407 auto track = fInputEvent->GetTrackByID(neutronCaptureTrackId);
408 if (track->GetParticleName() != "neutron") {
409 cerr << "TRestGeant4VetoAnalysisProcess::ProcessEvent: track is not a neutron" << endl;
410 exit(1);
411 }
412
413 int generation = 0;
414 double energy = track->GetInitialKineticEnergy();
415
416 while (track->GetParentTrack() != nullptr) {
417 track = track->GetParentTrack();
418 if (track->GetParticleName() == "neutron") {
419 generation++;
420 }
421 }
422
423 const TVector3& origin = track->GetTrackOrigin();
424 nCapturesInCaptureVolumesPositionOriginX.push_back(origin.X());
425 nCapturesInCaptureVolumesPositionOriginY.push_back(origin.Y());
426 nCapturesInCaptureVolumesPositionOriginZ.push_back(origin.Z());
427
428 nCapturesInCaptureVolumesNeutronInitialEnergy.push_back(energy);
429 nCapturesInCaptureVolumesNeutronGeneration.push_back(generation);
430 }
431
432 SetObservableValue("nCapturesInCaptureVolumesPositionOriginX", nCapturesInCaptureVolumesPositionOriginX);
433 SetObservableValue("nCapturesInCaptureVolumesPositionOriginY", nCapturesInCaptureVolumesPositionOriginY);
434 SetObservableValue("nCapturesInCaptureVolumesPositionOriginZ", nCapturesInCaptureVolumesPositionOriginZ);
435
436 SetObservableValue("nCapturesInCaptureVolumesNeutronInitialEnergy",
437 nCapturesInCaptureVolumesNeutronInitialEnergy);
438 SetObservableValue("nCapturesInCaptureVolumesNeutronGeneration",
439 nCapturesInCaptureVolumesNeutronGeneration);
440
441 // Set capture observables
442 SetObservableValue("nCaptures", nCaptures);
443 SetObservableValue("nCapturesInCaptureVolumes", nCapturesInCaptureVolumes);
444 SetObservableValue("nCapturesInVetoVolumes", nCapturesInVetoVolumes);
445
446 // Set capture time observables
447 SetObservableValue("nCapturesInCaptureVolumesTimes", nCapturesInCaptureVolumesTimes);
448 // cannot insert a vector of vectors, need to flatten it
449 vector<float> nCapturesInCaptureVolumesChildGammaEnergiesFlat;
450 vector<int> nCapturesInCaptureVolumesChildGammaCount;
451 for (const auto& v : nCapturesInCaptureVolumesChildGammaEnergies) {
452 nCapturesInCaptureVolumesChildGammaEnergiesFlat.insert(
453 nCapturesInCaptureVolumesChildGammaEnergiesFlat.end(), v.begin(), v.end());
454 nCapturesInCaptureVolumesChildGammaCount.push_back(v.size());
455 }
456
457 float nCapturesInCaptureVolumesChildGammaCountAverage = 0;
458 for (const auto& v : nCapturesInCaptureVolumesChildGammaCount) {
459 nCapturesInCaptureVolumesChildGammaCountAverage +=
460 float(v) / nCapturesInCaptureVolumesChildGammaCount.size();
461 }
462
463 SetObservableValue("nCapturesInCaptureVolumesChildGammaEnergies",
464 nCapturesInCaptureVolumesChildGammaEnergiesFlat);
465 SetObservableValue("nCapturesInCaptureVolumesChildGammaCount", nCapturesInCaptureVolumesChildGammaCount);
466 SetObservableValue("nCapturesInCaptureVolumesChildGammaCountAverage",
467 nCapturesInCaptureVolumesChildGammaCountAverage);
468 SetObservableValue("nCapturesInCaptureVolumesChildGammaCountMostFrequent",
469 findMostFrequent(nCapturesInCaptureVolumesChildGammaCount));
470 SetObservableValue("nCapturesInCaptureVolumesChildGammaCountTotal",
471 nCapturesInCaptureVolumesChildGammaEnergiesFlat.size());
472
473 SetObservableValue("nCapturesInCaptureVolumesChildGammasEnergyInVetos",
474 nCapturesInCaptureVolumesChildGammasEnergyInVetos);
475
476 auto nCapturesInCaptureVolumesChildGammasEnergyInVetosTotal = 0;
477 for (const auto& energy : nCapturesInCaptureVolumesChildGammasEnergyInVetos) {
478 nCapturesInCaptureVolumesChildGammasEnergyInVetosTotal += energy;
479 }
480
481 SetObservableValue("nCapturesInCaptureVolumesChildGammasEnergyInVetosTotal",
482 nCapturesInCaptureVolumesChildGammasEnergyInVetosTotal);
483
484 SetObservableValue("nCapturesInCaptureVolumesEnergyInVetoesForCapture",
485 nCapturesInCaptureVolumesEnergyInVetoesForCapture);
486
487 const vector<float> energyInVetoesThresholds = {0, 100, 250, 500, 1000, 1500};
488 for (const auto& threshold : energyInVetoesThresholds) {
489 vector<vector<int>> nCapturesInCaptureVolumesEnergyInVetoesForCaptureThreshold;
490 for (const auto& captureForNeutronEnergies : nCapturesInCaptureVolumesEnergyInVetoesForCapture) {
491 int nCapturesInCaptureVolumesVetoesAboveThresholdForCapture = 0;
492 for (const auto& energy : captureForNeutronEnergies) {
493 if (energy > threshold) {
494 nCapturesInCaptureVolumesVetoesAboveThresholdForCapture++;
495 }
496 }
497 nCapturesInCaptureVolumesEnergyInVetoesForCaptureThreshold.push_back(
498 {nCapturesInCaptureVolumesVetoesAboveThresholdForCapture});
499 }
501 "nCapturesInCaptureVolumesVetoesAboveThresholdForCapture" + to_string(int(threshold)) + "keV",
502 nCapturesInCaptureVolumesEnergyInVetoesForCaptureThreshold);
503 }
504 return fOutputEvent;
505}
506
512 // Function to be executed once at the end of the process
513 // (after all events have been processed)
514
515 // Start by calling the EndProcess function of the abstract class.
516 // Comment this if you don't want it.
517 // TRestEventProcess::EndProcess();
518}
519
525 fVetoVolumesExpression = GetParameter("vetoVolumesExpression", fVetoVolumesExpression);
526}
527
530
531 cout << "Number of veto volumes: " << fVetoVolumes.size() << endl;
532 for (const auto& veto : fVetoVolumes) {
533 cout << "Veto: " << veto.name << endl;
534 cout << " - Alias: " << veto.alias << endl;
535 cout << " - Group: " << veto.group << endl;
536 cout << " - Layer: " << veto.layer << endl;
537 cout << " - Number: " << veto.number << endl;
538 cout << " - Position: (" << veto.position.x() << ", " << veto.position.y() << ", "
539 << veto.position.z() << ")" << endl;
540 cout << " - Length: " << veto.length << endl;
541 }
542}
void BeginPrintProcess()
[name, cut range]
void SetObservableValue(const std::string &name, const T &value)
Set observable value for AnalysisTree.
A base class for any REST event.
Definition: TRestEvent.h:38
An event class to store geant4 generated event information.
const TRestGeant4GeometryInfo & GetGeant4GeometryInfo() const
Returns an immutable reference to the geometry info.
void LoadConfig(const std::string &configFilename, const std::string &name="")
Function to load the configuration from an external configuration file.
TRestEvent * ProcessEvent(TRestEvent *inputEvent) override
The main processing event function.
void PrintMetadata() override
Implemented it in the derived metadata class to print out specific metadata information.
void LoadDefaultConfig()
Function to load the default config in absence of RML input.
void EndProcess() override
Function to include required actions after all events have been processed.
void InitFromConfigFile() override
Function to read input parameters from the RML TRestGeant4VetoAnalysisProcess metadata section.
void Initialize() override
Function to initialize input/output event members and define the section name.
void InitProcess() override
Process initialization.
endl_t RESTendl
Termination flag object for TRestStringOutput.
Int_t LoadConfigFromFile(const std::string &configFilename, const std::string &sectionName="")
Give the file name, find out the corresponding section. Then call the main starter.
void SetLibraryVersion(TString version)
Set the library version of this metadata class.
void SetSectionName(std::string sName)
set the section name, clear the section content
std::string GetParameter(std::string parName, TiXmlElement *e, TString defaultValue=PARAMETER_NOT_FOUND_STR)
Returns the value for the parameter named parName in the given section.