Garfield++ 5.0
A toolkit for the detailed simulation of particle detectors based on ionisation measurement in gases and semiconductors
Loading...
Searching...
No Matches
ComponentUser.cc
Go to the documentation of this file.
1#include <iostream>
2
3#include <TInterpreter.h>
4#include <TROOT.h>
5
7
8namespace {
9
10void RemoveSpecialCharacters(std::string& str) {
11
12 str.erase(std::remove_if(str.begin(), str.end(),
13 [](char c) { return std::isspace(c) || !std::isalnum(c); }),
14 str.end());
15}
16
17void* MakeFieldFunction(const std::string& fname,
18 const std::string& expression,
19 const bool wfield = false,
20 const bool bfield = false,
21 const bool timeDependent = false) {
22 std::string code = "std::function<void("
23 "const double, const double, const double, ";
24 if (timeDependent) code += "const double, ";
25 code += "double&, double&, double&)> ";
26 code += fname + " = [](const double x, const double y, const double z, ";
27 if (timeDependent) code += "const double t, ";
28 if (wfield && (expression.find("wx") != std::string::npos ||
29 expression.find("wy") != std::string::npos ||
30 expression.find("wz") != std::string::npos)) {
31 code += "double& wx, double& wy, double& wz) {";
32 code += "wx = wy = wz = 0.;";
33 } else if (bfield) {
34 code += "double& bx, double& by, double& bz) {";
35 code += "bx = by = bz = 0.;";
36 } else {
37 code += "double& ex, double& ey, double& ez) {";
38 code += "ex = ey = ez = 0.;";
39 }
40 code += expression + ";};";
41
42 ROOT::GetROOT();
43 TInterpreter::EErrorCode ecode;
44 gInterpreter->ProcessLine(code.c_str(), &ecode);
45 code = fname + ";";
46 return (void*)gInterpreter->ProcessLine(code.c_str());
47}
48
49void* MakePotentialFunction(const std::string& fname,
50 const std::string& expression,
51 const bool timeDependent = false) {
52 std::string code = "std::function<double("
53 "const double, const double, const double";
54 if (timeDependent) code += ", const double";
55 code += ")> ";
56 code += fname + " = [](const double x, const double y, const double z";
57 if (timeDependent) code += ", const double t";
58 code += ") {";
59 if (expression.find("return") == std::string::npos) code += "return ";
60 code += expression + ";};";
61
62 ROOT::GetROOT();
63 TInterpreter::EErrorCode ecode;
64 gInterpreter->ProcessLine(code.c_str(), &ecode);
65 code = fname + ";";
66 return (void*)gInterpreter->ProcessLine(code.c_str());
67}
68
69}
70
71namespace Garfield {
72
74
75void ComponentUser::ElectricField(const double x, const double y,
76 const double z, double& ex, double& ey,
77 double& ez, Medium*& m, int& status) {
78 if (!m_efield) {
79 ex = ey = ez = 0.;
80 m = nullptr;
81 status = -10;
82 return;
83 }
84
85 m_efield(x, y, z, ex, ey, ez);
86 m = GetMedium(x, y, z);
87 if (!m) {
88 if (m_debug) {
89 std::cerr << m_className << "::ElectricField:\n (" << x << ", " << y
90 << ", " << z << ") is not inside a medium.\n";
91 }
92 status = -6;
93 return;
94 }
95
96 status = m->IsDriftable() ? 0 : -5;
97}
98
99void ComponentUser::ElectricField(const double x, const double y,
100 const double z, double& ex, double& ey,
101 double& ez, double& v, Medium*& m,
102 int& status) {
103 if (!m_efield) {
104 ex = ey = ez = v = 0.;
105 m = nullptr;
106 status = -10;
107 return;
108 }
109 m_efield(x, y, z, ex, ey, ez);
110
111 v = m_epot ? m_epot(x, y, z) : 0.;
112 m = GetMedium(x, y, z);
113 if (!m) {
114 if (m_debug) {
115 std::cerr << m_className << "::ElectricField:\n (" << x << ", " << y
116 << ", " << z << ") is not inside a medium.\n";
117 }
118 status = -6;
119 return;
120 }
121
122 status = m->IsDriftable() ? 0 : -5;
123}
124
125bool ComponentUser::GetVoltageRange(double& vmin, double& vmax) {
126 vmin = vmax = 0.;
127 return false;
128}
129
130void ComponentUser::MagneticField(const double x, const double y,
131 const double z, double& bx, double& by,
132 double& bz, int& status) {
133 if (!m_bfield) {
134 Component::MagneticField(x, y, z, bx, by, bz, status);
135 return;
136 }
137 m_bfield(x, y, z, bx, by, bz);
138 status = 0;
139}
140
141void ComponentUser::WeightingField(const double x, const double y,
142 const double z, double& wx, double& wy,
143 double& wz, const std::string& label) {
144 wx = wy = wz = 0.;
145 if (m_wfield.count(label) > 0) {
146 m_wfield[label](x, y, z, wx, wy, wz);
147 }
148}
149
150double ComponentUser::WeightingPotential(const double x, const double y,
151 const double z,
152 const std::string& label) {
153 double v = 0.;
154 if (m_wpot.count(label) > 0) v = m_wpot[label](x, y, z);
155 return v;
156}
157
158void ComponentUser::DelayedWeightingField(const double x, const double y,
159 const double z, const double t,
160 double& wx, double& wy, double& wz,
161 const std::string& label) {
162 wx = wy = wz = 0.;
163 if (m_dwfield.count(label) > 0) {
164 m_dwfield[label](x, y, z, t, wx, wy, wz);
165 }
166}
167
169 const double x, const double y, const double z, const double t,
170 const std::string& label) {
171
172 double v = 0.;
173 if (m_dwpot.count(label) > 0) v = m_dwpot[label](x, y, z, t);
174 return v;
175}
176
178 double& xmin, double& ymin, double& zmin,
179 double& xmax, double& ymax, double& zmax) {
180
181 if (!m_hasArea) {
182 return Component::GetBoundingBox(xmin, ymin, zmin, xmax, ymax, zmax);
183 }
184 xmin = m_xmin[0];
185 ymin = m_xmin[1];
186 zmin = m_xmin[2];
187 xmax = m_xmax[0];
188 ymax = m_xmax[1];
189 zmax = m_xmax[2];
190 return true;
191}
192
194 return m_bfield ? true : Component::HasMagneticField();
195}
196
198 std::function<void(const double, const double, const double,
199 double&, double&, double&)> f) {
200 if (!f) {
201 std::cerr << m_className << "::SetElectricField: Function is empty.\n";
202 return;
203 }
204 m_efield = f;
205 m_ready = true;
206}
207
208void ComponentUser::SetElectricField(const std::string& expression) {
209 const std::string fname = "fComponentUserEfield";
210 auto fPtr = MakeFieldFunction(fname, expression);
211 if (!fPtr) {
212 std::cerr << m_className << "::SetElectricField: "
213 << "Could not convert the expression.\n";
214 return;
215 }
216 typedef std::function<void(const double, const double, const double,
217 double&, double&, double&)> Fcn;
218 Fcn& f = *((Fcn *) fPtr);
219 m_efield = f;
220 m_ready = true;
221}
222
224 std::function<double(const double, const double, const double)> f) {
225 if (!f) {
226 std::cerr << m_className << "::SetPotential: Function is empty.\n";
227 return;
228 }
229 m_epot = f;
230}
231
232void ComponentUser::SetPotential(const std::string& expression) {
233 const std::string fname = "fComponentUserEpot";
234 auto fPtr = MakePotentialFunction(fname, expression);
235 if (!fPtr) {
236 std::cerr << m_className << "::SetPotential: "
237 << "Could not convert the expression.\n";
238 return;
239 }
240 typedef std::function<double(const double, const double, const double)> Fcn;
241 Fcn& f = *((Fcn *) fPtr);
242 m_epot = f;
243}
244
246 std::function<void(const double, const double, const double,
247 double&, double&, double&)> f,
248 const std::string& label) {
249 if (!f) {
250 std::cerr << m_className << "::SetWeightingField: Function is empty.\n";
251 return;
252 }
253 m_wfield[label] = f;
254}
255
256void ComponentUser::SetWeightingField(const std::string& expression,
257 const std::string& label) {
258 std::string fname = label;
259 RemoveSpecialCharacters(fname);
260 fname = "fComponentUserWfield" + fname;
261 auto fPtr = MakeFieldFunction(fname, expression, true);
262 if (!fPtr) {
263 std::cerr << m_className << "::SetWeightingField: "
264 << "Could not convert the expression.\n";
265 return;
266 }
267 typedef std::function<void(const double, const double, const double,
268 double&, double&, double&)> Fcn;
269 Fcn& f = *((Fcn *) fPtr);
270 m_wfield[label] = f;
271}
272
274 std::function<double(const double, const double, const double)> f,
275 const std::string& label) {
276 if (!f) {
277 std::cerr << m_className << "::SetWeightingPotential: Function is empty.\n";
278 return;
279 }
280 m_wpot[label] = f;
281}
282
283void ComponentUser::SetWeightingPotential(const std::string& expression,
284 const std::string& label) {
285 std::string fname = label;
286 RemoveSpecialCharacters(fname);
287 fname = "fComponentUserWpot" + fname;
288 auto fPtr = MakePotentialFunction(fname, expression);
289 if (!fPtr) {
290 std::cerr << m_className << "::SetWeightingPotential: "
291 << "Could not convert the expression.\n";
292 return;
293 }
294 typedef std::function<double(const double, const double, const double)> Fcn;
295 Fcn& f = *((Fcn *) fPtr);
296 m_wpot[label] = f;
297}
298
300 std::function<void(const double, const double, const double, const double,
301 double&, double&, double&)> f,
302 const std::string& label) {
303
304 if (!f) {
305 std::cerr << m_className << "::SetDelayedWeightingField: "
306 << "Function is empty.\n";
307 return;
308 }
309 m_dwfield[label] = f;
310}
311
312void ComponentUser::SetDelayedWeightingField(const std::string& expression,
313 const std::string& label) {
314
315 std::string fname = label;
316 RemoveSpecialCharacters(fname);
317 fname = "fComponentUserDWfield" + fname;
318 auto fPtr = MakeFieldFunction(fname, expression, true, false, true);
319 if (!fPtr) {
320 std::cerr << m_className << "::SetDelayedWeightingField: "
321 << "Could not convert the expression.\n";
322 return;
323 }
324 typedef std::function<void(const double, const double, const double,
325 const double, double&, double&, double&)> Fcn;
326 Fcn& f = *((Fcn *) fPtr);
327 m_dwfield[label] = f;
328}
329
331 std::function<double(const double, const double, const double,
332 const double)> f,
333 const std::string& label) {
334 if (!f) {
335 std::cerr << m_className << "::SetDelayedWeightingPotential: "
336 << "Function is empty.\n";
337 return;
338 }
339 m_dwpot[label] = f;
340}
341
343 const std::string& expression, const std::string& label) {
344 std::string fname = label;
345 RemoveSpecialCharacters(fname);
346 fname = "fComponentUserDWpot" + fname;
347 auto fPtr = MakePotentialFunction(fname, expression, true);
348 if (!fPtr) {
349 std::cerr << m_className << "::SetDelayedWeightingPotential: "
350 << "Could not convert the expression.\n";
351 return;
352 }
353 typedef std::function<double(const double, const double, const double,
354 const double)> Fcn;
355 Fcn& f = *((Fcn *) fPtr);
356 m_dwpot[label] = f;
357}
358
360 std::function<void(const double, const double, const double,
361 double&, double&, double&)> f) {
362 if (!f) {
363 std::cerr << m_className << "::SetMagneticField: Function is empty.\n";
364 return;
365 }
366 m_bfield = f;
367}
368
369void ComponentUser::SetMagneticField(const std::string& expression) {
370
371 const std::string fname = "fComponentUserBfield";
372 auto fPtr = MakeFieldFunction(fname, expression, false, true);
373 if (!fPtr) {
374 std::cerr << m_className << "::SetMagneticField: "
375 << "Could not convert the expression.\n";
376 return;
377 }
378 typedef std::function<void(const double, const double, const double,
379 double&, double&, double&)> Fcn;
380 Fcn& f = *((Fcn *) fPtr);
381 m_bfield = f;
382}
383
385 const double xmin, const double ymin, const double zmin,
386 const double xmax, const double ymax, const double zmax) {
387
388 m_xmin[0] = std::min(xmin, xmax);
389 m_xmin[1] = std::min(ymin, ymax);
390 m_xmin[2] = std::min(zmin, zmax);
391 m_xmax[0] = std::max(xmin, xmax);
392 m_xmax[1] = std::max(ymin, ymax);
393 m_xmax[2] = std::max(zmin, zmax);
394 m_hasArea = true;
395}
396
398 m_xmin.fill(0.);
399 m_xmax.fill(0.);
400 m_hasArea = false;
401}
402
403void ComponentUser::Reset() {
404 m_efield = nullptr;
405 m_epot = nullptr;
406 m_wfield.clear();
407 m_wpot.clear();
408 m_dwfield.clear();
409 m_dwpot.clear();
410 m_bfield = nullptr;
411 m_ready = false;
412 UnsetArea();
413 m_medium = nullptr;
414}
415
416void ComponentUser::UpdatePeriodicity() {
417 if (m_debug) {
418 std::cerr << m_className << "::UpdatePeriodicity:\n"
419 << " Periodicities are not supported.\n";
420 }
421}
422}
void DelayedWeightingField(const double x, const double y, const double z, const double t, double &wx, double &wy, double &wz, const std::string &label) override
void SetDelayedWeightingPotential(std::function< double(const double, const double, const double, const double)>, const std::string &label)
double WeightingPotential(const double x, const double y, const double z, const std::string &label) override
bool GetBoundingBox(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax) override
Get the bounding box coordinates.
void SetDelayedWeightingField(std::function< void(const double, const double, const double, const double, double &, double &, double &)>, const std::string &label)
Set the function to be called for calculating the delayed weighting field.
double DelayedWeightingPotential(const double x, const double y, const double z, const double t, const std::string &label) override
void UnsetArea()
Remove the explicit limits of the active area.
void SetElectricField(std::function< void(const double, const double, const double, double &, double &, double &)>)
Set the function to be called for calculating the electric field.
void WeightingField(const double x, const double y, const double z, double &wx, double &wy, double &wz, const std::string &label) override
ComponentUser()
Constructor.
void MagneticField(const double x, const double y, const double z, double &bx, double &by, double &bz, int &status) override
void SetWeightingPotential(std::function< double(const double, const double, const double)>, const std::string &label)
Set the function to be called for calculating the weighting potential.
void SetPotential(std::function< double(const double, const double, const double)>)
Set the function to be called for calculating the electric potential.
Medium * GetMedium(const double x, const double y, const double z) override
Get the medium at a given location (x, y, z).
void SetArea(const double xmin, const double ymin, const double zmin, const double xmax, const double ymax, const double zmax)
bool GetVoltageRange(double &vmin, double &vmax) override
Calculate the voltage range [V].
bool HasMagneticField() const override
Does the component have a non-zero magnetic field?
void SetWeightingField(std::function< void(const double, const double, const double, double &, double &, double &)>, const std::string &label)
Set the function to be called for calculating the weighting field.
void ElectricField(const double x, const double y, const double z, double &ex, double &ey, double &ez, Medium *&m, int &status) override
void SetMagneticField(std::function< void(const double, const double, const double, double &, double &, double &)>)
Set the function to be called for calculating the magnetic field.
virtual bool GetBoundingBox(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax)
Get the bounding box coordinates.
Definition Component.cc:120
bool m_debug
Switch on/off debugging messages.
Definition Component.hh:371
Component()=delete
Default constructor.
virtual bool HasMagneticField() const
Does the component have a non-zero magnetic field?
Definition Component.cc:155
std::string m_className
Class name.
Definition Component.hh:359
virtual void MagneticField(const double x, const double y, const double z, double &bx, double &by, double &bz, int &status)
Definition Component.cc:102
bool m_ready
Ready for use?
Definition Component.hh:368
Abstract base class for media.
Definition Medium.hh:16
bool IsDriftable() const
Is charge carrier transport enabled in this medium?
Definition Medium.hh:77