4.7 MiniAOD Analysis Documentation - 2017 VERSION UNDER CONSTRUCTION

This page documents the MiniAOD data tier as it is implemented for 2017 run and legacy 2016 miniaod ; the documentation for the 2015 and 2016 versions is in WorkBookMiniAOD2015 and WorkBookMiniAOD2016, that for the version used in CSA14 and Phys14 is in WorkBookMiniAOD2014

This version of MiniAOD is planned to be used for:

  • 2017 data
  • legacy reminiaod of 2016 data and MC (some new features of miniaod 2017 are not available in the the 2016 legacy re-processing)
  • See WorkBookMiniAOD for a comprehensive list of different versions and associated campaigns and CMSSW recommended releases and global tags to use.

Compared to 2016 version of miniAOD several improvement have been introduced to cover a broader range of analyses, including for example BPH and EXO PAGs needs. A detailed list of PRs of recently integrated features is available at MiniAODPhase1

Introduction

The MiniAOD format

The MiniAOD is a new high-level data tier introduced in Spring 2014 to serve the needs of the mainstream physics analyses while keeping a small event size (30-50 kb/event).

The main contents of the MiniAOD are:

  • High level physics objects (leptons, photons, jets, ETmiss), with detailed information in order to allow e.g. retuning of identification criteria, saved using PAT dataformats.
    Some preselection requirements are applied on the objects, and objects failing these requirements are either not stored or stored only with a more limited set of information.
    Some high level corrections are applied: L1+L2+L3(+residual) corrections to jets, type1 corrections to ETmiss.
  • The full list of particles reconstructed by the ParticleFlow, though only storing the most basic quantities for each object (4-vector, impact parameter, pdg id, some quality flags), and with reduced numerical precision; these are useful to recompute isolation, or to perform jet substructure studies.
    For charged particles with pT > 0.9 GeV, more information about the associated track is saved, including the covariance matrix, so that they can be used for b-tagging purposes.
  • MC Truth information: a subset of the genParticles enough to describe the hard scattering process, jet flavour information, and final state leptons and photons; GenJets with pT > 8 GeV are also stored, and so are the other mc summary information (e.g event weight, LHE header, PDF, PU information).
    In addition, all the stable genParticles with mc status code 1 are also saved, to allow reclustering of GenJets with different algorithms and substructure studies.
  • Trigger information: MiniAOD contains the trigger bits associated to all paths, and all the trigger objects that have contributed to firing at least one filter within the trigger. In addition, we store all objects reconstructed at L1 and the L1 global trigger summary, and the prescale values of all the triggers.

Structure of this documentation

This documentation will focus on analyzing MiniAOD files, since the production of MiniAODs is normally done centrally (but in the last part some instructions will be given also on how to produce MiniAOD files privately). The examples will be given both in the context of full CMSSW running using EDAnalyzers and in the context of FWLite with python whenever applicable. FWLite in C++ is of course also supported, but it's up to the reader to guess what the code should be starting from the two examples.

The color scheme of the twikipage is as follows:

  • Shell commands will be embedded in grey box, e.g.
    cmsrel CMSSW_9_2_4
  • Python code will be embedded in light blue box, e.g.
from DataFormats.FWLite import Handle, Events 
  • C++ code will be embedded in light green box, e.g.
iEvent.getByToken(muons_, muons); 
  • Example output will be in a yellow box, e.g.
    boh?

Setting up your environment

The documentation will use the CMSSW_9_2_4 release and assume you're working on a SLC6 node (e.g. lxplus.cern.ch) . To setup the release, you can do

cmsrel CMSSW_9_2_4
cd CMSSW_9_2_4/src
cmsenv

As input test files in the examples we will use /store/relval/CMSSW_8_0_3/RelValTTbarLepton_13/MINIAODSIM/80X_mcRun2_asymptotic_2016_v3_gs7120p2NewGTv3-v1/00000/4E291B64-DCEF-E511-B99D-0025905A60B0.root which contains 6k events of ttbar production, but any other MINIAODSIM file will work equally well.

Skeleton for CMSSW Analysis

To create a skeleton of c++ analyzer, you can do the following

mkdir Test
cd Test
mkedanlzr MiniAnalyzer

New package "MiniAnalyzer" of EDAnalyzer type is successfully generated
MiniAnalyzer/
|  plugins/
|  |-- BuildFile.xml
|  |-- MiniAnalyzer.cc
|  python/
|  |-- CfiFile_cfi.py
|  |-- ConfFile_cfg.py
|  test/
|  doc/
Total: 4 directories, 4 files

Then you'll need to edit the BuildFile.xml to add a <use name="DataFormats/PatCandidates"/>

Skeleton for Python FWLite Analysis

# import ROOT in batch mode
import sys
oldargv = sys.argv[:]
sys.argv = [ '-b-' ]
import ROOT
ROOT.gROOT.SetBatch(True)
sys.argv = oldargv

# load FWLite C++ libraries
ROOT.gSystem.Load("libFWCoreFWLite.so");
ROOT.gSystem.Load("libDataFormatsFWLite.so");
ROOT.FWLiteEnabler.enable()

# load FWlite python libraries
from DataFormats.FWLite import Handle, Events

# open file (you can use 'edmFileUtil -d /store/whatever.root' to get the physical file name)
events = Events("root://eoscms//eos/cms/store/relval/CMSSW_8_0_3/RelValTTbarLepton_13/MINIAODSIM/80X_mcRun2_asymptotic_2016_v3_gs7120p2NewGTv3-v1/00000/4E291B64-DCEF-E511-B99D-0025905A60B0.root")

for i,event in enumerate(events):
    print "\nEvent", i
    if i > 10: break

Analyzing MiniAOD

High level physics objects

High level physics objects in miniAOD are saved in the PAT dataformats, which in turn derive from the RECO/AOD formats, so almost everything that you can find in the WorkBook documentation on PAT and physics objects applies to them direcly.

Object Label C++ class Selection Detailed information
Muons slimmedMuons std::vector<pat::Muon> includes muons with pT > 5 GeV or that pass the PF muon ID (see below) All standard muon ID and isolations, the associated tracker, outer and global tracks, muonBestTrack and tunePMuonBestTrack
Electrons slimmedElectrons std::vector<pat::Electron> all gedGsfElectrons electrons For electrons of pT > 5 GeV, full information is saved (supercluster, seed cluster, interesting rechits, isolation and id variables).
For electrons below the threshold, only the superCluster and seedCluster are provided, and the id and isolation variables are zeroed out to save space
Taus slimmedTaus std::vector<pat::Tau> taus from hpsPFTauProducer with pT > 18 GeV, and passing the basic decayModeFindingNewDMs id All POG-supported tau id discriminators are included. Links to the PF candidates are also provided.
Note: different miniAOD version use different tau reconstructions, see below in the Tau entry
slimmedTausBoosted NEW std::vector<pat::Tau> taus from boosted tau reconstruction seeded by subjets (instead of jets) from hpsPFTauProducer with pT > 18 GeV, and passing the basic decayModeFindingNewDMs id All id discriminators of standard taus are available also for boosted taus see below in the Tau entry
Photons slimmedPhotons std::vector<pat::Photon> gedPhotons with pT > 14 GeV and hadTowOverEm() < 0.15
Since 74X In version 2 MiniAOD, keep also pt 10-14 GeV if chargedHadronIso() < 10
For photons that pass a minimal r9 or isolation cut, full information is saved (supercluster, seed cluster, interesting rechits, isolation and id variables).
The requirement is the logical or of the three conditions r9()>0.8 , chargedHadronIso()<20, chargedHadronIso()<0.3*pt()
oniaPhotonCandidates NEW std::vector<pat::CompositeCandidate> Conversions with highPurity or generalTracksOnly quality, rho > 1.5 cm Loe energy conversions for reconstruction of radiative decays are store, electron tracks are store as reco::Track
Jets slimmedJets std::vector<pat::Jet> ak4PFJetsCHS with pT > 10 GeV L1+L2+L3+residual corrections are applied; b-tagging and pileup jet id information are embedded. Links are provided to the constituent PF candidates.
slimmedJetsPuppi std::vector<pat::Jet> puppi jets with pT > 20 GeV L1+L2+L3+residual corrections are applied; b-tagging information is embedded. Links are provided to the constituent PF candidates.
slimmedGenJets std::vector<reco::GenJet> ak4GenJetsNoNu with pT > 8 GeV links to constituents (packed gen particles) are available
slimmedJetsAK8 std::vector<pat::Jet> ak8PFJetsPUPPI with pT > 170 GeV (for substructure) L1+L2+L3+residual corrections are applied (AK8PFPuppi corrections used); some precomputed substructure info is provided, and also links to the constituent PF candidates. Subjets themselves are also stored.
slimmedJetsAK8PFPuppiSoftDropPacked std::vector<pat::Jet> Subjets of PUPPI soft drop algorithm L1+L2+L3+residual corrections are applied (AK4PFpuppi corrections used); b-tagging information is embedded. Links are provided to the constituent PF candidates.
slimmedGenJetsAK8 std::vector<reco::GenJet> ak8GenJetsNoNu with pT > 150 GeV links to constituents (packed gen particles) are available
MET slimmedMETs std::vector<pat::MET> the type1 PF MET MET uncertainties are provided
Contains also the calo, raw pf and gen met values.
slimmedMETsNoHF std::vector<pat::MET> as above but excluding HF;  
slimmedMETsPuppi std::vector<pat::MET> puppi-corrected MET MET computed using the PFCandidate 4-vectors weighted with their puppi weights

Muons UPDATED

Muons from the AOD muons collection are included in MiniAOD if they pass at least one of these three requirements:

  • pT > 5 GeV
  • pT > 3 GeV and any of the following IDs: PF, global, arbitrated tracker, standalone, RPCMuLoose
  • any pT, if they pass the PF ID.

Muon id information is available and accessible as usual through the isLooseMuon, isTightMuon, isSoftMuon, isHighPtMuon and muonID methods as provided in the pat::Muon class.

The following tracks are embedded by value in the pat::Muon, if available: tracker, outer and global tracks, muonBestTrack and typePMuonBestTrack. DYT and TeV-muon refits are also available for muons with pt > 100 GeV

The ECal energy associated to the PF Muon is also stored, accessible as muon.pfEcalEnergy() . This has been used in some analyses, e.g. H→ZZ→4l, for collinear FSR recovery.

UPDATED Segments in DT and CSC are stored for Muon with pt > 50 GeV starting from MiniAOD2017, in addition a reduction of the floating point precision of the matching information is introduced.

Electrons TODO

All gedGsfElectrons electrons are saved.

