Geant4 11.2.2
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4IntersectingCone.cc
Go to the documentation of this file.
1//
2// ********************************************************************
3// * License and Disclaimer *
4// * *
5// * The Geant4 software is copyright of the Copyright Holders of *
6// * the Geant4 Collaboration. It is provided under the terms and *
7// * conditions of the Geant4 Software License, included in the file *
8// * LICENSE and available at http://cern.ch/geant4/license . These *
9// * include a list of copyright holders. *
10// * *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work make any representation or warranty, express or implied, *
14// * regarding this software system or assume any liability for its *
15// * use. Please see the license in the file LICENSE and URL above *
16// * for the full disclaimer and the limitation of liability. *
17// * *
18// * This code implementation is the result of the scientific and *
19// * technical work of the GEANT4 collaboration. *
20// * By using, copying, modifying or distributing the software (or *
21// * any work based on the software) you agree to acknowledge its *
22// * use in resulting scientific publications, and indicate your *
23// * acceptance of all terms of the Geant4 Software license. *
24// ********************************************************************
25//
26// Implementation of G4IntersectingCone, a utility class which calculates
27// the intersection of an arbitrary line with a fixed cone
28//
29// Author: David C. Williams ([email protected])
30// --------------------------------------------------------------------
31
32#include "G4IntersectingCone.hh"
34
35// Constructor
36//
38 const G4double z[2] )
39{
40 const G4double halfCarTolerance
42
43 // What type of cone are we?
44 //
45 type1 = (std::abs(z[1]-z[0]) > std::abs(r[1]-r[0]));
46
47 if (type1) // tube like
48 {
49 B = (r[1] - r[0]) / (z[1] - z[0]);
50 A = (r[0]*z[1] - r[1]*z[0]) / (z[1] -z[0]);
51 }
52 else // disk like
53 {
54 B = (z[1] - z[0]) / (r[1] - r[0]);
55 A = (z[0]*r[1] - z[1]*r[0]) / (r[1] - r[0]);
56 }
57
58 // Calculate extent
59 //
60 rLo = std::min(r[0], r[1]) - halfCarTolerance;
61 rHi = std::max(r[0], r[1]) + halfCarTolerance;
62 zLo = std::min(z[0], z[1]) - halfCarTolerance;
63 zHi = std::max(z[0], z[1]) + halfCarTolerance;
64}
65
66// Fake default constructor - sets only member data and allocates memory
67// for usage restricted to object persistency.
68//
70 : zLo(0.), zHi(0.), rLo(0.), rHi(0.), A(0.), B(0.)
71{
72}
73
74// Destructor
75//
77
78// HitOn
79//
80// Check r or z extent, as appropriate, to see if the point is possibly
81// on the cone.
82//
84 const G4double z )
85{
86 //
87 // Be careful! The inequalities cannot be "<=" and ">=" here without
88 // punching a tiny hole in our shape!
89 //
90 if (type1)
91 {
92 if (z < zLo || z > zHi) return false;
93 }
94 else
95 {
96 if (r < rLo || r > rHi) return false;
97 }
98
99 return true;
100}
101
102// LineHitsCone
103//
104// Calculate the intersection of a line with our conical surface, ignoring
105// any phi division
106//
108 const G4ThreeVector& v,
109 G4double* s1, G4double* s2 )
110{
111 if (type1)
112 {
113 return LineHitsCone1( p, v, s1, s2 );
114 }
115 else
116 {
117 return LineHitsCone2( p, v, s1, s2 );
118 }
119}
120
121// LineHitsCone1
122//
123// Calculate the intersections of a line with a conical surface. Only
124// suitable if zPlane[0] != zPlane[1].
125//
126// Equation of a line:
127//
128// x = x0 + s*tx y = y0 + s*ty z = z0 + s*tz
129//
130// Equation of a conical surface:
131//
132// x**2 + y**2 = (A + B*z)**2
133//
134// Solution is quadratic:
135//
136// a*s**2 + b*s + c = 0
137//
138// where:
139//
140// a = tx**2 + ty**2 - (B*tz)**2
141//
142// b = 2*( px*vx + py*vy - B*(A + B*pz)*vz )
143//
144// c = x0**2 + y0**2 - (A + B*z0)**2
145//
146// Notice, that if a < 0, this indicates that the two solutions (assuming
147// they exist) are in opposite cones (that is, given z0 = -A/B, one z < z0
148// and the other z > z0). For our shapes, the invalid solution is one
149// which produces A + Bz < 0, or the one where Bz is smallest (most negative).
150// Since Bz = B*s*tz, if B*tz > 0, we want the largest s, otherwise,
151// the smaller.
152//
153// If there are two solutions on one side of the cone, we want to make
154// sure that they are on the "correct" side, that is A + B*z0 + s*B*tz >= 0.
155//
156// If a = 0, we have a linear problem: s = c/b, which again gives one solution.
157// This should be rare.
158//
159// For b*b - 4*a*c = 0, we also have one solution, which is almost always
160// a line just grazing the surface of a the cone, which we want to ignore.
161// However, there are two other, very rare, possibilities:
162// a line intersecting the z axis and either:
163// 1. At the same angle std::atan(B) to just miss one side of the cone, or
164// 2. Intersecting the cone apex (0,0,-A/B)
165// We *don't* want to miss these! How do we identify them? Well, since
166// this case is rare, we can at least swallow a little more CPU than we would
167// normally be comfortable with. Intersection with the z axis means
168// x0*ty - y0*tx = 0. Case (1) means a==0, and we've already dealt with that
169// above. Case (2) means a < 0.
170//
171// Now: x0*tx + y0*ty = 0 in terms of roundoff error. We can write:
172// Delta = x0*tx + y0*ty
173// b = 2*( Delta - B*(A + B*z0)*tz )
174// For:
175// b*b - 4*a*c = epsilon
176// where epsilon is small, then:
177// Delta = epsilon/2/B
178//
180 const G4ThreeVector& v,
181 G4double* s1, G4double* s2 )
182{
183 static const G4double EPS = DBL_EPSILON; // Precision constant,
184 // originally it was 1E-6
185 G4double x0 = p.x(), y0 = p.y(), z0 = p.z();
186 G4double tx = v.x(), ty = v.y(), tz = v.z();
187
188 // Value of radical can be inaccurate due to loss of precision
189 // if to calculate the coefficiets a,b,c like the following:
190 // G4double a = tx*tx + ty*ty - sqr(B*tz);
191 // G4double b = 2*( x0*tx + y0*ty - B*(A + B*z0)*tz);
192 // G4double c = x0*x0 + y0*y0 - sqr(A + B*z0);
193 //
194 // For more accurate calculation of radical the coefficients
195 // are splitted in two components, radial and along z-axis
196 //
197 G4double ar = tx*tx + ty*ty;
198 G4double az = sqr(B*tz);
199 G4double br = 2*(x0*tx + y0*ty);
200 G4double bz = 2*B*(A + B*z0)*tz;
201 G4double cr = x0*x0 + y0*y0;
202 G4double cz = sqr(A + B*z0);
203
204 // Instead radical = b*b - 4*a*c
205 G4double arcz = 4*ar*cz;
206 G4double azcr = 4*az*cr;
207 G4double radical = (br*br - 4*ar*cr) + ((std::max(arcz,azcr) - 2*bz*br) + std::min(arcz,azcr));
208
209 // Find the coefficients
210 G4double a = ar - az;
211 G4double b = br - bz;
212 G4double c = cr - cz;
213
214 if (radical < -EPS*std::fabs(b)) { return 0; } // No solution
215
216 if (radical < EPS*std::fabs(b))
217 {
218 //
219 // The radical is roughly zero: check for special, very rare, cases
220 //
221 if (std::fabs(a) > 1/kInfinity)
222 {
223 if(B==0.) { return 0; }
224 if ( std::fabs(x0*ty - y0*tx) < std::fabs(EPS/B) )
225 {
226 *s1 = -0.5*b/a;
227 return 1;
228 }
229 return 0;
230 }
231 }
232 else
233 {
234 radical = std::sqrt(radical);
235 }
236
237 if (a > 1/kInfinity)
238 {
239 G4double sa, sb, q = -0.5*( b + (b < 0 ? -radical : +radical) );
240 sa = q/a;
241 sb = c/q;
242 if (sa < sb) { *s1 = sa; *s2 = sb; } else { *s1 = sb; *s2 = sa; }
243 if (A + B*(z0+(*s1)*tz) < 0) { return 0; }
244 return 2;
245 }
246 else if (a < -1/kInfinity)
247 {
248 G4double sa, sb, q = -0.5*( b + (b < 0 ? -radical : +radical) );
249 sa = q/a;
250 sb = c/q;
251 *s1 = (B*tz > 0)^(sa > sb) ? sb : sa;
252 return 1;
253 }
254 else if (std::fabs(b) < 1/kInfinity)
255 {
256 return 0;
257 }
258 else
259 {
260 *s1 = -c/b;
261 if (A + B*(z0+(*s1)*tz) < 0) { return 0; }
262 return 1;
263 }
264}
265
266// LineHitsCone2
267//
268// See comments under LineHitsCone1. In this routine, case2, we have:
269//
270// Z = A + B*R
271//
272// The solution is still quadratic:
273//
274// a = tz**2 - B*B*(tx**2 + ty**2)
275//
276// b = 2*( (z0-A)*tz - B*B*(x0*tx+y0*ty) )
277//
278// c = ( (z0-A)**2 - B*B*(x0**2 + y0**2) )
279//
280// The rest is much the same, except some details.
281//
282// a > 0 now means we intersect only once in the correct hemisphere.
283//
284// a > 0 ? We only want solution which produces R > 0.
285// since R = (z0+s*tz-A)/B, for tz/B > 0, this is the largest s
286// for tz/B < 0, this is the smallest s
287// thus, same as in case 1 ( since sign(tz/B) = sign(tz*B) )
288//
290 const G4ThreeVector& v,
291 G4double* s1, G4double* s2 )
292{
293 static const G4double EPS = DBL_EPSILON; // Precision constant,
294 // originally it was 1E-6
295 G4double x0 = p.x(), y0 = p.y(), z0 = p.z();
296 G4double tx = v.x(), ty = v.y(), tz = v.z();
297
298 // Special case which might not be so rare: B = 0 (precisely)
299 //
300 if (B==0)
301 {
302 if (std::fabs(tz) < 1/kInfinity) { return 0; }
303
304 *s1 = (A-z0)/tz;
305 return 1;
306 }
307
308 // Value of radical can be inaccurate due to loss of precision
309 // if to calculate the coefficiets a,b,c like the following:
310 // G4double a = tz*tz - B2*(tx*tx + ty*ty);
311 // G4double b = 2*( (z0-A)*tz - B2*(x0*tx + y0*ty) );
312 // G4double c = sqr(z0-A) - B2*( x0*x0 + y0*y0 );
313 //
314 // For more accurate calculation of radical the coefficients
315 // are splitted in two components, radial and along z-axis
316 //
317 G4double B2 = B*B;
318
319 G4double az = tz*tz;
320 G4double ar = B2*(tx*tx + ty*ty);
321 G4double bz = 2*(z0-A)*tz;
322 G4double br = 2*B2*(x0*tx + y0*ty);
323 G4double cz = sqr(z0-A);
324 G4double cr = B2*(x0*x0 + y0*y0);
325
326 // Instead radical = b*b - 4*a*c
327 G4double arcz = 4*ar*cz;
328 G4double azcr = 4*az*cr;
329 G4double radical = (br*br - 4*ar*cr) + ((std::max(arcz,azcr) - 2*bz*br) + std::min(arcz,azcr));
330
331 // Find the coefficients
332 G4double a = az - ar;
333 G4double b = bz - br;
334 G4double c = cz - cr;
335
336 if (radical < -EPS*std::fabs(b)) { return 0; } // No solution
337
338 if (radical < EPS*std::fabs(b))
339 {
340 //
341 // The radical is roughly zero: check for special, very rare, cases
342 //
343 if (std::fabs(a) > 1/kInfinity)
344 {
345 if ( std::fabs(x0*ty - y0*tx) < std::fabs(EPS/B) )
346 {
347 *s1 = -0.5*b/a;
348 return 1;
349 }
350 return 0;
351 }
352 }
353 else
354 {
355 radical = std::sqrt(radical);
356 }
357
358 if (a < -1/kInfinity)
359 {
360 G4double sa, sb, q = -0.5*( b + (b < 0 ? -radical : +radical) );
361 sa = q/a;
362 sb = c/q;
363 if (sa < sb) { *s1 = sa; *s2 = sb; } else { *s1 = sb; *s2 = sa; }
364 if ((z0 + (*s1)*tz - A)/B < 0) { return 0; }
365 return 2;
366 }
367 else if (a > 1/kInfinity)
368 {
369 G4double sa, sb, q = -0.5*( b + (b < 0 ? -radical : +radical) );
370 sa = q/a;
371 sb = c/q;
372 *s1 = (tz*B > 0)^(sa > sb) ? sb : sa;
373 return 1;
374 }
375 else if (std::fabs(b) < 1/kInfinity)
376 {
377 return 0;
378 }
379 else
380 {
381 *s1 = -c/b;
382 if ((z0 + (*s1)*tz - A)/B < 0) { return 0; }
383 return 1;
384 }
385}
G4double B(G4double temperature)
double G4double
Definition G4Types.hh:83
bool G4bool
Definition G4Types.hh:86
int G4int
Definition G4Types.hh:85
const G4double A[17]
double z() const
double x() const
double y() const
G4double GetSurfaceTolerance() const
static G4GeometryTolerance * GetInstance()
G4bool HitOn(const G4double r, const G4double z)
virtual ~G4IntersectingCone()
G4int LineHitsCone(const G4ThreeVector &p, const G4ThreeVector &v, G4double *s1, G4double *s2)
G4int LineHitsCone1(const G4ThreeVector &p, const G4ThreeVector &v, G4double *s1, G4double *s2)
G4IntersectingCone(const G4double r[2], const G4double z[2])
G4int LineHitsCone2(const G4ThreeVector &p, const G4ThreeVector &v, G4double *s1, G4double *s2)
#define EPS
T sqr(const T &x)
Definition templates.hh:128
#define DBL_EPSILON
Definition templates.hh:66