Garfield++ 4.0
A toolkit for the detailed simulation of particle detectors based on ionisation measurement in gases and semiconductors
Loading...
Searching...
No Matches
Component.cc
Go to the documentation of this file.
1#include <cmath>
2#include <iostream>
3
6
7namespace Garfield {
8
9Component::Component(const std::string& name) {
10 m_className = "Component" + name;
11}
12
14 // Make sure the geometry is defined
15 if (!geo) {
16 std::cerr << m_className << "::SetGeometry: Null pointer.\n";
17 return;
18 }
19 m_geometry = geo;
20}
21
22Medium* Component::GetMedium(const double x, const double y, const double z) {
23 if (!m_geometry) return nullptr;
24 return m_geometry->GetMedium(x, y, z);
25}
26
28 m_geometry = nullptr;
29 m_ready = false;
30 // Reset periodicities.
31 m_periodic.fill(false);
32 m_mirrorPeriodic.fill(false);
33 m_axiallyPeriodic.fill(false);
34 m_rotationSymmetric.fill(false);
35 // Reset the magnetic field.
36 m_b0.fill(0.);
37 Reset();
38}
39
40void Component::WeightingField(const double /*x*/, const double /*y*/,
41 const double /*z*/, double& wx, double& wy,
42 double& wz, const std::string& /*label*/) {
43 if (m_debug) {
44 std::cerr << m_className << "::WeightingField: Function not implemented.\n";
45 }
46 wx = wy = wz = 0.;
47}
48
49void Component::DelayedWeightingField(const double /*x*/, const double /*y*/,
50 const double /*z*/, const double /*t*/,
51 double& wx, double& wy, double& wz,
52 const std::string& /*label*/) {
53 if (m_debug) {
54 std::cerr << m_className << "::DelayedWeightingField: Not implemented.\n";
55 }
56 wx = wy = wz = 0.;
57}
58
59double Component::WeightingPotential(const double /*x*/, const double /*y*/,
60 const double /*z*/,
61 const std::string& /*label*/) {
62 if (m_debug) {
63 std::cerr << m_className << "::WeightingPotential: Not implemented.\n";
64 }
65 return 0.;
66}
67
68double Component::DelayedWeightingPotential(const double /*x*/,
69 const double /*y*/,
70 const double /*z*/,
71 const double /*t*/,
72 const std::string& /*label*/) {
73 if (m_debug) {
74 std::cerr << m_className
75 << "::DelayedWeightingPotential: Not implemented.\n";
76 }
77 return 0.;
78}
79
80
81void Component::MagneticField(const double x, const double y, const double z,
82 double& bx, double& by, double& bz, int& status) {
83 bx = m_b0[0];
84 by = m_b0[1];
85 bz = m_b0[2];
86 if (m_debug) {
87 std::cout << m_className << "::MagneticField: Field at (" << x << ", " << y
88 << ", " << z << ") is (" << bx << ", " << by << ", " << bz
89 << ")\n";
90 }
91 status = 0;
92}
93
94void Component::SetMagneticField(const double bx, const double by,
95 const double bz) {
96 m_b0 = {bx, by, bz};
97}
98
99bool Component::GetBoundingBox(double& xmin, double& ymin, double& zmin,
100 double& xmax, double& ymax, double& zmax) {
101 if (!m_geometry) return false;
102 return m_geometry->GetBoundingBox(xmin, ymin, zmin, xmax, ymax, zmax);
103}
104
105bool Component::GetElementaryCell(double& xmin, double& ymin, double& zmin,
106 double& xmax, double& ymax, double& zmax) {
107 return GetBoundingBox(xmin, ymin, zmin, xmax, ymax, zmax);
108}
109
110bool Component::IsWireCrossed(const double /*x0*/, const double /*y0*/,
111 const double /*z0*/, const double /*x1*/,
112 const double /*y1*/, const double /*z1*/,
113 double& /*xc*/, double& /*yc*/, double& /*zc*/,
114 const bool /*centre*/, double& /*rc*/) {
115 return false;
116}
117
118bool Component::IsInTrapRadius(const double /*q0*/, const double x0,
119 const double y0, const double /*z0*/, double& xw,
120 double& yw, double& rw) {
121 xw = x0;
122 yw = y0;
123 rw = 0.;
124 return false;
125}
126
127double Component::IntegrateFluxCircle(const double xc, const double yc,
128 const double r, const unsigned int nI) {
129 // FLDIN2, FCHK3
130 if (nI == 0) {
131 std::cerr << m_className << "::IntegrateFluxCircle:\n"
132 << " Number of intervals must be > 0.\n";
133 return 0.;
134 }
135 // Number of Gaussian quadrature points per interval.
136 constexpr size_t nG = 6;
137 constexpr std::array<double, nG> t = {
138 -0.932469514203152028, -0.661209386466264514, -0.238619186083196909,
139 0.238619186083196909, 0.661209386466264514, 0.932469514203152028};
140 constexpr std::array<double, nG> w = {
141 0.171324492379170345, 0.360761573048138608, 0.467913934572691047,
142 0.467913934572691047, 0.360761573048138608, 0.171324492379170345};
143
144 // Width and half-width of intervals.
145 const double d = TwoPi / nI;
146 const double h = 0.5 * d;
147 // Arguments of ElectricField.
148 double ex = 0., ey = 0., ez = 0.;
149 Medium* m = nullptr;
150 int status = 0;
151 // Perform the integration.
152 double s = 0.;
153 for (size_t i = 0; i < nG; ++i) {
154 const double phi0 = h * (1. + t[i]);
155 for (unsigned int k = 0; k < nI; ++k) {
156 const double phi = phi0 + k * d;
157 const double cp = cos(phi);
158 const double sp = sin(phi);
159 ElectricField(xc + cp * r, yc + sp * r, 0., ex, ey, ez, m, status);
160 s += w[i] * r * (ex * cp + ey * sp);
161 }
162 }
163 return h * s * VacuumPermittivity;
164}
165
166double Component::IntegrateFluxSphere(const double xc, const double yc,
167 const double zc, const double r,
168 const unsigned int nI) {
169 // FLDIN3, FCHK2, FCHK1
170 if (nI == 0) {
171 std::cerr << m_className << "::IntegrateFluxSphere:\n"
172 << " Number of intervals must be > 0.\n";
173 return 0.;
174 }
175 // Number of Gaussian quadrature points.
176 constexpr size_t nG = 6;
177 constexpr std::array<double, nG> t = {
178 -0.932469514203152028, -0.661209386466264514, -0.238619186083196909,
179 0.238619186083196909, 0.661209386466264514, 0.932469514203152028};
180 constexpr std::array<double, nG> w = {
181 0.171324492379170345, 0.360761573048138608, 0.467913934572691047,
182 0.467913934572691047, 0.360761573048138608, 0.171324492379170345};
183
184 const double r2 = r * r;
185 // Width and half-width of theta intervals.
186 const double dt = Pi / nI;
187 const double ht = 0.5 * dt;
188 // Width and half-width of phi intervals.
189 const double dp = TwoPi / nI;
190 const double hp = 0.5 * dp;
191 // Arguments of ElectricField.
192 double ex = 0., ey = 0., ez = 0.;
193 Medium* m = nullptr;
194 int status = 0;
195 // Perform the integration.
196 double s2 = 0.;
197 // Loop over theta.
198 for (size_t i = 0; i < nG; ++i) {
199 const double theta0 = ht * (1. + t[i]) - HalfPi;
200 for (unsigned int k = 0; k < nI; ++k) {
201 const double theta = theta0 + k * dt;
202 const double ct = cos(theta);
203 const double st = sin(theta);
204 const double z = zc + st * r;
205 double s1 = 0.;
206 // Loop over phi.
207 for (size_t ii = 0; ii < nG; ++ii) {
208 const double phi0 = hp * (1. + t[ii]);
209 for (unsigned int kk = 0; kk < nI; ++kk) {
210 const double phi = phi0 + kk * dp;
211 const double cp = cos(phi);
212 const double sp = sin(phi);
213 const double x = xc + cp * ct * r;
214 const double y = yc + sp * ct * r;
215 ElectricField(x, y, z, ex, ey, ez, m, status);
216 s1 += w[ii] * ((ex * cp + ey * sp) * ct + ez * st);
217 }
218 }
219 s2 += w[i] * r2 * ct * hp * s1;
220 }
221 }
222 return ht * s2 * VacuumPermittivity;
223}
224
226 const double x0, const double y0, const double z0, const double dx1,
227 const double dy1, const double dz1, const double dx2, const double dy2,
228 const double dz2, const unsigned int nU, const unsigned int nV) {
229
231 x0, y0, z0, dx1, dy1, dz1, dx2, dy2, dz2, nU, nV, false, "");
232}
233
235 const double x0, const double y0, const double z0, const double dx1,
236 const double dy1, const double dz1, const double dx2, const double dy2,
237 const double dz2, const unsigned int nU, const unsigned int nV) {
238
240 x0, y0, z0, dx1, dy1, dz1, dx2, dy2, dz2, nU, nV, true, id);
241}
242
244 const double x0, const double y0, const double z0, const double dx1,
245 const double dy1, const double dz1, const double dx2, const double dy2,
246 const double dz2, const unsigned int nU, const unsigned int nV,
247 const bool wfield, const std::string& label) {
248
249 // FLDIN4, FCHK4, FCHK5
250 if (nU <= 1 || nV <= 1) {
251 std::cerr << m_className << "::IntegrateFluxParallelogram:\n"
252 << " Number of points to integrate over must be > 1.\n";
253 return 0.;
254 }
255 // Number of Gaussian quadrature points.
256 constexpr size_t nG = 6;
257 constexpr std::array<double, nG> t = {
258 -0.932469514203152028, -0.661209386466264514, -0.238619186083196909,
259 0.238619186083196909, 0.661209386466264514, 0.932469514203152028};
260 constexpr std::array<double, nG> w = {
261 0.171324492379170345, 0.360761573048138608, 0.467913934572691047,
262 0.467913934572691047, 0.360761573048138608, 0.171324492379170345};
263
264 // Compute the normal vector.
265 const double xn = dy1 * dz2 - dz1 * dy2;
266 const double yn = dz1 * dx2 - dx1 * dz2;
267 const double zn = dx1 * dy2 - dy1 * dx2;
268 if (m_debug) {
269 std::cout << m_className << "::IntegrateFluxParallelogram:\n"
270 << " Normal vector = " << xn << ", " << yn << ", " << zn
271 << ".\n";
272 }
273 // If this vector has zero norm, return 0 flux.
274 const double d1 = dx1 * dx1 + dy1 * dy1 + dz1 * dz1;
275 const double d2 = dx2 * dx2 + dy2 * dy2 + dz2 * dz2;
276 if (xn * xn + yn * yn + zn * zn < 1.e-10 * sqrt(d1 * d2) ||
277 d1 < 1.e-10 * d2 || d2 < 1.e-10 * d1) {
278 std::cerr << m_className << "::IntegrateFluxParallelogram:\n"
279 << " Parallelogram does not have non-zero area.\n";
280 return 0.;
281 }
282
283 // (Half-)step sizes in the two directions.
284 const double du = 1. / nU;
285 const double hu = 0.5 * du;
286 const double dv = 1. / nV;
287 const double hv = 0.5 * dv;
288 // Arguments of ElectricField.
289 double fx = 0., fy = 0., fz = 0.;
290 Medium* m = nullptr;
291 int status = 0;
292 // Perform the integration.
293 double s2 = 0.;
294 for (size_t i = 0; i < nG; ++i) {
295 const double v0 = hv * (1. + t[i]);
296 for (unsigned int k = 0; k < nV; ++k) {
297 const double v = v0 + k * dv;
298 double s1 = 0.;
299 for (size_t ii = 0; ii < nG; ++ii) {
300 const double u0 = hu * (1. + t[ii]);
301 for (unsigned int kk = 0; kk < nU; ++kk) {
302 const double u = u0 + kk * du;
303 const double x = x0 + u * dx1 + v * dx2;
304 const double y = y0 + u * dy1 + v * dy2;
305 const double z = z0 + u * dz1 + v * dz2;
306 if (wfield) {
307 WeightingField(x, y, z, fx, fy, fz, label);
308 } else {
309 ElectricField(x, y, z, fx, fy, fz, m, status);
310 }
311 s1 += w[ii] * (fx * xn + fy * yn + fz * zn);
312 }
313 }
314 s2 += w[i] * hu * s1;
315 }
316 }
317 return hv * s2;
318}
319
320double Component::IntegrateFluxLine(const double x0, const double y0,
321 const double z0, const double x1,
322 const double y1, const double z1,
323 const double xp, const double yp,
324 const double zp, const unsigned int nI,
325 const int isign) {
326 // FLDIN5
327 // Normalise the norm vector.
328 const double pmag2 = xp * xp + yp * yp + zp * zp;
329 if (pmag2 <= 0.) {
330 std::cerr << m_className << "::IntegrateFluxLine:\n"
331 << " Normal vector has zero length; flux set to 0.\n";
332 return 0.;
333 }
334 const double pmag = sqrt(pmag2);
335 const double xn = xp / pmag;
336 const double yn = yp / pmag;
337 const double zn = zp / pmag;
338
339 // Check integration points.
340 if (nI <= 1) {
341 std::cerr << m_className << "::IntegrateFluxLine:\n"
342 << " Number of points to integrate over must be > 1.\n";
343 return 0.;
344 }
345 // Ensure the segment has non-zero length.
346 const double vx = x1 - x0;
347 const double vy = y1 - y0;
348 const double vz = z1 - z0;
349 const double vmag2 = vx * vx + vy * vy + vz * vz;
350 if (vmag2 <= 0.) {
351 std::cerr << m_className << "::IntegrateFluxLine:\n"
352 << " Segment has zero length; flux set to 0.\n";
353 return 0.;
354 }
355 const double vmag = sqrt(vmag2);
356 // Segment should be perpendicular to the norm vector.
357 if (fabs(vx * xn + vy * yn + vz * zn) > 1.e-4 * vmag) {
358 std::cerr << m_className << "::IntegrateFluxLine:\n"
359 << " Segment is not perpendicular to norm vector.\n";
360 return 0.;
361 }
362
363 // Perform the integration.
364 constexpr size_t nG = 6;
365 constexpr std::array<double, nG> t = {
366 -0.932469514203152028, -0.661209386466264514, -0.238619186083196909,
367 0.238619186083196909, 0.661209386466264514, 0.932469514203152028};
368 constexpr std::array<double, nG> w = {
369 0.171324492379170345, 0.360761573048138608, 0.467913934572691047,
370 0.467913934572691047, 0.360761573048138608, 0.171324492379170345};
371
372 const double d = 1. / nI;
373 const double h = 0.5 * d;
374 // Arguments of ElectricField.
375 double ex = 0., ey = 0., ez = 0.;
376 Medium* m = nullptr;
377 int status = 0;
378 double s = 0.;
379 for (size_t i = 0; i < nG; ++i) {
380 const double u0 = h * (1. + t[i]);
381 for (unsigned int k = 0; k < nI; ++k) {
382 const double u = u0 + k * d;
383 const double x = x0 + u * vx;
384 const double y = y0 + u * vy;
385 const double z = z0 + u * vz;
386 ElectricField(x, y, z, ex, ey, ez, m, status);
387 double fn = ex * xn + ey * yn + ez * zn;
388 if (isign != 0) {
389 // TODO: -1?
390 fn = isign * fn > 0 ? fabs(fn) : -1.;
391 }
392 s += w[i] * fn;
393 }
394 }
395 return s * vmag;
396}
397
398} // namespace Garfield
virtual double WeightingPotential(const double x, const double y, const double z, const std::string &label)
Definition: Component.cc:59
virtual bool GetBoundingBox(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax)
Get the bounding box coordinates.
Definition: Component.cc:99
std::array< bool, 3 > m_rotationSymmetric
Rotation symmetry around x-axis, y-axis, z-axis.
Definition: Component.hh:350
std::array< bool, 3 > m_mirrorPeriodic
Mirror periodicity in x, y, z.
Definition: Component.hh:346
virtual void Reset()=0
Reset the component.
virtual void ElectricField(const double x, const double y, const double z, double &ex, double &ey, double &ez, Medium *&m, int &status)=0
virtual Medium * GetMedium(const double x, const double y, const double z)
Get the medium at a given location (x, y, z).
Definition: Component.cc:22
virtual void WeightingField(const double x, const double y, const double z, double &wx, double &wy, double &wz, const std::string &label)
Definition: Component.cc:40
bool m_debug
Switch on/off debugging messages.
Definition: Component.hh:341
virtual void DelayedWeightingField(const double x, const double y, const double z, const double t, double &wx, double &wy, double &wz, const std::string &label)
Definition: Component.cc:49
double IntegrateWeightingFluxParallelogram(const std::string &label, const double x0, const double y0, const double z0, const double dx1, const double dy1, const double dz1, const double dx2, const double dy2, const double dz2, const unsigned int nU=20, const unsigned int nV=20)
Definition: Component.cc:234
virtual bool IsWireCrossed(const double x0, const double y0, const double z0, const double x1, const double y1, const double z1, double &xc, double &yc, double &zc, const bool centre, double &rc)
Definition: Component.cc:110
Component()=delete
Default constructor.
std::array< bool, 3 > m_periodic
Simple periodicity in x, y, z.
Definition: Component.hh:344
virtual void Clear()
Reset.
Definition: Component.cc:27
std::string m_className
Class name.
Definition: Component.hh:329
double IntegrateFluxCircle(const double xc, const double yc, const double r, const unsigned int nI=50)
Definition: Component.cc:127
Geometry * m_geometry
Pointer to the geometry.
Definition: Component.hh:332
double IntegrateFluxSphere(const double xc, const double yc, const double zc, const double r, const unsigned int nI=20)
Definition: Component.cc:166
virtual void MagneticField(const double x, const double y, const double z, double &bx, double &by, double &bz, int &status)
Definition: Component.cc:81
bool m_ready
Ready for use?
Definition: Component.hh:338
void SetMagneticField(const double bx, const double by, const double bz)
Set a constant magnetic field.
Definition: Component.cc:94
virtual bool IsInTrapRadius(const double q0, const double x0, const double y0, const double z0, double &xw, double &yw, double &rw)
Definition: Component.cc:118
std::array< double, 3 > m_b0
Constant magnetic field.
Definition: Component.hh:335
std::array< bool, 3 > m_axiallyPeriodic
Axial periodicity in x, y, z.
Definition: Component.hh:348
virtual bool GetElementaryCell(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax)
Get the coordinates of the elementary cell.
Definition: Component.cc:105
virtual double DelayedWeightingPotential(const double x, const double y, const double z, const double t, const std::string &label)
Definition: Component.cc:68
double IntegrateFluxParallelogram(const double x0, const double y0, const double z0, const double dx1, const double dy1, const double dz1, const double dx2, const double dy2, const double dz2, const unsigned int nU=20, const unsigned int nV=20)
Definition: Component.cc:225
virtual void SetGeometry(Geometry *geo)
Define the geometry.
Definition: Component.cc:13
double IntegrateFluxLine(const double x0, const double y0, const double z0, const double x1, const double y1, const double z1, const double xp, const double yp, const double zp, const unsigned int nI, const int isign=0)
Definition: Component.cc:320
Abstract base class for geometry classes.
Definition: Geometry.hh:13
virtual bool GetBoundingBox(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax)=0
Get the bounding box (envelope of the geometry).
virtual Medium * GetMedium(const double x, const double y, const double z, const bool tesselated=false) const =0
Retrieve the medium at a given point.
Abstract base class for media.
Definition: Medium.hh:13
DoubleAc sqrt(const DoubleAc &f)
Definition: DoubleAc.cpp:314