LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
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 
21 
22 #include "Geant4/G4DynamicParticle.hh"
23 #include "Geant4/G4KaonZeroLong.hh"
24 #include "Geant4/G4KaonZeroShort.hh"
25 #include "Geant4/G4LorentzVector.hh"
26 #include "Geant4/G4ParticleChange.hh"
27 #include "Geant4/G4ParticleDefinition.hh"
28 #include "Geant4/G4Step.hh"
29 #include "Geant4/G4String.hh"
30 #include "Geant4/G4ThreeVector.hh"
31 #include "Geant4/G4Track.hh"
32 #include "Geant4/G4VParticleChange.hh"
33 #include "Geant4/G4ios.hh"
34 #include "Geant4/Randomize.hh"
35 
36 #include "cetlib_except/exception.h"
37 
38 #include <TMath.h>
39 
40 namespace larg4 {
41 
42  G4VParticleChange* MuNuclearSplittingProcessXSecBias::PostStepDoIt(const G4Track& track,
43  const G4Step& step)
44  {
45 
46  G4VParticleChange* pChange = pRegProcess->PostStepDoIt(track, step);
47  pChange->SetVerboseLevel(0);
48  pChange->SetSecondaryWeightByProcess(true);
49 
50  G4double secWeight = 1.0;
51  if (fNSplit >= 1) secWeight = 1.0 / fNSplit;
52  std::vector<G4Track*> secondaries; // Secondary store
53 
54  G4double nw = 1.0;
55  // Let's go bias the underlying xsection.
56  if (xBiasMode == 1) {
57  G4double s = step.GetStepLength();
58  G4double x = pRegProcess->GetCurrentInteractionLength();
59  nw = pChange->GetParentWeight();
60  // need to undo the change made to the parent track in
61  // most recent step (1/wc).
62  // It seems to be possible to get here w.o. first having hit the
63  // AlongStep Method that initialied wc. So protect against division y 0.
64  if (wc < 1.0e-10) wc = 1.0;
65  nw *= 1 / wc * (1. - exp(-s / x)) / (1 - exp(-eFactor * s / x));
66  G4cout << " MNSPXSB.PostStepDoit(): original wt = " << pChange->GetParentWeight()
67  << " eF = " << eFactor << G4endl;
68  G4cout << " MNSPXSB.PostStepDoit(): New weight = " << nw << " wc = " << wc << " s= " << s
69  << " x = " << x << G4endl;
70  ((G4ParticleChange*)pChange)->ProposeParentWeight(nw);
71  }
72  else if (xBiasMode == 2) {
73  nw = pChange->GetParentWeight() * XBiasSecondaryWeight();
74  ((G4ParticleChange*)pChange)->ProposeParentWeight(nw);
75  // for (G4int i = 0; i < pChange->GetNumberOfSecondaries(); i++)
76  //pChange->GetSecondary(i)->SetWeight(nw);
77  if (G4UniformRand() <
78  XBiasSurvivalProbability()) { // need to add the primary back in to balance the weight
79  // the position of the extra track should be moved to the next volume, but I don't know how yet.
80  // need to change number of secondary first before adding an additional track
81  pChange->SetNumberOfSecondaries(pChange->GetNumberOfSecondaries() + 1);
82  G4ThreeVector mDirection = track.GetDynamicParticle()->GetMomentumDirection();
83  G4DynamicParticle* aD =
84  new G4DynamicParticle((track.GetDynamicParticle())->GetDefinition(),
85  G4LorentzVector(mDirection,
86  (track.GetDynamicParticle())->GetKineticEnergy() +
87  step.GetTotalEnergyDeposit()));
88  G4Track* secTrk = new G4Track(aD, step.GetDeltaTime(), step.GetDeltaPosition());
89  pChange->AddSecondary(secTrk);
90  pChange->GetSecondary(pChange->GetNumberOfSecondaries() - 1)
91  ->SetWeight(XBiasSurvivalProbability() * track.GetWeight());
92  }
93  else {
94  nw = track.GetWeight();
95  pChange->ProposeParentWeight(nw);
96  }
97  }
98 
99  secWeight = secWeight * nw;
100 
101  // Loop over PostStepDoIt method to generate multiple secondaries.
102  // The point is for each value of ii up to Nsplit we want to re-toss
103  // all secondaries for the muNucl process. Each toss gives back numSec
104  // secondaries, which will be a different sample of species/momenta each time.
105  G4VParticleChange* particleChange = new G4VParticleChange();
106 
107  for (unsigned int ii = 0; ii < (unsigned int)fNSplit; ii++) {
108  particleChange = pRegProcess->PostStepDoIt(track, step);
109  if (!particleChange)
110  throw std::runtime_error(
111  "MuNuclearSplittingProcessXSecBias::PostStepDoIt(): no particle change");
112  G4int j(0);
113  G4int numSec(particleChange->GetNumberOfSecondaries());
114  // Don't change weight of last secondary. It's the just-added primary in this mode.
115  for (j = 0; j < numSec; j++) {
116  G4Track* newSec = new G4Track(*(particleChange->GetSecondary(j)));
117  G4String pdgstr = newSec->GetParticleDefinition()->GetParticleName();
118  //G4double ke = newSec->GetKineticEnergy()/GeV;
119  G4int pdg = newSec->GetParticleDefinition()->GetPDGEncoding();
120  if (abs(pdg) == 310 || abs(pdg) == 311 || abs(pdg) == 3122 || abs(pdg) == 2112) {
121  // std::cout << "MuNuclSplProc: Creating " << pdgstr << " of Kinetic Energy " << ke << " GeV. numSec is " << j << std::endl;
122 
123  if (pdg == G4KaonZeroShort::KaonZeroShort()->GetPDGEncoding() && G4UniformRand() < 0.50) {
124  pdg = G4KaonZeroLong::KaonZeroLong()->GetPDGEncoding();
125  pdgstr = G4KaonZeroLong::KaonZeroLong()->GetParticleName();
126  G4LorentzVector pK0L(
127  newSec->GetMomentum(),
128  TMath::Sqrt(TMath::Power(G4KaonZeroLong::KaonZeroLong()->GetPDGMass(), 2) +
129  TMath::Power(newSec->GetMomentum().mag(), 2)));
130  G4DynamicParticle* newK0L = new G4DynamicParticle(G4KaonZeroLong::KaonZeroLong(), pK0L);
131 
132  G4Track* newSecK0L = new G4Track(newK0L, track.GetGlobalTime(), track.GetPosition());
133  secondaries.push_back(newSecK0L);
134  }
135  else {
136  secondaries.push_back(newSec);
137  }
138  }
139  }
140  }
141 
142  pChange->SetNumberOfSecondaries(secondaries.size());
143  pChange->SetSecondaryWeightByProcess(true);
144  //pChange->ProposeTrackStatus(fStopAndKill); // End of the story for this muon.
145 
146  //int numSecAdd = secondaries.size();
147  std::vector<G4Track*>::iterator iter = secondaries.begin(); // Add all secondaries
148  while (iter != secondaries.end()) {
149  G4Track* myTrack = *iter;
150  G4String pdgstr = myTrack->GetParticleDefinition()->GetParticleName();
151  G4double ke = myTrack->GetKineticEnergy() / CLHEP::GeV;
152  G4int pdg = myTrack->GetParticleDefinition()->GetPDGEncoding();
153  if (abs(pdg) == 130 || abs(pdg) == 310 || abs(pdg) == 311 || abs(pdg) == 3122 ||
154  abs(pdg) == 2112) {
155  if (pdg != 2112)
156  std::cout << "MuNuclSplXSB(): Adding " << pdgstr << " of Kinetic Energy and weight " << ke
157  << " GeV and " << secWeight << "." << std::endl;
158 
159  myTrack->SetWeight(secWeight);
160  pChange->AddSecondary(myTrack);
161  }
162  iter++;
163  }
164  return pChange;
165  }
166 
167  G4VParticleChange* MuNuclearSplittingProcessXSecBias::AlongStepDoIt(const G4Track& track,
168  const G4Step& step)
169  {
170 
171  wc = 1.0;
172 
173  if (xBiasMode == 2) {
174  /* I don't understand this. If I new it and Initialize(track) it works, but
175  it goes off and grinds through the event.
176  If I try to use pRegProcess->AlongStepDoIt() it crashes
177  at the GetParentWeight() just below.
178  */
179  G4VParticleChange* pC = new G4VParticleChange();
180  pC->Initialize(track);
181  //pC = pRegProcess->AlongStepDoIt( track, step);
182 
183  G4double nw = pC->GetParentWeight() * XBiasSecondaryWeight();
184  pC->ProposeParentWeight(nw);
185  for (G4int i = 0; i < pC->GetNumberOfSecondaries(); i++)
186  pC->GetSecondary(i)->SetWeight(nw);
187  //
188  if (G4UniformRand() < XBiasSurvivalProbability()) {
189  pC->SetNumberOfSecondaries(pC->GetNumberOfSecondaries() + 1);
190  G4ThreeVector mDirection = track.GetDynamicParticle()->GetMomentumDirection();
191  G4DynamicParticle* aD =
192  new G4DynamicParticle((track.GetDynamicParticle())->GetDefinition(),
193  G4LorentzVector(mDirection,
194  (track.GetDynamicParticle())->GetKineticEnergy() +
195  step.GetTotalEnergyDeposit()));
196  G4Track* secTrk =
197  new G4Track(aD,
198  track.GetGlobalTime(),
199  track.GetPosition()); // +step.GetDeltaTime(), ,+step.GetDeltaPosition()
200  secTrk->SetGoodForTrackingFlag(true);
201  pC->AddSecondary(secTrk); // Add the primary right back.
202  pC->GetSecondary(pC->GetNumberOfSecondaries() - 1)
203  ->SetWeight(XBiasSurvivalProbability() * track.GetWeight());
204  //pC->ProposeTrackStatus(fStopAndKill); // 8-June-2011-21:36 MDT, from Finland, I (EDC) added this. Seems right. Makes it go, anyway. Almost too fast.
205  }
206 
207  return pC;
208  }
209  else if (xBiasMode == 1) {
210  fParticleChange.Initialize(track);
211  G4double s = step.GetStepLength();
212  G4double x = pRegProcess->GetCurrentInteractionLength();
213  //fParticleChange = &(pRegProcess->AlongStepDoIt( track, step));
214  wc = exp(-(1. - eFactor) * s / x);
215  G4double w = wc * fParticleChange.GetParentWeight();
216  fParticleChange.SetParentWeightByProcess(false);
217  fParticleChange.ProposeParentWeight(w);
218  if (w > 100) {
219  // G4cout << " MNSPXSB.AlongStepDoit(): GPW is " << w/wc << " wc = " << wc << ", CIL = "<< x << G4endl;
220  }
221 
222  return &fParticleChange;
223  }
224 
225  if (xBiasMode != 1 && xBiasMode != 2) {
226  throw cet::exception("Incorrectly set Bias Mode. ")
227  << "Set XBiasMode to 0 or 1. " << xBiasMode << " not allowed!\n";
228  }
229  fParticleChange.Initialize(track);
230  return &fParticleChange;
231  }
232 
234  {
235  G4double result = 0;
236  G4double nLTraversed = GetTotalNumberOfInteractionLengthTraversed();
237  G4double biasedProbability = 1. - std::exp(-nLTraversed);
238  G4double realProbability = 1 - std::exp(-nLTraversed / eFactor);
239  result = (biasedProbability - realProbability) / biasedProbability;
240  return result;
241  }
242 
244  {
245  G4double result = 0;
246  G4double nLTraversed = GetTotalNumberOfInteractionLengthTraversed();
247  result = 1. / eFactor * std::exp(-nLTraversed / eFactor * (1 - 1. / eFactor));
248  return result;
249  }
250 
252  {
253  return theInitialNumberOfInteractionLength - G4VProcess::theNumberOfInteractionLengthLeft;
254  }
255 
257  const G4Track& track,
258  G4double previousStepSize,
259  G4ForceCondition* condition)
260  {
261  // I believe this is the money line for the whole thing. By shrinking the
262  // interaction length in MuNuclear's process, it's more likely that
263  // this process will be chosen in the competition among processes.
264  if (xBiasMode) {
265  G4double psgPIL = (1. / eFactor) * pRegProcess->PostStepGetPhysicalInteractionLength(
266  track, previousStepSize, condition);
267  return psgPIL;
268  }
269 
270  return pRegProcess->PostStepGetPhysicalInteractionLength(track, previousStepSize, condition);
271  }
272 
274  const G4Track& track,
275  G4double previousStepSize,
276  G4double currentMinimumStep,
277  G4double& proposedSafety,
278  G4GPILSelection* selection)
279  {
280  if (xBiasMode == 2) {
281  // I am pretty sure this mode does not work because MuNuclear doesn't interact
282  // AlongStep. Below often (always?) returns a negative number, which I have to
283  // swizzle.
284  G4double intLen;
285  intLen =
286  (1. / eFactor) * pRegProcess->AlongStepGetPhysicalInteractionLength(
287  track, previousStepSize, currentMinimumStep, proposedSafety, selection);
288  if (intLen < 0)
289  return currentMinimumStep;
290  else
291  return intLen;
292  }
293  else
294  return DBL_MAX;
295  }
296 
297 } // end namespace
Float_t x
Definition: compare.C:6
intermediate_table::iterator iterator
virtual G4double PostStepGetPhysicalInteractionLength(const G4Track &track, G4double previousStepSize, G4ForceCondition *condition)
constexpr auto abs(T v)
Returns the absolute value of the argument.
Geant4 interface.
Check of Geant4 to run the LArSoft detector simulation.
virtual G4double AlongStepGetPhysicalInteractionLength(const G4Track &track, G4double previousStepSize, G4double currentMinimumStep, G4double &proposedSafety, G4GPILSelection *selection)
G4VParticleChange * AlongStepDoIt(const G4Track &track, const G4Step &step)
Float_t e
Definition: plot.C:35
Float_t track
Definition: plot.C:35
Float_t w
Definition: plot.C:20
G4VParticleChange * PostStepDoIt(const G4Track &track, const G4Step &step)
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33