ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GB06BOptnSplitAndKillByImportance.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file GB06BOptnSplitAndKillByImportance.cc
1 //
2 // ********************************************************************
3 // * License and Disclaimer *
4 // * *
5 // * The Geant4 software is copyright of the Copyright Holders of *
6 // * the Geant4 Collaboration. It is provided under the terms and *
7 // * conditions of the Geant4 Software License, included in the file *
8 // * LICENSE and available at http://cern.ch/geant4/license . These *
9 // * include a list of copyright holders. *
10 // * *
11 // * Neither the authors of this software system, nor their employing *
12 // * institutes,nor the agencies providing financial support for this *
13 // * work make any representation or warranty, express or implied, *
14 // * regarding this software system or assume any liability for its *
15 // * use. Please see the license in the file LICENSE and URL above *
16 // * for the full disclaimer and the limitation of liability. *
17 // * *
18 // * This code implementation is the result of the scientific and *
19 // * technical work of the GEANT4 collaboration. *
20 // * By using, copying, modifying or distributing the software (or *
21 // * any work based on the software) you agree to acknowledge its *
22 // * use in resulting scientific publications, and indicate your *
23 // * acceptance of all terms of the Geant4 Software license. *
24 // ********************************************************************
25 //
26 //
29 
31 #include "Randomize.hh"
32 
33 
37 #include "G4ProcessManager.hh"
38 
39 
40 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
41 
43 : G4VBiasingOperation (name),
44  fParallelWorldIndex ( -1 ),
45  fBiasingSharedData ( nullptr ),
46  fParticleChange(),
47  fDummyParticleChange()
48 {}
49 
50 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
51 
53 {}
54 
55 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
56 
59  G4double,
61 {
62 
63  // -- Remember the touchable history (ie geometry state) at the beginning of the step:
64  // -- Start by getting the process handling the step limitation in parallel
65  // -- geometries for the generic biasing:
66  auto biasingLimiterProcess = fBiasingSharedData->GetParallelGeometriesLimiterProcess();
68  biasingLimiterProcess
69  ->GetNavigator( fParallelWorldIndex ) // -- get the navigator of the geometry...
70  ->CreateTouchableHistoryHandle(); // -- ...and collect the geometry state.
71 
72  // -- We request to be "forced" : meaning GenerateBiasingFinalState(...) will be called
73  // -- anyway at the PostStepDoIt(...) stage (ie, when the track will have been moved to
74  // -- its end point position) and, there, we will have to handle the decision to
75  // -- split/kill if we are on a volume boundary, or do nothing, if we're not:
76  *condition = Forced;
77 
78  // -- As we're forced, we make this returned length void:
79  return DBL_MAX;
80 }
81 
82 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
83 
86  const G4Step* )
87 {
88  // -- Given we used the "Forced" condition, this method is always called.
89  // -- We check the status of the step in the parallel geometry, and apply
90  // -- splitting/killing if the step has been limited by the geometry.
91 
92  // -- We first check if we limit the step in the parallel geometry:
93  G4bool isLimiting = fBiasingSharedData
96 
97  // -- if not limiting, we leave the track unchanged:
98  if ( !isLimiting )
99  {
101  return &fDummyParticleChange;
102  }
103 
104  // -- We collect the geometry state at the end point step:
105  // -- Note this is the same call than in the DistanceToApplyOperation(...) for the
106  // -- fPreStepTouchableHistory, but the navigator has pushed the track in the next
107  // -- volume since then (even if the track is still on the boundary), and hence the
108  // -- geometry state has changed.
109  auto biasingLimiterProcess = fBiasingSharedData->GetParallelGeometriesLimiterProcess();
111  biasingLimiterProcess
112  ->GetNavigator( fParallelWorldIndex )
113  ->CreateTouchableHistoryHandle();
114 
115 
116  // -- We verify we are still in the "same" physical volume:
117  // -- remember : using a replica, we have "one" physical volume
118  // -- but representing many different placements, distinguished
119  // -- by replica number. By checking we are in the same physical
120  // -- volume, we verify the end step point has not reached the
121  // -- world volume of the parallel geometry:
122  if ( fPreStepTouchableHistory ->GetVolume() !=
124  {
125  // -- the track is leaving the volumes in which biasing is applied,
126  // -- we leave this track unchanged:
128  return &fDummyParticleChange;
129  }
130 
131  // -------------------------------------------------------------------------------------
132  // -- At this stage, we know we have a particle crossing a boundary between two slices,
133  // -- each of this slice has a well defined importance : we apply the biasing.
134  // -- We will split if the track is entering a volume with higher importance, and
135  // -- kill (applying Russian roulette) in the other case.
136  // -------------------------------------------------------------------------------------
137 
138  // -- We start by getting the replica numbers:
139  G4int preReplicaNumber = fPreStepTouchableHistory->GetReplicaNumber();
140  G4int postReplicaNumber = fPostStepTouchableHistory->GetReplicaNumber();
141 
142  // -- and get the related importance we defined in the importance map:
143  G4int preImportance = (*fImportanceMap)[ preReplicaNumber];
144  G4int postImportance = (*fImportanceMap)[postReplicaNumber];
145 
146 
147  // -- Get track weight:
148  G4double initialWeight = track->GetWeight();
149 
150  // -- Initialize the "particle change" (it will communicate the new track state to
151  // -- the tracking):
152  fParticleChange.Initialize(*track);
153 
154  if ( postImportance > preImportance )
155  {
156  // -- We split :
157  G4int splittingFactor = postImportance/preImportance;
158 
159  // Define the tracks weight:
160  G4double weightOfTrack = initialWeight/splittingFactor;
161 
162  // Ask currect track weight to be changed to the new value:
163  fParticleChange.ProposeParentWeight( weightOfTrack );
164  // Now we clone this track (this is the actual splitting):
165  // we will then have the primary and clone of it, hence the
166  // splitting by a factor 2:
167  G4Track* clone = new G4Track( *track );
168  clone->SetWeight( weightOfTrack );
169  fParticleChange.AddSecondary( clone );
170  // -- Below's call added for safety & illustration : inform particle change to not
171  // -- modify the clone (ie : daughter) weight to make it that of the primary.
172  // -- Here this call is not mandatory as both tracks have same weights.
174  }
175  else
176  {
177  // -- We apply Russian roulette:
178  G4double survivingProbability = G4double(postImportance) / G4double(preImportance);
179 
180  // Shoot a random number (in ]0,1[ segment):
181  G4double random = G4UniformRand();
182  if ( random > survivingProbability )
183  {
184  // We ask for the the track to be killed:
186  }
187  else
188  {
189  // In this case, the track survives. We change its weight
190  // to conserve weight among killed and survival tracks:
191  fParticleChange.ProposeParentWeight( initialWeight/survivingProbability );
192  }
193  }
194 
195  return &fParticleChange;
196 
197 }
198 
199 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......