Garfield++ 4.0
A toolkit for the detailed simulation of particle detectors based on ionisation measurement in gases and semiconductors
Loading...
Searching...
No Matches
SolidSphere.cc
Go to the documentation of this file.
1#include <cmath>
2#include <iostream>
3
6#include "Garfield/Polygon.hh"
8
9namespace {
10
11bool InPolyhedron(const std::vector<Garfield::Panel>& panels,
12 const double x, const double y, const double z,
13 const bool inv = false) {
14
15 for (const auto& panel : panels) {
16 double d = panel.a * (panel.xv[0] - x) + panel.b * (panel.yv[0] - y) +
17 panel.c * (panel.zv[0] - z);
18 if (inv) d *= -1;
19 if (d < 0.) return false;
20 }
21 return true;
22}
23
24}
25
26namespace Garfield {
27
28SolidSphere::SolidSphere(const double cx, const double cy, const double cz,
29 const double r)
30 : Solid(cx, cy, cz, "SolidSphere") {
31 SetRadius(r);
32 UpdatePanels();
33}
34
35SolidSphere::SolidSphere(const double cx, const double cy, const double cz,
36 const double rmin, const double rmax)
37 : Solid(cx, cy, cz, "SolidSphere") {
38 SetRadii(rmin, rmax);
39 UpdatePanels();
40}
41
42bool SolidSphere::IsInside(const double x, const double y, const double z,
43 const bool tesselated) const {
44 // Transform the point to local coordinates.
45 const double dx = x - m_cX;
46 const double dy = y - m_cY;
47 const double dz = z - m_cZ;
48
49 if (fabs(dx) > m_rMax || fabs(dy) > m_rMax || fabs(dz) > m_rMax) {
50 return false;
51 }
52 const double r = sqrt(dx * dx + dy * dy + dz * dz);
53 if (!tesselated) return (r >= m_rMin && r <= m_rMax);
54 if (r > m_rMax || !InPolyhedron(m_panelsO, dx, dy, dz)) return false;
55 if (m_rMin > 0.) {
56 return (r >= m_rMin || !InPolyhedron(m_panelsI, dx, dy, dz, true));
57 }
58 return true;
59}
60
61bool SolidSphere::GetBoundingBox(double& xmin, double& ymin, double& zmin,
62 double& xmax, double& ymax,
63 double& zmax) const {
64 xmin = m_cX - m_rMax;
65 xmax = m_cX + m_rMax;
66 ymin = m_cY - m_rMax;
67 ymax = m_cY + m_rMax;
68 zmin = m_cZ - m_rMax;
69 zmax = m_cZ + m_rMax;
70 return true;
71}
72
73void SolidSphere::SetRadius(const double r) {
74 if (r <= 0.) {
75 std::cerr << "SolidSphere::SetRadius: Radius must be > 0.\n";
76 return;
77 }
78 m_rMax = r;
79 m_rMin = 0.;
80 UpdatePanels();
81}
82
83void SolidSphere::SetRadii(const double rmin, const double rmax) {
84 if (rmax <= 0.) {
85 std::cerr << "SolidSphere::SetRadii: Outer radius must be > 0.\n";
86 return;
87 }
88 if (rmin >= rmax) {
89 std::cerr << "SolidSphere::SetRadii:\n"
90 << " Outer radius must be > inner radius.\n";
91 return;
92 }
93 m_rMin = rmin;
94 m_rMax = rmax;
95 UpdatePanels();
96}
97
98void SolidSphere::SetMeridians(const unsigned int n) {
99 if (n < 3) {
100 std::cerr << "SolidSphere::SetMeridians: Number must be >= 3.\n";
101 return;
102 }
103 m_n = n;
104 UpdatePanels();
105}
106
107bool SolidSphere::SolidPanels(std::vector<Panel>& panels) {
108
109 const auto nPanels = panels.size();
110 panels.insert(panels.begin(), m_panelsO.begin(), m_panelsO.end());
111 panels.insert(panels.begin(), m_panelsI.begin(), m_panelsI.end());
112 std::cout << "SolidSphere::SolidPanels: " << panels.size() - nPanels
113 << " panels.\n";
114 return true;
115}
116
117void SolidSphere::UpdatePanels() {
118 std::lock_guard<std::mutex> guard(m_mutex);
119 m_panelsO.clear();
120 m_panelsI.clear();
121 const auto id = GetId();
122 MakePanels(id, m_rMax, true, m_panelsO);
123 if (m_rMin > 0.) {
124 MakePanels(id, m_rMin, false, m_panelsI);
125 }
126}
127
128void SolidSphere::MakePanels(const int vol, const double r, const bool out,
129 std::vector<Panel>& panels) const {
130
131 const double dphi = TwoPi / m_n;
132 const double dtheta = Pi / m_n;
133 // Loop over the sphere.
134 for (unsigned int i = 1; i <= m_n; ++i) {
135 const double phi0 = (i - 1.) * dphi;
136 const double phi1 = phi0 + dphi;
137 const double cphi0 = cos(phi0);
138 const double sphi0 = sin(phi0);
139 const double cphi1 = cos(phi1);
140 const double sphi1 = sin(phi1);
141 for (unsigned int j = 1; j <= m_n; ++j) {
142 const double theta0 = -HalfPi + (j - 1.) * dtheta;
143 const double theta1 = theta0 + dtheta;
144 const double ctheta0 = cos(theta0);
145 const double stheta0 = sin(theta0);
146 const double ctheta1 = cos(theta1);
147 const double stheta1 = sin(theta1);
148 Panel panel;
149 // Corners of this parcel.
150 if (j == 1) {
151 const double xv0 = m_cX + r * cphi0 * ctheta0;
152 const double yv0 = m_cY + r * sphi0 * ctheta0;
153 const double zv0 = m_cZ + r * stheta0;
154 const double xv1 = m_cX + r * cphi1 * ctheta1;
155 const double yv1 = m_cY + r * sphi1 * ctheta1;
156 const double zv1 = m_cZ + r * stheta1;
157 const double xv2 = m_cX + r * cphi0 * ctheta1;
158 const double yv2 = m_cY + r * sphi0 * ctheta1;
159 const double zv2 = m_cZ + r * stheta1;
160 panel.xv = {xv0, xv1, xv2};
161 panel.yv = {yv0, yv1, yv2};
162 panel.zv = {zv0, zv1, zv2};
163 } else if (j == m_n) {
164 const double xv0 = m_cX + r * cphi0 * ctheta0;
165 const double yv0 = m_cY + r * sphi0 * ctheta0;
166 const double zv0 = m_cZ + r * stheta0;
167 const double xv1 = m_cX + r * cphi1 * ctheta0;
168 const double yv1 = m_cY + r * sphi1 * ctheta0;
169 const double zv1 = m_cZ + r * stheta0;
170 const double xv2 = m_cX + r * cphi1 * ctheta1;
171 const double yv2 = m_cY + r * sphi1 * ctheta1;
172 const double zv2 = m_cZ + r * stheta1;
173 panel.xv = {xv0, xv1, xv2};
174 panel.yv = {yv0, yv1, yv2};
175 panel.zv = {zv0, zv1, zv2};
176 } else {
177 const double xv0 = m_cX + r * cphi0 * ctheta0;
178 const double yv0 = m_cY + r * sphi0 * ctheta0;
179 const double zv0 = m_cZ + r * stheta0;
180 const double xv1 = m_cX + r * cphi1 * ctheta0;
181 const double yv1 = m_cY + r * sphi1 * ctheta0;
182 const double zv1 = m_cZ + r * stheta0;
183 const double xv2 = m_cX + r * cphi1 * ctheta1;
184 const double yv2 = m_cY + r * sphi1 * ctheta1;
185 const double zv2 = m_cZ + r * stheta1;
186 const double xv3 = m_cX + r * cphi0 * ctheta1;
187 const double yv3 = m_cY + r * sphi0 * ctheta1;
188 const double zv3 = m_cZ + r * stheta1;
189 panel.xv = {xv0, xv1, xv2, xv3};
190 panel.yv = {yv0, yv1, yv2, yv3};
191 panel.zv = {zv0, zv1, zv2, zv3};
192 }
193 // Inclination angle in theta.
194 const double alpha =
195 atan2((ctheta0 - ctheta1) * sqrt((1. + cos(phi1 - phi0)) / 2),
196 stheta1 - stheta0);
197 const double calpha = cos(alpha);
198 const double salpha = sin(alpha);
199 // Store the panel.
200 if (out) {
201 panel.a = cos(0.5 * (phi0 + phi1)) * calpha;
202 panel.b = sin(0.5 * (phi0 + phi1)) * calpha;
203 panel.c = salpha;
204 } else {
205 panel.a = -cos(0.5 * (phi0 + phi1)) * calpha;
206 panel.b = -sin(0.5 * (phi0 + phi1)) * calpha;
207 panel.c = -salpha;
208 }
209 panel.volume = vol;
210 panels.push_back(std::move(panel));
211 }
212 }
213}
214
216 return m_dis;
217}
218
219void SolidSphere::Cut(const double x0, const double y0, const double z0,
220 const double xn, const double yn, const double zn,
221 std::vector<Panel>& panels) {
222
223 //-----------------------------------------------------------------------
224 // PLASPC - Cuts sphere IVOL with a plane.
225 //-----------------------------------------------------------------------
226 std::vector<double> xv;
227 std::vector<double> yv;
228 std::vector<double> zv;
229 // Loop over the sphere.
230 const double r = m_rMax;
231 for (unsigned int i = 1; i <= m_n; ++i) {
232 // phi-Coordinates.
233 const double phi0 = TwoPi * (i - 1.) / m_n;
234 const double phi1 = TwoPi * i / m_n;
235 for (unsigned int j = 1; j <= m_n; ++j) {
236 // theta-Coordinates.
237 const double theta0 = -HalfPi + Pi * (j - 1.) / m_n;
238 const double theta1 = -HalfPi + Pi * j / m_n;
239 // Reference point of this square.
240 const double x1 = x0 + r * cos(phi0) * cos(theta0);
241 const double y1 = y0 + r * sin(phi0) * cos(theta0);
242 const double z1 = z0 + r * sin(theta0);
243 // The meridian segment, doesn't exist at the S pole.
244 if (j > 0) {
245 const double x2 = x0 + r * cos(phi1) * cos(theta0);
246 const double y2 = y0 + r * sin(phi1) * cos(theta0);
247 const double z2 = z0 + r * sin(theta0);
248 // Cut with the plane.
249 double xc, yc, zc;
250 if (Intersect(x1, y1, z1, x2, y2, z2,
251 x0, y0, z0, xn, yn, zn, xc, yc, zc)) {
252 xv.push_back(xc);
253 yv.push_back(yc);
254 zv.push_back(zc);
255 }
256 }
257 // The latitude.
258 const double x2 = x0 + r * cos(phi0) * cos(theta1);
259 const double y2 = y0 + r * sin(phi0) * cos(theta1);
260 const double z2 = z0 + r * sin(theta1);
261 // Cut with the plane.
262 double xc, yc, zc;
263 if (Intersect(x1, y1, z1, x2, y2, z2,
264 x0, y0, z0, xn, yn, zn, xc, yc, zc)) {
265 xv.push_back(xc);
266 yv.push_back(yc);
267 zv.push_back(zc);
268 }
269 }
270 }
271 // Get rid of butterflies.
273
274 if (xv.size() >= 3) {
275 Panel panel;
276 panel.a = xn;
277 panel.b = yn;
278 panel.c = zn;
279 panel.xv = xv;
280 panel.yv = yv;
281 panel.zv = zv;
282 panel.colour = m_colour;
283 panel.volume = GetId();
284 panels.push_back(std::move(panel));
285 }
286}
287
288}
bool IsInside(const double x, const double y, const double z, const bool tesselated) const override
Definition: SolidSphere.cc:42
bool GetBoundingBox(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax) const override
Return the bounding box of the solid.
Definition: SolidSphere.cc:61
void SetRadii(const double rmin, const double rmax)
Set the inner and outer radius of the sphere.
Definition: SolidSphere.cc:83
void SetRadius(const double r)
Set the radius of the sphere.
Definition: SolidSphere.cc:73
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: SolidSphere.cc:219
double GetDiscretisationLevel(const Panel &panel) override
Retrieve the discretisation level of a panel.
Definition: SolidSphere.cc:215
bool SolidPanels(std::vector< Panel > &panels) override
Retrieve the surface panels of the solid.
Definition: SolidSphere.cc:107
SolidSphere(const double cx, const double cy, const double cz, const double r)
Constructor from centre and outer radius.
Definition: SolidSphere.cc:28
void SetMeridians(const unsigned int n)
Definition: SolidSphere.cc:98
Abstract base class for solids.
Definition: Solid.hh:28
double m_cZ
Definition: Solid.hh:202
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
unsigned int GetId() const
Get the ID of the solid.
Definition: Solid.hh:137
int m_colour
Colour.
Definition: Solid.hh:230
double m_cY
Definition: Solid.hh:202
double m_cX
Centre of the solid.
Definition: Solid.hh:202
void EliminateButterflies(std::vector< double > &xp, std::vector< double > &yp, std::vector< double > &zp)
Definition: Polygon.cc:355
DoubleAc cos(const DoubleAc &f)
Definition: DoubleAc.cpp:432
DoubleAc sin(const DoubleAc &f)
Definition: DoubleAc.cpp:384
DoubleAc sqrt(const DoubleAc &f)
Definition: DoubleAc.cpp:314
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
double c
Definition: Solid.hh:13
double b
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