For electrons of pT > 5 GeV, detailed information is saved:

  • Supercluster, basic clusters and seed clusters, accessible through the reco::GsfElectron information (though they're stored externally in the reducedEgamma collections). The final superclusters and clusters are saved, not also the intermediate unrefined "PF" superclusters and clusters.
  • Interesting rechits, saved in reducedEGamma:reducedEBRecHits, reducedEGamma:reducedEERecHits, reducedEGamma:reducedESRecHits for barrel, endcap and pre-showers respectively.
  • Shower shape variables computed from the standard superclusters are provided in the basic reco::GsfElectron interface, e.g. sigmaIetaIeta() (the only missing one in AOD is sigmaIetaIphi() which is added in pat::Electron interface).
    In addition, for backwards compatibility MiniAOD also includes the shower shape variables computed using the full 5x5 superclusters like in Run 1, which are accessible through the pat::Electron methods, e.g. full5x5_sigmaIetaIeta().
  • Isolation computed from PF Clusters, similar to what done in the HLT, is also available through the methods ele.ecalPFClusterIso() and ele.hcalPFClusterIso()
  • The set of embedded electron IDs and discriminators includes TODO: EGAMMA please fill in this

For electrons that don't satisfy this cut, only the supercluster and seed clusters are provided.

TODO TODO: changes in Gsf

Photons TODO

For photons, the source collection is the gedPhotons, with two levels of selection:

  • A basic selection defining which objects are kept: pT > 14 GeV and hadTowOverEm() < 0.15 ; photons with pT 10-14 GeV are also lept, if they satisfy hadTowOverEm() < 0.15 && chargedHadronIso()<10
  • A tighter selection defining for which objects the detailed information is kept: it's the logical or of a R9 requirement r9()>0.8 , and an absolute and relative isolation cuts done with charged hadrons only, chargedHadronIso()<20, chargedHadronIso()<0.3*pt()

Similarly to electrons, the basic information is only the supercluster and seed clusters, while the detailed information includes basic clusters and interesting rechits.

Note that electrons and photons share a common collection of interesting clusters and rechits, and so if the same supercluster gives rise to both an electron and a photon the two high-level physics objects will really reference to the same object (as it happens in AOD). For more technical details, refer to reducedEgamma_cfi.py

  • The set of embedded electron IDs and discriminators includes TODO: EGAMMA please fill in this

TODO: Out of time photons

NEW Photon conversion with basic information on p4, and vertex are stored, daughter tracks are store as UserData<reco::Track>, quality flags for TkVtxCompatibility, CompatibleInnerHits, Highpurity, pizero_rejected, large_pizero_window, Conversion Algorithm, are packed as single bit for each flag in the word flags. The quality of the conversion is store in the upper 8 bits, following the list: generalTracksOnly, arbitratedEcalSeeded, arbitratedMerged, arbitratedMergedEcalGeneral, highPurity, highEfficiency, ecalMatched1Track, and ecalMatched2Track.

Taus TODO

For taus, MiniAOD includes all objects with pT > 18 GeV and passing the decayModeFindingNewDMs discriminator (which is strictly looser than the decayModeFinding used up to 72X). Tighter tau ID requirements can be applied using the tauID(name) method, all POG-supported discriminators are included. The tau ID discriminators recommended for 13 TeV are described on this wiki.

Additional information on the taus, e.g. the impact parameter of the reconstructed tau vertex, are saved in the TauPFEssential format which is embedded in the pat::Tau object.

Links to the packed PF candidates corresponding to the PFCandidates used to reconstruct a given tau are accessible through the methods like leadChargedHadrCand(), leadNeutralCand(), leadCand(), signalCands(), isolationCands(), ...
Note instead that the older methods with similar name but with a PF inside, like signalPFCands(), are not usable on MiniAOD since they're not compatible with the packed PF candidate format used in MiniAOD.

Jets TODO

Several collections of jets are saved:

  • one general purpose collection of AK4 jets slimmedJets, made from ak4PFJetsCHS, i.e. using anti-kT clustering out of Particle Flow candidates, after rejecting the charged hadrons that are associated to a pileup primary vertex. These have standard jet energy corrections applied (L1FastJet, L2, L3), and a pT cut at 10 GeV
  • one general purpose collection of AK4 jets with the PUPPI algorithm applied slimmedJetsPuppi; they have the same clustering as the slimmedJets, but pileup mitigation is performed by weighting the particles according to the PUPPI algorithm, i.e. the jet 4-vector is the weighted sum of the particle 4-vectors.
    • note that the clustering is performed with the weighted particles, which can lead to a different set of jets in some events
    • these jets have L1, L2 and L3 jet energy corrections. n.b. L1 corrections are small, since the PUPPI procedure corrects the response for the pileup already.
      These jets have a pT cut at 20 GeV
  • one collection for substructure and large-jet analyses, slimmedJetsAK8 , made from ak8PFJetsPUPPI, i.e. the same clustering of the slimmedJetsPuppi but with a larger distance parameter R=0.8 instead of R=0.4 (R corresponds approximately to the radius of the jet).
    These jets have a pT cut at 170 GeV. If jet corrections are reapplied, the user should use pT above 200 GeV. The 200 GeV threshold is the pT at which W decay daughters begin merging.
  • A soft drop subjet collection, for use with top tagging or W-tagging, for the slimmedJetsAK8, are provided slimmedJetsAK8PFPuppiSoftDropPacked. The CMS top tagger subjets and slimmedJetsAK8PFCHSSoftDropPacked found in previous versions of miniAOD have been dropped, although CHS values are stored as user floats.

For the AK4 jet collections, links to the daughters are available through the daughter(idx) and numberOfDaughters() methods, and they will point into the collection of packed PF candidates described below.
It should be noted that the getPFConstituent and getPFConstituents methods instead will NOT work, since they explicitly require the daughter to be a full reco::PFCandidate and not a packed PF one.

For the AK8 jet collection, the links to the daughters are stored in an efficient way, but it is not the same way to access the daughters as in the past in pat::Jet. The jets have (by default) two substructure algorithms run, SoftDrop and PUPPI SoftDrop. The subjets of PUPPI softdrop, available through the subjets method in pat::Jet. However, each also point to their respective constituents. To save space, the Soft Drop Subjets are stored in positions 0 and 1 in the constituent list. These subjets contain pointers to their own constituents. The remaining constituents that are groomed away by the soft drop method are stored in the constituent vector in indices 2,3,....N. As such, to access all daughters, you must loop over the constituents of all of the constituents (see code snippet below). As with the AK4 collections, the daughter(idx) method will be the appropriate one, while getPFConstituent and getPFConstituents will also NOT work. This functionality is currently broken for 9x and will be fixed ASAP. The same code snippet below will work to obtain the constituents.

For the AK4 jets (both with and without PUPPI), the following information is provided:

  • b-tagging discriminators, available from the bDiscriminator(name) method, for: pfJetBProbabilityBJetTags, pfJetProbabilityBJetTags, pfTrackCountingHighEffBJetTags, pfSimpleSecondaryVertexHighEffBJetTags, pfSimpleInclusiveSecondaryVertexHighEffBJetTags, pfCombinedSecondaryVertexV2BJetTags, pfCombinedInclusiveSecondaryVertexV2BJetTags, softPFMuonBJetTags, softPFElectronBJetTags, pfCombinedMVAV2BJetTags, pfCombinedCvsLJetTags, pfCombinedCvsBJetTags, pfDeepCSVJetTags:probb, pfDeepCSVJetTags:probc, pfDeepCSVJetTags:probudsg, pfDeepCSVJetTags:probbb ;
  • for standard jets (not PUPPI), the discriminator for the MVA PileUp id, saved as userFloat("pileupJetId:fullDiscriminant").
    • In 80X version 1 miniAODs, the training is based on 76X simulation
    • In 80X version 2 miniAODs, the training is based on 80X simulation
  • For standard jets (not PUPPI), the pt and emEnergyFraction=(1-hadEnergyFraction) of the matched (dR<0.4) CaloJet are saved as userFloat("caloJetMap:pt") and userFloat("caloJetMap:emEnergyFraction").
    • For 90x, 91x, and 92x, the PUPPI tune is from 80x.
    • For 93x and onward, the PUPPI tune is rederived to fix anomalous MET tails.

For AK8 jets, the following information is included (UPDATED for 9x):

  • soft drop masses with PUPPI, available as a userFloat with label ak8PFJetsPuppiSoftDropMass. The trimmed and filtered userfloats have been dropped from 80X miniAOD. They are calculable with the jet toolbox.
  • soft drop and pruned masses with CHS, available as userFloats with labels ak8PFJetsCHSValueMap:ak8PFJetsCHSPrunedMass and ak8PFJetsCHSValueMap:ak8PFJetsCHSSoftDropMass.
  • n-subjettiness variables with PUPPI tau1, tau2, and tau3, available as userFloats with labels NjettinessAK8Puppi:tau1, NjettinessAK8Puppi:tau2, and NjettinessAK8Puppi:tau3
  • n-subjettiness variables with CHS (for backwards compatibility) tau1, tau2, and tau3, available as userFloats with labels ak8PFJetsCHSValueMap:NjettinessAK8CHSTau1, ak8PFJetsCHSValueMap:NjettinessAK8CHSTau2, and ak8PFJetsCHSValueMap:NjettinessAK8CHSTau3
  • : for AK8 jets PUPPI jets (instead of CHS jets) are stored in the slimmedJetAK8. The CHS momentum is available through a user float slimmedJetsAK8.userFloat(" ak8PFJetsCHSValueMap:pt"). The subjets for the soft drop CHS have been dropped and only soft drop PUPPI subjets are saved. To access them use the subjets method within pat::Jet with label SoftDropPuppi.
  • The documentation to use userFloats is highlighted here. A simple snippet to perform a very simple W/Z/H tagging selection would be :

double softdrop_puppi_mass = jet.userFloat("ak8PFJetsPuppiSoftDropMass");
double puppi_tau1         = jet.userFloat("NjettinessAK8Puppi:tau1");
double puppi_tau2         = jet.userFloat("NjettinessAK8Puppi:tau2");
double puppi_tau3         = jet.userFloat("NjettinessAK8Puppi:tau3");

// You can also get the subjets like this: 
TLorentzVector puppi_softdrop, puppi_softdrop_subjet;
auto const & sdSubjetsPuppi = jet.subjets("SoftDropPuppi");
for ( auto const & it : sbSubjetsPuppi ) {
  puppi_softdrop_subjet.SetPtEtaPhiM(it->correctedP4(0).pt(),it->correctedP4(0).eta(),it->correctedP4(0).phi(),it->correctedP4(0).mass());
  puppi_softdrop+=puppi_softdrop_subjet;
}

bool myPuppiSimpleWTagger = (puppi_tau2/puppi_tau1) < 0.5 && softdrop_puppi_mass > 50.0;

double pruned_chs_mass = jet.userFloat("ak8PFJetsCHSValueMap:ak8PFJetsCHSPrunedMass");     // access to pruned mass
double chs_tau1         = jet.userFloat("ak8PFJetsCHSValueMap:NjettinessAK8CHSTau1);
double chs_tau2         = jet.userFloat("ak8PFJetsCHSValueMap:NjettinessAK8CHSTau2");
double chs_tau3         = jet.userFloat("ak8PFJetsCHSValueMap:NjettinessAK8CHSTau3");

bool myCHSSimpleWTagger = (tau2/tau1) < 0.6 && pruned_mass > 50.0;

The PUPPI softdrop mass correction depends on the use case.

For W/Z/H tagging follow the instructions here:

https://twiki.cern.ch/twiki/bin/viewauth/CMS/JetWtagging

https://github.com/cms-jet/PuppiSoftdropMassCorr

For top tagging follow the instructions here:

https://twiki.cern.ch/twiki/bin/viewauth/CMS/JetTopTagging#13_TeV_working_points_CMSSW_8_0

B-tagging TODO

To use b-tagging with MiniAOD, please, refer to the b-tagging CMS DAS school short exercise at this link. Note that the exercise is currently still being updated for the 80X release.

This exercise shows how to access b tag discriminators stored in miniAOD here. In some cases it may be necessary to rerun the b-tag sequence from MiniAOD. For instance, to test a new discriminator. In order to rebuild the b-tag discriminators from the information stored in MiniAOD, we need to update the jet information. It is not needed anymore to recluster the jets from scratch, as in older versions of CMSSW. The new updateJetCollection tool can be used, as shown here. In some cases it may be necessary to rerun the b-tag sequence from MiniAOD for a jet collection which is not included in the MiniAOD files. ONLY in this case it is still needed to remake jets and then remake PAT jets from them, as shown here.

ETmiss

The type1 corrected ETmiss is used in the MiniAOD. Also, on MC the generated ETmiss is provided. The pT, φ and sumET of the calo ETmiss and of the uncorrected ETmiss are also saved within that object. You can access them respectively as slimmedMETs.genMET() and slimmedMETs.uncorPt() and slimmedMETs.caloMETPt()

The type1 corrections is computed from ak4PFJetsCHS jets with pT > 15 GeV, as per the updated prescribed by the JetMET group.

The pat::MET object also contains the information related to the type of corrections and uncertainties from the standard POG recipe of shifting and smearing objects, from the corXyz(level) methods and shiftedXyz(uncertainty, level) methods:

  • Xyz can be any of P2, P3, P4, Px, Py, Pz, Phi, SumEt
  • uncertainty can be any of the 19 variations considered (e.g. UnclusteredEnUp or JetResDown)
  • level is Type1 (default), Raw, Type1p2, etc; note that not all uncertainties are filled for levels.
  • the standard methods pt(), phi(), p4() etc all return the default type1 corrected MET
You can find the list of all values in version 2

In addition to the standard PF missing energy, also the ETmiss reconstructed with the PUPPI pileup mitigation algorithm is also provided, in the slimmedMETsPuppi collection. The type1 corrections are also computed and available as default for this MET definition.

If the JECs are updated, one would need to re-compute the type-1 MET for both PF and Puppi flavors. To learn about the re-computation recipe please look here

For releases older than 8_0_20, the latest recommended version of slimmedMETsPuppi requires a standalone recipe to run on top of miniAOD. Similarly, the met-significance is available with a standalone recipe for releases older than 8_0_20 to run on top of miniAOD. You can access this variable with metSignificance() call.

Isolated Tracks NEW

Starting in 9_2_4, there is a new collection isolatedTracks of pat::IsolatedTrack objects. The goal here is for a collection of isolated tracks that can be used for (a) isolated candidate vetoes in hadronic analyses and (b) candidates for stopped/missing tracks in analyses interested in these objects.

Objects in this collection are drawn from the packedPFCandidates, lostTracks, and generalTracks collections (care is taken to avoid duplicates, so for example if a track is in both the packedPFCandidate and generalTrack collections, it will only be taken from the packedPFCandidate collection). These collections are pruned to the following selection:

  • All candidates with pT >= 20 GeV
  • Isolated candidates with 5 <= pT < 20 GeV, where "isolated" means (absolute iso < 5 GeV || relative iso < 0.2 || mini relative iso < 0.2).

Isolations are calculated as sum-pT of charged hadron pf-candidates satisfying (fromPV>1 || dz<0.1) within the relevant cone (dR=0.3 for regular iso, and dR=min(0.2, max(0.05, 10/pT)) for mini iso).

The pat::IsolatedTrack class inherits from reco::LeafCandidate and so contains all of the basic particle properties (p4, charge, pdgId). In addition, it contains the following attributes:

  • pfIsolationDR03, miniPFIsolation - pat::PFIsolation objects containing 4 components of isolation (charged hadron, neutral hadron, photon, pileup).
  • matchedCaloJet(Em/Had)Energy - EM/hadronic energies of the nearest calo-jet within dR=0.3. Serves as a rough proxy for calo-isolation.
  • dz, dxy, dzError, dxyError
  • fromPV - result of fromPV() method of packedPFCandidates/lostTracks. Set to -1 for candidates solely from generalTracks.
  • trackQuality - the result of the qualityMask() method of generalTracks.
  • dEdxStrip, dEdxPixel - estimated dE/dx values in the strips/pixels.
  • hitPattern - a reco::HitPattern object, the result of the hitPattern() method of generalTracks.
  • crossed(Ecal/Hcal)Status - the status codes of the Ecal/Hcal cells crossed by the extrapolated track.
  • deltaEta, deltaPhi - the difference in eta/phi between the initial track trajectory and the point of intersection with the Ecal. Can be used to identify roughly the calorimeter cells the track should hit.
  • packedCandRef - reference to the original packedCandidate object, either in the packedPFCandidates or lostTracks collections. Candidates solely from the generalTracks collection have a NULL value for this.

Note that there are a small number of packedPFCandidates that have no associated track in the generalTracks collection (mostly electrons, with some muons too). These are included in this isolatedTracks collection (so that they may still be used for vetoes), and track-specific quantities above get default values (trackQuality = 0, dEdx(Pixel/Strip) = -1, delta(Eta/Phi) = 0, crossed(Ecal/Hcal)Status empty).

Example code accessing all high-level physics objects TODO

TODO update with new variables and collections the C++ example. The python one is more up to date.

// system include files
#include <memory>

// user include files
#include "FWCore/Framework/interface/Frameworkfwd.h"
#include "FWCore/Framework/interface/EDAnalyzer.h"

#include "FWCore/Framework/interface/Event.h"
#include "FWCore/Framework/interface/MakerMacros.h"

#include "FWCore/ParameterSet/interface/ParameterSet.h"

#include "DataFormats/VertexReco/interface/VertexFwd.h"
#include "DataFormats/VertexReco/interface/Vertex.h"
#include "DataFormats/PatCandidates/interface/Muon.h"
#include "DataFormats/PatCandidates/interface/Electron.h"
#include "DataFormats/PatCandidates/interface/Tau.h"
#include "DataFormats/PatCandidates/interface/Photon.h"
#include "DataFormats/PatCandidates/interface/Jet.h"
#include "DataFormats/PatCandidates/interface/MET.h"
#include "DataFormats/PatCandidates/interface/PackedCandidate.h"
//
// class declaration
//

class MiniAnalyzer : public edm::EDAnalyzer {
   public:
      explicit MiniAnalyzer (const edm::ParameterSet&);
      ~MiniAnalyzer();

   private:
      virtual void analyze(const edm::Event&, const edm::EventSetup&) override;

      // ----------member data ---------------------------
      edm::EDGetTokenT vtxToken_;
      edm::EDGetTokenT muonToken_;
      edm::EDGetTokenT electronToken_;
      edm::EDGetTokenT tauToken_;
      edm::EDGetTokenT photonToken_;
      edm::EDGetTokenT jetToken_;
      edm::EDGetTokenT fatjetToken_;
      edm::EDGetTokenT metToken_;
};

MiniAnalyzer::MiniAnalyzer(const edm::ParameterSet& iConfig):
    vtxToken_(consumes(iConfig.getParameter("vertices"))),
    muonToken_(consumes(iConfig.getParameter("muons"))),
    electronToken_(consumes(iConfig.getParameter("electrons"))),
    tauToken_(consumes(iConfig.getParameter("taus"))),
    photonToken_(consumes(iConfig.getParameter("photons"))),
    jetToken_(consumes(iConfig.getParameter("jets"))),
    fatjetToken_(consumes(iConfig.getParameter("fatjets"))),
    metToken_(consumes(iConfig.getParameter("mets")))
{
}

MiniAnalyzer::~MiniAnalyzer()
{
}

void
MiniAnalyzer::analyze(const edm::Event& iEvent, const edm::EventSetup& iSetup)
{
    edm::Handle vertices;
    iEvent.getByToken(vtxToken_, vertices);
    if (vertices->empty()) return; // skip the event if no PV found
    const reco::Vertex &PV = vertices->front();

    edm::Handle muons;
    iEvent.getByToken(muonToken_, muons);
    for (const pat::Muon &mu : *muons) {
        if (mu.pt() < 5 || !mu.isLooseMuon()) continue;
        printf("muon with pt %4.1f, dz(PV) %+5.3f, POG loose id %d, tight id %d\n",
                mu.pt(), mu.muonBestTrack()->dz(PV.position()), mu.isLooseMuon(), mu.isTightMuon(PV));
    }

    edm::Handle electrons;
    iEvent.getByToken(electronToken_, electrons);
    for (const pat::Electron &el : *electrons) {
        if (el.pt() < 5) continue;
        printf("elec with pt %4.1f, supercluster eta %+5.3f, sigmaIetaIeta %.3f (%.3f with full5x5 shower shapes), lost hits %d, pass conv veto %d\n",
                    el.pt(), el.superCluster()->eta(), el.sigmaIetaIeta(), el.full5x5_sigmaIetaIeta(), el.gsfTrack()->trackerExpectedHitsInner().numberOfLostHits(), el.passConversionVeto());
    }

    edm::Handle photons;
    iEvent.getByToken(photonToken_, photons);
    for (const pat::Photon &pho : *photons) {
        if (pho.pt() < 20 or pho.chargedHadronIso()/pho.pt() > 0.3) continue;
        printf("phot with pt %4.1f, supercluster eta %+5.3f, sigmaIetaIeta %.3f (%.3f with full5x5 shower shapes)\n",
                    pho.pt(), pho.superCluster()->eta(), pho.sigmaIetaIeta(), pho.full5x5_sigmaIetaIeta());
    }

    edm::Handle taus;
    iEvent.getByToken(tauToken_, taus);
    for (const pat::Tau &tau : *taus) {
        if (tau.pt() < 20) continue;
        printf("tau  with pt %4.1f, dxy signif %.1f, ID(byMediumCombinedIsolationDeltaBetaCorr3Hits) %.1f, lead candidate pt %.1f, pdgId %d \n",
                    tau.pt(), tau.dxy_Sig(), tau.tauID("byMediumCombinedIsolationDeltaBetaCorr3Hits"), tau.leadCand()->pt(), tau.leadCand()->pdgId());
    }

    edm::Handle jets;
    iEvent.getByToken(jetToken_, jets);
    int ijet = 0;
    for (const pat::Jet &j : *jets) {
        if (j.pt() < 20) continue;
        printf("jet  with pt %5.1f (raw pt %5.1f), eta %+4.2f, btag CSV %.3f, CISV %.3f, pileup mva disc %+.2f\n",
            j.pt(), j.pt()*j.jecFactor("Uncorrected"), j.eta(), std::max(0.f,j.bDiscriminator("combinedSecondaryVertexBJetTags")), std::max(0.f,j.bDiscriminator("combinedInclusiveSecondaryVertexBJetTags")), j.userFloat("pileupJetId:fullDiscriminant"));
        if ((++ijet) == 1) { // for the first jet, let's print the leading constituents
            std::vector daus(j.daughterPtrVector());
            std::sort(daus.begin(), daus.end(), [](const reco::CandidatePtr &p1, const reco::CandidatePtr &p2) { return p1->pt() > p2->pt(); }); // the joys of C++11
            for (unsigned int i2 = 0, n = daus.size(); i2 < n && i2 <= 3; ++i2) {
                const pat::PackedCandidate &cand = dynamic_cast<const pat::PackedCandidate &>(*daus[i2]);
                printf("         constituent %3d: pt %6.2f, dz(pv) %+.3f, pdgId %+3d\n", i2,cand.pt(),cand.dz(PV.position()),cand.pdgId());
            }
        }
    }

    edm::Handle fatjets;
    iEvent.getByToken(fatjetToken_, fatjets);
    for (const pat::Jet &j : *fatjets) {
        printf("AK8j with pt %5.1f (raw pt %5.1f), eta %+4.2f, mass %5.1f ungroomed, %5.1f softdrop, %5.1f pruned CHS\n",
            j.pt(), j.pt()*j.jecFactor("Uncorrected"), j.eta(), j.mass(), j.userFloat("ak8PFJetsPuppiSoftDropMass"), j.userFloat("ak8PFJetsCHSValueMap:ak8PFJetsCHSPrunedMass") );

        // To get the constituents of the AK8 jets, you have to loop over all of the
        // daughters recursively. To save space, the first two constituents are actually
        // the Soft Drop SUBJETS, which will then point to their daughters.
        // The remaining constituents are those constituents removed by soft drop but
        // still in the AK8 jet.
   std::vector constituents;
        for ( unsigned ida = 0; ida < j.numberOfDaughters(); ++ida ) {
     reco::Candidate const * cand = j.daughter(ida);
     if ( cand->numberOfDaughters() == 0 )
       constituents.push_back( cand ) ;
     else {
       for ( unsigned jda = 0; jda < cand->numberOfDaughters(); ++jda ) {
         reco::Candidate const * cand2 = cand->daughter(jda);
         constituents.push_back( cand2 );
       }
     }
   }
   std::sort( constituents.begin(), constituents.end(), [] (reco::Candidate const * ida, reco::Candidate const * jda){return ida->pt() > jda->pt();} );

   for ( unsigned int ida = 0; ida < constituents.size(); ++ida ) {
     const pat::PackedCandidate &cand = dynamic_cast<const pat::PackedCandidate &>(*constituents[ida]);
     printf("         constituent %3d: pt %6.2f, dz(pv) %+.3f, pdgId %+3d\n", ida,cand.pt(),cand.dz(PV.position()),cand.pdgId());
   }

   auto sdSubjets = j.subjets("SoftDropPuppi");
   for ( auto const & isd : sdSubjets ) {
     printf("  sd subjet with pt %5.1f (raw pt %5.1f), eta %+4.2f, mass %5.1f ungroomed\n",
       isd->pt(), isd->pt()*isd->jecFactor("Uncorrected"), isd->eta(), isd->mass() );

   }
    }

    edm::Handle mets;
    iEvent.getByToken(metToken_, mets);
    const pat::MET &met = mets->front();
    printf("MET: pt %5.1f, phi %+4.2f, sumEt (%.1f). genMET %.1f. MET with JES up/down: %.1f/%.1f\n",
        met.pt(), met.phi(), met.sumEt(),
        met.genMET()->pt(),
        met.shiftedPt(pat::MET::JetEnUp), met.shiftedPt(pat::MET::JetEnDown));

    printf("\n");
}


//define this as a plug-in
DEFINE_FWK_MODULE(MiniAnalyzer);

python configuration to run it

import FWCore.ParameterSet.Config as cms

process = cms.Process("Demo")

process.load("FWCore.MessageService.MessageLogger_cfi")
process.maxEvents = cms.untracked.PSet( input = cms.untracked.int32(10) )

process.source = cms.Source("PoolSource",
    fileNames = cms.untracked.vstring(
        '/store/cmst3/user/gpetrucc/miniAOD/v1/TT_Tune4C_13TeV-pythia8-tauola_PU_S14_PAT.root'
    )
)

process.demo = cms.EDAnalyzer("MiniAnalyzer",
    vertices = cms.InputTag("offlineSlimmedPrimaryVertices"),
    muons = cms.InputTag("slimmedMuons"),
    electrons = cms.InputTag("slimmedElectrons"),
    taus = cms.InputTag("slimmedTaus"),
    photons = cms.InputTag("slimmedPhotons"),
    jets = cms.InputTag("slimmedJets"),
    fatjets = cms.InputTag("slimmedJetsAK8"),
    mets = cms.InputTag("slimmedMETs"),
)

process.p = cms.Path(process.demo)

# import ROOT in batch mode
import sys
oldargv = sys.argv[:]
sys.argv = [ '-b-' ]
import ROOT
ROOT.gROOT.SetBatch(True)
sys.argv = oldargv

# load FWLite C++ libraries
ROOT.gSystem.Load("libFWCoreFWLite.so");
ROOT.gSystem.Load("libDataFormatsFWLite.so");
ROOT.FWLiteEnabler.enable()

# load FWlite python libraries
from DataFormats.FWLite import Handle, Events

muons, muonLabel = Handle("std::vector<pat::Muon>"), "slimmedMuons"
electrons, electronLabel = Handle("std::vector<pat::Electron>"), "slimmedElectrons"
photons, photonLabel = Handle("std::vector<pat::Photon>"), "slimmedPhotons"
taus, tauLabel = Handle("std::vector<pat::Tau>"), "slimmedTaus"
tauLabelb = "slimmedTausBoosted"
jets = Handle("std::vector<pat::Jet>")
fatjets, fatjetLabel = Handle("std::vector<pat::Jet>"), "slimmedJetsAK8"
mets, metLabel = Handle("std::vector<pat::MET>"), "slimmedMETs"
vertices, vertexLabel = Handle("std::vector<reco::Vertex>"), "offlineSlimmedPrimaryVertices"
verticesScore = Handle("edm::ValueMap<float>")
seenIt = {} # list of things we've seen (so that we dump them in full only once)

# open file (you can use 'edmFileUtil -d /store/whatever.root' to get the physical file name)
events = Events("root://eoscms//eos/cms/store/relval/CMSSW_8_0_3/RelValTTbarLepton_13/MINIAODSIM/80X_mcRun2_asymptotic_2016_v3_gs7120p2NewGTv3-v1/00000/4E291B64-DCEF-E511-B99D-0025905A60B0.root")

for iev,event in enumerate(events):
    if iev >= 10: break
    event.getByLabel(muonLabel, muons)
    event.getByLabel(electronLabel, electrons)
    event.getByLabel(photonLabel, photons)
    event.getByLabel(tauLabel, taus)
    event.getByLabel(fatjetLabel, fatjets)
    event.getByLabel(metLabel, mets)
    event.getByLabel(vertexLabel, vertices)
    event.getByLabel(vertexLabel, verticesScore)

    print "\nEvent %d: run %6d, lumi %4d, event %12d" % (iev,event.eventAuxiliary().run(), event.eventAuxiliary().luminosityBlock(),event.eventAuxiliary().event())

    # Vertices
    if len(vertices.product()) == 0 or vertices.product()[0].ndof() < 4:
        print "Event has no good primary vertex."
        continue
    else:
        PV = vertices.product()[0]
        print "PV at x,y,z = %+5.3f, %+5.3f, %+6.3f, ndof: %.1f, score: (pt2 of clustered objects) %.1f" % (PV.x(), PV.y(), PV.z(), PV.ndof(),verticesScore.product().get(0))

    # Muons
    for i,mu in enumerate(muons.product()):
        if mu.pt() < 5 or not mu.isLooseMuon(): continue
        print "muon %2d: pt %4.1f, dz(PV) %+5.3f, POG loose id %d, tight id %d." % (
            i, mu.pt(), mu.muonBestTrack().dz(PV.position()), mu.isLooseMuon(), mu.isTightMuon(PV))

    # Electrons
    for i,el in enumerate(electrons.product()):
        if el.pt() < 5: continue
        print "elec %2d: pt %4.1f, supercluster eta %+5.3f, sigmaIetaIeta %.3f (full5x5), non-triggering Spring15 MVA score %+.3f, lost hits %d, pass conv veto %d" % (
                    i, el.pt(), el.superCluster().eta(), el.full5x5_sigmaIetaIeta(), el.userFloat("ElectronMVAEstimatorRun2Spring15NonTrig25nsV1Values"), el.gsfTrack().hitPattern().numberOfLostHits(ROOT.reco.HitPattern.MISSING_INNER_HITS), el.passConversionVeto())
        if 'ele' not in seenIt:
            for  eleid in el.electronIDs():
                print  "\t%s %s" % (eleid.first, eleid.second)
            seenIt['ele'] = True

    # Photon
    for i,pho in enumerate(photons.product()):
        if pho.pt() < 20 or pho.chargedHadronIso()/pho.pt() > 0.3: continue
        print "phot %2d: pt %4.1f, supercluster eta %+5.3f, sigmaIetaIeta %.3f (full5x5 shower shapes)" % (
                    i, pho.pt(), pho.superCluster().eta(), pho.full5x5_sigmaIetaIeta())
        if 'pho' not in seenIt:
            for  phoid in pho.photonIDs():
                print  "\t%s %s" % (phoid.first, phoid.second)
            seenIt['pho'] = True

    # Tau
    event.getByLabel(tauLabel, taus)
    for i,tau in enumerate(taus.product()):
        if tau.pt() < 20: continue
        print "tau  %2d: pt %4.1f, dxy signif %.1f, ID(byMediumCombinedIsolationDeltaBetaCorr3Hits) %.1f, lead candidate pt %.1f, pdgId %d " % (
                    i, tau.pt(), tau.dxy_Sig(), tau.tauID("byMediumCombinedIsolationDeltaBetaCorr3Hits"), tau.leadCand().pt(), tau.leadCand().pdgId())
        if 'tau' not in seenIt:
            for  tauid in tau.tauIDs():
                print  "\t%s %s" % (tauid.first, tauid.second)
            seenIt['tau'] = True
    # Tau (Boosted)
    event.getByLabel(tauLabelb, taus)
    for i,tau in enumerate(taus.product()):
        if tau.pt() < 20: continue
        print "boosted tau  %2d: pt %4.1f, dxy signif %.1f, ID(byMediumCombinedIsolationDeltaBetaCorr3Hits) %.1f, lead candidate pt %.1f, pdgId %d " % (
                    i, tau.pt(), tau.dxy_Sig(), tau.tauID("byMediumCombinedIsolationDeltaBetaCorr3Hits"), tau.leadCand().pt(), tau.leadCand().pdgId())
        if 'taub' not in seenIt:
            for  tauid in tau.tauIDs():
                print  "\t%s %s" % (tauid.first, tauid.second)
            seenIt['taub'] = True

    # Jets (AK4, CHS and Puppi)
    for jetLabel, algo in ("slimmedJets", "CHS"), ("slimmedJetsPuppi", "PUPPI"):
        event.getByLabel(jetLabel, jets)
        for i,j in enumerate(jets.product()):
            if j.pt() < 20: continue
            print "jet %s %3d: pt %5.1f (raw pt %5.1f, matched-calojet pt %5.1f), eta %+4.2f, btag CSVIVFv2 %.3f, CMVAv2 %.3f, pileup mva disc %+.2f" % (
                algo, i, j.pt(), j.pt()*j.jecFactor('Uncorrected'), j.userFloat("caloJetMap:pt") if algo == "CHS" else -99.0, j.eta(), max(0,j.bDiscriminator("pfCombinedInclusiveSecondaryVertexV2BJetTags")), max(0,j.bDiscriminator("pfCombinedMVAV2BJetTags")), j.userFloat("pileupJetId:fullDiscriminant") if algo == "CHS" else -99)
            if 'jetAk4'+algo not in seenIt:
                constituents = [ j.daughter(i2) for i2 in xrange(j.numberOfDaughters()) ]
                constituents.sort(key = lambda c:c.pt(), reverse=True)
                for i2, cand in enumerate(constituents):
                    if i2 > 12:
                            print "         ....."
                            break
                    print "         constituent %3d: pt %6.2f, dz(pv) %+.3f, pdgId %+3d, hcal energy fraction %.2f, puppi weight %.3f " % (i2,cand.pt(),cand.dz(PV.position()),cand.pdgId(),cand.hcalFraction(),cand.puppiWeight())
                print "   btag discriminators:"
                for btag in j.getPairDiscri():
                    print  "\t%s %s" % (btag.first, btag.second)
                print "   userFloats:"
                for ufl in j.userFloatNames():
                    print  "\t%s %s" % (ufl, j.userFloat(ufl))
                seenIt['jetAk4'+algo] = True

    # Fat AK8 Jets
    for i,j in enumerate(fatjets.product()):
        print "jetAK8 %3d: pt %5.1f (raw pt %5.1f), eta %+4.2f, mass %5.1f ungroomed, %5.1f softdrop, %5.1f pruned CHS. " % (
            i, j.pt(), j.pt()*j.jecFactor('Uncorrected'), j.eta(), j.mass(), j.userFloat('ak8PFJetsPuppiSoftDropMass'), j.userFloat('ak8PFJetsCHSValueMap:ak8PFJetsCHSPrunedMass'))
        # To get the constituents of the AK8 jets, you have to loop over all of the
        # daughters recursively. To save space, the first two constituents are actually
        # the Soft Drop SUBJETS, which will then point to their daughters.
        # The remaining constituents are those constituents removed by soft drop but
        # still in the AK8 jet.
        if 'jetAk8' not in seenIt:
            constituents = []
            for ida in xrange( j.numberOfDaughters() ) :
                cand = j.daughter(ida)
                if cand.numberOfDaughters() == 0 :
                    constituents.append( cand )
                else :
                    for jda in xrange( cand.numberOfDaughters() ) :
                        cand2 = cand.daughter(jda)
                        constituents.append( cand2 )
            constituents.sort(key = lambda c:c.pt(), reverse=True)
            for i2, cand in enumerate(constituents):
                if i2 >4:
                            print "         ....."
                            break
                print "         constituent %3d: pt %6.2f, pdgId %+3d, #dau %+3d" % (i2,cand.pt(),cand.pdgId(), cand.numberOfDaughters())
            print "   btag discriminators:"
            for btag in j.getPairDiscri():
                print  "\t%s %s" % (btag.first, btag.second)
            print "   userFloats:"
            for ufl in j.userFloatNames():
                print  "\t%s %s" % (ufl, j.userFloat(ufl))
            seenIt['jetAk8'] = True
        # Print Subjets
        if 'jetAk8SD' not in seenIt:
            wSubjets = j.subjets('SoftDropPuppi')
            for isd,sdsub in enumerate( sdSubjets ) :
                print "   w subjet %3d: pt %5.1f (raw pt %5.1f), eta %+4.2f, mass %5.1f " % (
                    isd, sdsub.pt(), sdsub.pt()*sdsub.jecFactor('Uncorrected'), sdsub.eta(), sdsub.mass()
                    )
                print "   \tbtag discriminators:"
                for btag in sdsub.getPairDiscri():
                    print  "\t\t%s %s" % (btag.first, btag.second)
                print "   \tuserFloats:"
                for ufl in sdsub.userFloatNames():
                    print  "\t\t%s %s" % (ufl, sdsub.userFloat(ufl))
                seenIt['jetAk8SD'] = True

    # MET:
    met = mets.product().front()
    print "MET: pt %5.1f, phi %+4.2f, sumEt (%.1f). rawMET: %.1f, genMET %.1f. MET with JES up/down: %.1f/%.1f" % (
        met.pt(), met.phi(), met.sumEt(),
        met.uncorPt(),
        met.genMET().pt(),
        met.shiftedPt(ROOT.pat.MET.JetEnUp), met.shiftedPt(ROOT.pat.MET.JetEnDown));

Packed ParticleFlow Candidates UPDATED

All candidates reconstructed by the ParticleFlow algorithm are saved in MiniAOD in the packedPFCandidates collection, using as dataformat pat::PackedCandidate. Because some tracks are not associated to any ParticleFlow candidate in GED, the missing highpurity tracks are also stored in a collection of packed candidate named lostTracks.

For all packed PF candidates, this information is stored:

  • the momentum 4-vector, accessible through the usual methods like pt(), eta(), phi(), mass(), energy(), px(), p4(), polarP4().
    An additional method phiAtVtx() is provided, returning the phi of the candidate's track at the vertex; this is identical to phi() for the vast majority of the particles, but the two might differ for some of them if the calorimeters had contributed significantly in defining the 4-vector of the particle.
  • the particle charge and pdgId: 11, 13, 22 for ele/mu/gamma, 211 for charged hadrons, 130 for neutral hadrons, 1 and 2 for hadronic and em particles in HF.
  • quality flags:
    • Inner hit information: lostInnerHits() will return -1 (validHitInFirstPixelBarrelLayer) if the track has a valid hit in the first pixel barrel layer, 0 (noLostInnerHits) if it doesn't have such hit because of geometrical or detector inefficiencies (i.e. the hit wasn't expected to be there), 1 (oneLostHit) if the track extrapolation towards the beamline crosses an active detector but no hit is found there, 2 (moreLostHits) if there are at least two missing expected inner hits.
      For electrons, this information refers to the gsfTrack(), i.e. the usual cuts electron.gsfTrack()->trackerExpectedHitsInner().numberOfLostHits() < X= can be implemented as cand.lostInnerHits() < X= (but only for X equal to 0 or 1)
    • High-purity track: trackHighPurity() will return true for charged candidates whose reco::Track had the highPurity quality flag set.
  • Puppi Weights can be accessed via puppiWeight() and puppiWeightNoLep() functions.
    Two sets of weights are included, except in 74X version 1, so that one can compute puppi isolation for muons, electrons and taus (recipes forthcoming). For completeness, puppiWeight are used to cluster the jets and puppiWeightNoLep are used to compute the puppi MET.
  • Since 76X, the packed PF candidates corresponding to neutral hadrons (pdgId 130) and HF hadrons (pdgId 1) contain the fraction of energy measured from the hadronic calorimeter, accessible via the hcalFraction() method. UPDATED

PV Assignment

Starting from 74X, more information about PV association are provided in order to tune the PU rejection techniques to the analyses needs. The following features are added:

  • vertexRef() now returns for each packed candidate the associated PV (before 740 it was always the pv[0]). The association is based on CommonTools /RecoAlgos/python/sortedPFPrimaryVertices_cfi.py
  • pvAssociationQuality() method is added and returns the quality of PV-candidate association, in particular (please note that in the following the PV means the associated PV returned by vertexRef()):
    • UsedInFitTight: the track is used in the PV fit and the weight is above 0.5
    • UsedInFitLoose: the track is used in the PV fit and the weight is below 0.5
    • CompatibilityDz: the track is not used in fit but is very close in dZ to the PV (significance of dZ < 5 or dZ < 300um)
    • CompatibilityBTag: the track is not compatible with the PV but it is close to the nearest jet axis starting from the PV (distance to jet axis < 700um)
    • NotReconstructedPrimary: the track is not associted to any PV and is compatible with the BeamSpot hence it is likely to be originating from an interaction for which we did not reconstruct the PV (beamspot compatiblity: dxy sig < 2sigma and dxy < 200um)
    • OtherDeltaZ: none of the above criteria is satisfied, hence the closest in dZ vertex is associated

The old fromPV() is still provided and is expected to given in 99.99% of the tracks the same behaviour as in previous versions. In addition fromPV(int i) provides the same information of fromPV but computed wrt PV[i], this allow to rerun CHS changing the signal vertex.

The meaning of fromPV() results are unchanged, fromPV() returns a number between 3 and 0 to define how tight the association with the PV is:

  • the tighest, 3 (PVUsedInFit), is if the track is used in the PV fit;
  • 2 (PVTight) is if the track is not used in the fit of any of the other PVs, and is closest in z to the PV,
  • 1 (PVLoose) is if the track is closest in z to a PV other then the PV.
  • 0 (NoPV) is returned if the track is used in the fit of another PV.

The definition normally used for isolation calculations is fromPV() > 1; the definition used for CHS subtraction in jets is fromPV() > 0.

Impact Parameter
  • the longitudinal and transverse impact parameters with respect to the PV: dxz(), dz().
    The impact parameters can also be recomputed with respect to any other position by calling the methods dxz(point), dz(point)).
    The vertex() method returns the position of the point of closest approach to the PV. This shouldn't be confused with the vertexRef() method, that returns a reference to the PV itself.

