23 struct KFFittingSmootherParam {
25 : theEstimateCut(conf.getParameter<double>(
"EstimateCut")),
26 theMaxFractionOutliers(conf.getParameter<double>(
"MaxFractionOutliers")),
27 theMaxNumberOfOutliers(conf.getParameter<
int>(
"MaxNumberOfOutliers")),
28 theNoOutliersBeginEnd(conf.getParameter<
bool>(
"NoOutliersBeginEnd")),
29 theMinDof(conf.getParameter<
int>(
"MinDof")),
30 theMinNumberOfHits(conf.getParameter<
int>(
"MinNumberOfHits")),
31 theMinNumberOfHitsHighEta(conf.getParameter<
int>(
"MinNumberOfHitsHighEta")),
32 theHighEtaSwitch(conf.getParameter<double>(
"HighEtaSwitch")),
33 rejectTracksFlag(conf.getParameter<
bool>(
"RejectTracks")),
34 breakTrajWith2ConsecutiveMissing(conf.getParameter<
bool>(
"BreakTrajWith2ConsecutiveMissing")),
35 noInvalidHitsBeginEnd(conf.getParameter<
bool>(
"NoInvalidHitsBeginEnd")) {}
37 double theEstimateCut;
39 float theMaxFractionOutliers;
40 int theMaxNumberOfOutliers;
41 bool theNoOutliersBeginEnd;
44 int theMinNumberOfHits;
45 int theMinNumberOfHitsHighEta;
46 double theHighEtaSwitch;
47 bool rejectTracksFlag;
48 bool breakTrajWith2ConsecutiveMissing;
49 bool noInvalidHitsBeginEnd;
52 class KFFittingSmoother final :
public TrajectoryFitter,
private KFFittingSmootherParam {
54 ~KFFittingSmoother()
override {}
59 : KFFittingSmootherParam(conf), theFitter(aFitter.
clone()), theSmoother(aSmoother.
clone()) {}
63 desc.add<
double>(
"EstimateCut", -1);
64 desc.add<
double>(
"MaxFractionOutliers", 0.3);
65 desc.add<
int>(
"MaxNumberOfOutliers", 3);
66 desc.add<
int>(
"MinDof", 2);
67 desc.add<
bool>(
"NoOutliersBeginEnd",
false);
68 desc.add<
int>(
"MinNumberOfHits", 5);
69 desc.add<
int>(
"MinNumberOfHitsHighEta", 5);
70 desc.add<
double>(
"HighEtaSwitch", 5.0);
71 desc.add<
bool>(
"RejectTracks",
true);
72 desc.add<
bool>(
"BreakTrajWith2ConsecutiveMissing",
true);
73 desc.add<
bool>(
"NoInvalidHitsBeginEnd",
true);
74 desc.add<
double>(
"LogPixelProbabilityCut", 0);
78 double theHighEtaSwitch,
79 int theMinNumberOfHitsHighEta,
80 int theMinNumberOfHits)
const {
82 if (!
t.empty() &&
t.isValid()) {
87 double pt =
t.lastMeasurement().updatedState().freeTrajectoryState()->momentum().perp();
88 double pz =
t.lastMeasurement().updatedState().freeTrajectoryState()->momentum().z();
89 sinhTrajEta2 = (pz * pz) / (
pt *
pt);
91 double myEtaSwitch = sinh(theHighEtaSwitch);
92 const auto thisHitCut =
93 sinhTrajEta2 > (myEtaSwitch * myEtaSwitch) ? theMinNumberOfHitsHighEta : theMinNumberOfHits;
99 const RecHitContainer&
hits,
107 std::unique_ptr<TrajectoryFitter>
clone()
const override {
108 return std::unique_ptr<TrajectoryFitter>(
new KFFittingSmoother(*theFitter, *theSmoother, *
this));
112 theFitter->setHitCloner(hc);
113 theSmoother->setHitCloner(hc);
118 KFFittingSmootherParam
const&
other)
119 : KFFittingSmootherParam(
other), theFitter(aFitter.
clone()), theSmoother(aSmoother.
clone()) {}
122 const auto thisHitCut = getNhitCutValue(fitted, theHighEtaSwitch, theMinNumberOfHitsHighEta, theMinNumberOfHits);
124 if (theEstimateCut > 0) {
127 !fitted.empty() && fitted.foundHits() >= thisHitCut &&
128 (!fitted.lastMeasurement().recHitR().isValid() || (fitted.lastMeasurement().recHitR().det() !=
nullptr &&
129 fitted.lastMeasurement().estimate() > theEstimateCut)))
131 if (fitted.foundHits() < thisHitCut)
134 return theSmoother->trajectory(fitted);
138 const std::unique_ptr<TrajectoryFitter> theFitter;
139 const std::unique_ptr<TrajectorySmoother> theSmoother;
142 static bool checkForNans(
const Trajectory& theTraj);
144 friend class KFFittingSmootherESProducer;
150 #define DPRINT(x) std::cout << x << ": " 151 #define PRINT std::cout 153 #define DPRINT(x) LogTrace(x) 154 #define PRINT LogTrace("") 160 return smoothingStep(theFitter->fitOne(
t,
type));
163 inline bool KFFittingSmoother::checkForNans(
const Trajectory& theTraj) {
167 for (
auto const& tm : vtm) {
170 auto const&
v = tm.updatedState().localParameters().vector();
171 for (
int i = 0;
i < 5; ++
i)
174 if (!tm.updatedState().curvilinearError().posDef())
176 auto const&
m = tm.updatedState().curvilinearError().matrix();
177 for (
int i = 0;
i < 5; ++
i)
178 for (
int j = 0;
j < (
i + 1); ++
j)
194 const RecHitContainer&
hits,
197 LogDebug(
"TrackFitters") <<
"In KFFittingSmoother::fit";
199 print(
"firstPred ", firstPredTsos);
204 RecHitContainer myHits =
hits;
208 Trajectory smoothed = smoothingStep(theFitter->fitOne(aSeed, myHits, firstPredTsos));
213 for (
unsigned int j = 0;
j < myHits.size();
j++) {
214 if (myHits[
j]->det())
215 LogTrace(
"TrackFitters") <<
"hit #:" <<
j + 1 <<
" rawId=" << myHits[
j]->det()->geographicalId().rawId()
216 <<
" validity=" << myHits[
j]->isValid();
218 LogTrace(
"TrackFitters") <<
"hit #:" <<
j + 1 <<
" Hit with no Det information";
222 #if defined(VI_DEBUG) || defined(EDM_ML_DEBUG) 230 const auto thisHitCut =
231 getNhitCutValue(smoothed, theHighEtaSwitch, theMinNumberOfHitsHighEta, theMinNumberOfHits);
233 if (!smoothed.
isValid() || (hasNaN = !checkForNans(smoothed)) || (smoothed.
foundHits() < thisHitCut)) {
235 edm::LogWarning(
"TrackNaN") <<
"Track has NaN or the cov is not pos-definite";
237 LogTrace(
"TrackFitters") <<
"smoothed.foundHits()<thisHitCut";
238 DPRINT(
"TrackFitters") <<
"smoothed invalid => trajectory rejected with nhits/chi2 " << smoothed.
foundHits()
240 if (rejectTracksFlag) {
244 DPRINT(
"TrackFitters") <<
"smoothed invalid => returning orignal trajectory with nhits/chi2 " 251 LogTrace(
"TrackFitters") <<
"dump hits after smoothing";
253 for (Trajectory::DataContainer::iterator it = meas.begin(); it != meas.end(); ++it) {
254 LogTrace(
"TrackFitters") <<
"hit #" << meas.end() - it - 1 <<
" validity=" << it->recHit()->isValid()
255 <<
" det=" << it->recHit()->geographicalId().rawId();
261 DPRINT(
"TrackFitters") <<
"lost hits. before/after: " << myHits.size() <<
'/' << smoothed.
measurements().size()
264 if (theEstimateCut <= 0)
271 unsigned int nbad = 0;
272 unsigned int ind = 0;
273 unsigned int lastValid = smoothed.
measurements().size();
275 if (tm.estimate() > theEstimateCut &&
276 tm.recHitR().det() !=
nullptr 279 if (ind < lastValid && tm.recHitR().det() !=
nullptr && tm.recHitR().isValid())
287 DPRINT(
"TrackFitters") <<
"size/found/outliers list " << smoothed.
measurements().size() <<
'/' 288 << smoothed.
foundHits() <<
' ' << nbad <<
": ";
289 for (
auto i = 0
U;
i < nbad; ++
i)
295 int(nbad) > theMaxNumberOfOutliers ||
float(nbad) > theMaxFractionOutliers *
float(smoothed.
foundHits())) {
296 DPRINT(
"TrackFitters") <<
"smoothed low quality => trajectory with nhits/chi2 " << smoothed.
foundHits() <<
'/' 298 PRINT <<
"try to remove " << lastValid << std::endl;
314 bad[nbad++] = lastValid;
326 auto NHits = myHits.size();
330 for (
auto i = 0
U;
i < nbad; ++
i) {
333 auto removedHit = myHits[
j];
335 smoothedCand[
i] = smoothingStep(theFitter->fitOne(aSeed, myHits, firstPredTsos));
336 myHits[
j] = removedHit;
338 minChi2 = smoothedCand[
i].chiSquared();
344 DPRINT(
"TrackFitters") <<
"New trajectories all invalid" 356 PRINT << tm.recHitR().geographicalId() <<
'/' << tm.estimate() <<
' ';
358 for (
auto const& tm : smoothedCand[loc].measurements())
359 PRINT << tm.recHitR().geographicalId() <<
'/' << tm.estimate() <<
' ';
372 DPRINT(
"TrackFitters") <<
"new trajectory with nhits/chi2 " << smoothed.
foundHits() <<
'/' 376 if (breakTrajWith2ConsecutiveMissing) {
377 unsigned int firstinvalid = myHits.size();
378 for (
unsigned int j = 0;
j < myHits.size() - 1; ++
j) {
381 ((myHits[
j]->geographicalId().rawId() & (~3)) !=
382 (myHits[
j + 1]->geographicalId().rawId() & (~3)))
385 DPRINT(
"TrackFitters") <<
"Found two consecutive missing hits. First invalid: " << firstinvalid <<
"\n";
392 if (firstinvalid != myHits.size()) {
393 myHits.erase(myHits.begin() + firstinvalid, myHits.end());
394 smoothed = smoothingStep(theFitter->fitOne(aSeed, myHits, firstPredTsos));
404 if (noInvalidHitsBeginEnd && !smoothed.
empty()
408 LogTrace(
"TrackFitters") <<
"Last measurement is invalid";
415 LogTrace(
"TrackFitters") <<
"First measurement is in`valid";
418 auto it = meas.begin();
419 for (; it != meas.end(); ++it)
420 if (it->recHitR().isValid())
425 for (
auto itt = it + 1; itt != meas.end(); ++itt)
434 LogTrace(
"TrackFitters") <<
"end: returning smoothed trajectory with chi2=" << smoothed.
chiSquared();
448 const RecHitContainer&
hits,
451 "KFFittingSmoother::fit(TrajectorySeed, <TransientTrackingRecHit>) not implemented");
480 descriptions.
add(
"KFFittingSmoother",
desc);
484 return std::make_unique<KFFittingSmoother>(iRecord.
get(fitToken_), iRecord.
get(smoothToken_), pset_);
auto setWhatProduced(T *iThis, const es::Label &iLabel={})
ConstRecHitPointer::element_type const & recHitR() const
const bool isValid(const Frame &aFrame, const FrameQuality &aQuality, const uint16_t aExpectedPos)
constexpr bool isNotFinite(T x)
uint32_t cc[maxCellsPerHit]
void swap(Association< C > &lhs, Association< C > &rhs)
TrajectoryMeasurement const & lastMeasurement() const
DataContainer const & measurements() const
std::vector< TrajectoryMeasurement > DataContainer
GlobalPoint globalPosition() const
virtual void setHitCloner(TkCloner const *)=0
PropagationDirection const & direction() const
double signedInverseMomentum() const
void print(TMatrixD &m, const char *label=nullptr, bool mathematicaFormat=false)
virtual Trajectory fitOne(const Trajectory &traj, fitType type=standard) const =0
#define DEFINE_FWK_EVENTSETUP_MODULE(type)
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
TrajectorySeed const & seed() const
Access to the seed used to reconstruct the Trajectory.
double transverseCurvature() const
void add(std::string const &label, ParameterSetDescription const &psetDescription)
bool empty() const
True if trajectory has no measurements.
GlobalVector globalMomentum() const
TEveGeoShape * clone(const TEveElement *element, TEveElement *parent)
TrajectoryStateOnSurface const & updatedState() const
TrajectoryMeasurement const & firstMeasurement() const
#define declareDynArray(T, n, x)
Log< level::Warning, false > LogWarning
ProductT const & get(ESGetToken< ProductT, DepRecordT > const &iToken) const