418 lines
15 KiB
C++
418 lines
15 KiB
C++
//
|
|
// ********************************************************************
|
|
// * License and Disclaimer *
|
|
// * *
|
|
// * The Geant4 software is copyright of the Copyright Holders of *
|
|
// * the Geant4 Collaboration. It is provided under the terms and *
|
|
// * conditions of the Geant4 Software License, included in the file *
|
|
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
|
// * include a list of copyright holders. *
|
|
// * *
|
|
// * Neither the authors of this software system, nor their employing *
|
|
// * institutes,nor the agencies providing financial support for this *
|
|
// * work make any representation or warranty, express or implied, *
|
|
// * regarding this software system or assume any liability for its *
|
|
// * use. Please see the license in the file LICENSE and URL above *
|
|
// * for the full disclaimer and the limitation of liability. *
|
|
// * *
|
|
// * This code implementation is the result of the scientific and *
|
|
// * technical work of the GEANT4 collaboration. *
|
|
// * By using, copying, modifying or distributing the software (or *
|
|
// * any work based on the software) you agree to acknowledge its *
|
|
// * use in resulting scientific publications, and indicate your *
|
|
// * acceptance of all terms of the Geant4 Software license. *
|
|
// ********************************************************************
|
|
//
|
|
// G4ParallelGeometriesLimiterProcess
|
|
// --------------------------------------------------------------------
|
|
|
|
#include "G4ios.hh"
|
|
#include "G4ParallelGeometriesLimiterProcess.hh"
|
|
#include "G4BiasingProcessSharedData.hh"
|
|
#include "G4ProcessManager.hh"
|
|
#include "G4TransportationManager.hh"
|
|
#include "G4PathFinder.hh"
|
|
#include "G4FieldTrackUpdator.hh"
|
|
|
|
#include "G4SystemOfUnits.hh"
|
|
|
|
G4ParallelGeometriesLimiterProcess::
|
|
G4ParallelGeometriesLimiterProcess(const G4String& processName)
|
|
: G4VProcess(processName, fParallel)
|
|
{
|
|
// -- Process Sub Type ?
|
|
|
|
fPathFinder = G4PathFinder::GetInstance();
|
|
fTransportationManager = G4TransportationManager::GetTransportationManager();
|
|
}
|
|
|
|
// ----------------------------
|
|
// -- Add/Remove world volumes:
|
|
// ----------------------------
|
|
void G4ParallelGeometriesLimiterProcess::
|
|
AddParallelWorld(const G4String& parallelWorldName)
|
|
{
|
|
// -- Refuse adding parallel geometry during tracking time:
|
|
if (fIsTrackingTime)
|
|
{
|
|
G4ExceptionDescription ed;
|
|
ed << "G4ParallelGeometriesLimiterProcess `" << GetProcessName()
|
|
<< "': adding a parallel world volume at tracking time is not allowed."
|
|
<< G4endl;
|
|
G4Exception("G4ParallelGeometriesLimiterProcess::AddParallelWorld(..)",
|
|
"BIAS.GEN.21", JustWarning, ed, "Call ignored.");
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
G4VPhysicalVolume* newWorld = fTransportationManager->IsWorldExisting( parallelWorldName );
|
|
|
|
// -- Fatal exception if requested world does not exist:
|
|
if (newWorld == nullptr)
|
|
{
|
|
G4ExceptionDescription tellWhatIsWrong;
|
|
tellWhatIsWrong << "Volume `" << parallelWorldName
|
|
<< "' is not a parallel world nor the mass world volume."
|
|
<< G4endl;
|
|
G4Exception("G4ParallelGeometriesLimiterProcess::SetWorldVolume(..)",
|
|
"BIAS.GEN.22", FatalException, tellWhatIsWrong);
|
|
}
|
|
|
|
// -- Protection against adding the mass geometry world as parallel world:
|
|
if ( newWorld == fTransportationManager->GetNavigatorForTracking()->GetWorldVolume() )
|
|
{
|
|
G4ExceptionDescription ed;
|
|
ed << "G4ParallelGeometriesLimiterProcess `" << GetProcessName()
|
|
<< "': trying to add the world volume for tracking as a parallel world."
|
|
<< G4endl;
|
|
G4Exception("G4ParallelGeometriesLimiterProcess::AddParallelWorld(..)",
|
|
"BIAS.GEN.23", JustWarning, ed, "Call ignored.");
|
|
return;
|
|
}
|
|
|
|
// -- Add parallel world, taking care it is not in the list yet:
|
|
G4bool isNew = true;
|
|
for ( auto knownWorld : fParallelWorlds )
|
|
{
|
|
if ( knownWorld == newWorld ) { isNew = false; }
|
|
}
|
|
if ( isNew )
|
|
{
|
|
fParallelWorlds.push_back( newWorld );
|
|
}
|
|
else
|
|
{
|
|
G4ExceptionDescription ed;
|
|
ed << "G4ParallelGeometriesLimiterProcess `" << GetProcessName()
|
|
<< "': trying to re-add the parallel world volume `"
|
|
<< parallelWorldName << "'." << G4endl;
|
|
G4Exception("G4ParallelGeometriesLimiterProcess::AddParallelWorld(..)",
|
|
"BIAS.GEN.24", JustWarning, ed, "Call ignored.");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void G4ParallelGeometriesLimiterProcess::
|
|
RemoveParallelWorld(const G4String& parallelWorldName)
|
|
{
|
|
// -- Refuse refuse removing parallel geometry during tracking time:
|
|
if (fIsTrackingTime)
|
|
{
|
|
G4ExceptionDescription ed;
|
|
ed << "G4ParallelGeometriesLimiterProcess `" << GetProcessName()
|
|
<< "': removing a parallel world volume at tracking time is not allowed."
|
|
<< G4endl;
|
|
G4Exception("G4ParallelGeometriesLimiterProcess::RemoveParallelWorld(..)",
|
|
"BIAS.GEN.25", JustWarning, ed, "Call ignored.");
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
G4VPhysicalVolume* newWorld = fTransportationManager->IsWorldExisting( parallelWorldName );
|
|
if (newWorld == nullptr)
|
|
{
|
|
G4ExceptionDescription ed;
|
|
ed << "G4ParallelGeometriesLimiterProcess `" << GetProcessName()
|
|
<< "': trying to remove an inexisting parallel world '"
|
|
<< parallelWorldName << "'." << G4endl;
|
|
G4Exception("G4ParallelGeometriesLimiterProcess::RemoveParallelWorld(..)",
|
|
"BIAS.GEN.26", JustWarning, ed, "Call ignored.");
|
|
return;
|
|
}
|
|
|
|
// -- get position of world volume in list:
|
|
std::size_t iWorld = 0;
|
|
for ( auto knownWorld : fParallelWorlds )
|
|
{
|
|
if ( knownWorld == newWorld ) break;
|
|
++iWorld;
|
|
}
|
|
|
|
if ( iWorld == fParallelWorlds.size() )
|
|
{
|
|
G4ExceptionDescription ed;
|
|
ed << "G4ParallelGeometriesLimiterProcess `" << GetProcessName()
|
|
<< "': trying to remove an non-registerered parallel world '"
|
|
<< parallelWorldName << "'." << G4endl;
|
|
G4Exception("G4ParallelGeometriesLimiterProcess::RemoveParallelWorld(..)",
|
|
"BIAS.GEN.27", JustWarning, ed, "Call ignored.");
|
|
return;
|
|
}
|
|
// -- remove from vector:
|
|
fParallelWorlds.erase( fParallelWorlds.begin() + iWorld );
|
|
}
|
|
}
|
|
|
|
// --------------------
|
|
// Start/End tracking:
|
|
// --------------------
|
|
void G4ParallelGeometriesLimiterProcess::StartTracking(G4Track* track)
|
|
{
|
|
fIsTrackingTime = true;
|
|
|
|
// -- fetch the navigators, their indeces, and activate:
|
|
fParallelWorldNavigators.clear();
|
|
fParallelWorldNavigatorIndeces.clear();
|
|
fParallelWorldSafeties.clear();
|
|
fParallelWorldIsLimiting.clear();
|
|
fParallelWorldWasLimiting.clear();
|
|
fCurrentVolumes.clear();
|
|
fPreviousVolumes.clear();
|
|
for ( auto parallelWorld : fParallelWorlds )
|
|
{
|
|
fParallelWorldNavigators.push_back( fTransportationManager->GetNavigator( parallelWorld ) );
|
|
fParallelWorldNavigatorIndeces.push_back( fTransportationManager->ActivateNavigator( fParallelWorldNavigators.back() ) );
|
|
fParallelWorldSafeties.push_back( 0.0 );
|
|
fParallelWorldIsLimiting.push_back( false );
|
|
fParallelWorldWasLimiting.push_back( false );
|
|
}
|
|
|
|
fPathFinder->PrepareNewTrack( track->GetPosition(), track->GetMomentumDirection() );
|
|
// -- Does it work at this level, after "PrepareNewTrack" above ?
|
|
for ( auto navigatorIndex : fParallelWorldNavigatorIndeces )
|
|
{
|
|
fPreviousVolumes.push_back( nullptr );
|
|
fCurrentVolumes .push_back( fPathFinder->GetLocatedVolume( navigatorIndex ) );
|
|
}
|
|
|
|
// -- will force updating safety:
|
|
fParallelWorldSafety = 0.0;
|
|
for ( std::size_t i = 0 ; i < fParallelWorldNavigatorIndeces.size() ; ++i )
|
|
{
|
|
fParallelWorldSafeties[i] = 0.0;
|
|
}
|
|
}
|
|
|
|
void G4ParallelGeometriesLimiterProcess::EndTracking()
|
|
{
|
|
fIsTrackingTime = false;
|
|
for ( auto parallelWorldNavigator : fParallelWorldNavigators )
|
|
{
|
|
fTransportationManager->DeActivateNavigator( parallelWorldNavigator );
|
|
}
|
|
}
|
|
|
|
G4double G4ParallelGeometriesLimiterProcess::
|
|
PostStepGetPhysicalInteractionLength(const G4Track&, G4double,
|
|
G4ForceCondition* condition)
|
|
{
|
|
// -- push previous step limitation flags and volumes:
|
|
// -- consider switching pointers insteads of making copies of std::vector's:
|
|
fParallelWorldWasLimiting = fParallelWorldIsLimiting;
|
|
fPreviousVolumes = fCurrentVolumes;
|
|
|
|
// -- update volumes:
|
|
std::size_t i = 0;
|
|
for ( auto navigatorIndex : fParallelWorldNavigatorIndeces )
|
|
{
|
|
fCurrentVolumes[i++] = fPathFinder->GetLocatedVolume( navigatorIndex );
|
|
}
|
|
|
|
*condition = NotForced;
|
|
return DBL_MAX;
|
|
}
|
|
|
|
G4double G4ParallelGeometriesLimiterProcess::
|
|
AlongStepGetPhysicalInteractionLength(const G4Track& track,
|
|
G4double previousStepSize,
|
|
G4double currentMinimumStep,
|
|
G4double& proposedSafety,
|
|
G4GPILSelection* selection)
|
|
{
|
|
// -- Init:
|
|
// -- Note that the returnedStep must be physically meaningful,
|
|
// -- even if we return NotCandidateForSelection as condition;
|
|
// -- the reason is that the stepping manager always takes the smallest
|
|
// -- alongstep among the returned ones (point related
|
|
// -- to geometry step length wrt to true path length).
|
|
*selection = NotCandidateForSelection;
|
|
G4double returnedStep = DBL_MAX;
|
|
|
|
// -- G4FieldTrack and ELimited:
|
|
static G4ThreadLocal G4FieldTrack* endTrack_MT = nullptr;
|
|
if (!endTrack_MT) endTrack_MT = new G4FieldTrack ('0');
|
|
G4FieldTrack& endTrack = *endTrack_MT;
|
|
|
|
static G4ThreadLocal ELimited* eLimited_MT = nullptr;
|
|
if (!eLimited_MT) eLimited_MT = new ELimited;
|
|
ELimited &eLimited = *eLimited_MT;
|
|
|
|
// -------------------
|
|
// -- Update safeties:
|
|
// -------------------
|
|
if ( previousStepSize > 0.0 )
|
|
{
|
|
for ( auto& parallelWorldSafety : fParallelWorldSafeties )
|
|
{
|
|
parallelWorldSafety -= previousStepSize;
|
|
if ( parallelWorldSafety < 0. ) { parallelWorldSafety = 0.0; }
|
|
fParallelWorldSafety = parallelWorldSafety < fParallelWorldSafety
|
|
? parallelWorldSafety : fParallelWorldSafety;
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------
|
|
// Determination of the proposed step length:
|
|
// ------------------------------------------
|
|
if ( ( currentMinimumStep <= fParallelWorldSafety )
|
|
&& ( currentMinimumStep > 0. ) )
|
|
{
|
|
// -- No chance to limit the step, as proposed move inside safety
|
|
|
|
returnedStep = currentMinimumStep;
|
|
proposedSafety = fParallelWorldSafety - currentMinimumStep;
|
|
}
|
|
else
|
|
{
|
|
// -- Proposed move exceeds common safety, need to state
|
|
G4double smallestReturnedStep = -1.0;
|
|
ELimited eLimitedForSmallestStep = kDoNot;
|
|
for ( std::size_t i = 0 ; i < fParallelWorldNavigatorIndeces.size() ; ++i )
|
|
{
|
|
// -- Update safety of geometries having safety smaller than current minimum step
|
|
if ( currentMinimumStep >= fParallelWorldSafeties[i] )
|
|
{
|
|
G4FieldTrackUpdator::Update(&fFieldTrack, &track);
|
|
G4double tmpReturnedStep = fPathFinder->ComputeStep(fFieldTrack,
|
|
currentMinimumStep,
|
|
fParallelWorldNavigatorIndeces[i],
|
|
track.GetCurrentStepNumber(),
|
|
fParallelWorldSafeties[i],
|
|
eLimited, endTrack, track.GetVolume());
|
|
|
|
if ( ( smallestReturnedStep < 0.0 ) || ( tmpReturnedStep <= smallestReturnedStep ) )
|
|
{
|
|
smallestReturnedStep = tmpReturnedStep;
|
|
eLimitedForSmallestStep = eLimited;
|
|
}
|
|
|
|
if (eLimited == kDoNot)
|
|
{
|
|
// -- Step not limited by this geometry
|
|
fParallelWorldSafeties[i] = fParallelWorldNavigators[i]->ComputeSafety(endTrack.GetPosition());
|
|
fParallelWorldIsLimiting[i] = false;
|
|
}
|
|
else
|
|
{
|
|
fParallelWorldIsLimiting[i] = true;
|
|
}
|
|
}
|
|
|
|
// -- update with smallest safety:
|
|
fParallelWorldSafety = fParallelWorldSafeties[i] < fParallelWorldSafety
|
|
? fParallelWorldSafeties[i] : fParallelWorldSafety;
|
|
}
|
|
|
|
// -- no geometry limitation among all geometries, can return currentMinimumStep (or DBL_MAX):
|
|
// -- Beware : the returnedStep must be physically meaningful, even if we say "NotCandidateForSelection" !
|
|
if ( eLimitedForSmallestStep == kDoNot )
|
|
{
|
|
returnedStep = currentMinimumStep;
|
|
}
|
|
// -- proposed step length of limiting geometry:
|
|
if ( eLimitedForSmallestStep == kUnique ||
|
|
eLimitedForSmallestStep == kSharedOther )
|
|
{
|
|
*selection = CandidateForSelection;
|
|
returnedStep = smallestReturnedStep;
|
|
}
|
|
else if ( eLimitedForSmallestStep == kSharedTransport )
|
|
{
|
|
// -- Expand to disable its selection in Step Manager comparison
|
|
returnedStep = smallestReturnedStep* (1.0 + 1.0e-9);
|
|
}
|
|
|
|
// -- and smallest safety among geometries:
|
|
proposedSafety = fParallelWorldSafety ;
|
|
}
|
|
|
|
// -- returns step length, and proposedSafety
|
|
return returnedStep;
|
|
}
|
|
|
|
G4VParticleChange* G4ParallelGeometriesLimiterProcess::
|
|
AlongStepDoIt( const G4Track& track, const G4Step& )
|
|
{
|
|
fDummyParticleChange.Initialize(track);
|
|
return &fDummyParticleChange;
|
|
}
|
|
|
|
void G4ParallelGeometriesLimiterProcess::
|
|
SetProcessManager(const G4ProcessManager* mgr)
|
|
{
|
|
G4BiasingProcessSharedData *sharedData(nullptr);
|
|
|
|
// -- initialize sharedData pointer:
|
|
if ( G4BiasingProcessSharedData::fSharedDataMap.Find(mgr) == G4BiasingProcessSharedData::fSharedDataMap.End() )
|
|
{
|
|
sharedData = new G4BiasingProcessSharedData( mgr );
|
|
G4BiasingProcessSharedData::fSharedDataMap[mgr] = sharedData;
|
|
}
|
|
else
|
|
{
|
|
sharedData = G4BiasingProcessSharedData::fSharedDataMap[mgr] ;
|
|
}
|
|
|
|
// -- add itself to the shared data:
|
|
if ( sharedData->fParallelGeometriesLimiterProcess == nullptr )
|
|
{
|
|
sharedData->fParallelGeometriesLimiterProcess = this;
|
|
}
|
|
else
|
|
{
|
|
G4ExceptionDescription ed;
|
|
ed << " Trying to add more than one G4ParallelGeometriesLimiterProcess process to the process manager "
|
|
<< mgr
|
|
<< " (process manager for `" << mgr->GetParticleType()->GetParticleName()
|
|
<< "'). Only one is needed. Call ignored." << G4endl;
|
|
G4Exception(" G4ParallelGeometriesLimiterProcess::SetProcessManager(..)",
|
|
"BIAS.GEN.29", JustWarning, ed);
|
|
}
|
|
}
|
|
|
|
G4int G4ParallelGeometriesLimiterProcess::
|
|
GetParallelWorldIndex( const G4VPhysicalVolume* parallelWorld ) const
|
|
{
|
|
G4int toReturn = -1;
|
|
G4int iWorld = 0;
|
|
for ( auto world : fParallelWorlds )
|
|
{
|
|
if ( world == parallelWorld )
|
|
{
|
|
toReturn = iWorld;
|
|
break;
|
|
}
|
|
++iWorld;
|
|
}
|
|
return toReturn;
|
|
}
|
|
|
|
G4int G4ParallelGeometriesLimiterProcess::
|
|
GetParallelWorldIndex( const G4String& parallelWorldName ) const
|
|
{
|
|
G4VPhysicalVolume* aWorld = fTransportationManager->IsWorldExisting( parallelWorldName );
|
|
// note aWorld might be nullptr
|
|
return GetParallelWorldIndex( aWorld );
|
|
}
|