REST-for-Physics  v2.3
Rare Event Searches ToolKit for Physics
Loading...
Searching...
No Matches
TRestDetectorGarfieldDriftProcess.cxx
1
16
17#include "TRestDetectorGarfieldDriftProcess.h"
18
19#include <TGeoBBox.h>
20#include <TRandom3.h>
21
23
24#if defined USE_Garfield
25using namespace Garfield;
26#include <ComponentConstant.hh>
27
28#include "TGDMLParse.h"
29#endif
30
31#include <stdio.h>
32
33using namespace std;
34
35const double cmTomm = 10.;
36
37#if defined USE_Garfield
38
39TRestDetectorGarfieldDriftProcess::TRestDetectorGarfieldDriftProcess() : fRandom(0), fGfSensor(0) {
40 Initialize();
41}
42
43// __________________________________________________________
44// TODO : Perhaps this constructor should be removed
45// since we will always load the config from TRestRun
46// when we use AddProcess. It would be necessary only if we use the
47// process stand alone but even then we could just call LoadConfig
48// __________________________________________________________
49
50TRestDetectorGarfieldDriftProcess::TRestDetectorGarfieldDriftProcess(const char* configFilename)
51 : fRandom(0), fGfSensor(0) {
52 Initialize();
53
54 if (LoadConfigFromFile(configFilename) == -1) LoadDefaultConfig();
55
56 PrintMetadata();
57
58 if (fReadout == nullptr) fReadout = new TRestDetectorReadout(configFilename);
59}
60
61// TRestDetectorGarfieldDriftProcess destructor
62TRestDetectorGarfieldDriftProcess::~TRestDetectorGarfieldDriftProcess() {
63 delete fReadout;
64 delete fGeometry;
65 delete fOutputHitsEvent;
66}
67
68void TRestDetectorGarfieldDriftProcess::LoadDefaultConfig() {
69 SetName("garfieldDriftProcess-Default");
70 SetTitle("Default config");
71
72 cout << "TRestDetectorGarfieldDriftProcess metadata not found. Loading default values" << endl;
73
74 fDriftPotential = 1000;
75 fGasPressure = 10;
76}
77
78void TRestDetectorGarfieldDriftProcess::LoadConfig(const string& configFilename, const string& name) {
79 if (LoadConfigFromFile(configFilename, name)) LoadDefaultConfig();
80
81 if (fDriftPotential == PARAMETER_NOT_FOUND_DBL) {
82 fDriftPotential = 1000; // V
83 }
84}
85
86#endif
87
89 SetSectionName(ClassName());
90 SetLibraryVersion(LIBRARY_VERSION);
91
92 fRandom = new TRandom3(0);
93 fInputHitsEvent = nullptr;
94 fOutputHitsEvent = new TRestDetectorHitsEvent();
95
96#if defined USE_Garfield
97 fReadout = nullptr;
98 fGas = nullptr;
99 fGeometry = nullptr;
100 fPEReduction = 1.;
101 fStopDistance = 2; // default distance from readout to stop drift set to 2mm
102#endif
103}
104
105#if defined USE_Garfield
107 // Function to be executed once at the beginning of process
108 // (before starting the process of the events)
109
110 // Start by calling the InitProcess function of the abstract class.
111 // Comment this if you don't want it.
112 // TRestEventProcess::InitProcess();
113
114 // Getting gas data
115 fGas = GetMetadata<TRestDetectorGas>();
116 if (fGas != nullptr) {
117 if (fGasPressure <= 0)
118 fGasPressure = fGas->GetPressure();
119 else
120 fGas->SetPressure(fGasPressure);
121
122 } else {
123 cout << "REST_WARNING. No TRestDetectorGas found in TRestRun." << endl;
124 }
125
126 // Getting readout data
127 fReadout = GetMetadata<TRestDetectorReadout>();
128 if (fReadout == nullptr) {
129 cout << "REST ERROR: Readout has not been initialized" << endl;
130 exit(-1);
131 }
132
133 // Getting geometry data
134 if (fGDML_Filename == "") {
135 cout << "REST ERROR no geometry GDML file name parameter (gdml_file) given "
136 "in TRestDetectorGarfieldDriftProcess "
137 << endl;
138 exit(-1);
139 }
140
141 TGeoVolume* geovol = nullptr;
142 fGeometry = new TRestDetectorGeometry();
143 fGeometry->InitGfGeometry();
144
145 geovol = TGDMLParse::StartGDML(fGDML_Filename);
146 if (!geovol) {
147 cout << "REST ERROR when TRestDetectorGeometry read GDML file " << fGDML_Filename << endl;
148 exit(-1);
149 }
150
151 fGeometry->SetTopVolume(geovol);
152 fGeometry->CloseGeometry();
153 fGeometry->DefaultColors();
154 // fGeometry->UpdateElements();
155
156 cout << "TRestDetectorGarfieldDriftProcess GetVerboseLevel : "
157 << static_cast<int>(this->GetVerboseLevel()) << endl;
158
159 // analyze GDML geometry to find major elements (gas volume, electrodes,
160 // readout)
161 TObjArray* thenodes = geovol->GetNodes();
162 for (TIter it = thenodes->begin(); it != thenodes->end(); ++it) {
163 TGeoNode* itnode = (TGeoNode*)(*it);
165 cout << "****** itnode " << itnode->GetName() << endl;
166 itnode->PrintCandidates();
167 }
168 cout << "****** itnode " << itnode->GetName() << endl;
169 itnode->PrintCandidates();
170
171 TGeoVolume* itvol = itnode->GetVolume();
173 cout << " * * itvolume " << itvol->GetName() << endl;
174 itvol->Print();
175 }
176 cout << " * * itvolume " << itvol->GetName() << endl;
177 itvol->Print();
178
179 TGeoMedium* itmed = itvol->GetMedium();
181 cout << " * * itmed " << itmed->GetName() << endl;
182
183 // gas volume
184 if (fGas->GetGDMLMaterialRef() == itmed->GetName()) {
185 fGeometry->SetGfGeoMedium(itmed->GetName(), fGas);
187 cout << " -> gas volume SetMedium itmed " << itmed->GetName() << " fGas "
188 << fGas->GetGasMedium()->GetName() << endl;
189 fGas->GetGasMedium()->PrintGas();
190 }
191 cout << " -> gas volume SetMedium itmed " << itmed->GetName() << " fGas "
192 << fGas->GetGasMedium()->GetName() << endl;
193 fGas->GetGasMedium()->PrintGas();
194 }
195
196 // drift electrode (it should be called a cathode, not anode, no ?)
197 if ((strncmp(itvol->GetName(), "anodeVol", 8) == 0) ||
198 (strncmp(itvol->GetName(), "cathodeVol", 10) == 0)) {
199 fGeometry->SetDriftElecNode(itnode);
201 cout << " -> cathode volume " << endl;
202 cout << " -> cathode volume " << endl;
203 }
204
205 // micromegas readout electrode
206 if ((strncmp(itvol->GetName(), "micromegasVol", 13) == 0)) {
207 fGeometry->AddReadoutElecNode(itnode);
209 cout << " -> readout volume " << endl;
210 cout << " -> readout volume " << endl;
211 }
212 }
213
214 // For the moment we set only constant electric field in Garfield
215 double matrixZpos = 0, planeZpos = 0, planeZvec = 0;
216 cout << "fGeometry " << fGeometry << " nb node " << fGeometry->GetNReadoutElecNodes() << endl;
217 for (int ii = 0; ii < fGeometry->GetNReadoutElecNodes(); ii++) {
218 bool rdPlaneFound = false;
219
220 TGeoNode* readoutnode = fGeometry->GetReadoutElecNode(ii);
221 cout << "ii " << ii << " readoutnode " << readoutnode << " visible " << readoutnode->IsVisible()
222 << endl;
223 if (!readoutnode) continue;
224 cout << "readoutnode visible " << readoutnode->IsVisible() << endl;
225 readoutnode->ls();
226 readoutnode->PrintCandidates();
227 TGeoMatrix* readoutmatrix = readoutnode->GetMatrix();
228 if (!readoutmatrix) continue;
229 cout << "readoutmatrix " << endl;
230 readoutmatrix->Print();
231 matrixZpos = (readoutmatrix->IsTranslation() ? 10 * readoutmatrix->GetTranslation()[2]
232 : 0); // converted to mm
233 for (int jj = 0; jj < fReadout->GetNumberOfReadoutPlanes(); jj++) {
234 TRestDetectorReadoutPlane* readoutplane = fReadout->GetReadoutPlane(jj);
235 planeZpos = readoutplane->GetPosition().Z();
236 cout << " jj " << jj << " matrixZpos " << matrixZpos << " planeZpos " << planeZpos << endl;
237 if (fabs(planeZpos - matrixZpos) > 1)
238 continue; // we search for fReadout entry at same Z position
239 rdPlaneFound = true;
240 planeZvec = readoutplane->GetNormal().z();
241 cout << " planeZvec " << planeZvec << endl;
242 }
243
244 if (rdPlaneFound) {
245 double field = fDriftPotential /
246 (fGeometry->GetDriftElecNode()->GetMatrix()->GetTranslation()[2] - planeZpos);
247 ComponentConstant* cmp = new ComponentConstant();
248 // cmp->SetElectricField(0, 0, fElectricField); // assuming V/cm
249 cmp->SetElectricField(0, 0, field); // assuming V/cm
250 cmp->SetPotential(0, 0, planeZpos / 10., 0); // potential at readout level set to 0
251 cmp->SetWeightingField(0, 0, planeZvec, "m");
252 fGeometry->AddGfComponent(cmp);
253 cout << "add component field " << field << " planeZpos " << planeZpos << " planeZvec "
254 << planeZvec << " drift pos "
255 << fGeometry->GetDriftElecNode()->GetMatrix()->GetTranslation()[2] << endl;
256 }
257 }
258
259 // create Sensor corresponding to readout plane
260 // only the first component used, so 1 sensor only for the moment
261 if (fGeometry->GetNbOfGfComponent() > 0) {
262 fGfSensor = new Sensor();
263 fGfSensor->AddComponent(fGeometry->GetGfComponent(0));
264 fGfSensor->AddElectrode(fGeometry->GetGfComponent(0), "m");
265 fGfSensor->SetTimeWindow(0., 0.1, 500);
266
267 double xmin = -1e9, xmax = 1e9, ymin = -1e9, ymax = 1e9;
268 TGeoShape* readoutshape = fGeometry->GetReadoutElecNode(0)->GetVolume()->GetShape();
269 TGeoMatrix* readoutmatrix = fGeometry->GetReadoutElecNode(0)->GetMatrix();
270 double xmid = 10. * readoutmatrix->GetTranslation()[0],
271 ymid = 10. * readoutmatrix->GetTranslation()[1];
272 if (readoutshape->InheritsFrom("TGeoBBox")) {
273 // keep drifting electrons 10cm around the readout volume in x and y
274 TGeoBBox* readoutbox = (TGeoBBox*)readoutshape;
275 xmin = xmid - 10. * readoutbox->GetDX() - 100;
276 xmax = xmid + 10. * readoutbox->GetDX() + 100;
277 ymin = ymid - 10. * readoutbox->GetDY() - 100;
278 ymax = ymid + 10. * readoutbox->GetDY() + 100;
279 }
280 double driftelecZpos = fGeometry->GetDriftElecNode()
281 ->GetMatrix()
282 ->GetTranslation()[2]; // hope that all these objects are really there...
283 // drift area defined from bouding box of readout shape
284 fGfSensor->SetArea(xmin / 10., ymin / 10., planeZpos / 10. + fStopDistance, xmax / 10., ymax / 10.,
285 driftelecZpos); // drift stops fStopDistance above the readout plane
286 fGeometry->AddGfSensor(fGfSensor);
287 printf(" GfSensor area x- %lf y- %lf z- %lf x+ %lf y+ %lf z+ %lf\n", xmin / 10., ymin / 10.,
288 planeZpos / 10. + 0.2, xmax / 10., ymax / 10., driftelecZpos);
289
290 fGfDriftMethod = new DRIFT_METHOD();
291 // fGfDriftMethod->EnableDebugging();
292 // fGfDriftMethod->EnableVerbose();
293 fGfDriftMethod->SetSensor(fGfSensor);
294 // fGfDriftMethod->SetTimeSteps(0.2);
295 fGfDriftMethod->SetCollisionSteps(100);
296 }
297
298 if (!fGfDriftMethod || !fGfSensor) {
299 cout << "REST ERROR Garfield not fully initialized in "
300 "TRestDetectorGarfieldDriftProcess::InitProcess "
301 << endl;
302 cout << " fGfDriftMethod " << fGfDriftMethod << " fGfSensor " << fGfSensor << " GetNbOfGfComponent "
303 << fGeometry->GetNbOfGfComponent() << endl;
304 cout << " matrixZpos " << matrixZpos << " planeZpos " << planeZpos << " planeZvec " << planeZvec
305 << endl;
306 exit(-1);
307 }
308
309 // for (register double ix=-3000; ix<3000; ix+=10) {
310 // printf(" ix %lf medium %p is_inside %d", ix,
311 // fGeometry->GetGfGeometry()->GetMedium(ix/10.,5,0),
312 // fGeometry->GetGfGeometry()->IsInside(ix/10.,5,0));
313 // cout << " moduleId " <<
314 // fReadout->GetReadoutPlane(0)->isInsideDriftVolume( ix, 50, 0 );
315 // fGeometry->SetCurrentPoint(ix/10., 5,0);
316 // if (fGeometry->IsOutside()) cout << " is outside " << endl; else cout <<
317 // " is inside" << endl; TGeoNode* cnode =fGeometry ->GetCurrentNode();
318 // TGeoNode* cnode2= fGeometry->FindNode(ix/10., 5,0);
319 // std::string name(cnode->GetMedium()->GetMaterial()->GetName());
320 // register Medium* tmed = fGeometry->GetGfMedium(ix/10., 5,0);
321 // cout << " node " << cnode->GetName() << " material " << name;
322 // cout << " node2 " << cnode2->GetName() << " material " <<
323 // cnode2->GetMedium()->GetMaterial()->GetName(); if (tmed) cout << " medium
324 // " << tmed->GetName(); cout << endl;
325 // }
326}
327
328//------------------------------------------------------------------------------
329
330Int_t TRestDetectorGarfieldDriftProcess::FindModule(Int_t readoutPlane, Double_t x, Double_t y) {
331 // TODO verify this
332 TRestDetectorReadoutPlane* plane = fReadout->GetReadoutPlane(readoutPlane);
333 for (size_t md = 0; md < plane->GetNumberOfModules(); md++) {
334 if ((*plane)[md].IsInside({x, y})) {
335 return md;
336 }
337 }
338
339 return -1;
340}
341
342#endif
343
345#if defined USE_Garfield
346 fInputHitsEvent = (TRestDetectorHitsEvent*)inputEvent;
347
348 double x, y, z, energy;
349 double xi, yi, zi, ti, xf, yf, zf, tf, energyf;
350 int status;
351
353 cout << "Number of hits : " << fInputHitsEvent->GetNumberOfHits() << endl;
354 cout << "--------------------------" << endl;
355 fInputHitsEvent->PrintEvent(20);
356 }
357
358 for (unsigned int hit = 0; hit < fInputHitsEvent->GetNumberOfHits(); hit++) {
359 x = fInputHitsEvent->GetX(hit);
360 y = fInputHitsEvent->GetY(hit);
361 z = fInputHitsEvent->GetZ(hit);
362 energy = fInputHitsEvent->GetEnergy(hit);
363 // if (hit%10==0) printf("hit: x %lf y %lf z %lf Energy %lf\n", x,
364 // y, z, energy); cout << "hit: x " << x << " y " << y <<
365 // " z " << z << " Energy " << energy << endl;
366
367 // assuming energy in keV, W factor in eV
368 Medium* tmed = fGeometry->GetGfMedium(x, y, z);
369 if (!tmed) {
370 cout << "no medium found at x " << x << " y " << y << " z " << z << endl;
371 continue;
372 // } else {
373 // cout << " medium " << tmed->GetName() << " W " <<
374 // tmed->GetW() << " at x " << x << " y " << y << " z " << z <<
375 // endl;
376 }
377 double Wfactor = tmed->GetW();
378 double nb_electrons_real = energy * 1000. / Wfactor / fPEReduction;
379 unsigned int nb_electrons =
380 fRandom->Poisson(nb_electrons_real); // we need an int number of electrons to drift...
381 // if (nb_electrons>0) printf("hit: x %lf y %lf z %lf Energy %lf\n",
382 // x, y, z, energy); if (nb_electrons>0) cout << " : energy " <<
383 // energy << " nb_electrons_real " << nb_electrons_real << "
384 // nb_electrons " << nb_electrons << endl;
385
386 // lets drift all those electrons
387 for (unsigned int iel = 0; iel < nb_electrons; iel++) {
388 // drift an electron
389 fGfDriftMethod->DriftElectron(x / 10., y / 10., z / 10., 0);
390 // fGfDriftMethod->GetEndPoint(xf, yf, zf, tf, status);
391 if (fGfDriftMethod->GetNumberOfElectronEndpoints() == 0) {
392 cout << " TRestDetectorGarfieldDriftProcess::ProcessEvent: no electron end "
393 "point ???"
394 << endl;
395 continue;
396 }
397
398 // create an hit for the drifted electron
399 fGfDriftMethod->GetElectronEndpoint(0, xi, yi, zi, ti, xf, yf, zf, tf,
400 status); // works with AvalancheMC
401 // xi *= 10; yi *= 10; zi *= 10; // cm to mm
402 xf *= cmTomm;
403 yf *= cmTomm;
404 zf *= cmTomm; // cm to mm
405
406 tf /= 1000.; // ns to us
407 energyf = fPEReduction * Wfactor / 1000.; // back to keV
408 fOutputHitsEvent->AddHit(xf, yf, zf, energyf, tf);
409
410 // if (nb_electrons>0) cout << " : Nendpoint " <<
411 // fGfDriftMethod->GetNumberOfElectronEndpoints() << " xi " <<
412 // xi << " yi " << yi << " zi " << zi << " ti " << ti
413 // << " xf " << xf << " yf " << yf << " zf " <<
414 // zf << " tf " << tf << " status " << status ;
415 }
416 }
417
418 if (fOutputHitsEvent->GetNumberOfHits() == 0) return nullptr;
419
420 // fSignalEvent->PrintEvent();
421
423 cout << "TRestDetectorElectronDiffusionProcess. Hits added : " << fOutputHitsEvent->GetNumberOfHits()
424 << endl;
425 cout << "TRestDetectorElectronDiffusionProcess. Hits total energy : "
426 << fOutputHitsEvent->GetTotalEnergy() << endl;
427 cout << " fTimedHitsEvent " << fOutputHitsEvent << " class " << fOutputHitsEvent->ClassName() << endl;
428 fOutputHitsEvent->PrintEvent(20);
429 }
430
431 return fOutputHitsEvent;
432#else
433 fInputHitsEvent = (TRestDetectorHitsEvent*)inputEvent;
434 fOutputHitsEvent = fInputHitsEvent;
435 RESTDebug << "nullptr process" << RESTendl;
436 return inputEvent;
437
438#endif
439}
440
441#if defined USE_Garfield
442
444 // Function to be executed once at the end of the process
445 // (after all events have been processed)
446
447 // Start by calling the EndProcess function of the abstract class.
448 // Comment this if you don't want it.
449 // TRestEventProcess::EndProcess();
450}
451
453 fGasPressure = StringToDouble(GetParameter("gasPressure", "-1"));
454 // fElectricField = GetDblParameterWithUnits( "electricField" );
455 fDriftPotential = GetDblParameterWithUnits("driftPotential");
456 fPEReduction = StringToDouble(GetParameter("primaryElectronReduction", "1"));
457 fStopDistance = StringToDouble(GetParameter("stopDistance", "2"));
458
459 // TODO : Still units must be implemented for velocity quantities
460
461 fGDML_Filename = GetParameter("geometryPath", "") + GetParameter("gdml_file", "");
462}
463
464#endif
void Initialize() override
Making default settings.
TRestEvent * ProcessEvent(TRestEvent *inputEvent) override
Process one event.
virtual void PrintEvent() const
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.
TVector3 GetNormal() const
Returns a TVector3 with a vector normal to the readout plane.
TVector3 GetPosition() const
Returns a TVector3 with the readout plane position.
size_t GetNumberOfModules() const
Returns the total number of modules in the readout plane.
A metadata class to generate/store a readout description.
virtual void InitFromConfigFile() override
To make settings from rml file. This method must be implemented in the derived class.
virtual void EndProcess()
To be executed at the end of the run (outside event loop)
virtual void InitProcess()
To be executed at the beginning of the run (outside event loop)
A base class for any REST event.
Definition TRestEvent.h:38
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_Info
+show most of the information for each steps
@ REST_Debug
+show the defined debug messages
Double_t StringToDouble(std::string in)
Gets a double from a string.