Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-02-23 09:20:46

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 //
0027 /// \file GB06BOptnSplitAndKillByImportance.cc
0028 /// \brief Implementation of the GB06BOptnSplitAndKillByImportance class
0029 
0030 #include "GB06BOptnSplitAndKillByImportance.hh"
0031 
0032 #include "G4BiasingProcessInterface.hh"
0033 #include "G4BiasingProcessSharedData.hh"
0034 #include "G4ParallelGeometriesLimiterProcess.hh"
0035 #include "G4ProcessManager.hh"
0036 #include "Randomize.hh"
0037 
0038 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0039 
0040 GB06BOptnSplitAndKillByImportance::GB06BOptnSplitAndKillByImportance(G4String name)
0041   : G4VBiasingOperation(name),
0042     fParallelWorldIndex(-1),
0043     fBiasingSharedData(nullptr),
0044     fParticleChange(),
0045     fDummyParticleChange()
0046 {}
0047 
0048 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0049 
0050 GB06BOptnSplitAndKillByImportance::~GB06BOptnSplitAndKillByImportance() {}
0051 
0052 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0053 
0054 G4double GB06BOptnSplitAndKillByImportance::DistanceToApplyOperation(const G4Track*, G4double,
0055                                                                      G4ForceCondition* condition)
0056 {
0057   // -- Remember the touchable history (ie geometry state) at the beginning of the step:
0058   // -- Start by getting the process handling the step limitation in parallel
0059   // -- geometries for the generic biasing:
0060   auto biasingLimiterProcess = fBiasingSharedData->GetParallelGeometriesLimiterProcess();
0061   fPreStepTouchableHistory =
0062     biasingLimiterProcess
0063       ->GetNavigator(fParallelWorldIndex)  // -- get the navigator of the geometry...
0064       ->CreateTouchableHistoryHandle();  // -- ...and collect the geometry state.
0065 
0066   // -- We request to be "forced" : meaning GenerateBiasingFinalState(...) will be called
0067   // -- anyway at the PostStepDoIt(...) stage (ie, when the track will have been moved to
0068   // -- its end point position) and, there, we will have to handle the decision to
0069   // -- split/kill if we are on a volume boundary, or do nothing, if we're not:
0070   *condition = Forced;
0071 
0072   // -- As we're forced, we make this returned length void:
0073   return DBL_MAX;
0074 }
0075 
0076 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0077 
0078 G4VParticleChange*
0079 GB06BOptnSplitAndKillByImportance::GenerateBiasingFinalState(const G4Track* track, const G4Step*)
0080 {
0081   // -- Given we used the "Forced" condition, this method is always called.
0082   // -- We check the status of the step in the parallel geometry, and apply
0083   // -- splitting/killing if the step has been limited by the geometry.
0084 
0085   // -- We first check if we limit the step in the parallel geometry:
0086   G4bool isLimiting =
0087     fBiasingSharedData->GetParallelGeometriesLimiterProcess()->GetIsLimiting(fParallelWorldIndex);
0088 
0089   // -- if not limiting, we leave the track unchanged:
0090   if (!isLimiting) {
0091     fDummyParticleChange.Initialize(*track);
0092     return &fDummyParticleChange;
0093   }
0094 
0095   // -- We collect the geometry state at the end point step:
0096   // -- Note this is the same call than in the DistanceToApplyOperation(...) for the
0097   // -- fPreStepTouchableHistory, but the navigator has pushed the track in the next
0098   // -- volume since then (even if the track is still on the boundary), and hence the
0099   // -- geometry state has changed.
0100   auto biasingLimiterProcess = fBiasingSharedData->GetParallelGeometriesLimiterProcess();
0101   fPostStepTouchableHistory =
0102     biasingLimiterProcess->GetNavigator(fParallelWorldIndex)->CreateTouchableHistoryHandle();
0103 
0104   // -- We verify we are still in the "same" physical volume:
0105   // -- remember : using a replica, we have "one" physical volume
0106   // -- but representing many different placements, distinguished
0107   // -- by replica number. By checking we are in the same physical
0108   // -- volume, we verify the end step point has not reached the
0109   // -- world volume of the parallel geometry:
0110   if (fPreStepTouchableHistory->GetVolume() != fPostStepTouchableHistory->GetVolume()) {
0111     // -- the track is leaving the volumes in which biasing is applied,
0112     // -- we leave this track unchanged:
0113     fDummyParticleChange.Initialize(*track);
0114     return &fDummyParticleChange;
0115   }
0116 
0117   // -------------------------------------------------------------------------------------
0118   // -- At this stage, we know we have a particle crossing a boundary between two slices,
0119   // -- each of this slice has a well defined importance : we apply the biasing.
0120   // -- We will split if the track is entering a volume with higher importance, and
0121   // -- kill (applying Russian roulette) in the other case.
0122   // -------------------------------------------------------------------------------------
0123 
0124   // -- We start by getting the replica numbers:
0125   G4int preReplicaNumber = fPreStepTouchableHistory->GetReplicaNumber();
0126   G4int postReplicaNumber = fPostStepTouchableHistory->GetReplicaNumber();
0127 
0128   // -- and get the related importance we defined in the importance map:
0129   G4int preImportance = (*fImportanceMap)[preReplicaNumber];
0130   G4int postImportance = (*fImportanceMap)[postReplicaNumber];
0131 
0132   // -- Get track weight:
0133   G4double initialWeight = track->GetWeight();
0134 
0135   // -- Initialize the "particle change" (it will communicate the new track state to
0136   // -- the tracking):
0137   fParticleChange.Initialize(*track);
0138 
0139   if (postImportance > preImportance) {
0140     // -- We split :
0141     G4int splittingFactor = postImportance / preImportance;
0142 
0143     // Define the tracks weight:
0144     G4double weightOfTrack = initialWeight / splittingFactor;
0145 
0146     // Ask currect track weight to be changed to the new value:
0147     fParticleChange.ProposeParentWeight(weightOfTrack);
0148     // Now we clone this track (this is the actual splitting):
0149     // we will then have the primary and clone of it, hence the
0150     // splitting by a factor 2:
0151     G4Track* clone = new G4Track(*track);
0152     clone->SetWeight(weightOfTrack);
0153     fParticleChange.AddSecondary(clone);
0154     // -- Below's call added for safety & illustration : inform particle change to not
0155     // -- modify the clone (ie : daughter) weight to make it that of the primary.
0156     // -- Here this call is not mandatory as both tracks have same weights.
0157     fParticleChange.SetSecondaryWeightByProcess(true);
0158   }
0159   else {
0160     // -- We apply Russian roulette:
0161     G4double survivingProbability = G4double(postImportance) / G4double(preImportance);
0162 
0163     // Shoot a random number (in ]0,1[ segment):
0164     G4double random = G4UniformRand();
0165     if (random > survivingProbability) {
0166       // We ask for the the track to be killed:
0167       fParticleChange.ProposeTrackStatus(fStopAndKill);
0168     }
0169     else {
0170       // In this case, the track survives. We change its weight
0171       // to conserve weight among killed and survival tracks:
0172       fParticleChange.ProposeParentWeight(initialWeight / survivingProbability);
0173     }
0174   }
0175 
0176   return &fParticleChange;
0177 }
0178 
0179 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......