Files
geant4/source/processes/electromagnetic/dna/management/src/G4ITNavigator.cc2
T
2016-06-10 11:51:14 +02:00

1792 lines
76 KiB
Plaintext

//
// ********************************************************************
// * 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: G4ITNavigator.cc,v 1.46 2010-11-15 14:03:27 gcosmo Exp $
// GEANT4 tag $ Name: $
//
// class G4ITNavigator Implementation
//
// Original author: Paul Kent, July 95/96
//
// G4ITNavigator is a duplicate version of G4Navigator starting from Geant4.9.5
// initially written by Paul Kent and colleagues.
// The only difference resides in the way the information is saved and managed
//
// --------------------------------------------------------------------
#include "G4ITNavigator.hh"
#include "G4ios.hh"
#include <iomanip>
#include "G4GeometryTolerance.hh"
#include "G4VPhysicalVolume.hh"
#define G4DEBUG_NAVIGATION 1
// ********************************************************************
// Constructor
// ********************************************************************
//
G4ITNavigator::G4ITNavigator()
: G4Navigator(), fVerbose(0),
fTopPhysical(0), fCheck(false), fWarnPush(true)
{
fActive= false;
fActionThreshold_NoZeroSteps = 10;
fAbandonThreshold_NoZeroSteps = 25;
kCarTolerance = G4GeometryTolerance::GetInstance()->GetSurfaceTolerance();
fregularNav.SetNormalNavigation( &fnormalNav );
fpNavigatorState = 0;
CheckMode(true);
// this->SetVerboseLevel(3);
// this->CheckMode(true);
}
// !>
G4ITNavigator::G4NavigatorState::G4NavigatorState() : G4ITNavigatorState_Lock()
{
Reset();
}
void G4ITNavigator::G4NavigatorState::Reset()
{
fHistory.Reset();
fLastTriedStepComputation= false;
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;
fStepEndPoint = G4ThreeVector( kInfinity, kInfinity, kInfinity );
fLastStepEndPointLocal = G4ThreeVector( kInfinity, kInfinity, kInfinity );
fpBlockedPhysicalVolume = 0;
fBlockedReplicaNo = -1;
fLastLocatedPointLocal = G4ThreeVector( kInfinity, -kInfinity, 0.0 );
fLocatedOutsideWorld = false;
}
G4ITNavigator::G4NavigatorState::G4NavigatorState(const G4NavigatorState& rhs) : G4ITNavigatorState_Lock()
{
fExitNormal = rhs.fExitNormal;
fValidExitNormal = rhs.fValidExitNormal;
fExiting = rhs.fExiting;
fEntering = rhs.fEntering;
fpBlockedPhysicalVolume = rhs.fpBlockedPhysicalVolume;
fBlockedReplicaNo = rhs.fBlockedReplicaNo,
fLastStepWasZero = rhs.fLastStepWasZero;
fPreviousSftOrigin = rhs.fPreviousSftOrigin;
fPreviousSafety = rhs.fPreviousSafety;
fNumberZeroSteps = rhs.fNumberZeroSteps;
fLocatedOnEdge = rhs.fLocatedOnEdge;
fWasLimitedByGeometry= rhs.fWasLimitedByGeometry;
fPushed=rhs.fPushed;
fNumberZeroSteps=rhs.fNumberZeroSteps;
fEnteredDaughter = rhs.fEnteredDaughter;
fExitedMother = rhs.fExitedMother;
fLastLocatedPointLocal = rhs.fLastLocatedPointLocal;
fLocatedOutsideWorld = rhs.fLocatedOutsideWorld;
}
G4ITNavigator::G4NavigatorState& G4ITNavigator::G4NavigatorState::operator=(const G4NavigatorState& rhs)
{
if(this == &rhs) return *this;
fExitNormal = rhs.fExitNormal;
fValidExitNormal = rhs.fValidExitNormal;
fExiting = rhs.fExiting;
fEntering = rhs.fEntering;
fpBlockedPhysicalVolume = rhs.fpBlockedPhysicalVolume;
fBlockedReplicaNo = rhs.fBlockedReplicaNo,
fLastStepWasZero = rhs.fLastStepWasZero;
fPreviousSftOrigin = rhs.fPreviousSftOrigin;
fPreviousSafety = rhs.fPreviousSafety;
fNumberZeroSteps = rhs.fNumberZeroSteps;
fLocatedOnEdge = rhs.fLocatedOnEdge;
fWasLimitedByGeometry= rhs.fWasLimitedByGeometry;
fPushed=rhs.fPushed;
fNumberZeroSteps=rhs.fNumberZeroSteps;
fEnteredDaughter = rhs.fEnteredDaughter;
fExitedMother = rhs.fExitedMother;
fLastLocatedPointLocal = rhs.fLastLocatedPointLocal;
fLocatedOutsideWorld = rhs.fLocatedOutsideWorld;
return *this;
}
// <!
// ********************************************************************
// Destructor
// ********************************************************************
//
G4ITNavigator::~G4ITNavigator()
{;}
// ********************************************************************
// ResetHierarchyAndLocate
// ********************************************************************
//
G4VPhysicalVolume*
G4ITNavigator::ResetHierarchyAndLocate(const G4ThreeVector & p,
const G4ThreeVector & direction,
const G4TouchableHistory & h)
{
fpNavigatorState->fHistory = *h.GetHistory();
SetupHierarchy();
fpNavigatorState->fLastTriedStepComputation= false; // Redundant, but best
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)
// fpNavigatorState->fEntering - True if entering `daughter' volume (or replica)
// whether daughter of last mother directly
// or daughter of that volume's ancestor.
// ********************************************************************
//
G4VPhysicalVolume*
G4ITNavigator::LocateGlobalPointAndSetup( const G4ThreeVector& globalPoint,
const G4ThreeVector* pGlobalDirection,
const G4bool relativeSearch,
const G4bool ignoreDirection )
{
CheckNavigatorStateIsValid();
G4bool notKnownContained=true, noResult;
G4VPhysicalVolume *targetPhysical;
G4LogicalVolume *targetLogical;
G4VSolid *targetSolid=0;
G4ThreeVector localPoint, globalDirection;
EInside insideCode;
G4bool considerDirection = (!ignoreDirection) || fpNavigatorState->fLocatedOnEdge;
fpNavigatorState->fLastTriedStepComputation= false;
if( considerDirection && pGlobalDirection != 0 )
{
globalDirection=*pGlobalDirection;
}
#ifdef G4VERBOSE
if( fVerbose > 2 )
{
G4int oldcoutPrec = G4cout.precision(8);
G4cout << "*** G4ITNavigator::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 )
{
fpNavigatorState->Reset();
// ResetStackAndState();
}
else
{
if ( fpNavigatorState->fWasLimitedByGeometry )
{
fpNavigatorState->fWasLimitedByGeometry = false;
fpNavigatorState->fEnteredDaughter = fpNavigatorState->fEntering; // Remember
fpNavigatorState->fExitedMother = fpNavigatorState->fExiting; // Remember
if ( fpNavigatorState->fExiting )
{
if ( fpNavigatorState->fHistory.GetDepth() )
{
fpNavigatorState->fpBlockedPhysicalVolume = fpNavigatorState->fHistory.GetTopVolume();
fpNavigatorState->fBlockedReplicaNo = fpNavigatorState->fHistory.GetTopReplicaNo();
fpNavigatorState->fHistory.BackLevel();
}
else
{
fpNavigatorState->fLastLocatedPointLocal = localPoint;
fpNavigatorState->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 ( fpNavigatorState->fLocatedOnEdge && (VolumeType(fpNavigatorState->fpBlockedPhysicalVolume)!=kReplica ))
{
fpNavigatorState->fExiting= false;
}
}
else
if ( fpNavigatorState->fEntering )
{
switch (VolumeType(fpNavigatorState->fpBlockedPhysicalVolume))
{
case kNormal:
fpNavigatorState->fHistory.NewLevel(fpNavigatorState->fpBlockedPhysicalVolume, kNormal,
fpNavigatorState->fpBlockedPhysicalVolume->GetCopyNo());
break;
case kReplica:
freplicaNav.ComputeTransformation(fpNavigatorState->fBlockedReplicaNo,
fpNavigatorState->fpBlockedPhysicalVolume);
fpNavigatorState->fHistory.NewLevel(fpNavigatorState->fpBlockedPhysicalVolume, kReplica,
fpNavigatorState->fBlockedReplicaNo);
fpNavigatorState->fpBlockedPhysicalVolume->SetCopyNo(fpNavigatorState->fBlockedReplicaNo);
break;
case kParameterised:
if( fpNavigatorState->fpBlockedPhysicalVolume->GetRegularStructureId() == 0 )
{
G4VSolid *pSolid;
G4VPVParameterisation *pParam;
G4TouchableHistory parentTouchable( fpNavigatorState->fHistory );
pParam = fpNavigatorState->fpBlockedPhysicalVolume->GetParameterisation();
pSolid = pParam->ComputeSolid(fpNavigatorState->fBlockedReplicaNo,
fpNavigatorState->fpBlockedPhysicalVolume);
pSolid->ComputeDimensions(pParam, fpNavigatorState->fBlockedReplicaNo,
fpNavigatorState->fpBlockedPhysicalVolume);
pParam->ComputeTransformation(fpNavigatorState->fBlockedReplicaNo,
fpNavigatorState->fpBlockedPhysicalVolume);
fpNavigatorState->fHistory.NewLevel(fpNavigatorState->fpBlockedPhysicalVolume, kParameterised,
fpNavigatorState->fBlockedReplicaNo);
fpNavigatorState->fpBlockedPhysicalVolume->SetCopyNo(fpNavigatorState->fBlockedReplicaNo);
//
// Set the correct solid and material in Logical Volume
//
G4LogicalVolume *pLogical;
pLogical = fpNavigatorState->fpBlockedPhysicalVolume->GetLogicalVolume();
pLogical->SetSolid( pSolid );
pLogical->UpdateMaterial(pParam ->
ComputeMaterial(fpNavigatorState->fBlockedReplicaNo,
fpNavigatorState->fpBlockedPhysicalVolume,
&parentTouchable));
}
break;
}
fpNavigatorState->fEntering = false;
fpNavigatorState->fpBlockedPhysicalVolume = 0;
localPoint = fpNavigatorState->fHistory.GetTopTransform().TransformPoint(globalPoint);
notKnownContained = false;
}
}
else
{
fpNavigatorState->fpBlockedPhysicalVolume = 0;
fpNavigatorState->fEntering = false;
fpNavigatorState->fEnteredDaughter = false; // Full Step was not taken, did not enter
fpNavigatorState->fExiting = false;
fpNavigatorState->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 ( fpNavigatorState->fHistory.GetTopVolumeType()!=kReplica )
{
targetSolid = fpNavigatorState->fHistory.GetTopVolume()->GetLogicalVolume()->GetSolid();
localPoint = fpNavigatorState->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 << "*** G4ITNavigator::LocateGlobalPointAndSetup(): ***" << G4endl
<< " Invoked Inside() for solid: " << targetSolid->GetName()
<< ". Solid replied: " << solidResponse << G4endl
<< " For local point p: " << localPoint << G4endl;
}
#endif
}
else
{
insideCode = freplicaNav.BackLocate(fpNavigatorState->fHistory, globalPoint, localPoint,
fpNavigatorState->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 ( fpNavigatorState->fHistory.GetDepth() )
{
fpNavigatorState->fpBlockedPhysicalVolume = fpNavigatorState->fHistory.GetTopVolume();
fpNavigatorState->fBlockedReplicaNo = fpNavigatorState->fHistory.GetTopReplicaNo();
fpNavigatorState->fHistory.BackLevel();
fpNavigatorState->fExiting = false;
}
else
{
fpNavigatorState->fLastLocatedPointLocal = localPoint;
fpNavigatorState->fLocatedOutsideWorld = true;
return 0; // Have exited world volume
}
}
else
if ( insideCode==kSurface )
{
G4bool isExiting = fpNavigatorState->fExiting;
if( (!fpNavigatorState->fExiting)&&considerDirection )
{
// Figure out whether we are exiting this level's volume
// by using the direction
//
G4bool directionExiting = false;
G4ThreeVector localDirection =
fpNavigatorState->fHistory.GetTopTransform().TransformAxis(globalDirection);
if ( fpNavigatorState->fHistory.GetTopVolumeType()!=kReplica )
{
G4ThreeVector normal = targetSolid->SurfaceNormal(localPoint);
directionExiting = normal.dot(localDirection) > 0.0;
isExiting = isExiting || directionExiting;
}
}
if( isExiting )
{
if ( fpNavigatorState->fHistory.GetDepth() )
{
fpNavigatorState->fpBlockedPhysicalVolume = fpNavigatorState->fHistory.GetTopVolume();
fpNavigatorState->fBlockedReplicaNo = fpNavigatorState->fHistory.GetTopReplicaNo();
fpNavigatorState->fHistory.BackLevel();
//
// Still on surface but exited volume not necessarily convex
//
fpNavigatorState->fValidExitNormal = false;
}
else
{
fpNavigatorState->fLastLocatedPointLocal = localPoint;
fpNavigatorState->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 fpNavigatorState->fpBlockedPhysicalVolume/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 = fpNavigatorState->fHistory.GetTopVolume();
if (!targetPhysical) { break; }
targetLogical = targetPhysical->GetLogicalVolume();
switch( CharacteriseDaughters(targetLogical) )
{
case kNormal:
if ( targetLogical->GetVoxelHeader() ) // use optimised navigation
{
noResult = fvoxelNav.LevelLocate(fpNavigatorState->fHistory,
fpNavigatorState->fpBlockedPhysicalVolume,
fpNavigatorState->fBlockedReplicaNo,
globalPoint,
pGlobalDirection,
considerDirection,
localPoint);
}
else // do not use optimised navigation
{
noResult = fnormalNav.LevelLocate(fpNavigatorState->fHistory,
fpNavigatorState->fpBlockedPhysicalVolume,
fpNavigatorState->fBlockedReplicaNo,
globalPoint,
pGlobalDirection,
considerDirection,
localPoint);
}
break;
case kReplica:
noResult = freplicaNav.LevelLocate(fpNavigatorState->fHistory,
fpNavigatorState->fpBlockedPhysicalVolume,
fpNavigatorState->fBlockedReplicaNo,
globalPoint,
pGlobalDirection,
considerDirection,
localPoint);
break;
case kParameterised:
if( GetDaughtersRegularStructureId(targetLogical) != 1 )
{
noResult = fparamNav.LevelLocate(fpNavigatorState->fHistory,
fpNavigatorState->fpBlockedPhysicalVolume,
fpNavigatorState->fBlockedReplicaNo,
globalPoint,
pGlobalDirection,
considerDirection,
localPoint);
}
else // Regular structure
{
noResult = fregularNav.LevelLocate(fpNavigatorState->fHistory,
fpNavigatorState->fpBlockedPhysicalVolume,
fpNavigatorState->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
//
fpNavigatorState->fpBlockedPhysicalVolume = 0;
fpNavigatorState->fBlockedReplicaNo = -1;
// fpNavigatorState->fEntering should be false -- else blockedVolume is assumed good.
// fpNavigatorState->fEnteredDaughter is used for ExitNormal
//
fpNavigatorState->fEntering = false;
fpNavigatorState->fEnteredDaughter = true;
#ifdef G4DEBUG_NAVIGATION
if( fVerbose > 2 )
{
G4VPhysicalVolume* enteredPhysical = fpNavigatorState->fHistory.GetTopVolume();
G4cout << "*** G4ITNavigator::LocateGlobalPointAndSetup() ***" << G4endl;
G4cout << " Entering volume: " << enteredPhysical->GetName()
<< G4endl;
}
#endif
}
} while (noResult);
fpNavigatorState->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 << fpNavigatorState->fHistory << G4endl << G4endl;
#endif
G4cout.precision(oldcoutPrec);
}
#endif
fpNavigatorState->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
G4ITNavigator::LocateGlobalPointWithinVolume(const G4ThreeVector& pGlobalpoint)
{
CheckNavigatorStateIsValid();
fpNavigatorState->fLastLocatedPointLocal = ComputeLocalPoint(pGlobalpoint);
fpNavigatorState->fLastTriedStepComputation= false;
#ifdef G4DEBUG_NAVIGATION
if( fVerbose > 2 )
{
G4cout << "Entering LocateGlobalWithinVolume(): History = " << G4endl;
G4cout << fpNavigatorState->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 = fpNavigatorState->fHistory.GetTopVolume();
G4LogicalVolume* motherLogical = motherPhysical->GetLogicalVolume();
G4SmartVoxelHeader* pVoxelHeader = motherLogical->GetVoxelHeader();
if ( fpNavigatorState->fHistory.GetTopVolumeType()!=kReplica )
{
switch( CharacteriseDaughters(motherLogical) )
{
case kNormal:
if ( pVoxelHeader )
{
fvoxelNav.VoxelLocate( pVoxelHeader, fpNavigatorState->fLastLocatedPointLocal );
}
break;
case kParameterised:
if( GetDaughtersRegularStructureId(motherLogical) != 1 )
{
// Resets state & returns voxel node
//
fparamNav.ParamVoxelLocate( pVoxelHeader, fpNavigatorState->fLastLocatedPointLocal );
}
break;
case kReplica:
G4Exception("G4ITNavigator::LocateGlobalPointWithinVolume()",
"GeomNav0001", 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'.
//
fpNavigatorState->fpBlockedPhysicalVolume = 0;
fpNavigatorState->fBlockedReplicaNo = -1;
fpNavigatorState->fEntering = false;
fpNavigatorState->fEnteredDaughter = false; // Boundary not encountered, did not enter
fpNavigatorState->fExiting = false;
fpNavigatorState->fExitedMother = false; // Boundary not encountered, did not exit
}
// !>
void G4ITNavigator::CheckNavigatorState() const
{
if(fpNavigatorState == 0)
{
G4ExceptionDescription exceptionDescription;
exceptionDescription << "The navigator state is NULL. ";
exceptionDescription << "Either NewNavigatorStateAndLocate was not called ";
exceptionDescription << "or the provided navigator state was already NULL.";
G4Exception("G4ITNavigator::CheckNavigatorStateIsValid",
"NavigatorStateNotValid",FatalException,exceptionDescription);
return;
}
}
G4ITNavigatorState_Lock* G4ITNavigator::GetNavigatorState()
{
return fpNavigatorState;
}
void G4ITNavigator::SetNavigatorState(G4ITNavigatorState_Lock* navState)
{
fpNavigatorState = (G4NavigatorState*) navState;
if(fpNavigatorState) SetupHierarchy();
}
void G4ITNavigator::NewNavigatorState()
{
fpNavigatorState = new G4NavigatorState();
if(fTopPhysical == 0)
{
G4ExceptionDescription exceptionDescription;
exceptionDescription << "No World Volume";
G4Exception("G4ITNavigator::NewNavigatorState",
"NoWorldVolume",FatalException,exceptionDescription);
return;
}
fpNavigatorState->fHistory.SetFirstEntry(fTopPhysical );
SetupHierarchy();
}
G4VPhysicalVolume* G4ITNavigator::NewNavigatorStateAndLocate(const G4ThreeVector &p,
const G4ThreeVector &direction)
{
fpNavigatorState = new G4NavigatorState();
if(fTopPhysical == 0)
{
G4ExceptionDescription exceptionDescription;
exceptionDescription << "No World Volume";
G4Exception("G4ITNavigator::NewNavigatorStateAndLocate",
"NoWorldVolume",FatalException,exceptionDescription);
return 0;
}
fpNavigatorState->fHistory.SetFirstEntry(fTopPhysical );
SetupHierarchy();
return LocateGlobalPointAndSetup(p, &direction, true, false);
}
// ********************************************************************
// SetSavedState
//
// Save the state, in case this is a parasitic call
// Save fpNavigatorState->fValidExitNormal, fpNavigatorState->fExitNormal, fpNavigatorState->fExiting, fpNavigatorState->fEntering,
// fpNavigatorState->fpBlockedPhysicalVolume, fpNavigatorState->fBlockedReplicaNo, fpNavigatorState->fLastStepWasZero;
// ********************************************************************
//
void G4ITNavigator::SetSavedState()
{
fSaveState = *fpNavigatorState;
}
// ********************************************************************
// RestoreSavedState
//
// Restore the state (in Compute Step), in case this is a parasitic call
// ********************************************************************
//
void G4ITNavigator::RestoreSavedState()
{
*fpNavigatorState = fSaveState;
}
// <!
// ********************************************************************
// ComputeStep
//
// Computes the next geometric Step: intersections with current
// mother and `daughter' volumes.
//
// NOTE:
//
// Flags on entry:
// --------------
// fpNavigatorState->fValidExitNormal - Normal of exited volume is valid (convex, not a
// coincident boundary)
// fpNavigatorState->fExitNormal - Surface normal of exited volume
// fpNavigatorState->fExiting - True if have exited solid
//
// fpNavigatorState->fpBlockedPhysicalVolume - Ptr to exited volume (or 0)
// fpNavigatorState->fBlockedReplicaNo - Replication no of exited volume
// fpNavigatorState->fLastStepWasZero - True if last Step size was zero.
//
// Flags on exit:
// -------------
// fpNavigatorState->fValidExitNormal - True if surface normal of exited volume is valid
// fpNavigatorState->fExitNormal - Surface normal of exited volume rotated to mothers
// reference system
// fpNavigatorState->fExiting - True if exiting mother
// fpNavigatorState->fEntering - True if entering `daughter' volume (or replica)
// fpNavigatorState->fpBlockedPhysicalVolume - Ptr to candidate (entered) volume
// fpNavigatorState->fBlockedReplicaNo - Replication no of candidate (entered) volume
// fpNavigatorState->fLastStepWasZero - True if this Step size was zero.
// ********************************************************************
//
G4double G4ITNavigator::ComputeStep( const G4ThreeVector &pGlobalpoint,
const G4ThreeVector &pDirection,
const G4double pCurrentProposedStepLength,
G4double &pNewSafety)
{
CheckNavigatorStateIsValid();
G4ThreeVector localDirection = ComputeLocalAxis(pDirection);
G4double Step = kInfinity;
G4VPhysicalVolume *motherPhysical = fpNavigatorState->fHistory.GetTopVolume();
G4LogicalVolume *motherLogical = motherPhysical->GetLogicalVolume();
static G4int sNavCScalls=0;
sNavCScalls++;
fpNavigatorState->fLastTriedStepComputation= true;
#ifdef G4VERBOSE
if( fVerbose > 0 )
{
G4cout << "*** G4ITNavigator::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 != fpNavigatorState->fLastLocatedPointLocal )
{
// Check whether the relocation is within safety
//
G4ThreeVector oldLocalPoint = fpNavigatorState->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 );
fpNavigatorState->fLastTriedStepComputation= true; // Ensure that this is set again !!
}
}
if ( fpNavigatorState->fHistory.GetTopVolumeType()!=kReplica )
{
switch( CharacteriseDaughters(motherLogical) )
{
case kNormal:
if ( motherLogical->GetVoxelHeader() )
{
Step = fvoxelNav.ComputeStep(fpNavigatorState->fLastLocatedPointLocal,
localDirection,
pCurrentProposedStepLength,
pNewSafety,
fpNavigatorState->fHistory,
fpNavigatorState->fValidExitNormal,
fpNavigatorState->fExitNormal,
fpNavigatorState->fExiting,
fpNavigatorState->fEntering,
&fpNavigatorState->fpBlockedPhysicalVolume,
fpNavigatorState->fBlockedReplicaNo);
}
else
{
if( motherPhysical->GetRegularStructureId() == 0 )
{
Step = fnormalNav.ComputeStep(fpNavigatorState->fLastLocatedPointLocal,
localDirection,
pCurrentProposedStepLength,
pNewSafety,
fpNavigatorState->fHistory,
fpNavigatorState->fValidExitNormal,
fpNavigatorState->fExitNormal,
fpNavigatorState->fExiting,
fpNavigatorState->fEntering,
&fpNavigatorState->fpBlockedPhysicalVolume,
fpNavigatorState->fBlockedReplicaNo);
}
else // Regular (non-voxelised) structure
{
LocateGlobalPointAndSetup( pGlobalpoint, &pDirection, true, true );
fpNavigatorState->fLastTriedStepComputation= true; // Ensure that this is set again !!
//
// 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(fpNavigatorState->fHistory.GetTopVolume()->GetRegularStructureId() == 0 )
{
G4Exception("G4ITNavigator::ComputeStep()",
"GeomNav1001", JustWarning,
"Point is relocated in voxels, while it should be outside!");
Step = fnormalNav.ComputeStep(fpNavigatorState->fLastLocatedPointLocal,
localDirection,
pCurrentProposedStepLength,
pNewSafety,
fpNavigatorState->fHistory,
fpNavigatorState->fValidExitNormal,
fpNavigatorState->fExitNormal,
fpNavigatorState->fExiting,
fpNavigatorState->fEntering,
&fpNavigatorState->fpBlockedPhysicalVolume,
fpNavigatorState->fBlockedReplicaNo);
}
else
{
Step = fregularNav.
ComputeStepSkippingEqualMaterials(fpNavigatorState->fLastLocatedPointLocal,
localDirection,
pCurrentProposedStepLength,
pNewSafety,
fpNavigatorState->fHistory,
fpNavigatorState->fValidExitNormal,
fpNavigatorState->fExitNormal,
fpNavigatorState->fExiting,
fpNavigatorState->fEntering,
&fpNavigatorState->fpBlockedPhysicalVolume,
fpNavigatorState->fBlockedReplicaNo,
motherPhysical);
}
}
}
break;
case kParameterised:
if( GetDaughtersRegularStructureId(motherLogical) != 1 )
{
Step = fparamNav.ComputeStep(fpNavigatorState->fLastLocatedPointLocal,
localDirection,
pCurrentProposedStepLength,
pNewSafety,
fpNavigatorState->fHistory,
fpNavigatorState->fValidExitNormal,
fpNavigatorState->fExitNormal,
fpNavigatorState->fExiting,
fpNavigatorState->fEntering,
&fpNavigatorState->fpBlockedPhysicalVolume,
fpNavigatorState->fBlockedReplicaNo);
}
else // Regular structure
{
Step = fregularNav.ComputeStep(fpNavigatorState->fLastLocatedPointLocal,
localDirection,
pCurrentProposedStepLength,
pNewSafety,
fpNavigatorState->fHistory,
fpNavigatorState->fValidExitNormal,
fpNavigatorState->fExitNormal,
fpNavigatorState->fExiting,
fpNavigatorState->fEntering,
&fpNavigatorState->fpBlockedPhysicalVolume,
fpNavigatorState->fBlockedReplicaNo);
}
break;
case kReplica:
G4Exception("G4ITNavigator::ComputeStep()", "GeomNav0001",
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 = fpNavigatorState->fExitedMother;
Step = freplicaNav.ComputeStep(pGlobalpoint,
pDirection,
fpNavigatorState->fLastLocatedPointLocal,
localDirection,
pCurrentProposedStepLength,
pNewSafety,
fpNavigatorState->fHistory,
fpNavigatorState->fValidExitNormal,
fpNavigatorState->fExitNormal,
exitingReplica,
fpNavigatorState->fEntering,
&fpNavigatorState->fpBlockedPhysicalVolume,
fpNavigatorState->fBlockedReplicaNo);
fpNavigatorState->fExiting= exitingReplica; // still ok to set it ??
}
// Remember last safety origin & value.
//
fpNavigatorState->fPreviousSftOrigin = pGlobalpoint;
fpNavigatorState->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
//
fpNavigatorState->fLocatedOnEdge = fpNavigatorState->fLastStepWasZero && (Step==0.0);
fpNavigatorState->fLastStepWasZero = (Step==0.0);
if (fpNavigatorState->fPushed) fpNavigatorState->fPushed = fpNavigatorState->fLastStepWasZero;
// Handle large number of consecutive zero steps
//
if ( fpNavigatorState->fLastStepWasZero )
{
fpNavigatorState->fNumberZeroSteps++;
#ifdef G4DEBUG_NAVIGATION
if( fpNavigatorState->fNumberZeroSteps > 1 )
{
G4cout << "G4ITNavigator::ComputeStep(): another zero step, # "
<< fpNavigatorState->fNumberZeroSteps
<< " at " << pGlobalpoint
<< " in volume " << motherPhysical->GetName()
<< " nav-comp-step calls # " << sNavCScalls
<< G4endl;
}
#endif
if( fpNavigatorState->fNumberZeroSteps > fActionThreshold_NoZeroSteps-1 )
{
// Act to recover this stuck track. Pushing it along direction
//
Step += 100*kCarTolerance;
#ifdef G4VERBOSE
if ((!fpNavigatorState->fPushed) && (fWarnPush))
{
std::ostringstream message;
message << "Track stuck or not moving." << G4endl
<< " Track stuck, not moving for "
<< fpNavigatorState->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 ...";
G4Exception("G4ITNavigator::ComputeStep()", "GeomNav1002",
JustWarning, message, "Potential overlap in geometry!");
}
#endif
fpNavigatorState->fPushed = true;
}
if( fpNavigatorState->fNumberZeroSteps > fAbandonThreshold_NoZeroSteps-1 )
{
// Must kill this stuck track
//
std::ostringstream message;
message << "Stuck Track: potential geometry or navigation problem."
<< G4endl
<< " Track stuck, not moving for "
<< fpNavigatorState->fNumberZeroSteps << " steps" << G4endl
<< " in volume -" << motherPhysical->GetName()
<< "- at point " << pGlobalpoint << G4endl
<< " direction: " << pDirection << ".";
motherPhysical->CheckOverlaps(5000, false);
G4Exception("G4ITNavigator::ComputeStep()", "GeomNav0003",
EventMustBeAborted, message);
}
}
else
{
if (!fpNavigatorState->fPushed) fpNavigatorState->fNumberZeroSteps = 0;
}
fpNavigatorState->fEnteredDaughter = fpNavigatorState->fEntering; // I expect to enter a volume in this Step
fpNavigatorState->fExitedMother = fpNavigatorState->fExiting;
fpNavigatorState->fStepEndPoint = pGlobalpoint + Step * pDirection;
fpNavigatorState->fLastStepEndPointLocal = fpNavigatorState->fLastLocatedPointLocal + Step * localDirection;
if( fpNavigatorState->fExiting )
{
#ifdef G4DEBUG_NAVIGATION
if( fVerbose > 2 )
{
G4cout << " At G4Nav CompStep End - if(exiting) - fpNavigatorState->fExiting= " << fpNavigatorState->fExiting
<< " fpNavigatorState->fValidExitNormal = " << fpNavigatorState->fValidExitNormal << G4endl;
G4cout << " fpNavigatorState->fExitNormal= " << fpNavigatorState->fExitNormal << G4endl;
}
#endif
if(fpNavigatorState->fValidExitNormal)
{
// Convention: fpNavigatorState->fExitNormal is in the 'grand-mother' coordinate system
//
fpNavigatorState->fGrandMotherExitNormal= fpNavigatorState->fExitNormal;
}
else
{
// We must calculate the normal anyway (in order to have it if requested)
//
G4ThreeVector finalLocalPoint =
fpNavigatorState->fLastLocatedPointLocal + localDirection*Step;
// Now fpNavigatorState->fGrandMotherExitNormal is in the 'grand-mother' coordinate system
//
fpNavigatorState->fGrandMotherExitNormal =
motherLogical->GetSolid()->SurfaceNormal(finalLocalPoint);
const G4RotationMatrix* mRot = motherPhysical->GetRotation();
if( mRot )
{
fpNavigatorState->fGrandMotherExitNormal *= (*mRot).inverse();
}
// Do not set fpNavigatorState->fValidExitNormal -- this signifies that the solid is convex!
}
}
fpNavigatorState->fStepEndPoint= pGlobalpoint+Step*pDirection;
if( (Step == pCurrentProposedStepLength) && (!fpNavigatorState->fExiting) && (!fpNavigatorState->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 G4ITNavigator::CheckNextStep( const G4ThreeVector& pGlobalpoint,
const G4ThreeVector& pDirection,
const G4double pCurrentProposedStepLength,
G4double& pNewSafety)
{
G4double step;
CheckNavigatorStateIsValid();
// Save the state, for this parasitic call
//
SetSavedState();
// fSaveState = *fpNavigatorState;
step = ComputeStep ( pGlobalpoint,
pDirection,
pCurrentProposedStepLength,
pNewSafety );
// If a parasitic call, then attempt to restore the key parts of the state
//
RestoreSavedState();
// *fpNavigatorState = fSaveState;
return step;
}
// ********************************************************************
// ResetState
//
// Resets stack and minimum of navigator state `machine'
// ********************************************************************
//
void G4ITNavigator::ResetState()
{
G4Exception("G4ITNavigator::ResetState()",
"ResetState", FatalException,
"G4ITNavigator::ResetState() not supported");
}
// ********************************************************************
// SetupHierarchy
//
// Renavigates & resets hierarchy described by current history
// o Reset volumes
// o Recompute transforms and/or solids of replicated/parameterised volumes
// ********************************************************************
//
void G4ITNavigator::SetupHierarchy()
{
G4int i;
const G4int cdepth = fpNavigatorState->fHistory.GetDepth();
G4VPhysicalVolume *current;
G4VSolid *pSolid;
G4VPVParameterisation *pParam;
for ( i=1; i<=cdepth; i++ )
{
current = fpNavigatorState->fHistory.GetVolume(i);
switch ( fpNavigatorState->fHistory.GetVolumeType(i) )
{
case kNormal:
break;
case kReplica:
freplicaNav.ComputeTransformation(fpNavigatorState->fHistory.GetReplicaNo(i), current);
break;
case kParameterised:
G4int replicaNo;
pParam = current->GetParameterisation();
replicaNo = fpNavigatorState->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( fpNavigatorState->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;
}
}
}
// ********************************************************************
// GetLocalExitNormal
//
// Obtains the Normal vector to a surface (in local coordinates)
// pointing out of previous volume and into current volume
// ********************************************************************
//
G4ThreeVector G4ITNavigator::GetLocalExitNormal( G4bool* valid )
{
CheckNavigatorStateIsValid();
G4ThreeVector ExitNormal(0.,0.,0.);
G4VSolid *currentSolid=0;
G4LogicalVolume *candidateLogical;
if ( fpNavigatorState->fLastTriedStepComputation )
{
// use fpNavigatorState->fLastLocatedPointLocal
// and next candidate volume
G4ThreeVector nextSolidExitNormal(0.,0.,0.);
if( fpNavigatorState->fEntering && (fpNavigatorState->fpBlockedPhysicalVolume!=0) )
{
candidateLogical= fpNavigatorState->fpBlockedPhysicalVolume->GetLogicalVolume();
if( candidateLogical )
{
// fpNavigatorState->fLastStepEndPointLocal is in the coordinates of the mother
// we need it in the daughter's coordinate system.
if( CharacteriseDaughters(candidateLogical) != kReplica )
{
// First transform fpNavigatorState->fLastLocatedPointLocal to the new daughter
// coordinates
G4AffineTransform MotherToDaughterTransform=
GetMotherToDaughterTransform( fpNavigatorState->fpBlockedPhysicalVolume,
fpNavigatorState->fBlockedReplicaNo,
VolumeType(fpNavigatorState->fpBlockedPhysicalVolume) );
G4ThreeVector daughterPointOwnLocal=
MotherToDaughterTransform.TransformPoint( fpNavigatorState->fLastStepEndPointLocal );
// OK if it is a parameterised volume
//
EInside inSideIt;
G4bool onSurface;
G4double safety= -1.0;
currentSolid= candidateLogical->GetSolid();
inSideIt = currentSolid->Inside(daughterPointOwnLocal);
onSurface = (inSideIt == kSurface);
if( ! onSurface )
{
if( inSideIt == kOutside )
{
safety = (currentSolid->DistanceToIn(daughterPointOwnLocal));
onSurface = safety < 100.0 * kCarTolerance;
}
else if (inSideIt == kInside )
{
safety = (currentSolid->DistanceToOut(daughterPointOwnLocal));
onSurface = safety < 100.0 * kCarTolerance;
}
}
if( onSurface )
{
nextSolidExitNormal =
currentSolid->SurfaceNormal(daughterPointOwnLocal);
// Entering the solid ==> opposite
//
ExitNormal = -nextSolidExitNormal;
}
else
{
#ifdef G4VERBOSE
if(( fVerbose == 1 ) && ( fCheck ))
{
std::ostringstream message;
message << "Point not on surface ! " << G4endl
<< " Point = "
<< daughterPointOwnLocal << G4endl
<< " Physical volume = "
<< fpNavigatorState->fpBlockedPhysicalVolume->GetName() << G4endl
<< " Logical volume = "
<< candidateLogical->GetName() << G4endl
<< " Solid = " << currentSolid->GetName()
<< " Type = "
<< currentSolid->GetEntityType() << G4endl
<< *currentSolid << G4endl;
if( inSideIt == kOutside )
{
message << "Point is Outside. " << G4endl
<< " Safety (from outside) = " << safety << G4endl;
}
else // if( inSideIt == kInside )
{
message << "Point is Inside. " << G4endl
<< " Safety (from inside) = " << safety << G4endl;
}
G4Exception("G4ITNavigator::GetLocalExitNormal()", "GeomNav1001",
JustWarning, message);
}
#endif
}
*valid = onSurface; // was =true;
}
else
{
*valid = false; // TODO: Need Separate code for replica!!!!
#ifdef G4DEBUG_NAVIGATION
G4Exception("G4ITNavigator::GetLocalExitNormal()", "GeomNav0001",
FatalException,
"Local normal not (yet) available for replica volumes.");
#endif
}
}
}
else if ( fpNavigatorState->fExiting )
{
ExitNormal = fpNavigatorState->fGrandMotherExitNormal;
*valid = true;
}
else // ie ( fpNavigatorState->fpBlockedPhysicalVolume == 0 )
{
*valid = false;
}
}
else
{
if ( EnteredDaughterVolume() )
{
ExitNormal= -(fpNavigatorState->fHistory.GetTopVolume()->GetLogicalVolume()->
GetSolid()->SurfaceNormal(fpNavigatorState->fLastLocatedPointLocal));
*valid = true;
}
else
{
if( fpNavigatorState->fExitedMother )
{
ExitNormal = fpNavigatorState->fGrandMotherExitNormal;
*valid = true;
}
else // We are not at a boundary. ExitNormal remains (0,0,0)
{
*valid = false;
}
}
}
return ExitNormal;
}
// ********************************************************************
// GetMotherToDaughterTransform
//
// Obtains the mother to daughter affine transformation
// ********************************************************************
//
G4AffineTransform
G4ITNavigator::GetMotherToDaughterTransform( G4VPhysicalVolume *pEnteringPhysVol, // not Const
G4int enteringReplicaNo,
EVolume enteringVolumeType )
{
CheckNavigatorStateIsValid();
switch (enteringVolumeType)
{
case kNormal: // Nothing is needed to prepare the transformation
break; // It is stored already in the physical volume (placement)
case kReplica: // Sets the transform in the Replica - tbc
G4Exception("G4ITNavigator::GetMotherToDaughterTransform()",
"GeomNav0001", FatalException,
"Method NOT Implemented yet for replica volumes.");
break;
case kParameterised:
if( pEnteringPhysVol->GetRegularStructureId() == 0 )
{
G4VPVParameterisation *pParam =
pEnteringPhysVol->GetParameterisation();
G4VSolid* pSolid =
pParam->ComputeSolid(enteringReplicaNo, pEnteringPhysVol);
pSolid->ComputeDimensions(pParam, enteringReplicaNo, pEnteringPhysVol);
// Sets the transform in the Parameterisation
//
pParam->ComputeTransformation(enteringReplicaNo, pEnteringPhysVol);
// Set the correct solid and material in Logical Volume
//
G4LogicalVolume* pLogical = pEnteringPhysVol->GetLogicalVolume();
pLogical->SetSolid( pSolid );
}
break;
}
return G4AffineTransform(pEnteringPhysVol->GetRotation(),
pEnteringPhysVol->GetTranslation()).Invert();
}
// ********************************************************************
// GetLocalExitNormalAndCheck
//
// Obtains the Normal vector to a surface (in local coordinates)
// pointing out of previous volume and into current volume, and
// checks the current point against expected 'local' value.
// ********************************************************************
//
G4ThreeVector G4ITNavigator::
GetLocalExitNormalAndCheck(const G4ThreeVector& ExpectedBoundaryPointGlobal,
G4bool* pValid)
{
CheckNavigatorStateIsValid();
G4ThreeVector ExpectedBoundaryPointLocal;
// Check Current point against expected 'local' value
//
if ( fpNavigatorState->fLastTriedStepComputation )
{
const G4AffineTransform& GlobalToLocal= GetGlobalToLocalTransform();
ExpectedBoundaryPointLocal =
GlobalToLocal.TransformPoint( ExpectedBoundaryPointGlobal );
}
return GetLocalExitNormal( pValid);
}
// ********************************************************************
// GetGlobalExitNormal
//
// Obtains the Normal vector to a surface (in global coordinates)
// pointing out of previous volume and into current volume
// ********************************************************************
//
G4ThreeVector
G4ITNavigator::GetGlobalExitNormal(const G4ThreeVector& IntersectPointGlobal,
G4bool* pValidNormal)
{
CheckNavigatorStateIsValid();
G4bool validNormal;
G4ThreeVector localNormal, globalNormal;
localNormal = GetLocalExitNormalAndCheck( IntersectPointGlobal, &validNormal);
*pValidNormal = validNormal;
G4AffineTransform localToGlobal = GetLocalToGlobalTransform();
globalNormal = localToGlobal.TransformAxis( localNormal );
return globalNormal;
}
// ********************************************************************
// 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 G4ITNavigator::ComputeSafety( const G4ThreeVector &pGlobalpoint,
const G4double pMaxLength,
const G4bool keepState)
{
CheckNavigatorStateIsValid();
G4double newSafety = 0.0;
#ifdef G4DEBUG_NAVIGATION
G4int oldcoutPrec = G4cout.precision(8);
if( fVerbose > 0 )
{
G4cout << "*** G4ITNavigator::ComputeSafety: ***" << G4endl
<< " Called at point: " << pGlobalpoint << G4endl;
G4VPhysicalVolume *motherPhysical = fpNavigatorState->fHistory.GetTopVolume();
G4cout << " Volume = " << motherPhysical->GetName()
<< " - Maximum length = " << pMaxLength << G4endl;
if( fVerbose >= 4 )
{
G4cout << " ----- Upon entering Compute Safety:" << G4endl;
PrintState();
}
}
#endif
if (keepState)
{
// fSaveState = *fpNavigatorState;
SetSavedState();
}
// fpNavigatorState->fLastTriedStepComputation= true; -- this method is NOT computing the Step size
G4double distEndpointSq = (pGlobalpoint-fpNavigatorState->fStepEndPoint).mag2();
G4bool stayedOnEndpoint = distEndpointSq < kCarTolerance*kCarTolerance;
G4bool endpointOnSurface = fpNavigatorState->fEnteredDaughter || fpNavigatorState->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 << " G4ITNavigator::ComputeSafety() relocates-in-volume to point: "
<< pGlobalpoint << G4endl;
}
#endif
G4VPhysicalVolume *motherPhysical = fpNavigatorState->fHistory.GetTopVolume();
G4LogicalVolume *motherLogical = motherPhysical->GetLogicalVolume();
G4SmartVoxelHeader* pVoxelHeader = motherLogical->GetVoxelHeader();
G4ThreeVector localPoint = ComputeLocalPoint(pGlobalpoint);
if ( fpNavigatorState->fHistory.GetTopVolumeType()!=kReplica )
{
switch(CharacteriseDaughters(motherLogical))
{
case kNormal:
if ( pVoxelHeader )
{
newSafety=fvoxelNav.ComputeSafety(localPoint,fpNavigatorState->fHistory,pMaxLength);
}
else
{
newSafety=fnormalNav.ComputeSafety(localPoint,fpNavigatorState->fHistory,pMaxLength);
}
break;
case kParameterised:
if( GetDaughtersRegularStructureId(motherLogical) != 1 )
{
newSafety = fparamNav.ComputeSafety(localPoint,fpNavigatorState->fHistory,pMaxLength);
}
else // Regular structure
{
newSafety = fregularNav.ComputeSafety(localPoint,fpNavigatorState->fHistory,pMaxLength);
}
break;
case kReplica:
G4Exception("G4ITNavigator::ComputeSafety()", "NotApplicable",
FatalException, "Not applicable for replicated volumes.");
break;
}
}
else
{
newSafety = freplicaNav.ComputeSafety(pGlobalpoint, localPoint,
fpNavigatorState->fHistory, pMaxLength);
}
}
else // if( endpointOnSurface && stayedOnEndpoint )
{
#ifdef G4DEBUG_NAVIGATION
if( fVerbose >= 2 )
{
G4cout << " G4ITNavigator::ComputeSafety() finds that point - "
<< pGlobalpoint << " - is on surface " << G4endl;
if( fpNavigatorState->fEnteredDaughter ) { G4cout << " entered new daughter volume"; }
if( fpNavigatorState->fExitedMother ) { G4cout << " and exited previous volume."; }
G4cout << G4endl;
G4cout << " EndPoint was = " << fpNavigatorState->fStepEndPoint << G4endl;
}
#endif
newSafety = 0.0;
}
// Remember last safety origin & value
//
fpNavigatorState->fPreviousSftOrigin = pGlobalpoint;
fpNavigatorState->fPreviousSafety = newSafety;
if (keepState)
{
// *fpNavigatorState = fSaveState;
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 G4ITNavigator::CreateTouchableHistoryHandle() const
{
CheckNavigatorStateIsValid();
return G4TouchableHistoryHandle( CreateTouchableHistory() );
}
// ********************************************************************
// PrintState
// ********************************************************************
//
void G4ITNavigator::PrintState() const
{
CheckNavigatorStateIsValid();
G4int oldcoutPrec = G4cout.precision(4);
if( fVerbose == 4 )
{
G4cout << "The current state of G4ITNavigator is: " << G4endl;
G4cout << " ValidExitNormal= " << fpNavigatorState->fValidExitNormal << G4endl
<< " ExitNormal = " << fpNavigatorState->fExitNormal << G4endl
<< " Exiting = " << fpNavigatorState->fExiting << G4endl
<< " Entering = " << fpNavigatorState->fEntering << G4endl
<< " BlockedPhysicalVolume= " ;
if (fpNavigatorState->fpBlockedPhysicalVolume==0)
G4cout << "None";
else
G4cout << fpNavigatorState->fpBlockedPhysicalVolume->GetName();
G4cout << G4endl
<< " BlockedReplicaNo = " << fpNavigatorState->fBlockedReplicaNo << G4endl
<< " LastStepWasZero = " << fpNavigatorState->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) << fpNavigatorState->fExitNormal.x()
<< ", " << std::setw(7) << fpNavigatorState->fExitNormal.y()
<< ", " << std::setw(7) << fpNavigatorState->fExitNormal.z() << " ) "
<< std::setw( 5) << fpNavigatorState->fValidExitNormal << " "
<< std::setw( 9) << fpNavigatorState->fExiting << " "
<< std::setw( 9) << fpNavigatorState->fEntering << " ";
if ( fpNavigatorState->fpBlockedPhysicalVolume==0 )
G4cout << std::setw(15) << "None";
else
G4cout << std::setw(15)<< fpNavigatorState->fpBlockedPhysicalVolume->GetName();
G4cout << std::setw( 9) << fpNavigatorState->fBlockedReplicaNo << " "
<< std::setw( 8) << fpNavigatorState->fLastStepWasZero << " "
<< G4endl;
}
if( fVerbose > 2 )
{
G4cout.precision(8);
G4cout << " Current Localpoint = " << fpNavigatorState->fLastLocatedPointLocal << G4endl;
G4cout << " PreviousSftOrigin = " << fpNavigatorState->fPreviousSftOrigin << G4endl;
G4cout << " PreviousSafety = " << fpNavigatorState->fPreviousSafety << G4endl;
}
G4cout.precision(oldcoutPrec);
}
// ********************************************************************
// ComputeStepLog
// ********************************************************************
//
void G4ITNavigator::ComputeStepLog(const G4ThreeVector& pGlobalpoint,
G4double moveLenSq) const
{
CheckNavigatorStateIsValid();
// The following checks only make sense if the move is larger
// than the tolerance.
static const G4double fAccuracyForWarning = kCarTolerance,
fAccuracyForException = 1000*kCarTolerance;
G4ThreeVector OriginalGlobalpoint = fpNavigatorState->fHistory.GetTopTransform().Inverse().
TransformPoint(fpNavigatorState->fLastLocatedPointLocal);
G4double shiftOriginSafSq = (fpNavigatorState->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(fpNavigatorState->fPreviousSafety) )
{
G4double shiftOrigin = std::sqrt(shiftOriginSafSq);
G4double diffShiftSaf = shiftOrigin - fpNavigatorState->fPreviousSafety;
if( diffShiftSaf > fAccuracyForWarning )
{
G4int oldcoutPrec= G4cout.precision(8);
G4int oldcerrPrec= G4cerr.precision(10);
std::ostringstream message, suggestion;
message << "Accuracy error or slightly inaccurate position shift."
<< G4endl
<< " The Step's starting point has moved "
<< std::sqrt(moveLenSq)/mm << " mm " << G4endl
<< " since the last call to a Locate method." << G4endl
<< " This has resulted in moving "
<< shiftOrigin/mm << " mm "
<< " from the last point at which the safety "
<< " was calculated " << G4endl
<< " which is more than the computed safety= "
<< fpNavigatorState->fPreviousSafety/mm << " mm at that point." << G4endl
<< " This difference is "
<< diffShiftSaf/mm << " mm." << G4endl
<< " The tolerated accuracy is "
<< fAccuracyForException/mm << " mm.";
suggestion << " ";
static G4int warnNow = 0;
if( ((++warnNow % 100) == 1) )
{
message << G4endl
<< " This problem can be due to either " << G4endl
<< " - a process that has proposed a displacement"
<< " larger than the current safety , or" << G4endl
<< " - inaccuracy in the computation of the safety";
suggestion << "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 ";
}
G4Exception("G4ITNavigator::ComputeStep()",
"GeomNav1002", JustWarning,
message, G4String(suggestion.str()));
G4cout.precision(oldcoutPrec);
G4cerr.precision(oldcerrPrec);
}
#ifdef G4DEBUG_NAVIGATION
else
{
G4cerr << "WARNING - G4ITNavigator::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 = fpNavigatorState->fPreviousSafety + fAccuracyForException;
if ( shiftOriginSafSq > sqr(safetyPlus) )
{
std::ostringstream message;
message << "May lead to a crash or unreliable results." << G4endl
<< " Position has shifted considerably without"
<< " notifying the navigator !" << G4endl
<< " Tolerated safety: " << safetyPlus << G4endl
<< " Computed shift : " << shiftOriginSafSq;
G4Exception("G4ITNavigator::ComputeStep()", "GeomNav1002",
JustWarning, message);
}
}
// ********************************************************************
// Operator <<
// ********************************************************************
//
std::ostream& operator << (std::ostream &os,const G4ITNavigator &n)
{
n.CheckNavigatorState();
os << "Current History: " << G4endl << n.fpNavigatorState->fHistory;
return os;
}