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 
5 #include "CLHEP/Units/SystemOfUnits.h"
41 
42 #include <unordered_map>
43 #include <memory>
44 
46 public:
48 
49  static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
50 
51  void produce(edm::StreamID, edm::Event&, const edm::EventSetup&) const override;
52 
53 private:
54  // parameters
56  const bool useTiming_;
57  const bool useTimingQuality_;
59 
60  // inputs
71  // tracking particle associators by order of preference
72  const std::vector<edm::EDGetTokenT<reco::TrackToTrackingParticleAssociator>> associators_;
73 };
74 
77 
79  // simPFProducer
81  desc.add<edm::InputTag>("simClustersSrc", {"particleFlowClusterHGCalFromSimCl"});
82  desc.add<edm::InputTag>("trackSrc", {"generalTracks"});
83  desc.add<std::vector<edm::InputTag>>("associators",
84  {
85  {"quickTrackAssociatorByHits"},
86  });
87  desc.add<edm::InputTag>("pfRecTrackSrc", {"hgcalTrackCollection", "TracksInHGCal"});
88  desc.add<edm::InputTag>("trackingParticleSrc", {"mix", "MergedTrackTruth"});
89  desc.add<double>("neutralEMThreshold", 0.25);
90  desc.add<edm::InputTag>("caloParticlesSrc", {"mix", "MergedCaloTruth"});
91  desc.add<double>("superClusterThreshold", 4.0);
92  desc.add<edm::InputTag>("simClusterTruthSrc", {"mix", "MergedCaloTruth"});
93  desc.add<edm::InputTag>("muonSrc", {"muons1stStep"});
94  desc.add<double>("neutralHADThreshold", 0.25);
95  desc.add<edm::InputTag>("gsfTrackSrc", {"electronGsfTracks"});
96 
97  // if useTiming_
98  desc.addOptional<edm::InputTag>("trackTimeValueMap");
99  desc.addOptional<edm::InputTag>("trackTimeErrorMap");
100  desc.addOptional<edm::InputTag>("trackTimeQualityMap");
101  desc.addOptional<double>("timingQualityThreshold");
102  desc.addOptional<edm::InputTag>("gsfTrackTimeValueMap");
103  desc.addOptional<edm::InputTag>("gsfTrackTimeErrorMap");
104  desc.addOptional<edm::InputTag>("gsfTrackTimeQualityMap");
105 
106  descriptions.add("simPFProducer", desc);
107 }
108 
109 namespace {
110 
111  template <typename T>
112  uint64_t hashSimInfo(const T& simTruth, size_t i = 0) {
113  uint64_t evtid = simTruth.eventId().rawId();
114  uint64_t trackid = simTruth.g4Tracks()[i].trackId();
115  return ((evtid << 3) + 23401923) ^ trackid;
116  };
117 } // namespace
118 
120  : superClusterThreshold_(conf.getParameter<double>("superClusterThreshold")),
121  neutralEMThreshold_(conf.getParameter<double>("neutralEMThreshold")),
122  neutralHADThreshold_(conf.getParameter<double>("neutralHADThreshold")),
123  useTiming_(conf.existsAs<edm::InputTag>("trackTimeValueMap")),
124  useTimingQuality_(conf.existsAs<edm::InputTag>("trackTimeQualityMap")),
125  timingQualityThreshold_(useTimingQuality_ ? conf.getParameter<double>("timingQualityThreshold") : -99.),
126  pfRecTracks_(consumes<edm::View<reco::PFRecTrack>>(conf.getParameter<edm::InputTag>("pfRecTrackSrc"))),
127  tracks_(consumes<edm::View<reco::Track>>(conf.getParameter<edm::InputTag>("trackSrc"))),
128  gsfTracks_(consumes<edm::View<reco::Track>>(conf.getParameter<edm::InputTag>("gsfTrackSrc"))),
129  muons_(consumes<reco::MuonCollection>(conf.getParameter<edm::InputTag>("muonSrc"))),
130  srcTrackTime_(useTiming_ ? consumes<edm::ValueMap<float>>(conf.getParameter<edm::InputTag>("trackTimeValueMap"))
131  : edm::EDGetTokenT<edm::ValueMap<float>>()),
132  srcTrackTimeError_(useTiming_
133  ? consumes<edm::ValueMap<float>>(conf.getParameter<edm::InputTag>("trackTimeErrorMap"))
134  : edm::EDGetTokenT<edm::ValueMap<float>>()),
135  srcTrackTimeQuality_(useTimingQuality_
136  ? consumes<edm::ValueMap<float>>(conf.getParameter<edm::InputTag>("trackTimeQualityMap"))
137  : edm::EDGetTokenT<edm::ValueMap<float>>()),
138  srcGsfTrackTime_(useTiming_
139  ? consumes<edm::ValueMap<float>>(conf.getParameter<edm::InputTag>("gsfTrackTimeValueMap"))
140  : edm::EDGetTokenT<edm::ValueMap<float>>()),
141  srcGsfTrackTimeError_(
142  useTiming_ ? consumes<edm::ValueMap<float>>(conf.getParameter<edm::InputTag>("gsfTrackTimeErrorMap"))
143  : edm::EDGetTokenT<edm::ValueMap<float>>()),
144  srcGsfTrackTimeQuality_(
145  useTimingQuality_ ? consumes<edm::ValueMap<float>>(conf.getParameter<edm::InputTag>("gsfTrackTimeQualityMap"))
146  : edm::EDGetTokenT<edm::ValueMap<float>>()),
147  trackingParticles_(consumes<TrackingParticleCollection>(conf.getParameter<edm::InputTag>("trackingParticleSrc"))),
148  simClustersTruth_(consumes<SimClusterCollection>(conf.getParameter<edm::InputTag>("simClusterTruthSrc"))),
149  caloParticles_(consumes<CaloParticleCollection>(conf.getParameter<edm::InputTag>("caloParticlesSrc"))),
150  simClusters_(consumes<std::vector<reco::PFCluster>>(conf.getParameter<edm::InputTag>("simClustersSrc"))),
151  associators_(edm::vector_transform(
152  conf.getParameter<std::vector<edm::InputTag>>("associators"),
153  [this](const edm::InputTag& tag) { return this->consumes<reco::TrackToTrackingParticleAssociator>(tag); })) {
154  produces<reco::PFBlockCollection>();
155  produces<reco::SuperClusterCollection>("perfect");
156  produces<reco::PFCandidateCollection>();
157 }
158 
160  //get associators
161  std::vector<edm::Handle<reco::TrackToTrackingParticleAssociator>> associators;
162  for (const auto& token : associators_) {
163  associators.emplace_back();
164  auto& back = associators.back();
165  evt.getByToken(token, back);
166  }
167 
168  //get PFRecTrack
169  edm::Handle<edm::View<reco::PFRecTrack>> PFTrackCollectionH;
170  evt.getByToken(pfRecTracks_, PFTrackCollectionH);
171  const edm::View<reco::PFRecTrack> PFTrackCollection = *PFTrackCollectionH;
172  std::unordered_set<unsigned> PFTrackToGeneralTrack;
173  for (unsigned i = 0; i < PFTrackCollection.size(); ++i) {
174  const auto ptr = PFTrackCollection.ptrAt(i);
175  PFTrackToGeneralTrack.insert(ptr->trackRef().key());
176  }
177 
178  //get track collections
179  edm::Handle<edm::View<reco::Track>> TrackCollectionH;
180  evt.getByToken(tracks_, TrackCollectionH);
181  const edm::View<reco::Track>& TrackCollection = *TrackCollectionH;
182 
184  evt.getByToken(muons_, muons);
185  std::unordered_set<unsigned> MuonTrackToGeneralTrack;
186  for (auto const& mu : *muons.product()) {
187  reco::TrackRef muTrkRef = mu.track();
188  if (muTrkRef.isNonnull())
189  MuonTrackToGeneralTrack.insert(muTrkRef.key());
190  }
191 
192  // get timing, if enabled
193  edm::Handle<edm::ValueMap<float>> trackTimeH, trackTimeErrH, trackTimeQualH, gsfTrackTimeH, gsfTrackTimeErrH,
194  gsfTrackTimeQualH;
195  if (useTiming_) {
196  evt.getByToken(srcTrackTime_, trackTimeH);
197  evt.getByToken(srcTrackTimeError_, trackTimeErrH);
198  evt.getByToken(srcGsfTrackTime_, gsfTrackTimeH);
199  evt.getByToken(srcGsfTrackTimeError_, gsfTrackTimeErrH);
200 
201  if (useTimingQuality_) {
202  evt.getByToken(srcTrackTimeQuality_, trackTimeQualH);
203  evt.getByToken(srcGsfTrackTimeQuality_, gsfTrackTimeQualH);
204  }
205  }
206 
207  //get tracking particle collections
209  evt.getByToken(trackingParticles_, TPCollectionH);
210  //const TrackingParticleCollection& TPCollection = *TPCollectionH;
211 
212  // grab phony clustering information
213  edm::Handle<SimClusterCollection> SimClustersTruthH;
214  evt.getByToken(simClustersTruth_, SimClustersTruthH);
215  const SimClusterCollection& SimClustersTruth = *SimClustersTruthH;
216 
218  evt.getByToken(caloParticles_, CaloParticlesH);
219  const CaloParticleCollection& CaloParticles = *CaloParticlesH;
220 
222  evt.getByToken(simClusters_, SimClustersH);
223  const std::vector<reco::PFCluster>& SimClusters = *SimClustersH;
224 
225  std::unordered_map<uint64_t, size_t> hashToSimCluster;
226 
227  for (unsigned i = 0; i < SimClustersTruth.size(); ++i) {
228  const auto& simTruth = SimClustersTruth[i];
229  hashToSimCluster[hashSimInfo(simTruth)] = i;
230  }
231 
232  // associate the reco tracks / gsf Tracks
233  std::vector<reco::RecoToSimCollection> associatedTracks, associatedTracksGsf;
234  for (const auto& associator : associators) {
235  associatedTracks.emplace_back(associator->associateRecoToSim(TrackCollectionH, TPCollectionH));
236  //associatedTracksGsf.emplace_back(associator->associateRecoToSim(GsfTrackCollectionH, TPCollectionH));
237  }
238 
239  // make blocks out of calo particles so we can have cluster references
240  // likewise fill out superclusters
241  auto superclusters = std::make_unique<reco::SuperClusterCollection>();
242  auto blocks = std::make_unique<reco::PFBlockCollection>();
243  std::unordered_map<size_t, size_t> simCluster2Block;
244  std::unordered_map<size_t, size_t> simCluster2BlockIndex;
245  std::unordered_multimap<size_t, size_t> caloParticle2SimCluster;
246  std::vector<int> caloParticle2SuperCluster;
247  for (unsigned icp = 0; icp < CaloParticles.size(); ++icp) {
248  blocks->emplace_back();
249  auto& block = blocks->back();
250  const auto& simclusters = CaloParticles[icp].simClusters();
251  double pttot = 0.0;
252  double etot = 0.0;
253  std::vector<size_t> good_simclusters;
254  for (unsigned isc = 0; isc < simclusters.size(); ++isc) {
255  auto simc = simclusters[isc];
256  auto pdgId = std::abs(simc->pdgId());
257  edm::Ref<std::vector<reco::PFCluster>> clusterRef(SimClustersH, simc.key());
258  if (((pdgId == 22 || pdgId == 11) && clusterRef->energy() > neutralEMThreshold_) ||
259  clusterRef->energy() > neutralHADThreshold_) {
260  good_simclusters.push_back(isc);
261  etot += clusterRef->energy();
262  pttot += clusterRef->pt();
263  auto bec = std::make_unique<reco::PFBlockElementCluster>(clusterRef, reco::PFBlockElement::HGCAL);
264  block.addElement(bec.get());
265  simCluster2Block[simc.key()] = icp;
266  simCluster2BlockIndex[simc.key()] = bec->index();
267  caloParticle2SimCluster.emplace(CaloParticles[icp].g4Tracks()[0].trackId(), simc.key());
268  }
269  }
270 
271  auto pdgId = std::abs(CaloParticles[icp].pdgId());
272 
273  caloParticle2SuperCluster.push_back(-1);
274  if ((pdgId == 22 || pdgId == 11) && pttot > superClusterThreshold_) {
275  caloParticle2SuperCluster[icp] = superclusters->size();
276 
277  math::XYZPoint seedpos; // take seed pos as supercluster point
280  for (auto idx : good_simclusters) {
281  edm::Ptr<reco::PFCluster> ptr(SimClustersH, simclusters[idx].key());
282  clusters.push_back(ptr);
283  if (seed.isNull() || seed->energy() < ptr->energy()) {
284  seed = ptr;
285  seedpos = ptr->position();
286  }
287  }
288  superclusters->emplace_back(etot, seedpos, seed, clusters);
289  }
290  }
291 
292  auto blocksHandle = evt.put(std::move(blocks));
293  auto superClustersHandle = evt.put(std::move(superclusters), "perfect");
294 
295  // list tracks so we can mark them as used and/or fight over them
296  std::vector<bool> usedTrack(TrackCollection.size(), false),
297  //usedGsfTrack(GsfTrackCollection.size(),false),
298  usedSimCluster(SimClusters.size(), false);
299 
300  auto candidates = std::make_unique<reco::PFCandidateCollection>();
301  // in good particle flow fashion, start from the tracks and go out
302  for (unsigned itk = 0; itk < TrackCollection.size(); ++itk) {
303  auto tkRef = TrackCollection.refAt(itk);
304  // skip tracks not selected by PF
305  if (PFTrackToGeneralTrack.count(itk) == 0)
306  continue;
307  reco::RecoToSimCollection::const_iterator assoc_tps = associatedTracks.back().end();
308  for (const auto& association : associatedTracks) {
309  assoc_tps = association.find(tkRef);
310  if (assoc_tps != association.end())
311  break;
312  }
313  if (assoc_tps == associatedTracks.back().end())
314  continue;
315  // assured now that we are matched to a set of tracks
316  const auto& matches = assoc_tps->val;
317 
318  const auto absPdgId = std::abs(matches[0].first->pdgId());
319  const auto charge = tkRef->charge();
320  const auto three_mom = tkRef->momentum();
321  constexpr double mpion2 = 0.13957 * 0.13957;
322  double energy = std::sqrt(three_mom.mag2() + mpion2);
323  math::XYZTLorentzVector trk_p4(three_mom.x(), three_mom.y(), three_mom.z(), energy);
324 
326 
327  switch (absPdgId) {
328  case 11:
329  part_type = reco::PFCandidate::e;
330  break;
331  case 13:
332  part_type = reco::PFCandidate::mu;
333  break;
334  default:
335  part_type = reco::PFCandidate::h;
336  }
337 
338  candidates->emplace_back(charge, trk_p4, part_type);
339  auto& candidate = candidates->back();
340 
341  candidate.setTrackRef(tkRef.castTo<reco::TrackRef>());
342 
343  if (useTiming_) {
344  // check if track-mtd match is of sufficient quality
345  const bool assocQuality = useTimingQuality_ ? (*trackTimeQualH)[tkRef] > timingQualityThreshold_ : true;
346  if (assocQuality) {
347  candidate.setTime((*trackTimeH)[tkRef], (*trackTimeErrH)[tkRef]);
348  } else {
349  candidate.setTime(0., -1.);
350  }
351  }
352 
353  // bind to cluster if there is one and try to gather conversions, etc
354  for (const auto& match : matches) {
355  uint64_t hash = hashSimInfo(*(match.first));
356  if (hashToSimCluster.count(hash)) {
357  auto simcHash = hashToSimCluster[hash];
358 
359  if (!usedSimCluster[simcHash]) {
360  if (simCluster2Block.count(simcHash) && simCluster2BlockIndex.count(simcHash)) {
361  size_t block = simCluster2Block.find(simcHash)->second;
362  size_t blockIdx = simCluster2BlockIndex.find(simcHash)->second;
363  edm::Ref<reco::PFBlockCollection> blockRef(blocksHandle, block);
364  candidate.addElementInBlock(blockRef, blockIdx);
365  usedSimCluster[simcHash] = true;
366  }
367  }
368  if (absPdgId == 11) { // collect brems/conv. brems
369  if (simCluster2Block.count(simcHash)) {
370  auto block_index = simCluster2Block.find(simcHash)->second;
371  auto supercluster_index = caloParticle2SuperCluster[block_index];
372  if (supercluster_index != -1) {
373  edm::Ref<reco::PFBlockCollection> blockRef(blocksHandle, block_index);
374  for (const auto& elem : blockRef->elements()) {
375  const auto& ref = elem.clusterRef();
376  if (!usedSimCluster[ref.key()]) {
377  candidate.addElementInBlock(blockRef, elem.index());
378  usedSimCluster[ref.key()] = true;
379  }
380  }
381 
382  //*TODO* cluster time is not reliable at the moment, so just keep time from the track if available
383  }
384  }
385  }
386  }
387  // Now try to include also electrons that have been reconstructed using
388  // the GraphCaloParticles. In particular, recover the cases in which the
389  // tracking particle associated to the CaloParticle has not left any hits
390  // in the calorimeters or, if it had, the cluster has been skipped due to
391  // threshold requirements.
392  if (caloParticle2SimCluster.count(match.first->g4Tracks()[0].trackId())) {
393  auto range = caloParticle2SimCluster.equal_range(match.first->g4Tracks()[0].trackId());
394  for (auto it = range.first; it != range.second; ++it) {
395  if (!usedSimCluster[it->second]) {
396  usedSimCluster[it->second] = true;
397  if (simCluster2Block.find(it->second) != simCluster2Block.end()) {
398  size_t block = simCluster2Block.find(it->second)->second;
399  size_t blockIdx = simCluster2BlockIndex.find(it->second)->second;
400  edm::Ref<reco::PFBlockCollection> blockRef(blocksHandle, block);
401  candidate.addElementInBlock(blockRef, blockIdx);
402  }
403  }
404  }
405  }
406  }
407  usedTrack[tkRef.key()] = true;
408  // remove tracks already used by muons
409  if (MuonTrackToGeneralTrack.count(itk) || absPdgId == 13)
410  candidates->pop_back();
411  }
412 
413  // now loop over the non-collected clusters in blocks
414  // and turn them into neutral hadrons or photons
415  const auto& theblocks = *blocksHandle;
416  for (unsigned ibl = 0; ibl < theblocks.size(); ++ibl) {
417  reco::PFBlockRef blref(blocksHandle, ibl);
418  const auto& elements = theblocks[ibl].elements();
419  for (const auto& elem : elements) {
420  const auto& ref = elem.clusterRef();
421  const auto& simtruth = SimClustersTruth[ref.key()];
423  if (!usedSimCluster[ref.key()]) {
424  auto absPdgId = std::abs(simtruth.pdgId());
425  switch (absPdgId) {
426  case 11:
427  case 22:
428  part_type = reco::PFCandidate::gamma;
429  break;
430  default:
431  part_type = reco::PFCandidate::h0;
432  }
433  const auto three_mom = (ref->position() - math::XYZPoint(0, 0, 0)).unit() * ref->correctedEnergy();
434  math::XYZTLorentzVector clu_p4(three_mom.x(), three_mom.y(), three_mom.z(), ref->correctedEnergy());
435  candidates->emplace_back(0, clu_p4, part_type);
436  auto& candidate = candidates->back();
437  candidate.addElementInBlock(blref, elem.index());
438  }
439  }
440  }
441 
442  evt.put(std::move(candidates));
443 }
const math::XYZPoint & position() const
cluster centroid position
Definition: CaloCluster.h:154
const edm::EDGetTokenT< edm::ValueMap< float > > srcTrackTimeError_
OrphanHandle< PROD > put(std::unique_ptr< PROD > product)
Put a new product.
Definition: Event.h:133
ParticleType
particle types
Definition: PFCandidate.h:44
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:16
std::vector< Track > TrackCollection
collection of Tracks
Definition: TrackFwd.h:14
bool isNonnull() const
Checks for non-null.
Definition: Ref.h:238
void produce(edm::StreamID, edm::Event &, const edm::EventSetup &) const override
bool getByToken(EDGetToken token, Handle< PROD > &result) const
Definition: Event.h:539
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
key_type key() const
Accessor for product key.
Definition: Ref.h:250
std::vector< Muon > MuonCollection
collection of Muon objects
Definition: MuonFwd.h:9
const double neutralHADThreshold_
XYZTLorentzVectorD XYZTLorentzVector
Lorentz vector with cylindrical internal representation using pseudorapidity.
Definition: LorentzVector.h:29
const edm::EDGetTokenT< edm::ValueMap< float > > srcTrackTimeQuality_
const double timingQualityThreshold_
const edm::EDGetTokenT< CaloParticleCollection > caloParticles_
std::tuple< layerClusterToCaloParticle, caloParticleToLayerCluster > association
const std::vector< edm::EDGetTokenT< reco::TrackToTrackingParticleAssociator > > associators_
T sqrt(T t)
Definition: SSEVec.h:19
double energy() const
cluster energy
Definition: PFCluster.h:74
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
const edm::EDGetTokenT< edm::View< reco::Track > > tracks_
const edm::EDGetTokenT< edm::ValueMap< float > > srcGsfTrackTime_
const dim3 blockIdx
Definition: cudaCompat.h:32
Basic3DVector unit() const
const edm::EDGetTokenT< edm::View< reco::PFRecTrack > > pfRecTracks_
const edm::EDGetTokenT< SimClusterCollection > simClustersTruth_
const edm::EDGetTokenT< TrackingParticleCollection > trackingParticles_
unsigned long long uint64_t
Definition: Time.h:13
const bool useTimingQuality_
XYZPointD XYZPoint
point in space with cartesian internal representation
Definition: Point3D.h:12
key_type index() const
Definition: Ref.h:253
SimPFProducer(const edm::ParameterSet &)
void add(std::string const &label, ParameterSetDescription const &psetDescription)
const double superClusterThreshold_
const edm::EDGetTokenT< reco::MuonCollection > muons_
const edm::EDGetTokenT< edm::ValueMap< float > > srcGsfTrackTimeQuality_
std::vector< l1t::PFTrack > PFTrackCollection
Definition: PFTrack.h:84
const edm::EDGetTokenT< edm::ValueMap< float > > srcTrackTime_
fixed size matrix
HLT enums.
std::vector< CaloParticle > CaloParticleCollection
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
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< TrackingParticle > TrackingParticleCollection
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
const edm::EDGetTokenT< edm::View< reco::Track > > gsfTracks_