Geant4 10.7.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4Ellipsoid.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// class G4Ellipsoid
27//
28// Implementation of G4Ellipsoid class
29//
30// 10.11.99 G.Horton-Smith: first writing, based on G4Sphere class
31// 25.02.05 G.Guerrieri: Revised
32// 15.12.19 E.Tcherniaev: Complete revision
33// --------------------------------------------------------------------
34
35#include "G4Ellipsoid.hh"
36
37#if !(defined(G4GEOM_USE_UELLIPSOID) && defined(G4GEOM_USE_SYS_USOLIDS))
38
39#include "globals.hh"
40
41#include "G4VoxelLimits.hh"
42#include "G4AffineTransform.hh"
44#include "G4BoundingEnvelope.hh"
45#include "G4RandomTools.hh"
46#include "G4QuickRand.hh"
47
49
50#include "G4VGraphicsScene.hh"
51#include "G4VisExtent.hh"
52
53#include "G4AutoLock.hh"
54
55namespace
56{
57 G4Mutex polyhedronMutex = G4MUTEX_INITIALIZER;
58 G4Mutex lateralareaMutex = G4MUTEX_INITIALIZER;
59}
60
61using namespace CLHEP;
62
63//////////////////////////////////////////////////////////////////////////
64//
65// Constructor
66
68 G4double xSemiAxis,
69 G4double ySemiAxis,
70 G4double zSemiAxis,
71 G4double zBottomCut,
72 G4double zTopCut)
73 : G4VSolid(name), fDx(xSemiAxis), fDy(ySemiAxis), fDz(zSemiAxis),
74 fZBottomCut(zBottomCut), fZTopCut(zTopCut)
75{
76 CheckParameters();
77}
78
79//////////////////////////////////////////////////////////////////////////
80//
81// Fake default constructor - sets only member data and allocates memory
82// for usage restricted to object persistency
83
85 : G4VSolid(a), fDx(0.), fDy(0.), fDz(0.), fZBottomCut(0.), fZTopCut(0.)
86{
87}
88
89//////////////////////////////////////////////////////////////////////////
90//
91// Destructor
92
94{
95 delete fpPolyhedron; fpPolyhedron = nullptr;
96}
97
98//////////////////////////////////////////////////////////////////////////
99//
100// Copy constructor
101
103 : G4VSolid(rhs),
104 fDx(rhs.fDx), fDy(rhs.fDy), fDz(rhs.fDz),
105 fZBottomCut(rhs.fZBottomCut), fZTopCut(rhs.fZTopCut),
106 halfTolerance(rhs.halfTolerance),
107 fXmax(rhs.fXmax), fYmax(rhs.fYmax),
108 fRsph(rhs.fRsph), fR(rhs.fR),
109 fSx(rhs.fSx), fSy(rhs.fSy), fSz(rhs.fSz),
110 fZMidCut(rhs.fZMidCut), fZDimCut(rhs.fZDimCut),
111 fQ1(rhs.fQ1), fQ2(rhs.fQ2),
112 fCubicVolume(rhs.fCubicVolume),
113 fSurfaceArea(rhs.fSurfaceArea),
114 fLateralArea(rhs.fLateralArea)
115{
116}
117
118//////////////////////////////////////////////////////////////////////////
119//
120// Assignment operator
121
123{
124 // Check assignment to self
125 //
126 if (this == &rhs) { return *this; }
127
128 // Copy base class data
129 //
131
132 // Copy data
133 //
134 fDx = rhs.fDx;
135 fDy = rhs.fDy;
136 fDz = rhs.fDz;
137 fZBottomCut = rhs.fZBottomCut;
138 fZTopCut = rhs.fZTopCut;
139
140 halfTolerance = rhs.halfTolerance;
141 fXmax = rhs.fXmax;
142 fYmax = rhs.fYmax;
143 fRsph = rhs.fRsph;
144 fR = rhs.fR;
145 fSx = rhs.fSx;
146 fSy = rhs.fSy;
147 fSz = rhs.fSz;
148 fZMidCut = rhs.fZMidCut;
149 fZDimCut = rhs.fZDimCut;
150 fQ1 = rhs.fQ1;
151 fQ2 = rhs.fQ2;
152
153 fCubicVolume = rhs.fCubicVolume;
154 fSurfaceArea = rhs.fSurfaceArea;
155 fLateralArea = rhs.fLateralArea;
156
157 fRebuildPolyhedron = false;
158 delete fpPolyhedron; fpPolyhedron = nullptr;
159
160 return *this;
161}
162
163//////////////////////////////////////////////////////////////////////////
164//
165// Check parameters and make precalculation
166
167void G4Ellipsoid::CheckParameters()
168{
169 halfTolerance = 0.5 * kCarTolerance; // half tolerance
170 G4double dmin = 2. * kCarTolerance;
171
172 // Check dimensions
173 //
174 if (fDx < dmin || fDy < dmin || fDz < dmin)
175 {
176 std::ostringstream message;
177 message << "Invalid (too small or negative) dimensions for Solid: "
178 << GetName() << "\n"
179 << " semi-axis x: " << fDx << "\n"
180 << " semi-axis y: " << fDy << "\n"
181 << " semi-axis z: " << fDz;
182 G4Exception("G4Ellipsoid::CheckParameters()", "GeomSolids0002",
183 FatalException, message);
184 }
185 G4double A = fDx;
186 G4double B = fDy;
187 G4double C = fDz;
188
189 // Check cuts
190 //
191 if (fZBottomCut == 0. && fZTopCut == 0.)
192 {
193 fZBottomCut = -C;
194 fZTopCut = C;
195 }
196 if (fZBottomCut >= C || fZTopCut <= -C || fZBottomCut >= fZTopCut)
197 {
198 std::ostringstream message;
199 message << "Invalid Z cuts for Solid: "
200 << GetName() << "\n"
201 << " bottom cut: " << fZBottomCut << "\n"
202 << " top cut: " << fZTopCut;
203 G4Exception("G4Ellipsoid::CheckParameters()", "GeomSolids0002",
204 FatalException, message);
205
206 }
207 fZBottomCut = std::max(fZBottomCut, -C);
208 fZTopCut = std::min(fZTopCut, C);
209
210 // Set extent in x and y
211 fXmax = A;
212 fYmax = B;
213 if (fZBottomCut > 0.)
214 {
215 G4double ratio = fZBottomCut / C;
216 G4double scale = std::sqrt((1. - ratio) * (1 + ratio));
217 fXmax *= scale;
218 fYmax *= scale;
219 }
220 if (fZTopCut < 0.)
221 {
222 G4double ratio = fZTopCut / C;
223 G4double scale = std::sqrt((1. - ratio) * (1 + ratio));
224 fXmax *= scale;
225 fYmax *= scale;
226 }
227
228 // Set scale factors
229 fRsph = std::max(std::max(A, B), C); // bounding sphere
230 fR = std::min(std::min(A, B), C); // radius of sphere after scaling
231 fSx = fR / A; // X scale factor
232 fSy = fR / B; // Y scale factor
233 fSz = fR / C; // Z scale factor
234
235 // Scaled cuts
236 fZMidCut = 0.5 * (fZTopCut + fZBottomCut) * fSz; // middle position
237 fZDimCut = 0.5 * (fZTopCut - fZBottomCut) * fSz; // half distance
238
239 // Coefficients for approximation of distance: Q1 * (x^2 + y^2 + z^2) - Q2
240 fQ1 = 0.5 / fR;
241 fQ2 = 0.5 * fR + halfTolerance * halfTolerance * fQ1;
242
243 fCubicVolume = 0.; // volume
244 fSurfaceArea = 0.; // surface area
245 fLateralArea = 0.; // lateral surface area
246}
247
248//////////////////////////////////////////////////////////////////////////
249//
250// Dispatch to parameterisation for replication mechanism dimension
251// computation & modification
252
254 const G4int n,
255 const G4VPhysicalVolume* pRep)
256{
257 p->ComputeDimensions(*this,n,pRep);
258}
259
260//////////////////////////////////////////////////////////////////////////
261//
262// Get bounding box
263
265 G4ThreeVector& pMax) const
266{
267 pMin.set(-fXmax,-fYmax, fZBottomCut);
268 pMax.set( fXmax, fYmax, fZTopCut);
269}
270
271//////////////////////////////////////////////////////////////////////////
272//
273// Calculate extent under transform and specified limits
274
275G4bool
277 const G4VoxelLimits& pVoxelLimit,
278 const G4AffineTransform& pTransform,
279 G4double& pMin, G4double& pMax) const
280{
281 G4ThreeVector bmin, bmax;
282
283 // Get bounding box
284 BoundingLimits(bmin,bmax);
285
286 // Find extent
287 G4BoundingEnvelope bbox(bmin,bmax);
288 return bbox.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax);
289}
290
291//////////////////////////////////////////////////////////////////////////
292//
293// Return position of point: inside/outside/on surface
294
296{
297 G4double x = p.x() * fSx;
298 G4double y = p.y() * fSy;
299 G4double z = p.z() * fSz;
300 G4double rr = x * x + y * y + z * z;
301 G4double distZ = std::abs(z - fZMidCut) - fZDimCut;
302 G4double distR = fQ1 * rr - fQ2;
303 G4double dist = std::max(distZ, distR);
304
305 if (dist > halfTolerance) return kOutside;
306 return (dist > -halfTolerance) ? kSurface : kInside;
307}
308
309//////////////////////////////////////////////////////////////////////////
310//
311// Return unit normal to surface at p
312
314{
315 G4ThreeVector norm(0., 0., 0.);
316 G4int nsurf = 0;
317
318 // Check cuts
319 G4double x = p.x() * fSx;
320 G4double y = p.y() * fSy;
321 G4double z = p.z() * fSz;
322 G4double distZ = std::abs(z - fZMidCut) - fZDimCut;
323 if (std::abs(distZ) <= halfTolerance)
324 {
325 norm.setZ(std::copysign(1., z - fZMidCut));
326 ++nsurf;
327 }
328
329 // Check lateral surface
330 G4double distR = fQ1*(x*x + y*y + z*z) - fQ2;
331 if (std::abs(distR) <= halfTolerance)
332 {
333 // normal = (p.x/a^2, p.y/b^2, p.z/c^2)
334 norm += G4ThreeVector(x*fSx, y*fSy, z*fSz).unit();
335 ++nsurf;
336 }
337
338 // Return normal
339 if (nsurf == 1) return norm;
340 else if (nsurf > 1) return norm.unit(); // edge
341 else
342 {
343#ifdef G4SPECSDEBUG
344 std::ostringstream message;
345 G4int oldprc = message.precision(16);
346 message << "Point p is not on surface (!?) of solid: "
347 << GetName() << "\n";
348 message << "Position:\n";
349 message << " p.x() = " << p.x()/mm << " mm\n";
350 message << " p.y() = " << p.y()/mm << " mm\n";
351 message << " p.z() = " << p.z()/mm << " mm";
352 G4cout.precision(oldprc);
353 G4Exception("G4Ellipsoid::SurfaceNormal(p)", "GeomSolids1002",
354 JustWarning, message );
355 DumpInfo();
356#endif
357 return ApproxSurfaceNormal(p);
358 }
359}
360
361//////////////////////////////////////////////////////////////////////////
362//
363// Find surface nearest to point and return corresponding normal.
364// This method normally should not be called.
365
366G4ThreeVector G4Ellipsoid::ApproxSurfaceNormal(const G4ThreeVector& p) const
367{
368 G4double x = p.x() * fSx;
369 G4double y = p.y() * fSy;
370 G4double z = p.z() * fSz;
371 G4double rr = x * x + y * y + z * z;
372 G4double distZ = std::abs(z - fZMidCut) - fZDimCut;
373 G4double distR = std::sqrt(rr) - fR;
374 if (distR > distZ && rr > 0.) // distR > distZ is correct!
375 return G4ThreeVector(x*fSx, y*fSy, z*fSz).unit();
376 else
377 return G4ThreeVector(0., 0., std::copysign(1., z - fZMidCut));
378}
379
380//////////////////////////////////////////////////////////////////////////
381//
382// Calculate distance to shape from outside along normalised vector
383
385 const G4ThreeVector& v) const
386{
387 G4double offset = 0.;
388 G4ThreeVector pcur = p;
389
390 // Check if point is flying away, relative to bounding box
391 //
392 G4double safex = std::abs(p.x()) - fXmax;
393 G4double safey = std::abs(p.y()) - fYmax;
394 G4double safet = p.z() - fZTopCut;
395 G4double safeb = fZBottomCut - p.z();
396
397 if (safex >= -halfTolerance && p.x() * v.x() >= 0.) return kInfinity;
398 if (safey >= -halfTolerance && p.y() * v.y() >= 0.) return kInfinity;
399 if (safet >= -halfTolerance && v.z() >= 0.) return kInfinity;
400 if (safeb >= -halfTolerance && v.z() <= 0.) return kInfinity;
401
402 // Relocate point, if required
403 //
404 G4double safe = std::max(std::max(std::max(safex, safey), safet), safeb);
405 if (safe > 32. * fRsph)
406 {
407 offset = (1. - 1.e-08) * safe - 2. * fRsph;
408 pcur += offset * v;
409 G4double dist = DistanceToIn(pcur, v);
410 return (dist == kInfinity) ? kInfinity : dist + offset;
411 }
412
413 // Scale ellipsoid to sphere
414 //
415 G4double px = pcur.x() * fSx;
416 G4double py = pcur.y() * fSy;
417 G4double pz = pcur.z() * fSz;
418 G4double vx = v.x() * fSx;
419 G4double vy = v.y() * fSy;
420 G4double vz = v.z() * fSz;
421
422 // Check if point is leaving the solid
423 //
424 G4double dzcut = fZDimCut;
425 G4double pzcut = pz - fZMidCut;
426 G4double distZ = std::abs(pzcut) - dzcut;
427 if (distZ >= -halfTolerance && pzcut * vz >= 0.) return kInfinity;
428
429 G4double rr = px * px + py * py + pz * pz;
430 G4double pv = px * vx + py * vy + pz * vz;
431 G4double distR = fQ1 * rr - fQ2;
432 if (distR >= -halfTolerance && pv >= 0.) return kInfinity;
433
434 G4double A = vx * vx + vy * vy + vz * vz;
435 G4double B = pv;
436 G4double C = rr - fR * fR;
437 G4double D = B * B - A * C;
438 // scratch^2 = R^2 - (R - halfTolerance)^2 = 2 * R * halfTolerance
439 G4double EPS = A * A * fR * kCarTolerance; // discriminant at scratching
440 if (D <= EPS) return kInfinity; // no intersection or scratching
441
442 // Find intersection with Z planes
443 //
444 G4double invz = (vz == 0) ? DBL_MAX : -1./vz;
445 G4double dz = std::copysign(dzcut, invz);
446 G4double tzmin = (pzcut - dz) * invz;
447 G4double tzmax = (pzcut + dz) * invz;
448
449 // Find intersection with lateral surface
450 //
451 G4double tmp = -B - std::copysign(std::sqrt(D), B);
452 G4double t1 = tmp / A;
453 G4double t2 = C / tmp;
454 G4double trmin = std::min(t1, t2);
455 G4double trmax = std::max(t1, t2);
456
457 // Return distance
458 //
459 G4double tmin = std::max(tzmin, trmin);
460 G4double tmax = std::min(tzmax, trmax);
461
462 if (tmax - tmin <= halfTolerance) return kInfinity; // touch or no hit
463 return (tmin < halfTolerance) ? offset : tmin + offset;
464}
465
466//////////////////////////////////////////////////////////////////////////
467//
468// Estimate distance to surface from outside
469
471{
472 G4double px = p.x();
473 G4double py = p.y();
474 G4double pz = p.z();
475
476 // Safety distance to bounding box
477 G4double distX = std::abs(px) - fXmax;
478 G4double distY = std::abs(py) - fYmax;
479 G4double distZ = std::max(pz - fZTopCut, fZBottomCut - pz);
480 G4double distB = std::max(std::max(distX, distY), distZ);
481
482 // Safety distance to lateral surface
483 G4double x = px * fSx;
484 G4double y = py * fSy;
485 G4double z = pz * fSz;
486 G4double distR = std::sqrt(x*x + y*y + z*z) - fR;
487
488 // Return safety to in
489 G4double dist = std::max(distB, distR);
490 return (dist < 0.) ? 0. : dist;
491}
492
493//////////////////////////////////////////////////////////////////////////
494//
495// Calculate distance to surface from inside along normalised vector
496
498 const G4ThreeVector& v,
499 const G4bool calcNorm,
500 G4bool* validNorm,
501 G4ThreeVector* n ) const
502{
503 // Check if point flying away relative to Z planes
504 //
505 G4double pz = p.z() * fSz;
506 G4double vz = v.z() * fSz;
507 G4double dzcut = fZDimCut;
508 G4double pzcut = pz - fZMidCut;
509 G4double distZ = std::abs(pzcut) - dzcut;
510 if (distZ >= -halfTolerance && pzcut * vz > 0.)
511 {
512 if (calcNorm)
513 {
514 *validNorm = true;
515 n->set(0., 0., std::copysign(1., pzcut));
516 }
517 return 0.;
518 }
519
520 // Check if point is flying away relative to lateral surface
521 //
522 G4double px = p.x() * fSx;
523 G4double py = p.y() * fSy;
524 G4double vx = v.x() * fSx;
525 G4double vy = v.y() * fSy;
526 G4double rr = px * px + py * py + pz * pz;
527 G4double pv = px * vx + py * vy + pz * vz;
528 G4double distR = fQ1 * rr - fQ2;
529 if (distR >= -halfTolerance && pv > 0.)
530 {
531 if (calcNorm)
532 {
533 *validNorm = true;
534 *n = G4ThreeVector(px*fSx, py*fSy, pz*fSz).unit();
535 }
536 return 0.;
537 }
538
539 // Just in case check if point is outside (normally it should never be)
540 //
541 if (std::max(distZ, distR) > halfTolerance)
542 {
543#ifdef G4SPECSDEBUG
544 std::ostringstream message;
545 G4int oldprc = message.precision(16);
546 message << "Point p is outside (!?) of solid: "
547 << GetName() << G4endl;
548 message << "Position: " << p << G4endl;;
549 message << "Direction: " << v;
550 G4cout.precision(oldprc);
551 G4Exception("G4Ellipsoid::DistanceToOut(p,v)", "GeomSolids1002",
552 JustWarning, message );
553 DumpInfo();
554#endif
555 if (calcNorm)
556 {
557 *validNorm = true;
558 *n = ApproxSurfaceNormal(p);
559 }
560 return 0.;
561 }
562
563 // Set coefficients of quadratic equation: A t^2 + 2B t + C = 0
564 //
565 G4double A = vx * vx + vy * vy + vz * vz;
566 G4double B = pv;
567 G4double C = rr - fR * fR;
568 G4double D = B * B - A * C;
569 // It is expected that the point is located inside the sphere, so
570 // max term in the expression for discriminant is A * R^2 and
571 // max calculation error can be derived as follows:
572 // A * (1 + 2e) * R^2 * (1 + 2e) = A * R^2 + (4 * A * R^2 * e)
573 G4double EPS = 4. * A * fR * fR * DBL_EPSILON; // calculation error
574
575 if (D <= EPS) // no intersection
576 {
577 if (calcNorm)
578 {
579 *validNorm = true;
580 *n = G4ThreeVector(px*fSx, py*fSy, pz*fSz).unit();
581 }
582 return 0.;
583 }
584
585 // Find intersection with Z cuts
586 //
587 G4double tzmax = (vz == 0.) ? DBL_MAX : (std::copysign(dzcut, vz) - pzcut) / vz;
588
589 // Find intersection with lateral surface
590 //
591 G4double tmp = -B - std::copysign(std::sqrt(D), B);
592 G4double trmax = (tmp < 0.) ? C/tmp : tmp/A;
593
594 // Find distance and set normal, if required
595 //
596 G4double tmax = std::min(tzmax, trmax);
597 //if (tmax < halfTolerance) tmax = 0.;
598
599 if (calcNorm)
600 {
601 *validNorm = true;
602 if (tmax == tzmax)
603 {
604 G4double pznew = pz + tmax * vz;
605 n->set(0., 0., (pznew > fZMidCut) ? 1. : -1.);
606 }
607 else
608 {
609 G4double nx = (px + tmax * vx) * fSx;
610 G4double ny = (py + tmax * vy) * fSy;
611 G4double nz = (pz + tmax * vz) * fSz;
612 *n = G4ThreeVector(nx, ny, nz).unit();
613 }
614 }
615 return tmax;
616}
617
618//////////////////////////////////////////////////////////////////////////
619//
620// Estimate distance to surface from inside
621
623{
624 // Safety distance in z direction
625 G4double distZ = std::min(fZTopCut - p.z(), p.z() - fZBottomCut);
626
627 // Safety distance to lateral surface
628 G4double x = p.x() * fSx;
629 G4double y = p.y() * fSy;
630 G4double z = p.z() * fSz;
631 G4double distR = fR - std::sqrt(x*x + y*y + z*z);
632
633 // Return safety to out
634 G4double dist = std::min(distZ, distR);
635 return (dist < 0.) ? 0. : dist;
636}
637
638//////////////////////////////////////////////////////////////////////////
639//
640// Return entity type
641
643{
644 return G4String("G4Ellipsoid");
645}
646
647//////////////////////////////////////////////////////////////////////////
648//
649// Make a clone of the object
650
652{
653 return new G4Ellipsoid(*this);
654}
655
656//////////////////////////////////////////////////////////////////////////
657//
658// Stream object contents to output stream
659
660std::ostream& G4Ellipsoid::StreamInfo( std::ostream& os ) const
661{
662 G4int oldprc = os.precision(16);
663 os << "-----------------------------------------------------------\n"
664 << " *** Dump for solid - " << GetName() << " ***\n"
665 << " ===================================================\n"
666 << " Solid type: " << GetEntityType() << "\n"
667 << " Parameters: \n"
668 << " semi-axis x: " << GetDx()/mm << " mm \n"
669 << " semi-axis y: " << GetDy()/mm << " mm \n"
670 << " semi-axis z: " << GetDz()/mm << " mm \n"
671 << " lower cut in z: " << GetZBottomCut()/mm << " mm \n"
672 << " upper cut in z: " << GetZTopCut()/mm << " mm \n"
673 << "-----------------------------------------------------------\n";
674 os.precision(oldprc);
675 return os;
676}
677
678//////////////////////////////////////////////////////////////////////////
679//
680// Return volume
681
683{
684 if (fCubicVolume == 0.)
685 {
686 G4double piAB_3 = CLHEP::pi * fDx * fDy / 3.;
687 fCubicVolume = 4. * piAB_3 * fDz;
688 if (fZBottomCut > -fDz)
689 {
690 G4double hbot = 1. + fZBottomCut / fDz;
691 fCubicVolume -= piAB_3 * hbot * hbot * (2. * fDz - fZBottomCut);
692 }
693 if (fZTopCut < fDz)
694 {
695 G4double htop = 1. - fZTopCut / fDz;
696 fCubicVolume -= piAB_3 * htop * htop * (2. * fDz + fZTopCut);
697 }
698 }
699 return fCubicVolume;
700}
701
702//////////////////////////////////////////////////////////////////////////
703//
704// Calculate area of lateral surface
705
706G4double G4Ellipsoid::LateralSurfaceArea() const
707{
708 const G4int Nphi = 100;
709 const G4int Nz = 200;
710 G4double rho[Nz + 1];
711
712 // Set array of rho
713 G4double zbot = fZBottomCut / fDz;
714 G4double ztop = fZTopCut / fDz;
715 G4double dz = (ztop - zbot) / Nz;
716 for (G4int iz = 0; iz < Nz; ++iz)
717 {
718 G4double z = zbot + iz * dz;
719 rho[iz] = std::sqrt((1. + z) * (1. - z));
720 }
721 rho[Nz] = std::sqrt((1. + ztop) * (1. - ztop));
722
723 // Compute area
724 zbot = fZBottomCut;
725 ztop = fZTopCut;
726 dz = (ztop - zbot) / Nz;
727 G4double area = 0.;
728 G4double dphi = CLHEP::halfpi / Nphi;
729 for (G4int iphi = 0; iphi < Nphi; ++iphi)
730 {
731 G4double phi1 = iphi * dphi;
732 G4double phi2 = (iphi == Nphi - 1) ? CLHEP::halfpi : phi1 + dphi;
733 G4double cos1 = std::cos(phi1) * fDx;
734 G4double cos2 = std::cos(phi2) * fDx;
735 G4double sin1 = std::sin(phi1) * fDy;
736 G4double sin2 = std::sin(phi2) * fDy;
737 for (G4int iz = 0; iz < Nz; ++iz)
738 {
739 G4double z1 = zbot + iz * dz;
740 G4double z2 = (iz == Nz - 1) ? ztop : z1 + dz;
741 G4double rho1 = rho[iz];
742 G4double rho2 = rho[iz + 1];
743 G4ThreeVector p1(rho1 * cos1, rho1 * sin1, z1);
744 G4ThreeVector p2(rho1 * cos2, rho1 * sin2, z1);
745 G4ThreeVector p3(rho2 * cos1, rho2 * sin1, z2);
746 G4ThreeVector p4(rho2 * cos2, rho2 * sin2, z2);
747 area += ((p4 - p1).cross(p3 - p2)).mag();
748 }
749 }
750 return 2. * area;
751}
752
753//////////////////////////////////////////////////////////////////////////
754//
755// Return surface area
756
758{
759 if (fSurfaceArea == 0.)
760 {
761 G4double piAB = CLHEP::pi * fDx * fDy;
762 fSurfaceArea = LateralSurfaceArea();
763 if (fZBottomCut > -fDz)
764 {
765 G4double hbot = 1. + fZBottomCut / fDz;
766 fSurfaceArea += piAB * hbot * (2. - hbot);
767 }
768 if (fZTopCut < fDz)
769 {
770 G4double htop = 1. - fZTopCut / fDz;
771 fSurfaceArea += piAB * htop * (2. - htop);
772 }
773 }
774 return fSurfaceArea;
775}
776
777//////////////////////////////////////////////////////////////////////////
778//
779// Return random point on surface
780
782{
783 G4double A = GetDx();
784 G4double B = GetDy();
785 G4double C = GetDz();
786 G4double Zbot = GetZBottomCut();
787 G4double Ztop = GetZTopCut();
788
789 // Calculate cut areas
790 G4double Hbot = 1. + Zbot / C;
791 G4double Htop = 1. - Ztop / C;
792 G4double piAB = CLHEP::pi * A * B;
793 G4double Sbot = piAB * Hbot * (2. - Hbot);
794 G4double Stop = piAB * Htop * (2. - Htop);
795
796 // Get area of lateral surface
797 if (fLateralArea == 0.)
798 {
799 G4AutoLock l(&lateralareaMutex);
800 fLateralArea = LateralSurfaceArea();
801 l.unlock();
802 }
803 G4double Slat = fLateralArea;
804
805 // Select surface (0 - bottom cut, 1 - lateral surface, 2 - top cut)
806 G4double select = (Sbot + Slat + Stop) * G4QuickRand();
807 G4int k = 0;
808 if (select > Sbot) k = 1;
809 if (select > Sbot + Slat) k = 2;
810
811 // Pick random point on selected surface (rejection sampling)
813 switch (k)
814 {
815 case 0: // bootom z-cut
816 {
817 G4double scale = std::sqrt(Hbot * (2. - Hbot));
818 G4TwoVector rho = G4RandomPointInEllipse(A * scale, B * scale);
819 p.set(rho.x(), rho.y(), Zbot);
820 break;
821 }
822 case 1: // lateral surface
823 {
824 G4double x, y, z;
825 G4double mu_max = std::max(std::max(A * B, A * C), B * C);
826 for (G4int i = 0; i < 1000; ++i)
827 {
828 // generate random point on unit sphere
829 z = (Zbot + (Ztop - Zbot) * G4QuickRand()) / C;
830 G4double rho = std::sqrt((1. + z) * (1. - z));
831 G4double phi = CLHEP::twopi * G4QuickRand();
832 x = rho * std::cos(phi);
833 y = rho * std::sin(phi);
834 // check acceptance
835 G4double xbc = x * B * C;
836 G4double yac = y * A * C;
837 G4double zab = z * A * B;
838 G4double mu = std::sqrt(xbc * xbc + yac * yac + zab * zab);
839 if (mu_max * G4QuickRand() <= mu) break;
840 }
841 p.set(A * x, B * y, C * z);
842 break;
843 }
844 case 2: // top z-cut
845 {
846 G4double scale = std::sqrt(Htop * (2. - Htop));
847 G4TwoVector rho = G4RandomPointInEllipse(A * scale, B * scale);
848 p.set(rho.x(), rho.y(), Ztop);
849 break;
850 }
851 }
852 return p;
853}
854
855//////////////////////////////////////////////////////////////////////////
856//
857// Methods for visualisation
858
860{
861 scene.AddSolid(*this);
862}
863
864//////////////////////////////////////////////////////////////////////////
865//
866// Return vis extent
867
869{
870 return G4VisExtent(-fXmax, fXmax, -fYmax, fYmax, fZBottomCut, fZTopCut);
871}
872
873//////////////////////////////////////////////////////////////////////////
874//
875// Create polyhedron
876
878{
879 return new G4PolyhedronEllipsoid(fDx, fDy, fDz, fZBottomCut, fZTopCut);
880}
881
882//////////////////////////////////////////////////////////////////////////
883//
884// Return pointer to polyhedron
885
887{
888 if (fpPolyhedron == nullptr ||
889 fRebuildPolyhedron ||
891 fpPolyhedron->GetNumberOfRotationSteps())
892 {
893 G4AutoLock l(&polyhedronMutex);
894 delete fpPolyhedron;
895 fpPolyhedron = CreatePolyhedron();
896 fRebuildPolyhedron = false;
897 l.unlock();
898 }
899 return fpPolyhedron;
900}
901
902#endif // !defined(G4GEOM_USE_UELLIPSOID) || !defined(G4GEOM_USE_SYS_USOLIDS)
double B(double temperature)
double C(double temp)
double A(double temperature)
double D(double temp)
@ JustWarning
@ FatalException
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
Definition: G4Exception.cc:35
G4double G4QuickRand()
Definition: G4QuickRand.hh:34
G4TwoVector G4RandomPointInEllipse(G4double a, G4double b)
#define G4MUTEX_INITIALIZER
Definition: G4Threading.hh:85
std::mutex G4Mutex
Definition: G4Threading.hh:81
CLHEP::Hep3Vector G4ThreeVector
double G4double
Definition: G4Types.hh:83
bool G4bool
Definition: G4Types.hh:86
int G4int
Definition: G4Types.hh:85
#define G4endl
Definition: G4ios.hh:57
G4GLOB_DLL std::ostream G4cout
double x() const
double y() const
double z() const
Hep3Vector unit() const
double x() const
double y() const
void setZ(double)
void set(double x, double y, double z)
G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimits, const G4Transform3D &pTransform3D, G4double &pMin, G4double &pMax) const
G4double DistanceToOut(const G4ThreeVector &p, const G4ThreeVector &v, const G4bool calcNorm=false, G4bool *validNorm=nullptr, G4ThreeVector *n=nullptr) const
Definition: G4Ellipsoid.cc:497
G4double GetDx() const
void DescribeYourselfTo(G4VGraphicsScene &scene) const
Definition: G4Ellipsoid.cc:859
G4Ellipsoid(const G4String &name, G4double xSemiAxis, G4double ySemiAxis, G4double zSemiAxis, G4double zBottomCut=0., G4double zTopCut=0.)
Definition: G4Ellipsoid.cc:67
std::ostream & StreamInfo(std::ostream &os) const
Definition: G4Ellipsoid.cc:660
G4double DistanceToIn(const G4ThreeVector &p, const G4ThreeVector &v) const
Definition: G4Ellipsoid.cc:384
G4Polyhedron * GetPolyhedron() const
Definition: G4Ellipsoid.cc:886
G4double GetDy() const
G4VSolid * Clone() const
Definition: G4Ellipsoid.cc:651
G4Polyhedron * CreatePolyhedron() const
Definition: G4Ellipsoid.cc:877
G4double GetZTopCut() const
G4double GetZBottomCut() const
EInside Inside(const G4ThreeVector &p) const
Definition: G4Ellipsoid.cc:295
void ComputeDimensions(G4VPVParameterisation *p, const G4int n, const G4VPhysicalVolume *pRep)
Definition: G4Ellipsoid.cc:253
G4double GetDz() const
G4double GetSurfaceArea()
Definition: G4Ellipsoid.cc:757
G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimit, const G4AffineTransform &pTransform, G4double &pmin, G4double &pmax) const
Definition: G4Ellipsoid.cc:276
G4Ellipsoid & operator=(const G4Ellipsoid &rhs)
Definition: G4Ellipsoid.cc:122
void BoundingLimits(G4ThreeVector &pMin, G4ThreeVector &pMax) const
Definition: G4Ellipsoid.cc:264
G4double GetCubicVolume()
Definition: G4Ellipsoid.cc:682
G4ThreeVector GetPointOnSurface() const
Definition: G4Ellipsoid.cc:781
G4ThreeVector SurfaceNormal(const G4ThreeVector &p) const
Definition: G4Ellipsoid.cc:313
G4VisExtent GetExtent() const
Definition: G4Ellipsoid.cc:868
virtual ~G4Ellipsoid()
Definition: G4Ellipsoid.cc:93
G4GeometryType GetEntityType() const
Definition: G4Ellipsoid.cc:642
G4int GetNumberOfRotationStepsAtTimeOfCreation() const
virtual void AddSolid(const G4Box &)=0
virtual void ComputeDimensions(G4Box &, const G4int, const G4VPhysicalVolume *) const
G4String GetName() const
void DumpInfo() const
G4double kCarTolerance
Definition: G4VSolid.hh:302
G4VSolid & operator=(const G4VSolid &rhs)
Definition: G4VSolid.cc:98
static G4int GetNumberOfRotationSteps()
EAxis
Definition: geomdefs.hh:54
EInside
Definition: geomdefs.hh:67
@ kInside
Definition: geomdefs.hh:70
@ kOutside
Definition: geomdefs.hh:68
@ kSurface
Definition: geomdefs.hh:69
Definition: DoubConv.h:17
#define EPS
#define DBL_EPSILON
Definition: templates.hh:66
#define DBL_MAX
Definition: templates.hh:62