ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4ITNavigator1.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file G4ITNavigator1.cc
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 // class G4ITNavigator1 Implementation
28 //
29 // Original author: Paul Kent, July 95/96
30 //
31 // G4ITNavigator1 is a duplicate version of G4Navigator starting from Geant4.9.5
32 // initially written by Paul Kent and colleagues.
33 // The only difference resides in the way the information is saved and managed
34 //
35 // History:
36 // - Created. Paul Kent, Jul 95/96
37 // - Zero step protections J.A. / G.C., Nov 2004
38 // - Added check mode G. Cosmo, Mar 2004
39 // - Made Navigator Abstract G. Cosmo, Nov 2003
40 // - G4ITNavigator1 created M.K., Nov 2012
41 // --------------------------------------------------------------------
42 
43 #include <iomanip>
44 
45 #include "G4ITNavigator1.hh"
46 //#include "G4ITNavigator.hh"
47 #include "G4ios.hh"
48 #include "G4SystemOfUnits.hh"
49 #include "G4GeometryTolerance.hh"
50 #include "G4VPhysicalVolume.hh"
51 
52 #define G4DEBUG_NAVIGATION 1
53 #include "G4VoxelSafety.hh"
54 
55 // ********************************************************************
56 // Constructor
57 // ********************************************************************
58 //
60  : fWasLimitedByGeometry(false), fVerbose(0),
61  fTopPhysical(0), fCheck(false), fPushed(false), fWarnPush(true)
62 {
63  fActive= false;
65 
67  // Initialises also all
68  // - exit / entry flags
69  // - flags & variables for exit normals
70  // - zero step counters
71  // - blocked volume
72 
75 
78 
81 
83  fpSaveState = 0;
84 
85  // this->SetVerboseLevel(3);
86  // this->CheckMode(true);
87 }
88 
89 // !>
90 
92 {
93  sWasLimitedByGeometry = false;
94  sEntering = false;
95  sExiting = false;
96  sLocatedOnEdge = false;
97  sLastStepWasZero = false;
98  sEnteredDaughter = false;
99  sExitedMother = false;
100  sPushed = false;
101 
102  sValidExitNormal = false;
103  sExitNormal = G4ThreeVector(0,0,0);
104 
106  sPreviousSafety = 0.0;
107 
108  sNumberZeroSteps = 0;
109 
111  sBlockedReplicaNo = -1;
112 
114  sLocatedOutsideWorld = false;
115 }
116 
117 // <!
118 
119 // ********************************************************************
120 // Destructor
121 // ********************************************************************
122 //
124 { delete fpVoxelSafety; }
125 
126 // ********************************************************************
127 // ResetHierarchyAndLocate
128 // ********************************************************************
129 //
132  const G4ThreeVector &direction,
133  const G4TouchableHistory &h)
134 {
135  ResetState();
136  fHistory = *h.GetHistory();
137  SetupHierarchy();
138  fLastTriedStepComputation= false; // Redundant, but best
139  return LocateGlobalPointAndSetup(p, &direction, true, false);
140 }
141 
142 // ********************************************************************
143 // LocateGlobalPointAndSetup
144 //
145 // Locate the point in the hierarchy return 0 if outside
146 // The direction is required
147 // - if on an edge shared by more than two surfaces
148 // (to resolve likely looping in tracking)
149 // - at initial location of a particle
150 // (to resolve potential ambiguity at boundary)
151 //
152 // Flags on exit: (comments to be completed)
153 // fEntering - True if entering `daughter' volume (or replica)
154 // whether daughter of last mother directly
155 // or daughter of that volume's ancestor.
156 // ********************************************************************
157 //
160  const G4ThreeVector* pGlobalDirection,
161  const G4bool relativeSearch,
162  const G4bool ignoreDirection )
163 {
164  G4bool notKnownContained=true, noResult;
165  G4VPhysicalVolume *targetPhysical;
166  G4LogicalVolume *targetLogical;
167  G4VSolid *targetSolid=0;
168  G4ThreeVector localPoint, globalDirection;
169  EInside insideCode;
170 
171  G4bool considerDirection = (!ignoreDirection) || fLocatedOnEdge;
172 
174  fChangedGrandMotherRefFrame= false; // For local exit normal
175 
176  if( considerDirection && pGlobalDirection != 0 )
177  {
178  globalDirection=*pGlobalDirection;
179  }
180 
181 
182 #ifdef G4VERBOSE
183  if( fVerbose > 2 )
184  {
185  G4int oldcoutPrec = G4cout.precision(8);
186  G4cout << "*** G4ITNavigator1::LocateGlobalPointAndSetup: ***" << G4endl;
187  G4cout << " Called with arguments: " << G4endl
188  << " Globalpoint = " << globalPoint << G4endl
189  << " RelativeSearch = " << relativeSearch << G4endl;
190  if( fVerbose == 4 )
191  {
192  G4cout << " ----- Upon entering:" << G4endl;
193  PrintState();
194  }
195  G4cout.precision(oldcoutPrec);
196  }
197 #endif
198 
199  if ( !relativeSearch )
200  {
202  }
203  else
204  {
205  if ( fWasLimitedByGeometry )
206  {
207  fWasLimitedByGeometry = false;
208  fEnteredDaughter = fEntering; // Remember
209  fExitedMother = fExiting; // Remember
210  if ( fExiting )
211  {
212  if ( fHistory.GetDepth() )
213  {
217  }
218  else
219  {
220  fLastLocatedPointLocal = localPoint;
221  fLocatedOutsideWorld = true;
222  return 0; // Have exited world volume
223  }
224  // A fix for the case where a volume is "entered" at an edge
225  // and a coincident surface exists outside it.
226  // - This stops it from exiting further volumes and cycling
227  // - However ReplicaNavigator treats this case itself
228  //
230  {
231  fExiting= false;
232  }
233  }
234  else
235  if ( fEntering )
236  {
238  {
239  case kNormal:
242  break;
243  case kReplica:
249  break;
250  case kParameterised:
252  {
253  G4VSolid *pSolid;
254  G4VPVParameterisation *pParam;
255  G4TouchableHistory parentTouchable( fHistory );
257  pSolid = pParam->ComputeSolid(fBlockedReplicaNo,
259  pSolid->ComputeDimensions(pParam, fBlockedReplicaNo,
266  //
267  // Set the correct solid and material in Logical Volume
268  //
269  G4LogicalVolume *pLogical;
271  pLogical->SetSolid( pSolid );
272  pLogical->UpdateMaterial(pParam ->
273  ComputeMaterial(fBlockedReplicaNo,
275  &parentTouchable));
276  }
277  break;
278  case kExternal:
279  G4Exception("G4ITNavigator1::LocateGlobalPointAndSetup()",
280  "GeomNav0001", FatalException,
281  "Not applicable for external volumes.");
282  break;
283  }
284  fEntering = false;
286  localPoint = fHistory.GetTopTransform().TransformPoint(globalPoint);
287  notKnownContained = false;
288  }
289  }
290  else
291  {
293  fEntering = false;
294  fEnteredDaughter = false; // Full Step was not taken, did not enter
295  fExiting = false;
296  fExitedMother = false; // Full Step was not taken, did not exit
297  }
298  }
299  //
300  // Search from top of history up through geometry until
301  // containing volume found:
302  // If on
303  // o OUTSIDE - Back up level, not/no longer exiting volumes
304  // o SURFACE and EXITING - Back up level, setting new blocking no.s
305  // else
306  // o containing volume found
307  //
308  G4int noLevelsExited=0 ;
309 
310  while (notKnownContained)
311  {
313  {
314  targetSolid = fHistory.GetTopVolume()->GetLogicalVolume()->GetSolid();
315  localPoint = fHistory.GetTopTransform().TransformPoint(globalPoint);
316  insideCode = targetSolid->Inside(localPoint);
317 #ifdef G4VERBOSE
318  if(( fVerbose == 1 ) && ( fCheck ))
319  {
320  G4String solidResponse = "-kInside-";
321  if (insideCode == kOutside)
322  solidResponse = "-kOutside-";
323  else if (insideCode == kSurface)
324  solidResponse = "-kSurface-";
325  G4cout << "*** G4ITNavigator1::LocateGlobalPointAndSetup(): ***" << G4endl
326  << " Invoked Inside() for solid: " << targetSolid->GetName()
327  << ". Solid replied: " << solidResponse << G4endl
328  << " For local point p: " << localPoint << G4endl;
329  }
330 #endif
331  }
332  else
333  {
334  insideCode = freplicaNav.BackLocate(fHistory, globalPoint, localPoint,
335  fExiting, notKnownContained);
336  // !CARE! if notKnownContained returns false then the point is within
337  // the containing placement volume of the replica(s). If insidecode
338  // will result in the history being backed up one level, then the
339  // local point returned is the point in the system of this new level
340  }
341 
342 
343  if ( insideCode==kOutside )
344  {
345  noLevelsExited++;
346  if ( fHistory.GetDepth() )
347  {
351  fExiting = false;
352 
353  if( noLevelsExited > 1 )
354  {
355  // The first transformation was done by the sub-navigator
356  //
358  if( mRot )
359  {
360  fGrandMotherExitNormal *= (*mRot).inverse();
362  }
363  }
364  }
365  else
366  {
367  fLastLocatedPointLocal = localPoint;
368  fLocatedOutsideWorld = true;
369  // No extra transformation for ExitNormal - is in frame of Top Volume
370  return 0; // Have exited world volume
371  }
372  }
373  else
374  if ( insideCode==kSurface )
375  {
376  G4bool isExiting = fExiting;
377  if( (!fExiting)&&considerDirection )
378  {
379  // Figure out whether we are exiting this level's volume
380  // by using the direction
381  //
382  G4bool directionExiting = false;
383  G4ThreeVector localDirection =
384  fHistory.GetTopTransform().TransformAxis(globalDirection);
385 
386  // Make sure localPoint in correct reference frame
387  // ( Was it already correct ? How ? )
388  //
389  localPoint= fHistory.GetTopTransform().TransformPoint(globalPoint);
391  {
392  G4ThreeVector normal = targetSolid->SurfaceNormal(localPoint);
393  directionExiting = normal.dot(localDirection) > 0.0;
394  isExiting = isExiting || directionExiting;
395  }
396  }
397  if( isExiting )
398  {
399  noLevelsExited++;
400  if ( fHistory.GetDepth() )
401  {
405  //
406  // Still on surface but exited volume not necessarily convex
407  //
408  fValidExitNormal = false;
409 
410  if( noLevelsExited > 1 )
411  {
412  // The first transformation was done by the sub-navigator
413  //
415  if( mRot )
416  {
417  fGrandMotherExitNormal *= (*mRot).inverse();
419  }
420  }
421  }
422  else
423  {
424  fLastLocatedPointLocal = localPoint;
425  fLocatedOutsideWorld = true;
426  // No extra transformation for ExitNormal, is in frame of Top Vol
427  return 0; // Have exited world volume
428  }
429  }
430  else
431  {
432  notKnownContained=false;
433  }
434  }
435  else
436  {
437  notKnownContained=false;
438  }
439  } // END while (notKnownContained)
440  //
441  // Search downwards until deepest containing volume found,
442  // blocking fBlockedPhysicalVolume/BlockedReplicaNum
443  //
444  // 3 Cases:
445  //
446  // o Parameterised daughters
447  // =>Must be one G4PVParameterised daughter & voxels
448  // o Positioned daughters & voxels
449  // o Positioned daughters & no voxels
450 
451  noResult = true; // noResult should be renamed to
452  // something like enteredLevel, as that is its meaning.
453  do
454  {
455  // Determine `type' of current mother volume
456  //
457  targetPhysical = fHistory.GetTopVolume();
458  if (!targetPhysical) { break; }
459  targetLogical = targetPhysical->GetLogicalVolume();
460  switch( CharacteriseDaughters(targetLogical) )
461  {
462  case kNormal:
463  if ( targetLogical->GetVoxelHeader() ) // use optimised navigation
464  {
465  noResult = fvoxelNav.LevelLocate(fHistory,
468  globalPoint,
469  pGlobalDirection,
470  considerDirection,
471  localPoint);
472  }
473  else // do not use optimised navigation
474  {
475  noResult = fnormalNav.LevelLocate(fHistory,
478  globalPoint,
479  pGlobalDirection,
480  considerDirection,
481  localPoint);
482  }
483  break;
484  case kReplica:
485  noResult = freplicaNav.LevelLocate(fHistory,
488  globalPoint,
489  pGlobalDirection,
490  considerDirection,
491  localPoint);
492  break;
493  case kParameterised:
494  if( GetDaughtersRegularStructureId(targetLogical) != 1 )
495  {
496  noResult = fparamNav.LevelLocate(fHistory,
499  globalPoint,
500  pGlobalDirection,
501  considerDirection,
502  localPoint);
503  }
504  else // Regular structure
505  {
506  noResult = fregularNav.LevelLocate(fHistory,
509  globalPoint,
510  pGlobalDirection,
511  considerDirection,
512  localPoint);
513  }
514  break;
515  case kExternal:
516  G4Exception("G4ITNavigator1::LocateGlobalPointAndSetup()",
517  "GeomNav0001", FatalException,
518  "Not applicable for external volumes.");
519  break;
520  }
521 
522  // LevelLocate returns true if it finds a daughter volume
523  // in which globalPoint is inside (or on the surface).
524 
525  if ( noResult )
526  {
527  // Entering a daughter after ascending
528  //
529  // The blocked volume is no longer valid - it was for another level
530  //
532  fBlockedReplicaNo = -1;
533 
534  // fEntering should be false -- else blockedVolume is assumed good.
535  // fEnteredDaughter is used for ExitNormal
536  //
537  fEntering = false;
538  fEnteredDaughter = true;
539 
540  if( fExitedMother )
541  {
542  G4VPhysicalVolume* enteredPhysical = fHistory.GetTopVolume();
543  const G4RotationMatrix* mRot = enteredPhysical->GetRotation();
544  if( mRot )
545  {
546  fGrandMotherExitNormal *= (*mRot).inverse();
547  }
548  }
549 
550 #ifdef G4DEBUG_NAVIGATION
551  if( fVerbose > 2 )
552  {
553  G4VPhysicalVolume* enteredPhysical = fHistory.GetTopVolume();
554  G4cout << "*** G4ITNavigator1::LocateGlobalPointAndSetup() ***" << G4endl;
555  G4cout << " Entering volume: " << enteredPhysical->GetName()
556  << G4endl;
557  }
558 #endif
559  }
560  } while (noResult);
561 
562  fLastLocatedPointLocal = localPoint;
563 
564 #ifdef G4VERBOSE
565  if( fVerbose >= 4 )
566  {
567  G4int oldcoutPrec = G4cout.precision(8);
568  G4String curPhysVol_Name("None");
569  if (targetPhysical) { curPhysVol_Name = targetPhysical->GetName(); }
570  G4cout << " Return value = new volume = " << curPhysVol_Name << G4endl;
571  G4cout << " ----- Upon exiting:" << G4endl;
572  PrintState();
573  if( fVerbose == 5 )
574  {
575  G4cout << "Upon exiting LocateGlobalPointAndSetup():" << G4endl;
576  G4cout << " History = " << G4endl << fHistory << G4endl << G4endl;
577  }
578  G4cout.precision(oldcoutPrec);
579  }
580 #endif
581 
582  fLocatedOutsideWorld= false;
583 
584  return targetPhysical;
585 }
586 
587 // ********************************************************************
588 // LocateGlobalPointWithinVolume
589 //
590 // -> the state information of this Navigator and its subNavigators
591 // is updated in order to start the next step at pGlobalpoint
592 // -> no check is performed whether pGlobalpoint is inside the
593 // original volume (this must be the case).
594 //
595 // Note: a direction could be added to the arguments, to aid in future
596 // optional checking (via the old code below, flagged by OLD_LOCATE).
597 // [ This would be done only in verbose mode ]
598 // ********************************************************************
599 //
600 void
602 {
605  fChangedGrandMotherRefFrame= false; // Frame for Exit Normal
606 
607 #ifdef G4DEBUG_NAVIGATION
608  if( fVerbose > 2 )
609  {
610  G4cout << "Entering LocateGlobalWithinVolume(): History = " << G4endl;
611  G4cout << fHistory << G4endl;
612  }
613 #endif
614 
615  // For the case of Voxel (or Parameterised) volume the respective
616  // Navigator must be messaged to update its voxel information etc
617 
618  // Update the state of the Sub Navigators
619  // - in particular any voxel information they store/cache
620  //
621  G4VPhysicalVolume* motherPhysical = fHistory.GetTopVolume();
622  G4LogicalVolume* motherLogical = motherPhysical->GetLogicalVolume();
623  G4SmartVoxelHeader* pVoxelHeader = motherLogical->GetVoxelHeader();
624 
626  {
627  switch( CharacteriseDaughters(motherLogical) )
628  {
629  case kNormal:
630  if ( pVoxelHeader )
631  {
633  }
634  break;
635  case kParameterised:
636  if( GetDaughtersRegularStructureId(motherLogical) != 1 )
637  {
638  // Resets state & returns voxel node
639  //
641  }
642  break;
643  case kReplica:
644  G4Exception("G4ITNavigator1::LocateGlobalPointWithinVolume()",
645  "GeomNav0001", FatalException,
646  "Not applicable for replicated volumes.");
647  break;
648  case kExternal:
649  G4Exception("G4ITNavigator1::LocateGlobalPointWithinVolume()",
650  "GeomNav0001", FatalException,
651  "Not applicable for external volumes.");
652  break;
653  }
654  }
655 
656  // Reset the state variables
657  // - which would have been affected
658  // by the 'equivalent' call to LocateGlobalPointAndSetup
659  // - who's values have been invalidated by the 'move'.
660  //
662  fBlockedReplicaNo = -1;
663  fEntering = false;
664  fEnteredDaughter = false; // Boundary not encountered, did not enter
665  fExiting = false;
666  fExitedMother = false; // Boundary not encountered, did not exit
667 }
668 
669 // !>
671 {
672  SetSavedState();
673  return fpSaveState;
674 }
675 
677 {
678  fpSaveState = (G4SaveNavigatorState*) navState;
679  if(navState) RestoreSavedState();
680 }
681 
683 {
685  ResetState();
686 }
687 
688 
689 // ********************************************************************
690 // SetSavedState
691 //
692 // Save the state, in case this is a parasitic call
693 // Save fValidExitNormal, fExitNormal, fExiting, fEntering,
694 // fBlockedPhysicalVolume, fBlockedReplicaNo, fLastStepWasZero;
695 // ********************************************************************
696 //
698 {
699  // !>
700  // This check can be avoid if instead, at every first step of a track,
701  // the IT tracking uses NewNavigatorSate
702  // The normal tracking would just call once NewNavigatorState() before tracking
703 
704 // if(fpSaveState == 0)
705 // fpSaveState = new G4SaveNavigatorState;
706  // <!
707 
708  // fSaveExitNormal = fExitNormal;
713 
716 
718 
719  // !>
729 
732  // <!
733 }
734 
735 // ********************************************************************
736 // RestoreSavedState
737 //
738 // Restore the state (in Compute Step), in case this is a parasitic call
739 // ********************************************************************
740 //
742 {
747 
750 
752 
753  // !>
763 
766  // <!
767 }
768 // <!
769 
770 // ********************************************************************
771 // ComputeStep
772 //
773 // Computes the next geometric Step: intersections with current
774 // mother and `daughter' volumes.
775 //
776 // NOTE:
777 //
778 // Flags on entry:
779 // --------------
780 // fValidExitNormal - Normal of exited volume is valid (convex, not a
781 // coincident boundary)
782 // fExitNormal - Surface normal of exited volume
783 // fExiting - True if have exited solid
784 //
785 // fBlockedPhysicalVolume - Ptr to exited volume (or 0)
786 // fBlockedReplicaNo - Replication no of exited volume
787 // fLastStepWasZero - True if last Step size was zero.
788 //
789 // Flags on exit:
790 // -------------
791 // fValidExitNormal - True if surface normal of exited volume is valid
792 // fExitNormal - Surface normal of exited volume rotated to mothers
793 // reference system
794 // fExiting - True if exiting mother
795 // fEntering - True if entering `daughter' volume (or replica)
796 // fBlockedPhysicalVolume - Ptr to candidate (entered) volume
797 // fBlockedReplicaNo - Replication no of candidate (entered) volume
798 // fLastStepWasZero - True if this Step size was zero.
799 // ********************************************************************
800 //
802  const G4ThreeVector &pDirection,
803  const G4double pCurrentProposedStepLength,
804  G4double &pNewSafety)
805 {
806  G4ThreeVector localDirection = ComputeLocalAxis(pDirection);
807  G4double Step = kInfinity;
808  G4VPhysicalVolume *motherPhysical = fHistory.GetTopVolume();
809  G4LogicalVolume *motherLogical = motherPhysical->GetLogicalVolume();
810 
811  // All state relating to exiting normals must be reset
812  //
814  // Reset value - to erase its memory
816  // Reset - used for local exit normal
817  fGrandMotherExitNormal= G4ThreeVector( 0., 0., 0.);
818  fCalculatedExitNormal = false;
819  // Reset for new step
820 
821  static G4ThreadLocal G4int sNavCScalls=0;
822  sNavCScalls++;
823 
825 
826 #ifdef G4VERBOSE
827  if( fVerbose > 0 )
828  {
829  G4cout << "*** G4ITNavigator1::ComputeStep: ***" << G4endl;
830  G4cout << " Volume = " << motherPhysical->GetName()
831  << " - Proposed step length = " << pCurrentProposedStepLength
832  << G4endl;
833 #ifdef G4DEBUG_NAVIGATION
834  if( fVerbose >= 2 )
835  {
836  G4cout << " Called with the arguments: " << G4endl
837  << " Globalpoint = " << std::setw(25) << pGlobalpoint << G4endl
838  << " Direction = " << std::setw(25) << pDirection << G4endl;
839  if( fVerbose >= 4 )
840  {
841  G4cout << " ---- Upon entering : State" << G4endl;
842  PrintState();
843  }
844  }
845 #endif
846  }
847 #endif
848 
849  G4ThreeVector newLocalPoint = ComputeLocalPoint(pGlobalpoint);
850  if( newLocalPoint != fLastLocatedPointLocal )
851  {
852  // Check whether the relocation is within safety
853  //
854  G4ThreeVector oldLocalPoint = fLastLocatedPointLocal;
855  G4double moveLenSq = (newLocalPoint-oldLocalPoint).mag2();
856 
857  if ( moveLenSq >= kCarTolerance*kCarTolerance )
858  {
859 #ifdef G4VERBOSE
860  ComputeStepLog(pGlobalpoint, moveLenSq);
861 #endif
862  // Relocate the point within the same volume
863  //
864  LocateGlobalPointWithinVolume( pGlobalpoint );
865  fLastTriedStepComputation= true; // Ensure that this is set again !!
866  }
867  }
869  {
870  switch( CharacteriseDaughters(motherLogical) )
871  {
872  case kNormal:
873  if ( motherLogical->GetVoxelHeader() )
874  {
876  localDirection,
877  pCurrentProposedStepLength,
878  pNewSafety,
879  fHistory,
881  fExitNormal,
882  fExiting,
883  fEntering,
886 
887  }
888  else
889  {
890  if( motherPhysical->GetRegularStructureId() == 0 )
891  {
893  localDirection,
894  pCurrentProposedStepLength,
895  pNewSafety,
896  fHistory,
898  fExitNormal,
899  fExiting,
900  fEntering,
903  }
904  else // Regular (non-voxelised) structure
905  {
906  LocateGlobalPointAndSetup( pGlobalpoint, &pDirection, true, true );
907  fLastTriedStepComputation= true; // Ensure that this is set again !!
908  //
909  // if physical process limits the step, the voxel will not be the
910  // one given by ComputeStepSkippingEqualMaterials() and the local
911  // point will be wrongly calculated.
912 
913  // There is a problem: when msc limits the step and the point is
914  // assigned wrongly to phantom in previous step (while it is out
915  // of the container volume). Then LocateGlobalPointAndSetup() has
916  // reset the history topvolume to world.
917  //
919  {
920  G4Exception("G4ITNavigator1::ComputeStep()",
921  "GeomNav1001", JustWarning,
922  "Point is relocated in voxels, while it should be outside!");
924  localDirection,
925  pCurrentProposedStepLength,
926  pNewSafety,
927  fHistory,
929  fExitNormal,
930  fExiting,
931  fEntering,
934  }
935  else
936  {
937  Step = fregularNav.
938  ComputeStepSkippingEqualMaterials(fLastLocatedPointLocal,
939  localDirection,
940  pCurrentProposedStepLength,
941  pNewSafety,
942  fHistory,
944  fExitNormal,
945  fExiting,
946  fEntering,
949  motherPhysical);
950  }
951  }
952  }
953  break;
954  case kParameterised:
955  if( GetDaughtersRegularStructureId(motherLogical) != 1 )
956  {
958  localDirection,
959  pCurrentProposedStepLength,
960  pNewSafety,
961  fHistory,
963  fExitNormal,
964  fExiting,
965  fEntering,
968  }
969  else // Regular structure
970  {
972  localDirection,
973  pCurrentProposedStepLength,
974  pNewSafety,
975  fHistory,
977  fExitNormal,
978  fExiting,
979  fEntering,
982  }
983  break;
984  case kReplica:
985  G4Exception("G4ITNavigator1::ComputeStep()", "GeomNav0001",
986  FatalException, "Not applicable for replicated volumes.");
987  break;
988  case kExternal:
989  G4Exception("G4ITNavigator1::ComputeStep()", "GeomNav0001",
990  FatalException, "Not applicable for external volumes.");
991  break;
992  }
993  }
994  else
995  {
996  // In the case of a replica, it must handle the exiting
997  // edge/corner problem by itself
998  //
999  G4bool exitingReplica = fExitedMother;
1000  G4bool calculatedExitNormal= false;
1001 
1002  Step = freplicaNav.ComputeStep(pGlobalpoint,
1003  pDirection,
1005  localDirection,
1006  pCurrentProposedStepLength,
1007  pNewSafety,
1008  fHistory,
1010  calculatedExitNormal,
1011  fExitNormal,
1012  exitingReplica,
1013  fEntering,
1016  fExiting= exitingReplica;
1017  fCalculatedExitNormal= calculatedExitNormal;
1018  }
1019 
1020  // Remember last safety origin & value.
1021  //
1022  fPreviousSftOrigin = pGlobalpoint;
1023  fPreviousSafety = pNewSafety;
1024 
1025  // Count zero steps - one can occur due to changing momentum at a boundary
1026  // - one, two (or a few) can occur at common edges between
1027  // volumes
1028  // - more than two is likely a problem in the geometry
1029  // description or the Navigation
1030 
1031  // Rule of thumb: likely at an Edge if two consecutive steps are zero,
1032  // because at least two candidate volumes must have been
1033  // checked
1034  //
1035  fLocatedOnEdge = fLastStepWasZero && (Step==0.0);
1036  fLastStepWasZero = (Step==0.0);
1037  if (fPushed) { fPushed = fLastStepWasZero; }
1038 
1039  // Handle large number of consecutive zero steps
1040  //
1041  if ( fLastStepWasZero )
1042  {
1043  fNumberZeroSteps++;
1044 #ifdef G4DEBUG_NAVIGATION
1045  if( fNumberZeroSteps > 1 )
1046  {
1047  G4cout << "G4ITNavigator1::ComputeStep(): another zero step, # "
1048  << fNumberZeroSteps
1049  << " at " << pGlobalpoint
1050  << " in volume " << motherPhysical->GetName()
1051  << " nav-comp-step calls # " << sNavCScalls
1052  << G4endl;
1053  }
1054 #endif
1056  {
1057  // Act to recover this stuck track. Pushing it along direction
1058  //
1059  Step += 100*kCarTolerance;
1060 #ifdef G4VERBOSE
1061  if ((!fPushed) && (fWarnPush))
1062  {
1063  std::ostringstream message;
1064  message << "Track stuck or not moving." << G4endl
1065  << " Track stuck, not moving for "
1066  << fNumberZeroSteps << " steps" << G4endl
1067  << " in volume -" << motherPhysical->GetName()
1068  << "- at point " << pGlobalpoint << G4endl
1069  << " direction: " << pDirection << "." << G4endl
1070  << " Potential geometry or navigation problem !"
1071  << G4endl
1072  << " Trying pushing it of " << Step << " mm ...";
1073  G4Exception("G4ITNavigator1::ComputeStep()", "GeomNav1002",
1074  JustWarning, message, "Potential overlap in geometry!");
1075  }
1076 #endif
1077  fPushed = true;
1078  }
1080  {
1081  // Must kill this stuck track
1082  //
1083  std::ostringstream message;
1084  message << "Stuck Track: potential geometry or navigation problem."
1085  << G4endl
1086  << " Track stuck, not moving for "
1087  << fNumberZeroSteps << " steps" << G4endl
1088  << " in volume -" << motherPhysical->GetName()
1089  << "- at point " << pGlobalpoint << G4endl
1090  << " direction: " << pDirection << ".";
1091  motherPhysical->CheckOverlaps(5000, false);
1092  G4Exception("G4ITNavigator1::ComputeStep()", "GeomNav0003",
1093  EventMustBeAborted, message);
1094  }
1095  }
1096  else
1097  {
1098  if (!fPushed) fNumberZeroSteps = 0;
1099  }
1100 
1101  fEnteredDaughter = fEntering; // I expect to enter a volume in this Step
1103 
1104  fStepEndPoint = pGlobalpoint + Step * pDirection;
1105  fLastStepEndPointLocal = fLastLocatedPointLocal + Step * localDirection;
1106 
1107  if( fExiting )
1108  {
1109 #ifdef G4DEBUG_NAVIGATION
1110  if( fVerbose > 2 )
1111  {
1112  G4cout << " At G4Nav CompStep End - if(exiting) - fExiting= " << fExiting
1113  << " fValidExitNormal = " << fValidExitNormal << G4endl;
1114  G4cout << " fExitNormal= " << fExitNormal << G4endl;
1115  }
1116 #endif
1117 
1119  {
1121  {
1122  // Convention: fExitNormal is in the 'grand-mother' coordinate system
1123  //
1125  fCalculatedExitNormal= true;
1126  }
1127  else
1128  {
1130  }
1131  }
1132  else
1133  {
1134  // We must calculate the normal anyway (in order to have it if requested)
1135  //
1136  G4ThreeVector finalLocalPoint =
1137  fLastLocatedPointLocal + localDirection*Step;
1138 
1140  {
1141  // Find normal in the 'mother' coordinate system
1142  //
1143  G4ThreeVector exitNormalMotherFrame=
1144  motherLogical->GetSolid()->SurfaceNormal(finalLocalPoint);
1145 
1146  // Transform it to the 'grand-mother' coordinate system
1147  //
1148  const G4RotationMatrix* mRot = motherPhysical->GetRotation();
1149  if( mRot )
1150  {
1152  fGrandMotherExitNormal = (*mRot).inverse() * exitNormalMotherFrame;
1153  }
1154  else
1155  {
1156  fGrandMotherExitNormal = exitNormalMotherFrame;
1157  }
1158 
1159  // Do not set fValidExitNormal -- this signifies
1160  // that the solid is convex!
1161  //
1162  fCalculatedExitNormal= true;
1163  }
1164  else
1165  {
1166  fCalculatedExitNormal = false;
1167  //
1168  // Nothing can be done at this stage currently - to solve this
1169  // Replica Navigation must have calculated the normal for this case
1170  // already.
1171  // Cases: mother is not convex, and exit is at previous replica level
1172 
1173 #ifdef G4DEBUG_NAVIGATION
1175 
1176  desc << "Problem in ComputeStep: Replica Navigation did not provide"
1177  << " valid exit Normal. " << G4endl;
1178  desc << " Do not know how calculate it in this case." << G4endl;
1179  desc << " Location = " << finalLocalPoint << G4endl;
1180  desc << " Volume name = " << motherPhysical->GetName()
1181  << " copy/replica No = " << motherPhysical->GetCopyNo() << G4endl;
1182  G4Exception("G4ITNavigator1::ComputeStep()", "GeomNav0003",
1183  JustWarning, desc, "Normal not available for exiting.");
1184 #endif
1185  }
1186  }
1187 
1188  // Now transform it to the global reference frame !!
1189  //
1191  {
1192  G4int depth= fHistory.GetDepth();
1193  if( depth > 0 )
1194  {
1195  G4AffineTransform GrandMotherToGlobalTransf =
1196  fHistory.GetTransform(depth-1).Inverse();
1198  GrandMotherToGlobalTransf.TransformAxis( fGrandMotherExitNormal );
1199  }
1200  else
1201  {
1203  }
1204  }
1205  else
1206  {
1207  fExitNormalGlobalFrame= G4ThreeVector( 0., 0., 0.);
1208  }
1209  }
1210  fStepEndPoint= pGlobalpoint+Step*pDirection;
1211 
1212  if( (Step == pCurrentProposedStepLength) && (!fExiting) && (!fEntering) )
1213  {
1214  // This if Step is not really limited by the geometry.
1215  // The Navigator is obliged to return "infinity"
1216  //
1217  Step = kInfinity;
1218  }
1219 
1220 #ifdef G4VERBOSE
1221  if( fVerbose > 1 )
1222  {
1223  if( fVerbose >= 4 )
1224  {
1225  G4cout << " ----- Upon exiting :" << G4endl;
1226  PrintState();
1227  }
1228  G4cout << " Returned step= " << Step;
1229  if( fVerbose > 5 ) G4cout << G4endl;
1230  if( Step == kInfinity )
1231  {
1232  G4cout << " Requested step= " << pCurrentProposedStepLength ;
1233  if( fVerbose > 5) G4cout << G4endl;
1234  }
1235  G4cout << " Safety = " << pNewSafety << G4endl;
1236  }
1237 #endif
1238 
1239  return Step;
1240 }
1241 
1242 // ********************************************************************
1243 // CheckNextStep
1244 //
1245 // Compute the step without altering the navigator state
1246 // ********************************************************************
1247 //
1249  const G4ThreeVector& pDirection,
1250  const G4double pCurrentProposedStepLength,
1251  G4double& pNewSafety)
1252 {
1253  G4double step;
1254 
1255  // Save the state, for this parasitic call
1256  //
1257  SetSavedState();
1258 
1259  step = ComputeStep ( pGlobalpoint,
1260  pDirection,
1261  pCurrentProposedStepLength,
1262  pNewSafety );
1263 
1264  // If a parasitic call, then attempt to restore the key parts of the state
1265  //
1266  RestoreSavedState();
1267 
1268  return step;
1269 }
1270 
1271 // ********************************************************************
1272 // ResetState
1273 //
1274 // Resets stack and minimum of navigator state `machine'
1275 // ********************************************************************
1276 //
1278 {
1279  fWasLimitedByGeometry = false;
1280  fEntering = false;
1281  fExiting = false;
1282  fLocatedOnEdge = false;
1283  fLastStepWasZero = false;
1284  fEnteredDaughter = false;
1285  fExitedMother = false;
1286  fPushed = false;
1287 
1288  fValidExitNormal = false;
1290  fCalculatedExitNormal = false;
1291 
1292  fExitNormal = G4ThreeVector(0,0,0);
1295 
1297  fPreviousSafety = 0.0;
1298 
1299  fNumberZeroSteps = 0;
1300 
1302  fBlockedReplicaNo = -1;
1303 
1305  fLocatedOutsideWorld = false;
1306 }
1307 
1308 // ********************************************************************
1309 // SetupHierarchy
1310 //
1311 // Renavigates & resets hierarchy described by current history
1312 // o Reset volumes
1313 // o Recompute transforms and/or solids of replicated/parameterised volumes
1314 // ********************************************************************
1315 //
1317 {
1318  G4int i;
1319  const G4int cdepth = fHistory.GetDepth();
1320  G4VPhysicalVolume *current;
1321  G4VSolid *pSolid;
1322  G4VPVParameterisation *pParam;
1323 
1324  for ( i=1; i<=cdepth; i++ )
1325  {
1326  current = fHistory.GetVolume(i);
1327  switch ( fHistory.GetVolumeType(i) )
1328  {
1329  case kNormal:
1330  break;
1331  case kReplica:
1333  break;
1334  case kParameterised: {
1335  G4int replicaNo;
1336  pParam = current->GetParameterisation();
1337  replicaNo = fHistory.GetReplicaNo(i);
1338  pSolid = pParam->ComputeSolid(replicaNo, current);
1339 
1340  // Set up dimensions & transform in solid/physical volume
1341  //
1342  pSolid->ComputeDimensions(pParam, replicaNo, current);
1343  pParam->ComputeTransformation(replicaNo, current);
1344 
1345  G4TouchableHistory touchable( fHistory );
1346  touchable.MoveUpHistory(); // move up to the parent level
1347 
1348  // Set up the correct solid and material in Logical Volume
1349  //
1350  G4LogicalVolume *pLogical = current->GetLogicalVolume();
1351  pLogical->SetSolid( pSolid );
1352  pLogical->UpdateMaterial( pParam ->
1353  ComputeMaterial(replicaNo, current, &touchable) );
1354  break;
1355  }
1356  case kExternal:
1357  G4Exception("G4ITNavigator1::SetupHierarchy()",
1358  "GeomNav0001", FatalException,
1359  "Not applicable for external volumes.");
1360  break;
1361  }
1362  }
1363 }
1364 
1365 // ********************************************************************
1366 // GetLocalExitNormal
1367 //
1368 // Obtains the Normal vector to a surface (in local coordinates)
1369 // pointing out of previous volume and into current volume
1370 // ********************************************************************
1371 //
1373 {
1374  G4ThreeVector ExitNormal(0.,0.,0.);
1375  G4VSolid *currentSolid=0;
1376  G4LogicalVolume *candidateLogical;
1378  {
1379  // use fLastLocatedPointLocal and next candidate volume
1380  //
1381  G4ThreeVector nextSolidExitNormal(0.,0.,0.);
1382 
1383  if( fEntering && (fBlockedPhysicalVolume!=0) )
1384  {
1385  candidateLogical= fBlockedPhysicalVolume->GetLogicalVolume();
1386  if( candidateLogical )
1387  {
1388  // fLastStepEndPointLocal is in the coordinates of the mother
1389  // we need it in the daughter's coordinate system.
1390 
1391  // The following code should also work in case of Replica
1392  {
1393  // First transform fLastLocatedPointLocal to the new daughter
1394  // coordinates
1395  //
1396  G4AffineTransform MotherToDaughterTransform=
1400  G4ThreeVector daughterPointOwnLocal=
1401  MotherToDaughterTransform.TransformPoint( fLastStepEndPointLocal );
1402 
1403  // OK if it is a parameterised volume
1404  //
1405  EInside inSideIt;
1406  G4bool onSurface;
1407  G4double safety= -1.0;
1408  currentSolid= candidateLogical->GetSolid();
1409  inSideIt = currentSolid->Inside(daughterPointOwnLocal);
1410  onSurface = (inSideIt == kSurface);
1411  if( ! onSurface )
1412  {
1413  if( inSideIt == kOutside )
1414  {
1415  safety = (currentSolid->DistanceToIn(daughterPointOwnLocal));
1416  onSurface = safety < 100.0 * kCarTolerance;
1417  }
1418  else if (inSideIt == kInside )
1419  {
1420  safety = (currentSolid->DistanceToOut(daughterPointOwnLocal));
1421  onSurface = safety < 100.0 * kCarTolerance;
1422  }
1423  }
1424 
1425  if( onSurface )
1426  {
1427  nextSolidExitNormal =
1428  currentSolid->SurfaceNormal(daughterPointOwnLocal);
1429 
1430  // Entering the solid ==> opposite
1431  //
1432  ExitNormal = -nextSolidExitNormal;
1433  fCalculatedExitNormal= true;
1434  }
1435  else
1436  {
1437 #ifdef G4VERBOSE
1438  if(( fVerbose == 1 ) && ( fCheck ))
1439  {
1440  std::ostringstream message;
1441  message << "Point not on surface ! " << G4endl
1442  << " Point = "
1443  << daughterPointOwnLocal << G4endl
1444  << " Physical volume = "
1446  << " Logical volume = "
1447  << candidateLogical->GetName() << G4endl
1448  << " Solid = " << currentSolid->GetName()
1449  << " Type = "
1450  << currentSolid->GetEntityType() << G4endl
1451  << *currentSolid << G4endl;
1452  if( inSideIt == kOutside )
1453  {
1454  message << "Point is Outside. " << G4endl
1455  << " Safety (from outside) = " << safety << G4endl;
1456  }
1457  else // if( inSideIt == kInside )
1458  {
1459  message << "Point is Inside. " << G4endl
1460  << " Safety (from inside) = " << safety << G4endl;
1461  }
1462  G4Exception("G4ITNavigator1::GetLocalExitNormal()", "GeomNav1001",
1463  JustWarning, message);
1464  }
1465 #endif
1466  }
1467  *valid = onSurface; // was =true;
1468  }
1469  }
1470  }
1471  else if ( fExiting )
1472  {
1473  ExitNormal = fGrandMotherExitNormal;
1474  *valid = true;
1475  fCalculatedExitNormal= true; // Should be true already
1476  }
1477  else // i.e. ( fBlockedPhysicalVolume == 0 )
1478  {
1479  *valid = false;
1480  G4Exception("G4ITNavigator1::GetLocalExitNormal()",
1481  "GeomNav0003", JustWarning,
1482  "Incorrect call to GetLocalSurfaceNormal." );
1483  }
1484  }
1485  else // ( ! fLastTriedStepComputation ) ie. last call was to Locate
1486  {
1487  if ( EnteredDaughterVolume() )
1488  {
1489  G4VSolid* daughterSolid =fHistory.GetTopVolume()->GetLogicalVolume()
1490  ->GetSolid();
1491  ExitNormal= -(daughterSolid->SurfaceNormal(fLastLocatedPointLocal));
1492  if( std::fabs(ExitNormal.mag2()-1.0 ) > CLHEP::perMillion )
1493  {
1495  desc << " Parameters of solid: " << *daughterSolid
1496  << " Point for surface = " << fLastLocatedPointLocal << std::endl;
1497  G4Exception("G4ITNavigator1::GetLocalExitNormal()",
1498  "GeomNav0003", FatalException, desc,
1499  "Surface Normal returned by Solid is not a Unit Vector." );
1500  }
1501  fCalculatedExitNormal= true;
1502  *valid = true;
1503  }
1504  else
1505  {
1506  if( fExitedMother )
1507  {
1508  ExitNormal = fGrandMotherExitNormal;
1509  *valid = true;
1510  fCalculatedExitNormal= true;
1511  }
1512  else // We are not at a boundary. ExitNormal remains (0,0,0)
1513  {
1514  *valid = false;
1515  fCalculatedExitNormal= false;
1517  message << "Function called when *NOT* at a Boundary." << G4endl;
1518  G4Exception("G4ITNavigator1::GetLocalExitNormal()",
1519  "GeomNav0003", JustWarning, message);
1520  }
1521  }
1522  }
1523  return ExitNormal;
1524 }
1525 
1526 // ********************************************************************
1527 // GetMotherToDaughterTransform
1528 //
1529 // Obtains the mother to daughter affine transformation
1530 // ********************************************************************
1531 //
1534  G4int enteringReplicaNo,
1535  EVolume enteringVolumeType )
1536 {
1537  switch (enteringVolumeType)
1538  {
1539  case kNormal: // Nothing is needed to prepare the transformation
1540  break; // It is stored already in the physical volume (placement)
1541  case kReplica: // Sets the transform in the Replica - tbc
1542  G4Exception("G4ITNavigator1::GetMotherToDaughterTransform()",
1543  "GeomNav0001", FatalException,
1544  "Method NOT Implemented yet for replica volumes.");
1545  break;
1546  case kParameterised:
1547  if( pEnteringPhysVol->GetRegularStructureId() == 0 )
1548  {
1549  G4VPVParameterisation *pParam =
1550  pEnteringPhysVol->GetParameterisation();
1551  G4VSolid* pSolid =
1552  pParam->ComputeSolid(enteringReplicaNo, pEnteringPhysVol);
1553  pSolid->ComputeDimensions(pParam, enteringReplicaNo, pEnteringPhysVol);
1554 
1555  // Sets the transform in the Parameterisation
1556  //
1557  pParam->ComputeTransformation(enteringReplicaNo, pEnteringPhysVol);
1558 
1559  // Set the correct solid and material in Logical Volume
1560  //
1561  G4LogicalVolume* pLogical = pEnteringPhysVol->GetLogicalVolume();
1562  pLogical->SetSolid( pSolid );
1563  }
1564  break;
1565  case kExternal:
1566  G4Exception("G4ITNavigator1::GetMotherToDaughterTransform()",
1567  "GeomNav0001", FatalException,
1568  "Not applicable for external volumes.");
1569  break;
1570  }
1571  return G4AffineTransform(pEnteringPhysVol->GetRotation(),
1572  pEnteringPhysVol->GetTranslation()).Invert();
1573 }
1574 
1575 // ********************************************************************
1576 // GetLocalExitNormalAndCheck
1577 //
1578 // Obtains the Normal vector to a surface (in local coordinates)
1579 // pointing out of previous volume and into current volume, and
1580 // checks the current point against expected 'local' value.
1581 // ********************************************************************
1582 //
1585 #ifdef G4DEBUG_NAVIGATION
1586  const G4ThreeVector& ExpectedBoundaryPointGlobal,
1587 #else
1588  const G4ThreeVector&,
1589 #endif
1590  G4bool* pValid)
1591 {
1592 #ifdef G4DEBUG_NAVIGATION
1593  // Check Current point against expected 'local' value
1594  //
1596  {
1597  G4ThreeVector ExpectedBoundaryPointLocal;
1598 
1599  const G4AffineTransform& GlobalToLocal= GetGlobalToLocalTransform();
1600  ExpectedBoundaryPointLocal =
1601  GlobalToLocal.TransformPoint( ExpectedBoundaryPointGlobal );
1602 
1603  // Add here: Comparison against expected position,
1604  // i.e. the endpoint of ComputeStep
1605  }
1606 #endif
1607 
1608  return GetLocalExitNormal( pValid);
1609 }
1610 
1611 // ********************************************************************
1612 // GetGlobalExitNormal
1613 //
1614 // Obtains the Normal vector to a surface (in global coordinates)
1615 // pointing out of previous volume and into current volume
1616 // ********************************************************************
1617 //
1620  G4bool* pNormalCalculated)
1621 {
1622  G4bool validNormal;
1623  G4ThreeVector localNormal, globalNormal;
1624 
1626  {
1627  // This was computed in ComputeStep -- and only on arrival at boundary
1628  //
1629  globalNormal = fExitNormalGlobalFrame;
1630  *pNormalCalculated = true; // ComputeStep always computes it if Exiting
1631  // (fExiting==true)
1632  }
1633  else
1634  {
1635  localNormal = GetLocalExitNormalAndCheck(IntersectPointGlobal,&validNormal);
1636  *pNormalCalculated = fCalculatedExitNormal;
1637 
1638 #ifdef G4DEBUG_NAVIGATION
1639  if( (!validNormal) && !fCalculatedExitNormal)
1640  {
1642  edN << " Calculated = " << fCalculatedExitNormal << G4endl;
1643  edN << " Entering= " << fEntering << G4endl;
1644  G4int oldVerbose= this->GetVerboseLevel();
1645  this->SetVerboseLevel(4);
1646  edN << " State of Navigator: " << G4endl;
1647  edN << *this << G4endl;
1648  this->SetVerboseLevel( oldVerbose );
1649 
1650  G4Exception("G4ITNavigator1::GetGlobalExitNormal()",
1651  "GeomNav0003", JustWarning, edN,
1652  "LocalExitNormalAndCheck() did not calculate Normal.");
1653  }
1654 #endif
1655 
1656  G4double localMag2= localNormal.mag2();
1657  if( validNormal && (std::fabs(localMag2-1.0)) > CLHEP::perMillion )
1658  {
1660 
1661  edN << "G4ITNavigator1::GetGlobalExitNormal: "
1662  << " Using Local Normal - from call to GetLocalExitNormalAndCheck. "
1663  << G4endl
1664  << " Local Exit Normal = " << localNormal << " || = "
1665  << std::sqrt(localMag2) << G4endl
1666  << " Global Exit Normal = " << globalNormal << " || = "
1667  << globalNormal.mag() << G4endl;
1668  edN << " Calculated It = " << fCalculatedExitNormal << G4endl;
1669 
1670  G4Exception("G4ITNavigator1::GetGlobalExitNormal()",
1671  "GeomNav0003",JustWarning, edN,
1672  "Value obtained from new local *solid* is incorrect.");
1673  localNormal = localNormal.unit(); // Should we correct it ??
1674  }
1675  G4AffineTransform localToGlobal = GetLocalToGlobalTransform();
1676  globalNormal = localToGlobal.TransformAxis( localNormal );
1677  }
1678 
1679 #ifdef G4DEBUG_NAVIGATION
1680  // Temporary extra checks
1682  {
1683  localNormal = GetLocalExitNormalAndCheck( IntersectPointGlobal, &validNormal);
1684  *pNormalCalculated = fCalculatedExitNormal;
1685 
1686  G4AffineTransform localToGlobal = GetLocalToGlobalTransform();
1687  globalNormal = localToGlobal.TransformAxis( localNormal );
1688 
1689  // Check the value computed against fExitNormalGlobalFrame
1690  G4ThreeVector diffNorm = globalNormal - fExitNormalGlobalFrame;
1691  if( diffNorm.mag2() > perMillion*CLHEP::perMillion)
1692  {
1693  G4ExceptionDescription edDfn;
1694  edDfn << "Found difference in normals in case of exiting mother "
1695  << "- when Get is called after ComputingStep " << G4endl;
1696  edDfn << " Magnitude of diff = " << diffNorm.mag() << G4endl;
1697  edDfn << " Normal stored (Global) = " << fExitNormalGlobalFrame
1698  << G4endl;
1699  edDfn << " Global Computed from Local = " << globalNormal << G4endl;
1700  G4Exception("G4ITNavigator1::GetGlobalExitNormal()", "GeomNav0003",
1701  JustWarning, edDfn);
1702  }
1703  }
1704 #endif
1705 
1706  return globalNormal;
1707 }
1708 
1709 // To make the new Voxel Safety the default, uncomment the next line
1710 #define G4NEW_SAFETY 1
1711 
1712 // ********************************************************************
1713 // ComputeSafety
1714 //
1715 // It assumes that it will be
1716 // i) called at the Point in the same volume as the EndPoint of the
1717 // ComputeStep.
1718 // ii) after (or at the end of) ComputeStep OR after the relocation.
1719 // ********************************************************************
1720 //
1722  const G4double pMaxLength,
1723  const G4bool keepState)
1724 {
1725  G4double newSafety = 0.0;
1726 
1727 #ifdef G4DEBUG_NAVIGATION
1728  G4int oldcoutPrec = G4cout.precision(8);
1729  if( fVerbose > 0 )
1730  {
1731  G4cout << "*** G4ITNavigator1::ComputeSafety: ***" << G4endl
1732  << " Called at point: " << pGlobalpoint << G4endl;
1733 
1734  G4VPhysicalVolume *motherPhysical = fHistory.GetTopVolume();
1735  G4cout << " Volume = " << motherPhysical->GetName()
1736  << " - Maximum length = " << pMaxLength << G4endl;
1737  if( fVerbose >= 4 )
1738  {
1739  G4cout << " ----- Upon entering Compute Safety:" << G4endl;
1740  PrintState();
1741  }
1742  }
1743 #endif
1744 
1745  if (keepState) { SetSavedState(); }
1746 
1747  G4double distEndpointSq = (pGlobalpoint-fStepEndPoint).mag2();
1748  G4bool stayedOnEndpoint = distEndpointSq < kCarTolerance*kCarTolerance;
1749  G4bool endpointOnSurface = fEnteredDaughter || fExitedMother;
1750 
1751  if( !(endpointOnSurface && stayedOnEndpoint) )
1752  {
1753  // Pseudo-relocate to this point (updates voxel information only)
1754  //
1755  LocateGlobalPointWithinVolume( pGlobalpoint );
1756  // --->> DANGER: Side effects on sub-navigator voxel information <<---
1757  // Could be replaced again by 'granular' calls to sub-navigator
1758  // locates (similar side-effects, but faster.
1759  // Solutions:
1760  // 1) Re-locate (to where?)
1761  // 2) Insure that the methods using (G4ComputeStep?)
1762  // does a relocation (if information is disturbed only ?)
1763 
1764 #ifdef G4DEBUG_NAVIGATION
1765  if( fVerbose >= 2 )
1766  {
1767  G4cout << " G4ITNavigator1::ComputeSafety() relocates-in-volume to point: "
1768  << pGlobalpoint << G4endl;
1769  }
1770 #endif
1771  G4VPhysicalVolume *motherPhysical = fHistory.GetTopVolume();
1772  G4LogicalVolume *motherLogical = motherPhysical->GetLogicalVolume();
1773  G4SmartVoxelHeader* pVoxelHeader = motherLogical->GetVoxelHeader();
1774  G4ThreeVector localPoint = ComputeLocalPoint(pGlobalpoint);
1775 
1777  {
1778  switch(CharacteriseDaughters(motherLogical))
1779  {
1780  case kNormal:
1781  if ( pVoxelHeader )
1782  {
1783 #ifdef G4NEW_SAFETY
1784  G4double safetyTwo = fpVoxelSafety->ComputeSafety(localPoint,
1785  *motherPhysical, pMaxLength);
1786  newSafety= safetyTwo; // Faster and best available
1787 #else
1788  G4double safetyOldVoxel;
1789  safetyOldVoxel =
1790  fvoxelNav.ComputeSafety(localPoint,fHistory,pMaxLength);
1791  newSafety= safetyOldVoxel;
1792 #endif
1793  }
1794  else
1795  {
1796  newSafety=fnormalNav.ComputeSafety(localPoint,fHistory,pMaxLength);
1797  }
1798  break;
1799  case kParameterised:
1800  if( GetDaughtersRegularStructureId(motherLogical) != 1 )
1801  {
1802  newSafety=fparamNav.ComputeSafety(localPoint,fHistory,pMaxLength);
1803  }
1804  else // Regular structure
1805  {
1806  newSafety=fregularNav.ComputeSafety(localPoint,fHistory,pMaxLength);
1807  }
1808  break;
1809  case kReplica:
1810  G4Exception("G4ITNavigator1::ComputeSafety()", "GeomNav0001",
1811  FatalException, "Not applicable for replicated volumes.");
1812  break;
1813  case kExternal:
1814  G4Exception("G4ITNavigator1::ComputeSafety()",
1815  "GeomNav0001", FatalException,
1816  "Not applicable for external volumes.");
1817  break;
1818  }
1819  }
1820  else
1821  {
1822  newSafety = freplicaNav.ComputeSafety(pGlobalpoint, localPoint,
1823  fHistory, pMaxLength);
1824  }
1825  }
1826  else // if( endpointOnSurface && stayedOnEndpoint )
1827  {
1828 #ifdef G4DEBUG_NAVIGATION
1829  if( fVerbose >= 2 )
1830  {
1831  G4cout << " G4ITNavigator1::ComputeSafety() finds that point - "
1832  << pGlobalpoint << " - is on surface " << G4endl;
1833  if( fEnteredDaughter ) { G4cout << " entered new daughter volume"; }
1834  if( fExitedMother ) { G4cout << " and exited previous volume."; }
1835  G4cout << G4endl;
1836  G4cout << " EndPoint was = " << fStepEndPoint << G4endl;
1837  }
1838 #endif
1839  newSafety = 0.0;
1840  }
1841 
1842  // Remember last safety origin & value
1843  //
1844  fPreviousSftOrigin = pGlobalpoint;
1845  fPreviousSafety = newSafety;
1846 
1847  if (keepState) { RestoreSavedState(); }
1848 
1849 #ifdef G4DEBUG_NAVIGATION
1850  if( fVerbose > 1 )
1851  {
1852  G4cout << " ---- Exiting ComputeSafety " << G4endl;
1853  if( fVerbose > 2 ) { PrintState(); }
1854  G4cout << " Returned value of Safety = " << newSafety << G4endl;
1855  }
1856  G4cout.precision(oldcoutPrec);
1857 #endif
1858 
1859  return newSafety;
1860 }
1861 
1862 // ********************************************************************
1863 // CreateTouchableHistoryHandle
1864 // ********************************************************************
1865 //
1867 {
1869 }
1870 
1871 // ********************************************************************
1872 // PrintState
1873 // ********************************************************************
1874 //
1876 {
1877  G4int oldcoutPrec = G4cout.precision(4);
1878  if( fVerbose == 4 )
1879  {
1880  G4cout << "The current state of G4ITNavigator1 is: " << G4endl;
1881  G4cout << " ValidExitNormal= " << fValidExitNormal << G4endl
1882  << " ExitNormal = " << fExitNormal << G4endl
1883  << " Exiting = " << fExiting << G4endl
1884  << " Entering = " << fEntering << G4endl
1885  << " BlockedPhysicalVolume= " ;
1886  if (fBlockedPhysicalVolume==0)
1887  G4cout << "None";
1888  else
1890  G4cout << G4endl
1891  << " BlockedReplicaNo = " << fBlockedReplicaNo << G4endl
1892  << " LastStepWasZero = " << fLastStepWasZero << G4endl
1893  << G4endl;
1894  }
1895  if( ( 1 < fVerbose) && (fVerbose < 4) )
1896  {
1897  G4cout << G4endl; // Make sure to line up
1898  G4cout << std::setw(30) << " ExitNormal " << " "
1899  << std::setw( 5) << " Valid " << " "
1900  << std::setw( 9) << " Exiting " << " "
1901  << std::setw( 9) << " Entering" << " "
1902  << std::setw(15) << " Blocked:Volume " << " "
1903  << std::setw( 9) << " ReplicaNo" << " "
1904  << std::setw( 8) << " LastStepZero " << " "
1905  << G4endl;
1906  G4cout << "( " << std::setw(7) << fExitNormal.x()
1907  << ", " << std::setw(7) << fExitNormal.y()
1908  << ", " << std::setw(7) << fExitNormal.z() << " ) "
1909  << std::setw( 5) << fValidExitNormal << " "
1910  << std::setw( 9) << fExiting << " "
1911  << std::setw( 9) << fEntering << " ";
1912  if ( fBlockedPhysicalVolume==0 )
1913  {
1914  G4cout << std::setw(15) << "None";
1915  }
1916  else
1917  {
1918  G4cout << std::setw(15)<< fBlockedPhysicalVolume->GetName();
1919  }
1920  G4cout << std::setw( 9) << fBlockedReplicaNo << " "
1921  << std::setw( 8) << fLastStepWasZero << " "
1922  << G4endl;
1923  }
1924  if( fVerbose > 2 )
1925  {
1926  G4cout.precision(8);
1927  G4cout << " Current Localpoint = " << fLastLocatedPointLocal << G4endl;
1928  G4cout << " PreviousSftOrigin = " << fPreviousSftOrigin << G4endl;
1929  G4cout << " PreviousSafety = " << fPreviousSafety << G4endl;
1930  }
1931  G4cout.precision(oldcoutPrec);
1932 }
1933 
1934 // ********************************************************************
1935 // ComputeStepLog
1936 // ********************************************************************
1937 //
1939  G4double moveLenSq) const
1940 {
1941  // The following checks only make sense if the move is larger
1942  // than the tolerance.
1943 
1944  static const G4double fAccuracyForWarning = kCarTolerance,
1945  fAccuracyForException = 1000*kCarTolerance;
1946 
1947  G4ThreeVector OriginalGlobalpoint = fHistory.GetTopTransform().Inverse().
1948  TransformPoint(fLastLocatedPointLocal);
1949 
1950  G4double shiftOriginSafSq = (fPreviousSftOrigin-pGlobalpoint).mag2();
1951 
1952  // Check that the starting point of this step is
1953  // within the isotropic safety sphere of the last point
1954  // to a accuracy/precision given by fAccuracyForWarning.
1955  // If so give warning.
1956  // If it fails by more than fAccuracyForException exit with error.
1957  //
1958  if( shiftOriginSafSq >= sqr(fPreviousSafety) )
1959  {
1960  G4double shiftOrigin = std::sqrt(shiftOriginSafSq);
1961  G4double diffShiftSaf = shiftOrigin - fPreviousSafety;
1962 
1963  if( diffShiftSaf > fAccuracyForWarning )
1964  {
1965  G4int oldcoutPrec= G4cout.precision(8);
1966  G4int oldcerrPrec= G4cerr.precision(10);
1967  std::ostringstream message, suggestion;
1968  message << "Accuracy error or slightly inaccurate position shift."
1969  << G4endl
1970  << " The Step's starting point has moved "
1971  << std::sqrt(moveLenSq)/mm << " mm " << G4endl
1972  << " since the last call to a Locate method." << G4endl
1973  << " This has resulted in moving "
1974  << shiftOrigin/mm << " mm "
1975  << " from the last point at which the safety "
1976  << " was calculated " << G4endl
1977  << " which is more than the computed safety= "
1978  << fPreviousSafety/mm << " mm at that point." << G4endl
1979  << " This difference is "
1980  << diffShiftSaf/mm << " mm." << G4endl
1981  << " The tolerated accuracy is "
1982  << fAccuracyForException/mm << " mm.";
1983 
1984  suggestion << " ";
1985  static G4ThreadLocal G4int warnNow = 0;
1986  if( ((++warnNow % 100) == 1) )
1987  {
1988  message << G4endl
1989  << " This problem can be due to either " << G4endl
1990  << " - a process that has proposed a displacement"
1991  << " larger than the current safety , or" << G4endl
1992  << " - inaccuracy in the computation of the safety";
1993  suggestion << "We suggest that you " << G4endl
1994  << " - find i) what particle is being tracked, and "
1995  << " ii) through what part of your geometry " << G4endl
1996  << " for example by re-running this event with "
1997  << G4endl
1998  << " /tracking/verbose 1 " << G4endl
1999  << " - check which processes you declare for"
2000  << " this particle (and look at non-standard ones)"
2001  << G4endl
2002  << " - in case, create a detailed logfile"
2003  << " of this event using:" << G4endl
2004  << " /tracking/verbose 6 ";
2005  }
2006  G4Exception("G4ITNavigator1::ComputeStep()",
2007  "GeomNav1002", JustWarning,
2008  message, G4String(suggestion.str()));
2009  G4cout.precision(oldcoutPrec);
2010  G4cerr.precision(oldcerrPrec);
2011  }
2012 #ifdef G4DEBUG_NAVIGATION
2013  else
2014  {
2015  G4cerr << "WARNING - G4ITNavigator1::ComputeStep()" << G4endl
2016  << " The Step's starting point has moved "
2017  << std::sqrt(moveLenSq) << "," << G4endl
2018  << " which has taken it to the limit of"
2019  << " the current safety. " << G4endl;
2020  }
2021 #endif
2022  }
2023  G4double safetyPlus = fPreviousSafety + fAccuracyForException;
2024  if ( shiftOriginSafSq > sqr(safetyPlus) )
2025  {
2026  std::ostringstream message;
2027  message << "May lead to a crash or unreliable results." << G4endl
2028  << " Position has shifted considerably without"
2029  << " notifying the navigator !" << G4endl
2030  << " Tolerated safety: " << safetyPlus << G4endl
2031  << " Computed shift : " << shiftOriginSafSq;
2032  G4Exception("G4ITNavigator1::ComputeStep()", "GeomNav1002",
2033  JustWarning, message);
2034  }
2035 }
2036 
2037 // ********************************************************************
2038 // Operator <<
2039 // ********************************************************************
2040 //
2041 std::ostream& operator << (std::ostream &os,const G4ITNavigator1 &n)
2042 {
2043  // Old version did only the following:
2044  // os << "Current History: " << G4endl << n.fHistory;
2045  // Old behaviour is recovered for fVerbose = 0
2046 
2047  // Adapted from G4ITNavigator1::PrintState() const
2048 
2049  G4int oldcoutPrec = os.precision(4);
2050  if( n.fVerbose >= 4 )
2051  {
2052  os << "The current state of G4ITNavigator1 is: " << G4endl;
2053  os << " ValidExitNormal= " << n.fValidExitNormal << G4endl
2054  << " ExitNormal = " << n.fExitNormal << G4endl
2055  << " Exiting = " << n.fExiting << G4endl
2056  << " Entering = " << n.fEntering << G4endl
2057  << " BlockedPhysicalVolume= " ;
2058  if (n.fBlockedPhysicalVolume==0)
2059  os << "None";
2060  else
2061  os << n.fBlockedPhysicalVolume->GetName();
2062  os << G4endl
2063  << " BlockedReplicaNo = " << n.fBlockedReplicaNo << G4endl
2064  << " LastStepWasZero = " << n.fLastStepWasZero << G4endl
2065  << G4endl;
2066  }
2067  if( ( 1 < n.fVerbose) && (n.fVerbose < 4) )
2068  {
2069  os << G4endl; // Make sure to line up
2070  os << std::setw(30) << " ExitNormal " << " "
2071  << std::setw( 5) << " Valid " << " "
2072  << std::setw( 9) << " Exiting " << " "
2073  << std::setw( 9) << " Entering" << " "
2074  << std::setw(15) << " Blocked:Volume " << " "
2075  << std::setw( 9) << " ReplicaNo" << " "
2076  << std::setw( 8) << " LastStepZero " << " "
2077  << G4endl;
2078  os << "( " << std::setw(7) << n.fExitNormal.x()
2079  << ", " << std::setw(7) << n.fExitNormal.y()
2080  << ", " << std::setw(7) << n.fExitNormal.z() << " ) "
2081  << std::setw( 5) << n.fValidExitNormal << " "
2082  << std::setw( 9) << n.fExiting << " "
2083  << std::setw( 9) << n.fEntering << " ";
2084  if ( n.fBlockedPhysicalVolume==0 )
2085  { os << std::setw(15) << "None"; }
2086  else
2087  { os << std::setw(15)<< n.fBlockedPhysicalVolume->GetName(); }
2088  os << std::setw( 9) << n.fBlockedReplicaNo << " "
2089  << std::setw( 8) << n.fLastStepWasZero << " "
2090  << G4endl;
2091  }
2092  if( n.fVerbose > 2 )
2093  {
2094  os.precision(8);
2095  os << " Current Localpoint = " << n.fLastLocatedPointLocal << G4endl;
2096  os << " PreviousSftOrigin = " << n.fPreviousSftOrigin << G4endl;
2097  os << " PreviousSafety = " << n.fPreviousSafety << G4endl;
2098  }
2099  if( n.fVerbose > 3 || n.fVerbose == 0 )
2100  {
2101  os << "Current History: " << G4endl << n.fHistory;
2102  }
2103 
2104  os.precision(oldcoutPrec);
2105  return os;
2106 }