rivet is hosted by Hepforge, IPPP Durham
Particle.cc
Go to the documentation of this file.
00001 #include "Rivet/Particle.hh"
00002 #include "Rivet/Tools/Cuts.hh"
00003 #include "Rivet/Tools/ParticleIdUtils.hh"
00004 
00005 namespace Rivet {
00006 
00007 
00008   Particle& Particle::transformBy(const LorentzTransform& lt) {
00009     _momentum = lt.transform(_momentum);
00010     return *this;
00011   }
00012 
00013 
00014   bool Particle::isVisible() const {
00015     // Charged particles are visible
00016     if ( PID::threeCharge(pid()) != 0 ) return true;
00017     // Neutral hadrons are visible
00018     if ( PID::isHadron(pid()) ) return true;
00019     // Photons are visible
00020     if ( pid() == PID::PHOTON ) return true;
00021     // Gluons are visible (for parton level analyses)
00022     if ( pid() == PID::GLUON ) return true;
00023     // Everything else is invisible
00024     return false;
00025   }
00026 
00027 
00028   bool Particle::isStable() const {
00029     return genParticle() != NULL &&
00030       genParticle()->status() == 1 &&
00031       genParticle()->end_vertex() == NULL;
00032   }
00033 
00034 
00035   vector<Particle> Particle::parents(const Cut& c) const {
00036     vector<Particle> rtn;
00037     /// @todo Remove this const mess crap when HepMC doesn't suck
00038     GenVertexPtr gv = const_cast<GenVertexPtr>( genParticle()->production_vertex() );
00039     if (gv == NULL) return rtn;
00040     /// @todo Would like to do this, but the range objects are broken
00041     // foreach (const GenParticlePtr gp, gv->particles(HepMC::children))
00042     //   rtn += Particle(gp);
00043     for (GenVertex::particle_iterator it = gv->particles_begin(HepMC::parents); it != gv->particles_end(HepMC::parents); ++it) {
00044       const Particle p(*it);
00045       if (c != Cuts::OPEN && !c->accept(p)) continue;
00046       rtn += p;
00047     }
00048     return rtn;
00049   }
00050 
00051 
00052   vector<Particle> Particle::children(const Cut& c) const {
00053     vector<Particle> rtn;
00054     if (isStable()) return rtn;
00055     /// @todo Remove this const mess crap when HepMC doesn't suck
00056     GenVertexPtr gv = const_cast<GenVertexPtr>( genParticle()->end_vertex() );
00057     if (gv == NULL) return rtn;
00058     /// @todo Would like to do this, but the range objects are broken
00059     // foreach (const GenParticlePtr gp, gv->particles(HepMC::children))
00060     //   rtn += Particle(gp);
00061     for (GenVertex::particle_iterator it = gv->particles_begin(HepMC::children); it != gv->particles_end(HepMC::children); ++it) {
00062       const Particle p(*it);
00063       if (c != Cuts::OPEN && !c->accept(p)) continue;
00064       rtn += p;
00065     }
00066     return rtn;
00067   }
00068 
00069 
00070   /// @todo Insist that the current particle is post-hadronization, otherwise throw an exception?
00071   /// @todo Use recursion through replica-avoiding functions to avoid bookkeeping duplicates
00072   vector<Particle> Particle::allDescendants(const Cut& c, bool remove_duplicates) const {
00073     vector<Particle> rtn;
00074     if (isStable()) return rtn;
00075     /// @todo Remove this const mess crap when HepMC doesn't suck
00076     GenVertexPtr gv = const_cast<GenVertexPtr>( genParticle()->end_vertex() );
00077     if (gv == NULL) return rtn;
00078     /// @todo Would like to do this, but the range objects are broken
00079     // foreach (const GenParticlePtr gp, gv->particles(HepMC::descendants))
00080     for (GenVertex::particle_iterator it = gv->particles_begin(HepMC::descendants); it != gv->particles_end(HepMC::descendants); ++it) {
00081       const Particle p(*it);
00082       if (c != Cuts::OPEN && !c->accept(p)) continue;
00083       if (remove_duplicates && (*it)->end_vertex() != NULL) {
00084         // size_t n = 0; ///< @todo Only remove 1-to-1 duplicates?
00085         bool dup = false;
00086         /// @todo Yuck, HepMC
00087         for (GenVertex::particle_iterator it2 = (*it)->end_vertex()->particles_begin(HepMC::children); it2 != (*it)->end_vertex()->particles_end(HepMC::children); ++it2) {
00088           // n += 1; if (n > 1) break;
00089           if ((*it)->pdg_id() == (*it2)->pdg_id()) { dup = true; break; }
00090         }
00091         if (dup) continue;
00092       }
00093       rtn += p;
00094     }
00095     return rtn;
00096   }
00097 
00098 
00099   /// @todo Insist that the current particle is post-hadronization, otherwise throw an exception?
00100   vector<Particle> Particle::stableDescendants(const Cut& c) const {
00101     vector<Particle> rtn;
00102     if (isStable()) return rtn;
00103     /// @todo Remove this const mess crap when HepMC doesn't suck
00104     GenVertexPtr gv = const_cast<GenVertexPtr>( genParticle()->end_vertex() );
00105     if (gv == NULL) return rtn;
00106     /// @todo Would like to do this, but the range objects are broken
00107     // foreach (const GenParticlePtr gp, gv->particles(HepMC::descendants))
00108     for (GenVertex::particle_iterator it = gv->particles_begin(HepMC::descendants); it != gv->particles_end(HepMC::descendants); ++it) {
00109       // if ((*it)->status() != 1 || (*it)->end_vertex() != NULL) continue;
00110       const Particle p(*it);
00111       if (!p.isStable()) continue;
00112       if (c != Cuts::OPEN && !c->accept(p)) continue;
00113       rtn += p;
00114     }
00115     return rtn;
00116   }
00117 
00118 
00119   double Particle::flightLength() const {
00120     if (isStable()) return -1;
00121     if (genParticle() == NULL) return 0;
00122     if (genParticle()->production_vertex() == NULL) return 0;
00123     const HepMC::FourVector v1 = genParticle()->production_vertex()->position();
00124     const HepMC::FourVector v2 = genParticle()->end_vertex()->position();
00125     return sqrt(sqr(v2.x()-v1.x()) + sqr(v2.y()-v1.y()) + sqr(v2.z()-v1.z()));
00126   }
00127 
00128 
00129   bool Particle::hasParent(PdgId pid) const {
00130     return _hasRelativeWith(HepMC::parents, hasPID(pid));
00131   }
00132 
00133   bool Particle::hasParentWith(const Cut& c) const {
00134     return hasParentWith([&](const Particle& p){return c->accept(p);});
00135   }
00136 
00137 
00138   bool Particle::hasAncestor(PdgId pid) const {
00139     return _hasRelativeWith(HepMC::ancestors, hasPID(pid));
00140   }
00141 
00142   bool Particle::hasAncestorWith(const Cut& c) const {
00143     return hasAncestorWith([&](const Particle& p){return c->accept(p);});
00144   }
00145 
00146 
00147   bool Particle::fromBottom() const {
00148     return _hasRelativeWith(HepMC::ancestors, [](const Particle& p){
00149         return p.genParticle()->status() == 2 && p.isHadron() && p.hasBottom();
00150       });
00151     // const GenVertexPtr prodVtx = genParticle()->production_vertex();
00152     // if (prodVtx == NULL) return false;
00153     // foreach (const GenParticlePtr ancestor, particles(prodVtx, HepMC::ancestors)) {
00154     //   const PdgId pid = ancestor->pdg_id();
00155     //   if (ancestor->status() == 2 && (PID::isHadron(pid) && PID::hasBottom(pid))) return true;
00156     // }
00157     // return false;
00158   }
00159 
00160 
00161   bool Particle::fromCharm() const {
00162     return _hasRelativeWith(HepMC::ancestors, [](const Particle& p){
00163         return p.genParticle()->status() == 2 && p.isHadron() && p.hasCharm();
00164       });
00165     // const GenVertexPtr prodVtx = genParticle()->production_vertex();
00166     // if (prodVtx == NULL) return false;
00167     // foreach (const GenParticlePtr ancestor, particles(prodVtx, HepMC::ancestors)) {
00168     //   const PdgId pid = ancestor->pdg_id();
00169     //   if (ancestor->status() == 2 && (PID::isHadron(pid) && PID::hasCharm(pid) && !PID::hasBottom(pid))) return true;
00170     // }
00171     // return false;
00172   }
00173 
00174 
00175   bool Particle::fromHadron() const {
00176     return _hasRelativeWith(HepMC::ancestors, [](const Particle& p){
00177         return p.genParticle()->status() == 2 && p.isHadron();
00178       });
00179     // const GenVertexPtr prodVtx = genParticle()->production_vertex();
00180     // if (prodVtx == NULL) return false;
00181     // foreach (const GenParticlePtr ancestor, particles(prodVtx, HepMC::ancestors)) {
00182     //   const PdgId pid = ancestor->pdg_id();
00183     //   if (ancestor->status() == 2 && PID::isHadron(pid)) return true;
00184     // }
00185     // return false;
00186   }
00187 
00188 
00189   bool Particle::fromTau(bool prompt_taus_only) const {
00190     if (prompt_taus_only && fromHadron()) return false;
00191     return _hasRelativeWith(HepMC::ancestors, [](const Particle& p){
00192         return p.genParticle()->status() == 2 && isTau(p);
00193       });
00194     // const GenVertexPtr prodVtx = genParticle()->production_vertex();
00195     // if (prodVtx == NULL) return false;
00196     // foreach (const GenParticlePtr ancestor, particles(prodVtx, HepMC::ancestors)) {
00197     //   const PdgId pid = ancestor->pdg_id();
00198     //   if (ancestor->status() == 2 && abs(pid) == PID::TAU) return true;
00199     // }
00200     // return false;
00201   }
00202 
00203 
00204   // bool Particle::fromDecay() const {
00205   //   const GenVertexPtr prodVtx = genParticle()->production_vertex();
00206   //   if (prodVtx == NULL) return false;
00207   //   foreach (const GenParticlePtr ancestor, particles(prodVtx, HepMC::ancestors)) {
00208   //     const PdgId pid = ancestor->pdg_id();
00209   //     if (ancestor->status() == 2 && (PID::isHadron(pid) || abs(pid) == PID::TAU)) return true;
00210   //   }
00211   //   return false;
00212   // }
00213 
00214 
00215   bool Particle::isPrompt(bool allow_from_prompt_tau, bool allow_from_prompt_mu) const {
00216     if (genParticle() == NULL) return false; // no HepMC connection, give up! Throw UserError exception?
00217     const GenVertexPtr prodVtx = genParticle()->production_vertex();
00218     if (prodVtx == NULL) return false; // orphaned particle, has to be assume false
00219     const pair<GenParticlePtr, GenParticlePtr> beams = prodVtx->parent_event()->beam_particles();
00220 
00221     /// @todo Would be nicer to be able to write this recursively up the chain, exiting as soon as a parton or string/cluster is seen
00222     for (const GenParticlePtr ancestor : Rivet::particles(prodVtx, HepMC::ancestors)) {
00223       const PdgId pid = ancestor->pdg_id();
00224       if (ancestor->status() != 2) continue; // no non-standard statuses or beams to be used in decision making
00225       if (ancestor == beams.first || ancestor == beams.second) continue; // PYTHIA6 uses status 2 for beams, I think... (sigh)
00226       if (PID::isParton(pid)) continue; // PYTHIA6 also uses status 2 for some partons, I think... (sigh)
00227       if (PID::isHadron(pid)) return false; // prompt particles can't be from hadron decays
00228       if (abs(pid) == PID::TAU && abspid() != PID::TAU && !allow_from_prompt_tau) return false; // allow or ban particles from tau decays (permitting tau copies)
00229       if (abs(pid) == PID::MUON && abspid() != PID::MUON && !allow_from_prompt_mu) return false; // allow or ban particles from muon decays (permitting muon copies)
00230     }
00231     return true;
00232   }
00233 
00234 
00235 
00236   ///////////////////////
00237 
00238 
00239 
00240   string to_str(const Particle& p) {
00241     string pname;
00242     try {
00243       pname = PID::toParticleName(p.pid());
00244     } catch (...) {
00245       pname = "PID=" + to_str(p.pid());
00246     }
00247     stringstream out;
00248     out << pname << " @ " << p.momentum() << " GeV";
00249     return out.str();
00250   }
00251 
00252 
00253   string to_str(const ParticlePair& pair) {
00254     stringstream out;
00255     out << "[" << pair.first << ", " << pair.second << "]";
00256     // out << "["
00257     //     << PID::toParticleName(pair.first.pid()) << " @ "
00258     //     << pair.first.momentum().E()/GeV << " GeV, "
00259     //     << PID::toParticleName(pair.second.pid()) << " @ "
00260     //     << pair.second.momentum().E()/GeV << " GeV]";
00261     return out.str();
00262   }
00263 
00264 
00265 
00266 }