Geant4 10.7.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4ReplicaNavigation.cc
Go to the documentation of this file.
1// ********************************************************************
2// * License and Disclaimer *
3// * *
4// * The Geant4 software is copyright of the Copyright Holders of *
5// * the Geant4 Collaboration. It is provided under the terms and *
6// * conditions of the Geant4 Software License, included in the file *
7// * LICENSE and available at http://cern.ch/geant4/license . These *
8// * include a list of copyright holders. *
9// * *
10// * Neither the authors of this software system, nor their employing *
11// * institutes,nor the agencies providing financial support for this *
12// * work make any representation or warranty, express or implied, *
13// * regarding this software system or assume any liability for its *
14// * use. Please see the license in the file LICENSE and URL above *
15// * for the full disclaimer and the limitation of liability. *
16// * *
17// * This code implementation is the result of the scientific and *
18// * technical work of the GEANT4 collaboration. *
19// * By using, copying, modifying or distributing the software (or *
20// * any work based on the software) you agree to acknowledge its *
21// * use in resulting scientific publications, and indicate your *
22// * acceptance of all terms of the Geant4 Software license. *
23// ********************************************************************
24//
25// class G4ReplicaNavigation Implementation
26//
27// Author: P.Kent, 1996
28//
29// --------------------------------------------------------------------
30
32
33#include "G4AffineTransform.hh"
34#include "G4SmartVoxelProxy.hh"
35#include "G4SmartVoxelNode.hh"
36#include "G4VSolid.hh"
38
39namespace
40{
41 const G4ThreeVector VecCartAxes[3]=
42 { G4ThreeVector(1.,0.,0.), G4ThreeVector(0.,1.,0.), G4ThreeVector(0.,0.,1.) };
43 const G4ExitNormal::ESide SideCartAxesPlus[3]=
45 const G4ExitNormal::ESide SideCartAxesMinus[3]=
47}
48
49// ********************************************************************
50// Constructor
51// ********************************************************************
52//
54{
58 halfkCarTolerance = kCarTolerance*0.5;
59 halfkRadTolerance = kRadTolerance*0.5;
60 halfkAngTolerance = kAngTolerance*0.5;
61 fMinStep = 0.05*kCarTolerance;
62}
63
64// ********************************************************************
65// Destructor
66// ********************************************************************
67//
69{
70}
71
72// ********************************************************************
73// Inside
74// ********************************************************************
75//
78 const G4int replicaNo,
79 const G4ThreeVector& localPoint) const
80{
81 EInside in = kOutside;
82
83 // Replication data
84 //
85 EAxis axis;
86 G4int nReplicas;
87 G4double width, offset;
88 G4bool consuming;
89
90 G4double coord, rad2, rmin, tolRMax2, rmax, tolRMin2;
91
92 pVol->GetReplicationData(axis, nReplicas, width, offset, consuming);
93
94 switch (axis)
95 {
96 case kXAxis:
97 case kYAxis:
98 case kZAxis:
99 coord = std::fabs(localPoint(axis))-width*0.5;
100 if ( coord<=-halfkCarTolerance )
101 {
102 in = kInside;
103 }
104 else if ( coord<=halfkCarTolerance )
105 {
106 in = kSurface;
107 }
108 break;
109 case kPhi:
110 if ( localPoint.y()||localPoint.x() )
111 {
112 coord = std::fabs(std::atan2(localPoint.y(),localPoint.x()))-width*0.5;
113 if ( coord<=-halfkAngTolerance )
114 {
115 in = kInside;
116 }
117 else if ( coord<=halfkAngTolerance )
118 {
119 in = kSurface;
120 }
121 }
122 else
123 {
124 in = kSurface;
125 }
126 break;
127 case kRho:
128 rad2 = localPoint.perp2();
129 rmax = (replicaNo+1)*width+offset;
130 tolRMax2 = rmax-halfkRadTolerance;
131 tolRMax2 *= tolRMax2;
132 if ( rad2>tolRMax2 )
133 {
134 tolRMax2 = rmax+halfkRadTolerance;
135 tolRMax2 *= tolRMax2;
136 if ( rad2<=tolRMax2 )
137 {
138 in = kSurface;
139 }
140 }
141 else
142 {
143 // Known to be inside outer radius
144 //
145 if ( replicaNo||offset )
146 {
147 rmin = rmax-width;
148 tolRMin2 = rmin-halfkRadTolerance;
149 tolRMin2 *= tolRMin2;
150 if ( rad2>tolRMin2 )
151 {
152 tolRMin2 = rmin+halfkRadTolerance;
153 tolRMin2 *= tolRMin2;
154 if ( rad2>=tolRMin2 )
155 {
156 in = kInside;
157 }
158 else
159 {
160 in = kSurface;
161 }
162 }
163 }
164 else
165 {
166 in = kInside;
167 }
168 }
169 break;
170 default:
171 G4Exception("G4ReplicaNavigation::Inside()", "GeomNav0002",
172 FatalException, "Unknown axis!");
173 break;
174 }
175 return in;
176}
177
178// ********************************************************************
179// DistanceToOut
180// ********************************************************************
181//
184 const G4int replicaNo,
185 const G4ThreeVector& localPoint) const
186{
187 // Replication data
188 //
189 EAxis axis;
190 G4int nReplicas;
191 G4double width,offset;
192 G4bool consuming;
193
194 G4double safety = 0.;
195 G4double safe1,safe2;
196 G4double coord, rho, rmin, rmax;
197
198 pVol->GetReplicationData(axis, nReplicas, width, offset, consuming);
199 switch(axis)
200 {
201 case kXAxis:
202 case kYAxis:
203 case kZAxis:
204 coord = localPoint(axis);
205 safe1 = width*0.5-coord;
206 safe2 = width*0.5+coord;
207 safety = (safe1<=safe2) ? safe1 : safe2;
208 break;
209 case kPhi:
210 if ( localPoint.y()<=0 )
211 {
212 safety = localPoint.x()*std::sin(width*0.5)
213 + localPoint.y()*std::cos(width*0.5);
214 }
215 else
216 {
217 safety = localPoint.x()*std::sin(width*0.5)
218 - localPoint.y()*std::cos(width*0.5);
219 }
220 break;
221 case kRho:
222 rho = localPoint.perp();
223 rmax = width*(replicaNo+1)+offset;
224 if ( replicaNo||offset )
225 {
226 rmin = rmax-width;
227 safe1 = rho-rmin;
228 safe2 = rmax-rho;
229 safety = (safe1<=safe2) ? safe1 : safe2;
230 }
231 else
232 {
233 safety = rmax-rho;
234 }
235 break;
236 default:
237 G4Exception("G4ReplicaNavigation::DistanceToOut()", "GeomNav0002",
238 FatalException, "Unknown axis!");
239 break;
240 }
241 return (safety >= halfkCarTolerance) ? safety : 0;
242}
243
244// ********************************************************************
245// DistanceToOut
246// ********************************************************************
247//
250 const G4int replicaNo,
251 const G4ThreeVector& localPoint,
252 const G4ThreeVector& localDirection,
253 G4ExitNormal& arExitNormal ) const
254{
255 // Replication data
256 //
257 EAxis axis;
258 G4int nReplicas;
259 G4double width, offset;
260 G4bool consuming;
261
262 G4double Dist=kInfinity;
263 G4double coord, Comp, lindist;
264 G4double signC = 0.0;
265 G4ExitNormal candidateNormal;
266
267 pVol->GetReplicationData(axis, nReplicas, width, offset, consuming);
268 switch(axis)
269 {
270 case kXAxis:
271 case kYAxis:
272 case kZAxis:
273 coord = localPoint(axis);
274 Comp = localDirection(axis);
275 if ( Comp>0 )
276 {
277 lindist = width*0.5-coord;
278 Dist = (lindist>0) ? lindist/Comp : 0;
279 signC= 1.0;
280 }
281 else if ( Comp<0 )
282 {
283 lindist = width*0.5+coord;
284 Dist = (lindist>0) ? -lindist/Comp : 0;
285 signC= -1.0;
286 }
287 else
288 {
289 Dist = kInfinity;
290 }
291 // signC = sign<G4double>(Comp)
292 candidateNormal.exitNormal = ( signC * VecCartAxes[axis]);
293 candidateNormal.calculated = true;
294 candidateNormal.validConvex = true;
295 candidateNormal.exitSide =
296 (Comp>0) ? SideCartAxesPlus[axis] : SideCartAxesMinus[axis];
297 break;
298 case kPhi:
299 Dist = DistanceToOutPhi(localPoint,localDirection,width,candidateNormal);
300 // candidateNormal set in call
301 break;
302 case kRho:
303 Dist = DistanceToOutRad(localPoint,localDirection,width,offset,
304 replicaNo,candidateNormal);
305 // candidateNormal set in call
306 break;
307 default:
308 G4Exception("G4ReplicaNavigation::DistanceToOut()", "GeomNav0002",
309 FatalException, "Unknown axis!");
310 break;
311 }
312
313 arExitNormal= candidateNormal; // .exitNormal;
314
315 return Dist;
316}
317
318// ********************************************************************
319// DistanceToOutPhi
320// ********************************************************************
321//
323G4ReplicaNavigation::DistanceToOutPhi(const G4ThreeVector& localPoint,
324 const G4ThreeVector& localDirection,
325 const G4double width,
326 G4ExitNormal& foundNormal ) const
327{
328 // Phi Intersection
329 // NOTE: width<=pi by definition
330 //
331 G4double sinSPhi = -2.0, cosSPhi = -2.0;
332 G4double pDistS, pDistE, compS, compE, Dist, dist2, yi;
334 G4ThreeVector candidateNormal;
335
336 if ( (localPoint.x()!=0.0) || (localPoint.y()!=0.0) )
337 {
338 sinSPhi = std::sin(-width*0.5); // SIN of starting phi plane
339 cosSPhi = std::cos(width*0.5); // COS of starting phi plane
340
341 // pDist -ve when inside
342 //
343 pDistS = localPoint.x()*sinSPhi-localPoint.y()*cosSPhi;
344 // Start plane at phi= -S
345 pDistE = localPoint.x()*sinSPhi+localPoint.y()*cosSPhi;
346 // End plane at phi= +S
347
348 // Comp -ve when in direction of outwards normal
349 //
350 compS = -sinSPhi*localDirection.x()+cosSPhi*localDirection.y();
351 compE = -sinSPhi*localDirection.x()-cosSPhi*localDirection.y();
352
353 if ( (pDistS<=halfkCarTolerance)&&(pDistE<=halfkCarTolerance) )
354 {
355 // Inside both phi *full* planes
356 //
357 if ( compS<0 )
358 {
359 dist2 = pDistS/compS;
360 yi = localPoint.y()+dist2*localDirection.y();
361
362 // Check intersecting with correct half-plane (no -> no intersect)
363 //
364 if ( yi<=0 )
365 {
366 Dist = (pDistS<=-halfkCarTolerance) ? dist2 : 0;
367 sidePhi= G4ExitNormal::kSPhi; // tbc
368 }
369 else
370 {
371 Dist = kInfinity;
372 }
373 }
374 else
375 {
376 Dist = kInfinity;
377 }
378 if ( compE<0 )
379 {
380 dist2 = pDistE/compE;
381
382 // Only check further if < starting phi intersection
383 //
384 if ( dist2<Dist )
385 {
386 yi = localPoint.y()+dist2*localDirection.y();
387
388 // Check intersecting with correct half-plane
389 //
390 if ( yi>=0 )
391 {
392 // Leaving via ending phi
393 //
394 Dist = (pDistE<=-halfkCarTolerance) ? dist2 : 0;
395 sidePhi = G4ExitNormal::kEPhi;
396 }
397 }
398 }
399 }
400 else if ( (pDistS>halfkCarTolerance)&&(pDistE>halfkCarTolerance) )
401 {
402 // Outside both *full* phi planes
403 // if towards both >=0 then once inside will remain inside
404 //
405 Dist = ((compS>=0)&&(compE>=0)) ? kInfinity : 0;
406 }
407 else if ( (pDistS>halfkCarTolerance)&&(pDistE<=halfkCarTolerance) )
408 {
409 // Outside full starting plane, inside full ending plane
410 //
411 if ( compE<0 )
412 {
413 dist2 = pDistE/compE;
414 yi = localPoint.y()+dist2*localDirection.y();
415
416 // Check intersection in correct half-plane
417 // (if not -> remain in extent)
418 //
419 Dist = (yi>0) ? dist2 : kInfinity;
420 if( yi> 0 ) { sidePhi = G4ExitNormal::kEPhi; }
421 }
422 else // Leaving immediately by starting phi
423 {
424 Dist = kInfinity;
425 }
426 }
427 else
428 {
429 // Must be (pDistS<=halfkCarTolerance)&&(pDistE>halfkCarTolerance)
430 // Inside full starting plane, outside full ending plane
431 //
432 if ( compE>=0 )
433 {
434 if ( compS<0 )
435 {
436 dist2 = pDistS/compS;
437 yi = localPoint.y()+dist2*localDirection.y();
438
439 // Check intersection in correct half-plane
440 // (if not -> remain in extent)
441 //
442 Dist = (yi<0) ? dist2 : kInfinity;
443 if(yi<0) { sidePhi = G4ExitNormal::kSPhi; }
444 }
445 else
446 {
447 Dist = kInfinity;
448 }
449 }
450 else
451 {
452 // Leaving immediately by ending phi
453 //
454 Dist = 0.;
455 sidePhi = G4ExitNormal::kEPhi;
456 }
457 }
458 }
459 else
460 {
461 // On z axis + travel not || to z axis -> use direction vector
462 //
463 if( (std::fabs(localDirection.phi())<=width*0.5) )
464 {
465 Dist = kInfinity;
466 }
467 else
468 {
469 Dist = 0.;
470 sidePhi = G4ExitNormal::kMY;
471 }
472 }
473
474 if(sidePhi == G4ExitNormal::kSPhi )
475 {
476 candidateNormal = G4ThreeVector(sinSPhi,-cosSPhi,0.) ;
477 }
478 else if (sidePhi == G4ExitNormal::kEPhi)
479 {
480 candidateNormal = G4ThreeVector(sinSPhi,cosSPhi,0.) ;
481 }
482 else if (sidePhi == G4ExitNormal::kMY )
483 {
484 candidateNormal = G4ThreeVector(0., -1.0, 0.); // Split -S and +S 'phi'
485 }
486 foundNormal.calculated= (sidePhi != G4ExitNormal::kNull );
487 foundNormal.exitNormal= candidateNormal;
488
489 return Dist;
490}
491
492// ********************************************************************
493// DistanceToOutRad
494// ********************************************************************
495//
497G4ReplicaNavigation::DistanceToOutRad(const G4ThreeVector& localPoint,
498 const G4ThreeVector& localDirection,
499 const G4double width,
500 const G4double offset,
501 const G4int replicaNo,
502 G4ExitNormal& foundNormal ) const
503{
504 G4double rmin, rmax, t1, t2, t3, deltaR;
505 G4double b, c, d2, srd;
507
508 //
509 // Radial Intersections
510 //
511
512 // Find intersction with cylinders at rmax/rmin
513 // Intersection point (xi,yi,zi) on line
514 // x=localPoint.x+t*localDirection.x etc.
515 //
516 // Intersects with x^2+y^2=R^2
517 //
518 // Hence (localDirection.x^2+localDirection.y^2)t^2+
519 // 2t(localPoint.x*localDirection.x+localPoint.y*localDirection.y)+
520 // localPoint.x^2+localPoint.y^2-R^2=0
521 //
522 // t1 t2 t3
523
524 rmin = replicaNo*width+offset;
525 rmax = (replicaNo+1)*width+offset;
526
527 t1 = 1.0-localDirection.z()*localDirection.z(); // since v normalised
528 t2 = localPoint.x()*localDirection.x()+localPoint.y()*localDirection.y();
529 t3 = localPoint.x()*localPoint.x()+localPoint.y()*localPoint.y();
530
531 if ( t1>0 ) // Check not parallel
532 {
533 // Calculate srd, r exit distance
534 //
535 if ( t2>=0 )
536 {
537 // Delta r not negative => leaving via rmax
538 //
539 deltaR = t3-rmax*rmax;
540
541 // NOTE: Should use
542 // rho-rmax<-halfkRadTolerance - [no sqrts for efficiency]
543 //
544 if ( deltaR<-halfkRadTolerance )
545 {
546 b = t2/t1;
547 c = deltaR/t1;
548 srd = -b+std::sqrt(b*b-c);
549 sideR = G4ExitNormal::kRMax;
550 }
551 else
552 {
553 // On tolerant boundary & heading outwards (or locally
554 // perpendicular to) outer radial surface -> leaving immediately
555 //
556 srd = 0;
557 sideR = G4ExitNormal::kRMax;
558 }
559 }
560 else
561 {
562 // Possible rmin intersection
563 //
564 if (rmin)
565 {
566 deltaR = t3-rmin*rmin;
567 b = t2/t1;
568 c = deltaR/t1;
569 d2 = b*b-c;
570 if ( d2>=0 )
571 {
572 // Leaving via rmin
573 // NOTE: Should use
574 // rho-rmin>halfkRadTolerance - [no sqrts for efficiency]
575 //
576 srd = (deltaR>halfkRadTolerance) ? -b-std::sqrt(d2) : 0.0;
577 // Is the following more accurate ?
578 // srd = (deltaR>halfkRadTolerance) ? c/( -b - std::sqrt(d2)) : 0.0;
579 sideR = G4ExitNormal::kRMin;
580 }
581 else
582 {
583 // No rmin intersect -> must be rmax intersect
584 //
585 deltaR = t3-rmax*rmax;
586 c = deltaR/t1;
587 d2 = b*b-c;
588 srd = (d2 < 0.) ? 0.0 : -b+std::sqrt(d2);
589 sideR = G4ExitNormal::kRMax;
590 }
591 }
592 else
593 {
594 // No rmin intersect -> must be rmax intersect
595 //
596 deltaR = t3-rmax*rmax;
597 b = t2/t1;
598 c = deltaR/t1;
599 d2 = b*b-c;
600 srd = (d2 < 0.) ? 0.0 : -b+std::sqrt(d2);
601 sideR= G4ExitNormal::kRMax;
602 }
603 }
604 }
605 else
606 {
607 srd =kInfinity;
608 sideR = G4ExitNormal::kNull;
609 }
610
611 if( sideR != G4ExitNormal::kNull ) // if ((side == kRMax) || (side==kRMin))
612 {
613 // Note: returned vector not explicitly normalised
614 // (divided by fRMax for unit vector)
615
616 G4double xi, yi;
617 xi = localPoint.x() + srd*localDirection.x();
618 yi = localPoint.y() + srd*localDirection.y();
619 G4ThreeVector normalR = G4ThreeVector(xi,yi,0.0);
620
621 if( sideR == G4ExitNormal::kRMax )
622 {
623 normalR *= 1.0/rmax;
624 }
625 else
626 {
627 normalR *= (-1.0)/rmin;
628 }
629 foundNormal.exitNormal= normalR;
630 foundNormal.calculated= true;
631 foundNormal.validConvex = (sideR == G4ExitNormal::kRMax);
632 foundNormal.exitSide = sideR;
633 }
634 else
635 {
636 foundNormal.calculated = false;
637 }
638
639 return srd;
640}
641
642// ********************************************************************
643// ComputeTransformation
644//
645// Setup transformation and transform point into local system
646// ********************************************************************
647//
648void
650 G4VPhysicalVolume* pVol,
651 G4ThreeVector& point) const
652{
653 G4double val,cosv,sinv,tmpx,tmpy;
654
655 // Replication data
656 //
657 EAxis axis;
658 G4int nReplicas;
659 G4double width,offset;
660 G4bool consuming;
661
662 pVol->GetReplicationData(axis, nReplicas, width, offset, consuming);
663
664 switch (axis)
665 {
666 case kXAxis:
667 val = -width*0.5*(nReplicas-1)+width*replicaNo;
668 pVol->SetTranslation(G4ThreeVector(val,0,0));
669 point.setX(point.x()-val);
670 break;
671 case kYAxis:
672 val = -width*0.5*(nReplicas-1)+width*replicaNo;
673 pVol->SetTranslation(G4ThreeVector(0,val,0));
674 point.setY(point.y()-val);
675 break;
676 case kZAxis:
677 val = -width*0.5*(nReplicas-1)+width*replicaNo;
678 pVol->SetTranslation(G4ThreeVector(0,0,val));
679 point.setZ(point.z()-val);
680 break;
681 case kPhi:
682 val = -(offset+width*(replicaNo+0.5));
683 SetPhiTransformation(val,pVol);
684 cosv = std::cos(val);
685 sinv = std::sin(val);
686 tmpx = point.x()*cosv-point.y()*sinv;
687 tmpy = point.x()*sinv+point.y()*cosv;
688 point.setY(tmpy);
689 point.setX(tmpx);
690 break;
691 case kRho:
692 // No setup required for radial case
693 default:
694 break;
695 }
696}
697
698// ********************************************************************
699// ComputeTransformation
700//
701// Setup transformation into local system
702// ********************************************************************
703//
704void
706 G4VPhysicalVolume* pVol) const
707{
708 G4double val;
709
710 // Replication data
711 //
712 EAxis axis;
713 G4int nReplicas;
714 G4double width, offset;
715 G4bool consuming;
716
717 pVol->GetReplicationData(axis, nReplicas, width, offset, consuming);
718
719 switch (axis)
720 {
721 case kXAxis:
722 val = -width*0.5*(nReplicas-1)+width*replicaNo;
723 pVol->SetTranslation(G4ThreeVector(val,0,0));
724 break;
725 case kYAxis:
726 val = -width*0.5*(nReplicas-1)+width*replicaNo;
727 pVol->SetTranslation(G4ThreeVector(0,val,0));
728 break;
729 case kZAxis:
730 val = -width*0.5*(nReplicas-1)+width*replicaNo;
731 pVol->SetTranslation(G4ThreeVector(0,0,val));
732 break;
733 case kPhi:
734 val = -(offset+width*(replicaNo+0.5));
735 SetPhiTransformation(val,pVol);
736 break;
737 case kRho:
738 // No setup required for radial case
739 default:
740 break;
741 }
742}
743
744// ********************************************************************
745// ComputeStep
746// ********************************************************************
747//
750 const G4ThreeVector& globalDirection,
751 const G4ThreeVector& localPoint,
752 const G4ThreeVector& localDirection,
753 const G4double currentProposedStepLength,
754 G4double& newSafety,
755 G4NavigationHistory &history,
756 // std::pair<G4bool,G4bool>& validAndCalculated
757 G4bool& validExitNormal,
758 G4bool& calculatedExitNormal,
759 G4ThreeVector& exitNormalVector,
760 G4bool& exiting,
761 G4bool& entering,
762 G4VPhysicalVolume* (*pBlockedPhysical),
763 G4int& blockedReplicaNo )
764{
765 G4VPhysicalVolume *repPhysical, *motherPhysical;
766 G4VPhysicalVolume *samplePhysical, *blockedExitedVol = nullptr;
767 G4LogicalVolume *repLogical;
768 G4VSolid *motherSolid;
769 G4ThreeVector repPoint, repDirection, sampleDirection;
770 G4double ourStep=currentProposedStepLength;
771 G4double ourSafety=kInfinity;
772 G4double sampleStep, sampleSafety, motherStep, motherSafety;
773 G4int localNoDaughters, sampleNo;
774 G4int depth;
775 G4ExitNormal exitNormalStc;
776 // G4int depthDeterminingStep= -1; // Useful only for debugging - for now
777
778 calculatedExitNormal= false;
779
780 // Exiting normal optimisation
781 //
782 if ( exiting&&validExitNormal )
783 {
784 if ( localDirection.dot(exitNormalVector)>=kMinExitingNormalCosine )
785 {
786 // Block exited daughter volume
787 //
788 blockedExitedVol = *pBlockedPhysical;
789 ourSafety = 0;
790 }
791 }
792 exiting = false;
793 entering = false;
794
795 repPhysical = history.GetTopVolume();
796 repLogical = repPhysical->GetLogicalVolume();
797
798 //
799 // Compute intersection with replica boundaries & replica safety
800 //
801
802 sampleSafety = DistanceToOut(repPhysical,
803 history.GetTopReplicaNo(),
804 localPoint);
805 G4ExitNormal normalOutStc;
806 const G4int topDepth= history.GetDepth();
807
808 ourSafety = std::min( ourSafety, sampleSafety);
809
810 if ( sampleSafety<ourStep )
811 {
812
813 sampleStep = DistanceToOut(repPhysical,
814 history.GetTopReplicaNo(),
815 localPoint,
816 localDirection,
817 normalOutStc);
818 if ( sampleStep<ourStep )
819 {
820 ourStep = sampleStep;
821 exiting = true;
822 validExitNormal = normalOutStc.validConvex; // false; -> Old,Conservative
823
824 exitNormalStc = normalOutStc;
825 exitNormalStc.exitNormal =
826 history.GetTopTransform().InverseTransformAxis(normalOutStc.exitNormal);
827 calculatedExitNormal = true;
828 }
829 }
830 const G4int secondDepth = topDepth;
831 depth = secondDepth;
832
833 // Loop checking, 07.10.2016, JA -- Need to add: assert(depth>0)
834 while ( history.GetVolumeType(depth)==kReplica )
835 {
836 const G4AffineTransform& GlobalToLocal = history.GetTransform(depth);
837 repPoint = GlobalToLocal.TransformPoint(globalPoint);
838 // repPoint = history.GetTransform(depth).TransformPoint(globalPoint);
839
840 sampleSafety = DistanceToOut(history.GetVolume(depth),
841 history.GetReplicaNo(depth),
842 repPoint);
843 if ( sampleSafety < ourSafety )
844 {
845 ourSafety = sampleSafety;
846 }
847 if ( sampleSafety < ourStep )
848 {
849 G4ThreeVector newLocalDirection =
850 GlobalToLocal.TransformAxis(globalDirection);
851 sampleStep = DistanceToOut(history.GetVolume(depth),
852 history.GetReplicaNo(depth),
853 repPoint,
854 newLocalDirection,
855 normalOutStc);
856 if ( sampleStep < ourStep )
857 {
858 ourStep = sampleStep;
859 exiting = true;
860
861 // As step is limited by this level, must set Exit Normal
862 //
863 G4ThreeVector localExitNorm = normalOutStc.exitNormal;
864 G4ThreeVector globalExitNorm =
865 GlobalToLocal.InverseTransformAxis(localExitNorm);
866
867 exitNormalStc = normalOutStc; // Normal, convex, calculated, side
868 exitNormalStc.exitNormal = globalExitNorm;
869 calculatedExitNormal = true;
870 }
871 }
872 depth--;
873 }
874
875 // Compute mother safety & intersection
876 //
877 G4ThreeVector exitVectorMother;
878 G4bool exitConvex = false; // Value obtained in DistanceToOut(p,v) call
879 G4ExitNormal motherNormalStc;
880
881 repPoint = history.GetTransform(depth).TransformPoint(globalPoint);
882 motherPhysical = history.GetVolume(depth);
883 motherSolid = motherPhysical->GetLogicalVolume()->GetSolid();
884 motherSafety = motherSolid->DistanceToOut(repPoint);
885 repDirection = history.GetTransform(depth).TransformAxis(globalDirection);
886
887 motherStep = motherSolid->DistanceToOut(repPoint,repDirection,true,
888 &exitConvex,&exitVectorMother);
889 if( exitConvex )
890 {
891 motherNormalStc = G4ExitNormal( exitVectorMother, true, false,
893 calculatedExitNormal = true;
894 }
895 const G4AffineTransform& globalToLocalTop = history.GetTopTransform();
896
897 G4bool motherDeterminedStep = (motherStep<ourStep);
898
899 if( (!exitConvex) && motherDeterminedStep )
900 {
901 exitVectorMother = motherSolid->SurfaceNormal( repPoint );
902 motherNormalStc = G4ExitNormal( exitVectorMother, true, false,
904 // CalculatedExitNormal -> true;
905 // Convex -> false: do not know value
906 // ExitSide -> kMother (or kNull)
907
908 calculatedExitNormal = true;
909 }
910 if( motherDeterminedStep )
911 {
912 G4ThreeVector globalExitNormalTop =
913 globalToLocalTop.InverseTransformAxis(exitVectorMother);
914
915 exitNormalStc = motherNormalStc;
916 exitNormalStc.exitNormal = globalExitNormalTop;
917 }
918
919 // Push in principle no longer necessary. G4Navigator now takes care of ...
920 // Removing this however may cause additional almost-zero steps and generate
921 // warnings for pushed particles from G4Navigator, particularly for the case
922 // of 3D replicas (Cartesian or combined Radial/Phi cases).
923 // Requires further investigation and eventually reimplementation of
924 // LevelLocate() to take into account point and direction ...
925 //
926 if( ourStep<fMinStep )
927 {
928 ourStep = 100*kCarTolerance;
929 }
930
931 if ( motherSafety<ourSafety )
932 {
933 ourSafety = motherSafety;
934 }
935
936#ifdef G4VERBOSE
937 if ( fCheck )
938 {
939 if( motherSolid->Inside(localPoint)==kOutside )
940 {
941 std::ostringstream message;
942 message << "Point outside volume !" << G4endl
943 << " Point " << localPoint
944 << " is outside current volume " << motherPhysical->GetName()
945 << G4endl;
946 G4double estDistToSolid= motherSolid->DistanceToIn(localPoint);
947 message << " Estimated isotropic distance to solid (distToIn)= "
948 << estDistToSolid << G4endl;
949 if( estDistToSolid > 100.0 * kCarTolerance )
950 {
951 motherSolid->DumpInfo();
952 G4Exception("G4ReplicaNavigation::ComputeStep()",
953 "GeomNav0003", FatalException, message,
954 "Point is far outside Current Volume !" );
955 }
956 else
957 G4Exception("G4ReplicaNavigation::ComputeStep()",
958 "GeomNav1002", JustWarning, message,
959 "Point is a little outside Current Volume.");
960 }
961 }
962#endif
963
964 // Comparison of steps may need precision protection
965 //
966#if 1
967 if( motherDeterminedStep )
968 {
969 ourStep = motherStep;
970 exiting = true;
971 }
972
973 // Transform it to the Grand-Mother Reference Frame (current convention)
974 //
975 if ( calculatedExitNormal )
976 {
977 if ( motherDeterminedStep )
978 {
979 exitNormalVector = motherNormalStc.exitNormal;
980 }
981 else
982 {
983 G4ThreeVector exitNormalGlobal = exitNormalStc.exitNormal;
984 exitNormalVector = globalToLocalTop.TransformAxis(exitNormalGlobal);
985 // exitNormalVector= globalToLocal2nd.TransformAxis(exitNormalGlobal);
986 // Alt Make it in one go to Grand-Mother, avoiding transform below
987 }
988 // Transform to Grand-mother reference frame
989 const G4RotationMatrix* rot = motherPhysical->GetRotation();
990 if ( rot )
991 {
992 exitNormalVector *= rot->inverse();
993 }
994
995 }
996 else
997 {
998 validExitNormal = false;
999 }
1000
1001#else
1002 if ( motherSafety<=ourStep )
1003 {
1004 if ( motherStep<=ourStep )
1005 {
1006 ourStep = motherStep;
1007 exiting = true;
1008 if ( validExitNormal )
1009 {
1010 const G4RotationMatrix* rot = motherPhysical->GetRotation();
1011 if ( rot )
1012 {
1013 exitNormal *= rot->inverse();
1014 }
1015 }
1016 }
1017 else
1018 {
1019 validExitNormal = false;
1020 // calculatedExitNormal= false;
1021 }
1022 }
1023#endif
1024
1025
1026 G4bool daughterDeterminedStep = false;
1027 G4ThreeVector daughtNormRepCrd;
1028 // Exit normal of daughter transformed to
1029 // the coordinate system of Replica (i.e. last depth)
1030
1031 //
1032 // Compute daughter safeties & intersections
1033 //
1034 localNoDaughters = repLogical->GetNoDaughters();
1035 for ( sampleNo=localNoDaughters-1; sampleNo>=0; sampleNo-- )
1036 {
1037 samplePhysical = repLogical->GetDaughter(sampleNo);
1038 if ( samplePhysical!=blockedExitedVol )
1039 {
1040 G4ThreeVector localExitNorm;
1041 G4ThreeVector normReplicaCoord;
1042
1043 G4AffineTransform sampleTf(samplePhysical->GetRotation(),
1044 samplePhysical->GetTranslation());
1045 sampleTf.Invert();
1046 const G4ThreeVector samplePoint =
1047 sampleTf.TransformPoint(localPoint);
1048 const G4VSolid* sampleSolid =
1049 samplePhysical->GetLogicalVolume()->GetSolid();
1050 const G4double sampleSafetyDistance =
1051 sampleSolid->DistanceToIn(samplePoint);
1052 if ( sampleSafetyDistance<ourSafety )
1053 {
1054 ourSafety = sampleSafetyDistance;
1055 }
1056 if ( sampleSafetyDistance<=ourStep )
1057 {
1058 sampleDirection = sampleTf.TransformAxis(localDirection);
1059 const G4double sampleStepDistance =
1060 sampleSolid->DistanceToIn(samplePoint,sampleDirection);
1061 if ( sampleStepDistance<=ourStep )
1062 {
1063 daughterDeterminedStep = true;
1064
1065 ourStep = sampleStepDistance;
1066 entering = true;
1067 exiting = false;
1068 *pBlockedPhysical = samplePhysical;
1069 blockedReplicaNo = sampleNo;
1070
1071#ifdef DAUGHTER_NORMAL_ALSO
1072 // This norm can be calculated later, if needed daughter is available
1073 localExitNorm = sampleSolid->SurfaceNormal(samplePoint);
1074 daughtNormRepCrd = sampleTf.InverseTransformAxis(localExitNorm);
1075#endif
1076
1077#ifdef G4VERBOSE
1078 // Check to see that the resulting point is indeed in/on volume.
1079 // This check could eventually be made only for successful candidate.
1080
1081 if ( ( fCheck ) && ( sampleStepDistance < kInfinity ) )
1082 {
1083 G4ThreeVector intersectionPoint;
1084 intersectionPoint = samplePoint
1085 + sampleStepDistance * sampleDirection;
1086 EInside insideIntPt = sampleSolid->Inside(intersectionPoint);
1087 if ( insideIntPt != kSurface )
1088 {
1089 G4int oldcoutPrec = G4cout.precision(16);
1090 std::ostringstream message;
1091 message << "Navigator gets conflicting response from Solid."
1092 << G4endl
1093 << " Inaccurate DistanceToIn for solid "
1094 << sampleSolid->GetName() << G4endl
1095 << " Solid gave DistanceToIn = "
1096 << sampleStepDistance << " yet returns " ;
1097 if ( insideIntPt == kInside )
1098 message << "-kInside-";
1099 else if ( insideIntPt == kOutside )
1100 message << "-kOutside-";
1101 else
1102 message << "-kSurface-";
1103 message << " for this point !" << G4endl
1104 << " Point = " << intersectionPoint << G4endl;
1105 if ( insideIntPt != kInside )
1106 message << " DistanceToIn(p) = "
1107 << sampleSolid->DistanceToIn(intersectionPoint)
1108 << G4endl;
1109 if ( insideIntPt != kOutside )
1110 message << " DistanceToOut(p) = "
1111 << sampleSolid->DistanceToOut(intersectionPoint);
1112 G4Exception("G4ReplicaNavigation::ComputeStep()",
1113 "GeomNav1002", JustWarning, message);
1114 G4cout.precision(oldcoutPrec);
1115 }
1116 }
1117#endif
1118 }
1119 }
1120 }
1121 }
1122
1123 calculatedExitNormal &= (!daughterDeterminedStep);
1124
1125#ifdef DAUGHTER_NORMAL_ALSO
1126 if( daughterDeterminedStep )
1127 {
1128 // G4ThreeVector daughtNormGlobal =
1129 // GlobalToLastDepth.Inverse().TransformAxis(daughtNormRepCrd);
1130 // ==> Can calculate it, but have no way to transmit it to caller (for now)
1131
1132 exitNormalVector = globalToLocalTop.InverseTransformAxis(daughtNormGlobal);
1133 validExitNormal = false; // Entering daughter - never convex for parent
1134
1135 calculatedExitNormal = true;
1136 }
1137 // calculatedExitNormal= true; // Force it to true -- dubious
1138#endif
1139
1140 newSafety = ourSafety;
1141 return ourStep;
1142}
1143
1144// ********************************************************************
1145// ComputeSafety
1146//
1147// Compute the isotropic distance to current volume's boundaries
1148// and to daughter volumes.
1149// ********************************************************************
1150//
1153 const G4ThreeVector& localPoint,
1154 G4NavigationHistory& history,
1155 const G4double )
1156{
1157 G4VPhysicalVolume *repPhysical, *motherPhysical;
1158 G4VPhysicalVolume *samplePhysical, *blockedExitedVol = nullptr;
1159 G4LogicalVolume *repLogical;
1160 G4VSolid *motherSolid;
1161 G4ThreeVector repPoint;
1162 G4double ourSafety = kInfinity;
1163 G4double sampleSafety;
1164 G4int localNoDaughters, sampleNo;
1165 G4int depth;
1166
1167 repPhysical = history.GetTopVolume();
1168 repLogical = repPhysical->GetLogicalVolume();
1169
1170 //
1171 // Compute intersection with replica boundaries & replica safety
1172 //
1173
1174 sampleSafety = DistanceToOut(history.GetTopVolume(),
1175 history.GetTopReplicaNo(),
1176 localPoint);
1177 if ( sampleSafety<ourSafety )
1178 {
1179 ourSafety = sampleSafety;
1180 }
1181
1182 depth = history.GetDepth()-1;
1183
1184 // Loop checking, 07.10.2016, JA -- need to add: assert(depth>0)
1185 while ( history.GetVolumeType(depth)==kReplica )
1186 {
1187 repPoint = history.GetTransform(depth).TransformPoint(globalPoint);
1188 sampleSafety = DistanceToOut(history.GetVolume(depth),
1189 history.GetReplicaNo(depth),
1190 repPoint);
1191 if ( sampleSafety<ourSafety )
1192 {
1193 ourSafety = sampleSafety;
1194 }
1195 depth--;
1196 }
1197
1198 // Compute mother safety & intersection
1199 //
1200 repPoint = history.GetTransform(depth).TransformPoint(globalPoint);
1201 motherPhysical = history.GetVolume(depth);
1202 motherSolid = motherPhysical->GetLogicalVolume()->GetSolid();
1203 sampleSafety = motherSolid->DistanceToOut(repPoint);
1204
1205 if ( sampleSafety<ourSafety )
1206 {
1207 ourSafety = sampleSafety;
1208 }
1209
1210 // Compute daughter safeties & intersections
1211 //
1212 localNoDaughters = repLogical->GetNoDaughters();
1213 for ( sampleNo=localNoDaughters-1; sampleNo>=0; sampleNo-- )
1214 {
1215 samplePhysical = repLogical->GetDaughter(sampleNo);
1216 if ( samplePhysical!=blockedExitedVol )
1217 {
1218 G4AffineTransform sampleTf(samplePhysical->GetRotation(),
1219 samplePhysical->GetTranslation());
1220 sampleTf.Invert();
1221 const G4ThreeVector samplePoint =
1222 sampleTf.TransformPoint(localPoint);
1223 const G4VSolid *sampleSolid =
1224 samplePhysical->GetLogicalVolume()->GetSolid();
1225 const G4double sampleSafetyDistance =
1226 sampleSolid->DistanceToIn(samplePoint);
1227 if ( sampleSafetyDistance<ourSafety )
1228 {
1229 ourSafety = sampleSafetyDistance;
1230 }
1231 }
1232 }
1233 return ourSafety;
1234}
1235
1236// ********************************************************************
1237// BackLocate
1238// ********************************************************************
1239//
1240EInside
1242 const G4ThreeVector& globalPoint,
1243 G4ThreeVector& localPoint,
1244 const G4bool& exiting,
1245 G4bool& notKnownInside ) const
1246{
1247 G4VPhysicalVolume *pNRMother = nullptr;
1248 G4VSolid *motherSolid;
1249 G4ThreeVector repPoint, goodPoint;
1250 G4int mdepth, depth, cdepth;
1251 EInside insideCode;
1252
1253 cdepth = history.GetDepth();
1254
1255 // Find non replicated mother
1256 //
1257 for ( mdepth=cdepth-1; mdepth>=0; mdepth-- )
1258 {
1259 if ( history.GetVolumeType(mdepth)!=kReplica )
1260 {
1261 pNRMother = history.GetVolume(mdepth);
1262 break;
1263 }
1264 }
1265
1266 if( pNRMother == nullptr )
1267 {
1268 // All the tree of mother volumes were Replicas.
1269 // This is an error, as the World volume must be a Placement
1270 //
1271 G4Exception("G4ReplicaNavigation::BackLocate()", "GeomNav0002",
1272 FatalException, "The World volume must be a Placement!");
1273 return kInside;
1274 }
1275
1276 motherSolid = pNRMother->GetLogicalVolume()->GetSolid();
1277 goodPoint = history.GetTransform(mdepth).TransformPoint(globalPoint);
1278 insideCode = motherSolid->Inside(goodPoint);
1279 if ( (insideCode==kOutside)||((insideCode==kSurface)&&exiting) )
1280 {
1281 // Outside mother -> back up to mother level
1282 // Locate.. in Navigator will back up one more level
1283 // localPoint not required
1284 //
1285 history.BackLevel(cdepth-mdepth);
1286 // localPoint = goodPoint;
1287 }
1288 else
1289 {
1290 notKnownInside = false;
1291
1292 // Still within replications
1293 // Check down: if on outside stop at this level
1294 //
1295 for ( depth=mdepth+1; depth<cdepth; ++depth)
1296 {
1297 repPoint = history.GetTransform(depth).TransformPoint(globalPoint);
1298 insideCode = Inside(history.GetVolume(depth),
1299 history.GetReplicaNo(depth),
1300 repPoint);
1301 if ( (insideCode==kOutside)||((insideCode==kSurface)&&exiting) )
1302 {
1303 localPoint = goodPoint;
1304 history.BackLevel(cdepth-depth);
1305 return insideCode;
1306 }
1307 else
1308 {
1309 goodPoint = repPoint;
1310 }
1311 }
1312 localPoint = history.GetTransform(depth).TransformPoint(globalPoint);
1313 insideCode = Inside(history.GetVolume(depth),
1314 history.GetReplicaNo(depth),
1315 localPoint);
1316 // If outside level, set localPoint = coordinates in reference system
1317 // of *previous* level - location code in navigator will back up one
1318 // level [And also manage blocking]
1319 //
1320 if ( (insideCode==kOutside)||((insideCode==kSurface)&&exiting) )
1321 {
1322 localPoint = goodPoint;
1323 }
1324 }
1325 return insideCode;
1326}
@ JustWarning
@ FatalException
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
Definition: G4Exception.cc:35
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 z() const
double phi() const
double x() const
void setY(double)
double y() const
double dot(const Hep3Vector &) const
double perp2() const
void setZ(double)
void setX(double)
double perp() const
HepRotation inverse() const
G4ThreeVector InverseTransformAxis(const G4ThreeVector &axis) const
G4AffineTransform & Invert()
G4ThreeVector TransformPoint(const G4ThreeVector &vec) const
G4ThreeVector TransformAxis(const G4ThreeVector &axis) const
G4double GetSurfaceTolerance() const
G4double GetRadialTolerance() const
static G4GeometryTolerance * GetInstance()
G4double GetAngularTolerance() const
G4VSolid * GetSolid() const
size_t GetNoDaughters() const
G4VPhysicalVolume * GetDaughter(const G4int i) const
G4int GetReplicaNo(G4int n) const
size_t GetDepth() const
const G4AffineTransform & GetTopTransform() const
G4int GetTopReplicaNo() const
G4VPhysicalVolume * GetVolume(G4int n) const
G4VPhysicalVolume * GetTopVolume() const
EVolume GetVolumeType(G4int n) const
const G4AffineTransform & GetTransform(G4int n) const
G4double DistanceToOut(const G4VPhysicalVolume *pVol, const G4int replicaNo, const G4ThreeVector &localPoint) const
G4double ComputeStep(const G4ThreeVector &globalPoint, const G4ThreeVector &globalDirection, const G4ThreeVector &localPoint, const G4ThreeVector &localDirection, const G4double currentProposedStepLength, G4double &newSafety, G4NavigationHistory &history, G4bool &validExitNormal, G4bool &calculatedExitNormal, G4ThreeVector &exitNormal, G4bool &exiting, G4bool &entering, G4VPhysicalVolume *(*pBlockedPhysical), G4int &blockedReplicaNo)
G4double ComputeSafety(const G4ThreeVector &globalPoint, const G4ThreeVector &localPoint, G4NavigationHistory &history, const G4double pProposedMaxLength=DBL_MAX)
void ComputeTransformation(const G4int replicaNo, G4VPhysicalVolume *pVol, G4ThreeVector &point) const
EInside Inside(const G4VPhysicalVolume *pVol, const G4int replicaNo, const G4ThreeVector &localPoint) const
EInside BackLocate(G4NavigationHistory &history, const G4ThreeVector &globalPoint, G4ThreeVector &localPoint, const G4bool &exiting, G4bool &notKnownInside) const
const G4RotationMatrix * GetRotation() const
const G4ThreeVector GetTranslation() const
G4LogicalVolume * GetLogicalVolume() const
virtual void GetReplicationData(EAxis &axis, G4int &nReplicas, G4double &width, G4double &offset, G4bool &consuming) const =0
const G4String & GetName() const
void SetTranslation(const G4ThreeVector &v)
G4String GetName() const
virtual EInside Inside(const G4ThreeVector &p) const =0
virtual G4double DistanceToOut(const G4ThreeVector &p, const G4ThreeVector &v, const G4bool calcNorm=false, G4bool *validNorm=nullptr, G4ThreeVector *n=nullptr) const =0
void DumpInfo() const
virtual G4ThreeVector SurfaceNormal(const G4ThreeVector &p) const =0
virtual G4double DistanceToIn(const G4ThreeVector &p, const G4ThreeVector &v) const =0
EAxis
Definition: geomdefs.hh:54
@ kPhi
Definition: geomdefs.hh:60
@ kYAxis
Definition: geomdefs.hh:56
@ kXAxis
Definition: geomdefs.hh:55
@ kZAxis
Definition: geomdefs.hh:57
@ kRho
Definition: geomdefs.hh:58
EInside
Definition: geomdefs.hh:67
@ kInside
Definition: geomdefs.hh:70
@ kOutside
Definition: geomdefs.hh:68
@ kSurface
Definition: geomdefs.hh:69
@ kReplica
Definition: geomdefs.hh:85
G4ThreeVector exitNormal