In addition the impact parameter accessors behaviour is still compatible with previous versions but it provides additional features, namely:

  • dz() still returns the ip wrt PV[0]
  • dz(point) still return the ip wrt a given 3D point
  • dz(int i) returns the ip wrt PV[i]
  • dzAssociatedPV() returns the ip wrt the PV associated to this candidate

Embedded track information UPDATED

For charged packed PF candidates with pT > 0.5 GeV, additional information is stored with different precision (high precision for pt > 0.95 GeV, low precision for 0.5 GeV < pt < 0.95 GeV )

  • the uncertainty on the impact parameter dzError(), dxyError()
  • the number of hits and pixel hits on the track (numberOfHits(), numberOfPixelHits())
  • the number of layers with hits on the track
  • the sub/det and layer of first hit of the track
  • the reco::Track of the candidate is provided by the pseudoTrack() method, with:
    • the pt,eta and phi of the original track (if those are different from the one of the original PFCandidate)
    • an approximate covariance matrix of the track state at the vertex
    • approximate hitPattern() and trackerExpectedHitsInner() that yield the correct number of hits, pixel hits, layers and the information returned by lostInnerHits()
      (but nothing more, so e.g. you cannot access expected outer hits, or lost hits within the track)
    • the track normalized chisquare (truncated to an integer)
    • the highPurity quality flag set, if the original track had it.

