Geant4 11.4.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4Polycone.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 G4Polycone, a CSG polycone
27//
28// Author: David C. Williams (UCSC), 1998
29// --------------------------------------------------------------------
30
31#include "G4Polycone.hh"
32
33#if !defined(G4GEOM_USE_UPOLYCONE)
34
35#include "G4PolyconeSide.hh"
36#include "G4PolyPhiFace.hh"
37
38#include "G4GeomTools.hh"
39#include "G4VoxelLimits.hh"
40#include "G4AffineTransform.hh"
41#include "G4BoundingEnvelope.hh"
42
43#include "G4QuickRand.hh"
44
46#include "G4ReduciblePolygon.hh"
48
49namespace
50{
51 G4Mutex surface_elementsMutex = G4MUTEX_INITIALIZER;
52 G4Mutex polyconeMutex = G4MUTEX_INITIALIZER;
53}
54
55using namespace CLHEP;
56
57// Constructor (GEANT3 style parameters)
58//
60 G4double phiStart,
61 G4double phiTotal,
62 G4int numZPlanes,
63 const G4double zPlane[],
64 const G4double rInner[],
65 const G4double rOuter[] )
66 : G4VCSGfaceted( name )
67{
68 //
69 // Some historical ugliness
70 //
71 original_parameters = new G4PolyconeHistorical();
72
73 original_parameters->Start_angle = phiStart;
74 original_parameters->Opening_angle = phiTotal;
75 original_parameters->Num_z_planes = numZPlanes;
76 original_parameters->Z_values = new G4double[numZPlanes];
77 original_parameters->Rmin = new G4double[numZPlanes];
78 original_parameters->Rmax = new G4double[numZPlanes];
79
80 for (G4int i=0; i<numZPlanes; ++i)
81 {
82 if(rInner[i]>rOuter[i])
83 {
84 DumpInfo();
85 std::ostringstream message;
86 message << "Cannot create a Polycone with rInner > rOuter for the same Z"
87 << G4endl
88 << " rInner > rOuter for the same Z !" << G4endl
89 << " rMin[" << i << "] = " << rInner[i]
90 << " -- rMax[" << i << "] = " << rOuter[i];
91 G4Exception("G4Polycone::G4Polycone()", "GeomSolids0002",
92 FatalErrorInArgument, message);
93 }
94 if (( i < numZPlanes-1) && ( zPlane[i] == zPlane[i+1] ))
95 {
96 if( (rInner[i] > rOuter[i+1])
97 ||(rInner[i+1] > rOuter[i]) )
98 {
99 DumpInfo();
100 std::ostringstream message;
101 message << "Cannot create a Polycone with no contiguous segments."
102 << G4endl
103 << " Segments are not contiguous !" << G4endl
104 << " rMin[" << i << "] = " << rInner[i]
105 << " -- rMax[" << i+1 << "] = " << rOuter[i+1] << G4endl
106 << " rMin[" << i+1 << "] = " << rInner[i+1]
107 << " -- rMax[" << i << "] = " << rOuter[i];
108 G4Exception("G4Polycone::G4Polycone()", "GeomSolids0002",
109 FatalErrorInArgument, message);
110 }
111 }
112 original_parameters->Z_values[i] = zPlane[i];
113 original_parameters->Rmin[i] = rInner[i];
114 original_parameters->Rmax[i] = rOuter[i];
115 }
116
117 //
118 // Build RZ polygon using special PCON/PGON GEANT3 constructor
119 //
120 auto rz = new G4ReduciblePolygon( rInner, rOuter, zPlane, numZPlanes );
121
122 //
123 // Do the real work
124 //
125 Create( phiStart, phiTotal, rz );
126
127 delete rz;
128}
129
130// Constructor (generic parameters)
131//
133 G4double phiStart,
134 G4double phiTotal,
135 G4int numRZ,
136 const G4double r[],
137 const G4double z[] )
138 : G4VCSGfaceted( name )
139{
140
141 auto rz = new G4ReduciblePolygon( r, z, numRZ );
142
143 Create( phiStart, phiTotal, rz );
144
145 // Set original_parameters struct for consistency
146 //
147
148 G4bool convertible = SetOriginalParameters(rz);
149
150 if(!convertible)
151 {
152 std::ostringstream message;
153 message << "Polycone " << GetName() << "cannot be converted" << G4endl
154 << "to Polycone with (Rmin,Rmaz,Z) parameters!";
155 G4Exception("G4Polycone::G4Polycone()", "GeomSolids0002",
156 FatalException, message, "Use G4GenericPolycone instead!");
157 }
158 else
159 {
160 G4cout << "INFO: Converting polycone " << GetName() << G4endl
161 << "to optimized polycone with (Rmin,Rmaz,Z) parameters !"
162 << G4endl;
163 }
164 delete rz;
165}
166
167// Create
168//
169// Generic create routine, called by each constructor after
170// conversion of arguments
171//
172void G4Polycone::Create( G4double phiStart,
173 G4double phiTotal,
175{
176 //
177 // Perform checks of rz values
178 //
179 if (rz->Amin() < 0.0)
180 {
181 std::ostringstream message;
182 message << "Illegal input parameters - " << GetName() << G4endl
183 << " All R values must be >= 0 !";
184 G4Exception("G4Polycone::Create()", "GeomSolids0002",
185 FatalErrorInArgument, message);
186 }
187
188 G4double rzArea = rz->Area();
189 if (rzArea < -kCarTolerance)
190 {
191 rz->ReverseOrder();
192 }
193 else if (rzArea < kCarTolerance)
194 {
195 std::ostringstream message;
196 message << "Illegal input parameters - " << GetName() << G4endl
197 << " R/Z cross section is zero or near zero: " << rzArea;
198 G4Exception("G4Polycone::Create()", "GeomSolids0002",
199 FatalErrorInArgument, message);
200 }
201
204 {
205 std::ostringstream message;
206 message << "Illegal input parameters - " << GetName() << G4endl
207 << " Too few unique R/Z values !";
208 G4Exception("G4Polycone::Create()", "GeomSolids0002",
209 FatalErrorInArgument, message);
210 }
211
212 if (rz->CrossesItself(1/kInfinity))
213 {
214 std::ostringstream message;
215 message << "Illegal input parameters - " << GetName() << G4endl
216 << " R/Z segments cross !";
217 G4Exception("G4Polycone::Create()", "GeomSolids0002",
218 FatalErrorInArgument, message);
219 }
220
221 numCorner = rz->NumVertices();
222
223 startPhi = phiStart;
224 while( startPhi < 0. ) // Loop checking, 13.08.2015, G.Cosmo
225 {
226 startPhi += twopi;
227 }
228 //
229 // Phi opening? Account for some possible roundoff, and interpret
230 // nonsense value as representing no phi opening
231 //
232 if ( (phiTotal <= 0) || (phiTotal > twopi*(1-DBL_EPSILON)) )
233 {
234 phiIsOpen = false;
235 startPhi = 0.;
236 endPhi = twopi;
237 }
238 else
239 {
240 phiIsOpen = true;
241 endPhi = startPhi + phiTotal;
242 }
243
244 //
245 // Allocate corner array.
246 //
247 corners = new G4PolyconeSideRZ[numCorner];
248
249 //
250 // Copy corners
251 //
252 G4ReduciblePolygonIterator iterRZ(rz);
253
254 G4PolyconeSideRZ *next = corners;
255 iterRZ.Begin();
256 do // Loop checking, 13.08.2015, G.Cosmo
257 {
258 next->r = iterRZ.GetA();
259 next->z = iterRZ.GetB();
260 } while( ++next, iterRZ.Next() );
261
262 //
263 // Allocate face pointer array
264 //
265 numFace = phiIsOpen ? numCorner+2 : numCorner;
266 faces = new G4VCSGface*[numFace];
267
268 //
269 // Construct conical faces
270 //
271 // But! Don't construct a face if both points are at zero radius!
272 //
273 G4PolyconeSideRZ* corner = corners,
274 * prev = corners + numCorner-1,
275 * nextNext;
276 G4VCSGface **face = faces;
277 do // Loop checking, 13.08.2015, G.Cosmo
278 {
279 next = corner+1;
280 if (next >= corners+numCorner) { next = corners; }
281 nextNext = next+1;
282 if (nextNext >= corners+numCorner) { nextNext = corners; }
283
284 if (corner->r < 1/kInfinity && next->r < 1/kInfinity) { continue; }
285
286 //
287 // We must decide here if we can dare declare one of our faces
288 // as having a "valid" normal (i.e. allBehind = true). This
289 // is never possible if the face faces "inward" in r.
290 //
291 G4bool allBehind;
292 if (corner->z > next->z)
293 {
294 allBehind = false;
295 }
296 else
297 {
298 //
299 // Otherwise, it is only true if the line passing
300 // through the two points of the segment do not
301 // split the r/z cross section
302 //
303 allBehind = !rz->BisectedBy( corner->r, corner->z,
304 next->r, next->z, kCarTolerance );
305 }
306
307 *face++ = new G4PolyconeSide( prev, corner, next, nextNext,
308 startPhi, endPhi-startPhi, phiIsOpen, allBehind );
309 } while( prev=corner, corner=next, corner > corners );
310
311 if (phiIsOpen)
312 {
313 //
314 // Construct phi open edges
315 //
316 *face++ = new G4PolyPhiFace( rz, startPhi, 0, endPhi );
317 *face++ = new G4PolyPhiFace( rz, endPhi, 0, startPhi );
318 }
319
320 //
321 // We might have dropped a face or two: recalculate numFace
322 //
323 numFace = (G4int)(face-faces);
324
325 //
326 // Make enclosingCylinder
327 //
328 enclosingCylinder =
329 new G4EnclosingCylinder( rz, phiIsOpen, phiStart, phiTotal );
330}
331
332// Fake default constructor - sets only member data and allocates memory
333// for usage restricted to object persistency.
334//
336 : G4VCSGfaceted(a), startPhi(0.), endPhi(0.), numCorner(0)
337{
338}
339
340
341//
342// Destructor
343//
345{
346 delete [] corners;
347 delete original_parameters;
348 delete enclosingCylinder;
349 delete fElements;
350 delete fpPolyhedron;
351 corners = nullptr;
352 original_parameters = nullptr;
353 enclosingCylinder = nullptr;
354 fElements = nullptr;
355 fpPolyhedron = nullptr;
356}
357
358// Copy constructor
359//
361 : G4VCSGfaceted( source )
362{
363 CopyStuff( source );
364}
365
366// Assignment operator
367//
369{
370 if (this == &source) { return *this; }
371
372 G4VCSGfaceted::operator=( source );
373
374 delete [] corners;
375 delete original_parameters;
376
377 delete enclosingCylinder;
378
379 CopyStuff( source );
380
381 return *this;
382}
383
384// CopyStuff
385//
386void G4Polycone::CopyStuff( const G4Polycone& source )
387{
388 //
389 // Simple stuff
390 //
391 startPhi = source.startPhi;
392 endPhi = source.endPhi;
393 phiIsOpen = source.phiIsOpen;
394 numCorner = source.numCorner;
395
396 //
397 // The corner array
398 //
399 corners = new G4PolyconeSideRZ[numCorner];
400
401 G4PolyconeSideRZ* corn = corners,
402 * sourceCorn = source.corners;
403 do // Loop checking, 13.08.2015, G.Cosmo
404 {
405 *corn = *sourceCorn;
406 } while( ++sourceCorn, ++corn < corners+numCorner );
407
408 //
409 // Original parameters
410 //
411 if (source.original_parameters != nullptr)
412 {
413 original_parameters =
414 new G4PolyconeHistorical( *source.original_parameters );
415 }
416
417 //
418 // Enclosing cylinder
419 //
420 enclosingCylinder = new G4EnclosingCylinder( *source.enclosingCylinder );
421
422 //
423 // Surface elements
424 //
425 delete fElements;
426 fElements = nullptr;
427
428 //
429 // Polyhedron
430 //
431 fRebuildPolyhedron = false;
432 delete fpPolyhedron;
433 fpPolyhedron = nullptr;
434}
435
436// Reset
437//
439{
440 //
441 // Clear old setup
442 //
444 delete [] corners;
445 delete enclosingCylinder;
446 delete fElements;
447 corners = nullptr;
448 fElements = nullptr;
449 enclosingCylinder = nullptr;
450
451 //
452 // Rebuild polycone
453 //
454 auto rz = new G4ReduciblePolygon( original_parameters->Rmin,
455 original_parameters->Rmax,
456 original_parameters->Z_values,
457 original_parameters->Num_z_planes );
458 Create( original_parameters->Start_angle,
459 original_parameters->Opening_angle, rz );
460 delete rz;
461
462 return false;
463}
464
465// Inside
466//
467// This is an override of G4VCSGfaceted::Inside, created in order
468// to speed things up by first checking with G4EnclosingCylinder.
469//
471{
472 //
473 // Quick test
474 //
475 if (enclosingCylinder->MustBeOutside(p)) { return kOutside; }
476
477 //
478 // Long answer
479 //
480 return G4VCSGfaceted::Inside(p);
481}
482
483// DistanceToIn
484//
485// This is an override of G4VCSGfaceted::Inside, created in order
486// to speed things up by first checking with G4EnclosingCylinder.
487//
489 const G4ThreeVector& v ) const
490{
491 //
492 // Quick test
493 //
494 if (enclosingCylinder->ShouldMiss(p,v)) { return kInfinity; }
495
496 //
497 // Long answer
498 //
499 return G4VCSGfaceted::DistanceToIn( p, v );
500}
501
502// DistanceToIn
503//
508
509// Get bounding box
510//
512 G4ThreeVector& pMax) const
513{
514 G4double rmin = kInfinity, rmax = -kInfinity;
515 G4double zmin = kInfinity, zmax = -kInfinity;
516
517 for (G4int i=0; i<GetNumRZCorner(); ++i)
518 {
519 G4PolyconeSideRZ corner = GetCorner(i);
520 if (corner.r < rmin) { rmin = corner.r; }
521 if (corner.r > rmax) { rmax = corner.r; }
522 if (corner.z < zmin) { zmin = corner.z; }
523 if (corner.z > zmax) { zmax = corner.z; }
524 }
525
526 if (IsOpen())
527 {
528 G4TwoVector vmin,vmax;
529 G4GeomTools::DiskExtent(rmin,rmax,
532 vmin,vmax);
533 pMin.set(vmin.x(),vmin.y(),zmin);
534 pMax.set(vmax.x(),vmax.y(),zmax);
535 }
536 else
537 {
538 pMin.set(-rmax,-rmax, zmin);
539 pMax.set( rmax, rmax, zmax);
540 }
541
542 // Check correctness of the bounding box
543 //
544 if (pMin.x() >= pMax.x() || pMin.y() >= pMax.y() || pMin.z() >= pMax.z())
545 {
546 std::ostringstream message;
547 message << "Bad bounding box (min >= max) for solid: "
548 << GetName() << " !"
549 << "\npMin = " << pMin
550 << "\npMax = " << pMax;
551 G4Exception("G4Polycone::BoundingLimits()", "GeomMgt0001",
552 JustWarning, message);
553 DumpInfo();
554 }
555}
556
557// Calculate extent under transform and specified limit
558//
560 const G4VoxelLimits& pVoxelLimit,
561 const G4AffineTransform& pTransform,
562 G4double& pMin, G4double& pMax) const
563{
564 G4ThreeVector bmin, bmax;
565 G4bool exist;
566
567 // Check bounding box (bbox)
568 //
569 BoundingLimits(bmin,bmax);
570 G4BoundingEnvelope bbox(bmin,bmax);
571#ifdef G4BBOX_EXTENT
572 return bbox.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax);
573#endif
574 if (bbox.BoundingBoxVsVoxelLimits(pAxis,pVoxelLimit,pTransform,pMin,pMax))
575 {
576 return exist = pMin < pMax;
577 }
578
579 // To find the extent, RZ contour of the polycone is subdivided
580 // in triangles. The extent is calculated as cumulative extent of
581 // all sub-polycones formed by rotation of triangles around Z
582 //
583 G4TwoVectorList contourRZ;
584 G4TwoVectorList triangles;
585 std::vector<G4int> iout;
586 G4double eminlim = pVoxelLimit.GetMinExtent(pAxis);
587 G4double emaxlim = pVoxelLimit.GetMaxExtent(pAxis);
588
589 // get RZ contour, ensure anticlockwise order of corners
590 for (G4int i=0; i<GetNumRZCorner(); ++i)
591 {
592 G4PolyconeSideRZ corner = GetCorner(i);
593 contourRZ.emplace_back(corner.r,corner.z);
594 }
596 G4double area = G4GeomTools::PolygonArea(contourRZ);
597 if (area < 0.) { std::reverse(contourRZ.begin(),contourRZ.end()); }
598
599 // triangulate RZ countour
600 if (!G4GeomTools::TriangulatePolygon(contourRZ,triangles))
601 {
602 std::ostringstream message;
603 message << "Triangulation of RZ contour has failed for solid: "
604 << GetName() << " !"
605 << "\nExtent has been calculated using boundary box";
606 G4Exception("G4Polycone::CalculateExtent()",
607 "GeomMgt1002", JustWarning, message);
608 return bbox.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax);
609 }
610
611 // set trigonometric values
612 const G4int NSTEPS = 24; // number of steps for whole circle
613 G4double astep = twopi/NSTEPS; // max angle for one step
614
615 G4double sphi = GetStartPhi();
616 G4double ephi = GetEndPhi();
617 G4double dphi = IsOpen() ? ephi-sphi : twopi;
618 G4int ksteps = (dphi <= astep) ? 1 : (G4int)((dphi-deg)/astep) + 1;
619 G4double ang = dphi/ksteps;
620
621 G4double sinHalf = std::sin(0.5*ang);
622 G4double cosHalf = std::cos(0.5*ang);
623 G4double sinStep = 2.*sinHalf*cosHalf;
624 G4double cosStep = 1. - 2.*sinHalf*sinHalf;
625
626 G4double sinStart = GetSinStartPhi();
627 G4double cosStart = GetCosStartPhi();
628 G4double sinEnd = GetSinEndPhi();
629 G4double cosEnd = GetCosEndPhi();
630
631 // define vectors and arrays
632 std::vector<const G4ThreeVectorList *> polygons;
633 polygons.resize(ksteps+2);
634 G4ThreeVectorList pols[NSTEPS+2];
635 for (G4int k=0; k<ksteps+2; ++k)
636 {
637 pols[k].resize(6);
638 }
639 for (G4int k=0; k<ksteps+2; ++k)
640 {
641 polygons[k] = &pols[k];
642 }
643 G4double r0[6],z0[6]; // contour with original edges of triangle
644 G4double r1[6]; // shifted radii of external edges of triangle
645
646 // main loop along triangles
647 pMin = kInfinity;
648 pMax =-kInfinity;
649 G4int ntria = (G4int)triangles.size()/3;
650 for (G4int i=0; i<ntria; ++i)
651 {
652 G4int i3 = i*3;
653 for (G4int k=0; k<3; ++k)
654 {
655 G4int e0 = i3+k, e1 = (k<2) ? e0+1 : i3;
656 G4int k2 = k*2;
657 // set contour with original edges of triangle
658 r0[k2+0] = triangles[e0].x(); z0[k2+0] = triangles[e0].y();
659 r0[k2+1] = triangles[e1].x(); z0[k2+1] = triangles[e1].y();
660 // set shifted radii
661 r1[k2+0] = r0[k2+0];
662 r1[k2+1] = r0[k2+1];
663 if (z0[k2+1] - z0[k2+0] <= 0) { continue; }
664 r1[k2+0] /= cosHalf;
665 r1[k2+1] /= cosHalf;
666 }
667
668 // rotate countour, set sequence of 6-sided polygons
669 G4double sinCur = sinStart*cosHalf + cosStart*sinHalf;
670 G4double cosCur = cosStart*cosHalf - sinStart*sinHalf;
671 for (G4int j=0; j<6; ++j)
672 {
673 pols[0][j].set(r0[j]*cosStart,r0[j]*sinStart,z0[j]);
674 }
675 for (G4int k=1; k<ksteps+1; ++k)
676 {
677 for (G4int j=0; j<6; ++j)
678 {
679 pols[k][j].set(r1[j]*cosCur,r1[j]*sinCur,z0[j]);
680 }
681 G4double sinTmp = sinCur;
682 sinCur = sinCur*cosStep + cosCur*sinStep;
683 cosCur = cosCur*cosStep - sinTmp*sinStep;
684 }
685 for (G4int j=0; j<6; ++j)
686 {
687 pols[ksteps+1][j].set(r0[j]*cosEnd,r0[j]*sinEnd,z0[j]);
688 }
689
690 // set sub-envelope and adjust extent
691 G4double emin,emax;
692 G4BoundingEnvelope benv(polygons);
693 if (!benv.CalculateExtent(pAxis,pVoxelLimit,pTransform,emin,emax))
694 {
695 continue;
696 }
697 if (emin < pMin) { pMin = emin; }
698 if (emax > pMax) { pMax = emax; }
699 if (eminlim > pMin && emaxlim < pMax) { return true; } // max possible extent
700 }
701 return (pMin < pMax);
702}
703
704// ComputeDimensions
705//
707 const G4int n,
708 const G4VPhysicalVolume* pRep )
709{
710 p->ComputeDimensions(*this,n,pRep);
711}
712
713// GetEntityType
714//
716{
717 return {"G4Polycone"};
718}
719
720// Make a clone of the object
721//
723{
724 return new G4Polycone(*this);
725}
726
727//
728// Stream object contents to an output stream
729//
730std::ostream& G4Polycone::StreamInfo( std::ostream& os ) const
731{
732 G4long oldprc = os.precision(16);
733 os << "-----------------------------------------------------------\n"
734 << " *** Dump for solid - " << GetName() << " ***\n"
735 << " ===================================================\n"
736 << " Solid type: G4Polycone\n"
737 << " Parameters: \n"
738 << " starting phi angle : " << startPhi/degree << " degrees \n"
739 << " ending phi angle : " << endPhi/degree << " degrees \n";
740 G4int i=0;
741
742 G4int numPlanes = original_parameters->Num_z_planes;
743 os << " number of Z planes: " << numPlanes << "\n"
744 << " Z values: \n";
745 for (i=0; i<numPlanes; ++i)
746 {
747 os << " Z plane " << i << ": "
748 << original_parameters->Z_values[i] << "\n";
749 }
750 os << " Tangent distances to inner surface (Rmin): \n";
751 for (i=0; i<numPlanes; ++i)
752 {
753 os << " Z plane " << i << ": "
754 << original_parameters->Rmin[i] << "\n";
755 }
756 os << " Tangent distances to outer surface (Rmax): \n";
757 for (i=0; i<numPlanes; ++i)
758 {
759 os << " Z plane " << i << ": "
760 << original_parameters->Rmax[i] << "\n";
761 }
762
763 os << " number of RZ points: " << numCorner << "\n"
764 << " RZ values (corners): \n";
765 for (i=0; i<numCorner; ++i)
766 {
767 os << " "
768 << corners[i].r << ", " << corners[i].z << "\n";
769 }
770 os << "-----------------------------------------------------------\n";
771 os.precision(oldprc);
772
773 return os;
774}
775
776//////////////////////////////////////////////////////////////////////////
777//
778// Return volume
779
781{
782 if (fCubicVolume == 0)
783 {
784 G4AutoLock l(&polyconeMutex);
785 G4double total = 0.;
786 G4int nrz = GetNumRZCorner();
787 G4PolyconeSideRZ a = GetCorner(nrz - 1);
788 for (G4int i=0; i<nrz; ++i)
789 {
791 total += (b.r*b.r + b.r*a.r + a.r*a.r)*(b.z - a.z);
792 a = b;
793 }
794 fCubicVolume = std::abs(total)*(GetEndPhi() - GetStartPhi())/6.;
795 l.unlock();
796 }
797 return fCubicVolume;
798}
799
800//////////////////////////////////////////////////////////////////////////
801//
802// Return surface area
803
805{
806 if (fSurfaceArea == 0)
807 {
808 G4AutoLock l(&polyconeMutex);
809 // phi cut area
810 G4int nrz = GetNumRZCorner();
811 G4double scut = 0.;
812 if (IsOpen())
813 {
814 G4PolyconeSideRZ a = GetCorner(nrz - 1);
815 for (G4int i=0; i<nrz; ++i)
816 {
818 scut += a.r*b.z - a.z*b.r;
819 a = b;
820 }
821 scut = std::abs(scut);
822 }
823 // lateral surface area
824 G4double slat = 0;
825 G4PolyconeSideRZ a = GetCorner(nrz - 1);
826 for (G4int i=0; i<nrz; ++i)
827 {
829 G4double h = std::sqrt((b.r - a.r)*(b.r - a.r) + (b.z - a.z)*(b.z - a.z));
830 slat += (b.r + a.r)*h;
831 a = b;
832 }
833 slat *= (GetEndPhi() - GetStartPhi())/2.;
834 fSurfaceArea = scut + slat;
835 l.unlock();
836 }
837 return fSurfaceArea;
838}
839
840//////////////////////////////////////////////////////////////////////////
841//
842// Set vector of surface elements, auxiliary method for sampling
843// random points on surface
844
845void G4Polycone::SetSurfaceElements() const
846{
847 fElements = new std::vector<G4Polycone::surface_element>;
848 G4double total = 0.;
849 G4int nrz = GetNumRZCorner();
850
851 // set lateral surface elements
852 G4double dphi = GetEndPhi() - GetStartPhi();
853 G4int ia = nrz - 1;
854 for (G4int ib=0; ib<nrz; ++ib)
855 {
858 G4Polycone::surface_element selem;
859 selem.i0 = ia;
860 selem.i1 = ib;
861 selem.i2 = -1;
862 ia = ib;
863 if (a.r == 0. && b.r == 0.) { continue; }
864 G4double h = std::sqrt((b.r - a.r)*(b.r - a.r) + (b.z - a.z)*(b.z - a.z));
865 total += 0.5*dphi*(b.r + a.r)*h;
866 selem.area = total;
867 fElements->push_back(selem);
868 }
869
870 // set elements for phi cuts
871 if (IsOpen())
872 {
873 G4TwoVectorList contourRZ;
874 std::vector<G4int> triangles;
875 for (G4int i=0; i<nrz; ++i)
876 {
877 G4PolyconeSideRZ corner = GetCorner(i);
878 contourRZ.emplace_back(corner.r, corner.z);
879 }
880 G4GeomTools::TriangulatePolygon(contourRZ, triangles);
881 auto ntria = (G4int)triangles.size();
882 for (G4int i=0; i<ntria; i+=3)
883 {
884 G4Polycone::surface_element selem;
885 selem.i0 = triangles[i];
886 selem.i1 = triangles[i+1];
887 selem.i2 = triangles[i+2];
888 G4PolyconeSideRZ a = GetCorner(selem.i0);
889 G4PolyconeSideRZ b = GetCorner(selem.i1);
890 G4PolyconeSideRZ c = GetCorner(selem.i2);
891 G4double stria =
892 std::abs(G4GeomTools::TriangleArea(a.r, a.z, b.r, b.z, c.r, c.z));
893 total += stria;
894 selem.area = total;
895 fElements->push_back(selem); // start phi
896 total += stria;
897 selem.area = total;
898 selem.i0 += nrz;
899 fElements->push_back(selem); // end phi
900 }
901 }
902}
903
904//////////////////////////////////////////////////////////////////////////
905//
906// Generate random point on surface
907
909{
910 // Set surface elements
911 if (fElements == nullptr)
912 {
913 G4AutoLock l(&surface_elementsMutex);
914 SetSurfaceElements();
915 l.unlock();
916 }
917
918 // Select surface element
919 G4Polycone::surface_element selem;
920 selem = fElements->back();
921 G4double select = selem.area*G4QuickRand();
922 auto it = std::lower_bound(fElements->begin(), fElements->end(), select,
923 [](const G4Polycone::surface_element& x, G4double val)
924 -> G4bool { return x.area < val; });
925
926 // Generate random point
927 G4double r = 0, z = 0, phi = 0;
928 G4double u = G4QuickRand();
929 G4double v = G4QuickRand();
930 G4int i0 = (*it).i0;
931 G4int i1 = (*it).i1;
932 G4int i2 = (*it).i2;
933 if (i2 < 0) // lateral surface
934 {
937 if (p1.r < p0.r)
938 {
939 p0 = GetCorner(i1);
940 p1 = GetCorner(i0);
941 }
942 if (p1.r - p0.r < kCarTolerance) // cylindrical surface
943 {
944 r = (p1.r - p0.r)*u + p0.r;
945 z = (p1.z - p0.z)*u + p0.z;
946 }
947 else // conical surface
948 {
949 r = std::sqrt(p1.r*p1.r*u + p0.r*p0.r*(1. - u));
950 z = p0.z + (p1.z - p0.z)*(r - p0.r)/(p1.r - p0.r);
951 }
952 phi = (GetEndPhi() - GetStartPhi())*v + GetStartPhi();
953 }
954 else // phi cut
955 {
956 G4int nrz = GetNumRZCorner();
957 phi = (i0 < nrz) ? GetStartPhi() : GetEndPhi();
958 if (i0 >= nrz) { i0 -= nrz; }
962 if (u + v > 1.) { u = 1. - u; v = 1. - v; }
963 r = (p1.r - p0.r)*u + (p2.r - p0.r)*v + p0.r;
964 z = (p1.z - p0.z)*u + (p2.z - p0.z)*v + p0.z;
965 }
966 return { r*std::cos(phi), r*std::sin(phi), z };
967}
968
969//////////////////////////////////////////////////////////////////////////
970//
971// CreatePolyhedron
972
974{
975 std::vector<G4TwoVector> rz(numCorner);
976 for (G4int i = 0; i < numCorner; ++i)
977 {
978 rz[i].set(corners[i].r, corners[i].z);
979 }
980 return new G4PolyhedronPcon(startPhi, endPhi - startPhi, rz);
981}
982
983// SetOriginalParameters
984//
986{
987 G4int numPlanes = numCorner;
988 G4bool isConvertible = true;
989 G4double Zmax=rz->Bmax();
990 rz->StartWithZMin();
991
992 // Prepare vectors for storage
993 //
994 std::vector<G4double> Z;
995 std::vector<G4double> Rmin;
996 std::vector<G4double> Rmax;
997
998 G4int countPlanes=1;
999 G4int icurr=0;
1000 G4int icurl=0;
1001
1002 // first plane Z=Z[0]
1003 //
1004 Z.push_back(corners[0].z);
1005 G4double Zprev=Z[0];
1006 if (Zprev == corners[1].z)
1007 {
1008 Rmin.push_back(corners[0].r);
1009 Rmax.push_back (corners[1].r);icurr=1;
1010 }
1011 else if (Zprev == corners[numPlanes-1].z)
1012 {
1013 Rmin.push_back(corners[numPlanes-1].r);
1014 Rmax.push_back (corners[0].r);
1015 icurl=numPlanes-1;
1016 }
1017 else
1018 {
1019 Rmin.push_back(corners[0].r);
1020 Rmax.push_back (corners[0].r);
1021 }
1022
1023 // next planes until last
1024 //
1025 G4int inextr=0, inextl=0;
1026 for (G4int i=0; i < numPlanes-2; ++i)
1027 {
1028 inextr=1+icurr;
1029 inextl=(icurl <= 0)? numPlanes-1 : icurl-1;
1030
1031 if((static_cast<int>(corners[inextr].z >= Zmax) & static_cast<int>(corners[inextl].z >= Zmax)) != 0) { break; }
1032
1033 G4double Zleft = corners[inextl].z;
1034 G4double Zright = corners[inextr].z;
1035 if(Zright > Zleft) // Next plane will be Zleft
1036 {
1037 Z.push_back(Zleft);
1038 countPlanes++;
1039 G4double difZr=corners[inextr].z - corners[icurr].z;
1040 G4double difZl=corners[inextl].z - corners[icurl].z;
1041
1042 if(std::fabs(difZl) < kCarTolerance)
1043 {
1044 if(std::fabs(difZr) < kCarTolerance)
1045 {
1046 Rmin.push_back(corners[inextl].r);
1047 Rmax.push_back(corners[icurr].r);
1048 }
1049 else
1050 {
1051 Rmin.push_back(corners[inextl].r);
1052 Rmax.push_back(corners[icurr].r + (Zleft-corners[icurr].z)/difZr
1053 *(corners[inextr].r - corners[icurr].r));
1054 }
1055 }
1056 else if (difZl >= kCarTolerance)
1057 {
1058 if(std::fabs(difZr) < kCarTolerance)
1059 {
1060 Rmin.push_back(corners[icurl].r);
1061 Rmax.push_back(corners[icurr].r);
1062 }
1063 else
1064 {
1065 Rmin.push_back(corners[icurl].r);
1066 Rmax.push_back(corners[icurr].r + (Zleft-corners[icurr].z)/difZr
1067 *(corners[inextr].r - corners[icurr].r));
1068 }
1069 }
1070 else
1071 {
1072 isConvertible=false; break;
1073 }
1074 icurl=(icurl == 0)? numPlanes-1 : icurl-1;
1075 }
1076 else if(std::fabs(Zright-Zleft)<kCarTolerance) // Zright=Zleft
1077 {
1078 Z.push_back(Zleft);
1079 ++countPlanes;
1080 ++icurr;
1081
1082 icurl=(icurl == 0)? numPlanes-1 : icurl-1;
1083
1084 Rmin.push_back(corners[inextl].r);
1085 Rmax.push_back(corners[inextr].r);
1086 }
1087 else // Zright<Zleft
1088 {
1089 Z.push_back(Zright);
1090 ++countPlanes;
1091
1092 G4double difZr=corners[inextr].z - corners[icurr].z;
1093 G4double difZl=corners[inextl].z - corners[icurl].z;
1094 if(std::fabs(difZr) < kCarTolerance)
1095 {
1096 if(std::fabs(difZl) < kCarTolerance)
1097 {
1098 Rmax.push_back(corners[inextr].r);
1099 Rmin.push_back(corners[icurr].r);
1100 }
1101 else
1102 {
1103 Rmin.push_back(corners[icurl].r + (Zright-corners[icurl].z)/difZl
1104 *(corners[inextl].r - corners[icurl].r));
1105 Rmax.push_back(corners[inextr].r);
1106 }
1107 ++icurr;
1108 } // plate
1109 else if (difZr >= kCarTolerance)
1110 {
1111 if(std::fabs(difZl) < kCarTolerance)
1112 {
1113 Rmax.push_back(corners[inextr].r);
1114 Rmin.push_back (corners[icurr].r);
1115 }
1116 else
1117 {
1118 Rmax.push_back(corners[inextr].r);
1119 Rmin.push_back (corners[icurl].r+(Zright-corners[icurl].z)/difZl
1120 * (corners[inextl].r - corners[icurl].r));
1121 }
1122 ++icurr;
1123 }
1124 else
1125 {
1126 isConvertible=false; break;
1127 }
1128 }
1129 } // end for loop
1130
1131 // last plane Z=Zmax
1132 //
1133 Z.push_back(Zmax);
1134 ++countPlanes;
1135 inextr=1+icurr;
1136 inextl=(icurl <= 0)? numPlanes-1 : icurl-1;
1137
1138 Rmax.push_back(corners[inextr].r);
1139 Rmin.push_back(corners[inextl].r);
1140
1141 // Set original parameters Rmin,Rmax,Z
1142 //
1143 if(isConvertible)
1144 {
1145 original_parameters = new G4PolyconeHistorical;
1146 original_parameters->Z_values = new G4double[countPlanes];
1147 original_parameters->Rmin = new G4double[countPlanes];
1148 original_parameters->Rmax = new G4double[countPlanes];
1149
1150 for(G4int j=0; j < countPlanes; ++j)
1151 {
1152 original_parameters->Z_values[j] = Z[j];
1153 original_parameters->Rmax[j] = Rmax[j];
1154 original_parameters->Rmin[j] = Rmin[j];
1155 }
1156 original_parameters->Start_angle = startPhi;
1157 original_parameters->Opening_angle = endPhi-startPhi;
1158 original_parameters->Num_z_planes = countPlanes;
1159
1160 }
1161 else // Set parameters(r,z) with Rmin==0 as convention
1162 {
1163#ifdef G4SPECSDEBUG
1164 std::ostringstream message;
1165 message << "Polycone " << GetName() << G4endl
1166 << "cannot be converted to Polycone with (Rmin,Rmaz,Z) parameters!";
1167 G4Exception("G4Polycone::SetOriginalParameters()", "GeomSolids0002",
1168 JustWarning, message);
1169#endif
1170 original_parameters = new G4PolyconeHistorical;
1171 original_parameters->Z_values = new G4double[numPlanes];
1172 original_parameters->Rmin = new G4double[numPlanes];
1173 original_parameters->Rmax = new G4double[numPlanes];
1174
1175 for(G4int j=0; j < numPlanes; ++j)
1176 {
1177 original_parameters->Z_values[j] = corners[j].z;
1178 original_parameters->Rmax[j] = corners[j].r;
1179 original_parameters->Rmin[j] = 0.0;
1180 }
1181 original_parameters->Start_angle = startPhi;
1182 original_parameters->Opening_angle = endPhi-startPhi;
1183 original_parameters->Num_z_planes = numPlanes;
1184 }
1185 return isConvertible;
1186}
1187
1188#endif
G4TemplateAutoLock< G4Mutex > G4AutoLock
std::vector< G4ThreeVector > G4ThreeVectorList
@ JustWarning
@ FatalException
@ FatalErrorInArgument
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
std::vector< G4TwoVector > G4TwoVectorList
G4double G4QuickRand(uint32_t seed=0)
#define G4MUTEX_INITIALIZER
std::mutex G4Mutex
CLHEP::Hep3Vector G4ThreeVector
CLHEP::Hep2Vector G4TwoVector
double G4double
Definition G4Types.hh:83
long G4long
Definition G4Types.hh:87
bool G4bool
Definition G4Types.hh:86
int G4int
Definition G4Types.hh:85
G4String G4GeometryType
Definition G4VSolid.hh:70
#define G4endl
Definition G4ios.hh:67
G4GLOB_DLL std::ostream G4cout
double x() const
double y() const
double z() const
double x() const
double y() const
void set(double x, double y, double z)
G4AffineTransform is a class for geometric affine transformations. It supports efficient arbitrary ro...
G4BoundingEnvelope is a helper class to facilitate calculation of the extent of a solid within the li...
G4bool BoundingBoxVsVoxelLimits(const EAxis pAxis, const G4VoxelLimits &pVoxelLimits, const G4Transform3D &pTransform3D, G4double &pMin, G4double &pMax) const
G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimits, const G4Transform3D &pTransform3D, G4double &pMin, G4double &pMax) const
static G4bool DiskExtent(G4double rmin, G4double rmax, G4double startPhi, G4double delPhi, G4TwoVector &pmin, G4TwoVector &pmax)
static void RemoveRedundantVertices(G4TwoVectorList &polygon, std::vector< G4int > &iout, G4double tolerance=0.0)
static G4double TriangleArea(G4double Ax, G4double Ay, G4double Bx, G4double By, G4double Cx, G4double Cy)
static G4double PolygonArea(const G4TwoVectorList &polygon)
static G4bool TriangulatePolygon(const G4TwoVectorList &polygon, std::vector< G4int > &result)
G4PolyconeHistorical is a data structure for use in G4Polycone.
G4Polycone represents a composed closed shape (PCON) made of cones and cylinders, along the Z axis wi...
Definition G4Polycone.hh:82
~G4Polycone() override
void BoundingLimits(G4ThreeVector &pMin, G4ThreeVector &pMax) const override
G4double GetCosEndPhi() const
G4Polyhedron * CreatePolyhedron() const override
G4GeometryType GetEntityType() const override
G4Polycone(const G4String &name, G4double phiStart, G4double phiTotal, G4int numZPlanes, const G4double zPlane[], const G4double rInner[], const G4double rOuter[])
Definition G4Polycone.cc:59
G4double GetSurfaceArea() override
void ComputeDimensions(G4VPVParameterisation *p, const G4int n, const G4VPhysicalVolume *pRep) override
G4double GetEndPhi() const
G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimit, const G4AffineTransform &pTransform, G4double &pmin, G4double &pmax) const override
G4double GetSinEndPhi() const
G4double DistanceToIn(const G4ThreeVector &p, const G4ThreeVector &v) const override
EInside Inside(const G4ThreeVector &p) const override
G4double GetCosStartPhi() const
void SetOriginalParameters(G4PolyconeHistorical *pars)
G4double GetCubicVolume() override
G4double GetStartPhi() const
G4Polycone & operator=(const G4Polycone &source)
G4VSolid * Clone() const override
std::ostream & StreamInfo(std::ostream &os) const override
G4ThreeVector GetPointOnSurface() const override
G4bool IsOpen() const
G4bool Reset()
G4double GetSinStartPhi() const
G4int GetNumRZCorner() const
G4PolyconeSideRZ GetCorner(G4int index) const
G4ReduciblePolygon is a utility class used to specify, test, reduce, and/or otherwise manipulate a 2D...
G4bool BisectedBy(G4double a1, G4double b1, G4double a2, G4double b2, G4double tolerance)
G4double Amin() const
G4bool RemoveDuplicateVertices(G4double tolerance)
G4bool RemoveRedundantVertices(G4double tolerance)
G4bool CrossesItself(G4double tolerance)
G4double DistanceToIn(const G4ThreeVector &p, const G4ThreeVector &v) const override
G4VCSGfaceted & operator=(const G4VCSGfaceted &source)
G4double fCubicVolume
EInside Inside(const G4ThreeVector &p) const override
G4VCSGface ** faces
G4VCSGfaceted(const G4String &name)
G4Polyhedron * fpPolyhedron
G4bool fRebuildPolyhedron
G4double fSurfaceArea
G4VPVParameterisation ia an abstract base class for Parameterisation, able to compute the transformat...
virtual void ComputeDimensions(G4Box &, const G4int, const G4VPhysicalVolume *) const
G4VPhysicalVolume is an abstract base class for the representation of a positioned volume....
G4String GetName() const
G4VSolid(const G4String &name)
Definition G4VSolid.cc:59
void DumpInfo() const
G4double kCarTolerance
Definition G4VSolid.hh:418
G4VoxelLimits represents limitation/restrictions of space, where restrictions are only made perpendic...
G4double GetMinExtent(const EAxis pAxis) const
G4double GetMaxExtent(const EAxis pAxis) const
EAxis
Definition geomdefs.hh:54
EInside
Definition geomdefs.hh:67
@ kOutside
Definition geomdefs.hh:68
G4double total(Particle const *const p1, Particle const *const p2)
#define DBL_EPSILON
Definition templates.hh:66