CMS 3D CMS Logo

SimPFProducer.cc
Go to the documentation of this file.
1 // This producer assigns vertex times (with a specified resolution) to tracks.
2 // The times are produced as valuemaps associated to tracks, so the track dataformat doesn't
3 // need to be modified.
4 
7 
10 
12 
15 
17 
30 
33 
36 
39 
41 
43 
46 
49 
50 #include <unordered_map>
51 #include <memory>
52 
53 #include "CLHEP/Units/SystemOfUnits.h"
55 
57 
59 public:
61  ~SimPFProducer() override { }
62 
63  void produce(edm::StreamID, edm::Event&, const edm::EventSetup&) const override;
64 
65 private:
66  // parameters
68  const bool useTiming_;
69 
70  // inputs
81  // tracking particle associators by order of preference
82  const std::vector<edm::EDGetTokenT<reco::TrackToTrackingParticleAssociator> > associators_;
83 
84 };
85 
87 
88 namespace {
89 
90  template<typename T>
91  uint64_t hashSimInfo(const T& simTruth,size_t i = 0) {
92  uint64_t evtid = simTruth.eventId().rawId();
93  uint64_t trackid = simTruth.g4Tracks()[i].trackId();
94  return ( (evtid << 3) + 23401923 ) ^ trackid ;
95  };
96 }
97 
99  superClusterThreshold_( conf.getParameter<double>("superClusterThreshold") ),
100  neutralEMThreshold_( conf.getParameter<double>("neutralEMThreshold") ),
101  neutralHADThreshold_( conf.getParameter<double>("neutralHADThreshold") ),
102  useTiming_(conf.existsAs<edm::InputTag>("trackTimeValueMap")),
103  pfRecTracks_(consumes<edm::View<reco::PFRecTrack> >(conf.getParameter<edm::InputTag> ("pfRecTrackSrc"))),
104  tracks_(consumes<edm::View<reco::Track> >( conf.getParameter<edm::InputTag>("trackSrc") ) ),
105  gsfTracks_(consumes<edm::View<reco::Track> >( conf.getParameter<edm::InputTag>("gsfTrackSrc") ) ),
106  muons_(consumes<reco::MuonCollection>(conf.getParameter<edm::InputTag>("muonSrc"))),
107  srcTrackTime_(useTiming_ ? consumes<edm::ValueMap<float>>(conf.getParameter<edm::InputTag>("trackTimeValueMap")) : edm::EDGetTokenT<edm::ValueMap<float>>()),
108  srcTrackTimeError_(useTiming_ ? consumes<edm::ValueMap<float>>(conf.getParameter<edm::InputTag>("trackTimeErrorMap")) : edm::EDGetTokenT<edm::ValueMap<float>>()),
109  srcGsfTrackTime_(useTiming_ ? consumes<edm::ValueMap<float>>(conf.getParameter<edm::InputTag>("gsfTrackTimeValueMap")) : edm::EDGetTokenT<edm::ValueMap<float>>()),
110  srcGsfTrackTimeError_(useTiming_ ? consumes<edm::ValueMap<float>>(conf.getParameter<edm::InputTag>("gsfTrackTimeErrorMap")) : edm::EDGetTokenT<edm::ValueMap<float>>()),
111  trackingParticles_(consumes<TrackingParticleCollection>( conf.getParameter<edm::InputTag>("trackingParticleSrc") ) ),
112  simClustersTruth_(consumes<SimClusterCollection>( conf.getParameter<edm::InputTag>("simClusterTruthSrc") ) ),
113  caloParticles_(consumes<CaloParticleCollection>( conf.getParameter<edm::InputTag>("caloParticlesSrc") ) ),
114  simClusters_(consumes<std::vector<reco::PFCluster> >( conf.getParameter<edm::InputTag>("simClustersSrc") ) ),
115  associators_( edm::vector_transform( conf.getParameter<std::vector<edm::InputTag> >("associators"), [this](const edm::InputTag& tag){ return this->consumes<reco::TrackToTrackingParticleAssociator>(tag); } ) )
116 {
117  produces<reco::PFBlockCollection>();
118  produces<reco::SuperClusterCollection>("perfect");
119  produces<reco::PFCandidateCollection>();
120 }
121 
123  //get associators
124  std::vector<edm::Handle<reco::TrackToTrackingParticleAssociator> > associators;
125  for( const auto& token : associators_ ) {
126  associators.emplace_back();
127  auto& back = associators.back();
128  evt.getByToken(token,back);
129  }
130 
131  //get PFRecTrack
132  edm::Handle<edm::View<reco::PFRecTrack> > PFTrackCollectionH;
133  evt.getByToken(pfRecTracks_,PFTrackCollectionH);
134  const edm::View<reco::PFRecTrack> PFTrackCollection = *PFTrackCollectionH;
135  std::unordered_set<unsigned> PFTrackToGeneralTrack;
136  for( unsigned i = 0; i < PFTrackCollection.size(); ++i ) {
137  const auto ptr = PFTrackCollection.ptrAt(i);
138  PFTrackToGeneralTrack.insert(ptr->trackRef().key());
139  }
140 
141  //get track collections
142  edm::Handle<edm::View<reco::Track> > TrackCollectionH;
143  evt.getByToken(tracks_, TrackCollectionH);
144  const edm::View<reco::Track>& TrackCollection = *TrackCollectionH;
145 
147  evt.getByToken(muons_,muons);
148  std::unordered_set<unsigned> MuonTrackToGeneralTrack;
149  for (auto const& mu : *muons.product()){
150  reco::TrackRef muTrkRef = mu.track();
151  if (muTrkRef.isNonnull())
152  MuonTrackToGeneralTrack.insert(muTrkRef.key());
153  }
154 
155  // get timing, if enabled
156  edm::Handle<edm::ValueMap<float>> trackTimeH, trackTimeErrH, gsfTrackTimeH, gsfTrackTimeErrH;
157  if (useTiming_) {
158  evt.getByToken(srcTrackTime_, trackTimeH);
159  evt.getByToken(srcTrackTimeError_, trackTimeErrH);
160  evt.getByToken(srcGsfTrackTime_, gsfTrackTimeH);
161  evt.getByToken(srcGsfTrackTimeError_, gsfTrackTimeErrH);
162  }
163 
164  //get tracking particle collections
166  evt.getByToken(trackingParticles_, TPCollectionH);
167  //const TrackingParticleCollection& TPCollection = *TPCollectionH;
168 
169  // grab phony clustering information
170  edm::Handle<SimClusterCollection> SimClustersTruthH;
171  evt.getByToken(simClustersTruth_,SimClustersTruthH);
172  const SimClusterCollection& SimClustersTruth = *SimClustersTruthH;
173 
175  evt.getByToken(caloParticles_,CaloParticlesH);
176  const CaloParticleCollection& CaloParticles = *CaloParticlesH;
177 
179  evt.getByToken(simClusters_,SimClustersH);
180  const std::vector<reco::PFCluster>& SimClusters = *SimClustersH;
181 
182  std::unordered_map<uint64_t,size_t> hashToSimCluster;
183 
184  for( unsigned i = 0; i < SimClustersTruth.size(); ++i ) {
185  const auto& simTruth = SimClustersTruth[i];
186  hashToSimCluster[hashSimInfo(simTruth)] = i;
187  }
188 
189  // associate the reco tracks / gsf Tracks
190  std::vector<reco::RecoToSimCollection> associatedTracks, associatedTracksGsf;
191  for( auto associator : associators ) {
192  associatedTracks.emplace_back(associator->associateRecoToSim(TrackCollectionH, TPCollectionH));
193  //associatedTracksGsf.emplace_back(associator->associateRecoToSim(GsfTrackCollectionH, TPCollectionH));
194  }
195 
196  // make blocks out of calo particles so we can have cluster references
197  // likewise fill out superclusters
198  auto superclusters = std::make_unique<reco::SuperClusterCollection>();
199  auto blocks = std::make_unique<reco::PFBlockCollection>();
200  std::unordered_map<size_t,size_t> simCluster2Block;
201  std::unordered_map<size_t,size_t> simCluster2BlockIndex;
202  std::unordered_multimap<size_t,size_t> caloParticle2SimCluster;
203  std::vector<int> caloParticle2SuperCluster;
204  for( unsigned icp = 0; icp < CaloParticles.size(); ++icp ) {
205  blocks->emplace_back();
206  auto& block = blocks->back();
207  const auto& simclusters = CaloParticles[icp].simClusters();
208  double pttot = 0.0;
209  double etot = 0.0;
210  std::vector<size_t> good_simclusters;
211  for( unsigned isc = 0; isc < simclusters.size() ; ++isc ) {
212  auto simc = simclusters[isc];
213  auto pdgId = std::abs(simc->pdgId());
214  edm::Ref<std::vector<reco::PFCluster> > clusterRef(SimClustersH,simc.key());
215  if( ( (pdgId == 22 || pdgId == 11) && clusterRef->energy() > neutralEMThreshold_) ||
216  clusterRef->energy() > neutralHADThreshold_ ) {
217  good_simclusters.push_back(isc);
218  etot += clusterRef->energy();
219  pttot += clusterRef->pt();
220  auto bec = std::make_unique<reco::PFBlockElementCluster>(clusterRef,reco::PFBlockElement::HGCAL);
221  block.addElement(bec.get());
222  simCluster2Block[simc.key()] = icp;
223  simCluster2BlockIndex[simc.key()] = bec->index();
224  caloParticle2SimCluster.emplace(CaloParticles[icp].g4Tracks()[0].trackId(), simc.key());
225  }
226  }
227 
228  auto pdgId = std::abs(CaloParticles[icp].pdgId());
229 
230  caloParticle2SuperCluster.push_back(-1);
231  if( (pdgId == 22 || pdgId == 11) && pttot > superClusterThreshold_ ) {
232  caloParticle2SuperCluster[icp] = superclusters->size();
233 
234  math::XYZPoint seedpos; // take seed pos as supercluster point
237  for( auto idx : good_simclusters ) {
238  edm::Ptr<reco::PFCluster> ptr(SimClustersH, simclusters[idx].key());
239  clusters.push_back(ptr);
240  if( seed.isNull() || seed->energy() < ptr->energy() ) {
241  seed = ptr;
242  seedpos = ptr->position();
243  }
244  }
245  superclusters->emplace_back(etot,seedpos,seed,clusters);
246  }
247  }
248 
249  auto blocksHandle = evt.put(std::move(blocks));
250  auto superClustersHandle = evt.put(std::move(superclusters),"perfect");
251 
252  // list tracks so we can mark them as used and/or fight over them
253  std::vector<bool> usedTrack(TrackCollection.size(),false),
254  //usedGsfTrack(GsfTrackCollection.size(),false),
255  usedSimCluster(SimClusters.size(),false);
256 
257  auto candidates = std::make_unique<reco::PFCandidateCollection>();
258  // in good particle flow fashion, start from the tracks and go out
259  for( unsigned itk = 0; itk < TrackCollection.size(); ++itk ) {
260  auto tkRef = TrackCollection.refAt(itk);
261  // skip tracks not selected by PF
262  if( PFTrackToGeneralTrack.count(itk) == 0 ) continue;
263  reco::RecoToSimCollection::const_iterator assoc_tps = associatedTracks.back().end();
264  for( const auto& association : associatedTracks ) {
265  assoc_tps = association.find(tkRef);
266  if( assoc_tps != association.end() ) break;
267  }
268  if( assoc_tps == associatedTracks.back().end() ) continue;
269  // assured now that we are matched to a set of tracks
270  const auto& matches = assoc_tps->val;
271 
272  const auto absPdgId = std::abs(matches[0].first->pdgId());
273  const auto charge = tkRef->charge();
274  const auto three_mom = tkRef->momentum();
275  constexpr double mpion2 = 0.13957*0.13957;
276  double energy = std::sqrt(three_mom.mag2() + mpion2);
277  math::XYZTLorentzVector trk_p4(three_mom.x(),three_mom.y(),three_mom.z(),energy);
278 
280 
281  switch( absPdgId ) {
282  case 11:
283  part_type = reco::PFCandidate::e;
284  break;
285  case 13:
286  part_type = reco::PFCandidate::mu;
287  break;
288  default:
289  part_type = reco::PFCandidate::h;
290  }
291 
292  candidates->emplace_back(charge, trk_p4, part_type);
293  auto& candidate = candidates->back();
294 
295  candidate.setTrackRef(tkRef.castTo<reco::TrackRef>());
296 
297  if (useTiming_) candidate.setTime( (*trackTimeH)[tkRef], (*trackTimeErrH)[tkRef] );
298 
299  // bind to cluster if there is one and try to gather conversions, etc
300  for( const auto& match : matches ) {
301  uint64_t hash = hashSimInfo(*(match.first));
302  if( hashToSimCluster.count(hash) ) {
303  auto simcHash = hashToSimCluster[hash];
304 
305  if( !usedSimCluster[simcHash] ) {
306  if( simCluster2Block.count(simcHash) &&
307  simCluster2BlockIndex.count(simcHash) ) {
308  size_t block = simCluster2Block.find(simcHash)->second;
309  size_t blockIdx = simCluster2BlockIndex.find(simcHash)->second;
310  edm::Ref<reco::PFBlockCollection> blockRef(blocksHandle,block);
311  candidate.addElementInBlock(blockRef,blockIdx);
312  usedSimCluster[simcHash] = true;
313  }
314  }
315  if( absPdgId == 11 ) { // collect brems/conv. brems
316  if( simCluster2Block.count(simcHash) ) {
317  auto block_index = simCluster2Block.find(simcHash)->second;
318  auto supercluster_index = caloParticle2SuperCluster[ block_index ];
319  if( supercluster_index != -1 ) {
320  edm::Ref<reco::PFBlockCollection> blockRef(blocksHandle,block_index);
321  for( const auto& elem : blockRef->elements() ) {
322  const auto& ref = elem.clusterRef();
323  if( !usedSimCluster[ref.key()] ) {
324  candidate.addElementInBlock(blockRef,elem.index());
325  usedSimCluster[ref.key()] = true;
326  }
327  }
328 
329  //*TODO* cluster time is not reliable at the moment, so just keep time from the track if available
330 
331  }
332  }
333  }
334  }
335  // Now try to include also electrons that have been reconstructed using
336  // the GraphCaloParticles. In particular, recover the cases in which the
337  // tracking particle associated to the CaloParticle has not left any hits
338  // in the calorimeters or, if it had, the cluster has been skipped due to
339  // threshold requirements.
340  if (caloParticle2SimCluster.count(match.first->g4Tracks()[0].trackId()))
341  {
342  auto range = caloParticle2SimCluster.equal_range(match.first->g4Tracks()[0].trackId());
343  for (auto it = range.first; it != range.second; ++it) {
344  if (!usedSimCluster[it->second]) {
345  usedSimCluster[it->second] = true;
346  if (simCluster2Block.find(it->second) != simCluster2Block.end()) {
347  size_t block = simCluster2Block.find(it->second)->second;
348  size_t blockIdx = simCluster2BlockIndex.find(it->second)->second;
349  edm::Ref<reco::PFBlockCollection> blockRef(blocksHandle,block);
350  candidate.addElementInBlock(blockRef,blockIdx);
351  }
352  }
353  }
354  }
355  }
356  usedTrack[tkRef.key()] = true;
357  // remove tracks already used by muons
358  if( MuonTrackToGeneralTrack.count(itk) || absPdgId == 13)
359  candidates->pop_back();
360  }
361 
362  // now loop over the non-collected clusters in blocks
363  // and turn them into neutral hadrons or photons
364  const auto& theblocks = *blocksHandle;
365  for( unsigned ibl = 0; ibl < theblocks.size(); ++ibl ) {
366  reco::PFBlockRef blref(blocksHandle,ibl);
367  const auto& elements = theblocks[ibl].elements();
368  for( const auto& elem : elements ) {
369  const auto& ref = elem.clusterRef();
370  const auto& simtruth = SimClustersTruth[ref.key()];
372  if( !usedSimCluster[ref.key()] ) {
373  auto absPdgId = std::abs(simtruth.pdgId());
374  switch( absPdgId ) {
375  case 11:
376  case 22:
377  part_type = reco::PFCandidate::gamma;
378  break;
379  default:
380  part_type = reco::PFCandidate::h0;
381  }
382  const auto three_mom = (ref->position() - math::XYZPoint(0,0,0)).unit()*ref->correctedEnergy();
383  math::XYZTLorentzVector clu_p4(three_mom.x(),three_mom.y(),three_mom.z(),ref->correctedEnergy());
384  candidates->emplace_back(0, clu_p4, part_type);
385  auto& candidate = candidates->back();
386  candidate.addElementInBlock(blref,elem.index());
387  candidate.setTime(ref->time(), ref->timeError());
388  }
389  }
390  }
391 
392  evt.put(std::move(candidates));
393 }
const math::XYZPoint & position() const
cluster centroid position
Definition: CaloCluster.h:131
const edm::EDGetTokenT< edm::ValueMap< float > > srcTrackTimeError_
OrphanHandle< PROD > put(std::unique_ptr< PROD > product)
Put a new product.
Definition: Event.h:125
ParticleType
particle types
Definition: PFCandidate.h:45
bool isNonnull() const
Checks for non-null.
Definition: Ref.h:251
void produce(edm::StreamID, edm::Event &, const edm::EventSetup &) const override
std::vector< TrackingParticle > TrackingParticleCollection
friend struct const_iterator
bool getByToken(EDGetToken token, Handle< PROD > &result) const
Definition: Event.h:517
Ptr< value_type > ptrAt(size_type i) const
void push_back(Ptr< T > const &iPtr)
Definition: PtrVector.h:140
std::vector< Track > TrackCollection
collection of Tracks
Definition: TrackFwd.h:15
size_type size() const
key_type key() const
Accessor for product key.
Definition: Ref.h:263
~SimPFProducer() override
std::vector< Muon > MuonCollection
collection of Muon objects
Definition: MuonFwd.h:9
const double neutralHADThreshold_
EDGetTokenT< ProductType > consumes(edm::InputTag const &tag)
RefToBase< value_type > refAt(size_type i) const
XYZTLorentzVectorD XYZTLorentzVector
Lorentz vector with cylindrical internal representation using pseudorapidity.
Definition: LorentzVector.h:29
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:16
const edm::EDGetTokenT< CaloParticleCollection > caloParticles_
const std::vector< edm::EDGetTokenT< reco::TrackToTrackingParticleAssociator > > associators_
T sqrt(T t)
Definition: SSEVec.h:18
bool isNull() const
Checks for null.
Definition: Ptr.h:164
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
const edm::EDGetTokenT< edm::View< reco::Track > > tracks_
const int mu
Definition: Constants.h:22
const edm::EDGetTokenT< edm::ValueMap< float > > srcGsfTrackTime_
const edm::EDGetTokenT< edm::View< reco::PFRecTrack > > pfRecTracks_
double energy() const
cluster energy
Definition: PFCluster.h:82
const edm::EDGetTokenT< SimClusterCollection > simClustersTruth_
def elem(elemtype, innerHTML='', html_class='', kwargs)
Definition: HTMLExport.py:19
auto vector_transform(std::vector< InputType > const &input, Function predicate) -> std::vector< typename std::remove_cv< typename std::remove_reference< decltype(predicate(input.front()))>::type >::type >
Definition: transform.h:11
const edm::EDGetTokenT< TrackingParticleCollection > trackingParticles_
T const * product() const
Definition: Handle.h:74
unsigned long long uint64_t
Definition: Time.h:15
XYZPointD XYZPoint
point in space with cartesian internal representation
Definition: Point3D.h:12
SimPFProducer(const edm::ParameterSet &)
const double superClusterThreshold_
const edm::EDGetTokenT< reco::MuonCollection > muons_
const edm::EDGetTokenT< edm::ValueMap< float > > srcTrackTime_
fixed size matrix
HLT enums.
std::vector< CaloParticle > CaloParticleCollection
const edm::EDGetTokenT< edm::ValueMap< float > > srcGsfTrackTimeError_
std::pair< typename Association::data_type::first_type, double > match(Reference key, Association association, bool bestMatchByMaxValue)
Generic matching function.
Definition: Utils.h:10
const bool useTiming_
const double neutralEMThreshold_
std::vector< SimCluster > SimClusterCollection
Definition: SimClusterFwd.h:8
const edm::EDGetTokenT< std::vector< reco::PFCluster > > simClusters_
long double T
def move(src, dest)
Definition: eostools.py:511
#define constexpr
const edm::EDGetTokenT< edm::View< reco::Track > > gsfTracks_