Pointers and navigation

All physics objects except the MET contain pointers to the packed PF candidates corresponding to the PFCandidates they were made from:

  • For all objects, this information is returned by the methods numberOfSourceCandidatePtrs() and sourceCandidatePtr(index) methods.
  • For jets, they are also accessible through the natural interface daughter(index) and numberOfDaughters(), with the following caveat:
    • in case of slimmedJets (i.e. default AK4CHS jets) the daughters of the jets are directly the packed candidates
    • in case of slimmedJetsAK8 (i.e. fat jets used for substructures analysis) the daughter Ptrs are a mixed collection of SubJets and PackedCandidates. In order to have the full list of PackedCandidates you have to add the daughters of the subjets (see example below)

#! /usr/bin/env python
import ROOT
from DataFormats.FWLite import Events, Handle
events = Events (["root://cms-xrd-global.cern.ch//store/relval/CMSSW_7_4_0/RelValTTbar_13/MINIAODSIM/PU25ns_MCRUN2_74_V7_GENSIM_7_1_15-v1/00000/7628ED6B-99DD-E411-B9C8-0025905A60B0.root"])

handleFatJets  = Handle ("std::vector")
labelFatJets = ("slimmedJetsAK8")
c=0
for event in events:
    event.getByLabel (labelFatJets,handleFatJets)
    fatjets = handleFatJets.product()
    for fj in fatjets :
        if c > 10 :
                break
        c+=1

        print "FatJet",fj.pt(),fj.eta()
        allconstituents = []
        for constituent in fj.daughterPtrVector() :
                if constituent.numberOfDaughters() > 0 :
                        allconstituents.extend([x for x in constituent.daughterPtrVector()])
                else:
                        allconstituents.append(constituent)
        print " n. constituents  " , len(fj.daughterPtrVector())
        print " n. subjets       " , len(fj.subjets())
        print " n. all constituents      " , len(allconstituents)

  • For taus, they are also accessible through the more specific methods like leadChargedHadrCand(), leadNeutralCand(), leadCand(), signalCands(), isolationCands(), ...
    (note instead that the methods with similar name but with a PF inside, like signalPFCands(), are not usable on MiniAOD)
  • For muons and for electrons or photons associated to a single PF candidate, the originalObjectRef() also points to that PF candidate.
  • For electrons and photons, they're also accessible through the associatedPackedPFCandidates() method.

