File indexing completed on 2024-06-06 04:27:13
0001
0002
0003
0004
0005
0006 #include "SimG4CMS/Calo/interface/CaloSD.h"
0007 #include "SimDataFormats/SimHitMaker/interface/CaloSlaveSD.h"
0008 #include "SimG4Core/Geometry/interface/DD4hep2DDDName.h"
0009 #include "SimG4Core/Notification/interface/TrackInformation.h"
0010 #include "SimG4Core/Notification/interface/G4TrackToParticleID.h"
0011 #include "SimG4Core/Notification/interface/SimTrackManager.h"
0012 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0013 #include "FWCore/Utilities/interface/Exception.h"
0014
0015 #include "G4EventManager.hh"
0016 #include "G4LogicalVolumeStore.hh"
0017 #include "G4LogicalVolume.hh"
0018 #include "G4SDManager.hh"
0019 #include "G4Step.hh"
0020 #include "G4Track.hh"
0021 #include "G4VProcess.hh"
0022 #include "G4GFlashSpot.hh"
0023 #include "G4ParticleTable.hh"
0024 #include "G4PhysicalConstants.hh"
0025
0026 #include <CLHEP/Units/SystemOfUnits.h>
0027
0028 #include <fstream>
0029 #include <memory>
0030 #include <sstream>
0031
0032
0033
0034 CaloSD::CaloSD(const std::string& name,
0035 const SensitiveDetectorCatalog& clg,
0036 edm::ParameterSet const& p,
0037 const SimTrackManager* manager,
0038 float timeSliceUnit,
0039 bool ignoreTkID,
0040 const std::string& newcollName)
0041 : SensitiveCaloDetector(name, clg, newcollName),
0042 G4VGFlashSensitiveDetector(),
0043 eminHit(0.),
0044 m_trackManager(manager),
0045 ignoreTrackID(ignoreTkID),
0046 timeSlice(timeSliceUnit),
0047 eminHitD(0.) {
0048
0049 nHC_ = (newcollName.empty()) ? 1 : 2;
0050 for (int k = 0; k < 2; ++k) {
0051 currentHit[k] = nullptr;
0052 theHC[k] = nullptr;
0053 hcID[k] = -1;
0054 }
0055 bool dd4hep = p.getParameter<bool>("g4GeometryDD4hepSource");
0056 int addlevel = dd4hep ? 1 : 0;
0057 edm::ParameterSet m_CaloSD = p.getParameter<edm::ParameterSet>("CaloSD");
0058 energyCut = m_CaloSD.getParameter<double>("EminTrack") * CLHEP::GeV;
0059 tmaxHit = m_CaloSD.getParameter<double>("TmaxHit") * CLHEP::ns;
0060 std::vector<double> eminHits = m_CaloSD.getParameter<std::vector<double>>("EminHits");
0061 std::vector<double> tmaxHits = m_CaloSD.getParameter<std::vector<double>>("TmaxHits");
0062 hcn_ = m_CaloSD.getParameter<std::vector<std::string>>("HCNames");
0063 useResMap_ = m_CaloSD.getParameter<std::vector<int>>("UseResponseTables");
0064 std::vector<double> eminHitX = m_CaloSD.getParameter<std::vector<double>>("EminHitsDepth");
0065 suppressHeavy = m_CaloSD.getParameter<bool>("SuppressHeavy");
0066 kmaxIon = m_CaloSD.getParameter<double>("IonThreshold") * CLHEP::MeV;
0067 kmaxProton = m_CaloSD.getParameter<double>("ProtonThreshold") * CLHEP::MeV;
0068 kmaxNeutron = m_CaloSD.getParameter<double>("NeutronThreshold") * CLHEP::MeV;
0069 nCheckedHits[0] = m_CaloSD.getUntrackedParameter<int>("CheckHits", 25);
0070 nCheckedHits[1] = nCheckedHits[0];
0071 useMap = m_CaloSD.getUntrackedParameter<bool>("UseMap", true);
0072 int verbn = m_CaloSD.getUntrackedParameter<int>("Verbosity", 0);
0073 corrTOFBeam = m_CaloSD.getParameter<bool>("CorrectTOFBeam");
0074 double beamZ = m_CaloSD.getParameter<double>("BeamPosition") * CLHEP::cm;
0075 correctT = beamZ / CLHEP::c_light / CLHEP::nanosecond;
0076 doFineCalo_ = m_CaloSD.getParameter<bool>("DoFineCalo");
0077 eMinFine_ = m_CaloSD.getParameter<double>("EminFineTrack") * CLHEP::MeV;
0078 std::vector<std::string> fineNames = m_CaloSD.getParameter<std::vector<std::string>>("FineCaloNames");
0079 std::vector<int> fineLevels = m_CaloSD.getParameter<std::vector<int>>("FineCaloLevels");
0080 std::vector<int> useFines = m_CaloSD.getParameter<std::vector<int>>("UseFineCalo");
0081 for (auto& level : fineLevels)
0082 level += addlevel;
0083
0084 SetVerboseLevel(verbn);
0085 for (int k = 0; k < 2; ++k)
0086 meanResponse[k].reset(nullptr);
0087 for (unsigned int k = 0; k < hcn_.size(); ++k) {
0088 if (name == hcn_[k]) {
0089 if (k < eminHits.size())
0090 eminHit = eminHits[k] * CLHEP::MeV;
0091 if (k < eminHitX.size())
0092 eminHitD = eminHitX[k] * CLHEP::MeV;
0093 if (k < tmaxHits.size())
0094 tmaxHit = tmaxHits[k] * CLHEP::ns;
0095 if (k < useResMap_.size() && useResMap_[k] > 0) {
0096 meanResponse[0] = std::make_unique<CaloMeanResponse>(p);
0097 break;
0098 }
0099 }
0100 }
0101 detName_ = name;
0102 collName_[0] = name;
0103 collName_[1] = newcollName;
0104 slave[0] = std::make_unique<CaloSlaveSD>(name);
0105 slave[1].reset(nullptr);
0106
0107 for (int k = 0; k < 2; ++k) {
0108 currentID[k] = CaloHitID(timeSlice, ignoreTrackID);
0109 previousID[k] = CaloHitID(timeSlice, ignoreTrackID);
0110 }
0111 isParameterized = false;
0112
0113 entrancePoint.set(0., 0., 0.);
0114 entranceLocal.set(0., 0., 0.);
0115 posGlobal.set(0., 0., 0.);
0116 incidentEnergy = edepositEM = edepositHAD = 0.f;
0117
0118 primAncestor = 0;
0119 forceSave = false;
0120 for (int k = 0; k < 2; ++k) {
0121 cleanIndex[k] = primIDSaved[k] = totalHits[k] = 0;
0122 }
0123
0124 edm::LogVerbatim("CaloSim") << "CaloSD: Minimum energy of track for saving it " << energyCut / CLHEP::GeV
0125 << " GeV\n Use of HitID Map " << useMap << "\n Check last "
0126 << nCheckedHits[0] << " before saving the hit\n Correct TOF globally by "
0127 << correctT << " ns (Flag =" << corrTOFBeam << ")\n Save hits recorded before "
0128 << tmaxHit << " ns and if energy is above " << eminHit / CLHEP::MeV
0129 << " MeV (for depth 0) or " << eminHitD / CLHEP::MeV
0130 << " MeV (for nonzero depths);\n Time Slice Unit " << timeSlice
0131 << "\nIgnore TrackID Flag " << ignoreTrackID << " doFineCalo flag " << doFineCalo_
0132 << "\nBeam Position " << beamZ / CLHEP::cm << " cm";
0133 if (doFineCalo_)
0134 edm::LogVerbatim("DoFineCalo") << "Using finecalo v2";
0135
0136
0137 edm::LogVerbatim("CaloSim") << "CaloSD: Have a possibility of " << fineNames.size() << " fine calorimeters of which "
0138 << useFines.size() << " are selected";
0139 for (unsigned int k = 0; k < fineNames.size(); ++k)
0140 edm::LogVerbatim("CaloSim") << "[" << k << "] " << fineNames[k] << " at " << fineLevels[k];
0141 std::ostringstream st1;
0142 for (unsigned int k = 0; k < useFines.size(); ++k)
0143 st1 << " [" << k << "] " << useFines[k] << ":" << fineNames[useFines[k]];
0144 edm::LogVerbatim("CaloSim") << "CaloSD used calorimeters" << st1.str();
0145 const G4LogicalVolumeStore* lvs = G4LogicalVolumeStore::GetInstance();
0146 std::vector<G4LogicalVolume*>::const_iterator lvcite;
0147 for (unsigned int i = 0; i < useFines.size(); i++) {
0148 G4LogicalVolume* lv = nullptr;
0149 G4String name = static_cast<G4String>(fineNames[useFines[i]]);
0150 for (lvcite = lvs->begin(); lvcite != lvs->end(); lvcite++) {
0151 G4String namx(static_cast<G4String>(DD4hep2DDDName::nameMatterLV((*lvcite)->GetName(), dd4hep)));
0152 if (namx == name) {
0153 lv = (*lvcite);
0154 break;
0155 }
0156 }
0157 if (lv != nullptr) {
0158 CaloSD::Detector detector;
0159 detector.name = name;
0160 detector.lv = lv;
0161 detector.level = fineLevels[useFines[i]];
0162 fineDetectors_.emplace_back(detector);
0163 }
0164 }
0165 #ifdef EDM_ML_DEBUG
0166 edm::LogVerbatim("CaloSim") << "CaloSD::Loads information for " << fineDetectors_.size() << " fine detectors";
0167 unsigned int k(0);
0168 for (const auto& detector : fineDetectors_) {
0169 edm::LogVerbatim("CaloSim") << "Detector[" << k << "] " << detector.name << " at level " << detector.level
0170 << " pointer to LV: " << detector.lv;
0171 }
0172 #endif
0173 }
0174
0175 CaloSD::~CaloSD() {}
0176
0177 void CaloSD::newCollection(const std::string& name, edm::ParameterSet const& p) {
0178 for (unsigned int k = 0; k < hcn_.size(); ++k) {
0179 if (name == hcn_[k]) {
0180 if (k < useResMap_.size() && useResMap_[k] > 0) {
0181 meanResponse[1] = std::make_unique<CaloMeanResponse>(p);
0182 break;
0183 }
0184 }
0185 }
0186 slave[1] = std::make_unique<CaloSlaveSD>(name);
0187 #ifdef EDM_ML_DEBUG
0188 edm::LogVerbatim("CaloSim") << "CaloSD:: Initialise a second collection for " << name;
0189 for (int k = 0; k < nHC_; ++k)
0190 edm::LogVerbatim("CaloSim") << "Detector[" << k << "]" << detName_ << " collection " << collName_[k];
0191
0192 #endif
0193 }
0194
0195 G4bool CaloSD::ProcessHits(G4Step* aStep, G4TouchableHistory*) {
0196 NaNTrap(aStep);
0197 ignoreReject = false;
0198
0199 #ifdef EDM_ML_DEBUG
0200 edm::LogVerbatim("CaloSim") << "CaloSD::" << GetName() << " ID= " << aStep->GetTrack()->GetTrackID()
0201 << " prID= " << aStep->GetTrack()->GetParentID()
0202 << " Eprestep= " << aStep->GetPreStepPoint()->GetKineticEnergy()
0203 << " step= " << aStep->GetStepLength() << " Edep= " << aStep->GetTotalEnergyDeposit();
0204 #endif
0205
0206
0207 doFineCaloThisStep_ = (doFineCalo_ && isItFineCalo(aStep->GetPreStepPoint()->GetTouchable()));
0208
0209
0210
0211 if (isParameterized) {
0212 if (getFromLibrary(aStep)) {
0213
0214
0215 (aStep->GetTrack())->SetTrackStatus(fStopAndKill);
0216 if (0 < aStep->GetNumberOfSecondariesInCurrentStep()) {
0217 auto tv = aStep->GetSecondaryInCurrentStep();
0218 auto vol = aStep->GetPreStepPoint()->GetPhysicalVolume();
0219 for (auto& tk : *tv) {
0220 if (tk->GetVolume() == vol) {
0221 const_cast<G4Track*>(tk)->SetTrackStatus(fStopAndKill);
0222 }
0223 }
0224 }
0225 return true;
0226 }
0227 }
0228
0229
0230 edepositEM = edepositHAD = 0.f;
0231 if (aStep->GetTotalEnergyDeposit() <= 0.0) {
0232 return false;
0233 }
0234
0235
0236 unsigned int unitID = setDetUnitId(aStep);
0237 auto const theTrack = aStep->GetTrack();
0238 uint16_t depth = getDepth(aStep);
0239
0240 double time = theTrack->GetGlobalTime() / CLHEP::nanosecond;
0241 int primaryID = getTrackID(theTrack);
0242 if (unitID > 0) {
0243 currentID[0].setID(unitID, time, primaryID, depth);
0244 } else {
0245 if (!ignoreReject) {
0246 const G4TouchableHistory* touch = static_cast<const G4TouchableHistory*>(theTrack->GetTouchable());
0247 edm::LogVerbatim("CaloSim") << "CaloSD::ProcessHits: unitID= " << unitID
0248 << " currUnit= " << currentID[0].unitID() << " Detector: " << GetName()
0249 << " trackID= " << theTrack->GetTrackID() << " "
0250 << theTrack->GetDefinition()->GetParticleName()
0251 << "\n Edep= " << aStep->GetTotalEnergyDeposit()
0252 << " PV: " << touch->GetVolume(0)->GetName()
0253 << " PVid= " << touch->GetReplicaNumber(0) << " MVid= " << touch->GetReplicaNumber(1);
0254 }
0255 return false;
0256 }
0257 double energy = getEnergyDeposit(aStep);
0258 if (energy <= 0.0) {
0259 return false;
0260 }
0261
0262 if (doFineCaloThisStep_) {
0263 currentID[0].setID(unitID, time, findBoundaryCrossingParent(theTrack), depth);
0264 currentID[0].markAsFinecaloTrackID();
0265 }
0266
0267 if (G4TrackToParticleID::isGammaElectronPositron(theTrack)) {
0268 edepositEM = energy;
0269 } else {
0270 edepositHAD = energy;
0271 }
0272 #ifdef EDM_ML_DEBUG
0273 const G4TouchableHistory* touch = static_cast<const G4TouchableHistory*>(theTrack->GetTouchable());
0274 edm::LogVerbatim("CaloSim") << "CaloSD::" << GetName() << " PV:" << touch->GetVolume(0)->GetName()
0275 << " PVid=" << touch->GetReplicaNumber(0) << " MVid=" << touch->GetReplicaNumber(1)
0276 << " Unit:" << std::hex << unitID << std::dec << " Edep=" << edepositEM << " "
0277 << edepositHAD << " ID=" << theTrack->GetTrackID() << " pID=" << theTrack->GetParentID()
0278 << " E=" << theTrack->GetKineticEnergy() << " S=" << aStep->GetStepLength() << "\n "
0279 << theTrack->GetDefinition()->GetParticleName() << " primaryID= " << primaryID
0280 << " currentID= (" << currentID[0] << ") previousID= (" << previousID[0] << ")";
0281 #endif
0282 if (!hitExists(aStep, 0)) {
0283 currentHit[0] = createNewHit(aStep, theTrack, 0);
0284 } else {
0285 #ifdef EDM_ML_DEBUG
0286 edm::LogVerbatim("DoFineCalo") << "Not creating new hit, only updating " << shortreprID(currentHit[0]);
0287 #endif
0288 }
0289
0290 processSecondHit(aStep, theTrack);
0291
0292 return true;
0293 }
0294
0295 bool CaloSD::ProcessHits(G4GFlashSpot* aSpot, G4TouchableHistory*) {
0296 edepositEM = edepositHAD = 0.f;
0297 const G4Track* track = aSpot->GetOriginatorTrack()->GetPrimaryTrack();
0298
0299 double edep = aSpot->GetEnergySpot()->GetEnergy();
0300 if (edep <= 0.0) {
0301 return false;
0302 }
0303
0304 G4Step fFakeStep;
0305 G4StepPoint* fFakePreStepPoint = fFakeStep.GetPreStepPoint();
0306 G4StepPoint* fFakePostStepPoint = fFakeStep.GetPostStepPoint();
0307 fFakePreStepPoint->SetPosition(aSpot->GetPosition());
0308 fFakePostStepPoint->SetPosition(aSpot->GetPosition());
0309
0310 G4TouchableHandle fTouchableHandle = aSpot->GetTouchableHandle();
0311 fFakePreStepPoint->SetTouchableHandle(fTouchableHandle);
0312 fFakeStep.SetTotalEnergyDeposit(edep);
0313 edep = EnergyCorrected(fFakeStep, track);
0314
0315
0316 if (edep <= 0.0) {
0317 return false;
0318 }
0319
0320 if (G4TrackToParticleID::isGammaElectronPositron(track)) {
0321 edepositEM = edep;
0322 } else {
0323 edepositHAD = edep;
0324 }
0325
0326 unsigned int unitID = setDetUnitId(&fFakeStep);
0327
0328 if (unitID > 0) {
0329
0330 double time = track->GetGlobalTime() / CLHEP::nanosecond;
0331 int primaryID = getTrackID(track);
0332 uint16_t depth = getDepth(&fFakeStep);
0333 currentID[0].setID(unitID, time, primaryID, depth);
0334 #ifdef EDM_ML_DEBUG
0335 edm::LogVerbatim("CaloSim") << "CaloSD:: GetSpotInfo for Unit 0x" << std::hex << currentID[0].unitID() << std::dec
0336 << " Edeposit = " << edepositEM << " " << edepositHAD;
0337 #endif
0338
0339 if (currentID[0] == previousID[0]) {
0340 updateHit(currentHit[0], 0);
0341 } else {
0342 posGlobal = aSpot->GetEnergySpot()->GetPosition();
0343
0344 if (currentID[0].trackID() != previousID[0].trackID()) {
0345 entrancePoint = aSpot->GetPosition();
0346 entranceLocal = aSpot->GetTouchableHandle()->GetHistory()->GetTopTransform().TransformPoint(entrancePoint);
0347 incidentEnergy = track->GetKineticEnergy();
0348 #ifdef EDM_ML_DEBUG
0349 edm::LogVerbatim("CaloSim") << "CaloSD: Incident energy " << incidentEnergy / CLHEP::GeV << " GeV and"
0350 << " entrance point " << entrancePoint << " (Global) " << entranceLocal
0351 << " (Local)";
0352 #endif
0353 }
0354 if (!checkHit()) {
0355 currentHit[0] = createNewHit(&fFakeStep, track, 0);
0356 }
0357 }
0358 return true;
0359 }
0360 return false;
0361 }
0362
0363 double CaloSD::getEnergyDeposit(const G4Step* aStep) { return aStep->GetTotalEnergyDeposit(); }
0364
0365 double CaloSD::EnergyCorrected(const G4Step& aStep, const G4Track*) { return aStep.GetTotalEnergyDeposit(); }
0366
0367 bool CaloSD::getFromLibrary(const G4Step*) { return false; }
0368
0369 bool CaloSD::isItFineCalo(const G4VTouchable* touch) {
0370 bool ok(false);
0371 int level = ((touch->GetHistoryDepth()) + 1);
0372 for (const auto& detector : fineDetectors_) {
0373 if (level > 0 && level >= detector.level) {
0374 int ii = level - detector.level;
0375 G4LogicalVolume* lv = touch->GetVolume(ii)->GetLogicalVolume();
0376 ok = (lv == detector.lv);
0377 #ifdef EDM_ML_DEBUG
0378 std::string name1 = (lv == nullptr) ? "Unknown" : lv->GetName();
0379 edm::LogVerbatim("CaloSim") << "CaloSD: volume " << name1 << ":" << detector.name << " at Level "
0380 << detector.level << " Flag " << ok;
0381 #endif
0382 if (ok)
0383 break;
0384 }
0385 }
0386 return ok;
0387 }
0388
0389 void CaloSD::Initialize(G4HCofThisEvent* HCE) {
0390 #ifdef EDM_ML_DEBUG
0391 edm::LogVerbatim("CaloSim") << "CaloSD : Initialize called for " << detName_;
0392 #endif
0393
0394 for (int k = 0; k < nHC_; ++k) {
0395 totalHits[k] = 0;
0396
0397
0398
0399 theHC[k] = new CaloG4HitCollection(detName_, collName_[k]);
0400
0401 if (hcID[k] < 0) {
0402 hcID[k] = G4SDManager::GetSDMpointer()->GetCollectionID(collName_[k]);
0403 }
0404
0405 HCE->AddHitsCollection(hcID[k], theHC[k]);
0406 #ifdef EDM_ML_DEBUG
0407 edm::LogVerbatim("CaloSim") << "CaloSD : Add hits collection for " << hcID[k] << " for " << k << ":" << detName_
0408 << ":" << collName_[k];
0409 #endif
0410 }
0411 }
0412
0413 void CaloSD::EndOfEvent(G4HCofThisEvent*) {
0414
0415
0416 cleanHitCollection();
0417
0418 #ifdef EDM_ML_DEBUG
0419 for (int k = 0; k < nHC_; ++k) {
0420 if (theHC[k] == nullptr)
0421 edm::LogVerbatim("CaloSim") << "CaloSD: EndofEvent entered for container " << k << " with no entries";
0422 else
0423 edm::LogVerbatim("CaloSim") << "CaloSD: EndofEvent entered for container " << k << " with " << theHC[k]->entries()
0424 << " entries";
0425 }
0426 #endif
0427 }
0428
0429 void CaloSD::clear() {}
0430
0431 void CaloSD::DrawAll() {}
0432
0433 void CaloSD::PrintAll() {
0434 for (int k = 0; k < nHC_; ++k) {
0435 #ifdef EDM_ML_DEBUG
0436 edm::LogVerbatim("CaloSim") << "CaloSD: Collection " << theHC[k]->GetName();
0437 #endif
0438 theHC[k]->PrintAllHits();
0439 }
0440 }
0441
0442 void CaloSD::fillHits(edm::PCaloHitContainer& cc, const std::string& hname) {
0443 for (int k = 0; k < nHC_; ++k) {
0444 #ifdef EDM_ML_DEBUG
0445 edm::LogVerbatim("CaloSim") << "CaloSD: Tries to transfer " << slave[k].get()->hits().size() << " hits for "
0446 << slave[k].get()->name() << " " << hname;
0447 #endif
0448 if (slave[k].get()->name() == hname) {
0449 cc = slave[k].get()->hits();
0450 slave[k].get()->Clean();
0451 }
0452 }
0453 }
0454
0455 G4ThreeVector CaloSD::setToLocal(const G4ThreeVector& global, const G4VTouchable* touch) const {
0456 return touch->GetHistory()->GetTopTransform().TransformPoint(global);
0457 }
0458
0459 G4ThreeVector CaloSD::setToGlobal(const G4ThreeVector& local, const G4VTouchable* touch) const {
0460 return touch->GetHistory()->GetTopTransform().Inverse().TransformPoint(local);
0461 }
0462
0463 bool CaloSD::hitExists(const G4Step* aStep, int k) {
0464 #ifdef EDM_ML_DEBUG
0465 edm::LogVerbatim("CaloSim") << "CaloSD: hitExists for " << k;
0466 #endif
0467
0468 if (currentID[k] == previousID[k]) {
0469 updateHit(currentHit[k], k);
0470 return true;
0471 }
0472
0473
0474
0475
0476
0477
0478
0479
0480 if (k == 0) {
0481 posGlobal = aStep->GetPreStepPoint()->GetPosition();
0482 if (currentID[k].trackID() != previousID[k].trackID()) {
0483 resetForNewPrimary(aStep);
0484 }
0485 }
0486 return checkHit(k);
0487 }
0488
0489 bool CaloSD::checkHit(int k) {
0490 #ifdef EDM_ML_DEBUG
0491 edm::LogVerbatim("CaloSim") << "CaloSD: checkHit for " << k << " for map " << useMap << ":" << &hitMap[k] << " Nhits "
0492 << nCheckedHits[k] << " HC " << theHC[k] << " ID " << currentID[k];
0493 #endif
0494
0495 bool found = false;
0496 if (useMap) {
0497 std::map<CaloHitID, CaloG4Hit*>::const_iterator it = hitMap[k].find(currentID[k]);
0498 if (it != hitMap[k].end()) {
0499 currentHit[k] = it->second;
0500 found = true;
0501 }
0502 } else if (nCheckedHits[k] > 0) {
0503 int nhits = theHC[k]->entries();
0504 int minhit = std::max(nhits - nCheckedHits[k], 0);
0505 int maxhit = nhits - 1;
0506
0507 for (int j = maxhit; j > minhit; --j) {
0508 if ((*theHC[k])[j]->getID() == currentID[k]) {
0509 currentHit[k] = (*theHC[k])[j];
0510 found = true;
0511 break;
0512 }
0513 }
0514 }
0515
0516 if (found) {
0517 updateHit(currentHit[k], k);
0518 }
0519 return found;
0520 }
0521
0522 int CaloSD::getNumberOfHits(int k) { return theHC[k]->entries(); }
0523
0524
0525
0526
0527
0528 std::string CaloSD::printableDecayChain(const std::vector<unsigned int>& decayChain) {
0529 std::stringstream ss;
0530 for (long unsigned int i = 0; i < decayChain.size(); i++) {
0531 if (i > 0)
0532 ss << " <- ";
0533 ss << decayChain[i];
0534 }
0535 return ss.str();
0536 }
0537
0538
0539 std::string CaloSD::shortreprID(const CaloHitID& ID) {
0540 std::stringstream ss;
0541 ss << GetName() << "/" << ID.unitID() << "/trk" << ID.trackID() << "/d" << ID.depth() << "/time" << ID.timeSliceID();
0542 if (ID.isFinecaloTrackID())
0543 ss << "/FC";
0544 return ss.str();
0545 }
0546
0547
0548 std::string CaloSD::shortreprID(const CaloG4Hit* hit) { return shortreprID(hit->getID()); }
0549
0550
0551
0552
0553 unsigned int CaloSD::findBoundaryCrossingParent(const G4Track* track, bool markAsSaveable) {
0554 TrackInformation* trkInfo = cmsTrackInformation(track);
0555 unsigned int id = track->GetTrackID();
0556
0557 auto it = boundaryCrossingParentMap_.find(id);
0558 if (it != boundaryCrossingParentMap_.end()) {
0559 #ifdef EDM_ML_DEBUG
0560 edm::LogVerbatim("DoFineCalo") << "Track " << id << " parent already cached: " << it->second;
0561 #endif
0562 return it->second;
0563 }
0564
0565 else if (trkInfo->crossedBoundary()) {
0566 #ifdef EDM_ML_DEBUG
0567 edm::LogVerbatim("DoFineCalo") << "Track " << id << " crosses boundary itself";
0568 #endif
0569 boundaryCrossingParentMap_[id] = id;
0570 trkInfo->setStoreTrack();
0571 return id;
0572 }
0573
0574 std::vector<unsigned int> decayChain{id};
0575 #ifdef EDM_ML_DEBUG
0576 edm::LogVerbatim("DoFineCalo") << "Track " << id << ": Traversing history to find boundary-crossing parent";
0577 #endif
0578 unsigned int parentID = track->GetParentID();
0579 while (true) {
0580 if (parentID == 0)
0581 throw cms::Exception("Unknown", "CaloSD")
0582 << "Hit end of parentage for track " << id << " without finding a boundary-crossing parent";
0583
0584 auto it = boundaryCrossingParentMap_.find(parentID);
0585 if (it != boundaryCrossingParentMap_.end()) {
0586 #ifdef EDM_ML_DEBUG
0587 edm::LogVerbatim("DoFineCalo") << " Track " << parentID
0588 << " boundary-crossing parent already cached: " << it->second;
0589 #endif
0590
0591 for (auto ancestorID : decayChain)
0592 boundaryCrossingParentMap_[ancestorID] = it->second;
0593 #ifdef EDM_ML_DEBUG
0594
0595 decayChain.push_back(parentID);
0596 while (parentID != it->second) {
0597 parentID = m_trackManager->getTrackByID(parentID, true)->parentID();
0598 decayChain.push_back(parentID);
0599 }
0600 edm::LogVerbatim("DoFineCalo") << " Full decay chain: " << printableDecayChain(decayChain);
0601 #endif
0602 return it->second;
0603 }
0604
0605 TrackWithHistory* parentTrack = m_trackManager->getTrackByID(parentID, true);
0606 if (parentTrack->crossedBoundary()) {
0607 if (markAsSaveable)
0608 parentTrack->setToBeSaved();
0609 decayChain.push_back(parentID);
0610
0611 for (auto ancestorID : decayChain)
0612 boundaryCrossingParentMap_[ancestorID] = parentID;
0613 #ifdef EDM_ML_DEBUG
0614 edm::LogVerbatim("DoFineCalo") << " Found boundary-crossing ancestor " << parentID << " for track " << id
0615 << "; decay chain: " << printableDecayChain(decayChain);
0616 #endif
0617 return parentID;
0618 }
0619
0620 decayChain.push_back(parentID);
0621 parentID = parentTrack->parentID();
0622 }
0623 }
0624
0625 CaloG4Hit* CaloSD::createNewHit(const G4Step* aStep, const G4Track* theTrack, int k) {
0626 #ifdef EDM_ML_DEBUG
0627 edm::LogVerbatim("CaloSim") << "CaloSD::CreateNewHit " << getNumberOfHits() << " for " << GetName()
0628 << " Unit:" << currentID[k].unitID() << " " << currentID[k].depth()
0629 << " Edep= " << edepositEM << " " << edepositHAD
0630 << " primaryID= " << currentID[k].trackID()
0631 << " timeSlice= " << currentID[k].timeSliceID() << " ID= " << theTrack->GetTrackID()
0632 << " " << theTrack->GetDefinition()->GetParticleName()
0633 << " E(GeV)= " << theTrack->GetKineticEnergy() / CLHEP::GeV
0634 << " parentID= " << theTrack->GetParentID() << "\n Ein= " << incidentEnergy
0635 << " entranceGlobal: " << entrancePoint << " entranceLocal: " << entranceLocal
0636 << " posGlobal: " << posGlobal;
0637 #endif
0638
0639 CaloG4Hit* aHit;
0640 if (!reusehit[k].empty()) {
0641 aHit = reusehit[k].back().release();
0642 aHit->setEM(0.f);
0643 aHit->setHadr(0.f);
0644 reusehit[k].pop_back();
0645 } else {
0646 aHit = new CaloG4Hit;
0647 }
0648
0649 aHit->setID(currentID[k]);
0650 aHit->setEntry(entrancePoint.x(), entrancePoint.y(), entrancePoint.z());
0651 aHit->setEntryLocal(entranceLocal.x(), entranceLocal.y(), entranceLocal.z());
0652 aHit->setPosition(posGlobal.x(), posGlobal.y(), posGlobal.z());
0653 aHit->setIncidentEnergy(incidentEnergy);
0654 updateHit(aHit, k);
0655
0656 storeHit(aHit, k);
0657 TrackInformation* trkInfo = cmsTrackInformation(theTrack);
0658
0659 #ifdef EDM_ML_DEBUG
0660 if (doFineCaloThisStep_)
0661 edm::LogVerbatim("DoFineCalo") << "New hit " << shortreprID(aHit) << " using finecalo;"
0662 << " isItFineCalo(post)=" << isItFineCalo(aStep->GetPostStepPoint()->GetTouchable())
0663 << " isItFineCalo(pre)=" << isItFineCalo(aStep->GetPreStepPoint()->GetTouchable());
0664 #endif
0665
0666
0667 if (!doFineCaloThisStep_) {
0668 double etrack = 0;
0669 if (currentID[k].trackID() == primIDSaved[k]) {
0670 } else if (currentID[k].trackID() == theTrack->GetTrackID()) {
0671 etrack = theTrack->GetKineticEnergy();
0672 #ifdef EDM_ML_DEBUG
0673 edm::LogVerbatim("CaloSim") << "CaloSD: set save the track " << currentID[k].trackID() << " etrack " << etrack
0674 << " eCut " << energyCut << " force: " << forceSave
0675 << " save: " << (etrack >= energyCut || forceSave);
0676 #endif
0677 if (etrack >= energyCut || forceSave) {
0678 trkInfo->setStoreTrack();
0679 }
0680 } else {
0681 TrackWithHistory* trkh = tkMap[currentID[k].trackID()];
0682 #ifdef EDM_ML_DEBUG
0683 edm::LogVerbatim("CaloSim") << "CaloSD : TrackWithHistory pointer for " << currentID[k].trackID() << " is "
0684 << trkh;
0685 #endif
0686 if (trkh != nullptr) {
0687 etrack = sqrt(trkh->momentum().Mag2());
0688 if (etrack >= energyCut) {
0689 trkh->setToBeSaved();
0690 #ifdef EDM_ML_DEBUG
0691 edm::LogVerbatim("CaloSim") << "CaloSD: set save the track " << currentID[k].trackID() << " with Hit";
0692 #endif
0693 }
0694 }
0695 }
0696 primIDSaved[k] = currentID[k].trackID();
0697 }
0698
0699 if (useMap)
0700 ++totalHits[k];
0701 return aHit;
0702 }
0703
0704 void CaloSD::updateHit(CaloG4Hit* aHit, int k) {
0705 aHit->addEnergyDeposit(edepositEM, edepositHAD);
0706 #ifdef EDM_ML_DEBUG
0707 edm::LogVerbatim("CaloSim") << "CaloSD:" << GetName() << " Add energy deposit in " << currentID[k]
0708 << " Edep_em(MeV)= " << edepositEM << " Edep_had(MeV)= " << edepositHAD;
0709 #endif
0710
0711
0712 previousID[k] = currentID[k];
0713 }
0714
0715 void CaloSD::resetForNewPrimary(const G4Step* aStep) {
0716 auto const preStepPoint = aStep->GetPreStepPoint();
0717 entrancePoint = preStepPoint->GetPosition();
0718 entranceLocal = setToLocal(entrancePoint, preStepPoint->GetTouchable());
0719 incidentEnergy = preStepPoint->GetKineticEnergy();
0720 #ifdef EDM_ML_DEBUG
0721 edm::LogVerbatim("CaloSim") << "CaloSD::resetForNewPrimary for " << GetName()
0722 << " ID= " << aStep->GetTrack()->GetTrackID() << " Ein= " << incidentEnergy / CLHEP::GeV
0723 << " GeV and"
0724 << " entrance point global: " << entrancePoint << " local: " << entranceLocal;
0725 #endif
0726 }
0727
0728 double CaloSD::getAttenuation(const G4Step* aStep, double birk1, double birk2, double birk3) const {
0729 double weight = 1.;
0730 double charge = aStep->GetPreStepPoint()->GetCharge();
0731 double length = aStep->GetStepLength();
0732
0733 if (charge != 0. && length > 0.) {
0734 double density = aStep->GetPreStepPoint()->GetMaterial()->GetDensity();
0735 double dedx = aStep->GetTotalEnergyDeposit() / length;
0736 double rkb = birk1 / density;
0737 double c = birk2 * rkb * rkb;
0738 if (std::abs(charge) >= 2.)
0739 rkb /= birk3;
0740 weight = 1. / (1. + rkb * dedx + c * dedx * dedx);
0741 #ifdef EDM_ML_DEBUG
0742 edm::LogVerbatim("CaloSim") << "CaloSD::getAttenuation in " << aStep->GetPreStepPoint()->GetMaterial()->GetName()
0743 << " Charge " << charge << " dE/dx " << dedx << " Birk Const " << rkb << ", " << c
0744 << " Weight = " << weight << " dE " << aStep->GetTotalEnergyDeposit();
0745 #endif
0746 }
0747 return weight;
0748 }
0749
0750 void CaloSD::update(const BeginOfRun*) { initRun(); }
0751
0752 void CaloSD::update(const BeginOfEvent* g4Event) {
0753 #ifdef EDM_ML_DEBUG
0754 edm::LogVerbatim("CaloSim") << "CaloSD: Dispatched BeginOfEvent for " << GetName() << " !";
0755 #endif
0756 clearHits();
0757 initEvent(g4Event);
0758 }
0759
0760 void CaloSD::update(const EndOfTrack* trk) {
0761 int id = (*trk)()->GetTrackID();
0762 TrackInformation* trkI = cmsTrackInformation((*trk)());
0763 int lastTrackID = -1;
0764 if (trkI)
0765 lastTrackID = trkI->getIDonCaloSurface();
0766 if (id == lastTrackID) {
0767 auto trksForThisEvent = m_trackManager->trackContainer();
0768 if (!trksForThisEvent->empty()) {
0769 TrackWithHistory* trkH = trksForThisEvent->back();
0770 if (trkH->trackID() == id) {
0771 tkMap[id] = trkH;
0772 #ifdef EDM_ML_DEBUG
0773 edm::LogVerbatim("CaloSim") << "CaloSD: get track " << id << " from Container of size "
0774 << trksForThisEvent->size() << " with ID " << trkH->trackID();
0775 #endif
0776 }
0777 }
0778 }
0779 }
0780
0781 void CaloSD::update(const ::EndOfEvent*) {
0782 endEvent();
0783 for (int k = 0; k < nHC_; ++k) {
0784 slave[k].get()->ReserveMemory(theHC[k]->entries());
0785
0786 int count(0);
0787 double eEM(0.0);
0788 double eHAD(0.0);
0789 double eEM2(0.0);
0790 double eHAD2(0.0);
0791 #ifdef EDM_ML_DEBUG
0792 int wrong(0);
0793 double tt(0.0);
0794 double zloc(0.0);
0795 double zglob(0.0);
0796 double ee(0.0);
0797 #endif
0798 int hc_entries = theHC[k]->entries();
0799 for (int i = 0; i < hc_entries; ++i) {
0800 #ifdef EDM_ML_DEBUG
0801 if (!saveHit((*theHC[k])[i], k)) {
0802 ++wrong;
0803 }
0804 #else
0805 saveHit((*theHC[k])[i], k);
0806 #endif
0807
0808 ++count;
0809 double x = (*theHC[k])[i]->getEM();
0810 eEM += x;
0811 eEM2 += x * x;
0812 x = (*theHC[k])[i]->getHadr();
0813 eHAD += x;
0814 eHAD2 += x * x;
0815 #ifdef EDM_ML_DEBUG
0816 tt += (*theHC[k])[i]->getTimeSlice();
0817 ee += (*theHC[k])[i]->getIncidentEnergy();
0818 zglob += std::abs((*theHC[k])[i]->getEntry().z());
0819 zloc += std::abs((*theHC[k])[i]->getEntryLocal().z());
0820 #endif
0821 }
0822
0823 double norm = (count > 0) ? 1.0 / count : 0.0;
0824 eEM *= norm;
0825 eEM2 *= norm;
0826 eHAD *= norm;
0827 eHAD2 *= norm;
0828 eEM2 = std::sqrt(eEM2 - eEM * eEM);
0829 eHAD2 = std::sqrt(eHAD2 - eHAD * eHAD);
0830 #ifdef EDM_ML_DEBUG
0831 tt *= norm;
0832 ee *= norm;
0833 zglob *= norm;
0834 zloc *= norm;
0835 edm::LogVerbatim("CaloSim") << "CaloSD: " << GetName() << " store " << count << " hits; " << wrong
0836 << " track IDs not given properly and " << totalHits - count
0837 << " hits not passing cuts\n EmeanEM= " << eEM << " ErmsEM= " << eEM2
0838 << "\n EmeanHAD= " << eHAD << " ErmsHAD= " << eHAD2 << " TimeMean= " << tt
0839 << " E0mean= " << ee << " Zglob= " << zglob << " Zloc= " << zloc << " ";
0840 #endif
0841 std::vector<std::unique_ptr<CaloG4Hit>>().swap(reusehit[k]);
0842 if (useMap)
0843 hitMap[k].erase(hitMap[k].begin(), hitMap[k].end());
0844 }
0845 tkMap.erase(tkMap.begin(), tkMap.end());
0846 boundaryCrossingParentMap_.clear();
0847 }
0848
0849 void CaloSD::clearHits() {
0850 for (int k = 0; k < nHC_; ++k) {
0851 previousID[k].reset();
0852 primIDSaved[k] = -99;
0853 cleanIndex[k] = 0;
0854 #ifdef EDM_ML_DEBUG
0855 edm::LogVerbatim("CaloSim") << "CaloSD: Clears hit vector for " << GetName()
0856 << " and initialise slave: " << slave[k].get()->name();
0857 #endif
0858 slave[k].get()->Initialize();
0859 }
0860 }
0861
0862 void CaloSD::reset() {
0863 if (fpCaloG4HitAllocator) {
0864 fpCaloG4HitAllocator->ResetStorage();
0865 }
0866 }
0867
0868 void CaloSD::initRun() {}
0869
0870 void CaloSD::initEvent(const BeginOfEvent*) {}
0871
0872 void CaloSD::endEvent() {}
0873
0874 int CaloSD::getTrackID(const G4Track* aTrack) {
0875 int primaryID = 0;
0876 TrackInformation* trkInfo = cmsTrackInformation(aTrack);
0877 if (trkInfo) {
0878 primaryID = trkInfo->getIDonCaloSurface();
0879 #ifdef EDM_ML_DEBUG
0880 edm::LogVerbatim("CaloSim") << "Track ID: " << trkInfo->getIDonCaloSurface() << ":" << aTrack->GetTrackID() << ":"
0881 << primaryID;
0882 #endif
0883 } else {
0884 primaryID = aTrack->GetTrackID();
0885 #ifdef EDM_ML_DEBUG
0886 edm::LogWarning("CaloSim") << "CaloSD: Problem with primaryID **** set by force to TkID **** " << primaryID;
0887 #endif
0888 }
0889 return primaryID;
0890 }
0891
0892 int CaloSD::setTrackID(const G4Step* aStep) {
0893 auto const theTrack = aStep->GetTrack();
0894 TrackInformation* trkInfo = cmsTrackInformation(theTrack);
0895 int primaryID = trkInfo->getIDonCaloSurface();
0896 if (primaryID <= 0) {
0897 primaryID = theTrack->GetTrackID();
0898 }
0899 #ifdef EDM_ML_DEBUG
0900 edm::LogVerbatim("CaloSim") << "Track ID: " << trkInfo->getIDonCaloSurface() << ":" << theTrack->GetTrackID() << ":"
0901 << primaryID;
0902 #endif
0903
0904 if (primaryID != previousID[0].trackID()) {
0905 resetForNewPrimary(aStep);
0906 }
0907 #ifdef EDM_ML_DEBUG
0908 edm::LogVerbatim("CaloSim") << "CaloSD::setTrackID for " << GetName()
0909 << " trackID= " << aStep->GetTrack()->GetTrackID() << " primaryID= " << primaryID;
0910 #endif
0911 return primaryID;
0912 }
0913
0914 uint16_t CaloSD::getDepth(const G4Step*) { return 0; }
0915
0916 void CaloSD::processSecondHit(const G4Step*, const G4Track*) {}
0917
0918 bool CaloSD::filterHit(CaloG4Hit* hit, double time) {
0919 double emin(eminHit);
0920 if (hit->getDepth() > 0)
0921 emin = eminHitD;
0922 #ifdef EDM_ML_DEBUG
0923 edm::LogVerbatim("CaloSim") << "CaloSD::filterHit(..) Depth " << hit->getDepth() << " Emin = " << emin << " ("
0924 << eminHit << ", " << eminHitD << ")";
0925 #endif
0926 return ((time <= tmaxHit) && (hit->getEnergyDeposit() > emin));
0927 }
0928
0929 double CaloSD::getResponseWt(const G4Track* aTrack, int k) {
0930 double wt = 1.0;
0931 if (meanResponse[k].get()) {
0932 TrackInformation* trkInfo = cmsTrackInformation(aTrack);
0933 wt = meanResponse[k].get()->getWeight(trkInfo->genParticlePID(), trkInfo->genParticleP());
0934 }
0935 return wt;
0936 }
0937
0938 void CaloSD::storeHit(CaloG4Hit* hit, int k) {
0939 if (hit == nullptr || previousID[k].trackID() < 0) {
0940 edm::LogWarning("CaloSim") << "CaloSD: hit to be stored is nullptr !!"
0941 << " previousID.trackID()= " << previousID[k].trackID();
0942 return;
0943 }
0944
0945 theHC[k]->insert(hit);
0946 if (useMap)
0947 hitMap[k].insert(std::pair<CaloHitID, CaloG4Hit*>(previousID[k], hit));
0948 }
0949
0950 bool CaloSD::saveHit(CaloG4Hit* aHit, int k) {
0951 int tkID;
0952 bool ok = true;
0953
0954 double time = aHit->getTimeSlice();
0955 if (corrTOFBeam)
0956 time += correctT;
0957
0958
0959 if (doFineCalo_ && aHit->isFinecaloTrackID()) {
0960 #ifdef EDM_ML_DEBUG
0961 edm::LogVerbatim("DoFineCalo") << "Saving hit " << shortreprID(aHit);
0962 #endif
0963 if (!m_trackManager)
0964 throw cms::Exception("Unknown", "CaloSD") << "m_trackManager not set, needed for finecalo!";
0965 if (!m_trackManager->trackExists(aHit->getTrackID()))
0966 throw cms::Exception("Unknown", "CaloSD")
0967 << "Error on hit " << shortreprID(aHit) << ": Parent track not in track manager";
0968 slave[k].get()->processHits(aHit->getUnitID(),
0969 aHit->getEM() / CLHEP::GeV,
0970 aHit->getHadr() / CLHEP::GeV,
0971 time,
0972 aHit->getTrackID(),
0973 aHit->getDepth());
0974 }
0975
0976 else {
0977 if (m_trackManager) {
0978 tkID = m_trackManager->giveMotherNeeded(aHit->getTrackID());
0979 if (tkID == 0) {
0980 if (m_trackManager->trackExists(aHit->getTrackID()))
0981 tkID = (aHit->getTrackID());
0982 else {
0983 ok = false;
0984 }
0985 }
0986 } else {
0987 tkID = aHit->getTrackID();
0988 ok = false;
0989 }
0990 #ifdef EDM_ML_DEBUG
0991 edm::LogVerbatim("DoFineCalo") << "Saving hit " << shortreprID(aHit) << " with trackID=" << tkID;
0992 #endif
0993
0994 slave[k].get()->processHits(
0995 aHit->getUnitID(), aHit->getEM() / CLHEP::GeV, aHit->getHadr() / CLHEP::GeV, time, tkID, aHit->getDepth());
0996 }
0997
0998 #ifdef EDM_ML_DEBUG
0999 if (!ok)
1000 edm::LogWarning("CaloSim") << "CaloSD:Cannot find track ID for " << aHit->getTrackID();
1001 edm::LogVerbatim("CaloSim") << "CalosD: Track ID " << aHit->getTrackID() << " changed to " << tkID
1002 << " by SimTrackManager Status " << ok;
1003 #endif
1004
1005 #ifdef EDM_ML_DEBUG
1006 edm::LogVerbatim("CaloSim") << "CaloSD: Store Hit at " << std::hex << aHit->getUnitID() << std::dec << " "
1007 << aHit->getDepth() << " due to " << tkID << " in time " << time << " of energy "
1008 << aHit->getEM() / CLHEP::GeV << " GeV (EM) and " << aHit->getHadr() / CLHEP::GeV
1009 << " GeV (Hadr)";
1010 #endif
1011 return ok;
1012 }
1013
1014 void CaloSD::update(const BeginOfTrack* trk) {
1015 int primary = -1;
1016 TrackInformation* trkInfo = cmsTrackInformation((*trk)());
1017 if (trkInfo->isPrimary())
1018 primary = (*trk)()->GetTrackID();
1019
1020 #ifdef EDM_ML_DEBUG
1021 edm::LogVerbatim("CaloSim") << "New track: isPrimary " << trkInfo->isPrimary() << " primary ID = " << primary
1022 << " primary ancestor ID " << primAncestor;
1023 #endif
1024
1025
1026
1027 if (primary > 0 && primary != primAncestor) {
1028 primAncestor = primary;
1029
1030
1031
1032 bool clean(false);
1033 for (int k = 0; k < nHC_; ++k)
1034 if (theHC[k]->entries() > 0)
1035 clean = true;
1036 if (clean)
1037 cleanHitCollection();
1038 }
1039 }
1040
1041 void CaloSD::cleanHitCollection() {
1042 for (int k = 0; k < nHC_; ++k) {
1043 std::vector<CaloG4Hit*>* theCollection = theHC[k]->GetVector();
1044
1045 #ifdef EDM_ML_DEBUG
1046 edm::LogVerbatim("CaloSim") << "CaloSD: collection before merging, size = " << theHC[k]->entries();
1047 #endif
1048 if (reusehit[k].empty())
1049 reusehit[k].reserve(theHC[k]->entries() - cleanIndex[k]);
1050
1051
1052 if (!useMap) {
1053 std::vector<CaloG4Hit*> hitvec;
1054
1055 hitvec.swap(*theCollection);
1056 sort((hitvec.begin() + cleanIndex[k]), hitvec.end(), CaloG4HitLess());
1057 #ifdef EDM_ML_DEBUG
1058 edm::LogVerbatim("CaloSim") << "CaloSD::cleanHitCollection: sort hits in buffer starting from "
1059 << "element = " << cleanIndex[k];
1060 for (unsigned int i = 0; i < hitvec.size(); ++i) {
1061 if (hitvec[i] == nullptr)
1062 edm::LogVerbatim("CaloSim") << i << " has a null pointer";
1063 else
1064 edm::LogVerbatim("CaloSim") << i << " " << *hitvec[i];
1065 }
1066 #endif
1067 CaloG4HitEqual equal;
1068 for (unsigned int i = cleanIndex[k]; i < hitvec.size(); ++i) {
1069 int jump = 0;
1070 for (unsigned int j = i + 1; j < hitvec.size() && equal(hitvec[i], hitvec[j]); ++j) {
1071 ++jump;
1072
1073 (*hitvec[i]).addEnergyDeposit(*hitvec[j]);
1074 (*hitvec[j]).setEM(0.);
1075 (*hitvec[j]).setHadr(0.);
1076 reusehit[k].emplace_back(hitvec[j]);
1077 hitvec[j] = nullptr;
1078 }
1079 i += jump;
1080 }
1081 #ifdef EDM_ML_DEBUG
1082 edm::LogVerbatim("CaloSim") << "CaloSD: cleanHitCollection merge the hits in buffer ";
1083 for (unsigned int i = 0; i < hitvec.size(); ++i) {
1084 if (hitvec[i] == nullptr)
1085 edm::LogVerbatim("CaloSim") << i << " has a null pointer";
1086 else
1087 edm::LogVerbatim("CaloSim") << i << " " << *hitvec[i];
1088 }
1089 #endif
1090
1091 hitvec.erase(std::stable_partition(
1092 hitvec.begin() + cleanIndex[k], hitvec.end(), [](CaloG4Hit* p) { return p != nullptr; }),
1093 hitvec.end());
1094 #ifdef EDM_ML_DEBUG
1095 edm::LogVerbatim("CaloSim") << "CaloSD::cleanHitCollection: remove the merged hits in buffer, new size = "
1096 << hitvec.size();
1097 #endif
1098 hitvec.swap(*theCollection);
1099 totalHits[k] = theHC[k]->entries();
1100 }
1101
1102 #ifdef EDM_ML_DEBUG
1103 edm::LogVerbatim("CaloSim") << "CaloSD: collection after merging, size= " << theHC[k]->entries()
1104 << " Size of reusehit= " << reusehit[k].size()
1105 << "\n starting hit selection from index = " << cleanIndex[k];
1106 #endif
1107
1108 int addhit = 0;
1109 for (unsigned int i = cleanIndex[k]; i < theCollection->size(); ++i) {
1110 CaloG4Hit* aHit((*theCollection)[i]);
1111
1112
1113
1114 double time = aHit->getTimeSlice();
1115 if (corrTOFBeam)
1116 time += correctT;
1117 if (!filterHit(aHit, time)) {
1118 #ifdef EDM_ML_DEBUG
1119 edm::LogVerbatim("CaloSim") << "CaloSD: dropped CaloG4Hit "
1120 << " " << *aHit;
1121 #endif
1122
1123
1124
1125 reusehit[k].emplace_back((*theCollection)[i]);
1126 (*theCollection)[i] = nullptr;
1127 ++addhit;
1128 }
1129 }
1130
1131 #ifdef EDM_ML_DEBUG
1132 edm::LogVerbatim("CaloSim") << "CaloSD: Size of reusehit after selection = " << reusehit[k].size()
1133 << " Number of added hit = " << addhit;
1134 #endif
1135 if (useMap) {
1136 if (addhit > 0) {
1137 int offset = reusehit[k].size() - addhit;
1138 for (int ii = addhit - 1; ii >= 0; --ii) {
1139 CaloHitID theID = reusehit[k][offset + ii]->getID();
1140 hitMap[k].erase(theID);
1141 }
1142 }
1143 }
1144
1145
1146 theCollection->erase(
1147 std::stable_partition(
1148 theCollection->begin() + cleanIndex[k], theCollection->end(), [](CaloG4Hit* p) { return p != nullptr; }),
1149 theCollection->end());
1150 #ifdef EDM_ML_DEBUG
1151 edm::LogVerbatim("CaloSim") << "CaloSD: hit collection after selection, size = " << theHC[k]->entries();
1152 theHC[k]->PrintAllHits();
1153 #endif
1154
1155 cleanIndex[k] = theHC[k]->entries();
1156 }
1157 }
1158
1159 void CaloSD::printDetectorLevels(const G4VTouchable* touch) const {
1160
1161 int level = ((touch->GetHistoryDepth()) + 1);
1162 std::ostringstream st1;
1163 st1 << level << " Levels:";
1164 if (level > 0) {
1165 for (int ii = 0; ii < level; ii++) {
1166 int i = level - ii - 1;
1167 G4VPhysicalVolume* pv = touch->GetVolume(i);
1168 std::string name = (pv != nullptr) ? pv->GetName() : "Unknown";
1169 st1 << " " << name << ":" << touch->GetReplicaNumber(i);
1170 }
1171 }
1172 edm::LogVerbatim("CaloSim") << st1.str();
1173 }