REST-for-Physics  v2.3
Rare Event Searches ToolKit for Physics
TRestGeant4NeutronTaggingProcess.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 
87 
88 #include "TRestGeant4NeutronTaggingProcess.h"
89 
90 using namespace std;
91 
93 
94 TRestGeant4NeutronTaggingProcess::TRestGeant4NeutronTaggingProcess() { Initialize(); }
95 
96 TRestGeant4NeutronTaggingProcess::TRestGeant4NeutronTaggingProcess(const char* configFilename) {
97  Initialize();
98  if (LoadConfigFromFile(configFilename)) LoadDefaultConfig();
99 }
100 
105 
109 void TRestGeant4NeutronTaggingProcess::LoadDefaultConfig() { SetTitle("Default config"); }
110 
116  fG4Metadata = nullptr;
117 
118  SetSectionName(this->ClassName());
119  SetLibraryVersion(LIBRARY_VERSION);
120 
121  fInputG4Event = nullptr;
122  fOutputG4Event = new TRestGeant4Event();
123 }
124 
137 void TRestGeant4NeutronTaggingProcess::LoadConfig(const string& configFilename, const string& name) {
138  if (LoadConfigFromFile(configFilename, name)) LoadDefaultConfig();
139 }
140 
145  fG4Metadata = GetMetadata<TRestGeant4Metadata>();
146 
147  // CAREFUL THIS METHOD IS CALLED TWICE!
148  // we need to reset these variables to zero
149  Reset();
150  // get "veto" volumes
151  if (fVetoVolumeIds.empty()) {
152  for (unsigned int i = 0; i < fG4Metadata->GetNumberOfActiveVolumes(); i++) {
153  string volume_name = (string)fG4Metadata->GetActiveVolumeName(i);
154  volume_name = TrimAndLower(volume_name);
155  if (volume_name.find(TrimAndLower(fVetoKeyword)) != string::npos) {
156  fVetoVolumeIds.push_back(i);
157  } else if (volume_name.find(TrimAndLower(fCaptureKeyword)) != string::npos) {
158  fCaptureVolumeIds.push_back(i);
159  } else if (volume_name.find(TrimAndLower(fShieldingKeyword)) != string::npos) {
160  fShieldingVolumeIds.push_back(i);
161  }
162  }
163 
164  // veto groups (fill fVetoGroupVolumeNames)
165  for (unsigned int i = 0; i < fVetoGroupKeywords.size(); i++) {
166  string veto_group_keyword = TrimAndLower(fVetoGroupKeywords[i]);
167  fVetoGroupVolumeNames[veto_group_keyword] = std::vector<string>{};
168  for (int& id : fVetoVolumeIds) {
169  string volume_name = (string)fG4Metadata->GetActiveVolumeName(id);
170  volume_name = TrimAndLower(volume_name);
171  if (volume_name.find(veto_group_keyword) != string::npos) {
172  fVetoGroupVolumeNames[veto_group_keyword].push_back(
173  (string)fG4Metadata->GetActiveVolumeName(id));
174  }
175  }
176  }
177  }
178 
179  PrintMetadata();
180 }
181 
182 void TRestGeant4NeutronTaggingProcess::Reset() {
183  /*
184  fVetoVolumeIds.clear();
185  fVetoGroupVolumeNames.clear();
186  fCaptureVolumeIds.clear();
187  */
188  fNeutronsCapturedNumber = 0;
189  fNeutronsCapturedPosX.clear();
190  fNeutronsCapturedPosY.clear();
191  fNeutronsCapturedPosZ.clear();
192  fNeutronsCapturedIsCaptureVolume.clear();
193  fNeutronsCapturedProductionE.clear();
194  fNeutronsCapturedEDepByNeutron.clear();
195  fNeutronsCapturedEDepByNeutronAndChildren.clear();
196  fNeutronsCapturedEDepByNeutronInVeto.clear();
197  fNeutronsCapturedEDepByNeutronAndChildrenInVeto.clear();
198  fNeutronsCapturedEDepByNeutronAndChildrenInVetoMax.clear();
199  fNeutronsCapturedEDepByNeutronAndChildrenInVetoMin.clear();
200 
201  fGammasNeutronCaptureNumber = 0;
202  fGammasNeutronCapturePosX.clear();
203  fGammasNeutronCapturePosY.clear();
204  fGammasNeutronCapturePosZ.clear();
205  fGammasNeutronCaptureIsCaptureVolume.clear();
206  fGammasNeutronCaptureProductionE.clear();
207 
208  fSecondaryNeutronsShieldingNumber = 0;
209  fSecondaryNeutronsShieldingExitPosX.clear();
210  fSecondaryNeutronsShieldingExitPosY.clear();
211  fSecondaryNeutronsShieldingExitPosZ.clear();
212  fSecondaryNeutronsShieldingIsCaptured.clear();
213  fSecondaryNeutronsShieldingIsCapturedInCaptureVolume.clear();
214  fSecondaryNeutronsShieldingProductionE.clear();
215  fSecondaryNeutronsShieldingExitE.clear();
216 }
221  fInputG4Event = (TRestGeant4Event*)inputEvent;
222  *fOutputG4Event = *((TRestGeant4Event*)inputEvent);
223 
224  Reset();
225  std::map<string, Double_t> volume_energy_map;
226 
227  for (unsigned int i = 0; i < fVetoVolumeIds.size(); i++) {
228  int id = fVetoVolumeIds[i];
229  string volume_name = (string)fG4Metadata->GetActiveVolumeName(id);
230 
231  Double_t energy = fOutputG4Event->GetEnergyInVolume(volume_name);
232  volume_energy_map[volume_name] = energy;
233  }
234 
235  Double_t energy_veto_max = 0;
236  for (const auto& pair : volume_energy_map) {
237  Double_t veto_energy = pair.second;
238  SetObservableValue(pair.first + "VolumeEDep", veto_energy);
239  if (veto_energy > energy_veto_max) {
240  energy_veto_max = veto_energy;
241  };
242  }
243  SetObservableValue("vetoAllEVetoMax", energy_veto_max);
244 
245  // veto groups
246  for (const auto& pair : fVetoGroupVolumeNames) {
247  Double_t energy_veto_max_group = 0;
248  for (unsigned int i = 0; i < pair.second.size(); i++) {
249  string volume_name = pair.second[i];
250  Double_t veto_energy = volume_energy_map[volume_name];
251  if (veto_energy > energy_veto_max_group) {
252  energy_veto_max_group = veto_energy;
253  };
254  }
255  // convert to Upper + lower case (VetoGroupTopEVetoMax, ...)
256  string group_name;
257  for (auto it = pair.first.cbegin(); it != pair.first.cend(); ++it) {
258  if (it == pair.first.cbegin()) {
259  group_name += std::toupper(*it);
260  } else {
261  group_name += std::tolower(*it);
262  }
263  }
264  SetObservableValue("vetoGroup" + group_name + "EVetoMax", energy_veto_max_group);
265  }
266 
267  //
268 
269  for (const auto& quenching_factor : fQuenchingFactors) {
270  string quenching_factor_string = std::to_string(quenching_factor);
271  // replace "." in string by "_" because its gives very strange problems
272  quenching_factor_string =
273  quenching_factor_string.replace(quenching_factor_string.find("."), sizeof(".") - 1, "_");
274  volume_energy_map.clear();
275  for (unsigned int i = 0; i < fOutputG4Event->GetNumberOfTracks(); i++) {
276  const auto& track = fOutputG4Event->GetTrack(i);
277  string particle_name = (string)track.GetParticleName();
278  for (const auto& id : fVetoVolumeIds) {
279  string volume_name = (string)fG4Metadata->GetActiveVolumeName(id);
280 
281  if (particle_name == "e-" || particle_name == "e+" || particle_name == "gamma") {
282  // no quenching factor
283  volume_energy_map[volume_name] += track.GetEnergyInVolume(id);
284  } else {
285  // apply quenching factor
286  volume_energy_map[volume_name] += quenching_factor * track.GetEnergyInVolume(id);
287  }
288  }
289  }
290 
291  Double_t energy_veto_max = 0;
292  for (const auto& pair : volume_energy_map) {
293  Double_t veto_energy = pair.second;
294  SetObservableValue(pair.first + "VolumeEDep" + "Qf" + quenching_factor_string, veto_energy);
295  if (veto_energy > energy_veto_max) {
296  energy_veto_max = veto_energy;
297  };
298  }
299  SetObservableValue(string("vetoAllEVetoMax") + "Qf" + quenching_factor_string, energy_veto_max);
300 
301  // veto groups
302  for (const auto& pair : fVetoGroupVolumeNames) {
303  Double_t energy_veto_max_group = 0;
304  for (unsigned int i = 0; i < pair.second.size(); i++) {
305  string volume_name = pair.second[i];
306  Double_t veto_energy = volume_energy_map[volume_name];
307  if (veto_energy > energy_veto_max_group) {
308  energy_veto_max_group = veto_energy;
309  };
310  }
311  // convert to Upper + lower case (VetoGroupTopEVetoMax, ...)
312  string group_name;
313  for (auto it = pair.first.cbegin(); it != pair.first.cend(); ++it) {
314  if (it == pair.first.cbegin()) {
315  group_name += std::toupper(*it);
316  } else {
317  group_name += std::tolower(*it);
318  }
319  }
320  SetObservableValue("vetoGroup" + group_name + "EVetoMax" + "Qf" + quenching_factor_string,
321  energy_veto_max_group);
322  }
323  }
324 
325  std::set<int> neutronsCaptured = {};
326  for (unsigned int i = 0; i < fOutputG4Event->GetNumberOfTracks(); i++) {
327  auto track = fOutputG4Event->GetTrack(i);
328  string particle_name = (string)track.GetParticleName();
329  if (particle_name == "neutron") {
330  auto hits = track.GetHits();
331  for (unsigned int j = 0; j < hits.GetNumberOfHits(); j++) {
332  string process_name = (string)track.GetProcessName(hits.GetProcess(j));
333  if (process_name == "nCapture") {
334  // << "Neutron capture!!!!!! " << particle_name << "trackId " << track.GetTrackID()
335  // << " hit " << j << endl;
336  // track.PrintTrack();
337  // hits.PrintHits(j + 1);
338 
339  neutronsCaptured.insert(track.GetTrackID());
340 
341  fNeutronsCapturedNumber += 1;
342  fNeutronsCapturedPosX.push_back(hits.GetX(j));
343  fNeutronsCapturedPosY.push_back(hits.GetY(j));
344  fNeutronsCapturedPosZ.push_back(hits.GetZ(j));
345 
346  Int_t volumeId = hits.GetVolumeId(j);
347  Int_t isCaptureVolume = 0;
348  for (const auto& id : fCaptureVolumeIds) {
349  if (volumeId == id) {
350  isCaptureVolume = 1;
351  continue;
352  }
353  }
354  fNeutronsCapturedIsCaptureVolume.push_back(isCaptureVolume);
355  fNeutronsCapturedProductionE.push_back(track.GetInitialKineticEnergy());
356 
357  // get energy deposited by neutron that undergoes capture and children
358  double neutronsCapturedEDepByNeutron = 0;
359  double neutronsCapturedEDepByNeutronAndChildren = 0;
360  double neutronsCapturedEDepByNeutronInVeto = 0;
361  double neutronsCapturedEDepByNeutronAndChildrenInVeto = 0;
362 
363  std::set<int> parents = {track.GetTrackID()};
364  std::map<int, double> energyInVeto;
365  for (unsigned int child = 0; child < fOutputG4Event->GetNumberOfTracks(); child++) {
366  const auto& trackChild = fOutputG4Event->GetTrack(child);
367  if ((parents.count(trackChild.GetParentID()) > 0) ||
368  parents.count(trackChild.GetTrackID()) > 0) {
369  // track or parent is in list of tracks, we add to list and add energy
370  parents.insert(trackChild.GetTrackID());
371  neutronsCapturedEDepByNeutronAndChildren += trackChild.GetTotalEnergy();
372  if (trackChild.GetTrackID() == track.GetTrackID()) {
373  neutronsCapturedEDepByNeutron += trackChild.GetTotalEnergy();
374  }
375  for (const auto& vetoId : fVetoVolumeIds) {
376  neutronsCapturedEDepByNeutronAndChildrenInVeto +=
377  trackChild.GetEnergyInVolume(vetoId);
378  energyInVeto[vetoId] += trackChild.GetEnergyInVolume(vetoId);
379  if (trackChild.GetTrackID() == track.GetTrackID()) {
380  neutronsCapturedEDepByNeutronInVeto +=
381  trackChild.GetEnergyInVolume(vetoId);
382  }
383  }
384  }
385  }
386 
387  fNeutronsCapturedEDepByNeutron.push_back(neutronsCapturedEDepByNeutron);
388  fNeutronsCapturedEDepByNeutronAndChildren.push_back(
389  neutronsCapturedEDepByNeutronAndChildren);
390  fNeutronsCapturedEDepByNeutronInVeto.push_back(neutronsCapturedEDepByNeutronInVeto);
391  fNeutronsCapturedEDepByNeutronAndChildrenInVeto.push_back(
392  neutronsCapturedEDepByNeutronAndChildrenInVeto);
393 
394  // get max and min energy in each veto (to compare with energy in ALL vetoes)
395  double energyMaxVeto = 0;
396  double energyMinVeto = -1;
397  for (const auto& pair : energyInVeto) {
398  auto E = pair.second;
399  if (E > energyMaxVeto) energyMaxVeto = E;
400  if (E < energyMaxVeto || energyMinVeto == -1) energyMinVeto = E;
401  }
402 
403  fNeutronsCapturedEDepByNeutronAndChildrenInVetoMax.push_back(energyMaxVeto);
404  fNeutronsCapturedEDepByNeutronAndChildrenInVetoMin.push_back(energyMinVeto);
405  }
406  }
407  }
408  }
409 
410  SetObservableValue("neutronsCapturedNumber", fNeutronsCapturedNumber);
411  SetObservableValue("neutronsCapturedPosX", fNeutronsCapturedPosX);
412  SetObservableValue("neutronsCapturedPosY", fNeutronsCapturedPosY);
413  SetObservableValue("neutronsCapturedPosZ", fNeutronsCapturedPosZ);
414  SetObservableValue("neutronsCapturedIsCaptureVolume", fNeutronsCapturedIsCaptureVolume);
415  SetObservableValue("neutronsCapturedProductionE", fNeutronsCapturedProductionE);
416  SetObservableValue("neutronsCapturedEDepByNeutron", fNeutronsCapturedEDepByNeutron);
417  SetObservableValue("neutronsCapturedEDepByNeutronAndChildren", fNeutronsCapturedEDepByNeutronAndChildren);
418  SetObservableValue("neutronsCapturedEDepByNeutronInVeto", fNeutronsCapturedEDepByNeutronInVeto);
419  SetObservableValue("neutronsCapturedEDepByNeutronAndChildrenInVeto",
420  fNeutronsCapturedEDepByNeutronAndChildrenInVeto);
421  SetObservableValue("neutronsCapturedEDepByNeutronAndChildrenInVetoMax",
422  fNeutronsCapturedEDepByNeutronAndChildrenInVetoMax);
423  SetObservableValue("neutronsCapturedEDepByNeutronAndChildrenInVetoMin",
424  fNeutronsCapturedEDepByNeutronAndChildrenInVetoMin);
425  for (unsigned int i = 0; i < fOutputG4Event->GetNumberOfTracks(); i++) {
426  auto track = fOutputG4Event->GetTrack(i);
427  string particle_name = (string)track.GetParticleName();
428  if (particle_name == "gamma") {
429  // check if gamma is child of captured neutron
430  Int_t parent = track.GetParentID();
431  if (neutronsCaptured.count(parent) > 0) {
432  const auto& hits = track.GetHits();
433 
434  fGammasNeutronCaptureNumber += 1;
435  fGammasNeutronCapturePosX.push_back(hits.GetX(0));
436  fGammasNeutronCapturePosY.push_back(hits.GetY(0));
437  fGammasNeutronCapturePosZ.push_back(hits.GetZ(0));
438 
439  Int_t volumeId = hits.GetVolumeId(0);
440  Int_t isCaptureVolume = 0;
441  for (const auto& id : fCaptureVolumeIds) {
442  if (volumeId == id) {
443  isCaptureVolume = 1;
444  continue;
445  }
446  }
447  fGammasNeutronCaptureIsCaptureVolume.push_back(isCaptureVolume);
448  fGammasNeutronCaptureProductionE.push_back(track.GetInitialKineticEnergy());
449 
450  // cout << "gamma capture" << endl;
451 
452  // hits.PrintHits(1);
453  }
454  }
455  }
456 
457  SetObservableValue("gammasNeutronCaptureNumber", fGammasNeutronCaptureNumber);
458  SetObservableValue("gammasNeutronCapturePosX", fGammasNeutronCapturePosX);
459  SetObservableValue("gammasNeutronCapturePosY", fGammasNeutronCapturePosY);
460  SetObservableValue("gammasNeutronCapturePosZ", fGammasNeutronCapturePosZ);
461  SetObservableValue("gammasNeutronCaptureIsCaptureVolume", fGammasNeutronCaptureIsCaptureVolume);
462  SetObservableValue("gammasNeutronCaptureProductionE", fGammasNeutronCaptureProductionE);
463 
464  std::set<int> secondaryNeutrons = {}; // avoid counting twice
465  for (unsigned int i = 0; i < fOutputG4Event->GetNumberOfTracks(); i++) {
466  auto track = fOutputG4Event->GetTrack(i);
467  string particle_name = (string)track.GetParticleName();
468  if (particle_name == "neutron" && track.GetParentID() != 0) { // not consider primary
469  // check if neutron exits shielding
470  auto hits = track.GetHits();
471  for (unsigned int j = 0; j < hits.GetNumberOfHits(); j++) {
472  string process_name = (string)track.GetProcessName(hits.GetProcess(j));
473  if (process_name == "Transportation") {
474  for (const auto& id : fShieldingVolumeIds) {
475  if (hits.GetVolumeId(j) == id) {
476  // transportation and shielding == exits shielding
477  if (secondaryNeutrons.count(track.GetTrackID()) == 0) {
478  // first time adding this secondary neutron
479  secondaryNeutrons.insert(track.GetTrackID());
480  } else {
481  continue;
482  }
483  fSecondaryNeutronsShieldingNumber += 1;
484  fSecondaryNeutronsShieldingExitPosX.push_back(hits.GetX(j));
485  fSecondaryNeutronsShieldingExitPosY.push_back(hits.GetY(j));
486  fSecondaryNeutronsShieldingExitPosZ.push_back(hits.GetZ(j));
487 
488  Int_t volumeId = hits.GetVolumeId(j);
489  Int_t isCaptureVolume = 0;
490  for (const auto& id : fCaptureVolumeIds) {
491  if (volumeId == id) {
492  isCaptureVolume = 1;
493  continue;
494  }
495  }
496  Int_t isCaptured = 0;
497  if (neutronsCaptured.count(track.GetTrackID()) > 0) {
498  isCaptured = 1;
499  }
500  fSecondaryNeutronsShieldingIsCaptured.push_back(isCaptured);
501  if (isCaptured)
502  fSecondaryNeutronsShieldingIsCapturedInCaptureVolume.push_back(
503  isCaptureVolume);
504  else {
505  fSecondaryNeutronsShieldingIsCapturedInCaptureVolume.push_back(0);
506  }
507 
508  fSecondaryNeutronsShieldingProductionE.push_back(track.GetInitialKineticEnergy());
509  fSecondaryNeutronsShieldingExitE.push_back(hits.GetKineticEnergy(j));
510  }
511  }
512  }
513  }
514  }
515  }
516 
517  SetObservableValue("secondaryNeutronsShieldingNumber", fSecondaryNeutronsShieldingNumber);
518  SetObservableValue("secondaryNeutronsShieldingExitPosX", fSecondaryNeutronsShieldingExitPosX);
519  SetObservableValue("secondaryNeutronsShieldingExitPosY", fSecondaryNeutronsShieldingExitPosY);
520  SetObservableValue("secondaryNeutronsShieldingExitPosZ", fSecondaryNeutronsShieldingExitPosZ);
521  SetObservableValue("secondaryNeutronsShieldingIsCaptured", fSecondaryNeutronsShieldingIsCaptured);
522  SetObservableValue("secondaryNeutronsShieldingIsCapturedInCaptureVolume",
523  fSecondaryNeutronsShieldingIsCapturedInCaptureVolume);
524  SetObservableValue("secondaryNeutronsShieldingProductionE", fSecondaryNeutronsShieldingProductionE);
525  SetObservableValue("secondaryNeutronsShieldingExitE", fSecondaryNeutronsShieldingExitE);
526 
527  return fOutputG4Event;
528 }
529 
535  // Function to be executed once at the end of the process
536  // (after all events have been processed)
537 
538  // Start by calling the EndProcess function of the abstract class.
539  // Comment this if you don't want it.
540  // TRestEventProcess::EndProcess();
541 }
542 
548  // word to identify active volume as veto (default = "veto" e.g. "vetoTop")
549  string veto_keyword = GetParameter("vetoKeyword", "veto");
550  fVetoKeyword = TrimAndLower(veto_keyword);
551  // comma separated tags: "top, bottom, ..."
552  string veto_group_keywords = GetParameter("vetoGroupKeywords", "");
553  stringstream ss(veto_group_keywords);
554  while (ss.good()) {
555  string substr;
556  getline(ss, substr, ',');
557  fVetoGroupKeywords.push_back(TrimAndLower(substr));
558  }
559 
560  // word to identify active volume as capture sheet (cadmium, default = "sheet" e.g.
561  // "scintillatorSheetTop1of4")
562  string capture_keyword = GetParameter("captureKeyword", "sheet");
563  fCaptureKeyword = TrimAndLower(capture_keyword);
564 
565  // word to identify active volume as shielding
566 
567  string shielding_keyword = GetParameter("shieldingKeyword", "shielding");
568  fShieldingKeyword = TrimAndLower(shielding_keyword);
569 
570  // comma separated quenching factors: "0.15, 1.00, ..."
571  string quenching_factors = GetParameter("vetoQuenchingFactors", "-1");
572  stringstream ss_qf(quenching_factors);
573  while (ss_qf.good()) {
574  string substr;
575  getline(ss_qf, substr, ',');
576  substr = TrimAndLower(substr);
577  Float_t quenching_factor = (Float_t)std::atof(substr.c_str());
578  if (quenching_factor > 1 || quenching_factor < 0) {
579  cout << "ERROR: quenching factor must be between 0 and 1" << endl;
580  continue;
581  }
582  fQuenchingFactors.push_back(quenching_factor);
583  }
584 }
A base class for any REST event.
Definition: TRestEvent.h:38
An event class to store geant4 generated event information.
void InitProcess() override
Process initialization.
void Initialize() override
Function to initialize input/output event members and define the section name.
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 InitFromConfigFile() override
Function to read input parameters from the RML TRestGeant4NeutronTaggingProcess metadata section.
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.
std::string TrimAndLower(std::string s)
It trims and lowers the string.