MuNuclearSplittingProcessXSecBias.cxx
Go to the documentation of this file.
1 //
2 // This(these) is (are) a variance reduction technique(s).
3 //
4 //
5 // Secondary biasing code adapted from EventBiasing from Jane Tinslay, SLAC. 2008.
6 // (Who's now at Cisco, I think.) XSBiasing code from http://geant4.cern.ch/collaboration/workshops/workshop2002/slides/docs/flei/biasing.pdf. (And NOT from http://www.lcsim.org/software/geant4/doxygen/html/classG4HadronicProcess.html, where I *believe* the point is to bias primaries and secondaries from sub-classes of Cross-Sections in an already chosen
7 // broader class of XSs. This doesn't help us. We need more occurrences (albeit with small
8 // weights) of a specific process.
9 //
10 //
11 // The point is to create Nsplit secondaries with each muNucl process, so
12 // that we may, e.g., create many, otherwise-rare, K0s which
13 // may charge exchange into pernicious K+s which then mimic proton dk. And,
14 // additionally now to make the XSection for the muNucl process itself higher,
15 // keeping track of appropriate weights everywhere.
16 //
17 // echurch@fnal.gov, May, 2011.
18 //
19 
20 
22 
23 #include "Geant4/G4WrapperProcess.hh"
24 #include "Geant4/G4VParticleChange.hh"
25 #include "Geant4/G4SDManager.hh"
26 #include "Geant4/G4RunManager.hh"
27 #include "Geant4/G4Event.hh"
28 #include "Geant4/G4HCofThisEvent.hh"
29 #include "Geant4/G4Track.hh"
30 #include "Geant4/G4Step.hh"
31 #include "Geant4/G4TrackStatus.hh"
32 #include "Geant4/G4ParticleDefinition.hh"
33 #include "Geant4/G4ParticleTypes.hh"
34 #include "Geant4/Randomize.hh"
35 #include "Geant4/G4KaonZeroLong.hh"
36 #include "Geant4/G4ios.hh"
37 
38 #include "cetlib_except/exception.h"
39 
40 #include <TMath.h>
41 
42 namespace gar {
43  namespace garg4 {
44 
45 
46 
47  G4VParticleChange* MuNuclearSplittingProcessXSecBias::PostStepDoIt(const G4Track& track, const G4Step& step)
48  {
49 
50  G4VParticleChange* pChange = pRegProcess->PostStepDoIt( track, step );
51  pChange->SetVerboseLevel(0);
52  pChange->SetSecondaryWeightByProcess(true);
53 
54  G4double secWeight = 1.0;
55  if (fNSplit>=1) secWeight = 1.0/fNSplit;
56  std::vector<G4Track*> secondaries; // Secondary store
57 
58  G4double nw=1.0;
59  // Let's go bias the underlying xsection.
60  if(xBiasMode==1)
61  {
62  G4double s = step.GetStepLength();
63  G4double x = pRegProcess->GetCurrentInteractionLength();
64  nw = pChange->GetParentWeight();
65  // need to undo the change made to the parent track in
66  // most recent step (1/wc).
67  // It seems to be possible to get here w.o. first having hit the
68  // AlongStep Method that initialied wc. So protect against division y 0.
69  if (wc < 1.0e-10) wc = 1.0;
70  nw *= 1/wc * (1. - exp(-s/x))/(1 - exp(-eFactor*s/x)) ;
71  G4cout << " MNSPXSB.PostStepDoit(): original wt = " << pChange->GetParentWeight() << " eF = " << eFactor << G4endl;
72  G4cout << " MNSPXSB.PostStepDoit(): New weight = " << nw << " wc = " << wc << " s= " << s <<" x = " << x << G4endl;
73  ((G4ParticleChange*)pChange)->ProposeParentWeight(nw) ;
74  }
75  else if (xBiasMode==2)
76  {
77  nw = pChange->GetParentWeight()*XBiasSecondaryWeight();
78  ((G4ParticleChange*)pChange)->ProposeParentWeight(nw) ;
79  // for (G4int i = 0; i < pChange->GetNumberOfSecondaries(); i++)
80  //pChange->GetSecondary(i)->SetWeight(nw);
81  if(G4UniformRand()<XBiasSurvivalProbability())
82  { // need to add the primary back in to balance the weight
83  // the position of the extra track should be moved to the next volume, but I don't know how yet.
84  // need to change number of secondary first before adding an additional track
85  pChange->SetNumberOfSecondaries(pChange->GetNumberOfSecondaries()+1);
86  G4ThreeVector mDirection = track.GetDynamicParticle()->GetMomentumDirection();
87  G4DynamicParticle* aD = new G4DynamicParticle((track.GetDynamicParticle())->GetDefinition(),
88  G4LorentzVector(mDirection,
89  (track.GetDynamicParticle())->GetKineticEnergy()+step.GetTotalEnergyDeposit()));
90  G4Track* secTrk = new G4Track(aD,step.GetDeltaTime(),step.GetDeltaPosition());
91  pChange->AddSecondary(secTrk);
92  pChange->GetSecondary(pChange->GetNumberOfSecondaries()-1)->
93  SetWeight(XBiasSurvivalProbability()*track.GetWeight());
94  }
95  else
96  {
97  nw = track.GetWeight();
98  pChange->ProposeParentWeight(nw);
99  }
100  }
101 
102  secWeight = secWeight*nw;
103 
104  // Loop over PostStepDoIt method to generate multiple secondaries.
105  // The point is for each value of ii up to Nsplit we want to re-toss
106  // all secondaries for the muNucl process. Each toss gives back numSec
107  // secondaries, which will be a different sample of species/momenta each time.
108  G4VParticleChange* particleChange = new G4VParticleChange();
109 
110  for (unsigned int ii=0; ii<(unsigned int)fNSplit; ii++) {
111  particleChange = pRegProcess->PostStepDoIt(track, step);
112  if (!particleChange)
113  throw std::runtime_error("MuNuclearSplittingProcessXSecBias::PostStepDoIt(): no particle change");
114  G4int j(0);
115  G4int numSec(particleChange->GetNumberOfSecondaries());
116  // Don't change weight of last secondary. It's the just-added primary in this mode.
117  for (j=0; j<numSec; j++)
118  {
119  G4Track* newSec = new G4Track(*(particleChange->GetSecondary(j)));
120  G4String pdgstr = newSec->GetParticleDefinition()->GetParticleName();
121  //G4double ke = newSec->GetKineticEnergy()/GeV;
122  G4int pdg = newSec->GetParticleDefinition()->GetPDGEncoding();
123  if (abs(pdg)==310 ||abs(pdg)==311 || abs(pdg)==3122 || abs(pdg)==2112)
124  {
125  // std::cout << "MuNuclSplProc: Creating " << pdgstr << " of Kinetic Energy " << ke << " GeV. numSec is " << j << std::endl;
126 
127  if (pdg==G4KaonZeroShort::KaonZeroShort()->GetPDGEncoding()&&G4UniformRand()<0.50)
128  {
129  pdg = G4KaonZeroLong::KaonZeroLong()->GetPDGEncoding();
130  pdgstr = G4KaonZeroLong::KaonZeroLong()->GetParticleName();
131  G4LorentzVector pK0L(newSec->GetMomentum(),TMath::Sqrt(TMath::Power(G4KaonZeroLong::KaonZeroLong()->GetPDGMass(),2)+TMath::Power(newSec->GetMomentum().mag(),2)));
132  G4DynamicParticle *newK0L = new G4DynamicParticle(G4KaonZeroLong::KaonZeroLong(),pK0L);
133 
134  G4Track* newSecK0L = new G4Track(newK0L,track.GetGlobalTime(),track.GetPosition());
135  secondaries.push_back(newSecK0L);
136  }
137  else
138  {
139  secondaries.push_back(newSec);
140  }
141  }
142  }
143  }
144 
145  pChange->SetNumberOfSecondaries(secondaries.size());
146  pChange->SetSecondaryWeightByProcess(true);
147  //pChange->ProposeTrackStatus(fStopAndKill); // End of the story for this muon.
148 
149  //int numSecAdd = secondaries.size();
150  std::vector<G4Track*>::iterator iter = secondaries.begin(); // Add all secondaries
151  while (iter != secondaries.end()) {
152  G4Track* myTrack = *iter;
153  G4String pdgstr = myTrack->GetParticleDefinition()->GetParticleName();
154  G4double ke = myTrack->GetKineticEnergy()/CLHEP::GeV;
155  G4int pdg = myTrack->GetParticleDefinition()->GetPDGEncoding();
156  if (abs(pdg)==130 ||abs(pdg)==310 ||abs(pdg)==311 || abs(pdg)==3122 || abs(pdg)==2112)
157  {
158  if (pdg!=2112)
159  std::cout << "MuNuclSplXSB(): Adding " << pdgstr << " of Kinetic Energy and weight " << ke << " GeV and " << secWeight << "." << std::endl;
160 
161  myTrack->SetWeight(secWeight);
162  pChange->AddSecondary(myTrack);
163  }
164  iter++;
165  }
166  return pChange;
167 
168  }
169 
171  const G4Track& track,
172  const G4Step& step
173  )
174  {
175 
176  wc = 1.0;
177 
178  if (xBiasMode==2)
179  {
180  /* I don't understand this. If I new it and Initialize(track) it works, but
181  it goes off and grinds through the event.
182  If I try to use pRegProcess->AlongStepDoIt() it crashes
183  at the GetParentWeight() just below.
184  */
185  G4VParticleChange* pC = new G4VParticleChange();
186  pC->Initialize(track);
187  //pC = pRegProcess->AlongStepDoIt( track, step);
188 
189  G4double nw = pC->GetParentWeight()*XBiasSecondaryWeight();
190  pC->ProposeParentWeight(nw) ;
191  for (G4int i = 0; i < pC->GetNumberOfSecondaries(); i++)
192  pC->GetSecondary(i)->SetWeight(nw);
193  //
194  if(G4UniformRand()<XBiasSurvivalProbability())
195  {
196  pC->SetNumberOfSecondaries(pC->GetNumberOfSecondaries()+1);
197  G4ThreeVector mDirection = track.GetDynamicParticle()->GetMomentumDirection();
198  G4DynamicParticle* aD = new G4DynamicParticle((track.GetDynamicParticle())->GetDefinition(),
199  G4LorentzVector(mDirection,
200  (track.GetDynamicParticle())->GetKineticEnergy()+step.GetTotalEnergyDeposit()));
201  G4Track* secTrk = new G4Track(aD,track.GetGlobalTime(),track.GetPosition()); // +step.GetDeltaTime(), ,+step.GetDeltaPosition()
202  secTrk->SetGoodForTrackingFlag(true);
203  pC->AddSecondary(secTrk); // Add the primary right back.
204  pC->GetSecondary(pC->GetNumberOfSecondaries()-1)->SetWeight(XBiasSurvivalProbability()*track.GetWeight());
205  //pC->ProposeTrackStatus(fStopAndKill); // 8-June-2011-21:36 MDT, from Finland, I (EDC) added this. Seems right. Makes it go, anyway. Almost too fast.
206  }
207 
208  return pC;
209  }
210  else if (xBiasMode==1)
211  {
212  fParticleChange.Initialize(track) ;
213  G4double s = step.GetStepLength();
214  G4double x = pRegProcess->GetCurrentInteractionLength();
215  //fParticleChange = &(pRegProcess->AlongStepDoIt( track, step));
216  wc = exp(-(1. - eFactor)*s/x);
217  G4double w = wc * fParticleChange.GetParentWeight();
218  fParticleChange.SetParentWeightByProcess(false);
219  fParticleChange.ProposeParentWeight(w) ;
220  if (w>100)
221  {
222  // G4cout << " MNSPXSB.AlongStepDoit(): GPW is " << w/wc << " wc = " << wc << ", CIL = "<< x << G4endl;
223  }
224 
225  return &fParticleChange;
226  }
227 
228  if (xBiasMode!=1 && xBiasMode!=2)
229  {
230  throw cet::exception("Incorrectly set Bias Mode. ")
231  << "Set XBiasMode to 0 or 1. " << xBiasMode << " not allowed!\n";
232  }
233  fParticleChange.Initialize(track) ;
234  return &fParticleChange;
235  }
236 
237 
239  {
240  G4double result = 0;
241  G4double nLTraversed = GetTotalNumberOfInteractionLengthTraversed();
242  G4double biasedProbability = 1.-std::exp(-nLTraversed);
243  G4double realProbability = 1-std::exp(-nLTraversed/eFactor);
244  result = (biasedProbability-realProbability)/biasedProbability;
245  return result;
246  }
247 
249  {
250  G4double result = 0;
251  G4double nLTraversed = GetTotalNumberOfInteractionLengthTraversed();
252  result = 1./eFactor*std::exp(-nLTraversed/eFactor*(1-1./eFactor));
253  return result;
254  }
255 
256 
258  {
260  -G4VProcess::theNumberOfInteractionLengthLeft;
261  }
262 
263 
265  G4double previousStepSize,
266  G4ForceCondition* condition )
267  {
268  // I believe this is the money line for the whole thing. By shrinking the
269  // interaction length in MuNuclear's process, it's more likely that
270  // this process will be chosen in the competition among processes.
271  if(xBiasMode)
272  {
273  G4double psgPIL = (1./eFactor) * pRegProcess->PostStepGetPhysicalInteractionLength(
274  track,
275  previousStepSize,
276  condition );
277  return psgPIL;
278  }
279 
280  return pRegProcess->PostStepGetPhysicalInteractionLength(
281  track,
282  previousStepSize,
283  condition );
284 
285  }
286 
287 
289  G4double previousStepSize,
290  G4double currentMinimumStep,
291  G4double& proposedSafety,
292  G4GPILSelection* selection )
293  {
294  if (xBiasMode==2)
295  {
296  // I am pretty sure this mode does not work because MuNuclear doesn't interact
297  // AlongStep. Below often (always?) returns a negative number, which I have to
298  // swizzle.
299  G4double intLen;
300  intLen = (1./eFactor) *
301  pRegProcess->AlongStepGetPhysicalInteractionLength( track,previousStepSize,
302  currentMinimumStep,proposedSafety,selection);
303  if (intLen<0) return currentMinimumStep;
304  else return intLen;
305  }
306  else
307  return DBL_MAX ;
308  }
309 
310 
311  } // end namespace
312 } // gar
G4VParticleChange * AlongStepDoIt(const G4Track &track, const G4Step &step)
intermediate_table::iterator iterator
static QCString result
G4VParticleChange * PostStepDoIt(const G4Track &track, const G4Step &step)
T abs(T value)
const double e
static constexpr double GeV
Definition: Units.h:28
General GArSoft Utilities.
virtual G4double AlongStepGetPhysicalInteractionLength(const G4Track &track, G4double previousStepSize, G4double currentMinimumStep, G4double &proposedSafety, G4GPILSelection *selection)
list x
Definition: train.py:276
virtual G4double PostStepGetPhysicalInteractionLength(const G4Track &track, G4double previousStepSize, G4ForceCondition *condition)
static QCString * s
Definition: config.cpp:1042
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
QTextStream & endl(QTextStream &s)