Repository: kerstinlovisa/EXOnanoAOD
Pull request #4: Displaced jet
Author: login: kskovpen
Created: 2025-03-21T12:49:11Z | Merged: 2025-05-16T11:25:03Z

First version of the DisplacedJet analysis module for EXOnanoAOD


Diff:
diff --git a/plugins/DSAMuonTableProducer.cc b/plugins/DSAMuonTableProducer.cc
index f129014..764fb45 100644
--- a/plugins/DSAMuonTableProducer.cc
+++ b/plugins/DSAMuonTableProducer.cc
@@ -22,12 +22,14 @@
 #include "DataFormats/VertexReco/interface/VertexFwd.h"
 #include "DataFormats/VertexReco/interface/Vertex.h"
 
+#include "DataFormats/PatCandidates/interface/PackedCandidate.h"
 
 class DSAMuonTableProducer : public edm::global::EDProducer<> {
   public:
     DSAMuonTableProducer(const edm::ParameterSet &iConfig)
       :
-      dsaMuonTag_(consumes<std::vector<reco::Track>>(iConfig.getParameter<edm::InputTag>("dsaMuons"))),
+      //      dsaMuonTag_(consumes<std::vector<reco::Track>>(iConfig.getParameter<edm::InputTag>("dsaMuons"))),
+      dsaMuonTag_(consumes<edm::View<pat::PackedCandidate>>(iConfig.getParameter<edm::InputTag>("dsaMuons"))),
       muonTag_(consumes<std::vector<pat::Muon>>(iConfig.getParameter<edm::InputTag>("muons"))),
       vtxTag_(consumes<reco::VertexCollection>(iConfig.getParameter<edm::InputTag>("primaryVertex"))),
       bsTag_(consumes<reco::BeamSpot>(iConfig.getParameter<edm::InputTag>("beamspot"))),
@@ -58,7 +60,8 @@ class DSAMuonTableProducer : public edm::global::EDProducer<> {
     int getDTSegments(const reco::Track& dsaMuon) const;
     int getCSCSegments(const reco::Track& dsaMuon) const;
 
-    edm::EDGetTokenT<std::vector<reco::Track>> dsaMuonTag_;
+  //    edm::EDGetTokenT<std::vector<reco::Track>> dsaMuonTag_;
+    edm::EDGetTokenT<edm::View<pat::PackedCandidate>> dsaMuonTag_;
     edm::EDGetTokenT<std::vector<pat::Muon>> muonTag_;
     edm::EDGetTokenT<reco::VertexCollection> vtxTag_;
     edm::EDGetTokenT<reco::BeamSpot> bsTag_;
@@ -137,8 +140,8 @@ void DSAMuonTableProducer::produce(edm::StreamID, edm::Event& iEvent, const edm:
     trkNumCSCHits.push_back(dsaMuon.hitPattern().numberOfValidMuonCSCHits());
     normChi2.push_back(dsaMuon.normalizedChi2());
 
-    outerEta.push_back(dsaMuon.outerEta());
-    outerPhi.push_back(dsaMuon.outerPhi());
+    outerEta.push_back(dsaMuon.extra().isNonnull() && dsaMuon.extra().isAvailable() ? dsaMuon.outerEta() : -999);
+    outerPhi.push_back(dsaMuon.extra().isNonnull() && dsaMuon.extra().isAvailable() ? dsaMuon.outerPhi() : -999);
 
     dzPV.push_back(dsaMuon.dz(pv.position()));
     dzPVErr.push_back(std::hypot(dsaMuon.dzError(), pv.zError()));
@@ -327,27 +330,30 @@ bool DSAMuonTableProducer::passesDisplacedID(const reco::Track& dsaMuon) const {
 int DSAMuonTableProducer::getMatches(const pat::Muon& muon, const reco::Track& dsaMuon, float minPositionDiff) const {
 
   int nMatches = 0;
-  
-  for (auto& hit : dsaMuon.recHits()){
-
-    if (!hit->isValid()) continue;
-    DetId id = hit->geographicalId();
-    if (id.det() != DetId::Muon) continue;
-
-    if (id.subdetId() == MuonSubdetId::DT || id.subdetId() == MuonSubdetId::CSC){
 
-      for (auto& chamber : muon.matches()) {
-
-        if (chamber.id.rawId() != id.rawId()) continue;
-
-        for (auto& segment : chamber.segmentMatches) {
-          
-          if (fabs(segment.x - hit->localPosition().x()) < minPositionDiff &&
-              fabs(segment.y - hit->localPosition().y()) < minPositionDiff) {
+  if( dsaMuon.extra().isNonnull() && dsaMuon.extra().isAvailable() ) {
+    
+    for (auto& hit : dsaMuon.recHits()){
+
+      if (!hit->isValid()) continue;
+      DetId id = hit->geographicalId();
+      if (id.det() != DetId::Muon) continue;
+      
+      if (id.subdetId() == MuonSubdetId::DT || id.subdetId() == MuonSubdetId::CSC){
+
+	for (auto& chamber : muon.matches()) {
+	  
+	  if (chamber.id.rawId() != id.rawId()) continue;
+	  
+	  for (auto& segment : chamber.segmentMatches) {
+	    
+	    if (fabs(segment.x - hit->localPosition().x()) < minPositionDiff &&
+		fabs(segment.y - hit->localPosition().y()) < minPositionDiff) {
               nMatches++;
               break;
-          }
-        }
+	    }
+	  }
+	}
       }
     }
   }
@@ -358,26 +364,29 @@ int DSAMuonTableProducer::getDTMatches(const pat::Muon& muon, const reco::Track&
 
   int nMatches = 0;
 
-  for (auto& hit : dsaMuon.recHits()){
-
-    if (!hit->isValid()) continue;
-    DetId id = hit->geographicalId();
-    if (id.det() != DetId::Muon) continue;
-
-    if (id.subdetId() == MuonSubdetId::DT){
-
-      for (auto& chamber : muon.matches()) {
-
-        if (chamber.id.rawId() != id.rawId()) continue;
-
-        for (auto& segment : chamber.segmentMatches) {
-
-          if (fabs(segment.x - hit->localPosition().x()) < minPositionDiff &&
-              fabs(segment.y - hit->localPosition().y()) < minPositionDiff) {
+  if( dsaMuon.extra().isNonnull() && dsaMuon.extra().isAvailable() ) {
+    
+    for (auto& hit : dsaMuon.recHits()){
+      
+      if (!hit->isValid()) continue;
+      DetId id = hit->geographicalId();
+      if (id.det() != DetId::Muon) continue;
+      
+      if (id.subdetId() == MuonSubdetId::DT){
+	
+	for (auto& chamber : muon.matches()) {
+	  
+	  if (chamber.id.rawId() != id.rawId()) continue;
+	  
+	  for (auto& segment : chamber.segmentMatches) {
+	    
+	    if (fabs(segment.x - hit->localPosition().x()) < minPositionDiff &&
+		fabs(segment.y - hit->localPosition().y()) < minPositionDiff) {
               nMatches++;
               break;
-          }
-        }
+	    }
+	  }
+	}
       }
     }
   }
@@ -388,26 +397,29 @@ int DSAMuonTableProducer::getCSCMatches(const pat::Muon& muon, const reco::Track
 
   int nMatches = 0;
 
-  for (auto& hit : dsaMuon.recHits()){
-
-    if (!hit->isValid()) continue;
-    DetId id = hit->geographicalId();
-    if (id.det() != DetId::Muon) continue;
-
-    if (id.subdetId() == MuonSubdetId::CSC){
-
-      for (auto& chamber : muon.matches()) {
-
-        if (chamber.id.rawId() != id.rawId()) continue;
-
-        for (auto& segment : chamber.segmentMatches) {
-
-          if (fabs(segment.x - hit->localPosition().x()) < minPositionDiff &&
-              fabs(segment.y - hit->localPosition().y()) < minPositionDiff) {
+  if( dsaMuon.extra().isNonnull() && dsaMuon.extra().isAvailable() ) {
+    
+    for (auto& hit : dsaMuon.recHits()){
+      
+      if (!hit->isValid()) continue;
+      DetId id = hit->geographicalId();
+      if (id.det() != DetId::Muon) continue;
+      
+      if (id.subdetId() == MuonSubdetId::CSC){
+	
+	for (auto& chamber : muon.matches()) {
+	  
+	  if (chamber.id.rawId() != id.rawId()) continue;
+	  
+	  for (auto& segment : chamber.segmentMatches) {
+	    
+	    if (fabs(segment.x - hit->localPosition().x()) < minPositionDiff &&
+		fabs(segment.y - hit->localPosition().y()) < minPositionDiff) {
               nMatches++;
               break;
-          }
-        }
+	    }
+	  }
+	}
       }
     }
   }
@@ -416,33 +428,39 @@ int DSAMuonTableProducer::getCSCMatches(const pat::Muon& muon, const reco::Track
 
 int DSAMuonTableProducer::getTotSegments(const reco::Track& dsaMuon) const {
   int nHits = 0;
-  for (auto& hit : dsaMuon.recHits()){
-    if (!hit->isValid()) continue;
-    DetId id = hit->geographicalId();
-    if (id.det() != DetId::Muon) continue;
-    if (id.subdetId() == MuonSubdetId::DT || id.subdetId() == MuonSubdetId::CSC) nHits++;
+  if( dsaMuon.extra().isNonnull() && dsaMuon.extra().isAvailable() ) {
+    for (auto& hit : dsaMuon.recHits()){
+      if (!hit->isValid()) continue;
+      DetId id = hit->geographicalId();
+      if (id.det() != DetId::Muon) continue;
+      if (id.subdetId() == MuonSubdetId::DT || id.subdetId() == MuonSubdetId::CSC) nHits++;
+    }
   }
   return nHits;
 }
 
 int DSAMuonTableProducer::getDTSegments(const reco::Track& dsaMuon) const {
   int nHits = 0;
-  for (auto& hit : dsaMuon.recHits()){
-    if (!hit->isValid()) continue;
-    DetId id = hit->geographicalId();
-    if (id.det() != DetId::Muon) continue;
-    if (id.subdetId() == MuonSubdetId::DT) nHits++;
+  if( dsaMuon.extra().isNonnull() && dsaMuon.extra().isAvailable() ) {
+    for (auto& hit : dsaMuon.recHits()){
+      if (!hit->isValid()) continue;
+      DetId id = hit->geographicalId();
+      if (id.det() != DetId::Muon) continue;
+      if (id.subdetId() == MuonSubdetId::DT) nHits++;
+    }
   }
   return nHits;
 }
 
 int DSAMuonTableProducer::getCSCSegments(const reco::Track& dsaMuon) const {
   int nHits = 0;
-  for (auto& hit : dsaMuon.recHits()){
-    if (!hit->isValid()) continue;
-    DetId id = hit->geographicalId();
-    if (id.det() != DetId::Muon) continue;
-    if (id.subdetId() == MuonSubdetId::CSC) nHits++;
+  if( dsaMuon.extra().isNonnull() && dsaMuon.extra().isAvailable() ) {
+    for (auto& hit : dsaMuon.recHits()){
+      if (!hit->isValid()) continue;
+      DetId id = hit->geographicalId();
+      if (id.det() != DetId::Muon) continue;
+      if (id.subdetId() == MuonSubdetId::CSC) nHits++;
+    }
   }
   return nHits;
 }
diff --git a/plugins/DispJetTableProducer.cc b/plugins/DispJetTableProducer.cc
new file mode 100644
index 0000000..6650564
--- /dev/null
+++ b/plugins/DispJetTableProducer.cc
@@ -0,0 +1,434 @@
+// -*- C++ -*-
+//
+// Package:    PhysicsTools/EXOnanoAOD
+// Class:      DispJetTableProducer
+//
+/**\class DispJetTableProducer
+
+ Description: Additional variables for displaced vertices involving at least one lepton and other tracks
+
+*/
+//
+// Original Author:  Kirill Skovpen
+//         Created:  Sat, 1 Mar 2025 08:37:01 GMT
+//
+
+// system include files
+#include <memory>
+
+// user include files
+#include "FWCore/Framework/interface/Frameworkfwd.h"
+#include "FWCore/Framework/interface/stream/EDProducer.h"
+
+#include "FWCore/Framework/interface/Event.h"
+#include "FWCore/Framework/interface/MakerMacros.h"
+
+#include "FWCore/ParameterSet/interface/ParameterSet.h"
+#include "FWCore/Utilities/interface/StreamID.h"
+
+#include "DataFormats/PatCandidates/interface/Electron.h"
+#include "DataFormats/PatCandidates/interface/Muon.h"
+#include "DataFormats/PatCandidates/interface/Jet.h"
+#include "DataFormats/MuonReco/interface/MuonSelectors.h"
+
+// nanoAOD include files
+#include "DataFormats/NanoAOD/interface/FlatTable.h"
+
+// object specific include files
+#include "TrackingTools/TransientTrack/interface/TransientTrackBuilder.h"
+#include "TrackingTools/Records/interface/TransientTrackRecord.h"
+#include "TrackingTools/IPTools/interface/IPTools.h"
+#include "DataFormats/TrackReco/interface/Track.h"
+#include "DataFormats/VertexReco/interface/VertexFwd.h"
+#include "DataFormats/VertexReco/interface/Vertex.h"
+
+class DispJetTableProducer : public edm::stream::EDProducer<> {
+protected:
+  
+  edm::ESGetToken<TransientTrackBuilder, TransientTrackRecord> ttbToken_;
+  edm::EDGetTokenT<std::vector<pat::Electron> > electronTag_;
+  edm::EDGetTokenT<std::vector<pat::Muon> > muonTag_;
+  edm::EDGetTokenT<reco::VertexCollection> vtxTag_;
+  edm::EDGetTokenT<reco::VertexCollection> secVtxTag_;
+
+  const TransientTrackBuilder* theB;
+  
+  std::vector<int> el_idx;
+  std::vector<bool> el_lIVF_match;
+  std::vector<int> el_IVF_df, el_IVF_ntracks, el_IVF_elid;
+  std::vector<float> el_IVF_x, el_IVF_y, el_IVF_z, el_IVF_cx, el_IVF_cy, el_IVF_cz, el_IVF_chi2, el_IVF_pt, el_IVF_eta, el_IVF_phi, el_IVF_E, el_IVF_mass;
+  std::vector<int> el_IVF_trackcharge, el_IVF_trackelid, el_IVF_trackvtxid;
+  std::vector<float> el_IVF_trackpt, el_IVF_tracketa, el_IVF_trackphi, el_IVF_trackE, el_IVF_trackdxy, el_IVF_trackdz;
+  std::vector<float> el_IVF_tracksignedIP2D, el_IVF_tracksignedIP3D, el_IVF_tracksignedIP2Dsig, el_IVF_tracksignedIP3Dsig;
+  std::vector<float> el_IVF_signedIP2D, el_IVF_signedIP3D, el_IVF_signedIP2Dsig, el_IVF_signedIP3Dsig;
+   
+  std::vector<int> mu_idx;
+  std::vector<bool> mu_lIVF_match;
+  std::vector<int> mu_IVF_df, mu_IVF_ntracks, mu_IVF_muid;
+  std::vector<float> mu_IVF_x, mu_IVF_y, mu_IVF_z, mu_IVF_cx, mu_IVF_cy, mu_IVF_cz, mu_IVF_chi2, mu_IVF_pt, mu_IVF_eta, mu_IVF_phi, mu_IVF_E, mu_IVF_mass;
+  std::vector<int> mu_IVF_trackcharge, mu_IVF_trackmuid, mu_IVF_trackvtxid;
+  std::vector<float> mu_IVF_trackpt, mu_IVF_tracketa, mu_IVF_trackphi, mu_IVF_trackE, mu_IVF_trackdxy, mu_IVF_trackdz;
+  std::vector<float> mu_IVF_tracksignedIP2D, mu_IVF_tracksignedIP3D, mu_IVF_tracksignedIP2Dsig, mu_IVF_tracksignedIP3Dsig;
+  std::vector<float> mu_IVF_signedIP2D, mu_IVF_signedIP3D, mu_IVF_signedIP2Dsig, mu_IVF_signedIP3Dsig;
+
+public:
+  DispJetTableProducer(edm::ParameterSet const& params)
+    :
+    ttbToken_(esConsumes(edm::ESInputTag("", "TransientTrackBuilder"))),
+    electronTag_(consumes<std::vector<pat::Electron>>(params.getParameter<edm::InputTag>("electrons"))),
+    muonTag_(consumes<std::vector<pat::Muon>>(params.getParameter<edm::InputTag>("muons"))),
+    vtxTag_(consumes<reco::VertexCollection>(params.getParameter<edm::InputTag>("primaryVertex"))),
+    secVtxTag_(consumes<reco::VertexCollection>(params.getParameter<edm::InputTag>("secondaryVertex"))) {
+       produces<nanoaod::FlatTable>("DispJetElectron");
+       produces<nanoaod::FlatTable>("DispJetElectronVtx");
+       produces<nanoaod::FlatTable>("DispJetElectronTrk");
+       produces<nanoaod::FlatTable>("DispJetMuon");
+       produces<nanoaod::FlatTable>("DispJetMuonVtx");
+       produces<nanoaod::FlatTable>("DispJetMuonTrk");
+  }   
+
+  ~DispJetTableProducer() override {}
+  
+  void produce(edm::Event& iEvent, const edm::EventSetup& iSetup) override {
+
+    theB = &iSetup.getData(ttbToken_);
+    
+    edm::Handle<std::vector<pat::Electron> > electronHandle;
+    iEvent.getByToken(electronTag_, electronHandle);
+    
+    edm::Handle<std::vector<pat::Muon> > muonHandle;
+    iEvent.getByToken(muonTag_, muonHandle);
+    
+    edm::Handle<reco::VertexCollection> primaryVertexHandle;
+    iEvent.getByToken(vtxTag_, primaryVertexHandle);
+    
+    edm::Handle<reco::VertexCollection> secondaryVertexHandle;
+    iEvent.getByToken(secVtxTag_, secondaryVertexHandle);
+    
+    const auto& pv = primaryVertexHandle->at(0);
+    GlobalPoint primaryVertex(pv.x(), pv.y(), pv.z());
+    
+    const reco::VertexCollection & secVertices = (*secondaryVertexHandle);
+    
+    unsigned int nElectrons = electronHandle->size();
+    unsigned int nMuons = muonHandle->size();
+    
+    el_idx.clear();
+    el_lIVF_match.clear();
+    el_IVF_df.clear(); el_IVF_ntracks.clear(); el_IVF_elid.clear();
+    el_IVF_x.clear(); el_IVF_y.clear(); el_IVF_z.clear(); el_IVF_cx.clear(); el_IVF_cy.clear(); el_IVF_cz.clear(); el_IVF_chi2.clear(); el_IVF_pt.clear(); el_IVF_eta.clear(); el_IVF_phi.clear(); el_IVF_E.clear(); el_IVF_mass.clear();
+    el_IVF_trackcharge.clear(); el_IVF_trackelid.clear(); el_IVF_trackvtxid.clear();
+    el_IVF_trackpt.clear(); el_IVF_tracketa.clear(); el_IVF_trackphi.clear(); el_IVF_trackE.clear(); el_IVF_trackdxy.clear(); el_IVF_trackdz.clear();
+    el_IVF_tracksignedIP2D.clear(); el_IVF_tracksignedIP2Dsig.clear(); el_IVF_tracksignedIP3D.clear(); el_IVF_tracksignedIP3Dsig.clear();
+    
+    el_IVF_signedIP2D.clear(); el_IVF_signedIP2Dsig.clear(); el_IVF_signedIP3D.clear(); el_IVF_signedIP3Dsig.clear();
+    
+    mu_idx.clear();
+    mu_lIVF_match.clear();
+    mu_IVF_df.clear(); mu_IVF_ntracks.clear(); mu_IVF_muid.clear();
+    mu_IVF_x.clear(); mu_IVF_y.clear(); mu_IVF_z.clear(); mu_IVF_cx.clear(); mu_IVF_cy.clear(); mu_IVF_cz.clear(); mu_IVF_chi2.clear(); mu_IVF_pt.clear(); mu_IVF_eta.clear(); mu_IVF_phi.clear(); mu_IVF_E.clear(); mu_IVF_mass.clear();
+    mu_IVF_trackcharge.clear(); mu_IVF_trackmuid.clear(); mu_IVF_trackvtxid.clear();
+    mu_IVF_trackpt.clear(); mu_IVF_tracketa.clear(); mu_IVF_trackphi.clear(); mu_IVF_trackE.clear(); mu_IVF_trackdxy.clear(); mu_IVF_trackdz.clear();
+    mu_IVF_tracksignedIP2D.clear(); mu_IVF_tracksignedIP2Dsig.clear(); mu_IVF_tracksignedIP3D.clear(); mu_IVF_tracksignedIP3Dsig.clear();
+    
+    mu_IVF_signedIP2D.clear(); mu_IVF_signedIP2Dsig.clear(); mu_IVF_signedIP3D.clear(); mu_IVF_signedIP3Dsig.clear();
+     
+    int ntrack_max = 100;
+    int nElectronsSel = 0;
+    int nMuonsSel = 0;
+    
+    for(unsigned int i = 0; i < nElectrons; i++) {
+      
+      const pat::Electron & el = (*electronHandle)[i];
+      
+      if(el.gsfTrack().isNull()) continue;
+      if(el.pt() < 7) continue;     
+      if(fabs(el.eta()) > 2.5) continue;
+      
+      el_idx.push_back(i);
+      el_lIVF_match.push_back(false);
+      
+      bool new_vtx = false;
+      double dR, deta, normchi2;
+      double mindR = 20, minnormchi2 = 10000;
+      int nVtx = 0;
+      reco::Vertex *vtxDisp = NULL;
+      for(const reco::Vertex& vtx : secVertices) {
+	for(reco::Vertex::trackRef_iterator vtxTrackref = vtx.tracks_begin(); vtxTrackref != vtx.tracks_end(); vtxTrackref++) {
+	  reco::TrackRef vtxTrack = vtxTrackref->castTo<reco::TrackRef>();
+	  for(edm::Ref<pat::PackedCandidateCollection> cand : el.associatedPackedPFCandidates()) {	       
+	    dR       = reco::deltaR(cand->eta(), cand->phi(), vtxTrack->eta(), vtxTrack->phi());
+	    deta     = fabs(cand->eta() - vtxTrack->eta());
+	    normchi2 = fabs(vtx.chi2()/vtx.ndof());
+	    
+	    if((dR < 0.05 or (dR < 0.1 and deta < 0.03)) and (dR < mindR or (dR == mindR and normchi2 < minnormchi2))) {	       
+	      new_vtx = true;
+	      vtxDisp = const_cast<reco::Vertex*>(&vtx);
+	      el_lIVF_match[nElectronsSel] = true;
+	      mindR       = dR;
+	      minnormchi2 = normchi2;
+	    }
+	  }
+	}
+	
+	if(new_vtx) {
+	  el_IVF_x.push_back(vtx.x());
+	  el_IVF_y.push_back(vtx.y());
+	  el_IVF_z.push_back(vtx.z());
+	  el_IVF_cx.push_back(vtx.xError());
+	  el_IVF_cy.push_back(vtx.yError());
+	  el_IVF_cz.push_back(vtx.zError());
+	  el_IVF_df.push_back(vtx.ndof());
+	  el_IVF_chi2.push_back(vtx.chi2());
+	  el_IVF_pt.push_back(vtx.p4().pt());
+	  el_IVF_eta.push_back(vtx.p4().eta());
+	  el_IVF_phi.push_back(vtx.p4().phi());
+	  el_IVF_E.push_back(vtx.p4().energy());
+	  el_IVF_mass.push_back(vtx.p4().mass());
+	  el_IVF_elid.push_back(nElectronsSel);
+	  
+	  el_IVF_ntracks.push_back(0);
+	  for(reco::Vertex::trackRef_iterator vtxTrackref = vtx.tracks_begin(); vtxTrackref != vtx.tracks_end(); vtxTrackref++) {
+	    if(el_IVF_ntracks.back() == ntrack_max) break;
+	    reco::TrackRef vtxTrack = vtxTrackref->castTo<reco::TrackRef>();
+	    const auto& trk = theB->build(vtxTrack);
+	    Global3DVector dir(vtxTrack->px(), vtxTrack->py(), vtxTrack->pz());
+	    const auto& ip2d = IPTools::signedTransverseImpactParameter(trk, dir, *vtxDisp);
+	    const auto& ip3d = IPTools::signedImpactParameter3D(trk, dir, *vtxDisp);
+	    el_IVF_tracksignedIP2D.push_back(ip2d.second.value());
+	    el_IVF_tracksignedIP3D.push_back(ip3d.second.value());
+	    el_IVF_tracksignedIP2Dsig.push_back(ip2d.second.significance());
+	    el_IVF_tracksignedIP3Dsig.push_back(ip3d.second.significance());
+	    el_IVF_trackpt.push_back(vtxTrack->pt());
+	    el_IVF_tracketa.push_back(vtxTrack->eta());
+	    el_IVF_trackphi.push_back(vtxTrack->phi());
+	    el_IVF_trackE.push_back(vtxTrack->p());
+	    el_IVF_trackcharge.push_back(vtxTrack->charge());
+	    el_IVF_trackdxy.push_back(std::abs(vtxTrack->dxy(pv.position())));
+	    el_IVF_trackdz.push_back(std::abs(vtxTrack->dz(pv.position())));
+	    el_IVF_trackelid.push_back(nElectronsSel);
+	    el_IVF_trackvtxid.push_back(nVtx);
+	    el_IVF_ntracks.back()++;	    
+	  }
+	  nVtx++;
+	  new_vtx = false;
+
+	  auto track = el.gsfTrack();
+	  if( track.isNonnull() ) {
+	    const auto& trk = theB->build(track);
+	    Global3DVector dir(track->px(), track->py(), track->pz());
+	    const auto& ip2d = IPTools::signedTransverseImpactParameter(trk, dir, *vtxDisp);
+	    const auto& ip3d = IPTools::signedImpactParameter3D(trk, dir, *vtxDisp);
+	    el_IVF_signedIP2D.push_back(ip2d.second.value());
+	    el_IVF_signedIP3D.push_back(ip3d.second.value());
+	    el_IVF_signedIP2Dsig.push_back(ip2d.second.significance());
+	    el_IVF_signedIP3Dsig.push_back(ip3d.second.significance());
+	  } else {
+	    el_IVF_signedIP2D.push_back(-999);
+	    el_IVF_signedIP3D.push_back(-999);
+	    el_IVF_signedIP2Dsig.push_back(-999);
+	    el_IVF_signedIP3Dsig.push_back(-999);	    
+	  }
+	}
+      }
+      nElectronsSel += 1;
+    }
+    
+    for(unsigned int i = 0; i < nMuons; i++) {
+      
+      const pat::Muon & mu = (*muonHandle)[i];
+      
+      if(mu.innerTrack().isNull()) continue;
+      if(mu.pt() < 5) continue;
+      if(fabs(mu.eta()) > 2.4) continue;
+      if(!mu.isPFMuon()) continue;
+      if(!(mu.isTrackerMuon() || mu.isGlobalMuon())) continue;
+      
+      mu_idx.push_back(i);
+      mu_lIVF_match.push_back(false);
+      
+      bool new_vtx = false;
+      double ptdiff, normchi2;
+      double minptdiff = 10, minnormchi2 = 10000;
+      int nVtx = 0;
+      reco::Vertex *vtxDisp = NULL;
+      for(const reco::Vertex& vtx : secVertices) {
+	for(reco::Vertex::trackRef_iterator vtxTrackref = vtx.tracks_begin(); vtxTrackref != vtx.tracks_end(); vtxTrackref++) {
+	  reco::TrackRef vtxTrack = vtxTrackref->castTo<reco::TrackRef>();
+	  for( size_t iCand=0;iCand<mu.numberOfSourceCandidatePtrs();++iCand ) {
+	    if( !(mu.sourceCandidatePtr(iCand).isNonnull() and mu.sourceCandidatePtr(iCand).isAvailable()) ) continue;
+	    ptdiff   = fabs(mu.sourceCandidatePtr(iCand)->pt() - vtxTrack->pt());
+	    normchi2 = fabs(vtx.chi2()/vtx.ndof());
+	    
+	    if(ptdiff < 0.001 and (ptdiff < minptdiff or (ptdiff == minptdiff and normchi2 < minnormchi2))) {
+	      new_vtx = true;
+	      vtxDisp = const_cast<reco::Vertex*>(&vtx);
+	      mu_lIVF_match[nMuonsSel] = true;
+	      minptdiff   = ptdiff;
+	      minnormchi2 = normchi2;
+	    }
+	  }
+	}       
+	if(new_vtx) {
+	  mu_IVF_x.push_back(vtx.x());
+	  mu_IVF_y.push_back(vtx.y());
+	  mu_IVF_z.push_back(vtx.z());
+	  mu_IVF_cx.push_back(vtx.xError());
+	  mu_IVF_cy.push_back(vtx.yError());
+	  mu_IVF_cz.push_back(vtx.zError());
+	  mu_IVF_df.push_back(vtx.ndof());
+	  mu_IVF_chi2.push_back(vtx.chi2());
+	  mu_IVF_pt.push_back(vtx.p4().pt());
+	  mu_IVF_eta.push_back(vtx.p4().eta());
+	  mu_IVF_phi.push_back(vtx.p4().phi());
+	  mu_IVF_E.push_back(vtx.p4().energy());
+	  mu_IVF_mass.push_back(vtx.p4().mass());
+	  mu_IVF_muid.push_back(nMuonsSel);
+	  
+	  mu_IVF_ntracks.push_back(0);
+	  for(reco::Vertex::trackRef_iterator vtxTrackref = vtx.tracks_begin(); vtxTrackref != vtx.tracks_end(); vtxTrackref++) {
+	    if(mu_IVF_ntracks.back() == ntrack_max) break;
+	    reco::TrackRef vtxTrack = vtxTrackref->castTo<reco::TrackRef>();
+	    const auto& trk = theB->build(vtxTrack);
+	    Global3DVector dir(vtxTrack->px(), vtxTrack->py(), vtxTrack->pz());
+	    const auto& ip2d = IPTools::signedTransverseImpactParameter(trk, dir, *vtxDisp);
+	    const auto& ip3d = IPTools::signedImpactParameter3D(trk, dir, *vtxDisp);
+	    mu_IVF_tracksignedIP2D.push_back(ip2d.second.value());
+	    mu_IVF_tracksignedIP3D.push_back(ip3d.second.value());
+	    mu_IVF_tracksignedIP2Dsig.push_back(ip2d.second.significance());
+	    mu_IVF_tracksignedIP3Dsig.push_back(ip3d.second.significance());
+	    mu_IVF_trackpt.push_back(vtxTrack->pt());
+	    mu_IVF_tracketa.push_back(vtxTrack->eta());
+	    mu_IVF_trackphi.push_back(vtxTrack->phi());
+	    mu_IVF_trackE.push_back(vtxTrack->p());
+	    mu_IVF_trackcharge.push_back(vtxTrack->charge());
+	    mu_IVF_trackdxy.push_back(std::abs(vtxTrack->dxy(pv.position())));
+	    mu_IVF_trackdz.push_back(std::abs(vtxTrack->dz(pv.position())));
+	    mu_IVF_trackmuid.push_back(nMuonsSel);
+	    mu_IVF_trackvtxid.push_back(nVtx);
+	    mu_IVF_ntracks.back()++;
+	  }
+	  nVtx++;
+	  new_vtx = false;
+
+	  auto track = mu.innerTrack();
+	  if( track.isNonnull() ) {
+	    const auto& trk = theB->build(track);
+	    Global3DVector dir(track->px(), track->py(), track->pz());
+	    const auto& ip2d = IPTools::signedTransverseImpactParameter(trk, dir, *vtxDisp);
+	    const auto& ip3d = IPTools::signedImpactParameter3D(trk, dir, *vtxDisp);
+	    mu_IVF_signedIP2D.push_back(ip2d.second.value());
+	    mu_IVF_signedIP3D.push_back(ip3d.second.value());
+	    mu_IVF_signedIP2Dsig.push_back(ip2d.second.significance());
+	    mu_IVF_signedIP3Dsig.push_back(ip3d.second.significance());
+	  } else {
+	    mu_IVF_signedIP2D.push_back(-999);
+	    mu_IVF_signedIP3D.push_back(-999);
+	    mu_IVF_signedIP2Dsig.push_back(-999);
+	    mu_IVF_signedIP3Dsig.push_back(-999);	    	    
+	  }
+	}	 
+      }      
+      nMuonsSel += 1;
+    }
+    
+    auto dispJetElectronTab = std::make_unique<nanoaod::FlatTable>(nElectronsSel, "DispJetElectron", false, false);
+    auto dispJetMuonTab = std::make_unique<nanoaod::FlatTable>(nMuonsSel, "DispJetMuon", false, false);
+    
+    dispJetElectronTab->addColumn<int>("idx", el_idx, "");
+    dispJetElectronTab->addColumn<bool>("lIVF_match", el_lIVF_match, "");
+    
+    auto dispJetElectronVtxTab = std::make_unique<nanoaod::FlatTable>(el_IVF_x.size(), "DispJetElectronVtx", false, false);
+    dispJetElectronVtxTab->addColumn<int>("IVF_df", el_IVF_df, "");
+    dispJetElectronVtxTab->addColumn<int>("IVF_ntracks", el_IVF_ntracks, "");
+    dispJetElectronVtxTab->addColumn<int>("IVF_elid", el_IVF_elid, "");
+    dispJetElectronVtxTab->addColumn<float>("IVF_x", el_IVF_x, "");
+    dispJetElectronVtxTab->addColumn<float>("IVF_y", el_IVF_y, "");
+    dispJetElectronVtxTab->addColumn<float>("IVF_z", el_IVF_z, "");
+    dispJetElectronVtxTab->addColumn<float>("IVF_cx", el_IVF_cx, "");
+    dispJetElectronVtxTab->addColumn<float>("IVF_cy", el_IVF_cy, "");
+    dispJetElectronVtxTab->addColumn<float>("IVF_cz", el_IVF_cz, "");
+    dispJetElectronVtxTab->addColumn<float>("IVF_chi2", el_IVF_chi2, "");
+    dispJetElectronVtxTab->addColumn<float>("IVF_pt", el_IVF_pt, "");
+    dispJetElectronVtxTab->addColumn<float>("IVF_eta", el_IVF_eta, "");
+    dispJetElectronVtxTab->addColumn<float>("IVF_phi", el_IVF_phi, "");
+    dispJetElectronVtxTab->addColumn<float>("IVF_E", el_IVF_E, "");
+    dispJetElectronVtxTab->addColumn<float>("IVF_mass", el_IVF_mass, "");
+    dispJetElectronVtxTab->addColumn<float>("IVF_signedIP2D", el_IVF_signedIP2D, "");
+    dispJetElectronVtxTab->addColumn<float>("IVF_signedIP2Dsig", el_IVF_signedIP2Dsig, "");   
+    dispJetElectronVtxTab->addColumn<float>("IVF_signedIP3D", el_IVF_signedIP3D, "");
+    dispJetElectronVtxTab->addColumn<float>("IVF_signedIP3Dsig", el_IVF_signedIP3Dsig, "");   
+    
+    int nTracksElectron = 0;
+    for( unsigned int iv=0;iv<el_IVF_ntracks.size();iv++ ) {
+      nTracksElectron += std::min(el_IVF_ntracks[iv], ntrack_max);
+    }
+    auto dispJetElectronTrkTab = std::make_unique<nanoaod::FlatTable>(nTracksElectron, "DispJetElectronTrk", false, false);
+    dispJetElectronTrkTab->addColumn<int>("IVF_trackcharge", el_IVF_trackcharge, "");
+    dispJetElectronTrkTab->addColumn<float>("IVF_trackpt", el_IVF_trackpt, "");
+    dispJetElectronTrkTab->addColumn<float>("IVF_tracketa", el_IVF_tracketa, "");
+    dispJetElectronTrkTab->addColumn<float>("IVF_trackphi", el_IVF_trackphi, "");
+    dispJetElectronTrkTab->addColumn<float>("IVF_trackE", el_IVF_trackE, "");
+    dispJetElectronTrkTab->addColumn<float>("IVF_trackdxy", el_IVF_trackdxy, "");
+    dispJetElectronTrkTab->addColumn<float>("IVF_trackdz", el_IVF_trackdz, "");
+    dispJetElectronTrkTab->addColumn<int>("IVF_trackelid", el_IVF_trackelid, "");
+    dispJetElectronTrkTab->addColumn<int>("IVF_trackvtxid", el_IVF_trackvtxid, "");
+    dispJetElectronTrkTab->addColumn<float>("IVF_tracksignedIP2D", el_IVF_tracksignedIP2D, "");
+    dispJetElectronTrkTab->addColumn<float>("IVF_tracksignedIP2Dsig", el_IVF_tracksignedIP2Dsig, "");   
+    dispJetElectronTrkTab->addColumn<float>("IVF_tracksignedIP3D", el_IVF_tracksignedIP3D, "");
+    dispJetElectronTrkTab->addColumn<float>("IVF_tracksignedIP3Dsig", el_IVF_tracksignedIP3Dsig, "");   
+    
+    dispJetMuonTab->addColumn<int>("idx", mu_idx, "");
+    dispJetMuonTab->addColumn<bool>("lIVF_match", mu_lIVF_match, "");
+     
+    auto dispJetMuonVtxTab = std::make_unique<nanoaod::FlatTable>(mu_IVF_x.size(), "DispJetMuonVtx", false, false);
+    dispJetMuonVtxTab->addColumn<int>("IVF_df", mu_IVF_df, "");
+    dispJetMuonVtxTab->addColumn<int>("IVF_ntracks", mu_IVF_ntracks, "");
+    dispJetMuonVtxTab->addColumn<int>("IVF_muid", mu_IVF_muid, "");
+    dispJetMuonVtxTab->addColumn<float>("IVF_x", mu_IVF_x, "");
+    dispJetMuonVtxTab->addColumn<float>("IVF_y", mu_IVF_y, "");
+    dispJetMuonVtxTab->addColumn<float>("IVF_z", mu_IVF_z, "");
+    dispJetMuonVtxTab->addColumn<float>("IVF_cx", mu_IVF_cx, "");
+    dispJetMuonVtxTab->addColumn<float>("IVF_cy", mu_IVF_cy, "");
+    dispJetMuonVtxTab->addColumn<float>("IVF_cz", mu_IVF_cz, "");
+    dispJetMuonVtxTab->addColumn<float>("IVF_chi2", mu_IVF_chi2, "");
+    dispJetMuonVtxTab->addColumn<float>("IVF_pt", mu_IVF_pt, "");
+    dispJetMuonVtxTab->addColumn<float>("IVF_eta", mu_IVF_eta, "");
+    dispJetMuonVtxTab->addColumn<float>("IVF_phi", mu_IVF_phi, "");
+    dispJetMuonVtxTab->addColumn<float>("IVF_E", mu_IVF_E, "");
+    dispJetMuonVtxTab->addColumn<float>("IVF_mass", mu_IVF_mass, "");
+    dispJetMuonVtxTab->addColumn<float>("IVF_signedIP2D", mu_IVF_signedIP2D, "");
+    dispJetMuonVtxTab->addColumn<float>("IVF_signedIP2Dsig", mu_IVF_signedIP2Dsig, "");   
+    dispJetMuonVtxTab->addColumn<float>("IVF_signedIP3D", mu_IVF_signedIP3D, "");
+    dispJetMuonVtxTab->addColumn<float>("IVF_signedIP3Dsig", mu_IVF_signedIP3Dsig, "");   
+    
+    int nTracksMuon = 0;
+    for( unsigned int iv=0;iv<mu_IVF_ntracks.size();iv++ ) {
+      nTracksMuon += std::min(mu_IVF_ntracks[iv], ntrack_max);
+    }
+    auto dispJetMuonTrkTab = std::make_unique<nanoaod::FlatTable>(nTracksMuon, "DispJetMuonTrk", false, false);
+    dispJetMuonTrkTab->addColumn<int>("IVF_trackcharge", mu_IVF_trackcharge, "");
+    dispJetMuonTrkTab->addColumn<float>("IVF_trackpt", mu_IVF_trackpt, "");
+    dispJetMuonTrkTab->addColumn<float>("IVF_tracketa", mu_IVF_tracketa, "");
+    dispJetMuonTrkTab->addColumn<float>("IVF_trackphi", mu_IVF_trackphi, "");
+    dispJetMuonTrkTab->addColumn<float>("IVF_trackE", mu_IVF_trackE, "");
+    dispJetMuonTrkTab->addColumn<float>("IVF_trackdxy", mu_IVF_trackdxy, "");
+    dispJetMuonTrkTab->addColumn<float>("IVF_trackdz", mu_IVF_trackdz, "");
+    dispJetMuonTrkTab->addColumn<int>("IVF_trackmuid", mu_IVF_trackmuid, "");
+    dispJetMuonTrkTab->addColumn<int>("IVF_trackvtxid", mu_IVF_trackvtxid, "");
+    dispJetMuonTrkTab->addColumn<float>("IVF_tracksignedIP2D", mu_IVF_tracksignedIP2D, "");
+    dispJetMuonTrkTab->addColumn<float>("IVF_tracksignedIP2Dsig", mu_IVF_tracksignedIP2Dsig, "");   
+    dispJetMuonTrkTab->addColumn<float>("IVF_tracksignedIP3D", mu_IVF_tracksignedIP3D, "");
+    dispJetMuonTrkTab->addColumn<float>("IVF_tracksignedIP3Dsig", mu_IVF_tracksignedIP3Dsig, "");   
+    
+    iEvent.put(std::move(dispJetElectronTab), "DispJetElectron");
+    iEvent.put(std::move(dispJetElectronVtxTab), "DispJetElectronVtx");
+    iEvent.put(std::move(dispJetElectronTrkTab), "DispJetElectronTrk");
+    iEvent.put(std::move(dispJetMuonTab), "DispJetMuon");
+    iEvent.put(std::move(dispJetMuonVtxTab), "DispJetMuonVtx");
+    iEvent.put(std::move(dispJetMuonTrkTab), "DispJetMuonTrk");
+  }      
+};
+
+#include "FWCore/Framework/interface/MakerMacros.h"
+DEFINE_FWK_MODULE(DispJetTableProducer);
diff --git a/plugins/ElectronExtendedTableProducer.cc b/plugins/ElectronExtendedTableProducer.cc
index 583f32c..8206eb5 100644
--- a/plugins/ElectronExtendedTableProducer.cc
+++ b/plugins/ElectronExtendedTableProducer.cc
@@ -12,13 +12,27 @@
 #include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
 
 #include "DataFormats/PatCandidates/interface/Electron.h"
+#include "DataFormats/PatCandidates/interface/Jet.h"
 #include "DataFormats/NanoAOD/interface/FlatTable.h"
+#include "DataFormats/PatCandidates/interface/PackedCandidate.h"
+
+#include "TrackingTools/TransientTrack/interface/TransientTrackBuilder.h"
+#include "TrackingTools/Records/interface/TransientTrackRecord.h"
+#include "TrackingTools/IPTools/interface/IPTools.h"
+#include "DataFormats/TrackReco/interface/Track.h"
+#include "DataFormats/VertexReco/interface/VertexFwd.h"
+#include "DataFormats/VertexReco/interface/Vertex.h"
 
 class ElectronExtendedTableProducer : public edm::global::EDProducer<> {
   public:
     explicit ElectronExtendedTableProducer(const edm::ParameterSet &iConfig) :
       name_(iConfig.getParameter<std::string>("name")),
-      electronTag_(consumes<std::vector<pat::Electron>>(iConfig.getParameter<edm::InputTag>("electrons")))
+      rhoTag_(consumes<double>(iConfig.getParameter<edm::InputTag>("rho"))),
+      electronTag_(consumes<std::vector<pat::Electron>>(iConfig.getParameter<edm::InputTag>("electrons"))),
+      vtxTag_(consumes<reco::VertexCollection>(iConfig.getParameter<edm::InputTag>("primaryVertex"))),
+      jetTag_(consumes<std::vector<pat::Jet>>(iConfig.getParameter<edm::InputTag>("jets"))),
+      jetFatTag_(consumes<std::vector<pat::Jet>>(iConfig.getParameter<edm::InputTag>("jetsFat"))),
+      jetSubTag_(consumes<std::vector<pat::Jet>>(iConfig.getParameter<edm::InputTag>("jetsSub")))
     {
       produces<nanoaod::FlatTable>();
     }
@@ -27,7 +41,12 @@ class ElectronExtendedTableProducer : public edm::global::EDProducer<> {
 
     static void fillDescriptions(edm::ConfigurationDescriptions & descriptions) {
       edm::ParameterSetDescription desc;
+      desc.add<edm::InputTag>("rho")->setComment("input rho parameter");
       desc.add<edm::InputTag>("electrons")->setComment("input electron collection");
+      desc.add<edm::InputTag>("primaryVertex")->setComment("input primary vertex collection");
+      desc.add<edm::InputTag>("jets")->setComment("input jet collection");
+      desc.add<edm::InputTag>("jetsFat")->setComment("input fat jet collection");
+      desc.add<edm::InputTag>("jetsSub")->setComment("input sub jet collection");
       desc.add<std::string>("name")->setComment("name of the electron nanoaod::FlatTable we are extending");
       descriptions.add("electronTable", desc);
     }
@@ -35,27 +54,219 @@ class ElectronExtendedTableProducer : public edm::global::EDProducer<> {
   private:
     void produce(edm::StreamID, edm::Event&, edm::EventSetup const&) const override;
 
+    float GetDEtaInSeed(const pat::Electron* el) const;
+    float getPFIso(const pat::Electron& electron) const;
+    int findMatchedJet(const reco::Candidate& lepton, const edm::Handle< std::vector< pat::Jet > >& jets) const;
+    void fillLeptonJetVariables(const reco::GsfElectron *el, edm::Handle< std::vector< pat::Jet > >& jets, const reco::Vertex& vertex, const double rho, std::vector<int> *jetIdx, std::vector<float> relIso0p4, std::vector<float> *jetPtRatio, std::vector<float> *jetPtRel, std::vector<int> *jrtSelectedChargedMultiplicity) const;
+
     std::string name_;
+    edm::EDGetTokenT<double> rhoTag_;    
     edm::EDGetTokenT<std::vector<pat::Electron>> electronTag_;
-
+    edm::EDGetTokenT<reco::VertexCollection> vtxTag_;
+    edm::EDGetTokenT<std::vector<pat::Jet> > jetTag_;
+    edm::EDGetTokenT<std::vector<pat::Jet> > jetFatTag_;
+    edm::EDGetTokenT<std::vector<pat::Jet> > jetSubTag_;
 };
 
 void ElectronExtendedTableProducer::produce(edm::StreamID, edm::Event& iEvent, const edm::EventSetup& iSetup) const 
 {
+  edm::Handle<double> rhoHandle;
+  iEvent.getByToken(rhoTag_, rhoHandle);
   edm::Handle<std::vector<pat::Electron>> electrons;
   iEvent.getByToken(electronTag_, electrons);
+  edm::Handle<reco::VertexCollection> primaryVertices;
+  iEvent.getByToken(vtxTag_, primaryVertices);
+  edm::Handle<std::vector<pat::Jet> > jetHandle;
+  iEvent.getByToken(jetTag_, jetHandle);
+  edm::Handle<std::vector<pat::Jet> > jetFatHandle;
+  iEvent.getByToken(jetFatTag_, jetFatHandle);
+  edm::Handle<std::vector<pat::Jet> > jetSubHandle;
+  iEvent.getByToken(jetSubTag_, jetSubHandle);  
 
+  const auto& pv = primaryVertices->at(0);
+  GlobalPoint primaryVertex(pv.x(), pv.y(), pv.z());
+  
   unsigned int nElectrons = electrons->size();
-  std::vector<float> idx;
+
+  std::vector<float> idx, charge;
+  
+  std::vector<float> relIso0p4;
+  std::vector<float> jetPtRatio, jetPtRel;
+  std::vector<int> jetIdx;
+  std::vector<int> jetFatIdx, jetSubIdx;
+  std::vector<int> jetSelectedChargedMultiplicity;
+  std::vector<float> dxy, dz, IP3d, IP3dSig;
+
+  std::vector<bool> isEB, isEE;
+  std::vector<float> superClusterOverP, ecalEnergy, dEtaInSeed;
+  std::vector<int> numberInnerHitsMissing, numberOfValidPixelHits, numberOfValidTrackerHits;
+  std::vector<float> sigmaIetaIeta, deltaPhiSuperClusterTrack, deltaEtaSuperClusterTrack, eInvMinusPInv, hOverE;  
+  
   for (unsigned int i = 0; i < nElectrons; i++) {
+    const pat::Electron & electron = (*electrons)[i];
+    
     idx.push_back(i);
+
+    charge.push_back(electron.charge());
+
+    isEB.push_back(electron.isEB());
+    isEE.push_back(electron.isEE());
+    superClusterOverP.push_back(electron.eSuperClusterOverP());
+    ecalEnergy.push_back(electron.ecalEnergy());
+    dEtaInSeed.push_back(std::abs(GetDEtaInSeed(&electron)));
+    numberInnerHitsMissing.push_back(electron.gsfTrack()->hitPattern().numberOfLostHits(reco::HitPattern::MISSING_INNER_HITS));
+    numberOfValidPixelHits.push_back((!electron.gsfTrack().isNull())? electron.gsfTrack()->hitPattern().numberOfValidPixelHits() : 0);
+    numberOfValidTrackerHits.push_back((!electron.gsfTrack().isNull())? electron.gsfTrack()->hitPattern().numberOfValidTrackerHits() : 0);
+
+    sigmaIetaIeta.push_back(electron.full5x5_sigmaIetaIeta());
+    deltaPhiSuperClusterTrack.push_back(fabs(electron.deltaPhiSuperClusterTrackAtVtx()));
+    deltaEtaSuperClusterTrack.push_back(fabs(electron.deltaEtaSuperClusterTrackAtVtx()));
+    eInvMinusPInv.push_back((1.0 - electron.eSuperClusterOverP())/electron.correctedEcalEnergy());
+    hOverE.push_back(electron.hadronicOverEm());
+
+    dxy.push_back(electron.dB(pat::Electron::PV2D));
+    dz.push_back(electron.dB(pat::Electron::PVDZ));
+    IP3d.push_back(electron.dB(pat::Electron::PV3D));
+    IP3dSig.push_back(fabs(electron.dB(pat::Electron::PV3D)/electron.edB(pat::Electron::PV3D)));
+
+    relIso0p4.push_back(getPFIso(electron));
+
+    fillLeptonJetVariables(&electron, jetHandle, pv, *rhoHandle, &jetIdx, relIso0p4, &jetPtRatio, &jetPtRel, &jetSelectedChargedMultiplicity);
+
+    const reco::Candidate *el_cand = dynamic_cast<const reco::Candidate*>(&electron);
+    jetFatIdx.push_back(findMatchedJet(*el_cand, jetFatHandle));
+    jetSubIdx.push_back(findMatchedJet(*el_cand, jetSubHandle));
   }
 
   auto tab  = std::make_unique<nanoaod::FlatTable>(nElectrons, name_, false, true);
   tab->addColumn<float>("idx", idx, "LLPnanoAOD electron index");
+
+  tab->addColumn<float>("dxy", dxy, "");
+  tab->addColumn<float>("dz", dz, "");
+  tab->addColumn<float>("IP3d", IP3d, "");
+  tab->addColumn<float>("IP3dSig", IP3dSig, "");
+
+  tab->addColumn<float>("relIso0p4", relIso0p4, "");
+  tab->addColumn<float>("jetPtRatio", jetPtRatio, "");
+  tab->addColumn<float>("jetPtRel", jetPtRel, "");
+  tab->addColumn<int>("jetSelectedChargedMultiplicity", jetSelectedChargedMultiplicity, "");
+  tab->addColumn<int>("jetIdx", jetIdx, "");
+  tab->addColumn<int>("jetFatIdx", jetFatIdx, "");
+  tab->addColumn<int>("jetSubIdx", jetSubIdx, "");
+
+  tab->addColumn<bool>("isEB", isEB, "");
+  tab->addColumn<bool>("isEE", isEE, "");
+  tab->addColumn<float>("superClusterOverP", superClusterOverP, "");
+  tab->addColumn<float>("ecalEnergy", ecalEnergy, "");
+  tab->addColumn<float>("dEtaInSeed", dEtaInSeed, "");
+  tab->addColumn<int>("numberInnerHitsMissing", numberInnerHitsMissing, "");
+  tab->addColumn<int>("numberOfValidPixelHits", numberOfValidPixelHits, "");
+  tab->addColumn<int>("numberOfValidTrackerHits", numberOfValidTrackerHits, "");
+  tab->addColumn<float>("sigmaIetaIeta", sigmaIetaIeta, "");
+  tab->addColumn<float>("deltaPhiSuperClusterTrack", deltaPhiSuperClusterTrack, "");
+  tab->addColumn<float>("deltaEtaSuperClusterTrack", deltaEtaSuperClusterTrack, "");
+  tab->addColumn<float>("eInvMinusPInv", eInvMinusPInv, "");
+  tab->addColumn<float>("hOverE", hOverE, "");
+  
   iEvent.put(std::move(tab));
 }
 
+float ElectronExtendedTableProducer::GetDEtaInSeed(const pat::Electron* el) const {
+  if( el->superCluster().isNonnull() and el->superCluster()->seed().isNonnull()) return el->deltaEtaSuperClusterTrackAtVtx() - el->superCluster()->eta() + el->superCluster()->seed()->eta();
+  else return std::numeric_limits<float>::max();
+}
+
+template< typename T1, typename T2 > bool isSourceCandidatePtrMatch( const T1& lhs, const T2& rhs ) {
+  
+  for( size_t lhsIndex = 0; lhsIndex < lhs.numberOfSourceCandidatePtrs(); ++lhsIndex ) {
+    auto lhsSourcePtr = lhs.sourceCandidatePtr( lhsIndex );
+    for( size_t rhsIndex = 0; rhsIndex < rhs.numberOfSourceCandidatePtrs(); ++rhsIndex ) {
+      auto rhsSourcePtr = rhs.sourceCandidatePtr( rhsIndex );
+      if( lhsSourcePtr == rhsSourcePtr ) {
+	return true;
+      }
+    }
+  }
+  
+  return false;
+}
+
+int ElectronExtendedTableProducer::findMatchedJet(const reco::Candidate& lepton, const edm::Handle< std::vector< pat::Jet > >& jets) const {
+
+  int iJet = -1;
+  
+  unsigned int nJets = jets->size();
+  
+  for(unsigned int i = 0; i < nJets; i++) {
+    const pat::Jet & jet = (*jets)[i];
+    if( isSourceCandidatePtrMatch( lepton, jet ) ) {
+      return i;
+    }
+  }
+  
+  return iJet;
+}
+
+void ElectronExtendedTableProducer::fillLeptonJetVariables(const reco::GsfElectron *el, edm::Handle< std::vector< pat::Jet > >& jets, const reco::Vertex& vertex, const double rho, std::vector<int> *jetIdx, std::vector<float> relIso0p4, std::vector<float> *jetPtRatio, std::vector<float> *jetPtRel, std::vector<int> *jetSelectedChargedMultiplicity) const {
+   
+  const reco::Candidate *cand = dynamic_cast<const reco::Candidate*>(el);
+  int matchedJetIdx = findMatchedJet( *cand, jets );
+  
+  jetIdx->push_back(matchedJetIdx);
+
+  if( matchedJetIdx < 0 ) {
+    float ptRatio = ( 1. / ( 1. + relIso0p4.back() ) );
+    jetPtRatio->push_back(ptRatio);	 
+    jetPtRel->push_back(0);
+    jetSelectedChargedMultiplicity->push_back(0);
+  } else {
+    const pat::Jet& jet = (*jets)[matchedJetIdx];
+    auto rawJetP4 = jet.correctedP4("Uncorrected");
+    auto leptonP4 = cand->p4();
+    
+    bool leptonEqualsJet = ( ( rawJetP4 - leptonP4 ).P() < 1e-4 );
+    
+    if( leptonEqualsJet ) {
+      jetPtRatio->push_back(1);
+      jetPtRel->push_back(0);
+      jetSelectedChargedMultiplicity->push_back(0);	    
+    } else {
+      auto L1JetP4 = jet.correctedP4("L1FastJet");
+      double L2L3JEC = jet.pt()/L1JetP4.pt();
+      auto lepAwareJetP4 = ( L1JetP4 - leptonP4 )*L2L3JEC + leptonP4;
+      
+      float ptRatio = cand->pt() / lepAwareJetP4.pt();
+      float ptRel = leptonP4.Vect().Cross( (lepAwareJetP4 - leptonP4 ).Vect().Unit() ).R();
+      jetPtRatio->push_back(ptRatio);
+      jetPtRel->push_back(ptRel);
+      jetSelectedChargedMultiplicity->push_back(0);
+      
+      for( const auto &daughterPtr : jet.daughterPtrVector() ) {
+	const pat::PackedCandidate& daughter = *( (const pat::PackedCandidate*) daughterPtr.get() );
+	
+	if( daughter.charge() == 0 ) continue;
+	if( daughter.fromPV() < 2 ) continue;
+	if( reco::deltaR( daughter, *cand ) > 0.4 ) continue;
+	if( !daughter.hasTrackDetails() ) continue;
+	
+	auto daughterTrack = daughter.pseudoTrack();
+	    
+	if( daughterTrack.pt() <= 1 ) continue;
+	if( daughterTrack.hitPattern().numberOfValidHits() < 8 ) continue;
+	if( daughterTrack.hitPattern().numberOfValidPixelHits() < 2 ) continue;
+	if( daughterTrack.normalizedChi2() >= 5 ) continue;
+	if( std::abs( daughterTrack.dz( vertex.position() ) ) >= 17 ) continue;
+	if( std::abs( daughterTrack.dxy( vertex.position() ) ) >= 0.2 ) continue;
+	++jetSelectedChargedMultiplicity->back();
+      }
+    }      
+  }
+}
+
+float ElectronExtendedTableProducer::getPFIso(const pat::Electron& electron) const {
+  return electron.userFloat("PFIsoAll04") / electron.pt();
+}
+
 #include "FWCore/Framework/interface/MakerMacros.h"
 //define this as a plug-in
 DEFINE_FWK_MODULE(ElectronExtendedTableProducer);
diff --git a/plugins/ElectronVertexTableProducer.cc b/plugins/ElectronVertexTableProducer.cc
index e19d20f..4f467af 100644
--- a/plugins/ElectronVertexTableProducer.cc
+++ b/plugins/ElectronVertexTableProducer.cc
@@ -319,19 +319,19 @@ void ElectronVertexTableProducer::produce(edm::StreamID, edm::Event& iEvent, con
           refittedVertEta.push_back(diele_state.globalMomentum().eta());
           refittedVertPhi.push_back(diele_state.globalMomentum().phi());
         }
-        else {
-          refittedVertMass.push_back(-999.);
-          refittedVertPt.push_back(-999.);
-          refittedVertEta.push_back(-999.);
-          refittedVertPhi.push_back(-999.);
-        }
+	else {
+	  refittedVertMass.push_back(-999.);
+	  refittedVertPt.push_back(-999.);
+	  refittedVertEta.push_back(-999.);
+	  refittedVertPhi.push_back(-999.);
+	}
       }
       catch (std::exception ex) {
-	      std::cout << "kinematic vertex fit failed!" << std::endl;
-        refittedVertMass.push_back(-999.);
-        refittedVertPt.push_back(-999.);
-        refittedVertEta.push_back(-999.);
-        refittedVertPhi.push_back(-999.);
+	  std::cout << "kinematic vertex fit failed!" << std::endl;
+	  refittedVertMass.push_back(-999.);
+	  refittedVertPt.push_back(-999.);
+	  refittedVertEta.push_back(-999.);
+	  refittedVertPhi.push_back(-999.);
       }
     }
   }
diff --git a/plugins/MuonExtendedTableProducer.cc b/plugins/MuonExtendedTableProducer.cc
index 28ae8e3..dcf8836 100644
--- a/plugins/MuonExtendedTableProducer.cc
+++ b/plugins/MuonExtendedTableProducer.cc
@@ -13,6 +13,7 @@
 
 #include "DataFormats/PatCandidates/interface/Muon.h"
 #include "DataFormats/MuonReco/interface/MuonSelectors.h"
+#include "DataFormats/PatCandidates/interface/Jet.h"
 #include "DataFormats/NanoAOD/interface/FlatTable.h"
 #include "DataFormats/PatCandidates/interface/PackedCandidate.h"
 
@@ -28,11 +29,15 @@ class MuonExtendedTableProducer : public edm::global::EDProducer<> {
   public:
     explicit MuonExtendedTableProducer(const edm::ParameterSet &iConfig) :
       name_(iConfig.getParameter<std::string>("name")),
+      rhoTag_(consumes<double>(iConfig.getParameter<edm::InputTag>("rho"))),
       muonTag_(consumes<std::vector<pat::Muon>>(iConfig.getParameter<edm::InputTag>("muons"))),
       dsaMuonTag_(consumes<std::vector<reco::Track>>(iConfig.getParameter<edm::InputTag>("dsaMuons"))),
       vtxTag_(consumes<reco::VertexCollection>(iConfig.getParameter<edm::InputTag>("primaryVertex"))),
       bsTag_(consumes<reco::BeamSpot>(iConfig.getParameter<edm::InputTag>("beamspot"))),
       generalTrackTag_(consumes<std::vector<reco::Track>>(iConfig.getParameter<edm::InputTag>("generalTracks"))),
+      jetTag_(consumes<std::vector<pat::Jet>>(iConfig.getParameter<edm::InputTag>("jets"))),
+      jetFatTag_(consumes<std::vector<pat::Jet>>(iConfig.getParameter<edm::InputTag>("jetsFat"))),
+      jetSubTag_(consumes<std::vector<pat::Jet>>(iConfig.getParameter<edm::InputTag>("jetsSub"))),
       transientTrackBuilderToken_(esConsumes(edm::ESInputTag("", "TransientTrackBuilder")))
     {
       produces<nanoaod::FlatTable>();
@@ -42,11 +47,15 @@ class MuonExtendedTableProducer : public edm::global::EDProducer<> {
 
     static void fillDescriptions(edm::ConfigurationDescriptions & descriptions) {
       edm::ParameterSetDescription desc;
+      desc.add<edm::InputTag>("rho")->setComment("input rho parameter");
       desc.add<edm::InputTag>("muons")->setComment("input muon collection");
       desc.add<edm::InputTag>("dsaMuons")->setComment("input displaced standalone muon collection");
       desc.add<edm::InputTag>("primaryVertex")->setComment("input primary vertex collection");
       desc.add<edm::InputTag>("beamspot")->setComment("input beamspot collection");
       desc.add<edm::InputTag>("generalTracks")->setComment("input generalTracks collection");
+      desc.add<edm::InputTag>("jets")->setComment("input jet collection");
+      desc.add<edm::InputTag>("jetsFat")->setComment("input fat jet collection");
+      desc.add<edm::InputTag>("jetsSub")->setComment("input sub jet collection");
       desc.add<std::string>("name")->setComment("name of the muon nanoaod::FlatTable we are extending");
       descriptions.add("muonTable", desc);
     }
@@ -56,21 +65,30 @@ class MuonExtendedTableProducer : public edm::global::EDProducer<> {
 
     int getMatches(const pat::Muon& muon, const reco::Track& dsaMuon, const float minPositionDiff) const;
 
+    float getPFIso(const pat::Muon& muon) const;
+    int findMatchedJet(const reco::Candidate& lepton, const edm::Handle< std::vector< pat::Jet > >& jets) const;
+    void fillLeptonJetVariables(const reco::Muon *mu, edm::Handle< std::vector< pat::Jet > >& jets, const reco::Vertex& vertex, const double rho, std::vector<int> *jetIdx, std::vector<float> relIso0p4, std::vector<float> *jetPtRatio, std::vector<float> *jetPtRel, std::vector<int> *jetSelectedChargedMultiplicity) const;
+
     std::string name_;
+    edm::EDGetTokenT<double> rhoTag_;
     edm::EDGetTokenT<std::vector<pat::Muon>> muonTag_;
     edm::EDGetTokenT<std::vector<reco::Track>> dsaMuonTag_;
     edm::EDGetTokenT<reco::VertexCollection> vtxTag_;
     edm::EDGetTokenT<reco::BeamSpot> bsTag_;
     edm::EDGetTokenT<std::vector<reco::Track>> generalTrackTag_;
-    edm::ESGetToken<TransientTrackBuilder, TransientTrackRecord> transientTrackBuilderToken_;
-
+    edm::EDGetTokenT<std::vector<pat::Jet> > jetTag_;
+    edm::EDGetTokenT<std::vector<pat::Jet> > jetFatTag_;
+    edm::EDGetTokenT<std::vector<pat::Jet> > jetSubTag_;
+    edm::ESGetToken<TransientTrackBuilder, TransientTrackRecord> transientTrackBuilderToken_;  
 };
 
-void MuonExtendedTableProducer::produce(edm::StreamID, edm::Event& iEvent, const edm::EventSetup& iSetup) const 
+void MuonExtendedTableProducer::produce(edm::StreamID, edm::Event& iEvent, const edm::EventSetup& iSetup) const
 {
 
   float minPositionDiffForMatching = 1e-6;
 
+  edm::Handle<double> rhoHandle;
+  iEvent.getByToken(rhoTag_, rhoHandle);
   edm::Handle<std::vector<pat::Muon>> muons;
   iEvent.getByToken(muonTag_, muons);
   edm::Handle<std::vector<reco::Track>> dsaMuons;
@@ -81,6 +99,12 @@ void MuonExtendedTableProducer::produce(edm::StreamID, edm::Event& iEvent, const
   iEvent.getByToken(bsTag_, beamspots);
   edm::Handle<std::vector<reco::Track>> generalTracks;
   iEvent.getByToken(generalTrackTag_, generalTracks);
+  edm::Handle<std::vector<pat::Jet> > jetHandle;
+  iEvent.getByToken(jetTag_, jetHandle);
+  edm::Handle<std::vector<pat::Jet> > jetFatHandle;
+  iEvent.getByToken(jetFatTag_, jetFatHandle);
+  edm::Handle<std::vector<pat::Jet> > jetSubHandle;
+  iEvent.getByToken(jetSubTag_, jetSubHandle);
 
   const auto& pv = primaryVertices->at(0);
   GlobalPoint primaryVertex(pv.x(), pv.y(), pv.z());
@@ -95,13 +119,21 @@ void MuonExtendedTableProducer::produce(edm::StreamID, edm::Event& iEvent, const
   edm::ESHandle<TransientTrackBuilder> builder = iSetup.getHandle(transientTrackBuilderToken_);
 
   unsigned int nMuons = muons->size();
-  unsigned int nDsaMuons = dsaMuons->size();
-  
+  unsigned int nDsaMuons = dsaMuons->size();  
 
   std::vector<float> idx, charge, trkPt, trkPtErr;
 
+  std::vector<float> innerTrackValidFraction, globalTrackNormalizedChi2, CQChi2Position, CQTrackKink;
+  std::vector<int> numberOfMatchedStation, numberOfValidPixelHits, numberOfValidTrackerHits, numberInnerHitsMissing, trackerLayersWithMeasurement, numberInnerHits;
+  std::vector<float> relIso0p4;
+  std::vector<float> jetPtRatio, jetPtRel;
+  std::vector<int> jetIdx;
+  std::vector<int> jetFatIdx, jetSubIdx;
+  std::vector<int> jetSelectedChargedMultiplicity;
+  std::vector<float> dxy, dz, IP3d, IP3dSig;
+  
   std::vector<float> dzPV,dzPVErr,dxyPVTraj,dxyPVTrajErr,dxyPVSigned,dxyPVSignedErr,ip3DPVSigned,ip3DPVSignedErr;
-  std::vector<float> dxyBS,dxyBSErr,dzBS,dzBSErr,dxyBSTraj,dxyBSTrajErr,dxyBSSigned,dxyBSSignedErr,ip3DBSSigned,ip3DBSSignedErr;
+  std::vector<float> dxyBS,dxyBSErr,dzBS,dzBSErr,dxyBSTraj,dxyBSTrajErr,dxyBSSigned,dxyBSSignedErr,ip3DBSSigned,ip3DBSSignedErr;  
 
   std::vector<float> trkNumPlanes,trkNumHits,trkNumDTHits,trkNumCSCHits,trkNumPixelHits(nMuons,-1),trkNumTrkLayers(nMuons,-1),normChi2;
   std::vector<float> outerEta(nMuons,-5),outerPhi(nMuons,-5);
@@ -141,6 +173,30 @@ void MuonExtendedTableProducer::produce(edm::StreamID, edm::Event& iEvent, const
     trkPt.push_back(track->pt());
     trkPtErr.push_back(track->ptError());
 
+    dxy.push_back(muon.dB(pat::Muon::PV2D));
+    dz.push_back(muon.dB(pat::Muon::PVDZ));
+    IP3d.push_back(muon.dB(pat::Muon::PV3D));
+    IP3dSig.push_back(fabs(muon.dB(pat::Muon::PV3D)/muon.edB(pat::Muon::PV3D)));
+
+    relIso0p4.push_back(getPFIso(muon));
+
+    fillLeptonJetVariables(&muon, jetHandle, pv, *rhoHandle, &jetIdx, relIso0p4, &jetPtRatio, &jetPtRel, &jetSelectedChargedMultiplicity);
+
+    const reco::Candidate *mu_cand = dynamic_cast<const reco::Candidate*>(&muon);
+    jetFatIdx.push_back(findMatchedJet(*mu_cand, jetFatHandle));
+    jetSubIdx.push_back(findMatchedJet(*mu_cand, jetSubHandle));
+
+    innerTrackValidFraction.push_back((!muon.innerTrack().isNull()) ? muon.innerTrack()->validFraction() : -1);
+    globalTrackNormalizedChi2.push_back((!muon.globalTrack().isNull()) ? muon.globalTrack()->normalizedChi2() : -1);
+    CQChi2Position.push_back(muon.combinedQuality().chi2LocalPosition);
+    CQTrackKink.push_back(muon.combinedQuality().trkKink);
+    numberOfMatchedStation.push_back(muon.numberOfMatchedStations());
+    numberOfValidPixelHits.push_back((!muon.innerTrack().isNull()) ? muon.innerTrack()->hitPattern().numberOfValidPixelHits() : 0);
+    numberOfValidTrackerHits.push_back((!muon.innerTrack().isNull()) ? muon.innerTrack()->hitPattern().numberOfValidTrackerHits() : 0);
+    numberInnerHitsMissing.push_back(muon.innerTrack()->hitPattern().numberOfLostHits(reco::HitPattern::MISSING_INNER_HITS));
+    trackerLayersWithMeasurement.push_back((!muon.innerTrack().isNull()) ? muon.innerTrack()->hitPattern().trackerLayersWithMeasurement() : 0);
+    numberInnerHits.push_back((!muon.globalTrack().isNull()) ? muon.globalTrack()->hitPattern().numberOfValidMuonHits() : (!muon.outerTrack().isNull() ? muon.outerTrack()->hitPattern().numberOfValidMuonHits() : 0));
+
     dzPV.push_back(track->dz(pv.position()));
     dzPVErr.push_back(std::hypot(track->dzError(), pv.zError()));
     TrajectoryStateClosestToPoint trajectoryPV = transientTrack.trajectoryStateClosestToPoint(primaryVertex);
@@ -218,9 +274,33 @@ void MuonExtendedTableProducer::produce(edm::StreamID, edm::Event& iEvent, const
   auto tab  = std::make_unique<nanoaod::FlatTable>(nMuons, name_, false, true);
   tab->addColumn<float>("idx", idx, "LLPnanoAOD muon index");
 
+  tab->addColumn<float>("dxy", dxy, "");
+  tab->addColumn<float>("dz", dz, "");
+  tab->addColumn<float>("IP3d", IP3d, "");
+  tab->addColumn<float>("IP3dSig", IP3dSig, "");
+  
   tab->addColumn<float>("trkPt", trkPt, "");
   tab->addColumn<float>("trkPtErr", trkPtErr, "");
 
+  tab->addColumn<float>("relIso0p4", relIso0p4, "");
+  tab->addColumn<float>("jetPtRatio", jetPtRatio, "");
+  tab->addColumn<float>("jetPtRel", jetPtRel, "");
+  tab->addColumn<int>("jetSelectedChargedMultiplicity", jetSelectedChargedMultiplicity, "");
+  tab->addColumn<int>("jetIdx", jetIdx, "");
+  tab->addColumn<int>("jetFatIdx", jetFatIdx, "");
+  tab->addColumn<int>("jetSubIdx", jetSubIdx, "");
+  
+  tab->addColumn<float>("innerTrackValidFraction", innerTrackValidFraction, "");
+  tab->addColumn<float>("globalTrackNormalizedChi2", globalTrackNormalizedChi2, "");
+  tab->addColumn<float>("CQChi2Position", CQChi2Position, "");
+  tab->addColumn<float>("CQTrackKink", CQTrackKink, "");
+  tab->addColumn<int>("numberOfMatchedStation", numberOfMatchedStation, "");
+  tab->addColumn<int>("numberOfValidPixelHits", numberOfValidPixelHits, "");
+  tab->addColumn<int>("numberOfValidTrackerHits", numberOfValidTrackerHits, "");
+  tab->addColumn<int>("numberInnerHitsMissing", numberInnerHitsMissing, "");
+  tab->addColumn<int>("trackerLayersWithMeasurement", trackerLayersWithMeasurement, "");
+  tab->addColumn<int>("numberInnerHits", numberInnerHits, "");
+
   tab->addColumn<float>("dzPV", dzPV, "");
   tab->addColumn<float>("dzPVErr", dzPVErr, "");
   tab->addColumn<float>("dxyPVTraj", dxyPVTraj, "");
@@ -277,30 +357,127 @@ int MuonExtendedTableProducer::getMatches(const pat::Muon& muon, const reco::Tra
 
   int nMatches = 0;
 
-  for (auto& hit : dsaMuon.recHits()){
-
-    if (!hit->isValid()) continue;
-    DetId id = hit->geographicalId();
-    if (id.det() != DetId::Muon) continue;
+  if( dsaMuon.extra().isNonnull() && dsaMuon.extra().isAvailable() ) {
+    
+    for (auto& hit : dsaMuon.recHits()){
+
+      if (!hit->isValid()) continue;
+      DetId id = hit->geographicalId();
+      if (id.det() != DetId::Muon) continue;
+      
+      if (id.subdetId() == MuonSubdetId::DT || id.subdetId() == MuonSubdetId::CSC){
+	
+	for (auto& chamber : muon.matches()) {
+
+	  if (chamber.id.rawId() != id.rawId()) continue;
+	  
+	  for (auto& segment : chamber.segmentMatches) {
+	    
+	    if (fabs(segment.x - hit->localPosition().x()) < minPositionDiff &&
+		fabs(segment.y - hit->localPosition().y()) < minPositionDiff) {
+              nMatches++;
+              break;
+	    }
+	  }
+	}
+      }
+    }
+  }
+  return nMatches;
+}
 
-    if (id.subdetId() == MuonSubdetId::DT || id.subdetId() == MuonSubdetId::CSC){
+float MuonExtendedTableProducer::getPFIso(const pat::Muon& muon) const {
+  return (muon.pfIsolationR04().sumChargedHadronPt +
+          std::max(0.,
+                   muon.pfIsolationR04().sumNeutralHadronEt + muon.pfIsolationR04().sumPhotonEt -
+                   0.5 * muon.pfIsolationR04().sumPUPt)) / muon.pt();
+}
 
-      for (auto& chamber : muon.matches()) {
+template< typename T1, typename T2 > bool isSourceCandidatePtrMatch( const T1& lhs, const T2& rhs ) {
+  
+  for( size_t lhsIndex = 0; lhsIndex < lhs.numberOfSourceCandidatePtrs(); ++lhsIndex ) {
+    auto lhsSourcePtr = lhs.sourceCandidatePtr( lhsIndex );
+    for( size_t rhsIndex = 0; rhsIndex < rhs.numberOfSourceCandidatePtrs(); ++rhsIndex ) {
+      auto rhsSourcePtr = rhs.sourceCandidatePtr( rhsIndex );
+      if( lhsSourcePtr == rhsSourcePtr ) {
+	return true;
+      }
+    }
+  }
+  
+  return false;
+}
 
-        if (chamber.id.rawId() != id.rawId()) continue;
+int MuonExtendedTableProducer::findMatchedJet(const reco::Candidate& lepton, const edm::Handle< std::vector< pat::Jet > >& jets) const {
 
-        for (auto& segment : chamber.segmentMatches) {
+  int iJet = -1;
+  
+  unsigned int nJets = jets->size();
+  
+  for(unsigned int i = 0; i < nJets; i++) {
+    const pat::Jet & jet = (*jets)[i];
+    if( isSourceCandidatePtrMatch( lepton, jet ) ) {
+      return i;
+    }
+  }
+  
+  return iJet;
+}
 
-          if (fabs(segment.x - hit->localPosition().x()) < minPositionDiff &&
-              fabs(segment.y - hit->localPosition().y()) < minPositionDiff) {
-              nMatches++;
-              break;
-          }
-        }
+void MuonExtendedTableProducer::fillLeptonJetVariables(const reco::Muon *mu, edm::Handle< std::vector< pat::Jet > >& jets, const reco::Vertex& vertex, const double rho, std::vector<int> *jetIdx, std::vector<float> relIso0p4, std::vector<float> *jetPtRatio, std::vector<float> *jetPtRel, std::vector<int> *jetSelectedChargedMultiplicity) const {
+   
+  const reco::Candidate *cand = dynamic_cast<const reco::Candidate*>(mu);
+  int matchedJetIdx = findMatchedJet( *cand, jets );
+  
+  jetIdx->push_back(matchedJetIdx);
+
+  if( matchedJetIdx < 0 ) {
+    float ptRatio = ( 1. / ( 1. + relIso0p4.back() ) );
+    jetPtRatio->push_back(ptRatio);	 
+    jetPtRel->push_back(0);
+    jetSelectedChargedMultiplicity->push_back(0);
+  } else {
+    const pat::Jet& jet = (*jets)[matchedJetIdx];
+    auto rawJetP4 = jet.correctedP4("Uncorrected");
+    auto leptonP4 = cand->p4();
+    
+    bool leptonEqualsJet = ( ( rawJetP4 - leptonP4 ).P() < 1e-4 );
+    
+    if( leptonEqualsJet ) {
+      jetPtRatio->push_back(1);
+      jetPtRel->push_back(0);
+      jetSelectedChargedMultiplicity->push_back(0);	    
+    } else {
+      auto L1JetP4 = jet.correctedP4("L1FastJet");
+      double L2L3JEC = jet.pt()/L1JetP4.pt();
+      auto lepAwareJetP4 = ( L1JetP4 - leptonP4 )*L2L3JEC + leptonP4;
+      
+      float ptRatio = cand->pt() / lepAwareJetP4.pt();
+      float ptRel = leptonP4.Vect().Cross( (lepAwareJetP4 - leptonP4 ).Vect().Unit() ).R();
+      jetPtRatio->push_back(ptRatio);
+      jetPtRel->push_back(ptRel);
+      jetSelectedChargedMultiplicity->push_back(0);
+      
+      for( const auto &daughterPtr : jet.daughterPtrVector() ) {
+	const pat::PackedCandidate& daughter = *( (const pat::PackedCandidate*) daughterPtr.get() );
+	
+	if( daughter.charge() == 0 ) continue;
+	if( daughter.fromPV() < 2 ) continue;
+	if( reco::deltaR( daughter, *cand ) > 0.4 ) continue;
+	if( !daughter.hasTrackDetails() ) continue;
+	
+	auto daughterTrack = daughter.pseudoTrack();
+	    
+	if( daughterTrack.pt() <= 1 ) continue;
+	if( daughterTrack.hitPattern().numberOfValidHits() < 8 ) continue;
+	if( daughterTrack.hitPattern().numberOfValidPixelHits() < 2 ) continue;
+	if( daughterTrack.normalizedChi2() >= 5 ) continue;
+	if( std::abs( daughterTrack.dz( vertex.position() ) ) >= 17 ) continue;
+	if( std::abs( daughterTrack.dxy( vertex.position() ) ) >= 0.2 ) continue;
+	++jetSelectedChargedMultiplicity->back();
       }
-    }
+    }      
   }
-  return nMatches;
 }
 
 #include "FWCore/Framework/interface/MakerMacros.h"
diff --git a/plugins/MuonVertexTableProducer.cc b/plugins/MuonVertexTableProducer.cc
index 38085fd..0841d29 100644
--- a/plugins/MuonVertexTableProducer.cc
+++ b/plugins/MuonVertexTableProducer.cc
@@ -84,9 +84,9 @@ class MuonVertexTableProducer : public edm::global::EDProducer<> {
 
     template <typename MuonType1 = pat::Muon, typename MuonType2>
     float getDisplacedTrackerIsolation(const std::vector<reco::Track>& generalTracks, const MuonType1& muon_1,
-                                      const reco::Vertex muonVertex, const reco::BeamSpot& beamspot, 
-                                      const MuonType2* muon_2 = nullptr, float maxDR = 0.3, float minDR = 0.01,
-                                      float maxDz = 0.5, float maxDxy = 0.2) const;
+				       const reco::Vertex muonVertex, const reco::BeamSpot& beamspot, 
+				       const MuonType2* muon_2 = nullptr, float maxDR = 0.3, float minDR = 0.01,
+				       float maxDz = 0.5, float maxDxy = 0.2) const;
     
     template <typename MuonType=reco::Track>
     float getProximityDeltaR(const MuonType& track, 
diff --git a/python/custom_dispjet_cff.py b/python/custom_dispjet_cff.py
new file mode 100644
index 0000000..701cff5
--- /dev/null
+++ b/python/custom_dispjet_cff.py
@@ -0,0 +1,23 @@
+import FWCore.ParameterSet.Config as cms
+from PhysicsTools.NanoAOD.common_cff import *
+
+process.load('PhysicsTools.EXOnanoAOD.displacedInclusiveVertexing_cff')
+
+outputTable = cms.EDProducer("DispJetTableProducer",
+                             rho=cms.InputTag("fixedGridRhoFastjetAll"),
+                             electrons=cms.InputTag("linkedObjects","electrons"),
+                             muons=cms.InputTag("linkedObjects","muons"),
+                             jets=cms.InputTag("linkedObjects","jets"),
+                             jetsFat=cms.InputTag("slimmedJetsAK8"),
+                             jetsSub=cms.InputTag("slimmedJetsAK8PFPuppiSoftDropPacked", "SubJets"),
+                             primaryVertex = cms.InputTag("offlineSlimmedPrimaryVertices"),
+                             secondaryVertex = cms.InputTag("displacedInclusiveSecondaryVertices")
+)
+
+def add_dispJetTables(process):
+
+    process.outputTable = outputTable
+    process.exonanoaodTask = cms.Task(process.outputTable)
+    process.nanoTableTaskCommon.add(process.exonanoaodTask)
+    
+    return process
diff --git a/python/custom_exo_cff.py b/python/custom_exo_cff.py
index 513b64f..fa19ce5 100644
--- a/python/custom_exo_cff.py
+++ b/python/custom_exo_cff.py
@@ -53,11 +53,15 @@
 
 PATmuonExtendedTable = cms.EDProducer("MuonExtendedTableProducer",
     name=cms.string("Muon"),
+    rho=cms.InputTag("fixedGridRhoFastjetAll"),
     muons=cms.InputTag("linkedObjects","muons"),
     dsaMuons=cms.InputTag("displacedStandAloneMuons"),
     primaryVertex=cms.InputTag("offlineSlimmedPrimaryVertices"),
-    beamspot=cms.InputTag("offlineBeamSpot"),
-    generalTracks=cms.InputTag("generalTracks")
+    beamspot=cms.InputTag("offlineBeamSpot"),                        
+    generalTracks=cms.InputTag("generalTracks"),
+    jets=cms.InputTag("linkedObjects","jets"),
+    jetsFat=cms.InputTag("slimmedJetsAK8"),
+    jetsSub=cms.InputTag("slimmedJetsAK8PFPuppiSoftDropPacked", "SubJets")
 )
 
 electronVertexTable = cms.EDProducer("ElectronVertexTableProducer",
@@ -69,9 +73,34 @@
 
 electronExtendedTable = cms.EDProducer("ElectronExtendedTableProducer",
     name=cms.string("Electron"),
+    rho=cms.InputTag("fixedGridRhoFastjetAll"),                                       
     electrons=cms.InputTag("linkedObjects","electrons"),
+    primaryVertex=cms.InputTag("offlineSlimmedPrimaryVertices"),
+    jets=cms.InputTag("linkedObjects","jets"),
+    jetsFat=cms.InputTag("slimmedJetsAK8"),
+    jetsSub=cms.InputTag("slimmedJetsAK8PFPuppiSoftDropPacked", "SubJets")
+)
+
+dispJetTable = cms.EDProducer("DispJetTableProducer",
+    electrons=cms.InputTag("linkedObjects","electrons"),
+    muons=cms.InputTag("linkedObjects","muons"),
+    primaryVertex = cms.InputTag("offlineSlimmedPrimaryVertices"),
+    secondaryVertex = cms.InputTag("displacedInclusiveSecondaryVertices")
 )
 
+def add_dispJetTables(process):
+    process.load('PhysicsTools.EXOnanoAOD.displacedInclusiveVertexing_cff')
+    process.dispJetTable = dispJetTable
+    process.dispJetTask = cms.Task(process.unpackedTracksAndVertices)
+    process.dispJetTask.add(process.displacedInclusiveVertexFinder)
+    process.dispJetTask.add(process.displacedVertexMerger)
+    process.dispJetTask.add(process.displacedTrackVertexArbitrator)
+    process.dispJetTask.add(process.displacedInclusiveSecondaryVertices)
+    process.dispJetTask.add(process.dispJetTable)
+    process.nanoTableTaskCommon.add(process.dispJetTask)
+
+    return process
+
 def add_mdsTables(process):
     process.ca4CSCrechitClusters = cscRechitClusterProducer    
     process.ca4DTrechitClusters = dtRechitClusterProducer
@@ -115,12 +144,24 @@ def add_electronVertexTables(process):
 
     process.electronVertexTask = cms.Task(process.electronVertexTable)
     process.electronExtendedTask = cms.Task(process.electronExtendedTable)
-
+    
     process.nanoTableTaskCommon.add(process.electronVertexTask)
     process.nanoTableTaskCommon.add(process.electronExtendedTask)
 
     return process
 
+def add_muonExtendedTable(process):
+    process.load("TrackingTools.TransientTrack.TransientTrackBuilder_cfi")
+    process.load('TrackPropagation.SteppingHelixPropagator.SteppingHelixPropagatorAny_cfi')
+
+    process.PATmuonExtendedTable = PATmuonExtendedTable
+
+    process.muonExtendedTask = cms.Task(process.PATmuonExtendedTable)
+
+    process.nanoTableTaskCommon.add(process.muonExtendedTask)
+
+    return process
+
 def update_genParticleTable(process):
 
     process.genParticleTable.variables.vx = Var("vx",float, doc = "gen particle production vertex x coordinate (cm)", precision=8)
@@ -138,6 +179,18 @@ def add_exonanoTables(process):
     process = add_mdsTables(process)
     process = add_dsamuonTables(process)
     process = add_electronVertexTables(process)
+    process = add_dispJetTables(process)
+    process = update_genParticleTable(process)
+
+    return process
+
+def add_exonanoTablesMINIAOD(process):
+
+#    process = add_mdsTables(process)
+#    process = add_dsamuonTables(process)
+    process = add_electronVertexTables(process)
+    process = add_muonExtendedTable(process)
+    process = add_dispJetTables(process)
     process = update_genParticleTable(process)
 
     return process
diff --git a/python/displacedInclusiveVertexing_cff.py b/python/displacedInclusiveVertexing_cff.py
new file mode 100644
index 0000000..cfcf526
--- /dev/null
+++ b/python/displacedInclusiveVertexing_cff.py
@@ -0,0 +1,75 @@
+import FWCore.ParameterSet.Config as cms
+
+unpackedTracksAndVertices = cms.EDProducer('PATTrackAndVertexUnpacker',
+                                           slimmedVertices = cms.InputTag("offlineSlimmedPrimaryVertices"),
+                                           slimmedSecondaryVertices = cms.InputTag("slimmedSecondaryVertices"),
+                                           additionalTracks= cms.InputTag("lostTracks"),
+                                           packedCandidates = cms.InputTag("packedPFCandidates"))
+
+# ref: https://github.com/cms-sw/cmssw/blob/2bed69b1658e4deeaef914e462741919e9183be3/RecoVertex/AdaptiveVertexFinder/plugins/InclusiveVertexFinder.h#L48
+
+displacedInclusiveVertexFinder  = cms.EDProducer("InclusiveVertexFinder",
+                                                 beamSpot = cms.InputTag("offlineBeamSpot"),
+                                                 primaryVertices = cms.InputTag("offlineSlimmedPrimaryVertices"),
+                                                 tracks = cms.InputTag("unpackedTracksAndVertices"),
+                                                 minHits = cms.uint32(6), # 8
+                                                 maximumLongitudinalImpactParameter = cms.double(20), # 0.3
+                                                 minPt = cms.double(0.8), # 0.8
+                                                 maxNTracks = cms.uint32(100), # 30
+                                                 
+                                                 clusterizer = cms.PSet(
+                                                     seedMax3DIPSignificance = cms.double(9999.), # 9999.
+                                                     seedMax3DIPValue = cms.double(9999.), # 9999.
+                                                     seedMin3DIPSignificance = cms.double(1.2), # 1.2
+                                                     seedMin3DIPValue = cms.double(0.005), # 0.005
+                                                     clusterMaxDistance = cms.double(0.4), # 0.05
+                                                     clusterMaxSignificance = cms.double(4.5), # 4.5
+                                                     distanceRatio = cms.double(20), # 20
+                                                     clusterMinAngleCosine = cms.double(0.5), # 0.5
+                                                 ),
+                                                     
+                                                 vertexMinAngleCosine = cms.double(0.95), # 0.95
+                                                 vertexMinDLen2DSig = cms.double(2.5), # 2.5
+                                                 vertexMinDLenSig = cms.double(0.5), # 0.5
+                                                 fitterSigmacut =  cms.double(3), # 3
+                                                 fitterTini = cms.double(256), # 256
+                                                 fitterRatio = cms.double(0.25), # 0.25
+                                                 useDirectVertexFitter = cms.bool(True), # True
+                                                 useVertexReco  = cms.bool(True), # True
+                                                 vertexReco = cms.PSet(
+                                                     finder = cms.string('avr'),
+                                                     primcut = cms.double(1.0), # 1.0
+                                                     seccut = cms.double(3), # 3
+                                                     smoothing = cms.bool(True)) # True
+                                            )
+                                            
+displacedVertexMerger = cms.EDProducer("VertexMerger",
+                                       secondaryVertices = cms.InputTag("displacedInclusiveVertexFinder"),
+                                       maxFraction = cms.double(0.7),
+                                       minSignificance = cms.double(2))
+
+# ref: https://github.com/cms-sw/cmssw/blob/2bed69b1658e4deeaef914e462741919e9183be3/RecoVertex/AdaptiveVertexFinder/plugins/VertexArbitrators.cc#L54
+
+displacedTrackVertexArbitrator = cms.EDProducer("TrackVertexArbitrator",
+                                                beamSpot = cms.InputTag("offlineBeamSpot"),
+                                                primaryVertices = cms.InputTag("offlineSlimmedPrimaryVertices"),
+                                                tracks = cms.InputTag("unpackedTracksAndVertices"),
+                                                secondaryVertices = cms.InputTag("displacedVertexMerger"),
+                                                dLenFraction = cms.double(0.333), # 0.333
+                                                dRCut = cms.double(1), # 0.4
+                                                distCut = cms.double(0.1), # 0.04
+                                                sigCut = cms.double(5), # 5
+                                                fitterSigmacut =  cms.double(3), # 3
+                                                fitterTini = cms.double(256), # 256
+                                                fitterRatio = cms.double(0.25), # 0.25
+                                                trackMinLayers = cms.int32(4), # 4
+                                                trackMinPt = cms.double(.4), # 0.4
+                                                trackMinPixels = cms.int32(0) # 1
+)
+    
+displacedInclusiveSecondaryVertices = displacedVertexMerger.clone()
+displacedInclusiveSecondaryVertices.secondaryVertices = cms.InputTag("displacedTrackVertexArbitrator")
+displacedInclusiveSecondaryVertices.maxFraction = 0.2
+displacedInclusiveSecondaryVertices.minSignificance = 10
+    
+displacedInclusiveVertexing = cms.Sequence(unpackedTracksAndVertices * displacedInclusiveVertexFinder  * displacedVertexMerger * displacedTrackVertexArbitrator * displacedInclusiveSecondaryVertices)
diff --git a/test/Run3_2023_MINIAOD_EXONANO_template.py b/test/Run3_2023_MINIAOD_EXONANO_template.py
new file mode 100644
index 0000000..a3de83a
--- /dev/null
+++ b/test/Run3_2023_MINIAOD_EXONANO_template.py
@@ -0,0 +1,134 @@
+import FWCore.ParameterSet.Config as cms
+from FWCore.ParameterSet.VarParsing import VarParsing
+
+from Configuration.Eras.Era_Run3_cff import Run3
+
+options = VarParsing('analysis')
+options.register('runOnData',
+                    False,
+                    VarParsing.multiplicity.singleton,
+                    VarParsing.varType.bool,
+                    "If running on data"
+                )
+options.parseArguments()
+
+process = cms.Process('NANO',Run3)
+
+# import of standard configurations
+process.load('Configuration.StandardSequences.Services_cff')
+process.load('SimGeneral.HepPDTESSource.pythiapdt_cfi')
+process.load('FWCore.MessageService.MessageLogger_cfi')
+process.load('Configuration.EventContent.EventContent_cff')
+process.load('SimGeneral.MixingModule.mixNoPU_cfi')
+process.load('Configuration.StandardSequences.GeometryRecoDB_cff')
+process.load('Configuration.StandardSequences.MagneticField_cff')
+#process.load('Configuration.StandardSequences.PATMC_cff')
+process.load('PhysicsTools.NanoAOD.nano_cff')
+process.load('Configuration.StandardSequences.EndOfProcess_cff')
+process.load('Configuration.StandardSequences.FrontierConditions_GlobalTag_cff')
+
+process.maxEvents = cms.untracked.PSet(
+    input = cms.untracked.int32(10),
+    output = cms.optional.untracked.allowed(cms.int32,cms.PSet)
+)
+
+# Input source
+process.source = cms.Source("PoolSource",
+#    fileNames = cms.untracked.vstring('/store/mc/Run3Summer23MiniAODv4/TTto2L2Nu_TuneCP5_13p6TeV_powheg-pythia8/MINIAODSIM/130X_mcRun3_2023_realistic_v14-v2/70001/5b425dde-7d94-4469-8558-3ffc4d7d3fd3.root'),
+#    fileNames = cms.untracked.vstring('file:/pnfs/iihe/cms/store/user/kskovpen/LRSM/input/5b425dde-7d94-4469-8558-3ffc4d7d3fd3.root'),
+    fileNames = cms.untracked.vstring(options.inputFiles),
+    secondaryFileNames = cms.untracked.vstring()
+)
+
+process.options = cms.untracked.PSet(
+    IgnoreCompletely = cms.untracked.vstring(),
+    Rethrow = cms.untracked.vstring(),
+    TryToContinue = cms.untracked.vstring(),
+    accelerators = cms.untracked.vstring('*'),
+    allowUnscheduled = cms.obsolete.untracked.bool,
+    canDeleteEarly = cms.untracked.vstring(),
+    deleteNonConsumedUnscheduledModules = cms.untracked.bool(True),
+    dumpOptions = cms.untracked.bool(False),
+    emptyRunLumiMode = cms.obsolete.untracked.string,
+    eventSetup = cms.untracked.PSet(
+        forceNumberOfConcurrentIOVs = cms.untracked.PSet(
+            allowAnyLabel_=cms.required.untracked.uint32
+        ),
+        numberOfConcurrentIOVs = cms.untracked.uint32(0)
+    ),
+    fileMode = cms.untracked.string('FULLMERGE'),
+    forceEventSetupCacheClearOnNewRun = cms.untracked.bool(False),
+    holdsReferencesToDeleteEarly = cms.untracked.VPSet(),
+    makeTriggerResults = cms.obsolete.untracked.bool,
+    modulesToCallForTryToContinue = cms.untracked.vstring(),
+    modulesToIgnoreForDeleteEarly = cms.untracked.vstring(),
+    numberOfConcurrentLuminosityBlocks = cms.untracked.uint32(0),
+    numberOfConcurrentRuns = cms.untracked.uint32(1),
+    numberOfStreams = cms.untracked.uint32(0),
+    numberOfThreads = cms.untracked.uint32(1),
+    printDependencies = cms.untracked.bool(False),
+    sizeOfStackForThreadsInKB = cms.optional.untracked.uint32,
+    throwIfIllegalParameter = cms.untracked.bool(True),
+    wantSummary = cms.untracked.bool(False)
+)
+
+# Production Info
+process.configurationMetadata = cms.untracked.PSet(
+    annotation = cms.untracked.string('test nevts:100'),
+    name = cms.untracked.string('Applications'),
+    version = cms.untracked.string('$Revision: 1.19 $')
+)
+
+# Output definition
+
+process.NANOAODoutput = cms.OutputModule("NanoAODOutputModule",
+    compressionAlgorithm = cms.untracked.string('LZMA'),
+    compressionLevel = cms.untracked.int32(9),
+    dataset = cms.untracked.PSet(
+        dataTier = cms.untracked.string('NANOAOD'),
+        filterName = cms.untracked.string('')
+    ),
+    fileName = cms.untracked.string('file:{0}'.format(options.outputFile)),
+#    fileName = cms.untracked.string('Run3_2023_PAT_EXONANO_template.root'),
+    outputCommands = process.NANOAODEventContent.outputCommands
+)
+
+# Additional output definition
+
+# Other statements
+from Configuration.AlCa.GlobalTag import GlobalTag
+process.GlobalTag = GlobalTag(process.GlobalTag, 'auto:phase1_2023_realistic_postBPix', '')
+
+# Path and EndPath definitions
+process.nanoAOD_step = cms.Path(process.nanoSequenceMC)
+process.endjob_step = cms.EndPath(process.endOfProcess)
+process.NANOAODoutput_step = cms.EndPath(process.NANOAODoutput)
+
+# Schedule definition
+process.schedule = cms.Schedule(process.nanoAOD_step,process.endjob_step,process.NANOAODoutput_step)
+##process.schedule.associate(process.patTask)
+from PhysicsTools.PatAlgos.tools.helpers import associatePatAlgosToolsTask
+associatePatAlgosToolsTask(process)
+
+# customisation of the process.
+
+# Automatic addition of the customisation function from PhysicsTools.NanoAOD.nano_cff
+from PhysicsTools.NanoAOD.nano_cff import nanoAOD_customizeCommon 
+
+#call to customisation function nanoAOD_customizeCommon imported from PhysicsTools.NanoAOD.nano_cff
+process = nanoAOD_customizeCommon(process)
+
+# EXOnanoAOD customisations
+from PhysicsTools.EXOnanoAOD.custom_exo_cff import add_exonanoTablesMINIAOD, add_exonanoMCTables
+process = add_exonanoTablesMINIAOD(process)
+process = add_exonanoMCTables(process)
+
+# End of customisation functions
+
+# Customisation from command line
+
+process.add_(cms.Service('InitRootHandlers', EnableIMT = cms.untracked.bool(False)));process.MessageLogger.cerr.FwkReport.reportEvery=1000
+# Add early deletion of temporary data products to reduce peak memory need
+from Configuration.StandardSequences.earlyDeleteSettings_cff import customiseEarlyDelete
+process = customiseEarlyDelete(process)
+# End adding early deletion


Reviews:
user: login: kerstinlovisa
body: Hi @kskovpen, sorry for the late review I've been a bit busy.

Thanks a lot for this work! Let me know if my comments are unclear in some way. 
state: COMMENTED
author_association: OWNER
submitted_at: 2025-04-09T15:02:12Z
user: login: kskovpen
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-03T18:42:40Z
user: login: kskovpen
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-03T18:43:36Z
user: login: kskovpen
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-03T18:44:02Z
user: login: kskovpen
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-03T18:53:25Z
user: login: kskovpen
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-03T19:06:58Z
user: login: kerstinlovisa
body: Thanks a lot Kirill! I will merge it now
state: APPROVED
author_association: OWNER
submitted_at: 2025-05-16T11:19:26Z

Review comments:
diff_hunk: @@ -0,0 +1,733 @@
+// -*- C++ -*-
+//
+// Package:    PhysicsTools/EXOnanoAOD
+// Class:      DispJetTableProducer
+//
+/**\class DispJetTableProducer
+
+ Description: Additional variables for displaced vertices involving at least one lepton and other tracks
+
+*/
+//
+// Original Author:  Kirill Skovpen
+//         Created:  Sat, 1 Mar 2025 08:37:01 GMT
+//
+
+// system include files
+#include <memory>
+
+// user include files
+#include "FWCore/Framework/interface/Frameworkfwd.h"
+#include "FWCore/Framework/interface/stream/EDProducer.h"
+
+#include "FWCore/Framework/interface/Event.h"
+#include "FWCore/Framework/interface/MakerMacros.h"
+
+#include "FWCore/ParameterSet/interface/ParameterSet.h"
+#include "FWCore/Utilities/interface/StreamID.h"
+
+#include "DataFormats/PatCandidates/interface/Electron.h"
+#include "DataFormats/PatCandidates/interface/Muon.h"
+#include "DataFormats/PatCandidates/interface/Jet.h"
+#include "DataFormats/MuonReco/interface/MuonSelectors.h"
+
+// nanoAOD include files
+#include "DataFormats/NanoAOD/interface/FlatTable.h"
+
+// object specific include files
+#include "TrackingTools/TransientTrack/interface/TransientTrackBuilder.h"
+#include "TrackingTools/Records/interface/TransientTrackRecord.h"
+#include "TrackingTools/IPTools/interface/IPTools.h"
+#include "DataFormats/TrackReco/interface/Track.h"
+#include "DataFormats/VertexReco/interface/VertexFwd.h"
+#include "DataFormats/VertexReco/interface/Vertex.h"
+
+class DispJetTableProducer : public edm::stream::EDProducer<> {
+protected:
+
+  float dEtaInSeed(const pat::Electron* el) const;
+  float getPFIso(const pat::Muon& muon) const;
+  float getPFIso(const pat::Electron& electron) const;
+  int findMatchedJet(const reco::Candidate& lepton, const edm::Handle< std::vector< pat::Jet > >& jets);
+  void fillLeptonJetVariables(const reco::GsfElectron *el, const reco::Muon *mu, edm::Handle< std::vector< pat::Jet > >& jets, const reco::Vertex& vertex, const double rho);
+
+  edm::ESGetToken<TransientTrackBuilder, TransientTrackRecord> ttbToken_;
+  edm::EDGetTokenT<double> rhoTag_;
+  edm::EDGetTokenT<std::vector<pat::Electron> > electronTag_;
+  edm::EDGetTokenT<std::vector<pat::Muon> > muonTag_;
+  edm::EDGetTokenT<std::vector<pat::Jet> > jetTag_;
+  edm::EDGetTokenT<std::vector<pat::Jet> > jetFatTag_;
+  edm::EDGetTokenT<std::vector<pat::Jet> > jetSubTag_;
+  edm::EDGetTokenT<reco::VertexCollection> vtxTag_;
+  edm::EDGetTokenT<reco::VertexCollection> secVtxTag_;
+
+  const TransientTrackBuilder* theB;
+  
+  std::vector<int> el_idx;
+  std::vector<bool> el_lIVF_match;
+  std::vector<bool> el_isEB, el_isEE;
+  std::vector<float> el_superClusterOverP, el_ecalEnergy, el_dEtaInSeed;
+  std::vector<int> el_numberInnerHitsMissing, el_numberOfValidPixelHits, el_numberOfValidTrackerHits;
+  std::vector<int> el_IVF_df, el_IVF_ntracks, el_IVF_elid;
+  std::vector<float> el_IVF_x, el_IVF_y, el_IVF_z, el_IVF_cx, el_IVF_cy, el_IVF_cz, el_IVF_chi2, el_IVF_pt, el_IVF_eta, el_IVF_phi, el_IVF_E, el_IVF_mass;
+  std::vector<int> el_IVF_trackcharge, el_IVF_trackelid, el_IVF_trackvtxid;
+  std::vector<float> el_IVF_trackpt, el_IVF_tracketa, el_IVF_trackphi, el_IVF_trackE, el_IVF_trackdxy, el_IVF_trackdz;
+  std::vector<float> el_IVF_tracksignedIP2D, el_IVF_tracksignedIP3D, el_IVF_tracksignedIP2Dsig, el_IVF_tracksignedIP3Dsig;
+  
+  std::vector<float> el_jetPtRatio, el_jetPtRel;
+  std::vector<int> el_jetIdx, el_jetSelectedChargedMultiplicity;
+  std::vector<int> el_jetFatIdx, el_jetSubIdx;
+  std::vector<float> el_relIso0p4;
+  std::vector<float> el_sigmaIetaIeta, el_deltaPhiSuperClusterTrack, el_deltaEtaSuperClusterTrack, el_eInvMinusPInv, el_hOverE;
+  
+  std::vector<float> el_dxy, el_dz, el_3dIP, el_3dIPSig;
+  std::vector<float> el_IVF_signedIP2D, el_IVF_signedIP3D, el_IVF_signedIP2Dsig, el_IVF_signedIP3Dsig;
+   
+  std::vector<int> mu_idx;
+  std::vector<bool> mu_lIVF_match;
+  std::vector<float> mu_innerTrackValidFraction, mu_globalTrackNormalizedChi2, mu_CQChi2Position, mu_CQTrackKink;
+  std::vector<int> mu_numberOfMatchedStation, mu_numberOfValidPixelHits, mu_numberOfValidTrackerHits, mu_numberInnerHitsMissing, mu_trackerLayersWithMeasurement, mu_numberInnerHits;
+  std::vector<int> mu_IVF_df, mu_IVF_ntracks, mu_IVF_muid;
+  std::vector<float> mu_IVF_x, mu_IVF_y, mu_IVF_z, mu_IVF_cx, mu_IVF_cy, mu_IVF_cz, mu_IVF_chi2, mu_IVF_pt, mu_IVF_eta, mu_IVF_phi, mu_IVF_E, mu_IVF_mass;
+  std::vector<int> mu_IVF_trackcharge, mu_IVF_trackmuid, mu_IVF_trackvtxid;
+  std::vector<float> mu_IVF_trackpt, mu_IVF_tracketa, mu_IVF_trackphi, mu_IVF_trackE, mu_IVF_trackdxy, mu_IVF_trackdz;
+  std::vector<float> mu_IVF_tracksignedIP2D, mu_IVF_tracksignedIP3D, mu_IVF_tracksignedIP2Dsig, mu_IVF_tracksignedIP3Dsig;
+  
+  std::vector<float> mu_jetPtRatio, mu_jetPtRel;
+  std::vector<int> mu_jetIdx, mu_jetSelectedChargedMultiplicity;
+  std::vector<int> mu_jetFatIdx, mu_jetSubIdx;
+  std::vector<float> mu_relIso0p4;
+  std::vector<float> mu_trackPt, mu_trackPtErr;
+  
+  std::vector<float> mu_dxy, mu_dz, mu_3dIP, mu_3dIPSig;
+  std::vector<float> mu_IVF_signedIP2D, mu_IVF_signedIP3D, mu_IVF_signedIP2Dsig, mu_IVF_signedIP3Dsig;
+
+public:
+  DispJetTableProducer(edm::ParameterSet const& params)
+    :
+    ttbToken_(esConsumes(edm::ESInputTag("", "TransientTrackBuilder"))),
+    rhoTag_(consumes<double>(params.getParameter<edm::InputTag>("rho"))),
+    electronTag_(consumes<std::vector<pat::Electron>>(params.getParameter<edm::InputTag>("electrons"))),
+    muonTag_(consumes<std::vector<pat::Muon>>(params.getParameter<edm::InputTag>("muons"))),
+    jetTag_(consumes<std::vector<pat::Jet>>(params.getParameter<edm::InputTag>("jets"))),
+    jetFatTag_(consumes<std::vector<pat::Jet>>(params.getParameter<edm::InputTag>("jetsFat"))),
+    jetSubTag_(consumes<std::vector<pat::Jet>>(params.getParameter<edm::InputTag>("jetsSub"))),
+    vtxTag_(consumes<reco::VertexCollection>(params.getParameter<edm::InputTag>("primaryVertex"))),
+    secVtxTag_(consumes<reco::VertexCollection>(params.getParameter<edm::InputTag>("secondaryVertex"))) {
+       produces<nanoaod::FlatTable>("DispJetElectron");
+       produces<nanoaod::FlatTable>("DispJetElectronVtx");
+       produces<nanoaod::FlatTable>("DispJetElectronTrk");
+       produces<nanoaod::FlatTable>("DispJetMuon");
+       produces<nanoaod::FlatTable>("DispJetMuonVtx");
+       produces<nanoaod::FlatTable>("DispJetMuonTrk");
+  }   
+
+  ~DispJetTableProducer() override {}
+  
+  void produce(edm::Event& iEvent, const edm::EventSetup& iSetup) override {
+
+    theB = &iSetup.getData(ttbToken_);
+    
+    edm::Handle<double> rhoHandle;
+    iEvent.getByToken(rhoTag_, rhoHandle);
+    
+    edm::Handle<std::vector<pat::Electron> > electronHandle;
+    iEvent.getByToken(electronTag_, electronHandle);
+    
+    edm::Handle<std::vector<pat::Muon> > muonHandle;
+    iEvent.getByToken(muonTag_, muonHandle);
+    
+    edm::Handle<std::vector<pat::Jet> > jetHandle;
+    iEvent.getByToken(jetTag_, jetHandle);
+
+    edm::Handle<std::vector<pat::Jet> > jetFatHandle;
+    iEvent.getByToken(jetFatTag_, jetFatHandle);
+
+    edm::Handle<std::vector<pat::Jet> > jetSubHandle;
+    iEvent.getByToken(jetSubTag_, jetSubHandle);
+    
+    edm::Handle<reco::VertexCollection> primaryVertexHandle;
+    iEvent.getByToken(vtxTag_, primaryVertexHandle);
+    
+    edm::Handle<reco::VertexCollection> secondaryVertexHandle;
+    iEvent.getByToken(secVtxTag_, secondaryVertexHandle);
+    
+    const auto& pv = primaryVertexHandle->at(0);
+    GlobalPoint primaryVertex(pv.x(), pv.y(), pv.z());
+    
+    const reco::VertexCollection & secVertices = (*secondaryVertexHandle);
+    
+    unsigned int nElectrons = electronHandle->size();
+    unsigned int nMuons = muonHandle->size();
+    
+    el_idx.clear();
+    el_lIVF_match.clear();
+    el_isEB.clear(); el_isEE.clear();
+    el_superClusterOverP.clear(); el_ecalEnergy.clear(); el_dEtaInSeed.clear();
+    el_numberInnerHitsMissing.clear(); el_numberOfValidPixelHits.clear(); el_numberOfValidTrackerHits.clear();
+    el_IVF_df.clear(); el_IVF_ntracks.clear(); el_IVF_elid.clear();
+    el_IVF_x.clear(); el_IVF_y.clear(); el_IVF_z.clear(); el_IVF_cx.clear(); el_IVF_cy.clear(); el_IVF_cz.clear(); el_IVF_chi2.clear(); el_IVF_pt.clear(); el_IVF_eta.clear(); el_IVF_phi.clear(); el_IVF_E.clear(); el_IVF_mass.clear();
+    el_IVF_trackcharge.clear(); el_IVF_trackelid.clear(); el_IVF_trackvtxid.clear();
+    el_IVF_trackpt.clear(); el_IVF_tracketa.clear(); el_IVF_trackphi.clear(); el_IVF_trackE.clear(); el_IVF_trackdxy.clear(); el_IVF_trackdz.clear();
+    el_IVF_tracksignedIP2D.clear(); el_IVF_tracksignedIP2Dsig.clear(); el_IVF_tracksignedIP3D.clear(); el_IVF_tracksignedIP3Dsig.clear();
+    
+    el_jetPtRatio.clear(); el_jetPtRel.clear();
+    el_jetIdx.clear(); el_jetSelectedChargedMultiplicity.clear();
+    el_jetFatIdx.clear(); el_jetSubIdx.clear();
+    el_relIso0p4.clear();
+    el_sigmaIetaIeta.clear(); el_deltaPhiSuperClusterTrack.clear(); el_deltaEtaSuperClusterTrack.clear(); el_eInvMinusPInv.clear(); el_hOverE.clear();    
+    el_dxy.clear(); el_dz.clear(); el_3dIP.clear(); el_3dIPSig.clear();
+    el_IVF_signedIP2D.clear(); el_IVF_signedIP2Dsig.clear(); el_IVF_signedIP3D.clear(); el_IVF_signedIP3Dsig.clear();
+    
+    mu_idx.clear();
+    mu_lIVF_match.clear();
+    mu_innerTrackValidFraction.clear(); mu_globalTrackNormalizedChi2.clear(); mu_CQChi2Position.clear(); mu_CQTrackKink.clear();
+    mu_numberOfMatchedStation.clear(); mu_numberOfValidPixelHits.clear(); mu_numberOfValidTrackerHits.clear(); mu_numberInnerHitsMissing.clear(); mu_trackerLayersWithMeasurement.clear(); mu_numberInnerHits.clear();
+    mu_IVF_df.clear(); mu_IVF_ntracks.clear(); mu_IVF_muid.clear();
+    mu_IVF_x.clear(); mu_IVF_y.clear(); mu_IVF_z.clear(); mu_IVF_cx.clear(); mu_IVF_cy.clear(); mu_IVF_cz.clear(); mu_IVF_chi2.clear(); mu_IVF_pt.clear(); mu_IVF_eta.clear(); mu_IVF_phi.clear(); mu_IVF_E.clear(); mu_IVF_mass.clear();
+    mu_IVF_trackcharge.clear(); mu_IVF_trackmuid.clear(); mu_IVF_trackvtxid.clear();
+    mu_IVF_trackpt.clear(); mu_IVF_tracketa.clear(); mu_IVF_trackphi.clear(); mu_IVF_trackE.clear(); mu_IVF_trackdxy.clear(); mu_IVF_trackdz.clear();
+    mu_IVF_tracksignedIP2D.clear(); mu_IVF_tracksignedIP2Dsig.clear(); mu_IVF_tracksignedIP3D.clear(); mu_IVF_tracksignedIP3Dsig.clear();
+    
+    mu_jetPtRatio.clear(); mu_jetPtRel.clear();
+    mu_jetIdx.clear(); mu_jetSelectedChargedMultiplicity.clear();
+    mu_jetFatIdx.clear(); mu_jetSubIdx.clear();
+    mu_relIso0p4.clear();
+    mu_trackPt.clear(); mu_trackPtErr.clear();
+    
+    mu_dxy.clear(); mu_dz.clear(); mu_3dIP.clear(); mu_3dIPSig.clear();
+    mu_IVF_signedIP2D.clear(); mu_IVF_signedIP2Dsig.clear(); mu_IVF_signedIP3D.clear(); mu_IVF_signedIP3Dsig.clear();
+     
+    int ntrack_max = 100;
+    int nElectronsSel = 0;
+    int nMuonsSel = 0;
+    
+    for(unsigned int i = 0; i < nElectrons; i++) {
+      
+      const pat::Electron & el = (*electronHandle)[i];
+      
+      if(el.gsfTrack().isNull()) continue;
+      if(el.pt() < 7) continue;     
+      if(fabs(el.eta()) > 2.5) continue;
+      
+      int ielCand = 0;
+      for(edm::Ref<pat::PackedCandidateCollection> cand : el.associatedPackedPFCandidates()){	  
+	if( cand.isNonnull() and cand.isAvailable() ) {
+	  break;
+	}       
+	ielCand++;
+      }
+      
+      el_idx.push_back(i);
+      el_lIVF_match.push_back(false);
+      
+      el_isEB.push_back(el.isEB());
+      el_isEE.push_back(el.isEE());
+      el_superClusterOverP.push_back(el.eSuperClusterOverP());
+      el_ecalEnergy.push_back(el.ecalEnergy());
+      el_dEtaInSeed.push_back(std::abs(dEtaInSeed(&el)));
+      el_numberInnerHitsMissing.push_back(el.gsfTrack()->hitPattern().numberOfLostHits(reco::HitPattern::MISSING_INNER_HITS));
+      el_numberOfValidPixelHits.push_back((!el.gsfTrack().isNull())? el.gsfTrack()->hitPattern().numberOfValidPixelHits() : 0);
+      el_numberOfValidTrackerHits.push_back((!el.gsfTrack().isNull())? el.gsfTrack()->hitPattern().numberOfValidTrackerHits() : 0);
+      
+      el_relIso0p4.push_back(getPFIso(el));
+      el_sigmaIetaIeta.push_back(el.full5x5_sigmaIetaIeta());
+      el_deltaPhiSuperClusterTrack.push_back(fabs(el.deltaPhiSuperClusterTrackAtVtx()));
+      el_deltaEtaSuperClusterTrack.push_back(fabs(el.deltaEtaSuperClusterTrackAtVtx()));
+      el_eInvMinusPInv.push_back((1.0 - el.eSuperClusterOverP())/el.correctedEcalEnergy());
+      el_hOverE.push_back(el.hadronicOverEm());
+      
+      el_dxy.push_back(el.dB(pat::Electron::PV2D));
+      el_dz.push_back(el.dB(pat::Electron::PVDZ));
+      el_3dIP.push_back(el.dB(pat::Electron::PV3D));
+      el_3dIPSig.push_back(fabs(el.dB(pat::Electron::PV3D)/el.edB(pat::Electron::PV3D)));
+      
+      fillLeptonJetVariables(&el, NULL, jetHandle, pv, *rhoHandle);
+
+      const reco::Candidate *el_cand = dynamic_cast<const reco::Candidate*>(&el);
+      el_jetFatIdx.push_back(findMatchedJet(*el_cand, jetFatHandle));
+      el_jetSubIdx.push_back(findMatchedJet(*el_cand, jetSubHandle));
+      
+      bool new_vtx = false;
+      double dR, deta, normchi2;
+      double mindR = 20, minnormchi2 = 10000;
+      int nVtx = 0;
+      reco::Vertex *vtxDisp = NULL;
+      for(const reco::Vertex& vtx : secVertices) {
+	for(reco::Vertex::trackRef_iterator vtxTrackref = vtx.tracks_begin(); vtxTrackref != vtx.tracks_end(); vtxTrackref++) {
+	  reco::TrackRef vtxTrack = vtxTrackref->castTo<reco::TrackRef>();
+	  for(edm::Ref<pat::PackedCandidateCollection> cand : el.associatedPackedPFCandidates()) {	       
+	    dR       = reco::deltaR(cand->eta(), cand->phi(), vtxTrack->eta(), vtxTrack->phi());
+	    deta     = fabs(cand->eta() - vtxTrack->eta());
+	    normchi2 = fabs(vtx.chi2()/vtx.ndof());
+	    
+	    if((dR < 0.05 or (dR < 0.1 and deta < 0.03)) and (dR < mindR or (dR == mindR and normchi2 < minnormchi2))) {	       
+	      new_vtx = true;
+	      vtxDisp = const_cast<reco::Vertex*>(&vtx);
+	      el_lIVF_match[nElectronsSel] = true;
+	      mindR       = dR;
+	      minnormchi2 = normchi2;
+	    }
+	  }
+	}
+	
+	if(new_vtx) {
+	  el_IVF_x.push_back(vtx.x());
+	  el_IVF_y.push_back(vtx.y());
+	  el_IVF_z.push_back(vtx.z());
+	  el_IVF_cx.push_back(vtx.xError());
+	  el_IVF_cy.push_back(vtx.yError());
+	  el_IVF_cz.push_back(vtx.zError());
+	  el_IVF_df.push_back(vtx.ndof());
+	  el_IVF_chi2.push_back(vtx.chi2());
+	  el_IVF_pt.push_back(vtx.p4().pt());
+	  el_IVF_eta.push_back(vtx.p4().eta());
+	  el_IVF_phi.push_back(vtx.p4().phi());
+	  el_IVF_E.push_back(vtx.p4().energy());
+	  el_IVF_mass.push_back(vtx.p4().mass());
+	  el_IVF_elid.push_back(nElectronsSel);
+	  
+	  el_IVF_ntracks.push_back(0);
+	  for(reco::Vertex::trackRef_iterator vtxTrackref = vtx.tracks_begin(); vtxTrackref != vtx.tracks_end(); vtxTrackref++) {
+	    if(el_IVF_ntracks.back() == ntrack_max) break;
+	    reco::TrackRef vtxTrack = vtxTrackref->castTo<reco::TrackRef>();
+	    const auto& trk = theB->build(vtxTrack);
+	    Global3DVector dir(vtxTrack->px(), vtxTrack->py(), vtxTrack->pz());
+	    const auto& ip2d = IPTools::signedTransverseImpactParameter(trk, dir, *vtxDisp);
+	    const auto& ip3d = IPTools::signedImpactParameter3D(trk, dir, *vtxDisp);
+	    el_IVF_tracksignedIP2D.push_back(ip2d.second.value());
+	    el_IVF_tracksignedIP3D.push_back(ip3d.second.value());
+	    el_IVF_tracksignedIP2Dsig.push_back(ip2d.second.significance());
+	    el_IVF_tracksignedIP3Dsig.push_back(ip3d.second.significance());
+	    el_IVF_trackpt.push_back(vtxTrack->pt());
+	    el_IVF_tracketa.push_back(vtxTrack->eta());
+	    el_IVF_trackphi.push_back(vtxTrack->phi());
+	    el_IVF_trackE.push_back(vtxTrack->p());
+	    el_IVF_trackcharge.push_back(vtxTrack->charge());
+	    el_IVF_trackdxy.push_back(std::abs(vtxTrack->dxy(pv.position())));
+	    el_IVF_trackdz.push_back(std::abs(vtxTrack->dz(pv.position())));
+	    el_IVF_trackelid.push_back(nElectronsSel);
+	    el_IVF_trackvtxid.push_back(nVtx);
+	    el_IVF_ntracks.back()++;	    
+	  }
+	  nVtx++;
+	  new_vtx = false;
+
+	  auto track = el.gsfTrack();
+	  if( track.isNonnull() ) {
+	    const auto& trk = theB->build(track);
+	    Global3DVector dir(track->px(), track->py(), track->pz());
+	    const auto& ip2d = IPTools::signedTransverseImpactParameter(trk, dir, *vtxDisp);
+	    const auto& ip3d = IPTools::signedImpactParameter3D(trk, dir, *vtxDisp);
+	    el_IVF_signedIP2D.push_back(ip2d.second.value());
+	    el_IVF_signedIP3D.push_back(ip3d.second.value());
+	    el_IVF_signedIP2Dsig.push_back(ip2d.second.significance());
+	    el_IVF_signedIP3Dsig.push_back(ip3d.second.significance());
+	  } else {
+	    el_IVF_signedIP2D.push_back(-999);
+	    el_IVF_signedIP3D.push_back(-999);
+	    el_IVF_signedIP2Dsig.push_back(-999);
+	    el_IVF_signedIP3Dsig.push_back(-999);	    
+	  }
+	}
+      }
+      nElectronsSel += 1;
+    }
+    
+    for(unsigned int i = 0; i < nMuons; i++) {
path: plugins/DispJetTableProducer.cc
user: login: kerstinlovisa
body: Could you have a look at this producer https://github.com/kerstinlovisa/EXOnanoAOD/blob/main/plugins/MuonExtendedTableProducer.cc

I am pretty sure we can add your extra variables to the Muon collection in MuonExtendedTableProducer.cc. You are looping over muons and including muon indices the same way as I did there. 
Similarly, I added ElectronExtendedTableProducer.cc so you can add electron information there.
created_at: 2025-04-09T14:52:44Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,733 @@
+// -*- C++ -*-
+//
+// Package:    PhysicsTools/EXOnanoAOD
+// Class:      DispJetTableProducer
+//
+/**\class DispJetTableProducer
+
+ Description: Additional variables for displaced vertices involving at least one lepton and other tracks
+
+*/
+//
+// Original Author:  Kirill Skovpen
+//         Created:  Sat, 1 Mar 2025 08:37:01 GMT
+//
+
+// system include files
+#include <memory>
+
+// user include files
+#include "FWCore/Framework/interface/Frameworkfwd.h"
+#include "FWCore/Framework/interface/stream/EDProducer.h"
+
+#include "FWCore/Framework/interface/Event.h"
+#include "FWCore/Framework/interface/MakerMacros.h"
+
+#include "FWCore/ParameterSet/interface/ParameterSet.h"
+#include "FWCore/Utilities/interface/StreamID.h"
+
+#include "DataFormats/PatCandidates/interface/Electron.h"
+#include "DataFormats/PatCandidates/interface/Muon.h"
+#include "DataFormats/PatCandidates/interface/Jet.h"
+#include "DataFormats/MuonReco/interface/MuonSelectors.h"
+
+// nanoAOD include files
+#include "DataFormats/NanoAOD/interface/FlatTable.h"
+
+// object specific include files
+#include "TrackingTools/TransientTrack/interface/TransientTrackBuilder.h"
+#include "TrackingTools/Records/interface/TransientTrackRecord.h"
+#include "TrackingTools/IPTools/interface/IPTools.h"
+#include "DataFormats/TrackReco/interface/Track.h"
+#include "DataFormats/VertexReco/interface/VertexFwd.h"
+#include "DataFormats/VertexReco/interface/Vertex.h"
+
+class DispJetTableProducer : public edm::stream::EDProducer<> {
+protected:
+
+  float dEtaInSeed(const pat::Electron* el) const;
+  float getPFIso(const pat::Muon& muon) const;
+  float getPFIso(const pat::Electron& electron) const;
+  int findMatchedJet(const reco::Candidate& lepton, const edm::Handle< std::vector< pat::Jet > >& jets);
+  void fillLeptonJetVariables(const reco::GsfElectron *el, const reco::Muon *mu, edm::Handle< std::vector< pat::Jet > >& jets, const reco::Vertex& vertex, const double rho);
+
+  edm::ESGetToken<TransientTrackBuilder, TransientTrackRecord> ttbToken_;
+  edm::EDGetTokenT<double> rhoTag_;
+  edm::EDGetTokenT<std::vector<pat::Electron> > electronTag_;
+  edm::EDGetTokenT<std::vector<pat::Muon> > muonTag_;
+  edm::EDGetTokenT<std::vector<pat::Jet> > jetTag_;
+  edm::EDGetTokenT<std::vector<pat::Jet> > jetFatTag_;
+  edm::EDGetTokenT<std::vector<pat::Jet> > jetSubTag_;
+  edm::EDGetTokenT<reco::VertexCollection> vtxTag_;
+  edm::EDGetTokenT<reco::VertexCollection> secVtxTag_;
+
+  const TransientTrackBuilder* theB;
+  
+  std::vector<int> el_idx;
+  std::vector<bool> el_lIVF_match;
+  std::vector<bool> el_isEB, el_isEE;
+  std::vector<float> el_superClusterOverP, el_ecalEnergy, el_dEtaInSeed;
+  std::vector<int> el_numberInnerHitsMissing, el_numberOfValidPixelHits, el_numberOfValidTrackerHits;
+  std::vector<int> el_IVF_df, el_IVF_ntracks, el_IVF_elid;
+  std::vector<float> el_IVF_x, el_IVF_y, el_IVF_z, el_IVF_cx, el_IVF_cy, el_IVF_cz, el_IVF_chi2, el_IVF_pt, el_IVF_eta, el_IVF_phi, el_IVF_E, el_IVF_mass;
+  std::vector<int> el_IVF_trackcharge, el_IVF_trackelid, el_IVF_trackvtxid;
+  std::vector<float> el_IVF_trackpt, el_IVF_tracketa, el_IVF_trackphi, el_IVF_trackE, el_IVF_trackdxy, el_IVF_trackdz;
+  std::vector<float> el_IVF_tracksignedIP2D, el_IVF_tracksignedIP3D, el_IVF_tracksignedIP2Dsig, el_IVF_tracksignedIP3Dsig;
+  
+  std::vector<float> el_jetPtRatio, el_jetPtRel;
+  std::vector<int> el_jetIdx, el_jetSelectedChargedMultiplicity;
+  std::vector<int> el_jetFatIdx, el_jetSubIdx;
+  std::vector<float> el_relIso0p4;
+  std::vector<float> el_sigmaIetaIeta, el_deltaPhiSuperClusterTrack, el_deltaEtaSuperClusterTrack, el_eInvMinusPInv, el_hOverE;
+  
+  std::vector<float> el_dxy, el_dz, el_3dIP, el_3dIPSig;
+  std::vector<float> el_IVF_signedIP2D, el_IVF_signedIP3D, el_IVF_signedIP2Dsig, el_IVF_signedIP3Dsig;
+   
+  std::vector<int> mu_idx;
+  std::vector<bool> mu_lIVF_match;
+  std::vector<float> mu_innerTrackValidFraction, mu_globalTrackNormalizedChi2, mu_CQChi2Position, mu_CQTrackKink;
+  std::vector<int> mu_numberOfMatchedStation, mu_numberOfValidPixelHits, mu_numberOfValidTrackerHits, mu_numberInnerHitsMissing, mu_trackerLayersWithMeasurement, mu_numberInnerHits;
+  std::vector<int> mu_IVF_df, mu_IVF_ntracks, mu_IVF_muid;
+  std::vector<float> mu_IVF_x, mu_IVF_y, mu_IVF_z, mu_IVF_cx, mu_IVF_cy, mu_IVF_cz, mu_IVF_chi2, mu_IVF_pt, mu_IVF_eta, mu_IVF_phi, mu_IVF_E, mu_IVF_mass;
+  std::vector<int> mu_IVF_trackcharge, mu_IVF_trackmuid, mu_IVF_trackvtxid;
+  std::vector<float> mu_IVF_trackpt, mu_IVF_tracketa, mu_IVF_trackphi, mu_IVF_trackE, mu_IVF_trackdxy, mu_IVF_trackdz;
+  std::vector<float> mu_IVF_tracksignedIP2D, mu_IVF_tracksignedIP3D, mu_IVF_tracksignedIP2Dsig, mu_IVF_tracksignedIP3Dsig;
+  
+  std::vector<float> mu_jetPtRatio, mu_jetPtRel;
+  std::vector<int> mu_jetIdx, mu_jetSelectedChargedMultiplicity;
+  std::vector<int> mu_jetFatIdx, mu_jetSubIdx;
+  std::vector<float> mu_relIso0p4;
+  std::vector<float> mu_trackPt, mu_trackPtErr;
+  
+  std::vector<float> mu_dxy, mu_dz, mu_3dIP, mu_3dIPSig;
+  std::vector<float> mu_IVF_signedIP2D, mu_IVF_signedIP3D, mu_IVF_signedIP2Dsig, mu_IVF_signedIP3Dsig;
+
+public:
+  DispJetTableProducer(edm::ParameterSet const& params)
+    :
+    ttbToken_(esConsumes(edm::ESInputTag("", "TransientTrackBuilder"))),
+    rhoTag_(consumes<double>(params.getParameter<edm::InputTag>("rho"))),
+    electronTag_(consumes<std::vector<pat::Electron>>(params.getParameter<edm::InputTag>("electrons"))),
+    muonTag_(consumes<std::vector<pat::Muon>>(params.getParameter<edm::InputTag>("muons"))),
+    jetTag_(consumes<std::vector<pat::Jet>>(params.getParameter<edm::InputTag>("jets"))),
+    jetFatTag_(consumes<std::vector<pat::Jet>>(params.getParameter<edm::InputTag>("jetsFat"))),
+    jetSubTag_(consumes<std::vector<pat::Jet>>(params.getParameter<edm::InputTag>("jetsSub"))),
+    vtxTag_(consumes<reco::VertexCollection>(params.getParameter<edm::InputTag>("primaryVertex"))),
+    secVtxTag_(consumes<reco::VertexCollection>(params.getParameter<edm::InputTag>("secondaryVertex"))) {
+       produces<nanoaod::FlatTable>("DispJetElectron");
+       produces<nanoaod::FlatTable>("DispJetElectronVtx");
+       produces<nanoaod::FlatTable>("DispJetElectronTrk");
+       produces<nanoaod::FlatTable>("DispJetMuon");
+       produces<nanoaod::FlatTable>("DispJetMuonVtx");
+       produces<nanoaod::FlatTable>("DispJetMuonTrk");
+  }   
+
+  ~DispJetTableProducer() override {}
+  
+  void produce(edm::Event& iEvent, const edm::EventSetup& iSetup) override {
+
+    theB = &iSetup.getData(ttbToken_);
+    
+    edm::Handle<double> rhoHandle;
+    iEvent.getByToken(rhoTag_, rhoHandle);
+    
+    edm::Handle<std::vector<pat::Electron> > electronHandle;
+    iEvent.getByToken(electronTag_, electronHandle);
+    
+    edm::Handle<std::vector<pat::Muon> > muonHandle;
+    iEvent.getByToken(muonTag_, muonHandle);
+    
+    edm::Handle<std::vector<pat::Jet> > jetHandle;
+    iEvent.getByToken(jetTag_, jetHandle);
+
+    edm::Handle<std::vector<pat::Jet> > jetFatHandle;
+    iEvent.getByToken(jetFatTag_, jetFatHandle);
+
+    edm::Handle<std::vector<pat::Jet> > jetSubHandle;
+    iEvent.getByToken(jetSubTag_, jetSubHandle);
+    
+    edm::Handle<reco::VertexCollection> primaryVertexHandle;
+    iEvent.getByToken(vtxTag_, primaryVertexHandle);
+    
+    edm::Handle<reco::VertexCollection> secondaryVertexHandle;
+    iEvent.getByToken(secVtxTag_, secondaryVertexHandle);
+    
+    const auto& pv = primaryVertexHandle->at(0);
+    GlobalPoint primaryVertex(pv.x(), pv.y(), pv.z());
+    
+    const reco::VertexCollection & secVertices = (*secondaryVertexHandle);
+    
+    unsigned int nElectrons = electronHandle->size();
+    unsigned int nMuons = muonHandle->size();
+    
+    el_idx.clear();
+    el_lIVF_match.clear();
+    el_isEB.clear(); el_isEE.clear();
+    el_superClusterOverP.clear(); el_ecalEnergy.clear(); el_dEtaInSeed.clear();
+    el_numberInnerHitsMissing.clear(); el_numberOfValidPixelHits.clear(); el_numberOfValidTrackerHits.clear();
+    el_IVF_df.clear(); el_IVF_ntracks.clear(); el_IVF_elid.clear();
+    el_IVF_x.clear(); el_IVF_y.clear(); el_IVF_z.clear(); el_IVF_cx.clear(); el_IVF_cy.clear(); el_IVF_cz.clear(); el_IVF_chi2.clear(); el_IVF_pt.clear(); el_IVF_eta.clear(); el_IVF_phi.clear(); el_IVF_E.clear(); el_IVF_mass.clear();
+    el_IVF_trackcharge.clear(); el_IVF_trackelid.clear(); el_IVF_trackvtxid.clear();
+    el_IVF_trackpt.clear(); el_IVF_tracketa.clear(); el_IVF_trackphi.clear(); el_IVF_trackE.clear(); el_IVF_trackdxy.clear(); el_IVF_trackdz.clear();
+    el_IVF_tracksignedIP2D.clear(); el_IVF_tracksignedIP2Dsig.clear(); el_IVF_tracksignedIP3D.clear(); el_IVF_tracksignedIP3Dsig.clear();
+    
+    el_jetPtRatio.clear(); el_jetPtRel.clear();
+    el_jetIdx.clear(); el_jetSelectedChargedMultiplicity.clear();
+    el_jetFatIdx.clear(); el_jetSubIdx.clear();
+    el_relIso0p4.clear();
+    el_sigmaIetaIeta.clear(); el_deltaPhiSuperClusterTrack.clear(); el_deltaEtaSuperClusterTrack.clear(); el_eInvMinusPInv.clear(); el_hOverE.clear();    
+    el_dxy.clear(); el_dz.clear(); el_3dIP.clear(); el_3dIPSig.clear();
+    el_IVF_signedIP2D.clear(); el_IVF_signedIP2Dsig.clear(); el_IVF_signedIP3D.clear(); el_IVF_signedIP3Dsig.clear();
+    
+    mu_idx.clear();
+    mu_lIVF_match.clear();
+    mu_innerTrackValidFraction.clear(); mu_globalTrackNormalizedChi2.clear(); mu_CQChi2Position.clear(); mu_CQTrackKink.clear();
+    mu_numberOfMatchedStation.clear(); mu_numberOfValidPixelHits.clear(); mu_numberOfValidTrackerHits.clear(); mu_numberInnerHitsMissing.clear(); mu_trackerLayersWithMeasurement.clear(); mu_numberInnerHits.clear();
+    mu_IVF_df.clear(); mu_IVF_ntracks.clear(); mu_IVF_muid.clear();
+    mu_IVF_x.clear(); mu_IVF_y.clear(); mu_IVF_z.clear(); mu_IVF_cx.clear(); mu_IVF_cy.clear(); mu_IVF_cz.clear(); mu_IVF_chi2.clear(); mu_IVF_pt.clear(); mu_IVF_eta.clear(); mu_IVF_phi.clear(); mu_IVF_E.clear(); mu_IVF_mass.clear();
+    mu_IVF_trackcharge.clear(); mu_IVF_trackmuid.clear(); mu_IVF_trackvtxid.clear();
+    mu_IVF_trackpt.clear(); mu_IVF_tracketa.clear(); mu_IVF_trackphi.clear(); mu_IVF_trackE.clear(); mu_IVF_trackdxy.clear(); mu_IVF_trackdz.clear();
+    mu_IVF_tracksignedIP2D.clear(); mu_IVF_tracksignedIP2Dsig.clear(); mu_IVF_tracksignedIP3D.clear(); mu_IVF_tracksignedIP3Dsig.clear();
+    
+    mu_jetPtRatio.clear(); mu_jetPtRel.clear();
+    mu_jetIdx.clear(); mu_jetSelectedChargedMultiplicity.clear();
+    mu_jetFatIdx.clear(); mu_jetSubIdx.clear();
+    mu_relIso0p4.clear();
+    mu_trackPt.clear(); mu_trackPtErr.clear();
+    
+    mu_dxy.clear(); mu_dz.clear(); mu_3dIP.clear(); mu_3dIPSig.clear();
+    mu_IVF_signedIP2D.clear(); mu_IVF_signedIP2Dsig.clear(); mu_IVF_signedIP3D.clear(); mu_IVF_signedIP3Dsig.clear();
+     
+    int ntrack_max = 100;
+    int nElectronsSel = 0;
+    int nMuonsSel = 0;
+    
+    for(unsigned int i = 0; i < nElectrons; i++) {
+      
+      const pat::Electron & el = (*electronHandle)[i];
+      
+      if(el.gsfTrack().isNull()) continue;
+      if(el.pt() < 7) continue;     
+      if(fabs(el.eta()) > 2.5) continue;
+      
+      int ielCand = 0;
+      for(edm::Ref<pat::PackedCandidateCollection> cand : el.associatedPackedPFCandidates()){	  
+	if( cand.isNonnull() and cand.isAvailable() ) {
+	  break;
+	}       
+	ielCand++;
+      }
+      
+      el_idx.push_back(i);
+      el_lIVF_match.push_back(false);
+      
+      el_isEB.push_back(el.isEB());
+      el_isEE.push_back(el.isEE());
+      el_superClusterOverP.push_back(el.eSuperClusterOverP());
+      el_ecalEnergy.push_back(el.ecalEnergy());
+      el_dEtaInSeed.push_back(std::abs(dEtaInSeed(&el)));
+      el_numberInnerHitsMissing.push_back(el.gsfTrack()->hitPattern().numberOfLostHits(reco::HitPattern::MISSING_INNER_HITS));
+      el_numberOfValidPixelHits.push_back((!el.gsfTrack().isNull())? el.gsfTrack()->hitPattern().numberOfValidPixelHits() : 0);
+      el_numberOfValidTrackerHits.push_back((!el.gsfTrack().isNull())? el.gsfTrack()->hitPattern().numberOfValidTrackerHits() : 0);
+      
+      el_relIso0p4.push_back(getPFIso(el));
+      el_sigmaIetaIeta.push_back(el.full5x5_sigmaIetaIeta());
+      el_deltaPhiSuperClusterTrack.push_back(fabs(el.deltaPhiSuperClusterTrackAtVtx()));
+      el_deltaEtaSuperClusterTrack.push_back(fabs(el.deltaEtaSuperClusterTrackAtVtx()));
+      el_eInvMinusPInv.push_back((1.0 - el.eSuperClusterOverP())/el.correctedEcalEnergy());
+      el_hOverE.push_back(el.hadronicOverEm());
+      
+      el_dxy.push_back(el.dB(pat::Electron::PV2D));
+      el_dz.push_back(el.dB(pat::Electron::PVDZ));
+      el_3dIP.push_back(el.dB(pat::Electron::PV3D));
+      el_3dIPSig.push_back(fabs(el.dB(pat::Electron::PV3D)/el.edB(pat::Electron::PV3D)));
+      
+      fillLeptonJetVariables(&el, NULL, jetHandle, pv, *rhoHandle);
+
+      const reco::Candidate *el_cand = dynamic_cast<const reco::Candidate*>(&el);
+      el_jetFatIdx.push_back(findMatchedJet(*el_cand, jetFatHandle));
+      el_jetSubIdx.push_back(findMatchedJet(*el_cand, jetSubHandle));
+      
+      bool new_vtx = false;
+      double dR, deta, normchi2;
+      double mindR = 20, minnormchi2 = 10000;
+      int nVtx = 0;
+      reco::Vertex *vtxDisp = NULL;
+      for(const reco::Vertex& vtx : secVertices) {
+	for(reco::Vertex::trackRef_iterator vtxTrackref = vtx.tracks_begin(); vtxTrackref != vtx.tracks_end(); vtxTrackref++) {
+	  reco::TrackRef vtxTrack = vtxTrackref->castTo<reco::TrackRef>();
+	  for(edm::Ref<pat::PackedCandidateCollection> cand : el.associatedPackedPFCandidates()) {	       
+	    dR       = reco::deltaR(cand->eta(), cand->phi(), vtxTrack->eta(), vtxTrack->phi());
+	    deta     = fabs(cand->eta() - vtxTrack->eta());
+	    normchi2 = fabs(vtx.chi2()/vtx.ndof());
+	    
+	    if((dR < 0.05 or (dR < 0.1 and deta < 0.03)) and (dR < mindR or (dR == mindR and normchi2 < minnormchi2))) {	       
+	      new_vtx = true;
+	      vtxDisp = const_cast<reco::Vertex*>(&vtx);
+	      el_lIVF_match[nElectronsSel] = true;
+	      mindR       = dR;
+	      minnormchi2 = normchi2;
+	    }
+	  }
+	}
+	
+	if(new_vtx) {
+	  el_IVF_x.push_back(vtx.x());
+	  el_IVF_y.push_back(vtx.y());
+	  el_IVF_z.push_back(vtx.z());
+	  el_IVF_cx.push_back(vtx.xError());
+	  el_IVF_cy.push_back(vtx.yError());
+	  el_IVF_cz.push_back(vtx.zError());
+	  el_IVF_df.push_back(vtx.ndof());
+	  el_IVF_chi2.push_back(vtx.chi2());
+	  el_IVF_pt.push_back(vtx.p4().pt());
+	  el_IVF_eta.push_back(vtx.p4().eta());
+	  el_IVF_phi.push_back(vtx.p4().phi());
+	  el_IVF_E.push_back(vtx.p4().energy());
+	  el_IVF_mass.push_back(vtx.p4().mass());
+	  el_IVF_elid.push_back(nElectronsSel);
+	  
+	  el_IVF_ntracks.push_back(0);
+	  for(reco::Vertex::trackRef_iterator vtxTrackref = vtx.tracks_begin(); vtxTrackref != vtx.tracks_end(); vtxTrackref++) {
+	    if(el_IVF_ntracks.back() == ntrack_max) break;
+	    reco::TrackRef vtxTrack = vtxTrackref->castTo<reco::TrackRef>();
+	    const auto& trk = theB->build(vtxTrack);
+	    Global3DVector dir(vtxTrack->px(), vtxTrack->py(), vtxTrack->pz());
+	    const auto& ip2d = IPTools::signedTransverseImpactParameter(trk, dir, *vtxDisp);
+	    const auto& ip3d = IPTools::signedImpactParameter3D(trk, dir, *vtxDisp);
+	    el_IVF_tracksignedIP2D.push_back(ip2d.second.value());
+	    el_IVF_tracksignedIP3D.push_back(ip3d.second.value());
+	    el_IVF_tracksignedIP2Dsig.push_back(ip2d.second.significance());
+	    el_IVF_tracksignedIP3Dsig.push_back(ip3d.second.significance());
+	    el_IVF_trackpt.push_back(vtxTrack->pt());
+	    el_IVF_tracketa.push_back(vtxTrack->eta());
+	    el_IVF_trackphi.push_back(vtxTrack->phi());
+	    el_IVF_trackE.push_back(vtxTrack->p());
+	    el_IVF_trackcharge.push_back(vtxTrack->charge());
+	    el_IVF_trackdxy.push_back(std::abs(vtxTrack->dxy(pv.position())));
+	    el_IVF_trackdz.push_back(std::abs(vtxTrack->dz(pv.position())));
+	    el_IVF_trackelid.push_back(nElectronsSel);
+	    el_IVF_trackvtxid.push_back(nVtx);
+	    el_IVF_ntracks.back()++;	    
+	  }
+	  nVtx++;
+	  new_vtx = false;
+
+	  auto track = el.gsfTrack();
+	  if( track.isNonnull() ) {
+	    const auto& trk = theB->build(track);
+	    Global3DVector dir(track->px(), track->py(), track->pz());
+	    const auto& ip2d = IPTools::signedTransverseImpactParameter(trk, dir, *vtxDisp);
+	    const auto& ip3d = IPTools::signedImpactParameter3D(trk, dir, *vtxDisp);
+	    el_IVF_signedIP2D.push_back(ip2d.second.value());
+	    el_IVF_signedIP3D.push_back(ip3d.second.value());
+	    el_IVF_signedIP2Dsig.push_back(ip2d.second.significance());
+	    el_IVF_signedIP3Dsig.push_back(ip3d.second.significance());
+	  } else {
+	    el_IVF_signedIP2D.push_back(-999);
+	    el_IVF_signedIP3D.push_back(-999);
+	    el_IVF_signedIP2Dsig.push_back(-999);
+	    el_IVF_signedIP3Dsig.push_back(-999);	    
+	  }
+	}
+      }
+      nElectronsSel += 1;
+    }
+    
+    for(unsigned int i = 0; i < nMuons; i++) {
+      
+      const pat::Muon & mu = (*muonHandle)[i];
+      
+      if(mu.innerTrack().isNull()) continue;
+      if(mu.pt() < 5) continue;
+      if(fabs(mu.eta()) > 2.4) continue;
+      if(!mu.isPFMuon()) continue;
+      if(!(mu.isTrackerMuon() || mu.isGlobalMuon())) continue;
+      
+      mu_idx.push_back(i);
+      mu_lIVF_match.push_back(false);
+      
+      mu_innerTrackValidFraction.push_back((!mu.innerTrack().isNull()) ? mu.innerTrack()->validFraction() : -1);
+      mu_globalTrackNormalizedChi2.push_back((!mu.globalTrack().isNull()) ? mu.globalTrack()->normalizedChi2() : -1);
+      mu_CQChi2Position.push_back(mu.combinedQuality().chi2LocalPosition);
+      mu_CQTrackKink.push_back(mu.combinedQuality().trkKink);
+      mu_numberOfMatchedStation.push_back(mu.numberOfMatchedStations());
+      mu_numberOfValidPixelHits.push_back((!mu.innerTrack().isNull()) ? mu.innerTrack()->hitPattern().numberOfValidPixelHits() : 0);
+      mu_numberOfValidTrackerHits.push_back((!mu.innerTrack().isNull()) ? mu.innerTrack()->hitPattern().numberOfValidTrackerHits() : 0);
+      mu_numberInnerHitsMissing.push_back(mu.innerTrack()->hitPattern().numberOfLostHits(reco::HitPattern::MISSING_INNER_HITS));
+      mu_trackerLayersWithMeasurement.push_back((!mu.innerTrack().isNull()) ? mu.innerTrack()->hitPattern().trackerLayersWithMeasurement() : 0);
+      mu_numberInnerHits.push_back((!mu.globalTrack().isNull()) ? mu.globalTrack()->hitPattern().numberOfValidMuonHits() : (!mu.outerTrack().isNull() ? mu.outerTrack()->hitPattern().numberOfValidMuonHits() : 0));
+      
+      mu_relIso0p4.push_back(getPFIso(mu));
+      mu_trackPt.push_back(mu.innerTrack()->pt());
+      mu_trackPtErr.push_back(mu.innerTrack()->ptError());
+      
+      mu_dxy.push_back(mu.dB(pat::Muon::PV2D));
+      mu_dz.push_back(mu.dB(pat::Muon::PVDZ));
+      mu_3dIP.push_back(mu.dB(pat::Muon::PV3D));
+      mu_3dIPSig.push_back(fabs(mu.dB(pat::Muon::PV3D)/mu.edB(pat::Muon::PV3D)));
+      
+      fillLeptonJetVariables(NULL, &mu, jetHandle, pv, *rhoHandle);
+
+      const reco::Candidate *mu_cand = dynamic_cast<const reco::Candidate*>(&mu);
+      mu_jetFatIdx.push_back(findMatchedJet(*mu_cand, jetFatHandle));
+      mu_jetSubIdx.push_back(findMatchedJet(*mu_cand, jetSubHandle));      
+      
+      bool new_vtx = false;
+      double ptdiff, normchi2;
+      double minptdiff = 10, minnormchi2 = 10000;
+      int nVtx = 0;
+      reco::Vertex *vtxDisp = NULL;
+      for(const reco::Vertex& vtx : secVertices) {
+	for(reco::Vertex::trackRef_iterator vtxTrackref = vtx.tracks_begin(); vtxTrackref != vtx.tracks_end(); vtxTrackref++) {
+	  reco::TrackRef vtxTrack = vtxTrackref->castTo<reco::TrackRef>();
+	  for( size_t iCand=0;iCand<mu.numberOfSourceCandidatePtrs();++iCand ) {
+	    if( !(mu.sourceCandidatePtr(iCand).isNonnull() and mu.sourceCandidatePtr(iCand).isAvailable()) ) continue;
+	    ptdiff   = fabs(mu.sourceCandidatePtr(iCand)->pt() - vtxTrack->pt());
+	    normchi2 = fabs(vtx.chi2()/vtx.ndof());
+	    
+	    if(ptdiff < 0.001 and (ptdiff < minptdiff or (ptdiff == minptdiff and normchi2 < minnormchi2))) {
+	      new_vtx = true;
+	      vtxDisp = const_cast<reco::Vertex*>(&vtx);
+	      mu_lIVF_match[nMuonsSel] = true;
+	      minptdiff   = ptdiff;
+	      minnormchi2 = normchi2;
+	    }
+	  }
+	}       
+	if(new_vtx) {
+	  mu_IVF_x.push_back(vtx.x());
+	  mu_IVF_y.push_back(vtx.y());
+	  mu_IVF_z.push_back(vtx.z());
+	  mu_IVF_cx.push_back(vtx.xError());
+	  mu_IVF_cy.push_back(vtx.yError());
+	  mu_IVF_cz.push_back(vtx.zError());
+	  mu_IVF_df.push_back(vtx.ndof());
+	  mu_IVF_chi2.push_back(vtx.chi2());
+	  mu_IVF_pt.push_back(vtx.p4().pt());
+	  mu_IVF_eta.push_back(vtx.p4().eta());
+	  mu_IVF_phi.push_back(vtx.p4().phi());
+	  mu_IVF_E.push_back(vtx.p4().energy());
+	  mu_IVF_mass.push_back(vtx.p4().mass());
+	  mu_IVF_muid.push_back(nMuonsSel);
+	  
+	  mu_IVF_ntracks.push_back(0);
+	  for(reco::Vertex::trackRef_iterator vtxTrackref = vtx.tracks_begin(); vtxTrackref != vtx.tracks_end(); vtxTrackref++) {
+	    if(mu_IVF_ntracks.back() == ntrack_max) break;
+	    reco::TrackRef vtxTrack = vtxTrackref->castTo<reco::TrackRef>();
+	    const auto& trk = theB->build(vtxTrack);
+	    Global3DVector dir(vtxTrack->px(), vtxTrack->py(), vtxTrack->pz());
+	    const auto& ip2d = IPTools::signedTransverseImpactParameter(trk, dir, *vtxDisp);
+	    const auto& ip3d = IPTools::signedImpactParameter3D(trk, dir, *vtxDisp);
+	    mu_IVF_tracksignedIP2D.push_back(ip2d.second.value());
+	    mu_IVF_tracksignedIP3D.push_back(ip3d.second.value());
+	    mu_IVF_tracksignedIP2Dsig.push_back(ip2d.second.significance());
+	    mu_IVF_tracksignedIP3Dsig.push_back(ip3d.second.significance());
+	    mu_IVF_trackpt.push_back(vtxTrack->pt());
+	    mu_IVF_tracketa.push_back(vtxTrack->eta());
+	    mu_IVF_trackphi.push_back(vtxTrack->phi());
+	    mu_IVF_trackE.push_back(vtxTrack->p());
+	    mu_IVF_trackcharge.push_back(vtxTrack->charge());
+	    mu_IVF_trackdxy.push_back(std::abs(vtxTrack->dxy(pv.position())));
+	    mu_IVF_trackdz.push_back(std::abs(vtxTrack->dz(pv.position())));
+	    mu_IVF_trackmuid.push_back(nMuonsSel);
+	    mu_IVF_trackvtxid.push_back(nVtx);
+	    mu_IVF_ntracks.back()++;
+	  }
+	  nVtx++;
+	  new_vtx = false;
+
+	  auto track = mu.innerTrack();
+	  if( track.isNonnull() ) {
+	    const auto& trk = theB->build(track);
+	    Global3DVector dir(track->px(), track->py(), track->pz());
+	    const auto& ip2d = IPTools::signedTransverseImpactParameter(trk, dir, *vtxDisp);
+	    const auto& ip3d = IPTools::signedImpactParameter3D(trk, dir, *vtxDisp);
+	    mu_IVF_signedIP2D.push_back(ip2d.second.value());
+	    mu_IVF_signedIP3D.push_back(ip3d.second.value());
+	    mu_IVF_signedIP2Dsig.push_back(ip2d.second.significance());
+	    mu_IVF_signedIP3Dsig.push_back(ip3d.second.significance());
+	  } else {
+	    mu_IVF_signedIP2D.push_back(-999);
+	    mu_IVF_signedIP3D.push_back(-999);
+	    mu_IVF_signedIP2Dsig.push_back(-999);
+	    mu_IVF_signedIP3Dsig.push_back(-999);	    	    
+	  }
+	}	 
+      }      
+      nMuonsSel += 1;
+    }
+    
+    auto dispJetElectronTab = std::make_unique<nanoaod::FlatTable>(nElectronsSel, "DispJetElectron", false, false);
+    auto dispJetMuonTab = std::make_unique<nanoaod::FlatTable>(nMuonsSel, "DispJetMuon", false, false);
+    
+    dispJetElectronTab->addColumn<int>("idx", el_idx, "");
+    dispJetElectronTab->addColumn<bool>("lIVF_match", el_lIVF_match, "");
+    dispJetElectronTab->addColumn<bool>("isEB", el_isEB, "");
+    dispJetElectronTab->addColumn<bool>("isEE", el_isEE, "");
+    dispJetElectronTab->addColumn<float>("superClusterOverP", el_superClusterOverP, "");
+    dispJetElectronTab->addColumn<float>("ecalEnergy", el_ecalEnergy, "");
+    dispJetElectronTab->addColumn<float>("dEtaInSeed", el_dEtaInSeed, "");
+    dispJetElectronTab->addColumn<int>("numberInnerHitsMissing", el_numberInnerHitsMissing, "");
+    dispJetElectronTab->addColumn<int>("numberOfValidPixelHits", el_numberOfValidPixelHits, "");
+    dispJetElectronTab->addColumn<int>("numberOfValidTrackerHits", el_numberOfValidTrackerHits, "");
+    dispJetElectronTab->addColumn<float>("relIso0p4", el_relIso0p4, "");
+    dispJetElectronTab->addColumn<float>("jetPtRatio", el_jetPtRatio, "");
+    dispJetElectronTab->addColumn<float>("jetPtRel", el_jetPtRel, "");
+    dispJetElectronTab->addColumn<int>("jetIdx", el_jetIdx, "");
+    dispJetElectronTab->addColumn<int>("jetFatIdx", el_jetFatIdx, "");
+    dispJetElectronTab->addColumn<int>("jetSubIdx", el_jetSubIdx, "");
+    dispJetElectronTab->addColumn<int>("jetSelectedChargedMultiplicity", el_jetSelectedChargedMultiplicity, "");
+    dispJetElectronTab->addColumn<float>("sigmaIetaIeta", el_sigmaIetaIeta, "");
+    dispJetElectronTab->addColumn<float>("deltaPhiSuperClusterTrack", el_deltaPhiSuperClusterTrack, "");
+    dispJetElectronTab->addColumn<float>("deltaEtaSuperClusterTrack", el_deltaEtaSuperClusterTrack, "");
+    dispJetElectronTab->addColumn<float>("eInvMinusPInv", el_eInvMinusPInv, "");
+    dispJetElectronTab->addColumn<float>("hOverE", el_hOverE, "");
+    dispJetElectronTab->addColumn<float>("dxy", el_dxy, "");
+    dispJetElectronTab->addColumn<float>("dz", el_dz, "");
+    dispJetElectronTab->addColumn<float>("3dIP", el_3dIP, "");
+    dispJetElectronTab->addColumn<float>("3dIPSig", el_3dIPSig, "");
+    
+    auto dispJetElectronVtxTab = std::make_unique<nanoaod::FlatTable>(el_IVF_x.size(), "DispJetElectronVtx", false, false);
+    dispJetElectronVtxTab->addColumn<int>("IVF_df", el_IVF_df, "");
path: plugins/DispJetTableProducer.cc
user: login: kerstinlovisa
body: Is IVF inclusive Vertex Fit? Do you need this in the name since it's added to all variables? 
created_at: 2025-04-09T14:57:00Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,23 @@
+import FWCore.ParameterSet.Config as cms
+from PhysicsTools.NanoAOD.common_cff import *
+
+process.load('PhysicsTools.EXOnanoAOD.displacedInclusiveVertexing_cff')
+
+outputTable = cms.EDProducer("DispJetTableProducer",
path: python/custom_dispjet_cff.py
user: login: kerstinlovisa
body: Is the same as you added in custom_exo_cff.py? If so, I think we can ignore this file
created_at: 2025-04-09T14:59:08Z
author_association: OWNER
diff_hunk: @@ -126,8 +150,9 @@ def update_genParticleTable(process):
 def add_exonanoTables(process):
 
     # process = add_mdsTables(process) ## Commented out right now because it needs changes in PhysicsTools/NanoAOD
path: python/custom_exo_cff.py
user: login: kerstinlovisa
body: Could you uncomment these again please?
created_at: 2025-04-09T14:59:46Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,122 @@
+import FWCore.ParameterSet.Config as cms
path: test/Run3_2023_MINIAOD_EXONANO_template.py
user: login: kerstinlovisa
body: I tested running your code with the AOD->EXOnanoAOD template and it works fine, so I think we can ignore this file too. As we need AOD for some of the other customizations
created_at: 2025-04-09T15:01:00Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,122 @@
+import FWCore.ParameterSet.Config as cms
path: test/Run3_2023_MINIAOD_EXONANO_template.py
user: login: kskovpen
body: As far as I can tell, EXOnanoAOD does not work on MiniAODs with the provided PAT configs, and this was one of the reasons to add one more config that can be run on MiniAOD.
created_at: 2025-05-03T18:42:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -126,8 +150,9 @@ def update_genParticleTable(process):
 def add_exonanoTables(process):
 
     # process = add_mdsTables(process) ## Commented out right now because it needs changes in PhysicsTools/NanoAOD
path: python/custom_exo_cff.py
user: login: kskovpen
body: I will uncomment add_electronVertexTables in my next commit, however, add_dsamuonTables crashes on MiniAOD.
created_at: 2025-05-03T18:43:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,23 @@
+import FWCore.ParameterSet.Config as cms
+from PhysicsTools.NanoAOD.common_cff import *
+
+process.load('PhysicsTools.EXOnanoAOD.displacedInclusiveVertexing_cff')
+
+outputTable = cms.EDProducer("DispJetTableProducer",
path: python/custom_dispjet_cff.py
user: login: kskovpen
body: Will remove it.
created_at: 2025-05-03T18:44:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,733 @@
+// -*- C++ -*-
+//
+// Package:    PhysicsTools/EXOnanoAOD
+// Class:      DispJetTableProducer
+//
+/**\class DispJetTableProducer
+
+ Description: Additional variables for displaced vertices involving at least one lepton and other tracks
+
+*/
+//
+// Original Author:  Kirill Skovpen
+//         Created:  Sat, 1 Mar 2025 08:37:01 GMT
+//
+
+// system include files
+#include <memory>
+
+// user include files
+#include "FWCore/Framework/interface/Frameworkfwd.h"
+#include "FWCore/Framework/interface/stream/EDProducer.h"
+
+#include "FWCore/Framework/interface/Event.h"
+#include "FWCore/Framework/interface/MakerMacros.h"
+
+#include "FWCore/ParameterSet/interface/ParameterSet.h"
+#include "FWCore/Utilities/interface/StreamID.h"
+
+#include "DataFormats/PatCandidates/interface/Electron.h"
+#include "DataFormats/PatCandidates/interface/Muon.h"
+#include "DataFormats/PatCandidates/interface/Jet.h"
+#include "DataFormats/MuonReco/interface/MuonSelectors.h"
+
+// nanoAOD include files
+#include "DataFormats/NanoAOD/interface/FlatTable.h"
+
+// object specific include files
+#include "TrackingTools/TransientTrack/interface/TransientTrackBuilder.h"
+#include "TrackingTools/Records/interface/TransientTrackRecord.h"
+#include "TrackingTools/IPTools/interface/IPTools.h"
+#include "DataFormats/TrackReco/interface/Track.h"
+#include "DataFormats/VertexReco/interface/VertexFwd.h"
+#include "DataFormats/VertexReco/interface/Vertex.h"
+
+class DispJetTableProducer : public edm::stream::EDProducer<> {
+protected:
+
+  float dEtaInSeed(const pat::Electron* el) const;
+  float getPFIso(const pat::Muon& muon) const;
+  float getPFIso(const pat::Electron& electron) const;
+  int findMatchedJet(const reco::Candidate& lepton, const edm::Handle< std::vector< pat::Jet > >& jets);
+  void fillLeptonJetVariables(const reco::GsfElectron *el, const reco::Muon *mu, edm::Handle< std::vector< pat::Jet > >& jets, const reco::Vertex& vertex, const double rho);
+
+  edm::ESGetToken<TransientTrackBuilder, TransientTrackRecord> ttbToken_;
+  edm::EDGetTokenT<double> rhoTag_;
+  edm::EDGetTokenT<std::vector<pat::Electron> > electronTag_;
+  edm::EDGetTokenT<std::vector<pat::Muon> > muonTag_;
+  edm::EDGetTokenT<std::vector<pat::Jet> > jetTag_;
+  edm::EDGetTokenT<std::vector<pat::Jet> > jetFatTag_;
+  edm::EDGetTokenT<std::vector<pat::Jet> > jetSubTag_;
+  edm::EDGetTokenT<reco::VertexCollection> vtxTag_;
+  edm::EDGetTokenT<reco::VertexCollection> secVtxTag_;
+
+  const TransientTrackBuilder* theB;
+  
+  std::vector<int> el_idx;
+  std::vector<bool> el_lIVF_match;
+  std::vector<bool> el_isEB, el_isEE;
+  std::vector<float> el_superClusterOverP, el_ecalEnergy, el_dEtaInSeed;
+  std::vector<int> el_numberInnerHitsMissing, el_numberOfValidPixelHits, el_numberOfValidTrackerHits;
+  std::vector<int> el_IVF_df, el_IVF_ntracks, el_IVF_elid;
+  std::vector<float> el_IVF_x, el_IVF_y, el_IVF_z, el_IVF_cx, el_IVF_cy, el_IVF_cz, el_IVF_chi2, el_IVF_pt, el_IVF_eta, el_IVF_phi, el_IVF_E, el_IVF_mass;
+  std::vector<int> el_IVF_trackcharge, el_IVF_trackelid, el_IVF_trackvtxid;
+  std::vector<float> el_IVF_trackpt, el_IVF_tracketa, el_IVF_trackphi, el_IVF_trackE, el_IVF_trackdxy, el_IVF_trackdz;
+  std::vector<float> el_IVF_tracksignedIP2D, el_IVF_tracksignedIP3D, el_IVF_tracksignedIP2Dsig, el_IVF_tracksignedIP3Dsig;
+  
+  std::vector<float> el_jetPtRatio, el_jetPtRel;
+  std::vector<int> el_jetIdx, el_jetSelectedChargedMultiplicity;
+  std::vector<int> el_jetFatIdx, el_jetSubIdx;
+  std::vector<float> el_relIso0p4;
+  std::vector<float> el_sigmaIetaIeta, el_deltaPhiSuperClusterTrack, el_deltaEtaSuperClusterTrack, el_eInvMinusPInv, el_hOverE;
+  
+  std::vector<float> el_dxy, el_dz, el_3dIP, el_3dIPSig;
+  std::vector<float> el_IVF_signedIP2D, el_IVF_signedIP3D, el_IVF_signedIP2Dsig, el_IVF_signedIP3Dsig;
+   
+  std::vector<int> mu_idx;
+  std::vector<bool> mu_lIVF_match;
+  std::vector<float> mu_innerTrackValidFraction, mu_globalTrackNormalizedChi2, mu_CQChi2Position, mu_CQTrackKink;
+  std::vector<int> mu_numberOfMatchedStation, mu_numberOfValidPixelHits, mu_numberOfValidTrackerHits, mu_numberInnerHitsMissing, mu_trackerLayersWithMeasurement, mu_numberInnerHits;
+  std::vector<int> mu_IVF_df, mu_IVF_ntracks, mu_IVF_muid;
+  std::vector<float> mu_IVF_x, mu_IVF_y, mu_IVF_z, mu_IVF_cx, mu_IVF_cy, mu_IVF_cz, mu_IVF_chi2, mu_IVF_pt, mu_IVF_eta, mu_IVF_phi, mu_IVF_E, mu_IVF_mass;
+  std::vector<int> mu_IVF_trackcharge, mu_IVF_trackmuid, mu_IVF_trackvtxid;
+  std::vector<float> mu_IVF_trackpt, mu_IVF_tracketa, mu_IVF_trackphi, mu_IVF_trackE, mu_IVF_trackdxy, mu_IVF_trackdz;
+  std::vector<float> mu_IVF_tracksignedIP2D, mu_IVF_tracksignedIP3D, mu_IVF_tracksignedIP2Dsig, mu_IVF_tracksignedIP3Dsig;
+  
+  std::vector<float> mu_jetPtRatio, mu_jetPtRel;
+  std::vector<int> mu_jetIdx, mu_jetSelectedChargedMultiplicity;
+  std::vector<int> mu_jetFatIdx, mu_jetSubIdx;
+  std::vector<float> mu_relIso0p4;
+  std::vector<float> mu_trackPt, mu_trackPtErr;
+  
+  std::vector<float> mu_dxy, mu_dz, mu_3dIP, mu_3dIPSig;
+  std::vector<float> mu_IVF_signedIP2D, mu_IVF_signedIP3D, mu_IVF_signedIP2Dsig, mu_IVF_signedIP3Dsig;
+
+public:
+  DispJetTableProducer(edm::ParameterSet const& params)
+    :
+    ttbToken_(esConsumes(edm::ESInputTag("", "TransientTrackBuilder"))),
+    rhoTag_(consumes<double>(params.getParameter<edm::InputTag>("rho"))),
+    electronTag_(consumes<std::vector<pat::Electron>>(params.getParameter<edm::InputTag>("electrons"))),
+    muonTag_(consumes<std::vector<pat::Muon>>(params.getParameter<edm::InputTag>("muons"))),
+    jetTag_(consumes<std::vector<pat::Jet>>(params.getParameter<edm::InputTag>("jets"))),
+    jetFatTag_(consumes<std::vector<pat::Jet>>(params.getParameter<edm::InputTag>("jetsFat"))),
+    jetSubTag_(consumes<std::vector<pat::Jet>>(params.getParameter<edm::InputTag>("jetsSub"))),
+    vtxTag_(consumes<reco::VertexCollection>(params.getParameter<edm::InputTag>("primaryVertex"))),
+    secVtxTag_(consumes<reco::VertexCollection>(params.getParameter<edm::InputTag>("secondaryVertex"))) {
+       produces<nanoaod::FlatTable>("DispJetElectron");
+       produces<nanoaod::FlatTable>("DispJetElectronVtx");
+       produces<nanoaod::FlatTable>("DispJetElectronTrk");
+       produces<nanoaod::FlatTable>("DispJetMuon");
+       produces<nanoaod::FlatTable>("DispJetMuonVtx");
+       produces<nanoaod::FlatTable>("DispJetMuonTrk");
+  }   
+
+  ~DispJetTableProducer() override {}
+  
+  void produce(edm::Event& iEvent, const edm::EventSetup& iSetup) override {
+
+    theB = &iSetup.getData(ttbToken_);
+    
+    edm::Handle<double> rhoHandle;
+    iEvent.getByToken(rhoTag_, rhoHandle);
+    
+    edm::Handle<std::vector<pat::Electron> > electronHandle;
+    iEvent.getByToken(electronTag_, electronHandle);
+    
+    edm::Handle<std::vector<pat::Muon> > muonHandle;
+    iEvent.getByToken(muonTag_, muonHandle);
+    
+    edm::Handle<std::vector<pat::Jet> > jetHandle;
+    iEvent.getByToken(jetTag_, jetHandle);
+
+    edm::Handle<std::vector<pat::Jet> > jetFatHandle;
+    iEvent.getByToken(jetFatTag_, jetFatHandle);
+
+    edm::Handle<std::vector<pat::Jet> > jetSubHandle;
+    iEvent.getByToken(jetSubTag_, jetSubHandle);
+    
+    edm::Handle<reco::VertexCollection> primaryVertexHandle;
+    iEvent.getByToken(vtxTag_, primaryVertexHandle);
+    
+    edm::Handle<reco::VertexCollection> secondaryVertexHandle;
+    iEvent.getByToken(secVtxTag_, secondaryVertexHandle);
+    
+    const auto& pv = primaryVertexHandle->at(0);
+    GlobalPoint primaryVertex(pv.x(), pv.y(), pv.z());
+    
+    const reco::VertexCollection & secVertices = (*secondaryVertexHandle);
+    
+    unsigned int nElectrons = electronHandle->size();
+    unsigned int nMuons = muonHandle->size();
+    
+    el_idx.clear();
+    el_lIVF_match.clear();
+    el_isEB.clear(); el_isEE.clear();
+    el_superClusterOverP.clear(); el_ecalEnergy.clear(); el_dEtaInSeed.clear();
+    el_numberInnerHitsMissing.clear(); el_numberOfValidPixelHits.clear(); el_numberOfValidTrackerHits.clear();
+    el_IVF_df.clear(); el_IVF_ntracks.clear(); el_IVF_elid.clear();
+    el_IVF_x.clear(); el_IVF_y.clear(); el_IVF_z.clear(); el_IVF_cx.clear(); el_IVF_cy.clear(); el_IVF_cz.clear(); el_IVF_chi2.clear(); el_IVF_pt.clear(); el_IVF_eta.clear(); el_IVF_phi.clear(); el_IVF_E.clear(); el_IVF_mass.clear();
+    el_IVF_trackcharge.clear(); el_IVF_trackelid.clear(); el_IVF_trackvtxid.clear();
+    el_IVF_trackpt.clear(); el_IVF_tracketa.clear(); el_IVF_trackphi.clear(); el_IVF_trackE.clear(); el_IVF_trackdxy.clear(); el_IVF_trackdz.clear();
+    el_IVF_tracksignedIP2D.clear(); el_IVF_tracksignedIP2Dsig.clear(); el_IVF_tracksignedIP3D.clear(); el_IVF_tracksignedIP3Dsig.clear();
+    
+    el_jetPtRatio.clear(); el_jetPtRel.clear();
+    el_jetIdx.clear(); el_jetSelectedChargedMultiplicity.clear();
+    el_jetFatIdx.clear(); el_jetSubIdx.clear();
+    el_relIso0p4.clear();
+    el_sigmaIetaIeta.clear(); el_deltaPhiSuperClusterTrack.clear(); el_deltaEtaSuperClusterTrack.clear(); el_eInvMinusPInv.clear(); el_hOverE.clear();    
+    el_dxy.clear(); el_dz.clear(); el_3dIP.clear(); el_3dIPSig.clear();
+    el_IVF_signedIP2D.clear(); el_IVF_signedIP2Dsig.clear(); el_IVF_signedIP3D.clear(); el_IVF_signedIP3Dsig.clear();
+    
+    mu_idx.clear();
+    mu_lIVF_match.clear();
+    mu_innerTrackValidFraction.clear(); mu_globalTrackNormalizedChi2.clear(); mu_CQChi2Position.clear(); mu_CQTrackKink.clear();
+    mu_numberOfMatchedStation.clear(); mu_numberOfValidPixelHits.clear(); mu_numberOfValidTrackerHits.clear(); mu_numberInnerHitsMissing.clear(); mu_trackerLayersWithMeasurement.clear(); mu_numberInnerHits.clear();
+    mu_IVF_df.clear(); mu_IVF_ntracks.clear(); mu_IVF_muid.clear();
+    mu_IVF_x.clear(); mu_IVF_y.clear(); mu_IVF_z.clear(); mu_IVF_cx.clear(); mu_IVF_cy.clear(); mu_IVF_cz.clear(); mu_IVF_chi2.clear(); mu_IVF_pt.clear(); mu_IVF_eta.clear(); mu_IVF_phi.clear(); mu_IVF_E.clear(); mu_IVF_mass.clear();
+    mu_IVF_trackcharge.clear(); mu_IVF_trackmuid.clear(); mu_IVF_trackvtxid.clear();
+    mu_IVF_trackpt.clear(); mu_IVF_tracketa.clear(); mu_IVF_trackphi.clear(); mu_IVF_trackE.clear(); mu_IVF_trackdxy.clear(); mu_IVF_trackdz.clear();
+    mu_IVF_tracksignedIP2D.clear(); mu_IVF_tracksignedIP2Dsig.clear(); mu_IVF_tracksignedIP3D.clear(); mu_IVF_tracksignedIP3Dsig.clear();
+    
+    mu_jetPtRatio.clear(); mu_jetPtRel.clear();
+    mu_jetIdx.clear(); mu_jetSelectedChargedMultiplicity.clear();
+    mu_jetFatIdx.clear(); mu_jetSubIdx.clear();
+    mu_relIso0p4.clear();
+    mu_trackPt.clear(); mu_trackPtErr.clear();
+    
+    mu_dxy.clear(); mu_dz.clear(); mu_3dIP.clear(); mu_3dIPSig.clear();
+    mu_IVF_signedIP2D.clear(); mu_IVF_signedIP2Dsig.clear(); mu_IVF_signedIP3D.clear(); mu_IVF_signedIP3Dsig.clear();
+     
+    int ntrack_max = 100;
+    int nElectronsSel = 0;
+    int nMuonsSel = 0;
+    
+    for(unsigned int i = 0; i < nElectrons; i++) {
+      
+      const pat::Electron & el = (*electronHandle)[i];
+      
+      if(el.gsfTrack().isNull()) continue;
+      if(el.pt() < 7) continue;     
+      if(fabs(el.eta()) > 2.5) continue;
+      
+      int ielCand = 0;
+      for(edm::Ref<pat::PackedCandidateCollection> cand : el.associatedPackedPFCandidates()){	  
+	if( cand.isNonnull() and cand.isAvailable() ) {
+	  break;
+	}       
+	ielCand++;
+      }
+      
+      el_idx.push_back(i);
+      el_lIVF_match.push_back(false);
+      
+      el_isEB.push_back(el.isEB());
+      el_isEE.push_back(el.isEE());
+      el_superClusterOverP.push_back(el.eSuperClusterOverP());
+      el_ecalEnergy.push_back(el.ecalEnergy());
+      el_dEtaInSeed.push_back(std::abs(dEtaInSeed(&el)));
+      el_numberInnerHitsMissing.push_back(el.gsfTrack()->hitPattern().numberOfLostHits(reco::HitPattern::MISSING_INNER_HITS));
+      el_numberOfValidPixelHits.push_back((!el.gsfTrack().isNull())? el.gsfTrack()->hitPattern().numberOfValidPixelHits() : 0);
+      el_numberOfValidTrackerHits.push_back((!el.gsfTrack().isNull())? el.gsfTrack()->hitPattern().numberOfValidTrackerHits() : 0);
+      
+      el_relIso0p4.push_back(getPFIso(el));
+      el_sigmaIetaIeta.push_back(el.full5x5_sigmaIetaIeta());
+      el_deltaPhiSuperClusterTrack.push_back(fabs(el.deltaPhiSuperClusterTrackAtVtx()));
+      el_deltaEtaSuperClusterTrack.push_back(fabs(el.deltaEtaSuperClusterTrackAtVtx()));
+      el_eInvMinusPInv.push_back((1.0 - el.eSuperClusterOverP())/el.correctedEcalEnergy());
+      el_hOverE.push_back(el.hadronicOverEm());
+      
+      el_dxy.push_back(el.dB(pat::Electron::PV2D));
+      el_dz.push_back(el.dB(pat::Electron::PVDZ));
+      el_3dIP.push_back(el.dB(pat::Electron::PV3D));
+      el_3dIPSig.push_back(fabs(el.dB(pat::Electron::PV3D)/el.edB(pat::Electron::PV3D)));
+      
+      fillLeptonJetVariables(&el, NULL, jetHandle, pv, *rhoHandle);
+
+      const reco::Candidate *el_cand = dynamic_cast<const reco::Candidate*>(&el);
+      el_jetFatIdx.push_back(findMatchedJet(*el_cand, jetFatHandle));
+      el_jetSubIdx.push_back(findMatchedJet(*el_cand, jetSubHandle));
+      
+      bool new_vtx = false;
+      double dR, deta, normchi2;
+      double mindR = 20, minnormchi2 = 10000;
+      int nVtx = 0;
+      reco::Vertex *vtxDisp = NULL;
+      for(const reco::Vertex& vtx : secVertices) {
+	for(reco::Vertex::trackRef_iterator vtxTrackref = vtx.tracks_begin(); vtxTrackref != vtx.tracks_end(); vtxTrackref++) {
+	  reco::TrackRef vtxTrack = vtxTrackref->castTo<reco::TrackRef>();
+	  for(edm::Ref<pat::PackedCandidateCollection> cand : el.associatedPackedPFCandidates()) {	       
+	    dR       = reco::deltaR(cand->eta(), cand->phi(), vtxTrack->eta(), vtxTrack->phi());
+	    deta     = fabs(cand->eta() - vtxTrack->eta());
+	    normchi2 = fabs(vtx.chi2()/vtx.ndof());
+	    
+	    if((dR < 0.05 or (dR < 0.1 and deta < 0.03)) and (dR < mindR or (dR == mindR and normchi2 < minnormchi2))) {	       
+	      new_vtx = true;
+	      vtxDisp = const_cast<reco::Vertex*>(&vtx);
+	      el_lIVF_match[nElectronsSel] = true;
+	      mindR       = dR;
+	      minnormchi2 = normchi2;
+	    }
+	  }
+	}
+	
+	if(new_vtx) {
+	  el_IVF_x.push_back(vtx.x());
+	  el_IVF_y.push_back(vtx.y());
+	  el_IVF_z.push_back(vtx.z());
+	  el_IVF_cx.push_back(vtx.xError());
+	  el_IVF_cy.push_back(vtx.yError());
+	  el_IVF_cz.push_back(vtx.zError());
+	  el_IVF_df.push_back(vtx.ndof());
+	  el_IVF_chi2.push_back(vtx.chi2());
+	  el_IVF_pt.push_back(vtx.p4().pt());
+	  el_IVF_eta.push_back(vtx.p4().eta());
+	  el_IVF_phi.push_back(vtx.p4().phi());
+	  el_IVF_E.push_back(vtx.p4().energy());
+	  el_IVF_mass.push_back(vtx.p4().mass());
+	  el_IVF_elid.push_back(nElectronsSel);
+	  
+	  el_IVF_ntracks.push_back(0);
+	  for(reco::Vertex::trackRef_iterator vtxTrackref = vtx.tracks_begin(); vtxTrackref != vtx.tracks_end(); vtxTrackref++) {
+	    if(el_IVF_ntracks.back() == ntrack_max) break;
+	    reco::TrackRef vtxTrack = vtxTrackref->castTo<reco::TrackRef>();
+	    const auto& trk = theB->build(vtxTrack);
+	    Global3DVector dir(vtxTrack->px(), vtxTrack->py(), vtxTrack->pz());
+	    const auto& ip2d = IPTools::signedTransverseImpactParameter(trk, dir, *vtxDisp);
+	    const auto& ip3d = IPTools::signedImpactParameter3D(trk, dir, *vtxDisp);
+	    el_IVF_tracksignedIP2D.push_back(ip2d.second.value());
+	    el_IVF_tracksignedIP3D.push_back(ip3d.second.value());
+	    el_IVF_tracksignedIP2Dsig.push_back(ip2d.second.significance());
+	    el_IVF_tracksignedIP3Dsig.push_back(ip3d.second.significance());
+	    el_IVF_trackpt.push_back(vtxTrack->pt());
+	    el_IVF_tracketa.push_back(vtxTrack->eta());
+	    el_IVF_trackphi.push_back(vtxTrack->phi());
+	    el_IVF_trackE.push_back(vtxTrack->p());
+	    el_IVF_trackcharge.push_back(vtxTrack->charge());
+	    el_IVF_trackdxy.push_back(std::abs(vtxTrack->dxy(pv.position())));
+	    el_IVF_trackdz.push_back(std::abs(vtxTrack->dz(pv.position())));
+	    el_IVF_trackelid.push_back(nElectronsSel);
+	    el_IVF_trackvtxid.push_back(nVtx);
+	    el_IVF_ntracks.back()++;	    
+	  }
+	  nVtx++;
+	  new_vtx = false;
+
+	  auto track = el.gsfTrack();
+	  if( track.isNonnull() ) {
+	    const auto& trk = theB->build(track);
+	    Global3DVector dir(track->px(), track->py(), track->pz());
+	    const auto& ip2d = IPTools::signedTransverseImpactParameter(trk, dir, *vtxDisp);
+	    const auto& ip3d = IPTools::signedImpactParameter3D(trk, dir, *vtxDisp);
+	    el_IVF_signedIP2D.push_back(ip2d.second.value());
+	    el_IVF_signedIP3D.push_back(ip3d.second.value());
+	    el_IVF_signedIP2Dsig.push_back(ip2d.second.significance());
+	    el_IVF_signedIP3Dsig.push_back(ip3d.second.significance());
+	  } else {
+	    el_IVF_signedIP2D.push_back(-999);
+	    el_IVF_signedIP3D.push_back(-999);
+	    el_IVF_signedIP2Dsig.push_back(-999);
+	    el_IVF_signedIP3Dsig.push_back(-999);	    
+	  }
+	}
+      }
+      nElectronsSel += 1;
+    }
+    
+    for(unsigned int i = 0; i < nMuons; i++) {
+      
+      const pat::Muon & mu = (*muonHandle)[i];
+      
+      if(mu.innerTrack().isNull()) continue;
+      if(mu.pt() < 5) continue;
+      if(fabs(mu.eta()) > 2.4) continue;
+      if(!mu.isPFMuon()) continue;
+      if(!(mu.isTrackerMuon() || mu.isGlobalMuon())) continue;
+      
+      mu_idx.push_back(i);
+      mu_lIVF_match.push_back(false);
+      
+      mu_innerTrackValidFraction.push_back((!mu.innerTrack().isNull()) ? mu.innerTrack()->validFraction() : -1);
+      mu_globalTrackNormalizedChi2.push_back((!mu.globalTrack().isNull()) ? mu.globalTrack()->normalizedChi2() : -1);
+      mu_CQChi2Position.push_back(mu.combinedQuality().chi2LocalPosition);
+      mu_CQTrackKink.push_back(mu.combinedQuality().trkKink);
+      mu_numberOfMatchedStation.push_back(mu.numberOfMatchedStations());
+      mu_numberOfValidPixelHits.push_back((!mu.innerTrack().isNull()) ? mu.innerTrack()->hitPattern().numberOfValidPixelHits() : 0);
+      mu_numberOfValidTrackerHits.push_back((!mu.innerTrack().isNull()) ? mu.innerTrack()->hitPattern().numberOfValidTrackerHits() : 0);
+      mu_numberInnerHitsMissing.push_back(mu.innerTrack()->hitPattern().numberOfLostHits(reco::HitPattern::MISSING_INNER_HITS));
+      mu_trackerLayersWithMeasurement.push_back((!mu.innerTrack().isNull()) ? mu.innerTrack()->hitPattern().trackerLayersWithMeasurement() : 0);
+      mu_numberInnerHits.push_back((!mu.globalTrack().isNull()) ? mu.globalTrack()->hitPattern().numberOfValidMuonHits() : (!mu.outerTrack().isNull() ? mu.outerTrack()->hitPattern().numberOfValidMuonHits() : 0));
+      
+      mu_relIso0p4.push_back(getPFIso(mu));
+      mu_trackPt.push_back(mu.innerTrack()->pt());
+      mu_trackPtErr.push_back(mu.innerTrack()->ptError());
+      
+      mu_dxy.push_back(mu.dB(pat::Muon::PV2D));
+      mu_dz.push_back(mu.dB(pat::Muon::PVDZ));
+      mu_3dIP.push_back(mu.dB(pat::Muon::PV3D));
+      mu_3dIPSig.push_back(fabs(mu.dB(pat::Muon::PV3D)/mu.edB(pat::Muon::PV3D)));
+      
+      fillLeptonJetVariables(NULL, &mu, jetHandle, pv, *rhoHandle);
+
+      const reco::Candidate *mu_cand = dynamic_cast<const reco::Candidate*>(&mu);
+      mu_jetFatIdx.push_back(findMatchedJet(*mu_cand, jetFatHandle));
+      mu_jetSubIdx.push_back(findMatchedJet(*mu_cand, jetSubHandle));      
+      
+      bool new_vtx = false;
+      double ptdiff, normchi2;
+      double minptdiff = 10, minnormchi2 = 10000;
+      int nVtx = 0;
+      reco::Vertex *vtxDisp = NULL;
+      for(const reco::Vertex& vtx : secVertices) {
+	for(reco::Vertex::trackRef_iterator vtxTrackref = vtx.tracks_begin(); vtxTrackref != vtx.tracks_end(); vtxTrackref++) {
+	  reco::TrackRef vtxTrack = vtxTrackref->castTo<reco::TrackRef>();
+	  for( size_t iCand=0;iCand<mu.numberOfSourceCandidatePtrs();++iCand ) {
+	    if( !(mu.sourceCandidatePtr(iCand).isNonnull() and mu.sourceCandidatePtr(iCand).isAvailable()) ) continue;
+	    ptdiff   = fabs(mu.sourceCandidatePtr(iCand)->pt() - vtxTrack->pt());
+	    normchi2 = fabs(vtx.chi2()/vtx.ndof());
+	    
+	    if(ptdiff < 0.001 and (ptdiff < minptdiff or (ptdiff == minptdiff and normchi2 < minnormchi2))) {
+	      new_vtx = true;
+	      vtxDisp = const_cast<reco::Vertex*>(&vtx);
+	      mu_lIVF_match[nMuonsSel] = true;
+	      minptdiff   = ptdiff;
+	      minnormchi2 = normchi2;
+	    }
+	  }
+	}       
+	if(new_vtx) {
+	  mu_IVF_x.push_back(vtx.x());
+	  mu_IVF_y.push_back(vtx.y());
+	  mu_IVF_z.push_back(vtx.z());
+	  mu_IVF_cx.push_back(vtx.xError());
+	  mu_IVF_cy.push_back(vtx.yError());
+	  mu_IVF_cz.push_back(vtx.zError());
+	  mu_IVF_df.push_back(vtx.ndof());
+	  mu_IVF_chi2.push_back(vtx.chi2());
+	  mu_IVF_pt.push_back(vtx.p4().pt());
+	  mu_IVF_eta.push_back(vtx.p4().eta());
+	  mu_IVF_phi.push_back(vtx.p4().phi());
+	  mu_IVF_E.push_back(vtx.p4().energy());
+	  mu_IVF_mass.push_back(vtx.p4().mass());
+	  mu_IVF_muid.push_back(nMuonsSel);
+	  
+	  mu_IVF_ntracks.push_back(0);
+	  for(reco::Vertex::trackRef_iterator vtxTrackref = vtx.tracks_begin(); vtxTrackref != vtx.tracks_end(); vtxTrackref++) {
+	    if(mu_IVF_ntracks.back() == ntrack_max) break;
+	    reco::TrackRef vtxTrack = vtxTrackref->castTo<reco::TrackRef>();
+	    const auto& trk = theB->build(vtxTrack);
+	    Global3DVector dir(vtxTrack->px(), vtxTrack->py(), vtxTrack->pz());
+	    const auto& ip2d = IPTools::signedTransverseImpactParameter(trk, dir, *vtxDisp);
+	    const auto& ip3d = IPTools::signedImpactParameter3D(trk, dir, *vtxDisp);
+	    mu_IVF_tracksignedIP2D.push_back(ip2d.second.value());
+	    mu_IVF_tracksignedIP3D.push_back(ip3d.second.value());
+	    mu_IVF_tracksignedIP2Dsig.push_back(ip2d.second.significance());
+	    mu_IVF_tracksignedIP3Dsig.push_back(ip3d.second.significance());
+	    mu_IVF_trackpt.push_back(vtxTrack->pt());
+	    mu_IVF_tracketa.push_back(vtxTrack->eta());
+	    mu_IVF_trackphi.push_back(vtxTrack->phi());
+	    mu_IVF_trackE.push_back(vtxTrack->p());
+	    mu_IVF_trackcharge.push_back(vtxTrack->charge());
+	    mu_IVF_trackdxy.push_back(std::abs(vtxTrack->dxy(pv.position())));
+	    mu_IVF_trackdz.push_back(std::abs(vtxTrack->dz(pv.position())));
+	    mu_IVF_trackmuid.push_back(nMuonsSel);
+	    mu_IVF_trackvtxid.push_back(nVtx);
+	    mu_IVF_ntracks.back()++;
+	  }
+	  nVtx++;
+	  new_vtx = false;
+
+	  auto track = mu.innerTrack();
+	  if( track.isNonnull() ) {
+	    const auto& trk = theB->build(track);
+	    Global3DVector dir(track->px(), track->py(), track->pz());
+	    const auto& ip2d = IPTools::signedTransverseImpactParameter(trk, dir, *vtxDisp);
+	    const auto& ip3d = IPTools::signedImpactParameter3D(trk, dir, *vtxDisp);
+	    mu_IVF_signedIP2D.push_back(ip2d.second.value());
+	    mu_IVF_signedIP3D.push_back(ip3d.second.value());
+	    mu_IVF_signedIP2Dsig.push_back(ip2d.second.significance());
+	    mu_IVF_signedIP3Dsig.push_back(ip3d.second.significance());
+	  } else {
+	    mu_IVF_signedIP2D.push_back(-999);
+	    mu_IVF_signedIP3D.push_back(-999);
+	    mu_IVF_signedIP2Dsig.push_back(-999);
+	    mu_IVF_signedIP3Dsig.push_back(-999);	    	    
+	  }
+	}	 
+      }      
+      nMuonsSel += 1;
+    }
+    
+    auto dispJetElectronTab = std::make_unique<nanoaod::FlatTable>(nElectronsSel, "DispJetElectron", false, false);
+    auto dispJetMuonTab = std::make_unique<nanoaod::FlatTable>(nMuonsSel, "DispJetMuon", false, false);
+    
+    dispJetElectronTab->addColumn<int>("idx", el_idx, "");
+    dispJetElectronTab->addColumn<bool>("lIVF_match", el_lIVF_match, "");
+    dispJetElectronTab->addColumn<bool>("isEB", el_isEB, "");
+    dispJetElectronTab->addColumn<bool>("isEE", el_isEE, "");
+    dispJetElectronTab->addColumn<float>("superClusterOverP", el_superClusterOverP, "");
+    dispJetElectronTab->addColumn<float>("ecalEnergy", el_ecalEnergy, "");
+    dispJetElectronTab->addColumn<float>("dEtaInSeed", el_dEtaInSeed, "");
+    dispJetElectronTab->addColumn<int>("numberInnerHitsMissing", el_numberInnerHitsMissing, "");
+    dispJetElectronTab->addColumn<int>("numberOfValidPixelHits", el_numberOfValidPixelHits, "");
+    dispJetElectronTab->addColumn<int>("numberOfValidTrackerHits", el_numberOfValidTrackerHits, "");
+    dispJetElectronTab->addColumn<float>("relIso0p4", el_relIso0p4, "");
+    dispJetElectronTab->addColumn<float>("jetPtRatio", el_jetPtRatio, "");
+    dispJetElectronTab->addColumn<float>("jetPtRel", el_jetPtRel, "");
+    dispJetElectronTab->addColumn<int>("jetIdx", el_jetIdx, "");
+    dispJetElectronTab->addColumn<int>("jetFatIdx", el_jetFatIdx, "");
+    dispJetElectronTab->addColumn<int>("jetSubIdx", el_jetSubIdx, "");
+    dispJetElectronTab->addColumn<int>("jetSelectedChargedMultiplicity", el_jetSelectedChargedMultiplicity, "");
+    dispJetElectronTab->addColumn<float>("sigmaIetaIeta", el_sigmaIetaIeta, "");
+    dispJetElectronTab->addColumn<float>("deltaPhiSuperClusterTrack", el_deltaPhiSuperClusterTrack, "");
+    dispJetElectronTab->addColumn<float>("deltaEtaSuperClusterTrack", el_deltaEtaSuperClusterTrack, "");
+    dispJetElectronTab->addColumn<float>("eInvMinusPInv", el_eInvMinusPInv, "");
+    dispJetElectronTab->addColumn<float>("hOverE", el_hOverE, "");
+    dispJetElectronTab->addColumn<float>("dxy", el_dxy, "");
+    dispJetElectronTab->addColumn<float>("dz", el_dz, "");
+    dispJetElectronTab->addColumn<float>("3dIP", el_3dIP, "");
+    dispJetElectronTab->addColumn<float>("3dIPSig", el_3dIPSig, "");
+    
+    auto dispJetElectronVtxTab = std::make_unique<nanoaod::FlatTable>(el_IVF_x.size(), "DispJetElectronVtx", false, false);
+    dispJetElectronVtxTab->addColumn<int>("IVF_df", el_IVF_df, "");
path: plugins/DispJetTableProducer.cc
user: login: kskovpen
body: It is Inclusive Vertex Finder (IVF) - I prefer to keep it in the name since these variables contain information about the vertex as well as tracks associated to it. Since the algorithm is different from AVF (runs iteratively), keeping it in the name would allow to distinguish among various algorithms, in case more are added in the future.
created_at: 2025-05-03T18:53:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,733 @@
+// -*- C++ -*-
+//
+// Package:    PhysicsTools/EXOnanoAOD
+// Class:      DispJetTableProducer
+//
+/**\class DispJetTableProducer
+
+ Description: Additional variables for displaced vertices involving at least one lepton and other tracks
+
+*/
+//
+// Original Author:  Kirill Skovpen
+//         Created:  Sat, 1 Mar 2025 08:37:01 GMT
+//
+
+// system include files
+#include <memory>
+
+// user include files
+#include "FWCore/Framework/interface/Frameworkfwd.h"
+#include "FWCore/Framework/interface/stream/EDProducer.h"
+
+#include "FWCore/Framework/interface/Event.h"
+#include "FWCore/Framework/interface/MakerMacros.h"
+
+#include "FWCore/ParameterSet/interface/ParameterSet.h"
+#include "FWCore/Utilities/interface/StreamID.h"
+
+#include "DataFormats/PatCandidates/interface/Electron.h"
+#include "DataFormats/PatCandidates/interface/Muon.h"
+#include "DataFormats/PatCandidates/interface/Jet.h"
+#include "DataFormats/MuonReco/interface/MuonSelectors.h"
+
+// nanoAOD include files
+#include "DataFormats/NanoAOD/interface/FlatTable.h"
+
+// object specific include files
+#include "TrackingTools/TransientTrack/interface/TransientTrackBuilder.h"
+#include "TrackingTools/Records/interface/TransientTrackRecord.h"
+#include "TrackingTools/IPTools/interface/IPTools.h"
+#include "DataFormats/TrackReco/interface/Track.h"
+#include "DataFormats/VertexReco/interface/VertexFwd.h"
+#include "DataFormats/VertexReco/interface/Vertex.h"
+
+class DispJetTableProducer : public edm::stream::EDProducer<> {
+protected:
+
+  float dEtaInSeed(const pat::Electron* el) const;
+  float getPFIso(const pat::Muon& muon) const;
+  float getPFIso(const pat::Electron& electron) const;
+  int findMatchedJet(const reco::Candidate& lepton, const edm::Handle< std::vector< pat::Jet > >& jets);
+  void fillLeptonJetVariables(const reco::GsfElectron *el, const reco::Muon *mu, edm::Handle< std::vector< pat::Jet > >& jets, const reco::Vertex& vertex, const double rho);
+
+  edm::ESGetToken<TransientTrackBuilder, TransientTrackRecord> ttbToken_;
+  edm::EDGetTokenT<double> rhoTag_;
+  edm::EDGetTokenT<std::vector<pat::Electron> > electronTag_;
+  edm::EDGetTokenT<std::vector<pat::Muon> > muonTag_;
+  edm::EDGetTokenT<std::vector<pat::Jet> > jetTag_;
+  edm::EDGetTokenT<std::vector<pat::Jet> > jetFatTag_;
+  edm::EDGetTokenT<std::vector<pat::Jet> > jetSubTag_;
+  edm::EDGetTokenT<reco::VertexCollection> vtxTag_;
+  edm::EDGetTokenT<reco::VertexCollection> secVtxTag_;
+
+  const TransientTrackBuilder* theB;
+  
+  std::vector<int> el_idx;
+  std::vector<bool> el_lIVF_match;
+  std::vector<bool> el_isEB, el_isEE;
+  std::vector<float> el_superClusterOverP, el_ecalEnergy, el_dEtaInSeed;
+  std::vector<int> el_numberInnerHitsMissing, el_numberOfValidPixelHits, el_numberOfValidTrackerHits;
+  std::vector<int> el_IVF_df, el_IVF_ntracks, el_IVF_elid;
+  std::vector<float> el_IVF_x, el_IVF_y, el_IVF_z, el_IVF_cx, el_IVF_cy, el_IVF_cz, el_IVF_chi2, el_IVF_pt, el_IVF_eta, el_IVF_phi, el_IVF_E, el_IVF_mass;
+  std::vector<int> el_IVF_trackcharge, el_IVF_trackelid, el_IVF_trackvtxid;
+  std::vector<float> el_IVF_trackpt, el_IVF_tracketa, el_IVF_trackphi, el_IVF_trackE, el_IVF_trackdxy, el_IVF_trackdz;
+  std::vector<float> el_IVF_tracksignedIP2D, el_IVF_tracksignedIP3D, el_IVF_tracksignedIP2Dsig, el_IVF_tracksignedIP3Dsig;
+  
+  std::vector<float> el_jetPtRatio, el_jetPtRel;
+  std::vector<int> el_jetIdx, el_jetSelectedChargedMultiplicity;
+  std::vector<int> el_jetFatIdx, el_jetSubIdx;
+  std::vector<float> el_relIso0p4;
+  std::vector<float> el_sigmaIetaIeta, el_deltaPhiSuperClusterTrack, el_deltaEtaSuperClusterTrack, el_eInvMinusPInv, el_hOverE;
+  
+  std::vector<float> el_dxy, el_dz, el_3dIP, el_3dIPSig;
+  std::vector<float> el_IVF_signedIP2D, el_IVF_signedIP3D, el_IVF_signedIP2Dsig, el_IVF_signedIP3Dsig;
+   
+  std::vector<int> mu_idx;
+  std::vector<bool> mu_lIVF_match;
+  std::vector<float> mu_innerTrackValidFraction, mu_globalTrackNormalizedChi2, mu_CQChi2Position, mu_CQTrackKink;
+  std::vector<int> mu_numberOfMatchedStation, mu_numberOfValidPixelHits, mu_numberOfValidTrackerHits, mu_numberInnerHitsMissing, mu_trackerLayersWithMeasurement, mu_numberInnerHits;
+  std::vector<int> mu_IVF_df, mu_IVF_ntracks, mu_IVF_muid;
+  std::vector<float> mu_IVF_x, mu_IVF_y, mu_IVF_z, mu_IVF_cx, mu_IVF_cy, mu_IVF_cz, mu_IVF_chi2, mu_IVF_pt, mu_IVF_eta, mu_IVF_phi, mu_IVF_E, mu_IVF_mass;
+  std::vector<int> mu_IVF_trackcharge, mu_IVF_trackmuid, mu_IVF_trackvtxid;
+  std::vector<float> mu_IVF_trackpt, mu_IVF_tracketa, mu_IVF_trackphi, mu_IVF_trackE, mu_IVF_trackdxy, mu_IVF_trackdz;
+  std::vector<float> mu_IVF_tracksignedIP2D, mu_IVF_tracksignedIP3D, mu_IVF_tracksignedIP2Dsig, mu_IVF_tracksignedIP3Dsig;
+  
+  std::vector<float> mu_jetPtRatio, mu_jetPtRel;
+  std::vector<int> mu_jetIdx, mu_jetSelectedChargedMultiplicity;
+  std::vector<int> mu_jetFatIdx, mu_jetSubIdx;
+  std::vector<float> mu_relIso0p4;
+  std::vector<float> mu_trackPt, mu_trackPtErr;
+  
+  std::vector<float> mu_dxy, mu_dz, mu_3dIP, mu_3dIPSig;
+  std::vector<float> mu_IVF_signedIP2D, mu_IVF_signedIP3D, mu_IVF_signedIP2Dsig, mu_IVF_signedIP3Dsig;
+
+public:
+  DispJetTableProducer(edm::ParameterSet const& params)
+    :
+    ttbToken_(esConsumes(edm::ESInputTag("", "TransientTrackBuilder"))),
+    rhoTag_(consumes<double>(params.getParameter<edm::InputTag>("rho"))),
+    electronTag_(consumes<std::vector<pat::Electron>>(params.getParameter<edm::InputTag>("electrons"))),
+    muonTag_(consumes<std::vector<pat::Muon>>(params.getParameter<edm::InputTag>("muons"))),
+    jetTag_(consumes<std::vector<pat::Jet>>(params.getParameter<edm::InputTag>("jets"))),
+    jetFatTag_(consumes<std::vector<pat::Jet>>(params.getParameter<edm::InputTag>("jetsFat"))),
+    jetSubTag_(consumes<std::vector<pat::Jet>>(params.getParameter<edm::InputTag>("jetsSub"))),
+    vtxTag_(consumes<reco::VertexCollection>(params.getParameter<edm::InputTag>("primaryVertex"))),
+    secVtxTag_(consumes<reco::VertexCollection>(params.getParameter<edm::InputTag>("secondaryVertex"))) {
+       produces<nanoaod::FlatTable>("DispJetElectron");
+       produces<nanoaod::FlatTable>("DispJetElectronVtx");
+       produces<nanoaod::FlatTable>("DispJetElectronTrk");
+       produces<nanoaod::FlatTable>("DispJetMuon");
+       produces<nanoaod::FlatTable>("DispJetMuonVtx");
+       produces<nanoaod::FlatTable>("DispJetMuonTrk");
+  }   
+
+  ~DispJetTableProducer() override {}
+  
+  void produce(edm::Event& iEvent, const edm::EventSetup& iSetup) override {
+
+    theB = &iSetup.getData(ttbToken_);
+    
+    edm::Handle<double> rhoHandle;
+    iEvent.getByToken(rhoTag_, rhoHandle);
+    
+    edm::Handle<std::vector<pat::Electron> > electronHandle;
+    iEvent.getByToken(electronTag_, electronHandle);
+    
+    edm::Handle<std::vector<pat::Muon> > muonHandle;
+    iEvent.getByToken(muonTag_, muonHandle);
+    
+    edm::Handle<std::vector<pat::Jet> > jetHandle;
+    iEvent.getByToken(jetTag_, jetHandle);
+
+    edm::Handle<std::vector<pat::Jet> > jetFatHandle;
+    iEvent.getByToken(jetFatTag_, jetFatHandle);
+
+    edm::Handle<std::vector<pat::Jet> > jetSubHandle;
+    iEvent.getByToken(jetSubTag_, jetSubHandle);
+    
+    edm::Handle<reco::VertexCollection> primaryVertexHandle;
+    iEvent.getByToken(vtxTag_, primaryVertexHandle);
+    
+    edm::Handle<reco::VertexCollection> secondaryVertexHandle;
+    iEvent.getByToken(secVtxTag_, secondaryVertexHandle);
+    
+    const auto& pv = primaryVertexHandle->at(0);
+    GlobalPoint primaryVertex(pv.x(), pv.y(), pv.z());
+    
+    const reco::VertexCollection & secVertices = (*secondaryVertexHandle);
+    
+    unsigned int nElectrons = electronHandle->size();
+    unsigned int nMuons = muonHandle->size();
+    
+    el_idx.clear();
+    el_lIVF_match.clear();
+    el_isEB.clear(); el_isEE.clear();
+    el_superClusterOverP.clear(); el_ecalEnergy.clear(); el_dEtaInSeed.clear();
+    el_numberInnerHitsMissing.clear(); el_numberOfValidPixelHits.clear(); el_numberOfValidTrackerHits.clear();
+    el_IVF_df.clear(); el_IVF_ntracks.clear(); el_IVF_elid.clear();
+    el_IVF_x.clear(); el_IVF_y.clear(); el_IVF_z.clear(); el_IVF_cx.clear(); el_IVF_cy.clear(); el_IVF_cz.clear(); el_IVF_chi2.clear(); el_IVF_pt.clear(); el_IVF_eta.clear(); el_IVF_phi.clear(); el_IVF_E.clear(); el_IVF_mass.clear();
+    el_IVF_trackcharge.clear(); el_IVF_trackelid.clear(); el_IVF_trackvtxid.clear();
+    el_IVF_trackpt.clear(); el_IVF_tracketa.clear(); el_IVF_trackphi.clear(); el_IVF_trackE.clear(); el_IVF_trackdxy.clear(); el_IVF_trackdz.clear();
+    el_IVF_tracksignedIP2D.clear(); el_IVF_tracksignedIP2Dsig.clear(); el_IVF_tracksignedIP3D.clear(); el_IVF_tracksignedIP3Dsig.clear();
+    
+    el_jetPtRatio.clear(); el_jetPtRel.clear();
+    el_jetIdx.clear(); el_jetSelectedChargedMultiplicity.clear();
+    el_jetFatIdx.clear(); el_jetSubIdx.clear();
+    el_relIso0p4.clear();
+    el_sigmaIetaIeta.clear(); el_deltaPhiSuperClusterTrack.clear(); el_deltaEtaSuperClusterTrack.clear(); el_eInvMinusPInv.clear(); el_hOverE.clear();    
+    el_dxy.clear(); el_dz.clear(); el_3dIP.clear(); el_3dIPSig.clear();
+    el_IVF_signedIP2D.clear(); el_IVF_signedIP2Dsig.clear(); el_IVF_signedIP3D.clear(); el_IVF_signedIP3Dsig.clear();
+    
+    mu_idx.clear();
+    mu_lIVF_match.clear();
+    mu_innerTrackValidFraction.clear(); mu_globalTrackNormalizedChi2.clear(); mu_CQChi2Position.clear(); mu_CQTrackKink.clear();
+    mu_numberOfMatchedStation.clear(); mu_numberOfValidPixelHits.clear(); mu_numberOfValidTrackerHits.clear(); mu_numberInnerHitsMissing.clear(); mu_trackerLayersWithMeasurement.clear(); mu_numberInnerHits.clear();
+    mu_IVF_df.clear(); mu_IVF_ntracks.clear(); mu_IVF_muid.clear();
+    mu_IVF_x.clear(); mu_IVF_y.clear(); mu_IVF_z.clear(); mu_IVF_cx.clear(); mu_IVF_cy.clear(); mu_IVF_cz.clear(); mu_IVF_chi2.clear(); mu_IVF_pt.clear(); mu_IVF_eta.clear(); mu_IVF_phi.clear(); mu_IVF_E.clear(); mu_IVF_mass.clear();
+    mu_IVF_trackcharge.clear(); mu_IVF_trackmuid.clear(); mu_IVF_trackvtxid.clear();
+    mu_IVF_trackpt.clear(); mu_IVF_tracketa.clear(); mu_IVF_trackphi.clear(); mu_IVF_trackE.clear(); mu_IVF_trackdxy.clear(); mu_IVF_trackdz.clear();
+    mu_IVF_tracksignedIP2D.clear(); mu_IVF_tracksignedIP2Dsig.clear(); mu_IVF_tracksignedIP3D.clear(); mu_IVF_tracksignedIP3Dsig.clear();
+    
+    mu_jetPtRatio.clear(); mu_jetPtRel.clear();
+    mu_jetIdx.clear(); mu_jetSelectedChargedMultiplicity.clear();
+    mu_jetFatIdx.clear(); mu_jetSubIdx.clear();
+    mu_relIso0p4.clear();
+    mu_trackPt.clear(); mu_trackPtErr.clear();
+    
+    mu_dxy.clear(); mu_dz.clear(); mu_3dIP.clear(); mu_3dIPSig.clear();
+    mu_IVF_signedIP2D.clear(); mu_IVF_signedIP2Dsig.clear(); mu_IVF_signedIP3D.clear(); mu_IVF_signedIP3Dsig.clear();
+     
+    int ntrack_max = 100;
+    int nElectronsSel = 0;
+    int nMuonsSel = 0;
+    
+    for(unsigned int i = 0; i < nElectrons; i++) {
+      
+      const pat::Electron & el = (*electronHandle)[i];
+      
+      if(el.gsfTrack().isNull()) continue;
+      if(el.pt() < 7) continue;     
+      if(fabs(el.eta()) > 2.5) continue;
+      
+      int ielCand = 0;
+      for(edm::Ref<pat::PackedCandidateCollection> cand : el.associatedPackedPFCandidates()){	  
+	if( cand.isNonnull() and cand.isAvailable() ) {
+	  break;
+	}       
+	ielCand++;
+      }
+      
+      el_idx.push_back(i);
+      el_lIVF_match.push_back(false);
+      
+      el_isEB.push_back(el.isEB());
+      el_isEE.push_back(el.isEE());
+      el_superClusterOverP.push_back(el.eSuperClusterOverP());
+      el_ecalEnergy.push_back(el.ecalEnergy());
+      el_dEtaInSeed.push_back(std::abs(dEtaInSeed(&el)));
+      el_numberInnerHitsMissing.push_back(el.gsfTrack()->hitPattern().numberOfLostHits(reco::HitPattern::MISSING_INNER_HITS));
+      el_numberOfValidPixelHits.push_back((!el.gsfTrack().isNull())? el.gsfTrack()->hitPattern().numberOfValidPixelHits() : 0);
+      el_numberOfValidTrackerHits.push_back((!el.gsfTrack().isNull())? el.gsfTrack()->hitPattern().numberOfValidTrackerHits() : 0);
+      
+      el_relIso0p4.push_back(getPFIso(el));
+      el_sigmaIetaIeta.push_back(el.full5x5_sigmaIetaIeta());
+      el_deltaPhiSuperClusterTrack.push_back(fabs(el.deltaPhiSuperClusterTrackAtVtx()));
+      el_deltaEtaSuperClusterTrack.push_back(fabs(el.deltaEtaSuperClusterTrackAtVtx()));
+      el_eInvMinusPInv.push_back((1.0 - el.eSuperClusterOverP())/el.correctedEcalEnergy());
+      el_hOverE.push_back(el.hadronicOverEm());
+      
+      el_dxy.push_back(el.dB(pat::Electron::PV2D));
+      el_dz.push_back(el.dB(pat::Electron::PVDZ));
+      el_3dIP.push_back(el.dB(pat::Electron::PV3D));
+      el_3dIPSig.push_back(fabs(el.dB(pat::Electron::PV3D)/el.edB(pat::Electron::PV3D)));
+      
+      fillLeptonJetVariables(&el, NULL, jetHandle, pv, *rhoHandle);
+
+      const reco::Candidate *el_cand = dynamic_cast<const reco::Candidate*>(&el);
+      el_jetFatIdx.push_back(findMatchedJet(*el_cand, jetFatHandle));
+      el_jetSubIdx.push_back(findMatchedJet(*el_cand, jetSubHandle));
+      
+      bool new_vtx = false;
+      double dR, deta, normchi2;
+      double mindR = 20, minnormchi2 = 10000;
+      int nVtx = 0;
+      reco::Vertex *vtxDisp = NULL;
+      for(const reco::Vertex& vtx : secVertices) {
+	for(reco::Vertex::trackRef_iterator vtxTrackref = vtx.tracks_begin(); vtxTrackref != vtx.tracks_end(); vtxTrackref++) {
+	  reco::TrackRef vtxTrack = vtxTrackref->castTo<reco::TrackRef>();
+	  for(edm::Ref<pat::PackedCandidateCollection> cand : el.associatedPackedPFCandidates()) {	       
+	    dR       = reco::deltaR(cand->eta(), cand->phi(), vtxTrack->eta(), vtxTrack->phi());
+	    deta     = fabs(cand->eta() - vtxTrack->eta());
+	    normchi2 = fabs(vtx.chi2()/vtx.ndof());
+	    
+	    if((dR < 0.05 or (dR < 0.1 and deta < 0.03)) and (dR < mindR or (dR == mindR and normchi2 < minnormchi2))) {	       
+	      new_vtx = true;
+	      vtxDisp = const_cast<reco::Vertex*>(&vtx);
+	      el_lIVF_match[nElectronsSel] = true;
+	      mindR       = dR;
+	      minnormchi2 = normchi2;
+	    }
+	  }
+	}
+	
+	if(new_vtx) {
+	  el_IVF_x.push_back(vtx.x());
+	  el_IVF_y.push_back(vtx.y());
+	  el_IVF_z.push_back(vtx.z());
+	  el_IVF_cx.push_back(vtx.xError());
+	  el_IVF_cy.push_back(vtx.yError());
+	  el_IVF_cz.push_back(vtx.zError());
+	  el_IVF_df.push_back(vtx.ndof());
+	  el_IVF_chi2.push_back(vtx.chi2());
+	  el_IVF_pt.push_back(vtx.p4().pt());
+	  el_IVF_eta.push_back(vtx.p4().eta());
+	  el_IVF_phi.push_back(vtx.p4().phi());
+	  el_IVF_E.push_back(vtx.p4().energy());
+	  el_IVF_mass.push_back(vtx.p4().mass());
+	  el_IVF_elid.push_back(nElectronsSel);
+	  
+	  el_IVF_ntracks.push_back(0);
+	  for(reco::Vertex::trackRef_iterator vtxTrackref = vtx.tracks_begin(); vtxTrackref != vtx.tracks_end(); vtxTrackref++) {
+	    if(el_IVF_ntracks.back() == ntrack_max) break;
+	    reco::TrackRef vtxTrack = vtxTrackref->castTo<reco::TrackRef>();
+	    const auto& trk = theB->build(vtxTrack);
+	    Global3DVector dir(vtxTrack->px(), vtxTrack->py(), vtxTrack->pz());
+	    const auto& ip2d = IPTools::signedTransverseImpactParameter(trk, dir, *vtxDisp);
+	    const auto& ip3d = IPTools::signedImpactParameter3D(trk, dir, *vtxDisp);
+	    el_IVF_tracksignedIP2D.push_back(ip2d.second.value());
+	    el_IVF_tracksignedIP3D.push_back(ip3d.second.value());
+	    el_IVF_tracksignedIP2Dsig.push_back(ip2d.second.significance());
+	    el_IVF_tracksignedIP3Dsig.push_back(ip3d.second.significance());
+	    el_IVF_trackpt.push_back(vtxTrack->pt());
+	    el_IVF_tracketa.push_back(vtxTrack->eta());
+	    el_IVF_trackphi.push_back(vtxTrack->phi());
+	    el_IVF_trackE.push_back(vtxTrack->p());
+	    el_IVF_trackcharge.push_back(vtxTrack->charge());
+	    el_IVF_trackdxy.push_back(std::abs(vtxTrack->dxy(pv.position())));
+	    el_IVF_trackdz.push_back(std::abs(vtxTrack->dz(pv.position())));
+	    el_IVF_trackelid.push_back(nElectronsSel);
+	    el_IVF_trackvtxid.push_back(nVtx);
+	    el_IVF_ntracks.back()++;	    
+	  }
+	  nVtx++;
+	  new_vtx = false;
+
+	  auto track = el.gsfTrack();
+	  if( track.isNonnull() ) {
+	    const auto& trk = theB->build(track);
+	    Global3DVector dir(track->px(), track->py(), track->pz());
+	    const auto& ip2d = IPTools::signedTransverseImpactParameter(trk, dir, *vtxDisp);
+	    const auto& ip3d = IPTools::signedImpactParameter3D(trk, dir, *vtxDisp);
+	    el_IVF_signedIP2D.push_back(ip2d.second.value());
+	    el_IVF_signedIP3D.push_back(ip3d.second.value());
+	    el_IVF_signedIP2Dsig.push_back(ip2d.second.significance());
+	    el_IVF_signedIP3Dsig.push_back(ip3d.second.significance());
+	  } else {
+	    el_IVF_signedIP2D.push_back(-999);
+	    el_IVF_signedIP3D.push_back(-999);
+	    el_IVF_signedIP2Dsig.push_back(-999);
+	    el_IVF_signedIP3Dsig.push_back(-999);	    
+	  }
+	}
+      }
+      nElectronsSel += 1;
+    }
+    
+    for(unsigned int i = 0; i < nMuons; i++) {
path: plugins/DispJetTableProducer.cc
user: login: kskovpen
body: Moving them now :)
created_at: 2025-05-03T19:06:58Z
author_association: CONTRIBUTOR

PR comments:
user: login: kskovpen
created_at: 2025-05-04T16:42:46Z
body: Thanks for the comments. As of now, we are running our analysis on MiniAODs, this is the reason why there is an additional config. Looking at the DSA muon vertexing code, it can only run on AODs in its current form, but it should be possible to update it to run on MiniAODs by switching from reco::Track to pat::PackedCandidate, but I do not know if you want to switch to MiniAODs for your analysis. Now the extended variable definitions are shared among different analyses, as was suggested earlier.
author_association: CONTRIBUTOR
user: login: kskovpen
created_at: 2025-05-04T16:47:09Z
body: I have also added a few small protections in DSA muon code to avoid crashing on MiniAOD due to missing TrackExtra and det ID information; just in case you will switch to MiniAOD at some point.
author_association: CONTRIBUTOR