Skip to content

Commit 9ba07e6

Browse files
authored
Merge pull request #101 from rest-for-physics/lobis-quenching
Add process to quench energy deposits
2 parents 714c067 + cb7240c commit 9ba07e6

9 files changed

+503
-8
lines changed

inc/TRestGeant4Hits.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ class TRestGeant4Hits : public TRestHits {
7070

7171
size_t GetNumberOfHitsInVolume(Int_t volumeID) const;
7272

73+
// non-const methods (should only be used on the analysis, carefully)
74+
std::vector<Float_t>& GetEnergyRef() { return fEnergy; }
75+
7376
// Constructor
7477
TRestGeant4Hits();
7578
// Destructor

inc/TRestGeant4QuenchingProcess.h

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*************************************************************************
2+
* This file is part of the REST software framework. *
3+
* *
4+
* Copyright (C) 2016 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+
23+
#ifndef RestCore_TRestGeant4QuenchingProcess
24+
#define RestCore_TRestGeant4QuenchingProcess
25+
26+
#include <TRestEventProcess.h>
27+
28+
#include "TRestGeant4Event.h"
29+
#include "TRestGeant4Metadata.h"
30+
31+
//! Recomputes the energy of every hit based on quenching factor for each particle and volume
32+
class TRestGeant4QuenchingProcess : public TRestEventProcess {
33+
private:
34+
/// A pointer to the specific TRestGeant4Event input
35+
TRestGeant4Event* fInputG4Event{}; //!
36+
37+
/// A pointer to the specific TRestGeant4Event output
38+
TRestGeant4Event* fOutputG4Event{}; //!
39+
40+
/// A pointer to the simulation metadata information accessible to TRestRun
41+
TRestGeant4Metadata* fGeant4Metadata{}; //!
42+
43+
/// It stores the quenching factor for each particle for each user volume expression
44+
std::map<std::string, std::map<std::string, float_t>> fUserVolumeParticleQuenchingFactor = {};
45+
46+
/// It stores the quenching factor for each particle for each volume of the simulation
47+
std::map<std::string, std::map<std::string, float_t>> fVolumeParticleQuenchingFactor = {};
48+
49+
void Initialize() override;
50+
void InitFromConfigFile() override;
51+
void LoadDefaultConfig();
52+
53+
public:
54+
std::vector<std::string> GetUserVolumeExpressions() const;
55+
float_t GetQuenchingFactorForVolumeAndParticle(const std::string& volumeName,
56+
const std::string& particleName) const;
57+
58+
//
59+
any GetInputEvent() const override { return fInputG4Event; }
60+
any GetOutputEvent() const override { return fOutputG4Event; }
61+
62+
void InitProcess() override;
63+
TRestEvent* ProcessEvent(TRestEvent* inputEvent) override;
64+
void EndProcess() override;
65+
66+
void LoadConfig(const std::string& configFilename, const std::string& name = "");
67+
68+
void PrintMetadata() override;
69+
70+
/// Returns a new instance of this class
71+
TRestEventProcess* Maker() { return new TRestGeant4QuenchingProcess; }
72+
73+
/// Returns the name of this process
74+
const char* GetProcessName() const override { return "Geant4Quenching"; }
75+
76+
TRestGeant4QuenchingProcess();
77+
explicit TRestGeant4QuenchingProcess(const char* configFilename);
78+
~TRestGeant4QuenchingProcess() override;
79+
80+
ClassDefOverride(TRestGeant4QuenchingProcess, 1);
81+
};
82+
#endif

inc/TRestGeant4Track.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ class TRestGeant4Track {
5555

5656
public:
5757
inline const TRestGeant4Hits& GetHits() const { return fHits; }
58+
inline TRestGeant4Hits* GetHitsPointer() { return &fHits; }
5859
inline const TRestGeant4Event* GetEvent() const { return fEvent; }
5960
const TRestGeant4Metadata* GetGeant4Metadata() const;
6061

macros/REST_Geant4_ViewEvent.C

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
//***
1212
//*******************************************************************************************************
1313
Int_t REST_Geant4_ViewEvent(TString fName, Double_t geomScale = 0.1) {
14-
1514
TFile* f = TFile::Open(fName);
1615

1716
TIter nextkey(f->GetListOfKeys());
Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
/*************************************************************************
2+
* This file is part of the REST software framework. *
3+
* *
4+
* Copyright (C) 2016 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+
23+
//////////////////////////////////////////////////////////////////////////
24+
/// The TRestGeant4QuenchingProcess modifies the energy deposits of the simulation by multiplying by a
25+
/// user-defined quenching factor. This quenching factor is specified by volume and by particle and has the
26+
/// value 1.0 by default (no change). Physical volumes, logical volumes, or expressions (to be matched to
27+
/// either physical or logical) can be used for volumes. Example usage: \code
28+
///< TRestGeant4QuenchingProcess>
29+
///
30+
/// <volume name="^scintillatorVolume">
31+
/// <particle name="gamma" quenchingFactor="1.0"/>
32+
/// <particle name="e-" quenchingFactor="0.5"/>
33+
/// <particle name="e+" quenchingFactor="0.9"/>
34+
/// <particle name="mu-" quenchingFactor="0.2"/>
35+
/// <particle name="neutron" quenchingFactor="0.1"/>
36+
/// </volume>
37+
///
38+
/// <volume name="gasVolume">
39+
/// <particle name="gamma" quenchingFactor="0.2"/>
40+
/// <particle name="e-" quenchingFactor="0.2"/>
41+
/// </volume>
42+
///
43+
/// </TRestGeant4QuenchingProcess>
44+
/// \endcode
45+
///
46+
47+
#include "TRestGeant4QuenchingProcess.h"
48+
49+
using namespace std;
50+
51+
ClassImp(TRestGeant4QuenchingProcess);
52+
53+
///////////////////////////////////////////////
54+
/// \brief Default constructor
55+
///
56+
TRestGeant4QuenchingProcess::TRestGeant4QuenchingProcess() { Initialize(); }
57+
58+
///////////////////////////////////////////////
59+
/// \brief Constructor loading data from a config file
60+
///
61+
/// If no configuration path is defined using TRestMetadata::SetConfigFilePath
62+
/// the path to the config file must be specified using full path, absolute or
63+
/// relative.
64+
///
65+
/// The default behaviour is that the config file must be specified with
66+
/// full path, absolute or relative.
67+
///
68+
/// \param configFilename A const char* giving the path to an RML file.
69+
///
70+
TRestGeant4QuenchingProcess::TRestGeant4QuenchingProcess(const char* configFilename) {
71+
Initialize();
72+
73+
if (LoadConfigFromFile(configFilename)) {
74+
LoadDefaultConfig();
75+
}
76+
}
77+
78+
///////////////////////////////////////////////
79+
/// \brief Default destructor
80+
///
81+
TRestGeant4QuenchingProcess::~TRestGeant4QuenchingProcess() { delete fOutputG4Event; }
82+
83+
///////////////////////////////////////////////
84+
/// \brief Function to load the default config in absence of RML input
85+
///
86+
void TRestGeant4QuenchingProcess::LoadDefaultConfig() { SetTitle("Default config"); }
87+
88+
///////////////////////////////////////////////
89+
/// \brief Function to initialize input/output event members and define the
90+
/// section name
91+
///
92+
void TRestGeant4QuenchingProcess::Initialize() {
93+
fGeant4Metadata = nullptr;
94+
SetSectionName(this->ClassName());
95+
SetLibraryVersion(LIBRARY_VERSION);
96+
97+
fInputG4Event = nullptr;
98+
fOutputG4Event = new TRestGeant4Event();
99+
}
100+
101+
///////////////////////////////////////////////
102+
/// \brief Function to load the configuration from an external configuration
103+
/// file.
104+
///
105+
/// If no configuration path is defined in TRestMetadata::SetConfigFilePath
106+
/// the path to the config file must be specified using full path, absolute or
107+
/// relative.
108+
///
109+
/// \param configFilename A const char* giving the path to an RML file.
110+
/// \param name The name of the specific metadata. It will be used to find the
111+
/// corresponding TRestGeant4QuenchingProcess section inside the RML.
112+
///
113+
void TRestGeant4QuenchingProcess::LoadConfig(const string& configFilename, const string& name) {
114+
if (LoadConfigFromFile(configFilename, name)) {
115+
LoadDefaultConfig();
116+
}
117+
}
118+
119+
void TRestGeant4QuenchingProcess::InitFromConfigFile() {
120+
TiXmlElement* volumeElement = GetElement("volume");
121+
while (volumeElement) {
122+
TiXmlElement* particleElement = GetElement("particle", volumeElement);
123+
const string volumeName = GetParameter("name", volumeElement, "");
124+
if (volumeName.empty()) {
125+
cerr << "TRestGeant4QuenchingProcess: No volume expression specified" << endl;
126+
exit(1);
127+
}
128+
while (particleElement) {
129+
const string particleName = GetParameter("name", particleElement, "");
130+
if (particleName.empty()) {
131+
cerr << "TRestGeant4QuenchingProcess: No particle name specified" << endl;
132+
exit(1);
133+
}
134+
const auto quenchingFactor = stof(GetParameter("quenchingFactor", particleElement, -1.0));
135+
// if no value is specified, give error
136+
if (quenchingFactor < 0.0 || quenchingFactor > 1.0) {
137+
cerr << "TRestGeant4QuenchingProcess: Quenching factor must be between 0 and 1" << endl;
138+
exit(1);
139+
}
140+
fUserVolumeParticleQuenchingFactor[volumeName][particleName] = quenchingFactor;
141+
particleElement = GetNextElement(particleElement);
142+
}
143+
volumeElement = GetNextElement(volumeElement);
144+
}
145+
}
146+
147+
///////////////////////////////////////////////
148+
/// \brief Process initialization. User volume expressions are matched to physical volumes
149+
void TRestGeant4QuenchingProcess::InitProcess() {
150+
fGeant4Metadata = GetMetadata<TRestGeant4Metadata>();
151+
if (fGeant4Metadata == nullptr) {
152+
cerr << "TRestGeant4QuenchingProcess: No TRestGeant4Metadata found" << endl;
153+
exit(1);
154+
}
155+
156+
const auto geometryInfo = fGeant4Metadata->GetGeant4GeometryInfo();
157+
// check all the user volume expressions are valid and correspond to at least a volume
158+
for (const auto& [userVolume, particleToQuenchingMap] : fUserVolumeParticleQuenchingFactor) {
159+
set<string> physicalVolumes = {};
160+
for (const auto& volume : geometryInfo.GetAllPhysicalVolumesMatchingExpression(userVolume)) {
161+
physicalVolumes.insert(volume.Data());
162+
}
163+
if (!physicalVolumes.empty()) {
164+
continue;
165+
}
166+
// maybe it refers to a logical volume
167+
for (const auto& logicalVolume : geometryInfo.GetAllLogicalVolumesMatchingExpression(userVolume)) {
168+
for (const auto& volume : geometryInfo.GetAllPhysicalVolumesFromLogical(logicalVolume.Data())) {
169+
physicalVolumes.insert(volume.Data());
170+
}
171+
}
172+
173+
if (physicalVolumes.empty()) {
174+
cerr << "TRestGeant4QuenchingProcess: No volume found matching expression " << userVolume << endl;
175+
exit(1);
176+
}
177+
178+
for (const auto& physicalVolume : physicalVolumes) {
179+
fVolumeParticleQuenchingFactor[physicalVolume] = particleToQuenchingMap;
180+
}
181+
}
182+
183+
RESTDebug << "TRestGeant4QuenchingProcess initialized with volumes" << RESTendl;
184+
for (const auto& [volume, particleToQuenchingMap] : fVolumeParticleQuenchingFactor) {
185+
RESTDebug << volume << RESTendl;
186+
for (const auto& [particle, quenchingFactor] : particleToQuenchingMap) {
187+
RESTDebug << "\t" << particle << " " << quenchingFactor << RESTendl;
188+
}
189+
}
190+
}
191+
192+
///////////////////////////////////////////////
193+
/// \brief The main processing event function
194+
///
195+
TRestEvent* TRestGeant4QuenchingProcess::ProcessEvent(TRestEvent* inputEvent) {
196+
fInputG4Event = (TRestGeant4Event*)inputEvent;
197+
*fOutputG4Event = *((TRestGeant4Event*)inputEvent);
198+
199+
fOutputG4Event->InitializeReferences(GetRunInfo());
200+
201+
// loop over all tracks
202+
for (int trackIndex = 0; trackIndex < int(fOutputG4Event->GetNumberOfTracks()); trackIndex++) {
203+
// get the track
204+
TRestGeant4Track* track = fOutputG4Event->GetTrackPointer(trackIndex);
205+
const auto& particleName = track->GetParticleName();
206+
207+
auto hits = track->GetHitsPointer();
208+
auto& energy = hits->GetEnergyRef();
209+
for (int hitIndex = 0; hitIndex < int(hits->GetNumberOfHits()); hitIndex++) {
210+
const auto& volumeName = hits->GetVolumeName(hitIndex);
211+
const float_t quenchingFactor =
212+
GetQuenchingFactorForVolumeAndParticle(volumeName.Data(), particleName.Data());
213+
// default is 1.0, so no quenching
214+
energy[hitIndex] *= quenchingFactor;
215+
}
216+
}
217+
218+
return fOutputG4Event;
219+
}
220+
221+
///////////////////////////////////////////////
222+
/// \brief Function to include required actions after all events have been processed.
223+
void TRestGeant4QuenchingProcess::EndProcess() {}
224+
225+
vector<string> TRestGeant4QuenchingProcess::GetUserVolumeExpressions() const {
226+
vector<string> userVolumeExpressions;
227+
userVolumeExpressions.reserve(fUserVolumeParticleQuenchingFactor.size());
228+
for (auto const& x : fUserVolumeParticleQuenchingFactor) {
229+
userVolumeExpressions.push_back(x.first);
230+
}
231+
return userVolumeExpressions;
232+
}
233+
234+
float_t TRestGeant4QuenchingProcess::GetQuenchingFactorForVolumeAndParticle(
235+
const string& volumeName, const string& particleName) const {
236+
float_t quenchingFactor = 1.0;
237+
// check if the volume is in the map
238+
if (fVolumeParticleQuenchingFactor.find(volumeName) != fVolumeParticleQuenchingFactor.end()) {
239+
// check if the particle is in the map
240+
if (fVolumeParticleQuenchingFactor.at(volumeName).find(particleName) !=
241+
fVolumeParticleQuenchingFactor.at(volumeName).end()) {
242+
quenchingFactor = fVolumeParticleQuenchingFactor.at(volumeName).at(particleName);
243+
}
244+
}
245+
return quenchingFactor;
246+
}
247+
248+
void TRestGeant4QuenchingProcess::PrintMetadata() {
249+
BeginPrintProcess();
250+
cout << "Printing TRestGeant4QuenchingProcess user configuration" << endl;
251+
for (auto const& [volume, particleQuenchingFactorMap] : fUserVolumeParticleQuenchingFactor) {
252+
cout << "Volume: " << volume << endl;
253+
for (auto const& [particle, quenchingFactor] : particleQuenchingFactorMap) {
254+
cout << " - Particle: " << particle << " Quenching factor: " << quenchingFactor << endl;
255+
}
256+
}
257+
258+
if (!fVolumeParticleQuenchingFactor.empty()) {
259+
cout << "Printing TRestGeant4QuenchingProcess configuration with actual volumes" << endl;
260+
for (auto const& [volume, particleQuenchingFactorMap] : fVolumeParticleQuenchingFactor) {
261+
cout << "Volume: " << volume << endl;
262+
for (auto const& [particle, quenchingFactor] : particleQuenchingFactorMap) {
263+
cout << " - Particle: " << particle << " Quenching factor: " << quenchingFactor << endl;
264+
}
265+
}
266+
}
267+
EndPrintProcess();
268+
}

0 commit comments

Comments
 (0)