CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
MkFitOutputConverter.cc
Go to the documentation of this file.
2 
7 
15 
19 
22 
31 
38 
39 // mkFit indludes
40 #include "LayerNumberConverter.h"
41 #include "Track.h"
42 #include "mkFit/HitStructures.h"
43 
44 namespace {
45  template <typename T>
46  bool isBarrel(T subdet) {
47  return subdet == PixelSubdetector::PixelBarrel || subdet == StripSubdetector::TIB ||
48  subdet == StripSubdetector::TOB;
49  }
50 
51  template <typename T>
52  bool isEndcap(T subdet) {
53  return subdet == PixelSubdetector::PixelEndcap || subdet == StripSubdetector::TID ||
54  subdet == StripSubdetector::TEC;
55  }
56 } // namespace
57 
59 public:
61  ~MkFitOutputConverter() override = default;
62 
63  static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
64 
65 private:
66  void produce(edm::StreamID, edm::Event& iEvent, const edm::EventSetup& iSetup) const override;
67 
69  const mkfit::EventOfHits& eventOfHits,
70  const MkFitClusterIndexToHit& pixelClusterIndexToHit,
71  const MkFitClusterIndexToHit& stripClusterIndexToHit,
73  const MagneticField& mf,
76  const TkClonerImpl& hitCloner,
77  const std::vector<const DetLayer*>& detLayers,
78  const mkfit::TrackVec& mkFitSeeds) const;
79 
80  std::pair<TrajectoryStateOnSurface, const GeomDet*> backwardFit(const FreeTrajectoryState& fts,
82  const Propagator& propagatorAlong,
83  const Propagator& propagatorOpposite,
84  const TkClonerImpl& hitCloner,
85  bool lastHitWasInvalid,
86  bool lastHitWasChanged) const;
87 
88  std::pair<TrajectoryStateOnSurface, const GeomDet*> convertInnermostState(const FreeTrajectoryState& fts,
90  const Propagator& propagatorAlong,
91  const Propagator& propagatorOpposite) const;
92 
109 };
110 
112  : eventOfHitsToken_{consumes<MkFitEventOfHits>(iConfig.getParameter<edm::InputTag>("mkFitEventOfHits"))},
113  pixelClusterIndexToHitToken_{consumes(iConfig.getParameter<edm::InputTag>("mkFitPixelHits"))},
114  stripClusterIndexToHitToken_{consumes(iConfig.getParameter<edm::InputTag>("mkFitStripHits"))},
115  mkfitSeedToken_{consumes<MkFitSeedWrapper>(iConfig.getParameter<edm::InputTag>("mkFitSeeds"))},
116  tracksToken_{consumes<MkFitOutputWrapper>(iConfig.getParameter<edm::InputTag>("tracks"))},
117  seedToken_{consumes<edm::View<TrajectorySeed>>(iConfig.getParameter<edm::InputTag>("seeds"))},
118  propagatorAlongToken_{
119  esConsumes<Propagator, TrackingComponentsRecord>(iConfig.getParameter<edm::ESInputTag>("propagatorAlong"))},
120  propagatorOppositeToken_{esConsumes<Propagator, TrackingComponentsRecord>(
121  iConfig.getParameter<edm::ESInputTag>("propagatorOpposite"))},
122  mfToken_{esConsumes<MagneticField, IdealMagneticFieldRecord>()},
123  ttrhBuilderToken_{esConsumes<TransientTrackingRecHitBuilder, TransientRecHitRecord>(
124  iConfig.getParameter<edm::ESInputTag>("ttrhBuilder"))},
125  mkFitGeomToken_{esConsumes<MkFitGeometry, TrackerRecoGeometryRecord>()},
126  putTrackCandidateToken_{produces<TrackCandidateCollection>()},
127  putSeedStopInfoToken_{produces<std::vector<SeedStopInfo>>()} {}
128 
131 
132  desc.add("mkFitEventOfHits", edm::InputTag{"mkFitEventOfHits"});
133  desc.add("mkFitPixelHits", edm::InputTag{"mkFitSiPixelHits"});
134  desc.add("mkFitStripHits", edm::InputTag{"mkFitSiStripHits"});
135  desc.add("mkFitSeeds", edm::InputTag{"mkFitSeedConverter"});
136  desc.add("tracks", edm::InputTag{"mkFitProducer"});
137  desc.add("seeds", edm::InputTag{"initialStepSeeds"});
138  desc.add("ttrhBuilder", edm::ESInputTag{"", "WithTrackAngle"});
139  desc.add("propagatorAlong", edm::ESInputTag{"", "PropagatorWithMaterial"});
140  desc.add("propagatorOpposite", edm::ESInputTag{"", "PropagatorWithMaterialOpposite"});
141 
142  descriptions.addWithDefaultLabel(desc);
143 }
144 
146  const auto& seeds = iEvent.get(seedToken_);
147  const auto& mkfitSeeds = iEvent.get(mkfitSeedToken_);
148 
149  const auto& ttrhBuilder = iSetup.getData(ttrhBuilderToken_);
150  const auto* tkBuilder = dynamic_cast<TkTransientTrackingRecHitBuilder const*>(&ttrhBuilder);
151  if (!tkBuilder) {
152  throw cms::Exception("LogicError") << "TTRHBuilder must be of type TkTransientTrackingRecHitBuilder";
153  }
154  const auto& mkFitGeom = iSetup.getData(mkFitGeomToken_);
155 
156  // Convert mkfit presentation back to CMSSW
159  iEvent.get(eventOfHitsToken_).get(),
162  seeds,
163  iSetup.getData(mfToken_),
166  tkBuilder->cloner(),
167  mkFitGeom.detLayers(),
168  mkfitSeeds.seeds()));
169 
170  // TODO: SeedStopInfo is currently unfilled
171  iEvent.emplace(putSeedStopInfoToken_, seeds.size());
172 }
173 
175  const mkfit::EventOfHits& eventOfHits,
176  const MkFitClusterIndexToHit& pixelClusterIndexToHit,
177  const MkFitClusterIndexToHit& stripClusterIndexToHit,
179  const MagneticField& mf,
182  const TkClonerImpl& hitCloner,
183  const std::vector<const DetLayer*>& detLayers,
184  const mkfit::TrackVec& mkFitSeeds) const {
186  const auto& candidates = mkFitOutput.tracks();
187  output.reserve(candidates.size());
188 
189  LogTrace("MkFitOutputConverter") << "Number of candidates " << candidates.size();
190 
191  int candIndex = -1;
192  for (const auto& cand : candidates) {
193  ++candIndex;
194  LogTrace("MkFitOutputConverter") << "Candidate " << candIndex << " pT " << cand.pT() << " eta " << cand.momEta()
195  << " phi " << cand.momPhi() << " chi2 " << cand.chi2();
196 
197  // hits
199  // nTotalHits() gives sum of valid hits (nFoundHits()) and invalid/missing hits.
200  const int nhits = cand.nTotalHits();
201  bool lastHitInvalid = false;
202  for (int i = 0; i < nhits; ++i) {
203  const auto& hitOnTrack = cand.getHitOnTrack(i);
204  LogTrace("MkFitOutputConverter") << " hit on layer " << hitOnTrack.layer << " index " << hitOnTrack.index;
205  if (hitOnTrack.index < 0) {
206  // See index-desc.txt file in mkFit for description of negative values
207  //
208  // In order to use the regular InvalidTrackingRecHit I'd need
209  // a GeomDet (and "unfortunately" that is needed in
210  // TrackProducer).
211  //
212  // I guess we could take the track state and propagate it to
213  // each layer to find the actual module the track crosses, and
214  // check whether it is active or not to be able to mark
215  // inactive hits
216  const auto* detLayer = detLayers.at(hitOnTrack.layer);
217  if (detLayer == nullptr) {
218  throw cms::Exception("LogicError") << "DetLayer for layer index " << hitOnTrack.layer << " is null!";
219  }
220  // In principle an InvalidTrackingRecHitNoDet could be
221  // inserted here, but it seems that it is best to deal with
222  // them in the TrackProducer.
223  lastHitInvalid = true;
224  } else {
225  auto const isPixel = eventOfHits[hitOnTrack.layer].is_pix_lyr();
226  auto const& hits = isPixel ? pixelClusterIndexToHit.hits() : stripClusterIndexToHit.hits();
227 
228  auto const& thit = static_cast<BaseTrackerRecHit const&>(*hits[hitOnTrack.index]);
229  if (thit.firstClusterRef().isPixel() || thit.detUnit()->type().isEndcap()) {
230  recHits.push_back(hits[hitOnTrack.index]->clone());
231  } else {
232  recHits.push_back(std::make_unique<SiStripRecHit1D>(
233  thit.localPosition(),
234  LocalError(thit.localPositionError().xx(), 0.f, std::numeric_limits<float>::max()),
235  *thit.det(),
236  thit.firstClusterRef()));
237  }
238  LogTrace("MkFitOutputConverter") << " pos " << recHits.back().globalPosition().x() << " "
239  << recHits.back().globalPosition().y() << " "
240  << recHits.back().globalPosition().z() << " mag2 "
241  << recHits.back().globalPosition().mag2() << " detid "
242  << recHits.back().geographicalId().rawId() << " cluster " << hitOnTrack.index;
243  lastHitInvalid = false;
244  }
245  }
246 
247  const auto lastHitId = recHits.back().geographicalId();
248 
249  // MkFit hits are *not* in the order of propagation, sort by 3D radius for now (as we don't have loopers)
250  // TODO: Improve the sorting (extract keys? maybe even bubble sort would work well as the hits are almost in the correct order)
251  recHits.sort([](const auto& a, const auto& b) {
252  const auto asub = a.geographicalId().subdetId();
253  const auto bsub = b.geographicalId().subdetId();
254  if (asub != bsub) {
255  // Subdetector order (BPix, FPix, TIB, TID, TOB, TEC) corresponds also the navigation
256  return asub < bsub;
257  }
258 
259  const auto& apos = a.globalPosition();
260  const auto& bpos = b.globalPosition();
261 
262  if (isBarrel(asub)) {
263  return apos.perp2() < bpos.perp2();
264  }
265  return std::abs(apos.z()) < std::abs(bpos.z());
266  });
267 
268  const bool lastHitChanged = (recHits.back().geographicalId() != lastHitId); // TODO: make use of the bools
269 
270  // seed
271  const auto seedIndex = cand.label();
272  LogTrace("MkFitOutputConverter") << " from seed " << seedIndex << " seed hits";
273 
274  // state
275  auto state = cand.state(); // copy because have to modify
276  state.convertFromCCSToGlbCurvilinear();
277  const auto& param = state.parameters;
278  const auto& err = state.errors;
280  for (int i = 0; i < 5; ++i) {
281  for (int j = i; j < 5; ++j) {
282  cov[i][j] = err.At(i, j);
283  }
284  }
285 
286  auto fts = FreeTrajectoryState(
288  GlobalPoint(param[0], param[1], param[2]), GlobalVector(param[3], param[4], param[5]), state.charge, &mf),
290  if (!fts.curvilinearError().posDef()) {
291  edm::LogInfo("MkFitOutputConverter") << "Curvilinear error not pos-def\n"
292  << fts.curvilinearError().matrix() << "\ncandidate ignored";
293  continue;
294  }
295 
296  auto tsosDet =
297  mkFitOutput.propagatedToFirstLayer()
298  ? convertInnermostState(fts, recHits, propagatorAlong, propagatorOpposite)
299  : backwardFit(fts, recHits, propagatorAlong, propagatorOpposite, hitCloner, lastHitInvalid, lastHitChanged);
300  if (!tsosDet.first.isValid()) {
301  edm::LogInfo("MkFitOutputConverter")
302  << "Backward fit of candidate " << candIndex << " failed, ignoring the candidate";
303  continue;
304  }
305 
306  // convert to persistent, from CkfTrackCandidateMakerBase
307  auto pstate = trajectoryStateTransform::persistentState(tsosDet.first, tsosDet.second->geographicalId().rawId());
308 
309  output.emplace_back(
310  recHits,
311  seeds.at(seedIndex),
312  pstate,
313  seeds.refAt(seedIndex),
314  0, // mkFit does not produce loopers, so set nLoops=0
315  static_cast<uint8_t>(StopReason::UNINITIALIZED) // TODO: ignore details of stopping reason as well for now
316  );
317  }
318  return output;
319 }
320 
321 std::pair<TrajectoryStateOnSurface, const GeomDet*> MkFitOutputConverter::backwardFit(
322  const FreeTrajectoryState& fts,
323  const edm::OwnVector<TrackingRecHit>& hits,
326  const TkClonerImpl& hitCloner,
327  bool lastHitWasInvalid,
328  bool lastHitWasChanged) const {
329  // First filter valid hits as in TransientInitialStateEstimator
331 
332  for (int i = hits.size() - 1; i >= 0; --i) {
333  if (hits[i].det()) {
334  // TransientTrackingRecHit::ConstRecHitContainer has shared_ptr,
335  // and it is passed to backFitter below so it is really needed
336  // to keep the interface. Since we keep the ownership in hits,
337  // let's disable the deleter.
338  firstHits.emplace_back(&(hits[i]), edm::do_nothing_deleter{});
339  }
340  }
341 
342  // Then propagate along to the surface of the last hit to get a TSOS
343  const auto& lastHitSurface = firstHits.front()->det()->surface();
344 
345  const Propagator* tryFirst = &propagatorAlong;
346  const Propagator* trySecond = &propagatorOpposite;
347  if (lastHitWasInvalid || lastHitWasChanged) {
348  LogTrace("MkFitOutputConverter") << "Propagating first opposite, then along, because lastHitWasInvalid? "
349  << lastHitWasInvalid << " or lastHitWasChanged? " << lastHitWasChanged;
350  std::swap(tryFirst, trySecond);
351  } else {
352  const auto lastHitSubdet = firstHits.front()->geographicalId().subdetId();
353  const auto& surfacePos = lastHitSurface.position();
354  const auto& lastHitPos = firstHits.front()->globalPosition();
355  bool doSwitch = false;
356  if (isBarrel(lastHitSubdet)) {
357  doSwitch = (surfacePos.perp2() < lastHitPos.perp2());
358  } else {
359  doSwitch = (surfacePos.z() < lastHitPos.z());
360  }
361  if (doSwitch) {
362  LogTrace("MkFitOutputConverter")
363  << "Propagating first opposite, then along, because surface is inner than the hit; surface perp2 "
364  << surfacePos.perp() << " hit " << lastHitPos.perp2() << " surface z " << surfacePos.z() << " hit "
365  << lastHitPos.z();
366 
367  std::swap(tryFirst, trySecond);
368  }
369  }
370 
371  auto tsosDouble = tryFirst->propagateWithPath(fts, lastHitSurface);
372  if (!tsosDouble.first.isValid()) {
373  LogDebug("MkFitOutputConverter") << "Propagating to startingState failed, trying in another direction next";
374  tsosDouble = trySecond->propagateWithPath(fts, lastHitSurface);
375  }
376  auto& startingState = tsosDouble.first;
377 
378  if (!startingState.isValid()) {
379  edm::LogWarning("MkFitOutputConverter")
380  << "startingState is not valid, FTS was\n"
381  << fts << " last hit surface surface:"
382  << "\n position " << lastHitSurface.position() << "\n phiSpan " << lastHitSurface.phiSpan().first << ","
383  << lastHitSurface.phiSpan().first << "\n rSpan " << lastHitSurface.rSpan().first << ","
384  << lastHitSurface.rSpan().first << "\n zSpan " << lastHitSurface.zSpan().first << ","
385  << lastHitSurface.zSpan().first;
386  return std::pair<TrajectoryStateOnSurface, const GeomDet*>();
387  }
388 
389  // Then return back to the logic from TransientInitialStateEstimator
390  startingState.rescaleError(100.);
391 
392  // avoid cloning
393  KFUpdator const aKFUpdator;
394  Chi2MeasurementEstimator const aChi2MeasurementEstimator(100., 3);
395  KFTrajectoryFitter backFitter(
396  &propagatorAlong, &aKFUpdator, &aChi2MeasurementEstimator, firstHits.size(), nullptr, &hitCloner);
397 
398  // assume for now that the propagation in mkfit always alongMomentum
399  PropagationDirection backFitDirection = oppositeToMomentum;
400 
401  // only direction matters in this context
403 
404  // ignore loopers for now
405  Trajectory fitres = backFitter.fitOne(fakeSeed, firstHits, startingState, TrajectoryFitter::standard);
406 
407  LogDebug("MkFitOutputConverter") << "using a backward fit of :" << firstHits.size() << " hits, starting from:\n"
408  << startingState << " to get the estimate of the initial state of the track.";
409 
410  if (!fitres.isValid()) {
411  edm::LogWarning("MkFitOutputConverter") << "FitTester: first hits fit failed";
412  return std::pair<TrajectoryStateOnSurface, const GeomDet*>();
413  }
414 
415  TrajectoryMeasurement const& firstMeas = fitres.lastMeasurement();
416 
417  // magnetic field can be different!
418  TrajectoryStateOnSurface firstState(firstMeas.updatedState().localParameters(),
419  firstMeas.updatedState().localError(),
420  firstMeas.updatedState().surface(),
421  propagatorAlong.magneticField());
422 
423  firstState.rescaleError(100.);
424 
425  LogDebug("MkFitOutputConverter") << "the initial state is found to be:\n:" << firstState
426  << "\n it's field pointer is: " << firstState.magneticField()
427  << "\n the pointer from the state of the back fit was: "
428  << firstMeas.updatedState().magneticField();
429 
430  return std::make_pair(firstState, firstMeas.recHit()->det());
431 }
432 
433 std::pair<TrajectoryStateOnSurface, const GeomDet*> MkFitOutputConverter::convertInnermostState(
434  const FreeTrajectoryState& fts,
435  const edm::OwnVector<TrackingRecHit>& hits,
437  const Propagator& propagatorOpposite) const {
438  auto det = hits[0].det();
439  if (det == nullptr) {
440  throw cms::Exception("LogicError") << "Got nullptr from the first hit det()";
441  }
442 
443  const auto& firstHitSurface = det->surface();
444 
445  auto tsosDouble = propagatorAlong.propagateWithPath(fts, firstHitSurface);
446  if (!tsosDouble.first.isValid()) {
447  LogDebug("MkFitOutputConverter") << "Propagating to startingState along momentum failed, trying opposite next";
448  tsosDouble = propagatorOpposite.propagateWithPath(fts, firstHitSurface);
449  }
450 
451  return std::make_pair(tsosDouble.first, det);
452 }
453 
static constexpr auto TEC
const edm::EDGetTokenT< MkFitClusterIndexToHit > pixelClusterIndexToHitToken_
void addWithDefaultLabel(ParameterSetDescription const &psetDescription)
T mag2() const
Definition: PV3DBase.h:63
reference back()
Definition: OwnVector.h:431
std::pair< TrajectoryStateOnSurface, const GeomDet * > backwardFit(const FreeTrajectoryState &fts, const edm::OwnVector< TrackingRecHit > &hits, const Propagator &propagatorAlong, const Propagator &propagatorOpposite, const TkClonerImpl &hitCloner, bool lastHitWasInvalid, bool lastHitWasChanged) const
ConstRecHitPointer const & recHit() const
const edm::ESGetToken< MkFitGeometry, TrackerRecoGeometryRecord > mkFitGeomToken_
const edm::ESGetToken< Propagator, TrackingComponentsRecord > propagatorOppositeToken_
const LocalTrajectoryParameters & localParameters() const
tuple propagatorAlong
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:16
std::vector< TrackCandidate > TrackCandidateCollection
size_type size() const
Definition: OwnVector.h:300
Global3DPoint GlobalPoint
Definition: GlobalPoint.h:10
constexpr uint32_t rawId() const
get the raw id
Definition: DetId.h:57
PTrajectoryStateOnDet persistentState(const TrajectoryStateOnSurface &ts, unsigned int detid)
T y() const
Definition: PV3DBase.h:60
void produce(edm::StreamID, edm::Event &iEvent, const edm::EventSetup &iSetup) const override
PropagationDirection
const edm::EDGetTokenT< MkFitOutputWrapper > tracksToken_
virtual GlobalPoint globalPosition() const
const MagneticField * magneticField() const
#define LogTrace(id)
RefToBase< value_type > refAt(size_type i) const
bool getData(T &iHolder) const
Definition: EventSetup.h:128
const edm::EDPutTokenT< std::vector< SeedStopInfo > > putSeedStopInfoToken_
void push_back(D *&d)
Definition: OwnVector.h:326
int iEvent
Definition: GenABIO.cc:224
const SurfaceType & surface() const
void swap(edm::DataFrameContainer &lhs, edm::DataFrameContainer &rhs)
const edm::ESGetToken< MagneticField, IdealMagneticFieldRecord > mfToken_
~MkFitOutputConverter() override=default
TrajectoryMeasurement const & lastMeasurement() const
Definition: Trajectory.h:150
bool propagatedToFirstLayer() const
T z() const
Definition: PV3DBase.h:61
MkFitOutputConverter(edm::ParameterSet const &iConfig)
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
TrackCandidateCollection convertCandidates(const MkFitOutputWrapper &mkFitOutput, const mkfit::EventOfHits &eventOfHits, const MkFitClusterIndexToHit &pixelClusterIndexToHit, const MkFitClusterIndexToHit &stripClusterIndexToHit, const edm::View< TrajectorySeed > &seeds, const MagneticField &mf, const Propagator &propagatorAlong, const Propagator &propagatorOpposite, const TkClonerImpl &hitCloner, const std::vector< const DetLayer * > &detLayers, const mkfit::TrackVec &mkFitSeeds) const
const edm::EDGetTokenT< edm::View< TrajectorySeed > > seedToken_
bool get(ProductID const &oid, Handle< PROD > &result) const
Definition: Event.h:346
const edm::EDPutTokenT< TrackCandidateCollection > putTrackCandidateToken_
const LocalTrajectoryError & localError() const
static constexpr auto TOB
ParameterDescriptionBase * add(U const &iLabel, T const &value)
virtual std::pair< TrajectoryStateOnSurface, double > propagateWithPath(const FreeTrajectoryState &, const Surface &) const final
Definition: Propagator.cc:10
const std::string ttrhBuilderName_
bool isEndcap(GeomDetEnumerators::SubDetector m)
const edm::EDGetTokenT< MkFitSeedWrapper > mkfitSeedToken_
std::vector< ConstRecHitPointer > ConstRecHitContainer
Log< level::Info, false > LogInfo
GlobalPoint position() const
std::vector< Track > TrackVec
bool isValid() const
Definition: Trajectory.h:257
static constexpr auto TIB
OrphanHandle< PROD > emplace(EDPutTokenT< PROD > token, Args &&...args)
puts a new product
Definition: Event.h:433
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
void sort(S s)
Definition: OwnVector.h:502
T getParameter(std::string const &) const
Definition: ParameterSet.h:303
ROOT::Math::SMatrix< double, 5, 5, ROOT::Math::MatRepSym< double, 5 > > AlgebraicSymMatrix55
double b
Definition: hdecay.h:118
virtual const MagneticField * magneticField() const =0
std::pair< TrajectoryStateOnSurface, const GeomDet * > convertInnermostState(const FreeTrajectoryState &fts, const edm::OwnVector< TrackingRecHit > &hits, const Propagator &propagatorAlong, const Propagator &propagatorOpposite) const
tuple propagatorOpposite
const edm::EDGetTokenT< MkFitEventOfHits > eventOfHitsToken_
double a
Definition: hdecay.h:119
const std::string propagatorOppositeName_
bool isPixel(HitType hitType)
const_reference at(size_type pos) const
const std::string propagatorAlongName_
TrajectoryStateOnSurface const & updatedState() const
const edm::ESGetToken< Propagator, TrackingComponentsRecord > propagatorAlongToken_
std::vector< TrackingRecHit const * > & hits()
DetId geographicalId() const
Log< level::Warning, false > LogWarning
mkfit::TrackVec const & tracks() const
long double T
T x() const
Definition: PV3DBase.h:59
static constexpr auto TID
Global3DVector GlobalVector
Definition: GlobalVector.h:10
const edm::ESGetToken< TransientTrackingRecHitBuilder, TransientRecHitRecord > ttrhBuilderToken_
#define LogDebug(id)
const edm::EDGetTokenT< MkFitClusterIndexToHit > stripClusterIndexToHitToken_