// // ******************************************************************** // * 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: G4CoupledTransportation.cc,v 1.27 2008/11/26 13:01:28 japost Exp $ // --> Merged with 1.60.4.2.2.3 2007/05/09 09:30:28 japost // GEANT4 tag $Name: geant4-09-03 $ // ------------------------------------------------------------ // GEANT 4 class implementation // ======================================================================= // Modified: // 13 May 2006, J. Apostolakis: Revised for parallel navigation (PathFinder) // 19 Jan 2006, P.MoraDeFreitas: Fix for suspended tracks (StartTracking) // 11 Aug 2004, M.Asai: Add G4VSensitiveDetector* for updating stepPoint. // 21 June 2003, J.Apostolakis: Calling field manager with // track, to enable it to configure its accuracy // 13 May 2003, J.Apostolakis: Zero field areas now taken into // account correclty in all cases (thanks to W Pokorski). // 29 June 2001, J.Apostolakis, D.Cote-Ahern, P.Gumplinger: // correction for spin tracking // 20 Febr 2001, J.Apostolakis: update for new FieldTrack // 22 Sept 2000, V.Grichine: update of Kinetic Energy // Created: 19 March 1997, J. Apostolakis // ======================================================================= #include "G4CoupledTransportation.hh" #include "G4ProductionCutsTable.hh" #include "G4ParticleTable.hh" #include "G4ChordFinder.hh" #include "G4FieldManagerStore.hh" class G4VSensitiveDetector; ////////////////////////////////////////////////////////////////////////// // // Constructor G4CoupledTransportation::G4CoupledTransportation( G4int verboseLevel ) : G4VProcess( G4String("CoupledTransportation"), fTransportation ), fParticleIsLooping( false ), fPreviousSftOrigin (0.,0.,0.), fPreviousMassSafety ( 0.0 ), fPreviousFullSafety ( 0.0 ), fThreshold_Warning_Energy( 100 * MeV ), fThreshold_Important_Energy( 250 * MeV ), fThresholdTrials( 10 ), fUnimportant_Energy( 1 * MeV ), fNoLooperTrials(0), fSumEnergyKilled( 0.0 ), fMaxEnergyKilled( 0.0 ), fVerboseLevel(verboseLevel) // ( verboseLevel ? verboseLevel : 2 ) // or 4 { G4TransportationManager* transportMgr ; transportMgr = G4TransportationManager::GetTransportationManager() ; fMassNavigator = transportMgr->GetNavigatorForTracking() ; fFieldPropagator = transportMgr->GetPropagatorInField() ; // fGlobalFieldMgr = transportMgr->GetFieldManager() ; fNavigatorId= transportMgr->ActivateNavigator( fMassNavigator ); if( fVerboseLevel > 0 ){ G4cout << " G4CoupledTransportation constructor: ----- " << G4endl; G4cout << " Verbose level is " << fVerboseLevel << G4endl; G4cout << " Navigator Id obtained in G4CoupledTransportation constructor " << fNavigatorId << G4endl; } fPathFinder= G4PathFinder::GetInstance(); fpSafetyHelper = transportMgr->GetSafetyHelper(); // New // Following assignment is to fix small memory leak from simple use of 'new' static G4TouchableHandle nullTouchableHandle; // Points to (G4VTouchable*) 0 fCurrentTouchableHandle = nullTouchableHandle; // fCurrentTouchableHandle = G4TouchableHandle( 0 ); // new G4TouchableHistory(); fEndGlobalTimeComputed = false; fCandidateEndGlobalTime = 0; } ////////////////////////////////////////////////////////////////////////// G4CoupledTransportation::~G4CoupledTransportation() { // fCurrentTouchableHandle is a data member - no deletion required if( (fVerboseLevel > 0) || (fSumEnergyKilled > 0.0 ) ){ G4cout << " G4CoupledTransportation: Statistics for looping particles " << G4endl; G4cout << " Sum of energy of loopers killed: " << fSumEnergyKilled << G4endl; G4cout << " Max energy of loopers killed: " << fMaxEnergyKilled << G4endl; } } ////////////////////////////////////////////////////////////////////////// // // Responsibilities: // Find whether the geometry limits the Step, and to what length // Calculate the new value of the safety and return it. // Store the final time, position and momentum. G4double G4CoupledTransportation:: AlongStepGetPhysicalInteractionLength( const G4Track& track, G4double, // previousStepSize G4double currentMinimumStep, G4double& proposedSafetyForStart, G4GPILSelection* selection ) { G4double geometryStepLength; G4double startMassSafety= 0.0; // estimated safety for start point (mass geometry) G4double startFullSafety= 0.0; // estimated safety for start point (all geometries) G4double safetyProposal= -1.0; // local copy of proposal G4ThreeVector EndUnitMomentum ; G4double lengthAlongCurve=0.0 ; fParticleIsLooping = false ; // Initial actions moved to StartTrack() // -------------------------------------- // Note: in case another process changes touchable handle // it will be necessary to add here (for all steps) // fCurrentTouchableHandle = aTrack->GetTouchableHandle(); // GPILSelection is set to defaule value of CandidateForSelection // It is a return value // *selection = CandidateForSelection ; // Get initial Energy/Momentum of the track // const G4DynamicParticle* pParticle = track.GetDynamicParticle() ; const G4ParticleDefinition* pParticleDef = pParticle->GetDefinition() ; G4ThreeVector startMomentumDir = pParticle->GetMomentumDirection() ; G4ThreeVector startPosition = track.GetPosition() ; G4VPhysicalVolume* currentVolume= track.GetVolume(); #ifdef G4DEBUG_TRANSPORT if( fVerboseLevel > 1 ) { G4cout << "G4CoupledTransportation::AlongStepGPIL> called in volume " << currentVolume->GetName() << G4endl; } #endif // G4double theTime = track.GetGlobalTime() ; // The Step Point safety can be limited by other geometries and/or the // assumptions of any process - it's not always the geometrical safety. // We calculate the starting point's isotropic safety here. // G4ThreeVector OriginShift = startPosition - fPreviousSftOrigin ; G4double MagSqShift = OriginShift.mag2() ; startMassSafety = 0.0; startFullSafety= 0.0; // Recall that FullSafety <= MassSafety // Original: if( MagSqShift < sqr(fPreviousMassSafety) ) { if( MagSqShift < sqr(fPreviousFullSafety) ) { // Revision proposed by Alex H, 2 Oct 07 G4double mag_shift= std::sqrt(MagSqShift); startMassSafety = std::max( (fPreviousMassSafety - mag_shift), 0.0); startFullSafety = std::max( (fPreviousFullSafety - mag_shift), 0.0); // Need to be consistent between full safety with Mass safety // in order reproduce results in simple case --> use same calculation method // Only compute full safety if massSafety > 0. Else it remains 0 // startFullSafety = fPathFinder->ComputeSafety( startPosition ); } // Is the particle charged ? // G4double particleCharge = pParticle->GetCharge() ; fMassGeometryLimitedStep = false ; // Set default - alex fAnyGeometryLimitedStep = false; // fEndGlobalTimeComputed = false ; // There is no need to locate the current volume. It is Done elsewhere: // On track construction // By the tracking, after all AlongStepDoIts, in "Relocation" // Check whether the particle has an (EM) field force exerted upon it // G4FieldManager* fieldMgr=0; G4bool fieldExertsForce = false; if( (particleCharge != 0.0) ) // || (magneticMoment != 0.0 ) ) { fieldMgr= fFieldPropagator->FindAndSetFieldManager( currentVolume ); if (fieldMgr != 0) { // Message the field Manager, to configure it for this track fieldMgr->ConfigureForTrack( &track ); fieldExertsForce = (fieldMgr->GetDetectorField() != 0); } // the PathFinder will recognise whether the field exerts force } G4double momentumMagnitude = pParticle->GetTotalMomentum() ; G4double restMass = pParticleDef->GetPDGMass() ; fFieldPropagator->SetChargeMomentumMass( particleCharge, // in e+ units momentumMagnitude, // in Mev/c restMass ) ; // This should be obsolete - the call to SetChargeAndMoments below should do the work G4ThreeVector spin = track.GetPolarization() ; G4FieldTrack theFieldTrack = G4FieldTrack( startPosition, track.GetMomentumDirection(), 0.0, track.GetKineticEnergy(), restMass, 0.0, // UNUSED: track.GetVelocity(), track.GetGlobalTime(), // Lab. track.GetProperTime(), // Part. &spin ) ; theFieldTrack.SetChargeAndMoments( particleCharge ); // EM moments -- future extension G4int stepNo= track.GetCurrentStepNumber(); ELimited limitedStep; G4FieldTrack endTrackState('a'); // Default values fMassGeometryLimitedStep = false ; // default fAnyGeometryLimitedStep = false ; if( currentMinimumStep > 0 ) { G4double newMassSafety= 0.0; // temp. for recalculation // Do the Transport in the field (non recti-linear) // lengthAlongCurve = fPathFinder->ComputeStep( theFieldTrack, currentMinimumStep, fNavigatorId, stepNo, newMassSafety, limitedStep, endTrackState, currentVolume ) ; // G4cout << " PathFinder ComputeStep returns " << lengthAlongCurve << G4endl; G4double newFullSafety= fPathFinder->GetCurrentSafety(); // this was estimated already in step above // G4double newFullStep= fPathFinder->GetMinimumStep(); if( limitedStep == kUnique || limitedStep == kSharedTransport ) { fMassGeometryLimitedStep = true ; } fAnyGeometryLimitedStep = (fPathFinder->GetNumberGeometriesLimitingStep() != 0); // #ifdef G4DEBUG if( fMassGeometryLimitedStep && !fAnyGeometryLimitedStep ){ G4cerr << " Error in determining geometries limiting the step" << G4endl; G4cerr << " Limiting: mass=" << fMassGeometryLimitedStep << " any= " << fAnyGeometryLimitedStep << G4endl; G4Exception("G4CoupledTransportation::AlongStepGetPhysicalInteractionLength()", "PathFinderConfused", FatalException, "Incompatible conditions - was limited by a geometry?"); } // #endif // Other potential // fAnyGeometryLimitedStep = newFullStep < currentMinimumStep; // ^^^ Not good enough; // Must compare with maximum requested step size // (eg in case another process requested bigger, got this!) geometryStepLength = std::min( lengthAlongCurve, currentMinimumStep); // Momentum: Magnitude and direction can be changed too now ... // fMomentumChanged = true ; fTransportEndMomentumDir = endTrackState.GetMomentumDir() ; // Remember last safety origin & value. fPreviousSftOrigin = startPosition ; fPreviousMassSafety = newMassSafety ; fPreviousFullSafety = newFullSafety ; // fpSafetyHelper->SetCurrentSafety( newFullSafety, startPosition); #ifdef G4DEBUG_TRANSPORT if( fVerboseLevel > 1 ){ G4cout << "G4Transport:CompStep> " << " called the pathfinder for a new step at " << startPosition << " and obtained step = " << lengthAlongCurve << G4endl; G4cout << " New safety (preStep) = " << newMassSafety << " versus precalculated = " << startMassSafety << G4endl; } #endif // Store as best estimate value startMassSafety = newMassSafety ; startFullSafety = newFullSafety ; // Get the End-Position and End-Momentum (Dir-ection) fTransportEndPosition = endTrackState.GetPosition() ; fTransportEndKineticEnergy = endTrackState.GetKineticEnergy() ; } else { geometryStepLength = lengthAlongCurve= 0.0 ; fMomentumChanged = false ; // fMassGeometryLimitedStep = false ; // --- ??? // fAnyGeometryLimitedStep = true; fTransportEndMomentumDir = track.GetMomentumDirection(); fTransportEndKineticEnergy = track.GetKineticEnergy(); fTransportEndPosition = startPosition; // If the step length requested is 0, and we are on a boundary // then a boundary will also limit the step. if( startMassSafety == 0.0 ) { fMassGeometryLimitedStep = true ; fAnyGeometryLimitedStep = true; } // TODO: Add explicit logical status for being at a boundary } // G4FieldTrack aTrackState(endTrackState); if( !fieldExertsForce ) { fParticleIsLooping = false ; fMomentumChanged = false ; fEndGlobalTimeComputed = false ; // G4cout << " global time is false " << G4endl; } else { #ifdef G4DEBUG_TRANSPORT if( fVerboseLevel > 1 ){ G4cout << " G4CT::CS End Position = " << fTransportEndPosition << G4endl; G4cout << " G4CT::CS End Direction = " << fTransportEndMomentumDir << G4endl; } #endif // G4cout << " G4CoupledTransportation Before if change energy statement: " << fFieldPropagator->GetCurrentFieldManager()->DoesFieldChangeEnergy() << G4endl; if( fFieldPropagator->GetCurrentFieldManager()->DoesFieldChangeEnergy() ) { // If the field can change energy, then the time must be integrated // - so this should have been updated // fCandidateEndGlobalTime = endTrackState.GetLabTimeOfFlight(); fEndGlobalTimeComputed = true; // G4cout << " setting global time to true - why? " << G4endl; // was ( fCandidateEndGlobalTime != track.GetGlobalTime() ); // a cleaner way is to have FieldTrack knowing whether time is updated. } else { // The energy should be unchanged by field transport, // - so the time changed will be calculated elsewhere // fEndGlobalTimeComputed = false; // Check that the integration preserved the energy // - and if not correct this! G4double startEnergy= track.GetKineticEnergy(); G4double endEnergy= fTransportEndKineticEnergy; static G4int no_inexact_steps=0; // , no_large_ediff; G4double absEdiff = std::fabs(startEnergy- endEnergy); if( absEdiff > perMillion * endEnergy ) { no_inexact_steps++; // Possible statistics keeping here ... } #ifdef G4VERBOSE if( (fVerboseLevel > 1) && ( absEdiff > perThousand * endEnergy) ){ ReportInexactEnergy(startEnergy, endEnergy); } // end of if (fVerboseLevel) #endif // Correct the energy for fields that conserve it // This - hides the integration error // - but gives a better physical answer fTransportEndKineticEnergy= track.GetKineticEnergy(); } } endpointDistance = (fTransportEndPosition - startPosition).mag() ; fParticleIsLooping = fFieldPropagator->IsParticleLooping() ; fTransportEndSpin = endTrackState.GetSpin(); // Calculate the safety safetyProposal= startFullSafety; // used to be startMassSafety // Changed to accomodate processes that cannot update the safety -- JA 22 Nov 06 // Update safety for the end-point, if becomes negative at the end-point. if( (startFullSafety < endpointDistance ) && ( particleCharge != 0.0 ) ) // Only needed to prepare for Mult Scat. // && !fAnyGeometryLimitedStep ) // To-Try: No safety update if at a boundary { G4double endFullSafety = fPathFinder->ComputeSafety( fTransportEndPosition); // Expected mission -- only mass geometry's safety // fMassNavigator->ComputeSafety( fTransportEndPosition) ; // Yet discrete processes only have poststep -- and this cannot // currently revise the safety // ==> so we use the all-geometry safety as a precaution fpSafetyHelper->SetCurrentSafety( endFullSafety, fTransportEndPosition); // Pushing safety to Helper avoids recalculation at this point G4ThreeVector centerPt= G4ThreeVector(0.0, 0.0, 0.0); // Used for return value G4double endMassSafety= fPathFinder->ObtainSafety( fNavigatorId, centerPt); // Retrieves the mass value from PathFinder (it calculated it) fPreviousMassSafety = endMassSafety ; fPreviousFullSafety = endFullSafety; fPreviousSftOrigin = fTransportEndPosition ; // The convention (Stepping Manager's) is safety from the start point // safetyProposal = endFullSafety + endpointDistance; // --> was endMassSafety // Changed to accomodate processes that cannot update the safety -- JA 22 Nov 06 // #define G4DEBUG_TRANSPORT 1 #ifdef G4DEBUG_TRANSPORT int prec= G4cout.precision(12) ; G4cout << "***Transportation::AlongStepGPIL ** " << G4endl ; G4cout << " Revised Safety at endpoint " << fTransportEndPosition << " give safety values: Mass= " << endMassSafety << " All= " << endFullSafety << G4endl ; G4cout << " Adding endpoint distance " << endpointDistance << " to obtain pseudo-safety= " << safetyProposal << G4endl ; G4cout.precision(prec); } else{ int prec= G4cout.precision(12) ; G4cout << "***Transportation::AlongStepGPIL ** " << G4endl ; G4cout << " Quick Safety estimate at endpoint " << fTransportEndPosition << " gives safety endpoint value = " << startFullSafety - endpointDistance << " using start-point value " << startFullSafety << " and endpointDistance " << endpointDistance << G4endl; G4cout.precision(prec); #endif } proposedSafetyForStart= safetyProposal; fParticleChange.ProposeTrueStepLength(geometryStepLength) ; return geometryStepLength ; } ////////////////////////////////////////////////////////////////////////// G4VParticleChange* G4CoupledTransportation::AlongStepDoIt( const G4Track& track, const G4Step& stepData ) { static G4int noCalls=0; static const G4ParticleDefinition* fOpticalPhoton = G4ParticleTable::GetParticleTable()->FindParticle("opticalphoton"); noCalls++; fParticleChange.Initialize(track) ; // sets all its members to the value of corresponding members in G4Track // Code specific for Transport // fParticleChange.ProposePosition(fTransportEndPosition) ; // G4cout << " G4CoupledTransportation::AlongStepDoIt" // << " proposes position = " << fTransportEndPosition // << " and end momentum direction = " << fTransportEndMomentumDir << G4endl; fParticleChange.ProposeMomentumDirection(fTransportEndMomentumDir) ; fParticleChange.ProposeEnergy(fTransportEndKineticEnergy) ; fParticleChange.SetMomentumChanged(fMomentumChanged) ; fParticleChange.ProposePolarization(fTransportEndSpin); G4double deltaTime = 0.0 ; // Calculate Lab Time of Flight (ONLY if field Equations used it!) // G4double endTime = fCandidateEndGlobalTime; // G4double delta_time = endTime - startTime; G4double startTime = track.GetGlobalTime() ; if (!fEndGlobalTimeComputed) { G4double finalInverseVel= DBL_MAX, initialInverseVel=DBL_MAX; // The time was not integrated .. make the best estimate possible // G4double finalVelocity = track.GetVelocity() ; if( finalVelocity > 0.0 ) { finalInverseVel= 1.0 / finalVelocity; } G4double initialVelocity = stepData.GetPreStepPoint()->GetVelocity() ; if( initialVelocity > 0.0 ) { initialInverseVel= 1.0 / initialVelocity; } G4double stepLength = track.GetStepLength() ; const G4DynamicParticle* fpDynamicParticle = track.GetDynamicParticle(); if (fpDynamicParticle->GetDefinition()== fOpticalPhoton) { // A photon is in the medium of the final point // during the step, so Peter says it has the final velocity. deltaTime = stepLength * finalInverseVel ; // G4cout << " dt = s / finalV " << " s = " << stepLength // << " 1 / finalV= " << finalInverseVel << G4endl; } else if (finalVelocity > 0.0) { // deltaTime = stepLength/finalVelocity ; G4double meanInverseVelocity = 0.5 * ( initialInverseVel + finalInverseVel ); deltaTime = stepLength * meanInverseVelocity ; // G4cout << " dt = s * mean(1/v) , with " << " s = " << stepLength // << " mean(1/v)= " << meanInverseVelocity << G4endl; } else { deltaTime = stepLength * initialInverseVel ; // G4cout << " dt = s / initV " << " s = " << stepLength // << " 1 / initV= " << initialInverseVel << G4endl; } // Could do with better estimate for final step (finalVelocity = 0) ? fCandidateEndGlobalTime = startTime + deltaTime ; // G4cout << " Calculated global time from start = " << startTime << " and " // << " delta time = " << deltaTime << G4endl; } else { deltaTime = fCandidateEndGlobalTime - startTime ; // G4cout << " Calculated global time from candidate end time = " // << fCandidateEndGlobalTime << " and start time = " << startTime << G4endl; } // G4cout << " G4CoupledTransportation::AlongStepDoIt " // << " flag whether computed time = " << fEndGlobalTimeComputed << " and " // << " is proposes end time " << fCandidateEndGlobalTime << G4endl; fParticleChange.ProposeGlobalTime( fCandidateEndGlobalTime ) ; // Now Correct by Lorentz factor to get "proper" deltaTime G4double restMass = track.GetDynamicParticle()->GetMass() ; G4double deltaProperTime = deltaTime*( restMass/track.GetTotalEnergy() ) ; fParticleChange.ProposeProperTime(track.GetProperTime() + deltaProperTime) ; //fParticleChange. ProposeTrueStepLength( track.GetStepLength() ) ; // If the particle is caught looping or is stuck (in very difficult // boundaries) in a magnetic field (doing many steps) // THEN this kills it ... // if ( fParticleIsLooping ) { G4double endEnergy= fTransportEndKineticEnergy; if( (endEnergy < fThreshold_Important_Energy) || (fNoLooperTrials >= fThresholdTrials ) ){ // Kill the looping particle // fParticleChange.ProposeTrackStatus( fStopAndKill ) ; // 'Bare' statistics fSumEnergyKilled += endEnergy; if( endEnergy > fMaxEnergyKilled) { fMaxEnergyKilled= endEnergy; } #ifdef G4VERBOSE if( (fVerboseLevel > 1) || ( endEnergy > fThreshold_Warning_Energy ) ) { G4cout << " G4CoupledTransportation is killing track that is looping or stuck " << G4endl << " This track has " << track.GetKineticEnergy() / MeV << " MeV energy." << G4endl; } if( fVerboseLevel > 0 ) { G4cout << " Steps by this track: " << track.GetCurrentStepNumber() << G4endl; } #endif fNoLooperTrials=0; } else{ fNoLooperTrials ++; #ifdef G4VERBOSE if( (fVerboseLevel > 2) ){ G4cout << " ** G4CoupledTransportation::AlongStepDoIt(): Particle looping - " << G4endl << " Number of consecutive problem step (this track) = " << fNoLooperTrials << G4endl << " Steps by this track: " << track.GetCurrentStepNumber() << G4endl << " Total no of calls to this method (all tracks) = " << noCalls << G4endl; } #endif } }else{ fNoLooperTrials=0; } // Another (sometimes better way) is to use a user-limit maximum Step size // to alleviate this problem .. // Add smooth curved trajectories to particle-change // // fParticleChange.SetPointerToVectorOfAuxiliaryPoints // (fFieldPropagator->GimmeTrajectoryVectorAndForgetIt() ); return &fParticleChange ; } ////////////////////////////////////////////////////////////////////////// // // This ensures that the PostStep action is always called, // so that it can do the relocation if it is needed. // G4double G4CoupledTransportation:: PostStepGetPhysicalInteractionLength( const G4Track&, G4double, // previousStepSize G4ForceCondition* pForceCond ) { // Must act as PostStep action -- to relocate particle *pForceCond = Forced ; return DBL_MAX ; } static void ReportMove( G4ThreeVector OldVector, G4ThreeVector NewVector, G4String& Quantity ) { G4ThreeVector moveVec = ( NewVector - OldVector ); G4cerr << G4endl << "**************************************************************" << G4endl; G4cerr << "Endpoint has moved between value expected from TransportEndPosition " << " and value from Track in PostStepDoIt. " << G4endl << "Change of " << Quantity << " is " << moveVec.mag() / mm << " mm long, " << " and its vector is " << (1.0/mm) * moveVec << " mm " << G4endl << "Endpoint of ComputeStep was " << OldVector << " and current position to locate is " << NewVector << G4endl; } ///////////////////////////////////////////////////////////////////////////// G4VParticleChange* G4CoupledTransportation::PostStepDoIt( const G4Track& track, const G4Step& ) { G4TouchableHandle retCurrentTouchable ; // The one to return // Initialize ParticleChange (by setting all its members equal // to corresponding members in G4Track) // fParticleChange.Initialize(track) ; // To initialise TouchableChange fParticleChange.ProposeTrackStatus(track.GetTrackStatus()) ; // Check that the end position and direction are preserved // since call to AlongStepDoIt if( (fTransportEndPosition - track.GetPosition()).mag2() >= 1.0e-16 ){ static G4String EndLabelString("End of Step Position"); ReportMove( track.GetPosition(), fTransportEndPosition, EndLabelString ); G4cerr << " Problem in G4CoupledTransportation::PostStepDoIt " << G4endl; } // If the Step was determined by the volume boundary, relocate the particle // The pathFinder will know that the geometry limited the step (!?) if( fVerboseLevel > 0 ){ G4cout << " Calling PathFinder::Locate() from " << " G4CoupledTransportation::PostStepDoIt " << G4endl; G4cout << " fAnyGeometryLimitedStep is " << fAnyGeometryLimitedStep << G4endl; } if(fAnyGeometryLimitedStep) { fPathFinder->Locate( track.GetPosition(), track.GetMomentumDirection(), true); // fCurrentTouchable will now become the previous touchable, // and what was the previous will be freed. // (Needed because the preStepPoint can point to the previous touchable) if( fVerboseLevel > 0 ) G4cout << "G4CoupledTransportation::PostStepDoIt --- fNavigatorId = " << fNavigatorId << G4endl; fCurrentTouchableHandle= fPathFinder->CreateTouchableHandle( fNavigatorId ); // Check whether the particle is out of the world volume // If so it has exited and must be killed. // #ifdef G4DEBUG_TRANSPORT if( fVerboseLevel > 1 ){ G4VPhysicalVolume* vol= fCurrentTouchableHandle->GetVolume(); G4cout << "CHECK !!!!!!!!!!! fCurrentTouchableHandle->GetVolume() = " << vol; if( vol ) { G4cout << "Name=" << vol->GetName(); } G4cout << G4endl; } #endif if( fCurrentTouchableHandle->GetVolume() == 0 ) { fParticleChange.ProposeTrackStatus( fStopAndKill ) ; } retCurrentTouchable = fCurrentTouchableHandle ; // fParticleChange.SetTouchableHandle( fCurrentTouchableHandle ) ; // Notify particle change that this is last step in volume fParticleChange.ProposeLastStepInVolume(true); // Double check that a boundary limited the step, and // if( fLinearNavigator->Get } else // fAnyGeometryLimitedStep is false { #ifdef G4DEBUG_TRANSPORT if( fVerboseLevel > 1 ){ G4cout << "G4CoupledTransportation::PostStepDoIt -- " << " fAnyGeometryLimitedStep = " << fAnyGeometryLimitedStep << " must be false " << G4endl; } #endif // This serves only to move each of the Navigator's location // // fLinearNavigator->LocateGlobalPointWithinVolume( track.GetPosition() ) ; // G4cout << "G4CoupledTransportation calling PathFinder::ReLocate() " << G4endl; fPathFinder->ReLocate( track.GetPosition() ); // track.GetMomentumDirection() ); // Keep the value of the track's current Touchable is retained, // and use it to overwrite the (unset) one in particle change. // Expect this must be fCurrentTouchable too // - could it be different, eg at the start of a step ? // retCurrentTouchable = track.GetTouchableHandle() ; // fParticleChange.SetTouchableHandle( track.GetTouchableHandle() ) ; // Have not reached a boundary fParticleChange.ProposeLastStepInVolume(false); } // endif ( fAnyGeometryLimitedStep ) const G4VPhysicalVolume* pNewVol = retCurrentTouchable->GetVolume() ; const G4Material* pNewMaterial = 0 ; const G4VSensitiveDetector* pNewSensitiveDetector = 0 ; if( pNewVol != 0 ) { pNewMaterial= pNewVol->GetLogicalVolume()->GetMaterial(); pNewSensitiveDetector= pNewVol->GetLogicalVolume()->GetSensitiveDetector(); } // ( const_cast pNewMaterial ) ; // ( const_cast pNewSensitiveDetector) ; fParticleChange.SetMaterialInTouchable( (G4Material *) pNewMaterial ) ; fParticleChange.SetSensitiveDetectorInTouchable( (G4VSensitiveDetector *) pNewSensitiveDetector ) ; // "temporarily" until Get/Set Material of ParticleChange, // and StepPoint can be made const. const G4MaterialCutsCouple* pNewMaterialCutsCouple = 0; if( pNewVol != 0 ) { pNewMaterialCutsCouple=pNewVol->GetLogicalVolume()->GetMaterialCutsCouple(); if( pNewMaterialCutsCouple!=0 && pNewMaterialCutsCouple->GetMaterial()!=pNewMaterial ) { // for parametrized volume // pNewMaterialCutsCouple = G4ProductionCutsTable::GetProductionCutsTable() ->GetMaterialCutsCouple(pNewMaterial, pNewMaterialCutsCouple->GetProductionCuts()); } } fParticleChange.SetMaterialCutsCoupleInTouchable( pNewMaterialCutsCouple ); // Must always set the touchable in ParticleChange, whether relocated or not fParticleChange.SetTouchableHandle(retCurrentTouchable) ; return &fParticleChange ; } // New method takes over the responsibility to reset the state of // G4CoupledTransportation object: // - at the start of a new track, and // - on the resumption of a suspended track. void G4CoupledTransportation::StartTracking(G4Track* aTrack) { static G4TransportationManager* transportMgr= G4TransportationManager::GetTransportationManager(); // G4VProcess::StartTracking(aTrack); // The 'initialising' actions // once taken in AlongStepGPIL -- if ( track.GetCurrentStepNumber()==1 ) // fStartedNewTrack= true; fMassNavigator = transportMgr->GetNavigatorForTracking() ; fNavigatorId= transportMgr->ActivateNavigator( fMassNavigator ); // Confirm it! // if( fVerboseLevel > 1 ){ // G4cout << " Navigator Id obtained in StartTracking " << fNavigatorId << G4endl; // } G4ThreeVector position = aTrack->GetPosition(); G4ThreeVector direction = aTrack->GetMomentumDirection(); // if( fVerboseLevel > 1 ){ // G4cout << " Calling PathFinder::PrepareNewTrack from " // << " G4CoupledTransportation::StartTracking -- which calls Locate()" << G4endl; // } fPathFinder->PrepareNewTrack( position, direction); // This implies a call to fPathFinder->Locate( position, direction ); // Global field, if any, must exist before tracking is started fGlobalFieldExists= DoesGlobalFieldExist(); // reset safety value and center // fPreviousMassSafety = 0.0 ; fPreviousFullSafety = 0.0 ; fPreviousSftOrigin = G4ThreeVector(0.,0.,0.) ; // reset looping counter -- for motion in field fNoLooperTrials= 0; // Must clear this state .. else it depends on last track's value // --> a better solution would set this from state of suspended track TODO ? // Was if( aTrack->GetCurrentStepNumber()==1 ) { .. } // ChordFinder reset internal state // if( fGlobalFieldExists ) { fFieldPropagator->ClearPropagatorState(); // Resets safety values, in case of overlaps. G4ChordFinder* chordF= fFieldPropagator->GetChordFinder(); if( chordF ) chordF->ResetStepEstimate(); } // Clear the chord finders of all fields (ie managers) derived objects static G4FieldManagerStore* fieldMgrStore= G4FieldManagerStore::GetInstance(); fieldMgrStore->ClearAllChordFindersState(); #ifdef G4DEBUG_TRANSPORT if( fVerboseLevel > 1 ){ G4cout << " Returning touchable handle " << fCurrentTouchableHandle << G4endl; } #endif // Update the current touchable handle (from the track's) // fCurrentTouchableHandle = aTrack->GetTouchableHandle(); } void G4CoupledTransportation:: ReportInexactEnergy(G4double startEnergy, G4double endEnergy) { static G4int no_warnings= 0, warnModulo=1, moduloFactor= 10, no_large_ediff= 0; if( std::fabs(startEnergy- endEnergy) > perThousand * endEnergy ) { no_large_ediff ++; if( (no_large_ediff% warnModulo) == 0 ) { no_warnings++; G4cout << "WARNING - G4CoupledTransportation::AlongStepGetPIL() " << " Energy change in Step is above 1^-3 relative value. " << G4endl << " Relative change in 'tracking' step = " << std::setw(15) << (endEnergy-startEnergy)/startEnergy << G4endl << " Starting E= " << std::setw(12) << startEnergy / MeV << " MeV " << G4endl << " Ending E= " << std::setw(12) << endEnergy / MeV << " MeV " << G4endl; G4cout << " Energy has been corrected -- however, review" << " field propagation parameters for accuracy." << G4endl; if( (fVerboseLevel > 2 ) || (no_warnings<4) || (no_large_ediff == warnModulo * moduloFactor) ){ G4cout << " These include EpsilonStepMax(/Min) in G4FieldManager " << " which determine fractional error per step for integrated quantities. " << G4endl << " Note also the influence of the permitted number of integration steps." << G4endl; } G4cerr << "ERROR - G4CoupledTransportation::AlongStepGetPIL()" << G4endl << " Bad 'endpoint'. Energy change detected" << " and corrected. " << " Has occurred already " << no_large_ediff << " times." << G4endl; if( no_large_ediff == warnModulo * moduloFactor ) { warnModulo *= moduloFactor; } } } }