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