Geant4 11.2.2
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4UCutTubs.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 for G4UCutTubs wrapper class
27//
28// 07.07.17 G.Cosmo, CERN/PH
29// --------------------------------------------------------------------
30
31#include "G4CutTubs.hh"
32#include "G4UCutTubs.hh"
33
34#if ( defined(G4GEOM_USE_USOLIDS) || defined(G4GEOM_USE_PARTIAL_USOLIDS) )
35
36#include "G4GeomTools.hh"
37#include "G4AffineTransform.hh"
39#include "G4BoundingEnvelope.hh"
40
41using namespace CLHEP;
42
43/////////////////////////////////////////////////////////////////////////
44//
45// Constructor - check parameters, convert angles so 0<sphi+dpshi<=2_PI
46// - note if pdphi>2PI then reset to 2PI
47
48G4UCutTubs::G4UCutTubs( const G4String& pName,
49 G4double pRMin, G4double pRMax,
50 G4double pDz,
51 G4double pSPhi, G4double pDPhi,
52 const G4ThreeVector& pLowNorm,
53 const G4ThreeVector& pHighNorm )
54 : Base_t(pName, pRMin, pRMax, pDz, pSPhi, pDPhi,
55 pLowNorm.x(), pLowNorm.y(), pLowNorm.z(),
56 pHighNorm.x(), pHighNorm.y(), pHighNorm.z())
57{
58}
59
60///////////////////////////////////////////////////////////////////////
61//
62// Fake default constructor - sets only member data and allocates memory
63// for usage restricted to object persistency.
64//
65G4UCutTubs::G4UCutTubs( __void__& a )
66 : Base_t(a)
67{
68}
69
70//////////////////////////////////////////////////////////////////////////
71//
72// Destructor
73
74G4UCutTubs::~G4UCutTubs() = default;
75
76//////////////////////////////////////////////////////////////////////////
77//
78// Copy constructor
79
80G4UCutTubs::G4UCutTubs(const G4UCutTubs& rhs)
81 : Base_t(rhs)
82{
83}
84
85//////////////////////////////////////////////////////////////////////////
86//
87// Assignment operator
88
89G4UCutTubs& G4UCutTubs::operator = (const G4UCutTubs& rhs)
90{
91 // Check assignment to self
92 //
93 if (this == &rhs) { return *this; }
94
95 // Copy base class data
96 //
97 Base_t::operator=(rhs);
98
99 return *this;
100}
101
102/////////////////////////////////////////////////////////////////////////
103//
104// Accessors and modifiers
105
106G4double G4UCutTubs::GetInnerRadius() const
107{
108 return rmin();
109}
110G4double G4UCutTubs::GetOuterRadius() const
111{
112 return rmax();
113}
114G4double G4UCutTubs::GetZHalfLength() const
115{
116 return z();
117}
118G4double G4UCutTubs::GetStartPhiAngle() const
119{
120 return sphi();
121}
122G4double G4UCutTubs::GetDeltaPhiAngle() const
123{
124 return dphi();
125}
126G4double G4UCutTubs::GetSinStartPhi() const
127{
128 return std::sin(GetStartPhiAngle());
129}
130G4double G4UCutTubs::GetCosStartPhi() const
131{
132 return std::cos(GetStartPhiAngle());
133}
134G4double G4UCutTubs::GetSinEndPhi() const
135{
136 return std::sin(GetStartPhiAngle()+GetDeltaPhiAngle());
137}
138G4double G4UCutTubs::GetCosEndPhi() const
139{
140 return std::cos(GetStartPhiAngle()+GetDeltaPhiAngle());
141}
142G4ThreeVector G4UCutTubs::GetLowNorm () const
143{
144 U3Vector lc = BottomNormal();
145 return {lc.x(), lc.y(), lc.z()};
146}
147G4ThreeVector G4UCutTubs::GetHighNorm () const
148{
149 U3Vector hc = TopNormal();
150 return {hc.x(), hc.y(), hc.z()};
151}
152
153void G4UCutTubs::SetInnerRadius(G4double newRMin)
154{
155 SetRMin(newRMin);
156 fRebuildPolyhedron = true;
157}
158void G4UCutTubs::SetOuterRadius(G4double newRMax)
159{
160 SetRMax(newRMax);
161 fRebuildPolyhedron = true;
162}
163void G4UCutTubs::SetZHalfLength(G4double newDz)
164{
165 SetDz(newDz);
166 fRebuildPolyhedron = true;
167}
168void G4UCutTubs::SetStartPhiAngle(G4double newSPhi, G4bool)
169{
170 SetSPhi(newSPhi);
171 fRebuildPolyhedron = true;
172}
173void G4UCutTubs::SetDeltaPhiAngle(G4double newDPhi)
174{
175 SetDPhi(newDPhi);
176 fRebuildPolyhedron = true;
177}
178
179/////////////////////////////////////////////////////////////////////////
180//
181// Make a clone of the object
182
183G4VSolid* G4UCutTubs::Clone() const
184{
185 return new G4UCutTubs(*this);
186}
187
188//////////////////////////////////////////////////////////////////////////
189//
190// Get bounding box
191
192void G4UCutTubs::BoundingLimits(G4ThreeVector& pMin, G4ThreeVector& pMax) const
193{
194 static G4bool checkBBox = true;
195
196 G4double rmin = GetInnerRadius();
197 G4double rmax = GetOuterRadius();
198 G4double dz = GetZHalfLength();
199 G4double dphi = GetDeltaPhiAngle();
200
201 G4double sinSphi = GetSinStartPhi();
202 G4double cosSphi = GetCosStartPhi();
203 G4double sinEphi = GetSinEndPhi();
204 G4double cosEphi = GetCosEndPhi();
205
206 G4ThreeVector norm;
207 G4double mag, topx, topy, dists, diste;
208 G4bool iftop;
209
210 // Find Zmin
211 //
212 G4double zmin;
213 norm = GetLowNorm();
214 mag = std::sqrt(norm.x()*norm.x() + norm.y()*norm.y());
215 topx = (mag == 0) ? 0 : -rmax*norm.x()/mag;
216 topy = (mag == 0) ? 0 : -rmax*norm.y()/mag;
217 dists = sinSphi*topx - cosSphi*topy;
218 diste = -sinEphi*topx + cosEphi*topy;
219 if (dphi > pi)
220 {
221 iftop = true;
222 if (dists > 0 && diste > 0)iftop = false;
223 }
224 else
225 {
226 iftop = false;
227 if (dists <= 0 && diste <= 0) iftop = true;
228 }
229 if (iftop)
230 {
231 zmin = -(norm.x()*topx + norm.y()*topy)/norm.z() - dz;
232 }
233 else
234 {
235 G4double z1 = -rmin*(norm.x()*cosSphi + norm.y()*sinSphi)/norm.z() - dz;
236 G4double z2 = -rmin*(norm.x()*cosEphi + norm.y()*sinEphi)/norm.z() - dz;
237 G4double z3 = -rmax*(norm.x()*cosSphi + norm.y()*sinSphi)/norm.z() - dz;
238 G4double z4 = -rmax*(norm.x()*cosEphi + norm.y()*sinEphi)/norm.z() - dz;
239 zmin = std::min(std::min(std::min(z1,z2),z3),z4);
240 }
241
242 // Find Zmax
243 //
244 G4double zmax;
245 norm = GetHighNorm();
246 mag = std::sqrt(norm.x()*norm.x() + norm.y()*norm.y());
247 topx = (mag == 0) ? 0 : -rmax*norm.x()/mag;
248 topy = (mag == 0) ? 0 : -rmax*norm.y()/mag;
249 dists = sinSphi*topx - cosSphi*topy;
250 diste = -sinEphi*topx + cosEphi*topy;
251 if (dphi > pi)
252 {
253 iftop = true;
254 if (dists > 0 && diste > 0) iftop = false;
255 }
256 else
257 {
258 iftop = false;
259 if (dists <= 0 && diste <= 0) iftop = true;
260 }
261 if (iftop)
262 {
263 zmax = -(norm.x()*topx + norm.y()*topy)/norm.z() + dz;
264 }
265 else
266 {
267 G4double z1 = -rmin*(norm.x()*cosSphi + norm.y()*sinSphi)/norm.z() + dz;
268 G4double z2 = -rmin*(norm.x()*cosEphi + norm.y()*sinEphi)/norm.z() + dz;
269 G4double z3 = -rmax*(norm.x()*cosSphi + norm.y()*sinSphi)/norm.z() + dz;
270 G4double z4 = -rmax*(norm.x()*cosEphi + norm.y()*sinEphi)/norm.z() + dz;
271 zmax = std::max(std::max(std::max(z1,z2),z3),z4);
272 }
273
274 // Find bounding box
275 //
276 if (GetDeltaPhiAngle() < twopi)
277 {
278 G4TwoVector vmin,vmax;
279 G4GeomTools::DiskExtent(rmin,rmax,
280 GetSinStartPhi(),GetCosStartPhi(),
281 GetSinEndPhi(),GetCosEndPhi(),
282 vmin,vmax);
283 pMin.set(vmin.x(),vmin.y(), zmin);
284 pMax.set(vmax.x(),vmax.y(), zmax);
285 }
286 else
287 {
288 pMin.set(-rmax,-rmax, zmin);
289 pMax.set( rmax, rmax, zmax);
290 }
291
292 // Check correctness of the bounding box
293 //
294 if (pMin.x() >= pMax.x() || pMin.y() >= pMax.y() || pMin.z() >= pMax.z())
295 {
296 std::ostringstream message;
297 message << "Bad bounding box (min >= max) for solid: "
298 << GetName() << " !"
299 << "\npMin = " << pMin
300 << "\npMax = " << pMax;
301 G4Exception("G4CUutTubs::BoundingLimits()", "GeomMgt0001",
302 JustWarning, message);
303 StreamInfo(G4cout);
304 }
305
306 // Check consistency of bounding boxes
307 //
308 if (checkBBox)
309 {
310 U3Vector vmin, vmax;
311 Extent(vmin,vmax);
312 if (std::abs(pMin.x()-vmin.x()) > kCarTolerance ||
313 std::abs(pMin.y()-vmin.y()) > kCarTolerance ||
314 std::abs(pMin.z()-vmin.z()) > kCarTolerance ||
315 std::abs(pMax.x()-vmax.x()) > kCarTolerance ||
316 std::abs(pMax.y()-vmax.y()) > kCarTolerance ||
317 std::abs(pMax.z()-vmax.z()) > kCarTolerance)
318 {
319 std::ostringstream message;
320 message << "Inconsistency in bounding boxes for solid: "
321 << GetName() << " !"
322 << "\nBBox min: wrapper = " << pMin << " solid = " << vmin
323 << "\nBBox max: wrapper = " << pMax << " solid = " << vmax;
324 G4Exception("G4UCutTubs::BoundingLimits()", "GeomMgt0001",
325 JustWarning, message);
326 checkBBox = false;
327 }
328 }
329}
330
331//////////////////////////////////////////////////////////////////////////
332//
333// Calculate extent under transform and specified limit
334
335G4bool
336G4UCutTubs::CalculateExtent(const EAxis pAxis,
337 const G4VoxelLimits& pVoxelLimit,
338 const G4AffineTransform& pTransform,
339 G4double& pMin, G4double& pMax) const
340{
341 G4ThreeVector bmin, bmax;
342 G4bool exist;
343
344 // Get bounding box
345 BoundingLimits(bmin,bmax);
346
347 // Check bounding box
348 G4BoundingEnvelope bbox(bmin,bmax);
349#ifdef G4BBOX_EXTENT
350 if (true) return bbox.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax);
351#endif
352 if (bbox.BoundingBoxVsVoxelLimits(pAxis,pVoxelLimit,pTransform,pMin,pMax))
353 {
354 return exist = pMin < pMax;
355 }
356
357 // Get parameters of the solid
358 G4double rmin = GetInnerRadius();
359 G4double rmax = GetOuterRadius();
360 G4double dphi = GetDeltaPhiAngle();
361 G4double zmin = bmin.z();
362 G4double zmax = bmax.z();
363
364 // Find bounding envelope and calculate extent
365 //
366 const G4int NSTEPS = 24; // number of steps for whole circle
367 G4double astep = twopi/NSTEPS; // max angle for one step
368 G4int ksteps = (dphi <= astep) ? 1 : (G4int)((dphi-deg)/astep) + 1;
369 G4double ang = dphi/ksteps;
370
371 G4double sinHalf = std::sin(0.5*ang);
372 G4double cosHalf = std::cos(0.5*ang);
373 G4double sinStep = 2.*sinHalf*cosHalf;
374 G4double cosStep = 1. - 2.*sinHalf*sinHalf;
375 G4double rext = rmax/cosHalf;
376
377 // bounding envelope for full cylinder consists of two polygons,
378 // in other cases it is a sequence of quadrilaterals
379 if (rmin == 0 && dphi == twopi)
380 {
381 G4double sinCur = sinHalf;
382 G4double cosCur = cosHalf;
383
384 G4ThreeVectorList baseA(NSTEPS),baseB(NSTEPS);
385 for (G4int k=0; k<NSTEPS; ++k)
386 {
387 baseA[k].set(rext*cosCur,rext*sinCur,zmin);
388 baseB[k].set(rext*cosCur,rext*sinCur,zmax);
389
390 G4double sinTmp = sinCur;
391 sinCur = sinCur*cosStep + cosCur*sinStep;
392 cosCur = cosCur*cosStep - sinTmp*sinStep;
393 }
394 std::vector<const G4ThreeVectorList *> polygons(2);
395 polygons[0] = &baseA;
396 polygons[1] = &baseB;
397 G4BoundingEnvelope benv(bmin,bmax,polygons);
398 exist = benv.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax);
399 }
400 else
401 {
402 G4double sinStart = GetSinStartPhi();
403 G4double cosStart = GetCosStartPhi();
404 G4double sinEnd = GetSinEndPhi();
405 G4double cosEnd = GetCosEndPhi();
406 G4double sinCur = sinStart*cosHalf + cosStart*sinHalf;
407 G4double cosCur = cosStart*cosHalf - sinStart*sinHalf;
408
409 // set quadrilaterals
410 G4ThreeVectorList pols[NSTEPS+2];
411 for (G4int k=0; k<ksteps+2; ++k) pols[k].resize(4);
412 pols[0][0].set(rmin*cosStart,rmin*sinStart,zmax);
413 pols[0][1].set(rmin*cosStart,rmin*sinStart,zmin);
414 pols[0][2].set(rmax*cosStart,rmax*sinStart,zmin);
415 pols[0][3].set(rmax*cosStart,rmax*sinStart,zmax);
416 for (G4int k=1; k<ksteps+1; ++k)
417 {
418 pols[k][0].set(rmin*cosCur,rmin*sinCur,zmax);
419 pols[k][1].set(rmin*cosCur,rmin*sinCur,zmin);
420 pols[k][2].set(rext*cosCur,rext*sinCur,zmin);
421 pols[k][3].set(rext*cosCur,rext*sinCur,zmax);
422
423 G4double sinTmp = sinCur;
424 sinCur = sinCur*cosStep + cosCur*sinStep;
425 cosCur = cosCur*cosStep - sinTmp*sinStep;
426 }
427 pols[ksteps+1][0].set(rmin*cosEnd,rmin*sinEnd,zmax);
428 pols[ksteps+1][1].set(rmin*cosEnd,rmin*sinEnd,zmin);
429 pols[ksteps+1][2].set(rmax*cosEnd,rmax*sinEnd,zmin);
430 pols[ksteps+1][3].set(rmax*cosEnd,rmax*sinEnd,zmax);
431
432 // set envelope and calculate extent
433 std::vector<const G4ThreeVectorList *> polygons;
434 polygons.resize(ksteps+2);
435 for (G4int k=0; k<ksteps+2; ++k) polygons[k] = &pols[k];
436 G4BoundingEnvelope benv(bmin,bmax,polygons);
437 exist = benv.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax);
438 }
439 return exist;
440}
441
442///////////////////////////////////////////////////////////////////////////
443//
444// Return real Z coordinate of point on Cutted +/- fDZ plane
445
446G4double G4UCutTubs::GetCutZ(const G4ThreeVector& p) const
447{
448 G4double newz = p.z(); // p.z() should be either +fDz or -fDz
449 G4ThreeVector fLowNorm = GetLowNorm();
450 G4ThreeVector fHighNorm = GetHighNorm();
451
452 if (p.z()<0)
453 {
454 if(fLowNorm.z()!=0.)
455 {
456 newz = -GetZHalfLength()
457 - (p.x()*fLowNorm.x()+p.y()*fLowNorm.y())/fLowNorm.z();
458 }
459 }
460 else
461 {
462 if(fHighNorm.z()!=0.)
463 {
464 newz = GetZHalfLength()
465 - (p.x()*fHighNorm.x()+p.y()*fHighNorm.y())/fHighNorm.z();
466 }
467 }
468 return newz;
469}
470
471//////////////////////////////////////////////////////////////////////////
472//
473// Create polyhedron for visualization
474//
475G4Polyhedron* G4UCutTubs::CreatePolyhedron() const
476{
477 typedef G4double G4double3[3];
478 typedef G4int G4int4[4];
479
480 auto ph = new G4Polyhedron;
481 G4Polyhedron *ph1 = new G4PolyhedronTubs(GetInnerRadius(),
482 GetOuterRadius(),
483 GetZHalfLength(),
484 GetStartPhiAngle(),
485 GetDeltaPhiAngle());
486 G4int nn=ph1->GetNoVertices();
487 G4int nf=ph1->GetNoFacets();
488 auto xyz = new G4double3[nn]; // number of nodes
489 auto faces = new G4int4[nf] ; // number of faces
490 G4double fDz = GetZHalfLength();
491
492 for(G4int i=0; i<nn; ++i)
493 {
494 xyz[i][0]=ph1->GetVertex(i+1).x();
495 xyz[i][1]=ph1->GetVertex(i+1).y();
496 G4double tmpZ=ph1->GetVertex(i+1).z();
497 if (tmpZ>=fDz-kCarTolerance)
498 {
499 xyz[i][2]=GetCutZ(G4ThreeVector(xyz[i][0],xyz[i][1],fDz));
500 }
501 else if(tmpZ<=-fDz+kCarTolerance)
502 {
503 xyz[i][2]=GetCutZ(G4ThreeVector(xyz[i][0],xyz[i][1],-fDz));
504 }
505 else
506 {
507 xyz[i][2]=tmpZ;
508 }
509 }
510 G4int iNodes[4];
511 G4int* iEdge=nullptr;
512 G4int n;
513 for(G4int i=0; i<nf; ++i)
514 {
515 ph1->GetFacet(i+1,n,iNodes,iEdge);
516 for(G4int k=0; k<n; ++k)
517 {
518 faces[i][k]=iNodes[k];
519 }
520 for(G4int k=n; k<4; ++k)
521 {
522 faces[i][k]=0;
523 }
524 }
525 ph->createPolyhedron(nn,nf,xyz,faces);
526
527 delete [] xyz;
528 delete [] faces;
529 delete ph1;
530
531 return ph;
532}
533
534#endif // G4GEOM_USE_USOLIDS
const G4double kCarTolerance
std::vector< G4ThreeVector > G4ThreeVectorList
@ JustWarning
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
CLHEP::Hep3Vector G4ThreeVector
double G4double
Definition G4Types.hh:83
bool G4bool
Definition G4Types.hh:86
int G4int
Definition G4Types.hh:85
double x() const
double y() const
double z() const
double x() const
double y() const
void set(double x, double y, double z)
static G4bool DiskExtent(G4double rmin, G4double rmax, G4double startPhi, G4double delPhi, G4TwoVector &pmin, G4TwoVector &pmax)
G4Point3D GetVertex(G4int index) const
void GetFacet(G4int iFace, G4int &n, G4int *iNodes, G4int *edgeFlags=nullptr, G4int *iFaces=nullptr) const
G4int GetNoFacets() const
G4int GetNoVertices() const
EAxis
Definition geomdefs.hh:54
const G4double hc
[MeV*fm]