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 
178  // primary
179  if (aTrack->GetCreatorProcess() == nullptr || aTrack->GetParentID() == 0) {
180  if (!trackNeutrino && (abspdg == 12 || abspdg == 14 || abspdg == 16 || abspdg == 18)) {
181  classification = fKill;
182  } else if (worldSolid->Inside(aTrack->GetPosition()) == kOutside) {
183  classification = fKill;
184  } else {
185  newTA->primary(aTrack);
186  }
187  } else {
188  // secondary
189  const G4Region* reg = aTrack->GetVolume()->GetLogicalVolume()->GetRegion();
190  const double time = aTrack->GetGlobalTime();
191 
192  // definetly killed tracks
193  if (aTrack->GetTrackStatus() == fStopAndKill) {
194  classification = fKill;
195  } else if (!trackNeutrino && (abspdg == 12 || abspdg == 14 || abspdg == 16 || abspdg == 18)) {
196  classification = fKill;
197 
198  } else if (std::abs(aTrack->GetPosition().z()) >= maxZCentralCMS) {
199  // very forward secondary
200  if (time > maxTrackTimeForward) {
201  classification = fKill;
202  } else {
203  const G4Track* mother = trackAction->geant4Track();
204  newTA->secondary(aTrack, *mother, 0);
205  }
206 
207  } else if (isItOutOfTimeWindow(reg, time)) {
208  // time window check
209  classification = fKill;
210 
211  } else {
212  // potentially good for tracking
213  const double ke = aTrack->GetKineticEnergy();
214  auto proc = aTrack->GetCreatorProcess();
215  G4int subType = proc->GetProcessSubType();
216  if (subType == 16) {
217  auto ptr = static_cast<const G4GammaGeneralProcess*>(proc);
218  proc = ptr->GetSelectedProcess();
219  subType = proc->GetProcessSubType();
220  const_cast<G4Track*>(aTrack)->SetCreatorProcess(proc);
221  }
222  LogDebug("SimG4CoreApplication") << "##StackingAction:Classify Track " << aTrack->GetTrackID() << " Parent "
223  << aTrack->GetParentID() << " " << aTrack->GetDefinition()->GetParticleName()
224  << " Ekin(MeV)=" << ke / CLHEP::MeV << " subType=" << subType << " "
225  << proc->GetProcessName();
226 
227  // kill tracks in specific regions
228  if (isThisRegion(reg, deadRegions)) {
229  classification = fKill;
230  }
231  if (classification != fKill && ke <= limitEnergyForVacuum && isThisRegion(reg, lowdensRegions)) {
232  classification = fKill;
233 
234  } else if (classification != fKill) {
235  // very low-energy gamma
236  if (pdg == 22 && killGamma && ke < kmaxGamma) {
237  classification = fKill;
238  }
239 
240  // specific track killing - not for production
241  if (killExtra && classification != fKill) {
242  if (killHeavy && classification != fKill) {
243  if (((pdg / 1000000000 == 1) && (((pdg / 10000) % 100) > 0) && (((pdg / 10) % 100) > 0) &&
244  (ke < kmaxIon)) ||
245  ((pdg == 2212) && (ke < kmaxProton)) || ((pdg == 2112) && (ke < kmaxNeutron))) {
246  classification = fKill;
247  }
248  }
249 
250  if (killDeltaRay && classification != fKill &&
251  aTrack->GetCreatorProcess()->GetProcessSubType() == fIonisation) {
252  classification = fKill;
253  }
254  if (killInCalo && classification != fKill && isThisRegion(reg, caloRegions)) {
255  classification = fKill;
256  }
257  if (killInCaloEfH && classification != fKill) {
258  int pdgMother = std::abs(trackAction->geant4Track()->GetDefinition()->GetPDGEncoding());
259  if ((pdg == 22 || abspdg == 11) && pdgMother != 11 && pdgMother != 22 && isThisRegion(reg, caloRegions)) {
260  classification = fKill;
261  }
262  }
263  }
264 
265  // Russian roulette && MC truth
266  if (classification != fKill) {
267  const G4Track* mother = trackAction->geant4Track();
268  int flag = 0;
269  if (savePDandCinAll) {
270  flag = isItPrimaryDecayProductOrConversion(aTrack, *mother);
271  } else {
275  flag = isItPrimaryDecayProductOrConversion(aTrack, *mother);
276  }
277  }
278  if (saveFirstSecondary && 0 == flag) {
279  flag = isItFromPrimary(*mother, flag);
280  }
281 
282  // Russian roulette
283  if (2112 == pdg || 22 == pdg) {
284  double currentWeight = aTrack->GetWeight();
285 
286  if (1.0 >= currentWeight) {
287  double prob = 1.0;
288  double elim = 0.0;
289 
290  // neutron
291  if (nRRactive && pdg == 2112) {
292  elim = nRusRoEnerLim;
293  if (reg == regionEcal) {
294  prob = nRusRoEcal;
295  } else if (reg == regionHcal) {
296  prob = nRusRoHcal;
297  } else if (reg == regionMuonIron) {
299  } else if (reg == regionPreShower) {
301  } else if (reg == regionCastor) {
302  prob = nRusRoCastor;
303  } else if (reg == regionWorld) {
304  prob = nRusRoWorld;
305  }
306 
307  // gamma
308  } else if (gRRactive && pdg == 22) {
309  elim = gRusRoEnerLim;
310  if (reg == regionEcal || reg == regionPreShower) {
311  if (rrApplicable(aTrack, *mother)) {
312  if (reg == regionEcal) {
313  prob = gRusRoEcal;
314  } else {
316  }
317  }
318  } else {
319  if (reg == regionHcal) {
320  prob = gRusRoHcal;
321  } else if (reg == regionMuonIron) {
323  } else if (reg == regionCastor) {
324  prob = gRusRoCastor;
325  } else if (reg == regionWorld) {
326  prob = gRusRoWorld;
327  }
328  }
329  }
330  if (prob < 1.0 && aTrack->GetKineticEnergy() < elim) {
331  if (G4UniformRand() < prob) {
332  const_cast<G4Track*>(aTrack)->SetWeight(currentWeight / prob);
333  } else {
334  classification = fKill;
335  }
336  }
337  }
338  }
339  if (classification != fKill) {
340  newTA->secondary(aTrack, *mother, flag);
341  }
342  LogDebug("SimG4CoreApplication")
343  << "StackingAction:Classify Track " << aTrack->GetTrackID() << " Parent " << aTrack->GetParentID()
344  << " Type " << aTrack->GetDefinition()->GetParticleName() << " Ekin=" << ke / CLHEP::MeV
345  << " MeV from process " << proc->GetProcessName() << " subType=" << subType << " as " << classification
346  << " Flag: " << flag;
347  }
348  }
349  }
350  }
351  if (nullptr != steppingVerbose) {
352  steppingVerbose->StackFilled(aTrack, (classification == fKill));
353  }
354  return classification;
355 }
356 
358 
360 
362  // prepare region vector
363  const unsigned int num = maxTimeNames.size();
364  maxTimeRegions.resize(num, nullptr);
365 
366  // Russian roulette
367  const std::vector<G4Region*>* rs = G4RegionStore::GetInstance();
368 
369  for (auto& reg : *rs) {
370  const G4String& rname = reg->GetName();
371  if ((gRusRoEcal < 1.0 || nRusRoEcal < 1.0) && rname == "EcalRegion") {
372  regionEcal = reg;
373  }
374  if ((gRusRoHcal < 1.0 || nRusRoHcal < 1.0) && rname == "HcalRegion") {
375  regionHcal = reg;
376  }
377  if ((gRusRoMuonIron < 1.0 || nRusRoMuonIron < 1.0) && rname == "MuonIron") {
378  regionMuonIron = reg;
379  }
380  if ((gRusRoPreShower < 1.0 || nRusRoPreShower < 1.0) && rname == "PreshowerRegion") {
381  regionPreShower = reg;
382  }
383  if ((gRusRoCastor < 1.0 || nRusRoCastor < 1.0) && rname == "CastorRegion") {
384  regionCastor = reg;
385  }
386  if ((gRusRoWorld < 1.0 || nRusRoWorld < 1.0) && rname == "DefaultRegionForTheWorld") {
387  regionWorld = reg;
388  }
389 
390  // time limits
391  for (unsigned int i = 0; i < num; ++i) {
392  if (rname == (G4String)(maxTimeNames[i])) {
393  maxTimeRegions[i] = reg;
394  break;
395  }
396  }
397  //
398  if (savePDandCinTracker &&
399  (rname == "BeamPipe" || rname == "BeamPipeVacuum" || rname == "TrackerPixelSensRegion" ||
400  rname == "TrackerPixelDeadRegion" || rname == "TrackerDeadRegion" || rname == "TrackerSensRegion" ||
401  rname == "FastTimerRegion" || rname == "FastTimerRegionSensBTL" || rname == "FastTimerRegionSensETL")) {
402  trackerRegions.push_back(reg);
403  }
404  if (savePDandCinCalo && (rname == "HcalRegion" || rname == "EcalRegion" || rname == "PreshowerSensRegion" ||
405  rname == "PreshowerRegion" || rname == "APDRegion" || rname == "HGCalRegion")) {
406  caloRegions.push_back(reg);
407  }
408  if (savePDandCinMuon && (rname == "MuonChamber" || rname == "MuonSensitive_RPC" || rname == "MuonIron" ||
409  rname == "Muon" || rname == "MuonSensitive_DT-CSC")) {
410  muonRegions.push_back(reg);
411  }
412  if (rname == "BeamPipeOutside" || rname == "BeamPipeVacuum") {
413  lowdensRegions.push_back(reg);
414  }
415  for (auto& dead : deadRegionNames) {
416  if (rname == (G4String)(dead)) {
417  deadRegions.push_back(reg);
418  }
419  }
420  }
421 }
422 
423 bool StackingAction::isThisRegion(const G4Region* reg, std::vector<const G4Region*>& regions) const {
424  bool flag = false;
425  for (auto& region : regions) {
426  if (reg == region) {
427  flag = true;
428  break;
429  }
430  }
431  return flag;
432 }
433 
434 int StackingAction::isItPrimaryDecayProductOrConversion(const G4Track* aTrack, const G4Track& mother) const {
435  int flag = 0;
436  const TrackInformation& motherInfo(extractor(mother));
437  // Check whether mother is a primary
438  if (motherInfo.isPrimary()) {
439  if (aTrack->GetCreatorProcess()->GetProcessType() == fDecay) {
440  flag = 1;
441  } else if (aTrack->GetCreatorProcess()->GetProcessSubType() == fGammaConversion) {
442  flag = 2;
443  }
444  }
445  return flag;
446 }
447 
448 bool StackingAction::rrApplicable(const G4Track* aTrack, const G4Track& mother) const {
449  const TrackInformation& motherInfo(extractor(mother));
450 
451  // Check whether mother is gamma, e+, e-
452  const int genID = motherInfo.genParticlePID();
453  return (22 != genID && 11 != std::abs(genID));
454 }
455 
456 int StackingAction::isItFromPrimary(const G4Track& mother, int flagIn) const {
457  int flag = flagIn;
458  if (flag != 1) {
459  const TrackInformation& motherInfo(extractor(mother));
460  if (motherInfo.isPrimary()) {
461  flag = 3;
462  }
463  }
464  return flag;
465 }
466 
467 bool StackingAction::isItOutOfTimeWindow(const G4Region* reg, const double& t) const {
468  double tofM = maxTrackTime;
469  for (unsigned int i = 0; i < numberTimes; ++i) {
470  if (reg == maxTimeRegions[i]) {
471  tofM = maxTrackTimes[i];
472  break;
473  }
474  }
475  return (t > tofM);
476 }
477 
478 void StackingAction::printRegions(const std::vector<const G4Region*>& reg, const std::string& word) const {
479  for (unsigned int i = 0; i < reg.size(); ++i) {
480  edm::LogVerbatim("SimG4CoreApplication")
481  << " StackingAction: " << word << "Region " << i << ". " << reg[i]->GetName();
482  }
483 }
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