Examples

The packed PF candidates can be used either directly in the analysis code, e.g. to recompute isolation variables, or it is possible to use them as input to standard CMSSW tools in order to re-reconstruct jets with different algorithms or after masking the leptons, to run b-tagging, and so on.

In the code examples below we will show how to use the packed PF candidates to compute some isolation variable or some quantity based on the constituents of a jet. The more advanced CMSSW patterns are instead covered in the last section of this tutorial.

Code snippets for an EDAnalyzer
// system include files
#include <memory>
#include <cmath>

// user include files
#include "FWCore/Framework/interface/Frameworkfwd.h"
#include "FWCore/Framework/interface/EDAnalyzer.h"
#include "FWCore/Framework/interface/Event.h"
#include "FWCore/Framework/interface/MakerMacros.h"
#include "FWCore/ParameterSet/interface/ParameterSet.h"

#include "DataFormats/Math/interface/deltaR.h"
#include "DataFormats/PatCandidates/interface/PackedCandidate.h"
#include "DataFormats/PatCandidates/interface/Muon.h"
#include "DataFormats/PatCandidates/interface/Electron.h"
#include "DataFormats/PatCandidates/interface/Jet.h"

class PackedCandAnalyzer : public edm::EDAnalyzer {
   public:
      explicit PackedCandAnalyzer (const edm::ParameterSet&);
      ~PackedCandAnalyzer() {}

   private:
      virtual void analyze(const edm::Event&, const edm::EventSetup&) override;

      edm::EDGetTokenT electronToken_;
      edm::EDGetTokenT muonToken_;
      edm::EDGetTokenT jetToken_;
      edm::EDGetTokenT pfToken_;
};

PackedCandAnalyzer::PackedCandAnalyzer(const edm::ParameterSet& iConfig):
    electronToken_(consumes(iConfig.getParameter("electrons"))),
    muonToken_(consumes(iConfig.getParameter("muons"))),
    jetToken_(consumes(iConfig.getParameter("jets"))),
    pfToken_(consumes(iConfig.getParameter("pfCands")))
{
}

void PackedCandAnalyzer::analyze(const edm::Event& iEvent, const edm::EventSetup& iSetup)
{
    edm::Handle muons;
    iEvent.getByToken(muonToken_, muons);
    edm::Handle electrons;
    iEvent.getByToken(electronToken_, electrons);
    edm::Handle pfs;
    iEvent.getByToken(pfToken_, pfs);
    edm::Handle jets;
    iEvent.getByToken(jetToken_, jets);

    std::vector<const reco::Candidate *> leptons;
    for (const pat::Muon &mu : *muons) leptons.push_back(&mu);
    for (const pat::Electron &el : *electrons) leptons.push_back(&el);

    for (const reco::Candidate *lep : leptons) {
        if (lep->pt() < 5) continue;
        // initialize sums
        double charged = 0, neutral = 0, pileup  = 0;
        // now get a list of the PF candidates used to build this lepton, so to exclude them
        std::vector footprint;
        for (unsigned int i = 0, n = lep->numberOfSourceCandidatePtrs(); i < n; ++i) {
            footprint.push_back(lep->sourceCandidatePtr(i));
        }
        // now loop on pf candidates
        for (unsigned int i = 0, n = pfs->size(); i < n; ++i) {
            const pat::PackedCandidate &pf = (*pfs)[i];
            if (deltaR(pf,*lep) < 0.2) {
                // pfcandidate-based footprint removal
                if (std::find(footprint.begin(), footprint.end(), reco::CandidatePtr(pfs,i)) != footprint.end()) {
                    continue;
                }
                if (pf.charge() == 0) {
                    if (pf.pt() > 0.5) neutral += pf.pt();
                } else if (pf.fromPV() >= 2) {
                    charged += pf.pt();
                } else {
                    if (pf.pt() > 0.5) pileup += pf.pt();
                }
            }
        }
        // do deltaBeta
        double iso = charged + std::max(0.0, neutral-0.5*pileup);
        printf("%-8s of pt %6.1f, eta %+4.2f: relIso = %5.2f\n",
                    abs(lep->pdgId())==13 ? "muon" : "electron",
                    lep->pt(), lep->eta(), iso/lep->pt());

    }

    // Let's compute the fraction of charged pt from particles with dz < 0.1 cm
    for (const pat::Jet &j :  *jets) {
        if (j.pt() < 40 || fabs(j.eta()) > 2.4) continue;
        double in = 0, out = 0;
        for (unsigned int id = 0, nd = j.numberOfDaughters(); id < nd; ++id) {
            const pat::PackedCandidate &dau = dynamic_cast<const pat::PackedCandidate &>(*j.daughter(id));
            if (dau.charge() == 0) continue;
            (fabs(dau.dz())<0.1 ? in : out) += dau.pt();
        }
        double sum = in + out;
        printf("Jet with pt %6.1f, eta %+4.2f, beta(0.1) = %+5.3f, pileup mva disc %+.2f\n",
                j.pt(),j.eta(), sum ? in/sum : 0, j.userFloat("pileupJetId:fullDiscriminant"));
    }
}


//define this as a plug-in
DEFINE_FWK_MODULE(PackedCandAnalyzer);

Python configuration

import FWCore.ParameterSet.Config as cms

process = cms.Process("Demo")

process.load("FWCore.MessageService.MessageLogger_cfi")
process.maxEvents = cms.untracked.PSet( input = cms.untracked.int32(10) )

process.source = cms.Source("PoolSource",
    fileNames = cms.untracked.vstring(
        '/store/cmst3/user/gpetrucc/miniAOD/v1/TT_Tune4C_13TeV-pythia8-tauola_PU_S14_PAT.root'
    )
)

process.demo = cms.EDAnalyzer("PackedCandAnalyzer",
    electrons = cms.InputTag("slimmedElectrons"),
    muons = cms.InputTag("slimmedMuons"),
    jets = cms.InputTag("slimmedJets"),
    pfCands = cms.InputTag("packedPFCandidates"),
)

process.p = cms.Path(process.demo)

# after loading ROOT and FWlite libraries as described in the introduction
# define deltaR
from math import hypot, pi
def deltaR(a,b):
    dphi = abs(a.phi()-b.phi());
    if dphi < pi: dphi = 2*pi-dphi
    return hypot(a.eta()-b.eta(),dphi)

muons, muonLabel = Handle("std::vector"), "slimmedMuons"
electrons, electronLabel = Handle("std::vector"), "slimmedElectrons"
jets, jetLabel = Handle("std::vector"), "slimmedJets"
pfs, pfLabel = Handle("std::vector"), "packedPFCandidates"

# open file (you can use 'edmFileUtil -d /store/whatever.root' to get the physical file name)
events = Events("root://eoscms//eos/cms/store/cmst3/user/gpetrucc/miniAOD/v1/TT_Tune4C_13TeV-pythia8-tauola_PU_S14_PAT.root")

for iev,event in enumerate(events):
    event.getByLabel(muonLabel, muons)
    event.getByLabel(electronLabel, electrons)
    event.getByLabel(pfLabel, pfs)
    event.getByLabel(jetLabel, jets)

    print "\nEvent %d: run %6d, lumi %4d, event %12d" % (iev,event.eventAuxiliary().run(), event.eventAuxiliary().luminosityBlock(),event.eventAuxiliary().event())

    # Let's compute lepton PF Isolation with R=0.2, 0.5 GeV threshold on neutrals, and deltaBeta corrections
    leps  = [ p for p in muons.product() ] + [ p for p in electrons.product() ]
    for lep in leps:
        # skip those below 5 GeV, which we don't care about
        if lep.pt() < 5: continue
        # initialize sums
        charged = 0
        neutral = 0
        pileup  = 0
        # now get a list of the PF candidates used to build this lepton, so to exclude them
        footprint = set()
        for i in xrange(lep.numberOfSourceCandidatePtrs()):
            footprint.add(lep.sourceCandidatePtr(i).key()) # the key is the index in the pf collection
        # now loop on pf candidates
        for ipf,pf in enumerate(pfs.product()):
            if deltaR(pf,lep) < 0.2:
                # pfcandidate-based footprint removal
                if ipf in footprint: continue
                # add up
                if (pf.charge() == 0):
                    if pf.pt() > 0.5: neutral += pf.pt()
                elif pf.fromPV() >= 2:
                    charged += pf.pt()
                else:
                    if pf.pt() > 0.5: pileup += pf.pt()
        # do deltaBeta
        iso = charged + max(0, neutral-0.5*pileup)
        print "%-8s of pt %6.1f, eta %+4.2f: relIso = %5.2f" % (
                    "muon" if abs(lep.pdgId())==13 else "electron",
                    lep.pt(), lep.eta(), iso/lep.pt())

    # Let's compute the fraction of charged pt from particles with dz < 0.1 cm
    for i,j in enumerate(jets.product()):
        if j.pt() < 40 or abs(j.eta()) > 2.4: continue
        sums = [0,0]
        for id in xrange(j.numberOfDaughters()):
            dau = j.daughter(id)
            if (dau.charge() == 0): continue
            sums[ abs(dau.dz())<0.1 ] += dau.pt()
        sum = sums[0]+sums[1]
        print "Jet with pt %6.1f, eta %+4.2f, beta(0.1) = %+5.3f, pileup mva disc %+.2f" % (
                j.pt(),j.eta(), sums[1]/sum if sum else 0, j.userFloat("pileupJetId:fullDiscriminant"))

    if iev > 10: break

