ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4Navigator.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file G4Navigator.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 // class G4Navigator Implementation
27 //
28 // Original author: Paul Kent, July 95/96
29 // Responsible 1996-present: John Apostolakis, Gabriele Cosmo
30 // Additional revisions by: Pedro Arce, Vladimir Grichine
31 // --------------------------------------------------------------------
32 
33 #include <iomanip>
34 
35 #include "G4Navigator.hh"
36 #include "G4ios.hh"
37 #include "G4SystemOfUnits.hh"
38 #include "G4GeometryTolerance.hh"
39 #include "G4VPhysicalVolume.hh"
40 
41 #include "G4VoxelSafety.hh"
42 
43 // Constant determining how precise normals should be (how close to unit
44 // vectors). If exceeded, warnings will be issued.
45 // Can be CLHEP::perMillion (its old default) for geometry checking.
46 //
48 
49 // ********************************************************************
50 // Constructor
51 // ********************************************************************
52 //
54 {
56  // Initialises also all
57  // - exit / entry flags
58  // - flags & variables for exit normals
59  // - zero step counters
60  // - blocked volume
61 
62  if( fVerbose > 2 )
63  {
64  G4cout << " G4Navigator parameters: Action Threshold (No Zero Steps) = "
66  << " Abandon Threshold (No Zero Steps) = "
68  }
70  fMinStep = 0.05*kCarTolerance;
72 
74 
77 
79 }
80 
81 // ********************************************************************
82 // Destructor
83 // ********************************************************************
84 //
86 {
87  delete fpVoxelSafety;
88  delete fpExternalNav;
89 }
90 
91 // ********************************************************************
92 // ResetHierarchyAndLocate
93 // ********************************************************************
94 //
97  const G4ThreeVector& direction,
98  const G4TouchableHistory& h)
99 {
100  ResetState();
101  fHistory = *h.GetHistory();
102  SetupHierarchy();
103  fLastTriedStepComputation = false; // Redundant, but best
104  return LocateGlobalPointAndSetup(p, &direction, true, false);
105 }
106 
107 // ********************************************************************
108 // LocateGlobalPointAndSetup
109 //
110 // Locate the point in the hierarchy return 0 if outside
111 // The direction is required
112 // - if on an edge shared by more than two surfaces
113 // (to resolve likely looping in tracking)
114 // - at initial location of a particle
115 // (to resolve potential ambiguity at boundary)
116 //
117 // Flags on exit: (comments to be completed)
118 // fEntering - True if entering `daughter' volume (or replica)
119 // whether daughter of last mother directly
120 // or daughter of that volume's ancestor.
121 // fExiting - True if exited 'mother' volume
122 // (always ? - how about if going back down ? - tbc)
123 // ********************************************************************
124 //
127  const G4ThreeVector* pGlobalDirection,
128  const G4bool relativeSearch,
129  const G4bool ignoreDirection )
130 {
131  G4bool notKnownContained = true, noResult;
132  G4VPhysicalVolume *targetPhysical;
133  G4LogicalVolume *targetLogical;
134  G4VSolid *targetSolid = 0;
135  G4ThreeVector localPoint, globalDirection;
136  EInside insideCode;
137 
138  G4bool considerDirection = (!ignoreDirection) || fLocatedOnEdge;
139 
140  fLastTriedStepComputation = false;
141  fChangedGrandMotherRefFrame = false; // For local exit normal
142 
143  if( considerDirection && pGlobalDirection != nullptr )
144  {
145  globalDirection=*pGlobalDirection;
146  }
147 
148 #ifdef G4VERBOSE
149  if( fVerbose > 2 )
150  {
151  G4int oldcoutPrec = G4cout.precision(8);
152  G4cout << "*** G4Navigator::LocateGlobalPointAndSetup: ***" << G4endl;
153  G4cout << " Called with arguments: " << G4endl
154  << " Globalpoint = " << globalPoint << G4endl
155  << " RelativeSearch = " << relativeSearch << G4endl;
156  if( fVerbose >= 4 )
157  {
158  G4cout << " ----- Upon entering:" << G4endl;
159  PrintState();
160  }
161  G4cout.precision(oldcoutPrec);
162  }
163 #endif
164 
165  G4int noLevelsExited = 0;
166  G4int noLevelsEntered = 0;
167 
168  if ( !relativeSearch )
169  {
171  }
172  else
173  {
174  if ( fWasLimitedByGeometry )
175  {
176  fWasLimitedByGeometry = false;
177  fEnteredDaughter = fEntering; // Remember
178  fExitedMother = fExiting; // Remember
179  if ( fExiting )
180  {
181  ++noLevelsExited; // count this first level entered too
182 
183  if ( fHistory.GetDepth() )
184  {
188  }
189  else
190  {
191  fLastLocatedPointLocal = localPoint;
192  fLocatedOutsideWorld = true;
193  fBlockedPhysicalVolume = 0; // to be sure
194  fBlockedReplicaNo = -1;
195  fEntering = false; // No longer
196  fEnteredDaughter = false;
197  fExitedMother = true; // ??
198 
199  return nullptr; // Have exited world volume
200  }
201  // A fix for the case where a volume is "entered" at an edge
202  // and a coincident surface exists outside it.
203  // - This stops it from exiting further volumes and cycling
204  // - However ReplicaNavigator treats this case itself
205  //
206  // assert( fBlockedPhysicalVolume!=0 );
207 
208  // Expect to be on edge => on surface
209  //
211  {
212  fExiting = false;
213  // Consider effect on Exit Normal !?
214  }
215  }
216  else
217  if ( fEntering )
218  {
219  // assert( fBlockedPhysicalVolume!=0 );
220 
221  ++noLevelsEntered; // count the first level entered too
222 
224  {
225  case kNormal:
228  break;
229  case kReplica:
235  break;
236  case kParameterised:
238  {
239  G4VSolid *pSolid;
240  G4VPVParameterisation *pParam;
241  G4TouchableHistory parentTouchable( fHistory );
243  pSolid = pParam->ComputeSolid(fBlockedReplicaNo,
245  pSolid->ComputeDimensions(pParam, fBlockedReplicaNo,
252  //
253  // Set the correct solid and material in Logical Volume
254  //
255  G4LogicalVolume *pLogical;
257  pLogical->SetSolid( pSolid );
258  pLogical->UpdateMaterial(pParam ->
259  ComputeMaterial(fBlockedReplicaNo,
261  &parentTouchable));
262  }
263  break;
264  case kExternal:
265  G4Exception("G4Navigator::LocateGlobalPointAndSetup()",
266  "GeomNav0001", FatalException,
267  "Extra levels not applicable for external volumes.");
268  break;
269  }
270  fEntering = false;
271  fBlockedPhysicalVolume = nullptr;
272  localPoint = fHistory.GetTopTransform().TransformPoint(globalPoint);
273  notKnownContained = false;
274  }
275  }
276  else
277  {
278  fBlockedPhysicalVolume = nullptr;
279  fEntering = false;
280  fEnteredDaughter = false; // Full Step was not taken, did not enter
281  fExiting = false;
282  fExitedMother = false; // Full Step was not taken, did not exit
283  }
284  }
285  //
286  // Search from top of history up through geometry until
287  // containing volume found:
288  // If on
289  // o OUTSIDE - Back up level, not/no longer exiting volumes
290  // o SURFACE and EXITING - Back up level, setting new blocking no.s
291  // else
292  // o containing volume found
293  //
294 
295  while (notKnownContained) // Loop checking, 07.10.2016, J.Apostolakis
296  {
297  EVolume topVolumeType = fHistory.GetTopVolumeType();
298  if (topVolumeType!=kReplica && topVolumeType!=kExternal)
299  {
300  targetSolid = fHistory.GetTopVolume()->GetLogicalVolume()->GetSolid();
301  localPoint = fHistory.GetTopTransform().TransformPoint(globalPoint);
302  insideCode = targetSolid->Inside(localPoint);
303 #ifdef G4VERBOSE
304  if(( fVerbose == 1 ) && ( fCheck ))
305  {
306  G4String solidResponse = "-kInside-";
307  if (insideCode == kOutside)
308  solidResponse = "-kOutside-";
309  else if (insideCode == kSurface)
310  solidResponse = "-kSurface-";
311  G4cout << "*** G4Navigator::LocateGlobalPointAndSetup(): ***" << G4endl
312  << " Invoked Inside() for solid: " << targetSolid->GetName()
313  << ". Solid replied: " << solidResponse << G4endl
314  << " For local point p: " << localPoint << G4endl;
315  }
316 #endif
317  }
318  else
319  {
320  if( topVolumeType == kReplica )
321  {
322  insideCode = freplicaNav.BackLocate(fHistory, globalPoint, localPoint,
323  fExiting, notKnownContained);
324  // !CARE! if notKnownContained returns false then the point is within
325  // the containing placement volume of the replica(s). If insidecode
326  // will result in the history being backed up one level, then the
327  // local point returned is the point in the system of this new level
328  }
329  else
330  {
331  targetSolid = fHistory.GetTopVolume()->GetLogicalVolume()->GetSolid();
332  localPoint = fHistory.GetTopTransform().TransformPoint(globalPoint);
333  G4ThreeVector localDirection =
334  fHistory.GetTopTransform().TransformAxis(globalDirection);
335  insideCode = fpExternalNav->Inside(targetSolid, localPoint, localDirection);
336  }
337  }
338 
339  if ( insideCode==kOutside )
340  {
341  ++noLevelsExited;
342  if ( fHistory.GetDepth() )
343  {
347  fExiting = false;
348 
349  if( noLevelsExited > 1 )
350  {
351  // The first transformation was done by the sub-navigator
352  //
354  if( mRot )
355  {
356  fGrandMotherExitNormal *= (*mRot).inverse();
358  }
359  }
360  }
361  else
362  {
363  fLastLocatedPointLocal = localPoint;
364  fLocatedOutsideWorld = true;
365  // No extra transformation for ExitNormal - is in frame of Top Volume
366  return nullptr; // Have exited world volume
367  }
368  }
369  else
370  if ( insideCode==kSurface )
371  {
372  G4bool isExiting = fExiting;
373  if( (!fExiting) && considerDirection )
374  {
375  // Figure out whether we are exiting this level's volume
376  // by using the direction
377  //
378  G4bool directionExiting = false;
379  G4ThreeVector localDirection =
380  fHistory.GetTopTransform().TransformAxis(globalDirection);
381 
382  // Make sure localPoint in correct reference frame
383  // ( Was it already correct ? How ? )
384  //
385  localPoint= fHistory.GetTopTransform().TransformPoint(globalPoint);
387  {
388  G4ThreeVector normal = targetSolid->SurfaceNormal(localPoint);
389  directionExiting = normal.dot(localDirection) > 0.0;
390  isExiting = isExiting || directionExiting;
391  }
392  }
393  if( isExiting )
394  {
395  ++noLevelsExited;
396  if ( fHistory.GetDepth() )
397  {
401  //
402  // Still on surface but exited volume not necessarily convex
403  //
404  fValidExitNormal = false;
405 
406  if( noLevelsExited > 1 )
407  {
408  // The first transformation was done by the sub-navigator
409  //
410  const G4RotationMatrix* mRot =
412  if( mRot )
413  {
414  fGrandMotherExitNormal *= (*mRot).inverse();
416  }
417  }
418  }
419  else
420  {
421  fLastLocatedPointLocal = localPoint;
422  fLocatedOutsideWorld = true;
423  // No extra transformation for ExitNormal, is in frame of Top Vol
424  return nullptr; // Have exited world volume
425  }
426  }
427  else
428  {
429  notKnownContained = false;
430  }
431  }
432  else
433  {
434  notKnownContained = false;
435  }
436  } // END while (notKnownContained)
437  //
438  // Search downwards until deepest containing volume found,
439  // blocking fBlockedPhysicalVolume/BlockedReplicaNum
440  //
441  // 3 Cases:
442  //
443  // o Parameterised daughters
444  // =>Must be one G4PVParameterised daughter & voxels
445  // o Positioned daughters & voxels
446  // o Positioned daughters & no voxels
447 
448  noResult = true; // noResult should be renamed to
449  // something like enteredLevel, as that is its meaning.
450  do
451  {
452  // Determine `type' of current mother volume
453  //
454  targetPhysical = fHistory.GetTopVolume();
455  if (!targetPhysical) { break; }
456  targetLogical = targetPhysical->GetLogicalVolume();
457  switch( CharacteriseDaughters(targetLogical) )
458  {
459  case kNormal:
460  if ( targetLogical->GetVoxelHeader() ) // use optimised navigation
461  {
462  noResult = fvoxelNav.LevelLocate(fHistory,
465  globalPoint,
466  pGlobalDirection,
467  considerDirection,
468  localPoint);
469  }
470  else // do not use optimised navigation
471  {
472  noResult = fnormalNav.LevelLocate(fHistory,
475  globalPoint,
476  pGlobalDirection,
477  considerDirection,
478  localPoint);
479  }
480  break;
481  case kReplica:
482  noResult = freplicaNav.LevelLocate(fHistory,
485  globalPoint,
486  pGlobalDirection,
487  considerDirection,
488  localPoint);
489  break;
490  case kParameterised:
491  if( GetDaughtersRegularStructureId(targetLogical) != 1 )
492  {
493  noResult = fparamNav.LevelLocate(fHistory,
496  globalPoint,
497  pGlobalDirection,
498  considerDirection,
499  localPoint);
500  }
501  else // Regular structure
502  {
503  noResult = fregularNav.LevelLocate(fHistory,
506  globalPoint,
507  pGlobalDirection,
508  considerDirection,
509  localPoint);
510  }
511  break;
512  case kExternal:
513  noResult = fpExternalNav->LevelLocate(fHistory,
516  globalPoint,
517  pGlobalDirection,
518  considerDirection,
519  localPoint);
520  break;
521  }
522 
523  // LevelLocate returns true if it finds a daughter volume
524  // in which globalPoint is inside (or on the surface).
525 
526  if ( noResult )
527  {
528  ++noLevelsEntered;
529 
530  // Entering a daughter after ascending
531  //
532  // The blocked volume is no longer valid - it was for another level
533  //
534  fBlockedPhysicalVolume = nullptr;
535  fBlockedReplicaNo = -1;
536 
537  // fEntering should be false -- else blockedVolume is assumed good.
538  // fEnteredDaughter is used for ExitNormal
539  //
540  fEntering = false;
541  fEnteredDaughter = true;
542 
543  if( fExitedMother )
544  {
545  G4VPhysicalVolume* enteredPhysical = fHistory.GetTopVolume();
546  const G4RotationMatrix* mRot = enteredPhysical->GetRotation();
547  if( mRot )
548  {
549  // Go deeper, i.e. move 'down' in the hierarchy
550  // Apply direct rotation, not inverse
551  //
552  fGrandMotherExitNormal *= (*mRot);
554  }
555  }
556 
557 #ifdef G4DEBUG_NAVIGATION
558  if( fVerbose > 2 )
559  {
560  G4VPhysicalVolume* enteredPhysical = fHistory.GetTopVolume();
561  G4cout << "*** G4Navigator::LocateGlobalPointAndSetup() ***" << G4endl;
562  G4cout << " Entering volume: " << enteredPhysical->GetName()
563  << G4endl;
564  }
565 #endif
566  }
567  } while (noResult); // Loop checking, 07.10.2016, J.Apostolakis
568 
569  fLastLocatedPointLocal = localPoint;
570 
571 #ifdef G4VERBOSE
572  if( fVerbose >= 4 )
573  {
574  G4int oldcoutPrec = G4cout.precision(8);
575  G4String curPhysVol_Name("None");
576  if (targetPhysical) { curPhysVol_Name = targetPhysical->GetName(); }
577  G4cout << " Return value = new volume = " << curPhysVol_Name << G4endl;
578  G4cout << " ----- Upon exiting:" << G4endl;
579  PrintState();
580  if( fVerbose >= 5 )
581  {
582  G4cout << "Upon exiting LocateGlobalPointAndSetup():" << G4endl;
583  G4cout << " History = " << G4endl << fHistory << G4endl << G4endl;
584  }
585  G4cout.precision(oldcoutPrec);
586  }
587 #endif
588 
589  fLocatedOutsideWorld = false;
590 
591  return targetPhysical;
592 }
593 
594 // ********************************************************************
595 // LocateGlobalPointWithinVolume
596 //
597 // -> the state information of this Navigator and its subNavigators
598 // is updated in order to start the next step at pGlobalpoint
599 // -> no check is performed whether pGlobalpoint is inside the
600 // original volume (this must be the case).
601 //
602 // Note: a direction could be added to the arguments, to aid in future
603 // optional checking (via the old code below, flagged by OLD_LOCATE).
604 // [ This would be done only in verbose mode ]
605 // ********************************************************************
606 //
607 void
609 {
610 #ifdef G4DEBUG_NAVIGATION
611  assert( !fWasLimitedByGeometry );
612  // Check: Either step was not limited by a boundary or
613  // else the full step is no longer being taken
614 #endif
615 
618  fChangedGrandMotherRefFrame = false; // Frame for Exit Normal
619 
620  // For the case of Voxel (or Parameterised) volume the respective
621  // Navigator must be messaged to update its voxel information etc
622 
623  // Update the state of the Sub Navigators
624  // - in particular any voxel information they store/cache
625  //
626  G4VPhysicalVolume* motherPhysical = fHistory.GetTopVolume();
627  G4LogicalVolume* motherLogical = motherPhysical->GetLogicalVolume();
628  G4SmartVoxelHeader* pVoxelHeader = motherLogical->GetVoxelHeader();
629 
630  switch( CharacteriseDaughters(motherLogical) )
631  {
632  case kNormal:
633  if ( pVoxelHeader )
634  {
636  }
637  break;
638  case kParameterised:
639  if( GetDaughtersRegularStructureId(motherLogical) != 1 )
640  {
641  // Resets state & returns voxel node
642  //
644  }
645  break;
646  case kReplica:
647  // Nothing to do
648  break;
649  case kExternal:
650  fpExternalNav->RelocateWithinVolume( motherPhysical,
652  break;
653  }
654 
655  // Reset the state variables
656  // - which would have been affected
657  // by the 'equivalent' call to LocateGlobalPointAndSetup
658  // - who's values have been invalidated by the 'move'.
659  //
660  fBlockedPhysicalVolume = nullptr;
661  fBlockedReplicaNo = -1;
662  fEntering = false;
663  fEnteredDaughter = false; // Boundary not encountered, did not enter
664  fExiting = false;
665  fExitedMother = false; // Boundary not encountered, did not exit
666 }
667 
668 // ********************************************************************
669 // SetSavedState
670 //
671 // Save the state, in case this is a parasitic call
672 // Save fValidExitNormal, fExitNormal, fExiting, fEntering,
673 // fBlockedPhysicalVolume, fBlockedReplicaNo, fLastStepWasZero;
674 // ********************************************************************
675 //
677 {
678  // Note: the state of dependent objects is not currently saved.
679  // ( This means that the full state is changed by calls between
680  // SetSavedState() and RestoreSavedState();
681 
686 
689 
691 
697 
698  // Even the safety sphere - if you want to change it do it explicitly!
699  //
702 }
703 
704 // ********************************************************************
705 // RestoreSavedState
706 //
707 // Restore the state (in Compute Step), in case this is a parasitic call
708 // ********************************************************************
709 //
711 {
716 
719 
721 
727 
728  // The 'expected' behaviour is to restore these too (fix 2014.05.26)
731 }
732 
733 // ********************************************************************
734 // ComputeStep
735 //
736 // Computes the next geometric Step: intersections with current
737 // mother and `daughter' volumes.
738 //
739 // NOTE:
740 //
741 // Flags on entry:
742 // --------------
743 // fValidExitNormal - Normal of exited volume is valid (convex, not a
744 // coincident boundary)
745 // fExitNormal - Surface normal of exited volume
746 // fExiting - True if have exited solid
747 //
748 // fBlockedPhysicalVolume - Ptr to exited volume (or 0)
749 // fBlockedReplicaNo - Replication no of exited volume
750 // fLastStepWasZero - True if last Step size was almost zero.
751 //
752 // Flags on exit:
753 // -------------
754 // fValidExitNormal - True if surface normal of exited volume is valid
755 // fExitNormal - Surface normal of exited volume rotated to mothers
756 // reference system
757 // fExiting - True if exiting mother
758 // fEntering - True if entering `daughter' volume (or replica)
759 // fBlockedPhysicalVolume - Ptr to candidate (entered) volume
760 // fBlockedReplicaNo - Replication no of candidate (entered) volume
761 // fLastStepWasZero - True if this Step size was almost zero.
762 // ********************************************************************
763 //
765  const G4ThreeVector& pDirection,
766  const G4double pCurrentProposedStepLength,
767  G4double& pNewSafety)
768 {
769  G4ThreeVector localDirection = ComputeLocalAxis(pDirection);
770  G4double Step = kInfinity;
771  G4VPhysicalVolume *motherPhysical = fHistory.GetTopVolume();
772  G4LogicalVolume *motherLogical = motherPhysical->GetLogicalVolume();
773 
774  // All state relating to exiting normals must be reset
775  //
776  fExitNormalGlobalFrame = G4ThreeVector( 0., 0., 0.);
777  // Reset value - to erase its memory
779  // Reset - used for local exit normal
780  fGrandMotherExitNormal = G4ThreeVector( 0., 0., 0.);
781  fCalculatedExitNormal = false;
782  // Reset for new step
783 
784  static G4ThreadLocal G4int sNavCScalls = 0;
785  ++sNavCScalls;
786 
788 
789 #ifdef G4VERBOSE
790  if( fVerbose > 0 )
791  {
792  G4cout << "*** G4Navigator::ComputeStep: ***" << G4endl;
793  G4cout << " Volume = " << motherPhysical->GetName()
794  << " - Proposed step length = " << pCurrentProposedStepLength
795  << G4endl;
796 #ifdef G4DEBUG_NAVIGATION
797  if( fVerbose >= 2 )
798  {
799  G4cout << " Called with the arguments: " << G4endl
800  << " Globalpoint = " << std::setw(25) << pGlobalpoint << G4endl
801  << " Direction = " << std::setw(25) << pDirection << G4endl;
802  if( fVerbose >= 4 )
803  {
804  G4cout << " ---- Upon entering : State" << G4endl;
805  PrintState();
806  }
807  }
808 #endif
809  }
810 #endif
811 
812  G4ThreeVector newLocalPoint = ComputeLocalPoint(pGlobalpoint);
813  if( newLocalPoint != fLastLocatedPointLocal )
814  {
815  // Check whether the relocation is within safety
816  //
817  G4ThreeVector oldLocalPoint = fLastLocatedPointLocal;
818  G4double moveLenSq = (newLocalPoint-oldLocalPoint).mag2();
819 
820  if ( moveLenSq >= fSqTol )
821  {
822 #ifdef G4VERBOSE
823  ComputeStepLog(pGlobalpoint, moveLenSq);
824 #endif
825  // Relocate the point within the same volume
826  //
827  LocateGlobalPointWithinVolume( pGlobalpoint );
828  fLastTriedStepComputation = true; // Ensure that this is set again !!
829  }
830  }
832  {
833  switch( CharacteriseDaughters(motherLogical) )
834  {
835  case kNormal:
836  if ( motherLogical->GetVoxelHeader() )
837  {
839  localDirection,
840  pCurrentProposedStepLength,
841  pNewSafety,
842  fHistory,
844  fExitNormal,
845  fExiting,
846  fEntering,
849 
850  }
851  else
852  {
853  if( motherPhysical->GetRegularStructureId() == 0 )
854  {
856  localDirection,
857  pCurrentProposedStepLength,
858  pNewSafety,
859  fHistory,
861  fExitNormal,
862  fExiting,
863  fEntering,
866  }
867  else // Regular (non-voxelised) structure
868  {
869  LocateGlobalPointAndSetup( pGlobalpoint, &pDirection, true, true );
870  fLastTriedStepComputation = true; // Ensure that this is set again!!
871  //
872  // if physical process limits the step, the voxel will not be the
873  // one given by ComputeStepSkippingEqualMaterials() and the local
874  // point will be wrongly calculated.
875 
876  // There is a problem: when msc limits the step and the point is
877  // assigned wrongly to phantom in previous step (while it is out
878  // of the container volume). Then LocateGlobalPointAndSetup() has
879  // reset the history topvolume to world.
880  //
882  {
883  G4Exception("G4Navigator::ComputeStep()",
884  "GeomNav1001", JustWarning,
885  "Point is relocated in voxels, while it should be outside!");
887  localDirection,
888  pCurrentProposedStepLength,
889  pNewSafety,
890  fHistory,
892  fExitNormal,
893  fExiting,
894  fEntering,
897  }
898  else
899  {
900  Step = fregularNav.
901  ComputeStepSkippingEqualMaterials(fLastLocatedPointLocal,
902  localDirection,
903  pCurrentProposedStepLength,
904  pNewSafety,
905  fHistory,
907  fExitNormal,
908  fExiting,
909  fEntering,
912  motherPhysical);
913  }
914  }
915  }
916  break;
917  case kParameterised:
918  if( GetDaughtersRegularStructureId(motherLogical) != 1 )
919  {
921  localDirection,
922  pCurrentProposedStepLength,
923  pNewSafety,
924  fHistory,
926  fExitNormal,
927  fExiting,
928  fEntering,
931  }
932  else // Regular structure
933  {
935  localDirection,
936  pCurrentProposedStepLength,
937  pNewSafety,
938  fHistory,
940  fExitNormal,
941  fExiting,
942  fEntering,
945  }
946  break;
947  case kReplica:
948  G4Exception("G4Navigator::ComputeStep()", "GeomNav0001",
949  FatalException, "Not applicable for replicated volumes.");
950  break;
951  case kExternal:
953  localDirection,
954  pCurrentProposedStepLength,
955  pNewSafety,
956  fHistory,
958  fExitNormal,
959  fExiting,
960  fEntering,
963  break;
964  }
965  }
966  else
967  {
968  // In the case of a replica, it must handle the exiting
969  // edge/corner problem by itself
970  //
971  G4bool exitingReplica = fExitedMother;
972  G4bool calculatedExitNormal;
973  Step = freplicaNav.ComputeStep(pGlobalpoint,
974  pDirection,
976  localDirection,
977  pCurrentProposedStepLength,
978  pNewSafety,
979  fHistory,
981  calculatedExitNormal,
982  fExitNormal,
983  exitingReplica,
984  fEntering,
987  fExiting = exitingReplica;
988  fCalculatedExitNormal = calculatedExitNormal;
989  }
990 
991  // Remember last safety origin & value.
992  //
993  fPreviousSftOrigin = pGlobalpoint;
994  fPreviousSafety = pNewSafety;
995 
996  // Count zero steps - one can occur due to changing momentum at a boundary
997  // - one, two (or a few) can occur at common edges between
998  // volumes
999  // - more than two is likely a problem in the geometry
1000  // description or the Navigation
1001 
1002  // Rule of thumb: likely at an Edge if two consecutive steps are zero,
1003  // because at least two candidate volumes must have been
1004  // checked
1005  //
1006  fLocatedOnEdge = fLastStepWasZero && (Step==0.0);
1007  fLastStepWasZero = (Step<fMinStep);
1008  if (fPushed) { fPushed = fLastStepWasZero; }
1009 
1010  // Handle large number of consecutive zero steps
1011  //
1012  if ( fLastStepWasZero )
1013  {
1014  ++fNumberZeroSteps;
1015 
1017  G4bool actAndReport = false;
1019  G4bool inform = false;
1020 #ifdef G4VERBOSE
1021  actAndReport = act && (!fPushed) && fWarnPush;
1022 #endif
1023 #ifdef G4DEBUG_NAVIGATION
1024  inform = fNumberZeroSteps > 1;
1025 #endif
1026 
1027  if ( act || inform )
1028  {
1029  if( act && !abandon )
1030  {
1031  // Act to recover this stuck track. Pushing it along original direction
1032  //
1033  Step += 100*kCarTolerance;
1034  fPushed = true;
1035  }
1036 
1037  if( actAndReport || abandon || inform )
1038  {
1039  std::ostringstream message;
1040 
1041  message.precision(16);
1042  message << "Stuck Track: potential geometry or navigation problem."
1043  << G4endl;
1044  message << " Track stuck, not moving for "
1045  << fNumberZeroSteps << " steps." << G4endl
1046  << " Current phys volume: '" << motherPhysical->GetName()
1047  << "'" << G4endl
1048  << " - at position : " << pGlobalpoint << G4endl
1049  << " in direction: " << pDirection << G4endl
1050  << " (local position: " << newLocalPoint << ")" << G4endl
1051  << " (local direction: " << localDirection << ")." << G4endl
1052  << " Previous phys volume: '"
1053  << ( fLastMotherPhys ? fLastMotherPhys->GetName() : "" )
1054  << "'" << G4endl << G4endl;
1055  if( actAndReport || abandon )
1056  {
1057  message << " Likely geometry overlap - else navigation problem !"
1058  << G4endl;
1059  }
1060  if( abandon ) // i.e. fNumberZeroSteps >= fAbandonThreshold_NoZeroSteps
1061  {
1062  // Must kill this stuck track
1063 #ifdef G4VERBOSE
1064  if ( fWarnPush ) { CheckOverlapsIterative(motherPhysical); }
1065 #endif
1066  message << " Track *abandoned* due to excessive number of Zero steps."
1067  << " Event aborted. " << G4endl << G4endl;
1068  G4Exception("G4Navigator::ComputeStep()", "GeomNav0003",
1069  EventMustBeAborted, message);
1070  }
1071  else
1072  {
1073 #ifdef G4VERBOSE
1074  if ( actAndReport ) // (!fPushed => !wasPushed) && (fWarnPush))
1075  {
1076  message << " *** Trying to get *unstuck* using a push"
1077  << " - expanding step to " << Step << " (mm) ..."
1078  << " Potential overlap in geometry !" << G4endl;
1079  G4Exception("G4Navigator::ComputeStep()", "GeomNav1002",
1080  JustWarning, message);
1081  }
1082 #endif
1083 #ifdef G4DEBUG_NAVIGATION
1084  else
1085  {
1086  if( fNumberZeroSteps > 1 )
1087  {
1088  message << ", nav-comp-step calls # " << sNavCScalls
1089  << ", Step= " << Step << G4endl;
1090  G4cout << message.str();
1091  }
1092  }
1093 #endif
1094  } // end of else if ( abandon )
1095  } // end of if( actAndReport || abandon || inform )
1096  } // end of if ( act || inform )
1097  }
1098  else
1099  {
1100  if (!fPushed) { fNumberZeroSteps = 0; }
1101  }
1102  fLastMotherPhys = motherPhysical;
1103 
1104  fEnteredDaughter = fEntering; // I expect to enter a volume in this Step
1106 
1107  fStepEndPoint = pGlobalpoint
1108  + std::min(Step,pCurrentProposedStepLength) * pDirection;
1109  fLastStepEndPointLocal = fLastLocatedPointLocal + Step * localDirection;
1110 
1111  if( fExiting )
1112  {
1113 #ifdef G4DEBUG_NAVIGATION
1114  if( fVerbose > 2 )
1115  {
1116  G4cout << " At G4Nav CompStep End - if(exiting) - fExiting= " << fExiting
1117  << " fValidExitNormal = " << fValidExitNormal << G4endl;
1118  G4cout << " fExitNormal= " << fExitNormal << G4endl;
1119  }
1120 #endif
1121 
1123  {
1124  if ( fHistory.GetTopVolumeType() != kReplica )
1125  {
1126  // Convention: fExitNormal is in the 'grand-mother' coordinate system
1127  //
1129  fCalculatedExitNormal = true;
1130  }
1131  else
1132  {
1134  }
1135  }
1136  else
1137  {
1138  // We must calculate the normal anyway (in order to have it if requested)
1139  //
1140  G4ThreeVector finalLocalPoint = fLastLocatedPointLocal
1141  + localDirection*Step;
1142 
1143  if ( fHistory.GetTopVolumeType() != kReplica )
1144  {
1145  // Find normal in the 'mother' coordinate system
1146  //
1147  G4ThreeVector exitNormalMotherFrame=
1148  motherLogical->GetSolid()->SurfaceNormal(finalLocalPoint);
1149 
1150  // Transform it to the 'grand-mother' coordinate system
1151  //
1152  const G4RotationMatrix* mRot = motherPhysical->GetRotation();
1153  if( mRot )
1154  {
1156  fGrandMotherExitNormal = (*mRot).inverse() * exitNormalMotherFrame;
1157  }
1158  else
1159  {
1160  fGrandMotherExitNormal = exitNormalMotherFrame;
1161  }
1162 
1163  // Do not set fValidExitNormal -- this signifies
1164  // that the solid is convex!
1165  //
1166  fCalculatedExitNormal = true;
1167  }
1168  else
1169  {
1170  fCalculatedExitNormal = false;
1171  //
1172  // Nothing can be done at this stage currently - to solve this
1173  // Replica Navigation must have calculated the normal for this case
1174  // already.
1175  // Cases: mother is not convex, and exit is at previous replica level
1176 
1177 #ifdef G4DEBUG_NAVIGATION
1179 
1180  desc << "Problem in ComputeStep: Replica Navigation did not provide"
1181  << " valid exit Normal. " << G4endl;
1182  desc << " Do not know how calculate it in this case." << G4endl;
1183  desc << " Location = " << finalLocalPoint << G4endl;
1184  desc << " Volume name = " << motherPhysical->GetName()
1185  << " copy/replica No = " << motherPhysical->GetCopyNo() << G4endl;
1186  G4Exception("G4Navigator::ComputeStep()", "GeomNav0003",
1187  JustWarning, desc, "Normal not available for exiting.");
1188 #endif
1189  }
1190  }
1191 
1192  // Now transform it to the global reference frame !!
1193  //
1195  {
1196  G4int depth = fHistory.GetDepth();
1197  if( depth > 0 )
1198  {
1201  }
1202  else
1203  {
1205  }
1206  }
1207  else
1208  {
1209  fExitNormalGlobalFrame = G4ThreeVector( 0., 0., 0.);
1210  }
1211  }
1212 
1213  if( (Step == pCurrentProposedStepLength) && (!fExiting) && (!fEntering) )
1214  {
1215  // This if Step is not really limited by the geometry.
1216  // The Navigator is obliged to return "infinity"
1217  //
1218  Step = kInfinity;
1219  }
1220 
1221 #ifdef G4VERBOSE
1222  if( fVerbose > 1 )
1223  {
1224  if( fVerbose >= 4 )
1225  {
1226  G4cout << " ----- Upon exiting :" << G4endl;
1227  PrintState();
1228  }
1229  G4cout << " Returned step= " << Step;
1230  if( fVerbose > 5 ) { G4cout << G4endl; }
1231  if( Step == kInfinity )
1232  {
1233  G4cout << " Requested step= " << pCurrentProposedStepLength ;
1234  if( fVerbose > 5) { G4cout << G4endl; }
1235  }
1236  G4cout << " Safety = " << pNewSafety << G4endl;
1237  }
1238 #endif
1239 
1240  return Step;
1241 }
1242 
1243 // ********************************************************************
1244 // CheckNextStep
1245 //
1246 // Compute the step without altering the navigator state
1247 // ********************************************************************
1248 //
1250  const G4ThreeVector& pDirection,
1251  const G4double pCurrentProposedStepLength,
1252  G4double& pNewSafety)
1253 {
1254  G4double step;
1255 
1256  // Save the state, for this parasitic call
1257  //
1258  SetSavedState();
1259 
1260  step = ComputeStep ( pGlobalpoint,
1261  pDirection,
1262  pCurrentProposedStepLength,
1263  pNewSafety );
1264 
1265  // It is a parasitic call, so attempt to restore the key parts of the state
1266  //
1267  RestoreSavedState();
1268  // NOTE: the state of the current subnavigator is NOT restored.
1269  // ***> TODO: restore subnavigator state
1270  // if( last_located) Need Position of last location
1271  // if( last_computed step) Need Endposition of last step
1272 
1273  return step;
1274 }
1275 
1276 // ********************************************************************
1277 // ResetState
1278 //
1279 // Resets stack and minimum of navigator state `machine'
1280 // ********************************************************************
1281 //
1283 {
1284  fWasLimitedByGeometry = false;
1285  fEntering = false;
1286  fExiting = false;
1287  fLocatedOnEdge = false;
1288  fLastStepWasZero = false;
1289  fEnteredDaughter = false;
1290  fExitedMother = false;
1291  fPushed = false;
1292 
1293  fValidExitNormal = false;
1295  fCalculatedExitNormal = false;
1296 
1297  fExitNormal = G4ThreeVector(0,0,0);
1300 
1302  fPreviousSafety = 0.0;
1303 
1304  fNumberZeroSteps = 0;
1305 
1306  fBlockedPhysicalVolume = nullptr;
1307  fBlockedReplicaNo = -1;
1308 
1310  fLocatedOutsideWorld = false;
1311 
1312  fLastMotherPhys = nullptr;
1313 }
1314 
1315 // ********************************************************************
1316 // SetupHierarchy
1317 //
1318 // Renavigates & resets hierarchy described by current history
1319 // o Reset volumes
1320 // o Recompute transforms and/or solids of replicated/parameterised volumes
1321 // ********************************************************************
1322 //
1324 {
1325  const G4int cdepth = fHistory.GetDepth();
1326  G4VPhysicalVolume* current;
1327  G4VSolid* pSolid;
1328  G4VPVParameterisation* pParam;
1329 
1330  for ( auto i=1; i<=cdepth; ++i )
1331  {
1332  current = fHistory.GetVolume(i);
1333  switch ( fHistory.GetVolumeType(i) )
1334  {
1335  case kNormal:
1336  case kExternal:
1337  break;
1338  case kReplica:
1340  break;
1341  case kParameterised:
1342  G4int replicaNo;
1343  pParam = current->GetParameterisation();
1344  replicaNo = fHistory.GetReplicaNo(i);
1345  pSolid = pParam->ComputeSolid(replicaNo, current);
1346 
1347  // Set up dimensions & transform in solid/physical volume
1348  //
1349  pSolid->ComputeDimensions(pParam, replicaNo, current);
1350  pParam->ComputeTransformation(replicaNo, current);
1351 
1352  G4TouchableHistory* pTouchable = nullptr;
1353  if( pParam->IsNested() )
1354  {
1355  pTouchable= new G4TouchableHistory( fHistory );
1356  pTouchable->MoveUpHistory(); // Move up to the parent level
1357  // Adequate only if Nested at the Branch level (last)
1358  // To extend to other cases:
1359  // pTouchable->MoveUpHistory(cdepth-i-1);
1360  // Move to the parent level of *Current* level
1361  // Could replace this line and constructor with a revised
1362  // c-tor for History(levels to drop)
1363  }
1364  // Set up the correct solid and material in Logical Volume
1365  //
1366  G4LogicalVolume* pLogical = current->GetLogicalVolume();
1367  pLogical->SetSolid( pSolid );
1368  pLogical->UpdateMaterial( pParam ->
1369  ComputeMaterial(replicaNo, current, pTouchable) );
1370  delete pTouchable;
1371  break;
1372  }
1373  }
1374 }
1375 
1376 // ********************************************************************
1377 // GetLocalExitNormal
1378 //
1379 // Obtains the Normal vector to a surface (in local coordinates)
1380 // pointing out of previous volume and into current volume
1381 // ********************************************************************
1382 //
1384 {
1385  G4ThreeVector ExitNormal(0.,0.,0.);
1386  G4VSolid* currentSolid = nullptr;
1387  G4LogicalVolume* candidateLogical;
1388 
1390  {
1391  // use fLastLocatedPointLocal and next candidate volume
1392  //
1393  G4ThreeVector nextSolidExitNormal(0.,0.,0.);
1394 
1395  if( fEntering && (fBlockedPhysicalVolume!=0) )
1396  {
1397  candidateLogical = fBlockedPhysicalVolume->GetLogicalVolume();
1398  if( candidateLogical )
1399  {
1400  // fLastStepEndPointLocal is in the coordinates of the mother
1401  // we need it in the daughter's coordinate system.
1402 
1403  // The following code should also work in case of Replica
1404  {
1405  // First transform fLastLocatedPointLocal to the new daughter
1406  // coordinates
1407  //
1408  G4AffineTransform MotherToDaughterTransform=
1412  G4ThreeVector daughterPointOwnLocal =
1413  MotherToDaughterTransform.TransformPoint( fLastStepEndPointLocal );
1414 
1415  // OK if it is a parameterised volume
1416  //
1417  EInside inSideIt;
1418  G4bool onSurface;
1419  G4double safety = -1.0;
1420  currentSolid = candidateLogical->GetSolid();
1421  inSideIt = currentSolid->Inside(daughterPointOwnLocal);
1422  onSurface = (inSideIt == kSurface);
1423  if( !onSurface )
1424  {
1425  if( inSideIt == kOutside )
1426  {
1427  safety = (currentSolid->DistanceToIn(daughterPointOwnLocal));
1428  onSurface = safety < 100.0 * kCarTolerance;
1429  }
1430  else if (inSideIt == kInside )
1431  {
1432  safety = (currentSolid->DistanceToOut(daughterPointOwnLocal));
1433  onSurface = safety < 100.0 * kCarTolerance;
1434  }
1435  }
1436 
1437  if( onSurface )
1438  {
1439  nextSolidExitNormal =
1440  currentSolid->SurfaceNormal(daughterPointOwnLocal);
1441 
1442  // Entering the solid ==> opposite
1443  //
1444  // First flip ( ExitNormal = -nextSolidExitNormal; )
1445  // and then rotate the the normal to the frame of the mother (current volume)
1446  ExitNormal = MotherToDaughterTransform
1447  .InverseTransformAxis( -nextSolidExitNormal );
1448  fCalculatedExitNormal = true;
1449  }
1450  else
1451  {
1452 #ifdef G4VERBOSE
1453  if(( fVerbose == 1 ) && ( fCheck ))
1454  {
1455  std::ostringstream message;
1456  message << "Point not on surface ! " << G4endl
1457  << " Point = "
1458  << daughterPointOwnLocal << G4endl
1459  << " Physical volume = "
1461  << " Logical volume = "
1462  << candidateLogical->GetName() << G4endl
1463  << " Solid = " << currentSolid->GetName()
1464  << " Type = "
1465  << currentSolid->GetEntityType() << G4endl
1466  << *currentSolid << G4endl;
1467  if( inSideIt == kOutside )
1468  {
1469  message << "Point is Outside. " << G4endl
1470  << " Safety (from outside) = " << safety << G4endl;
1471  }
1472  else // if( inSideIt == kInside )
1473  {
1474  message << "Point is Inside. " << G4endl
1475  << " Safety (from inside) = " << safety << G4endl;
1476  }
1477  G4Exception("G4Navigator::GetLocalExitNormal()", "GeomNav1001",
1478  JustWarning, message);
1479  }
1480 #endif
1481  }
1482  *valid = onSurface; // was =true;
1483  }
1484  }
1485  }
1486  else if ( fExiting )
1487  {
1488  ExitNormal = fGrandMotherExitNormal;
1489  *valid = true;
1490  fCalculatedExitNormal = true; // Should be true already
1491  }
1492  else // i.e. ( fBlockedPhysicalVolume == 0 )
1493  {
1494  *valid = false;
1495  G4Exception("G4Navigator::GetLocalExitNormal()",
1496  "GeomNav0003", JustWarning,
1497  "Incorrect call to GetLocalSurfaceNormal." );
1498  }
1499  }
1500  else // ( ! fLastTriedStepComputation ) i.e. last call was to Locate
1501  {
1502  if ( EnteredDaughterVolume() )
1503  {
1504  G4VSolid* daughterSolid = fHistory.GetTopVolume()->GetLogicalVolume()
1505  ->GetSolid();
1506  ExitNormal = -(daughterSolid->SurfaceNormal(fLastLocatedPointLocal));
1507  if( std::fabs(ExitNormal.mag2()-1.0 ) > kToleranceNormalCheck )
1508  {
1510  desc << " Parameters of solid: " << *daughterSolid
1511  << " Point for surface = " << fLastLocatedPointLocal << std::endl;
1512  G4Exception("G4Navigator::GetLocalExitNormal()",
1513  "GeomNav0003", FatalException, desc,
1514  "Surface Normal returned by Solid is not a Unit Vector." );
1515  }
1516  fCalculatedExitNormal = true;
1517  *valid = true;
1518  }
1519  else
1520  {
1521  if( fExitedMother )
1522  {
1523  ExitNormal = fGrandMotherExitNormal;
1524  *valid = true;
1525  fCalculatedExitNormal = true;
1526  }
1527  else // We are not at a boundary. ExitNormal remains (0,0,0)
1528  {
1529  *valid = false;
1530  fCalculatedExitNormal = false;
1532  message << "Function called when *NOT* at a Boundary." << G4endl;
1533  message << "Exit Normal not calculated." << G4endl;
1534  G4Exception("G4Navigator::GetLocalExitNormal()",
1535  "GeomNav0003", JustWarning, message);
1536  }
1537  }
1538  }
1539  return ExitNormal;
1540 }
1541 
1542 // ********************************************************************
1543 // GetMotherToDaughterTransform
1544 //
1545 // Obtains the mother to daughter affine transformation
1546 // ********************************************************************
1547 //
1550  G4int enteringReplicaNo,
1551  EVolume enteringVolumeType )
1552 {
1553  switch (enteringVolumeType)
1554  {
1555  case kNormal: // Nothing is needed to prepare the transformation
1556  break; // It is stored already in the physical volume (placement)
1557  case kReplica: // Sets the transform in the Replica - tbc
1558  G4Exception("G4Navigator::GetMotherToDaughterTransform()",
1559  "GeomNav0001", FatalException,
1560  "Method NOT Implemented yet for replica volumes.");
1561  break;
1562  case kParameterised:
1563  if( pEnteringPhysVol->GetRegularStructureId() == 0 )
1564  {
1565  G4VPVParameterisation *pParam =
1566  pEnteringPhysVol->GetParameterisation();
1567  G4VSolid* pSolid =
1568  pParam->ComputeSolid(enteringReplicaNo, pEnteringPhysVol);
1569  pSolid->ComputeDimensions(pParam, enteringReplicaNo, pEnteringPhysVol);
1570 
1571  // Sets the transform in the Parameterisation
1572  //
1573  pParam->ComputeTransformation(enteringReplicaNo, pEnteringPhysVol);
1574 
1575  // Set the correct solid and material in Logical Volume
1576  //
1577  G4LogicalVolume* pLogical = pEnteringPhysVol->GetLogicalVolume();
1578  pLogical->SetSolid( pSolid );
1579  }
1580  break;
1581  case kExternal:
1582  // Expect that nothing is needed to prepare the transformation.
1583  // It is stored already in the physical volume (placement)
1584  break;
1585  }
1586  return G4AffineTransform(pEnteringPhysVol->GetRotation(),
1587  pEnteringPhysVol->GetTranslation()).Invert();
1588 }
1589 
1590 
1591 // ********************************************************************
1592 // GetLocalExitNormalAndCheck
1593 //
1594 // Obtains the Normal vector to a surface (in local coordinates)
1595 // pointing out of previous volume and into current volume, and
1596 // checks the current point against expected 'local' value.
1597 // ********************************************************************
1598 //
1601 #ifdef G4DEBUG_NAVIGATION
1602  const G4ThreeVector& ExpectedBoundaryPointGlobal,
1603 #else
1604  const G4ThreeVector&,
1605 #endif
1606  G4bool* pValid)
1607 {
1608 #ifdef G4DEBUG_NAVIGATION
1609  // Check Current point against expected 'local' value
1610  //
1612  {
1613  G4ThreeVector ExpectedBoundaryPointLocal;
1614 
1615  const G4AffineTransform& GlobalToLocal = GetGlobalToLocalTransform();
1616  ExpectedBoundaryPointLocal =
1617  GlobalToLocal.TransformPoint( ExpectedBoundaryPointGlobal );
1618 
1619  // Add here: Comparison against expected position,
1620  // i.e. the endpoint of ComputeStep
1621  }
1622 #endif
1623 
1624  return GetLocalExitNormal( pValid );
1625 }
1626 
1627 
1628 // ********************************************************************
1629 // GetGlobalExitNormal
1630 //
1631 // Obtains the Normal vector to a surface (in global coordinates)
1632 // pointing out of previous volume and into current volume
1633 // ********************************************************************
1634 //
1637  G4bool* pNormalCalculated)
1638 {
1639  G4bool validNormal;
1640  G4ThreeVector localNormal, globalNormal;
1641 
1642  G4bool usingStored = fCalculatedExitNormal && (
1643  ( fLastTriedStepComputation && fExiting ) // Just calculated it
1644  || // No locate in between
1646  && (IntersectPointGlobal-fStepEndPoint).mag2() < 10.0*fSqTol ) );
1647  // Calculated it 'just' before & then called locate
1648  // but it did not move position
1649 
1650  if( usingStored )
1651  {
1652  // This was computed in last call to ComputeStep
1653  // and only if it arrived at boundary
1654  //
1655  globalNormal = fExitNormalGlobalFrame;
1656  G4double normMag2 = globalNormal.mag2();
1657  if( std::fabs ( normMag2 - 1.0 ) < perThousand ) // was perMillion
1658  {
1659  *pNormalCalculated = true; // ComputeStep always computes it if Exiting
1660  // (fExiting==true)
1661  }
1662  else
1663  {
1665  message.precision(10);
1666  message << " WARNING> Expected normal-global-frame to be valid, "
1667  << " i.e. a unit vector!" << G4endl
1668  << " - but |normal| = " << std::sqrt(normMag2)
1669  << " - and |normal|^2 = " << normMag2 << G4endl
1670  << " which differs from 1.0 by " << normMag2 - 1.0 << G4endl
1671  << " n = " << fExitNormalGlobalFrame << G4endl
1672  << " Global point: " << IntersectPointGlobal << G4endl
1673  << " Volume: " << fHistory.GetTopVolume()->GetName() << G4endl;
1674 #ifdef G4VERBOSE
1676  if ( candLog )
1677  {
1678  message << " Solid: " << candLog->GetSolid()->GetName()
1679  << ", Type: " << candLog->GetSolid()->GetEntityType() << G4endl
1680  << *candLog->GetSolid() << G4endl;
1681  }
1682 #endif
1683  message << "============================================================"
1684  << G4endl;
1685  G4int oldVerbose = fVerbose;
1686  fVerbose = 4;
1687  message << " State of Navigator: " << G4endl;
1688  message << *this << G4endl;
1689  fVerbose = oldVerbose;
1690  message << "============================================================"
1691  << G4endl;
1692 
1693  G4Exception("G4Navigator::GetGlobalExitNormal()",
1694  "GeomNav0003",JustWarning, message,
1695  "Value obtained from stored global-normal is not a unit vector.");
1696 
1697  // (Re)Compute it now -- as either it was not computed, or it is wrong.
1698  //
1699  localNormal = GetLocalExitNormalAndCheck(IntersectPointGlobal,
1700  &validNormal);
1701  *pNormalCalculated = fCalculatedExitNormal;
1702  globalNormal = fHistory.GetTopTransform()
1703  .InverseTransformAxis(localNormal);
1704  }
1705  }
1706  else
1707  {
1708  localNormal = GetLocalExitNormalAndCheck(IntersectPointGlobal,&validNormal);
1709  *pNormalCalculated = fCalculatedExitNormal;
1710 
1711 #ifdef G4DEBUG_NAVIGATION
1712  usingStored = false;
1713 
1714  if( (!validNormal) && !fCalculatedExitNormal )
1715  {
1717  edN << " Calculated = " << fCalculatedExitNormal << G4endl;
1718  edN << " Entering= " << fEntering << G4endl;
1719  G4int oldVerbose = this->GetVerboseLevel();
1720  this->SetVerboseLevel(4);
1721  edN << " State of Navigator: " << G4endl;
1722  edN << *this << G4endl;
1723  this->SetVerboseLevel( oldVerbose );
1724 
1725  G4Exception("G4Navigator::GetGlobalExitNormal()",
1726  "GeomNav0003", JustWarning, edN,
1727  "LocalExitNormalAndCheck() did not calculate Normal.");
1728  }
1729 #endif
1730 
1731  G4double localMag2 = localNormal.mag2();
1732  if( validNormal && (std::fabs(localMag2-1.0)) > kToleranceNormalCheck )
1733  {
1735  edN.precision(10);
1736  edN << "G4Navigator::GetGlobalExitNormal: "
1737  << " Using Local Normal - from call to GetLocalExitNormalAndCheck. "
1738  << G4endl
1739  << " Local Exit Normal : " << " || = " << std::sqrt(localMag2)
1740  << " vec = " << localNormal << G4endl
1741  << " Global Exit Normal : " << " || = " << globalNormal.mag()
1742  << " vec = " << globalNormal << G4endl
1743  << " Global point: " << IntersectPointGlobal << G4endl;
1744  edN << " Calculated It = " << fCalculatedExitNormal << G4endl
1745  << " Volume: " << fHistory.GetTopVolume()->GetName() << G4endl;
1746 #ifdef G4VERBOSE
1748  if ( candLog )
1749  {
1750  edN << " Solid: " << candLog->GetSolid()->GetName()
1751  << ", Type: " << candLog->GetSolid()->GetEntityType() << G4endl
1752  << *candLog->GetSolid();
1753  }
1754 #endif
1755  G4Exception("G4Navigator::GetGlobalExitNormal()",
1756  "GeomNav0003",JustWarning, edN,
1757  "Value obtained from new local *solid* is incorrect.");
1758  localNormal = localNormal.unit(); // Should we correct it ??
1759  }
1760  globalNormal = fHistory.GetTopTransform()
1761  .InverseTransformAxis(localNormal);
1762  }
1763 
1764 #ifdef G4DEBUG_NAVIGATION
1765  if( usingStored )
1766  {
1767  G4ThreeVector globalNormAgn;
1768 
1769  localNormal = GetLocalExitNormalAndCheck(IntersectPointGlobal,&validNormal);
1770 
1771  globalNormAgn = fHistory.GetTopTransform()
1772  .InverseTransformAxis(localNormal);
1773 
1774  // Check the value computed against fExitNormalGlobalFrame
1775  G4ThreeVector diffNorm = globalNormAgn - fExitNormalGlobalFrame;
1776  if( diffNorm.mag2() > kToleranceNormalCheck )
1777  {
1778  G4ExceptionDescription edDfn;
1779  edDfn << "Found difference in normals in case of exiting mother "
1780  << "- when Get is called after ComputingStep " << G4endl;
1781  edDfn << " Magnitude of diff = " << diffNorm.mag() << G4endl;
1782  edDfn << " Normal stored (Global) = " << fExitNormalGlobalFrame
1783  << G4endl;
1784  edDfn << " Global Computed from Local = " << globalNormAgn << G4endl;
1785  G4Exception("G4Navigator::GetGlobalExitNormal()", "GeomNav0003",
1786  JustWarning, edDfn);
1787  }
1788  }
1789 #endif
1790 
1791  // Synchronise stored global exit normal as possibly re-computed here
1792  //
1793  fExitNormalGlobalFrame = globalNormal;
1794 
1795  return globalNormal;
1796 }
1797 
1798 // To make the new Voxel Safety the default, uncomment the next line
1799 #define G4NEW_SAFETY 1
1800 
1801 // ********************************************************************
1802 // ComputeSafety
1803 //
1804 // It assumes that it will be
1805 // i) called at the Point in the same volume as the EndPoint of the
1806 // ComputeStep.
1807 // ii) after (or at the end of) ComputeStep OR after the relocation.
1808 // ********************************************************************
1809 //
1811  const G4double pMaxLength,
1812  const G4bool keepState)
1813 {
1814  G4double newSafety = 0.0;
1815 
1816 #ifdef G4DEBUG_NAVIGATION
1817  G4int oldcoutPrec = G4cout.precision(8);
1818  if( fVerbose > 0 )
1819  {
1820  G4cout << "*** G4Navigator::ComputeSafety: ***" << G4endl
1821  << " Called at point: " << pGlobalpoint << G4endl;
1822 
1823  G4VPhysicalVolume *motherPhysical = fHistory.GetTopVolume();
1824  G4cout << " Volume = " << motherPhysical->GetName()
1825  << " - Maximum length = " << pMaxLength << G4endl;
1826  if( fVerbose >= 4 )
1827  {
1828  G4cout << " ----- Upon entering Compute Safety:" << G4endl;
1829  PrintState();
1830  }
1831  }
1832 #endif
1833 
1834  G4double distEndpointSq = (pGlobalpoint-fStepEndPoint).mag2();
1835  G4bool stayedOnEndpoint = distEndpointSq < sqr(kCarTolerance);
1836  G4bool endpointOnSurface = fEnteredDaughter || fExitedMother;
1837 
1838  if( endpointOnSurface && stayedOnEndpoint )
1839  {
1840 #ifdef G4DEBUG_NAVIGATION
1841  if( fVerbose >= 2 )
1842  {
1843  G4cout << " G4Navigator::ComputeSafety() finds that point - "
1844  << pGlobalpoint << " - is on surface " << G4endl;
1845  if( fEnteredDaughter ) { G4cout << " entered new daughter volume"; }
1846  if( fExitedMother ) { G4cout << " and exited previous volume."; }
1847  G4cout << G4endl;
1848  G4cout << " EndPoint was = " << fStepEndPoint << G4endl;
1849  }
1850 #endif
1851  newSafety = 0.0;
1852  }
1853  else // if( !(endpointOnSurface && stayedOnEndpoint) )
1854  {
1855  if (keepState) { SetSavedState(); }
1856 
1857  // Pseudo-relocate to this point (updates voxel information only)
1858  //
1859  LocateGlobalPointWithinVolume( pGlobalpoint );
1860  // --->> DANGER: Side effects on sub-navigator voxel information <<---
1861  // Could be replaced again by 'granular' calls to sub-navigator
1862  // locates (similar side-effects, but faster.
1863  // Solutions:
1864  // 1) Re-locate (to where?)
1865  // 2) Insure that the methods using (G4ComputeStep?)
1866  // does a relocation (if information is disturbed only ?)
1867 
1868 #ifdef G4DEBUG_NAVIGATION
1869  if( fVerbose >= 2 )
1870  {
1871  G4cout << " G4Navigator::ComputeSafety() relocates-in-volume to point: "
1872  << pGlobalpoint << G4endl;
1873  }
1874 #endif
1875  G4VPhysicalVolume* motherPhysical = fHistory.GetTopVolume();
1876  G4LogicalVolume* motherLogical = motherPhysical->GetLogicalVolume();
1877  G4SmartVoxelHeader* pVoxelHeader = motherLogical->GetVoxelHeader();
1878  G4ThreeVector localPoint = ComputeLocalPoint(pGlobalpoint);
1879 
1880  if ( fHistory.GetTopVolumeType() != kReplica )
1881  {
1882  switch(CharacteriseDaughters(motherLogical))
1883  {
1884  case kNormal:
1885  if ( pVoxelHeader )
1886  {
1887 #ifdef G4NEW_SAFETY
1888  G4double safetyTwo = fpVoxelSafety->ComputeSafety(localPoint,
1889  *motherPhysical, pMaxLength);
1890  newSafety = safetyTwo; // Faster and best available
1891 #else
1892  G4double safetyOldVoxel;
1893  safetyOldVoxel =
1894  fvoxelNav.ComputeSafety(localPoint,fHistory,pMaxLength);
1895  newSafety = safetyOldVoxel;
1896 #endif
1897  }
1898  else
1899  {
1900  newSafety=fnormalNav.ComputeSafety(localPoint,fHistory,pMaxLength);
1901  }
1902  break;
1903  case kParameterised:
1904  if( GetDaughtersRegularStructureId(motherLogical) != 1 )
1905  {
1906  newSafety=fparamNav.ComputeSafety(localPoint,fHistory,pMaxLength);
1907  }
1908  else // Regular structure
1909  {
1910  newSafety=fregularNav.ComputeSafety(localPoint,fHistory,pMaxLength);
1911  }
1912  break;
1913  case kReplica:
1914  G4Exception("G4Navigator::ComputeSafety()", "GeomNav0001",
1915  FatalException, "Not applicable for replicated volumes.");
1916  break;
1917  case kExternal:
1918  newSafety = fpExternalNav->ComputeSafety(localPoint, fHistory,
1919  pMaxLength);
1920  break;
1921  }
1922  }
1923  else
1924  {
1925  newSafety = freplicaNav.ComputeSafety(pGlobalpoint, localPoint,
1926  fHistory, pMaxLength);
1927  }
1928 
1929  if (keepState)
1930  {
1932  // This now overwrites the values of the Safety 'sphere' (correction)
1933  }
1934 
1935  // Remember last safety origin & value
1936  //
1937  // We overwrite the Safety 'sphere' - keeping old behaviour
1938  fPreviousSftOrigin = pGlobalpoint;
1939  fPreviousSafety = newSafety;
1940  }
1941 
1942 #ifdef G4DEBUG_NAVIGATION
1943  if( fVerbose > 1 )
1944  {
1945  G4cout << " ---- Exiting ComputeSafety " << G4endl;
1946  if( fVerbose > 2 ) { PrintState(); }
1947  G4cout << " Returned value of Safety = " << newSafety << G4endl;
1948  }
1949  G4cout.precision(oldcoutPrec);
1950 #endif
1951 
1952  return newSafety;
1953 }
1954 
1955 
1956 // ********************************************************************
1957 // RecheckDistanceToCurrentBoundary
1958 //
1959 // Trial method for checking potential displacement for MS
1960 // Check position aDisplacedGlobalpoint, to see whether it is in the
1961 // current volume (mother).
1962 // If in mother, check distance to boundary along aNewDirection.
1963 // If in entering daughter, check distance back to boundary.
1964 // NOTE:
1965 // Can be called only after ComputeStep() is called - before ReLocation
1966 // Deals only with current volume (and potentially entered)
1967 // Caveats
1968 // First VERSION: Does not consider daughter volumes if it remained in mother
1969 // neither for checking whether it has exited current (mother) volume,
1970 // nor for determining distance to exit this (mother) volume.
1971 // ********************************************************************
1972 //
1974  const G4ThreeVector& aDisplacedGlobalPoint,
1975  const G4ThreeVector& aNewDirection,
1976  const G4double ProposedMove,
1977  G4double* prDistance,
1978  G4double* prNewSafety) const
1979 {
1980  G4ThreeVector localPosition = ComputeLocalPoint(aDisplacedGlobalPoint);
1981  G4ThreeVector localDirection = ComputeLocalAxis(aNewDirection);
1982  // G4double Step = kInfinity;
1983 
1984  G4bool validExitNormal;
1985  G4ThreeVector exitNormal;
1986  // Check against mother solid
1987  G4VPhysicalVolume* motherPhysical = fHistory.GetTopVolume();
1988  G4LogicalVolume* motherLogical = motherPhysical->GetLogicalVolume();
1989 
1990 #ifdef CHECK_ORDER_OF_METHODS
1992  {
1993  G4Exception("G4Navigator::RecheckDistanceToCurrentBoundary()",
1994  "GeomNav0001", FatalException,
1995  "Method must be called after ComputeStep(), before call to LocateMethod.");
1996  }
1997 #endif
1998 
1999  EInside locatedDaug; // = kUndefined;
2000  G4double daughterStep = DBL_MAX;
2001  G4double daughterSafety = DBL_MAX;
2002 
2003  if( fEnteredDaughter )
2004  {
2005  if( motherLogical->CharacteriseDaughters() == kReplica ) { return false; }
2006 
2007  // Track arrived at boundary of a daughter volume at
2008  // the last call of ComputeStep().
2009  // In case the proposed displaced point is inside this daughter,
2010  // it must backtrack at least to the entry point.
2011  // NOTE: No check is made against other daughter volumes. It is
2012  // assumed that the proposed displacement is small enough that
2013  // this is not needed.
2014 
2015  // Must check boundary of current daughter
2016  //
2017  G4VPhysicalVolume* candPhysical = fBlockedPhysicalVolume;
2018  G4LogicalVolume* candLogical = candPhysical->GetLogicalVolume();
2019  G4VSolid* candSolid = candLogical->GetSolid();
2020 
2021  G4AffineTransform nextLevelTrf(candPhysical->GetRotation(),
2022  candPhysical->GetTranslation());
2023 
2024  G4ThreeVector dgPosition = nextLevelTrf.TransformPoint(localPosition);
2025  G4ThreeVector dgDirection = nextLevelTrf.TransformAxis(localDirection);
2026  locatedDaug = candSolid->Inside(dgPosition);
2027 
2028  if( locatedDaug == kInside )
2029  {
2030  // Reverse direction - and find first exit. ( Is it valid?)
2031  // Must backtrack
2032  G4double distanceBackOut =
2033  candSolid->DistanceToOut(dgPosition,
2034  - dgDirection, // Reverse direction
2035  true, &validExitNormal, &exitNormal);
2036  daughterStep= -distanceBackOut;
2037  // No check is made whether the particle could have arrived at
2038  // at this location without encountering another volume or
2039  // a different psurface of the current volume
2040  if( prNewSafety )
2041  {
2042  daughterSafety = candSolid->DistanceToOut(dgPosition);
2043  }
2044  }
2045  else
2046  {
2047  if( locatedDaug == kOutside )
2048  {
2049  // See whether it still intersects it
2050  //
2051  daughterStep = candSolid->DistanceToIn(dgPosition, dgDirection);
2052  if( prNewSafety )
2053  {
2054  daughterSafety = candSolid->DistanceToIn(dgPosition);
2055  }
2056  }
2057  else
2058  {
2059  // The point remains on the surface of candidate solid
2060  //
2061  daughterStep = 0.0;
2062  daughterSafety = 0.0;
2063  }
2064  }
2065 
2066  // If trial point is in daughter (or on its surface) we have the
2067  // answer, the rest is not relevant
2068  //
2069  if( locatedDaug != kOutside )
2070  {
2071  *prDistance = daughterStep;
2072  if( prNewSafety ) { *prNewSafety= daughterSafety; }
2073  return true;
2074  }
2075  // If ever extended, so that some type of mother cut daughter,
2076  // this would change
2077  }
2078 
2079  G4VSolid* motherSolid = motherLogical->GetSolid();
2080 
2081  G4double motherStep = DBL_MAX, motherSafety = DBL_MAX;
2082 
2083  // Check distance to boundary of mother
2084  //
2086  {
2087  EInside locatedMoth = motherSolid->Inside(localPosition);
2088 
2089  if( locatedMoth == kInside )
2090  {
2091  motherSafety = motherSolid->DistanceToOut(localPosition);
2092  if( ProposedMove >= motherSafety )
2093  {
2094  motherStep = motherSolid->DistanceToOut(localPosition,
2095  localDirection,
2096  true, &validExitNormal, &exitNormal);
2097  }
2098  else
2099  {
2100  motherStep= ProposedMove;
2101  }
2102  }
2103  else if( locatedMoth == kOutside)
2104  {
2105  motherSafety= motherSolid->DistanceToIn(localPosition);
2106  if( ProposedMove >= motherSafety )
2107  {
2108  motherStep = -motherSolid->DistanceToIn(localPosition,
2109  -localDirection);
2110  }
2111  }
2112  else
2113  {
2114  motherSafety = 0.0;
2115  *prDistance = 0.0; // On surface - no move // motherStep;
2116  if( prNewSafety ) { *prNewSafety= motherSafety; }
2117  return false;
2118  }
2119  }
2120  else
2121  {
2122  return false;
2123  }
2124 
2125  *prDistance = std::min( motherStep, daughterStep );
2126  if( prNewSafety )
2127  {
2128  *prNewSafety = std::min( motherSafety, daughterSafety );
2129  }
2130  return true;
2131 }
2132 
2133 
2134 // ********************************************************************
2135 // CreateTouchableHistoryHandle
2136 // ********************************************************************
2137 //
2139 {
2141 }
2142 
2143 // ********************************************************************
2144 // PrintState
2145 // ********************************************************************
2146 //
2148 {
2149  G4int oldcoutPrec = G4cout.precision(4);
2150  if( fVerbose >= 4 )
2151  {
2152  G4cout << "The current state of G4Navigator is: " << G4endl;
2153  G4cout << " ValidExitNormal= " << fValidExitNormal // << G4endl
2154  << " ExitNormal = " << fExitNormal // << G4endl
2155  << " Exiting = " << fExiting // << G4endl
2156  << " Entering = " << fEntering // << G4endl
2157  << " BlockedPhysicalVolume= " ;
2158  if (fBlockedPhysicalVolume==0)
2159  {
2160  G4cout << "None";
2161  }
2162  else
2163  {
2165  }
2166  G4cout << G4endl
2167  << " BlockedReplicaNo = " << fBlockedReplicaNo // << G4endl
2168  << " LastStepWasZero = " << fLastStepWasZero // << G4endl
2169  << G4endl;
2170  }
2171  if( ( 1 < fVerbose) && (fVerbose < 4) )
2172  {
2173  G4cout << G4endl; // Make sure to line up
2174  G4cout << std::setw(30) << " ExitNormal " << " "
2175  << std::setw( 5) << " Valid " << " "
2176  << std::setw( 9) << " Exiting " << " "
2177  << std::setw( 9) << " Entering" << " "
2178  << std::setw(15) << " Blocked:Volume " << " "
2179  << std::setw( 9) << " ReplicaNo" << " "
2180  << std::setw( 8) << " LastStepZero " << " "
2181  << G4endl;
2182  G4cout << "( " << std::setw(7) << fExitNormal.x()
2183  << ", " << std::setw(7) << fExitNormal.y()
2184  << ", " << std::setw(7) << fExitNormal.z() << " ) "
2185  << std::setw( 5) << fValidExitNormal << " "
2186  << std::setw( 9) << fExiting << " "
2187  << std::setw( 9) << fEntering << " ";
2188  if ( fBlockedPhysicalVolume == nullptr )
2189  { G4cout << std::setw(15) << "None"; }
2190  else
2191  { G4cout << std::setw(15)<< fBlockedPhysicalVolume->GetName(); }
2192  G4cout << std::setw( 9) << fBlockedReplicaNo << " "
2193  << std::setw( 8) << fLastStepWasZero << " "
2194  << G4endl;
2195  }
2196  if( fVerbose > 2 )
2197  {
2198  G4cout.precision(8);
2199  G4cout << " Current Localpoint = " << fLastLocatedPointLocal << G4endl;
2200  G4cout << " PreviousSftOrigin = " << fPreviousSftOrigin << G4endl;
2201  G4cout << " PreviousSafety = " << fPreviousSafety << G4endl;
2202  }
2203  G4cout.precision(oldcoutPrec);
2204 }
2205 
2206 // ********************************************************************
2207 // ComputeStepLog
2208 // ********************************************************************
2209 //
2211  G4double moveLenSq) const
2212 {
2213  // The following checks only make sense if the move is larger
2214  // than the tolerance.
2215 
2216  const G4double fAccuracyForWarning = kCarTolerance,
2217  fAccuracyForException = 1000*kCarTolerance;
2218 
2219  G4ThreeVector OriginalGlobalpoint = fHistory.GetTopTransform().
2220  InverseTransformPoint(fLastLocatedPointLocal);
2221 
2222  G4double shiftOriginSafSq = (fPreviousSftOrigin-pGlobalpoint).mag2();
2223 
2224  // Check that the starting point of this step is
2225  // within the isotropic safety sphere of the last point
2226  // to a accuracy/precision given by fAccuracyForWarning.
2227  // If so give warning.
2228  // If it fails by more than fAccuracyForException exit with error.
2229  //
2230  if( shiftOriginSafSq >= sqr(fPreviousSafety) )
2231  {
2232  G4double shiftOrigin = std::sqrt(shiftOriginSafSq);
2233  G4double diffShiftSaf = shiftOrigin - fPreviousSafety;
2234 
2235  if( diffShiftSaf > fAccuracyForWarning )
2236  {
2237  G4int oldcoutPrec = G4cout.precision(8);
2238  G4int oldcerrPrec = G4cerr.precision(10);
2239  std::ostringstream message, suggestion;
2240  message << "Accuracy error or slightly inaccurate position shift."
2241  << G4endl
2242  << " The Step's starting point has moved "
2243  << std::sqrt(moveLenSq)/mm << " mm " << G4endl
2244  << " since the last call to a Locate method." << G4endl
2245  << " This has resulted in moving "
2246  << shiftOrigin/mm << " mm "
2247  << " from the last point at which the safety "
2248  << " was calculated " << G4endl
2249  << " which is more than the computed safety= "
2250  << fPreviousSafety/mm << " mm at that point." << G4endl
2251  << " This difference is "
2252  << diffShiftSaf/mm << " mm." << G4endl
2253  << " The tolerated accuracy is "
2254  << fAccuracyForException/mm << " mm.";
2255 
2256  suggestion << " ";
2257  static G4ThreadLocal G4int warnNow = 0;
2258  if( ((++warnNow % 100) == 1) )
2259  {
2260  message << G4endl
2261  << " This problem can be due to either " << G4endl
2262  << " - a process that has proposed a displacement"
2263  << " larger than the current safety , or" << G4endl
2264  << " - inaccuracy in the computation of the safety";
2265  suggestion << "We suggest that you " << G4endl
2266  << " - find i) what particle is being tracked, and "
2267  << " ii) through what part of your geometry " << G4endl
2268  << " for example by re-running this event with "
2269  << G4endl
2270  << " /tracking/verbose 1 " << G4endl
2271  << " - check which processes you declare for"
2272  << " this particle (and look at non-standard ones)"
2273  << G4endl
2274  << " - in case, create a detailed logfile"
2275  << " of this event using:" << G4endl
2276  << " /tracking/verbose 6 ";
2277  }
2278  G4Exception("G4Navigator::ComputeStep()",
2279  "GeomNav1002", JustWarning,
2280  message, G4String(suggestion.str()));
2281  G4cout.precision(oldcoutPrec);
2282  G4cerr.precision(oldcerrPrec);
2283  }
2284 #ifdef G4DEBUG_NAVIGATION
2285  else
2286  {
2287  G4cerr << "WARNING - G4Navigator::ComputeStep()" << G4endl
2288  << " The Step's starting point has moved "
2289  << std::sqrt(moveLenSq) << "," << G4endl
2290  << " which has taken it to the limit of"
2291  << " the current safety. " << G4endl;
2292  }
2293 #endif
2294  }
2295  G4double safetyPlus = fPreviousSafety + fAccuracyForException;
2296  if ( shiftOriginSafSq > sqr(safetyPlus) )
2297  {
2298  std::ostringstream message;
2299  message << "May lead to a crash or unreliable results." << G4endl
2300  << " Position has shifted considerably without"
2301  << " notifying the navigator !" << G4endl
2302  << " Tolerated safety: " << safetyPlus << G4endl
2303  << " Computed shift : " << shiftOriginSafSq;
2304  G4Exception("G4Navigator::ComputeStep()", "GeomNav1002",
2305  JustWarning, message);
2306  }
2307 }
2308 
2309 // ********************************************************************
2310 // CheckOverlapsIterative
2311 // ********************************************************************
2312 //
2314 {
2315  // Check and report overlaps
2316  //
2317  G4bool foundOverlap = false;
2318  G4int nPoints = 300000, ntrials = 9, numOverlaps = 5;
2319  G4double trialLength = 1.0 * CLHEP::centimeter;
2320  while ( ntrials-- > 0 && !foundOverlap )
2321  {
2322  if ( fVerbose > 1 )
2323  {
2324  G4cout << " ** Running overlap checks in volume "
2325  << vol->GetName()
2326  << " with length = " << trialLength << G4endl;
2327  }
2328  foundOverlap = vol->CheckOverlaps(nPoints, trialLength,
2329  fVerbose, numOverlaps);
2330  trialLength *= 0.1;
2331  if ( trialLength <= 1.0e-5 ) { numOverlaps= 1;}
2332  }
2333  return foundOverlap;
2334 }
2335 
2336 // ********************************************************************
2337 // Operator <<
2338 // ********************************************************************
2339 //
2340 std::ostream& operator << (std::ostream &os,const G4Navigator &n)
2341 {
2342  // Old version did only the following:
2343  // os << "Current History: " << G4endl << n.fHistory;
2344  // Old behaviour is recovered for fVerbose = 0
2345 
2346  // Adapted from G4Navigator::PrintState() const
2347 
2348  G4int oldcoutPrec = os.precision(4);
2349  if( n.fVerbose >= 4 )
2350  {
2351  os << "The current state of G4Navigator is: " << G4endl;
2352  os << " ValidExitNormal= " << n.fValidExitNormal << G4endl
2353  << " ExitNormal = " << n.fExitNormal << G4endl
2354  << " Exiting = " << n.fExiting << G4endl
2355  << " Entering = " << n.fEntering << G4endl
2356  << " BlockedPhysicalVolume= " ;
2357  if (n.fBlockedPhysicalVolume==0)
2358  os << "None";
2359  else
2360  os << n.fBlockedPhysicalVolume->GetName();
2361  os << G4endl
2362  << " BlockedReplicaNo = " << n.fBlockedReplicaNo << G4endl
2363  << " LastStepWasZero = " << n.fLastStepWasZero << G4endl
2364  << G4endl;
2365  }
2366  if( ( 1 < n.fVerbose) && (n.fVerbose < 4) )
2367  {
2368  os << G4endl; // Make sure to line up
2369  os << std::setw(30) << " ExitNormal " << " "
2370  << std::setw( 5) << " Valid " << " "
2371  << std::setw( 9) << " Exiting " << " "
2372  << std::setw( 9) << " Entering" << " "
2373  << std::setw(15) << " Blocked:Volume " << " "
2374  << std::setw( 9) << " ReplicaNo" << " "
2375  << std::setw( 8) << " LastStepZero " << " "
2376  << G4endl;
2377  os << "( " << std::setw(7) << n.fExitNormal.x()
2378  << ", " << std::setw(7) << n.fExitNormal.y()
2379  << ", " << std::setw(7) << n.fExitNormal.z() << " ) "
2380  << std::setw( 5) << n.fValidExitNormal << " "
2381  << std::setw( 9) << n.fExiting << " "
2382  << std::setw( 9) << n.fEntering << " ";
2383  if ( n.fBlockedPhysicalVolume==0 )
2384  { os << std::setw(15) << "None"; }
2385  else
2386  { os << std::setw(15)<< n.fBlockedPhysicalVolume->GetName(); }
2387  os << std::setw( 9) << n.fBlockedReplicaNo << " "
2388  << std::setw( 8) << n.fLastStepWasZero << " "
2389  << G4endl;
2390  }
2391  if( n.fVerbose > 2 )
2392  {
2393  os.precision(8);
2394  os << " Current Localpoint = " << n.fLastLocatedPointLocal << G4endl;
2395  os << " PreviousSftOrigin = " << n.fPreviousSftOrigin << G4endl;
2396  os << " PreviousSafety = " << n.fPreviousSafety << G4endl;
2397  }
2398  if( n.fVerbose > 3 || n.fVerbose == 0 )
2399  {
2400  os << "Current History: " << G4endl << n.fHistory;
2401  }
2402 
2403  os.precision(oldcoutPrec);
2404  return os;
2405 }