ATLAS Offline Software
FitProcedure.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3 */
4 
6 // class FitProcedure
7 // Basic iterative least square fit procedure producing a fitted Track
8 //
9 // execute and constructTrack methods allow use from standard ITrackFitter
10 // and iPatRec specific Algtools.
11 // This class is kept transient rather than a tool as there are many state
12 // variables.
13 //
14 // for clarity (i.e. to avoid an overly long class) the inner loop over
15 // measurements is performed by MeasurementProcessor
16 //
18 
20 
21 #include <cmath>
22 #include <iomanip>
23 #include <memory>
24 #include <utility> //std::as_const
25 
26 #include "CLHEP/GenericFunctions/CumulativeChiSquare.hh"
27 #include "GaudiKernel/MsgStream.h"
28 #include "GaudiKernel/SystemOfUnits.h"
38 #include "TrkTrack/Track.h"
39 #include "TrkTrack/TrackInfo.h"
44 
45 namespace Trk {
46 
47 // constructor
48 FitProcedure::FitProcedure(bool constrainedAlignmentEffects, bool extendedDebug,
49  bool lineFit,
50  ToolHandle<IIntersector>& rungeKuttaIntersector,
51  ToolHandle<IIntersector>& solenoidalIntersector,
52  ToolHandle<IIntersector>& straightLineIntersector,
53  const ToolHandle<IPropagator>& stepPropagator,
54  const Volume* indetVolume, int maxIterations,
55  int useStepPropagator)
56  : m_constrainedAlignmentEffects(constrainedAlignmentEffects),
57  m_extendedDebug(extendedDebug),
58  m_extremeOneOverP(1. / (10. * Gaudi::Units::TeV)),
59  m_indetVolume(indetVolume),
60  m_largeRadius(1000. * Gaudi::Units::mm),
61  m_lineFit(lineFit),
62  m_maxIter(maxIterations),
63  m_minIter(0),
64  m_minPt(0.05 * Gaudi::Units::GeV),
65  m_rungeKuttaIntersector(rungeKuttaIntersector),
66  m_solenoidalIntersector(solenoidalIntersector),
67  m_straightLineIntersector(straightLineIntersector),
68  m_stepPropagator(stepPropagator),
69  m_useStepPropagator(useStepPropagator) {}
70 
71 // destructor
72 
74  cache.fitMatrices->releaseMemory();
75 }
76 
78  FitProcedure::Cache& cache,
79  const std::vector<FitMeasurement*>& measurements, FitParameters& parameters,
80  const TrackInfo& trackInfo,
81  const Trk::TrackStates* leadingTSOS) {
82  // debug
83  if (cache.debug) {
84  reportQuality(cache, measurements, parameters);
85  }
86 
87  // NB keep first and last measurements distinct i.e. separate TSOS (no
88  // scatterers etc) NB trackParameters outwards from TSOS i.e. always last
89  // FitMeas on surface
90 
91  // create vector of TSOS - reserve upper limit for size (+1 as starts with
92  // perigee)
93  auto trackStateOnSurfaces = std::make_unique<Trk::TrackStates>();
94  unsigned size = measurements.size() + 1;
95  if (leadingTSOS)
96  size += leadingTSOS->size();
97  trackStateOnSurfaces->reserve(size);
98  std::unique_ptr<AlignmentEffectsOnTrack> alignmentEffects{};
99  const FitMeasurement* fitMeasurement = measurements.front();
100  const FitQualityOnSurface fitQoS{};
101  std::unique_ptr<MaterialEffectsBase> materialEffects{};
102  std::unique_ptr<MeasurementBase> measurementBase{};
103  const Surface* surface = nullptr;
104  std::unique_ptr<TrackParameters> trackParameters{};
105  std::bitset<TrackStateOnSurface::NumberOfTrackStateOnSurfaceTypes>
106  defaultPattern;
107  std::bitset<TrackStateOnSurface::NumberOfTrackStateOnSurfaceTypes>
108  typePattern = defaultPattern;
109 
110  // start with (measured) perigee
111  unsigned scatter = 0;
112  unsigned tsos = 0;
113  std::unique_ptr<Perigee> perigee(parameters.perigee());
114  typePattern.set(TrackStateOnSurface::Perigee);
115  trackStateOnSurfaces->push_back(new TrackStateOnSurface(
116  fitQoS, std::move(measurementBase), std::move(perigee),
117  std::move(materialEffects), typePattern, std::move(alignmentEffects)));
118  ++tsos;
119 
120  // append leading TSOS to perigee
121  if (leadingTSOS) {
122  for (const auto* t : *leadingTSOS) {
123  if (!(*t).type(Trk::TrackStateOnSurface::Perigee)) {
124  trackStateOnSurfaces->push_back((*t).clone());
125  ++tsos;
126  }
127  }
128  }
129 
130  // then append the fitted TSOS
131  for (auto* m : measurements) {
132  if (m->isMaterialDelimiter())
133  continue;
134 
135  // push back previous TSOS when fresh surface reached
136  if (m->surface() != surface || alignmentEffects || m->alignmentEffects()) {
137  if (surface) {
138  if (typePattern == defaultPattern) {
139  if (cache.debug) {
140  *cache.log << MSG::DEBUG << " skip empty TSOS# " << tsos + 1;
141  if (m->materialEffects())
142  *cache.log << " with material";
143  m->print(*cache.log);
144  *cache.log << endmsg;
145  }
146  } else {
147  // get the MeasuredParameters (with covariance)
148  bool withCovariance = true;
149  trackParameters.reset(parameters.trackParameters(
150  *cache.log, *fitMeasurement, withCovariance));
151 
152  if (!trackParameters) {
153  *cache.log
154  << MSG::WARNING
155  << " fail track with incomplete return TSOS: no trackParameters"
156  << endmsg;
157  return nullptr;
158  }
159  typePattern.set(TrackStateOnSurface::Parameter);
160  trackStateOnSurfaces->push_back(new TrackStateOnSurface(
161  fitQoS, std::move(measurementBase), std::move(trackParameters),
162  std::move(materialEffects), typePattern,
163  std::move(alignmentEffects)));
164  ++tsos;
165  }
166  }
167  fitMeasurement = m;
168  surface = m->surface();
169  measurementBase.reset();
170  materialEffects.reset();
171  typePattern = defaultPattern;
172  alignmentEffects.reset();
173  } else {
174  fitMeasurement = m;
175  if (cache.verbose)
176  *cache.log << MSG::VERBOSE << " tsos# " << tsos << " shared surface"
177  << endmsg;
178  }
179 
180  // it's a measurement
181  if (m->measurementBase()) {
182  // create an extra TSOS if there is already a measurement on this surface
183  // (dirty fix for pseudoMeasurements)
184  if (measurementBase) {
185  // get the MeasuredParameters (with covariance)
186  bool withCovariance = true;
187  trackParameters.reset(parameters.trackParameters(
188  *cache.log, *fitMeasurement, withCovariance));
189  if (!trackParameters) {
190  *cache.log
191  << MSG::WARNING
192  << " fail track with incomplete return TSOS: no trackParameters"
193  << endmsg;
194  return nullptr;
195  }
196  typePattern.set(TrackStateOnSurface::Parameter);
197  trackStateOnSurfaces->push_back(new TrackStateOnSurface(
198  fitQoS, std::move(measurementBase), std::move(trackParameters),
199  std::move(materialEffects), typePattern,
200  std::move(alignmentEffects)));
201  ++tsos;
202  fitMeasurement = m;
203  materialEffects.reset();
204  typePattern = defaultPattern;
205  alignmentEffects.reset();
206  }
207 
208  measurementBase = m->measurementBase()->uniqueClone();
209  typePattern.set(TrackStateOnSurface::Measurement);
210  if (m->isOutlier())
211  typePattern.set(TrackStateOnSurface::Outlier);
212  }
213 
214  // it's a CaloDeposit or Scatterer (scatterers may be fitted or not fitted)
215  if (m->materialEffects()) {
216  // update momentum to account for energy loss
217 
218  if (m->isEnergyDeposit()) {
219  materialEffects = m->materialEffects()->uniqueClone();
220  typePattern.set(TrackStateOnSurface::CaloDeposit);
221  } else if (m->isScatterer()) {
222  // set materialPattern as the scattering parameters are fitted
223  std::bitset<MaterialEffectsBase::NumberOfMaterialEffectsTypes>
224  typeMaterial;
226  const MaterialEffectsOnTrack* meot =
227  dynamic_cast<const MaterialEffectsOnTrack*>(m->materialEffects());
228  if (meot && meot->energyLoss()) // standard scatterer
229  {
230  auto energyLoss =
231  std::unique_ptr<EnergyLoss>(meot->energyLoss()->clone());
233  if (m->numberDoF()) // fitted scatterer
234  {
235  materialEffects = std::make_unique<MaterialEffectsOnTrack>(
236  m->materialEffects()->thicknessInX0(),
237  parameters.scatteringAngles(*m, scatter), std::move(energyLoss),
238  m->materialEffects()->associatedSurface(), typeMaterial);
239  ++scatter;
240  } else // unfitted (leading material)
241  {
242  materialEffects = std::make_unique<MaterialEffectsOnTrack>(
243  m->materialEffects()->thicknessInX0(),
244  parameters.scatteringAngles(*m), std::move(energyLoss),
245  m->materialEffects()->associatedSurface(), typeMaterial);
246  }
247  } else // no meot for special calo scattering centres
248  {
249  if (m->numberDoF()) // fitted scatterer
250  {
251  materialEffects = std::make_unique<MaterialEffectsOnTrack>(
252  m->materialEffects()->thicknessInX0(),
253  parameters.scatteringAngles(*m, scatter),
254  m->materialEffects()->associatedSurface(), typeMaterial);
255  ++scatter;
256  } else // unfitted (leading material)
257  {
258  materialEffects = std::make_unique<MaterialEffectsOnTrack>(
259  m->materialEffects()->thicknessInX0(),
260  parameters.scatteringAngles(*m),
261  m->materialEffects()->associatedSurface(), typeMaterial);
262  }
263  }
264 
265  typePattern.set(TrackStateOnSurface::Scatterer);
266  } else {
267  *cache.log << MSG::WARNING
268  << " deprecated TrackStateOnSurface::InertMaterial"
269  << endmsg;
270  materialEffects = m->materialEffects()->uniqueClone();
271  typePattern.set(TrackStateOnSurface::InertMaterial);
272  }
273  }
274 
275  // additional perigee (e.g. at MS entrance)
276  if (m->isPerigee()) {
277  typePattern.set(TrackStateOnSurface::Perigee);
278  }
279 
280  // or alignment effects
281  else if (m->alignmentEffects()) {
282  const AlignmentEffectsOnTrack& AEOT = *m->alignmentEffects();
283  unsigned align = m->alignmentParameter() - 1;
284 
285  *cache.log << MSG::VERBOSE << " Fitprocedure AEOT input deltaTranslation "
286  << AEOT.deltaTranslation() << " deltaAngle "
287  << AEOT.deltaAngle() << " output Trans "
288  << parameters.alignmentOffset(align) << " deltaAngle "
289  << parameters.alignmentAngle(align) << endmsg;
290  alignmentEffects = std::make_unique<Trk::AlignmentEffectsOnTrack>(
291  parameters.alignmentOffset(align), AEOT.sigmaDeltaTranslation(),
292  parameters.alignmentAngle(align), AEOT.sigmaDeltaAngle(),
293  AEOT.vectorOfAffectedTSOS(), *m->surface());
294  typePattern.set(TrackStateOnSurface::Alignment);
295  }
296 
297  // passive types: hole for now
298  else if (m->isPassive()) {
299  if (m->type() == hole)
300  typePattern.set(TrackStateOnSurface::Hole);
301  }
302  }
303 
304  // remember the final TSOS !
305  bool withCovariance = true;
306  trackParameters.reset(
307  parameters.trackParameters(*cache.log, *fitMeasurement, withCovariance));
308  if (!trackParameters) {
309  *cache.log << MSG::WARNING
310  << " fail track with incomplete return TSOS: no trackParameters"
311  << endmsg;
312  return nullptr;
313  }
314  typePattern.set(TrackStateOnSurface::Parameter);
315  trackStateOnSurfaces->push_back(new TrackStateOnSurface(
316  fitQoS, std::move(measurementBase), std::move(trackParameters),
317  std::move(materialEffects), typePattern, std::move(alignmentEffects)));
318  ++tsos;
319 
320  // construct track
321  double chiSquared = cache.chiSq * static_cast<double>(cache.numberDoF);
322  Track* track = new Track(trackInfo, std::move(trackStateOnSurfaces),
323  std::make_unique<FitQuality>(chiSquared, cache.numberDoF));
324 
325  if (cache.verbose)
326  *cache.log << MSG::VERBOSE << " track with " << tsos << " TSOS " << endmsg;
327  return track;
328 }
329 
331  FitProcedure::Cache& cache, bool asymmetricCaloEnergy, MsgStream& log,
332  std::vector<FitMeasurement*>& measurements, FitParameters*& parameters,
333  const FitQuality* perigeeQuality, bool for_iPatTrack) const {
334  // report start value
335  cache.log = &log;
336  if (cache.log->level() > MSG::DEBUG) {
337  cache.debug = false;
338  cache.verbose = false;
339  } else {
340  cache.debug = true;
341  if (cache.log->level() < MSG::DEBUG)
342  cache.verbose = true;
343  *cache.log << MSG::DEBUG << "parameter start values: ";
344  parameters->print(*cache.log);
345  *cache.log << endmsg;
346  }
347 
348  // choose appropriate intersector
349  const ToolHandle<IIntersector>& intersector =
350  chooseIntersector(measurements, *parameters);
351 
352  // resize matrices
353  int fitCode = cache.fitMatrices->setDimensions(measurements, parameters);
354  if (fitCode) {
355  cache.fitQuality = std::make_unique<FitProcedureQuality>(
356  fitCode, cache.fitMatrices->numberDoF());
357  if (cache.debug)
358  reportQuality(cache, measurements, *parameters);
359  return *cache.fitQuality;
360  }
361 
362  // remaining initialization
363  cache.chiSq = 0.;
364  cache.chiSqWorst = 0.;
365  cache.driftSum = 0.;
366  cache.driftSumLast = 0.;
367  cache.fitProbability = 0.;
368  cache.iteration = -1;
369  cache.numberDoF = cache.fitMatrices->numberDoF();
370  cache.numberParameters = parameters->numberParameters();
371  cache.worstMeasurement = 0;
372  MeasurementProcessor measurementProcessor(
373  asymmetricCaloEnergy, cache.fitMatrices->derivativeMatrix(), intersector,
376 
377  // perigee or vertex used as measurements in fit
378  if (measurements.front()->isPerigee()) {
379  cache.fitMatrices->usePerigee(*measurements.front());
380  }
381 
382  // set requested options and initial values
383  double ptInvCut = 1. / m_minPt; // protection against trapped particles
384  cache.cutStep = true;
385  cache.convergence = false;
386  cache.nearConvergence = false;
387 
388  // keep best (original if not reasonable quality) results
389  double bestChiSq = cache.chiSqCut;
390  std::optional<FitParameters> bestParameters = std::nullopt;
391 
392  // iteration loop to fit track parameters
393  while (!fitCode && !cache.convergence) {
394  bool forceIteration = false;
395  if (cache.iteration > m_maxIter && bestParameters && !for_iPatTrack) {
396  parameters->reset(*bestParameters);
397  cache.convergence = true;
398  cache.cutStep = false;
399  if (cache.verbose)
400  *cache.log << MSG::VERBOSE
401  << " convergence problem: accept after max iter " << endmsg;
402  } else if (!cache.cutStep) {
403  // solve equations and update parameters
404  if (!cache.iteration) {
405  cache.fitMatrices->refinePointers();
406  if (m_extendedDebug)
407  cache.fitMatrices->checkPointers(*cache.log);
408  if (cache.verbose)
409  cache.fitMatrices->printDerivativeMatrix();
410  }
411 
412  if (!cache.fitMatrices->solveEquations()) {
413  fitCode = 11; // fails matrix inversion
414  } else if (parameters->fitEnergyDeposit() &&
415  !parameters->extremeMomentum() &&
416  std::abs(parameters->qOverP()) < m_extremeOneOverP) {
417  if (cache.debug)
418  *cache.log << MSG::DEBUG << " extremeMomentum " << endmsg;
419  parameters->extremeMomentum(true);
420  fitCode = cache.fitMatrices->setDimensions(measurements, parameters);
421  bestChiSq = cache.chiSqCut;
422  bestParameters = std::nullopt;
423  forceIteration = true;
424  cache.chiSq = 0.;
425  cache.chiSqWorst = 0.;
426  cache.driftSum = 0.;
427  cache.driftSumLast = 0.;
428  cache.numberParameters = parameters->numberParameters();
429  }
430  if (cache.verbose && !cache.iteration)
431  cache.fitMatrices->printWeightMatrix();
432  }
433  ++cache.iteration;
434 
435  // report parameters
436  if (cache.verbose) {
437  *cache.log << MSG::VERBOSE << " ===== start iteration "
438  << cache.iteration;
439  if (cache.iteration) {
440  if (cache.cutStep)
441  *cache.log << " ====== cutStep";
442  } else {
443  if (for_iPatTrack)
444  *cache.log << " ====== for_iPatTrack ";
445  }
446  parameters->printVerbose(*cache.log);
447  }
448 
449  // check for some error conditions (if none found yet)
450  if (fitCode) {
451  // e.g. fitCode == 11 (singular matrix)
452  } else if (std::abs(parameters->ptInv0()) > ptInvCut) {
453  fitCode = 8; // fail with pt below cutoff
454  } else if (measurements.front()->isVertex() && m_indetVolume &&
455  !m_indetVolume->inside(parameters->position())) {
456  fitCode = 9; // fail if vertex outside indet
457  } else if (cache.iteration &&
458  (std::abs(parameters->difference(3)) > 1.0 ||
459  std::abs(parameters->difference(0)) > m_largeRadius) &&
460  !measurements.front()->isVertex()) {
461  if (std::abs(parameters->difference(3)) > 1.0) {
462  fitCode = 10; // fail with ill-defined cot_theta
463  } else {
464  fitCode = 9; // fail crazy impact parameter
465  }
466  } else if (!fitCode) {
467  // extrapolate to each measurement and calculate derivatives
468  if (!measurementProcessor.calculateFittedTrajectory(cache.iteration) ||
469  !measurementProcessor.calculateDerivatives()) {
470  fitCode = 5; // fail as trapped
471  cache.fitQuality = std::make_unique<FitProcedureQuality>(
472  cache.chiSq, cache.chiSqWorst, cache.fitProbability, fitCode,
473  cache.iteration, parameters->numberAlignments(),
474  cache.fitMatrices->numberDoF(), parameters->numberScatterers(),
475  cache.worstMeasurement);
476 
477  if (cache.debug) {
478  if (cache.verbose)
479  *cache.log << endmsg;
480  reportQuality(cache, measurements, *parameters);
481  }
482  return *cache.fitQuality;
483  }
484 
485  // have extrapolation and derivatives, calculate residual
486  measurementProcessor.calculateResiduals();
487 
488  // check for remaining error conditions. If OK then compute chisquared.
489  if (cache.iteration > m_maxIter && !cache.cutStep && for_iPatTrack) {
490  fitCode = 6; // fail with no convergence
491  } else if (cache.iteration == 4 && cache.chiSq > 1000. && for_iPatTrack) {
492  fitCode = 7; // fail with too high chisquared
493  } else if (!fitCode) {
494  calculateChiSq(cache, measurements);
495 
496  // check for cutstep conditions if no significant chi2 improvement
497  if (!forceIteration && !cache.convergence && cache.chRatio1 > 0.9) {
498  double cutStep = 0.;
499  if (cache.iteration > 4 &&
500  cache.driftSum * cache.driftSumLast < -1.) {
501  cache.cutStep = true;
502  cutStep = std::abs(cache.driftSumLast /
503  (cache.driftSum - cache.driftSumLast));
504  if (cutStep < 0.001)
505  cutStep = 0.001;
506  if (cache.verbose)
507  *cache.log
508  << MSG::VERBOSE
509  << " take cutStep following chi2 increase on iteration "
510  << cache.iteration << " chi2Ratio " << cache.chRatio1
511  << " driftSum " << cache.driftSum << " prev "
512  << cache.driftSumLast << " " << cutStep << endmsg;
513  } else if (parameters->numberOscillations() > 2) {
514  cache.cutStep = true;
515  cutStep = 0.5;
516  if (cache.verbose)
517  *cache.log << MSG::VERBOSE
518  << " take cutStep as oscillating, iteration "
519  << cache.iteration << ", numberOscillations "
520  << parameters->numberOscillations() << endmsg;
521  }
522 
523  // perform cutstep
524  if (cache.cutStep) {
525  cache.convergence = false;
526  parameters->performCutStep(cutStep);
527  if (cache.verbose)
528  parameters->printVerbose(*cache.log);
529  if (measurementProcessor.calculateFittedTrajectory(
530  cache.iteration)) {
531  // note: derivatives should not be recalculated for cutstep
532  measurementProcessor.calculateResiduals();
533  calculateChiSq(cache, measurements);
534  if (cache.verbose)
535  *cache.log << " after cutStep: "
536  << " chi2Ratio " << cache.chRatio1 << " driftSum "
537  << cache.driftSum << endmsg;
538  }
539  }
540  }
541 
542  // keep current best parameters
543  if (!bestParameters || cache.chiSq < bestChiSq) {
544  bestChiSq = cache.chiSq;
545  bestParameters = *parameters;
546  parameters->resetOscillations();
547  }
548 
549  if (bestParameters &&
550  ((cache.convergence && cache.chiSq > bestChiSq + 0.5) ||
551  (parameters->phiInstability() && cache.iteration == m_maxIter))) {
552  parameters->reset(*bestParameters);
553  if (cache.verbose) {
554  *cache.log << MSG::VERBOSE << " revert to bestParameters ";
555  parameters->printVerbose(*cache.log);
556  }
557  if (measurementProcessor.calculateFittedTrajectory(cache.iteration)) {
558  measurementProcessor.calculateDerivatives();
559  measurementProcessor.calculateResiduals();
560  calculateChiSq(cache, measurements);
561  cache.convergence = true;
562  }
563  }
564 
565  if (forceIteration)
566  cache.convergence = false;
567  }
568  } // if (std::abs(ptInv0) > ptInvCut)
569  if (cache.verbose)
570  *cache.log << endmsg;
571 
572  // try to rescue phi instability failures
573  if (fitCode && cache.iteration && bestParameters &&
574  !parameters->phiInstability() &&
575  (**(measurements.rbegin())).position().perp() > m_largeRadius) {
576  if (cache.verbose)
577  *cache.log << MSG::VERBOSE << " phi instability " << endmsg;
578  parameters->reset(*bestParameters);
579  parameters->setPhiInstability();
580  cache.cutStep = true;
581  cache.convergence = false;
582  fitCode = 0;
583  cache.iteration = 0;
584  }
585  } // while
586 
587  // store successful fit :
588  if (!fitCode) {
589  // set covariance in parameters class after inclusion of uncertainty from
590  // field integral
591  const Amg::MatrixX* fullCovariance = cache.fitMatrices->fullCovariance();
592  if (fullCovariance) {
593  Amg::MatrixX& finalCovariance = cache.fitMatrices->finalCovariance();
594  if (!for_iPatTrack) {
595  if (!m_lineFit)
596  measurementProcessor.fieldIntegralUncertainty(*cache.log,
597  finalCovariance);
598  measurementProcessor.propagationDerivatives();
599  }
600  parameters->covariance(&finalCovariance, fullCovariance);
601 
602  // fit quality
603  if (perigeeQuality) {
604  // take care when mixing normalized with unnormalized
605  cache.chiSq = perigeeQuality->chiSquared() +
606  cache.chiSq * static_cast<double>(cache.numberDoF);
607  cache.numberDoF += perigeeQuality->numberDoF();
608  cache.chiSq /= static_cast<double>(cache.numberDoF);
609  }
610 
611  // probability of chisquared
612  cache.fitProbability = 1.;
613  if (cache.numberDoF > 0 && cache.chiSq > 0.) {
614  if (cache.chiSq < 100.) {
615  double chiSquared =
616  cache.chiSq * static_cast<double>(cache.numberDoF);
617  cache.fitProbability -=
618  Genfun::CumulativeChiSquare(cache.numberDoF)(chiSquared);
619  } else {
620  cache.fitProbability = 0.;
621  }
622  }
623 
624  if (cache.verbose) {
625  *cache.log << MSG::VERBOSE << " fit converged";
626  if (cache.chiSqWorst > 6.25)
627  *cache.log << " with possible outlier #" << cache.worstMeasurement
628  << " (residual " << std::sqrt(cache.chiSqWorst) << ")";
629  *cache.log << endmsg;
630  }
631  } else {
632  fitCode = 11; // singular weight matrix
633  }
634  }
635 
636  cache.fitQuality = std::make_unique<FitProcedureQuality>(
637  cache.chiSq, cache.chiSqWorst, cache.fitProbability, fitCode,
638  cache.iteration, parameters->numberAlignments(), cache.numberDoF,
639  parameters->numberScatterers(), cache.worstMeasurement);
640  if (cache.debug && (for_iPatTrack || fitCode))
641  reportQuality(cache, measurements, *parameters);
642 
643  return *cache.fitQuality;
644 }
645 
647  // note const_cast - ughhh
648  // return const_cast<Amg::MatrixX*>(cache.fitMatrices->fullCovariance());
649  return nullptr; // NOT mig5
650 }
651 
653  m_minIter = minIter;
654  if (m_minIter > m_maxIter)
656 }
657 
659  FitProcedure::Cache& cache,
660  std::vector<FitMeasurement*>& measurements) const {
661  // convergence criterion
662  const double dChisqConv = 0.025;
663 
664  // compute total chisquared and sum of hit differences
665  // flag hit with highest chisquared contribution (on entry if RoadFit)
666  cache.chiSq = 0.;
667  double driftResidual = 0.;
668  double DSqMax = 0.;
669  for (auto* m : measurements) {
670  if (!m->numberDoF())
671  continue;
672  // if (m->isPerigee())
673  // {
674  // cache.chiSq += cache.fitMatrices->perigeeChiSquared();
675  // continue;
676  // }
677 
678  double residual = m->residual();
679  double DiffSq = residual * residual;
680  cache.chiSq += DiffSq;
681  if (m->isPositionMeasurement()) {
682  if (m->isDrift())
683  driftResidual += residual;
684  if (DiffSq > DSqMax) {
685  DSqMax = DiffSq;
686  cache.worstMeasurement = m->hitIndex() + 1;
687  cache.chiSqWorst = std::min(999., DSqMax);
688  }
689  }
690  if (m->is2Dimensional()) {
691  residual = m->residual2();
692  DiffSq = residual * residual;
693  cache.chiSq += DiffSq;
694  if (m->isPositionMeasurement()) {
695  if (DiffSq > DSqMax) {
696  DSqMax = DiffSq;
697  cache.worstMeasurement = m->hitIndex() + 1;
698  cache.chiSqWorst = std::min(999., DSqMax);
699  }
700  }
701  }
702  }
703 
704  // assess chi squared per degree of freedom (and its stability)
705  if (cache.fitMatrices->numberDoF() > 0)
706  cache.chiSq /= static_cast<double>(cache.fitMatrices->numberDoF());
707  if (cache.iteration == 0) {
708  cache.cutTaken = 0;
709  cache.chRatio1 = 0.;
710  cache.chRatio2 = 0.;
711  cache.chiSqMin = cache.chiSq;
712  }
713 
714  cache.chiSqOld = cache.chiSqMin;
715  double DChiSq = cache.chiSqOld - cache.chiSq;
716  if (DChiSq > -dChisqConv) {
717  cache.chiSqMin = cache.chiSq;
718  cache.nCuts = 0;
719  }
720  if (cache.iteration > 0) {
721  cache.chRatio2 = cache.chRatio1;
722  cache.chRatio1 = cache.chiSq / cache.chiSqOld;
723  }
724  if (cache.fitMatrices->numberDriftCircles()) {
725  cache.driftSumLast = cache.driftSum;
726  cache.driftSum =
727  driftResidual /
728  static_cast<double>(cache.fitMatrices->numberDriftCircles());
729  }
730 
731  //
732  // debugging info
733  if (cache.verbose) {
734  *cache.log << "----------------------------------" << std::endl
735  << std::setiosflags(std::ios::fixed)
736  << " Debugging Info in ChiSquare method" << std::endl
737  << " # of track-fit iterations " << std::setw(3)
738  << cache.iteration << std::endl
739  << " fit ChiSquared (per degree of freedom) " << std::setw(13)
740  << std::setprecision(3) << cache.chiSq
741  << " # of degrees of freedom "
742  << cache.fitMatrices->numberDoF() << std::endl
743  << " ChSq Ratio1/2 " << std::setw(9) << std::setprecision(3)
744  << cache.chRatio1 << std::setw(10) << std::setprecision(3)
745  << cache.chRatio2 << std::endl
746  << " driftResidual " << std::setw(9) << std::setprecision(3)
747  << cache.driftSum << " #driftCircles "
748  << cache.fitMatrices->numberDriftCircles() << std::endl
749  << " CutTaken " << cache.cutTaken << std::endl
750  << "----------------------------------" << std::endl
751  << " ";
752 
753  (**measurements.begin()).printHeading(*cache.log);
754  int n = 0;
755  for (auto* m : measurements) {
756  *cache.log << std::setiosflags(std::ios::fixed) << std::setw(3) << ++n;
757  if (m->isPerigee()) {
758  *cache.log << " perigee ";
759  *cache.log << std::endl;
760  } else {
761  m->print(*cache.log);
762  }
763  }
764  }
765 
766  //
767  // check for possible convergence (nearConvergence forces extra iteration)
768  if (!cache.cutStep && !cache.nCuts &&
769  (cache.chiSq < 0.1 ||
770  (cache.chRatio2 < 1.1 &&
771  (std::abs(DChiSq) < dChisqConv ||
772  std::abs((cache.chiSq - cache.chiSqOld) / cache.chiSqOld) < 0.01)))) {
773  if ((cache.chiSq < 2.0 || cache.nearConvergence || cache.iteration == 1) &&
774  cache.iteration >= m_minIter) {
775  cache.convergence = true;
776  } else {
777  cache.nearConvergence = true;
778  if (cache.verbose)
779  *cache.log << MSG::VERBOSE << " near convergence " << endmsg;
780  }
781  } else {
782  cache.nearConvergence = false;
783  }
784 
785  // else take cutstep if divergent or oscillating
786  cache.cutStep = false;
787 }
788 
789 const ToolHandle<IIntersector>& FitProcedure::chooseIntersector(
790  std::vector<FitMeasurement*>& measurements,
791  const FitParameters& parameters) const {
792  if (m_lineFit) {
794  }
795 
796  // decide which intersector to use for curved tracks (default RungeKutta)
797  // ToolHandle<IIntersector>& intersector = m_rungeKuttaIntersector;
798 
799  // solenoidal intersector must start close to origin with last measurement
800  // inside valid region
801  for (std::vector<FitMeasurement*>::reverse_iterator m = measurements.rbegin();
802  m != measurements.rend(); ++m) {
803  if (!(**m).isPositionMeasurement())
804  continue;
805  if (!m_solenoidalIntersector->isValid(parameters.position(),
806  (**m).position()))
807  break;
809  }
810 
812 }
813 
815  FitProcedure::Cache& cache,
816  const std::vector<FitMeasurement*>& measurements,
817  const FitParameters& parameters) {
818  if (!cache.fitQuality)
819  return;
820 
821  int fitCode = cache.fitQuality->fitCode();
822  if (fitCode) {
823  *cache.log << MSG::DEBUG << "failure: fitCode " << fitCode;
824  std::string msg = "";
825  switch (fitCode) {
826  case 1:
827  *cache.log << " missing Trk::Surface ";
828  break;
829  case 2:
830  *cache.log << " too many measurements for fit matrix size: "
831  << measurements.size();
832  break;
833  case 3:
834  *cache.log << " too many parameters for fit matrix size: "
835  << parameters.numberParameters();
836  break;
837  case 4:
838  *cache.log << " unconstrained fit: negative numberDoF "
839  << cache.fitQuality->numberDoF();
840  break;
841  case 5:
842  *cache.log << " trapped in magnetic field: pT = "
843  << 1. / (parameters.ptInv0() * Gaudi::Units::GeV)
844  << " at iteration# " << cache.fitQuality->iterations();
845  break;
846  case 6:
847  *cache.log << " no convergence: chiSq = " << cache.fitQuality->chiSq()
848  << " at iteration# " << cache.fitQuality->iterations();
849  break;
850  case 7:
851  *cache.log << " enormous chi squared: chiSq = "
852  << cache.fitQuality->chiSq() << " at iteration# "
853  << cache.fitQuality->iterations();
854  break;
855  case 8:
856  *cache.log << " below pT cutoff. pT = "
857  << 1. / (parameters.ptInv0() * Gaudi::Units::GeV)
858  << " at iteration# " << cache.fitQuality->iterations();
859  break;
860  case 9:
861  *cache.log << " ill-defined impact parameter " << parameters.d0()
862  << " with difference " << parameters.difference(0)
863  << " at iteration# " << cache.fitQuality->iterations();
864  break;
865  case 10:
866  *cache.log << " ill-defined cotTheta " << parameters.cotTheta()
867  << " with difference " << parameters.difference(3)
868  << " at iteration# " << cache.fitQuality->iterations();
869  break;
870  case 11:
871  *cache.log << " singular matrix fails inversion:"
872  << " at iteration# " << cache.fitQuality->iterations();
873  break;
874  case 12:
875  *cache.log << " maximum of one calorimeter permitted";
876  break;
877  case 13:
878  *cache.log << " NO derivativeMatrix available";
879  break;
880  default:
881  break;
882  };
883  *cache.log << std::endl << endmsg;
884  } else {
885  *cache.log << MSG::DEBUG << "fitted parameter values: ";
886  parameters.print(*cache.log);
887  *cache.log << endmsg;
888  *cache.log << MSG::DEBUG;
889  cache.fitQuality->print(*cache.log);
890  parameters.printCovariance(*cache.log);
891  *cache.log << endmsg;
892  }
893 }
894 
895 } // namespace Trk
Trk::TrackStateOnSurface::CaloDeposit
@ CaloDeposit
This TSOS contains a CaloEnergy object.
Definition: TrackStateOnSurface.h:135
EnergyLoss.h
Trk::TrackInfo
Contains information about the 'fitter' of this track.
Definition: Tracking/TrkEvent/TrkTrack/TrkTrack/TrackInfo.h:32
Trk::TrackStateOnSurface::Perigee
@ Perigee
This represents a perigee, and so will contain a Perigee object only.
Definition: TrackStateOnSurface.h:117
ScatteringAngles.h
GeV
#define GeV
Definition: PhysicsAnalysis/TauID/TauAnalysisTools/Root/HelperFunctions.cxx:17
AlignmentEffectsOnTrack.h
Amg::MatrixX
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic > MatrixX
Dynamic Matrix - dynamic allocation.
Definition: EventPrimitives.h:27
Trk::FitProcedure::m_largeRadius
double m_largeRadius
Definition: FitProcedure.h:169
Trk::MeasurementProcessor::calculateFittedTrajectory
bool calculateFittedTrajectory(int iteration)
Definition: MeasurementProcessor.cxx:240
python.SystemOfUnits.m
int m
Definition: SystemOfUnits.py:91
TrackParameters.h
MeasurementBase.h
Trk::Volume::inside
bool inside(const Amg::Vector3D &gp, double tol=0.) const
Inside() method for checks.
Definition: Volume.cxx:90
ClusterSeg::residual
@ residual
Definition: ClusterNtuple.h:20
Trk::FitProcedure::Cache::log
MsgStream * log
Definition: FitProcedure.h:98
Trk::FitProcedure::m_straightLineIntersector
ToolHandle< IIntersector > & m_straightLineIntersector
Definition: FitProcedure.h:176
Trk::FitProcedure::m_stepPropagator
const ToolHandle< IPropagator > & m_stepPropagator
Definition: FitProcedure.h:177
min
constexpr double min()
Definition: ap_fixedTest.cxx:26
Trk::AlignmentEffectsOnTrack::vectorOfAffectedTSOS
const std::vector< Identifier > & vectorOfAffectedTSOS() const
Returns a vector of the affected TSOS in the track.
Definition: AlignmentEffectsOnTrack.h:115
Trk::FitProcedure::Cache::fitQuality
std::unique_ptr< FitProcedureQuality > fitQuality
Definition: FitProcedure.h:96
Trk::FitProcedure::Cache::fitProbability
double fitProbability
Definition: FitProcedure.h:95
xAOD::JetInput::Track
@ Track
Definition: JetContainerInfo.h:61
Trk::FitProcedure::Cache::worstMeasurement
int worstMeasurement
Definition: FitProcedure.h:104
Trk::FitProcedure::Cache::chiSqMin
double chiSqMin
Definition: FitProcedure.h:85
Trk::FitProcedure::setMinIterations
void setMinIterations(int minIter)
Definition: FitProcedure.cxx:652
Trk::FitProcedure::execute
const FitProcedureQuality & execute(FitProcedure::Cache &cache, bool asymmetricCaloEnergy, MsgStream &log, std::vector< FitMeasurement * > &measurements, FitParameters *&parameters, const FitQuality *perigeeQuality=0, bool for_iPatTrack=false) const
Definition: FitProcedure.cxx:330
Trk::FitProcedure::m_minPt
double m_minPt
Definition: FitProcedure.h:173
Trk::MaterialEffectsBase::FittedMaterialEffects
@ FittedMaterialEffects
contains values obtained by fitting the scatterer or e-loss
Definition: MaterialEffectsBase.h:56
Trk::FitProcedure::Cache::convergence
bool convergence
Definition: FitProcedure.h:88
IPropagator.h
python.SystemOfUnits.TeV
int TeV
Definition: SystemOfUnits.py:158
Trk::AlignmentEffectsOnTrack::deltaAngle
double deltaAngle() const
returns the
Definition: AlignmentEffectsOnTrack.h:103
read_hist_ntuple.t
t
Definition: read_hist_ntuple.py:5
Trk::FitProcedure::clear
static void clear(FitProcedure::Cache &cache)
Definition: FitProcedure.cxx:73
Trk::AlignmentEffectsOnTrack
Class to represent misalignments or 'discontinuities' on tracks These have a surface where the z axis...
Definition: AlignmentEffectsOnTrack.h:24
Trk::FitProcedure::Cache::cutTaken
int cutTaken
Definition: FitProcedure.h:90
Trk::TrackStateOnSurface::Alignment
@ Alignment
This TSOS contains a Trk::AlignmentEffectsOnTrack.
Definition: TrackStateOnSurface.h:150
Trk::FitProcedure::Cache
Definition: FitProcedure.h:47
FitProcedure.h
Trk::FitProcedure::Cache::chiSqCut
double chiSqCut
Definition: FitProcedure.h:84
FitParameters.h
Trk::FitProcedureQuality
Definition: FitProcedureQuality.h:19
Trk::FitProcedure::Cache::nCuts
int nCuts
Definition: FitProcedure.h:100
Trk::TrackStateOnSurface::Outlier
@ Outlier
This TSoS contains an outlier, that is, it contains a MeasurementBase/RIO_OnTrack which was not used ...
Definition: TrackStateOnSurface.h:122
Track.h
MaterialEffectsOnTrack.h
Trk::FitProcedure::m_lineFit
bool m_lineFit
Definition: FitProcedure.h:170
Trk::FitProcedure::Cache::numberDoF
int numberDoF
Definition: FitProcedure.h:101
Trk::FitQualityOnSurface
Definition: FitQualityOnSurface.h:19
python.setupRTTAlg.size
int size
Definition: setupRTTAlg.py:39
Trk::FitProcedure::Cache::cutStep
bool cutStep
Definition: FitProcedure.h:89
Trk::MeasurementProcessor::fieldIntegralUncertainty
void fieldIntegralUncertainty(MsgStream &log, Amg::MatrixX &covariance)
Definition: MeasurementProcessor.cxx:417
Trk::MaterialEffectsOnTrack
represents the full description of deflection and e-loss of a track in material.
Definition: MaterialEffectsOnTrack.h:40
Trk::FitProcedure::m_extremeOneOverP
double m_extremeOneOverP
Definition: FitProcedure.h:167
Trk::FitProcedure::Cache::chRatio2
double chRatio2
Definition: FitProcedure.h:82
Trk::FitProcedure::m_indetVolume
const Trk::Volume * m_indetVolume
Definition: FitProcedure.h:168
Trk::FitProcedure::Cache::nearConvergence
bool nearConvergence
Definition: FitProcedure.h:99
Trk::FitProcedure::m_extendedDebug
bool m_extendedDebug
Definition: FitProcedure.h:166
Trk::TrackStateOnSurface::Hole
@ Hole
A hole on the track - this is defined in the following way.
Definition: TrackStateOnSurface.h:128
Trk::MeasurementProcessor
Definition: MeasurementProcessor.h:34
beamspotman.n
n
Definition: beamspotman.py:731
Trk::FitProcedure::Cache::driftSum
double driftSum
Definition: FitProcedure.h:92
Trk::FitMeasurement
Definition: FitMeasurement.h:40
endmsg
#define endmsg
Definition: AnalysisConfig_Ntuple.cxx:63
Trk::FitProcedure::m_useStepPropagator
int m_useStepPropagator
Definition: FitProcedure.h:178
Trk::FitProcedure::Cache::driftSumLast
double driftSumLast
Definition: FitProcedure.h:93
Trk::MeasurementProcessor::calculateResiduals
void calculateResiduals(void)
Definition: MeasurementProcessor.cxx:296
Trk::FitProcedure::Cache::debug
bool debug
Definition: FitProcedure.h:91
Trk::FitProcedure::Cache::numberParameters
int numberParameters
Definition: FitProcedure.h:102
Trk::FitQuality
Class to represent and store fit qualities from track reconstruction in terms of and number of degre...
Definition: FitQuality.h:97
Trk::FitProcedure::Cache::chiSq
double chiSq
Definition: FitProcedure.h:83
DataVector< const Trk::TrackStateOnSurface >
Trk::TrackStateOnSurface::Parameter
@ Parameter
This TSOS contains a Trk::ParameterBase.
Definition: TrackStateOnSurface.h:140
trackInfo
Definition: TrigInDetUtils.h:13
Trk::FitProcedure::reportQuality
static void reportQuality(FitProcedure::Cache &cache, const std::vector< FitMeasurement * > &measurements, const FitParameters &parameters)
Definition: FitProcedure.cxx:814
Athena::Units
Definition: Units.h:45
Trk
Ensure that the ATLAS eigen extensions are properly loaded.
Definition: FakeTrackBuilder.h:9
Trk::FitProcedure::Cache::chiSqOld
double chiSqOld
Definition: FitProcedure.h:86
Trk::MeasurementProcessor::calculateDerivatives
bool calculateDerivatives(void)
Definition: MeasurementProcessor.cxx:123
Trk::FitProcedure::constructTrack
static Track * constructTrack(FitProcedure::Cache &cache, const std::vector< FitMeasurement * > &measurements, FitParameters &parameters, const TrackInfo &trackInfo, const DataVector< const TrackStateOnSurface > *leadingTSOS=nullptr)
Definition: FitProcedure.cxx:77
Trk::FitProcedure::Cache::chiSqWorst
double chiSqWorst
Definition: FitProcedure.h:87
Trk::TrackStateOnSurface
represents the track state (measurement, material, fit parameters and quality) at a surface.
Definition: TrackStateOnSurface.h:71
TrackInfo.h
Trk::TrackStateOnSurface::InertMaterial
@ InertMaterial
This represents inert material, and so will contain MaterialEffectsBase.
Definition: TrackStateOnSurface.h:105
Trk::FitProcedure::m_rungeKuttaIntersector
ToolHandle< IIntersector > & m_rungeKuttaIntersector
Definition: FitProcedure.h:174
IIntersector.h
Trk::MaterialEffectsBase::EnergyLossEffects
@ EnergyLossEffects
contains energy loss corrections
Definition: MaterialEffectsBase.h:48
Trk::FitProcedure::m_solenoidalIntersector
const ToolHandle< IIntersector > & m_solenoidalIntersector
Definition: FitProcedure.h:175
FitMeasurement.h
IDTPM::chiSquared
float chiSquared(const U &p)
Definition: TrackParametersHelper.h:128
Trk::FitProcedure::m_maxIter
int m_maxIter
Definition: FitProcedure.h:171
python.SystemOfUnits.mm
int mm
Definition: SystemOfUnits.py:83
TrackingVolume.h
Trk::FitProcedure::FitProcedure
FitProcedure(bool constrainedAlignmentEffects, bool extendedDebug, bool lineFit, ToolHandle< IIntersector > &rungeKuttaIntersector, ToolHandle< IIntersector > &solenoidalIntersector, ToolHandle< IIntersector > &straightLineIntersector, const ToolHandle< IPropagator > &stepPropagator, const Volume *indetVolume=0, int maxIterations=25, int useStepPropagator=0)
Definition: FitProcedure.cxx:48
Trk::MaterialEffectsOnTrack::energyLoss
const EnergyLoss * energyLoss() const
returns the energy loss object.
Trk::FitProcedure::chooseIntersector
const ToolHandle< IIntersector > & chooseIntersector(std::vector< FitMeasurement * > &measurements, const FitParameters &parameters) const
Definition: FitProcedure.cxx:789
Trk::FitProcedure::fullCovariance
static Amg::MatrixX * fullCovariance()
Definition: FitProcedure.cxx:646
Trk::FitProcedure::Cache::iteration
int iteration
Definition: FitProcedure.h:97
DEBUG
#define DEBUG
Definition: page_access.h:11
MeasurementProcessor.h
python.CaloCondTools.log
log
Definition: CaloCondTools.py:20
Trk::FitProcedure::m_minIter
int m_minIter
Definition: FitProcedure.h:172
Trk::TrackStateOnSurface::Scatterer
@ Scatterer
This represents a scattering point on the track, and so will contain TrackParameters and MaterialEffe...
Definition: TrackStateOnSurface.h:113
Gaudi
=============================================================================
Definition: CaloGPUClusterAndCellDataMonitorOptions.h:273
physics_parameters.parameters
parameters
Definition: physics_parameters.py:144
Trk::FitQuality::chiSquared
double chiSquared() const
returns the of the overall track fit
Definition: FitQuality.h:56
Trk::AlignmentEffectsOnTrack::sigmaDeltaTranslation
double sigmaDeltaTranslation() const
returns the
Definition: AlignmentEffectsOnTrack.h:97
Trk::hole
@ hole
Definition: MeasurementType.h:36
Track
Definition: TriggerChamberClusterOnTrackCreator.h:21
Trk::FitQuality::numberDoF
int numberDoF() const
returns the number of degrees of freedom of the overall track or vertex fit as integer
Definition: FitQuality.h:60
Trk::FitProcedure::Cache::fitMatrices
std::unique_ptr< FitMatrices > fitMatrices
Definition: FitProcedure.h:94
Trk::AlignmentEffectsOnTrack::deltaTranslation
double deltaTranslation() const
returns the
Definition: AlignmentEffectsOnTrack.h:91
xAOD::track
@ track
Definition: TrackingPrimitives.h:512
Trk::FitParameters
Definition: FitParameters.h:29
python.Constants.VERBOSE
int VERBOSE
Definition: Control/AthenaCommon/python/Constants.py:14
Trk::FitProcedure::calculateChiSq
void calculateChiSq(FitProcedure::Cache &cache, std::vector< FitMeasurement * > &measurements) const
Definition: FitProcedure.cxx:658
Trk::Surface
Definition: Tracking/TrkDetDescr/TrkSurfaces/TrkSurfaces/Surface.h:75
Trk::MeasurementProcessor::propagationDerivatives
void propagationDerivatives(void)
Definition: MeasurementProcessor.cxx:541
Trk::Volume
Definition: Volume.h:35
Trk::EnergyLoss::clone
virtual EnergyLoss * clone() const
Virtual constructor.
DataVector::size
size_type size() const noexcept
Returns the number of elements in the collection.
python.AutoConfigFlags.msg
msg
Definition: AutoConfigFlags.py:7
Trk::FitProcedure::Cache::chRatio1
double chRatio1
Definition: FitProcedure.h:81
Trk::FitProcedure::Cache::verbose
bool verbose
Definition: FitProcedure.h:103
Trk::TrackStateOnSurface::Measurement
@ Measurement
This is a measurement, and will at least contain a Trk::MeasurementBase.
Definition: TrackStateOnSurface.h:101
TrackStateOnSurface.h
Trk::AlignmentEffectsOnTrack::sigmaDeltaAngle
double sigmaDeltaAngle() const
returns the
Definition: AlignmentEffectsOnTrack.h:109