MC Truth

The standard PAT methods to access the MC truth are working with miniAOD, in particular you can for example use

pat::Electron::genParticle()
pat::Muon::genParticle()
pat::Jet::genParton()
pat::Jet::hadronFlavour()
pat::Jet::partonFlavour()

The only important difference wrt normal PAT is that not all gen particles are stored. In fact gen particles are stored in two different collections as explained below.

The prunedGenParticles are standard GenParticle selected with the GenParticlePruner, in particular

  • only a subset (about 50-100 per event) of the gen particle are stored
  • the selection is made trying to keep the most important information; see prunedGenParticles_cfi.py
  • the navigation between the particles is working but it takes "shortcuts" (i.e. you do not go through the dropped particles)
  • due to switch to Pythia8 (no more status = 3), the exact content is still being tuned. However, the selection used in 74X should contain essentially everything that was status 3 in pythia 6

In 74X and later, GenParticles now contain additional status flags that allow to select particles depending on their history without the need of navigating through the mother-daughter links manually. The information is provided by the GenStatusFlags class, which can be accessed via methods of the GenParticle object.
A presentation describing this feature was given in the PPD general meeting of 17 Jun 2015: slides

The pruned genParticles are the ones pointed by the MC matching of the high level patObjectes (e.g. pat::Electron::genParticle())

The packedGenParticles collection contains all status=1 GenParticle in a reduced format as pat::PackedGenParticle, similar to the one used for PFCandidates. Besides the 4-vector, pdgId, a link to the first ancestor is saved in the prunedGenParticles collection (this can be accessed via the motherRef() or mother(0) methods; note that some generator level particles may be motherless, in that case motherRef will return a null reference, numberOfMothers will return zero, and mother(0) will return a null c++ pointer). This collection is used to re-cluster the MC truth (e.g. if you want to study a different jet algorithm or some substructure techniques).

  • Note that particles are kept only op to a rapidity 6 (note that it's not a cut |y| < 6 and not on |&eta| < 6), so they should not be used for studying particles outside the detector acceptance, nor to recompute the generator level missing energy (that's anyway already available from the pat::MET object)
  • Also the packedGenParticles now include information from the new status flags

The following examples show how to navigate between the two collections: the B mesons (500 < pdg ID < 600) are looked for in the pruned collection (because B are important particles, but they are not stable) and then we search which of the stable (status = 1) particles originated from a B decay. In order to do so we first ask to each packed candidate its "pruned" mother (NB, it is actually the first ancestor that survived the pruning), then we navigate back the pruned collection from such initial mother and see if we find the B meson.

import ROOT
import sys
from DataFormats.FWLite import Events, Handle
from math import *

def isAncestor(a,p) :
        if a == p :
                return True
        for i in xrange(0,p.numberOfMothers()) :
                if isAncestor(a,p.mother(i)) :
                         return True
        return False

events = Events (['root://cms-xrd-global.cern.ch//store/mc/Spring14miniaod/TTJets_MSDecaysCKM_central_Tune4C_13TeV-madgraph-tauola/MINIAODSIM/PU20bx25_POSTLS170_V5-v1/00000/F6EDDC10-8DFC-E311-BC5D-0025905A60D6.root'])

handlePruned  = Handle ("std::vector")
handlePacked  = Handle ("std::vector")
labelPruned = ("prunedGenParticles")
labelPacked = ("packedGenParticles")

# loop over events
count= 0
for event in events:
    event.getByLabel (labelPacked, handlePacked)
    event.getByLabel (labelPruned, handlePruned)
    # get the product
    packed = handlePacked.product()
    pruned = handlePruned.product()

    for p in pruned :
        if abs(p.pdgId()) > 500 and abs(p.pdgId()) < 600 :
                print "PdgId : %s   pt : %s  eta : %s   phi : %s" %(p.pdgId(),p.pt(),p.eta(),p.phi())    
                print "     daughters"
                for pa in packed:
                        mother = pa.mother(0)
                        if mother and isAncestor(p,mother) :
                              print "     PdgId : %s   pt : %s  eta : %s   phi : %s" %(pa.pdgId(),pa.pt(),pa.eta(),pa.phi())

// Original Author:  Andrea RIZZI
//         Created:  Mon, 07 Jul 2014 07:56:38 GMT

// system include files
#include <memory>

// user include files
#include "FWCore/Framework/interface/Frameworkfwd.h"
#include "FWCore/Framework/interface/EDAnalyzer.h"

#include "FWCore/Framework/interface/Event.h"
#include "FWCore/Framework/interface/MakerMacros.h"

#include "FWCore/ParameterSet/interface/ParameterSet.h"
#include "DataFormats/PatCandidates/interface/PackedGenParticle.h"
#include "DataFormats/Candidate/interface/Candidate.h"
#include "DataFormats/HepMCCandidate/interface/GenParticle.h"
//
// class declaration
//

class MiniAODGenPartAnalyzer : public edm::EDAnalyzer {
   public:
      explicit MiniAODGenPartAnalyzer (const edm::ParameterSet&);
      ~MiniAODGenPartAnalyzer();
      bool isAncestor(const reco::Candidate * ancestor, const reco::Candidate * particle);

   private:
      virtual void beginJob() override;
      virtual void analyze(const edm::Event&, const edm::EventSetup&) override;
      virtual void endJob() override;

      edm::EDGetTokenT<edm::View<reco::GenParticle> > prunedGenToken_;
      edm::EDGetTokenT<edm::View<pat::PackedGenParticle> > packedGenToken_;
};

MiniAODGenPartAnalyzer::MiniAODGenPartAnalyzer(const edm::ParameterSet& iConfig):
  prunedGenToken_(consumes<edm::View<reco::GenParticle> >(iConfig.getParameter("pruned"))),
  packedGenToken_(consumes<edm::View<pat::PackedGenParticle> >(iConfig.getParameter("packed")))
{
}

MiniAODGenPartAnalyzer::~MiniAODGenPartAnalyzer()
{
}

//Check recursively if any ancestor of particle is the given one

bool MiniAODGenPartAnalyzer::isAncestor(const reco::Candidate* ancestor, const reco::Candidate * particle)
{
//particle is already the ancestor
        if(ancestor == particle ) return true;

//otherwise loop on mothers, if any and return true if the ancestor is found
        for(size_t i=0;i< particle->numberOfMothers();i++)
        {
                if(isAncestor(ancestor,particle->mother(i))) return true;
        }
//if we did not return yet, then particle and ancestor are not relatives
        return false;
}

void
MiniAODGenPartAnalyzer::analyze(const edm::Event& iEvent, const edm::EventSetup& iSetup)
{
        using namespace edm;
        using namespace reco;
        using namespace pat;

        // Pruned particles are the one containing "important" stuff
        Handle<edm::View<reco::GenParticle> > pruned;
        iEvent.getByToken(prunedGenToken_,pruned);

        // Packed particles are all the status 1, so usable to remake jets
        // The navigation from status 1 to pruned is possible (the other direction should be made by hand)
        Handle<edm::View<pat::PackedGenParticle> > packed;
        iEvent.getByToken(packedGenToken_,packed);

        //let's try to find all status1 originating directly from a B meson decay

        for(size_t i=0; isize();i++){
                if(abs((*pruned)[i].pdgId()) > 500 && abs((*pruned)[i].pdgId()) <600){
                        const Candidate * bMeson = &(*pruned)[i];
                        std::cout << "PdgID: " << bMeson->pdgId() << " pt " << bMeson->pt() << " eta: " << bMeson->eta() << " phi: " << bMeson->phi() << std::endl;
                        std::cout << "  found daugthers: " << std::endl;
                        for(size_t j=0; jsize();j++){
//get the pointer to the first survied ancestor of a given packed GenParticle in the prunedCollection
                                const Candidate * motherInPrunedCollection = (*packed)[j].mother(0) ;
                                if(motherInPrunedCollection != nullptr && isAncestor( bMeson , motherInPrunedCollection)){
                                        std::cout << "     PdgID: " << (*packed)[j].pdgId() << " pt " << (*packed)[j].pt() << " eta: " << (*packed)[j].eta() << " phi: " << (*packed)[j].phi() << std::endl;
                                }
                        }
                }

        }

}


// ------------ method called once each job just before starting event loop  ------------
        void
MiniAODGenPartAnalyzer::beginJob()
{
}

// ------------ method called once each job just after ending the event loop  ------------
        void
MiniAODGenPartAnalyzer::endJob()
{
}

DEFINE_FWK_MODULE(MiniAODGenPartAnalyzer);

Python cfg for cmsRun

import FWCore.ParameterSet.Config as cms

process = cms.Process("Demo")

process.load("FWCore.MessageService.MessageLogger_cfi")

process.maxEvents = cms.untracked.PSet( input = cms.untracked.int32(-1) )

process.source = cms.Source("PoolSource",
    fileNames = cms.untracked.vstring("root://cms-xrd-global.cern.ch//store/mc/Spring14miniaod/TTJets_MSDecaysCKM_central_Tune4C_13TeV-madgraph-tauola/MINIAODSIM/PU20bx25_POSTLS170_V5-v1/00000/F6EDDC10-8DFC-E311-BC5D-0025905A60D6.root")
)

process.demo = cms.EDAnalyzer('MiniAODGenPartAnalyzer',
packed = cms.InputTag("packedGenParticles"),
pruned = cms.InputTag("prunedGenParticles")
)

process.p = cms.Path(process.demo)

Please note that you need to the following libraries in your BuildFile.xml

DataFormats/PatCandidates
DataFormats/HepMCCandidate

Flavour information has been updated in 74X version 2 miniAODs (see 1, 2). The differences wrt to version 1 are the following:

  • hadron-based flavour is no longer given priority over the parton-based flavour. This means that partonFlavour() will return a purely parton-based flavor (in version 1 if there was a mismatch between the parton- and hadron-based flavour, the priority was given to the hadron-based flavour). The hadronFlavour() will return a purely hadron-based flavour, as was the case in version 1
  • the selection of generator partons matched to jets has been updated so that genParton().pdgId() can be used to obtain the physics definition of the jet flavour
  • generator particles used in the jet flavour definition are now selected from the prunedGenParticles collection (in version 1 the genParticles collection was used), which means that more jets will have undefined partonFlavour() because some of the soft partons, which would otherwise be used to set the jet flavor, are dropped from the prunedGenParticles collection
  • generator leptons are clustered by default, in addition to generator partons and hadrons. This is potentially useful for identifying jets from hadronic tau decays
  • JetFlavourInfo is embedded into PAT jets by default making it possible to get additional information about the clustered generator-level partons, hadrons, and leptons
For more information about different jet flavour definitions, please refer to SWGuideBTagMCTools.

GenJets

One collections of gen jets is saved, slimmedGenJets, made from ak4GenJets, i.e. using anti-kT clustering out of stable gen particles. Starting from 74X neutrinos and other invisible BSM particles are excluded from GenJets, while they were included in CMSSW 70X (CSA14) and 72X (Phys14) campaigns.

Links to the daughters are available through the daughter(idx) and numberOfDaughters() methods, and they will point into the collection of packed gen candidates described below.
It should be noted that the getGenConstituents method instead will NOT work, since they explicitly require the daughter to be a full reco::GenParticle and not a packed one. Issues with missing daughter references that affected forward jets in CSA14 and Phys14 campaigns should be solved now in 74X, for jets within the detector acceptance.

Trigger

HLT Trigger bits for each path are stored as edm::TriggerResults, as standard in CMSSW.

In order to access paths by trigger name, you can get an edm::TriggerNames instance from the Event (both in full framework and in fwlite, see example at the bottom of the section), which translates indices in names. The mapping is the same in all events sharing the same trigger configuration (which is identified by the parameterSetID() method of the trigger results object).

Trigger objects associated to filters in the HLT are saved as instances of pat::TriggerObjectStandAlone, so that they can be used e.g. for trigger matching and measurements of trigger efficiency with the tag-and-probe method. The trigger names stored in the objects are packed, but they can be unpacked by passing an edm::TriggerNames instance, as shown in the example code at the bottom of this section.

