CMS 3D CMS Logo

StackingAction.cc
Go to the documentation of this file.
6 
8 
9 #include "G4VProcess.hh"
10 #include "G4EmProcessSubType.hh"
11 #include "G4LogicalVolumeStore.hh"
12 #include "G4RegionStore.hh"
13 #include "Randomize.hh"
14 #include "G4SystemOfUnits.hh"
15 #include "G4VSolid.hh"
16 #include "G4TransportationManager.hh"
17 #include "G4GammaGeneralProcess.hh"
18 
20  : trackAction(trka), steppingVerbose(sv) {
21  trackNeutrino = p.getParameter<bool>("TrackNeutrino");
22  killHeavy = p.getParameter<bool>("KillHeavy");
23  killGamma = p.getParameter<bool>("KillGamma");
24  kmaxGamma = p.getParameter<double>("GammaThreshold") * CLHEP::MeV;
25  kmaxIon = p.getParameter<double>("IonThreshold") * CLHEP::MeV;
26  kmaxProton = p.getParameter<double>("ProtonThreshold") * CLHEP::MeV;
27  kmaxNeutron = p.getParameter<double>("NeutronThreshold") * CLHEP::MeV;
28  killDeltaRay = p.getParameter<bool>("KillDeltaRay");
29  limitEnergyForVacuum = p.getParameter<double>("CriticalEnergyForVacuum") * CLHEP::MeV;
30  maxTrackTime = p.getParameter<double>("MaxTrackTime") * ns;
31  maxTrackTimeForward = p.getParameter<double>("MaxTrackTimeForward") * ns;
32  maxZCentralCMS = p.getParameter<double>("MaxZCentralCMS") * CLHEP::m;
33  maxTrackTimes = p.getParameter<std::vector<double> >("MaxTrackTimes");
34  maxTimeNames = p.getParameter<std::vector<std::string> >("MaxTimeNames");
35  deadRegionNames = p.getParameter<std::vector<std::string> >("DeadRegions");
36  savePDandCinAll = p.getUntrackedParameter<bool>("SaveAllPrimaryDecayProductsAndConversions", true);
37  savePDandCinTracker = p.getUntrackedParameter<bool>("SavePrimaryDecayProductsAndConversionsInTracker", false);
38  savePDandCinCalo = p.getUntrackedParameter<bool>("SavePrimaryDecayProductsAndConversionsInCalo", false);
39  savePDandCinMuon = p.getUntrackedParameter<bool>("SavePrimaryDecayProductsAndConversionsInMuon", false);
40  saveFirstSecondary = p.getUntrackedParameter<bool>("SaveFirstLevelSecondary", false);
41  killInCalo = false;
42  killInCaloEfH = false;
43 
44  // Russian Roulette
45  regionEcal = nullptr;
46  regionHcal = nullptr;
47  regionMuonIron = nullptr;
48  regionPreShower = nullptr;
49  regionCastor = nullptr;
50  regionWorld = nullptr;
51 
52  gRusRoEnerLim = p.getParameter<double>("RusRoGammaEnergyLimit") * CLHEP::MeV;
53  nRusRoEnerLim = p.getParameter<double>("RusRoNeutronEnergyLimit") * CLHEP::MeV;
54 
55  gRusRoEcal = p.getParameter<double>("RusRoEcalGamma");
56  gRusRoHcal = p.getParameter<double>("RusRoHcalGamma");
57  gRusRoMuonIron = p.getParameter<double>("RusRoMuonIronGamma");
58  gRusRoPreShower = p.getParameter<double>("RusRoPreShowerGamma");
59  gRusRoCastor = p.getParameter<double>("RusRoCastorGamma");
60  gRusRoWorld = p.getParameter<double>("RusRoWorldGamma");
61 
62  nRusRoEcal = p.getParameter<double>("RusRoEcalNeutron");
63  nRusRoHcal = p.getParameter<double>("RusRoHcalNeutron");
64  nRusRoMuonIron = p.getParameter<double>("RusRoMuonIronNeutron");
65  nRusRoPreShower = p.getParameter<double>("RusRoPreShowerNeutron");
66  nRusRoCastor = p.getParameter<double>("RusRoCastorNeutron");
67  nRusRoWorld = p.getParameter<double>("RusRoWorldNeutron");
68 
69  gRRactive = false;
70  nRRactive = false;
71  if (gRusRoEnerLim > 0.0 && (gRusRoEcal < 1.0 || gRusRoHcal < 1.0 || gRusRoMuonIron < 1.0 || gRusRoPreShower < 1.0 ||
72  gRusRoCastor < 1.0 || gRusRoWorld < 1.0)) {
73  gRRactive = true;
74  }
75  if (nRusRoEnerLim > 0.0 && (nRusRoEcal < 1.0 || nRusRoHcal < 1.0 || nRusRoMuonIron < 1.0 || nRusRoPreShower < 1.0 ||
76  nRusRoCastor < 1.0 || nRusRoWorld < 1.0)) {
77  nRRactive = true;
78  }
79 
80  if (p.exists("TestKillingOptions")) {
81  killInCalo = (p.getParameter<edm::ParameterSet>("TestKillingOptions")).getParameter<bool>("KillInCalo");
82  killInCaloEfH = (p.getParameter<edm::ParameterSet>("TestKillingOptions")).getParameter<bool>("KillInCaloEfH");
83  edm::LogWarning("SimG4CoreApplication")
84  << " *** Activating special test killing options in StackingAction \n"
85  << " *** Kill secondaries in Calorimetetrs volume = " << killInCalo << "\n"
86  << " *** Kill electromagnetic secondaries from hadrons in Calorimeters volume= " << killInCaloEfH;
87  }
88 
89  initPointer();
90  newTA = new NewTrackAction();
91 
92  edm::LogVerbatim("SimG4CoreApplication")
93  << "StackingAction initiated with"
94  << " flag for saving decay products in "
95  << " Tracker: " << savePDandCinTracker << " in Calo: " << savePDandCinCalo << " in Muon: " << savePDandCinMuon
96  << " everywhere: " << savePDandCinAll << "\n saveFirstSecondary"
97  << ": " << saveFirstSecondary << " Tracking neutrino flag: " << trackNeutrino
98  << " Kill Delta Ray flag: " << killDeltaRay << " Kill hadrons/ions flag: " << killHeavy
99  << " MaxZCentralCMS = " << maxZCentralCMS / CLHEP::m << " m"
100  << " MaxTrackTimeForward = " << maxTrackTimeForward / CLHEP::ns << " ns";
101 
102  if (killHeavy) {
103  edm::LogVerbatim("SimG4CoreApplication") << "StackingAction kill protons below " << kmaxProton / CLHEP::MeV
104  << " MeV, neutrons below " << kmaxNeutron / CLHEP::MeV << " MeV and ions"
105  << " below " << kmaxIon / CLHEP::MeV << " MeV";
106  }
108 
109  edm::LogVerbatim("SimG4CoreApplication") << "StackingAction kill tracks with "
110  << "time larger than " << maxTrackTime / CLHEP::ns << " ns ";
111  numberTimes = maxTimeNames.size();
112  if (0 < numberTimes) {
113  for (unsigned int i = 0; i < numberTimes; ++i) {
114  edm::LogVerbatim("SimG4CoreApplication")
115  << " MaxTrackTime for " << maxTimeNames[i] << " is " << maxTrackTimes[i] << " ns ";
116  maxTrackTimes[i] *= CLHEP::ns;
117  }
118  }
119  if (limitEnergyForVacuum > 0.0) {
120  edm::LogVerbatim("SimG4CoreApplication")
121  << "StackingAction LowDensity regions - kill if E < " << limitEnergyForVacuum / CLHEP::MeV << " MeV";
122  printRegions(lowdensRegions, "LowDensity");
123  }
124  if (deadRegions.size() > 0.0) {
125  edm::LogVerbatim("SimG4CoreApplication") << "StackingAction Dead regions - kill all secondaries ";
126  printRegions(deadRegions, "Dead");
127  }
128  if (gRRactive) {
129  edm::LogVerbatim("SimG4CoreApplication")
130  << "StackingAction: "
131  << "Russian Roulette for gamma Elimit(MeV)= " << gRusRoEnerLim / CLHEP::MeV << "\n"
132  << " ECAL Prob= " << gRusRoEcal << "\n"
133  << " HCAL Prob= " << gRusRoHcal << "\n"
134  << " MuonIron Prob= " << gRusRoMuonIron << "\n"
135  << " PreShower Prob= " << gRusRoPreShower << "\n"
136  << " CASTOR Prob= " << gRusRoCastor << "\n"
137  << " World Prob= " << gRusRoWorld;
138  }
139  if (nRRactive) {
140  edm::LogVerbatim("SimG4CoreApplication")
141  << "StackingAction: "
142  << "Russian Roulette for neutron Elimit(MeV)= " << nRusRoEnerLim / CLHEP::MeV << "\n"
143  << " ECAL Prob= " << nRusRoEcal << "\n"
144  << " HCAL Prob= " << nRusRoHcal << "\n"
145  << " MuonIron Prob= " << nRusRoMuonIron << "\n"
146  << " PreShower Prob= " << nRusRoPreShower << "\n"
147  << " CASTOR Prob= " << nRusRoCastor << "\n"
148  << " World Prob= " << nRusRoWorld;
149  }
150 
151  if (savePDandCinTracker) {
152  edm::LogVerbatim("SimG4CoreApplication") << "StackingAction Tracker regions: ";
153  printRegions(trackerRegions, "Tracker");
154  }
155  if (savePDandCinCalo) {
156  edm::LogVerbatim("SimG4CoreApplication") << "StackingAction Calo regions: ";
157  printRegions(caloRegions, "Calo");
158  }
159  if (savePDandCinMuon) {
160  edm::LogVerbatim("SimG4CoreApplication") << "StackingAction Muon regions: ";
161  printRegions(muonRegions, "Muon");
162  }
163  worldSolid = G4TransportationManager::GetTransportationManager()
164  ->GetNavigatorForTracking()
165  ->GetWorldVolume()
166  ->GetLogicalVolume()
167  ->GetSolid();
168 }
169 
171 
172 G4ClassificationOfNewTrack StackingAction::ClassifyNewTrack(const G4Track* aTrack) {
173  // G4 interface part
174  G4ClassificationOfNewTrack classification = fUrgent;
175  const int pdg = aTrack->GetDefinition()->GetPDGEncoding();
176  const int abspdg = std::abs(pdg);
177  auto track = const_cast<G4Track*>(aTrack);
178 
179  // primary
180  if (aTrack->GetCreatorProcess() == nullptr || aTrack->GetParentID() == 0) {
181  if (!trackNeutrino && (abspdg == 12 || abspdg == 14 || abspdg == 16 || abspdg == 18)) {
182  classification = fKill;
183  } else if (worldSolid->Inside(aTrack->GetPosition()) == kOutside) {
184  classification = fKill;
185  } else {
186  newTA->primary(track);
187  }
188  } else {
189  // secondary
190  const G4Region* reg = aTrack->GetVolume()->GetLogicalVolume()->GetRegion();
191  const double time = aTrack->GetGlobalTime();
192 
193  // definetly killed tracks
194  if (aTrack->GetTrackStatus() == fStopAndKill) {
195  classification = fKill;
196  } else if (!trackNeutrino && (abspdg == 12 || abspdg == 14 || abspdg == 16 || abspdg == 18)) {
197  classification = fKill;
198 
199  } else if (std::abs(aTrack->GetPosition().z()) >= maxZCentralCMS) {
200  // very forward secondary
201  if (time > maxTrackTimeForward) {
202  classification = fKill;
203  } else {
204  const G4Track* mother = trackAction->geant4Track();
205  newTA->secondary(track, *mother, 0);
206  }
207 
208  } else if (isItOutOfTimeWindow(reg, time)) {
209  // time window check
210  classification = fKill;
211 
212  } else {
213  // potentially good for tracking
214  const double ke = aTrack->GetKineticEnergy();
215  auto proc = aTrack->GetCreatorProcess();
216  G4int subType = proc->GetProcessSubType();
217  if (subType == 16) {
218  auto ptr = static_cast<const G4GammaGeneralProcess*>(proc);
219  proc = ptr->GetSelectedProcess();
220  subType = proc->GetProcessSubType();
221  track->SetCreatorProcess(proc);
222  }
223  LogDebug("SimG4CoreApplication") << "##StackingAction:Classify Track " << aTrack->GetTrackID() << " Parent "
224  << aTrack->GetParentID() << " " << aTrack->GetDefinition()->GetParticleName()
225  << " Ekin(MeV)=" << ke / CLHEP::MeV << " subType=" << subType << " "
226  << proc->GetProcessName();
227 
228  // kill tracks in specific regions
229  if (isThisRegion(reg, deadRegions)) {
230  classification = fKill;
231  }
232  if (classification != fKill && ke <= limitEnergyForVacuum && isThisRegion(reg, lowdensRegions)) {
233  classification = fKill;
234 
235  } else if (classification != fKill) {
236  // very low-energy gamma
237  if (pdg == 22 && killGamma && ke < kmaxGamma) {
238  classification = fKill;
239  }
240 
241  // specific track killing - not for production
242  if (killExtra && classification != fKill) {
243  if (killHeavy && classification != fKill) {
244  if (((pdg / 1000000000 == 1) && (((pdg / 10000) % 100) > 0) && (((pdg / 10) % 100) > 0) &&
245  (ke < kmaxIon)) ||
246  ((pdg == 2212) && (ke < kmaxProton)) || ((pdg == 2112) && (ke < kmaxNeutron))) {
247  classification = fKill;
248  }
249  }
250 
251  if (killDeltaRay && classification != fKill &&
252  aTrack->GetCreatorProcess()->GetProcessSubType() == fIonisation) {
253  classification = fKill;
254  }
255  if (killInCalo && classification != fKill && isThisRegion(reg, caloRegions)) {
256  classification = fKill;
257  }
258  if (killInCaloEfH && classification != fKill) {
259  int pdgMother = std::abs(trackAction->geant4Track()->GetDefinition()->GetPDGEncoding());
260  if ((pdg == 22 || abspdg == 11) && pdgMother != 11 && pdgMother != 22 && isThisRegion(reg, caloRegions)) {
261  classification = fKill;
262  }
263  }
264  }
265 
266  // Russian roulette && MC truth
267  if (classification != fKill) {
268  const G4Track* mother = trackAction->geant4Track();
269  int flag = 0;
270  if (savePDandCinAll) {
271  flag = isItPrimaryDecayProductOrConversion(aTrack, *mother);
272  } else {
276  flag = isItPrimaryDecayProductOrConversion(aTrack, *mother);
277  }
278  }
279  if (saveFirstSecondary && 0 == flag) {
280  flag = isItFromPrimary(*mother, flag);
281  }
282 
283  // Russian roulette
284  if (2112 == pdg || 22 == pdg) {
285  double currentWeight = aTrack->GetWeight();
286 
287  if (1.0 >= currentWeight) {
288  double prob = 1.0;
289  double elim = 0.0;
290 
291  // neutron
292  if (nRRactive && pdg == 2112) {
293  elim = nRusRoEnerLim;
294  if (reg == regionEcal) {
295  prob = nRusRoEcal;
296  } else if (reg == regionHcal) {
297  prob = nRusRoHcal;
298  } else if (reg == regionMuonIron) {
300  } else if (reg == regionPreShower) {
302  } else if (reg == regionCastor) {
303  prob = nRusRoCastor;
304  } else if (reg == regionWorld) {
305  prob = nRusRoWorld;
306  }
307 
308  // gamma
309  } else if (gRRactive && pdg == 22) {
310  elim = gRusRoEnerLim;
311  if (reg == regionEcal || reg == regionPreShower) {
312  if (rrApplicable(aTrack, *mother)) {
313  if (reg == regionEcal) {
314  prob = gRusRoEcal;
315  } else {
317  }
318  }
319  } else {
320  if (reg == regionHcal) {
321  prob = gRusRoHcal;
322  } else if (reg == regionMuonIron) {
324  } else if (reg == regionCastor) {
325  prob = gRusRoCastor;
326  } else if (reg == regionWorld) {
327  prob = gRusRoWorld;
328  }
329  }
330  }
331  if (prob < 1.0 && aTrack->GetKineticEnergy() < elim) {
332  if (G4UniformRand() < prob) {
333  track->SetWeight(currentWeight / prob);
334  } else {
335  classification = fKill;
336  }
337  }
338  }
339  }
340  if (classification != fKill) {
341  newTA->secondary(track, *mother, flag);
342  }
343  LogDebug("SimG4CoreApplication")
344  << "StackingAction:Classify Track " << aTrack->GetTrackID() << " Parent " << aTrack->GetParentID()
345  << " Type " << aTrack->GetDefinition()->GetParticleName() << " Ekin=" << ke / CLHEP::MeV
346  << " MeV from process " << proc->GetProcessName() << " subType=" << subType << " as " << classification
347  << " Flag: " << flag;
348  }
349  }
350  }
351  }
352  if (nullptr != steppingVerbose) {
353  steppingVerbose->StackFilled(aTrack, (classification == fKill));
354  }
355  return classification;
356 }
357 
359 
361 
363  // prepare region vector
364  const unsigned int num = maxTimeNames.size();
365  maxTimeRegions.resize(num, nullptr);
366 
367  // Russian roulette
368  const std::vector<G4Region*>* rs = G4RegionStore::GetInstance();
369 
370  for (auto& reg : *rs) {
371  const G4String& rname = reg->GetName();
372  if ((gRusRoEcal < 1.0 || nRusRoEcal < 1.0) && rname == "EcalRegion") {
373  regionEcal = reg;
374  }
375  if ((gRusRoHcal < 1.0 || nRusRoHcal < 1.0) && rname == "HcalRegion") {
376  regionHcal = reg;
377  }
378  if ((gRusRoMuonIron < 1.0 || nRusRoMuonIron < 1.0) && rname == "MuonIron") {
379  regionMuonIron = reg;
380  }
381  if ((gRusRoPreShower < 1.0 || nRusRoPreShower < 1.0) && rname == "PreshowerRegion") {
382  regionPreShower = reg;
383  }
384  if ((gRusRoCastor < 1.0 || nRusRoCastor < 1.0) && rname == "CastorRegion") {
385  regionCastor = reg;
386  }
387  if ((gRusRoWorld < 1.0 || nRusRoWorld < 1.0) && rname == "DefaultRegionForTheWorld") {
388  regionWorld = reg;
389  }
390 
391  // time limits
392  for (unsigned int i = 0; i < num; ++i) {
393  if (rname == (G4String)(maxTimeNames[i])) {
394  maxTimeRegions[i] = reg;
395  break;
396  }
397  }
398  //
399  if (savePDandCinTracker &&
400  (rname == "BeamPipe" || rname == "BeamPipeVacuum" || rname == "TrackerPixelSensRegion" ||
401  rname == "TrackerPixelDeadRegion" || rname == "TrackerDeadRegion" || rname == "TrackerSensRegion" ||
402  rname == "FastTimerRegion" || rname == "FastTimerRegionSensBTL" || rname == "FastTimerRegionSensETL")) {
403  trackerRegions.push_back(reg);
404  }
405  if (savePDandCinCalo && (rname == "HcalRegion" || rname == "EcalRegion" || rname == "PreshowerSensRegion" ||
406  rname == "PreshowerRegion" || rname == "APDRegion" || rname == "HGCalRegion")) {
407  caloRegions.push_back(reg);
408  }
409  if (savePDandCinMuon && (rname == "MuonChamber" || rname == "MuonSensitive_RPC" || rname == "MuonIron" ||
410  rname == "Muon" || rname == "MuonSensitive_DT-CSC")) {
411  muonRegions.push_back(reg);
412  }
413  if (rname == "BeamPipeOutside" || rname == "BeamPipeVacuum") {
414  lowdensRegions.push_back(reg);
415  }
416  for (auto& dead : deadRegionNames) {
417  if (rname == (G4String)(dead)) {
418  deadRegions.push_back(reg);
419  }
420  }
421  }
422 }
423 
424 bool StackingAction::isThisRegion(const G4Region* reg, std::vector<const G4Region*>& regions) const {
425  bool flag = false;
426  for (auto& region : regions) {
427  if (reg == region) {
428  flag = true;
429  break;
430  }
431  }
432  return flag;
433 }
434 
435 int StackingAction::isItPrimaryDecayProductOrConversion(const G4Track* aTrack, const G4Track& mother) const {
436  int flag = 0;
437  const TrackInformation& motherInfo(extractor(mother));
438  // Check whether mother is a primary
439  if (motherInfo.isPrimary()) {
440  if (aTrack->GetCreatorProcess()->GetProcessType() == fDecay) {
441  flag = 1;
442  } else if (aTrack->GetCreatorProcess()->GetProcessSubType() == fGammaConversion) {
443  flag = 2;
444  }
445  }
446  return flag;
447 }
448 
449 bool StackingAction::rrApplicable(const G4Track* aTrack, const G4Track& mother) const {
450  const TrackInformation& motherInfo(extractor(mother));
451 
452  // Check whether mother is gamma, e+, e-
453  const int genID = motherInfo.genParticlePID();
454  return (22 != genID && 11 != std::abs(genID));
455 }
456 
457 int StackingAction::isItFromPrimary(const G4Track& mother, int flagIn) const {
458  int flag = flagIn;
459  if (flag != 1) {
460  const TrackInformation& motherInfo(extractor(mother));
461  if (motherInfo.isPrimary()) {
462  flag = 3;
463  }
464  }
465  return flag;
466 }
467 
468 bool StackingAction::isItOutOfTimeWindow(const G4Region* reg, const double& t) const {
469  double tofM = maxTrackTime;
470  for (unsigned int i = 0; i < numberTimes; ++i) {
471  if (reg == maxTimeRegions[i]) {
472  tofM = maxTrackTimes[i];
473  break;
474  }
475  }
476  return (t > tofM);
477 }
478 
479 void StackingAction::printRegions(const std::vector<const G4Region*>& reg, const std::string& word) const {
480  for (unsigned int i = 0; i < reg.size(); ++i) {
481  edm::LogVerbatim("SimG4CoreApplication")
482  << " StackingAction: " << word << "Region " << i << ". " << reg[i]->GetName();
483  }
484 }
double nRusRoPreShower
Log< level::Info, true > LogVerbatim
NewTrackAction * newTA
bool isPrimary() const
G4ClassificationOfNewTrack ClassifyNewTrack(const G4Track *aTrack) final
StackingAction(const TrackingAction *, const edm::ParameterSet &ps, const CMSSteppingVerbose *)
std::vector< const G4Region * > lowdensRegions
double maxZCentralCMS
void PrepareNewEvent() override
std::vector< double > maxTrackTimes
TrackInformationExtractor extractor
bool rrApplicable(const G4Track *, const G4Track &) const
double gRusRoPreShower
double nRusRoEnerLim
const G4Region * regionCastor
const G4Region * regionMuonIron
const G4Track * geant4Track() const
int isItFromPrimary(const G4Track &, int) const
std::vector< const G4Region * > deadRegions
const CMSSteppingVerbose * steppingVerbose
uint64_t word
std::vector< const G4Region * > muonRegions
std::vector< std::string > maxTimeNames
void NewStage() override
const G4Region * regionEcal
~StackingAction() override
unsigned int numberTimes
void printRegions(const std::vector< const G4Region *> &reg, const std::string &word) const
double nRusRoMuonIron
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
G4VSolid * worldSolid
bool isItOutOfTimeWindow(const G4Region *, const double &) const
void secondary(const G4Track *aSecondary, const G4Track &mother, int) const
int genParticlePID() const
int isItPrimaryDecayProductOrConversion(const G4Track *, const G4Track &) const
bool isThisRegion(const G4Region *, std::vector< const G4Region *> &) const
void primary(const G4Track *aSecondary) const
bool savePDandCinTracker
std::vector< std::string > deadRegionNames
double gRusRoEnerLim
const G4Region * regionHcal
std::vector< const G4Region * > maxTimeRegions
double maxTrackTimeForward
const G4String rname[NREG]
void StackFilled(const G4Track *, bool isKilled) const
const G4Region * regionPreShower
const TrackingAction * trackAction
Log< level::Warning, false > LogWarning
double gRusRoMuonIron
std::vector< const G4Region * > trackerRegions
#define LogDebug(id)
std::vector< const G4Region * > caloRegions
double limitEnergyForVacuum
const G4Region * regionWorld