Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-31 07:53:28

0001 //
0002 // ********************************************************************
0003 // * License and Disclaimer                                           *
0004 // *                                                                  *
0005 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
0006 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
0007 // * conditions of the Geant4 Software License,  included in the file *
0008 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
0009 // * include a list of copyright holders.                             *
0010 // *                                                                  *
0011 // * Neither the authors of this software system, nor their employing *
0012 // * institutes,nor the agencies providing financial support for this *
0013 // * work  make  any representation or  warranty, express or implied, *
0014 // * regarding  this  software system or assume any liability for its *
0015 // * use.  Please see the license in the file  LICENSE  and URL above *
0016 // * for the full disclaimer and the limitation of liability.         *
0017 // *                                                                  *
0018 // * This  code  implementation is the result of  the  scientific and *
0019 // * technical work of the GEANT4 collaboration.                      *
0020 // * By using,  copying,  modifying or  distributing the software (or *
0021 // * any work based  on the software)  you  agree  to acknowledge its *
0022 // * use  in  resulting  scientific  publications,  and indicate your *
0023 // * acceptance of all terms of the Geant4 Software license.          *
0024 // ********************************************************************
0025 //
0026 /// \file GB06BOptnSplitAndKillByImportance.cc
0027 /// \brief Implementation of the GB06BOptnSplitAndKillByImportance class
0028 
0029 #include "GB06BOptnSplitAndKillByImportance.hh"
0030 
0031 #include "G4BiasingProcessInterface.hh"
0032 #include "G4BiasingProcessSharedData.hh"
0033 #include "G4ParallelGeometriesLimiterProcess.hh"
0034 #include "G4ProcessManager.hh"
0035 #include "Randomize.hh"
0036 
0037 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0038 
0039 GB06BOptnSplitAndKillByImportance::GB06BOptnSplitAndKillByImportance(G4String name)
0040   : G4VBiasingOperation(name),
0041     fParallelWorldIndex(-1),
0042     fBiasingSharedData(nullptr),
0043     fParticleChange(),
0044     fDummyParticleChange()
0045 {}
0046 
0047 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0048 
0049 GB06BOptnSplitAndKillByImportance::~GB06BOptnSplitAndKillByImportance() = default;
0050 
0051 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0052 
0053 G4double GB06BOptnSplitAndKillByImportance::DistanceToApplyOperation(const G4Track*, G4double,
0054                                                                      G4ForceCondition* condition)
0055 {
0056   // -- Remember the touchable history (ie geometry state) at the beginning of the step:
0057   // -- Start by getting the process handling the step limitation in parallel
0058   // -- geometries for the generic biasing:
0059   auto biasingLimiterProcess = fBiasingSharedData->GetParallelGeometriesLimiterProcess();
0060   fPreStepTouchableHistory =
0061     biasingLimiterProcess
0062       ->GetNavigator(fParallelWorldIndex)  // -- get the navigator of the geometry...
0063       ->CreateTouchableHistoryHandle();  // -- ...and collect the geometry state.
0064 
0065   // -- We request to be "forced" : meaning GenerateBiasingFinalState(...) will be called
0066   // -- anyway at the PostStepDoIt(...) stage (ie, when the track will have been moved to
0067   // -- its end point position) and, there, we will have to handle the decision to
0068   // -- split/kill if we are on a volume boundary, or do nothing, if we're not:
0069   *condition = Forced;
0070 
0071   // -- As we're forced, we make this returned length void:
0072   return DBL_MAX;
0073 }
0074 
0075 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0076 
0077 G4VParticleChange*
0078 GB06BOptnSplitAndKillByImportance::GenerateBiasingFinalState(const G4Track* track, const G4Step*)
0079 {
0080   // -- Given we used the "Forced" condition, this method is always called.
0081   // -- We check the status of the step in the parallel geometry, and apply
0082   // -- splitting/killing if the step has been limited by the geometry.
0083 
0084   // -- We first check if we limit the step in the parallel geometry:
0085   G4bool isLimiting =
0086     fBiasingSharedData->GetParallelGeometriesLimiterProcess()->GetIsLimiting(fParallelWorldIndex);
0087 
0088   // -- if not limiting, we leave the track unchanged:
0089   if (!isLimiting) {
0090     fDummyParticleChange.Initialize(*track);
0091     return &fDummyParticleChange;
0092   }
0093 
0094   // -- We collect the geometry state at the end point step:
0095   // -- Note this is the same call than in the DistanceToApplyOperation(...) for the
0096   // -- fPreStepTouchableHistory, but the navigator has pushed the track in the next
0097   // -- volume since then (even if the track is still on the boundary), and hence the
0098   // -- geometry state has changed.
0099   auto biasingLimiterProcess = fBiasingSharedData->GetParallelGeometriesLimiterProcess();
0100   fPostStepTouchableHistory =
0101     biasingLimiterProcess->GetNavigator(fParallelWorldIndex)->CreateTouchableHistoryHandle();
0102 
0103   // -- We verify we are still in the "same" physical volume:
0104   // -- remember : using a replica, we have "one" physical volume
0105   // -- but representing many different placements, distinguished
0106   // -- by replica number. By checking we are in the same physical
0107   // -- volume, we verify the end step point has not reached the
0108   // -- world volume of the parallel geometry:
0109   if (fPreStepTouchableHistory->GetVolume() != fPostStepTouchableHistory->GetVolume()) {
0110     // -- the track is leaving the volumes in which biasing is applied,
0111     // -- we leave this track unchanged:
0112     fDummyParticleChange.Initialize(*track);
0113     return &fDummyParticleChange;
0114   }
0115 
0116   // -------------------------------------------------------------------------------------
0117   // -- At this stage, we know we have a particle crossing a boundary between two slices,
0118   // -- each of this slice has a well defined importance : we apply the biasing.
0119   // -- We will split if the track is entering a volume with higher importance, and
0120   // -- kill (applying Russian roulette) in the other case.
0121   // -------------------------------------------------------------------------------------
0122 
0123   // -- We start by getting the replica numbers:
0124   G4int preReplicaNumber = fPreStepTouchableHistory->GetReplicaNumber();
0125   G4int postReplicaNumber = fPostStepTouchableHistory->GetReplicaNumber();
0126 
0127   // -- and get the related importance we defined in the importance map:
0128   G4int preImportance = (*fImportanceMap)[preReplicaNumber];
0129   G4int postImportance = (*fImportanceMap)[postReplicaNumber];
0130 
0131   // -- Get track weight:
0132   G4double initialWeight = track->GetWeight();
0133 
0134   // -- Initialize the "particle change" (it will communicate the new track state to
0135   // -- the tracking):
0136   fParticleChange.Initialize(*track);
0137 
0138   if (postImportance > preImportance) {
0139     // -- We split :
0140     G4int splittingFactor = postImportance / preImportance;
0141 
0142     // Define the tracks weight:
0143     G4double weightOfTrack = initialWeight / splittingFactor;
0144 
0145     // Ask currect track weight to be changed to the new value:
0146     fParticleChange.ProposeParentWeight(weightOfTrack);
0147     // Now we clone this track (this is the actual splitting):
0148     // we will then have the primary and clone of it, hence the
0149     // splitting by a factor 2:
0150     auto clone = new G4Track(*track);
0151     clone->SetWeight(weightOfTrack);
0152     fParticleChange.AddSecondary(clone);
0153     // -- Below's call added for safety & illustration : inform particle change to not
0154     // -- modify the clone (ie : daughter) weight to make it that of the primary.
0155     // -- Here this call is not mandatory as both tracks have same weights.
0156     fParticleChange.SetSecondaryWeightByProcess(true);
0157   }
0158   else {
0159     // -- We apply Russian roulette:
0160     G4double survivingProbability = G4double(postImportance) / G4double(preImportance);
0161 
0162     // Shoot a random number (in ]0,1[ segment):
0163     G4double random = G4UniformRand();
0164     if (random > survivingProbability) {
0165       // We ask for the the track to be killed:
0166       fParticleChange.ProposeTrackStatus(fStopAndKill);
0167     }
0168     else {
0169       // In this case, the track survives. We change its weight
0170       // to conserve weight among killed and survival tracks:
0171       fParticleChange.ProposeParentWeight(initialWeight / survivingProbability);
0172     }
0173   }
0174 
0175   return &fParticleChange;
0176 }
0177 
0178 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......