1424 lines
51 KiB
C++
1424 lines
51 KiB
C++
//
|
|
// ********************************************************************
|
|
// * License and Disclaimer *
|
|
// * *
|
|
// * The Geant4 software is copyright of the Copyright Holders of *
|
|
// * the Geant4 Collaboration. It is provided under the terms and *
|
|
// * conditions of the Geant4 Software License, included in the file *
|
|
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
|
// * include a list of copyright holders. *
|
|
// * *
|
|
// * Neither the authors of this software system, nor their employing *
|
|
// * institutes,nor the agencies providing financial support for this *
|
|
// * work make any representation or warranty, express or implied, *
|
|
// * regarding this software system or assume any liability for its *
|
|
// * use. Please see the license in the file LICENSE and URL above *
|
|
// * for the full disclaimer and the limitation of liability. *
|
|
// * *
|
|
// * This code implementation is the result of the scientific and *
|
|
// * technical work of the GEANT4 collaboration. *
|
|
// * By using, copying, modifying or distributing the software (or *
|
|
// * any work based on the software) you agree to acknowledge its *
|
|
// * use in resulting scientific publications, and indicate your *
|
|
// * acceptance of all terms of the Geant4 Software license. *
|
|
// ********************************************************************
|
|
//
|
|
//
|
|
// $Id: G4Navigator.cc,v 1.46 2010/11/15 14:03:27 gcosmo Exp $
|
|
// GEANT4 tag $ Name: $
|
|
//
|
|
// class G4Navigator Implementation
|
|
//
|
|
// Original author: Paul Kent, July 95/96
|
|
//
|
|
// --------------------------------------------------------------------
|
|
|
|
#include "G4Navigator.hh"
|
|
#include "G4ios.hh"
|
|
#include <iomanip>
|
|
|
|
#include "G4GeometryTolerance.hh"
|
|
#include "G4VPhysicalVolume.hh"
|
|
|
|
// ********************************************************************
|
|
// Constructor
|
|
// ********************************************************************
|
|
//
|
|
G4Navigator::G4Navigator()
|
|
: fWasLimitedByGeometry(false), fVerbose(0),
|
|
fTopPhysical(0), fCheck(false), fPushed(false), fWarnPush(true)
|
|
{
|
|
fActive= false;
|
|
ResetStackAndState();
|
|
|
|
fActionThreshold_NoZeroSteps = 10;
|
|
fAbandonThreshold_NoZeroSteps = 25;
|
|
|
|
kCarTolerance = G4GeometryTolerance::GetInstance()->GetSurfaceTolerance();
|
|
fregularNav.SetNormalNavigation( &fnormalNav );
|
|
|
|
fStepEndPoint = G4ThreeVector( kInfinity, kInfinity, kInfinity );
|
|
}
|
|
|
|
// ********************************************************************
|
|
// Destructor
|
|
// ********************************************************************
|
|
//
|
|
G4Navigator::~G4Navigator()
|
|
{;}
|
|
|
|
// ********************************************************************
|
|
// ResetHierarchyAndLocate
|
|
// ********************************************************************
|
|
//
|
|
G4VPhysicalVolume*
|
|
G4Navigator::ResetHierarchyAndLocate(const G4ThreeVector &p,
|
|
const G4ThreeVector &direction,
|
|
const G4TouchableHistory &h)
|
|
{
|
|
ResetState();
|
|
fHistory = *h.GetHistory();
|
|
SetupHierarchy();
|
|
return LocateGlobalPointAndSetup(p, &direction, true, false);
|
|
}
|
|
|
|
// ********************************************************************
|
|
// LocateGlobalPointAndSetup
|
|
//
|
|
// Locate the point in the hierarchy return 0 if outside
|
|
// The direction is required
|
|
// - if on an edge shared by more than two surfaces
|
|
// (to resolve likely looping in tracking)
|
|
// - at initial location of a particle
|
|
// (to resolve potential ambiguity at boundary)
|
|
//
|
|
// Flags on exit: (comments to be completed)
|
|
// fEntering - True if entering `daughter' volume (or replica)
|
|
// whether daughter of last mother directly
|
|
// or daughter of that volume's ancestor.
|
|
// ********************************************************************
|
|
//
|
|
G4VPhysicalVolume*
|
|
G4Navigator::LocateGlobalPointAndSetup( const G4ThreeVector& globalPoint,
|
|
const G4ThreeVector* pGlobalDirection,
|
|
const G4bool relativeSearch,
|
|
const G4bool ignoreDirection )
|
|
{
|
|
G4bool notKnownContained=true, noResult;
|
|
G4VPhysicalVolume *targetPhysical;
|
|
G4LogicalVolume *targetLogical;
|
|
G4VSolid *targetSolid=0;
|
|
G4ThreeVector localPoint, globalDirection;
|
|
EInside insideCode;
|
|
|
|
G4bool considerDirection = (!ignoreDirection) || fLocatedOnEdge;
|
|
|
|
if( considerDirection && pGlobalDirection != 0 )
|
|
{
|
|
globalDirection=*pGlobalDirection;
|
|
}
|
|
|
|
#ifdef G4DEBUG_NAVIGATION
|
|
if( fVerbose > 2 )
|
|
{
|
|
G4cout << "Upon entering LocateGlobalPointAndSetup():" << G4endl;
|
|
G4cout << " History = " << G4endl << fHistory << G4endl << G4endl;
|
|
}
|
|
#endif
|
|
|
|
#ifdef G4VERBOSE
|
|
if( fVerbose > 2 )
|
|
{
|
|
G4int oldcoutPrec = G4cout.precision(8);
|
|
G4cout << "*** G4Navigator::LocateGlobalPointAndSetup: ***" << G4endl;
|
|
G4cout << " Called with arguments: " << G4endl
|
|
<< " Globalpoint = " << globalPoint << G4endl
|
|
<< " RelativeSearch = " << relativeSearch << G4endl;
|
|
if( fVerbose == 4 )
|
|
{
|
|
G4cout << " ----- Upon entering:" << G4endl;
|
|
PrintState();
|
|
}
|
|
G4cout.precision(oldcoutPrec);
|
|
}
|
|
#endif
|
|
|
|
if ( !relativeSearch )
|
|
{
|
|
ResetStackAndState();
|
|
}
|
|
else
|
|
{
|
|
if ( fWasLimitedByGeometry )
|
|
{
|
|
fWasLimitedByGeometry = false;
|
|
fEnteredDaughter = fEntering; // Remember
|
|
fExitedMother = fExiting; // Remember
|
|
if ( fExiting )
|
|
{
|
|
if ( fHistory.GetDepth() )
|
|
{
|
|
fBlockedPhysicalVolume = fHistory.GetTopVolume();
|
|
fBlockedReplicaNo = fHistory.GetTopReplicaNo();
|
|
fHistory.BackLevel();
|
|
}
|
|
else
|
|
{
|
|
fLastLocatedPointLocal = localPoint;
|
|
fLocatedOutsideWorld = true;
|
|
return 0; // Have exited world volume
|
|
}
|
|
// A fix for the case where a volume is "entered" at an edge
|
|
// and a coincident surface exists outside it.
|
|
// - This stops it from exiting further volumes and cycling
|
|
// - However ReplicaNavigator treats this case itself
|
|
//
|
|
if ( fLocatedOnEdge && (VolumeType(fBlockedPhysicalVolume)!=kReplica ))
|
|
{
|
|
fExiting= false;
|
|
}
|
|
}
|
|
else
|
|
if ( fEntering )
|
|
{
|
|
switch (VolumeType(fBlockedPhysicalVolume))
|
|
{
|
|
case kNormal:
|
|
fHistory.NewLevel(fBlockedPhysicalVolume, kNormal,
|
|
fBlockedPhysicalVolume->GetCopyNo());
|
|
break;
|
|
case kReplica:
|
|
freplicaNav.ComputeTransformation(fBlockedReplicaNo,
|
|
fBlockedPhysicalVolume);
|
|
fHistory.NewLevel(fBlockedPhysicalVolume, kReplica,
|
|
fBlockedReplicaNo);
|
|
fBlockedPhysicalVolume->SetCopyNo(fBlockedReplicaNo);
|
|
break;
|
|
case kParameterised:
|
|
if( fBlockedPhysicalVolume->GetRegularStructureId() == 0 )
|
|
{
|
|
G4VSolid *pSolid;
|
|
G4VPVParameterisation *pParam;
|
|
G4TouchableHistory parentTouchable( fHistory );
|
|
pParam = fBlockedPhysicalVolume->GetParameterisation();
|
|
pSolid = pParam->ComputeSolid(fBlockedReplicaNo,
|
|
fBlockedPhysicalVolume);
|
|
pSolid->ComputeDimensions(pParam, fBlockedReplicaNo,
|
|
fBlockedPhysicalVolume);
|
|
pParam->ComputeTransformation(fBlockedReplicaNo,
|
|
fBlockedPhysicalVolume);
|
|
fHistory.NewLevel(fBlockedPhysicalVolume, kParameterised,
|
|
fBlockedReplicaNo);
|
|
fBlockedPhysicalVolume->SetCopyNo(fBlockedReplicaNo);
|
|
//
|
|
// Set the correct solid and material in Logical Volume
|
|
//
|
|
G4LogicalVolume *pLogical;
|
|
pLogical = fBlockedPhysicalVolume->GetLogicalVolume();
|
|
pLogical->SetSolid( pSolid );
|
|
pLogical->UpdateMaterial(pParam ->
|
|
ComputeMaterial(fBlockedReplicaNo,
|
|
fBlockedPhysicalVolume,
|
|
&parentTouchable));
|
|
}
|
|
break;
|
|
}
|
|
fEntering = false;
|
|
fBlockedPhysicalVolume = 0;
|
|
localPoint = fHistory.GetTopTransform().TransformPoint(globalPoint);
|
|
notKnownContained = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fBlockedPhysicalVolume = 0;
|
|
fEntering = false;
|
|
fEnteredDaughter = false; // Full Step was not taken, did not enter
|
|
fExiting = false;
|
|
fExitedMother = false; // Full Step was not taken, did not exit
|
|
}
|
|
}
|
|
//
|
|
// Search from top of history up through geometry until
|
|
// containing volume found:
|
|
// If on
|
|
// o OUTSIDE - Back up level, not/no longer exiting volumes
|
|
// o SURFACE and EXITING - Back up level, setting new blocking no.s
|
|
// else
|
|
// o containing volume found
|
|
//
|
|
while (notKnownContained)
|
|
{
|
|
if ( fHistory.GetTopVolumeType()!=kReplica )
|
|
{
|
|
targetSolid = fHistory.GetTopVolume()->GetLogicalVolume()->GetSolid();
|
|
localPoint = fHistory.GetTopTransform().TransformPoint(globalPoint);
|
|
insideCode = targetSolid->Inside(localPoint);
|
|
#ifdef G4VERBOSE
|
|
if(( fVerbose == 1 ) && ( fCheck ))
|
|
{
|
|
G4String solidResponse = "-kInside-";
|
|
if (insideCode == kOutside)
|
|
solidResponse = "-kOutside-";
|
|
else if (insideCode == kSurface)
|
|
solidResponse = "-kSurface-";
|
|
G4cout << "*** G4Navigator::LocateGlobalPointAndSetup(): ***" << G4endl
|
|
<< " Invoked Inside() for solid: " << targetSolid->GetName()
|
|
<< ". Solid replied: " << solidResponse << G4endl
|
|
<< " For local point p: " << localPoint << G4endl;
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
insideCode = freplicaNav.BackLocate(fHistory, globalPoint, localPoint,
|
|
fExiting, notKnownContained);
|
|
// !CARE! if notKnownContained returns false then the point is within
|
|
// the containing placement volume of the replica(s). If insidecode
|
|
// will result in the history being backed up one level, then the
|
|
// local point returned is the point in the system of this new level
|
|
}
|
|
if ( insideCode==kOutside )
|
|
{
|
|
if ( fHistory.GetDepth() )
|
|
{
|
|
fBlockedPhysicalVolume = fHistory.GetTopVolume();
|
|
fBlockedReplicaNo = fHistory.GetTopReplicaNo();
|
|
fHistory.BackLevel();
|
|
fExiting = false;
|
|
}
|
|
else
|
|
{
|
|
fLastLocatedPointLocal = localPoint;
|
|
fLocatedOutsideWorld = true;
|
|
return 0; // Have exited world volume
|
|
}
|
|
}
|
|
else
|
|
if ( insideCode==kSurface )
|
|
{
|
|
G4bool isExiting = fExiting;
|
|
if( (!fExiting)&&considerDirection )
|
|
{
|
|
// Figure out whether we are exiting this level's volume
|
|
// by using the direction
|
|
//
|
|
G4bool directionExiting = false;
|
|
G4ThreeVector localDirection =
|
|
fHistory.GetTopTransform().TransformAxis(globalDirection);
|
|
if ( fHistory.GetTopVolumeType()!=kReplica )
|
|
{
|
|
G4ThreeVector normal = targetSolid->SurfaceNormal(localPoint);
|
|
directionExiting = normal.dot(localDirection) > 0.0;
|
|
isExiting = isExiting || directionExiting;
|
|
}
|
|
}
|
|
if( isExiting )
|
|
{
|
|
if ( fHistory.GetDepth() )
|
|
{
|
|
fBlockedPhysicalVolume = fHistory.GetTopVolume();
|
|
fBlockedReplicaNo = fHistory.GetTopReplicaNo();
|
|
fHistory.BackLevel();
|
|
//
|
|
// Still on surface but exited volume not necessarily convex
|
|
//
|
|
fValidExitNormal = false;
|
|
}
|
|
else
|
|
{
|
|
fLastLocatedPointLocal = localPoint;
|
|
fLocatedOutsideWorld = true;
|
|
return 0; // Have exited world volume
|
|
}
|
|
}
|
|
else
|
|
{
|
|
notKnownContained=false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
notKnownContained=false;
|
|
}
|
|
} // END while (notKnownContained)
|
|
//
|
|
// Search downwards until deepest containing volume found,
|
|
// blocking fBlockedPhysicalVolume/BlockedReplicaNum
|
|
//
|
|
// 3 Cases:
|
|
//
|
|
// o Parameterised daughters
|
|
// =>Must be one G4PVParameterised daughter & voxels
|
|
// o Positioned daughters & voxels
|
|
// o Positioned daughters & no voxels
|
|
|
|
noResult = true; // noResult should be renamed to
|
|
// something like enteredLevel, as that is its meaning.
|
|
do
|
|
{
|
|
// Determine `type' of current mother volume
|
|
//
|
|
targetPhysical = fHistory.GetTopVolume();
|
|
if (!targetPhysical) { break; }
|
|
targetLogical = targetPhysical->GetLogicalVolume();
|
|
switch( CharacteriseDaughters(targetLogical) )
|
|
{
|
|
case kNormal:
|
|
if ( targetLogical->GetVoxelHeader() ) // use optimised navigation
|
|
{
|
|
noResult = fvoxelNav.LevelLocate(fHistory,
|
|
fBlockedPhysicalVolume,
|
|
fBlockedReplicaNo,
|
|
globalPoint,
|
|
pGlobalDirection,
|
|
considerDirection,
|
|
localPoint);
|
|
}
|
|
else // do not use optimised navigation
|
|
{
|
|
noResult = fnormalNav.LevelLocate(fHistory,
|
|
fBlockedPhysicalVolume,
|
|
fBlockedReplicaNo,
|
|
globalPoint,
|
|
pGlobalDirection,
|
|
considerDirection,
|
|
localPoint);
|
|
}
|
|
break;
|
|
case kReplica:
|
|
noResult = freplicaNav.LevelLocate(fHistory,
|
|
fBlockedPhysicalVolume,
|
|
fBlockedReplicaNo,
|
|
globalPoint,
|
|
pGlobalDirection,
|
|
considerDirection,
|
|
localPoint);
|
|
break;
|
|
case kParameterised:
|
|
if( GetDaughtersRegularStructureId(targetLogical) != 1 )
|
|
{
|
|
noResult = fparamNav.LevelLocate(fHistory,
|
|
fBlockedPhysicalVolume,
|
|
fBlockedReplicaNo,
|
|
globalPoint,
|
|
pGlobalDirection,
|
|
considerDirection,
|
|
localPoint);
|
|
}
|
|
else // Regular structure
|
|
{
|
|
noResult = fregularNav.LevelLocate(fHistory,
|
|
fBlockedPhysicalVolume,
|
|
fBlockedReplicaNo,
|
|
globalPoint,
|
|
pGlobalDirection,
|
|
considerDirection,
|
|
localPoint);
|
|
}
|
|
break;
|
|
}
|
|
|
|
// LevelLocate returns true if it finds a daughter volume
|
|
// in which globalPoint is inside (or on the surface).
|
|
|
|
if ( noResult )
|
|
{
|
|
// Entering a daughter after ascending
|
|
//
|
|
// The blocked volume is no longer valid - it was for another level
|
|
//
|
|
fBlockedPhysicalVolume = 0;
|
|
fBlockedReplicaNo = -1;
|
|
|
|
// fEntering should be false -- else blockedVolume is assumed good.
|
|
// fEnteredDaughter is used for ExitNormal
|
|
//
|
|
fEntering = false;
|
|
fEnteredDaughter = true;
|
|
#ifdef G4DEBUG_NAVIGATION
|
|
if( fVerbose > 2 )
|
|
{
|
|
G4VPhysicalVolume* enteredPhysical = fHistory.GetTopVolume();
|
|
G4cout << "*** G4Navigator::LocateGlobalPointAndSetup() ***" << G4endl;
|
|
G4cout << " Entering volume: " << enteredPhysical->GetName()
|
|
<< G4endl;
|
|
}
|
|
#endif
|
|
}
|
|
} while (noResult);
|
|
|
|
fLastLocatedPointLocal = localPoint;
|
|
|
|
#ifdef G4VERBOSE
|
|
if( fVerbose == 4 )
|
|
{
|
|
G4int oldcoutPrec = G4cout.precision(8);
|
|
G4String curPhysVol_Name("None");
|
|
if (targetPhysical) { curPhysVol_Name = targetPhysical->GetName(); }
|
|
G4cout << " Return value = new volume = " << curPhysVol_Name << G4endl;
|
|
G4cout << " ----- Upon exiting:" << G4endl;
|
|
PrintState();
|
|
#ifdef G4DEBUG_NAVIGATION
|
|
G4cout << "Upon exiting LocateGlobalPointAndSetup():" << G4endl;
|
|
G4cout << " History = " << G4endl << fHistory << G4endl << G4endl;
|
|
#endif
|
|
G4cout.precision(oldcoutPrec);
|
|
}
|
|
#endif
|
|
|
|
fLocatedOutsideWorld= false;
|
|
|
|
return targetPhysical;
|
|
}
|
|
|
|
// ********************************************************************
|
|
// LocateGlobalPointWithinVolume
|
|
//
|
|
// -> the state information of this Navigator and its subNavigators
|
|
// is updated in order to start the next step at pGlobalpoint
|
|
// -> no check is performed whether pGlobalpoint is inside the
|
|
// original volume (this must be the case).
|
|
//
|
|
// Note: a direction could be added to the arguments, to aid in future
|
|
// optional checking (via the old code below, flagged by OLD_LOCATE).
|
|
// [ This would be done only in verbose mode ]
|
|
// ********************************************************************
|
|
//
|
|
void
|
|
G4Navigator::LocateGlobalPointWithinVolume(const G4ThreeVector& pGlobalpoint)
|
|
{
|
|
fLastLocatedPointLocal = ComputeLocalPoint(pGlobalpoint);
|
|
|
|
#ifdef G4DEBUG_NAVIGATION
|
|
if( fVerbose > 2 )
|
|
{
|
|
G4cout << "Entering LocateGlobalWithinVolume(): History = " << G4endl;
|
|
G4cout << fHistory << G4endl;
|
|
}
|
|
#endif
|
|
|
|
// For the case of Voxel (or Parameterised) volume the respective
|
|
// Navigator must be messaged to update its voxel information etc
|
|
|
|
// Update the state of the Sub Navigators
|
|
// - in particular any voxel information they store/cache
|
|
//
|
|
G4VPhysicalVolume* motherPhysical = fHistory.GetTopVolume();
|
|
G4LogicalVolume* motherLogical = motherPhysical->GetLogicalVolume();
|
|
G4SmartVoxelHeader* pVoxelHeader = motherLogical->GetVoxelHeader();
|
|
|
|
if ( fHistory.GetTopVolumeType()!=kReplica )
|
|
{
|
|
switch( CharacteriseDaughters(motherLogical) )
|
|
{
|
|
case kNormal:
|
|
if ( pVoxelHeader )
|
|
{
|
|
fvoxelNav.VoxelLocate( pVoxelHeader, fLastLocatedPointLocal );
|
|
}
|
|
break;
|
|
case kParameterised:
|
|
if( GetDaughtersRegularStructureId(motherLogical) != 1 )
|
|
{
|
|
// Resets state & returns voxel node
|
|
//
|
|
fparamNav.ParamVoxelLocate( pVoxelHeader, fLastLocatedPointLocal );
|
|
}
|
|
break;
|
|
case kReplica:
|
|
G4Exception("G4Navigator::LocateGlobalPointWithinVolume()",
|
|
"NotApplicable", FatalException,
|
|
"Not applicable for replicated volumes.");
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Reset the state variables
|
|
// - which would have been affected
|
|
// by the 'equivalent' call to LocateGlobalPointAndSetup
|
|
// - who's values have been invalidated by the 'move'.
|
|
//
|
|
fBlockedPhysicalVolume = 0;
|
|
fBlockedReplicaNo = -1;
|
|
fEntering = false;
|
|
fEnteredDaughter = false; // Boundary not encountered, did not enter
|
|
fExiting = false;
|
|
fExitedMother = false; // Boundary not encountered, did not exit
|
|
}
|
|
|
|
// ********************************************************************
|
|
// SetSavedState
|
|
//
|
|
// Save the state, in case this is a parasitic call
|
|
// Save fValidExitNormal, fExitNormal, fExiting, fEntering,
|
|
// fBlockedPhysicalVolume, fBlockedReplicaNo, fLastStepWasZero;
|
|
// ********************************************************************
|
|
//
|
|
void G4Navigator::SetSavedState()
|
|
{
|
|
// fSaveExitNormal = fExitNormal;
|
|
fSaveState.sExitNormal = fExitNormal;
|
|
fSaveState.sValidExitNormal = fValidExitNormal;
|
|
fSaveState.sExiting = fExiting;
|
|
fSaveState.sEntering = fEntering;
|
|
|
|
fSaveState.spBlockedPhysicalVolume = fBlockedPhysicalVolume;
|
|
fSaveState.sBlockedReplicaNo = fBlockedReplicaNo,
|
|
|
|
fSaveState.sLastStepWasZero = fLastStepWasZero;
|
|
}
|
|
|
|
// ********************************************************************
|
|
// RestoreSavedState
|
|
//
|
|
// Restore the state (in Compute Step), in case this is a parasitic call
|
|
// ********************************************************************
|
|
//
|
|
void G4Navigator::RestoreSavedState()
|
|
{
|
|
fExitNormal = fSaveState.sExitNormal;
|
|
fValidExitNormal = fSaveState.sValidExitNormal;
|
|
fExiting = fSaveState.sExiting;
|
|
fEntering = fSaveState.sEntering;
|
|
|
|
fBlockedPhysicalVolume = fSaveState.spBlockedPhysicalVolume;
|
|
fBlockedReplicaNo = fSaveState.sBlockedReplicaNo,
|
|
|
|
fLastStepWasZero = fSaveState.sLastStepWasZero;
|
|
}
|
|
|
|
// ********************************************************************
|
|
// ComputeStep
|
|
//
|
|
// Computes the next geometric Step: intersections with current
|
|
// mother and `daughter' volumes.
|
|
//
|
|
// NOTE:
|
|
//
|
|
// Flags on entry:
|
|
// --------------
|
|
// fValidExitNormal - Normal of exited volume is valid (convex, not a
|
|
// coincident boundary)
|
|
// fExitNormal - Surface normal of exited volume
|
|
// fExiting - True if have exited solid
|
|
//
|
|
// fBlockedPhysicalVolume - Ptr to exited volume (or 0)
|
|
// fBlockedReplicaNo - Replication no of exited volume
|
|
// fLastStepWasZero - True if last Step size was zero.
|
|
//
|
|
// Flags on exit:
|
|
// -------------
|
|
// fValidExitNormal - True if surface normal of exited volume is valid
|
|
// fExitNormal - Surface normal of exited volume rotated to mothers
|
|
// reference system
|
|
// fExiting - True if exiting mother
|
|
// fEntering - True if entering `daughter' volume (or replica)
|
|
// fBlockedPhysicalVolume - Ptr to candidate (entered) volume
|
|
// fBlockedReplicaNo - Replication no of candidate (entered) volume
|
|
// fLastStepWasZero - True if this Step size was zero.
|
|
// ********************************************************************
|
|
//
|
|
G4double G4Navigator::ComputeStep( const G4ThreeVector &pGlobalpoint,
|
|
const G4ThreeVector &pDirection,
|
|
const G4double pCurrentProposedStepLength,
|
|
G4double &pNewSafety)
|
|
{
|
|
G4ThreeVector localDirection = ComputeLocalAxis(pDirection);
|
|
G4double Step = kInfinity;
|
|
G4VPhysicalVolume *motherPhysical = fHistory.GetTopVolume();
|
|
G4LogicalVolume *motherLogical = motherPhysical->GetLogicalVolume();
|
|
|
|
static G4int sNavCScalls=0;
|
|
sNavCScalls++;
|
|
|
|
#ifdef G4VERBOSE
|
|
if( fVerbose > 0 )
|
|
{
|
|
G4cout << "*** G4Navigator::ComputeStep: ***" << G4endl;
|
|
G4cout << " Volume = " << motherPhysical->GetName()
|
|
<< " - Proposed step length = " << pCurrentProposedStepLength
|
|
<< G4endl;
|
|
#ifdef G4DEBUG_NAVIGATION
|
|
if( fVerbose >= 4 )
|
|
{
|
|
G4cout << " Called with the arguments: " << G4endl
|
|
<< " Globalpoint = " << std::setw(25) << pGlobalpoint << G4endl
|
|
<< " Direction = " << std::setw(25) << pDirection << G4endl;
|
|
G4cout << " ---- Upon entering :" << G4endl;
|
|
PrintState();
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
G4ThreeVector newLocalPoint = ComputeLocalPoint(pGlobalpoint);
|
|
if( newLocalPoint != fLastLocatedPointLocal )
|
|
{
|
|
// Check whether the relocation is within safety
|
|
//
|
|
G4ThreeVector oldLocalPoint = fLastLocatedPointLocal;
|
|
G4double moveLenSq = (newLocalPoint-oldLocalPoint).mag2();
|
|
|
|
if ( moveLenSq >= kCarTolerance*kCarTolerance )
|
|
{
|
|
#ifdef G4VERBOSE
|
|
ComputeStepLog(pGlobalpoint, moveLenSq);
|
|
#endif
|
|
// Relocate the point within the same volume
|
|
//
|
|
LocateGlobalPointWithinVolume( pGlobalpoint );
|
|
}
|
|
}
|
|
if ( fHistory.GetTopVolumeType()!=kReplica )
|
|
{
|
|
switch( CharacteriseDaughters(motherLogical) )
|
|
{
|
|
case kNormal:
|
|
if ( motherLogical->GetVoxelHeader() )
|
|
{
|
|
Step = fvoxelNav.ComputeStep(fLastLocatedPointLocal,
|
|
localDirection,
|
|
pCurrentProposedStepLength,
|
|
pNewSafety,
|
|
fHistory,
|
|
fValidExitNormal,
|
|
fExitNormal,
|
|
fExiting,
|
|
fEntering,
|
|
&fBlockedPhysicalVolume,
|
|
fBlockedReplicaNo);
|
|
|
|
}
|
|
else
|
|
{
|
|
if( motherPhysical->GetRegularStructureId() == 0 )
|
|
{
|
|
Step = fnormalNav.ComputeStep(fLastLocatedPointLocal,
|
|
localDirection,
|
|
pCurrentProposedStepLength,
|
|
pNewSafety,
|
|
fHistory,
|
|
fValidExitNormal,
|
|
fExitNormal,
|
|
fExiting,
|
|
fEntering,
|
|
&fBlockedPhysicalVolume,
|
|
fBlockedReplicaNo);
|
|
}
|
|
else // Regular (non-voxelised) structure
|
|
{
|
|
LocateGlobalPointAndSetup( pGlobalpoint, &pDirection, true, true );
|
|
//
|
|
// if physical process limits the step, the voxel will not be the
|
|
// one given by ComputeStepSkippingEqualMaterials() and the local
|
|
// point will be wrongly calculated.
|
|
|
|
// There is a problem: when msc limits the step and the point is
|
|
// assigned wrongly to phantom in previous step (while it is out
|
|
// of the container volume). Then LocateGlobalPointAndSetup() has
|
|
// reset the history topvolume to world.
|
|
//
|
|
if(fHistory.GetTopVolume()->GetRegularStructureId() == 0 )
|
|
{
|
|
G4Exception("G4Navigator::ComputeStep()",
|
|
"Bad-location-of-point", JustWarning,
|
|
"Point is relocated in voxels, while it should be outside!");
|
|
Step = fnormalNav.ComputeStep(fLastLocatedPointLocal,
|
|
localDirection,
|
|
pCurrentProposedStepLength,
|
|
pNewSafety,
|
|
fHistory,
|
|
fValidExitNormal,
|
|
fExitNormal,
|
|
fExiting,
|
|
fEntering,
|
|
&fBlockedPhysicalVolume,
|
|
fBlockedReplicaNo);
|
|
}
|
|
else
|
|
{
|
|
Step = fregularNav.
|
|
ComputeStepSkippingEqualMaterials(fLastLocatedPointLocal,
|
|
localDirection,
|
|
pCurrentProposedStepLength,
|
|
pNewSafety,
|
|
fHistory,
|
|
fValidExitNormal,
|
|
fExitNormal,
|
|
fExiting,
|
|
fEntering,
|
|
&fBlockedPhysicalVolume,
|
|
fBlockedReplicaNo,
|
|
motherPhysical);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case kParameterised:
|
|
if( GetDaughtersRegularStructureId(motherLogical) != 1 )
|
|
{
|
|
Step = fparamNav.ComputeStep(fLastLocatedPointLocal,
|
|
localDirection,
|
|
pCurrentProposedStepLength,
|
|
pNewSafety,
|
|
fHistory,
|
|
fValidExitNormal,
|
|
fExitNormal,
|
|
fExiting,
|
|
fEntering,
|
|
&fBlockedPhysicalVolume,
|
|
fBlockedReplicaNo);
|
|
}
|
|
else // Regular structure
|
|
{
|
|
Step = fregularNav.ComputeStep(fLastLocatedPointLocal,
|
|
localDirection,
|
|
pCurrentProposedStepLength,
|
|
pNewSafety,
|
|
fHistory,
|
|
fValidExitNormal,
|
|
fExitNormal,
|
|
fExiting,
|
|
fEntering,
|
|
&fBlockedPhysicalVolume,
|
|
fBlockedReplicaNo);
|
|
}
|
|
break;
|
|
case kReplica:
|
|
G4Exception("G4Navigator::ComputeStep()", "NotApplicable",
|
|
FatalException, "Not applicable for replicated volumes.");
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// In the case of a replica, it must handle the exiting
|
|
// edge/corner problem by itself
|
|
//
|
|
G4bool exitingReplica = fExitedMother;
|
|
Step = freplicaNav.ComputeStep(pGlobalpoint,
|
|
pDirection,
|
|
fLastLocatedPointLocal,
|
|
localDirection,
|
|
pCurrentProposedStepLength,
|
|
pNewSafety,
|
|
fHistory,
|
|
fValidExitNormal,
|
|
fExitNormal,
|
|
exitingReplica,
|
|
fEntering,
|
|
&fBlockedPhysicalVolume,
|
|
fBlockedReplicaNo);
|
|
fExiting= exitingReplica; // still ok to set it ??
|
|
}
|
|
|
|
// Remember last safety origin & value.
|
|
//
|
|
fPreviousSftOrigin = pGlobalpoint;
|
|
fPreviousSafety = pNewSafety;
|
|
|
|
// Count zero steps - one can occur due to changing momentum at a boundary
|
|
// - one, two (or a few) can occur at common edges between
|
|
// volumes
|
|
// - more than two is likely a problem in the geometry
|
|
// description or the Navigation
|
|
|
|
// Rule of thumb: likely at an Edge if two consecutive steps are zero,
|
|
// because at least two candidate volumes must have been
|
|
// checked
|
|
//
|
|
fLocatedOnEdge = fLastStepWasZero && (Step==0.0);
|
|
fLastStepWasZero = (Step==0.0);
|
|
if (fPushed) fPushed = fLastStepWasZero;
|
|
|
|
// Handle large number of consecutive zero steps
|
|
//
|
|
if ( fLastStepWasZero )
|
|
{
|
|
fNumberZeroSteps++;
|
|
#ifdef G4DEBUG_NAVIGATION
|
|
if( fNumberZeroSteps > 1 )
|
|
{
|
|
G4cout << "G4Navigator::ComputeStep(): another zero step, # "
|
|
<< fNumberZeroSteps
|
|
<< " at " << pGlobalpoint
|
|
<< " in volume " << motherPhysical->GetName()
|
|
<< " nav-comp-step calls # " << sNavCScalls
|
|
<< G4endl;
|
|
}
|
|
#endif
|
|
if( fNumberZeroSteps > fActionThreshold_NoZeroSteps-1 )
|
|
{
|
|
// Act to recover this stuck track. Pushing it along direction
|
|
//
|
|
Step += 100*kCarTolerance;
|
|
#ifdef G4VERBOSE
|
|
if ((!fPushed) && (fWarnPush))
|
|
{
|
|
G4cerr << "WARNING - G4Navigator::ComputeStep()" << G4endl
|
|
<< " Track stuck, not moving for "
|
|
<< fNumberZeroSteps << " steps" << G4endl
|
|
<< " in volume -" << motherPhysical->GetName()
|
|
<< "- at point " << pGlobalpoint << G4endl
|
|
<< " direction: " << pDirection << "." << G4endl
|
|
<< " Potential geometry or navigation problem !"
|
|
<< G4endl
|
|
<< " Trying pushing it of " << Step << " mm ..."
|
|
<< G4endl;
|
|
}
|
|
#endif
|
|
fPushed = true;
|
|
}
|
|
if( fNumberZeroSteps > fAbandonThreshold_NoZeroSteps-1 )
|
|
{
|
|
// Must kill this stuck track
|
|
//
|
|
G4cerr << "ERROR - G4Navigator::ComputeStep()" << G4endl
|
|
<< " Track stuck, not moving for "
|
|
<< fNumberZeroSteps << " steps" << G4endl
|
|
<< " in volume -" << motherPhysical->GetName()
|
|
<< "- at point " << pGlobalpoint << G4endl
|
|
<< " direction: " << pDirection << "." << G4endl;
|
|
motherPhysical->CheckOverlaps(5000, false);
|
|
G4Exception("G4Navigator::ComputeStep()",
|
|
"StuckTrack", EventMustBeAborted,
|
|
"Stuck Track: potential geometry or navigation problem.");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!fPushed) fNumberZeroSteps = 0;
|
|
}
|
|
|
|
fEnteredDaughter = fEntering; // I expect to enter a volume in this Step
|
|
fExitedMother = fExiting;
|
|
|
|
if( fExiting )
|
|
{
|
|
#ifdef G4DEBUG_NAVIGATION
|
|
if( fVerbose > 2 )
|
|
{
|
|
G4cout << " At G4Nav CompStep End - if(exiting) - fExiting= " << fExiting
|
|
<< " fValidExitNormal = " << fValidExitNormal << G4endl;
|
|
G4cout << " fExitNormal= " << fExitNormal << G4endl;
|
|
}
|
|
#endif
|
|
|
|
if(fValidExitNormal)
|
|
{
|
|
// Convention: fExitNormal is in the 'grand-mother' coordinate system
|
|
//
|
|
fGrandMotherExitNormal= fExitNormal;
|
|
}
|
|
else
|
|
{
|
|
// We must calculate the normal anyway (in order to have it if requested)
|
|
//
|
|
G4ThreeVector finalLocalPoint =
|
|
fLastLocatedPointLocal + localDirection*Step;
|
|
|
|
// Now fGrandMotherExitNormal is in the 'grand-mother' coordinate system
|
|
//
|
|
fGrandMotherExitNormal =
|
|
motherLogical->GetSolid()->SurfaceNormal(finalLocalPoint);
|
|
|
|
const G4RotationMatrix* mRot = motherPhysical->GetRotation();
|
|
if( mRot )
|
|
{
|
|
fGrandMotherExitNormal *= (*mRot).inverse();
|
|
}
|
|
}
|
|
}
|
|
fStepEndPoint= pGlobalpoint+Step*pDirection;
|
|
|
|
if( (Step == pCurrentProposedStepLength) && (!fExiting) && (!fEntering) )
|
|
{
|
|
// This if Step is not really limited by the geometry.
|
|
// The Navigator is obliged to return "infinity"
|
|
//
|
|
Step = kInfinity;
|
|
}
|
|
|
|
#ifdef G4VERBOSE
|
|
if( fVerbose > 1 )
|
|
{
|
|
if( fVerbose >= 4 )
|
|
{
|
|
G4cout << " ----- Upon exiting :" << G4endl;
|
|
PrintState();
|
|
}
|
|
G4cout <<" Returned step = " << Step << G4endl;
|
|
if( Step == kInfinity )
|
|
{
|
|
G4cout << " Original proposed step = "
|
|
<< pCurrentProposedStepLength << G4endl;
|
|
}
|
|
G4cout << " Safety = " << pNewSafety << G4endl;
|
|
}
|
|
#endif
|
|
|
|
return Step;
|
|
}
|
|
|
|
// ********************************************************************
|
|
// CheckNextStep
|
|
//
|
|
// Compute the step without altering the navigator state
|
|
// ********************************************************************
|
|
//
|
|
G4double G4Navigator::CheckNextStep( const G4ThreeVector& pGlobalpoint,
|
|
const G4ThreeVector& pDirection,
|
|
const G4double pCurrentProposedStepLength,
|
|
G4double& pNewSafety)
|
|
{
|
|
G4double step;
|
|
|
|
// Save the state, for this parasitic call
|
|
//
|
|
SetSavedState();
|
|
|
|
step = ComputeStep ( pGlobalpoint,
|
|
pDirection,
|
|
pCurrentProposedStepLength,
|
|
pNewSafety );
|
|
|
|
// If a parasitic call, then attempt to restore the key parts of the state
|
|
//
|
|
RestoreSavedState();
|
|
|
|
return step;
|
|
}
|
|
|
|
// ********************************************************************
|
|
// ResetState
|
|
//
|
|
// Resets stack and minimum of navigator state `machine'
|
|
// ********************************************************************
|
|
//
|
|
void G4Navigator::ResetState()
|
|
{
|
|
fWasLimitedByGeometry = false;
|
|
fEntering = false;
|
|
fExiting = false;
|
|
fLocatedOnEdge = false;
|
|
fLastStepWasZero = false;
|
|
fEnteredDaughter = false;
|
|
fExitedMother = false;
|
|
fPushed = false;
|
|
|
|
fValidExitNormal = false;
|
|
fExitNormal = G4ThreeVector(0,0,0);
|
|
|
|
fPreviousSftOrigin = G4ThreeVector(0,0,0);
|
|
fPreviousSafety = 0.0;
|
|
|
|
fNumberZeroSteps = 0;
|
|
|
|
fBlockedPhysicalVolume = 0;
|
|
fBlockedReplicaNo = -1;
|
|
|
|
fLastLocatedPointLocal = G4ThreeVector( kInfinity, -kInfinity, 0.0 );
|
|
fLocatedOutsideWorld = false;
|
|
}
|
|
|
|
// ********************************************************************
|
|
// SetupHierarchy
|
|
//
|
|
// Renavigates & resets hierarchy described by current history
|
|
// o Reset volumes
|
|
// o Recompute transforms and/or solids of replicated/parameterised volumes
|
|
// ********************************************************************
|
|
//
|
|
void G4Navigator::SetupHierarchy()
|
|
{
|
|
G4int i;
|
|
const G4int cdepth = fHistory.GetDepth();
|
|
G4VPhysicalVolume *mother, *current;
|
|
G4VSolid *pSolid;
|
|
G4VPVParameterisation *pParam;
|
|
|
|
for ( i=1; i<=cdepth; i++ )
|
|
{
|
|
current = fHistory.GetVolume(i);
|
|
switch ( fHistory.GetVolumeType(i) )
|
|
{
|
|
case kNormal:
|
|
break;
|
|
case kReplica:
|
|
freplicaNav.ComputeTransformation(fHistory.GetReplicaNo(i), current);
|
|
break;
|
|
case kParameterised:
|
|
G4int replicaNo;
|
|
pParam = current->GetParameterisation();
|
|
replicaNo = fHistory.GetReplicaNo(i);
|
|
pSolid = pParam->ComputeSolid(replicaNo, current);
|
|
|
|
// Set up dimensions & transform in solid/physical volume
|
|
//
|
|
pSolid->ComputeDimensions(pParam, replicaNo, current);
|
|
pParam->ComputeTransformation(replicaNo, current);
|
|
|
|
G4TouchableHistory touchable( fHistory );
|
|
touchable.MoveUpHistory(); // move up to the parent level
|
|
|
|
// Set up the correct solid and material in Logical Volume
|
|
//
|
|
G4LogicalVolume *pLogical = current->GetLogicalVolume();
|
|
pLogical->SetSolid( pSolid );
|
|
pLogical->UpdateMaterial( pParam ->
|
|
ComputeMaterial(replicaNo, current, &touchable) );
|
|
break;
|
|
}
|
|
mother = current;
|
|
}
|
|
}
|
|
|
|
// ********************************************************************
|
|
// GetLocalExitNormal
|
|
//
|
|
// Obtains the Normal vector to a surface (in local coordinates)
|
|
// pointing out of previous volume and into current volume
|
|
// ********************************************************************
|
|
//
|
|
G4ThreeVector G4Navigator::GetLocalExitNormal( G4bool* valid )
|
|
{
|
|
G4ThreeVector ExitNormal(0.,0.,0.);
|
|
|
|
if ( EnteredDaughterVolume() )
|
|
{
|
|
ExitNormal= -(fHistory.GetTopVolume()->GetLogicalVolume()->
|
|
GetSolid()->SurfaceNormal(fLastLocatedPointLocal));
|
|
*valid = true;
|
|
}
|
|
else
|
|
{
|
|
if( fExitedMother )
|
|
{
|
|
ExitNormal = fGrandMotherExitNormal;
|
|
*valid = true;
|
|
}
|
|
else
|
|
{
|
|
// We are not at a boundary.
|
|
// ExitNormal remains (0,0,0)
|
|
//
|
|
*valid = false;
|
|
}
|
|
}
|
|
return ExitNormal;
|
|
}
|
|
|
|
// ********************************************************************
|
|
// ComputeSafety
|
|
//
|
|
// It assumes that it will be
|
|
// i) called at the Point in the same volume as the EndPoint of the
|
|
// ComputeStep.
|
|
// ii) after (or at the end of) ComputeStep OR after the relocation.
|
|
// ********************************************************************
|
|
//
|
|
G4double G4Navigator::ComputeSafety( const G4ThreeVector &pGlobalpoint,
|
|
const G4double pMaxLength,
|
|
const G4bool keepState)
|
|
{
|
|
G4double newSafety = 0.0;
|
|
|
|
#ifdef G4DEBUG_NAVIGATION
|
|
G4int oldcoutPrec = G4cout.precision(8);
|
|
if( fVerbose > 0 )
|
|
{
|
|
G4cout << "*** G4Navigator::ComputeSafety: ***" << G4endl
|
|
<< " Called at point: " << pGlobalpoint << G4endl;
|
|
|
|
G4VPhysicalVolume *motherPhysical = fHistory.GetTopVolume();
|
|
G4cout << " Volume = " << motherPhysical->GetName()
|
|
<< " - Maximum length = " << pMaxLength << G4endl;
|
|
if( fVerbose >= 4 )
|
|
{
|
|
G4cout << " ----- Upon entering Compute Safety:" << G4endl;
|
|
PrintState();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (keepState) { SetSavedState(); }
|
|
|
|
G4double distEndpointSq = (pGlobalpoint-fStepEndPoint).mag2();
|
|
G4bool stayedOnEndpoint = distEndpointSq < kCarTolerance*kCarTolerance;
|
|
G4bool endpointOnSurface = fEnteredDaughter || fExitedMother;
|
|
|
|
if( !(endpointOnSurface && stayedOnEndpoint) )
|
|
{
|
|
// Pseudo-relocate to this point (updates voxel information only)
|
|
//
|
|
LocateGlobalPointWithinVolume( pGlobalpoint );
|
|
// --->> Danger: Side effects on sub-navigator voxel information <<---
|
|
// Could be replaced again by 'granular' calls to sub-navigator
|
|
// locates (similar side-effects, but faster.
|
|
// Solutions:
|
|
// 1) Re-locate (to where?)
|
|
// 2) Insure that the methods using (G4ComputeStep?)
|
|
// does a relocation (if information is disturbed only ?)
|
|
|
|
#ifdef G4DEBUG_NAVIGATION
|
|
if( fVerbose >= 2 )
|
|
{
|
|
G4cout << " G4Navigator::ComputeSafety() relocates-in-volume to point: "
|
|
<< pGlobalpoint << G4endl;
|
|
}
|
|
#endif
|
|
G4VPhysicalVolume *motherPhysical = fHistory.GetTopVolume();
|
|
G4LogicalVolume *motherLogical = motherPhysical->GetLogicalVolume();
|
|
G4SmartVoxelHeader* pVoxelHeader = motherLogical->GetVoxelHeader();
|
|
G4ThreeVector localPoint = ComputeLocalPoint(pGlobalpoint);
|
|
|
|
if ( fHistory.GetTopVolumeType()!=kReplica )
|
|
{
|
|
switch(CharacteriseDaughters(motherLogical))
|
|
{
|
|
case kNormal:
|
|
if ( pVoxelHeader )
|
|
{
|
|
newSafety=fvoxelNav.ComputeSafety(localPoint,fHistory,pMaxLength);
|
|
}
|
|
else
|
|
{
|
|
newSafety=fnormalNav.ComputeSafety(localPoint,fHistory,pMaxLength);
|
|
}
|
|
break;
|
|
case kParameterised:
|
|
if( GetDaughtersRegularStructureId(motherLogical) != 1 )
|
|
{
|
|
newSafety = fparamNav.ComputeSafety(localPoint,fHistory,pMaxLength);
|
|
}
|
|
else // Regular structure
|
|
{
|
|
newSafety = fregularNav.ComputeSafety(localPoint,fHistory,pMaxLength);
|
|
}
|
|
break;
|
|
case kReplica:
|
|
G4Exception("G4Navigator::ComputeSafety()", "NotApplicable",
|
|
FatalException, "Not applicable for replicated volumes.");
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
newSafety = freplicaNav.ComputeSafety(pGlobalpoint, localPoint,
|
|
fHistory, pMaxLength);
|
|
}
|
|
}
|
|
else // if( endpointOnSurface && stayedOnEndpoint )
|
|
{
|
|
#ifdef G4DEBUG_NAVIGATION
|
|
if( fVerbose >= 2 )
|
|
{
|
|
G4cout << " G4Navigator::ComputeSafety() finds that point - "
|
|
<< pGlobalpoint << " - is on surface " << G4endl;
|
|
if( fEnteredDaughter ) { G4cout << " entered new daughter volume"; }
|
|
if( fExitedMother ) { G4cout << " and exited previous volume."; }
|
|
G4cout << G4endl;
|
|
G4cout << " EndPoint was = " << fStepEndPoint << G4endl;
|
|
}
|
|
#endif
|
|
newSafety = 0.0;
|
|
}
|
|
|
|
// Remember last safety origin & value
|
|
//
|
|
fPreviousSftOrigin = pGlobalpoint;
|
|
fPreviousSafety = newSafety;
|
|
|
|
if (keepState) { RestoreSavedState(); }
|
|
|
|
#ifdef G4DEBUG_NAVIGATION
|
|
if( fVerbose > 1 )
|
|
{
|
|
G4cout << " ---- Exiting ComputeSafety " << G4endl;
|
|
if( fVerbose > 2 ) { PrintState(); }
|
|
G4cout << " Returned value of Safety = " << newSafety << G4endl;
|
|
}
|
|
G4cout.precision(oldcoutPrec);
|
|
#endif
|
|
|
|
return newSafety;
|
|
}
|
|
|
|
// ********************************************************************
|
|
// CreateTouchableHistoryHandle
|
|
// ********************************************************************
|
|
//
|
|
G4TouchableHistoryHandle G4Navigator::CreateTouchableHistoryHandle() const
|
|
{
|
|
return G4TouchableHistoryHandle( CreateTouchableHistory() );
|
|
}
|
|
|
|
// ********************************************************************
|
|
// PrintState
|
|
// ********************************************************************
|
|
//
|
|
void G4Navigator::PrintState() const
|
|
{
|
|
G4int oldcoutPrec = G4cout.precision(4);
|
|
if( fVerbose == 4 )
|
|
{
|
|
G4cout << "The current state of G4Navigator is: " << G4endl;
|
|
G4cout << " ValidExitNormal= " << fValidExitNormal << G4endl
|
|
<< " ExitNormal = " << fExitNormal << G4endl
|
|
<< " Exiting = " << fExiting << G4endl
|
|
<< " Entering = " << fEntering << G4endl
|
|
<< " BlockedPhysicalVolume= " ;
|
|
if (fBlockedPhysicalVolume==0)
|
|
G4cout << "None";
|
|
else
|
|
G4cout << fBlockedPhysicalVolume->GetName();
|
|
G4cout << G4endl
|
|
<< " BlockedReplicaNo = " << fBlockedReplicaNo << G4endl
|
|
<< " LastStepWasZero = " << fLastStepWasZero << G4endl
|
|
<< G4endl;
|
|
}
|
|
if( ( 1 < fVerbose) && (fVerbose < 4) )
|
|
{
|
|
G4cout << std::setw(30) << " ExitNormal " << " "
|
|
<< std::setw( 5) << " Valid " << " "
|
|
<< std::setw( 9) << " Exiting " << " "
|
|
<< std::setw( 9) << " Entering" << " "
|
|
<< std::setw(15) << " Blocked:Volume " << " "
|
|
<< std::setw( 9) << " ReplicaNo" << " "
|
|
<< std::setw( 8) << " LastStepZero " << " "
|
|
<< G4endl;
|
|
G4cout << "( " << std::setw(7) << fExitNormal.x()
|
|
<< ", " << std::setw(7) << fExitNormal.y()
|
|
<< ", " << std::setw(7) << fExitNormal.z() << " ) "
|
|
<< std::setw( 5) << fValidExitNormal << " "
|
|
<< std::setw( 9) << fExiting << " "
|
|
<< std::setw( 9) << fEntering << " ";
|
|
if ( fBlockedPhysicalVolume==0 )
|
|
G4cout << std::setw(15) << "None";
|
|
else
|
|
G4cout << std::setw(15)<< fBlockedPhysicalVolume->GetName();
|
|
G4cout << std::setw( 9) << fBlockedReplicaNo << " "
|
|
<< std::setw( 8) << fLastStepWasZero << " "
|
|
<< G4endl;
|
|
}
|
|
if( fVerbose > 2 )
|
|
{
|
|
G4cout.precision(8);
|
|
G4cout << " Current Localpoint = " << fLastLocatedPointLocal << G4endl;
|
|
G4cout << " PreviousSftOrigin = " << fPreviousSftOrigin << G4endl;
|
|
G4cout << " PreviousSafety = " << fPreviousSafety << G4endl;
|
|
}
|
|
G4cout.precision(oldcoutPrec);
|
|
}
|
|
|
|
// ********************************************************************
|
|
// ComputeStepLog
|
|
// ********************************************************************
|
|
//
|
|
void G4Navigator::ComputeStepLog(const G4ThreeVector& pGlobalpoint,
|
|
G4double moveLenSq) const
|
|
{
|
|
// The following checks only make sense if the move is larger
|
|
// than the tolerance.
|
|
|
|
static const G4double fAccuracyForWarning = kCarTolerance,
|
|
fAccuracyForException = 1000*kCarTolerance;
|
|
|
|
G4ThreeVector OriginalGlobalpoint = fHistory.GetTopTransform().Inverse().
|
|
TransformPoint(fLastLocatedPointLocal);
|
|
|
|
G4double shiftOriginSafSq = (fPreviousSftOrigin-pGlobalpoint).mag2();
|
|
|
|
// Check that the starting point of this step is
|
|
// within the isotropic safety sphere of the last point
|
|
// to a accuracy/precision given by fAccuracyForWarning.
|
|
// If so give warning.
|
|
// If it fails by more than fAccuracyForException exit with error.
|
|
//
|
|
if( shiftOriginSafSq >= sqr(fPreviousSafety) )
|
|
{
|
|
G4double shiftOrigin = std::sqrt(shiftOriginSafSq);
|
|
G4double diffShiftSaf = shiftOrigin - fPreviousSafety;
|
|
|
|
if( diffShiftSaf > fAccuracyForWarning )
|
|
{
|
|
G4int oldcoutPrec= G4cout.precision(8);
|
|
G4int oldcerrPrec= G4cerr.precision(10);
|
|
G4Exception("G4Navigator::ComputeStep()",
|
|
"UnexpectedPositionShift", JustWarning,
|
|
"Accuracy error or slightly inaccurate position shift.");
|
|
G4cerr << " The Step's starting point has moved "
|
|
<< std::sqrt(moveLenSq)/mm << " mm " << G4endl
|
|
<< " since the last call to a Locate method." << G4endl;
|
|
G4cerr << " This has resulted in moving "
|
|
<< shiftOrigin/mm << " mm "
|
|
<< " from the last point at which the safety "
|
|
<< " was calculated " << G4endl;
|
|
G4cerr << " which is more than the computed safety= "
|
|
<< fPreviousSafety/mm << " mm at that point." << G4endl;
|
|
G4cerr << " This difference is "
|
|
<< diffShiftSaf/mm << " mm." << G4endl
|
|
<< " The tolerated accuracy is "
|
|
<< fAccuracyForException/mm << " mm." << G4endl;
|
|
|
|
static G4int warnNow = 0;
|
|
if( ((++warnNow % 100) == 1) )
|
|
{
|
|
G4cerr << " This problem can be due to either " << G4endl;
|
|
G4cerr << " - a process that has proposed a displacement"
|
|
<< " larger than the current safety , or" << G4endl;
|
|
G4cerr << " - inaccuracy in the computation of the safety"
|
|
<< G4endl;
|
|
G4cerr << " We suggest that you " << G4endl
|
|
<< " - find i) what particle is being tracked, and "
|
|
<< " ii) through what part of your geometry " << G4endl
|
|
<< " for example by re-running this event with "
|
|
<< G4endl
|
|
<< " /tracking/verbose 1 " << G4endl
|
|
<< " - check which processes you declare for"
|
|
<< " this particle (and look at non-standard ones)"
|
|
<< G4endl
|
|
<< " - in case, create a detailed logfile"
|
|
<< " of this event using:" << G4endl
|
|
<< " /tracking/verbose 6 "
|
|
<< G4endl;
|
|
}
|
|
G4cout.precision(oldcoutPrec);
|
|
G4cerr.precision(oldcerrPrec);
|
|
}
|
|
#ifdef G4DEBUG_NAVIGATION
|
|
else
|
|
{
|
|
G4cerr << "WARNING - G4Navigator::ComputeStep()" << G4endl
|
|
<< " The Step's starting point has moved "
|
|
<< std::sqrt(moveLenSq) << "," << G4endl
|
|
<< " which has taken it to the limit of"
|
|
<< " the current safety. " << G4endl;
|
|
}
|
|
#endif
|
|
}
|
|
G4double safetyPlus = fPreviousSafety + fAccuracyForException;
|
|
if ( shiftOriginSafSq > sqr(safetyPlus) )
|
|
{
|
|
G4cerr << "ERROR - G4Navigator::ComputeStep()" << G4endl
|
|
<< " Position has shifted considerably without"
|
|
<< " notifying the navigator !" << G4endl
|
|
<< " Tolerated safety: " << safetyPlus << G4endl
|
|
<< " Computed shift : " << shiftOriginSafSq << G4endl;
|
|
G4Exception("G4Navigator::ComputeStep()",
|
|
"SignificantPositionShift", JustWarning,
|
|
"May lead to a crash or unreliable results.");
|
|
}
|
|
}
|
|
|
|
// ********************************************************************
|
|
// Operator <<
|
|
// ********************************************************************
|
|
//
|
|
std::ostream& operator << (std::ostream &os,const G4Navigator &n)
|
|
{
|
|
os << "Current History: " << G4endl << n.fHistory;
|
|
return os;
|
|
}
|