// // ******************************************************************** // * 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 #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; } // 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; } // 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; }