CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_5/src/RecoJets/FFTJetProducers/plugins/FFTJetPFPileupCleaner.cc

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 //
00003 // Package:    FFTJetProducers
00004 // Class:      FFTJetPFPileupCleaner
00005 // 
00013 //
00014 // Original Author:  Igor Volobouev
00015 //         Created:  Thu Jul 14 17:50:33 CDT 2011
00016 // $Id: FFTJetPFPileupCleaner.cc,v 1.5 2012/06/22 07:23:21 igv Exp $
00017 //
00018 //
00019 #include <cmath>
00020 #include <climits>
00021 #include <utility>
00022 #include <algorithm>
00023 
00024 // framework include files
00025 #include "FWCore/Framework/interface/Frameworkfwd.h"
00026 #include "FWCore/Framework/interface/EDProducer.h"
00027 #include "FWCore/Framework/interface/Event.h"
00028 #include "FWCore/Framework/interface/MakerMacros.h"
00029 #include "FWCore/Utilities/interface/Exception.h"
00030 #include "FWCore/ParameterSet/interface/ParameterSet.h"
00031 
00032 #include "DataFormats/Common/interface/View.h"
00033 #include "DataFormats/Common/interface/Handle.h"
00034 
00035 #include "DataFormats/ParticleFlowCandidate/interface/PFCandidate.h"
00036 #include "DataFormats/ParticleFlowCandidate/interface/PFCandidateFwd.h"
00037 
00038 #include "DataFormats/VertexReco/interface/Vertex.h"
00039 #include "DataFormats/VertexReco/interface/VertexFwd.h"
00040 
00041 #define init_param(type, varname) varname (ps.getParameter< type >( #varname ))
00042 
00043 //
00044 // class declaration
00045 //
00046 class FFTJetPFPileupCleaner : public edm::EDProducer
00047 {
00048 public:
00049     explicit FFTJetPFPileupCleaner(const edm::ParameterSet&);
00050     ~FFTJetPFPileupCleaner();
00051 
00052 protected:
00053     // methods
00054     void beginJob();
00055     void produce(edm::Event&, const edm::EventSetup&);
00056     void endJob();
00057 
00058 private:
00059     FFTJetPFPileupCleaner();
00060     FFTJetPFPileupCleaner(const FFTJetPFPileupCleaner&);
00061     FFTJetPFPileupCleaner& operator=(const FFTJetPFPileupCleaner&);
00062 
00063     bool isRemovable(reco::PFCandidate::ParticleType ptype) const;
00064     void setRemovalBit(reco::PFCandidate::ParticleType ptype, bool onOff);
00065     void buildRemovalMask();
00066     bool isAcceptableVtx(reco::VertexCollection::const_iterator iv) const;
00067 
00068     reco::VertexRef findSomeVertexWFakes(
00069         const edm::Handle<reco::VertexCollection>& vertices,
00070         const edm::Handle<reco::VertexCollection>& fakeVertices,
00071         const reco::PFCandidate& pfcand, bool* fromFakeSet) const;
00072 
00073     edm::InputTag PFCandidates;
00074     edm::InputTag Vertices;
00075     edm::InputTag FakePrimaryVertices;
00076 
00077     // The following, if true, will switch to an algorithm
00078     // which takes a fake primary vertex into account
00079     bool useFakePrimaryVertex;
00080 
00081     // The following, if true, will cause association of a candidate
00082     // with some vertex no matter what
00083     bool checkClosestZVertex;
00084 
00085     // The following switch will check if the primary vertex
00086     // is a neighbor (in Z) of a track and will keep the
00087     // track if this is so, even if it is not directly associated
00088     // with the primary vertex. This switch is meaningful only if
00089     // "checkClosestZVertex" is true.
00090     bool keepIfPVneighbor;
00091 
00092     // The following, if true, will cause removal of candidates
00093     // associated with the main vertex
00094     bool removeMainVertex;
00095 
00096     // The following will tell us to remove candidates not associated
00097     // with any vertex
00098     bool removeUnassociated;
00099 
00100     // Do we want to reverse the decision?
00101     bool reverseRemovalDecision;
00102 
00103     // Flags for removing things. See PFCandidate header
00104     // for particle types.
00105     bool remove_X;         // undefined
00106     bool remove_h;         // charged hadron
00107     bool remove_e;         // electron
00108     bool remove_mu;        // muon
00109     bool remove_gamma;     // photon
00110     bool remove_h0;        // neutral hadron
00111     bool remove_h_HF;      // HF tower identified as a hadron
00112     bool remove_egamma_HF; // HF tower identified as an EM particle
00113 
00114     // Mask for removing things
00115     unsigned removalMask;
00116 
00117     // Min and max eta for keeping things
00118     double etaMin;
00119     double etaMax;
00120 
00121     // Cut for the vertex Ndof
00122     double vertexNdofCut;
00123 
00124     // Cut for the vertex Z
00125     double vertexZmaxCut;
00126 
00127     // Vector for associating tracks with Z positions of the vertices
00128     mutable std::vector<std::pair<double, unsigned> > zAssoc;
00129 };
00130 
00131 //
00132 // constructors and destructor
00133 //
00134 FFTJetPFPileupCleaner::FFTJetPFPileupCleaner(const edm::ParameterSet& ps)
00135     : init_param(edm::InputTag, PFCandidates),
00136       init_param(edm::InputTag, Vertices),
00137       init_param(edm::InputTag, FakePrimaryVertices),
00138       init_param(bool, useFakePrimaryVertex),
00139       init_param(bool, checkClosestZVertex),
00140       init_param(bool, keepIfPVneighbor),
00141       init_param(bool, removeMainVertex),
00142       init_param(bool, removeUnassociated),
00143       init_param(bool, reverseRemovalDecision),
00144       init_param(bool, remove_X        ),
00145       init_param(bool, remove_h        ),
00146       init_param(bool, remove_e        ),
00147       init_param(bool, remove_mu       ),
00148       init_param(bool, remove_gamma    ),
00149       init_param(bool, remove_h0       ),
00150       init_param(bool, remove_h_HF     ),
00151       init_param(bool, remove_egamma_HF),
00152       removalMask(0),
00153        init_param(double, etaMin),
00154       init_param(double, etaMax),
00155       init_param(double, vertexNdofCut),
00156       init_param(double, vertexZmaxCut)
00157 {
00158     buildRemovalMask();
00159     produces<reco::PFCandidateCollection>();
00160 }
00161 
00162 
00163 FFTJetPFPileupCleaner::~FFTJetPFPileupCleaner()
00164 {
00165 }
00166 
00167 
00168 bool FFTJetPFPileupCleaner::isAcceptableVtx(
00169     reco::VertexCollection::const_iterator iv) const
00170 {
00171     return !iv->isFake() &&
00172             static_cast<double>(iv->ndof()) > vertexNdofCut &&
00173             std::abs(iv->z()) < vertexZmaxCut;
00174 }
00175 
00176 
00177 // ------------ method called to produce the data  ------------
00178 void FFTJetPFPileupCleaner::produce(
00179     edm::Event& iEvent, const edm::EventSetup& iSetup)
00180 {
00181     // get PFCandidates
00182     std::auto_ptr<reco::PFCandidateCollection> 
00183         pOutput(new reco::PFCandidateCollection);
00184 
00185     edm::Handle<reco::PFCandidateCollection> pfCandidates;
00186     iEvent.getByLabel(PFCandidates, pfCandidates);
00187 
00188     // get vertices
00189     edm::Handle<reco::VertexCollection> vertices;
00190     iEvent.getByLabel(Vertices, vertices);
00191 
00192     edm::Handle<reco::VertexCollection> fakeVertices;
00193     if (useFakePrimaryVertex)
00194     {
00195         iEvent.getByLabel(FakePrimaryVertices, fakeVertices);
00196         if (!fakeVertices.isValid())
00197             throw cms::Exception("FFTJetBadConfig")
00198                 << "ERROR in FFTJetPFPileupCleaner:"
00199                 " could not find fake vertices"
00200                 << std::endl;
00201     }
00202 
00203     const unsigned ncand = pfCandidates->size();
00204     for (unsigned i=0; i<ncand; ++i)
00205     {
00206         reco::PFCandidatePtr candptr(pfCandidates, i);
00207         bool remove = false;
00208 
00209         if (isRemovable(candptr->particleId()))
00210         {
00211             bool fromFakeSet = false;
00212             reco::VertexRef vertexref(findSomeVertexWFakes(vertices, fakeVertices,
00213                                                            *candptr, &fromFakeSet));
00214             if (vertexref.isNull())
00215             {
00216                 // Track is not associated with any vertex 
00217                 // in any of the vertex sets
00218                 remove = removeUnassociated;
00219             }
00220             else if (vertexref.key() == 0 && 
00221                      (!useFakePrimaryVertex || fromFakeSet))
00222             {
00223                 // Track is associated with the main primary vertex
00224                 // However, if we are using fake vertices, this only
00225                 // matters if the vertex comes from the fake set. If
00226                 // it comes from the real set, remove the track anyway
00227                 // because in the combined set the associated vertex
00228                 // would not be the main primary vertex.
00229                 remove = removeMainVertex;
00230             }
00231             else
00232                 remove = true;
00233         }
00234 
00235         // Check the eta range
00236         if (!remove)
00237         {
00238             const double eta = candptr->p4().Eta();
00239             remove = eta < etaMin || eta > etaMax;
00240         }
00241 
00242         // Should we remember this candidate?
00243         if (reverseRemovalDecision)
00244             remove = !remove;
00245         if (!remove)
00246         {
00247             const reco::PFCandidate& cand = (*pfCandidates)[i];
00248             pOutput->push_back(cand);
00249             pOutput->back().setSourceCandidatePtr(candptr);
00250         }
00251     }
00252 
00253     iEvent.put(pOutput);
00254 }
00255 
00256 
00257 bool FFTJetPFPileupCleaner::isRemovable(
00258     const reco::PFCandidate::ParticleType ptype) const
00259 {
00260     const unsigned shift = static_cast<unsigned>(ptype);
00261     assert(shift < 32U);
00262     return removalMask & (1U << shift);
00263 }
00264 
00265 
00266 void FFTJetPFPileupCleaner::setRemovalBit(
00267     const reco::PFCandidate::ParticleType ptype, const bool value)
00268 {
00269     const unsigned shift = static_cast<unsigned>(ptype);
00270     assert(shift < 32U);
00271     const unsigned mask = (1U << shift);
00272     if (value)
00273         removalMask |= mask;
00274     else
00275         removalMask &= ~mask;
00276 }
00277 
00278 
00279 // The following essentially follows the code in PFPileUp.cc,
00280 // with added cut on ndof, vertex Z position, and iteration
00281 // over fakes
00282 reco::VertexRef FFTJetPFPileupCleaner::findSomeVertexWFakes(
00283     const edm::Handle<reco::VertexCollection>& vertices,
00284     const edm::Handle<reco::VertexCollection>& fakeVertices,
00285     const reco::PFCandidate& pfcand, bool* fromFakeSet) const
00286 {
00287     typedef reco::VertexCollection::const_iterator IV;
00288     typedef reco::Vertex::trackRef_iterator IT;
00289 
00290     *fromFakeSet = false;
00291     reco::TrackBaseRef trackBaseRef(pfcand.trackRef());
00292 
00293     size_t iVertex = 0;
00294     unsigned nFoundVertex = 0;
00295     const IV vertend(vertices->end());
00296 
00297     {
00298         unsigned index = 0;
00299         double bestweight = 0.0;
00300         for (IV iv=vertices->begin(); iv!=vertend; ++iv, ++index)
00301             if (isAcceptableVtx(iv))
00302             {
00303                 const reco::Vertex& vtx = *iv;
00304 
00305                 // loop on tracks in vertices
00306                 IT trackend(vtx.tracks_end());
00307                 for (IT iTrack=vtx.tracks_begin(); iTrack!=trackend; ++iTrack)
00308                 {
00309                     const reco::TrackBaseRef& baseRef = *iTrack;
00310 
00311                     // one of the tracks in the vertex is the same as 
00312                     // the track considered in the function
00313                     if (baseRef == trackBaseRef)
00314                     {
00315                         // select the vertex for which the track has the highest weight
00316                         const double w = vtx.trackWeight(baseRef);
00317                         if (w > bestweight)
00318                         {
00319                             bestweight=w;
00320                             iVertex=index;
00321                             nFoundVertex++;
00322                         }       
00323                     }
00324                 }
00325             }
00326     }
00327 
00328     if (nFoundVertex > 0)
00329     {
00330         if (nFoundVertex != 1)
00331             edm::LogWarning("TrackOnTwoVertex")
00332                 << "a track is shared by at least two vertices. "
00333                 << "Used to be an assert";
00334 
00335         // Check if we can re-associate this track with one
00336         // of the fake vertices
00337         if (useFakePrimaryVertex)
00338         {
00339             const double ztrack = pfcand.vertex().z();
00340             double dzmin = std::abs(ztrack - ((*vertices)[iVertex]).z());
00341 
00342             const IV fakeEnd(fakeVertices->end());
00343             unsigned index = 0;
00344             for (IV iv=fakeVertices->begin(); iv!=fakeEnd; ++iv, ++index)
00345                 if (isAcceptableVtx(iv))
00346                 {
00347                     const double dz = std::abs(ztrack - iv->z());
00348                     if (dz < dzmin)
00349                     {
00350                         dzmin = dz; 
00351                         iVertex = index;
00352                         *fromFakeSet = true;
00353                     }
00354                 }
00355         }
00356 
00357         return reco::VertexRef(*fromFakeSet ? fakeVertices : vertices, iVertex);
00358     }
00359 
00360     // optional: as a secondary solution, associate the closest vertex in z
00361     if (checkClosestZVertex) 
00362     {
00363         const double ztrack = pfcand.vertex().z();
00364         bool foundVertex = false;
00365 
00366         if (keepIfPVneighbor)
00367         {
00368             // Sort all vertices according to their Z coordinate
00369             zAssoc.clear();
00370             unsigned index = 0;
00371             for (IV iv=vertices->begin(); iv!=vertend; ++iv, ++index)
00372                 if (isAcceptableVtx(iv))
00373                     zAssoc.push_back(std::pair<double,unsigned>(iv->z(), index));
00374             const unsigned numRealVertices = index;
00375 
00376             // Mix the fake vertex collection into zAssoc.
00377             // Note that we do not reset "index" before doing this.
00378             if (useFakePrimaryVertex)
00379             {
00380                 const IV fakeEnd(fakeVertices->end());
00381                 for (IV iv=fakeVertices->begin(); iv!=fakeEnd; ++iv, ++index)
00382                     if (isAcceptableVtx(iv))
00383                         zAssoc.push_back(std::pair<double,unsigned>(iv->z(), index));
00384             }
00385 
00386             // Check where the track z position fits into this sequence
00387             if (!zAssoc.empty())
00388             {
00389                 std::sort(zAssoc.begin(), zAssoc.end());
00390                 std::pair<double,unsigned> tPair(ztrack, UINT_MAX);
00391                 const unsigned iAbove = std::upper_bound(
00392                     zAssoc.begin(), zAssoc.end(), tPair) - zAssoc.begin();
00393 
00394                 // Check whether one of the vertices with indices
00395                 // iAbove or (iAbove - 1) is a primary vertex.
00396                 // If so, return it. Otherwise return the one
00397                 // with closest distance to the track.
00398                 unsigned ich[2] = {0U, 0U};
00399                 unsigned nch = 1;
00400                 if (iAbove)
00401                 {
00402                     ich[0] = iAbove - 1U;
00403                     ich[1] = iAbove;
00404                     if (iAbove < zAssoc.size())
00405                         nch = 2;
00406                 }
00407 
00408                 double dzmin = 1.0e100;
00409                 unsigned bestVertexNum = UINT_MAX;
00410                 for (unsigned icheck=0; icheck<nch; ++icheck)
00411                 {
00412                     const unsigned zAssocIndex = ich[icheck];
00413                     const unsigned vertexNum = zAssoc[zAssocIndex].second;
00414 
00415                     if (vertexNum == numRealVertices || 
00416                         (!useFakePrimaryVertex && vertexNum == 0U))
00417                     {
00418                         bestVertexNum = vertexNum;
00419                         break;
00420                     }
00421 
00422                     const double dz = std::abs(ztrack - zAssoc[zAssocIndex].first);
00423                     if (dz < dzmin)
00424                     {
00425                         dzmin = dz; 
00426                         bestVertexNum = vertexNum;
00427                     }
00428                 }
00429 
00430                 foundVertex = bestVertexNum < UINT_MAX;
00431                 if (foundVertex)
00432                 {
00433                     iVertex = bestVertexNum;
00434                     if (iVertex >= numRealVertices)
00435                     {
00436                         *fromFakeSet = true;
00437                         iVertex -= numRealVertices;
00438                     }
00439                 }
00440             }
00441         }
00442         else
00443         {
00444             // This is a simple association algorithm (from PFPileUp)
00445             // extended to take fake vertices into account
00446             double dzmin = 1.0e100;
00447             unsigned index = 0;
00448             for (IV iv=vertices->begin(); iv!=vertend; ++iv, ++index)
00449                 if (isAcceptableVtx(iv))
00450                 {
00451                     const double dz = std::abs(ztrack - iv->z());
00452                     if (dz < dzmin)
00453                     {
00454                         dzmin = dz; 
00455                         iVertex = index;
00456                         foundVertex = true;
00457                     }
00458                 }
00459 
00460             if (useFakePrimaryVertex)
00461             {
00462                 const IV fakeEnd(fakeVertices->end());
00463                 index = 0;
00464                 for (IV iv=fakeVertices->begin(); iv!=fakeEnd; ++iv, ++index)
00465                     if (isAcceptableVtx(iv))
00466                     {
00467                         const double dz = std::abs(ztrack - iv->z());
00468                         if (dz < dzmin)
00469                         {
00470                             dzmin = dz; 
00471                             iVertex = index;
00472                             *fromFakeSet = true;
00473                             foundVertex = true;
00474                        }
00475                     }
00476             }
00477         }
00478 
00479         if (foundVertex) 
00480             return reco::VertexRef(*fromFakeSet ? fakeVertices : vertices, iVertex);
00481     }
00482 
00483     return reco::VertexRef();
00484 }
00485 
00486 
00487 void FFTJetPFPileupCleaner::buildRemovalMask()
00488 {
00489     setRemovalBit(reco::PFCandidate::X,         remove_X        );
00490     setRemovalBit(reco::PFCandidate::h,         remove_h        );
00491     setRemovalBit(reco::PFCandidate::e,         remove_e        );
00492     setRemovalBit(reco::PFCandidate::mu,        remove_mu       );
00493     setRemovalBit(reco::PFCandidate::gamma,     remove_gamma    );
00494     setRemovalBit(reco::PFCandidate::h0,        remove_h0       );
00495     setRemovalBit(reco::PFCandidate::h_HF,      remove_h_HF     );
00496     setRemovalBit(reco::PFCandidate::egamma_HF, remove_egamma_HF);
00497 }
00498 
00499 
00500 // ------------ method called once each job just before starting event loop
00501 void FFTJetPFPileupCleaner::beginJob()
00502 {
00503 }
00504 
00505 
00506 // ------------ method called once each job just after ending the event loop
00507 void FFTJetPFPileupCleaner::endJob()
00508 {
00509 }
00510 
00511 
00512 //define this as a plug-in
00513 DEFINE_FWK_MODULE(FFTJetPFPileupCleaner);