Trigger prescales are encoded for each path into an pat::PackedTriggerPrescales, which can be unpacked with an edm::TriggerNames if access by path name is needed, just like for the TriggerResults.

  • The L1 prescales are also saved. Since a single HLT path may be seeded by multiple L1s with different prescales, there are two collections with instance labels "l1min" and "l1max": those are the maximum and minimum non-zero prescale for a given path. Useful cases are l1min = 1 (at least one seed is unprescaled), and l1min = l1max (the path has only one L1 seed, or all seeds have with the same prescale); paths which do not fall in either of the two cases should probably be handled with more care using the HLTConfigProvider (which works also on miniAOD, Not yet tested on 2016 data with stage2 L1)
  • Trigger prescales for paths that have a prescale dependent on the luminosity are not reported correctly in PromptReco data. We're working at it. See below for how to access the prescale column, this may enough.
    HLT Prescales have been correct starting from Run2016 C, while L1 are probably still wrong.

L1 trigger objects are available in the form of BXVectors containing the primitives in each bunch crossing. The collections are gmtStage2Digis:Muon, caloStage2Digis:EGamma, caloStage2Digis:EtSum, caloStage2Digis:Jet, caloStage2Digis:Tau and the corresponding dataformats can be found under DataFormats/L1Trigger. For the EtSum objects, the getType() method can be used determine the type of sum (ET, ETmiss, HT, HTmiss), as they're all dumped in the same BXVector.
L1 algorithm trigger bits are available as BXVectors of GlobalAlgBlk gtStage2Digis, but at the moment we don't know a way to translate the bits into names that works in FWLite.
The prescale column can be accessed from the BXVector of GlobalAlgBlk as bxvec.at(0,0).getPreScColumn() (This is tested and working on 2016 data, also on PromptReco )

Events contain also the old l1extra and L1GlobalTriggerReadoutRecord objects, but they should be ignored since they're not relevant for 2016 data.

EDAnalyzer code
// system include files
#include <memory>
#include <cmath>

// user include files
#include "FWCore/Framework/interface/Frameworkfwd.h"
#include "FWCore/Framework/interface/EDAnalyzer.h"
#include "FWCore/Framework/interface/Event.h"
#include "FWCore/Framework/interface/MakerMacros.h"
#include "FWCore/ParameterSet/interface/ParameterSet.h"

#include "DataFormats/Math/interface/deltaR.h"
#include "FWCore/Common/interface/TriggerNames.h"
#include "DataFormats/Common/interface/TriggerResults.h"
#include "DataFormats/PatCandidates/interface/TriggerObjectStandAlone.h"
#include "DataFormats/PatCandidates/interface/PackedTriggerPrescales.h"

class MiniAODTriggerAnalyzer : public edm::EDAnalyzer {
   public:
      explicit MiniAODTriggerAnalyzer (const edm::ParameterSet&);
      ~MiniAODTriggerAnalyzer() {}

   private:
      virtual void analyze(const edm::Event&, const edm::EventSetup&) override;

      edm::EDGetTokenT triggerBits_;
      edm::EDGetTokenT triggerObjects_;
      edm::EDGetTokenT triggerPrescales_;
};

MiniAODTriggerAnalyzer::MiniAODTriggerAnalyzer(const edm::ParameterSet& iConfig):
    triggerBits_(consumes(iConfig.getParameter("bits"))),
    triggerObjects_(consumes(iConfig.getParameter("objects"))),
    triggerPrescales_(consumes(iConfig.getParameter("prescales")))
{
}

void MiniAODTriggerAnalyzer::analyze(const edm::Event& iEvent, const edm::EventSetup& iSetup)
{
    edm::Handle triggerBits;
    edm::Handle triggerObjects;
    edm::Handle triggerPrescales;

    iEvent.getByToken(triggerBits_, triggerBits);
    iEvent.getByToken(triggerObjects_, triggerObjects);
    iEvent.getByToken(triggerPrescales_, triggerPrescales);

    const edm::TriggerNames &names = iEvent.triggerNames(*triggerBits);
    std::cout << "\n == TRIGGER PATHS= " << std::endl;
    for (unsigned int i = 0, n = triggerBits->size(); i < n; ++i) {
        std::cout << "Trigger " << names.triggerName(i) <<
                ", prescale " << triggerPrescales->getPrescaleForIndex(i) <<
                ": " << (triggerBits->accept(i) ? "PASS" : "fail (or not run)")
                << std::endl;
    }
    std::cout << "\n TRIGGER OBJECTS " << std::endl;
    for (pat::TriggerObjectStandAlone obj : *triggerObjects) { // note: not "const &" since we want to call unpackPathNames
        obj.unpackPathNames(names);
        std::cout << "\tTrigger object:  pt " << obj.pt() << ", eta " << obj.eta() << ", phi " << obj.phi() << std::endl;
        // Print trigger object collection and type
        std::cout << "\t   Collection: " << obj.collection() << std::endl;
        std::cout << "\t   Type IDs:   ";
        for (unsigned h = 0; h < obj.filterIds().size(); ++h) std::cout << " " << obj.filterIds()[h] ;
        std::cout << std::endl;
        // Print associated trigger filters
        std::cout << "\t   Filters:    ";
        for (unsigned h = 0; h < obj.filterLabels().size(); ++h) std::cout << " " << obj.filterLabels()[h];
        std::cout << std::endl;
        std::vector pathNamesAll  obj.pathNames(false);
        std::vector pathNamesLast = obj.pathNames(true);
        // Print all trigger paths, for each one record also if the object is associated to a 'l3' filter (always true for the
        // definition used in the PAT trigger producer) and if it's associated to the last filter of a successfull path (which
        // means that this object did cause this trigger to succeed; however, it doesn't work on some multi-object triggers)
        std::cout << "\t   Paths (" << pathNamesAll.size()<<"/"<<pathNamesLast.size()<<"):    ";
        for (unsigned h = 0, n = pathNamesAll.size(); h < n; ++h) {
            bool isBoth = obj.hasPathName( pathNamesAll[h], true, true );
            bool isL3   = obj.hasPathName( pathNamesAll[h], false, true );
            bool isLF   = obj.hasPathName( pathNamesAll[h], true, false );
            bool isNone = obj.hasPathName( pathNamesAll[h], false, false );
            std::cout << "   " << pathNamesAll[h];
            if (isBoth) std::cout << "(L,3)";
            if (isL3 && !isBoth) std::cout << "(*,3)";
            if (isLF && !isBoth) std::cout << "(L,*)";
            if (isNone && !isBoth && !isL3 && !isLF) std::cout << "(*,*)";
        }
        std::cout << std::endl;
    }
    std::cout << std::endl;

}


//define this as a plug-in
DEFINE_FWK_MODULE(MiniAODTriggerAnalyzer);

Python configuration

import FWCore.ParameterSet.Config as cms

process = cms.Process("Demo")

process.load("FWCore.MessageService.MessageLogger_cfi")
process.maxEvents = cms.untracked.PSet( input = cms.untracked.int32(10) )

process.source = cms.Source("PoolSource",
    fileNames = cms.untracked.vstring(
        '/store/cmst3/user/gpetrucc/miniAOD/v1/TT_Tune4C_13TeV-pythia8-tauola_PU_S14_PAT.root'
    )
)

process.demo = cms.EDAnalyzer("MiniAODTriggerAnalyzer",
    bits = cms.InputTag("TriggerResults","","HLT"),
    prescales = cms.InputTag("patTrigger"),
    objects = cms.InputTag("selectedPatTrigger"),
)

process.p = cms.Path(process.demo)

# import ROOT in batch mode
import sys
oldargv = sys.argv[:]
sys.argv = [ '-b-' ]
import ROOT
ROOT.gROOT.SetBatch(True)
sys.argv = oldargv

# load FWLite C++ libraries
ROOT.gSystem.Load("libFWCoreFWLite.so");
ROOT.gSystem.Load("libDataFormatsFWLite.so");
ROOT.FWLiteEnabler.enable()

# load FWlite python libraries
from DataFormats.FWLite import Handle, Events

triggerBits, triggerBitLabel = Handle("edm::TriggerResults"), ("TriggerResults","","HLT")
triggerObjects, triggerObjectLabel  = Handle("std::vector<pat::TriggerObjectStandAlone>"), "slimmedPatTrigger"
triggerPrescales, triggerPrescaleLabel  = Handle("pat::PackedTriggerPrescales"), "patTrigger"
l1Muons, l1MuonLabel  = Handle("BXVector"), "gmtStage2Digis:Muon"
l1EGammas, l1EGammaLabel  = Handle("BXVector"), "caloStage2Digis:EGamma"
l1Jets, l1JetLabel  = Handle("BXVector"), "caloStage2Digis:Jet"
l1EtSums, l1EtSumLabel  = Handle("BXVector"), "caloStage2Digis:EtSum"
l1Taus, l1TauLabel  = Handle("BXVector"), "caloStage2Digis:Tau"

events = Events(sys.argv[1])

for iev,event in enumerate(events):
    event.getByLabel(triggerBitLabel, triggerBits)
    event.getByLabel(triggerObjectLabel, triggerObjects)
    event.getByLabel(triggerPrescaleLabel, triggerPrescales)
    event.getByLabel(l1MuonLabel, l1Muons)
    event.getByLabel(l1EGammaLabel, l1EGammas)
    event.getByLabel(l1JetLabel, l1Jets)
    event.getByLabel(l1EtSumLabel, l1EtSums)
    event.getByLabel(l1TauLabel, l1Taus)

    print "\nEvent %d: run %6d, lumi %4d, event %12d" % (iev,event.eventAuxiliary().run(), event.eventAuxiliary().luminosityBlock(),event.eventAuxiliary().event())
    print "\n === TRIGGER PATHS ==="
    names = event.object().triggerNames(triggerBits.product())
    for i in xrange(triggerBits.product().size()):
        print "Trigger ", names.triggerName(i), ", prescale ", triggerPrescales.product().getPrescaleForIndex(i), ": ", ("PASS" if triggerBits.product().accept(i) else "fail (or not run)")

    print "\n === TRIGGER OBJECTS ==="
    for j,to in enumerate(triggerObjects.product()):
        to.unpackNamesAndLabels(event.object(), triggerBits.product());
        print "Trigger object pt %6.2f eta %+5.3f phi %+5.3f  " % (to.pt(),to.eta(),to.phi())
        print "         collection: ", to.collection()
        print "         type ids: ", ", ".join([str(f) for f in to.filterIds()])
        print "         filters: ", ", ".join([str(f) for f in to.filterLabels()])
        pathslast = set(to.pathNames(True))
        print "         paths:   ", ", ".join([("%s*" if f in pathslast else "%s")%f for f in to.pathNames()])

    print "\n === BARE L1 OBJECTS ==="
    for where, what in (l1Muons, l1MuonLabel), (l1EGammas, l1EGammaLabel), (l1Jets, l1JetLabel), (l1Taus, l1TauLabel):
        shortname = what.split(":")[1]
        bxvector = where.product()
        for bx in 0,: # xrange(bxvector.getFirstBX(), bxvector.getLastBX()+1): # typically we want only bx=0
            for i in xrange(bxvector.size(bx)):
                l1obj = bxvector.at(bx,i)
                if shortname != "Muon" and l1obj.pt() &lt;= 0.01: continue
                print "%-10s  bx %+1d  pt %6.2f eta %+5.3f phi %+5.3f " % (shortname, bx, l1obj.pt(), l1obj.eta(), l1obj.phi())
    for shortname in ("TotalEt", "TotalHt", "MissingEt", "MissingHt"):
        bxvector = l1EtSums.product()
        for bx in 0,: # xrange(bxvector.getFirstBX(), bxvector.getLastBX()+1): # typically we want only bx=0
            for i in xrange(bxvector.size(bx)):
                l1obj = bxvector.at(bx,i)
                if l1obj.getType() != getattr(l1obj, "k"+shortname): continue
                print "%-10s  bx %+1d  pt %6.2f eta %+5.3f phi %+5.3f " % (shortname, bx, l1obj.pt(), l1obj.eta(), l1obj.phi())
    if iev > 10: break

Miscellanea

Primary vertices and BeamSpot

The BeamSpot is copied as is from the AOD in the offlineBeamSpot collection.

For the primary vertices, a collection offlineSlimmedPrimaryVertices is provided, that has the same content as the AOD offlinePrimaryVertices collection. Slimmed primary vertices differ from the AOD collection as follows:

  • vertices don't contain track references, but the association of candidates to vertices is provided in the packed candidates themself
  • the primary vertex covariance matrix for vertices beyond the first one are stored in reduced precision

In addition the score used to rank primary vertices is stored in floatedmValueMap_offlineSlimmedPrimaryVertices__PAT.

Secondary Vertices and V0s

s TODO: AR to fill this

Pileup Summary Info

The MC truth information about pileup is available in the form of a vector of PileupSummaryInfo objects for the different bunch crossings: The collection is slimmedAddPileupInfo and is slimmed by not saving the detailed information for the out-of-time bunch crossings.

ETmiss filters

Some filters for ETmiss cleaning are run at MiniAOD production stage, and saved as a trigger results (an edm::TriggerResults of the RECO or PAT process, depeding on whether MiniAOD was produced simultaneously with RECO or as a separate step). Remember, Trigger bits for each path are stored as edm::TriggerResults, as standard in CMSSW. The ETmiss cleaning filters are run in separate paths and the path success/failure is saved as the filter decision bit.

The individual filters can be accessed with the same code as for the HLT paths, except of course for the process name.

  • In addition, some summary objects that can be used to study / re-optimize implement MET filters on the fly are available:
    • HCAL noise information can be accessed from: HcalNoiseSummary object hcalnoise
    • Halo data can be accessed from: CSCHaloData , BeamHaloSummary

