CMS 3D CMS Logo

CaloSD.cc
Go to the documentation of this file.
1 // File: CaloSD.cc
3 // Description: Sensitive Detector class for calorimeters
5 
13 
14 #include "G4EventManager.hh"
15 #include "G4LogicalVolumeStore.hh"
16 #include "G4LogicalVolume.hh"
17 #include "G4SDManager.hh"
18 #include "G4Step.hh"
19 #include "G4Track.hh"
20 #include "G4VProcess.hh"
21 #include "G4GFlashSpot.hh"
22 #include "G4ParticleTable.hh"
23 #include "G4SystemOfUnits.hh"
24 #include "G4PhysicalConstants.hh"
25 #include "DD4hep/Filter.h"
26 
27 #include <fstream>
28 #include <memory>
29 #include <sstream>
30 
31 //#define EDM_ML_DEBUG
32 
34  const SensitiveDetectorCatalog& clg,
35  edm::ParameterSet const& p,
36  const SimTrackManager* manager,
37  float timeSliceUnit,
38  bool ignoreTkID,
39  const std::string& newcollName)
40  : SensitiveCaloDetector(name, clg, newcollName),
41  G4VGFlashSensitiveDetector(),
42  eminHit(0.),
43  m_trackManager(manager),
44  ignoreTrackID(ignoreTkID),
45  timeSlice(timeSliceUnit),
46  eminHitD(0.) {
47  //Parameters
48  nHC_ = (newcollName.empty()) ? 1 : 2;
49  for (int k = 0; k < 2; ++k) {
50  currentHit[k] = nullptr;
51  theHC[k] = nullptr;
52  hcID[k] = -1;
53  }
54  bool dd4hep = p.getParameter<bool>("g4GeometryDD4hepSource");
55  int addlevel = dd4hep ? 1 : 0;
56  edm::ParameterSet m_CaloSD = p.getParameter<edm::ParameterSet>("CaloSD");
57  energyCut = m_CaloSD.getParameter<double>("EminTrack") * CLHEP::GeV;
58  tmaxHit = m_CaloSD.getParameter<double>("TmaxHit") * CLHEP::ns;
59  std::vector<double> eminHits = m_CaloSD.getParameter<std::vector<double>>("EminHits");
60  std::vector<double> tmaxHits = m_CaloSD.getParameter<std::vector<double>>("TmaxHits");
61  hcn_ = m_CaloSD.getParameter<std::vector<std::string>>("HCNames");
62  useResMap_ = m_CaloSD.getParameter<std::vector<int>>("UseResponseTables");
63  std::vector<double> eminHitX = m_CaloSD.getParameter<std::vector<double>>("EminHitsDepth");
64  suppressHeavy = m_CaloSD.getParameter<bool>("SuppressHeavy");
65  kmaxIon = m_CaloSD.getParameter<double>("IonThreshold") * CLHEP::MeV;
66  kmaxProton = m_CaloSD.getParameter<double>("ProtonThreshold") * CLHEP::MeV;
67  kmaxNeutron = m_CaloSD.getParameter<double>("NeutronThreshold") * CLHEP::MeV;
68  nCheckedHits[0] = m_CaloSD.getUntrackedParameter<int>("CheckHits", 25);
69  nCheckedHits[1] = nCheckedHits[0];
70  useMap = m_CaloSD.getUntrackedParameter<bool>("UseMap", true);
71  int verbn = m_CaloSD.getUntrackedParameter<int>("Verbosity", 0);
72  corrTOFBeam = m_CaloSD.getParameter<bool>("CorrectTOFBeam");
73  double beamZ = m_CaloSD.getParameter<double>("BeamPosition") * CLHEP::cm;
74  correctT = beamZ / CLHEP::c_light / CLHEP::nanosecond;
75  doFineCalo_ = m_CaloSD.getParameter<bool>("DoFineCalo");
76  eMinFine_ = m_CaloSD.getParameter<double>("EminFineTrack") * CLHEP::MeV;
77  std::vector<std::string> fineNames = m_CaloSD.getParameter<std::vector<std::string>>("FineCaloNames");
78  std::vector<int> fineLevels = m_CaloSD.getParameter<std::vector<int>>("FineCaloLevels");
79  std::vector<int> useFines = m_CaloSD.getParameter<std::vector<int>>("UseFineCalo");
80  for (auto& level : fineLevels)
81  level += addlevel;
82 
83  SetVerboseLevel(verbn);
84  for (int k = 0; k < 2; ++k)
85  meanResponse[k].reset(nullptr);
86  for (unsigned int k = 0; k < hcn_.size(); ++k) {
87  if (name == hcn_[k]) {
88  if (k < eminHits.size())
89  eminHit = eminHits[k] * CLHEP::MeV;
90  if (k < eminHitX.size())
91  eminHitD = eminHitX[k] * CLHEP::MeV;
92  if (k < tmaxHits.size())
93  tmaxHit = tmaxHits[k] * CLHEP::ns;
94  if (k < useResMap_.size() && useResMap_[k] > 0) {
95  meanResponse[0] = std::make_unique<CaloMeanResponse>(p);
96  break;
97  }
98  }
99  }
100  detName_ = name;
101  collName_[0] = name;
102  collName_[1] = newcollName;
103  slave[0] = std::make_unique<CaloSlaveSD>(name);
104  slave[1].reset(nullptr);
105 
106  for (int k = 0; k < 2; ++k) {
109  }
110  isParameterized = false;
111 
112  entrancePoint.set(0., 0., 0.);
113  entranceLocal.set(0., 0., 0.);
114  posGlobal.set(0., 0., 0.);
116 
117  primAncestor = 0;
118  forceSave = false;
119  for (int k = 0; k < 2; ++k) {
120  cleanIndex[k] = primIDSaved[k] = totalHits[k] = 0;
121  }
122 
123  edm::LogVerbatim("CaloSim") << "CaloSD: Minimum energy of track for saving it " << energyCut / CLHEP::GeV
124  << " GeV\n Use of HitID Map " << useMap << "\n Check last "
125  << nCheckedHits[0] << " before saving the hit\n Correct TOF globally by "
126  << correctT << " ns (Flag =" << corrTOFBeam << ")\n Save hits recorded before "
127  << tmaxHit << " ns and if energy is above " << eminHit / CLHEP::MeV
128  << " MeV (for depth 0) or " << eminHitD / CLHEP::MeV
129  << " MeV (for nonzero depths);\n Time Slice Unit " << timeSlice
130  << "\nIgnore TrackID Flag " << ignoreTrackID << " doFineCalo flag " << doFineCalo_
131  << "\nBeam Position " << beamZ / CLHEP::cm << " cm";
132  if (doFineCalo_)
133  edm::LogVerbatim("DoFineCalo") << "Using finecalo v2";
134 
135  // Treat fine calorimeters
136  edm::LogVerbatim("CaloSim") << "CaloSD: Have a possibility of " << fineNames.size() << " fine calorimeters of which "
137  << useFines.size() << " are selected";
138  for (unsigned int k = 0; k < fineNames.size(); ++k)
139  edm::LogVerbatim("CaloSim") << "[" << k << "] " << fineNames[k] << " at " << fineLevels[k];
140  std::ostringstream st1;
141  for (unsigned int k = 0; k < useFines.size(); ++k)
142  st1 << " [" << k << "] " << useFines[k] << ":" << fineNames[useFines[k]];
143  edm::LogVerbatim("CaloSim") << "CaloSD used calorimeters" << st1.str();
144  const G4LogicalVolumeStore* lvs = G4LogicalVolumeStore::GetInstance();
145  std::vector<G4LogicalVolume*>::const_iterator lvcite;
146  for (unsigned int i = 0; i < useFines.size(); i++) {
147  G4LogicalVolume* lv = nullptr;
148  G4String name = static_cast<G4String>(fineNames[useFines[i]]);
149  for (lvcite = lvs->begin(); lvcite != lvs->end(); lvcite++) {
150  G4String namx(static_cast<std::string>(dd4hep::dd::noNamespace((*lvcite)->GetName())));
151  if (namx == name) {
152  lv = (*lvcite);
153  break;
154  }
155  }
156  if (lv != nullptr) {
158  detector.name = name;
159  detector.lv = lv;
160  detector.level = fineLevels[useFines[i]];
161  fineDetectors_.emplace_back(detector);
162  }
163  }
164 #ifdef EDM_ML_DEBUG
165  edm::LogVerbatim("CaloSim") << "CaloSD::Loads information for " << fineDetectors_.size() << " fine detectors";
166  unsigned int k(0);
167  for (const auto& detector : fineDetectors_) {
168  edm::LogVerbatim("CaloSim") << "Detector[" << k << "] " << detector.name << " at level " << detector.level
169  << " pointer to LV: " << detector.lv;
170  }
171 #endif
172 }
173 
175 
177  for (unsigned int k = 0; k < hcn_.size(); ++k) {
178  if (name == hcn_[k]) {
179  if (k < useResMap_.size() && useResMap_[k] > 0) {
180  meanResponse[1] = std::make_unique<CaloMeanResponse>(p);
181  break;
182  }
183  }
184  }
185  slave[1] = std::make_unique<CaloSlaveSD>(name);
186 #ifdef EDM_ML_DEBUG
187  edm::LogVerbatim("CaloSim") << "CaloSD:: Initialise a second collection for " << name;
188  for (int k = 0; k < nHC_; ++k)
189  edm::LogVerbatim("CaloSim") << "Detector[" << k << "]" << detName_ << " collection " << collName_[k];
190 
191 #endif
192 }
193 
194 G4bool CaloSD::ProcessHits(G4Step* aStep, G4TouchableHistory*) {
195  NaNTrap(aStep);
196  ignoreReject = false;
197 
198 #ifdef EDM_ML_DEBUG
199  edm::LogVerbatim("CaloSim") << "CaloSD::" << GetName() << " ID= " << aStep->GetTrack()->GetTrackID()
200  << " prID= " << aStep->GetTrack()->GetParentID()
201  << " Eprestep= " << aStep->GetPreStepPoint()->GetKineticEnergy()
202  << " step= " << aStep->GetStepLength() << " Edep= " << aStep->GetTotalEnergyDeposit();
203 #endif
204 
205  // Class variable to determine whether finecalo rules should apply for this step
206  doFineCaloThisStep_ = (doFineCalo_ && isItFineCalo(aStep->GetPreStepPoint()->GetTouchable()));
207 
208  // apply shower library or parameterisation
209  // independent on energy deposition at a step
210  if (isParameterized) {
211  if (getFromLibrary(aStep)) {
212  // for parameterized showers the primary track should be killed
213  // secondary tracks should be killed if they are in the same volume
214  (aStep->GetTrack())->SetTrackStatus(fStopAndKill);
215  if (0 < aStep->GetNumberOfSecondariesInCurrentStep()) {
216  auto tv = aStep->GetSecondaryInCurrentStep();
217  auto vol = aStep->GetPreStepPoint()->GetPhysicalVolume();
218  for (auto& tk : *tv) {
219  if (tk->GetVolume() == vol) {
220  const_cast<G4Track*>(tk)->SetTrackStatus(fStopAndKill);
221  }
222  }
223  }
224  return true;
225  }
226  }
227 
228  // ignore steps without energy deposit
229  edepositEM = edepositHAD = 0.f;
230  if (aStep->GetTotalEnergyDeposit() <= 0.0) {
231  return false;
232  }
233 
234  // check unitID
235  unsigned int unitID = setDetUnitId(aStep);
236  auto const theTrack = aStep->GetTrack();
237  uint16_t depth = getDepth(aStep);
238 
239  double time = theTrack->GetGlobalTime() / nanosecond;
240  int primaryID = getTrackID(theTrack);
241  if (unitID > 0) {
242  currentID[0].setID(unitID, time, primaryID, depth);
243  } else {
244  if (!ignoreReject) {
245  const G4TouchableHistory* touch = static_cast<const G4TouchableHistory*>(theTrack->GetTouchable());
246  edm::LogVerbatim("CaloSim") << "CaloSD::ProcessHits: unitID= " << unitID
247  << " currUnit= " << currentID[0].unitID() << " Detector: " << GetName()
248  << " trackID= " << theTrack->GetTrackID() << " "
249  << theTrack->GetDefinition()->GetParticleName()
250  << "\n Edep= " << aStep->GetTotalEnergyDeposit()
251  << " PV: " << touch->GetVolume(0)->GetName()
252  << " PVid= " << touch->GetReplicaNumber(0) << " MVid= " << touch->GetReplicaNumber(1);
253  }
254  return false;
255  }
256  double energy = getEnergyDeposit(aStep);
257  if (energy <= 0.0) {
258  return false;
259  }
260 
261  if (doFineCaloThisStep_) {
262  currentID[0].setID(unitID, time, findBoundaryCrossingParent(theTrack), depth);
264  }
265 
267  edepositEM = energy;
268  } else {
270  }
271 #ifdef EDM_ML_DEBUG
272  const G4TouchableHistory* touch = static_cast<const G4TouchableHistory*>(theTrack->GetTouchable());
273  edm::LogVerbatim("CaloSim") << "CaloSD::" << GetName() << " PV:" << touch->GetVolume(0)->GetName()
274  << " PVid=" << touch->GetReplicaNumber(0) << " MVid=" << touch->GetReplicaNumber(1)
275  << " Unit:" << std::hex << unitID << std::dec << " Edep=" << edepositEM << " "
276  << edepositHAD << " ID=" << theTrack->GetTrackID() << " pID=" << theTrack->GetParentID()
277  << " E=" << theTrack->GetKineticEnergy() << " S=" << aStep->GetStepLength() << "\n "
278  << theTrack->GetDefinition()->GetParticleName() << " primaryID= " << primaryID
279  << " currentID= (" << currentID[0] << ") previousID= (" << previousID[0] << ")";
280 #endif
281  if (!hitExists(aStep, 0)) {
282  currentHit[0] = createNewHit(aStep, theTrack, 0);
283  } else {
284 #ifdef EDM_ML_DEBUG
285  edm::LogVerbatim("DoFineCalo") << "Not creating new hit, only updating " << shortreprID(currentHit[0]);
286 #endif
287  }
288 
289  processSecondHit(aStep, theTrack);
290 
291  return true;
292 }
293 
294 bool CaloSD::ProcessHits(G4GFlashSpot* aSpot, G4TouchableHistory*) {
295  edepositEM = edepositHAD = 0.f;
296  const G4Track* track = aSpot->GetOriginatorTrack()->GetPrimaryTrack();
297 
298  double edep = aSpot->GetEnergySpot()->GetEnergy();
299  if (edep <= 0.0) {
300  return false;
301  }
302 
303  G4Step fFakeStep;
304  G4StepPoint* fFakePreStepPoint = fFakeStep.GetPreStepPoint();
305  G4StepPoint* fFakePostStepPoint = fFakeStep.GetPostStepPoint();
306  fFakePreStepPoint->SetPosition(aSpot->GetPosition());
307  fFakePostStepPoint->SetPosition(aSpot->GetPosition());
308 
309  G4TouchableHandle fTouchableHandle = aSpot->GetTouchableHandle();
310  fFakePreStepPoint->SetTouchableHandle(fTouchableHandle);
311  fFakeStep.SetTotalEnergyDeposit(edep);
312  edep = EnergyCorrected(fFakeStep, track);
313 
314  // zero edep means hit outside the calorimeter
315  if (edep <= 0.0) {
316  return false;
317  }
318 
320  edepositEM = edep;
321  } else {
322  edepositHAD = edep;
323  }
324 
325  unsigned int unitID = setDetUnitId(&fFakeStep);
326 
327  if (unitID > 0) {
328  // time of initial track
329  double time = track->GetGlobalTime() / nanosecond;
330  int primaryID = getTrackID(track);
331  uint16_t depth = getDepth(&fFakeStep);
332  currentID[0].setID(unitID, time, primaryID, depth);
333 #ifdef EDM_ML_DEBUG
334  edm::LogVerbatim("CaloSim") << "CaloSD:: GetSpotInfo for Unit 0x" << std::hex << currentID[0].unitID() << std::dec
335  << " Edeposit = " << edepositEM << " " << edepositHAD;
336 #endif
337  // Update if in the same detector, time-slice and for same track
338  if (currentID[0] == previousID[0]) {
339  updateHit(currentHit[0], 0);
340  } else {
341  posGlobal = aSpot->GetEnergySpot()->GetPosition();
342  // Reset entry point for new primary
343  if (currentID[0].trackID() != previousID[0].trackID()) {
344  entrancePoint = aSpot->GetPosition();
345  entranceLocal = aSpot->GetTouchableHandle()->GetHistory()->GetTopTransform().TransformPoint(entrancePoint);
346  incidentEnergy = track->GetKineticEnergy();
347 #ifdef EDM_ML_DEBUG
348  edm::LogVerbatim("CaloSim") << "CaloSD: Incident energy " << incidentEnergy / CLHEP::GeV << " GeV and"
349  << " entrance point " << entrancePoint << " (Global) " << entranceLocal
350  << " (Local)";
351 #endif
352  }
353  if (!checkHit()) {
354  currentHit[0] = createNewHit(&fFakeStep, track, 0);
355  }
356  }
357  return true;
358  }
359  return false;
360 }
361 
362 double CaloSD::getEnergyDeposit(const G4Step* aStep) { return aStep->GetTotalEnergyDeposit(); }
363 
364 double CaloSD::EnergyCorrected(const G4Step& aStep, const G4Track*) { return aStep.GetTotalEnergyDeposit(); }
365 
366 bool CaloSD::getFromLibrary(const G4Step*) { return false; }
367 
368 bool CaloSD::isItFineCalo(const G4VTouchable* touch) {
369  bool ok(false);
370  int level = ((touch->GetHistoryDepth()) + 1);
371  for (const auto& detector : fineDetectors_) {
372  if (level > 0 && level >= detector.level) {
373  int ii = level - detector.level;
374  G4LogicalVolume* lv = touch->GetVolume(ii)->GetLogicalVolume();
375  ok = (lv == detector.lv);
376 #ifdef EDM_ML_DEBUG
377  std::string name1 = (lv == nullptr) ? "Unknown" : lv->GetName();
378  edm::LogVerbatim("CaloSim") << "CaloSD: volume " << name1 << ":" << detector.name << " at Level "
379  << detector.level << " Flag " << ok;
380 #endif
381  if (ok)
382  break;
383  }
384  }
385  return ok;
386 }
387 
388 void CaloSD::Initialize(G4HCofThisEvent* HCE) {
389 #ifdef EDM_ML_DEBUG
390  edm::LogVerbatim("CaloSim") << "CaloSD : Initialize called for " << detName_;
391 #endif
392 
393  for (int k = 0; k < nHC_; ++k) {
394  totalHits[k] = 0;
395 
396  //This initialization is performed at the beginning of an event
397  //------------------------------------------------------------
399 
400  if (hcID[k] < 0) {
401  hcID[k] = G4SDManager::GetSDMpointer()->GetCollectionID(collName_[k]);
402  }
403  //theHC ownership is transfered here to HCE
404  HCE->AddHitsCollection(hcID[k], theHC[k]);
405 #ifdef EDM_ML_DEBUG
406  edm::LogVerbatim("CaloSim") << "CaloSD : Add hits collection for " << hcID[k] << " for " << k << ":" << detName_
407  << ":" << collName_[k];
408 #endif
409  }
410 }
411 
412 void CaloSD::EndOfEvent(G4HCofThisEvent*) {
413  // clean the hits for the last tracks
414 
416 
417 #ifdef EDM_ML_DEBUG
418  for (int k = 0; k < nHC_; ++k) {
419  if (theHC[k] == nullptr)
420  edm::LogVerbatim("CaloSim") << "CaloSD: EndofEvent entered for container " << k << " with no entries";
421  else
422  edm::LogVerbatim("CaloSim") << "CaloSD: EndofEvent entered for container " << k << " with " << theHC[0]->entries()
423  << " entries";
424  }
425 #endif
426 }
427 
428 void CaloSD::clear() {}
429 
431 
433  for (int k = 0; k < nHC_; ++k) {
434 #ifdef EDM_ML_DEBUG
435  edm::LogVerbatim("CaloSim") << "CaloSD: Collection " << theHC[k]->GetName();
436 #endif
437  theHC[k]->PrintAllHits();
438  }
439 }
440 
442  for (int k = 0; k < nHC_; ++k) {
443 #ifdef EDM_ML_DEBUG
444  edm::LogVerbatim("CaloSim") << "CaloSD: Tries to transfer " << slave[k].get()->hits().size() << " hits for "
445  << slave[k].get()->name() << " " << hname;
446 #endif
447  if (slave[k].get()->name() == hname) {
448  cc = slave[k].get()->hits();
449  slave[k].get()->Clean();
450  }
451  }
452 }
453 
454 G4ThreeVector CaloSD::setToLocal(const G4ThreeVector& global, const G4VTouchable* touch) const {
455  return touch->GetHistory()->GetTopTransform().TransformPoint(global);
456 }
457 
458 G4ThreeVector CaloSD::setToGlobal(const G4ThreeVector& local, const G4VTouchable* touch) const {
459  return touch->GetHistory()->GetTopTransform().Inverse().TransformPoint(local);
460 }
461 
462 bool CaloSD::hitExists(const G4Step* aStep, int k) {
463 #ifdef EDM_ML_DEBUG
464  edm::LogVerbatim("CaloSim") << "CaloSD: hitExists for " << k;
465 #endif
466  // Update if in the same detector, time-slice and for same track
467  if (currentID[k] == previousID[k]) {
468  updateHit(currentHit[k], k);
469  return true;
470  }
471 
472  // Note T. Klijnsma:
473  // This is a rather strange place to set these class variables.
474  // The code would be much more readable if all logic for determining
475  // whether to update a hit or create a new hit is done in one place,
476  // and only then perform the actual updating or creating of the hit.
477 
478  // Reset entry point for new primary (only for the primary hit)
479  if (k == 0) {
480  posGlobal = aStep->GetPreStepPoint()->GetPosition();
481  if (currentID[k].trackID() != previousID[k].trackID()) {
482  resetForNewPrimary(aStep);
483  }
484  }
485  return checkHit(k);
486 }
487 
488 bool CaloSD::checkHit(int k) {
489 #ifdef EDM_ML_DEBUG
490  edm::LogVerbatim("CaloSim") << "CaloSD: checkHit for " << k;
491 #endif
492  //look in the HitContainer whether a hit with the same ID already exists:
493  bool found = false;
494  if (useMap) {
495  std::map<CaloHitID, CaloG4Hit*>::const_iterator it = hitMap[k].find(currentID[k]);
496  if (it != hitMap[k].end()) {
497  currentHit[k] = it->second;
498  found = true;
499  }
500  } else if (nCheckedHits[k] > 0) {
501  int nhits = theHC[k]->entries();
502  int minhit = std::max(nhits - nCheckedHits[k], 0);
503  int maxhit = nhits - 1;
504 
505  for (int j = maxhit; j > minhit; --j) {
506  if ((*theHC[k])[j]->getID() == currentID[k]) {
507  currentHit[k] = (*theHC[k])[j];
508  found = true;
509  break;
510  }
511  }
512  }
513 
514  if (found) {
515  updateHit(currentHit[k], k);
516  }
517  return found;
518 }
519 
520 int CaloSD::getNumberOfHits(int k) { return theHC[k]->entries(); }
521 
522 /*
523 Takes a vector of ints (representing trackIDs), and returns a formatted string
524 for debugging purposes
525 */
526 std::string CaloSD::printableDecayChain(const std::vector<unsigned int>& decayChain) {
527  std::stringstream ss;
528  for (long unsigned int i = 0; i < decayChain.size(); i++) {
529  if (i > 0)
530  ss << " <- ";
531  ss << decayChain[i];
532  }
533  return ss.str();
534 }
535 
536 /* Very short representation of a CaloHitID */
538  std::stringstream ss;
539  ss << GetName() << "/" << ID.unitID() << "/trk" << ID.trackID() << "/d" << ID.depth() << "/time" << ID.timeSliceID();
540  if (ID.isFinecaloTrackID())
541  ss << "/FC";
542  return ss.str();
543 }
544 
545 /* As above, but with a hit as input */
547 
548 /*
549 Finds the boundary-crossing parent of a track, and stores it in the CaloSD's map
550 */
551 unsigned int CaloSD::findBoundaryCrossingParent(const G4Track* track, bool markAsSaveable) {
553  unsigned int id = track->GetTrackID();
554  // First see if this track is already in the map
555  auto it = boundaryCrossingParentMap_.find(id);
556  if (it != boundaryCrossingParentMap_.end()) {
557 #ifdef EDM_ML_DEBUG
558  edm::LogVerbatim("DoFineCalo") << "Track " << id << " parent already cached: " << it->second;
559 #endif
560  return it->second;
561  }
562  // Then see if the track itself crosses the boundary
563  else if (trkInfo->crossedBoundary()) {
564 #ifdef EDM_ML_DEBUG
565  edm::LogVerbatim("DoFineCalo") << "Track " << id << " crosses boundary itself";
566 #endif
568  trkInfo->setStoreTrack();
569  return id;
570  }
571  // Else, traverse the history of the track
572  std::vector<unsigned int> decayChain{id};
573 #ifdef EDM_ML_DEBUG
574  edm::LogVerbatim("DoFineCalo") << "Track " << id << ": Traversing history to find boundary-crossing parent";
575 #endif
576  unsigned int parentID = track->GetParentID();
577  while (true) {
578  if (parentID == 0)
579  throw cms::Exception("Unknown", "CaloSD")
580  << "Hit end of parentage for track " << id << " without finding a boundary-crossing parent";
581  // First check if this ancestor is already in the map
582  auto it = boundaryCrossingParentMap_.find(parentID);
583  if (it != boundaryCrossingParentMap_.end()) {
584 #ifdef EDM_ML_DEBUG
585  edm::LogVerbatim("DoFineCalo") << " Track " << parentID
586  << " boundary-crossing parent already cached: " << it->second;
587 #endif
588  // Store this parent also for the rest of the traversed decay chain
589  for (auto ancestorID : decayChain)
590  boundaryCrossingParentMap_[ancestorID] = it->second;
591 #ifdef EDM_ML_DEBUG
592  // In debug mode, still build the rest of the decay chain for debugging
593  decayChain.push_back(parentID);
594  while (parentID != it->second) {
595  parentID = m_trackManager->getTrackByID(parentID, true)->parentID();
596  decayChain.push_back(parentID);
597  }
598  edm::LogVerbatim("DoFineCalo") << " Full decay chain: " << printableDecayChain(decayChain);
599 #endif
600  return it->second;
601  }
602  // If not, get this parent from the track manager (expensive)
604  if (parentTrack->crossedBoundary()) {
605  if (markAsSaveable)
606  parentTrack->setToBeSaved();
607  decayChain.push_back(parentID);
608  // Record this boundary crossing parent for all traversed ancestors
609  for (auto ancestorID : decayChain)
610  boundaryCrossingParentMap_[ancestorID] = parentID;
611 #ifdef EDM_ML_DEBUG
612  edm::LogVerbatim("DoFineCalo") << " Found boundary-crossing ancestor " << parentID << " for track " << id
613  << "; decay chain: " << printableDecayChain(decayChain);
614 #endif
615  return parentID;
616  }
617  // Next iteration
618  decayChain.push_back(parentID);
619  parentID = parentTrack->parentID();
620  }
621 }
622 
623 CaloG4Hit* CaloSD::createNewHit(const G4Step* aStep, const G4Track* theTrack, int k) {
624 #ifdef EDM_ML_DEBUG
625  edm::LogVerbatim("CaloSim") << "CaloSD::CreateNewHit " << getNumberOfHits() << " for " << GetName()
626  << " Unit:" << currentID[k].unitID() << " " << currentID[k].depth()
627  << " Edep= " << edepositEM << " " << edepositHAD
628  << " primaryID= " << currentID[k].trackID()
629  << " timeSlice= " << currentID[k].timeSliceID() << " ID= " << theTrack->GetTrackID()
630  << " " << theTrack->GetDefinition()->GetParticleName()
631  << " E(GeV)= " << theTrack->GetKineticEnergy() / CLHEP::GeV
632  << " parentID= " << theTrack->GetParentID() << "\n Ein= " << incidentEnergy
633  << " entranceGlobal: " << entrancePoint << " entranceLocal: " << entranceLocal
634  << " posGlobal: " << posGlobal;
635 #endif
636 
637  CaloG4Hit* aHit;
638  if (!reusehit[k].empty()) {
639  aHit = reusehit[k].back().release();
640  aHit->setEM(0.f);
641  aHit->setHadr(0.f);
642  reusehit[k].pop_back();
643  } else {
644  aHit = new CaloG4Hit;
645  }
646 
647  aHit->setID(currentID[k]);
648  aHit->setEntry(entrancePoint.x(), entrancePoint.y(), entrancePoint.z());
650  aHit->setPosition(posGlobal.x(), posGlobal.y(), posGlobal.z());
652  updateHit(aHit, k);
653 
654  storeHit(aHit, k);
655  TrackInformation* trkInfo = cmsTrackInformation(theTrack);
656 
657 #ifdef EDM_ML_DEBUG
659  edm::LogVerbatim("DoFineCalo") << "New hit " << shortreprID(aHit) << " using finecalo;"
660  << " isItFineCalo(post)=" << isItFineCalo(aStep->GetPostStepPoint()->GetTouchable())
661  << " isItFineCalo(pre)=" << isItFineCalo(aStep->GetPreStepPoint()->GetTouchable());
662 #endif
663 
664  // 'Traditional', non-fine history bookkeeping
665  if (!doFineCaloThisStep_) {
666  double etrack = 0;
667  if (currentID[k].trackID() == primIDSaved[k]) { // The track is saved; nothing to be done
668  } else if (currentID[k].trackID() == theTrack->GetTrackID()) {
669  etrack = theTrack->GetKineticEnergy();
670 #ifdef EDM_ML_DEBUG
671  edm::LogVerbatim("CaloSim") << "CaloSD: set save the track " << currentID[k].trackID() << " etrack " << etrack
672  << " eCut " << energyCut << " force: " << forceSave
673  << " save: " << (etrack >= energyCut || forceSave);
674 #endif
675  if (etrack >= energyCut || forceSave) {
676  trkInfo->setStoreTrack();
677  }
678  } else {
680 #ifdef EDM_ML_DEBUG
681  edm::LogVerbatim("CaloSim") << "CaloSD : TrackWithHistory pointer for " << currentID[k].trackID() << " is "
682  << trkh;
683 #endif
684  if (trkh != nullptr) {
685  etrack = sqrt(trkh->momentum().Mag2());
686  if (etrack >= energyCut) {
687  trkh->setToBeSaved();
688 #ifdef EDM_ML_DEBUG
689  edm::LogVerbatim("CaloSim") << "CaloSD: set save the track " << currentID[k].trackID() << " with Hit";
690 #endif
691  }
692  }
693  }
695  }
696 
697  if (useMap)
698  ++totalHits[k];
699  return aHit;
700 }
701 
702 void CaloSD::updateHit(CaloG4Hit* aHit, int k) {
704 #ifdef EDM_ML_DEBUG
705  edm::LogVerbatim("CaloSim") << "CaloSD:" << GetName() << " Add energy deposit in " << currentID[k]
706  << " Edep_em(MeV)= " << edepositEM << " Edep_had(MeV)= " << edepositHAD;
707 #endif
708 
709  // buffer for next steps:
710  previousID[k] = currentID[k];
711 }
712 
713 void CaloSD::resetForNewPrimary(const G4Step* aStep) {
714  auto const preStepPoint = aStep->GetPreStepPoint();
715  entrancePoint = preStepPoint->GetPosition();
716  entranceLocal = setToLocal(entrancePoint, preStepPoint->GetTouchable());
717  incidentEnergy = preStepPoint->GetKineticEnergy();
718 #ifdef EDM_ML_DEBUG
719  edm::LogVerbatim("CaloSim") << "CaloSD::resetForNewPrimary for " << GetName()
720  << " ID= " << aStep->GetTrack()->GetTrackID() << " Ein= " << incidentEnergy / CLHEP::GeV
721  << " GeV and"
722  << " entrance point global: " << entrancePoint << " local: " << entranceLocal;
723 #endif
724 }
725 
726 double CaloSD::getAttenuation(const G4Step* aStep, double birk1, double birk2, double birk3) const {
727  double weight = 1.;
728  double charge = aStep->GetPreStepPoint()->GetCharge();
729  double length = aStep->GetStepLength();
730 
731  if (charge != 0. && length > 0.) {
732  double density = aStep->GetPreStepPoint()->GetMaterial()->GetDensity();
733  double dedx = aStep->GetTotalEnergyDeposit() / length;
734  double rkb = birk1 / density;
735  double c = birk2 * rkb * rkb;
736  if (std::abs(charge) >= 2.)
737  rkb /= birk3; // based on alpha particle data
738  weight = 1. / (1. + rkb * dedx + c * dedx * dedx);
739 #ifdef EDM_ML_DEBUG
740  edm::LogVerbatim("CaloSim") << "CaloSD::getAttenuation in " << aStep->GetPreStepPoint()->GetMaterial()->GetName()
741  << " Charge " << charge << " dE/dx " << dedx << " Birk Const " << rkb << ", " << c
742  << " Weight = " << weight << " dE " << aStep->GetTotalEnergyDeposit();
743 #endif
744  }
745  return weight;
746 }
747 
748 void CaloSD::update(const BeginOfRun*) { initRun(); }
749 
750 void CaloSD::update(const BeginOfEvent* g4Event) {
751 #ifdef EDM_ML_DEBUG
752  edm::LogVerbatim("CaloSim") << "CaloSD: Dispatched BeginOfEvent for " << GetName() << " !";
753 #endif
754  clearHits();
755  initEvent(g4Event);
756 }
757 
758 void CaloSD::update(const EndOfTrack* trk) {
759  int id = (*trk)()->GetTrackID();
760  TrackInformation* trkI = cmsTrackInformation((*trk)());
761  int lastTrackID = -1;
762  if (trkI)
763  lastTrackID = trkI->getIDonCaloSurface();
764  if (id == lastTrackID) {
765  auto trksForThisEvent = m_trackManager->trackContainer();
766  if (!trksForThisEvent->empty()) {
767  TrackWithHistory* trkH = trksForThisEvent->back();
768  if (trkH->trackID() == id) {
769  tkMap[id] = trkH;
770 #ifdef EDM_ML_DEBUG
771  edm::LogVerbatim("CaloSim") << "CaloSD: get track " << id << " from Container of size "
772  << trksForThisEvent->size() << " with ID " << trkH->trackID();
773 #endif
774  }
775  }
776  }
777 }
778 
779 void CaloSD::update(const ::EndOfEvent*) {
780  endEvent();
781  for (int k = 0; k < nHC_; ++k) {
782  slave[k].get()->ReserveMemory(theHC[k]->entries());
783 
784  int count(0);
785  double eEM(0.0);
786  double eHAD(0.0);
787  double eEM2(0.0);
788  double eHAD2(0.0);
789 #ifdef EDM_ML_DEBUG
790  int wrong(0);
791  double tt(0.0);
792  double zloc(0.0);
793  double zglob(0.0);
794  double ee(0.0);
795 #endif
796  int hc_entries = theHC[k]->entries();
797  for (int i = 0; i < hc_entries; ++i) {
798 #ifdef EDM_ML_DEBUG
799  if (!saveHit((*theHC[k])[i], k)) {
800  ++wrong;
801  }
802 #else
803  saveHit((*theHC[k])[i], k);
804 #endif
805 
806  ++count;
807  double x = (*theHC[k])[i]->getEM();
808  eEM += x;
809  eEM2 += x * x;
810  x = (*theHC[k])[i]->getHadr();
811  eHAD += x;
812  eHAD2 += x * x;
813 #ifdef EDM_ML_DEBUG
814  tt += (*theHC[k])[i]->getTimeSlice();
815  ee += (*theHC[k])[i]->getIncidentEnergy();
816  zglob += std::abs((*theHC[k])[i]->getEntry().z());
817  zloc += std::abs((*theHC[k])[i]->getEntryLocal().z());
818 #endif
819  }
820 
821  double norm = (count > 0) ? 1.0 / count : 0.0;
822  eEM *= norm;
823  eEM2 *= norm;
824  eHAD *= norm;
825  eHAD2 *= norm;
826  eEM2 = std::sqrt(eEM2 - eEM * eEM);
827  eHAD2 = std::sqrt(eHAD2 - eHAD * eHAD);
828 #ifdef EDM_ML_DEBUG
829  tt *= norm;
830  ee *= norm;
831  zglob *= norm;
832  zloc *= norm;
833  edm::LogVerbatim("CaloSim") << "CaloSD: " << GetName() << " store " << count << " hits; " << wrong
834  << " track IDs not given properly and " << totalHits - count
835  << " hits not passing cuts\n EmeanEM= " << eEM << " ErmsEM= " << eEM2
836  << "\n EmeanHAD= " << eHAD << " ErmsHAD= " << eHAD2 << " TimeMean= " << tt
837  << " E0mean= " << ee << " Zglob= " << zglob << " Zloc= " << zloc << " ";
838 #endif
839  std::vector<std::unique_ptr<CaloG4Hit>>().swap(reusehit[k]);
840  if (useMap)
841  hitMap[k].erase(hitMap[k].begin(), hitMap[k].end());
842  }
843  tkMap.erase(tkMap.begin(), tkMap.end());
845 }
846 
848  for (int k = 0; k < nHC_; ++k) {
849  previousID[k].reset();
850  primIDSaved[k] = -99;
851  cleanIndex[k] = 0;
852 #ifdef EDM_ML_DEBUG
853  edm::LogVerbatim("CaloSim") << "CaloSD: Clears hit vector for " << GetName()
854  << " and initialise slave: " << slave[k].get()->name();
855 #endif
856  slave[k].get()->Initialize();
857  }
858 }
859 
861  if (fpCaloG4HitAllocator) {
862  fpCaloG4HitAllocator->ResetStorage();
863  }
864 }
865 
867 
869 
871 
872 int CaloSD::getTrackID(const G4Track* aTrack) {
873  int primaryID = 0;
874  TrackInformation* trkInfo = cmsTrackInformation(aTrack);
875  if (trkInfo) {
876  primaryID = trkInfo->getIDonCaloSurface();
877 #ifdef EDM_ML_DEBUG
878  edm::LogVerbatim("CaloSim") << "Track ID: " << trkInfo->getIDonCaloSurface() << ":" << aTrack->GetTrackID() << ":"
879  << primaryID;
880 #endif
881  } else {
882  primaryID = aTrack->GetTrackID();
883 #ifdef EDM_ML_DEBUG
884  edm::LogWarning("CaloSim") << "CaloSD: Problem with primaryID **** set by force to TkID **** " << primaryID;
885 #endif
886  }
887  return primaryID;
888 }
889 
890 int CaloSD::setTrackID(const G4Step* aStep) {
891  auto const theTrack = aStep->GetTrack();
892  TrackInformation* trkInfo = cmsTrackInformation(theTrack);
893  int primaryID = trkInfo->getIDonCaloSurface();
894  if (primaryID <= 0) {
895  primaryID = theTrack->GetTrackID();
896  }
897 #ifdef EDM_ML_DEBUG
898  edm::LogVerbatim("CaloSim") << "Track ID: " << trkInfo->getIDonCaloSurface() << ":" << theTrack->GetTrackID() << ":"
899  << primaryID;
900 #endif
901 
902  if (primaryID != previousID[0].trackID()) {
903  resetForNewPrimary(aStep);
904  }
905 #ifdef EDM_ML_DEBUG
906  edm::LogVerbatim("CaloSim") << "CaloSD::setTrackID for " << GetName()
907  << " trackID= " << aStep->GetTrack()->GetTrackID() << " primaryID= " << primaryID;
908 #endif
909  return primaryID;
910 }
911 
912 uint16_t CaloSD::getDepth(const G4Step*) { return 0; }
913 
914 void CaloSD::processSecondHit(const G4Step*, const G4Track*) {}
915 
917  double emin(eminHit);
918  if (hit->getDepth() > 0)
919  emin = eminHitD;
920 #ifdef EDM_ML_DEBUG
921  edm::LogVerbatim("CaloSim") << "CaloSD::filterHit(..) Depth " << hit->getDepth() << " Emin = " << emin << " ("
922  << eminHit << ", " << eminHitD << ")";
923 #endif
924  return ((time <= tmaxHit) && (hit->getEnergyDeposit() > emin));
925 }
926 
927 double CaloSD::getResponseWt(const G4Track* aTrack, int k) {
928  double wt = 1.0;
929  if (meanResponse[k].get()) {
930  TrackInformation* trkInfo = cmsTrackInformation(aTrack);
931  wt = meanResponse[k].get()->getWeight(trkInfo->genParticlePID(), trkInfo->genParticleP());
932  }
933  return wt;
934 }
935 
937  if (hit == nullptr || previousID[k].trackID() < 0) {
938  edm::LogWarning("CaloSim") << "CaloSD: hit to be stored is nullptr !!"
939  << " previousID.trackID()= " << previousID[k].trackID();
940  return;
941  }
942 
943  theHC[k]->insert(hit);
944  if (useMap)
945  hitMap[k].insert(std::pair<CaloHitID, CaloG4Hit*>(previousID[k], hit));
946 }
947 
948 bool CaloSD::saveHit(CaloG4Hit* aHit, int k) {
949  int tkID;
950  bool ok = true;
951 
952  double time = aHit->getTimeSlice();
953  if (corrTOFBeam)
954  time += correctT;
955 
956  // More strict bookkeeping for finecalo
957  if (doFineCalo_ && aHit->isFinecaloTrackID()) {
958 #ifdef EDM_ML_DEBUG
959  edm::LogVerbatim("DoFineCalo") << "Saving hit " << shortreprID(aHit);
960 #endif
961  if (!m_trackManager)
962  throw cms::Exception("Unknown", "CaloSD") << "m_trackManager not set, needed for finecalo!";
963  if (!m_trackManager->trackExists(aHit->getTrackID()))
964  throw cms::Exception("Unknown", "CaloSD")
965  << "Error on hit " << shortreprID(aHit) << ": Parent track not in track manager";
966  slave[k].get()->processHits(aHit->getUnitID(),
967  aHit->getEM() / CLHEP::GeV,
968  aHit->getHadr() / CLHEP::GeV,
969  time,
970  aHit->getTrackID(),
971  aHit->getDepth());
972  }
973  // Regular, not-fine way:
974  else {
975  if (m_trackManager) {
976  tkID = m_trackManager->giveMotherNeeded(aHit->getTrackID());
977  if (tkID == 0) {
978  if (m_trackManager->trackExists(aHit->getTrackID()))
979  tkID = (aHit->getTrackID());
980  else {
981  ok = false;
982  }
983  }
984  } else {
985  tkID = aHit->getTrackID();
986  ok = false;
987  }
988 #ifdef EDM_ML_DEBUG
989  edm::LogVerbatim("DoFineCalo") << "Saving hit " << shortreprID(aHit) << " with trackID=" << tkID;
990 #endif
991 
992  slave[k].get()->processHits(
993  aHit->getUnitID(), aHit->getEM() / CLHEP::GeV, aHit->getHadr() / CLHEP::GeV, time, tkID, aHit->getDepth());
994  }
995 
996 #ifdef EDM_ML_DEBUG
997  if (!ok)
998  edm::LogWarning("CaloSim") << "CaloSD:Cannot find track ID for " << aHit->getTrackID();
999  edm::LogVerbatim("CaloSim") << "CalosD: Track ID " << aHit->getTrackID() << " changed to " << tkID
1000  << " by SimTrackManager Status " << ok;
1001 #endif
1002 
1003 #ifdef EDM_ML_DEBUG
1004  edm::LogVerbatim("CaloSim") << "CaloSD: Store Hit at " << std::hex << aHit->getUnitID() << std::dec << " "
1005  << aHit->getDepth() << " due to " << tkID << " in time " << time << " of energy "
1006  << aHit->getEM() / CLHEP::GeV << " GeV (EM) and " << aHit->getHadr() / CLHEP::GeV
1007  << " GeV (Hadr)";
1008 #endif
1009  return ok;
1010 }
1011 
1012 void CaloSD::update(const BeginOfTrack* trk) {
1013  int primary = -1;
1014  TrackInformation* trkInfo = cmsTrackInformation((*trk)());
1015  if (trkInfo->isPrimary())
1016  primary = (*trk)()->GetTrackID();
1017 
1018 #ifdef EDM_ML_DEBUG
1019  edm::LogVerbatim("CaloSim") << "New track: isPrimary " << trkInfo->isPrimary() << " primary ID = " << primary
1020  << " primary ancestor ID " << primAncestor;
1021 #endif
1022 
1023  // update the information if a different primary track ID
1024 
1025  if (primary > 0 && primary != primAncestor) {
1026  primAncestor = primary;
1027 
1028  // clean the hits information
1029 
1030  bool clean(false);
1031  for (int k = 0; k < nHC_; ++k)
1032  if (theHC[k]->entries() > 0)
1033  clean = true;
1034  if (clean)
1036  }
1037 }
1038 
1040  for (int k = 0; k < nHC_; ++k) {
1041  std::vector<CaloG4Hit*>* theCollection = theHC[k]->GetVector();
1042 
1043 #ifdef EDM_ML_DEBUG
1044  edm::LogVerbatim("CaloSim") << "CaloSD: collection before merging, size = " << theHC[k]->entries();
1045 #endif
1046  if (reusehit[k].empty())
1047  reusehit[k].reserve(theHC[k]->entries() - cleanIndex[k]);
1048 
1049  // if no map used, merge before hits to have the save situation as a map
1050  if (!useMap) {
1051  std::vector<CaloG4Hit*> hitvec;
1052 
1053  hitvec.swap(*theCollection);
1054  sort((hitvec.begin() + cleanIndex[k]), hitvec.end(), CaloG4HitLess());
1055 #ifdef EDM_ML_DEBUG
1056  edm::LogVerbatim("CaloSim") << "CaloSD::cleanHitCollection: sort hits in buffer starting from "
1057  << "element = " << cleanIndex[k];
1058  for (unsigned int i = 0; i < hitvec.size(); ++i) {
1059  if (hitvec[i] == nullptr)
1060  edm::LogVerbatim("CaloSim") << i << " has a null pointer";
1061  else
1062  edm::LogVerbatim("CaloSim") << i << " " << *hitvec[i];
1063  }
1064 #endif
1066  for (unsigned int i = cleanIndex[k]; i < hitvec.size(); ++i) {
1067  int jump = 0;
1068  for (unsigned int j = i + 1; j < hitvec.size() && equal(hitvec[i], hitvec[j]); ++j) {
1069  ++jump;
1070  // merge j to i
1071  (*hitvec[i]).addEnergyDeposit(*hitvec[j]);
1072  (*hitvec[j]).setEM(0.);
1073  (*hitvec[j]).setHadr(0.);
1074  reusehit[k].emplace_back(hitvec[j]);
1075  hitvec[j] = nullptr;
1076  }
1077  i += jump;
1078  }
1079 #ifdef EDM_ML_DEBUG
1080  edm::LogVerbatim("CaloSim") << "CaloSD: cleanHitCollection merge the hits in buffer ";
1081  for (unsigned int i = 0; i < hitvec.size(); ++i) {
1082  if (hitvec[i] == nullptr)
1083  edm::LogVerbatim("CaloSim") << i << " has a null pointer";
1084  else
1085  edm::LogVerbatim("CaloSim") << i << " " << *hitvec[i];
1086  }
1087 #endif
1088  //move all nullptr to end of list and then remove them
1089  hitvec.erase(std::stable_partition(
1090  hitvec.begin() + cleanIndex[k], hitvec.end(), [](CaloG4Hit* p) { return p != nullptr; }),
1091  hitvec.end());
1092 #ifdef EDM_ML_DEBUG
1093  edm::LogVerbatim("CaloSim") << "CaloSD::cleanHitCollection: remove the merged hits in buffer, new size = "
1094  << hitvec.size();
1095 #endif
1096  hitvec.swap(*theCollection);
1097  totalHits[k] = theHC[k]->entries();
1098  }
1099 
1100 #ifdef EDM_ML_DEBUG
1101  edm::LogVerbatim("CaloSim") << "CaloSD: collection after merging, size= " << theHC[k]->entries()
1102  << " Size of reusehit= " << reusehit[k].size()
1103  << "\n starting hit selection from index = " << cleanIndex[k];
1104 #endif
1105 
1106  int addhit = 0;
1107  for (unsigned int i = cleanIndex[k]; i < theCollection->size(); ++i) {
1108  CaloG4Hit* aHit((*theCollection)[i]);
1109 
1110  // selection
1111 
1112  double time = aHit->getTimeSlice();
1113  if (corrTOFBeam)
1114  time += correctT;
1115  if (!filterHit(aHit, time)) {
1116 #ifdef EDM_ML_DEBUG
1117  edm::LogVerbatim("CaloSim") << "CaloSD: dropped CaloG4Hit "
1118  << " " << *aHit;
1119 #endif
1120 
1121  // create the list of hits to be reused
1122 
1123  reusehit[k].emplace_back((*theCollection)[i]);
1124  (*theCollection)[i] = nullptr;
1125  ++addhit;
1126  }
1127  }
1128 
1129 #ifdef EDM_ML_DEBUG
1130  edm::LogVerbatim("CaloSim") << "CaloSD: Size of reusehit after selection = " << reusehit[k].size()
1131  << " Number of added hit = " << addhit;
1132 #endif
1133  if (useMap) {
1134  if (addhit > 0) {
1135  int offset = reusehit[k].size() - addhit;
1136  for (int ii = addhit - 1; ii >= 0; --ii) {
1137  CaloHitID theID = reusehit[k][offset + ii]->getID();
1138  hitMap[k].erase(theID);
1139  }
1140  }
1141  }
1142 
1143  //move all nullptr to end of list and then remove them
1144  theCollection->erase(
1145  std::stable_partition(
1146  theCollection->begin() + cleanIndex[k], theCollection->end(), [](CaloG4Hit* p) { return p != nullptr; }),
1147  theCollection->end());
1148 #ifdef EDM_ML_DEBUG
1149  edm::LogVerbatim("CaloSim") << "CaloSD: hit collection after selection, size = " << theHC[k]->entries();
1150  theHC[k]->PrintAllHits();
1151 #endif
1152 
1153  cleanIndex[k] = theHC[k]->entries();
1154  }
1155 }
1156 
1157 void CaloSD::printDetectorLevels(const G4VTouchable* touch) const {
1158  //Print name and copy numbers
1159  int level = ((touch->GetHistoryDepth()) + 1);
1160  std::ostringstream st1;
1161  st1 << level << " Levels:";
1162  if (level > 0) {
1163  for (int ii = 0; ii < level; ii++) {
1164  int i = level - ii - 1;
1165  G4VPhysicalVolume* pv = touch->GetVolume(i);
1166  std::string name = (pv != nullptr) ? pv->GetName() : "Unknown";
1167  st1 << " " << name << ":" << touch->GetReplicaNumber(i);
1168  }
1169  }
1170  edm::LogVerbatim("CaloSim") << st1.str();
1171 }
CaloG4Hit * currentHit[2]
Definition: CaloSD.h:152
float edepositEM
Definition: CaloSD.h:144
virtual void processSecondHit(const G4Step *, const G4Track *)
Definition: CaloSD.cc:914
int getNumberOfHits(int k=0)
Definition: CaloSD.cc:520
double genParticleP() const
Int_t getEntry(TBranch *branch, EntryNumber entryNumber)
Definition: RootTree.cc:527
double energyCut
Definition: CaloSD.h:148
Log< level::Info, true > LogVerbatim
int getTrackID() const
Definition: CaloG4Hit.h:64
bool isPrimary() const
bool ignoreReject
Definition: CaloSD.h:178
void setStoreTrack()
can only be set to true, cannot be reset to false!
bool crossedBoundary() const
T getParameter(std::string const &) const
Definition: ParameterSet.h:307
virtual bool getFromLibrary(const G4Step *step)
Definition: CaloSD.cc:366
std::vector< PCaloHit > PCaloHitContainer
double kmaxNeutron
Definition: CaloSD.h:155
bool doFineCaloThisStep_
Definition: CaloSD.h:200
G4ThreadLocal G4Allocator< CaloG4Hit > * fpCaloG4HitAllocator
Definition: CaloG4Hit.cc:11
std::map< CaloHitID, CaloG4Hit * > hitMap[2]
Definition: CaloSD.h:195
virtual uint16_t getDepth(const G4Step *)
Definition: CaloSD.cc:912
virtual double getEnergyDeposit(const G4Step *step)
Definition: CaloSD.cc:362
virtual double EnergyCorrected(const G4Step &step, const G4Track *)
Definition: CaloSD.cc:364
int parentID() const
unsigned int findBoundaryCrossingParent(const G4Track *track, bool markParentAsSaveable=true)
Definition: CaloSD.cc:551
double eMinFine_
Definition: CaloSD.h:193
bool corrTOFBeam
Definition: CaloSD.h:180
double getEM() const
Definition: CaloG4Hit.h:55
TrackWithHistory * getTrackByID(int trackID, bool strict=false) const
void setIncidentEnergy(double e)
Definition: CaloG4Hit.h:62
const math::XYZVectorD & momentum() const
uint32_t cc[maxCellsPerHit]
Definition: gpuFishbone.h:49
void setEntryLocal(double x, double y, double z)
Definition: CaloG4Hit.h:50
void DrawAll() override
Definition: CaloSD.cc:430
uint32_t ID
Definition: Definitions.h:24
void clear() override
Definition: CaloSD.cc:428
uint32_t setDetUnitId(const G4Step *step) override=0
bool useMap
Definition: CaloSD.h:179
void newCollection(const std::string &name, edm::ParameterSet const &p)
Definition: CaloSD.cc:176
double eminHitD
Definition: CaloSD.h:190
uint16_t getDepth() const
Definition: CaloG4Hit.h:69
G4ThreeVector setToLocal(const G4ThreeVector &, const G4VTouchable *) const
Definition: CaloSD.cc:454
Definition: weight.py:1
int nCheckedHits[2]
Definition: CaloSD.h:187
G4ThreeVector posGlobal
Definition: CaloSD.h:142
virtual int getTrackID(const G4Track *)
Definition: CaloSD.cc:872
CaloG4HitCollection * theHC[2]
Definition: CaloSD.h:174
void Initialize(G4HCofThisEvent *HCE) override
Definition: CaloSD.cc:388
int primAncestor
Definition: CaloSD.h:183
int cleanIndex[2]
Definition: CaloSD.h:184
std::vector< int > useResMap_
Definition: CaloSD.h:150
void reset() override
Definition: CaloSD.cc:860
double kmaxProton
Definition: CaloSD.h:155
void fillHits(edm::PCaloHitContainer &, const std::string &) override
Definition: CaloSD.cc:441
std::vector< Detector > fineDetectors_
Definition: CaloSD.h:199
double eminHit
Definition: CaloSD.h:148
void swap(Association< C > &lhs, Association< C > &rhs)
Definition: Association.h:112
bool saveHit(CaloG4Hit *, int k=0)
Definition: CaloSD.cc:948
double getHadr() const
Definition: CaloG4Hit.h:58
bool checkHit(int k=0)
Definition: CaloSD.cc:488
bool equal(const T &first, const T &second)
Definition: Equal.h:32
virtual void initEvent(const BeginOfEvent *)
Definition: CaloSD.cc:868
std::unordered_map< unsigned int, unsigned int > boundaryCrossingParentMap_
Definition: CaloSD.h:197
void cleanHitCollection()
Definition: CaloSD.cc:1039
void reset()
Definition: CaloHitID.cc:49
static void clean(char *s)
T getUntrackedParameter(std::string const &, T const &) const
int primIDSaved[2]
Definition: CaloSD.h:186
bool forceSave
Definition: CaloSD.h:157
int nHC_
Definition: CaloSD.h:158
int timeSliceID() const
Definition: CaloHitID.h:21
bool isItFineCalo(const G4VTouchable *touch)
Definition: CaloSD.cc:368
void addEnergyDeposit(double em, double hd)
Definition: CaloG4Hit.cc:45
float timeSlice
Definition: CaloSD.h:189
Definition: TTTypes.h:54
double getResponseWt(const G4Track *, int k=0)
Definition: CaloSD.cc:927
bool isFinecaloTrackID() const
Definition: CaloG4Hit.h:70
void updateHit(CaloG4Hit *, int k)
Definition: CaloSD.cc:702
CaloG4Hit * createNewHit(const G4Step *, const G4Track *, int k)
Definition: CaloSD.cc:623
static std::string printableDecayChain(const std::vector< unsigned int > &decayChain)
Definition: CaloSD.cc:526
double kmaxIon
Definition: CaloSD.h:155
bool suppressHeavy
Definition: CaloSD.h:154
float edepositHAD
Definition: CaloSD.h:144
T sqrt(T t)
Definition: SSEVec.h:19
void resetForNewPrimary(const G4Step *)
Definition: CaloSD.cc:713
void setEM(double e)
Definition: CaloG4Hit.h:56
bool doFineCalo_
Definition: CaloSD.h:192
void setID(uint32_t i, double d, int j, uint16_t k=0)
Definition: CaloG4Hit.h:73
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
G4bool ProcessHits(G4Step *step, G4TouchableHistory *) override
Definition: CaloSD.cc:194
std::vector< std::string > hcn_
Definition: CaloSD.h:149
double f[11][100]
~CaloSD() override
Definition: CaloSD.cc:174
std::vector< std::unique_ptr< CaloG4Hit > > reusehit[2]
Definition: CaloSD.h:198
uint32_t unitID() const
Definition: CaloHitID.h:20
G4ThreeVector setToGlobal(const G4ThreeVector &, const G4VTouchable *) const
Definition: CaloSD.cc:458
int totalHits[2]
Definition: CaloSD.h:185
TrackInformation * cmsTrackInformation(const G4Track *aTrack)
virtual bool filterHit(CaloG4Hit *, double)
Definition: CaloSD.cc:916
int getIDonCaloSurface() const
ii
Definition: cuy.py:589
CaloHitID previousID[2]
Definition: CaloSD.h:146
double tmaxHit
Definition: CaloSD.h:148
void setID(uint32_t unitID, double timeSlice, int trackID, uint16_t depth=0)
Definition: CaloHitID.cc:41
int genParticlePID() const
CaloSD(const std::string &aSDname, const SensitiveDetectorCatalog &clg, edm::ParameterSet const &p, const SimTrackManager *, float timeSlice=1., bool ignoreTkID=false, const std::string &newcolname="")
Definition: CaloSD.cc:33
virtual void initRun()
Definition: CaloSD.cc:866
double correctT
Definition: CaloSD.h:191
double getAttenuation(const G4Step *aStep, double birk1, double birk2, double birk3) const
Definition: CaloSD.cc:726
void EndOfEvent(G4HCofThisEvent *eventHC) override
Definition: CaloSD.cc:412
CSCCFEBTimeSlice const *const timeSlice(T const &data, int nCFEB, int nSample)
void storeHit(CaloG4Hit *, int k=0)
Definition: CaloSD.cc:936
uint32_t getUnitID() const
Definition: CaloG4Hit.h:66
const std::vector< TrackWithHistory * > * trackContainer() const
bool hitExists(const G4Step *, int k)
Definition: CaloSD.cc:462
virtual void endEvent()
Definition: CaloSD.cc:870
bool trackExists(int i) const
void printDetectorLevels(const G4VTouchable *) const
Definition: CaloSD.cc:1157
void setHadr(double e)
Definition: CaloG4Hit.h:59
float incidentEnergy
Definition: CaloSD.h:143
virtual int setTrackID(const G4Step *)
Definition: CaloSD.cc:890
void markAsFinecaloTrackID(bool flag=true)
Definition: CaloHitID.h:29
void setPosition(double x, double y, double z)
Definition: CaloG4Hit.h:53
void setEntry(double x, double y, double z)
Definition: CaloG4Hit.h:47
G4THitsCollection< CaloG4Hit > CaloG4HitCollection
int trackID() const
static bool isGammaElectronPositron(int pdgCode)
bool isParameterized
Definition: CaloSD.h:177
double getTimeSlice() const
Definition: CaloG4Hit.h:67
std::string detName_
Definition: CaloSD.h:159
CaloHitID currentID[2]
Definition: CaloSD.h:146
std::string collName_[2]
Definition: CaloSD.h:159
std::map< int, TrackWithHistory * > tkMap
Definition: CaloSD.h:196
int giveMotherNeeded(int i) const
std::unique_ptr< CaloMeanResponse > meanResponse[2]
Definition: CaloSD.h:172
const SimTrackManager * m_trackManager
Definition: CaloSD.h:169
std::string shortreprID(const CaloHitID &ID)
Definition: CaloSD.cc:537
Log< level::Warning, false > LogWarning
void clearHits() override
Definition: CaloSD.cc:847
int hcID[2]
Definition: CaloSD.h:182
int trackID() const
Definition: CaloHitID.h:23
std::unique_ptr< CaloSlaveSD > slave[2]
Definition: CaloSD.h:171
void PrintAll() override
Definition: CaloSD.cc:432
void NaNTrap(const G4Step *step) const
G4ThreeVector entrancePoint
Definition: CaloSD.h:140
G4ThreeVector entranceLocal
Definition: CaloSD.h:141
void update(const BeginOfRun *) override
This routine will be called when the appropriate signal arrives.
Definition: CaloSD.cc:748
bool ignoreTrackID
Definition: CaloSD.h:176
uint16_t depth() const
Definition: CaloHitID.h:24