Geant4 11.2.2
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// Inside
72// ********************************************************************
73//
76 const G4int replicaNo,
77 const G4ThreeVector& localPoint) const
78{
79 EInside in = kOutside;
80
81 // Replication data
82 //
83 EAxis axis;
84 G4int nReplicas;
85 G4double width, offset;
86 G4bool consuming;
87
88 G4double coord, rad2, rmin, tolRMax2, rmax, tolRMin2;
89
90 pVol->GetReplicationData(axis, nReplicas, width, offset, consuming);
91
92 switch (axis)
93 {
94 case kXAxis:
95 case kYAxis:
96 case kZAxis:
97 coord = std::fabs(localPoint(axis))-width*0.5;
98 if ( coord<=-halfkCarTolerance )
99 {
100 in = kInside;
101 }
102 else if ( coord<=halfkCarTolerance )
103 {
104 in = kSurface;
105 }
106 break;
107 case kPhi:
108 if ( (localPoint.y() != 0.0)||(localPoint.x() != 0.0) )
109 {
110 coord = std::fabs(std::atan2(localPoint.y(),localPoint.x()))-width*0.5;
111 if ( coord<=-halfkAngTolerance )
112 {
113 in = kInside;
114 }
115 else if ( coord<=halfkAngTolerance )
116 {
117 in = kSurface;
118 }
119 }
120 else
121 {
122 in = kSurface;
123 }
124 break;
125 case kRho:
126 rad2 = localPoint.perp2();
127 rmax = (replicaNo+1)*width+offset;
128 tolRMax2 = rmax-halfkRadTolerance;
129 tolRMax2 *= tolRMax2;
130 if ( rad2>tolRMax2 )
131 {
132 tolRMax2 = rmax+halfkRadTolerance;
133 tolRMax2 *= tolRMax2;
134 if ( rad2<=tolRMax2 )
135 {
136 in = kSurface;
137 }
138 }
139 else
140 {
141 // Known to be inside outer radius
142 //
143 if ( (replicaNo != 0)||(offset != 0.0) )
144 {
145 rmin = rmax-width;
146 tolRMin2 = rmin-halfkRadTolerance;
147 tolRMin2 *= tolRMin2;
148 if ( rad2>tolRMin2 )
149 {
150 tolRMin2 = rmin+halfkRadTolerance;
151 tolRMin2 *= tolRMin2;
152 if ( rad2>=tolRMin2 )
153 {
154 in = kInside;
155 }
156 else
157 {
158 in = kSurface;
159 }
160 }
161 }
162 else
163 {
164 in = kInside;
165 }
166 }
167 break;
168 default:
169 G4Exception("G4ReplicaNavigation::Inside()", "GeomNav0002",
170 FatalException, "Unknown axis!");
171 break;
172 }
173 return in;
174}
175
176// ********************************************************************
177// DistanceToOut
178// ********************************************************************
179//
182 const G4int replicaNo,
183 const G4ThreeVector& localPoint) const
184{
185 // Replication data
186 //
187 EAxis axis;
188 G4int nReplicas;
189 G4double width,offset;
190 G4bool consuming;
191
192 G4double safety = 0.;
193 G4double safe1,safe2;
194 G4double coord, rho, rmin, rmax;
195
196 pVol->GetReplicationData(axis, nReplicas, width, offset, consuming);
197 switch(axis)
198 {
199 case kXAxis:
200 case kYAxis:
201 case kZAxis:
202 coord = localPoint(axis);
203 safe1 = width*0.5-coord;
204 safe2 = width*0.5+coord;
205 safety = (safe1<=safe2) ? safe1 : safe2;
206 break;
207 case kPhi:
208 if ( localPoint.y()<=0 )
209 {
210 safety = localPoint.x()*std::sin(width*0.5)
211 + localPoint.y()*std::cos(width*0.5);
212 }
213 else
214 {
215 safety = localPoint.x()*std::sin(width*0.5)
216 - localPoint.y()*std::cos(width*0.5);
217 }
218 break;
219 case kRho:
220 rho = localPoint.perp();
221 rmax = width*(replicaNo+1)+offset;
222 if ( (replicaNo != 0)||(offset != 0.0) )
223 {
224 rmin = rmax-width;
225 safe1 = rho-rmin;
226 safe2 = rmax-rho;
227 safety = (safe1<=safe2) ? safe1 : safe2;
228 }
229 else
230 {
231 safety = rmax-rho;
232 }
233 break;
234 default:
235 G4Exception("G4ReplicaNavigation::DistanceToOut()", "GeomNav0002",
236 FatalException, "Unknown axis!");
237 break;
238 }
239 return (safety >= halfkCarTolerance) ? safety : 0;
240}
241
242// ********************************************************************
243// DistanceToOut
244// ********************************************************************
245//
248 const G4int replicaNo,
249 const G4ThreeVector& localPoint,
250 const G4ThreeVector& localDirection,
251 G4ExitNormal& arExitNormal ) const
252{
253 // Replication data
254 //
255 EAxis axis;
256 G4int nReplicas;
257 G4double width, offset;
258 G4bool consuming;
259
260 G4double Dist=kInfinity;
261 G4double coord, Comp, lindist;
262 G4double signC = 0.0;
263 G4ExitNormal candidateNormal;
264
265 pVol->GetReplicationData(axis, nReplicas, width, offset, consuming);
266 switch(axis)
267 {
268 case kXAxis:
269 case kYAxis:
270 case kZAxis:
271 coord = localPoint(axis);
272 Comp = localDirection(axis);
273 if ( Comp>0 )
274 {
275 lindist = width*0.5-coord;
276 Dist = (lindist>0) ? lindist/Comp : 0;
277 signC= 1.0;
278 }
279 else if ( Comp<0 )
280 {
281 lindist = width*0.5+coord;
282 Dist = (lindist>0) ? -lindist/Comp : 0;
283 signC= -1.0;
284 }
285 else
286 {
287 Dist = kInfinity;
288 }
289 // signC = sign<G4double>(Comp)
290 candidateNormal.exitNormal = ( signC * VecCartAxes[axis]);
291 candidateNormal.calculated = true;
292 candidateNormal.validConvex = true;
293 candidateNormal.exitSide =
294 (Comp>0) ? SideCartAxesPlus[axis] : SideCartAxesMinus[axis];
295 break;
296 case kPhi:
297 Dist = DistanceToOutPhi(localPoint,localDirection,width,candidateNormal);
298 // candidateNormal set in call
299 break;
300 case kRho:
301 Dist = DistanceToOutRad(localPoint,localDirection,width,offset,
302 replicaNo,candidateNormal);
303 // candidateNormal set in call
304 break;
305 default:
306 G4Exception("G4ReplicaNavigation::DistanceToOut()", "GeomNav0002",
307 FatalException, "Unknown axis!");
308 break;
309 }
310
311 arExitNormal= candidateNormal; // .exitNormal;
312
313 return Dist;
314}
315
316// ********************************************************************
317// DistanceToOutPhi
318// ********************************************************************
319//
321G4ReplicaNavigation::DistanceToOutPhi(const G4ThreeVector& localPoint,
322 const G4ThreeVector& localDirection,
323 const G4double width,
324 G4ExitNormal& foundNormal ) const
325{
326 // Phi Intersection
327 // NOTE: width<=pi by definition
328 //
329 G4double sinSPhi = -2.0, cosSPhi = -2.0;
330 G4double pDistS, pDistE, compS, compE, Dist, dist2, yi;
332 G4ThreeVector candidateNormal;
333
334 if ( (localPoint.x()!=0.0) || (localPoint.y()!=0.0) )
335 {
336 sinSPhi = std::sin(-width*0.5); // SIN of starting phi plane
337 cosSPhi = std::cos(width*0.5); // COS of starting phi plane
338
339 // pDist -ve when inside
340 //
341 pDistS = localPoint.x()*sinSPhi-localPoint.y()*cosSPhi;
342 // Start plane at phi= -S
343 pDistE = localPoint.x()*sinSPhi+localPoint.y()*cosSPhi;
344 // End plane at phi= +S
345
346 // Comp -ve when in direction of outwards normal
347 //
348 compS = -sinSPhi*localDirection.x()+cosSPhi*localDirection.y();
349 compE = -sinSPhi*localDirection.x()-cosSPhi*localDirection.y();
350
351 if ( (pDistS<=halfkCarTolerance)&&(pDistE<=halfkCarTolerance) )
352 {
353 // Inside both phi *full* planes
354 //
355 if ( compS<0 )
356 {
357 dist2 = pDistS/compS;
358 yi = localPoint.y()+dist2*localDirection.y();
359
360 // Check intersecting with correct half-plane (no -> no intersect)
361 //
362 if ( yi<=0 )
363 {
364 Dist = (pDistS<=-halfkCarTolerance) ? dist2 : 0;
365 sidePhi= G4ExitNormal::kSPhi; // tbc
366 }
367 else
368 {
369 Dist = kInfinity;
370 }
371 }
372 else
373 {
374 Dist = kInfinity;
375 }
376 if ( compE<0 )
377 {
378 dist2 = pDistE/compE;
379
380 // Only check further if < starting phi intersection
381 //
382 if ( dist2<Dist )
383 {
384 yi = localPoint.y()+dist2*localDirection.y();
385
386 // Check intersecting with correct half-plane
387 //
388 if ( yi>=0 )
389 {
390 // Leaving via ending phi
391 //
392 Dist = (pDistE<=-halfkCarTolerance) ? dist2 : 0;
393 sidePhi = G4ExitNormal::kEPhi;
394 }
395 }
396 }
397 }
398 else if ( (pDistS>halfkCarTolerance)&&(pDistE>halfkCarTolerance) )
399 {
400 // Outside both *full* phi planes
401 // if towards both >=0 then once inside will remain inside
402 //
403 Dist = ((compS>=0)&&(compE>=0)) ? kInfinity : 0;
404 }
405 else if ( (pDistS>halfkCarTolerance)&&(pDistE<=halfkCarTolerance) )
406 {
407 // Outside full starting plane, inside full ending plane
408 //
409 if ( compE<0 )
410 {
411 dist2 = pDistE/compE;
412 yi = localPoint.y()+dist2*localDirection.y();
413
414 // Check intersection in correct half-plane
415 // (if not -> remain in extent)
416 //
417 Dist = (yi>0) ? dist2 : kInfinity;
418 if( yi> 0 ) { sidePhi = G4ExitNormal::kEPhi; }
419 }
420 else // Leaving immediately by starting phi
421 {
422 Dist = kInfinity;
423 }
424 }
425 else
426 {
427 // Must be (pDistS<=halfkCarTolerance)&&(pDistE>halfkCarTolerance)
428 // Inside full starting plane, outside full ending plane
429 //
430 if ( compE>=0 )
431 {
432 if ( compS<0 )
433 {
434 dist2 = pDistS/compS;
435 yi = localPoint.y()+dist2*localDirection.y();
436
437 // Check intersection in correct half-plane
438 // (if not -> remain in extent)
439 //
440 Dist = (yi<0) ? dist2 : kInfinity;
441 if(yi<0) { sidePhi = G4ExitNormal::kSPhi; }
442 }
443 else
444 {
445 Dist = kInfinity;
446 }
447 }
448 else
449 {
450 // Leaving immediately by ending phi
451 //
452 Dist = 0.;
453 sidePhi = G4ExitNormal::kEPhi;
454 }
455 }
456 }
457 else
458 {
459 // On z axis + travel not || to z axis -> use direction vector
460 //
461 if( (std::fabs(localDirection.phi())<=width*0.5) )
462 {
463 Dist = kInfinity;
464 }
465 else
466 {
467 Dist = 0.;
468 sidePhi = G4ExitNormal::kMY;
469 }
470 }
471
472 if(sidePhi == G4ExitNormal::kSPhi )
473 {
474 candidateNormal = G4ThreeVector(sinSPhi,-cosSPhi,0.) ;
475 }
476 else if (sidePhi == G4ExitNormal::kEPhi)
477 {
478 candidateNormal = G4ThreeVector(sinSPhi,cosSPhi,0.) ;
479 }
480 else if (sidePhi == G4ExitNormal::kMY )
481 {
482 candidateNormal = G4ThreeVector(0., -1.0, 0.); // Split -S and +S 'phi'
483 }
484 foundNormal.calculated= (sidePhi != G4ExitNormal::kNull );
485 foundNormal.exitNormal= candidateNormal;
486
487 return Dist;
488}
489
490// ********************************************************************
491// DistanceToOutRad
492// ********************************************************************
493//
495G4ReplicaNavigation::DistanceToOutRad(const G4ThreeVector& localPoint,
496 const G4ThreeVector& localDirection,
497 const G4double width,
498 const G4double offset,
499 const G4int replicaNo,
500 G4ExitNormal& foundNormal ) const
501{
502 G4double rmin, rmax, t1, t2, t3, deltaR;
503 G4double b, c, d2, srd;
505
506 //
507 // Radial Intersections
508 //
509
510 // Find intersction with cylinders at rmax/rmin
511 // Intersection point (xi,yi,zi) on line
512 // x=localPoint.x+t*localDirection.x etc.
513 //
514 // Intersects with x^2+y^2=R^2
515 //
516 // Hence (localDirection.x^2+localDirection.y^2)t^2+
517 // 2t(localPoint.x*localDirection.x+localPoint.y*localDirection.y)+
518 // localPoint.x^2+localPoint.y^2-R^2=0
519 //
520 // t1 t2 t3
521
522 rmin = replicaNo*width+offset;
523 rmax = (replicaNo+1)*width+offset;
524
525 t1 = 1.0-localDirection.z()*localDirection.z(); // since v normalised
526 t2 = localPoint.x()*localDirection.x()+localPoint.y()*localDirection.y();
527 t3 = localPoint.x()*localPoint.x()+localPoint.y()*localPoint.y();
528
529 if ( t1>0 ) // Check not parallel
530 {
531 // Calculate srd, r exit distance
532 //
533 if ( t2>=0 )
534 {
535 // Delta r not negative => leaving via rmax
536 //
537 deltaR = t3-rmax*rmax;
538
539 // NOTE: Should use
540 // rho-rmax<-halfkRadTolerance - [no sqrts for efficiency]
541 //
542 if ( deltaR<-halfkRadTolerance )
543 {
544 b = t2/t1;
545 c = deltaR/t1;
546 srd = -b+std::sqrt(b*b-c);
547 sideR = G4ExitNormal::kRMax;
548 }
549 else
550 {
551 // On tolerant boundary & heading outwards (or locally
552 // perpendicular to) outer radial surface -> leaving immediately
553 //
554 srd = 0;
555 sideR = G4ExitNormal::kRMax;
556 }
557 }
558 else
559 {
560 // Possible rmin intersection
561 //
562 if (rmin != 0.0)
563 {
564 deltaR = t3-rmin*rmin;
565 b = t2/t1;
566 c = deltaR/t1;
567 d2 = b*b-c;
568 if ( d2>=0 )
569 {
570 // Leaving via rmin
571 // NOTE: Should use
572 // rho-rmin>halfkRadTolerance - [no sqrts for efficiency]
573 //
574 srd = (deltaR>halfkRadTolerance) ? -b-std::sqrt(d2) : 0.0;
575 // Is the following more accurate ?
576 // srd = (deltaR>halfkRadTolerance) ? c/( -b - std::sqrt(d2)) : 0.0;
577 sideR = G4ExitNormal::kRMin;
578 }
579 else
580 {
581 // No rmin intersect -> must be rmax intersect
582 //
583 deltaR = t3-rmax*rmax;
584 c = deltaR/t1;
585 d2 = b*b-c;
586 srd = (d2 < 0.) ? 0.0 : -b+std::sqrt(d2);
587 sideR = G4ExitNormal::kRMax;
588 }
589 }
590 else
591 {
592 // No rmin intersect -> must be rmax intersect
593 //
594 deltaR = t3-rmax*rmax;
595 b = t2/t1;
596 c = deltaR/t1;
597 d2 = b*b-c;
598 srd = (d2 < 0.) ? 0.0 : -b+std::sqrt(d2);
599 sideR= G4ExitNormal::kRMax;
600 }
601 }
602 }
603 else
604 {
605 srd =kInfinity;
606 sideR = G4ExitNormal::kNull;
607 }
608
609 if( sideR != G4ExitNormal::kNull ) // if ((side == kRMax) || (side==kRMin))
610 {
611 // Note: returned vector not explicitly normalised
612 // (divided by fRMax for unit vector)
613
614 G4double xi, yi;
615 xi = localPoint.x() + srd*localDirection.x();
616 yi = localPoint.y() + srd*localDirection.y();
617 G4ThreeVector normalR = G4ThreeVector(xi,yi,0.0);
618
619 if( sideR == G4ExitNormal::kRMax )
620 {
621 normalR *= 1.0/rmax;
622 }
623 else
624 {
625 normalR *= (-1.0)/rmin;
626 }
627 foundNormal.exitNormal= normalR;
628 foundNormal.calculated= true;
629 foundNormal.validConvex = (sideR == G4ExitNormal::kRMax);
630 foundNormal.exitSide = sideR;
631 }
632 else
633 {
634 foundNormal.calculated = false;
635 }
636
637 return srd;
638}
639
640// ********************************************************************
641// ComputeTransformation
642//
643// Setup transformation and transform point into local system
644// ********************************************************************
645//
646void
648 G4VPhysicalVolume* pVol,
649 G4ThreeVector& point) const
650{
651 G4double val,cosv,sinv,tmpx,tmpy;
652
653 // Replication data
654 //
655 EAxis axis;
656 G4int nReplicas;
657 G4double width,offset;
658 G4bool consuming;
659
660 pVol->GetReplicationData(axis, nReplicas, width, offset, consuming);
661
662 switch (axis)
663 {
664 case kXAxis:
665 val = -width*0.5*(nReplicas-1)+width*replicaNo;
666 pVol->SetTranslation(G4ThreeVector(val,0,0));
667 point.setX(point.x()-val);
668 break;
669 case kYAxis:
670 val = -width*0.5*(nReplicas-1)+width*replicaNo;
671 pVol->SetTranslation(G4ThreeVector(0,val,0));
672 point.setY(point.y()-val);
673 break;
674 case kZAxis:
675 val = -width*0.5*(nReplicas-1)+width*replicaNo;
676 pVol->SetTranslation(G4ThreeVector(0,0,val));
677 point.setZ(point.z()-val);
678 break;
679 case kPhi:
680 val = -(offset+width*(replicaNo+0.5));
681 SetPhiTransformation(val,pVol);
682 cosv = std::cos(val);
683 sinv = std::sin(val);
684 tmpx = point.x()*cosv-point.y()*sinv;
685 tmpy = point.x()*sinv+point.y()*cosv;
686 point.setY(tmpy);
687 point.setX(tmpx);
688 break;
689 case kRho:
690 // No setup required for radial case
691 default:
692 break;
693 }
694}
695
696// ********************************************************************
697// ComputeTransformation
698//
699// Setup transformation into local system
700// ********************************************************************
701//
702void
704 G4VPhysicalVolume* pVol) const
705{
706 G4double val;
707
708 // Replication data
709 //
710 EAxis axis;
711 G4int nReplicas;
712 G4double width, offset;
713 G4bool consuming;
714
715 pVol->GetReplicationData(axis, nReplicas, width, offset, consuming);
716
717 switch (axis)
718 {
719 case kXAxis:
720 val = -width*0.5*(nReplicas-1)+width*replicaNo;
721 pVol->SetTranslation(G4ThreeVector(val,0,0));
722 break;
723 case kYAxis:
724 val = -width*0.5*(nReplicas-1)+width*replicaNo;
725 pVol->SetTranslation(G4ThreeVector(0,val,0));
726 break;
727 case kZAxis:
728 val = -width*0.5*(nReplicas-1)+width*replicaNo;
729 pVol->SetTranslation(G4ThreeVector(0,0,val));
730 break;
731 case kPhi:
732 val = -(offset+width*(replicaNo+0.5));
733 SetPhiTransformation(val,pVol);
734 break;
735 case kRho:
736 // No setup required for radial case
737 default:
738 break;
739 }
740}
741
742// ********************************************************************
743// ComputeStep
744// ********************************************************************
745//
748 const G4ThreeVector& globalDirection,
749 const G4ThreeVector& localPoint,
750 const G4ThreeVector& localDirection,
751 const G4double currentProposedStepLength,
752 G4double& newSafety,
753 G4NavigationHistory &history,
754 // std::pair<G4bool,G4bool>& validAndCalculated
755 G4bool& validExitNormal,
756 G4bool& calculatedExitNormal,
757 G4ThreeVector& exitNormalVector,
758 G4bool& exiting,
759 G4bool& entering,
760 G4VPhysicalVolume* (*pBlockedPhysical),
761 G4int& blockedReplicaNo )
762{
763 G4VPhysicalVolume *repPhysical, *motherPhysical;
764 G4VPhysicalVolume *samplePhysical, *blockedExitedVol = nullptr;
765 G4LogicalVolume *repLogical;
766 G4VSolid *motherSolid;
767 G4ThreeVector repPoint, repDirection, sampleDirection;
768 G4double ourStep=currentProposedStepLength;
769 G4double ourSafety=kInfinity;
770 G4double sampleStep, sampleSafety, motherStep, motherSafety;
771 G4long localNoDaughters, sampleNo;
772 G4int depth;
773 G4ExitNormal exitNormalStc;
774 // G4int depthDeterminingStep= -1; // Useful only for debugging - for now
775
776 calculatedExitNormal= false;
777
778 // Exiting normal optimisation
779 //
780 if ( exiting&&validExitNormal )
781 {
782 if ( localDirection.dot(exitNormalVector)>=kMinExitingNormalCosine )
783 {
784 // Block exited daughter volume
785 //
786 blockedExitedVol = *pBlockedPhysical;
787 ourSafety = 0;
788 }
789 }
790 exiting = false;
791 entering = false;
792
793 repPhysical = history.GetTopVolume();
794 repLogical = repPhysical->GetLogicalVolume();
795
796 //
797 // Compute intersection with replica boundaries & replica safety
798 //
799
800 sampleSafety = DistanceToOut(repPhysical,
801 history.GetTopReplicaNo(),
802 localPoint);
803 G4ExitNormal normalOutStc;
804 const auto topDepth= (G4int)history.GetDepth();
805
806 ourSafety = std::min( ourSafety, sampleSafety);
807
808 if ( sampleSafety<ourStep )
809 {
810
811 sampleStep = DistanceToOut(repPhysical,
812 history.GetTopReplicaNo(),
813 localPoint,
814 localDirection,
815 normalOutStc);
816 if ( sampleStep<ourStep )
817 {
818 ourStep = sampleStep;
819 exiting = true;
820 validExitNormal = normalOutStc.validConvex; // false; -> Old,Conservative
821
822 exitNormalStc = normalOutStc;
823 exitNormalStc.exitNormal =
824 history.GetTopTransform().InverseTransformAxis(normalOutStc.exitNormal);
825 calculatedExitNormal = true;
826 }
827 }
828 const G4int secondDepth = topDepth;
829 depth = secondDepth;
830
831 // Loop checking, 07.10.2016, JA -- Need to add: assert(depth>0)
832 while ( history.GetVolumeType(depth)==kReplica )
833 {
834 const G4AffineTransform& GlobalToLocal = history.GetTransform(depth);
835 repPoint = GlobalToLocal.TransformPoint(globalPoint);
836 // repPoint = history.GetTransform(depth).TransformPoint(globalPoint);
837
838 sampleSafety = DistanceToOut(history.GetVolume(depth),
839 history.GetReplicaNo(depth),
840 repPoint);
841 if ( sampleSafety < ourSafety )
842 {
843 ourSafety = sampleSafety;
844 }
845 if ( sampleSafety < ourStep )
846 {
847 G4ThreeVector newLocalDirection =
848 GlobalToLocal.TransformAxis(globalDirection);
849 sampleStep = DistanceToOut(history.GetVolume(depth),
850 history.GetReplicaNo(depth),
851 repPoint,
852 newLocalDirection,
853 normalOutStc);
854 if ( sampleStep < ourStep )
855 {
856 ourStep = sampleStep;
857 exiting = true;
858
859 // As step is limited by this level, must set Exit Normal
860 //
861 G4ThreeVector localExitNorm = normalOutStc.exitNormal;
862 G4ThreeVector globalExitNorm =
863 GlobalToLocal.InverseTransformAxis(localExitNorm);
864
865 exitNormalStc = normalOutStc; // Normal, convex, calculated, side
866 exitNormalStc.exitNormal = globalExitNorm;
867 calculatedExitNormal = true;
868 }
869 }
870 depth--;
871 }
872
873 // Compute mother safety & intersection
874 //
875 G4ThreeVector exitVectorMother;
876 G4bool exitConvex = false; // Value obtained in DistanceToOut(p,v) call
877 G4ExitNormal motherNormalStc;
878
879 repPoint = history.GetTransform(depth).TransformPoint(globalPoint);
880 motherPhysical = history.GetVolume(depth);
881 motherSolid = motherPhysical->GetLogicalVolume()->GetSolid();
882 motherSafety = motherSolid->DistanceToOut(repPoint);
883 repDirection = history.GetTransform(depth).TransformAxis(globalDirection);
884
885 motherStep = motherSolid->DistanceToOut(repPoint,repDirection,true,
886 &exitConvex,&exitVectorMother);
887 if( exitConvex )
888 {
889 motherNormalStc = G4ExitNormal( exitVectorMother, true, false,
891 calculatedExitNormal = true;
892 }
893 const G4AffineTransform& globalToLocalTop = history.GetTopTransform();
894
895 G4bool motherDeterminedStep = (motherStep<ourStep);
896
897 if( (!exitConvex) && motherDeterminedStep )
898 {
899 exitVectorMother = motherSolid->SurfaceNormal( repPoint );
900 motherNormalStc = G4ExitNormal( exitVectorMother, true, false,
902 // CalculatedExitNormal -> true;
903 // Convex -> false: do not know value
904 // ExitSide -> kMother (or kNull)
905
906 calculatedExitNormal = true;
907 }
908 if( motherDeterminedStep )
909 {
910 G4ThreeVector globalExitNormalTop =
911 globalToLocalTop.InverseTransformAxis(exitVectorMother);
912
913 exitNormalStc = motherNormalStc;
914 exitNormalStc.exitNormal = globalExitNormalTop;
915 }
916
917 // Push in principle no longer necessary. G4Navigator now takes care of ...
918 // Removing this however may cause additional almost-zero steps and generate
919 // warnings for pushed particles from G4Navigator, particularly for the case
920 // of 3D replicas (Cartesian or combined Radial/Phi cases).
921 // Requires further investigation and eventually reimplementation of
922 // LevelLocate() to take into account point and direction ...
923 //
924 if( ourStep<fMinStep )
925 {
926 ourStep = 2*kCarTolerance;
927 }
928
929 if ( motherSafety<ourSafety )
930 {
931 ourSafety = motherSafety;
932 }
933
934#ifdef G4VERBOSE
935 if ( fCheck )
936 {
937 if( motherSolid->Inside(localPoint)==kOutside )
938 {
939 std::ostringstream message;
940 message << "Point outside volume !" << G4endl
941 << " Point " << localPoint
942 << " is outside current volume " << motherPhysical->GetName()
943 << G4endl;
944 G4double estDistToSolid= motherSolid->DistanceToIn(localPoint);
945 message << " Estimated isotropic distance to solid (distToIn)= "
946 << estDistToSolid << G4endl;
947 if( estDistToSolid > 100.0 * kCarTolerance )
948 {
949 motherSolid->DumpInfo();
950 G4Exception("G4ReplicaNavigation::ComputeStep()",
951 "GeomNav0003", FatalException, message,
952 "Point is far outside Current Volume !" );
953 }
954 else
955 {
956 G4Exception("G4ReplicaNavigation::ComputeStep()",
957 "GeomNav1002", JustWarning, message,
958 "Point is a little outside Current Volume.");
959 }
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 != nullptr )
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((G4int)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 = (G4int)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 G4long 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 }
1104 message << " for this point !" << G4endl
1105 << " Point = " << intersectionPoint << G4endl;
1106 if ( insideIntPt != kInside ) {
1107 message << " DistanceToIn(p) = "
1108 << sampleSolid->DistanceToIn(intersectionPoint)
1109 << G4endl;
1110}
1111 if ( insideIntPt != kOutside ) {
1112 message << " DistanceToOut(p) = "
1113 << sampleSolid->DistanceToOut(intersectionPoint);
1114}
1115 G4Exception("G4ReplicaNavigation::ComputeStep()",
1116 "GeomNav1002", JustWarning, message);
1117 G4cout.precision(oldcoutPrec);
1118 }
1119 }
1120#endif
1121 }
1122 }
1123 }
1124 }
1125
1126 calculatedExitNormal &= (!daughterDeterminedStep);
1127
1128#ifdef DAUGHTER_NORMAL_ALSO
1129 if( daughterDeterminedStep )
1130 {
1131 // G4ThreeVector daughtNormGlobal =
1132 // GlobalToLastDepth.Inverse().TransformAxis(daughtNormRepCrd);
1133 // ==> Can calculate it, but have no way to transmit it to caller (for now)
1134
1135 exitNormalVector = globalToLocalTop.InverseTransformAxis(daughtNormGlobal);
1136 validExitNormal = false; // Entering daughter - never convex for parent
1137
1138 calculatedExitNormal = true;
1139 }
1140 // calculatedExitNormal= true; // Force it to true -- dubious
1141#endif
1142
1143 newSafety = ourSafety;
1144 return ourStep;
1145}
1146
1147// ********************************************************************
1148// ComputeSafety
1149//
1150// Compute the isotropic distance to current volume's boundaries
1151// and to daughter volumes.
1152// ********************************************************************
1153//
1156 const G4ThreeVector& localPoint,
1157 const G4NavigationHistory& history,
1158 const G4double ) const
1159{
1160 G4VPhysicalVolume *repPhysical, *motherPhysical;
1161 G4VPhysicalVolume *samplePhysical, *blockedExitedVol = nullptr;
1162 G4LogicalVolume *repLogical;
1163 G4VSolid *motherSolid;
1164 G4ThreeVector repPoint;
1165 G4double ourSafety = kInfinity;
1166 G4double sampleSafety;
1167 G4long localNoDaughters, sampleNo;
1168 G4int depth;
1169
1170 repPhysical = history.GetTopVolume();
1171 repLogical = repPhysical->GetLogicalVolume();
1172
1173 //
1174 // Compute intersection with replica boundaries & replica safety
1175 //
1176
1177 sampleSafety = DistanceToOut(history.GetTopVolume(),
1178 history.GetTopReplicaNo(),
1179 localPoint);
1180 if ( sampleSafety<ourSafety )
1181 {
1182 ourSafety = sampleSafety;
1183 }
1184
1185 depth = (G4int)history.GetDepth()-1;
1186
1187 // Loop checking, 07.10.2016, JA -- need to add: assert(depth>0)
1188 while ( history.GetVolumeType(depth)==kReplica )
1189 {
1190 repPoint = history.GetTransform(depth).TransformPoint(globalPoint);
1191 sampleSafety = DistanceToOut(history.GetVolume(depth),
1192 history.GetReplicaNo(depth),
1193 repPoint);
1194 if ( sampleSafety<ourSafety )
1195 {
1196 ourSafety = sampleSafety;
1197 }
1198 depth--;
1199 }
1200
1201 // Compute mother safety & intersection
1202 //
1203 repPoint = history.GetTransform(depth).TransformPoint(globalPoint);
1204 motherPhysical = history.GetVolume(depth);
1205 motherSolid = motherPhysical->GetLogicalVolume()->GetSolid();
1206 sampleSafety = motherSolid->DistanceToOut(repPoint);
1207
1208 if ( sampleSafety<ourSafety )
1209 {
1210 ourSafety = sampleSafety;
1211 }
1212
1213 // Compute daughter safeties & intersections
1214 //
1215 localNoDaughters = repLogical->GetNoDaughters();
1216 for ( sampleNo=localNoDaughters-1; sampleNo>=0; sampleNo-- )
1217 {
1218 samplePhysical = repLogical->GetDaughter((G4int)sampleNo);
1219 if ( samplePhysical!=blockedExitedVol )
1220 {
1221 G4AffineTransform sampleTf(samplePhysical->GetRotation(),
1222 samplePhysical->GetTranslation());
1223 sampleTf.Invert();
1224 const G4ThreeVector samplePoint =
1225 sampleTf.TransformPoint(localPoint);
1226 const G4VSolid *sampleSolid =
1227 samplePhysical->GetLogicalVolume()->GetSolid();
1228 const G4double sampleSafetyDistance =
1229 sampleSolid->DistanceToIn(samplePoint);
1230 if ( sampleSafetyDistance<ourSafety )
1231 {
1232 ourSafety = sampleSafetyDistance;
1233 }
1234 }
1235 }
1236 return ourSafety;
1237}
1238
1239// ********************************************************************
1240// BackLocate
1241// ********************************************************************
1242//
1243EInside
1245 const G4ThreeVector& globalPoint,
1246 G4ThreeVector& localPoint,
1247 const G4bool& exiting,
1248 G4bool& notKnownInside ) const
1249{
1250 G4VPhysicalVolume *pNRMother = nullptr;
1251 G4VSolid *motherSolid;
1252 G4ThreeVector repPoint, goodPoint;
1253 G4int mdepth, depth, cdepth;
1254 EInside insideCode;
1255
1256 cdepth = (G4int)history.GetDepth();
1257
1258 // Find non replicated mother
1259 //
1260 for ( mdepth=cdepth-1; mdepth>=0; mdepth-- )
1261 {
1262 if ( history.GetVolumeType(mdepth)!=kReplica )
1263 {
1264 pNRMother = history.GetVolume(mdepth);
1265 break;
1266 }
1267 }
1268
1269 if( pNRMother == nullptr )
1270 {
1271 // All the tree of mother volumes were Replicas.
1272 // This is an error, as the World volume must be a Placement
1273 //
1274 G4Exception("G4ReplicaNavigation::BackLocate()", "GeomNav0002",
1275 FatalException, "The World volume must be a Placement!");
1276 return kInside;
1277 }
1278
1279 motherSolid = pNRMother->GetLogicalVolume()->GetSolid();
1280 goodPoint = history.GetTransform(mdepth).TransformPoint(globalPoint);
1281 insideCode = motherSolid->Inside(goodPoint);
1282 if ( (insideCode==kOutside)||((insideCode==kSurface)&&exiting) )
1283 {
1284 // Outside mother -> back up to mother level
1285 // Locate.. in Navigator will back up one more level
1286 // localPoint not required
1287 //
1288 history.BackLevel(cdepth-mdepth);
1289 // localPoint = goodPoint;
1290 }
1291 else
1292 {
1293 notKnownInside = false;
1294
1295 // Still within replications
1296 // Check down: if on outside stop at this level
1297 //
1298 for ( depth=mdepth+1; depth<cdepth; ++depth)
1299 {
1300 repPoint = history.GetTransform(depth).TransformPoint(globalPoint);
1301 insideCode = Inside(history.GetVolume(depth),
1302 history.GetReplicaNo(depth),
1303 repPoint);
1304 if ( (insideCode==kOutside)||((insideCode==kSurface)&&exiting) )
1305 {
1306 localPoint = goodPoint;
1307 history.BackLevel(cdepth-depth);
1308 return insideCode;
1309 }
1310 goodPoint = repPoint;
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)
CLHEP::Hep3Vector G4ThreeVector
double G4double
Definition G4Types.hh:83
long G4long
Definition G4Types.hh:87
bool G4bool
Definition G4Types.hh:86
int G4int
Definition G4Types.hh:85
#define G4endl
Definition G4ios.hh:67
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
std::size_t GetNoDaughters() const
G4VPhysicalVolume * GetDaughter(const std::size_t i) const
G4int GetReplicaNo(G4int n) const
const G4AffineTransform & GetTopTransform() const
G4int GetTopReplicaNo() const
G4VPhysicalVolume * GetVolume(G4int n) const
std::size_t GetDepth() 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, const G4NavigationHistory &history, const G4double pProposedMaxLength=DBL_MAX) const
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