Bunch spacing

The events contain a per-event unsigned int product bunchSpacingProducer saying whether the given event has 50ns or 25ns bunch spacing. As all 2016 data and MC is 25ns, this is no longer terribly useful.

Fast-jet rhos

miniAODs contain four generally-useful rho variables

  • fixedGridRhoFastjetAll : computed from all PF candidates
  • fixedGridRhoFastjetCentral : computed from all PF candidates with |η| < 2.5
  • fixedGridRhoFastjetCentralNeutral computed from all neutral PF candidates with |η| < 2.5 (neutral hadrons and photons)
  • fixedGridRhoFastjetCentralChargedPileUp computed from all PF charged hadrons associated to pileup vertices and with |η| < 2.5

Advanced topics: re-clustering, event interpretation

The following example shows how to re-run jet reconstruction with a different algorithm (in the example using AK5 instead of miniAOD default that is ak4). The example also shows how to rerun b-tagging. Note that this procedure is only valid when a new jet collection is needed, which is not present in the miniAOD files. In other cases, please, refer to this instructions, for accessing b tag discriminators from miniAOD or in order to update b tagging information for jet collections existing in miniAOD.

import FWCore.ParameterSet.Config as cms

from [[FWCore.ParameterSet.VarParsing]] import VarParsing

process = cms.Process("USER")

process.load("Configuration.StandardSequences.MagneticField_cff")
process.load("Configuration.Geometry.GeometryRecoDB_cff")
process.load("Configuration.StandardSequences.FrontierConditions_GlobalTag_cff")
from [[Configuration.AlCa.GlobalTag]] import GlobalTag
process.GlobalTag = GlobalTag (process.GlobalTag, 'auto:run2_mc')

## Events to process
process.maxEvents = cms.untracked.PSet( input = cms.untracked.int32(10) )

## Input files
process.source = cms.Source("PoolSource",
    fileNames = cms.untracked.vstring(
        '/store/relval/CMSSW_7_4_1/RelValTTbar_13/MINIAODSIM/PU50ns_MCRUN2_74_V8_gensim_740pre7-v1/00000/7EC72BA9-44EC-E411-9DF3-0025905A60B0.root'
    )
)

## Output file
from PhysicsTools.PatAlgos.patEventContent_cff import patEventContent
process.OUT = cms.OutputModule("PoolOutputModule",
    fileName = cms.untracked.string('test.root'),
    outputCommands = cms.untracked.vstring(['drop *','keep patJets_selectedPatJetsAK5PFCHS_*_*'])
)
process.endpath= cms.EndPath(process.OUT)

#################################################
## Remake jets
#################################################

## Filter out neutrinos from packed GenParticles
process.packedGenParticlesForJetsNoNu = cms.EDFilter("CandPtrSelector", src = cms.InputTag("packedGenParticles"), cut = cms.string("abs(pdgId) != 12 && abs(pdgId) != 14 && abs(pdgId) != 16"))
## Define GenJets
from RecoJets.JetProducers.ak5GenJets_cfi import ak5GenJets
process.ak5GenJetsNoNu = ak5GenJets.clone(src = 'packedGenParticlesForJetsNoNu')

## Select charged hadron subtracted packed PF candidates
process.pfCHS = cms.EDFilter("CandPtrSelector", src = cms.InputTag("packedPFCandidates"), cut = cms.string("fromPV"))
from RecoJets.JetProducers.ak5PFJets_cfi import ak5PFJets
## Define PFJetsCHS
process.ak5PFJetsCHS = ak5PFJets.clone(src = 'pfCHS', doAreaFastjet = True)

#################################################
## Remake PAT jets
#################################################

## b-tag discriminators
bTagDiscriminators = [
    'pfCombinedInclusiveSecondaryVertexV2BJetTags'
]

from PhysicsTools.PatAlgos.tools.jetTools import *
## Add PAT jet collection based on the above-defined ak5PFJetsCHS
addJetCollection(
    process,
    labelName = 'AK5PFCHS',
    jetSource = cms.InputTag('ak5PFJetsCHS'),
    pvSource = cms.InputTag('offlineSlimmedPrimaryVertices'),
    pfCandidates = cms.InputTag('packedPFCandidates'),
    svSource = cms.InputTag('slimmedSecondaryVertices'),
    btagDiscriminators = bTagDiscriminators,
    jetCorrections = ('AK5PFchs', ['L1FastJet', 'L2Relative', 'L3Absolute'], 'None'),
    genJetCollection = cms.InputTag('ak5GenJetsNoNu'),
    genParticles = cms.InputTag('prunedGenParticles'),
    algo = 'AK',
    rParam = 0.5
)

getattr(process,'selectedPatJetsAK5PFCHS').cut = cms.string('pt > 10')

process.p = cms.Path(process.selectedPatJetsAK5PFCHS)

from PhysicsTools.PatAlgos.tools.pfTools import *
## Adapt primary vertex collection
adaptPVs(process, pvCollection=cms.InputTag('offlineSlimmedPrimaryVertices'))

process.options = cms.untracked.PSet(
        wantSummary = cms.untracked.bool(True), # while the timing of this is not reliable in unscheduled mode, it still helps understanding what was actually run
        allowUnscheduled = cms.untracked.bool(True)
)

Event interpretations can be easily run starting from miniAOD with the following differences with respect to standard EI

  • The input candidates are the packedCandidates
  • The selector should be CandPtrSelector so that the Ptr to the original candidates are always kept
  • The projector to use should be CandPtrProjector

The following code shows a commented example of EI configuration.

import FWCore.ParameterSet.Config as cms

process = cms.Process("EX")
# Input source
process.source = cms.Source("PoolSource",
                                fileNames = cms.untracked.vstring(
        '/store/relval/CMSSW_7_4_1/RelValTTbar_13/MINIAODSIM/PU50ns_MCRUN2_74_V8_gensim_740pre7-v1/00000/7EC72BA9-44EC-E411-9DF3-0025905A60B0.root'
    )
)

process.maxEvents = cms.untracked.PSet( input = cms.untracked.int32(10) )

#select isolated  muons and electrons collections
#tune the requirements to whatever ID and isolation you prefer

process.selectedMuons = cms.EDFilter("CandPtrSelector", src = cms.InputTag("slimmedMuons"), cut = cms.string('''abs(eta)10. &&
       (pfIsolationR04().sumChargedHadronPt+
   max(0.,pfIsolationR04().sumNeutralHadronEt+
   pfIsolationR04().sumPhotonEt-
   1 50*pfIsolationR04().sumPUPt))/pt < 0.20 &&
   (isPFMuon && (isGlobalMuon || isTrackerMuon) )'''))
process.selectedElectrons = cms.EDFilter("CandPtrSelector", src = cms.InputTag("slimmedElectrons"), cut = cms.string('''abs(eta)20. &&
   gsfTrack.isAvailable() &&
   gsfTrack.hitPattern().numberOfLostHits(\'MISSING_INNER_HITS\') < 2 &&
   (pfIsolationVariables().sumChargedHadronPt+
   max(0.,pfIsolationVariables().sumNeutralHadronEt+
   pfIsolationVariables().sumPhotonEt-
   1 5*pfIsolationVariables().sumPUPt))/pt < 0.15'''))
## Do projections
process.pfCHS = cms.EDFilter("CandPtrSelector", src = cms.InputTag("packedPFCandidates"), cut = cms.string("fromPV"))
process.pfNoMuonCHS =  cms.EDProducer("CandPtrProjector", src = cms.InputTag("pfCHS"), veto = cms.InputTag("selectedMuons"))
process.pfNoElectronsCHS = cms.EDProducer("CandPtrProjector", src = cms.InputTag("pfNoMuonCHS"), veto = cms.InputTag("selectedElectrons"))

#Import RECO jet producer for ak4 PF and GEN jet
from RecoJets.JetProducers.ak4PFJets_cfi import ak4PFJets
from RecoJets.JetProducers.ak4GenJets_cfi import ak4GenJets
process.ak4PFJetsCHS = ak4PFJets.clone(src = 'pfNoElectronsCHS', doAreaFastjet = True)
process.packedGenParticlesForJetsNoNu = cms.EDFilter("CandPtrSelector", src = cms.InputTag("packedGenParticles"), cut = cms.string("abs(pdgId) != 12 && abs(pdgId) != 14 && abs(pdgId) != 16"))
process.ak4GenJetsNoNu = ak4GenJets.clone(src = 'packedGenParticlesForJetsNoNu')

# The following is make patJets, but EI is done with the above
process.load("Configuration.StandardSequences.MagneticField_cff")
process.load("Configuration.Geometry.GeometryRecoDB_cff")
process.load("Configuration.StandardSequences.FrontierConditions_GlobalTag_cff")
from [[Configuration.AlCa.GlobalTag]] import GlobalTag
process.GlobalTag = GlobalTag (process.GlobalTag, 'auto:run2_mc')

bTagDiscriminators = [
    'pfCombinedInclusiveSecondaryVertexV2BJetTags'
]

from PhysicsTools.PatAlgos.tools.jetTools import addJetCollection
addJetCollection(
    process,
    labelName = 'AK4PFCHS',
    jetSource = cms.InputTag('ak4PFJetsCHS'),
    pvSource = cms.InputTag('offlineSlimmedPrimaryVertices'),
    pfCandidates = cms.InputTag('packedPFCandidates'),
    svSource = cms.InputTag('slimmedSecondaryVertices'),
    btagDiscriminators = bTagDiscriminators,
    jetCorrections = ('AK4PFchs', ['L1FastJet', 'L2Relative', 'L3Absolute'], 'None'),
    genJetCollection = cms.InputTag('ak4GenJetsNoNu'),
    genParticles = cms.InputTag('prunedGenParticles'),
    algo = 'AK',
    rParam = 0.4
)

#adjust PV used for Jet Corrections
process.patJetCorrFactorsAK4PFCHS.primaryVertices = "offlineSlimmedPrimaryVertices"

#new PAT default running is "unscheduled" so we just need to say in the outputCommands what we want to store
process.options = cms.untracked.PSet(
        allowUnscheduled = cms.untracked.bool(True)
)

process.OUT = cms.OutputModule("PoolOutputModule",
    fileName = cms.untracked.string('test.root'),
    outputCommands = cms.untracked.vstring(['drop *','keep patJets_patJetsAK4PFCHS_*_*','keep *_*_*_PAT'])
)

process.endpath= cms.EndPath(process.OUT)

Producing MiniAOD

To run miniAOD, use cmsDriver to create a cfg file, specifying the kind of data and the global tag

cmsDriver.py miniAOD-prod -s PAT --eventcontent [ MINIAOD | MINIAODSIM ] --runUnscheduled [ --data | --mc [ --fast ] ] --filein xxx  --conditions yyy --era era  --no_exec

(the --fast is needed on fast sim to switch off some MET filters)

for example, for 80X MiniAOD v2 MC in CMSSW_8_0_5_patch1 (the patch1 part is important for data, it makes no difference on MC that lacks trigger information)

cmsDriver.py miniAOD-prod -s PAT --eventcontent MINIAODSIM --runUnscheduled --mc  --conditions 80X_mcRun2_asymptotic_2016_miniAODv2 --era Run2_2016  --no_exec --filein /store/relval/CMSSW_8_0_3/RelValTTbar_13/GEN-SIM-RECO/80X_mcRun2_asymptotic_2016_v3_gs7120p2NewGTv3-v1/00000/42BE3BF8-A7F0-E511-B6FA-0025905A612A.root

while for 80X MiniAOD v1 in CMSSW_8_0_3_patch1

cmsDriver.py miniAOD-prod -s PAT --eventcontent MINIAODSIM --runUnscheduled --mc  --conditions 80X_mcRun2_asymptotic_2016_v3 --era Run2_25ns  --no_exec --filein /store/relval/CMSSW_8_0_3/RelValTTbar_13/GEN-SIM-RECO/80X_mcRun2_asymptotic_2016_v3_gs7120p2NewGTv3-v1/00000/42BE3BF8-A7F0-E511-B6FA-0025905A612A.root

If you have to run on some input file that does not contain any HLT trigger information at all, e.g. from a private production or for the 2017 upgrade scenario, you can disable the HLT in MiniAOD adding to your cmsDriver command the option --customise_commands 'del process.patTrigger; del process.selectedPatTrigger' This is not needed on the 80X background MC samples, which contain some dummy HLT information.

The right and most recent global tag for a release can also be obtained with the auto: syntax in cmsDriver, for example auto:run2_mc automatically expands to the right GT for run2 MC with 25ns bunch spacing scenario. The full list of available tags is printed by cmsDriver if the --conditions option is omitted.

Edit | Attach | Watch | Print version | History: r23 | r12 < r11 < r10 < r9 | Backlinks | Raw View | Raw edit | More topic actions...
Topic revision: r10 - 2017-10-01 - WillemVerbeke
 
    • Cern Search Icon Cern Search
    • TWiki Search Icon TWiki Search
    • Google Search Icon Google Search

    CMSPublic All webs login

This site is powered by the TWiki collaboration platform Powered by PerlCopyright &© 2008-2023 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
or Ideas, requests, problems regarding TWiki? use Discourse or Send feedback