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(icp,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  auto blocksHandle = evt.put(std::move(blocks));
249  auto superClustersHandle = evt.put(std::move(superclusters),"perfect");
250 
251  // list tracks so we can mark them as used and/or fight over them
252  std::vector<bool> usedTrack(TrackCollection.size(),false),
253  //usedGsfTrack(GsfTrackCollection.size(),false),
254  usedSimCluster(SimClusters.size(),false);
255 
256  auto candidates = std::make_unique<reco::PFCandidateCollection>();
257  // in good particle flow fashion, start from the tracks and go out
258  for( unsigned itk = 0; itk < TrackCollection.size(); ++itk ) {
259  auto tkRef = TrackCollection.refAt(itk);
260  // skip tracks not selected by PF
261  if( PFTrackToGeneralTrack.count(itk) == 0 ) continue;
262  reco::RecoToSimCollection::const_iterator assoc_tps = associatedTracks.back().end();
263  for( const auto& association : associatedTracks ) {
264  assoc_tps = association.find(tkRef);
265  if( assoc_tps != association.end() ) break;
266  }
267  if( assoc_tps == associatedTracks.back().end() ) continue;
268  // assured now that we are matched to a set of tracks
269  const auto& matches = assoc_tps->val;
270 
271  const auto absPdgId = std::abs(matches[0].first->pdgId());
272  const auto charge = tkRef->charge();
273  const auto three_mom = tkRef->momentum();
274  constexpr double mpion2 = 0.13957*0.13957;
275  double energy = std::sqrt(three_mom.mag2() + mpion2);
276  math::XYZTLorentzVector trk_p4(three_mom.x(),three_mom.y(),three_mom.z(),energy);
277 
279 
280  switch( absPdgId ) {
281  case 11:
282  part_type = reco::PFCandidate::e;
283  break;
284  case 13:
285  part_type = reco::PFCandidate::mu;
286  break;
287  default:
288  part_type = reco::PFCandidate::h;
289  }
290 
291  candidates->emplace_back(charge, trk_p4, part_type);
292  auto& candidate = candidates->back();
293 
294  candidate.setTrackRef(tkRef.castTo<reco::TrackRef>());
295 
296  if (useTiming_) candidate.setTime( (*trackTimeH)[tkRef], (*trackTimeErrH)[tkRef] );
297 
298  // bind to cluster if there is one and try to gather conversions, etc
299  for( const auto& match : matches ) {
300  uint64_t hash = hashSimInfo(*(match.first));
301  if( hashToSimCluster.count(hash) ) {
302  auto simcHash = hashToSimCluster[hash];
303 
304  if( !usedSimCluster[simcHash] ) {
305  if( simCluster2Block.count(simcHash) &&
306  simCluster2BlockIndex.count(simcHash) ) {
307  size_t block = simCluster2Block.find(simcHash)->second;
308  size_t blockIdx = simCluster2BlockIndex.find(simcHash)->second;
309  edm::Ref<reco::PFBlockCollection> blockRef(blocksHandle,block);
310  candidate.addElementInBlock(blockRef,blockIdx);
311  usedSimCluster[simcHash] = true;
312  }
313  }
314  if( absPdgId == 11 ) { // collect brems/conv. brems
315  if( simCluster2Block.count(simcHash) ) {
316  auto block_index = simCluster2Block.find(simcHash)->second;
317  auto supercluster_index = caloParticle2SuperCluster[ block_index ];
318  if( supercluster_index != -1 ) {
319  edm::Ref<reco::PFBlockCollection> blockRef(blocksHandle,block_index);
320  for( const auto& elem : blockRef->elements() ) {
321  const auto& ref = elem.clusterRef();
322  if( !usedSimCluster[ref.key()] ) {
323  candidate.addElementInBlock(blockRef,elem.index());
324  usedSimCluster[ref.key()] = true;
325  }
326  }
327 
328  //*TODO* cluster time is not reliable at the moment, so just keep time from the track if available
329 
330  }
331  }
332  }
333  }
334  }
335  usedTrack[tkRef.key()] = true;
336  // remove tracks already used by muons
337  if( MuonTrackToGeneralTrack.count(itk) || absPdgId == 13)
338  candidates->pop_back();
339  }
340 
341  // now loop over the non-collected clusters in blocks
342  // and turn them into neutral hadrons or photons
343  const auto& theblocks = *blocksHandle;
344  for( unsigned ibl = 0; ibl < theblocks.size(); ++ibl ) {
345  reco::PFBlockRef blref(blocksHandle,ibl);
346  const auto& elements = theblocks[ibl].elements();
347  for( const auto& elem : elements ) {
348  const auto& ref = elem.clusterRef();
349  const auto& simtruth = SimClustersTruth[ref.key()];
351  if( !usedSimCluster[ref.key()] ) {
352  auto absPdgId = std::abs(simtruth.pdgId());
353  switch( absPdgId ) {
354  case 11:
355  case 22:
356  part_type = reco::PFCandidate::gamma;
357  break;
358  default:
359  part_type = reco::PFCandidate::h0;
360  }
361  const auto three_mom = (ref->position() - math::XYZPoint(0,0,0)).unit()*ref->energy();
362  math::XYZTLorentzVector clu_p4(three_mom.x(),three_mom.y(),three_mom.z(),ref->energy());
363  candidates->emplace_back(0, clu_p4, part_type);
364  auto& candidate = candidates->back();
365  candidate.addElementInBlock(blref,elem.index());
366  candidate.setTime(ref->time(), ref->timeError());
367  }
368  }
369  }
370 
371  evt.put(std::move(candidates));
372 }
const math::XYZPoint & position() const
cluster centroid position
Definition: CaloCluster.h:129
const edm::EDGetTokenT< edm::ValueMap< float > > srcTrackTimeError_
OrphanHandle< PROD > put(std::unique_ptr< PROD > product)
Put a new product.
Definition: Event.h:136
ParticleType
particle types
Definition: PFCandidate.h:45
bool isNonnull() const
Checks for non-null.
Definition: Ref.h:253
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:519
Ptr< value_type > ptrAt(size_type i) const
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:17
void push_back(Ptr< T > const &iPtr)
Definition: PtrVector.h:140
std::vector< Track > TrackCollection
collection of Tracks
Definition: TrackFwd.h:14
size_type size() const
key_type key() const
Accessor for product key.
Definition: Ref.h:265
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
~SimPFProducer() override
#define constexpr
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
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:18
const edm::EDGetTokenT< TrackingParticleCollection > trackingParticles_
T const * product() const
Definition: Handle.h:81
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:510
const edm::EDGetTokenT< edm::View< reco::Track > > gsfTracks_