Garfield++ 5.0
A toolkit for the detailed simulation of particle detectors based on ionisation measurement in gases and semiconductors
Loading...
Searching...
No Matches
SolidTube.cc
Go to the documentation of this file.
1#include <cmath>
2#include <iostream>
3
5#include "Garfield/Polygon.hh"
7
8namespace Garfield {
9
10SolidTube::SolidTube(const double cx, const double cy, const double cz,
11 const double rt, const double lz)
12 : SolidTube(cx, cy, cz, 0., rt, lz) {}
13
14SolidTube::SolidTube(const double cx, const double cy, const double cz,
15 const double rt, const double lz,
16 const double dx, const double dy, const double dz)
17 : SolidTube(cx, cy, cz, rt, lz) {
18 SetDirection(dx, dy, dz);
19}
20
21SolidTube::SolidTube(const double cx, const double cy, const double cz,
22 const double ri, const double ro, const double lz)
23 : Solid(cx, cy, cz, "SolidTube"),
24 m_rO(ro),
25 m_rI(ri),
26 m_lZ(lz) {
27 UpdatePolygon();
28}
29
30SolidTube::SolidTube(const double cx, const double cy, const double cz,
31 const double ri, const double ro, const double lz,
32 const double dx, const double dy, const double dz)
33 : SolidTube(cx, cy, cz, ri, ro, lz) {
34 SetDirection(dx, dy, dz);
35}
36
37void SolidTube::UpdatePolygon() {
38 std::lock_guard<std::mutex> guard(m_mutex);
39 const unsigned int nP = 4. * (m_n - 1);
40 const double alpha = Pi / nP;
41 const double calpha = cos(alpha);
42 // Set the radius of the approximating polygon.
43 m_rpO = m_rO;
44 m_rpI = m_rI;
45 if (m_average) {
46 const double f = 2. / (1. + asinh(tan(alpha)) * calpha / tan(alpha));
47 m_rpO *= f;
48 m_rpI *= f;
49 }
50 // Set the inradius of the polygon.
51 m_riO = m_rpO * calpha;
52 m_riI = m_rpI * calpha;
53 // Set the coordinates of the polygon corners.
54 m_xpO.clear();
55 m_ypO.clear();
56 m_xpI.clear();
57 m_ypI.clear();
58 for (unsigned int i = 0; i < nP; ++i) {
59 const double phi = m_rot + HalfPi * i / (m_n - 1.);
60 const double cphi = cos(phi);
61 const double sphi = sin(phi);
62 m_xpO.push_back(m_rpO * cphi);
63 m_ypO.push_back(m_rpO * sphi);
64 if (m_rpI > 0.) {
65 m_xpI.push_back(m_rpI * cphi);
66 m_ypI.push_back(m_rpI * sphi);
67 }
68 }
69}
70
71bool SolidTube::IsInside(const double x, const double y, const double z,
72 const bool tesselated) const {
73 // Transform the point to local coordinates.
74 double u = x, v = y, w = z;
75 ToLocal(x, y, z, u, v, w);
76
77 if (fabs(w) > m_lZ) return false;
78
79 const double rho = sqrt(u * u + v * v);
80 if (!tesselated) return (rho <= m_rO && rho >= m_rI);
81
82 if (rho > m_rpO || rho < m_riI) return false;
83 if (rho < m_riO && rho > m_rpI) return true;
84 bool inside = false;
85 bool edge = false;
86 Polygon::Inside(m_xpO, m_ypO, u, v, inside, edge);
87 if (inside && !m_xpI.empty()) {
88 Polygon::Inside(m_xpI, m_ypI, u, v, inside, edge);
89 return !inside;
90 }
91 return inside;
92}
93
94bool SolidTube::GetBoundingBox(double& xmin, double& ymin, double& zmin,
95 double& xmax, double& ymax, double& zmax) const {
96 if (m_cTheta == 1. && m_cPhi == 1.) {
97 xmin = m_cX - m_rO;
98 xmax = m_cX + m_rO;
99 ymin = m_cY - m_rO;
100 ymax = m_cY + m_rO;
101 zmin = m_cZ - m_lZ;
102 zmax = m_cZ + m_lZ;
103 return true;
104 }
105
106 const double dd = sqrt(m_rO * m_rO + m_lZ * m_lZ);
107 xmin = m_cX - dd;
108 xmax = m_cX + dd;
109 ymin = m_cY - dd;
110 ymax = m_cY + dd;
111 zmin = m_cZ - dd;
112 zmax = m_cZ + dd;
113 return true;
114}
115
116void SolidTube::SetRadius(const double r) {
117 if (r <= 0.) {
118 std::cerr << "SolidTube::SetRadius: Radius must be > 0.\n";
119 return;
120 }
121 m_rO = r;
122 UpdatePolygon();
123}
124
125void SolidTube::SetHalfLength(const double lz) {
126 if (lz <= 0.) {
127 std::cerr << "SolidTube::SetHalfLength: Half-length must be > 0.\n";
128 return;
129 }
130 m_lZ = lz;
131 UpdatePolygon();
132}
133
134void SolidTube::SetSectors(const unsigned int n) {
135 if (n < 1) {
136 std::cerr << "SolidTube::SetSectors: Number must be > 0.\n";
137 return;
138 }
139 m_n = n;
140 UpdatePolygon();
141}
142
143bool SolidTube::SolidPanels(std::vector<Panel>& panels) {
144
145 const auto id = GetId();
146 const auto nPanels = panels.size();
147 // Direction vector.
148 const double fnorm = sqrt(m_dX * m_dX + m_dY * m_dY + m_dZ * m_dZ);
149 if (fnorm <= 0) {
150 std::cerr << "SolidTube::SolidPanels:\n"
151 << " Zero norm direction vector; no panels generated.\n";
152 return false;
153 }
154
155 const unsigned int nPoints = 4 * (m_n - 1);
156 // Create the top lid(s).
157 if (m_toplid) {
158 const double a = m_cPhi * m_sTheta;
159 const double b = m_sPhi * m_sTheta;
160 const double c = m_cTheta;
161 if (m_rI > 0.) {
162 double alpha = m_rot;
163 double calpha = cos(alpha);
164 double salpha = sin(alpha);
165 double xv0, yv0, zv0;
166 ToGlobal(m_rpI * calpha, m_rpI * salpha, +m_lZ, xv0, yv0, zv0);
167 double xv1, yv1, zv1;
168 ToGlobal(m_rpO * calpha, m_rpO * salpha, +m_lZ, xv1, yv1, zv1);
169 // Go around the cylinder.
170 for (unsigned int i = 0; i < nPoints; ++i) {
171 alpha += HalfPi / (m_n - 1.);
172 calpha = cos(alpha);
173 salpha = sin(alpha);
174 double xv2, yv2, zv2;
175 ToGlobal(m_rpO * calpha, m_rpO * salpha, +m_lZ, xv2, yv2, zv2);
176 double xv3, yv3, zv3;
177 ToGlobal(m_rpI * calpha, m_rpI * salpha, +m_lZ, xv3, yv3, zv3);
178 std::vector<double> xv = {xv0, xv1, xv2, xv3};
179 std::vector<double> yv = {yv0, yv1, yv2, yv3};
180 std::vector<double> zv = {zv0, zv1, zv2, zv3};
181 Panel panel;
182 panel.a = a;
183 panel.b = b;
184 panel.c = c;
185 panel.xv = xv;
186 panel.yv = yv;
187 panel.zv = zv;
188 panel.colour = m_colour;
189 panel.volume = id;
190 panels.push_back(std::move(panel));
191 // Shift.
192 xv0 = xv3;
193 yv0 = yv3;
194 zv0 = zv3;
195 xv1 = xv2;
196 yv1 = yv2;
197 zv1 = zv2;
198 }
199 } else {
200 std::vector<double> xv;
201 std::vector<double> yv;
202 std::vector<double> zv;
203 const double r = m_rpO;
204 for (unsigned int i = 1; i <= nPoints; i++) {
205 const double alpha = m_rot + HalfPi * (i - 1.) / (m_n - 1.);
206 // Rotate into place.
207 double x, y, z;
208 ToGlobal(r * cos(alpha), r * sin(alpha), m_lZ, x, y, z);
209 xv.push_back(x);
210 yv.push_back(y);
211 zv.push_back(z);
212 }
213 Panel panel;
214 panel.a = a;
215 panel.b = b;
216 panel.c = c;
217 panel.xv = xv;
218 panel.yv = yv;
219 panel.zv = zv;
220 panel.colour = m_colour;
221 panel.volume = id;
222 panels.push_back(std::move(panel));
223 }
224 }
225 // Create the bottom lid(s).
226 if (m_botlid) {
227 const double a = -m_cPhi * m_sTheta;
228 const double b = -m_sPhi * m_sTheta;
229 const double c = -m_cTheta;
230 if (m_rI > 0.) {
231 double alpha = m_rot;
232 double calpha = cos(alpha);
233 double salpha = sin(alpha);
234 double xv0, yv0, zv0;
235 ToGlobal(m_rpI * calpha, m_rpI * salpha, -m_lZ, xv0, yv0, zv0);
236 double xv1, yv1, zv1;
237 ToGlobal(m_rpO * calpha, m_rpO * salpha, -m_lZ, xv1, yv1, zv1);
238 // Go around the cylinder.
239 for (unsigned int i = 0; i < nPoints; ++i) {
240 alpha += HalfPi / (m_n - 1.);
241 calpha = cos(alpha);
242 salpha = sin(alpha);
243 double xv2, yv2, zv2;
244 ToGlobal(m_rpO * calpha, m_rpO * salpha, -m_lZ, xv2, yv2, zv2);
245 double xv3, yv3, zv3;
246 ToGlobal(m_rpI * calpha, m_rpI * salpha, -m_lZ, xv3, yv3, zv3);
247 std::vector<double> xv = {xv0, xv1, xv2, xv3};
248 std::vector<double> yv = {yv0, yv1, yv2, yv3};
249 std::vector<double> zv = {zv0, zv1, zv2, zv3};
250 Panel panel;
251 panel.a = a;
252 panel.b = b;
253 panel.c = c;
254 panel.xv = xv;
255 panel.yv = yv;
256 panel.zv = zv;
257 panel.colour = m_colour;
258 panel.volume = id;
259 panels.push_back(std::move(panel));
260 // Shift.
261 xv0 = xv3;
262 yv0 = yv3;
263 zv0 = zv3;
264 xv1 = xv2;
265 yv1 = yv2;
266 zv1 = zv2;
267 }
268 } else {
269 std::vector<double> xv;
270 std::vector<double> yv;
271 std::vector<double> zv;
272 const double r = m_rpO;
273 for (unsigned int i = 1; i <= nPoints; i++) {
274 const double alpha = m_rot + HalfPi * (i - 1.) / (m_n - 1.);
275 // Rotate into place.
276 double x, y, z;
277 ToGlobal(r * cos(alpha), r * sin(alpha), -m_lZ, x, y, z);
278 xv.push_back(x);
279 yv.push_back(y);
280 zv.push_back(z);
281 }
282 Panel panel;
283 panel.a = a;
284 panel.b = b;
285 panel.c = c;
286 panel.xv = xv;
287 panel.yv = yv;
288 panel.zv = zv;
289 panel.colour = m_colour;
290 panel.volume = id;
291 panels.push_back(std::move(panel));
292 }
293 }
294 // Create the side panels.
295 const unsigned int n = m_rpI > 0. ? 2 : 1;
296 for (unsigned int j = 0; j < n; ++j) {
297 const double r = j == 0 ? m_rpO : m_rpI;
298 double u = r * cos(m_rot);
299 double v = r * sin(m_rot);
300 // Rotate into place.
301 double xv0, yv0, zv0;
302 ToGlobal(u, v, -m_lZ, xv0, yv0, zv0);
303 double xv1, yv1, zv1;
304 ToGlobal(u, v, +m_lZ, xv1, yv1, zv1);
305 // Go around the cylinder.
306 for (unsigned int i = 2; i <= nPoints + 1; i++) {
307 // Bottom and top of the line along the axis of the cylinder.
308 double alpha = m_rot + HalfPi * (i - 1.) / (m_n - 1.);
309 u = r * cos(alpha);
310 v = r * sin(alpha);
311 // Rotate into place.
312 double xv2, yv2, zv2;
313 ToGlobal(u, v, +m_lZ, xv2, yv2, zv2);
314 double xv3, yv3, zv3;
315 ToGlobal(u, v, -m_lZ, xv3, yv3, zv3);
316 // Store the plane.
317 Panel panel;
318 alpha = m_rot + HalfPi * (i - 1.5) / (m_n - 1.);
319 const double cAlpha = cos(alpha);
320 const double sAlpha = sin(alpha);
321 panel.a = m_cPhi * m_cTheta * cAlpha - m_sPhi * sAlpha;
322 panel.b = m_sPhi * m_cTheta * cAlpha + m_cPhi * sAlpha;
323 panel.c = -m_sTheta * cAlpha;
324 if (j == 1) {
325 panel.a *= -1.;
326 panel.b *= -1.;
327 panel.c *= -1.;
328 }
329 panel.xv = {xv0, xv1, xv2, xv3};
330 panel.yv = {yv0, yv1, yv2, yv3};
331 panel.zv = {zv0, zv1, zv2, zv3};
332 panel.colour = m_colour;
333 panel.volume = id;
334 panels.push_back(std::move(panel));
335 // Shift the points.
336 xv0 = xv3;
337 yv0 = yv3;
338 zv0 = zv3;
339 xv1 = xv2;
340 yv1 = yv2;
341 zv1 = zv2;
342 }
343 }
344 std::cout << "SolidTube::SolidPanels: " << panels.size() - nPanels
345 << " panels.\n";
346 return true;
347}
348
350
351 // Transform the normal vector to local coordinates.
352 double u = 0., v = 0., w = 0.;
353 VectorToLocal(panel.a, panel.b, panel.c, u, v, w);
354 // Identify the vector.
355 if (w > std::max(std::abs(u), std::abs(v))) {
356 return m_dis[0];
357 } else if (w < -std::max(std::abs(u), std::abs(v))) {
358 return m_dis[1];
359 }
360 return m_dis[2];
361}
362
363void SolidTube::Cut(const double x0, const double y0, const double z0,
364 const double xn, const double yn, const double zn,
365 std::vector<Panel>& panels) {
366
367 // -----------------------------------------------------------------------
368 // PLACYC - Cuts cylinder with a plane.
369 // -----------------------------------------------------------------------
370 std::vector<double> xv;
371 std::vector<double> yv;
372 std::vector<double> zv;
373 double r = m_rpO;
374 const unsigned int nPoints = 4 * (m_n - 1);
375 const double dphi = HalfPi / (m_n - 1.);
376 // Go through the lines of the top and bottom lids.
377 for (const auto zLid : {-m_lZ, +m_lZ}) {
378 double x1, y1, z1;
379 ToGlobal(r * cos(m_rot), r * sin(m_rot), zLid, x1, y1, z1);
380 // Loop over the points.
381 for (unsigned int i = 2; i <= nPoints + 1; ++i) {
382 const double phi = m_rot + (i - 1.) * dphi;
383 double x2, y2, z2;
384 ToGlobal(r * cos(phi), r * sin(phi), zLid, x2, y2, z2);
385 // Cut with the plane.
386 double xc, yc, zc;
387 if (Intersect(x1, y1, z1, x2, y2, z2, x0, y0, z0,
388 xn, yn, zn, xc, yc, zc)) {
389 xv.push_back(xc);
390 yv.push_back(yc);
391 zv.push_back(zc);
392 }
393 // Shift the coordinates.
394 x1 = x2;
395 y1 = y2;
396 z1 = z2;
397 }
398 }
399 // Go through the ribs.
400 for (unsigned int i = 2; i <= nPoints + 1; ++i) {
401 // Bottom and top of the line along the axis of the cylinder.
402 const double phi = m_rot + (i - 1.) * dphi;
403 const double u = r * cos(phi);
404 const double v = r * sin(phi);
405 double x1, y1, z1;
406 ToGlobal(u, v, +m_lZ, x1, y1, z1);
407 double x2, y2, z2;
408 ToGlobal(u, v, -m_lZ, x2, y2, z2);
409 // Cut with the plane.
410 double xc, yc, zc;
411 if (Intersect(x1, y1, z1, x2, y2, z2, x0, y0, z0, xn, yn, zn, xc, yc, zc)) {
412 xv.push_back(xc);
413 yv.push_back(yc);
414 zv.push_back(zc);
415 }
416 }
417 // Get rid of butterflies.
419
420 if (xv.size() >= 3) {
421 Panel panel;
422 panel.a = xn;
423 panel.b = yn;
424 panel.c = zn;
425 panel.xv = xv;
426 panel.yv = yv;
427 panel.zv = zv;
428 panel.colour = m_colour;
429 panel.volume = GetId();
430 panels.push_back(std::move(panel));
431 }
432}
433
434}
bool SolidPanels(std::vector< Panel > &panels) override
Retrieve the surface panels of the solid.
Definition SolidTube.cc:143
double GetDiscretisationLevel(const Panel &panel) override
Retrieve the discretisation level of a panel.
Definition SolidTube.cc:349
void SetSectors(const unsigned int n)
Definition SolidTube.cc:134
SolidTube(const double cx, const double cy, const double cz, const double r, const double lz)
Constructor from centre, outer radius, and half-length.
Definition SolidTube.cc:10
void SetHalfLength(const double lz)
Set the half-length of the tube.
Definition SolidTube.cc:125
void SetRadius(const double r)
Set the outer radius.
Definition SolidTube.cc:116
void Cut(const double x0, const double y0, const double z0, const double xn, const double yn, const double zn, std::vector< Panel > &panels) override
Definition SolidTube.cc:363
bool IsInside(const double x, const double y, const double z, const bool tesselated) const override
Definition SolidTube.cc:71
bool GetBoundingBox(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax) const override
Return the bounding box of the solid.
Definition SolidTube.cc:94
double m_dZ
Definition Solid.hh:205
double m_cZ
Definition Solid.hh:202
void VectorToLocal(const double x, const double y, const double z, double &u, double &v, double &w)
Transform a vector from global to local coordinates.
Definition Solid.hh:253
double m_cTheta
Polar angle.
Definition Solid.hh:209
static bool Intersect(const double x1, const double y1, const double z1, const double x2, const double y2, const double z2, const double x0, const double y0, const double z0, const double a, const double b, const double c, double &xc, double &yc, double &zc)
Definition Solid.cc:52
double m_dX
Direction vector.
Definition Solid.hh:205
unsigned int GetId() const
Get the ID of the solid.
Definition Solid.hh:137
void ToLocal(const double x, const double y, const double z, double &u, double &v, double &w) const
Definition Solid.hh:234
void SetDirection(const double dx, const double dy, const double dz)
Definition Solid.cc:12
int m_colour
Colour.
Definition Solid.hh:230
double m_sPhi
Definition Solid.hh:207
void ToGlobal(const double u, const double v, const double w, double &x, double &y, double &z) const
Definition Solid.hh:246
double m_sTheta
Definition Solid.hh:209
double m_cY
Definition Solid.hh:202
double m_dY
Definition Solid.hh:205
double m_cX
Centre of the solid.
Definition Solid.hh:202
double m_cPhi
Azimuthal angle.
Definition Solid.hh:207
Solid()=delete
Default constructor.
void EliminateButterflies(std::vector< double > &xp, std::vector< double > &yp, std::vector< double > &zp)
Definition Polygon.cc:355
void Inside(const std::vector< double > &xpl, const std::vector< double > &ypl, const double x, const double y, bool &inside, bool &edge)
Definition Polygon.cc:187
Surface panel.
Definition Solid.hh:11
std::vector< double > zv
Z-coordinates of vertices.
Definition Solid.hh:19
int volume
Reference to solid to which the panel belongs.
Definition Solid.hh:23
double a
Perpendicular vector.
Definition Solid.hh:13
std::vector< double > xv
X-coordinates of vertices.
Definition Solid.hh:15
std::vector< double > yv
Y-coordinates of vertices.
Definition Solid.hh:17
int colour
Colour index.
Definition Solid.hh:21