REST-for-Physics  v2.3
Rare Event Searches ToolKit for Physics
TRestDetectorElectronDiffusionProcess.cxx
1
15
16#include "TRestDetectorElectronDiffusionProcess.h"
17
18using namespace std;
19
21
22TRestDetectorElectronDiffusionProcess::TRestDetectorElectronDiffusionProcess() { Initialize(); }
23
24TRestDetectorElectronDiffusionProcess::TRestDetectorElectronDiffusionProcess(const char* configFilename) {
25 Initialize();
26 if (LoadConfigFromFile(configFilename)) {
27 LoadDefaultConfig();
28 }
29}
30
31TRestDetectorElectronDiffusionProcess::~TRestDetectorElectronDiffusionProcess() { delete fOutputHitsEvent; }
32
33void TRestDetectorElectronDiffusionProcess::LoadDefaultConfig() {
34 SetTitle("Default config");
35
36 fElectricField = 2000;
37 fAttachment = 0;
38 fGasPressure = -1;
39}
40
42 SetSectionName(this->ClassName());
43 SetLibraryVersion(LIBRARY_VERSION);
44
45 fElectricField = 0;
46 fAttachment = 0;
47 fGasPressure = -1;
48
49 fTransversalDiffusionCoefficient = 0;
50 fLongitudinalDiffusionCoefficient = 0;
51 fWValue = 0;
52 fFanoFactor = 0;
53
54 fOutputHitsEvent = new TRestDetectorHitsEvent();
55 fInputHitsEvent = nullptr;
56
57 fGas = nullptr;
58 fReadout = nullptr;
59
60 fRandom = nullptr;
61}
62
63void TRestDetectorElectronDiffusionProcess::LoadConfig(const string& configFilename, const string& name) {
64 if (LoadConfigFromFile(configFilename, name)) {
65 LoadDefaultConfig();
66 }
67}
68
70 fRandom = new TRandom3(fSeed);
71
72 fGas = GetMetadata<TRestDetectorGas>();
73 if (fGas == nullptr) {
74 if (fLongitudinalDiffusionCoefficient == -1 || fTransversalDiffusionCoefficient == -1) {
75 RESTWarning << "Gas has not been initialized" << RESTendl;
76 RESTError
77 << "TRestDetectorElectronDiffusionProcess: diffusion parameters are not defined in the rml "
78 "file!"
79 << RESTendl;
80 exit(-1);
81 }
82 if (fWValue == -1) {
83 RESTWarning << "Gas has not been initialized" << RESTendl;
84 RESTError
85 << "TRestDetectorElectronDiffusionProcess: gas work function has not been defined in the "
86 "rml file!"
87 << RESTendl;
88 exit(-1);
89 }
90 } else {
91#ifndef USE_Garfield
92 RESTError << "A TRestDetectorGas definition was found but REST was not linked to Garfield libraries."
93 << RESTendl;
94 RESTError
95 << "Please, remove the TRestDetectorGas definition, and add gas parameters inside the process "
96 "TRestDetectorElectronDiffusionProcess"
97 << RESTendl;
98 exit(1);
99#endif
100 if (fGasPressure <= 0) {
101 fGasPressure = fGas->GetPressure();
102 }
103 fGas->SetPressure(fGasPressure);
104
105 if (fElectricField <= 0) {
106 fElectricField = fGas->GetElectricField();
107 }
108 fGas->SetElectricField(fElectricField);
109
110 if (fWValue <= 0) {
111 fWValue = fGas->GetWvalue();
112 }
113 fGas->SetW(fWValue);
114
115 if (fFanoFactor <= 0) {
116 fFanoFactor = fGas->GetGasFanoFactor();
117 }
118
119 if (fLongitudinalDiffusionCoefficient <= 0) {
120 fLongitudinalDiffusionCoefficient = fGas->GetLongitudinalDiffusion();
121 } // (cm)^1/2
122
123 if (fTransversalDiffusionCoefficient <= 0) {
124 fTransversalDiffusionCoefficient = fGas->GetTransversalDiffusion();
125 } // (cm)^1/2
126 }
127
128 fReadout = GetMetadata<TRestDetectorReadout>();
129 if (fReadout == nullptr) {
130 cout << "REST ERROR: Readout has not been initialized" << endl;
131 exit(-1);
132 }
133}
134
136 fInputHitsEvent = (TRestDetectorHitsEvent*)inputEvent;
137 fOutputHitsEvent->SetEventInfo(fInputHitsEvent);
138
139 set<int> hitsToProcess; // indices of the hits to process (we do not want to process veto hits)
140 for (int n = 0; n < static_cast<int>(fInputHitsEvent->GetNumberOfHits()); n++) {
141 if (fInputHitsEvent->GetType(n) == REST_HitType::VETO) {
142 // keep unprocessed hits as they are
143 fOutputHitsEvent->AddHit(fInputHitsEvent->GetX(n), fInputHitsEvent->GetY(n),
144 fInputHitsEvent->GetZ(n), fInputHitsEvent->GetEnergy(n),
145 fInputHitsEvent->GetTime(n), fInputHitsEvent->GetType(n));
146 } else {
147 hitsToProcess.insert(n);
148 }
149 }
150
151 if (hitsToProcess.empty()) {
152 return nullptr;
153 }
154
155 double totalEnergy = 0;
156 for (const auto& hitIndex : hitsToProcess) {
157 totalEnergy += fInputHitsEvent->GetEnergy(hitIndex);
158 }
159
160 bool isAttached;
161
162 Double_t wValue = fWValue;
163 const auto totalElectrons = static_cast<unsigned int>(totalEnergy * REST_Units::eV / wValue);
164
165 // TODO: double check this
166 if (fMaxHits > 0 && totalElectrons > fMaxHits) {
167 // set a fake w-value if max hits are limited. this fake w-value will be larger
168 wValue = (totalEnergy * REST_Units::eV) / fMaxHits;
169 }
170
171 for (const auto& hitIndex : hitsToProcess) {
172 TRestHits* hits = fInputHitsEvent->GetHits();
173
174 const auto energy = hits->GetEnergy(hitIndex);
175 const auto time = hits->GetTime(hitIndex);
176 const auto type = hits->GetType(hitIndex);
177
178 if (energy <= 0) {
179 continue;
180 }
181
182 const Double_t x = hits->GetX(hitIndex);
183 const Double_t y = hits->GetY(hitIndex);
184 const Double_t z = hits->GetZ(hitIndex);
185
186 for (int p = 0; p < fReadout->GetNumberOfReadoutPlanes(); p++) {
187 TRestDetectorReadoutPlane* plane = &(*fReadout)[p];
188 const auto planeType = plane->GetType();
189 if (planeType == "veto") {
190 // do not drift veto planes
191 continue;
192 }
193
194 if (fCheckIsInside && !plane->IsInside({x, y, z})) {
195 continue;
196 }
197
198 Double_t driftDistance = plane->GetDistanceTo({x, y, z});
199
200 double numberOfElectrons = energy * REST_Units::eV / wValue;
201 if (fUseFanoFactor) {
202 if (fFanoFactor <= 0) {
203 throw runtime_error("Fano factor not valid");
204 }
205 const auto sigma = TMath::Sqrt(fFanoFactor * numberOfElectrons);
206 numberOfElectrons = fRandom->Gaus(numberOfElectrons, sigma);
207 } else if (fPoissonElectronExcitation) {
208 // this is probably a bad idea, we only keep it for backwards compatibility
209 numberOfElectrons = fRandom->Poisson(energy * REST_Units::eV / fWValue);
210 }
211
212 if (wValue != fWValue) {
213 // reduce the number of electrons to improve speed
214 numberOfElectrons = static_cast<unsigned int>(numberOfElectrons * fWValue / wValue);
215 }
216
217 if (numberOfElectrons <= 0) {
218 numberOfElectrons = 1;
219 }
220
221 const Double_t energyPerElectron = energy * REST_Units::eV / numberOfElectrons;
222
223 Double_t longitudinalDiffusion =
224 10. * TMath::Sqrt(driftDistance / 10.) * fLongitudinalDiffusionCoefficient; // mm
225 Double_t transversalDiffusion =
226 10. * TMath::Sqrt(driftDistance / 10.) * fTransversalDiffusionCoefficient; // mm
227
228 for (unsigned int i = 0; i < numberOfElectrons; i++) {
229 if (fAttachment > 0) {
230 // TODO: where is this formula from?
231 isAttached = (fRandom->Uniform(0, 1) > pow(1 - fAttachment, driftDistance / 10.));
232 } else {
233 isAttached = false;
234 }
235
236 if (isAttached) {
237 continue;
238 }
239
240 TVector3 positionAfterDiffusion = {x, y, z};
241 positionAfterDiffusion += {
242 fRandom->Gaus(0, transversalDiffusion), //
243 fRandom->Gaus(0, transversalDiffusion), //
244 fRandom->Gaus(0, longitudinalDiffusion) //
245 };
246 if (plane->GetDistanceTo(positionAfterDiffusion) < 0) {
247 // electron has been moved under the plane
248 positionAfterDiffusion.SetZ(
249 plane->GetPosition().Z() +
250 1E-6 * plane->GetNormal().Z()); // add a delta to make sure readout finds it
251 }
252 if (plane->GetDistanceTo(positionAfterDiffusion) > plane->GetHeight()) {
253 // electron has been moved over the plane
254 positionAfterDiffusion.SetZ(
255 plane->GetPosition().Z() + plane->GetHeight() -
256 1E-6 * plane->GetNormal().Z()); // add a delta to make sure readout finds it
257 }
258
259 if (fCheckIsInside && !plane->IsInside(positionAfterDiffusion)) {
260 // electron has been moved outside the readout plane
261 continue;
262 }
263
264 const double electronEnergy =
265 fUnitElectronEnergy ? 1 : energyPerElectron * REST_Units::keV / REST_Units::eV;
266
268 cout << "Adding hit. x : " << positionAfterDiffusion.X()
269 << " y : " << positionAfterDiffusion.Y() << " z : " << positionAfterDiffusion.Z()
270 << " en : " << energyPerElectron * REST_Units::keV / REST_Units::eV << " keV"
271 << endl;
272 }
273 fOutputHitsEvent->AddHit(positionAfterDiffusion.X(), positionAfterDiffusion.Y(),
274 positionAfterDiffusion.Z(), electronEnergy, time, type);
275 }
276 }
277 }
278
279 if (this->GetVerboseLevel() >= TRestStringOutput::REST_Verbose_Level::REST_Debug) {
280 cout << "TRestDetectorElectronDiffusionProcess. Processed hits total energy : " << totalEnergy
281 << endl;
282 cout << "TRestDetectorElectronDiffusionProcess. Hits processed : " << hitsToProcess.size() << endl;
283 cout << "TRestDetectorElectronDiffusionProcess. Hits added : " << fOutputHitsEvent->GetNumberOfHits()
284 << endl;
286 GetChar();
287 }
288 }
289
290 return fOutputHitsEvent;
291}
292
294
296 fGasPressure = GetDblParameterWithUnits("gasPressure", -1.);
297 fElectricField = GetDblParameterWithUnits("electricField", -1.);
298 fWValue = GetDblParameterWithUnits("WValue", 0.0) * REST_Units::eV;
299 fFanoFactor = GetDblParameterWithUnits("fanoFactor", 0.0);
300 fAttachment = StringToDouble(GetParameter("attachment", "0"));
301 fLongitudinalDiffusionCoefficient =
302 StringToDouble(GetParameter("longitudinalDiffusionCoefficient", "-1"));
303 if (fLongitudinalDiffusionCoefficient == -1)
304 fLongitudinalDiffusionCoefficient = StringToDouble(GetParameter("longDiff", "-1"));
305 else {
306 RESTWarning << "longitudinalDiffusionCoefficient is now OBSOLETE! It will soon disappear."
307 << RESTendl;
308 RESTWarning << " Please use the shorter form of this parameter : longDiff" << RESTendl;
309 }
310
311 fTransversalDiffusionCoefficient = StringToDouble(GetParameter("transversalDiffusionCoefficient", "-1"));
312 if (fTransversalDiffusionCoefficient == -1)
313 fTransversalDiffusionCoefficient = StringToDouble(GetParameter("transDiff", "-1"));
314 else {
315 RESTWarning << "transversalDiffusionCoefficient is now OBSOLETE! It will soon disappear." << RESTendl;
316 RESTWarning << " Please use the shorter form of this parameter : transDiff" << RESTendl;
317 }
318 fMaxHits = StringToInteger(GetParameter("maxHits", "1000"));
319 fSeed = static_cast<UInt_t>(StringToInteger(GetParameter("seed", "0")));
320 fPoissonElectronExcitation = StringToBool(GetParameter("poissonElectronExcitation", "true"));
321 fUnitElectronEnergy = StringToBool(GetParameter("unitElectronEnergy", "false"));
322 fCheckIsInside = StringToBool(GetParameter("checkIsInside", "false"));
323 fUseFanoFactor = StringToBool(GetParameter("useFano", "false"));
324}
virtual void SetW(double value)
Sets the electric field of the drift volume. Given in V/mm.
virtual void SetElectricField(double value)
Sets the electric field. Must be given in V/mm.
virtual Double_t GetElectricField() const
Returns the electric field in V/mm.
void InitProcess() override
To be executed at the beginning of the run (outside event loop)
void EndProcess() override
To be executed at the end of the run (outside event loop)
void InitFromConfigFile() override
To make settings from rml file. This method must be implemented in the derived class.
TRestEvent * ProcessEvent(TRestEvent *inputEvent) override
Process one event.
void Initialize() override
Making default settings.
Double_t GetGasFanoFactor() const
Returns the gas fano factor.
Double_t GetX(int n) const
Returns the X-coordinate of hit entry n in mm.
Double_t GetY(int n) const
Returns the Y-coordinate of hit entry n in mm.
Double_t GetZ(int n) const
Returns the Z-coordinate of hit entry n in mm.
void AddHit(Double_t x, Double_t y, Double_t z, Double_t en, Double_t t=0, REST_HitType type=XYZ)
Adds a new hit to this event.
bool IsInside(const TVector3 &point) const
Check if the point is inside any module of the readout plane.
A base class for any REST event.
Definition: TRestEvent.h:38
void SetEventInfo(TRestEvent *eve)
Definition: TRestEvent.cxx:137
It saves a 3-coordinate position and an energy for each punctual deposition.
Definition: TRestHits.h:39
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.
TRestStringOutput::REST_Verbose_Level GetVerboseLevel()
returns the verboselevel in type of REST_Verbose_Level enumerator
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.
@ REST_Debug
+show the defined debug messages
Int_t GetChar(std::string hint="Press a KEY to continue ...")
Helps to pause the program, printing a message before pausing.
Double_t StringToDouble(std::string in)
Gets a double from a string.
Int_t StringToInteger(std::string in)
Gets an integer from a string.