Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2025-02-05 23:51:52

0001 /*
0002  *  VertexClassifier.C
0003  */
0004 
0005 #include <cmath>
0006 #include <cstdlib>
0007 #include <iostream>
0008 
0009 #include "HepPDT/ParticleID.hh"
0010 
0011 #include "SimTracker/TrackHistory/interface/VertexClassifier.h"
0012 
0013 #define update(a, b)  \
0014   do {                \
0015     (a) = (a) || (b); \
0016   } while (0)
0017 
0018 VertexClassifier::VertexClassifier(edm::ParameterSet const &config, edm::ConsumesCollector collector)
0019     : VertexCategories(),
0020       tracer_(config, collector),
0021       hepMCLabel_(config.getUntrackedParameter<edm::InputTag>("hepMC")),
0022       particleDataTableToken_(collector.esConsumes()) {
0023   collector.consumes<edm::HepMCProduct>(hepMCLabel_);
0024   // Set the history depth after hadronization
0025   tracer_.depth(-2);
0026 
0027   // Set the minimum decay length for detecting long decays
0028   longLivedDecayLength_ = config.getUntrackedParameter<double>("longLivedDecayLength");
0029 
0030   // Set the distance for clustering vertices
0031   vertexClusteringDistance_ = config.getUntrackedParameter<double>("vertexClusteringDistance");
0032 }
0033 
0034 void VertexClassifier::newEvent(edm::Event const &event, edm::EventSetup const &setup) {
0035   // Get the new event information for the tracer
0036   tracer_.newEvent(event, setup);
0037 
0038   // Get hepmc of the event
0039   event.getByLabel(hepMCLabel_, mcInformation_);
0040 
0041   // Get the partivle data table
0042   particleDataTable_ = setup.getHandle(particleDataTableToken_);
0043 
0044   // Create the list of primary vertices associated to the event
0045   genPrimaryVertices();
0046 }
0047 
0048 void VertexClassifier::fillPSetDescription(edm::ParameterSetDescription &desc) {
0049   VertexHistory::fillPSetDescription(desc);
0050   desc.addUntracked<edm::InputTag>("hepMC", edm::InputTag("generatorSmeared"));
0051   desc.addUntracked<double>("longLivedDecayLength", 1e-14);
0052   desc.addUntracked<double>("vertexClusteringDistance", 0.003);
0053 }
0054 
0055 VertexClassifier const &VertexClassifier::evaluate(reco::VertexBaseRef const &vertex) {
0056   // Initializing the category vector
0057   reset();
0058 
0059   // Associate and evaluate the vertex history (check for fakes)
0060   if (tracer_.evaluate(vertex)) {
0061     // Get all the information related to the simulation details
0062     simulationInformation();
0063 
0064     // Get all the information related to decay process
0065     processesAtGenerator();
0066 
0067     // Get information about conversion and other interactions
0068     processesAtSimulation();
0069 
0070     // Get geometrical information about the vertices
0071     vertexInformation();
0072 
0073     // Check for unkown classification
0074     unknownVertex();
0075   } else
0076     flags_[Fake] = true;
0077 
0078   return *this;
0079 }
0080 
0081 VertexClassifier const &VertexClassifier::evaluate(TrackingVertexRef const &vertex) {
0082   // Initializing the category vector
0083   reset();
0084 
0085   // Trace the history for the given TP
0086   tracer_.evaluate(vertex);
0087 
0088   // Check for a reconstructed track
0089   if (tracer_.recoVertex().isNonnull())
0090     flags_[Reconstructed] = true;
0091   else
0092     flags_[Reconstructed] = false;
0093 
0094   // Get all the information related to the simulation details
0095   simulationInformation();
0096 
0097   // Get all the information related to decay process
0098   processesAtGenerator();
0099 
0100   // Get information about conversion and other interactions
0101   processesAtSimulation();
0102 
0103   // Get geometrical information about the vertices
0104   vertexInformation();
0105 
0106   // Check for unkown classification
0107   unknownVertex();
0108 
0109   return *this;
0110 }
0111 
0112 void VertexClassifier::simulationInformation() {
0113   // Get the event id for the initial TP.
0114   EncodedEventId eventId = tracer_.simVertex()->eventId();
0115   // Check for signal events
0116   flags_[SignalEvent] = !eventId.bunchCrossing() && !eventId.event();
0117 }
0118 
0119 void VertexClassifier::processesAtGenerator() {
0120   // Get the generated vetices from track history
0121   VertexHistory::GenVertexTrail const &genVertexTrail = tracer_.genVertexTrail();
0122 
0123   // Loop over the generated vertices
0124   for (VertexHistory::GenVertexTrail::const_iterator ivertex = genVertexTrail.begin(); ivertex != genVertexTrail.end();
0125        ++ivertex) {
0126     // Get the pointer to the vertex by removing the const-ness (no const methos
0127     // in HepMC::GenVertex)
0128     HepMC::GenVertex *vertex = const_cast<HepMC::GenVertex *>(*ivertex);
0129 
0130     // Loop over the sources looking for specific decays
0131     for (HepMC::GenVertex::particle_iterator iparent = vertex->particles_begin(HepMC::parents);
0132          iparent != vertex->particles_end(HepMC::parents);
0133          ++iparent) {
0134       // Collect the pdgid of the parent
0135       int pdgid = std::abs((*iparent)->pdg_id());
0136       // Get particle type
0137       HepPDT::ParticleID particleID(pdgid);
0138 
0139       // Check if the particle type is valid one
0140       if (particleID.isValid()) {
0141         // Get particle data
0142         ParticleData const *particleData = particleDataTable_->particle(particleID);
0143         // Check if the particle exist in the table
0144         if (particleData) {
0145           // Check if their life time is bigger than longLivedDecayLength_
0146           if (particleData->lifetime() > longLivedDecayLength_) {
0147             // Check for B, C weak decays and long lived decays
0148             update(flags_[BWeakDecay], particleID.hasBottom());
0149             update(flags_[CWeakDecay], particleID.hasCharm());
0150             update(flags_[LongLivedDecay], true);
0151           }
0152           // Check Tau, Ks and Lambda decay
0153           update(flags_[TauDecay], pdgid == 15);
0154           update(flags_[KsDecay], pdgid == 310);
0155           update(flags_[LambdaDecay], pdgid == 3122);
0156           update(flags_[JpsiDecay], pdgid == 443);
0157           update(flags_[XiDecay], pdgid == 3312);
0158           update(flags_[OmegaDecay], pdgid == 3334);
0159           update(flags_[SigmaPlusDecay], pdgid == 3222);
0160           update(flags_[SigmaMinusDecay], pdgid == 3112);
0161         }
0162       }
0163     }
0164   }
0165 }
0166 
0167 void VertexClassifier::processesAtSimulation() {
0168   VertexHistory::SimVertexTrail const &simVertexTrail = tracer_.simVertexTrail();
0169 
0170   for (VertexHistory::SimVertexTrail::const_iterator ivertex = simVertexTrail.begin(); ivertex != simVertexTrail.end();
0171        ++ivertex) {
0172     // pdgid of the real source parent vertex
0173     int pdgid = 0;
0174 
0175     // select the original source in case of combined vertices
0176     bool flag = false;
0177     TrackingVertex::tp_iterator itd, its;
0178 
0179     for (its = (*ivertex)->sourceTracks_begin(); its != (*ivertex)->sourceTracks_end(); ++its) {
0180       for (itd = (*ivertex)->daughterTracks_begin(); itd != (*ivertex)->daughterTracks_end(); ++itd)
0181         if (itd != its) {
0182           flag = true;
0183           break;
0184         }
0185       if (flag)
0186         break;
0187     }
0188     // Collect the pdgid of the original source track
0189     if (its != (*ivertex)->sourceTracks_end())
0190       pdgid = std::abs((*its)->pdgId());
0191     else
0192       pdgid = 0;
0193 
0194     // Geant4 process type is selected using first Geant4 vertex assigned to
0195     // the TrackingVertex
0196     unsigned int processG4 = 0;
0197 
0198     if ((*ivertex)->nG4Vertices() > 0) {
0199       processG4 = (*(*ivertex)->g4Vertices_begin()).processType();
0200     }
0201 
0202     unsigned int process = g4toCMSProcMap_.processId(processG4);
0203 
0204     // Flagging all the different processes
0205     update(flags_[KnownProcess], process != CMS::Undefined && process != CMS::Unknown && process != CMS::Primary);
0206 
0207     update(flags_[UndefinedProcess], process == CMS::Undefined);
0208     update(flags_[UnknownProcess], process == CMS::Unknown);
0209     update(flags_[PrimaryProcess], process == CMS::Primary);
0210     update(flags_[HadronicProcess], process == CMS::Hadronic);
0211     update(flags_[DecayProcess], process == CMS::Decay);
0212     update(flags_[ComptonProcess], process == CMS::Compton);
0213     update(flags_[AnnihilationProcess], process == CMS::Annihilation);
0214     update(flags_[EIoniProcess], process == CMS::EIoni);
0215     update(flags_[HIoniProcess], process == CMS::HIoni);
0216     update(flags_[MuIoniProcess], process == CMS::MuIoni);
0217     update(flags_[PhotonProcess], process == CMS::Photon);
0218     update(flags_[MuPairProdProcess], process == CMS::MuPairProd);
0219     update(flags_[ConversionsProcess], process == CMS::Conversions);
0220     update(flags_[EBremProcess], process == CMS::EBrem);
0221     update(flags_[SynchrotronRadiationProcess], process == CMS::SynchrotronRadiation);
0222     update(flags_[MuBremProcess], process == CMS::MuBrem);
0223     update(flags_[MuNuclProcess], process == CMS::MuNucl);
0224 
0225     // Loop over the simulated particles
0226     for (TrackingVertex::tp_iterator iparticle = (*ivertex)->daughterTracks_begin();
0227          iparticle != (*ivertex)->daughterTracks_end();
0228          ++iparticle) {
0229       if ((*iparticle)->numberOfTrackerLayers()) {
0230         // Special treatment for decays
0231         if (process == CMS::Decay) {
0232           // Get particle type
0233           HepPDT::ParticleID particleID(pdgid);
0234           // Check if the particle type is valid one
0235           if (particleID.isValid()) {
0236             // Get particle data
0237             ParticleData const *particleData = particleDataTable_->particle(particleID);
0238             // Check if the particle exist in the table
0239             if (particleData) {
0240               // Check if their life time is bigger than 1e-14
0241               if (particleDataTable_->particle(particleID)->lifetime() > longLivedDecayLength_) {
0242                 // Check for B, C weak decays and long lived decays
0243                 update(flags_[BWeakDecay], particleID.hasBottom());
0244                 update(flags_[CWeakDecay], particleID.hasCharm());
0245                 update(flags_[LongLivedDecay], true);
0246               }
0247               // Check Tau, Ks and Lambda decay
0248               update(flags_[TauDecay], pdgid == 15);
0249               update(flags_[KsDecay], pdgid == 310);
0250               update(flags_[LambdaDecay], pdgid == 3122);
0251               update(flags_[JpsiDecay], pdgid == 443);
0252               update(flags_[XiDecay], pdgid == 3312);
0253               update(flags_[OmegaDecay], pdgid == 3334);
0254               update(flags_[SigmaPlusDecay], pdgid == 3222);
0255               update(flags_[SigmaMinusDecay], pdgid == 3112);
0256             }
0257           }
0258         }
0259       }
0260     }
0261   }
0262 }
0263 
0264 void VertexClassifier::vertexInformation() {
0265   // Helper class for clusterization
0266   typedef std::multimap<double, HepMC::ThreeVector> Clusters;
0267   typedef std::pair<double, HepMC::ThreeVector> ClusterPair;
0268 
0269   Clusters clusters;
0270 
0271   // Get the main primary vertex from the list
0272   GeneratedPrimaryVertex const &genpv = genpvs_.back();
0273 
0274   // Get the generated history of the tracks
0275   const VertexHistory::GenVertexTrail &genVertexTrail = tracer_.genVertexTrail();
0276 
0277   // Unit transformation from mm to cm
0278   double const mm = 0.1;
0279 
0280   // Loop over the generated vertexes
0281   for (VertexHistory::GenVertexTrail::const_iterator ivertex = genVertexTrail.begin(); ivertex != genVertexTrail.end();
0282        ++ivertex) {
0283     // Check vertex exist
0284     if (*ivertex) {
0285       // Measure the distance2 respecto the primary vertex
0286       HepMC::ThreeVector p = (*ivertex)->point3d();
0287       double distance =
0288           sqrt(pow(p.x() * mm - genpv.x, 2) + pow(p.y() * mm - genpv.y, 2) + pow(p.z() * mm - genpv.z, 2));
0289 
0290       // If there is not any clusters add the first vertex.
0291       if (clusters.empty()) {
0292         clusters.insert(ClusterPair(distance, HepMC::ThreeVector(p.x() * mm, p.y() * mm, p.z() * mm)));
0293         continue;
0294       }
0295 
0296       // Check if there is already a cluster in the given distance from primary
0297       // vertex
0298       Clusters::const_iterator icluster = clusters.lower_bound(distance - vertexClusteringDistance_);
0299 
0300       if (icluster == clusters.upper_bound(distance + vertexClusteringDistance_)) {
0301         clusters.insert(ClusterPair(distance, HepMC::ThreeVector(p.x() * mm, p.y() * mm, p.z() * mm)));
0302         continue;
0303       }
0304 
0305       bool cluster = false;
0306 
0307       // Looping over the vertex clusters of a given distance from primary
0308       // vertex
0309       for (; icluster != clusters.upper_bound(distance + vertexClusteringDistance_); ++icluster) {
0310         double difference = sqrt(pow(p.x() * mm - icluster->second.x(), 2) + pow(p.y() * mm - icluster->second.y(), 2) +
0311                                  pow(p.z() * mm - icluster->second.z(), 2));
0312 
0313         if (difference < vertexClusteringDistance_) {
0314           cluster = true;
0315           break;
0316         }
0317       }
0318 
0319       if (!cluster)
0320         clusters.insert(ClusterPair(distance, HepMC::ThreeVector(p.x() * mm, p.y() * mm, p.z() * mm)));
0321     }
0322   }
0323 
0324   const VertexHistory::SimVertexTrail &simVertexTrail = tracer_.simVertexTrail();
0325 
0326   // Loop over the generated particles
0327   for (VertexHistory::SimVertexTrail::const_reverse_iterator ivertex = simVertexTrail.rbegin();
0328        ivertex != simVertexTrail.rend();
0329        ++ivertex) {
0330     // Look for those with production vertex
0331     TrackingVertex::LorentzVector p = (*ivertex)->position();
0332 
0333     double distance = sqrt(pow(p.x() - genpv.x, 2) + pow(p.y() - genpv.y, 2) + pow(p.z() - genpv.z, 2));
0334 
0335     // If there is not any clusters add the first vertex.
0336     if (clusters.empty()) {
0337       clusters.insert(ClusterPair(distance, HepMC::ThreeVector(p.x(), p.y(), p.z())));
0338       continue;
0339     }
0340 
0341     // Check if there is already a cluster in the given distance from primary
0342     // vertex
0343     Clusters::const_iterator icluster = clusters.lower_bound(distance - vertexClusteringDistance_);
0344 
0345     if (icluster == clusters.upper_bound(distance + vertexClusteringDistance_)) {
0346       clusters.insert(ClusterPair(distance, HepMC::ThreeVector(p.x(), p.y(), p.z())));
0347       continue;
0348     }
0349 
0350     bool cluster = false;
0351 
0352     // Looping over the vertex clusters of a given distance from primary vertex
0353     for (; icluster != clusters.upper_bound(distance + vertexClusteringDistance_); ++icluster) {
0354       double difference = sqrt(pow(p.x() - icluster->second.x(), 2) + pow(p.y() - icluster->second.y(), 2) +
0355                                pow(p.z() - icluster->second.z(), 2));
0356 
0357       if (difference < vertexClusteringDistance_) {
0358         cluster = true;
0359         break;
0360       }
0361     }
0362 
0363     if (!cluster)
0364       clusters.insert(ClusterPair(distance, HepMC::ThreeVector(p.x(), p.y(), p.z())));
0365   }
0366 
0367   if (clusters.size() == 1)
0368     flags_[PrimaryVertex] = true;
0369   else if (clusters.size() == 2)
0370     flags_[SecondaryVertex] = true;
0371   else
0372     flags_[TertiaryVertex] = true;
0373 }
0374 
0375 bool VertexClassifier::isFinalstateParticle(const HepMC::GenParticle *p) {
0376   return !p->end_vertex() && p->status() == 1;
0377 }
0378 
0379 bool VertexClassifier::isCharged(const HepMC::GenParticle *p) {
0380   const ParticleData *part = particleDataTable_->particle(p->pdg_id());
0381   if (part)
0382     return part->charge() != 0;
0383   else {
0384     // the new/improved particle table doesn't know anti-particles
0385     return particleDataTable_->particle(-p->pdg_id()) != nullptr;
0386   }
0387 }
0388 
0389 void VertexClassifier::genPrimaryVertices() {
0390   genpvs_.clear();
0391 
0392   const HepMC::GenEvent *event = mcInformation_->GetEvent();
0393 
0394   if (event) {
0395     // Loop over the different GenVertex
0396     for (HepMC::GenEvent::vertex_const_iterator ivertex = event->vertices_begin(); ivertex != event->vertices_end();
0397          ++ivertex) {
0398       bool hasParentVertex = false;
0399 
0400       // Loop over the parents looking to see if they are coming from a
0401       // production vertex
0402       for (HepMC::GenVertex::particle_iterator iparent = (*ivertex)->particles_begin(HepMC::parents);
0403            iparent != (*ivertex)->particles_end(HepMC::parents);
0404            ++iparent)
0405         if ((*iparent)->production_vertex()) {
0406           hasParentVertex = true;
0407           break;
0408         }
0409 
0410       // Reject those vertices with parent vertices
0411       if (hasParentVertex)
0412         continue;
0413 
0414       // Get the position of the vertex
0415       HepMC::FourVector pos = (*ivertex)->position();
0416 
0417       double const mm = 0.1;
0418 
0419       GeneratedPrimaryVertex pv(pos.x() * mm, pos.y() * mm, pos.z() * mm);
0420 
0421       std::vector<GeneratedPrimaryVertex>::iterator ientry = genpvs_.begin();
0422 
0423       // Search for a VERY close vertex in the list
0424       for (; ientry != genpvs_.end(); ++ientry) {
0425         double distance = sqrt(pow(pv.x - ientry->x, 2) + pow(pv.y - ientry->y, 2) + pow(pv.z - ientry->z, 2));
0426         if (distance < vertexClusteringDistance_)
0427           break;
0428       }
0429 
0430       // Check if there is not a VERY close vertex and added to the list
0431       if (ientry == genpvs_.end())
0432         ientry = genpvs_.insert(ientry, pv);
0433 
0434       // Add the vertex barcodes to the new or existent vertices
0435       ientry->genVertex.push_back((*ivertex)->barcode());
0436 
0437       // Collect final state descendants
0438       for (HepMC::GenVertex::particle_iterator idecendants = (*ivertex)->particles_begin(HepMC::descendants);
0439            idecendants != (*ivertex)->particles_end(HepMC::descendants);
0440            ++idecendants) {
0441         if (isFinalstateParticle(*idecendants))
0442           if (find(ientry->finalstateParticles.begin(), ientry->finalstateParticles.end(), (*idecendants)->barcode()) ==
0443               ientry->finalstateParticles.end()) {
0444             ientry->finalstateParticles.push_back((*idecendants)->barcode());
0445             HepMC::FourVector m = (*idecendants)->momentum();
0446 
0447             ientry->ptot.setPx(ientry->ptot.px() + m.px());
0448             ientry->ptot.setPy(ientry->ptot.py() + m.py());
0449             ientry->ptot.setPz(ientry->ptot.pz() + m.pz());
0450             ientry->ptot.setE(ientry->ptot.e() + m.e());
0451             ientry->ptsq += m.perp() * m.perp();
0452 
0453             if (m.perp() > 0.8 && std::abs(m.pseudoRapidity()) < 2.5 && isCharged(*idecendants))
0454               ientry->nGenTrk++;
0455           }
0456       }
0457     }
0458   }
0459 
0460   std::sort(genpvs_.begin(), genpvs_.end());
0461 }