ATLAS Offline Software
GlobalChi2Fitter.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3 */
6 
8 
13 #include "TrkSurfaces/DiscBounds.h"
18 
19 #include "TrkGeometry/Layer.h"
21 #include "TrkGeometry/DiscLayer.h"
24 
25 #include "TrkVolumes/Volume.h"
27 
29 
33 
37 #include "TrkTrack/Track.h"
40 
47 
49 
52 
55 
56 #include "CLHEP/Units/SystemOfUnits.h"
57 
60 
63 #include "CxxUtils/inline_hints.h"
64 
66 #include "LayerSort.h"
68 #include "cmath"
69 #include <Eigen/Dense>
70 #include <Eigen/StdVector>
71 
72 #include <exception>
73 #include <memory>
74 
75 using CLHEP::MeV;
76 using CLHEP::mm;
77 
78 namespace {
79  double getDistance(const Trk::DistanceSolution& distsol) {
80  if (distsol.numberOfSolutions() == 1) {
81  return distsol.first();
82  } if (distsol.numberOfSolutions() == 2) {
83  return (
84  std::abs(distsol.first()) < std::abs(distsol.second()) ?
85  distsol.first() :
86  distsol.second()
87  );
88  } else {
89  return 0;
90  }
91  }
92  //This function used to avoid FPE divide by zero or overflow by limiting the q/p values to a
93  //more limited range
94  double
95  limitInversePValue(double qOverP){
96  const double magnitude = std::abs(qOverP);
97  //limits found empirically to leave the 25-event q431 digest unchanged
98  constexpr double maxP{100.*10e6*MeV};
99  constexpr double minP{1.e-3*MeV};
100  constexpr double lo {1./maxP};
101  constexpr double hi {1./minP};
102  const double limited = std::clamp(magnitude, lo, hi);
103  return std::copysign(limited, qOverP);
104  }
105 
106 
107  std::pair<const Trk::TrackParameters *, const Trk::TrackParameters *> getFirstLastIdPar(const Trk::Track & track) {
108  const Trk::TrackParameters *firstidpar = nullptr;
109  const Trk::TrackParameters *lastidpar = nullptr;
110 
111  DataVector<const Trk::TrackParameters>::const_iterator parit = track.trackParameters()->begin();
112 
113  while ((firstidpar == nullptr) && parit != track.trackParameters()->end()) {
114  if (
115  ((**parit).covariance() != nullptr) &&
116  (**parit).associatedSurface().type() == Trk::SurfaceType::Perigee)
117  {
118  firstidpar = *parit;
119  }
120 
121  ++parit;
122  }
123 
124  parit = track.trackParameters()->end();
125  do {
126  --parit;
127  if (
128  ((**parit).covariance() != nullptr) &&
129  (**parit).associatedSurface().type() == Trk::SurfaceType::Perigee)
130  {
131  lastidpar = *parit;
132  }
133  } while ((lastidpar == nullptr) && parit != track.trackParameters()->begin());
134 
135  return std::make_pair(firstidpar, lastidpar);
136  }
137 
138  Trk::PropDirection invertPropdir(Trk::PropDirection i) {
139  if (i == Trk::alongMomentum) {
140  return Trk::oppositeMomentum;
141  } else if (i == Trk::oppositeMomentum) {
142  return Trk::alongMomentum;
143  } else {
144  return Trk::anyDirection;
145  }
146  }
147 
148  bool trackParametersClose(const Trk::TrackParameters & a, const Trk::TrackParameters & b, double e) {
149  return (
150  std::abs(a.parameters()[0] - b.parameters()[0]) < e &&
151  std::abs(a.parameters()[1] - b.parameters()[1]) < e &&
152  std::abs(a.parameters()[2] - b.parameters()[2]) < e
153  );
154  }
155 
156 // We compile this package with optimization, even in debug builds; otherwise,
157 // the heavy use of Eigen makes it too slow. However, from here we may call
158 // to out-of-line Eigen code that is linked from other DSOs; in that case,
159 // it would not be optimized. Avoid this by forcing all Eigen code
160 // to be inlined here if possible.
162  void
163  calculateJac(Eigen::Matrix<double, 5, 5> &jac,
164  Eigen::Matrix<double, 5, 5> &out,
165  int jmin, int jmax) {
166  out = (jac * out);
167 
168  if (jmin > 0) {
169  out.block(0, 0, 4, jmin).setZero();
170  }
171 
172  if (jmax < 4) {
173  out.block(0, jmax + 1, 4, 5 - (jmax + 1)).setZero();
174  }
175 
176  out(4, 4) = jac(4, 4);
177  }
178 
179  /*
180  * Analyse a 2x2 covariance matrix and find
181  * - the smaller eigenvalue
182  * - the stereo angle
183  * This assumes, that the covariance matrix is valid, i.e. symmetric.
184  * TODO: Find a source for the stereo angle calculation
185  */
186  std::pair<double, double> principalComponentAnalysis2x2(const Amg::MatrixX & mat) {
187  const double trace = mat(0, 0) + mat(1, 1);
188  const double diagonalProduct = mat(0, 0) * mat(1, 1);
189  const double mat01Sq = mat(0, 1) * mat(0, 1);
190  const double discriminant = std::sqrt(trace * trace - 4. * (diagonalProduct - mat01Sq));
191 
192  const double eigenValueSmall = 0.5 * (trace - discriminant);
193  const double stereoAngle = 0.5 * std::asin(2 * mat(0, 1) / (-discriminant));
194 
195  return std::make_pair(eigenValueSmall, stereoAngle);
196  }
197 } //end of anonymous namespace
198 
199 namespace Trk {
201  const std::string & t,
202  const std::string & n,
203  const IInterface * p
204  ):
205  base_class(t, n, p),
206  m_idVolume(nullptr, std::make_shared<Trk::CylinderVolumeBounds>(560, 2750))
207  {
208  }
209 
212 
213  if (!m_ROTcreator.name().empty()) {
214  ATH_CHECK(m_ROTcreator.retrieve());
215  }
216 
217  if (!m_broadROTcreator.name().empty()) {
218  ATH_CHECK(m_broadROTcreator.retrieve());
219  }
220 
221  ATH_CHECK(m_updator.retrieve());
222  ATH_CHECK(m_extrapolator.retrieve());
223  ATH_CHECK(m_navigator.retrieve());
225  ATH_CHECK(m_propagator.retrieve());
226 
227  if (!m_boundaryCheckTool.name().empty()) {
228  ATH_CHECK(m_boundaryCheckTool.retrieve());
229  } else if (m_holeSearch.value()) {
230  ATH_MSG_ERROR("Hole search requested but no boundary check tool provided.");
231  return StatusCode::FAILURE;
232  }
233 
234  if (m_calomat) {
235  ATH_CHECK(m_calotool.retrieve());
236 
237  if (!m_calotoolparam.empty()) {
238  ATH_CHECK(m_calotoolparam.retrieve());
239  }
240  } else{
241  m_calotool.disable();
242  m_calotoolparam.disable();
243  }
244 
245  ATH_CHECK(m_scattool.retrieve());
246  ATH_CHECK(m_elosstool.retrieve());
247 
248  if (!m_matupdator.name().empty()) {
249  ATH_CHECK(m_matupdator.retrieve());
250  }
251 
252  // need an Atlas id-helper to identify sub-detectors, take the one from detStore
253  ATH_CHECK(detStore()->retrieve(m_DetID, "AtlasID"));
254 
256  ATH_MSG_WARNING("FillDerivativeMatrix option selected, switching off acceleration!");
257  m_acceleration = false;
258  }
259 
260  if (!m_trackingGeometryReadKey.key().empty()){
261  ATH_CHECK( m_trackingGeometryReadKey.initialize());
262  }
263  if (m_useCaloTG) {
264  ATH_CHECK(m_caloMaterialProvider.retrieve());
265  ATH_MSG_INFO(m_caloMaterialProvider << " retrieved ");
266  }
267  else{
268  m_caloMaterialProvider.disable();
269  }
270 
272 
273  /*
274  * Doing a hole search only makes sense if we are also creating a track
275  * summary, because the track summary is the only way for us to export the
276  * hole search information out of the fitter. For this reason, we disable
277  * the hole search in the case that track summaries are disabled.
278  */
279  if (m_holeSearch.value() && !m_createSummary.value()) {
280  ATH_MSG_ERROR("Hole search requested but track summaries are disabled.");
281  return StatusCode::FAILURE;
282  }
283 
284  ATH_MSG_INFO("fixed momentum: " << m_p);
285 
286  return StatusCode::SUCCESS;
287  }
288 
290 
291  ATH_MSG_INFO(m_fit_status[S_FITS] << " attempted track fits");
292  if (m_fit_status[S_FITS] > 0) {
293  ATH_MSG_INFO(m_fit_status[S_SUCCESSFUL_FITS] << " successful track fits");
294  ATH_MSG_INFO(m_fit_status[S_MAT_INV_FAIL]
295  << " track fits failed because of a matrix inversion failure");
296  ATH_MSG_INFO(m_fit_status[S_NOT_ENOUGH_MEAS]
297  << " tracks were rejected by the outlier logic");
298  ATH_MSG_INFO(m_fit_status[S_PROPAGATION_FAIL]
299  << " track fits failed because of a propagation failure");
300  ATH_MSG_INFO(m_fit_status[S_INVALID_ANGLES]
301  << " track fits failed because of an invalid angle (theta/phi)");
302  ATH_MSG_INFO(m_fit_status[S_NOT_CONVERGENT]
303  << " track fits failed because the fit did not converge");
304  ATH_MSG_INFO(m_fit_status[S_HIGH_CHI2]
305  << " tracks did not pass the chi^2 cut");
306  ATH_MSG_INFO(m_fit_status[S_LOW_MOMENTUM]
307  << " tracks were killed by the energy loss update");
308  }
309 
310  return StatusCode::SUCCESS;
311  }
312 
313  // combined fit of two tracks
314  // --------------------------------
315  std::unique_ptr<Track>
317  const EventContext& ctx,
318  const Track& intrk1,
319  const Track& intrk2,
320  const RunOutlierRemoval,
321  const ParticleHypothesis) const
322  {
323  ATH_MSG_DEBUG("--> entering GlobalChi2Fitter::fit(Track,Track,)");
324 
325  Cache cache(this);
326  initFieldCache(ctx,cache);
327 
328  GXFTrajectory trajectory;
329  if (!m_straightlineprop) {
330  trajectory.m_straightline = (
331  !cache.m_field_cache.solenoidOn() && !cache.m_field_cache.toroidOn()
332  );
333  }
334 
335  trajectory.m_fieldprop = trajectory.m_straightline ? Trk::NoField : Trk::FullField;
336 
337  const bool firstismuon = isMuonTrack(intrk1);
338  const Track *indettrack = firstismuon ? &intrk2 : &intrk1;
339  const Track *muontrack = firstismuon ? &intrk1 : &intrk2;
340  const bool muonisstraight = muontrack->info().trackProperties(TrackInfo::StraightTrack);
341  bool measphi = false;
342 
343  for (const auto *i : *(muontrack->measurementsOnTrack())) {
344  const RIO_OnTrack *rot = nullptr;
345 
347  const auto *const crot = static_cast<const CompetingRIOsOnTrack *>(i);
348  rot = &crot->rioOnTrack(0);
349  } else {
351  rot =static_cast<const RIO_OnTrack *>(i);
352  }
353  }
354  if ((rot != nullptr) && !m_DetID->is_mdt(rot->identify())) {
355  const Surface *surf = &rot->associatedSurface();
356  const Amg::Vector3D measdir = surf->transform().rotation().col(0);
357  const double dotprod1 = measdir.dot(Amg::Vector3D(0, 0, 1));
358  const double dotprod2 = measdir.dot(
359  Amg::Vector3D(surf->center().x(), surf->center().y(), 0) /
360  surf->center().perp());
361  if (std::abs(dotprod1) < .5 && std::abs(dotprod2) < .5) {
362  measphi = true;
363  break;
364  }
365  }
366  }
367 
368  const IPropagator *prop = &*m_propagator;
369  auto [firstidpar, lastidpar] = getFirstLastIdPar(*indettrack);
370 
371  if ((firstidpar == nullptr) || (lastidpar == nullptr)) {
372  return nullptr;
373  }
374 
375  std::unique_ptr<const TrackParameters> parforcalo = unique_clone(firstismuon ? firstidpar : lastidpar);
376 
377  if (!cache.m_field_cache.solenoidOn()) {
378  const AmgVector(5) & newpars = parforcalo->parameters();
379 
380  parforcalo=parforcalo->associatedSurface().createUniqueTrackParameters(
381  newpars[0], newpars[1], newpars[2], newpars[3], 1 / 5000., std::nullopt
382  );
383  }
384 
385  std::vector < MaterialEffectsOnTrack > calomeots;
386  if (!m_useCaloTG) {
387  if (!m_calotool.empty()) {
388  calomeots = m_calotool->extrapolationSurfacesAndEffects(
389  *m_navigator->highestVolume(ctx),
390  *prop,
391  *parforcalo,
392  parforcalo->associatedSurface(),
394  Trk::muon
395  );
396  }
397  } else {
398  m_caloMaterialProvider->getCaloMEOT(*indettrack, *muontrack, calomeots);
399  }
400 
401  if (firstismuon) {
402  std::reverse(calomeots.begin(), calomeots.end());
403  }
404 
405  if (calomeots.empty()) {
406  ATH_MSG_WARNING("No calorimeter material collected, failing fit");
407  return nullptr;
408  }
409 
410  std::unique_ptr<Track> track;
411 
412  const bool tmp = m_calomat;
413  cache.m_calomat = false;
414  const bool tmp2 = cache.m_extmat;
415  const bool tmp4 = cache.m_idmat;
416 
417  const TrackParameters *measperid = indettrack->perigeeParameters();
418  const TrackParameters *measpermuon = muontrack->perigeeParameters();
419 
420  const double qoverpid = measperid != nullptr ? measperid->parameters()[Trk::qOverP] : 0;
421  const double qoverpmuon = measpermuon != nullptr ? measpermuon->parameters()[Trk::qOverP] : 0;
422 
423  const AmgSymMatrix(5) * errmatid = measperid != nullptr ? measperid->covariance() : nullptr;
424  const AmgSymMatrix(5) * errmatmuon = measpermuon != nullptr ? measpermuon->covariance() : nullptr;
425 
426  if (
427  !firstismuon &&
428  (errmatid != nullptr) &&
429  (errmatmuon != nullptr) &&
430  qoverpmuon != 0 &&
431  !m_calotoolparam.empty() &&
432  !m_useCaloTG
433  ) {
434  const double piderror = std::sqrt((*errmatid) (4, 4)) / (qoverpid * qoverpid);
435  const double pmuonerror = std::sqrt((*errmatmuon) (4, 4)) / (qoverpmuon * qoverpmuon);
436  const double energyerror = std::sqrt(
437  calomeots[1].energyLoss()->sigmaDeltaE() *
438  calomeots[1].energyLoss()->sigmaDeltaE() + piderror * piderror +
439  pmuonerror * pmuonerror
440  );
441 
442  if (
443  (std::abs(calomeots[1].energyLoss()->deltaE()) -
444  std::abs(1 / qoverpid) + std::abs(1 / qoverpmuon)
445  ) / energyerror > 5
446  ) {
447  ATH_MSG_DEBUG("Changing from measured to parametrized energy loss");
448  calomeots = m_calotoolparam->extrapolationSurfacesAndEffects(
449  *m_navigator->highestVolume(ctx),
450  *prop,
451  *parforcalo,
452  parforcalo->associatedSurface(),
454  Trk::muon
455  );
456 
457  if (calomeots.empty()) {
458  ATH_MSG_WARNING("No calorimeter material collected, failing fit");
459  return nullptr;
460  }
461  }
462  }
463 
464  const int nfits = cache.m_fit_status[S_FITS];
465  bool firstfitwasattempted = false;
466 
467  const bool caloEntranceIsValid = ensureValidEntranceCalo(ctx, cache);
468  if (!caloEntranceIsValid) {
469  return nullptr;
470  }
471 
472  if (
473  (!cache.m_field_cache.toroidOn() && !cache.m_field_cache.solenoidOn()) ||
474  (
475  cache.m_getmaterialfromtrack &&
476  !muonisstraight &&
477  measphi &&
478  muontrack->info().trackFitter() != Trk::TrackInfo::Unknown &&
479  qoverpid * qoverpmuon > 0
480  )
481  ) {
482  track.reset(mainCombinationStrategy(ctx,cache, intrk1, intrk2, trajectory, calomeots));
483 
484  if (cache.m_fit_status[S_FITS] == (unsigned int) (nfits + 1)) {
485  firstfitwasattempted = true;
486  }
487  }
488 
489  if (
490  (track == nullptr) &&
491  !firstfitwasattempted &&
492  (cache.m_field_cache.toroidOn() || cache.m_field_cache.solenoidOn())
493  ) {
494  // Reset the trajectory
495  GXFTrajectory trajectory2;
496  trajectory2.m_straightline = trajectory.m_straightline;
497  trajectory2.m_fieldprop = trajectory.m_fieldprop;
498  trajectory = trajectory2;
499  track.reset(backupCombinationStrategy(ctx,cache, intrk1, intrk2, trajectory, calomeots));
500  }
501 
502  bool pseudoupdated = false;
503 
504  if (track != nullptr) {
505  for (std::unique_ptr<GXFTrackState> & pseudostate : trajectory.trackStates()) {
506  if (pseudostate == nullptr) {
507  continue;
508  }
509 
510  if (
511  pseudostate->measurementType() != TrackState::Pseudo ||
512  !pseudostate->getStateType(TrackStateOnSurface::Measurement)
513  ) {
514  continue;
515  }
516 
517  if ((pseudostate == nullptr) || pseudostate->fitQuality().chiSquared() < 10) {
518  continue;
519  }
520 
521  const TrackParameters *pseudopar = pseudostate->trackParameters();
522  const std::unique_ptr<const TrackParameters> updpar(m_updator->removeFromState(
523  *pseudopar,
524  pseudostate->measurement()->localParameters(),
525  pseudostate->measurement()->localCovariance()
526  ));
527 
528  if (updpar == nullptr) {
529  continue;
530  }
531 
532  Amg::MatrixX covMatrix(1, 1);
533  covMatrix(0, 0) = 100;
534 
535  std::unique_ptr<const PseudoMeasurementOnTrack> newpseudo = std::make_unique<const PseudoMeasurementOnTrack>(
537  DefinedParameter(updpar->parameters()[Trk::locY], Trk::locY)
538  ),
539  std::move(covMatrix),
540  pseudopar->associatedSurface()
541  );
542 
543  pseudostate->setMeasurement(std::move(newpseudo));
544  double errors[5];
545  errors[0] = errors[2] = errors[3] = errors[4] = -1;
546  errors[1] = 10;
547  pseudostate->setMeasurementErrors(errors);
548  pseudoupdated = true;
549  }
550 
551  if (pseudoupdated) {
552  trajectory.setConverged(false);
553  cache.m_matfilled = true;
554 
555  track.reset(myfit(
556  ctx,
557  cache,
558  trajectory,
559  *track->perigeeParameters(),
560  false,
562  ));
563 
564  cache.m_matfilled = false;
565  }
566  }
567 
568  cache.m_fit_status[S_FITS] = nfits + 1;
569 
570  if (track != nullptr) {
571  track->info().addPatternReco(intrk1.info());
572  track->info().addPatternReco(intrk2.info());
574  }
575 
576  cache.m_calomat = tmp;
577  cache.m_extmat = tmp2;
578  cache.m_idmat = tmp4;
579  return track;
580  }
581 
583  const EventContext& ctx,
584  Cache & cache,
585  const Track & intrk1,
586  const Track & intrk2,
587  GXFTrajectory & trajectory,
588  std::vector<MaterialEffectsOnTrack> & calomeots
589  ) const {
590  ATH_MSG_DEBUG("--> entering GlobalChi2Fitter::mainCombinationStrategy");
591 
592  const double mass = Trk::ParticleMasses::mass[muon];
593 
594  const bool firstismuon = isMuonTrack(intrk1);
595  const Track *indettrack = firstismuon ? &intrk2 : &intrk1;
596  const Track *muontrack = firstismuon ? &intrk1 : &intrk2;
597 
598  auto [tmpfirstidpar, tmplastidpar] = getFirstLastIdPar(*indettrack);
599  std::unique_ptr<const TrackParameters> firstidpar = unique_clone(tmpfirstidpar);
600  std::unique_ptr<const TrackParameters> lastidpar = unique_clone(tmplastidpar);
601 
602  if ((firstidpar == nullptr) || (lastidpar == nullptr)) {
603  return nullptr;
604  }
605 
606  if (muontrack->trackStateOnSurfaces()->empty()) {
607  return nullptr;
608  }
609 
611  firstismuon ?
612  muontrack->trackStateOnSurfaces()->end() - 1 :
613  muontrack->trackStateOnSurfaces()->begin();
614 
615  const MeasurementBase *closestmuonmeas = nullptr;
616  std::unique_ptr<const TrackParameters> tp_closestmuon = nullptr;
617 
618  while (closestmuonmeas == nullptr) {
619  closestmuonmeas = nullptr;
620  const TrackParameters *thispar = (**tsosit).trackParameters();
621 
622  if ((**tsosit).measurementOnTrack() != nullptr) {
623  closestmuonmeas = (**tsosit).measurementOnTrack();
624 
625  if (thispar != nullptr) {
626  const AmgVector(5) & parvec = thispar->parameters();
627  tp_closestmuon=thispar->associatedSurface().createUniqueTrackParameters(
628  parvec[0], parvec[1], parvec[2], parvec[3], parvec[4], std::nullopt
629  );
630  }
631  break;
632  }
633 
634  if (firstismuon) {
635  --tsosit;
636  } else {
637  ++tsosit;
638  }
639  }
640 
641  PropDirection propdir = firstismuon ? Trk::alongMomentum : oppositeMomentum;
642  std::unique_ptr<const TrackParameters> tmppar;
643 
644  const bool msEntranceIsValid = ensureValidEntranceMuonSpectrometer(ctx, cache);
645  if ((tp_closestmuon != nullptr) && msEntranceIsValid) {
646  tmppar = m_extrapolator->extrapolateToVolume(
647  ctx, *tp_closestmuon, *cache.m_msEntrance, propdir, nonInteracting);
648  }
649 
650  std::unique_ptr<const std::vector<const TrackStateOnSurface *>> matvec;
651 
652  if (tmppar != nullptr) {
653  const Surface & associatedSurface = tmppar->associatedSurface();
654  std::unique_ptr<Surface> muonsurf = nullptr;
655 
656  if (associatedSurface.type() == Trk::SurfaceType::Cylinder) {
657  if (associatedSurface.bounds().type() == Trk::SurfaceBounds::Cylinder) {
658  const CylinderBounds *cylbounds = static_cast <const CylinderBounds * >(&associatedSurface.bounds());
659  Amg::Transform3D const trans = Amg::Transform3D(associatedSurface.transform());
660  const double radius = cylbounds->r();
661  const double hlength = cylbounds->halflengthZ();
662  muonsurf = std::make_unique<CylinderSurface>(trans, radius + 1, hlength);
663  }
664  } else if (associatedSurface.type() == Trk::SurfaceType::Disc) {
665  if (associatedSurface.bounds().type() == Trk::SurfaceBounds::Disc) {
666  const double newz = (
667  associatedSurface.center().z() > 0 ?
668  associatedSurface.center().z() + 1 :
669  associatedSurface.center().z() - 1
670  );
671 
672  const Amg::Vector3D newpos(
673  associatedSurface.center().x(),
674  associatedSurface.center().y(),
675  newz
676  );
677  Amg::Transform3D trans = associatedSurface.transform();
678  trans.translation() << newpos;
679 
680  const DiscBounds *discbounds = static_cast<const DiscBounds *>(&associatedSurface.bounds());
681  const double rmin = discbounds->rMin();
682  const double rmax = discbounds->rMax();
683  muonsurf = std::make_unique<DiscSurface>(trans, rmin, rmax);
684  }
685  }
686 
687  if (muonsurf != nullptr) {
688  matvec.reset(m_extrapolator->extrapolateM(
689  ctx,
690  *tp_closestmuon,
691  *muonsurf,
692  propdir,
693  false,
694  muon
695  ));
696  }
697  }
698 
699  std::vector<const TrackStateOnSurface *> tmp_matvec;
700 
701  if ((matvec != nullptr) && !matvec->empty()) {
702  tmp_matvec = *matvec;
703  delete tmp_matvec.back();
704  tmp_matvec.pop_back();
705 
706  for (auto & i : tmp_matvec) {
707  propdir = firstismuon ? Trk::alongMomentum : oppositeMomentum;
708  if (i->materialEffectsOnTrack()->derivedType() != MaterialEffectsBase::MATERIAL_EFFECTS_ON_TRACK){
709  continue;
710  }
711  const MaterialEffectsOnTrack *meff = static_cast<const MaterialEffectsOnTrack *>(i->materialEffectsOnTrack());
712 
713  const Surface *matsurf = &meff->associatedSurface();
714  tmppar = m_propagator->propagateParameters(
715  ctx,
716  *tp_closestmuon,
717  *matsurf,
718  propdir,
719  false,
720  trajectory.m_fieldprop,
722  );
723 
724 
725  if (tmppar == nullptr) {
726  propdir = !firstismuon ? Trk::alongMomentum : oppositeMomentum;
727  tmppar=m_propagator->propagateParameters(
728  ctx,
729  *tp_closestmuon,
730  *matsurf,
731  propdir,
732  false,
733  trajectory.m_fieldprop,
735  );
736 
737  }
738 
739  if (tmppar == nullptr) {
740  return nullptr;
741  }
742 
743  AmgVector(5) newpars = tmppar->parameters();
744 
745  if (newpars[Trk::qOverP] != 0) {
746  const double sign = (newpars[Trk::qOverP] > 0) ? 1 : -1;
747  const double de = std::abs(meff->energyLoss()->deltaE());
748  const double oldp = std::abs(1 / newpars[Trk::qOverP]);
749  const double newp2 = oldp * oldp + (!firstismuon ? 2 : -2) * de * std::sqrt(mass * mass + oldp * oldp) + de * de;
750 
751  if (newp2 > 0) {
752  newpars[Trk::qOverP] = sign / std::sqrt(newp2);
753  }
754  }
755 
756  tp_closestmuon=tmppar->associatedSurface().createUniqueTrackParameters(
757  newpars[0], newpars[1], newpars[2], newpars[3], newpars[4], std::nullopt
758  );
759  }
760 
761  if (!firstismuon) {
762  std::reverse(tmp_matvec.begin(), tmp_matvec.end());
763  }
764  }
765 
766  const Trk::TrackStates::const_iterator beginStates = intrk1.trackStateOnSurfaces()->begin();
767  Trk::TrackStates::const_iterator itStates = beginStates;
768  const Trk::TrackStates::const_iterator endState = firstismuon ? tsosit + 1 : intrk1.trackStateOnSurfaces()->end();
769  const Trk::TrackStates::const_iterator beginStates2 = !firstismuon ? tsosit : intrk2.trackStateOnSurfaces()->begin();
770  Trk::TrackStates::const_iterator itStates2 = beginStates2;
771  const Trk::TrackStates::const_iterator endState2 = intrk2.trackStateOnSurfaces()->end();
772 
773  for (; itStates != endState; ++itStates) {
774  if (firstismuon && (*itStates)->measurementOnTrack()->type(Trk::MeasurementBaseType::PseudoMeasurementOnTrack)) {
775  continue;
776  }
777 
778  const bool tmpgetmat = cache.m_getmaterialfromtrack;
779 
780  if ((*itStates)->materialEffectsOnTrack() != nullptr) {
781  if (firstismuon) {
782  cache.m_extmat = false;
783  } else {
784  cache.m_idmat = false;
785  }
786 
787  const auto *const pBaseMEOT = (*itStates)->materialEffectsOnTrack();
788  const bool itsAnMEOT = (pBaseMEOT->derivedType() == MaterialEffectsBase::MATERIAL_EFFECTS_ON_TRACK);
789 
790  if (itsAnMEOT ){
791  const auto *const pMEOT =static_cast<const MaterialEffectsOnTrack *>((*itStates)->materialEffectsOnTrack());
792  if ((pMEOT->scatteringAngles() == nullptr) or (pMEOT->energyLoss() == nullptr)) {
793  cache.m_getmaterialfromtrack = true; // always take calorimeter layers
794  }
795  }
796  }
797 
798  makeProtoState(cache, trajectory, *itStates);
799  cache.m_getmaterialfromtrack = tmpgetmat;
800  }
801 
802  if (
803  !firstismuon &&
805  ) {
806  trajectory.trackStates().back()->setTrackParameters(nullptr);
807  }
808 
809  std::unique_ptr<const TrackParameters> firstscatpar;
810  std::unique_ptr<const TrackParameters> lastscatpar;
811  const TrackParameters *origlastidpar = unique_clone(lastidpar).release();
812 
813  double newqoverpid = 0;
814 
815  if (!firstismuon) {
816  const double de = std::abs(calomeots[1].energyLoss()->deltaE());
817  const double sigmade = std::abs(calomeots[1].energyLoss()->sigmaDeltaE());
818 
819  const double pbefore = std::abs(1 / firstidpar->parameters()[Trk::qOverP]);
820  const double pafter = std::abs(1 / tp_closestmuon->parameters()[Trk::qOverP]);
821  const double elosspull = (pbefore - pafter - de) / sigmade;
822 
823  if (std::abs(elosspull) > 10) {
824  if (elosspull > 10) {
825  newqoverpid = 1 / (de + pafter + 10 * sigmade);
826  } else {
827  newqoverpid = 1 / (de + pafter - 10 * sigmade);
828  }
829 
830  if (tp_closestmuon->parameters()[Trk::qOverP] * newqoverpid < 0) {
831  newqoverpid *= -1;
832  }
833 
834  const AmgVector(5) & newpar = firstidpar->parameters();
835  firstidpar=firstidpar->associatedSurface().createUniqueTrackParameters(
836  newpar[0], newpar[1], newpar[2], newpar[3], newqoverpid, std::nullopt
837  );
838  }
839 
840  lastidpar = m_extrapolator->extrapolateToVolume(
841  ctx, *firstidpar, *cache.m_caloEntrance, alongMomentum, Trk::muon);
842  }
843 
844  if (lastidpar == nullptr) {
845  lastidpar = unique_clone(origlastidpar);
846  }
847 
848  firstscatpar= m_propagator->propagateParameters(
849  ctx,
850  *(firstismuon ? tp_closestmuon.get() : lastidpar.get()),
851  calomeots[0].associatedSurface(),
853  false,
854  trajectory.m_fieldprop,
856  );
857 
858  if (firstscatpar == nullptr) {
859  return nullptr;
860  }
861 
862  lastscatpar = m_propagator->propagateParameters(
863  ctx,
864  *(firstismuon ? firstidpar : tp_closestmuon),
865  calomeots[2].associatedSurface(),
867  false,
868  trajectory.m_fieldprop,
870  );
871 
872  if (lastscatpar == nullptr) {
873  return nullptr;
874  }
875 
876  std::optional<TransportJacobian> jac1;
877  std::optional<TransportJacobian> jac2;
878  std::unique_ptr<const TrackParameters> elosspar;
879 
880  double firstscatphi = 0;
881  double secondscatphi = 0;
882  double firstscattheta = 0;
883  double secondscattheta = 0;
884  double muonscatphi = 0;
885  double muonscattheta = 0;
886 
887  const TrackParameters *idscatpar = !firstismuon ? firstscatpar.get() : lastscatpar.get();
888  const TrackParameters *muonscatpar = firstismuon ? firstscatpar.get() : lastscatpar.get();
889 
890  newqoverpid = idscatpar->parameters()[Trk::qOverP];
891 
892  const Amg::Vector3D calosegment = lastscatpar->position() - firstscatpar->position();
893  muonscatphi = xAOD::P4Helpers::deltaPhi(calosegment.phi(), muonscatpar->parameters()[Trk::phi]);
894 
895  muonscattheta = calosegment.theta() - muonscatpar->parameters()[Trk::theta];
896  std::unique_ptr<const TrackParameters> startPar = unique_clone(cache.m_idmat ? lastidpar.get() : indettrack->perigeeParameters());
897 
898  for (int i = 0; i < 2; i++) {
899  std::unique_ptr<const TrackParameters> tmpelosspar;
900  AmgVector(5) params1 = muonscatpar->parameters();
901  params1[Trk::phi] += muonscatphi;
902  params1[Trk::theta] += muonscattheta;
903 
904  if (!correctAngles(params1[Trk::phi], params1[Trk::theta])) {
905  return nullptr;
906  }
907 
908  const std::unique_ptr<const TrackParameters> tmppar1(muonscatpar->associatedSurface().createUniqueTrackParameters(
909  params1[0], params1[1], params1[2], params1[3], params1[4], std::nullopt
910  ));
911 
912  const PropDirection propdir = !firstismuon ? oppositeMomentum : alongMomentum;
913 
914  tmpelosspar = m_propagator->propagateParameters(
915  ctx,
916  *tmppar1,
917  calomeots[1].
918  associatedSurface(),
919  propdir,
920  false,
921  trajectory.m_fieldprop,
922  jac1,
924  );
925 
926  if (m_numderiv) {
927  jac1 = numericalDerivatives(
928  ctx,
929  firstscatpar.get(),
930  calomeots[1].associatedSurface(),
931  propdir,
932  trajectory.m_fieldprop
933  );
934  }
935 
936  if ((tmpelosspar == nullptr) || (jac1 == std::nullopt)) {
937  // @TODO
938  // according to coverity elosspar cannot be non NULL here
939  // because elosspar is initially NULL and only set in the last loop iteration (i==1)
940  // is this intended ?
941  // delete elosspar;
942  return nullptr;
943  }
944 
945  const AmgVector(5) & newpars = tmpelosspar->parameters();
946  const std::unique_ptr<const TrackParameters> elosspar2(tmpelosspar->associatedSurface().createUniqueTrackParameters(
947  newpars[0], newpars[1], newpars[2], newpars[3], newqoverpid, std::nullopt
948  ));
949 
950  if (i == 1) {
951  elosspar = std::move(tmpelosspar);
952  }
953 
954  std::unique_ptr<const TrackParameters> scat2(m_propagator->propagateParameters(
955  ctx,
956  *elosspar2,
957  !firstismuon ?
958  calomeots[0].associatedSurface() :
959  calomeots[2].associatedSurface(),
960  propdir,
961  false,
962  trajectory.m_fieldprop,
963  jac2,
965  ));
966 
967  if (m_numderiv) {
968  jac2 = numericalDerivatives(
969  ctx,
970  elosspar2.get(),
971  !firstismuon ?
972  calomeots[0].associatedSurface() :
973  calomeots[2].associatedSurface(),
974  !firstismuon ?
977  trajectory.m_fieldprop
978  );
979  }
980 
981  if ((scat2 == nullptr) || (jac2 == std::nullopt)) {
982  return nullptr;
983  }
984 
985  double jac3[5][5];
986  for (int j = 0; j < 5; j++) {
987  for (int k = 0; k < 5; k++) {
988  jac3[j][k] = 0;
989  for (int l = 0; l < 5; l++) {
990  jac3[j][k] += (*jac2) (j, l) * (*jac1) (l, k);
991  }
992  }
993  }
994 
995  jac1.reset();
996  jac2.reset();
997  Amg::MatrixX jac4(2, 2);
998 
999  jac4(0, 0) = jac3[0][2];
1000  jac4(1, 1) = jac3[1][3];
1001  jac4(0, 1) = jac3[0][3];
1002  jac4(1, 0) = jac3[1][2];
1003 
1004  jac4 = jac4.inverse();
1005 
1006  double dloc1 = idscatpar->parameters()[Trk::loc1] - scat2->parameters()[Trk::loc1];
1007  double dloc2 = idscatpar->parameters()[Trk::loc2] - scat2->parameters()[Trk::loc2];
1008  const Trk::CylinderSurface * cylsurf = nullptr;
1009 
1010  if (scat2->associatedSurface().type() == Trk::SurfaceType::Cylinder)
1011  cylsurf = static_cast<const Trk::CylinderSurface *>(&scat2->associatedSurface());
1012 
1013  const Trk::DiscSurface * discsurf = nullptr;
1014 
1015  if (scat2->associatedSurface().type() == Trk::SurfaceType::Cylinder)
1016  discsurf = static_cast<const Trk::DiscSurface *>(&scat2->associatedSurface());
1017 
1018  if (cylsurf != nullptr) {
1019  dloc1 = -std::remainder(-dloc1, 2 * M_PI * cylsurf->bounds().r());
1020  }
1021 
1022  if (discsurf != nullptr) {
1023  dloc2 = -std::remainder(-dloc2, 2 * M_PI);
1024  }
1025 
1026  double dphi = jac4(0, 0) * dloc1 + jac4(0, 1) * dloc2;
1027  double dtheta = jac4(1, 0) * dloc1 + jac4(1, 1) * dloc2;
1028 
1029  if (i == 1) {
1030  dphi = dtheta = 0;
1031  }
1032 
1033  muonscatphi += dphi;
1034  muonscattheta += dtheta;
1035 
1036  const double idscatphi = xAOD::P4Helpers::deltaPhi(idscatpar->parameters()[Trk::phi], scat2->parameters()[Trk::phi] + dphi);
1037  const double idscattheta = idscatpar->parameters()[Trk::theta] - (scat2->parameters()[Trk::theta] + dtheta);
1038 
1039  if (firstismuon) {
1040  firstscatphi = muonscatphi;
1041  secondscatphi = idscatphi;
1042  firstscattheta = muonscattheta;
1043  secondscattheta = idscattheta;
1044  } else {
1045  firstscatphi = -idscatphi;
1046  secondscatphi = -muonscatphi;
1047  firstscattheta = -idscattheta;
1048  secondscattheta = -muonscattheta;
1049  }
1050 
1051  if (i == 1 && cache.m_field_cache.toroidOn() && !firstismuon) {
1052  AmgVector(5) params2 = scat2->parameters();
1053  params2[Trk::phi] += idscatphi;
1054  params2[Trk::theta] += idscattheta;
1055 
1056  if (!correctAngles(params2[Trk::phi], params2[Trk::theta])) {
1057  return nullptr;
1058  }
1059 
1060  firstscatpar=scat2->associatedSurface().createUniqueTrackParameters(
1061  params2[0], params2[1], params2[2], params2[3], params2[4], std::nullopt
1062  );
1063  idscatpar = firstscatpar.get();
1064 
1065  startPar = m_extrapolator->extrapolateToVolume(ctx,
1066  *idscatpar,
1067  *cache.m_caloEntrance,
1070 
1071  if (startPar != nullptr) {
1072  const Amg::Vector3D trackdir = startPar->momentum().unit();
1073  const Amg::Vector3D curvZcrossT = -(trackdir.cross(Amg::Vector3D(0, 0, 1)));
1074  const Amg::Vector3D curvU = curvZcrossT.unit();
1075  const Amg::Vector3D curvV = trackdir.cross(curvU);
1076  Amg::RotationMatrix3D rot = Amg::RotationMatrix3D::Identity();
1077 
1078  rot.col(0) = curvU;
1079  rot.col(1) = curvV;
1080  rot.col(2) = trackdir;
1081 
1082  Amg::Transform3D trans;
1083  trans.linear().matrix() << rot;
1084  trans.translation() << startPar->position() - .1 * trackdir;
1085  PlaneSurface const curvlinsurf(trans);
1086 
1087  const TrackParameters *curvlinpar = m_extrapolator->extrapolateDirectly(
1088  ctx,
1089  *startPar,
1090  curvlinsurf,
1093  ).release();
1094 
1095  if (curvlinpar != nullptr) {
1096  startPar.reset(curvlinpar);
1097  }
1098  }
1099 
1100  firstscatpar = std::move(scat2);
1101  }
1102  }
1103 
1104  std::unique_ptr<GXFMaterialEffects> firstscatmeff = std::make_unique<GXFMaterialEffects>(calomeots[0]);
1105  std::unique_ptr<GXFMaterialEffects> elossmeff = std::make_unique<GXFMaterialEffects>(calomeots[1]);
1106  std::unique_ptr<GXFMaterialEffects> secondscatmeff = std::make_unique<GXFMaterialEffects>(calomeots[2]);
1107 
1108  const double pull1 = std::abs(firstscatphi / firstscatmeff->sigmaDeltaPhi());
1109  const double pull2 = std::abs(secondscatphi / secondscatmeff->sigmaDeltaPhi());
1110 
1111  if (firstismuon) {
1112  for (auto & i : tmp_matvec) {
1113  makeProtoState(cache, trajectory, i, -1);
1114  }
1115  }
1116 
1117  firstscatmeff->setScatteringAngles(firstscatphi, firstscattheta);
1118  secondscatmeff->setScatteringAngles(secondscatphi, secondscattheta);
1119 
1120  if (!firstismuon) {
1121  elossmeff->setdelta_p(1000 * (lastscatpar->parameters()[Trk::qOverP] - newqoverpid));
1122  } else {
1123  elossmeff->setdelta_p(1000 * (newqoverpid - firstscatpar->parameters()[Trk::qOverP]));
1124  }
1125 
1126  elossmeff->setSigmaDeltaE(calomeots[1].energyLoss()->sigmaDeltaE());
1127 
1128  trajectory.addMaterialState(std::make_unique<GXFTrackState>(std::move(firstscatmeff), std::move(firstscatpar)), -1);
1129  trajectory.addMaterialState(std::make_unique<GXFTrackState>(std::move(elossmeff), std::move(elosspar)), -1);
1130  trajectory.addMaterialState(std::make_unique<GXFTrackState>(std::move(secondscatmeff), std::move(lastscatpar)), -1);
1131 
1132  if (!firstismuon) {
1133  for (auto & i : tmp_matvec) {
1134  makeProtoState(cache, trajectory, i, -1);
1135  }
1136  }
1137 
1138  ATH_MSG_DEBUG("pull1: " << pull1 << " pull2: " << pull2);
1139 
1140  if (startPar == nullptr) {
1141  return nullptr;
1142  }
1143 
1144  if (
1145  (pull1 > 5 || pull2 > 5) &&
1146  (pull1 > 25 || pull2 > 25 || closestmuonmeas->associatedSurface().type() == Trk::SurfaceType::Line)
1147  ) {
1148  return nullptr;
1149  }
1150 
1151  bool largegap = false;
1152  double previousz = 0;
1153 
1154  for (itStates2 = beginStates2; itStates2 != endState2; ++itStates2) {
1155  const MaterialEffectsBase *meff = (*itStates2)->materialEffectsOnTrack();
1156  const TrackParameters *tpar = (*itStates2)->trackParameters();
1157  const MeasurementBase *meas = (*itStates2)->measurementOnTrack();
1158 
1159  if (meff != nullptr) {
1160  if (!firstismuon) {
1161  const MaterialEffectsOnTrack *mefot{};
1163  mefot = static_cast<const MaterialEffectsOnTrack *>(meff);
1164  }
1165  if ( mefot and mefot->energyLoss() and
1166  std::abs(mefot->energyLoss()->deltaE()) > 250 &&
1167  mefot->energyLoss()->sigmaDeltaE() < 1.e-9
1168  ) {
1169  return nullptr;
1170  }
1171 
1172  cache.m_extmat = false;
1173  } else {
1174  cache.m_idmat = false;
1175  }
1176  }
1178  if (
1179  ispseudo &&
1180  !(itStates2 == beginStates2 || itStates2 == beginStates2 + 1) &&
1181  !largegap
1182  ) {
1183  continue;
1184  }
1185 
1186  makeProtoState(cache, trajectory, *itStates2);
1187 
1188  if (
1189  itStates2 == endState2 - 1 &&
1191  tpar->position().perp() > 9000 &&
1192  std::abs(tpar->position().z()) < 13000
1193  ) {
1194  std::unique_ptr<const TrackParameters> pseudopar(tpar->clone());
1195  Amg::MatrixX covMatrix(1, 1);
1196  covMatrix(0, 0) = 100;
1197 
1198  std::unique_ptr<const PseudoMeasurementOnTrack> newpseudo = std::make_unique<const PseudoMeasurementOnTrack>(
1199  LocalParameters(DefinedParameter(pseudopar->parameters()[Trk::locY], Trk::locY)),
1200  std::move(covMatrix),
1201  pseudopar->associatedSurface()
1202  );
1203 
1204  std::unique_ptr<GXFTrackState> pseudostate = std::make_unique<GXFTrackState>(std::move(newpseudo), std::move(pseudopar));
1205  pseudostate->setMeasurementType(TrackState::Pseudo);
1206 
1207  double errors[5];
1208  errors[0] = errors[2] = errors[3] = errors[4] = -1;
1209  errors[1] = 10;
1210 
1211  pseudostate->setMeasurementErrors(errors);
1212  trajectory.addMeasurementState(std::move(pseudostate));
1213  ispseudo = true;
1214  ATH_MSG_DEBUG("Adding pseudomeasurement");
1215  }
1216 
1217  if (
1218  std::abs(trajectory.trackStates().back()->position().z()) > 20000 &&
1219  std::abs(previousz) < 12000
1220  ) {
1221  largegap = true;
1222  }
1223 
1224  if (trajectory.trackStates().back()->getStateType(TrackStateOnSurface::Measurement)) {
1225  previousz = trajectory.trackStates().back()->position().z();
1226  }
1227  }
1228 
1229  Track *track = myfit(
1230  ctx,
1231  cache,
1232  trajectory,
1233  *startPar,
1234  false,
1236  );
1237 
1238  return track;
1239  }
1240 
1241  Track *
1243  const EventContext& ctx,
1244  Cache & cache,
1245  const Track & intrk1,
1246  const Track & intrk2,
1247  GXFTrajectory & trajectory,
1248  std::vector<MaterialEffectsOnTrack> & calomeots
1249  ) const {
1250  ATH_MSG_DEBUG("--> entering GlobalChi2Fitter::backupCombinationStrategy");
1251 
1252  const bool firstismuon = isMuonTrack(intrk1);
1253  const Track *indettrack = firstismuon ? &intrk2 : &intrk1;
1254 
1255  const Trk::TrackStates::const_iterator beginStates = intrk1.trackStateOnSurfaces()->begin();
1256  Trk::TrackStates::const_iterator itStates = beginStates;
1257  const Trk::TrackStates::const_iterator endState = intrk1.trackStateOnSurfaces()->end();
1258  const Trk::TrackStates::const_iterator beginStates2 = intrk2.trackStateOnSurfaces()->begin();
1259  Trk::TrackStates::const_iterator itStates2 = beginStates2;
1260  const Trk::TrackStates::const_iterator endState2 = intrk2.trackStateOnSurfaces()->end();
1261 
1262  const TrackParameters *firstidpar = nullptr;
1263  const auto *const pParametersVector = indettrack->trackParameters();
1264  // Dont understand why the second track parameters are taken
1265  // Is it assumed the ID track is slimmed?
1266  if (pParametersVector->size() > 1)
1267  firstidpar = (*pParametersVector)[1];
1268  else
1269  firstidpar = pParametersVector->back();
1270 
1271  std::unique_ptr<const TrackParameters> lastidpar = nullptr;
1272  if ((firstidpar != nullptr) && (cache.m_caloEntrance != nullptr))
1273  lastidpar = m_extrapolator->extrapolateToVolume(
1274  ctx, *firstidpar, *cache.m_caloEntrance, alongMomentum, Trk::muon);
1275 
1276  if (lastidpar == nullptr) {
1277  lastidpar.reset(pParametersVector->back()->clone());
1278  }
1279 
1280  std::unique_ptr < const TrackParameters > firstscatpar;
1281  std::unique_ptr < const TrackParameters > lastscatpar;
1282  std::unique_ptr < const TrackParameters > elosspar;
1283 
1284  const double charge = (lastidpar->parameters()[Trk::qOverP] < 0) ? -1 : 1;
1285 
1286  Perigee startper(
1287  lastidpar->position(),
1288  lastidpar->momentum(),
1289  charge,
1290  lastidpar->position()
1291  );
1292 
1293  if (!firstismuon) {
1294  firstscatpar = m_propagator->propagateParameters(
1295  ctx,
1296  *lastidpar,
1297  calomeots[0].associatedSurface(),
1299  false,
1300  trajectory.m_fieldprop,
1302 
1303  if (!firstscatpar) {
1304  return nullptr;
1305  }
1306 
1307  const std::unique_ptr<const TrackParameters> tmppar(
1308  m_propagator->propagateParameters(
1309  ctx,
1310  *firstscatpar,
1311  calomeots[1].associatedSurface(),
1313  false,
1314  trajectory.m_fieldprop,
1316 
1317  if (!tmppar) {
1318  return nullptr;
1319  }
1320 
1321  const double sign = (tmppar->parameters()[Trk::qOverP] < 0) ? -1 : 1;
1322  const double mass = Trk::ParticleMasses::mass[muon];
1323 
1324  const double oldp = std::abs(1 / tmppar->parameters()[Trk::qOverP]);
1325  const double de = std::abs(calomeots[1].energyLoss()->deltaE());
1326 
1327  double newp2 = oldp * oldp - 2 * de * std::sqrt(mass * mass + oldp * oldp) + de * de;
1328 
1329  if (newp2 < 4.e6) {
1330  newp2 = 4.e6;
1331  }
1332 
1333  const double newqoverp = sign / std::sqrt(newp2);
1334 
1335  const AmgVector(5) & pars = tmppar->parameters();
1336 
1337  elosspar=
1338  tmppar->associatedSurface().createUniqueTrackParameters(
1339  pars[0], pars[1], pars[2], pars[3], newqoverp, std::nullopt
1340  );
1341 
1342  lastscatpar = m_propagator->propagateParameters(
1343  ctx,
1344  *elosspar,
1345  calomeots[2].associatedSurface(),
1347  false,
1348  trajectory.m_fieldprop,
1350 
1351  if (!lastscatpar) {
1352  return nullptr;
1353  }
1354  } else {
1355  lastscatpar = m_propagator->propagateParameters(
1356  ctx,
1357  *firstidpar,
1358  calomeots[2].associatedSurface(),
1360  false,
1361  trajectory.m_fieldprop,
1363  );
1364 
1365  if (!lastscatpar) {
1366  return nullptr;
1367  }
1368 
1369  elosspar= m_propagator->propagateParameters(
1370  ctx,
1371  *lastscatpar,
1372  calomeots[1].associatedSurface(),
1374  false,
1375  trajectory.m_fieldprop,
1377  );
1378 
1379  if (!elosspar) {
1380  return nullptr;
1381  }
1382 
1383  const double sign = (elosspar->parameters()[Trk::qOverP] < 0) ? -1 : 1;
1384  const double newqoverp = sign /
1385  (1. / std::abs(elosspar->parameters()[Trk::qOverP]) +
1386  std::abs(calomeots[1].energyLoss()->deltaE()));
1387 
1388  const AmgVector(5) & pars = elosspar->parameters();
1389 
1390  std::unique_ptr<const TrackParameters>const tmppar(
1391  elosspar->associatedSurface().createUniqueTrackParameters(
1392  pars[0], pars[1], pars[2], pars[3], newqoverp, std::nullopt
1393  )
1394  );
1395 
1396  firstscatpar = m_propagator->propagateParameters(
1397  ctx,
1398  *tmppar,
1399  calomeots[0].associatedSurface(),
1401  false,
1402  trajectory.m_fieldprop,
1404  );
1405 
1406  if (!firstscatpar) {
1407  return nullptr;
1408  }
1409  }
1410 
1411  for (; itStates != endState; ++itStates) {
1412  if (
1413  firstismuon &&
1414  (*itStates)->measurementOnTrack()->type(Trk::MeasurementBaseType::PseudoMeasurementOnTrack)
1415  ) {
1416  continue;
1417  }
1418 
1419  if ((*itStates)->materialEffectsOnTrack() != nullptr) {
1420  if (!firstismuon) {
1421  cache.m_idmat = false;
1422  } else {
1423  continue;
1424  }
1425  }
1426 
1427  if (firstismuon) {
1428  makeProtoState(cache, trajectory, *itStates);
1429  }
1430  }
1431 
1432  std::unique_ptr<GXFMaterialEffects> firstscatmeff = std::make_unique<GXFMaterialEffects>(calomeots[0]);
1433  std::unique_ptr<GXFMaterialEffects> elossmeff = std::make_unique<GXFMaterialEffects>(calomeots[1]);
1434  std::unique_ptr<GXFMaterialEffects> secondscatmeff = std::make_unique<GXFMaterialEffects>(calomeots[2]);
1435 
1436  double dp = 0;
1437  double sigmadp = 0;
1438  sigmadp = calomeots[1].energyLoss()->sigmaDeltaE();
1439  elossmeff->setSigmaDeltaE(sigmadp);
1440 
1441  dp = 1000 * (lastscatpar->parameters()[Trk::qOverP] - firstscatpar->parameters()[Trk::qOverP]);
1442  elossmeff->setdelta_p(dp);
1443 
1444  trajectory.addMaterialState(std::make_unique<GXFTrackState>(std::move(firstscatmeff), std::move(firstscatpar)), -1);
1445  trajectory.addMaterialState(std::make_unique<GXFTrackState>(std::move(elossmeff), std::move(elosspar)), -1);
1446  trajectory.addMaterialState(std::make_unique<GXFTrackState>(std::move(secondscatmeff), std::move(lastscatpar)), -1);
1447 
1448  GXFTrackState *secondscatstate = trajectory.trackStates().back().get();
1449  const Surface *triggersurf1 = nullptr;
1450  const Surface *triggersurf2 = nullptr;
1451  Amg::Vector3D triggerpos1(0, 0, 0);
1452  Amg::Vector3D triggerpos2(0, 0, 0);
1453 
1454  bool seenmdt = false;
1455  bool mdtbetweenphihits = false;
1456  int nphi = 0;
1457 
1458  for (
1459  itStates2 = (!firstismuon ? beginStates2 : endState - 1);
1460  itStates2 != (!firstismuon ? endState2 : beginStates - 1);
1461  (!firstismuon ? ++itStates2 : --itStates2)
1462  ) {
1463  if (
1464  ((*itStates2)->measurementOnTrack() == nullptr) ||
1465  (*itStates2)->type(TrackStateOnSurface::Outlier)
1466  ) {
1467  continue;
1468  }
1469  const auto *const pMeasurement = (*itStates2)->measurementOnTrack();
1470  const Surface *surf = &pMeasurement->associatedSurface();
1471  const bool isCompetingRIOsOnTrack = pMeasurement->type(Trk::MeasurementBaseType::CompetingRIOsOnTrack);
1472  const RIO_OnTrack *rot = nullptr;
1473 
1474  if (isCompetingRIOsOnTrack) {
1475  const auto *const crot = static_cast<const CompetingRIOsOnTrack *>(pMeasurement);
1476  rot = &crot->rioOnTrack(0);
1477  } else {
1478  if (pMeasurement->type(Trk::MeasurementBaseType::RIO_OnTrack)){
1479  rot = static_cast<const RIO_OnTrack *>(pMeasurement);
1480  }
1481  }
1482  if ((rot != nullptr) && m_DetID->is_mdt(rot->identify()) && (triggersurf1 != nullptr)) {
1483  seenmdt = true;
1484  }
1485  if (
1486  (rot != nullptr) && (
1487  m_DetID->is_tgc(rot->identify()) ||
1488  m_DetID->is_rpc(rot->identify()) ||
1489  m_DetID->is_stgc(rot->identify())
1490  )
1491  ) {
1492  const Amg::Vector3D measdir = surf->transform().rotation().col(0);
1493  const double dotprod1 = measdir.dot(Amg::Vector3D(0, 0, 1));
1494  const double dotprod2 = measdir.dot(Amg::Vector3D(surf->center().x(), surf->center().y(), 0) / surf->center().perp());
1495 
1496  const bool measphi = std::abs(dotprod1) <= .5 && std::abs(dotprod2) <= .5;
1497  if (measphi) {
1498  nphi++;
1499  const Amg::Vector3D thispos =
1500  (*itStates2)->trackParameters() != nullptr ?
1501  (*itStates2)->trackParameters()->position() :
1502  rot->globalPosition();
1503  if (triggersurf1 != nullptr) {
1504  triggerpos2 = thispos;
1505  triggersurf2 = surf;
1506  if (seenmdt) {
1507  mdtbetweenphihits = true;
1508  }
1509  } else {
1510  triggerpos1 = thispos;
1511  triggersurf1 = surf;
1512  }
1513  }
1514  }
1515  }
1516 
1517  double mdttrig1 = 999999;
1518  double mdttrig2 = 999999;
1519  const Surface *mdtsurf1 = nullptr;
1520  const Surface *mdtsurf2 = nullptr;
1521 
1522  for (
1523  itStates2 = (!firstismuon ? beginStates2 : endState - 1);
1524  itStates2 != (!firstismuon ? endState2 : beginStates - 1);
1525  (!firstismuon ? ++itStates2 : --itStates2)
1526  ) {
1527  const Surface *surf = nullptr;
1528  if (
1529  ((*itStates2)->measurementOnTrack() != nullptr) &&
1530  !(*itStates2)->type(TrackStateOnSurface::Outlier)
1531  ) {
1532  surf = &(*itStates2)->measurementOnTrack()->associatedSurface();
1533  }
1534 
1535  if (surf == nullptr) {
1536  continue;
1537  }
1538  const auto *const pThisMeasurement = (*itStates2)->measurementOnTrack();
1539  const bool isCompetingRioOnTrack = pThisMeasurement->type(Trk::MeasurementBaseType::CompetingRIOsOnTrack);
1540  const RIO_OnTrack *rot = nullptr;
1541 
1542  if (isCompetingRioOnTrack) {
1543  const auto *crot = static_cast<const CompetingRIOsOnTrack *>(pThisMeasurement);
1544  rot = &crot->rioOnTrack(0);
1545  } else {
1546  if (pThisMeasurement->type(Trk::MeasurementBaseType::RIO_OnTrack)){
1547  rot = static_cast<const RIO_OnTrack *>(pThisMeasurement);
1548  }
1549  }
1550  const bool thisismdt = rot and m_DetID->is_mdt(rot->identify());
1551  if (thisismdt) {
1552  const Amg::Vector3D globpos =
1553  (*itStates2)->trackParameters() != nullptr ?
1554  (*itStates2)->trackParameters()->position() :
1555  pThisMeasurement->globalPosition();
1556  if (triggerpos1.mag() > 1 && (globpos - triggerpos1).mag() < mdttrig1) {
1557  mdttrig1 = (globpos - triggerpos1).mag();
1558  mdtsurf1 = surf;
1559  }
1560  if (triggerpos2.mag() > 1 && (globpos - triggerpos2).mag() < mdttrig2) {
1561  mdttrig2 = (globpos - triggerpos2).mag();
1562  mdtsurf2 = surf;
1563  }
1564  }
1565  }
1566 
1567  GXFTrackState * firstpseudostate = nullptr;
1568  std::vector<GXFTrackState *> outlierstates;
1569  std::vector<GXFTrackState *> outlierstates2;
1570 
1571  outlierstates.reserve(10);
1572  outlierstates2.reserve(10);
1573 
1574  std::unique_ptr<PseudoMeasurementOnTrack> newpseudo;
1575 
1576  for (itStates2 = beginStates2; itStates2 != endState2; ++itStates2) {
1577  const auto *const pMeasurement{(*itStates2)->measurementOnTrack()};
1578  const bool isPseudo = pMeasurement->type(Trk::MeasurementBaseType::PseudoMeasurementOnTrack);
1579  const bool isStraightLine =
1580  pMeasurement != nullptr ?
1581  pMeasurement->associatedSurface().type() == Trk::SurfaceType::Line :
1582  false;
1583 
1584  if (
1585  isStraightLine &&
1586  !firstismuon &&
1587  (newpseudo == nullptr) && (
1588  (itStates2 == beginStates2 || itStates2 == beginStates2 + 1) &&
1589  std::abs(pMeasurement->globalPosition().z()) < 10000
1590  )
1591  ) {
1592  std::unique_ptr<const TrackParameters> par2;
1593  if (((*itStates2)->trackParameters() != nullptr) && nphi > 99) {
1594  par2.reset((*itStates2)->trackParameters()->clone());
1595  } else {
1596  par2 = m_propagator->propagateParameters(
1597  ctx,
1598  *secondscatstate->trackParameters(),
1599  pMeasurement->associatedSurface(),
1600  alongMomentum,
1601  false,
1602  trajectory.m_fieldprop,
1604  );
1605  }
1606  if (par2 == nullptr) {
1607  continue;
1608  }
1609  Amg::MatrixX covMatrix(1, 1);
1610  covMatrix(0, 0) = 100;
1611 
1612  newpseudo = std::make_unique<PseudoMeasurementOnTrack>(
1613  LocalParameters(DefinedParameter(par2->parameters()[Trk::locY], Trk::locY)),
1614  std::move(covMatrix),
1615  par2->associatedSurface()
1616  );
1617 
1618  std::unique_ptr<GXFTrackState> firstpseudo = std::make_unique<GXFTrackState>(std::move(newpseudo), std::move(par2));
1619  firstpseudo->setMeasurementType(TrackState::Pseudo);
1620 
1621  double errors[5];
1622  errors[0] = errors[2] = errors[3] = errors[4] = -1;
1623  errors[1] = 10;
1624 
1625  firstpseudo->setMeasurementErrors(errors);
1626  firstpseudostate = firstpseudo.get();
1627  trajectory.addMeasurementState(std::move(firstpseudo));
1628  ATH_MSG_DEBUG("Adding PseudoMeasurement");
1629  continue;
1630  }
1631 
1632  if (isPseudo && !firstismuon) {
1633  continue;
1634  }
1635 
1636  if ((**itStates2).materialEffectsOnTrack() != nullptr) {
1637  if (firstismuon) {
1638  cache.m_idmat = false;
1639  } else {
1640  continue;
1641  }
1642  }
1643 
1644  if (!firstismuon) {
1645  if (
1646  ((**itStates2).measurementOnTrack() != nullptr) &&
1647  &(**itStates2).measurementOnTrack()->associatedSurface() == triggersurf1 &&
1648  (mdtsurf1 != nullptr)
1649  ) {
1650  std::unique_ptr<Amg::Transform3D> transf = std::make_unique<Amg::Transform3D>(mdtsurf1->transform());
1651 
1652  transf->translation() << triggerpos1;
1653  StraightLineSurface const slsurf(*transf);
1654  Amg::MatrixX covMatrix(1, 1);
1655  covMatrix(0, 0) = 100;
1656 
1657  std::unique_ptr<const PseudoMeasurementOnTrack> newpseudo = std::make_unique<const PseudoMeasurementOnTrack>(
1658  LocalParameters(DefinedParameter(0, Trk::locY)), std::move(covMatrix), slsurf
1659  );
1660 
1661  std::unique_ptr<GXFTrackState> pseudostate1 = std::make_unique<GXFTrackState>(std::move(newpseudo), nullptr);
1662  pseudostate1->setMeasurementType(TrackState::Pseudo);
1663 
1664  double errors[5];
1665  errors[0] = errors[2] = errors[3] = errors[4] = -1;
1666  errors[1] = 10;
1667 
1668  pseudostate1->setMeasurementErrors(errors);
1669  outlierstates2.push_back(pseudostate1.get());
1670  trajectory.addMeasurementState(std::move(pseudostate1));
1671  }
1672 
1673  if (
1674  ((**itStates2).measurementOnTrack() != nullptr) &&
1675  &(**itStates2).measurementOnTrack()->associatedSurface() == triggersurf2 &&
1676  mdtbetweenphihits &&
1677  (mdtsurf2 != nullptr)
1678  ) {
1679  std::unique_ptr<Amg::Transform3D> transf = std::make_unique<Amg::Transform3D>(mdtsurf2->transform());
1680  transf->translation() << triggerpos2;
1681  StraightLineSurface const slsurf(*transf);
1682  Amg::MatrixX covMatrix(1, 1);
1683  covMatrix(0, 0) = 100;
1684 
1685  std::unique_ptr<const PseudoMeasurementOnTrack> newpseudo = std::make_unique<const PseudoMeasurementOnTrack>(
1686  LocalParameters(DefinedParameter(0, Trk::locY)), std::move(covMatrix), slsurf
1687  );
1688 
1689  std::unique_ptr<GXFTrackState> pseudostate2 = std::make_unique<GXFTrackState>(std::move(newpseudo), nullptr);
1690  pseudostate2->setMeasurementType(TrackState::Pseudo);
1691 
1692  double errors[5];
1693  errors[0] = errors[2] = errors[3] = errors[4] = -1;
1694  errors[1] = 10;
1695 
1696  pseudostate2->setMeasurementErrors(errors);
1697  // cppcheck-suppress invalidLifetime; false positive
1698  outlierstates2.push_back(pseudostate2.get());
1699  trajectory.addMeasurementState(std::move(pseudostate2));
1700  }
1701 
1702  makeProtoState(cache, trajectory, *itStates2);
1703 
1704  if (
1705  (
1706  trajectory.trackStates().back()->measurementType() == TrackState::TGC ||
1707  (
1708  trajectory.trackStates().back()->measurementType() == TrackState::RPC &&
1709  trajectory.trackStates().back()->measuresPhi()
1710  )
1711  ) &&
1712  trajectory.trackStates().back()->getStateType(TrackStateOnSurface::Measurement)
1713  ) {
1714  outlierstates.push_back(trajectory.trackStates().back().get());
1715  trajectory.setOutlier((int) trajectory.trackStates().size() - 1, true);
1716  }
1717  }
1718  }
1719 
1720  trajectory.setNumberOfPerigeeParameters(0);
1721 
1722  Track *track = nullptr;
1723 
1724  trajectory.setPrefit(2);
1725  const TrackParameters *startpar2 = &startper;
1726  cache.m_matfilled = true;
1727  const bool tmpacc = cache.m_acceleration;
1728  cache.m_acceleration = false;
1729  // @TODO eventually track created but not used why ?
1730  const std::unique_ptr<Trk::Track> tmp_track(
1731  myfit(ctx, cache, trajectory, *startpar2, false, muon));
1732  cache.m_acceleration = tmpacc;
1733 
1734  cache.m_matfilled = false;
1735  if (
1736  !firstismuon &&
1737  trajectory.converged() &&
1738  std::abs(trajectory.residuals().tail<1>()(0) / trajectory.errors().tail<1>()(0)) > 10
1739  ) {
1740  return nullptr;
1741  }
1742 
1743  if (trajectory.converged()) {
1744  if (firstpseudostate != nullptr) {
1745  const TrackParameters *par2 = firstpseudostate->trackParameters();
1746  Amg::MatrixX covMatrix(1, 1);
1747  covMatrix(0, 0) = 100;
1748 
1749  std::unique_ptr<const PseudoMeasurementOnTrack> newpseudo = std::make_unique<const PseudoMeasurementOnTrack>(
1750  LocalParameters(DefinedParameter(par2->parameters()[Trk::locY], Trk::locY)),
1751  std::move(covMatrix),
1752  par2->associatedSurface()
1753  );
1754  firstpseudostate->setMeasurement(std::move(newpseudo));
1755  firstpseudostate->setRecalibrated(false);
1756  }
1757 
1758  for (int j = 0; j < (int) trajectory.trackStates().size(); j++) {
1759  for (const auto & i : outlierstates2) {
1760  if (trajectory.trackStates()[j].get() == i) {
1761  trajectory.setOutlier(j, true);
1762  }
1763  }
1764 
1765  for (const auto & i : outlierstates) {
1766  if (trajectory.trackStates()[j].get() == i) {
1767  trajectory.setOutlier(j, false);
1768  }
1769  }
1770  }
1771 
1772  for (
1773  itStates = (firstismuon ? beginStates2 : endState - 1);
1774  itStates != (firstismuon ? endState2 : beginStates - 1);
1775  (firstismuon ? ++itStates : --itStates)
1776  ) {
1777  if ((*itStates)->measurementOnTrack()->type(Trk::MeasurementBaseType::PseudoMeasurementOnTrack)) {
1778  continue;
1779  }
1780 
1781  makeProtoState(cache, trajectory, *itStates, (firstismuon ? -1 : 0));
1782  }
1783 
1784  trajectory.reset();
1785  trajectory.setPrefit(0);
1786  trajectory.setNumberOfPerigeeParameters(5);
1787  track = myfit(ctx, cache, trajectory, *firstidpar, false, muon);
1788  cache.m_matfilled = false;
1789  }
1790 
1791  return track;
1792  }
1793 
1794  std::unique_ptr<Track>
1796  const EventContext& ctx,
1797  const Track& inputTrack,
1798  const RunOutlierRemoval runOutlier,
1799  const ParticleHypothesis matEffects) const
1800  {
1801  ATH_MSG_DEBUG("--> entering GlobalChi2Fitter::fit(Track,)");
1802 
1803  Cache cache(this);
1804  initFieldCache(ctx,cache);
1805 
1806  GXFTrajectory trajectory;
1807 
1808  if (!m_straightlineprop) {
1809  trajectory.m_straightline = (!cache.m_field_cache.solenoidOn() && !cache.m_field_cache.toroidOn());
1810  }
1811 
1812  trajectory.m_fieldprop = trajectory.m_straightline ? Trk::NoField : Trk::FullField;
1813 
1814  return std::unique_ptr<Track>(
1815  fitIm(ctx, cache, inputTrack, runOutlier, matEffects));
1816  }
1817 
1818  Track *
1819  GlobalChi2Fitter::alignmentFit(AlignmentCache& alignCache,
1820  const Track &inputTrack,
1821  const RunOutlierRemoval runOutlier,
1822  const ParticleHypothesis matEffects) const {
1823 
1824 
1825  const EventContext& ctx = Gaudi::Hive::currentContext();
1826  Cache cache(this);
1827  initFieldCache(ctx, cache);
1828 
1829  delete alignCache.m_derivMatrix;
1830  alignCache.m_derivMatrix = nullptr;
1831 
1832  delete alignCache.m_fullCovarianceMatrix;
1833  alignCache.m_fullCovarianceMatrix = nullptr;
1834  alignCache.m_iterationsOfLastFit = 0;
1835 
1836  Trk::Track* newTrack =
1837  fitIm(ctx, cache, inputTrack, runOutlier, matEffects);
1838  if(newTrack != nullptr){
1839  if(cache.m_derivmat.size() != 0)
1840  alignCache.m_derivMatrix = new Amg::MatrixX(cache.m_derivmat);
1841  if(cache.m_fullcovmat.size() != 0)
1842  alignCache.m_fullCovarianceMatrix = new Amg::MatrixX(cache.m_fullcovmat);
1843  alignCache.m_iterationsOfLastFit = cache.m_lastiter;
1844  }
1845  return newTrack;
1846  }
1847 
1848  Track*
1850  const EventContext& ctx,
1851  Cache& cache,
1852  const Track& inputTrack,
1853  const RunOutlierRemoval runOutlier,
1854  const ParticleHypothesis matEffects) const
1855  {
1856 
1857  ATH_MSG_DEBUG("--> entering GlobalChi2Fitter::fit(Track,,)");
1858 
1859  GXFTrajectory trajectory;
1860 
1861  if (!m_straightlineprop) {
1862  trajectory.m_straightline = (!cache.m_field_cache.solenoidOn() && !cache.m_field_cache.toroidOn());
1863  }
1864 
1865  trajectory.m_fieldprop = trajectory.m_straightline ? Trk::NoField : Trk::FullField;
1866 
1867  if (inputTrack.trackStateOnSurfaces()->empty()) {
1868  ATH_MSG_WARNING("Track with zero track states, cannot perform fit");
1869  return nullptr;
1870  }
1871 
1872  if (inputTrack.trackParameters()->empty()) {
1873  ATH_MSG_WARNING("Track without track parameters, cannot perform fit");
1874  return nullptr;
1875  }
1876 
1877  std::unique_ptr<const TrackParameters> minpar = unique_clone(inputTrack.perigeeParameters());
1878  const TrackParameters *firstidpar = nullptr;
1879  const TrackParameters *lastidpar = nullptr;
1880 
1881  if (minpar == nullptr) {
1882  minpar = unique_clone(*(inputTrack.trackParameters()->begin()));
1883  }
1884 
1885  const bool tmpgetmat = cache.m_getmaterialfromtrack;
1886 
1887  if (
1888  matEffects == Trk::nonInteracting ||
1889  inputTrack.info().trackFitter() == TrackInfo::Unknown
1890  ) {
1891  cache.m_getmaterialfromtrack = false;
1892  }
1893 
1894  Trk::TrackStates::const_iterator itStates = inputTrack.trackStateOnSurfaces()->begin();
1895  const Trk::TrackStates::const_iterator endState = inputTrack.trackStateOnSurfaces()->end();
1896 
1897  trajectory.trackStates().reserve(inputTrack.trackStateOnSurfaces()->size());
1898 
1899  const Surface *firsthitsurf = nullptr;
1900  const Surface *lasthitsurf = nullptr;
1901  bool hasid = false;
1902  bool hasmuon = false;
1903  bool iscombined = false;
1904  bool seenphimeas = false;
1905  bool phiem = false;
1906  bool phibo = false;
1907 
1908  for (; itStates != endState; ++itStates) {
1909  const auto *const pMeasurement = (**itStates).measurementOnTrack();
1910  if (
1911  (pMeasurement == nullptr) &&
1912  ((**itStates).materialEffectsOnTrack() != nullptr) &&
1913  matEffects != inputTrack.info().particleHypothesis()
1914  ) {
1915  continue;
1916  }
1917 
1918  if (pMeasurement != nullptr) {
1919  const Surface *surf = &pMeasurement->associatedSurface();
1921  if (!hitid.is_valid()) {
1922  if (pMeasurement->type(Trk::MeasurementBaseType::CompetingRIOsOnTrack)) {
1923  const CompetingRIOsOnTrack *crot = static_cast<const CompetingRIOsOnTrack *>(pMeasurement);
1924  hitid = crot->rioOnTrack(0).identify();
1925  }
1926  }
1927  if (hitid.is_valid()) {
1928  if (firsthitsurf == nullptr) {
1929  firsthitsurf = surf;
1930  }
1931  lasthitsurf = surf;
1932  if (m_DetID->is_indet(hitid)) {
1933  hasid = true;
1934  if (hasmuon) {
1935  iscombined = true;
1936  }
1937  if ((**itStates).trackParameters() != nullptr) {
1938  lastidpar = (**itStates).trackParameters();
1939  if (firstidpar == nullptr) {
1940  firstidpar = lastidpar;
1941  }
1942  }
1943  } else {
1944  if (!(**itStates).type(TrackStateOnSurface::Outlier)) {
1945  const Amg::Vector3D measdir = surf->transform().rotation().col(0);
1946  const double dotprod1 = measdir.dot(Amg::Vector3D(0, 0, 1));
1947  const double dotprod2 = measdir.dot(Amg::Vector3D(surf->center().x(), surf->center().y(), 0) / surf->center().perp());
1948  if (std::abs(dotprod1) < .5 && std::abs(dotprod2) < .5) {
1949  seenphimeas = true;
1950  if (std::abs(surf->center().z()) > 13000) {
1951  phiem = true;
1952  }
1953  if (surf->center().perp() > 9000 && std::abs(surf->center().z()) < 13000) {
1954  phibo = true;
1955  }
1956  }
1957  }
1958  hasmuon = true;
1959  if (hasid) {
1960  iscombined = true;
1961  }
1962  }
1963  }
1964 
1965  if (iscombined && seenphimeas && (phiem || phibo)) {
1966  if (pMeasurement->type(Trk::MeasurementBaseType::PseudoMeasurementOnTrack)) {
1967  continue;
1968  }
1969  }
1970  }
1971  makeProtoState(cache, trajectory, *itStates);
1972  }
1973 
1974  if (
1975  cache.m_getmaterialfromtrack && trajectory.numberOfScatterers() != 0 &&
1976  (hasmuon || cache.m_acceleration)
1977  ) {
1978  cache.m_matfilled = true;
1979  }
1980 
1981  if (firstidpar == lastidpar) {
1982  firstidpar = lastidpar = nullptr;
1983  }
1984 
1985  if (
1986  iscombined &&
1987  !cache.m_matfilled &&
1988  (
1991  ) &&
1992  (firstidpar != nullptr)
1993  ) {
1994  if (m_DetID->is_indet(firsthitsurf->associatedDetectorElementIdentifier())) {
1995  minpar = unique_clone(lastidpar);
1996  } else {
1997  minpar = unique_clone(firstidpar);
1998  }
1999  }
2000 
2001  const bool tmpacc = cache.m_acceleration;
2002  const bool tmpfiteloss = m_fiteloss;
2003  const bool tmpsirecal = cache.m_sirecal;
2004  std::unique_ptr<Track> tmptrack = nullptr;
2005 
2006  if (matEffects == Trk::proton || matEffects == Trk::kaon || matEffects == Trk::electron) {
2007  ATH_MSG_DEBUG("call myfit(GXFTrajectory,TP,,)");
2008  cache.m_fiteloss = true;
2009  cache.m_sirecal = false;
2010 
2011  if (matEffects == Trk::electron) {
2012  cache.m_asymeloss = true;
2013  }
2014 
2015  tmptrack.reset(myfit(ctx, cache, trajectory, *minpar, false, matEffects));
2016  cache.m_sirecal = tmpsirecal;
2017 
2018  if (tmptrack == nullptr) {
2019  cache.m_matfilled = false;
2020  cache.m_getmaterialfromtrack = tmpgetmat;
2021  cache.m_acceleration = tmpacc;
2022  cache.m_fiteloss = tmpfiteloss;
2023  return nullptr;
2024  }
2025 
2026  int nscats = 0;
2027  bool isbrem = false;
2028  double bremdp = 0;
2029  unsigned int n_brem=0;
2030 
2031  for (std::unique_ptr<GXFTrackState> & state : trajectory.trackStates()) {
2032  GXFMaterialEffects *meff = state->materialEffects();
2033 
2034  if (meff != nullptr) {
2035  nscats++;
2036 
2037  const TrackParameters *layerpars = state->trackParameters();
2038  const MaterialProperties *matprop = meff->materialProperties();
2039 
2040  const double p = 1. / std::abs(layerpars->parameters()[Trk::qOverP] - .0005 * meff->delta_p());
2041 
2042  std::optional<Amg::Vector2D> locpos(state->associatedSurface().globalToLocal(layerpars->position()));
2043  const Amg::Vector3D layerNormal(state->associatedSurface().normal(*locpos));
2044  double costracksurf = 1.;
2045 
2046  costracksurf = std::abs(layerNormal.dot(layerpars->momentum().unit()));
2047 
2048  const double oldde = meff->deltaE();
2049 
2050  std::unique_ptr<EnergyLoss> eloss;
2051  double sigmascat = 0;
2052 
2053  if (matprop != nullptr) {
2054  eloss = std::make_unique<EnergyLoss>(
2055  m_elosstool->energyLoss(*matprop, p, 1. / costracksurf,
2056  Trk::alongMomentum, matEffects));
2057  sigmascat = std::sqrt(m_scattool->sigmaSquare(*matprop, p, 1. / costracksurf, matEffects));
2058 
2059  if (eloss != nullptr) {
2060  meff->setDeltaE(eloss->deltaE());
2061  }
2062  } else {
2063  MaterialProperties const tmpprop(1., meff->x0(), 0., 0., 0., 0.);
2064  sigmascat = std::sqrt(m_scattool->sigmaSquare(tmpprop, p, 1. / costracksurf, matEffects));
2065  }
2066 
2067  meff->setScatteringSigmas(
2068  sigmascat / std::sin(layerpars->parameters()[Trk::theta]),
2069  sigmascat
2070  );
2071 
2072 
2073  if (matEffects == electron) {
2074  state->resetStateType(TrackStateOnSurface::Scatterer);
2075  meff->setDeltaE(oldde);
2076  if (!meff->isKink()) {
2077  meff->setSigmaDeltaE(0);
2078  } else {
2079  isbrem = true;
2080  bremdp = meff->delta_p();
2081  }
2082  } else if (eloss != nullptr) {
2083  meff->setSigmaDeltaE(eloss->sigmaDeltaE());
2084  }
2085  if (meff->sigmaDeltaE() > 0) {
2086  ++n_brem;
2087  }
2088  }
2089  }
2090 
2091  const AmgVector(5) & refpars = trajectory.referenceParameters()->parameters();
2093  refpars[0], refpars[1], refpars[2], refpars[3], refpars[4], std::nullopt
2094  );
2095 
2096  trajectory.reset();
2097  cache.m_matfilled = true;
2098 
2099  if (matEffects == Trk::electron) {
2100  if (!isbrem) {
2101  trajectory.brems().clear();
2102  } else {
2103  trajectory.brems().resize(1);
2104  trajectory.brems()[0] = bremdp;
2105  }
2106 
2107  cache.m_asymeloss = false;
2108  trajectory.setNumberOfScatterers(nscats);
2109  // @TODO fillResiduals assumes that numberOfBrems == number of states with material effects and sigmaDeltaE() > 0
2110  // not clear whether fillResiduals has to be adjusted for electrons rather than this
2111  trajectory.setNumberOfBrems(n_brem);
2112  }
2113  }
2114 
2115  std::unique_ptr<Track> track(myfit(ctx, cache, trajectory, *minpar, runOutlier, matEffects));
2116 
2117  bool pseudoupdated = false;
2118 
2119  if ((track != nullptr) && hasid && hasmuon) {
2120  for (std::unique_ptr<GXFTrackState> & pseudostate : trajectory.trackStates()) {
2121  if (
2122  (pseudostate == nullptr) ||
2123  pseudostate->measurementType() != TrackState::Pseudo ||
2124  pseudostate->fitQuality().chiSquared() < 10
2125  ) {
2126  continue;
2127  }
2128 
2129  const TrackParameters *pseudopar = pseudostate->trackParameters();
2130  const std::unique_ptr<const TrackParameters> updpar(m_updator->removeFromState(
2131  *pseudopar,
2132  pseudostate->measurement()->localParameters(),
2133  pseudostate->measurement()->localCovariance()
2134  ));
2135 
2136  if (updpar == nullptr) {
2137  continue;
2138  }
2139 
2140  Amg::MatrixX covMatrix(1, 1);
2141  covMatrix(0, 0) = 100;
2142 
2143  std::unique_ptr<const PseudoMeasurementOnTrack> newpseudo = std::make_unique<const PseudoMeasurementOnTrack>(
2144  LocalParameters(DefinedParameter(updpar->parameters()[Trk::locY], Trk::locY)),
2145  std::move(covMatrix),
2146  pseudopar->associatedSurface()
2147  );
2148 
2149  pseudostate->setMeasurement(std::move(newpseudo));
2150  double errors[5];
2151  errors[0] = errors[2] = errors[3] = errors[4] = -1;
2152  errors[1] = 10;
2153  pseudostate->setMeasurementErrors(errors);
2154  pseudoupdated = true;
2155  }
2156 
2157  if (pseudoupdated) {
2158  trajectory.setConverged(false);
2159  cache.m_matfilled = true;
2160  track.reset(myfit(ctx, cache, trajectory, *track->perigeeParameters(), false, muon));
2161  cache.m_matfilled = false;
2162  }
2163  }
2164 
2165  cache.m_matfilled = false;
2166  cache.m_getmaterialfromtrack = tmpgetmat;
2167  cache.m_acceleration = tmpacc;
2168  cache.m_fiteloss = tmpfiteloss;
2169 
2170  if (track != nullptr) {
2172  const TrackInfo& old_info = inputTrack.info();
2173  track->info().addPatternReco(old_info);
2174  }
2175 
2176  return track.release();
2177  }
2178 
2179  std::unique_ptr<Track>
2181  const EventContext& ctx,
2182  const PrepRawDataSet& prds,
2183  const TrackParameters& param,
2184  const RunOutlierRemoval runOutlier,
2185  const ParticleHypothesis matEffects) const
2186  {
2187  ATH_MSG_DEBUG("--> entering GlobalChi2Fitter::fit(PRDS,TP,)");
2188  MeasurementSet rots;
2189 
2190  for (const auto *prd : prds) {
2191  const Surface & prdsurf = (*prd).detectorElement()->surface((*prd).identify());
2192  const RIO_OnTrack *rot = nullptr;
2193  const PlaneSurface *plsurf = nullptr;
2194 
2195  if (prdsurf.type() == Trk::SurfaceType::Plane)
2196  plsurf = static_cast < const PlaneSurface *>(&prdsurf);
2197 
2198  const StraightLineSurface *slsurf = nullptr;
2199 
2200  if (prdsurf.type() == Trk::SurfaceType::Line)
2201  slsurf = static_cast < const StraightLineSurface *>(&prdsurf);
2202 
2203  if ((slsurf == nullptr) && (plsurf == nullptr)) {
2204  ATH_MSG_ERROR("Surface is neither PlaneSurface nor StraightLineSurface!");
2205  }
2206 
2207  if (!m_broadROTcreator.empty() && (slsurf != nullptr)) {
2208  rot = m_broadROTcreator->correct(*prd, param, ctx);
2209  } else if (slsurf != nullptr) {
2210  AtaStraightLine const atasl(
2211  slsurf->center(),
2212  param.parameters()[Trk::phi],
2213  param.parameters()[Trk::theta],
2214  param.parameters()[Trk::qOverP],
2215  *slsurf
2216  );
2217  rot = m_ROTcreator->correct(*prd, atasl, ctx);
2218  } else if (plsurf != nullptr) {
2219  if (param.covariance() != nullptr) {
2220  AtaPlane const atapl(
2221  plsurf->center(),
2222  param.parameters()[Trk::phi],
2223  param.parameters()[Trk::theta],
2224  param.parameters()[Trk::qOverP],
2225  *plsurf,
2226  AmgSymMatrix(5)(*param.covariance())
2227  );
2228  rot = m_ROTcreator->correct(*prd, atapl, ctx);
2229  } else {
2230  AtaPlane const atapl(
2231  plsurf->center(),
2232  param.parameters()[Trk::phi],
2233  param.parameters()[Trk::theta],
2234  param.parameters()[Trk::qOverP],
2235  *plsurf
2236  );
2237  rot = m_ROTcreator->correct(*prd, atapl, ctx);
2238  }
2239  }
2240 
2241  if (rot != nullptr) {
2242  rots.push_back(rot);
2243  }
2244  }
2245 
2246  std::unique_ptr<Track> track =
2247  fit(ctx, rots, param, runOutlier, matEffects);
2248 
2249  for (const auto *rot : rots) {
2250  delete rot;
2251  }
2252 
2253  return track;
2254  }
2255 
2256  std::unique_ptr<Track>
2258  const EventContext& ctx,
2259  const Track& inputTrack,
2260  const MeasurementSet& addMeasColl,
2261  const RunOutlierRemoval runOutlier,
2262  const ParticleHypothesis matEffects) const
2263  {
2264  ATH_MSG_DEBUG("--> entering GlobalChi2Fitter::fit(Track,Meas'BaseSet,,)");
2265 
2266  Cache cache(this);
2267  initFieldCache(ctx,cache);
2268 
2269  GXFTrajectory trajectory;
2270 
2271  if (!m_straightlineprop) {
2272  trajectory.m_straightline = (!cache.m_field_cache.solenoidOn() && !cache.m_field_cache.toroidOn());
2273  }
2274 
2275  trajectory.m_fieldprop = trajectory.m_straightline ? Trk::NoField : Trk::FullField;
2276 
2277  const TrackParameters *minpar = inputTrack.perigeeParameters();
2278 
2279  if (minpar == nullptr) {
2280  minpar = *(inputTrack.trackParameters()->begin());
2281  }
2282 
2283  MeasurementSet const hitColl;
2284 
2285  // collect MBs from Track (speed: assume this method is used for extending track at end)
2286  Trk::TrackStates::const_iterator itStates = inputTrack.trackStateOnSurfaces()->begin();
2287  const Trk::TrackStates::const_iterator endState = inputTrack.trackStateOnSurfaces()->end();
2288 
2289  const bool old_reintoutl = cache.m_reintoutl;
2290  cache.m_reintoutl = false;
2291  const bool tmpasymeloss = cache.m_asymeloss;
2292 
2293  if (matEffects == electron) {
2294  cache.m_asymeloss = true;
2295  }
2296 
2297  for (; itStates != endState; ++itStates) {
2298  makeProtoState(cache, trajectory, *itStates);
2299  if (
2300  matEffects == electron &&
2301  !trajectory.trackStates().empty() &&
2302  (trajectory.trackStates().back()->materialEffects() != nullptr) &&
2303  trajectory.trackStates().back()->materialEffects()->sigmaDeltaE() > 50.001
2304  ) {
2305  trajectory.trackStates().back()->materialEffects()->setKink(true);
2306  }
2307  }
2308 
2309  cache.m_reintoutl = old_reintoutl;
2310 
2311  for (const auto & measBase : addMeasColl) {
2312  if (measBase == nullptr) {
2313  ATH_MSG_WARNING("There is an empty MeasurementBase object in the track! Skip this object..");
2314  continue;
2315  }
2316 
2317  makeProtoStateFromMeasurement(cache, trajectory, measBase);
2318  }
2319 
2320  // fit set of MeasurementBase using main method, start with first TrkParameter in inputTrack
2321  std::unique_ptr<Track> track(myfit(ctx, cache, trajectory, *minpar, runOutlier, matEffects));
2322  cache.m_asymeloss = tmpasymeloss;
2323 
2324  if (track != nullptr) {
2325  const double oldqual =
2326  inputTrack.fitQuality()->numberDoF() != 0 ?
2327  inputTrack.fitQuality()->chiSquared() / inputTrack.fitQuality()->numberDoF() :
2328  -999;
2329 
2330  const double newqual =
2331  track->fitQuality()->numberDoF() != 0 ?
2332  track->fitQuality()->chiSquared() / track->fitQuality()->numberDoF() :
2333  -999;
2334 
2335  if (m_extensioncuts && runOutlier && newqual > 2 && newqual > 2 * oldqual) {
2336  ATH_MSG_DEBUG("Extension rejected");
2337 
2339  track.reset(nullptr);
2340  }
2341  }
2342 
2343  if (track != nullptr) {
2345  }
2346 
2347  return track;
2348  }
2349 
2350  // extend a track fit to include an additional set of PrepRawData objects
2351  // --------------------------------
2352  std::unique_ptr<Track>
2354  const EventContext& ctx,
2355  const Track& intrk,
2356  const PrepRawDataSet& prds,
2357  const RunOutlierRemoval runOutlier,
2358  const ParticleHypothesis matEffects) const
2359  {
2360  ATH_MSG_DEBUG("--> entering GlobalChi2Fitter::fit(Track,PRDS,)");
2361  MeasurementSet rots;
2362  const TrackParameters *hitparam = intrk.trackParameters()->back();
2363 
2364  for (const auto *prd : prds) {
2365  const Surface & prdsurf = (*prd).detectorElement()->surface((*prd).identify());
2366 
2367  Amg::VectorX parameterVector = hitparam->parameters();
2368  std::unique_ptr<const TrackParameters>const trackparForCorrect(
2370  parameterVector[Trk::loc1],
2371  parameterVector[Trk::loc2],
2372  parameterVector[Trk::phi],
2373  parameterVector[Trk::theta],
2374  parameterVector[Trk::qOverP],
2375  AmgSymMatrix(5)(*hitparam->covariance())
2376  )
2377  );
2378 
2379  const RIO_OnTrack *rot = nullptr;
2380 
2381  if (!m_broadROTcreator.empty() && prdsurf.type() == Trk::SurfaceType::Line) {
2382  rot = m_broadROTcreator->correct(*prd, *hitparam, ctx);
2383  } else {
2384  rot = m_ROTcreator->correct(*prd, *trackparForCorrect, ctx);
2385  }
2386 
2387  if (rot != nullptr) {
2388  rots.push_back(rot);
2389  }
2390  }
2391 
2392  std::unique_ptr<Track> track = fit(ctx,intrk, rots, runOutlier, matEffects);
2393 
2394  for (const auto *rot : rots) {
2395  delete rot;
2396  }
2397 
2398  return track;
2399  }
2400 
2401  std::unique_ptr<Track> GlobalChi2Fitter::fit(
2402  const EventContext& ctx,
2403  const MeasurementSet & rots,
2404  const TrackParameters & param,
2405  const RunOutlierRemoval runOutlier,
2406  const ParticleHypothesis matEffects
2407  ) const {
2408  ATH_MSG_DEBUG("--> entering GlobalChi2Fitter::fit(Meas'BaseSet,,)");
2409 
2410  Cache cache(this);
2411  initFieldCache(ctx,cache);
2412 
2413  GXFTrajectory trajectory;
2414 
2415  if (!m_straightlineprop) {
2416  trajectory.m_straightline = (!cache.m_field_cache.solenoidOn() && !cache.m_field_cache.toroidOn());
2417  }
2418 
2419  trajectory.m_fieldprop = trajectory.m_straightline ? Trk::NoField : Trk::FullField;
2420 
2421  for (const auto *itSet : rots) {
2422  if (itSet == nullptr) {
2423  ATH_MSG_WARNING("There is an empty MeasurementBase object in the track! Skip this object..");
2424  } else {
2425  makeProtoStateFromMeasurement(cache, trajectory, itSet);
2426  }
2427  }
2428 
2429  std::unique_ptr<const TrackParameters> startpar(param.clone());
2430 
2431  if (
2432  matEffects == muon &&
2433  trajectory.numberOfSiliconHits() + trajectory.numberOfTRTHits() == 0
2434  ) {
2435  cache.m_matfilled = true;
2436  trajectory.setPrefit(2);
2437 
2438  myfit(ctx,cache, trajectory, *startpar, runOutlier, matEffects);
2439 
2440  cache.m_matfilled = false;
2441 
2442  if (!trajectory.converged()) {
2443  return nullptr;
2444  }
2445 
2446  trajectory.setConverged(false);
2447  const TrackParameters *firstpar = trajectory.trackStates()[0]->trackParameters();
2448  const TrackParameters *lastpar = trajectory.trackStates().back()->trackParameters();
2449 
2450  PerigeeSurface const persurf(firstpar->position() - 10 * firstpar->momentum().unit());
2451 
2452  if (trajectory.trackStates().front()->measurementType() == TrackState::Pseudo) {
2453  Amg::MatrixX covMatrix(1, 1);
2454  covMatrix(0, 0) = 100;
2455 
2456  std::unique_ptr<const PseudoMeasurementOnTrack> newpseudo = std::make_unique<const PseudoMeasurementOnTrack>(
2457  LocalParameters(DefinedParameter(firstpar->parameters()[Trk::locY], Trk::locY)),
2458  std::move(covMatrix),
2459  firstpar->associatedSurface()
2460  );
2461 
2462  trajectory.trackStates().front()->setMeasurement(std::move(newpseudo));
2463  }
2464 
2465  if (trajectory.trackStates().back()->measurementType() == TrackState::Pseudo) {
2466  Amg::MatrixX covMatrix(1, 1);
2467  covMatrix(0, 0) = 100;
2468 
2469  std::unique_ptr<const PseudoMeasurementOnTrack> newpseudo = std::make_unique<const PseudoMeasurementOnTrack>(
2470  LocalParameters(DefinedParameter(lastpar->parameters()[Trk::locY], Trk::locY)),
2471  std::move(covMatrix),
2472  lastpar->associatedSurface()
2473  );
2474 
2475  trajectory.trackStates().back()->setMeasurement(std::move(newpseudo));
2476  }
2477 
2478  if (!trajectory.m_straightline) {
2479  trajectory.setPrefit(3);
2480  const AmgVector(5) & refpars = trajectory.referenceParameters()->parameters();
2482  refpars[0], refpars[1], refpars[2], refpars[3], refpars[4], std::nullopt
2483  );
2484 
2485  trajectory.reset();
2486 
2487  myfit(ctx,cache, trajectory, *startpar, runOutlier, matEffects);
2488 
2489  cache.m_matfilled = true;
2490 
2491  if (!trajectory.converged()) {
2492  return nullptr;
2493  }
2494  }
2495 
2496  const AmgVector(5) & refpars = trajectory.referenceParameters()->parameters();
2498  refpars[0], refpars[1], refpars[2], refpars[3], refpars[4], std::nullopt
2499  );
2500 
2501  trajectory.reset();
2502  trajectory.setPrefit(0);
2503 
2504  if (trajectory.trackStates().front()->measurementType() == TrackState::Pseudo) {
2505  firstpar = trajectory.trackStates().front()->trackParameters();
2506 
2507  Amg::MatrixX covMatrix(1, 1);
2508  covMatrix(0, 0) = 100;
2509 
2510  std::unique_ptr<const PseudoMeasurementOnTrack> newpseudo = std::make_unique<const PseudoMeasurementOnTrack>(
2511  LocalParameters(DefinedParameter(firstpar->parameters()[Trk::locY], Trk::locY)),
2512  std::move(covMatrix),
2513  firstpar->associatedSurface()
2514  );
2515 
2516  trajectory.trackStates().front()->setMeasurement(std::move(newpseudo));
2517  double errors[5];
2518  errors[0] = errors[2] = errors[3] = errors[4] = -1;
2519  errors[1] = 10;
2520  trajectory.trackStates().front()->setMeasurementErrors(errors);
2521  }
2522 
2523  if (trajectory.trackStates().back()->measurementType() == TrackState::Pseudo) {
2524  lastpar = trajectory.trackStates().back()->trackParameters();
2525 
2526  Amg::MatrixX covMatrix(1, 1);
2527  covMatrix(0, 0) = 100;
2528 
2529  std::unique_ptr<const PseudoMeasurementOnTrack> newpseudo = std::make_unique<const PseudoMeasurementOnTrack>(
2530  LocalParameters(DefinedParameter(lastpar->parameters()[Trk::locY], Trk::locY)),
2531  std::move(covMatrix),
2532  lastpar->associatedSurface()
2533  );
2534 
2535  trajectory.trackStates().back()->setMeasurement(std::move(newpseudo));
2536  double errors[5];
2537  errors[0] = errors[2] = errors[3] = errors[4] = -1;
2538  errors[1] = 10;
2539  trajectory.trackStates().back()->setMeasurementErrors(errors);
2540  }
2541  }
2542 
2543  std::unique_ptr<Track> track;
2544 
2545  if (startpar != nullptr) {
2546  track.reset(myfit(ctx,cache, trajectory, *startpar, runOutlier, matEffects));
2547  }
2548 
2549  if (track != nullptr) {
2551  }
2552  cache.m_matfilled = false;
2553 
2554  return track;
2555  }
2556 
2558  Cache & cache,
2559  GXFTrajectory & trajectory,
2560  const TrackStateOnSurface * tsos,
2561  int index
2562  ) const {
2563  if (
2564  (
2569  ) && cache.m_getmaterialfromtrack
2570  ) {
2571  if (cache.m_acceleration && trajectory.numberOfHits() == 0) {
2572  return;
2573  }
2575  return;
2576  }
2577  const MaterialEffectsOnTrack *meff = static_cast<const MaterialEffectsOnTrack *>(tsos->materialEffectsOnTrack());
2578 
2579  std::unique_ptr<GXFMaterialEffects> newmeff;
2580 
2581  if (
2582  meff->scatteringAngles() or
2583  meff->energyLoss() or
2585  (tsos->trackParameters() == nullptr)
2586  ) {
2587  newmeff = std::make_unique<GXFMaterialEffects>(*meff);
2588  } else {
2589  Trk::MaterialProperties const matprop(meff->thicknessInX0(), 1., 0., 0., 0., 0.);
2590 
2591  const double sigmascat = std::sqrt(m_scattool->sigmaSquare(
2592  matprop,
2593  std::abs(1. / tsos->trackParameters()->parameters()[Trk::qOverP]),
2594  1.,
2595  Trk::muon)
2596  );
2597 
2598  auto newsa = Trk::ScatteringAngles(
2599  0,
2600  0,
2601  sigmascat / std::sin(tsos->trackParameters()->parameters()[Trk::theta]),
2602  sigmascat
2603  );
2604 
2605  Trk::MaterialEffectsOnTrack const newmeot(
2606  meff->thicknessInX0(),
2607  newsa,
2608  nullptr,
2609  tsos->surface()
2610  );
2611 
2612  newmeff = std::make_unique<GXFMaterialEffects>(newmeot);
2613  }
2614 
2615  if (
2616  (meff->energyLoss() != nullptr) &&
2617  meff->energyLoss()->sigmaDeltaE() > 0 &&
2618  (
2619  (tsos->type(TrackStateOnSurface::BremPoint) && (meff->scatteringAngles() != nullptr)) ||
2620  ((meff->scatteringAngles() == nullptr) || meff->thicknessInX0() == 0)
2621  )
2622  ) {
2623  newmeff->setSigmaDeltaE(meff->energyLoss()->sigmaDeltaE());
2624 
2625  if (
2626  (tsos->trackParameters() != nullptr) &&
2627  !trajectory.trackStates().empty() &&
2628  ((**trajectory.trackStates().rbegin()).trackParameters() != nullptr)
2629  ) {
2630  const double delta_p = 1000 * (
2631  tsos->trackParameters()->parameters()[Trk::qOverP] -
2632  (**trajectory.trackStates().rbegin()).trackParameters()->
2634  );
2635 
2636  newmeff->setdelta_p(delta_p);
2637  }
2638  }
2639 
2640  trajectory.addMaterialState(std::make_unique<GXFTrackState>(std::move(newmeff), unique_clone(tsos->trackParameters())), index);
2641  }
2642 
2643  if (
2646  ) {
2647  const bool isoutlier = tsos->type(TrackStateOnSurface::Outlier) && !cache.m_reintoutl;
2648 
2650  cache,
2651  trajectory,
2652  tsos->measurementOnTrack(),
2653  tsos->trackParameters(),
2654  isoutlier,
2655  index
2656  );
2657  }
2658  }
2659 
2661  Cache & cache,
2662  GXFTrajectory & trajectory,
2663  const MeasurementBase * measbase,
2664  const TrackParameters * trackpar,
2665  bool isoutlier,
2666  int index
2667  ) const {
2668  const Segment *seg = nullptr;
2669 
2671  if (measbase->type(Trk::MeasurementBaseType::Segment)){
2672  seg = static_cast<const Segment *>(measbase);
2673  }
2674  }
2675 
2676  int imax = 1;
2677 
2678  if ((seg != nullptr) && m_decomposesegments) {
2679  imax = (int) seg->numberOfMeasurementBases();
2680  }
2681 
2682  for (int i = 0; i < imax; i++) {
2683  const MeasurementBase *measbase2 = ((seg != nullptr) && m_decomposesegments) ? seg->measurement(i) : measbase;
2684  const TrackParameters *newtrackpar = ((seg != nullptr) && m_decomposesegments) ? nullptr : trackpar;
2685  std::unique_ptr<GXFTrackState> ptsos = std::make_unique<GXFTrackState>(
2686  std::unique_ptr<const MeasurementBase>(measbase2->clone()),
2687  std::unique_ptr<const TrackParameters>(newtrackpar != nullptr ? newtrackpar->clone() : nullptr)
2688  );
2689  const Amg::MatrixX & covmat = measbase2->localCovariance();
2690  double sinstereo = 0;
2691  double errors[5];
2692  errors[0] = errors[1] = errors[2] = errors[3] = errors[4] = -1;
2695  //const CompetingRIOsOnTrack *crot = nullptr;
2696  if (!hitid.is_valid()) {
2698  const CompetingRIOsOnTrack *crot = static_cast<const CompetingRIOsOnTrack *>(measbase2);
2699  hitid = crot->rioOnTrack(0).identify();
2700  }
2701  }
2702 
2703  bool measphi = false;
2704 
2705  if (hitid.is_valid() && measbase2->localParameters().contains(Trk::locX)) {
2706  bool rotated = false;
2707 
2708  if (m_DetID->is_indet(hitid) && !m_DetID->is_muon(hitid)) {
2709  if (m_DetID->is_pixel(hitid)) {
2710  hittype = TrackState::Pixel;
2711  } else if (m_DetID->is_sct(hitid)) {
2712  if (covmat.cols() != 1 && covmat(1, 0) != 0) {
2713  rotated = true;
2714  }
2715  hittype = TrackState::SCT;
2716  } else if (m_DetID->is_trt(hitid)) {
2717  hittype = TrackState::TRT;
2718  }
2719  } else { // Muon hit
2720  if (m_DetID->is_rpc(hitid)) {
2721  hittype = TrackState::RPC;
2722  if (measbase->localParameters().parameterKey() != 1) {
2723  ATH_MSG_WARNING("Corrupt RPC hit, skipping it");
2724  continue;
2725  }
2726  } else if (m_DetID->is_mdt(hitid)) {
2727  hittype = TrackState::MDT;
2728  } else if (m_DetID->is_tgc(hitid)) {
2729  if (measbase2->associatedSurface().bounds().type() == Trk::SurfaceBounds::Trapezoid) {
2730  rotated = true;
2731  }
2732  hittype = TrackState::TGC;
2733  } else if (m_DetID->is_csc(hitid)) {
2734  hittype = TrackState::CSC;
2735  } else if (m_DetID->is_mm(hitid)) {
2736  hittype = TrackState::MM;
2737  } else if (m_DetID->is_stgc(hitid)) {
2738  hittype = TrackState::STGC;
2739  }
2740  }
2741 
2742  if (rotated) {
2743  const auto [covEigenValueSmall, covStereoAngle] = principalComponentAnalysis2x2(covmat);
2744  errors[0] = std::sqrt(covEigenValueSmall);
2745  sinstereo = std::sin(covStereoAngle);
2746  } else {
2747  errors[0] = std::sqrt(covmat(0, 0));
2748  if (hittype == TrackState::Pixel) {
2749  errors[1] = std::sqrt(covmat(1, 1));
2750  }
2751  }
2752  if (
2753  hittype == TrackState::RPC ||
2754  hittype == TrackState::TGC ||
2755  hittype == TrackState::CSC ||
2756  hittype == TrackState::STGC
2757  ) {
2758  const Surface *surf = &measbase2->associatedSurface();
2759  const Amg::Vector3D measdir = surf->transform().rotation().col(0);
2760  const double dotprod1 = measdir.dot(Amg::Vector3D(0, 0, 1));
2761  const double dotprod2 = measdir.dot(Amg::Vector3D(surf->center().x(), surf->center().y(), 0) / surf->center().perp());
2762  if (std::abs(dotprod1) < .5 && std::abs(dotprod2) < .5) {
2763  measphi = true;
2764  }
2765  }
2766  } else {
2767  const Trk::LocalParameters & psmpar = measbase2->localParameters();
2768  // @TODO coverity complains about index shadowing the method argument index
2769  // this is solved by renaming index in this block by param_index
2770  int param_index = 0;
2771  if (psmpar.contains(Trk::locRPhi)) {
2772  errors[0] = std::sqrt(covmat(0, 0));
2773  param_index++;
2774  }
2775 
2776  if (psmpar.contains(Trk::locZ)) {
2777  errors[1] = std::sqrt(covmat(param_index, param_index));
2778  param_index++;
2779  }
2780 
2781  if (psmpar.contains(Trk::phi)) {
2782  errors[2] = std::sqrt(covmat(param_index, param_index));
2783  param_index++;
2784  }
2785 
2786  if (psmpar.contains(Trk::theta)) {
2787  errors[3] = std::sqrt(covmat(param_index, param_index));
2788  param_index++;
2789  }
2790 
2791  if (psmpar.contains(Trk::qOverP)) {
2792  errors[4] = std::sqrt(covmat(param_index, param_index));
2793  param_index++;
2794  }
2796  hittype = TrackState::Pseudo;
2797  ATH_MSG_DEBUG("PseudoMeasurement, pos=" << measbase2->globalPosition());
2798  } else if (measbase2->type(Trk::MeasurementBaseType::VertexOnTrack )) {
2799  hittype = TrackState::Vertex;
2800  ATH_MSG_DEBUG("VertexOnTrack, pos=" << measbase2->globalPosition()); // print out the hit type
2801  } else if (measbase2->type(Trk::MeasurementBaseType::Segment )) {
2802  hittype = TrackState::Segment;
2803  ATH_MSG_DEBUG("Segment, pos=" << measbase2->globalPosition()); // print out the hit type
2804  }
2805  }
2806  if (
2807  errors[0] > 0 ||
2808  errors[1] > 0 ||
2809  errors[2] > 0 ||
2810  errors[3] > 0 ||
2811  errors[4] > 0
2812  ) {
2813  ptsos->setMeasurementErrors(errors);
2814  ptsos->setSinStereo(sinstereo);
2815  ptsos->setMeasurementType(hittype);
2816  ptsos->setMeasuresPhi(measphi);
2817 
2818  if (isoutlier && !cache.m_reintoutl) {
2819  ptsos->resetStateType(TrackStateOnSurface::Outlier);
2820  }
2821 
2822  // @TODO here index really is supposed to refer to the method argument index ?
2823  const bool ok = trajectory.addMeasurementState(std::move(ptsos), index);
2824  if (!ok) {
2825  ATH_MSG_WARNING("Duplicate hit on track");
2826  }
2827  } else {
2828  ATH_MSG_WARNING("Measurement error is zero or negative, drop hit");
2829  }
2830  }
2831  }
2832 
2834  Cache & cache,
2835  const Trk::TrackingVolume *tvol
2836  ) const {
2837  if (tvol == nullptr) {
2838  return false;
2839  }
2840 
2841  const Trk::BinnedArray < Trk::Layer > *confinedLayers = tvol->confinedLayers();
2842 
2843  // loop over confined layers
2844  if (confinedLayers != nullptr) {
2845  // loop over layers
2846  for (const auto & layer : confinedLayers->arrayObjects()) {
2847  // push_back the layer
2848  if (layer != nullptr) {
2849  // get the layerIndex
2850  const Trk::LayerIndex & layIndex = layer->layerIndex();
2851  // skip navigaion layers for the moment
2852 
2853  if ((layIndex.value() == 0) || (layer->layerMaterialProperties() == nullptr)) {
2854  continue;
2855  }
2856 
2857  const CylinderLayer *cyllay = nullptr;
2858  if (layer->surfaceRepresentation().type() == Trk::SurfaceType::Cylinder) {
2859  cyllay = static_cast<const CylinderLayer *>(layer);
2860  }
2861 
2862  const DiscLayer *disclay = nullptr;
2863  if (layer->surfaceRepresentation().type() == Trk::SurfaceType::Disc) {
2864  disclay = static_cast<const DiscLayer *>(layer);
2865  }
2866 
2867  if (disclay != nullptr) {
2868  if (disclay->center().z() < 0) {
2869  cache.m_negdiscs.push_back(disclay);
2870  } else {
2871  cache.m_posdiscs.push_back(disclay);
2872  }
2873  } else if (cyllay != nullptr) {
2874  cache.m_barrelcylinders.push_back(cyllay);
2875  } else {
2876  return false;
2877  }
2878  }
2879  }
2880  }
2881 
2882  const auto & bsurf = tvol->boundarySurfaces();
2883 
2884  for (size_t ib = 0 ; ib < bsurf.size(); ++ib) {
2885  const Layer *layer = bsurf[ib]->surfaceRepresentation().materialLayer();
2886 
2887  if (layer == nullptr) continue;
2888 
2889  const Trk::LayerIndex & layIndex = layer->layerIndex();
2890 
2891  if ((layIndex.value() == 0) || (layer->layerMaterialProperties() == nullptr)) {
2892  continue;
2893  }
2894 
2895  const CylinderSurface *cylsurf = nullptr;
2896 
2897  if (layer->surfaceRepresentation().type() == Trk::SurfaceType::Cylinder)
2898  cylsurf = static_cast<const CylinderSurface *>(&layer->surfaceRepresentation());
2899 
2900  const DiscSurface *discsurf = nullptr;
2901 
2902  if (layer->surfaceRepresentation().type() == Trk::SurfaceType::Disc)
2903  discsurf = static_cast<const DiscSurface *>(&layer->surfaceRepresentation());
2904 
2905  if (discsurf != nullptr) {
2906  if (
2907  discsurf->center().z() < 0 &&
2908  std::find(cache.m_negdiscs.begin(), cache.m_negdiscs.end(), layer) == cache.m_negdiscs.end()
2909  ) {
2910  cache.m_negdiscs.push_back(layer);
2911  } else if (
2912  discsurf->center().z() > 0 &&
2913  std::find(cache.m_posdiscs.begin(), cache.m_posdiscs.end(), layer) == cache.m_posdiscs.end()
2914  ) {
2915  cache.m_posdiscs.push_back(layer);
2916  }
2917  } else if (
2918  (cylsurf != nullptr) &&
2919  std::find(cache.m_barrelcylinders.begin(), cache.m_barrelcylinders.end(), layer) == cache.m_barrelcylinders.end()
2920  ) {
2921  cache.m_barrelcylinders.push_back(layer);
2922  }
2923 
2924  if ((cylsurf == nullptr) && (discsurf == nullptr)) {
2925  return false;
2926  }
2927  }
2928 
2929  const TrackingVolumeArray* confinedVolumes = tvol->confinedVolumes();
2930  // get the confined volumes and loop over it -> call recursively
2931  if (confinedVolumes != nullptr) {
2932  for (const auto & volume : confinedVolumes->arrayObjects()) {
2933  if (volume != nullptr) {
2934  const bool ok = processTrkVolume(cache, volume);
2935  if (!ok) {
2936  return false;
2937  }
2938  }
2939  }
2940  }
2941 
2942  return true;
2943  }
2944 
2945 
2946 
2947 
2948 
2949  std::optional<std::pair<Amg::Vector3D, double>>
2951  Cache & cache,
2952  const DiscSurface &surf,
2953  const TrackParameters &parforextrap,
2954  const TrackParameters &refpar2,
2955  const ParticleHypothesis matEffects
2956  ) {
2957  /*
2958  * Please refer to external sources on how to find the intersection between
2959  * a line and a disc.
2960  */
2961  double field[3];
2962  const double * pos = parforextrap.position().data();
2963  const double currentqoverp = (matEffects != Trk::electron) ? parforextrap.parameters()[Trk::qOverP] : refpar2.parameters()[Trk::qOverP];
2965  const double sinphi = std::sin(parforextrap.parameters()[Trk::phi0]);
2966  const double cosphi = std::cos(parforextrap.parameters()[Trk::phi0]);
2967  const double sintheta = std::sin(parforextrap.parameters()[Trk::theta]);
2968  const double costheta = std::cos(parforextrap.parameters()[Trk::theta]);
2969  //magnetic field deviation from straight line
2970  //https://cds.cern.ch/record/1281363/files/ATLAS-CONF-2010-072.pdf, equation 1
2971  //converted to MeV and kT
2972  const double r = (std::abs(currentqoverp) > 1e-10) ? -sintheta / (currentqoverp * 300. * field[2]) : 1e6;
2973  const double xc = parforextrap.position().x() - r * sinphi;
2974  const double yc = parforextrap.position().y() + r * cosphi;
2975  const double phi0 = std::atan2(parforextrap.position().y() - yc, parforextrap.position().x() - xc);
2976  const double z0 = parforextrap.position().z();
2977  const double delta_s = (surf.center().z() - z0) / costheta;
2978  const double delta_phi = delta_s * sintheta / r;
2979  const double x = xc + std::abs(r) * std::cos(phi0 + delta_phi);
2980  const double y = yc + std::abs(r) * std::sin(phi0 + delta_phi);
2981  const Amg::Vector3D intersect = Amg::Vector3D(x, y, surf.center().z());
2982  const double perp = intersect.perp();
2983  const DiscBounds *discbounds = static_cast<const DiscBounds *> (&surf.bounds());
2984 
2985  if (perp > discbounds->rMax() || perp < discbounds->rMin()) {
2986  return {};
2987  }
2988 
2989  const double costracksurf = std::abs(costheta);
2990 
2991  return std::make_pair(intersect, costracksurf);
2992  }
2993 
2994  std::optional<std::pair<Amg::Vector3D, double>>
2996  Cache & cache,
2997  const CylinderSurface &surf,
2998  const TrackParameters &parforextrap,
2999  const TrackParameters &refpar2,
3000  const ParticleHypothesis matEffects
3001  ) {
3002  /*
3003  * I hope you like trigonometry!
3004  *
3005  * For more information, please find a source elsewhere on finding
3006  * intersections with cylinders.
3007  */
3008  double field[3];
3009  const double * pos = parforextrap.position().data();
3010  const double currentqoverp = (matEffects != Trk::electron) ? parforextrap.parameters()[Trk::qOverP] : refpar2.parameters()[Trk::qOverP];
3012  const double sinphi = std::sin(parforextrap.parameters()[Trk::phi0]);
3013  const double cosphi = std::cos(parforextrap.parameters()[Trk::phi0]);
3014  const double sintheta = std::sin(parforextrap.parameters()[Trk::theta]);
3015  const double costheta = std::cos(parforextrap.parameters()[Trk::theta]);
3016  const double tantheta = std::tan(parforextrap.parameters()[Trk::theta]);
3017  const double r = (std::abs(currentqoverp) > 1e-10) ? -sintheta / (currentqoverp * 300. * field[2]) : 1e6;
3018  const double xc = parforextrap.position().x() - r * sinphi;
3019  const double yc = parforextrap.position().y() + r * cosphi;
3020  const double phi0 = std::atan2(parforextrap.position().y() - yc, parforextrap.position().x() - xc);
3021  const double z0 = parforextrap.position().z();
3022  const double d = xc * xc + yc * yc;
3023  const double rcyl = surf.bounds().r();
3024  double mysqrt = ((r + rcyl) * (r + rcyl) - d) * (d - (r - rcyl) * (r - rcyl));
3025 
3026  if (mysqrt < 0) {
3027  return {};
3028  }
3029 
3030  mysqrt = std::sqrt(mysqrt);
3031  double firstterm = xc / 2 + (xc * (rcyl * rcyl - r * r)) / (2 * d);
3032  double secondterm = (mysqrt * yc) / (2 * d);
3033  const double x1 = firstterm + secondterm;
3034  const double x2 = firstterm - secondterm;
3035  firstterm = yc / 2 + (yc * (rcyl * rcyl - r * r)) / (2 * d);
3036  secondterm = (mysqrt * xc) / (2 * d);
3037  const double y1 = firstterm - secondterm;
3038  const double y2 = firstterm + secondterm;
3039  double x = parforextrap.position().x();
3040  double y = parforextrap.position().y();
3041  const double dist1 = (x - x1) * (x - x1) + (y - y1) * (y - y1);
3042  const double dist2 = (x - x2) * (x - x2) + (y - y2) * (y - y2);
3043 
3044  if (dist1 < dist2) {
3045  x = x1;
3046  y = y1;
3047  } else {
3048  x = x2;
3049  y = y2;
3050  }
3051 
3052  const double phi1 = std::atan2(y - yc, x - xc);
3053  const double deltaphi = xAOD::P4Helpers::deltaPhi(phi1, phi0);
3054 
3055  const double delta_z = r * deltaphi / tantheta;
3056  const double z = z0 + delta_z;
3057 
3059 
3060  if (std::abs(z - surf.center().z()) > surf.bounds().halflengthZ()) {
3061  return {};
3062  }
3063 
3064  const Amg::Vector3D normal(x, y, 0);
3065  const double phidir = xAOD::P4Helpers::deltaPhi(parforextrap.parameters()[Trk::phi], -deltaphi);
3066 
3067  const Amg::Vector3D trackdir(cos(phidir) * sintheta, std::sin(phidir) * sintheta, costheta);
3068 
3069  const double costracksurf = std::abs(normal.unit().dot(trackdir));
3070 
3071  return std::make_pair(intersect, costracksurf);
3072  }
3073 
3075  Cache &cache,
3076  GXFTrajectory &trajectory,
3077  int indexoffset,
3078  std::vector<std::pair<const Layer *, const Layer *>> &layers,
3079  const TrackParameters *refpar,
3080  const TrackParameters *refpar2,
3081  ParticleHypothesis matEffects
3082  ) const {
3083  std::vector<std::unique_ptr<GXFTrackState>> & states = trajectory.trackStates();
3084  std::vector<std::unique_ptr<GXFTrackState>> oldstates = std::move(states);
3085 
3086  states.clear();
3087  states.reserve(oldstates.size() + layers.size());
3088 
3089  int layerindex = 0;
3090 
3091  /*
3092  * First, simply copy any upstream states. We do not need to anything with
3093  * them as they are presumably already fit.
3094  */
3095  for (int i = 0; i <= indexoffset; i++) {
3096  trajectory.addBasicState(std::move(oldstates[i]));
3097  }
3098 
3099  const TrackParameters *parforextrap = refpar;
3100 
3101  /*
3102  * For non-upstream layers, that is to say layers after the last existing
3103  * material, the logic is not so simple.
3104  */
3105  for (int i = indexoffset + 1; i < (int) oldstates.size(); i++) {
3106  const double rmeas = oldstates[i]->position().perp();
3107  const double zmeas = oldstates[i]->position().z();
3108 
3109  /*
3110  * Iterate over layers. Note that this is shared between different track
3111  * states! This makes sense, because the track states are sorted and so
3112  * are the layers. If that sorting is consistent between the two, which
3113  * it should be, this works.
3114  */
3115  while (layerindex < (int) layers.size()) {
3117  double costracksurf = 0.0;
3118  const Layer *layer = nullptr;
3119 
3120  /*
3121  * Remember how we distinguish between disc and cylinder surfaces: if
3122  * the first element of the pair is not null, then it points to a
3123  * cylinder. If the second element of the pais is not null, then it's a
3124  * disc surface. That is the logic being applied here. Separate
3125  * handling of cylinders and discs.
3126  */
3127  if (layers[layerindex].first != nullptr) {
3128  /*
3129  * First, convert the pointer to a real CylinderSurface pointer.
3130  */
3131  layer = layers[layerindex].first;
3132  const CylinderSurface *cylsurf = static_cast<const CylinderSurface *> (&layer->surfaceRepresentation());
3133 
3134  /*
3135  * Check if we have a different set of parameters that make more
3136  * sense. If not, reuse the ones we already had.
3137  */
3138  if (oldstates[i]->trackParameters() != nullptr) {
3139  const double rlayer = cylsurf->bounds().r();
3140  if (std::abs(rmeas - rlayer) < std::abs(parforextrap->position().perp() - rlayer)) {
3141  parforextrap = oldstates[i]->trackParameters();
3142  }
3143  }
3144 
3145  /*
3146  * Check if we have an intersection with this layer. If so, break out
3147  * of this loop, we have what we need. Otherwise, go to the next
3148  * layer and try again.
3149  */
3150  if (auto res = addMaterialFindIntersectionCyl(cache, *cylsurf, *parforextrap, *refpar2, matEffects)) {
3151  std::tie(intersect, costracksurf) = res.value();
3152  } else {
3153  layerindex++;
3154  continue;
3155  }
3156 
3157  if (cylsurf->bounds().r() > rmeas) break;
3158  } else if (layers[layerindex].second != nullptr) {
3159  /*
3160  * The logic for disc surfaces is essentially identical to the logic
3161  * for cylinder surfaces. You'll find comments for that just a dozen
3162  * lines up.
3163  */
3164  layer = layers[layerindex].second;
3165  const DiscSurface *discsurf = static_cast<const DiscSurface *> (&layer->surfaceRepresentation());
3166 
3167  if (oldstates[i]->trackParameters() != nullptr) {
3168  const double zlayer = discsurf->center().z();
3169  if (std::abs(zmeas - zlayer) < std::abs(parforextrap->position().z() - zlayer)) {
3170  parforextrap = oldstates[i]->trackParameters();
3171  }
3172  }
3173 
3174  if (auto res = addMaterialFindIntersectionDisc(cache, *discsurf, *parforextrap, *refpar2, matEffects)) {
3175  std::tie(intersect, costracksurf) = res.value();
3176  } else {
3177  layerindex++;
3178  continue;
3179  }
3180 
3181  if (std::abs(discsurf->center().z()) > std::abs(zmeas)) break;
3182  } else {
3183  throw std::logic_error("Unhandled surface.");
3184  }
3185 
3186  /*
3187  * Grab the material properties from our layer. If there are none, just
3188  * go to the next layer.
3189  */
3190  const MaterialProperties *matprop = layer->layerMaterialProperties()->fullMaterial(intersect);
3191  if (matprop == nullptr) {
3192  layerindex++;
3193  continue;
3194  }
3195 
3196  /*
3197  * Convert the material properties into the internal representation of
3198  * material effects.
3199  */
3200  const double X0 = matprop->thicknessInX0();
3201  const double currentqoverp = (matEffects != Trk::electron)
3202  ? parforextrap->parameters()[Trk::qOverP]
3203  : refpar2->parameters()[Trk::qOverP];
3204  const double actualx0 = X0 / costracksurf;
3205  const double de = -std::abs(
3206  (matprop->thickness() / costracksurf) *
3207  m_elosstool->dEdX(
3208  *matprop,
3209  (m_p != 0.0 ? std::abs(m_p) : std::abs(1. / currentqoverp)),
3210  matEffects));
3211  const double sintheta = std::sin(parforextrap->parameters()[Trk::theta]);
3212  const double sigmascat = std::sqrt(m_scattool->sigmaSquare(
3213  *matprop,
3214  (m_p != 0.0 ? std::abs(m_p) : std::abs(1. / currentqoverp)),
3215  1. / costracksurf,
3216  matEffects));
3217 
3218  std::unique_ptr<GXFMaterialEffects> meff = std::make_unique<GXFMaterialEffects>();
3219  meff->setDeltaE(de);
3220  meff->setScatteringSigmas(sigmascat / sintheta, sigmascat);
3221  meff->setX0(actualx0);
3222  meff->setSurface(&layer->surfaceRepresentation());
3223  meff->setMaterialProperties(matprop);
3224 
3225  /*
3226  * If we have an electron, or if so configured, calculate energy loss
3227  * as well.
3228  */
3229  std::unique_ptr<EnergyLoss> eloss;
3230 
3231  if (cache.m_fiteloss || (matEffects == electron && cache.m_asymeloss)) {
3232  eloss = std::make_unique<EnergyLoss>(m_elosstool->energyLoss(
3233  *matprop,
3234  (m_p != 0.0 ? std::abs(m_p) : std::abs(1. / currentqoverp)),
3235  1. / costracksurf,
3236  alongMomentum,
3237  matEffects
3238  ));
3239  if (eloss != nullptr) {
3240  meff->setSigmaDeltaE(eloss->sigmaDeltaE());
3241  }
3242  }
3243 
3244  if (matEffects == electron && cache.m_asymeloss) {
3245  meff->setDeltaE(-5);
3246  if (trajectory.numberOfTRTHits() == 0) {
3247  meff->setScatteringSigmas(0, 0);
3248  }
3249 
3250  meff->setSigmaDeltaE(50);
3251  if (eloss != nullptr) {
3252  meff->setSigmaDeltaEPos(eloss->sigmaPlusDeltaE());
3253  meff->setSigmaDeltaENeg(eloss->sigmaMinusDeltaE());
3254  }
3255  }
3256 
3257  ATH_MSG_DEBUG(
3258  "X0: " << meff->x0() << " qoverp: " << currentqoverp <<
3259  " sigmascat " << meff->sigmaDeltaTheta() <<" eloss: " << meff->deltaE() <<
3260  " sigma eloss: " << meff->sigmaDeltaE()
3261  );
3262 
3263  /*
3264  * Create a new track state in the internal representation and load it
3265  * with any and all information we might have.
3266  */
3267  std::unique_ptr<GXFTrackState> matstate = std::make_unique<GXFTrackState>(
3268  std::move(meff),
3269  std::unique_ptr<const TrackParameters>()
3270  );
3271  matstate->setPosition(intersect);
3272  trajectory.addMaterialState(std::move(matstate));
3273 
3274  /*
3275  * We're done on this layer, so the next state will go to the next
3276  * layer.
3277  */
3278  layerindex++;
3279  }
3280 
3281  trajectory.addBasicState(std::move(oldstates[i]));
3282  }
3283  }
3284 
3286  Cache & cache,
3287  std::vector<std::pair<const Layer *, const Layer *>> & layers,
3288  std::vector<std::pair<const Layer *, const Layer *>> & upstreamlayers,
3289  const std::vector<std::unique_ptr<GXFTrackState>> & oldstates,
3290  GXFTrackState & firstsistate,
3291  GXFTrackState & lastsistate,
3292  const TrackParameters *refpar,
3293  bool hasmat
3294  ) {
3295  /*
3296  * Reserve some arbitrary number of layers in the output vectors.
3297  */
3298  upstreamlayers.reserve(5);
3299  layers.reserve(30);
3300 
3301  /*
3302  * Gather a bunch of numbers from the parameters. Someties we need to grab
3303  * them from the first silicon state, sometimes from the last.
3304  */
3305  const double firstz = firstsistate.trackParameters()->position().z();
3306  const double firstr = firstsistate.trackParameters()->position().perp();
3307  const double firstz2 = hasmat ? lastsistate.trackParameters()->position().z() : firstsistate.trackParameters()->position().z();
3308  const double firstr2 = hasmat ? lastsistate.trackParameters()->position().perp() : firstsistate.trackParameters()->position().perp();
3309 
3310  GXFTrackState *firststate = oldstates.front().get();
3311  GXFTrackState *laststate = oldstates.back().get();
3312 
3313  /*
3314  * This number is particularly interesting, as it determines which side we
3315  * need to look at in regards to the disc layers.
3316  */
3317  const double lastz = laststate->position().z();
3318  const double lastr = laststate->position().perp();
3319 
3320  const Layer *startlayer = firststate->associatedSurface().associatedLayer();
3321  const Layer *startlayer2 = hasmat ? lastsistate.associatedSurface().associatedLayer() : nullptr;
3322  const Layer *endlayer = laststate->associatedSurface().associatedLayer();
3323 
3324  const double tantheta = std::tan(refpar->parameters()[Trk::theta]);
3325  const double slope = (tantheta != 0) ? 1 / tantheta : 0; // (lastz-firstz)/(lastr-firstr);
3326 
3327  /*
3328  * First, we will grab our disc layers.
3329  */
3330  if (slope != 0) {
3331  std::vector < const Layer *>::const_iterator it;
3332  std::vector < const Layer *>::const_iterator itend;
3333 
3334  /*
3335  * If we're on the positive z-side of the detector, we will iterate over
3336  * the positive discs. Otherwise, we will need to iterate over the
3337  * negative discs.
3338  */
3339  if (lastz > 0) {
3340  it = cache.m_posdiscs.begin();
3341  itend = cache.m_posdiscs.end();
3342  } else {
3343  it = cache.m_negdiscs.begin();
3344  itend = cache.m_negdiscs.end();
3345  }
3346 
3347  /*
3348  * Iterate over our disc layers.
3349  */
3350  for (; it != itend; ++it) {
3351  /*
3352  * If we've overshot the last hit in our track, we don't need to look
3353  * at any further layers. We're done!
3354  */
3355  if (std::abs((*it)->surfaceRepresentation().center().z()) > std::abs(lastz)) {
3356  break;
3357  }
3358 
3359  /*
3360  * Grab the bounds from the layer, which is a more useful kind of
3361  * object that allows us to do some geometric calculations.
3362  */
3363  const DiscBounds *discbounds = static_cast<const DiscBounds *> (&(*it)->surfaceRepresentation().bounds());
3364 
3365  /*
3366  * Ensure that we've actually hit the layer!
3367  */
3368  if (discbounds->rMax() < firstr || discbounds->rMin() > lastr) {
3369  continue;
3370  }
3371 
3372  const double rintersect = firstr + ((*it)->surfaceRepresentation().center().z() - firstz) / slope;
3373 
3374  if (
3375  rintersect < discbounds->rMin() - 50 ||
3376  rintersect > discbounds->rMax() + 50
3377  ) {
3378  continue;
3379  }
3380 
3381  /*
3382  * We also do not need to consider the last layer. If all goes well,
3383  * the next loop will immediately break because it will be an
3384  * overshoot.
3385  */
3386  if ((*it) == endlayer) {
3387  continue;
3388  }
3389 
3390  /*
3391  * If this layer lies before the first hit, it's an upstream hit and we
3392  * add it to the upstream layer vector.
3393  *
3394  * Notice how we add this layer on the right side of the pair, that's
3395  * the convention. Discs to right, cylinders go left.
3396  */
3397  if (
3398  std::abs((*it)->surfaceRepresentation().center().z()) < std::abs(firstz) ||
3399  (*it) == startlayer
3400  ) {
3401  upstreamlayers.emplace_back((Layer *) nullptr, (*it));
3402  }
3403 
3404  /*
3405  * Otherwise, it's a normal layer. Add it.
3406  */
3407  if (
3408  (*it) != startlayer &&
3409  (std::abs((*it)->surfaceRepresentation().center().z()) > std::abs(firstz2) ||
3410  (*it) == startlayer2)
3411  ) {
3412  layers.emplace_back((Layer *) nullptr, (*it));
3413  }
3414  }
3415  }
3416 
3417  /*
3418  * Now, we add the barrel cylinder layers.
3419  */
3420  for (const auto *barrelcylinder : cache.m_barrelcylinders) {
3421  /*
3422  * Check for overshoots and reject them.
3423  */
3424  if (barrelcylinder->surfaceRepresentation().bounds().r() > lastr) {
3425  break;
3426  }
3427 
3428  /*
3429  * Confirm intersection with the layer.
3430  */
3431  const double zintersect = firstz + (barrelcylinder->surfaceRepresentation().bounds().r() - firstr) * slope;
3432 
3433  if (std::abs(zintersect - barrelcylinder->surfaceRepresentation().center().z()) >
3434  ((const CylinderSurface*)(&barrelcylinder->surfaceRepresentation()))->bounds().halflengthZ() + 50) {
3435  continue;
3436  }
3437 
3438  if (barrelcylinder == endlayer) {
3439  continue;
3440  }
3441 
3442  /*
3443  * Same as with the discs, add the layers to the output vectors.
3444  */
3445  if (barrelcylinder->surfaceRepresentation().bounds().r() < firstr ||
3446  barrelcylinder == startlayer) {
3447  upstreamlayers.emplace_back(barrelcylinder, (Layer*)nullptr);
3448  }
3449 
3450  if (barrelcylinder != startlayer &&
3451  (barrelcylinder->surfaceRepresentation().bounds().r() > firstr2 ||
3452  barrelcylinder == startlayer2)) {
3453  layers.emplace_back(barrelcylinder, (Layer*)nullptr);
3454  }
3455  }
3456 
3457  /*
3458  * Sort the layers such that they are in the right order, from close to far
3459  * in respect to the experiment center.
3460  */
3461  std::sort(layers.begin(), layers.end(), GXF::LayerSort());
3462  std::sort(upstreamlayers.begin(), upstreamlayers.end(), GXF::LayerSort());
3463  }
3464 
3466  const EventContext& ctx,
3467  Cache & cache,
3468  GXFTrajectory & trajectory,
3469  const TrackParameters * refpar2,
3470  ParticleHypothesis matEffects
3471  ) const {
3472  /*
3473  * Ensure that the cache contains a valid tracking geometry that we can
3474  * use.
3475  */
3476  const bool caloEntranceIsValid = ensureValidEntranceCalo(ctx, cache);
3477  if (!caloEntranceIsValid) {
3478  return;
3479  }
3480 
3481  /*
3482  * If we have not yet set the discs on either side of the detector as well
3483  * as the barrel layers, do so now.
3484  */
3485  if (
3486  cache.m_negdiscs.empty() &&
3487  cache.m_posdiscs.empty() &&
3488  cache.m_barrelcylinders.empty()
3489  ) {
3490  /*
3491  * Attempt to add the layer information to the cache using the previously
3492  * selected tracking volume.
3493  */
3494  const bool ok = processTrkVolume(cache, cache.m_caloEntrance);
3495 
3496  /*
3497  * If this process somehow fails, we cannot use the fast material adding
3498  * algorithm and we must fall back to the slow version. As far as I know
3499  * this doesn't really happen.
3500  */
3501  if (!ok) {
3502  ATH_MSG_DEBUG("Falling back to slow material collection");
3503  cache.m_fastmat = false;
3504  addMaterial(ctx, cache, trajectory, refpar2, matEffects);
3505  return;
3506  }
3507 
3508  /*
3509  * Sort the discs and barrel layers such that they are in the right
3510  * order. What the right order is in this case is defined a bit above
3511  * this code, in the GXF::LayerSort2 class. Should be in increasing order
3512  * of distance from the detector center.
3513  */
3514  std::stable_sort(cache.m_negdiscs.begin(), cache.m_negdiscs.end(), GXF::LayerSort2());
3515  std::stable_sort(cache.m_posdiscs.begin(), cache.m_posdiscs.end(), GXF::LayerSort2());
3516  std::stable_sort(cache.m_barrelcylinders.begin(), cache.m_barrelcylinders.end(), GXF::LayerSort2());
3517  }
3518 
3519  const TrackParameters *refpar = refpar2;
3520  bool hasmat = false;
3521  int indexoffset = 0;
3522  int lastmatindex = 0;
3523  std::vector<std::unique_ptr<GXFTrackState>> & oldstates = trajectory.trackStates();
3524 
3525  GXFTrackState *firstsistate = nullptr;
3526  GXFTrackState *lastsistate = nullptr;
3527 
3528  /*
3529  * This loop serves several purposes in one, because it's very efficient:
3530  *
3531  * 1. It detects whether there are already any materials on this track, and
3532  * if so where they are.
3533  * 2. It determines what the first and last silicon hits are.
3534  * 3. It calculates trackparameters for any states that might not have them
3535  * for whatever reason.
3536  */
3537  for (int i = 0; i < (int) oldstates.size(); i++) {
3538  if (oldstates[i]->materialEffects() != nullptr) {
3539  hasmat = true;
3540  lastmatindex = i;
3541  }
3542 
3543  if (
3544  oldstates[i]->measurementType() == TrackState::Pixel ||
3545  oldstates[i]->measurementType() == TrackState::SCT
3546  ) {
3547  if (firstsistate == nullptr) {
3548  if (oldstates[i]->trackParameters() == nullptr) {
3549  std::unique_ptr<const TrackParameters> tmppar(m_propagator->propagateParameters(
3550  ctx,
3551  *refpar,
3552  oldstates[i]->associatedSurface(),
3553  alongMomentum,
3554  false,
3555  trajectory.m_fieldprop,
3557  ));
3558 
3559  if (tmppar == nullptr) return;
3560 
3561  oldstates[i]->setTrackParameters(std::move(tmppar));
3562  }
3563  firstsistate = oldstates[i].get();
3564  }
3565  lastsistate = oldstates[i].get();
3566  }
3567  }
3568 
3569  /*
3570  * Only happens when there are no tracks, and that shouldn't happen in the
3571  * first place.
3572  */
3573  if (lastsistate == nullptr) {
3574  throw std::logic_error("No track state");
3575  }
3576 
3577  /*
3578  * Also try to generate a set of track parameters for the last silicon hit
3579  * if it doesn't have any. I don't really know when that would happen, but
3580  * I suppose it's possible. Anything is possible, if you believe hard
3581  * enough.
3582  */
3583  if (lastsistate->trackParameters() == nullptr) {
3584  std::unique_ptr<const TrackParameters> tmppar(m_propagator->propagateParameters(
3585  ctx,
3586  *refpar,
3587  lastsistate->associatedSurface(),
3588  alongMomentum, false,
3589  trajectory.m_fieldprop,
3591  ));
3592 
3593  if (tmppar == nullptr) return;
3594 
3595  lastsistate->setTrackParameters(std::move(tmppar));
3596  }
3597 
3598  /*
3599  * If we have found any materials on the track, we've presumably already
3600  * done a fit for that part of the track, so the reference parameters are
3601  * either the first or last silicon state's parameters.
3602  */
3603  if (hasmat) {
3604  refpar = lastsistate->trackParameters();
3605  indexoffset = lastmatindex;
3606  } else {
3607  refpar = firstsistate->trackParameters();
3608  }
3609 
3610  /*
3611  * These vectors will hold the layers. The types here are a little bit
3612  * strange, but the idea is that the right member is a disc surface and the
3613  * left member is a cylindrical surface. Could be more elegantly done using
3614  * polymorphism.
3615  *
3616  * The upstream layers may already be filled due to previous fits.
3617  *
3618  * TODO: Use polymorphism to get rid of these strange types.
3619  */
3620  std::vector<std::pair<const Layer *, const Layer *>> layers;
3621  std::vector<std::pair<const Layer *, const Layer *>> & upstreamlayers = trajectory.upstreamMaterialLayers();
3622 
3623  /*
3624  * Fill the aforementioned layer vectors with layers.
3625  */
3626  addMaterialGetLayers(cache, layers, upstreamlayers, oldstates, *firstsistate, *lastsistate, refpar, hasmat);
3627 
3628  /*
3629  * Finally, use that layer information to actually add states to the track.
3630  */
3631  addMaterialUpdateTrajectory(cache, trajectory, indexoffset, layers, refpar, refpar2, matEffects);
3632  }
3633 
3635  const EventContext& ctx,
3636  Cache & cache,
3637  GXFTrajectory & trajectory,
3638  const TrackParameters * refpar2,
3639  ParticleHypothesis matEffects
3640  ) const {
3641  if (refpar2 == nullptr) {
3642  return;
3643  }
3644  const MeasurementBase *firstmuonhit = nullptr;
3645  const MeasurementBase *lastmuonhit = nullptr;
3646  const MeasurementBase *firstidhit =
3647  nullptr;
3648  const MeasurementBase *lastidhit = nullptr;
3649  const MeasurementBase *firsthit = nullptr;
3650  const MeasurementBase *lasthit = nullptr;
3651  std::vector<std::unique_ptr<GXFTrackState>> & states = trajectory.trackStates();
3652  std::vector<std::unique_ptr<GXFTrackState>> matstates;
3653  std::unique_ptr< const std::vector < const TrackStateOnSurface *>,
3654  void (*)(const std::vector<const TrackStateOnSurface *> *) >
3655  matvec(nullptr,&Trk::GlobalChi2Fitter::Cache::objVectorDeleter<TrackStateOnSurface>);
3656  bool matvec_used=false;
3657  std::unique_ptr<TrackParameters> startmatpar1;
3658  std::unique_ptr<TrackParameters> startmatpar2;
3659  const TrackParameters *firstidpar = nullptr;
3660  const TrackParameters *lastidpar = nullptr;
3661  const TrackParameters *firstsiliconpar = nullptr;
3662  const TrackParameters *lastsiliconpar = nullptr;
3663  const TrackParameters *firstmatpar = nullptr;
3664  const TrackParameters *firstcalopar = nullptr;
3665  const TrackParameters *lastcalopar = nullptr;
3666  const TrackParameters *firstmuonpar = nullptr;
3667  const TrackParameters *lastmuonpar = nullptr;
3668 
3669  int npseudomuon1 = 0;
3670  int npseudomuon2 = 0;
3671 
3672  for (auto & state : states) {
3673  TrackState::MeasurementType const meastype = state->measurementType();
3674  const TrackParameters *tp = state->trackParameters();
3675  GXFMaterialEffects *meff = state->materialEffects();
3676 
3677  if (meastype == TrackState::Pseudo) {
3678  if (firstidhit == nullptr) {
3679  npseudomuon1++;
3680  } else {
3681  npseudomuon2++;
3682  }
3683  continue;
3684  }
3685 
3686  if (state->getStateType(TrackStateOnSurface::Measurement) || state->getStateType(TrackStateOnSurface::Outlier)) {
3687  if (firsthit == nullptr) {
3688  firsthit = state->measurement();
3689  if (cache.m_acceleration) {
3690  if (tp == nullptr) {
3691  tp = m_extrapolator->extrapolate(
3692  ctx,
3693  *refpar2,
3694  state->associatedSurface(),
3695  alongMomentum,
3696  false,
3697  matEffects
3698  ).release();
3699 
3700  if (tp == nullptr) {
3701  return;
3702  }
3703 
3704  state->setTrackParameters(std::unique_ptr<const TrackParameters>(tp));
3705  }
3706  // When acceleration is enabled, material collection starts from first hit
3707  refpar2 = tp;
3708  }
3709  }
3710  lasthit = state->measurement();
3711  if (
3712  meastype == TrackState::Pixel ||
3713  meastype == TrackState::SCT ||
3714  meastype == TrackState::TRT
3715  ) {
3716  if (firstidhit == nullptr) {
3717  firstidhit = state->measurement();
3718  }
3719 
3720  if ((firstidpar == nullptr) && (tp != nullptr)) {
3721  firstidpar = tp;
3722  }
3723 
3724  lastidhit = state->measurement();
3725  if (tp != nullptr) {
3726  lastidpar = tp;
3727  }
3728 
3729  if ((tp != nullptr) && meastype != TrackState::TRT) {
3730  if (firstsiliconpar == nullptr) {
3731  firstsiliconpar = tp;
3732  }
3733  lastsiliconpar = tp;
3734  }
3735  }
3736 
3737  if (
3738  meastype == TrackState::RPC ||
3739  meastype == TrackState::CSC ||
3740  meastype == TrackState::TGC ||
3741  meastype == TrackState::MDT ||
3742  meastype == TrackState::MM ||
3743  meastype == TrackState::STGC
3744  ) {
3745  if (firstmuonhit == nullptr) {
3746  firstmuonhit = state->measurement();
3747  if (tp != nullptr) {
3748  firstmuonpar = tp;
3749  }
3750  }
3751  lastmuonhit = state->measurement();
3752  if (tp != nullptr) {
3753  lastmuonpar = tp;
3754  }
3755  }
3756  }
3757  if (state->getStateType(TrackStateOnSurface::Scatterer) || state->getStateType(TrackStateOnSurface::BremPoint)) {
3758  if (meff->deltaE() == 0) {
3759  if (firstcalopar == nullptr) {
3760  firstcalopar = state->trackParameters();
3761  }
3762  lastcalopar = state->trackParameters();
3763  }
3764  if (firstmatpar == nullptr) {
3765  firstmatpar = state->trackParameters();
3766  }
3767  }
3768  }
3769 
3770  std::unique_ptr<TrackParameters> refpar;
3771  AmgVector(5) newpars = refpar2->parameters();
3772 
3773  if (trajectory.m_straightline && m_p != 0) {
3774  newpars[Trk::qOverP] = 1 / m_p;
3775  }
3776 
3777  refpar = refpar2->associatedSurface().createUniqueTrackParameters(
3778  newpars[0], newpars[1], newpars[2], newpars[3], newpars[4], std::nullopt
3779  );
3780 
3781  if (firstmatpar != nullptr) {
3782  startmatpar1 = unique_clone(firstsiliconpar);
3783  startmatpar2 = unique_clone(lastsiliconpar);
3784  }
3785 
3786  if ((startmatpar1 == nullptr) || ((firstidhit != nullptr) && (firstmuonhit != nullptr))) {
3787  startmatpar1 = unique_clone(refpar);
3788  startmatpar2 = unique_clone(refpar);
3789 
3790  const double mass = trajectory.mass();
3791  if (mass > 200 * MeV) {
3792  const AmgVector(5) & newpars = startmatpar2->parameters();
3793  const double oldp = std::abs(1 / newpars[Trk::qOverP]);
3794  const double sign = (newpars[Trk::qOverP] < 0) ? -1 : 1;
3795 
3796  startmatpar2 = startmatpar2->associatedSurface().createUniqueTrackParameters(
3797  newpars[0], newpars[1], newpars[2], newpars[3],
3798  sign / std::sqrt(oldp * oldp + 2 * 100 * MeV * std::sqrt(oldp * oldp + mass * mass) + 100 * MeV * 100 * MeV),
3799  std::nullopt
3800  );
3801  }
3802  } else if (trajectory.m_straightline && m_p != 0) {
3803  AmgVector(5) newpars = startmatpar1->parameters();
3804  newpars[Trk::qOverP] = 1 / m_p;
3805 
3806  startmatpar1 = startmatpar1->associatedSurface().createUniqueTrackParameters(
3807  newpars[0], newpars[1], newpars[2], newpars[3], newpars[4], std::nullopt
3808  );
3809 
3810  newpars = startmatpar2->parameters();
3811  newpars[Trk::qOverP] = 1 / m_p;
3812 
3813  startmatpar2 = startmatpar2->associatedSurface().createUniqueTrackParameters(
3814  newpars[0], newpars[1], newpars[2], newpars[3], newpars[4], std::nullopt
3815  );
3816  }
3817 
3818  if ((firstidhit != nullptr) && trajectory.numberOfSiliconHits() > 0 && cache.m_idmat) {
3819 
3820  const DistanceSolution distsol = firstidhit->associatedSurface().straightLineDistanceEstimate(
3821  refpar->position(),
3822  refpar->momentum().unit()
3823  );
3824 
3825  const double distance = getDistance(distsol);
3826 
3827  if (distance < 0 && distsol.numberOfSolutions() > 0 && !cache.m_acceleration) {
3828  ATH_MSG_DEBUG("Obtaining upstream layers from Extrapolator");
3829 
3830  const Surface *destsurf = &firstidhit->associatedSurface();
3831  std::unique_ptr<const TrackParameters> tmppar;
3832 
3833  if (firstmuonhit != nullptr) {
3834  const bool caloEntranceIsValid = ensureValidEntranceCalo(ctx, cache);
3835  if (caloEntranceIsValid) {
3836  tmppar = m_extrapolator->extrapolateToVolume(ctx,
3837  *startmatpar1,
3838  *cache.m_caloEntrance,
3841 
3842  if (tmppar != nullptr) {
3843  destsurf = &tmppar->associatedSurface();
3844  }
3845  }
3846  }
3847 
3848  if (matvec_used) cache.m_matTempStore.push_back( std::move(matvec) );
3849  matvec.reset( m_extrapolator->extrapolateM(ctx,
3850  *startmatpar1,
3851  *destsurf,
3853  false, matEffects) );
3854  matvec_used=false;
3855 
3856  if (matvec && !matvec->empty()) {
3857  for (int i = (int)matvec->size() - 1; i > -1; i--) {
3858  const MaterialEffectsBase *meb = (*matvec)[i]->materialEffectsOnTrack();
3859  if (meb) {
3861  const MaterialEffectsOnTrack *meot = static_cast < const MaterialEffectsOnTrack * >(meb);
3862  std::unique_ptr<GXFMaterialEffects> meff = std::make_unique<GXFMaterialEffects>(*meot);
3863  const TrackParameters * newpars = (*matvec)[i]->trackParameters() != nullptr ? (*matvec)[i]->trackParameters()->clone() : nullptr;
3864  meff->setSigmaDeltaE(0);
3865  matstates.push_back(std::make_unique<GXFTrackState>(
3866  std::move(meff),
3867  std::unique_ptr<const TrackParameters>(newpars)
3868  ));
3869  matvec_used=true;
3870  }
3871  }
3872  }
3873  }
3874  }
3875  }
3876 
3877  if ((lastidhit != nullptr) && trajectory.numberOfSiliconHits() > 0 && cache.m_idmat) {
3879  refpar->position(),
3880  refpar->momentum().unit()
3881  );
3882 
3883  const double distance = getDistance(distsol);
3884 
3885  if (distance > 0 && distsol.numberOfSolutions() > 0) {
3886  ATH_MSG_DEBUG("Obtaining downstream ID layers from Extrapolator");
3887  const Surface *destsurf = &lastidhit->associatedSurface();
3888  std::unique_ptr<const TrackParameters> tmppar;
3889  std::unique_ptr<Surface> calosurf;
3890  if (firstmuonhit != nullptr) {
3891  const bool caloEntranceIsValid = ensureValidEntranceCalo(ctx, cache);
3892  if (caloEntranceIsValid) {
3893  tmppar = m_extrapolator->extrapolateToVolume(ctx,
3894  *startmatpar2,
3895  *cache.m_caloEntrance,
3898  }
3899 
3900  if (tmppar != nullptr) {
3901  const CylinderSurface *cylcalosurf = nullptr;
3902 
3903  if (tmppar->associatedSurface().type() == Trk::SurfaceType::Cylinder)
3904  cylcalosurf = static_cast<const CylinderSurface *>(&tmppar->associatedSurface());
3905 
3906  const DiscSurface *disccalosurf = nullptr;
3907 
3908  if (tmppar->associatedSurface().type() == Trk::SurfaceType::Disc)
3909  disccalosurf = static_cast<const DiscSurface *>(&tmppar->associatedSurface());
3910 
3911  if (cylcalosurf != nullptr) {
3912  Amg::Transform3D const trans = Amg::Transform3D(cylcalosurf->transform());
3913  const CylinderBounds & cylbounds = cylcalosurf->bounds();
3914  const double radius = cylbounds.r();
3915  const double hlength = cylbounds.halflengthZ();
3916  calosurf = std::make_unique<CylinderSurface>(trans, radius - 1, hlength);
3917  } else if (disccalosurf != nullptr) {
3918  const double newz = (
3919  disccalosurf->center().z() > 0 ?
3920  disccalosurf->center().z() - 1 :
3921  disccalosurf->center().z() + 1
3922  );
3923 
3924  const Amg::Vector3D newpos(
3925  disccalosurf->center().x(),
3926  disccalosurf->center().y(),
3927  newz
3928  );
3929 
3930  Amg::Transform3D trans = (disccalosurf->transform());
3931  trans.translation() << newpos;
3932 
3933  const DiscBounds *discbounds = static_cast<const DiscBounds *>(&disccalosurf->bounds());
3934  const double rmin = discbounds->rMin();
3935  const double rmax = discbounds->rMax();
3936  calosurf = std::make_unique<DiscSurface>(trans, rmin, rmax);
3937  }
3938  destsurf = calosurf.release();
3939  }
3940  }
3941 
3942  if (matvec_used) cache.m_matTempStore.push_back( std::move(matvec) );
3943  matvec.reset(m_extrapolator->extrapolateM(
3944  ctx, *startmatpar2, *destsurf, alongMomentum, false, matEffects));
3945  matvec_used = false;
3946 
3947  if (matvec && !matvec->empty()) {
3948  for (const auto & i : *matvec) {
3949  const Trk::MaterialEffectsBase * meb = i->materialEffectsOnTrack();
3950 
3951  if (meb) {
3953  const MaterialEffectsOnTrack *meot = static_cast<const MaterialEffectsOnTrack *>(meb);
3954  std::unique_ptr<GXFMaterialEffects> meff = std::make_unique<GXFMaterialEffects>(*meot);
3955  if (cache.m_fiteloss && (meot->energyLoss() != nullptr)) {
3956  meff->setSigmaDeltaE(meot->energyLoss()->sigmaDeltaE());
3957  }
3958 
3959  if (matEffects == electron && cache.m_asymeloss) {
3960  meff->setDeltaE(-5);
3961 
3962  if (trajectory.numberOfTRTHits() == 0) {
3963  meff->setScatteringSigmas(0, 0);
3964  }
3965 
3966  meff->setSigmaDeltaE(50);
3967  }
3968 
3969  const TrackParameters * newparams = i->trackParameters() != nullptr ? i->trackParameters()->clone() : nullptr;
3970 
3971  matstates.push_back(std::make_unique<GXFTrackState>(
3972  std::move(meff),
3973  std::unique_ptr<const TrackParameters>(newparams)
3974  ));
3975  matvec_used=true;
3976  }
3977  }
3978  }
3979  } else {
3980  ATH_MSG_WARNING("No material layers collected from Extrapolator");
3981  }
3982  }
3983  }
3984 
3985  if (cache.m_calomat && (firstmuonhit != nullptr) && (firstidhit != nullptr)) {
3986  const IPropagator *prop = &*m_propagator;
3987 
3988  std::vector<MaterialEffectsOnTrack> calomeots = m_calotool->extrapolationSurfacesAndEffects(
3989  *m_navigator->highestVolume(ctx),
3990  *prop,
3991  *lastidpar,
3992  firstmuonhit->associatedSurface(),
3993  alongMomentum,
3994  muon
3995  );
3996 
3997  if (calomeots.empty()) {
3998  ATH_MSG_WARNING("No material layers collected in calorimeter");
3999  return;
4000  }
4001 
4002  std::unique_ptr<const TrackParameters> prevtrackpars = unique_clone(lastidpar);
4003  if (lasthit == lastmuonhit) {
4004  for (int i = 0; i < (int) calomeots.size(); i++) {
4005  const PropDirection propdir = alongMomentum;
4006 
4007  std::unique_ptr<const TrackParameters> layerpar(m_propagator->propagateParameters(
4008  ctx,
4009  *prevtrackpars,
4010  calomeots[i].associatedSurface(),
4011  propdir,
4012  false,
4013  trajectory.m_fieldprop,
4015  ));
4016 
4017  if (layerpar == nullptr) {
4019  return;
4020  }
4021 
4022  std::unique_ptr<GXFMaterialEffects> meff = std::make_unique<GXFMaterialEffects>(calomeots[i]);
4023 
4024  if (i == 2) {
4025  lastcalopar = layerpar.get();
4026  }
4027 
4028  if (i == 1) {
4029  const double qoverp = layerpar->parameters()[Trk::qOverP];
4030  double qoverpbrem = 0;
4031 
4032  if (
4033  npseudomuon2 < 2 &&
4034  (firstmuonpar != nullptr) &&
4035  std::abs(firstmuonpar->parameters()[Trk::qOverP]) > 1.e-9
4036  ) {
4037  qoverpbrem = firstmuonpar->parameters()[Trk::qOverP];
4038  } else {
4039  const double sign = (qoverp > 0) ? 1 : -1;
4040  qoverpbrem = sign / (1 / std::abs(qoverp) - std::abs(calomeots[i].energyLoss()->deltaE()));
4041  }
4042 
4043  const AmgVector(5) & newpar = layerpar->parameters();
4044 
4045  layerpar = layerpar->associatedSurface().createUniqueTrackParameters(
4046  newpar[0], newpar[1], newpar[2], newpar[3], qoverpbrem, std::nullopt
4047  );
4048  meff->setdelta_p(1000 * (qoverpbrem - qoverp));
4049  }
4050 
4051  matstates.push_back(std::make_unique<GXFTrackState>(
4052  std::move(meff),
4053  std::unique_ptr<const TrackParameters>(layerpar != nullptr ? layerpar->clone() : nullptr)
4054  ));
4055  prevtrackpars = std::move(layerpar);
4056  }
4057  }
4058 
4059  if (
4060  firsthit == firstmuonhit &&
4061  (!cache.m_getmaterialfromtrack || lasthit == lastidhit)
4062  ) {
4063  prevtrackpars = unique_clone(firstidpar);
4064  for (int i = 0; i < (int) calomeots.size(); i++) {
4065  const PropDirection propdir = oppositeMomentum;
4066  std::unique_ptr<const TrackParameters> layerpar(m_propagator->propagateParameters(
4067  ctx,
4068  *prevtrackpars,
4069  calomeots[i].associatedSurface(),
4070  propdir,
4071  false,
4072  trajectory.m_fieldprop,
4074  ));
4075 
4076  if (layerpar == nullptr) {
4078  return;
4079  }
4080 
4081  std::unique_ptr<GXFMaterialEffects> meff = std::make_unique<GXFMaterialEffects>(calomeots[i]);
4082 
4083  if (i == 2) {
4084  firstcalopar = unique_clone(layerpar.get()).release();
4085  }
4086 
4087  prevtrackpars = unique_clone(layerpar.get());
4088 
4089  if (i == 1) {
4090  const double qoverpbrem = layerpar->parameters()[Trk::qOverP];
4091  double qoverp = 0;
4092 
4093  if (
4094  npseudomuon1 < 2 &&
4095  (lastmuonpar != nullptr) &&
4096  std::abs(lastmuonpar->parameters()[Trk::qOverP]) > 1.e-9
4097  ) {
4098  qoverp = lastmuonpar->parameters()[Trk::qOverP];
4099  } else {
4100  const double sign = (qoverpbrem > 0) ? 1 : -1;
4101  qoverp = sign / (1 / std::abs(qoverpbrem) + std::abs(calomeots[i].energyLoss()->deltaE()));
4102  }
4103 
4104  meff->setdelta_p(1000 * (qoverpbrem - qoverp));
4105  const AmgVector(5) & newpar = layerpar->parameters();
4106 
4107  prevtrackpars = layerpar->associatedSurface().createUniqueTrackParameters(
4108  newpar[0], newpar[1], newpar[2], newpar[3], qoverp, std::nullopt
4109  );
4110  }
4111 
4112  matstates.insert(matstates.begin(), std::make_unique<GXFTrackState>(std::move(meff), std::move(layerpar)));
4113  }
4114  }
4115  }
4116 
4117  if (lasthit == lastmuonhit && cache.m_extmat) {
4118  std::unique_ptr<const Trk::TrackParameters> muonpar1;
4119 
4120  if (lastcalopar != nullptr) {
4121  const bool msEntranceIsValid = ensureValidEntranceMuonSpectrometer(ctx, cache);
4122  if (msEntranceIsValid) {
4123  if (cache.m_msEntrance->inside(lastcalopar->position())) {
4124  muonpar1 = m_extrapolator->extrapolateToVolume(ctx,
4125  *lastcalopar,
4126  *cache.m_msEntrance,
4129 
4130  if (muonpar1 != nullptr) {
4131  const Amg::Vector3D trackdir = muonpar1->momentum().unit();
4132  const Amg::Vector3D curvZcrossT = -(trackdir.cross(Amg::Vector3D(0, 0, 1)));
4133  const Amg::Vector3D curvU = curvZcrossT.unit();
4134  const Amg::Vector3D curvV = trackdir.cross(curvU);
4135  Amg::RotationMatrix3D rot = Amg::RotationMatrix3D::Identity();
4136  rot.col(0) = curvU;
4137  rot.col(1) = curvV;
4138  rot.col(2) = trackdir;
4139  Amg::Transform3D trans;
4140  trans.linear().matrix() << rot;
4141  trans.translation() << muonpar1->position() - .1 * trackdir;
4142  PlaneSurface const curvlinsurf(trans);
4143 
4144  std::unique_ptr<const TrackParameters> curvlinpar(m_extrapolator->extrapolateDirectly(
4145  ctx,
4146  *muonpar1,
4147  curvlinsurf,
4150  ));
4151 
4152  if (curvlinpar != nullptr) {
4153  muonpar1 = std::move(curvlinpar);
4154  }
4155  }
4156  } else {
4157  muonpar1 = std::unique_ptr<TrackParameters>(lastcalopar->clone());
4158  }
4159  }
4160  } else {
4161  muonpar1 = std::unique_ptr<TrackParameters>(refpar->clone());
4162  }
4163 
4164  DistanceSolution distsol;
4165 
4166  if (muonpar1 != nullptr) {
4167  distsol = lastmuonhit->associatedSurface().straightLineDistanceEstimate(
4168  muonpar1->position(),
4169  muonpar1->momentum().unit()
4170  );
4171  }
4172 
4173  double distance = getDistance(distsol);
4174 
4175  if ((distance > 0) and(distsol.numberOfSolutions() >
4176  0) and (firstmuonhit != nullptr)) {
4177  distsol = firstmuonhit->associatedSurface().straightLineDistanceEstimate(
4178  muonpar1->position(),
4179  muonpar1->momentum().unit()
4180  );
4181 
4182  distance = 0;
4183 
4184  if (distsol.numberOfSolutions() == 1) {
4185  distance = distsol.first();
4186  } else if (distsol.numberOfSolutions() == 2) {
4187  distance = (
4188  std::abs(distsol.first()) < std::abs(distsol.second()) ?
4189  distsol.first() :
4190  distsol.second()
4191  );
4192  }
4193 
4194  if (distance < 0 && distsol.numberOfSolutions() > 0 && (firstidhit == nullptr)) {
4195  if (firstmuonpar != nullptr) {
4196  AmgVector(5) newpars = firstmuonpar->parameters();
4197 
4198  if (trajectory.m_straightline && m_p != 0) {
4199  newpars[Trk::qOverP] = 1 / m_p;
4200  }
4201 
4202  muonpar1 = firstmuonpar->associatedSurface().createUniqueTrackParameters(
4203  newpars[0], newpars[1], newpars[2], newpars[3], newpars[4], std::nullopt
4204  );
4205  } else {
4206  std::unique_ptr<const TrackParameters> tmppar(m_propagator->propagateParameters(
4207  ctx,
4208  *muonpar1,
4209  firstmuonhit->associatedSurface(),
4211  false,
4212  trajectory.m_fieldprop,
4214  ));
4215 
4216  if (tmppar != nullptr) {
4217  muonpar1 = std::move(tmppar);
4218  }
4219  }
4220  }
4221 
4222  const TrackParameters *prevtp = muonpar1.get();
4223  ATH_MSG_DEBUG("Obtaining downstream layers from Extrapolator");
4224  if (matvec_used) cache.m_matTempStore.push_back( std::move(matvec) );
4225  matvec.reset(m_extrapolator->extrapolateM(ctx,
4226  *prevtp,
4227  states.back()->associatedSurface(),
4228  alongMomentum,
4229  false,
4231  matvec_used = false;
4232 
4233  if (matvec && matvec->size() > 1000 && m_rejectLargeNScat) {
4234  ATH_MSG_DEBUG("too many scatterers: " << matvec->size());
4235  return;
4236  }
4237 
4238  if (matvec && !matvec->empty()) {
4239  for (int j = 0; j < (int) matvec->size(); j++) {
4240  const MaterialEffectsBase *meb = (*matvec)[j]->materialEffectsOnTrack();
4241 
4242  if (meb) {
4243  if ((meb->derivedType() == MaterialEffectsBase::MATERIAL_EFFECTS_ON_TRACK) and (j < (int) matvec->size() - 1)) {
4244  const MaterialEffectsOnTrack *meot = static_cast<const MaterialEffectsOnTrack *>(meb);
4245  std::unique_ptr<GXFMaterialEffects> meff = std::make_unique<GXFMaterialEffects>(*meot);
4246 
4247  if (
4248  !trajectory.m_straightline &&
4249  (meot->energyLoss() != nullptr) &&
4250  std::abs(meff->deltaE()) > 25 &&
4251  std::abs((*matvec)[j]->trackParameters()->position().z()) < 13000
4252  ) {
4253  meff->setSigmaDeltaE(meot->energyLoss()->sigmaDeltaE());
4254  }
4255 
4256  const TrackParameters * newparams = (*matvec)[j]->trackParameters() != nullptr ? (*matvec)[j]->trackParameters()->clone() : nullptr;
4257 
4258  matstates.push_back(std::make_unique<GXFTrackState>(
4259  std::move(meff),
4260  std::unique_ptr<const TrackParameters>(newparams)
4261  ));
4262  matvec_used=true;
4263  }
4264  }
4265  }
4266  }
4267  }
4268  }
4269 
4270  if (firsthit == firstmuonhit && cache.m_extmat && (firstcalopar != nullptr)) {
4271  std::unique_ptr<const Trk::TrackParameters> muonpar1;
4272 
4273  const bool msEntranceIsValid = ensureValidEntranceMuonSpectrometer(ctx, cache);
4274  if (msEntranceIsValid) {
4275  if (cache.m_msEntrance->inside(firstcalopar->position())) {
4276  muonpar1 = m_extrapolator->extrapolateToVolume(ctx,
4277  *firstcalopar,
4278  *cache.m_msEntrance,
4281 
4282  if (muonpar1 != nullptr) {
4283  const Amg::Vector3D trackdir = muonpar1->momentum().unit();
4284  const Amg::Vector3D curvZcrossT = -(trackdir.cross(Amg::Vector3D(0, 0, 1)));
4285  const Amg::Vector3D curvU = curvZcrossT.unit();
4286  const Amg::Vector3D curvV = trackdir.cross(curvU);
4287  Amg::RotationMatrix3D rot = Amg::RotationMatrix3D::Identity();
4288  rot.col(0) = curvU;
4289  rot.col(1) = curvV;
4290  rot.col(2) = trackdir;
4291  Amg::Transform3D trans;
4292  trans.linear().matrix() << rot;
4293  trans.translation() << muonpar1->position() - .1 * trackdir;
4294  const PlaneSurface curvlinsurf(trans);
4295 
4296  std::unique_ptr<const TrackParameters> curvlinpar(m_extrapolator->extrapolateDirectly(
4297  ctx,
4298  *muonpar1,
4299  curvlinsurf,
4302  ));
4303 
4304  if (curvlinpar != nullptr) {
4305  muonpar1 = std::move(curvlinpar);
4306  }
4307  }
4308  } else {
4309  muonpar1 = std::unique_ptr<const TrackParameters>(firstcalopar->clone());
4310  }
4311  }
4312 
4313  DistanceSolution distsol;
4314 
4315  if (muonpar1 != nullptr) {
4316  distsol = firstmuonhit->associatedSurface().straightLineDistanceEstimate(
4317  muonpar1->position(),
4318  muonpar1->momentum().unit()
4319  );
4320  }
4321 
4322  const double distance = getDistance(distsol);
4323 
4324  if (distance < 0 && distsol.numberOfSolutions() > 0) {
4325  const TrackParameters *prevtp = muonpar1.get();
4326  ATH_MSG_DEBUG("Collecting upstream muon material from extrapolator");
4327  if (matvec_used) cache.m_matTempStore.push_back( std::move(matvec) );
4328  matvec.reset(m_extrapolator->extrapolateM(ctx,
4329  *prevtp,
4330  states[0]->associatedSurface(),
4332  false,
4334  matvec_used = false;
4335 
4336  if (matvec && !matvec->empty()) {
4337  ATH_MSG_DEBUG("Retrieved " << matvec->size() << " material states");
4338 
4339  for (int j = 0; j < (int) matvec->size(); j++) {
4340  const MaterialEffectsBase *meb = (*matvec)[j]->materialEffectsOnTrack();
4341 
4342  if (meb != nullptr) {
4343 
4344 
4345  if ((meb->derivedType() == MaterialEffectsBase::MATERIAL_EFFECTS_ON_TRACK) && j < (int) matvec->size() - 1) {
4346  const MaterialEffectsOnTrack *meot = static_cast<const MaterialEffectsOnTrack *>(meb);
4347  std::unique_ptr<GXFMaterialEffects> meff = std::make_unique<GXFMaterialEffects>(*meot);
4348 
4349  if (
4350  !trajectory.m_straightline &&
4351  (meot->energyLoss() != nullptr) &&
4352  std::abs(meff->deltaE()) > 25 &&
4353  std::abs((*matvec)[j]->trackParameters()->position().z()) < 13000
4354  ) {
4355  meff->setSigmaDeltaE(meot->energyLoss()->sigmaDeltaE());
4356  }
4357 
4358  const TrackParameters* tmpparams =
4359  (*matvec)[j]->trackParameters() != nullptr
4360  ? (*matvec)[j]->trackParameters()->clone()
4361  : nullptr;
4362 
4363  matstates.insert(matstates.begin(), std::make_unique<GXFTrackState>(
4364  std::move(meff),
4365  std::unique_ptr<const TrackParameters>(tmpparams)
4366  ));
4367  matvec_used=true;
4368  }
4369  }
4370  }
4371  }
4372  }
4373  }
4374 
4375  ATH_MSG_DEBUG("Number of layers: " << matstates.size());
4376 
4377  // Now insert the material states into the trajectory
4378  std::vector<std::unique_ptr<GXFTrackState>> & newstates = states;
4379  std::vector<std::unique_ptr<GXFTrackState>> oldstates = std::move(newstates);
4380 
4381  newstates.clear();
4382  newstates.reserve(oldstates.size() + matstates.size());
4383 
4384  int layerno = 0;
4385  int firstlayerno = -1;
4386 
4387  if (cache.m_acceleration) {
4388  trajectory.addBasicState(std::move(oldstates[0]));
4389  }
4390 
4391  const double cosphi = std::cos(refpar->parameters()[Trk::phi0]);
4392  const double sinphi = std::sin(refpar->parameters()[Trk::phi0]);
4393 
4394  for (int i = cache.m_acceleration ? 1 : 0; i < (int) oldstates.size(); i++) {
4395  bool addlayer = true;
4396 
4397  while (addlayer && layerno < (int) matstates.size()) {
4398  addlayer = false;
4399  const TrackParameters *layerpar = matstates[layerno]->trackParameters();
4400 
4401  const DistanceSolution distsol = oldstates[i]->associatedSurface().straightLineDistanceEstimate(
4402  layerpar->position(),
4403  layerpar->momentum().unit()
4404  );
4405 
4406  const double distance = getDistance(distsol);
4407 
4408  if (distance > 0 && distsol.numberOfSolutions() > 0) {
4409  addlayer = true;
4410  }
4411 
4412  if (layerpar->associatedSurface().type() == Trk::SurfaceType::Cylinder) {
4413  const double cylinderradius = layerpar->associatedSurface().bounds().r();
4414  const double trackimpact = std::abs(-refpar->position().x() * sinphi + refpar->position().y() * cosphi);
4415 
4416  if (trackimpact > cylinderradius - 5 * mm) {
4417  layerno++;
4418  continue;
4419  }
4420  }
4421 
4422  if (i == (int) oldstates.size() - 1) {
4423  addlayer = true;
4424  }
4425 
4426  if (addlayer) {
4427  GXFMaterialEffects *meff = matstates[layerno]->materialEffects();
4428 
4429  if (meff->sigmaDeltaPhi() > .4 || (meff->sigmaDeltaPhi() == 0 && meff->sigmaDeltaE() <= 0)) {
4430  if (meff->sigmaDeltaPhi() > .4) {
4431  ATH_MSG_DEBUG("Material state with excessive scattering, skipping it");
4432  }
4433 
4434  if (meff->sigmaDeltaPhi() == 0) {
4435  ATH_MSG_WARNING("Material state with zero scattering, skipping it");
4436  }
4437 
4438  layerno++;
4439  continue;
4440  }
4441 
4442  if (firstlayerno < 0) {
4443  firstlayerno = layerno;
4444  }
4445 
4446  trajectory.addMaterialState(std::move(matstates[layerno]));
4447 
4448  if ((layerpar != nullptr) && matEffects != pion && matEffects != muon) {
4449  const TrackingVolume *tvol = m_navigator->volume(ctx,layerpar->position());
4450  const Layer *lay = nullptr;
4451 
4452  if (tvol != nullptr) {
4453  lay = (tvol->closestMaterialLayer(layerpar->position(),layerpar->momentum().normalized())).object;
4454  }
4455 
4456  const MaterialProperties *matprop = lay != nullptr ? lay->fullUpdateMaterialProperties(*layerpar) : nullptr;
4457  meff->setMaterialProperties(matprop);
4458  }
4459 
4460  layerno++;
4461  }
4462  }
4463  trajectory.addBasicState(std::move(oldstates[i]));
4464  }
4465 
4466  ATH_MSG_DEBUG("Total X0: " << trajectory.totalX0() << " total eloss: " << trajectory.totalEnergyLoss());
4467 
4468  if (matvec_used) cache.m_matTempStore.push_back( std::move(matvec) );
4469  }
4470 
4471  std::unique_ptr<const TrackParameters> GlobalChi2Fitter::makePerigee(
4472  Cache & cache,
4473  const TrackParameters & param,
4474  ParticleHypothesis matEffects
4475  ) const {
4476  const PerigeeSurface *persurf = nullptr;
4477 
4479  persurf = static_cast<const PerigeeSurface *>(&param.associatedSurface());
4480 
4481  if ((persurf != nullptr) && (!cache.m_acceleration || persurf->center().perp() > 5)) {
4482  const AmgVector(5) & pars = param.parameters();
4484  pars[0], pars[1], pars[2], pars[3], pars[4], std::nullopt
4485  );
4486  }
4487 
4488  if (cache.m_acceleration) {
4489  return nullptr;
4490  }
4491 
4492  PerigeeSurface const tmppersf;
4493  std::unique_ptr<const TrackParameters> per(m_extrapolator->extrapolate(
4494  Gaudi::Hive::currentContext(),param, tmppersf, oppositeMomentum, false, matEffects));
4495 
4496  if (per == nullptr) {
4497  ATH_MSG_DEBUG("Cannot make Perigee with starting parameters");
4498  return nullptr;
4499  }
4500 
4501  if(std::abs(per->position().z())>5000.) {
4502  ATH_MSG_WARNING("Pathological perigee well outside of tracking detector!! Returning nullptr");
4503  return nullptr;
4504  }
4505 
4506  return per;
4507  }
4508 
4510  const EventContext& ctx,
4511  Cache & cache,
4512  GXFTrajectory & trajectory,
4513  const TrackParameters & param,
4514  const RunOutlierRemoval runOutlier,
4515  const ParticleHypothesis matEffects
4516  ) const {
4517  ATH_MSG_DEBUG("--> entering GlobalChi2Fitter::myfit_helper");
4519  trajectory.m_straightline = m_straightlineprop;
4520 
4521  if (!trajectory.m_straightline) {
4522  if (trajectory.numberOfSiliconHits() + trajectory.numberOfTRTHits() == trajectory.numberOfHits()) {
4523  trajectory.m_straightline = !cache.m_field_cache.solenoidOn();
4524  } else if ((trajectory.prefit() == 0) && trajectory.numberOfSiliconHits() + trajectory.numberOfTRTHits() == 0) {
4525  trajectory.m_straightline = !cache.m_field_cache.toroidOn();
4526  } else {
4527  trajectory.m_straightline = (!cache.m_field_cache.solenoidOn() && !cache.m_field_cache.toroidOn());
4528  }
4529  }
4530 
4531  trajectory.m_fieldprop = trajectory.m_straightline ? Trk::NoField : Trk::FullField;
4532  cache.m_lastiter = 0;
4533 
4534  Amg::SymMatrixX lu;
4535 
4536  if (trajectory.numberOfPerigeeParameters() == -1) {
4537  cache.incrementFitStatus(S_FITS);
4538  if (trajectory.m_straightline) {
4539  trajectory.setNumberOfPerigeeParameters(4);
4540  } else {
4541  trajectory.setNumberOfPerigeeParameters(5);
4542  }
4543  }
4544 
4545  if (trajectory.nDOF() < 0) {
4546  ATH_MSG_DEBUG("Not enough measurements, reject track");
4547  return nullptr;
4548  }
4549 
4550  cache.m_phiweight.clear();
4551  cache.m_firstmeasurement.clear();
4552  cache.m_lastmeasurement.clear();
4553 
4554  if (matEffects != nonInteracting && param.parameters()[Trk::qOverP] == 0 && m_p == 0) {
4555  ATH_MSG_WARNING("Attempt to apply material corrections with q/p=0, reject track");
4556  return nullptr;
4557  }
4558 
4559  if (matEffects == Trk::electron && trajectory.m_straightline) {
4560  ATH_MSG_WARNING("Electron fit requires helix track model");
4561  return nullptr;
4562  }
4563 
4564  const double mass = Trk::ParticleMasses::mass[matEffects];
4565  trajectory.setMass(mass);
4566 
4567  ATH_MSG_DEBUG("start param: " << param << " pos: " << param.position() << " pt: " << param.pT());
4568 
4569  std::unique_ptr<const TrackParameters> per = makePerigee(cache, param, matEffects);
4570 
4571  if (!cache.m_acceleration && (per == nullptr)) {
4574  ATH_MSG_DEBUG("Propagation to perigee failed 1");
4575  return nullptr;
4576  }
4577 
4578  if (matEffects != Trk::nonInteracting && !cache.m_matfilled) {
4579  if (
4580  cache.m_fastmat &&
4581  cache.m_acceleration &&
4582  trajectory.numberOfSiliconHits() + trajectory.numberOfTRTHits() == trajectory.numberOfHits() &&
4583  (m_matupdator.empty() || (m_trackingGeometryReadKey.key().empty()))
4584  ) {
4585  ATH_MSG_WARNING("Tracking Geometry Service and/or Material Updator Tool not configured");
4586  ATH_MSG_WARNING("Falling back to slow material collection");
4587 
4588  cache.m_fastmat = false;
4589  }
4590 
4591  if (
4592  !cache.m_fastmat ||
4593  !cache.m_acceleration ||
4594  trajectory.numberOfSiliconHits() + trajectory.numberOfTRTHits() != trajectory.numberOfHits()
4595  ) {
4596  addMaterial(ctx, cache, trajectory, per != nullptr ? per.get() : &param, matEffects);
4597  } else {
4599  ctx, cache, trajectory, per != nullptr ? per.get() : &param, matEffects);
4600  }
4601  }
4602 
4603  if (cache.m_acceleration && (trajectory.referenceParameters() == nullptr) && (per == nullptr)) {
4605 
4606  if (trajectory.numberOfScatterers() >= 2) {
4607  GXFTrackState *scatstate = nullptr;
4608  GXFTrackState *scatstate2 = nullptr;
4609  int scatindex = 0;
4610 
4611  for (const auto & state : trajectory.trackStates()) {
4612  if (state->getStateType(TrackStateOnSurface::Scatterer)) {
4613  if (
4614  scatindex == trajectory.numberOfScatterers() / 2 ||
4615  state->materialEffects()->deltaE() == 0
4616  ) {
4617  scatstate2 = state.get();
4618  break;
4619  }
4620 
4621  scatindex++;
4622  scatstate = state.get();
4623  }
4624  }
4625 
4626  // @TODO coverity complains about a possible null pointer dereferencing in scatstate->... or scatstate2->...
4627  // it seems to me that if (**it).materialEffects()->deltaE()==0 of the first scatterer
4628  // than scatstate will be NULL.
4629  if ((scatstate == nullptr) || (scatstate2 == nullptr)) {
4630  throw std::logic_error("Invalid scatterer");
4631  }
4632 
4633  vertex = .49 * (scatstate->position() + scatstate2->position());
4634  } else {
4635  const int nstates = (int) trajectory.trackStates().size();
4636  vertex = .49 * (
4637  trajectory.trackStates()[nstates / 2 - 1]->position() +
4638  trajectory.trackStates()[nstates / 2]->position()
4639  );
4640  }
4641 
4642  PerigeeSurface const persurf(vertex);
4643  std::unique_ptr<const TrackParameters> nearestpar;
4644  double mindist = 99999;
4645  std::vector < GXFTrackState * >mymatvec;
4646 
4647  for (auto & it : trajectory.trackStates()) {
4648  if ((*it).trackParameters() == nullptr) {
4649  continue;
4650  }
4651 
4652  const double distance = persurf
4654  (*it).trackParameters()->position(),
4655  (*it).trackParameters()->momentum().unit())
4656  .first();
4657 
4658  const bool insideid = (
4659  (cache.m_caloEntrance == nullptr) ||
4660  cache.m_caloEntrance->inside((*it).trackParameters()->position())
4661  );
4662 
4663  if (
4664  (((*it).measurement() != nullptr) && insideid) || (
4665  ((*it).materialEffects() != nullptr) &&
4666  distance > 0 && (
4667  (*it).materialEffects()->deltaE() == 0 ||
4668  ((*it).materialEffects()->sigmaDeltaPhi() == 0 &&
4669  !insideid) ||
4670  (*it).materialEffects()->deltaPhi() != 0
4671  )
4672  )
4673  ) {
4674  const double dist = ((*it).trackParameters()->position() - vertex).perp();
4675  if (dist < mindist) {
4676  mindist = dist;
4677  nearestpar = unique_clone((*it).trackParameters());
4678  mymatvec.clear();
4679  continue;
4680  }
4681  }
4682 
4683  if (((*it).materialEffects() != nullptr) && distance > 0) {
4684  mymatvec.push_back(it.get());
4685  }
4686  }
4687 
4688  if (nearestpar == nullptr) {
4689  nearestpar = unique_clone(&param);
4690  }
4691 
4692  for (auto & state : mymatvec) {
4694  const Surface &matsurf = state->associatedSurface();
4695  const DistanceSolution distsol = matsurf.straightLineDistanceEstimate(
4696  nearestpar->position(), nearestpar->momentum().unit());
4697 
4698  const double distance = getDistance(distsol);
4699 
4700  if (distance < 0 && distsol.numberOfSolutions() > 0) {
4701  propdir = oppositeMomentum;
4702  }
4703 
4704  std::unique_ptr<const TrackParameters> tmppar(m_propagator->propagateParameters(
4705  ctx,
4706  *nearestpar,
4707  matsurf,
4708  propdir,
4709  false,
4710  trajectory.m_fieldprop,
4712  ));
4713 
4714  if (tmppar == nullptr) {
4715  propdir = (propdir == oppositeMomentum) ? alongMomentum : oppositeMomentum;
4716  tmppar = m_propagator->propagateParameters(
4717  ctx,
4718  *nearestpar,
4719  matsurf,
4720  propdir,
4721  false,
4722  trajectory.m_fieldprop,
4724  );
4725 
4726  if (tmppar == nullptr) {
4729 
4730  ATH_MSG_DEBUG("Propagation to perigee failed 2");
4731 
4732  return nullptr;
4733  }
4734  }
4735 
4736  AmgVector(5) newpars = tmppar->parameters();
4737 
4738  if (state->materialEffects()->sigmaDeltaE() > 0) {
4739  newpars[Trk::qOverP] += .001 * state->materialEffects()->delta_p();
4740  } else if (newpars[Trk::qOverP] != 0) {
4741  const double sign = (newpars[Trk::qOverP] > 0) ? 1 : -1;
4742  const double de = std::abs(state->materialEffects()->deltaE());
4743  const double oldp = std::abs(1 / newpars[Trk::qOverP]);
4744  const double newp2 = oldp * oldp - 2 * de * std::sqrt(mass * mass + oldp * oldp) + de * de;
4745  if (newp2 > 0) {
4746  newpars[Trk::qOverP] = sign / std::sqrt(newp2);
4747  }
4748  }
4749 
4750  nearestpar = tmppar->associatedSurface().createUniqueTrackParameters(
4751  newpars[0], newpars[1], newpars[2], newpars[3], newpars[4], std::nullopt
4752  );
4753  }
4754 
4755  std::unique_ptr<Trk::TrackParameters> tmpPars(m_propagator->propagateParameters(
4756  ctx,
4757  *nearestpar,
4758  persurf,
4760  false,
4761  trajectory.m_fieldprop,
4763  ));
4764 
4765  // Parameters are at a Perigee surface so they are perigee parameters
4766  if (tmpPars != nullptr) {
4767  per.reset(static_cast < const Perigee *>(tmpPars.release()));
4768  }
4769 
4770  if ((per != nullptr) && (matEffects == Trk::proton || matEffects == Trk::kaon)) {
4771  const double sign = (per->parameters()[Trk::qOverP] < 0) ? -1. : 1.;
4772  const double oldp = 1. / std::abs(per->parameters()[Trk::qOverP]);
4773  const double toteloss = std::abs(trajectory.totalEnergyLoss());
4774  const double newp = std::sqrt(oldp * oldp + 2 * toteloss * std::sqrt(oldp * oldp + mass * mass) + toteloss * toteloss);
4775  AmgVector(5) params = per->parameters();
4776  params[Trk::qOverP] = sign / newp;
4777 
4778  per = per->associatedSurface().createUniqueTrackParameters(
4779  params[0], params[1], params[2], params[3], params[4], std::nullopt
4780  );
4781  }
4782 
4783  if (per == nullptr) {
4786  ATH_MSG_DEBUG("Propagation to perigee failed 3");
4787 
4788  return nullptr;
4789  }
4790 
4791  PerigeeSurface const persurf2(per->position());
4792  per = persurf2.createUniqueTrackParameters(
4793  0,
4794  0,
4795  per->parameters()[Trk::phi],
4796  per->parameters()[Trk::theta],
4797  per->parameters()[Trk::qOverP],
4798  std::nullopt
4799  );
4800  } else if (per == nullptr) {
4801  per = makePerigee(cache, param, matEffects);
4802  }
4803 
4804  if ((per == nullptr) && (trajectory.referenceParameters() == nullptr)) {
4807  ATH_MSG_DEBUG("Propagation to perigee failed 4");
4808 
4809  return nullptr;
4810  }
4811 
4812  if (trajectory.m_straightline && (per != nullptr)) {
4813  if (trajectory.numberOfPerigeeParameters() == -1) {
4814  trajectory.setNumberOfPerigeeParameters(4);
4815  }
4816 
4817  const AmgVector(5) & pars = per->parameters();
4818  per = per->associatedSurface().createUniqueTrackParameters(
4819  pars[0], pars[1], pars[2], pars[3], 0, std::nullopt
4820  );
4821  } else if (trajectory.numberOfPerigeeParameters() == -1) {
4822  trajectory.setNumberOfPerigeeParameters(5);
4823  }
4824 
4825  if (per != nullptr) {
4826  trajectory.setReferenceParameters(std::move(per));
4827  }
4828 
4829  const int nfitpar = trajectory.numberOfFitParameters();
4830  const int nperpars = trajectory.numberOfPerigeeParameters();
4831  const int nscat = trajectory.numberOfScatterers();
4832  const int nbrem = trajectory.numberOfBrems();
4833 
4834  Eigen::MatrixXd a;
4835  Eigen::MatrixXd a_inv;
4836  a.resize(nfitpar, nfitpar);
4837 
4838  Amg::VectorX b(nfitpar);
4839 
4840  Amg::MatrixX derivPool(5, nfitpar);
4841  derivPool.setZero();
4842 
4843  for (std::unique_ptr<GXFTrackState> & state : trajectory.trackStates()) {
4844  if (state->materialEffects() != nullptr) {
4845  continue;
4846  }
4847  state->setDerivatives(derivPool);
4848  }
4849 
4850  bool doderiv = true;
4851  const int tmpminiter = cache.m_miniter;
4852 
4853  for (int it = 0; it < m_maxit; ++it) {
4854  cache.m_lastiter = it;
4855 
4856  if (it >= m_maxit - 1) {
4857  ATH_MSG_DEBUG("Fit did not converge");
4860  cache.m_miniter = tmpminiter;
4861  return nullptr;
4862  }
4863 
4864  if (!trajectory.converged()) {
4865  cache.m_fittercode =
4866  runIteration(ctx, cache, trajectory, it, a, b, lu, doderiv);
4867  if (cache.m_fittercode != FitterStatusCode::Success) {
4870  } else if (cache.m_fittercode == FitterStatusCode::InvalidAngles) {
4874  }
4875  cache.m_miniter = tmpminiter;
4876  return nullptr;
4877  }
4878 
4879  const int nhits = trajectory.numberOfHits();
4880  const int ntrthits = trajectory.numberOfTRTHits();
4881  const int nsihits = trajectory.numberOfSiliconHits();
4882  const double redchi2 = (trajectory.nDOF() > 0) ? trajectory.chi2() / trajectory.nDOF() : 0;
4883  const double prevredchi2 = (trajectory.nDOF() > 0) ? trajectory.prevchi2() / trajectory.nDOF() : 0;
4884 
4885 
4886  if( nsihits > 0 && it > 0 && it < m_maxitPixelROT )
4887  updatePixelROTs( trajectory, a, b, ctx);
4888 
4889  if (
4890  it > 0 &&
4891  it < 4 && (
4892  (redchi2 < prevredchi2 &&
4893  (redchi2 > prevredchi2 - 1 || redchi2 < 2)) ||
4894  nsihits + ntrthits == nhits
4895  ) &&
4896  (runOutlier || m_trtrecal) &&
4897  ntrthits > 0
4898  ) {
4899  if (it != 1 || nsihits != 0 || trajectory.nDOF() <= 0 || trajectory.chi2() / trajectory.nDOF() <= 3) {
4900  ATH_MSG_DEBUG("Running TRT cleaner");
4901  runTrackCleanerTRT(cache, trajectory, a, b, lu, runOutlier, m_trtrecal, it, ctx);
4902  if (cache.m_fittercode != FitterStatusCode::Success) {
4903  ATH_MSG_DEBUG("TRT cleaner failed, returning null...");
4904  cache.m_miniter = tmpminiter;
4905  return nullptr;
4906  }
4907  }
4908  }
4909 
4910  // PHF cut at iteration 3 (to save CPU time)
4911  const int ntrtprechits = trajectory.numberOfTRTPrecHits();
4912  const int ntrttubehits = trajectory.numberOfTRTTubeHits();
4913  float phf = 1.;
4914  if (ntrtprechits+ntrttubehits) {
4915  phf = float(ntrtprechits)/float(ntrtprechits+ntrttubehits);
4916  }
4917  if (phf<m_minphfcut && it>=3) {
4918  if ((ntrtprechits+ntrttubehits)>=15) {
4919  return nullptr;
4920  }
4921  }
4922  ATH_MSG_DEBUG("Iter = " << it << " | nTRTStates = " << ntrthits
4923  << " | nTRTPrecHits = " << ntrtprechits
4924  << " | nTRTTubeHits = " << ntrttubehits
4925  << " | nOutliers = "
4926  << trajectory.numberOfOutliers());
4927 
4928  if (!trajectory.converged()) {
4929  cache.m_fittercode = updateFitParameters(trajectory, b, lu);
4930  if (cache.m_fittercode != FitterStatusCode::Success) {
4933  }
4934  cache.m_miniter = tmpminiter;
4935  return nullptr;
4936  }
4937  }
4938  } else {
4939  break;
4940  }
4941  }
4942 
4943  cache.m_miniter = tmpminiter;
4944 
4945  if (trajectory.prefit() == 0) {
4946  // Solve assuming the matrix is SPD.
4947  // Cholesky Decomposition is used -- could use LDLT
4948 
4949  Eigen::LLT < Eigen::MatrixXd > const lltOfW(a);
4950  if (lltOfW.info() == Eigen::Success) {
4951  // Solve for x where Wx = I
4952  // this is cheaper than invert as invert makes no assumptions about the
4953  // matrix being symmetric
4954  const int ncols = a.cols();
4955  Amg::MatrixX const weightInvAMG = Amg::MatrixX::Identity(ncols, ncols);
4956  a_inv = lltOfW.solve(weightInvAMG);
4957  } else {
4958  ATH_MSG_DEBUG("matrix inversion failed!");
4961  return nullptr;
4962  }
4963  }
4964 
4965  GXFTrajectory *finaltrajectory = &trajectory;
4966  if (
4967  (runOutlier || cache.m_sirecal) &&
4968  trajectory.numberOfSiliconHits() == trajectory.numberOfHits()
4969  ) {
4970  calculateTrackErrors(trajectory, a_inv, true);
4971  GXFTrajectory* traj = runTrackCleanerSilicon(ctx,cache, trajectory, a, a_inv, b, runOutlier);
4972 
4973  if (cache.m_fittercode != FitterStatusCode::Success) {
4974  ATH_MSG_DEBUG("Silicon cleaner failed, returning null...");
4975  if (traj != &trajectory) {
4976  delete traj;
4977  }
4978  return nullptr;
4979  }
4980  finaltrajectory = traj;
4981  }
4982 
4983  if (m_domeastrackpar && (finaltrajectory->prefit() == 0)) {
4984  calculateTrackErrors(*finaltrajectory, a_inv, false);
4985  }
4986 
4987  if (!cache.m_acceleration && (finaltrajectory->prefit() == 0)) {
4988  if (nperpars == 5) {
4989  for (int i = 0; i < a.cols(); i++) {
4990  a_inv(4, i) *= .001;
4991  a_inv(i, 4) *= .001;
4992  }
4993  }
4994 
4995  int scatterPos = nperpars + 2 * nscat;
4996  for (int bremno = 0; bremno < nbrem; bremno++, scatterPos++) {
4997  for (int i = 0; i < a.cols(); i++) {
4998  a_inv(scatterPos, i) *= .001;
4999  a_inv(i, scatterPos) *= .001;
5000  }
5001  }
5002 
5003  AmgSymMatrix(5) errmat;
5004  errmat.setZero();
5005  const int nperparams = finaltrajectory->numberOfPerigeeParameters();
5006  for (int i = 0; i < nperparams; i++) {
5007  for (int j = 0; j < nperparams; j++) {
5008  (errmat) (j, i) = a_inv(j, i);
5009  }
5010  }
5011 
5012  if (trajectory.m_straightline) {
5013  (errmat) (4, 4) = 1e-20;
5014  }
5015 
5016  const AmgVector(5) & perpars = finaltrajectory->referenceParameters()->parameters();
5017  std::unique_ptr<const TrackParameters> measper(
5019  perpars[0], perpars[1], perpars[2], perpars[3], perpars[4], std::move(errmat)
5020  )
5021  );
5022 
5023  finaltrajectory->setReferenceParameters(std::move(measper));
5024  if (m_fillderivmatrix) {
5025  cache.m_fullcovmat = a_inv;
5026  }
5027  }
5028 
5029  std::unique_ptr<Track> track = nullptr;
5030 
5031  if (finaltrajectory->prefit() > 0) {
5032  if (finaltrajectory != &trajectory) {
5033  // cppcheck-suppress autovarInvalidDeallocation; false positive
5034  delete finaltrajectory;
5035  }
5036  return nullptr;
5037  }
5038 
5039  if (finaltrajectory->numberOfOutliers() <= m_maxoutliers || !runOutlier) {
5040  track = makeTrack(ctx,cache, *finaltrajectory, matEffects);
5041  } else {
5044  }
5045 
5046  const double cut = (finaltrajectory->numberOfSiliconHits() ==
5047  finaltrajectory->numberOfHits())
5048  ? 999.0
5049  : m_chi2cut.value();
5050 
5051  if (
5052  runOutlier &&
5053  (track != nullptr) && (
5054  track->fitQuality()->numberDoF() != 0 &&
5055  track->fitQuality()->chiSquared() / track->fitQuality()->numberDoF() > cut
5056  )
5057  ) {
5058  track.reset(nullptr);
5060  }
5061 
5062  if (track == nullptr) {
5063  ATH_MSG_DEBUG("Track rejected");
5064  }
5065 
5066  if (finaltrajectory != &trajectory) {
5067  delete finaltrajectory;
5068  }
5069 
5070  return track.release();
5071  }
5072 
5074  const EventContext& ctx,
5075  const Cache & cache,
5076  GXFTrajectory & trajectory,
5077  const int it,
5078  Amg::VectorX & b,
5079  int & bremno_maxbrempull,
5080  GXFTrackState* & state_maxbrempull
5081  ) const {
5082  ATH_MSG_DEBUG("fillResidualsAndErrors");
5083 
5084  std::vector<std::unique_ptr<GXFTrackState>> & states = trajectory.trackStates();
5085 
5086  /*
5087  * The residual and error vectors, we want to fill in this function.
5088  */
5089  Amg::VectorX & res = trajectory.residuals();
5090  Amg::VectorX & error = trajectory.errors();
5091 
5092  /*
5093  * These variables are used inside the preprocessing loop for counting and
5094  * managing some quantities.
5095  */
5096  int scatno = 0;
5097  int bremno = 0;
5098  int measno = 0;
5099 
5100  /*
5101  * Total number of measurements, and brems and perigee parameters. This is
5102  * used later to fill the residual and error vector to find the offsets.
5103  */
5104  const int nmeas = (int) res.size();
5105  const int nbrem = trajectory.numberOfBrems();
5106  const int nperpars = trajectory.numberOfPerigeeParameters();
5107 
5108  /*
5109  * Under certain circumstances, we create new pseudo measurements. Here are
5110  * the static conditions. Later, we have also for each state a more
5111  * confining check.
5112  */
5113  const int nidhits = trajectory.numberOfSiliconHits() + trajectory.numberOfTRTHits();
5114  const int nDOF = trajectory.nDOF();
5115  const bool doNewPseudoMeasurements = (
5116  1 < it &&
5117  it <= 100 &&
5118  nDOF != 0 &&
5119  std::abs((trajectory.prevchi2() - trajectory.chi2()) / nDOF) < 15 &&
5120  nidhits < trajectory.numberOfHits() &&
5121  (nperpars == 0 || nidhits > 0)
5122  );
5123 
5124  /*
5125  * Temporary quantities.
5126  * - chi2 will be used later to set the new chi2.
5127  * - maxbrempull collects the elosspull for the kink with the largest
5128  * brems. It is initised to -0.2 to consider only definitely negative
5129  * pulls.
5130  */
5131  double chi2 = 0;
5132  double maxbrempull = -0.2;
5133 
5134  /*
5135  * Loop over all hits and do some preprocessing. In this step, we do:
5136  * - Get residuals
5137  * - Get errors
5138  * - Get scattering angles
5139  * - Fill b-vector and chi2 with scattering effects (others fill later)
5140  */
5141  for (int hitno = 0; hitno < (int) states.size(); hitno++) {
5142  std::unique_ptr<GXFTrackState> & state = states[hitno];
5143  const TrackParameters *currenttrackpar = state->trackParameters();
5144  TrackState::MeasurementType const hittype = state->measurementType();
5145  const MeasurementBase *measbase = state->measurement();
5146 
5147  /*
5148  * Measurements and outliers.
5149  */
5150  if (state->getStateType(TrackStateOnSurface::Measurement)) {
5151  /*
5152  * Create new pseudo measurements when the static check (evaluated
5153  * outside the loop) and the dynamic checks both pass
5154  */
5155  if (
5156  doNewPseudoMeasurements &&
5157  hittype == TrackState::Pseudo &&
5158  !state->associatedSurface().isFree() &&
5159  !state->isRecalibrated()
5160  ) {
5161  Amg::MatrixX covMatrix(1, 1);
5162  covMatrix(0, 0) = 100;
5163 
5164  std::unique_ptr<const PseudoMeasurementOnTrack> newpseudo = std::make_unique<const PseudoMeasurementOnTrack>(
5165  LocalParameters(DefinedParameter(currenttrackpar->parameters()[Trk::locY], Trk::locY)),
5166  std::move(covMatrix),
5167  currenttrackpar->associatedSurface()
5168  );
5169 
5170  state->setMeasurement(std::move(newpseudo));
5171  measbase = state->measurement();
5172  }
5173 
5174  /*
5175  * Separate all parameters in the residuals and errors. We will handle
5176  * them separately, asuming them uncorrelated.
5177  */
5178  double *errors = state->measurementErrors();
5179  std::array<double,5> residuals = m_residualPullCalculator->residuals(measbase, currenttrackpar, ResidualPull::Biased, hittype);
5180  for (int i = 0; i < 5; i++) {
5181  /*
5182  * Skip the parameter, if there is no accessor for it.
5183  */
5185  continue;
5186  }
5187 
5188  /*
5189  * SCT and TGC are 1-dimensional, so we can skip the other parameters.
5190  */
5191  if (i > 0 && (hittype == TrackState::SCT || hittype == TrackState::TGC)) {
5192  continue;
5193  }
5194 
5195  error[measno] =
5196  (trajectory.prefit() > 0 && (hittype == TrackState::MDT || (hittype == TrackState::CSC && !state->measuresPhi()))) ?
5197  2 :
5198  errors[i];
5199 
5200  res[measno] = residuals[i];
5201 
5202  /*
5203  * Ensure, that the phi-residual is mapped into the correct period.
5204  */
5205  if (i == 2) {
5206  res[measno] = -std::remainder(-res[measno], 2 * M_PI);
5207  }
5208 
5209  measno++;
5210  }
5211  } else if (state->getStateType(TrackStateOnSurface::Outlier)) {
5212  /*
5213  * NOTE: It seems the residuals are not set in this step. Why?
5214  */
5215  double *errors = state->measurementErrors();
5216  for (int i = 0; i < 5; i++) {
5217  if (errors[i] > 0) {
5218  error[measno] = errors[i];
5219  measno++;
5220  }
5221  }
5222  }
5223 
5224  /*
5225  * Scattering angles contribute to the b-vector and the chi2.
5226  */
5227  if (
5228  state->getStateType(TrackStateOnSurface::Scatterer) &&
5229  ((trajectory.prefit() == 0) || state->materialEffects()->deltaE() == 0)
5230  ) {
5231  const double deltaPhi = state->materialEffects()->deltaPhi();
5232  const double measDeltaPhi = state->materialEffects()->measuredDeltaPhi();
5233  const double sigma2deltaPhi = std::pow(state->materialEffects()->sigmaDeltaPhi(), 2);
5234  const double deltaTheta = state->materialEffects()->deltaTheta();
5235  const double sigma2deltaTheta = std::pow(state->materialEffects()->sigmaDeltaTheta(), 2);
5236 
5237  if (trajectory.prefit() != 1) {
5238  b[nperpars + 2 * scatno] -= (deltaPhi - measDeltaPhi) / sigma2deltaPhi;
5239  b[nperpars + 2 * scatno + 1] -= deltaTheta / sigma2deltaTheta;
5240  } else {
5241  b[nperpars + scatno] -= deltaTheta / sigma2deltaTheta;
5242  }
5243 
5244  chi2 += (
5245  deltaPhi * deltaPhi / sigma2deltaPhi +
5246  deltaTheta * deltaTheta / sigma2deltaTheta
5247  );
5248 
5249  scatno++;
5250  }
5251 
5252  /*
5253  * Energy loss will be considered in the form of a kink.
5254  */
5255  if ((state->materialEffects() != nullptr) && state->materialEffects()->sigmaDeltaE() > 0) {
5256  double averagenergyloss = std::abs(state->materialEffects()->deltaE());
5257  const double qoverpbrem = limitInversePValue(1000 * states[hitno]->trackParameters()->parameters()[Trk::qOverP]);
5258  const double qoverp = limitInversePValue(qoverpbrem - state->materialEffects()->delta_p());
5259  const double pbrem = 1. / std::abs(qoverpbrem);
5260  const double p = 1. / std::abs(qoverp);
5261  const double mass = .001 * trajectory.mass();
5262  const double energy = std::sqrt(p * p + mass * mass);
5263  const double bremEnergy = std::sqrt(pbrem * pbrem + mass * mass);
5264 
5265  const double resMaterial = .001 * averagenergyloss - energy + bremEnergy;
5266  res[nmeas - nbrem + bremno] = resMaterial;
5267 
5268  const double sigde = state->materialEffects()->sigmaDeltaE();
5269  const double sigdepos = state->materialEffects()->sigmaDeltaEPos();
5270  const double sigdeneg = state->materialEffects()->sigmaDeltaENeg();
5271 
5272  double errorMaterial = .001 * state->materialEffects()->sigmaDeltaE();
5273  error[nmeas - nbrem + bremno] = errorMaterial;
5274 
5275  /*
5276  * There is already a kink in the trajectory. No need to look for more.
5277  * - Set the maxbrempull to a small value, so no future candidate can
5278  * be found.
5279  * - Reset the pointer to the state, in case we have set one before.
5280  *
5281  * NOTE: I think, the new value of maxbrempull should be -inf since it
5282  * allows for some edge case pulls. Not sure if bug or feature.
5283  */
5284  if (state->materialEffects()->isKink()) {
5285  maxbrempull = -999999999;
5286  state_maxbrempull = nullptr;
5287  }
5288 
5289  if (
5290  cache.m_asymeloss &&
5291  it > 0 &&
5292  trajectory.prefit() == 0 &&
5293  sigde > 0 &&
5294  sigde != sigdepos &&
5295  sigde != sigdeneg
5296  ) {
5297  const double elosspull = resMaterial / errorMaterial;
5298 
5299  if (trajectory.mass() > 100) {
5300  /*
5301  * If the absolute energy loss pull is too large, update the
5302  * sigmaDeltaE of the state and also update the error/
5303  */
5304  if (std::abs(elosspull) > 1) {
5305  if (elosspull < -1) {
5306  state->materialEffects()->setSigmaDeltaE(sigdepos);
5307  } else {
5308  state->materialEffects()->setSigmaDeltaE(sigdeneg);
5309  }
5310 
5311  errorMaterial = .001 * state->materialEffects()->sigmaDeltaE();
5312  error[nmeas - nbrem + bremno] = errorMaterial;
5313  }
5314  } else if ((trajectory.numberOfTRTHits() == 0) || it >= 3) {
5315  /*
5316  * In case the state is not yet marked as a kink, we might want to
5317  * do so later. For this, we propose a maxbrempull state if either
5318  * - we did not provide an external kink with Gaudi and we want a
5319  * definitely negative elosspull.
5320  * or
5321  * - an external kink is given with Gaudi and we are on it now.
5322  */
5323  if (
5324  !state->materialEffects()->isKink() && (
5325  (m_fixbrem == -1 && elosspull < maxbrempull) ||
5326  (m_fixbrem >= 0 && bremno == m_fixbrem)
5327  )
5328  ) {
5329  bremno_maxbrempull = bremno;
5330  state_maxbrempull = state.get();
5331  maxbrempull = elosspull;
5332  }
5333  }
5334  }
5335 
5336  if (
5337  it > 0 &&
5338  hitno >= 2 &&
5339  !m_calotoolparam.empty() &&
5340  trajectory.prefit() == 0 &&
5341  state->materialEffects()->sigmaDeltaPhi() == 0 &&
5342  state->materialEffects()->isMeasuredEloss() &&
5343  resMaterial / (.001 * state->materialEffects()->sigmaDeltaEAve()) > 2.5
5344  ) {
5345  const TrackParameters* parforcalo = states[hitno - 2]->trackParameters();
5346  const IPropagator* prop = &*m_propagator;
5347 
5348  std::vector<MaterialEffectsOnTrack> calomeots =
5349  m_calotoolparam->extrapolationSurfacesAndEffects(
5350  *m_navigator->highestVolume(ctx),
5351  *prop,
5352  *parforcalo,
5353  parforcalo->associatedSurface(),
5355  Trk::muon);
5356 
5357  /*
5358  * Update energyLoss, sigma, residual, and error if the parametrised
5359  * energy loss results in a absolute smaller pull.
5360  */
5361  if (calomeots.size() == 3) {
5362  averagenergyloss = std::abs(calomeots[1].energyLoss()->deltaE());
5363  const double newres = .001 * averagenergyloss - energy + bremEnergy;
5364  const double newerr = .001 * calomeots[1].energyLoss()->sigmaDeltaE();
5365 
5366  const double oldPull = resMaterial / errorMaterial;
5367  const double newPull = newres / newerr;
5368 
5369  if (std::abs(newPull) < std::abs(oldPull)) {
5370  ATH_MSG_DEBUG("Changing from measured to parametrized energy loss");
5371 
5372  state->materialEffects()->setEloss(std::unique_ptr<EnergyLoss>(calomeots[1].energyLoss()->clone()));
5373  state->materialEffects()->setSigmaDeltaE(calomeots[1].energyLoss()->sigmaDeltaE());
5374  res[nmeas - nbrem + bremno] = newres;
5375  error[nmeas - nbrem + bremno] = newerr;
5376  }
5377  }
5378 
5379  state->materialEffects()->setMeasuredEloss(false);
5380  }
5381 
5382  bremno++;
5383  }
5384  }
5385 
5386  /*
5387  * Sum up the chi2 contributions from all measurements.
5388  */
5389  for (int imeas = 0; imeas < nmeas; imeas++) {
5390  if (error[imeas] == 0) {
5391  continue;
5392  }
5393 
5394  chi2 += std::pow(res[imeas] / error[imeas], 2);
5395  }
5396 
5397  /*
5398  * Update trajectory with previous and current chi2
5399  */
5400  trajectory.setPrevChi2(trajectory.chi2());
5401  trajectory.setChi2(chi2);
5402  }
5403 
5405  const Cache & cache,
5406  GXFTrajectory & trajectory,
5407  const int it
5408  ) const {
5409  ATH_MSG_DEBUG("tryToConverge");
5410 
5411  const double oldChi2 = trajectory.prevchi2();
5412  const double newChi2 = trajectory.chi2();
5413 
5414  /*
5415  * First convergence check
5416  */
5417  const double nDOF = trajectory.nDOF();
5418  const double oldRedChi2 = (nDOF > 0) ? oldChi2 / nDOF : 0;
5419  const double newRedChi2 = (nDOF > 0) ? newChi2 / nDOF : 0;
5420 
5421  if (
5422  trajectory.prefit() > 0 && (
5423  (newRedChi2 < 2 && it != 0) ||
5424  (newRedChi2 < oldRedChi2 + .1 && std::abs(newRedChi2 - oldRedChi2) < 1 && it != 1)
5425  )
5426  ) {
5427  trajectory.setConverged(true);
5428  }
5429 
5430  /*
5431  * Second convergence check
5432  */
5433  const int nsihits = trajectory.numberOfSiliconHits();
5434  const int ntrthits = trajectory.numberOfTRTHits();
5435  const int nhits = trajectory.numberOfHits();
5436 
5437  int miniter = (nsihits != 0 && nsihits + ntrthits == nhits) ? 1 : 2;
5438  miniter = std::max(miniter, cache.m_miniter);
5439 
5440  if (it >= miniter && std::abs(oldChi2 - newChi2) < 1) {
5441  trajectory.setConverged(true);
5442  }
5443  }
5444 
5446  GXFTrajectory & trajectory,
5447  const int bremno_maxbrempull,
5448  GXFTrackState* state_maxbrempull,
5449  Amg::SymMatrixX & a
5450  ) const {
5451  ATH_MSG_DEBUG("updateSystemWithMaxBremPull");
5452 
5453  if (state_maxbrempull == nullptr) {
5454  return;
5455  }
5456 
5457  state_maxbrempull->materialEffects()->setSigmaDeltaE(
5458  10 * state_maxbrempull->materialEffects()->sigmaDeltaEPos()
5459  );
5460 
5461  state_maxbrempull->materialEffects()->setKink(true);
5462 
5463  const int nbrem = trajectory.numberOfBrems();
5464  const Amg::VectorX & res = trajectory.residuals();
5465  const int nmeas = (int) res.size();
5466 
5467  Amg::VectorX & error = trajectory.errors();
5468  const double oldError = error[nmeas - nbrem + bremno_maxbrempull];
5469  const double newError = .001 * state_maxbrempull->materialEffects()->sigmaDeltaE();
5470  error[nmeas - nbrem + bremno_maxbrempull] = newError;
5471 
5472  const int nFitPars = trajectory.numberOfFitParameters();
5473  if (a.cols() != nFitPars) {
5474  ATH_MSG_ERROR("Your assumption is wrong!!!!");
5475  }
5476 
5477  const double errorRatio = oldError / newError;
5478  const double errorReductionRatio = 1 - std::pow(errorRatio, 2);
5479 
5480  Amg::MatrixX & weightderiv = trajectory.weightedResidualDerivatives();
5481  for (int i = 0; i < nFitPars; i++) {
5482  if (weightderiv(nmeas - nbrem + bremno_maxbrempull, i) == 0) {
5483  continue;
5484  }
5485 
5486  for (int j = i; j < nFitPars; j++) {
5487  const double newaij = a(i, j) - errorReductionRatio *
5488  weightderiv(nmeas - nbrem + bremno_maxbrempull, i) *
5489  weightderiv(nmeas - nbrem + bremno_maxbrempull, j);
5490 
5491  a.fillSymmetric(i, j, newaij);
5492  }
5493  weightderiv(nmeas - nbrem + bremno_maxbrempull, i) *= errorRatio;
5494  }
5495  }
5496 
5498  GXFTrajectory & trajectory
5499  ) const {
5500  ATH_MSG_DEBUG("fillDerivatives");
5501 
5502  std::vector<std::unique_ptr<GXFTrackState>> & states = trajectory.trackStates();
5503  int scatno = 0;
5504  int bremno = 0;
5505  int measno = 0;
5506  const int nscatupstream = trajectory.numberOfUpstreamScatterers();
5507  const int nbremupstream = trajectory.numberOfUpstreamBrems();
5508  const int nscat = trajectory.numberOfScatterers();
5509  const int nbrem = trajectory.numberOfBrems();
5510  const int nperparams = trajectory.numberOfPerigeeParameters();
5511 
5512  Amg::MatrixX & weightderiv = trajectory.weightedResidualDerivatives();
5513  Amg::VectorX & error = trajectory.errors();
5514 
5515  const int nmeas = (int) weightderiv.rows();
5516 
5517  for (std::unique_ptr<GXFTrackState> & state : states) {
5518  if (state->getStateType(TrackStateOnSurface::Measurement)) {
5519  TrackState::MeasurementType const hittype = state->measurementType();
5520  const MeasurementBase *measbase = state->measurement();
5521  const auto [scatmin, scatmax] = std::minmax(scatno, nscatupstream);
5522  const auto [bremmin, bremmax] = std::minmax(bremno, nbremupstream);
5523 
5524  Amg::MatrixX & derivatives = state->derivatives();
5525 
5526  /*
5527  * Get the stereo angles for SCT and TGC.
5528  */
5529  const double sinStereo =
5530  hittype == TrackState::SCT || hittype == TrackState::TGC ?
5531  state->sinStereo() :
5532  0;
5533  const double cosStereo =
5534  sinStereo != 0 ?
5535  std::sqrt(1 - std::pow(sinStereo, 2)) :
5536  1.;
5537 
5538  /*
5539  * For SCT and TGC we need modified derivatives, taking into account
5540  * the orientation.This lambda chooses the correct accessor and rotates
5541  * the derivative accordingly.
5542  */
5543  auto getThisDeriv = [sinStereo, cosStereo, &derivatives](int i, int j) -> double {
5544  if (i == 0 && sinStereo != 0) {
5545  return derivatives(0, j) * cosStereo + sinStereo * derivatives(1, j);
5546  } else {
5547  return derivatives(i, j);
5548  }
5549  };
5550 
5551  for (int i = 0; i < 5; i++) {
5553  continue;
5554  }
5555 
5556  /*
5557  * SCT and TGC have all information stored in the first parameter.
5558  */
5559  if ((hittype == TrackState::SCT || hittype == TrackState::TGC) && i > 0) {
5560  break;
5561  }
5562 
5563  if (trajectory.numberOfPerigeeParameters() > 0) {
5564  const int cols = trajectory.m_straightline ? 4 : 5;
5565 
5566  if (i == 0 && sinStereo != 0) {
5567  weightderiv.row(measno).head(cols) =
5568  (derivatives.row(0).head(cols) * cosStereo +
5569  sinStereo * derivatives.row(1).head(cols)) /
5570  error[measno];
5571  } else {
5572  weightderiv.row(measno).head(cols) = derivatives.row(i).head(cols) / error[measno];
5573  }
5574  }
5575 
5576  for (int j = scatmin; j < scatmax; j++) {
5577  if (trajectory.prefit() == 1) {
5578  const int index = nperparams + j;
5579  weightderiv(measno, index) = getThisDeriv(i, index) / error[measno];
5580  } else {
5581  const int index = nperparams + 2 * j;
5582  weightderiv(measno, index) = getThisDeriv(i, index) / error[measno];
5583  weightderiv(measno, index + 1) = getThisDeriv(i, index + 1) / error[measno];
5584  }
5585  }
5586 
5587  for (int j = bremmin; j < bremmax; j++) {
5588  const int index = j + nperparams + 2 * nscat;
5589  weightderiv(measno, index) = getThisDeriv(i, index) / error[measno];
5590  }
5591 
5592  measno++;
5593  }
5594  } else if (state->getStateType(TrackStateOnSurface::Outlier)) {
5595  double *errors = state->measurementErrors();
5596  for (int i = 0; i < 5; i++) {
5597  if (errors[i] > 0) {
5598  measno++;
5599  }
5600  }
5601  } else if (
5602  state->getStateType(TrackStateOnSurface::Scatterer) &&
5603  ((trajectory.prefit() == 0) || state->materialEffects()->deltaE() == 0)
5604  ) {
5605  scatno++;
5606  }
5607 
5608  if ((state->materialEffects() != nullptr) && state->materialEffects()->sigmaDeltaE() > 0) {
5609  //limit values to avoid FPE overflow or div by zero
5610  const double qoverpbrem = limitInversePValue(1000 * state->trackParameters()->parameters()[Trk::qOverP]);
5611  const double qoverp = limitInversePValue(qoverpbrem - state->materialEffects()->delta_p());
5612 
5613  const double mass = .001 * trajectory.mass();
5614 
5615  const auto thisMeasurementIdx{nmeas - nbrem + bremno};
5616  //references (courtesy of Christos Anastopoulos):
5617  //https://inspirehep.net/files/a810ad0047a22af32fbff587c6c98ce5
5618  //https://its.cern.ch/jira/browse/ATLASRECTS-6213
5619  auto multiplier = [] (double mass, double qOverP){
5620  return std::copysign(1./(qOverP * qOverP * std::sqrt(1. + mass * mass * qOverP * qOverP)), qOverP);
5621  };
5622  const auto qoverpTerm {multiplier(mass, qoverp) / error[thisMeasurementIdx]};
5623  const auto qoverpBremTerm {multiplier(mass, qoverpbrem) / error[thisMeasurementIdx]};
5624 
5625  if (trajectory.numberOfPerigeeParameters() > 0) {
5626  weightderiv(thisMeasurementIdx, 4) = qoverpBremTerm - qoverpTerm;
5627  }
5628  //
5629  const auto bremNoBase = nperparams + 2 * nscat;
5630  if (bremno < nbremupstream) {
5631  weightderiv(thisMeasurementIdx, bremNoBase + bremno) = qoverpTerm;
5632  for (int bremno2 = bremno + 1; bremno2 < nbremupstream; bremno2++) {
5633  weightderiv(thisMeasurementIdx, bremNoBase + bremno2) = qoverpTerm - qoverpBremTerm;
5634  }
5635  } else {
5636  weightderiv(thisMeasurementIdx, bremNoBase + bremno) = qoverpBremTerm;
5637  for (int bremno2 = nbremupstream; bremno2 < bremno; bremno2++) {
5638  weightderiv(thisMeasurementIdx, bremNoBase + bremno2) = qoverpBremTerm - qoverpTerm;
5639  }
5640  }
5641  bremno++;
5642  }
5643  }
5644  }
5645 
5647  Cache & cache,
5648  GXFTrajectory & trajectory
5649  ) {
5650  const int nFitPars = trajectory.numberOfFitParameters();
5651  const int nPerPars = trajectory.numberOfPerigeeParameters();
5652  const int nScatPars = 2 * trajectory.numberOfScatterers();
5653  const int nBrem = trajectory.numberOfBrems();
5654  const int nUpstreamStates = trajectory.numberOfUpstreamStates();
5655 
5656  const Amg::VectorX & res = trajectory.residuals();
5657  const int nMeas = (int) res.size();
5658 
5659  cache.m_firstmeasurement.resize(nFitPars);
5660  cache.m_lastmeasurement.resize(nFitPars);
5661 
5662  for (int i = 0; i < nPerPars; i++) {
5663  cache.m_firstmeasurement[i] = 0;
5664  cache.m_lastmeasurement[i] = nMeas - nBrem;
5665  }
5666 
5667  int measno = 0;
5668  int scatno = 0;
5669  int bremno = 0;
5670  for (int i = 0; i < (int) trajectory.trackStates().size(); i++) {
5671  const std::unique_ptr<GXFTrackState> & state = trajectory.trackStates()[i];
5672  const GXFMaterialEffects *meff = state->materialEffects();
5673 
5674  if (meff == nullptr) {
5675  measno += state->numberOfMeasuredParameters();
5676  continue;
5677  }
5678 
5679  const int firstMeasurement = i < nUpstreamStates ? 0 : measno;
5680  const int lastMeasurement = i < nUpstreamStates ? measno : nMeas - nBrem;
5681 
5682  if (meff->sigmaDeltaTheta() != 0
5683  && (trajectory.prefit() == 0 || meff->deltaE() == 0)) {
5684  const int scatterPos = nPerPars + 2 * scatno;
5685 
5686  cache.m_firstmeasurement[scatterPos] = firstMeasurement;
5687  cache.m_lastmeasurement[scatterPos] = lastMeasurement;
5688 
5689  cache.m_firstmeasurement[scatterPos + 1] = firstMeasurement;
5690  cache.m_lastmeasurement[scatterPos + 1] = lastMeasurement;
5691 
5692  scatno++;
5693  }
5694 
5695  if (meff->sigmaDeltaE() > 0) {
5696  const int bremPos = nPerPars + nScatPars + bremno;
5697 
5698  cache.m_firstmeasurement[bremPos] = firstMeasurement;
5699  cache.m_lastmeasurement[bremPos] = lastMeasurement;
5700 
5701  bremno++;
5702  }
5703  }
5704  }
5705 
5707  const Cache & cache,
5708  GXFTrajectory & trajectory,
5709  Amg::VectorX & b
5710  ) {
5711  const int nFitPars = trajectory.numberOfFitParameters();
5712  const int nPerPars = trajectory.numberOfPerigeeParameters();
5713  const int nScatPars = 2 * trajectory.numberOfScatterers();
5714  const int nBrem = trajectory.numberOfBrems();
5715  const Amg::MatrixX & weightDeriv = trajectory.weightedResidualDerivatives();
5716 
5717  const Amg::VectorX & res = trajectory.residuals();
5718  const Amg::VectorX & error = trajectory.errors();
5719 
5720  const int nMeas = (int) res.size();
5721 
5722  for (int k = 0; k < nFitPars; k++) {
5723  const int minMeasK = cache.m_firstmeasurement[k];
5724  const int maxMeasK = cache.m_lastmeasurement[k];
5725 
5726  /*
5727  * NOTE: It is necessary to do r * invError * weight instead of doing
5728  * r / error * w. Otherwise, the implementation tests fail do to
5729  * numerical reasons.
5730  */
5731  for (int measno = minMeasK; measno < maxMeasK; measno++) {
5732  b[k] += res[measno] * (1. / error[measno]) * weightDeriv(measno, k);
5733  }
5734 
5735  /*
5736  * For qOverP and brems, we also have a contribution to brems elements.
5737  *
5738  * NOTE: It is necessary to do r * invError * weight instead of doing
5739  * r / error * w. Otherwise, the implementation tests fail do to
5740  * numerical reasons.
5741  */
5742  if (k == 4 || k >= nPerPars + nScatPars) {
5743  for (int measno = nMeas - nBrem; measno < nMeas; measno++) {
5744  b[k] += res[measno] * (1. / error[measno]) * weightDeriv(measno, k);
5745  }
5746  }
5747  }
5748  }
5749 
5751  const Cache & cache,
5752  GXFTrajectory & trajectory,
5753  Amg::SymMatrixX & a
5754  ) {
5755  const int nFitPars = trajectory.numberOfFitParameters();
5756  const Amg::MatrixX & weightDeriv = trajectory.weightedResidualDerivatives();
5757 
5758  for (int k = 0; k < nFitPars; k++) {
5759  for (int l = k; l < nFitPars; l++) {
5760  const int minMeas = std::max(cache.m_firstmeasurement[k], cache.m_firstmeasurement[l]);
5761  const int maxMeas = std::min(cache.m_lastmeasurement[k], cache.m_lastmeasurement[l]);
5762 
5763  double a_kl = 0;
5764  for (int measno = minMeas; measno < maxMeas; measno++) {
5765  a_kl += weightDeriv(measno, k) * weightDeriv(measno, l);
5766  }
5767 
5768  a.fillSymmetric(l, k, a_kl);
5769  }
5770  }
5771  }
5772 
5774  GXFTrajectory & trajectory,
5775  Amg::SymMatrixX & a
5776  ) {
5777  const int nFitPars = trajectory.numberOfFitParameters();
5778  const int nPerPars = trajectory.numberOfPerigeeParameters();
5779  const int nScatPars = 2 * trajectory.numberOfScatterers();
5780  const int nBrem = trajectory.numberOfBrems();
5781  const Amg::MatrixX & weightDeriv = trajectory.weightedResidualDerivatives();
5782 
5783  const Amg::VectorX & res = trajectory.residuals();
5784  const auto & scatSigmas = trajectory.scatteringSigmas();
5785 
5786  const int nMeas = (int) res.size();
5787 
5788  int scatno = 0;
5789 
5790  /*
5791  * Direct contribution on the diagonal from the scatterer itself.
5792  */
5793  for (int k = nPerPars; k < nPerPars + nScatPars; k += 2) {
5794  a(k, k) += 1. / std::pow(scatSigmas[scatno].first, 2);
5795  a(k + 1, k + 1) += 1. / std::pow(scatSigmas[scatno].second, 2);
5796 
5797  scatno++;
5798  }
5799 
5800  /*
5801  * Indirect contribution on the qOverP and brems derivatives.
5802  */
5803  for (int measno = nMeas - nBrem; measno < nMeas; measno++) {
5804  for (int k = 4; k < nFitPars; k++) {
5805  if (k == 5) {
5806  k = nPerPars + nScatPars;
5807  }
5808 
5809  for (int l = k; l < nFitPars; l++) {
5810  if (l == 5) {
5811  l = nPerPars + nScatPars;
5812  }
5813 
5814  const double a_kl = a(l, k) + weightDeriv(measno, k) * weightDeriv(measno, l);
5815  a.fillSymmetric(l, k, a_kl);
5816  }
5817  }
5818  }
5819  }
5820 
5822  Cache & cache,
5823  GXFTrajectory & trajectory,
5824  Amg::SymMatrixX & a,
5825  const bool doDeriv,
5826  const int it,
5827  const double oldRedChi2,
5828  const double newRedChi2
5829  ) {
5830  const int nPerPars = trajectory.numberOfPerigeeParameters();
5831 
5832  /*
5833  * The return value collects, if any weights changed while looping over all
5834  * material states.
5835  */
5836  bool weightChanged = false;
5837 
5838  /*
5839  * The weights for the diagonal material components in the [a]-matrix
5840  * depend on how far we are in the iteration process (iteration number or
5841  * chi2 convergence).
5842  */
5843  double newPhiWeight = 1.1;
5844  double newThetaWeight = 1.001;
5845  if (trajectory.prefit() == 0) {
5846  /*
5847  * We do not consider theta at all in the prefit 0 case. Therefore, we do
5848  * not need to adjust the theta weights.
5849  */
5850  if (it == 0) {
5851  newPhiWeight = 1.00000001;
5852  } else if (it == 1) {
5853  newPhiWeight = 1.0000001;
5854  } else if (it <= 3) {
5855  newPhiWeight = 1.0001;
5856  } else if (it <= 6) {
5857  newPhiWeight = 1.01;
5858  }
5859  } else {
5860  if (newRedChi2 > oldRedChi2 - 1 && newRedChi2 < oldRedChi2) {
5861  newPhiWeight = 1.0001;
5862  newThetaWeight = 1.0001;
5863  } else if (newRedChi2 > oldRedChi2 - 25 && newRedChi2 < oldRedChi2) {
5864  newPhiWeight = 1.001;
5865  newThetaWeight = 1.0001;
5866  }
5867  }
5868 
5869  /*
5870  * Counter for the scattering states. We cannot directly loop over them.
5871  */
5872  std::size_t scatno = 0;
5873 
5874  /*
5875  * Loop over all track states. Skip states without material effects.
5876  */
5877  for (const auto & state : trajectory.trackStates()) {
5878  const GXFMaterialEffects *meff = state->materialEffects();
5879 
5880  if (meff == nullptr) {
5881  continue;
5882  }
5883 
5884  const bool isValidPlaneSurface =
5886  static_cast<const PlaneSurface *>(&state->associatedSurface()) != nullptr;
5887 
5888  /*
5889  * Modify the diagonal material elements in the [a]-matrix.
5890  */
5891  if (meff->deltaE() == 0 || (trajectory.prefit() == 0 && isValidPlaneSurface)) {
5892  weightChanged = true;
5893 
5894  const int scatNoIndex = 2 * scatno + nPerPars;
5895 
5896  if (trajectory.prefit() == 0 && meff->sigmaDeltaPhi() != 0) {
5897  if (scatno >= cache.m_phiweight.size()) {
5898  std::stringstream message;
5899  message << "scatno is out of range " << scatno << " !< " << cache.m_phiweight.size();
5900  throw std::range_error(message.str());
5901  }
5902 
5903  /*
5904  * In case, no derivative is necessary, the weight will be
5905  * effectively replaced by the relative weight change
5906  */
5907  if (!doDeriv) {
5908  a(scatNoIndex, scatNoIndex) /= cache.m_phiweight[scatno];
5909  }
5910 
5911  cache.m_phiweight[scatno] = newPhiWeight;
5912  a(scatNoIndex, scatNoIndex) *= newPhiWeight;
5913  } else if (trajectory.prefit() >= 2) {
5914  a(scatNoIndex, scatNoIndex) *= newPhiWeight;
5915  a(scatNoIndex + 1, scatNoIndex + 1) *= newThetaWeight;
5916  }
5917  }
5918 
5919  /*
5920  * The state is a valid scatterer even, if not considered in the
5921  * modification of the weights before. Therefore increment the count.
5922  *
5923  * NOTE: It is not clear, why this check is not at the beginning of the
5924  * loop. This way, a mismatch in the state counting could happen.
5925  */
5926  if (
5927  meff->sigmaDeltaPhi() != 0 &&
5928  (trajectory.prefit() == 0 || meff->deltaE() == 0)
5929  ) {
5930  scatno++;
5931  }
5932  }
5933 
5934  /*
5935  * Add a weight to the qOverP component of the [a]-matrix if a set of
5936  * pre-conditions are met and the reduced chi2 either
5937  * - converges very fast (e.g. at the beginning of the fit)
5938  * OR
5939  * - gets larger (e.g. moving away from minimum or overshooting by a lot)
5940  */
5941  if (
5942  trajectory.prefit() == 2 &&
5943  doDeriv &&
5944  trajectory.numberOfBrems() > 0 &&
5945  (newRedChi2 < oldRedChi2 - 25 || newRedChi2 > oldRedChi2)
5946  ) {
5947  a(4, 4) *= 1.001;
5948  }
5949 
5950  return weightChanged;
5951  }
5952 
5954  Cache & cache,
5955  GXFTrajectory & trajectory,
5956  Amg::SymMatrixX & a
5957  ) {
5958  const int nPerPars = trajectory.numberOfPerigeeParameters();
5959  std::size_t scatno = 0;
5960 
5961  for (auto & state : trajectory.trackStates()) {
5962  const GXFMaterialEffects *meff = state->materialEffects();
5963 
5964  if (meff == nullptr || meff->sigmaDeltaPhi() == 0) {
5965  continue;
5966  }
5967 
5968  if (scatno >= cache.m_phiweight.size()) {
5969  std::stringstream message;
5970  message << "scatno is out of range " << scatno << " !< " << cache.m_phiweight.size();
5971  throw std::range_error(message.str());
5972  }
5973 
5974  const bool isValidPlaneSurface =
5975  state->associatedSurface().type() == Trk::SurfaceType::Plane &&
5976  static_cast<const PlaneSurface *>(&state->associatedSurface()) != nullptr;
5977 
5978  if (meff->deltaE() == 0 || isValidPlaneSurface) {
5979  const int scatNoIndex = 2 * scatno + nPerPars;
5980  a(scatNoIndex, scatNoIndex) /= cache.m_phiweight[scatno];
5981  cache.m_phiweight[scatno] = 1;
5982  }
5983 
5984  /*
5985  * NOTE: We already check for this in the beginning of the loop. Is
5986  * there any way, this can change?
5987  */
5988  if (meff->sigmaDeltaPhi() != 0) {
5989  scatno++;
5990  }
5991  }
5992  }
5993 
5995  const EventContext& ctx,
5996  Cache & cache,
5997  GXFTrajectory & trajectory,
5998  const int it,
5999  Amg::SymMatrixX & a,
6000  Amg::VectorX & b,
6001  Amg::SymMatrixX & lu,
6002  bool & doDeriv
6003  ) const {
6004  const int nDOFold = trajectory.nDOF();
6005  const double oldChi2 = trajectory.chi2();
6006  const double oldRedChi2 = nDOFold > 0 ? oldChi2 / nDOFold : 0;
6007 
6008  if (cache.m_phiweight.empty()) {
6009  cache.m_phiweight.assign(trajectory.trackStates().size(), 1);
6010  }
6011 
6012  FitterStatusCode fsc = calculateTrackParameters(ctx, trajectory, doDeriv);
6013 
6014  if (fsc != FitterStatusCode::Success) {
6015  return fsc;
6016  }
6017 
6018  /*
6019  * Reset the b-vector. We want to add to the components later.
6020  */
6021  b.setZero();
6022 
6023  /*
6024  * Here we store the information on where to find the maxbrempull, in case
6025  * we find any large ones during the residual calculation. We might need it
6026  * later to update our errors.
6027  */
6028  int bremno_maxbrempull = 0;
6029  GXFTrackState* state_maxbrempull = nullptr;
6030 
6031  fillResidualsAndErrors(ctx, cache, trajectory, it, b, bremno_maxbrempull, state_maxbrempull);
6032 
6033  /*
6034  * Check if we hit any convergence conditions.
6035  */
6036  tryToConverge(cache, trajectory, it);
6037 
6038  /*
6039  * In case we converged but have a state with maxbrempull (a kink) we want
6040  * to do more iterations. Therefore, reset the convergence flag and inflate
6041  * the chi2. Then update the error estimates using the state with the
6042  * maxbrempull.
6043  */
6044  if ((state_maxbrempull != nullptr) && trajectory.converged()) {
6045  trajectory.setConverged(false);
6046  trajectory.setChi2(1e15);
6047  doDeriv = true;
6048 
6049  updateSystemWithMaxBremPull(trajectory, bremno_maxbrempull, state_maxbrempull, a);
6050  lu = a;
6051  }
6052 
6053  const int nDOFnew = trajectory.nDOF();
6054  const double newChi2 = trajectory.chi2();
6055  const double newRedChi2 = nDOFnew > 0 ? newChi2 / nDOFnew : 0;
6056 
6057  ATH_MSG_DEBUG("old chi2: " << oldChi2 << "/" << nDOFold << "=" << oldRedChi2 <<
6058  ", new chi2: " << newChi2 << "/" << nDOFnew << "=" << newRedChi2);
6059 
6060  if (trajectory.prefit() > 0 && trajectory.converged()) {
6062  }
6063 
6064  if (doDeriv) {
6065  calculateDerivatives(trajectory);
6066  fillDerivatives(trajectory);
6067  }
6068 
6069  if (cache.m_firstmeasurement.empty()) {
6070  fillFirstLastMeasurement(cache, trajectory);
6071  }
6072 
6073  if (a.cols() != trajectory.numberOfFitParameters()) {
6074  ATH_MSG_ERROR("Your assumption is wrong!!!!");
6075  }
6076 
6077  fillBfromMeasurements(cache, trajectory, b);
6078 
6079  /*
6080  * The [a]-matrix does not depend on the residuals. We only need to change
6081  * it, if the derivatives have changed.
6082  */
6083  if (doDeriv) {
6084  fillAfromMeasurements(cache, trajectory, a);
6085  fillAfromScatterers(trajectory, a);
6086  }
6087 
6088  const bool weightChanged = tryToWeightAfromMaterial(cache, trajectory, a, doDeriv, it, oldRedChi2, newRedChi2);
6089 
6090  /*
6091  * Update the [lu]-matrix if we modified the [a]-matrix.
6092  */
6093  if (doDeriv || weightChanged) {
6094  lu = a;
6095  }
6096 
6097  /*
6098  * Special handling for prefit == 0:
6099  * - If we already converged, but there are hits apart from Si and TRT or
6100  * the numbers don't match, the applied phi weights need to be reset.
6101  * - If we got in an early iteration to a low reduced chi2 or converged
6102  * with the reduced chi2, we don't need to redo derivatives.
6103  */
6104  if (trajectory.prefit() == 0) {
6105  if (trajectory.converged()) {
6106  const int nSiHits = trajectory.numberOfSiliconHits();
6107  const int nTrtHits = trajectory.numberOfTRTHits();
6108  const int nHits = trajectory.numberOfHits();
6109 
6110  if (nSiHits + nTrtHits != nHits) {
6111  compensatePhiWeights(cache, trajectory, a);
6112  lu = a;
6113  }
6114  } else if (
6115  !m_redoderivs &&
6116  it < 5 &&
6117  (newRedChi2 < 2 || (newRedChi2 < oldRedChi2 && newRedChi2 > oldRedChi2 - .5))
6118  ) {
6119  doDeriv = false;
6120  }
6121  }
6122 
6124  }
6125 
6127  GXFTrajectory & trajectory,
6128  const Amg::VectorX & b,
6129  const Amg::SymMatrixX & lu_m
6130  ) const {
6131  ATH_MSG_DEBUG("UpdateFitParameters");
6132 
6133  /*
6134  * Compute the parameter update from [llt] * deltaParameters = b.
6135  * In case we cannot do a Cholesky decomposition, we do not update and
6136  * use an early return.
6137  * TODO: Investigate, if it is really Success, if we do not update.
6138  */
6139  Eigen::LLT<Eigen::MatrixXd> const llt(lu_m);
6140 
6141  if (llt.info() != Eigen::Success) {
6143  }
6144 
6145  const Amg::VectorX deltaParameters = llt.solve(b);
6146 
6147  /*
6148  * Collect the number of each parameter type for the offsets in the
6149  * deltaParameters vector.
6150  */
6151  const int nscat = trajectory.numberOfScatterers();
6152  const int nbrem = trajectory.numberOfBrems();
6153  const int nperparams = trajectory.numberOfPerigeeParameters();
6154 
6155  /*
6156  * Update the perigee parameters.
6157  * The parameters are not modified in place. In case the angles are pushed
6158  * too far and cannot be corrected anymore, the parameters should not be
6159  * updated and the fit should fail.
6160  *
6161  * NOTE: It is not clear if the fit should fail for fitter reasons or
6162  * because the angle correction is not stable enough.
6163  */
6164  const TrackParameters *refpar = trajectory.referenceParameters();
6165  double d0 = refpar->parameters()[Trk::d0];
6166  double z0 = refpar->parameters()[Trk::z0];
6167  double phi = refpar->parameters()[Trk::phi0];
6168  double theta = refpar->parameters()[Trk::theta];
6169  double qoverp = refpar->parameters()[Trk::qOverP];
6170 
6171  if (nperparams > 0) {
6172  d0 += deltaParameters[0];
6173  z0 += deltaParameters[1];
6174  phi += deltaParameters[2];
6175  theta += deltaParameters[3];
6176  qoverp = (trajectory.m_straightline) ? 0 : .001 * deltaParameters[4] + qoverp;
6177  }
6178 
6179  if (!correctAngles(phi, theta)) {
6180  ATH_MSG_DEBUG("angles out of range: " << theta << " " << phi);
6181  ATH_MSG_DEBUG("Fit failed");
6183  }
6184 
6185  /*
6186  * Update the scattering angles.
6187  */
6188  std::vector < std::pair < double, double >>&scatangles = trajectory.scatteringAngles();
6189  for (int i = 0; i < nscat; i++) {
6190  scatangles[i].first += deltaParameters[2 * i + nperparams];
6191  scatangles[i].second += deltaParameters[2 * i + nperparams + 1];
6192  }
6193 
6194  /*
6195  * Update the brems.
6196  */
6197  std::vector < double >&delta_ps = trajectory.brems();
6198  for (int i = 0; i < nbrem; i++) {
6199  delta_ps[i] += deltaParameters[nperparams + 2 * nscat + i];
6200  }
6201 
6202  /*
6203  * Create new peregee parameters from the updated ones.
6204  */
6205  std::unique_ptr<const TrackParameters> newper(
6207  d0, z0, phi, theta, qoverp, std::nullopt
6208  )
6209  );
6210 
6211  /*
6212  * Apply all changes.
6213  */
6214  trajectory.setReferenceParameters(std::move(newper));
6215  trajectory.setScatteringAngles(scatangles);
6216  trajectory.setBrems(delta_ps);
6217 
6219  }
6220 
6222  GXFTrajectory & trajectory,
6223  Amg::SymMatrixX & a,
6224  Amg::VectorX & b,
6225  const EventContext& evtctx
6226  ) const{
6227  if ( trajectory.numberOfSiliconHits() == 0) {
6228  return;
6229  }
6230 
6232  return;
6233  }
6234 
6236  if (!splitProbContainer.isValid()) {
6237  ATH_MSG_FATAL("Failed to get cluster splitting probability container " << m_clusterSplitProbContainer);
6238  }
6239 
6240  std::vector<std::unique_ptr<GXFTrackState>> & states = trajectory.trackStates();
6241  Amg::VectorX & res = trajectory.residuals();
6242  Amg::VectorX & err = trajectory.errors();
6243  Amg::MatrixX & weightderiv = trajectory.weightedResidualDerivatives();
6244  const int nfitpars = trajectory.numberOfFitParameters();
6245 
6246  int measno = 0;
6247  for (size_t stateno = 0; stateno < states.size(); stateno++) {
6248 
6249  // Increment the measurement counter everytime we have crossed a measurement/outlier surface
6250  if ( stateno > 0 && ( states[stateno-1]->getStateType(TrackStateOnSurface::Measurement) ||
6251  states[stateno-1]->getStateType(TrackStateOnSurface::Outlier) ) ) {
6252  measno += states[stateno-1]->numberOfMeasuredParameters();
6253  }
6254 
6255  std::unique_ptr<GXFTrackState> & state = states[stateno];
6256  if (!state->getStateType(TrackStateOnSurface::Measurement)) {
6257  continue;
6258  }
6259 
6260  TrackState::MeasurementType const hittype = state->measurementType();
6261  if (hittype != TrackState::Pixel) {
6262  continue;
6263  }
6264 
6265  const PrepRawData *prd{};
6266  if (const auto *const pMeas = state->measurement(); pMeas->type(Trk::MeasurementBaseType::RIO_OnTrack)){
6267  const auto *const rot = static_cast<const RIO_OnTrack *>(pMeas);
6268  prd = rot->prepRawData();
6269  }
6270 
6271  if(!prd)
6272  continue;
6273 
6274  if(!prd->type(Trk::PrepRawDataType::PixelCluster)){
6275  continue;
6276  }
6277  const InDet::PixelCluster* pixelCluster = static_cast<const InDet::PixelCluster*> ( prd );
6278  const auto &splitProb = splitProbContainer->splitProbability(pixelCluster);
6279  if (!splitProb.isSplit()) {
6280  ATH_MSG_DEBUG( "Pixel cluster is not split so no need to update" );
6281  continue;
6282  }
6283 
6284  std::unique_ptr < const RIO_OnTrack > newrot;
6285  double *olderror = state->measurementErrors();
6286  const TrackParameters *trackpars = state->trackParameters();
6287 
6288  double newerror[5] = {-1,-1,-1,-1,-1};
6289  double newres[2] = {-1,-1};
6290 
6291  newrot.reset(m_ROTcreator->correct(*prd, *trackpars, evtctx));
6292 
6293  if(!newrot)
6294  continue;
6295 
6296  const Amg::MatrixX & covmat = newrot->localCovariance();
6297 
6298  newerror[0] = std::sqrt(covmat(0, 0));
6299  newres[0] = newrot->localParameters()[Trk::locX] - trackpars->parameters()[Trk::locX];
6300  newerror[1] = std::sqrt(covmat(1, 1));
6301  newres[1] = newrot->localParameters()[Trk::locY] - trackpars->parameters()[Trk::locY];
6302 
6303  if (a.cols() != nfitpars) {
6304  ATH_MSG_ERROR("Your assumption is wrong!!!!");
6305  }
6306 
6307  //loop over both measurements -- treated as uncorrelated
6308  for( int k =0; k<2; k++ ){
6309  const double oldres = res[measno+k];
6310  res[measno+k] = newres[k];
6311  err[measno+k] = newerror[k];
6312 
6313  for (int i = 0; i < nfitpars; i++) {
6314  if (weightderiv(measno+k, i) == 0) {
6315  continue;
6316  }
6317 
6318  b[i] -= weightderiv(measno+k, i) * (oldres / olderror[k] - (newres[k] * olderror[k]) / (newerror[k] * newerror[k]));
6319 
6320  for (int j = i; j < nfitpars; j++) {
6321  a.fillSymmetric(
6322  i, j,
6323  a(i, j) + (
6324  weightderiv(measno+k, i) *
6325  weightderiv(measno+k, j) *
6326  ((olderror[k] * olderror[k]) / (newerror[k] * newerror[k]) - 1)
6327  )
6328  );
6329  }
6330  weightderiv(measno+k, i) *= olderror[k] / newerror[k];
6331  }
6332  }
6333 
6334  state->setMeasurement(std::move(newrot));
6335  state->setMeasurementErrors(newerror);
6336 
6337  }// end for
6338  }
6339 
6340 
6342  Cache & cache,
6343  GXFTrajectory & trajectory,
6344  Amg::SymMatrixX & a,
6345  Amg::VectorX & b,
6346  Amg::SymMatrixX & lu_m,
6347  bool runOutlier,
6348  bool trtrecal,
6349  int it,
6350  const EventContext& ctx
6351  ) const {
6352  double scalefactor = m_scalefactor;
6353 
6354  if (it == 1 && trajectory.numberOfSiliconHits() + trajectory.numberOfTRTHits() == trajectory.numberOfHits()) {
6355  scalefactor *= 2;
6356  }
6357 
6358  std::vector<std::unique_ptr<GXFTrackState>> & states = trajectory.trackStates();
6359  Amg::VectorX & res = trajectory.residuals();
6360  Amg::VectorX & err = trajectory.errors();
6361  Amg::MatrixX & weightderiv = trajectory.weightedResidualDerivatives();
6362  const int nfitpars = trajectory.numberOfFitParameters();
6363 
6364  if (a.cols() != nfitpars) {
6365  ATH_MSG_ERROR("Your assumption is wrong!!!!");
6366  }
6367 
6368  const int nperpars = trajectory.numberOfPerigeeParameters();
6369  const int nscats = trajectory.numberOfScatterers();
6370  int hitno = 0;
6371  int measno = 0;
6372  bool outlierremoved = false;
6373  bool hitrecalibrated = false;
6374 
6375  for (int stateno = 0; stateno < (int) states.size(); stateno++) {
6376  std::unique_ptr<GXFTrackState> & state = states[stateno];
6377 
6378  if (state->getStateType(TrackStateOnSurface::Measurement)) { // Hit is not (yet) an outlier
6379  TrackState::MeasurementType const hittype = state->measurementType();
6380 
6381  if (hittype == TrackState::TRT) {
6382  if (
6383  runOutlier &&
6384  std::abs(state->trackParameters()->parameters()[Trk::driftRadius]) > 1.05 * state->associatedSurface().bounds().r()
6385  ) {
6386  ATH_MSG_DEBUG("Removing TRT hit #" << hitno);
6387 
6388  trajectory.setOutlier(stateno);
6389  outlierremoved = true;
6390 
6391  double *errors = state->measurementErrors();
6392  const double olderror = errors[0];
6393 
6394  trajectory.updateTRTHitCount(stateno, olderror);
6395 
6396  for (int i = 0; i < nfitpars; i++) {
6397  if (weightderiv(measno, i) == 0) {
6398  continue;
6399  }
6400 
6401  b[i] -= res[measno] * weightderiv(measno, i) / olderror;
6402 
6403  for (int j = i; j < nfitpars; j++) {
6404  a.fillSymmetric(
6405  i, j,
6406  a(i, j) - weightderiv(measno, i) * weightderiv(measno, j)
6407  );
6408  }
6409  weightderiv(measno, i) = 0;
6410  }
6411 
6412  res[measno] = 0;
6413  } else if (trtrecal) {
6414  double *errors = state->measurementErrors();
6415  const double olderror = errors[0];
6416  const Trk::RIO_OnTrack * oldrot{};
6417  const auto *const thisMeasurement{state->measurement()};
6418  if ( not thisMeasurement->type(Trk::MeasurementBaseType::RIO_OnTrack)){
6419  continue;
6420  }
6421  oldrot = static_cast<const Trk::RIO_OnTrack *>(thisMeasurement);
6422  const double oldradius = oldrot->localParameters()[Trk::driftRadius];
6423  if (oldrot->prepRawData() != nullptr) {
6424  const double dcradius = oldrot->prepRawData()->localPosition()[Trk::driftRadius];
6425  const double dcerror = std::sqrt(oldrot->prepRawData()->localCovariance()(Trk::driftRadius, Trk::driftRadius));
6426  const double trackradius = state->trackParameters()->parameters()[Trk::driftRadius];
6427 
6428  std::unique_ptr<const Trk::RIO_OnTrack> newrot = nullptr;
6429  const double distance = std::abs(std::abs(trackradius) - dcradius);
6430 
6431  if (distance < scalefactor * dcerror && (olderror > 1. || trackradius * oldradius < 0)) {
6432  newrot.reset(m_ROTcreator->correct(*oldrot->prepRawData(), *state->trackParameters(), ctx));
6433  } else if (distance > scalefactor * dcerror && olderror < 1.) {
6434  newrot.reset(m_broadROTcreator->correct(*oldrot->prepRawData(), *state->trackParameters(), ctx));
6435  }
6436 
6437  if (newrot != nullptr) {
6438  ATH_MSG_DEBUG("Recalibrating TRT hit #" << hitno);
6439  hitrecalibrated = true;
6440  const double newradius = newrot->localParameters()[Trk::driftRadius];
6441  const double newerror = std::sqrt(newrot->localCovariance()(Trk::driftRadius, Trk::driftRadius));
6442 
6443  if ((measno < 0) or (measno >= (int) res.size())) {
6444  throw std::runtime_error(
6445  "'res' array index out of range in TrkGlobalChi2Fitter/src/GlobalChi2Fitter.cxx:" + std::to_string(__LINE__)
6446  );
6447  }
6448 
6449  const double oldres = res[measno];
6450  const double newres = newradius - state->trackParameters()->parameters()[Trk::driftRadius];
6451  errors[0] = newerror;
6452  state->setMeasurement(std::move(newrot));
6453 
6454  trajectory.updateTRTHitCount(stateno, olderror);
6455 
6456  for (int i = 0; i < nfitpars; i++) {
6457  if (weightderiv(measno, i) == 0) {
6458  continue;
6459  }
6460 
6461  b[i] -= weightderiv(measno, i) * (oldres / olderror - (newres * olderror) / (newerror * newerror));
6462 
6463  for (int j = i; j < nfitpars; j++) {
6464  double weight = 1;
6465 
6466  if (
6467  !cache.m_phiweight.empty() &&
6468  i == j &&
6469  i >= nperpars &&
6470  i < nperpars + 2 * nscats &&
6471  (i - nperpars) % 2 == 0
6472  ) {
6473  weight = cache.m_phiweight[(i - nperpars) / 2];
6474  }
6475 
6476  a.fillSymmetric(
6477  i, j,
6478  a(i, j) + weightderiv(measno, i) * weightderiv(measno, j) * ((olderror * olderror) / (newerror * newerror) - 1) * weight
6479  );
6480  }
6481  weightderiv(measno, i) *= olderror / newerror;
6482  }
6483 
6484  res[measno] = newres;
6485  err[measno] = newerror;
6486  }
6487  }
6488  }
6489  }
6490  }
6491 
6492  if (state->getStateType(TrackStateOnSurface::Measurement) || state->getStateType(TrackStateOnSurface::Outlier)) {
6493  hitno++;
6494  measno += state->numberOfMeasuredParameters();
6495  }
6496  }
6497 
6498  if (trajectory.nDOF() < 0) {
6501  }
6502 
6503  if (outlierremoved || hitrecalibrated) {
6504  lu_m = a;
6505  trajectory.setConverged(false);
6506 
6507  cache.m_miniter = it + 2;
6508  }
6509  }
6510 
6512  const EventContext& ctx,
6513  Cache & cache,
6514  GXFTrajectory &trajectory,
6515  Amg::SymMatrixX & a,
6516  Amg::SymMatrixX &fullcov,
6517  Amg::VectorX & b,
6518  bool runoutlier
6519  ) const {
6520  bool trackok = false;
6521  GXFTrajectory *oldtrajectory = &trajectory;
6522  std::unique_ptr < GXFTrajectory > cleanup_oldtrajectory;
6523  GXFTrajectory *newtrajectory = nullptr;
6524  std::unique_ptr < GXFTrajectory > cleanup_newtrajectory;
6525 
6526  // the oldtrajectory will be returned, so in case newtrajectory==oldtrajectory
6527  // the cleanup_newtrajectory == NULL and cleanup_oldtrajectory = oldtrajectory, otherwise
6528  // cleanup_newtrajectory will destroy the object oldtrajectory is pointing to.
6529 
6530  while (!trackok && oldtrajectory->nDOF() > 0) {
6531  trackok = true;
6532  std::vector<std::unique_ptr<GXFTrackState>> & states = oldtrajectory->trackStates();
6533  Amg::VectorX & res = oldtrajectory->residuals();
6534  Amg::VectorX & err = oldtrajectory->errors();
6535  Amg::MatrixX & weightderiv = oldtrajectory->weightedResidualDerivatives();
6536  const int nfitpars = oldtrajectory->numberOfFitParameters();
6537  const int nhits = oldtrajectory->numberOfHits();
6538  const int nsihits = oldtrajectory->numberOfSiliconHits();
6539 
6540  if (nhits != nsihits) {
6541  return &trajectory;
6542  }
6543 
6544  double maxsipull = -1;
6545  int hitno = 0;
6546  int hitno_maxsipull = -1;
6547  int measno_maxsipull = -1;
6548  int stateno_maxsipull = 0;
6549  GXFTrackState *state_maxsipull = nullptr;
6550  int measno = 0;
6551  int n3sigma = 0;
6552  const double cut = m_outlcut;
6553  double cut2 = m_outlcut - 1.;
6554  const int noutl = oldtrajectory->numberOfOutliers();
6555 
6556  if (noutl > 0) {
6557  cut2 = cut - 1.25;
6558  }
6559 
6560  for (int stateno = 0; stateno < (int) states.size(); stateno++) {
6561  std::unique_ptr<GXFTrackState> & state = states[stateno];
6562 
6563  if (state->getStateType(TrackStateOnSurface::Measurement)) {
6564  TrackState::MeasurementType const hittype = state->measurementType();
6565 
6566  if ((hittype == TrackState::Pixel || hittype == TrackState::SCT) && state->hasTrackCovariance()) {
6567  double *errors = state->measurementErrors();
6568  AmgSymMatrix(5) & trackcov = state->trackCovariance();
6569  const Amg::MatrixX & hitcov = state->measurement()->localCovariance();
6570  const double sinstereo = state->sinStereo();
6571  const double cosstereo = (sinstereo == 0) ? 1 : std::sqrt(1 - sinstereo * sinstereo);
6572  double weight1 = -1;
6573 
6574  if (hitcov(0, 0) > trackcov(0, 0)) {
6575  if (sinstereo == 0) {
6576  weight1 = errors[0] * errors[0] - trackcov(0, 0);
6577  } else {
6578  weight1 = errors[0] * errors[0] - (
6579  trackcov(0, 0) * cosstereo * cosstereo + 2 *
6580  trackcov(1, 0) * cosstereo * sinstereo + trackcov(1, 1) * sinstereo * sinstereo
6581  );
6582  }
6583  }
6584 
6585  const double weight2 = (
6586  hittype == TrackState::Pixel && hitcov(1, 1) > trackcov(1, 1) ?
6587  errors[1] * errors[1] - trackcov(1, 1) :
6588  -1
6589  );
6590 
6591  double sipull1 = weight1 > 0 ? std::abs(res[measno] / std::sqrt(weight1)) : -1;
6592  const double sipull2 = (
6593  hittype == TrackState::Pixel && weight2 > 0 ?
6594  std::abs(res[measno + 1] / std::sqrt(weight2)) :
6595  -1
6596  );
6597  sipull1 = std::max(sipull1, sipull2);
6598 
6599  if (sipull1 > maxsipull) {
6600  maxsipull = sipull1;
6601  measno_maxsipull = measno;
6602  state_maxsipull = state.get();
6603  stateno_maxsipull = stateno;
6604  hitno_maxsipull = hitno;
6605  }
6606 
6607  if (hittype == TrackState::Pixel && sipull1 > cut2) {
6608  n3sigma++;
6609  }
6610  }
6611  }
6612 
6613  if (state->getStateType(TrackStateOnSurface::Measurement) || state->getStateType(TrackStateOnSurface::Outlier)) {
6614  hitno++;
6615  measno += state->numberOfMeasuredParameters();
6616  }
6617  }
6618 
6619  const double maxpull = maxsipull;
6620 
6621  ATH_MSG_DEBUG(" maxsipull: " << maxsipull << " hitno_maxsipull: " <<
6622  hitno_maxsipull << " n3sigma: " << n3sigma << " cut: " << cut << " cut2: " << cut2);
6623 
6624  Amg::SymMatrixX * newap = &a;
6625  Amg::VectorX * newbp = &b;
6626  Amg::SymMatrixX newa(nfitpars, nfitpars);
6627  Amg::VectorX newb(nfitpars);
6628 
6629  if (
6630  maxpull > 2 &&
6631  oldtrajectory->chi2() / oldtrajectory->nDOF() > .25 * m_chi2cut
6632  ) {
6633  state_maxsipull = oldtrajectory->trackStates()[stateno_maxsipull].get();
6634  const PrepRawData *prd{};
6635  if (const auto *const pMeas = state_maxsipull->measurement(); pMeas->type(Trk::MeasurementBaseType::RIO_OnTrack)){
6636  const auto *const rot = static_cast<const RIO_OnTrack *>(pMeas);
6637  prd = rot->prepRawData();
6638  }
6639  std::unique_ptr < const RIO_OnTrack > broadrot;
6640  double *olderror = state_maxsipull->measurementErrors();
6641  TrackState::MeasurementType const hittype_maxsipull = state_maxsipull->measurementType();
6642  const TrackParameters *trackpar_maxsipull = state_maxsipull->trackParameters();
6643 
6644  Amg::VectorX parameterVector = trackpar_maxsipull->parameters();
6645  const std::unique_ptr<const TrackParameters> trackparForCorrect(
6646  trackpar_maxsipull->associatedSurface().createUniqueTrackParameters(
6647  parameterVector[Trk::loc1],
6648  parameterVector[Trk::loc2],
6649  parameterVector[Trk::phi],
6650  parameterVector[Trk::theta],
6651  parameterVector[Trk::qOverP],
6652  state_maxsipull->hasTrackCovariance()
6653  ? std::optional<AmgSymMatrix(5)>(
6654  state_maxsipull->trackCovariance())
6655  : std::nullopt));
6656 
6657  double newerror[5];
6658  newerror[0] = newerror[1] = newerror[2] = newerror[3] = newerror[4] = -1;
6659  double newpull = -1;
6660  double newpull1 = -1;
6661  double newpull2 = -1;
6662  double newres1 = -1;
6663  double newres2 = -1;
6664  double newsinstereo = 0;
6665 
6666  if (
6667  (prd != nullptr) &&
6668  !state_maxsipull->isRecalibrated() &&
6669  maxpull > 2.5 &&
6670  oldtrajectory->chi2() / trajectory.nDOF() > .3 * m_chi2cut &&
6671  cache.m_sirecal
6672  ) {
6673  broadrot.reset(m_broadROTcreator->correct(*prd, *trackparForCorrect, ctx));
6674  }
6675 
6676  if (broadrot) {
6677  const Amg::MatrixX & covmat = broadrot->localCovariance();
6678 
6679  if (state_maxsipull->sinStereo() != 0) {
6680  const auto [covEigenValueSmall, covStereoAngle] = principalComponentAnalysis2x2(covmat);
6681  newerror[0] = std::sqrt(covEigenValueSmall);
6682  newsinstereo = std::sin(covStereoAngle);
6683  } else {
6684  newerror[0] = std::sqrt(covmat(0, 0));
6685  }
6686 
6687  const double cosstereo = (newsinstereo == 0) ? 1. : std::sqrt(1 - newsinstereo * newsinstereo);
6688 
6689  if (cosstereo != 1.) {
6690  newres1 = (
6691  cosstereo * (broadrot->localParameters()[Trk::locX] - trackpar_maxsipull->parameters()[Trk::locX]) +
6692  newsinstereo * (broadrot->localParameters()[Trk::locY] - trackpar_maxsipull->parameters()[Trk::locY])
6693  );
6694  } else {
6695  newres1 = broadrot->localParameters()[Trk::locX] - trackpar_maxsipull->parameters()[Trk::locX];
6696  }
6697 
6698  if (newerror[0] == 0.0) {
6699  ATH_MSG_WARNING("Measurement error is zero or negative, treating as outlier");
6700  newpull1 = 9999.;
6701  } else {
6702  newpull1 = std::abs(newres1 / newerror[0]);
6703  }
6704 
6705  if (hittype_maxsipull == TrackState::Pixel) {
6706  newerror[1] = std::sqrt(covmat(1, 1));
6707  newres2 = broadrot->localParameters()[Trk::locY] - trackpar_maxsipull->parameters()[Trk::locY];
6708  newpull2 = std::abs(newres2 / newerror[1]);
6709  }
6710 
6711  newpull = std::max(newpull1, newpull2);
6712  }
6713 
6714  if (
6715  broadrot &&
6716  newpull < m_outlcut &&
6717  (newerror[0] > 1.5 * olderror[0] || newerror[1] > 1.5 * std::abs(olderror[1]))
6718  ) {
6719  if ((measno_maxsipull < 0) or(measno_maxsipull >= (int) res.size())) {
6720  throw std::runtime_error(
6721  "'res' array index out of range in TrkGlobalChi2Fitter/src/GlobalChi2Fitter.cxx:" + std::to_string(__LINE__)
6722  );
6723  }
6724 
6725  trackok = false;
6726  newtrajectory = oldtrajectory;
6727 
6728  if (a.cols() != nfitpars) {
6729  ATH_MSG_ERROR("Your assumption is wrong!!!!");
6730  }
6731 
6732  const double oldres1 = res[measno_maxsipull];
6733  res[measno_maxsipull] = newres1;
6734  err[measno_maxsipull] = newerror[0];
6735 
6736  for (int i = 0; i < nfitpars; i++) {
6737  if (weightderiv(measno_maxsipull, i) == 0) {
6738  continue;
6739  }
6740 
6741  b[i] -= weightderiv(measno_maxsipull, i) * (oldres1 / olderror[0] - (newres1 * olderror[0]) / (newerror[0] * newerror[0]));
6742 
6743  for (int j = i; j < nfitpars; j++) {
6744  a.fillSymmetric(
6745  i, j,
6746  a(i, j) + (
6747  weightderiv(measno_maxsipull, i) *
6748  weightderiv(measno_maxsipull, j) *
6749  ((olderror[0] * olderror[0]) / (newerror[0] * newerror[0]) - 1)
6750  )
6751  );
6752  }
6753  weightderiv(measno_maxsipull, i) *= olderror[0] / newerror[0];
6754  }
6755 
6756  if (hittype_maxsipull == TrackState::Pixel) {
6757  const double oldres2 = res[measno_maxsipull + 1];
6758  res[measno_maxsipull + 1] = newres2;
6759  err[measno_maxsipull + 1] = newerror[1];
6760 
6761  for (int i = 0; i < nfitpars; i++) {
6762  if (weightderiv(measno_maxsipull + 1, i) == 0) {
6763  continue;
6764  }
6765 
6766  b[i] -= weightderiv(measno_maxsipull + 1, i) * (oldres2 / olderror[1] - (newres2 * olderror[1]) / (newerror[1] * newerror[1]));
6767 
6768  for (int j = i; j < nfitpars; j++) {
6769  a.fillSymmetric(
6770  i, j,
6771  a(i, j) + (
6772  weightderiv(measno_maxsipull + 1, i) *
6773  weightderiv(measno_maxsipull + 1, j) *
6774  ((olderror[1] * olderror[1]) / (newerror[1] * newerror[1]) - 1)
6775  )
6776  );
6777  }
6778 
6779  weightderiv(measno_maxsipull + 1, i) *= olderror[1] / newerror[1];
6780  }
6781  }
6782 
6783  ATH_MSG_DEBUG(
6784  "Recovering outlier, hitno=" << hitno_maxsipull << " measno=" <<
6785  measno_maxsipull << " pull=" << maxsipull << " olderror_0=" <<
6786  olderror[0] << " newerror_0=" << newerror[0] << " olderror_1=" <<
6787  olderror[1] << " newerror_1=" << newerror[1]
6788  );
6789 
6790  state_maxsipull->setMeasurement(std::move(broadrot));
6791  state_maxsipull->setSinStereo(newsinstereo);
6792  state_maxsipull->setMeasurementErrors(newerror);
6793  } else if (
6794  (
6795  (
6796  ((n3sigma < 2 && maxsipull > cut2 && maxsipull < cut) || n3sigma > 1) &&
6797  (oldtrajectory->chi2() / oldtrajectory->nDOF() > .3 * m_chi2cut || noutl > 1)
6798  ) ||
6799  maxsipull > cut
6800  ) &&
6801  (oldtrajectory->nDOF() > 1 || hittype_maxsipull == TrackState::SCT) &&
6802  runoutlier
6803  ) {
6804  trackok = false;
6805  ATH_MSG_DEBUG(
6806  "Removing outlier, hitno=" << hitno_maxsipull << ", measno=" <<
6807  measno_maxsipull << " pull=" << maxsipull
6808  );
6809 
6810  newa = a;
6811  newb = b;
6812  newap = &newa;
6813  newbp = &newb;
6814  cleanup_newtrajectory = std::make_unique<GXFTrajectory>(*oldtrajectory);
6815  newtrajectory = cleanup_newtrajectory.get();
6816 
6817  if (newa.cols() != nfitpars) {
6818  ATH_MSG_ERROR("Your assumption is wrong!!!!");
6819  }
6820 
6821  Amg::VectorX & newres = newtrajectory->residuals();
6822  Amg::MatrixX & newweightderiv = newtrajectory->weightedResidualDerivatives();
6823  if ((measno_maxsipull < 0) or(measno_maxsipull >= (int) res.size())) {
6824  throw std::runtime_error(
6825  "'res' array index out of range in TrkGlobalChi2Fitter/src/GlobalChi2Fitter.cxx:" + std::to_string(__LINE__)
6826  );
6827  }
6828 
6829  const double oldres1 = res[measno_maxsipull];
6830  newres[measno_maxsipull] = 0;
6831 
6832  for (int i = 0; i < nfitpars; i++) {
6833  if (weightderiv(measno_maxsipull, i) == 0) {
6834  continue;
6835  }
6836 
6837  newb[i] -= weightderiv(measno_maxsipull, i) * oldres1 / olderror[0];
6838 
6839  for (int j = i; j < nfitpars; j++) {
6840  newa.fillSymmetric(
6841  i, j,
6842  newa(i, j) - (
6843  weightderiv(measno_maxsipull, i) *
6844  weightderiv(measno_maxsipull, j)
6845  )
6846  );
6847  }
6848  newweightderiv(measno_maxsipull, i) = 0;
6849  }
6850 
6851  if (hittype_maxsipull == TrackState::Pixel) {
6852  const double oldres2 = res[measno_maxsipull + 1];
6853  newres[measno_maxsipull + 1] = 0;
6854 
6855  for (int i = 0; i < nfitpars; i++) {
6856  if (weightderiv(measno_maxsipull + 1, i) == 0) {
6857  continue;
6858  }
6859 
6860  newb[i] -= weightderiv(measno_maxsipull + 1, i) * oldres2 / olderror[1];
6861 
6862  for (int j = i; j < nfitpars; j++) {
6863  if (weightderiv(measno_maxsipull + 1, j) == 0) {
6864  continue;
6865  }
6866 
6867  newa.fillSymmetric(
6868  i, j,
6869  newa(i, j) - (
6870  weightderiv(measno_maxsipull + 1, i) *
6871  weightderiv(measno_maxsipull + 1, j)
6872  )
6873  );
6874  }
6875  newweightderiv(measno_maxsipull + 1, i) = 0;
6876  }
6877  }
6878 
6879  newtrajectory->setOutlier(stateno_maxsipull);
6880  }
6881  }
6882 
6883  if (!trackok) {
6884  Amg::SymMatrixX lu_m = *newap;
6885  newtrajectory->setConverged(false);
6886  bool doderiv = m_redoderivs;
6887  cache.m_fittercode = updateFitParameters(*newtrajectory, *newbp, lu_m);
6888  if (cache.m_fittercode != FitterStatusCode::Success) {
6890  return nullptr;
6891  }
6892 
6893  for (int it = 0; it < m_maxit; ++it) {
6894  if (it == m_maxit - 1) {
6895  ATH_MSG_DEBUG("Fit did not converge");
6898  return nullptr;
6899  }
6900 
6901  if (!newtrajectory->converged()) {
6902  cache.m_fittercode = runIteration(
6903  ctx, cache, *newtrajectory, it, *newap, *newbp, lu_m, doderiv);
6904 
6905  if (cache.m_fittercode != FitterStatusCode::Success) {
6907  return nullptr;
6908  }
6909 
6910  if (!newtrajectory->converged()) {
6911  cache.m_fittercode = updateFitParameters(*newtrajectory, *newbp, lu_m);
6912  if (cache.m_fittercode != FitterStatusCode::Success) {
6914 
6915  return nullptr;
6916  }
6917  }
6918  } else {
6919  const double oldchi2 = oldtrajectory->chi2() / oldtrajectory->nDOF();
6920  const double newchi2 = (newtrajectory->nDOF() > 0) ? newtrajectory->chi2() / newtrajectory->nDOF() : 0;
6921  double mindiff = 0;
6922 
6923  if (newtrajectory->nDOF() != oldtrajectory->nDOF() && maxsipull > cut2) {
6924  mindiff = (oldchi2 > .33 * m_chi2cut || noutl > 0) ? .8 : 1.;
6925 
6926  if (noutl == 0 && maxsipull < cut - .5 && oldchi2 < .5 * m_chi2cut) {
6927  mindiff = 2.;
6928  }
6929  }
6930 
6931  if (newchi2 > oldchi2 || (newchi2 > oldchi2 - mindiff && newchi2 > .33 * oldchi2)) {
6932  ATH_MSG_DEBUG("Outlier not confirmed, keeping old trajectory");
6933 
6934  if (oldchi2 > m_chi2cut) {
6937  return nullptr;
6938  }
6939 
6940  (void)cleanup_oldtrajectory.release();
6941  return oldtrajectory;
6942  }
6943  if (oldtrajectory != newtrajectory) {
6944  cleanup_oldtrajectory = std::move(cleanup_newtrajectory);
6945  oldtrajectory = newtrajectory;
6946  a = newa;
6947  b = newb;
6948  }
6949 
6950  // Solve assuming the matrix is SPD.
6951  // Cholesky Decomposition is used
6952  Eigen::LLT < Eigen::MatrixXd > const lltOfW(a);
6953  if (lltOfW.info() == Eigen::Success) {
6954  // Solve for x where Wx = I
6955  // this is cheaper than invert as invert makes no assumptions about the
6956  // matrix being symmetric
6957  const int ncols = a.cols();
6958  Amg::MatrixX const weightInvAMG = Amg::MatrixX::Identity(ncols, ncols);
6959  fullcov = lltOfW.solve(weightInvAMG);
6960  } else {
6961  ATH_MSG_DEBUG("matrix inversion failed!");
6964  return nullptr;
6965  }
6966  break;
6967  }
6968  }
6969  }
6970 
6971  if (!trackok) {
6972  calculateTrackErrors(*oldtrajectory, fullcov, true);
6973  }
6974  }
6975 
6976  if (
6977  oldtrajectory->nDOF() > 0 &&
6978  oldtrajectory->chi2() / oldtrajectory->nDOF() > m_chi2cut &&
6979  runoutlier
6980  ) {
6983  return nullptr;
6984  }
6985 
6986  (void)cleanup_oldtrajectory.release();
6987  return oldtrajectory;
6988  }
6989 
6991  Cache &cache,
6992  GXFTrajectory &oldtrajectory
6993  ) {
6994  Amg::MatrixX & derivs = oldtrajectory.weightedResidualDerivatives();
6995  Amg::VectorX & errors = oldtrajectory.errors();
6996  int nrealmeas = 0;
6997 
6998  for (auto & hit : oldtrajectory.trackStates()) {
6999  if (const auto *pMeas{hit->measurement()};
7000  hit->getStateType(TrackStateOnSurface::Measurement) and (
7003  )
7004  ) {
7005  nrealmeas += hit->numberOfMeasuredParameters();
7006  }
7007  }
7008  cache.m_derivmat.resize(nrealmeas, oldtrajectory.numberOfFitParameters());
7009  cache.m_derivmat.setZero();
7010  int measindex = 0;
7011  int measindex2 = 0;
7012  const int nperpars = oldtrajectory.numberOfPerigeeParameters();
7013  const int nscat = oldtrajectory.numberOfScatterers();
7014  for (auto & hit : oldtrajectory.trackStates()) {
7015  if (const auto *pMeas{hit->measurement()};
7016  hit->getStateType(TrackStateOnSurface::Measurement) and (
7019  )
7020  ) {
7021  for (int i = measindex; i < measindex + hit->numberOfMeasuredParameters(); i++) {
7022  for (int j = 0; j < oldtrajectory.numberOfFitParameters(); j++) {
7023  cache.m_derivmat(i, j) = derivs(measindex2, j) * errors[measindex2];
7024  if ((j == 4 && !oldtrajectory.m_straightline) || j >= nperpars + 2 * nscat) {
7025  cache.m_derivmat(i, j) *= 1000;
7026  }
7027  }
7028 
7029  measindex2++;
7030  }
7031 
7032  measindex += hit->numberOfMeasuredParameters();
7033  } else if (hit->materialEffects() == nullptr) {
7034  measindex2 += hit->numberOfMeasuredParameters();
7035  }
7036  }
7037  }
7038 
7039  std::unique_ptr<const TrackParameters> GlobalChi2Fitter::makeTrackFindPerigeeParameters(
7040  const EventContext & ctx,
7041  Cache &cache,
7042  GXFTrajectory &oldtrajectory,
7043  const ParticleHypothesis matEffects
7044  ) const {
7045  GXFTrackState *firstmeasstate = nullptr;
7046  GXFTrackState *lastmeasstate = nullptr;
7047  std::tie(firstmeasstate, lastmeasstate) = oldtrajectory.findFirstLastMeasurement();
7048  std::unique_ptr<const TrackParameters> per(nullptr);
7049 
7050  if (cache.m_acceleration && !m_matupdator.empty()) {
7051  std::unique_ptr<const TrackParameters> prevpar(
7052  firstmeasstate->trackParameters() != nullptr ?
7053  firstmeasstate->trackParameters()->clone() :
7054  nullptr
7055  );
7056  std::vector<std::pair<const Layer *, const Layer *>> & upstreamlayers = oldtrajectory.upstreamMaterialLayers();
7057  bool first = true;
7058 
7059  for (const auto & [layer1, layer2] : upstreamlayers | std::views::reverse) {
7060  if (prevpar == nullptr) {
7061  break;
7062  }
7063 
7064  PropDirection propdir = oppositeMomentum;
7065  const Layer *layer = layer1 != nullptr ? layer1 : layer2;
7066 
7067  const DistanceSolution distsol = layer->surfaceRepresentation().straightLineDistanceEstimate(
7068  prevpar->position(), prevpar->momentum().unit()
7069  );
7070  const double distance = getDistance(distsol);
7071 
7072  if (distsol.numberOfSolutions() == 2) {
7073  if (std::abs(distance) < 0.01) {
7074  continue;
7075  }
7076 
7077  if (distsol.first() * distsol.second() < 0 && !first) {
7078  continue;
7079  }
7080  }
7081 
7082  if (first && distance > 0) {
7083  propdir = alongMomentum;
7084  }
7085 
7086  std::unique_ptr<const TrackParameters> layerpar(
7087  m_propagator->propagate(
7088  ctx,
7089  *prevpar,
7090  layer->surfaceRepresentation(),
7091  propdir,
7092  true,
7093  oldtrajectory.m_fieldprop,
7095  )
7096  );
7097 
7098  if (layerpar == nullptr) {
7099  continue;
7100  }
7101 
7102  if (layer->surfaceRepresentation().bounds().inside(layerpar->localPosition())) {
7103  layerpar = m_matupdator->update(layerpar.get(), *layer, oppositeMomentum, matEffects);
7104  }
7105 
7106  prevpar = std::move(layerpar);
7107  first = false;
7108  }
7109 
7110  const Layer *startlayer = firstmeasstate->trackParameters()->associatedSurface().associatedLayer();
7111 
7112  if ((startlayer != nullptr) && (startlayer->layerMaterialProperties() != nullptr)) {
7113  double startfactor = startlayer->layerMaterialProperties()->alongPostFactor();
7114  const Surface & discsurf = startlayer->surfaceRepresentation();
7115 
7116  if (discsurf.type() == Trk::SurfaceType::Disc && discsurf.center().z() * discsurf.normal().z() < 0) {
7117  startfactor = startlayer->layerMaterialProperties()->oppositePostFactor();
7118  }
7119  if (startfactor > 0.5) {
7120  std::unique_ptr<const TrackParameters> updatedpar = m_matupdator->update(
7121  firstmeasstate->trackParameters(), *startlayer, oppositeMomentum, matEffects
7122  );
7123 
7124  if (updatedpar != nullptr) {
7125  firstmeasstate->setTrackParameters(std::move(updatedpar));
7126  }
7127  }
7128  }
7129 
7130  // @TODO Coverity complains about a possible NULL pointer dereferencing in lastmeasstate->...
7131  // Now an exception is thrown if there is no firstmeastate. Thus if the code here is
7132  // reached then there should be a firstmeasstate and a lastmeasstate
7133 
7134  const Layer *endlayer = lastmeasstate->trackParameters()->associatedSurface().associatedLayer();
7135 
7136  if ((endlayer != nullptr) && (endlayer->layerMaterialProperties() != nullptr)) {
7137  double endfactor = endlayer->layerMaterialProperties()->alongPreFactor();
7138  const Surface & discsurf = endlayer->surfaceRepresentation();
7139 
7140  if (discsurf.type() == Trk::SurfaceType::Disc && discsurf.center().z() * discsurf.normal().z() < 0) {
7141  endfactor = endlayer->layerMaterialProperties()->oppositePreFactor();
7142  }
7143 
7144  if (endfactor > 0.5) {
7145  std::unique_ptr<const TrackParameters> updatedpar = m_matupdator->update(
7146  lastmeasstate->trackParameters(), *endlayer, alongMomentum, matEffects
7147  );
7148 
7149  if (updatedpar != nullptr) {
7150  lastmeasstate->setTrackParameters(std::move(updatedpar));
7151  }
7152  }
7153  }
7154 
7155  if (prevpar != nullptr) {
7156  per = m_propagator->propagate(
7157  ctx,
7158  *prevpar,
7159  PerigeeSurface(Amg::Vector3D(0, 0, 0)),
7161  false,
7162  oldtrajectory.m_fieldprop,
7164  );
7165  }
7166 
7167  if (per == nullptr) {
7168  ATH_MSG_DEBUG("Failed to extrapolate to perigee, returning 0");
7171  return nullptr;
7172  }
7173  } else if (cache.m_acceleration && (firstmeasstate->trackParameters() != nullptr)) {
7174  per = m_extrapolator->extrapolate(ctx,
7175  *firstmeasstate->trackParameters(),
7176  PerigeeSurface(Amg::Vector3D(0, 0, 0)),
7178  false,
7179  matEffects);
7180  } else {
7181  per.reset(oldtrajectory.referenceParameters()->clone());
7182  }
7183 
7184  return per;
7185  }
7186 
7187  std::unique_ptr<GXFTrackState>
7189  const EventContext & ctx,
7190  Cache &cache,
7191  GXFTrajectory &oldtrajectory,
7192  const ParticleHypothesis matEffects
7193  ) const {
7194  std::unique_ptr<const TrackParameters> per = makeTrackFindPerigeeParameters(ctx, cache, oldtrajectory, matEffects);
7195 
7196  if (per == nullptr) {
7197  return nullptr;
7198  }
7199 
7200  ATH_MSG_DEBUG("Final perigee: " << *per << " pos: " << per->position() << " pT: " << per->pT());
7201 
7202  return std::make_unique<GXFTrackState>(std::move(per), TrackStateOnSurface::Perigee);
7203  }
7204 
7206  const std::vector<std::unique_ptr<TrackParameters>> & hc,
7207  std::set<Identifier> & id_set,
7208  std::set<Identifier> & sct_set,
7209  TrackHoleCount & rv,
7210  bool count_holes,
7211  bool count_dead
7212  ) const {
7213  /*
7214  * Our input is a list of track states, which we are iterating over. We
7215  * need to examine each one and update the values in our track hole count
7216  * accordingly.
7217  */
7218  for (const std::unique_ptr<TrackParameters> & tp : hc) {
7219  /*
7220  * It is possible, expected even, for some of these pointers to be null.
7221  * In those cases, it would be dangerous to continue, so we need to make
7222  * sure we skip them.
7223  */
7224  if (tp == nullptr) {
7225  continue;
7226  }
7227 
7228  /*
7229  * Extract the detector element of the track parameter surface for
7230  * examination. If for whatever reason there is none (i.e. the surface
7231  * is not a detector at all), we can skip it and continue.
7232  */
7233  const TrkDetElementBase * de = tp->associatedSurface().associatedDetectorElement();
7234 
7235  if (de == nullptr) {
7236  continue;
7237  }
7238 
7239  Identifier const id = de->identify();
7240 
7241  /*
7242  * If, for whatever reason, we have already visited this detector, we do
7243  * not want to visit it again. Otherwise we might end up with modules
7244  * counted twice, and that would be very bad.
7245  */
7246  if (id_set.find(id) != id_set.end()) {
7247  continue;
7248  }
7249 
7250  /*
7251  * This is the meat of the pudding, we use the boundary checking tool
7252  * to see whether this set of parameters is a hole candidate, a dead
7253  * module, or not a hole at all.
7254  */
7255  BoundaryCheckResult const bc = m_boundaryCheckTool->boundaryCheck(*tp);
7256 
7257  if (bc == BoundaryCheckResult::DeadElement && count_dead) {
7258  /*
7259  * If the module is dead, our job is very simple. We just check
7260  * whether it is a Pixel or an SCT and increment the appropriate
7261  * counter. We also insert the module into our set of visited elements.
7262  */
7263  if (m_DetID->is_pixel(id)) {
7264  ++rv.m_pixel_dead;
7265  } else if (m_DetID->is_sct(id)) {
7266  ++rv.m_sct_dead;
7267  }
7268  id_set.insert(id);
7269  } else if (bc == BoundaryCheckResult::Candidate && count_holes) {
7270  /*
7271  * If the module is a candidate, it's much the same, but we also need
7272  * to handle double SCT holes.
7273  */
7274  if (m_DetID->is_pixel(id)) {
7275  ++rv.m_pixel_hole;
7276  } else if (m_DetID->is_sct(id)) {
7277  ++rv.m_sct_hole;
7278 
7279  /*
7280  * To check for SCT double holes, we need to first fetch the other
7281  * side of the current SCT. Thankfully, the detector description
7282  * makes this very easy.
7283  */
7284  const InDetDD::SiDetectorElement* e = dynamic_cast<const InDetDD::SiDetectorElement *>(de);
7285  const Identifier os = e->otherSide()->identify();
7286 
7287  /*
7288  * We keep a special set containing only SCT hole IDs. We simply
7289  * check whether the ID of the other side of the SCT is in this set
7290  * to confirm that we have a double hole. Note that the first side
7291  * in a double hole will be counted as a SCT hole only, and the
7292  * second side will count as another hole as well as a double hole,
7293  * which is exactly the behaviour we would expect to see.
7294  */
7295  if (sct_set.find(os) != sct_set.end()) {
7296  ++rv.m_sct_double_hole;
7297  }
7298 
7299  /*
7300  * We need to add our SCT to the SCT identifier set if it is a
7301  * candidate hit, otherwise known as a hole in this context.
7302  */
7303  sct_set.insert(id);
7304  }
7305 
7306  /*
7307  * SCTs are also added to the set of all identifiers to avoid double
7308  * counting them.
7309  */
7310  id_set.insert(id);
7311  }
7312  }
7313  }
7314 
7315  std::vector<std::reference_wrapper<GXFTrackState>> GlobalChi2Fitter::holeSearchStates(
7316  GXFTrajectory & trajectory
7317  ) const {
7318  /*
7319  * Firstly, we will need to find the last measurement state on our track.
7320  * This will allow us to break the main loop later once we are done with
7321  * our work.
7322  */
7323  GXFTrackState * lastmeas = nullptr;
7324 
7325  for (const std::unique_ptr<GXFTrackState> & s : trajectory.trackStates()) {
7326  if (s->getStateType(TrackStateOnSurface::Measurement)) {
7327  lastmeas = s.get();
7328  }
7329  }
7330 
7331  /*
7332  * We create a vector of reference wrappers and reserve at least enough
7333  * space to contain the entire trajectory. This is perhaps a little
7334  * wasteful since we will never need this much space, but it may be more
7335  * efficient than taking the resizing pentalty on the chin.
7336  */
7337  std::vector<std::reference_wrapper<GXFTrackState>> rv;
7338  rv.reserve(trajectory.trackStates().size());
7339 
7340  /*
7341  * The main body of our method now. We iterate over all track states in
7342  * the track, at least until we find the last measurement state as found
7343  * above.
7344  */
7345  for (const std::unique_ptr<GXFTrackState> & s : trajectory.trackStates()) {
7346  /*
7347  * We are only interested in collecting measurements, perigees, and any
7348  * outlier states.
7349  */
7350  if (
7351  s->getStateType(TrackStateOnSurface::Measurement) ||
7352  s->getStateType(TrackStateOnSurface::Perigee) ||
7353  s->getStateType(TrackStateOnSurface::Outlier)
7354  ) {
7355  /*
7356  * We store a reference to the current track state in our return value
7357  * vector.
7358  */
7359  rv.emplace_back(*s);
7360 
7361  /*
7362  * We want to make sure we do not collect any TRT results or other
7363  * non-SCT and non-Pixel detector types. For that, we need to access
7364  * the details of the detector element and determine the detector type.
7365  */
7366  const TrkDetElementBase * de = s->trackParameters()->associatedSurface().associatedDetectorElement();
7367 
7368  if (de != nullptr) {
7369  Identifier const id = de->identify();
7370 
7371  if (!m_DetID->is_pixel(id) && !m_DetID->is_sct(id)) {
7372  break;
7373  }
7374  }
7375 
7376  /*
7377  * We also have no interest in going past the final measurement, so we
7378  * break out of the loop if we find it.
7379  */
7380  //cppcheck-suppress iterators3
7381  if (s.get() == lastmeas) {
7382  break;
7383  }
7384  }
7385  }
7386 
7387  return rv;
7388  }
7389 
7390  std::optional<GlobalChi2Fitter::TrackHoleCount> GlobalChi2Fitter::holeSearchProcess(
7391  const EventContext & ctx,
7392  const std::vector<std::reference_wrapper<GXFTrackState>> & states
7393  ) const {
7394  /*
7395  * Firstly, we need to guard against tracks having too few measurement
7396  * states to perform a good hole search. This is a mechanism that we
7397  * inherit from the reference hole search. If we have too few states, we
7398  * return a non-extant result to indicate an error state.
7399  *
7400  * TODO: The minimum value of 3 is also borrowed from the reference
7401  * implementation. It's hardcoded for now, but could be a parameter in the
7402  * future.
7403  */
7404  constexpr uint min_meas = 3;
7405  if (std::count_if(states.begin(), states.end(), [](const GXFTrackState & s){ return s.getStateType(TrackStateOnSurface::Measurement); }) < min_meas) {
7406  return {};
7407  }
7408 
7409  bool seen_meas = false;
7411  std::set<Identifier> id_set;
7412  std::set<Identifier> sct_set;
7413 
7414  /*
7415  * Using an old-school integer-based for loop because we need to iterate
7416  * over successive pairs of states to do an extrapolation between.
7417  */
7418  for (std::size_t i = 0; i < states.size() - 1; i++) {
7419  /*
7420  * Gather references to the state at the beginning of the extrapolation,
7421  * named beg, and the end, named end.
7422  */
7423  GXFTrackState & beg = states[i];
7424  GXFTrackState const& end = states[i + 1];
7425 
7426  /*
7427  * Update the boolean keeping track of whether we have seen a measurement
7428  * or outlier yet. Once we see one, this will remain true forever, but
7429  * it helps us make sure we don't collect holes before the first
7430  * measurement.
7431  */
7432  seen_meas |= beg.getStateType(TrackStateOnSurface::Measurement) || beg.getStateType(TrackStateOnSurface::Outlier);
7433 
7434  /*
7435  * Calculate the distance between the position of the starting parameters
7436  * and the end parameters. If this distance is sufficiently small, there
7437  * can be no elements between them (for example, between two SCTs), and
7438  * we don't need to do an extrapolation. This can easily save us a few
7439  * microseconds.
7440  */
7441  const double dist = (beg.trackParameters()->position() - end.trackParameters()->position()).norm();
7442 
7443  const bool zStartValid = std::abs(beg.trackParameters()->position().z())<10000.;
7444  if(!zStartValid){
7445  ATH_MSG_DEBUG("Pathological track parameter well outside of detector");
7446  ATH_MSG_DEBUG("Propagator might have issue with this, skipping");
7447  ATH_MSG_VERBOSE("dumping track parameters " << *(beg.trackParameters()));
7448  }
7449 
7450  /*
7451  * Only proceed to count holes if we have seen a measurement before (this
7452  * may include the starting track state, if it is a measurement) and the
7453  * distance between start and end is at least 2.5 millimeters
7454  * and the z position is valid
7455  */
7456  if (seen_meas && dist >= 2.5 && zStartValid) {
7457  /*
7458  * First, we retrieve the hole data stored in the beginning state. Note
7459  * that this may very well be non-extant, but it is possible for the
7460  * fitter to have deposited some hole information into the track state
7461  * earlier on in the fitting process.
7462  */
7463  std::optional<std::vector<std::unique_ptr<TrackParameters>>> & hc = beg.getHoles();
7464  std::vector<std::unique_ptr<TrackParameters>> states;
7465 
7466  /*
7467  * Gather the track states between the start and end of the
7468  * extrapolation. If the track state contained hole search information,
7469  * we simply move that out and use it. If there was no information, we
7470  * do a fresh extrapolation. This can be a CPU hog!
7471  */
7472  if (hc.has_value()) {
7473  states = std::move(*hc);
7474  } else {
7475  states = holesearchExtrapolation(ctx, *beg.trackParameters(), end, alongMomentum);
7476  }
7477 
7478  /*
7479  * Finally, we process the collected hole candidate states, checking
7480  * them for liveness and other properties. This helper function will
7481  * increment the values in rv accordingly.
7482  */
7483  holeSearchHelper(states, id_set, sct_set, rv, true, true);
7484  }
7485  }
7486 
7487  /*
7488  * Once we are done processing our measurements, we also need to do a
7489  * final blind extrapolation to collect and dead modules (but not holes)
7490  * behind the last measurement. For this, we do a blind extrapolation
7491  * from the final state.
7492  */
7493  GXFTrackState const& last = states.back();
7494 
7495  /*
7496  * To do the blind extrapolation, we need to have a set of track parameters
7497  * for our last measurement state. We also check whether the position of
7498  * the last measurement is still inside the inner detector. If it is not,
7499  * we don't need to blindly extrapolate because we're only interested in
7500  * collecting inner detector dead modules. This check saves us a few tens
7501  * of microseconds.
7502  */
7503  if (
7504  last.trackParameters() != nullptr &&
7506  ) {
7507  /*
7508  * Simply conduct the blind extrapolation, and then use the helper tool
7509  * to ensure that the hole counts are updated.
7510  */
7511  std::vector<std::unique_ptr<Trk::TrackParameters>> const bl = m_extrapolator->extrapolateBlindly(
7512  ctx,
7513  *last.trackParameters(),
7515  false,
7516  Trk::pion,
7517  &m_idVolume
7518  );
7519 
7520  /*
7521  * Note that we have flipped one of the boolean parameters of the helper
7522  * method here to make sure it only collects dead modules, not hole
7523  * candidates.
7524  */
7525  holeSearchHelper(bl, id_set, sct_set, rv, false, true);
7526  }
7527 
7528  return rv;
7529  }
7530 
7531  std::unique_ptr<Track> GlobalChi2Fitter::makeTrack(
7532  const EventContext & ctx,
7533  Cache & cache,
7534  GXFTrajectory & oldtrajectory,
7535  ParticleHypothesis matEffects
7536  ) const {
7537  // Convert internal trajectory into track
7538  auto trajectory = std::make_unique<Trk::TrackStates>();
7539 
7540  if (m_fillderivmatrix) {
7541  makeTrackFillDerivativeMatrix(cache, oldtrajectory);
7542  }
7543 
7544  GXFTrajectory tmptrajectory(oldtrajectory);
7545 
7546  std::unique_ptr<GXFTrackState> perigee_ts = makeTrackFindPerigee(ctx, cache, oldtrajectory, matEffects);
7547 
7548  if (perigee_ts == nullptr) {
7549  return nullptr;
7550  }
7551 
7552  tmptrajectory.addBasicState(std::move(perigee_ts), cache.m_acceleration ? 0 : tmptrajectory.numberOfUpstreamStates());
7553  //reserve the ouput size
7554  trajectory->reserve(tmptrajectory.trackStates().size());
7555  for (auto & hit : tmptrajectory.trackStates()) {
7556  if (
7557  hit->measurementType() == TrackState::Pseudo &&
7558  hit->getStateType(TrackStateOnSurface::Outlier)
7559  ) {
7560  hit->resetTrackCovariance();
7561  continue;
7562  }
7563 
7564  if (!Trk::consistentSurfaces (hit->trackParameters(),
7565  hit->measurement(),
7566  hit->materialEffects()))
7567  {
7568  return nullptr;
7569  }
7570 
7571  //should check hit->isSane() here with better equality check(other than ptr comparison)
7572  auto trackState = hit->trackStateOnSurface();
7573  hit->resetTrackCovariance();
7574  trajectory->emplace_back(trackState.release());
7575  }
7576 
7577  auto qual = std::make_unique<FitQuality>(tmptrajectory.chi2(), tmptrajectory.nDOF());
7578 
7579 
7580  TrackInfo info;
7581 
7582  if (matEffects != electron) {
7584  } else {
7586  info.setTrackProperties(TrackInfo::BremFit);
7587 
7588  if (matEffects == electron && tmptrajectory.hasKink()) {
7589  info.setTrackProperties(TrackInfo::BremFitSuccessful);
7590  }
7591  }
7592 
7593  if (tmptrajectory.m_straightline) {
7594  info.setTrackProperties(TrackInfo::StraightTrack);
7595  }
7596 
7597  std::unique_ptr<Track> rv = std::make_unique<Track>(info, std::move(trajectory), std::move(qual));
7598 
7599  /*
7600  * Here, we create a track summary and attach it to our newly created
7601  * track. Note that this code only runs if the m_createSummary Gaudi
7602  * property is set. In cases where having a track summary on the track is
7603  * not desired, such as for compatibility with other tools, this can be
7604  * turned off.
7605  */
7606  if (m_createSummary.value()) {
7607  std::unique_ptr<TrackSummary> ts = std::make_unique<TrackSummary>();
7608 
7609  /*
7610  * This segment determines the hole search behaviour of the track fitter.
7611  * It is only invoked if the DoHoleSearch parameter is set, but it can
7612  * take a significant amount of CPU time, since the hole search is rather
7613  * expensive. Beware of that!
7614  */
7615  if (m_holeSearch.value()) {
7616  std::optional<TrackHoleCount> hole_count;
7617 
7618  /*
7619  * First, we collect a list of states that will act as our hole search
7620  * extrapolation states. This will serve as our source of truth in
7621  * regards to which track states we need to extrapolate between.
7622  */
7623  std::vector<std::reference_wrapper<GXFTrackState>> const states = holeSearchStates(tmptrajectory);
7624 
7625  /*
7626  * Then, collect the actual hole search infomation using our state list
7627  * from before. This is the expensive operation, as it will invoke a
7628  * series of extrapolations if not all states have existing hole
7629  * information! It will also check all the hole candidates to see if
7630  * they are actually holes or not.
7631  */
7632  hole_count = holeSearchProcess(ctx, states);
7633 
7634  /*
7635  * Note that the hole search is not guaranteed to return a useful set
7636  * of values. It can, for example, reach an error state if the number
7637  * of measurements on a track is below a certain threshold. In that
7638  * case, a non-extant result will be returned, which we must guard
7639  * against. In that case, the hole counts will remain unset.
7640  */
7641  if (hole_count.has_value()) {
7642  /*
7643  * If the hole search did return good results, we can proceed to
7644  * simply copy the numerical values in the track summary.
7645  */
7646  ts->update(Trk::numberOfPixelHoles, hole_count->m_pixel_hole);
7647  ts->update(Trk::numberOfSCTHoles, hole_count->m_sct_hole);
7648  ts->update(Trk::numberOfSCTDoubleHoles, hole_count->m_sct_double_hole);
7649  ts->update(Trk::numberOfPixelDeadSensors, hole_count->m_pixel_dead);
7650  ts->update(Trk::numberOfSCTDeadSensors, hole_count->m_sct_dead);
7651  }
7652  }
7653 
7654  rv->setTrackSummary(std::move(ts));
7655  }
7656 
7657  return rv;
7658  }
7659 
7660  GlobalChi2Fitter::~GlobalChi2Fitter() = default;
7661 
7662  std::vector<std::unique_ptr<TrackParameters>> GlobalChi2Fitter::holesearchExtrapolation(
7663  const EventContext & ctx,
7664  const TrackParameters & src,
7665  const GXFTrackState & dst,
7666  PropDirection propdir
7667  ) const {
7668  /*
7669  * First, we conduct a bog standard stepwise extrapolation. This will
7670  * yield some unwanted results, but we will filter those later.
7671  */
7672  std::vector<std::unique_ptr<TrackParameters>> rv = m_extrapolator->extrapolateStepwise(
7673  ctx, src, dst.associatedSurface(), propdir, false
7674  );
7675 
7676  /*
7677  * It is possible for the first returned track parameter to be on the same
7678  * surface as we started on. That's probably due to some rounding errors.
7679  * We check for this possibility, and set the pointer to null if it
7680  * occurs. Note that this leaves some null pointers in the returned vector
7681  * but this is more performant compared to removing them properly.
7682  */
7683  if (
7684  !rv.empty() && (
7685  &rv.front()->associatedSurface() == &dst.associatedSurface() ||
7686  &rv.front()->associatedSurface() == &src.associatedSurface() ||
7687  trackParametersClose(*rv.front(), src, 0.001) ||
7688  trackParametersClose(*rv.front(), *dst.trackParameters(), 0.001)
7689  )
7690  ) {
7691  rv.front().reset(nullptr);
7692  }
7693 
7694  /*
7695  * Same logic, but for the last returned element. In that case, we get a
7696  * set of parameters on the destination surface, which we also do not
7697  * want.
7698  */
7699  if (
7700  rv.size() > 1 && (
7701  &rv.back()->associatedSurface() == &dst.associatedSurface() ||
7702  &rv.back()->associatedSurface() == &src.associatedSurface() ||
7703  trackParametersClose(*rv.back(), src, 0.001) ||
7704  trackParametersClose(*rv.back(), *dst.trackParameters(), 0.001)
7705  )
7706  ) {
7707  rv.back().reset(nullptr);
7708  }
7709 
7710  return rv;
7711  }
7712 
7714  const EventContext & ctx,
7715  const TrackParameters & prev,
7716  const GXFTrackState & ts,
7717  PropDirection propdir,
7718  const MagneticFieldProperties& bf,
7719  bool calcderiv,
7720  bool holesearch
7721  ) const {
7722  std::unique_ptr<const TrackParameters> rv;
7723  std::optional<TransportJacobian> jac{};
7724 
7725  if (calcderiv && !m_numderiv) {
7726  rv = m_propagator->propagateParameters(
7727  ctx, prev, ts.associatedSurface(), propdir, false, bf, jac, Trk::nonInteracting, false
7728  );
7729  } else {
7730  rv = m_propagator->propagateParameters(
7731  ctx, prev, ts.associatedSurface(), propdir, false, bf, Trk::nonInteracting, false
7732  );
7733 
7734  if (rv != nullptr && calcderiv) {
7735  jac = numericalDerivatives(ctx, &prev, ts.associatedSurface(), propdir, bf);
7736  }
7737  }
7738 
7739  std::optional<std::vector<std::unique_ptr<TrackParameters>>> extrapolation;
7740 
7741  if (holesearch) {
7742  extrapolation = holesearchExtrapolation(ctx, prev, ts, propdir);
7743  }
7744 
7745  return PropagationResult {
7746  std::move(rv),
7747  std::move(jac),
7748  std::move(extrapolation)
7749  };
7750  }
7751 
7753  const EventContext & ctx,
7754  const TrackParameters & prev,
7755  const GXFTrackState & ts,
7756  PropDirection propdir,
7757  const MagneticFieldProperties& bf,
7758  bool calcderiv,
7759  bool holesearch
7760  ) const {
7762 
7764  ctx, prev, ts, propdir, bf, calcderiv, holesearch
7765  );
7766 
7767  if (rv.m_parameters == nullptr) {
7768  propdir = invertPropdir(propdir);
7769 
7771  ctx, prev, ts, propdir, bf, calcderiv, holesearch
7772  );
7773  }
7774 
7775  return rv;
7776  }
7777 
7779  const EventContext& ctx,
7780  GXFTrajectory & trajectory,
7781  bool calcderiv
7782  ) const {
7783  // Loop over states, calculate track parameters and (optionally) jacobian at each state
7784  ATH_MSG_DEBUG("CalculateTrackParameters");
7785 
7786  std::vector<std::unique_ptr<GXFTrackState>> & states = trajectory.trackStates();
7787  const int nstatesupstream = trajectory.numberOfUpstreamStates();
7788  const TrackParameters *prevtrackpar = trajectory.referenceParameters();
7789  std::unique_ptr<const TrackParameters> tmptrackpar;
7790 
7791  for (int hitno = nstatesupstream - 1; hitno >= 0; hitno--) {
7792  const Surface &surf1 = states[hitno]->associatedSurface();
7794 
7795  const DistanceSolution distsol = surf1.straightLineDistanceEstimate(
7796  prevtrackpar->position(), prevtrackpar->momentum().unit()
7797  );
7798 
7799  const double distance = getDistance(distsol);
7800 
7801  if (
7802  distance > 0 &&
7803  distsol.numberOfSolutions() > 0 &&
7804  prevtrackpar != trajectory.referenceParameters()
7805  ) {
7806  propdir = Trk::alongMomentum;
7807  }
7808 
7810  ctx,
7811  *prevtrackpar,
7812  *states[hitno],
7813  propdir,
7814  trajectory.m_fieldprop,
7815  calcderiv,
7816  false
7817  );
7818 
7819  if (
7820  propdir == Trk::alongMomentum &&
7821  (rv.m_parameters != nullptr) &&
7822  (prevtrackpar->position() - rv.m_parameters->position()).mag() > 5 * mm
7823  ) {
7824  ATH_MSG_DEBUG("Propagation in wrong direction");
7825 
7826  }
7827 
7828  if (rv.m_parameters == nullptr) {
7829  ATH_MSG_DEBUG("propagation failed, prev par: " << *prevtrackpar <<
7830  " pos: " << prevtrackpar->position() << " destination surface: " << surf1);
7832  }
7833 
7834  states[hitno]->setTrackParameters(std::move(rv.m_parameters));
7835  const TrackParameters *currenttrackpar = states[hitno]->trackParameters();
7836  const Surface &surf = states[hitno]->associatedSurface();
7837 
7838  if (rv.m_jacobian != std::nullopt) {
7839  if (
7840  states[hitno]->materialEffects() != nullptr &&
7841  states[hitno]->materialEffects()->deltaE() != 0 &&
7842  states[hitno]->materialEffects()->sigmaDeltaE() <= 0 &&
7843  !trajectory.m_straightline
7844  ) {
7845  const double p = 1. / std::abs(currenttrackpar->parameters()[Trk::qOverP]);
7846  const double de = std::abs(states[hitno]->materialEffects()->deltaE());
7847  const double mass = trajectory.mass();
7848  const double newp = std::sqrt(p * p + 2 * de * std::sqrt(mass * mass + p * p) + de * de);
7849  (*rv.m_jacobian) (4, 4) = ((p + p * de / std::sqrt(p * p + mass * mass)) / newp) * p * p / (newp * newp);
7850  }
7851 
7852  states[hitno]->setJacobian(*rv.m_jacobian);
7853  } else if (calcderiv) {
7854  ATH_MSG_WARNING("Jacobian is null");
7856  }
7857 
7858  GXFMaterialEffects *meff = states[hitno]->materialEffects();
7859 
7860  if (meff != nullptr && hitno != 0) {
7861  std::variant<std::unique_ptr<const TrackParameters>, FitterStatusCode> r = updateEnergyLoss(
7862  surf, *meff, *states[hitno]->trackParameters(), trajectory.mass(), -1
7863  );
7864 
7865  if (std::holds_alternative<FitterStatusCode>(r)) {
7866  return std::get<FitterStatusCode>(r);
7867  }
7868 
7869  tmptrackpar = std::move(std::get<std::unique_ptr<const TrackParameters>>(r));
7870  prevtrackpar = tmptrackpar.get();
7871  } else {
7872  prevtrackpar = currenttrackpar;
7873  }
7874  }
7875 
7876  prevtrackpar = trajectory.referenceParameters();
7877 
7878  for (int hitno = nstatesupstream; hitno < (int) states.size(); hitno++) {
7879  const Surface &surf = states[hitno]->associatedSurface();
7881  const DistanceSolution distsol = surf.straightLineDistanceEstimate(prevtrackpar->position(), prevtrackpar->momentum().unit());
7882 
7883  const double distance = getDistance(distsol);
7884 
7885  if (distance < 0 && distsol.numberOfSolutions() > 0 && prevtrackpar != trajectory.referenceParameters()) {
7886  propdir = Trk::oppositeMomentum;
7887  }
7888 
7890  ctx,
7891  *prevtrackpar,
7892  *states[hitno],
7893  propdir,
7894  trajectory.m_fieldprop,
7895  calcderiv,
7896  false
7897  );
7898 
7899  if (
7900  (rv.m_parameters != nullptr) &&
7901  propdir == Trk::oppositeMomentum &&
7902  (prevtrackpar->position() - rv.m_parameters->position()).mag() > 5 * mm
7903  ) {
7904  ATH_MSG_DEBUG("Propagation in wrong direction");
7905  }
7906 
7907  if (rv.m_parameters == nullptr) {
7908  ATH_MSG_DEBUG("propagation failed, prev par: " << *prevtrackpar <<
7909  " pos: " << prevtrackpar->
7910  position() << " destination surface: " << surf);
7912  }
7913 
7914  if (rv.m_jacobian != std::nullopt) {
7915  if (
7916  states[hitno]->materialEffects() != nullptr &&
7917  states[hitno]->materialEffects()->deltaE() != 0 &&
7918  states[hitno]->materialEffects()->sigmaDeltaE() <= 0 &&
7919  !trajectory.m_straightline
7920  ) {
7921  const double p = 1 / std::abs(rv.m_parameters->parameters()[Trk::qOverP]);
7922  const double de = std::abs(states[hitno]->materialEffects()->deltaE());
7923  const double mass = trajectory.mass();
7924  double newp = p * p - 2 * de * std::sqrt(mass * mass + p * p) + de * de;
7925 
7926  if (newp > 0) {
7927  newp = std::sqrt(newp);
7928  }
7929 
7930  (*rv.m_jacobian) (4, 4) = ((p - p * de / std::sqrt(p * p + mass * mass)) / newp) * p * p / (newp * newp);
7931  }
7932 
7933  states[hitno]->setJacobian(*rv.m_jacobian);
7934  } else if (calcderiv) {
7935  ATH_MSG_WARNING("Jacobian is null");
7937  }
7938 
7939  GXFMaterialEffects *meff = states[hitno]->materialEffects();
7940 
7941  if (meff != nullptr) {
7942  std::variant<std::unique_ptr<const TrackParameters>, FitterStatusCode> r = updateEnergyLoss(
7943  surf, *meff, *rv.m_parameters, trajectory.mass(), +1
7944  );
7945 
7946  if (std::holds_alternative<FitterStatusCode>(r)) {
7947  return std::get<FitterStatusCode>(r);
7948  }
7949 
7950  rv.m_parameters = std::move(std::get<std::unique_ptr<const TrackParameters>>(r));
7951  }
7952 
7953  states[hitno]->setTrackParameters(std::move(rv.m_parameters));
7954  prevtrackpar = states[hitno]->trackParameters();
7955  }
7956 
7958  }
7959 
7960  std::variant<std::unique_ptr<const TrackParameters>, FitterStatusCode> GlobalChi2Fitter::updateEnergyLoss(
7961  const Surface & surf,
7962  const GXFMaterialEffects & meff,
7963  const TrackParameters & param,
7964  double mass,
7965  int sign
7966  ) const {
7967  const AmgVector(5) & old = param.parameters();
7968 
7969  double newphi = old[Trk::phi0] + sign * meff.deltaPhi();
7970  double newtheta = old[Trk::theta] + sign * meff.deltaTheta();
7971 
7972  if (!correctAngles(newphi, newtheta)) {
7973  ATH_MSG_DEBUG("Angles out of range, phi: " << newphi << " theta: " << newtheta);
7975  }
7976 
7977  double newqoverp = 0;
7978 
7979  if (meff.sigmaDeltaE() <= 0) {
7980  if (std::abs(old[Trk::qOverP]) < 1.e-12) {
7981  newqoverp = 0.;
7982  } else {
7983  const double oldp = std::abs(1 / old[Trk::qOverP]);
7984  const double newp2 = oldp * oldp - sign * 2 * std::abs(meff.deltaE()) * std::sqrt(mass * mass + oldp * oldp) + meff.deltaE() * meff.deltaE();
7985 
7986  if (newp2 < 0) {
7987  ATH_MSG_DEBUG("Track killed by energy loss update");
7989  }
7990 
7991  newqoverp = std::copysign(1 / std::sqrt(newp2), old[Trk::qOverP]);
7992  }
7993  } else {
7994  newqoverp = old[Trk::qOverP] + sign * .001 * meff.delta_p();
7995  }
7996 
7997  return surf.createUniqueTrackParameters(
7998  old[0], old[1], newphi, newtheta, newqoverp, std::nullopt
7999  );
8000  }
8001 
8003  const int nstatesupstream = trajectory.numberOfUpstreamStates();
8004  const int nscatupstream = trajectory.numberOfUpstreamScatterers();
8005  const int nbremupstream = trajectory.numberOfUpstreamBrems();
8006  const int nscats = trajectory.numberOfScatterers();
8007  const int nperpars = trajectory.numberOfPerigeeParameters();
8008  const int nfitpars = trajectory.numberOfFitParameters();
8009 
8010  using Matrix55 = Eigen::Matrix<double, 5, 5>;
8011 
8012  Matrix55 initialjac;
8013  initialjac.setZero();
8014  initialjac(4, 4) = 1;
8015 
8016  Matrix55 jacvertex(initialjac);
8017 
8018  std::vector<Matrix55, Eigen::aligned_allocator<Matrix55>> jacscat(trajectory.numberOfScatterers(), initialjac);
8019  std::vector<Matrix55, Eigen::aligned_allocator<Matrix55>> jacbrem(trajectory.numberOfBrems(), initialjac);
8020 
8021  std::vector<std::unique_ptr<GXFTrackState>> & states = trajectory.trackStates();
8022  GXFTrackState *prevstate = nullptr;
8023  GXFTrackState *state = nullptr;
8024 
8025  int hit_begin = 0;
8026  int hit_end = 0;
8027  int scatno = 0;
8028  int bremno = 0;
8029 
8030  for (const bool forward : {false, true}) {
8031  if (forward) {
8032  hit_begin = nstatesupstream;
8033  hit_end = (int) states.size();
8034  scatno = nscatupstream;
8035  bremno = nbremupstream;
8036  } else {
8037  hit_begin = nstatesupstream - 1;
8038  hit_end = 0;
8039  scatno = trajectory.numberOfUpstreamScatterers() - 1;
8040  bremno = trajectory.numberOfUpstreamBrems() - 1;
8041  }
8042 
8043  for (
8044  int hitno = hit_begin;
8045  forward ? (hitno < hit_end) : (hitno >= hit_end);
8046  hitno += (forward ? 1 : -1)
8047  ) {
8048 
8049  state = states[hitno].get();
8050 
8051  const bool fillderivmat = (!state->getStateType(TrackStateOnSurface::Scatterer) && !state->getStateType(TrackStateOnSurface::BremPoint));
8052 
8053  if (fillderivmat && state->derivatives().cols() != nfitpars) {
8054  state->derivatives().resize(5, nfitpars);
8055  state->derivatives().setZero();
8056  }
8057 
8058  int jminscat = 0;
8059  int jmaxscat = 4;
8060  int jminbrem = 0;
8061  const int jmaxbrem = 4;
8062 
8063  if (hitno == (forward ? hit_end - 1 : 0)) {
8064  if (!fillderivmat) {
8065  break;
8066  }
8067  jminscat = 2;
8068  jmaxscat = 3;
8069  jminbrem = 4;
8070  }
8071 
8072  Eigen::Matrix<double, 5, 5> & jac = state->jacobian();
8073 
8074  if (hitno == nstatesupstream + (forward ? 0 : -1)) {
8075  jacvertex.block<4, 5>(0, 0) = jac.block<4, 5>(0, 0);
8076  jacvertex(4, 4) = jac(4, 4);
8077  } else {
8078  int jmin = 0;
8079  int jmax = 0;
8080  int jcnt = 0;
8081  int lp_bgn = 0;
8082  int lp_end = 0;
8083 
8084  jmin = jminscat;
8085  jmax = jmaxscat;
8086  jcnt = jmax - jmin + 1;
8087 
8088  lp_bgn = forward ? nscatupstream : nscatupstream - 1;
8089  lp_end = scatno;
8090 
8091  for (int i = lp_bgn; forward ? (i < lp_end) : (i > lp_end); i += (forward ? 1 : -1)) {
8092  if (
8093  i == scatno + (forward ? -1 : 1) &&
8094  prevstate != nullptr &&
8096  (!trajectory.prefit() || prevstate->materialEffects()->deltaE() == 0)
8097  ) {
8098  jacscat[i].block(0, jmin, 4, jcnt) = jac.block(0, jmin, 4, jcnt);
8099  jacscat[i](4, 4) = jac(4, 4);
8100  } else {
8101  calculateJac(jac, jacscat[i], jmin, jmax);
8102  }
8103 
8104  if (fillderivmat) {
8105  Eigen::MatrixXd & derivmat = state->derivatives();
8106  const int scatterPos = nperpars + 2 * i;
8107 
8108  derivmat.block<4, 2>(0, scatterPos) = (forward ? 1 : -1) * jacscat[i].block<4, 2>(0, 2);
8109  }
8110  }
8111 
8112  jmin = jminbrem;
8113  jmax = jmaxbrem;
8114  jcnt = jmax - jmin + 1;
8115 
8116  lp_bgn = forward ? nbremupstream : nbremupstream - 1;
8117  lp_end = bremno;
8118 
8119  for (int i = lp_bgn; forward ? (i < lp_end) : (i > lp_end); i += (forward ? 1 : -1)) {
8120  if (
8121  i == bremno + (forward ? -1 : 1) &&
8122  prevstate &&
8123  prevstate->materialEffects() &&
8124  prevstate->materialEffects()->sigmaDeltaE() > 0
8125  ) {
8126  jacbrem[i].block(0, jmin, 4, jcnt) = jac.block(0, jmin, 4, jcnt);
8127  jacbrem[i](4, 4) = jac(4, 4);
8128  } else {
8129  calculateJac(jac, jacbrem[i], jmin, jmax);
8130  }
8131 
8132  if (fillderivmat) {
8133  Eigen::MatrixXd & derivmat = state->derivatives();
8134  const int scatterPos = nperpars + 2 * nscats + i;
8135 
8136  derivmat.block<5, 1>(0, scatterPos) = (forward ? .001 : -.001) * jacbrem[i].block<5, 1>(0, 4);
8137  }
8138  }
8139 
8140  calculateJac(jac, jacvertex, 0, 4);
8141  }
8142 
8143  if (fillderivmat) {
8144  Eigen::MatrixXd & derivmat = state->derivatives();
8145  derivmat.block(0, 0, 4, nperpars) = jacvertex.block(0, 0, 4, nperpars);
8146 
8147  if (nperpars == 5) {
8148  derivmat.col(4).segment(0, 4) *= .001;
8149  derivmat(4, 4) = .001 * jacvertex(4, 4);
8150  }
8151  }
8152 
8153  if (
8155  (!trajectory.prefit() || states[hitno]->materialEffects()->deltaE() == 0)
8156  ) {
8157  scatno += (forward ? 1 : -1);
8158  }
8159 
8160  if (
8161  states[hitno]->materialEffects() &&
8162  states[hitno]->materialEffects()->sigmaDeltaE() > 0
8163  ) {
8164  bremno += (forward ? 1 : -1);
8165  }
8166 
8167  prevstate = states[hitno].get();
8168  }
8169  }
8170  }
8171 
8172  void
8173 
8175  Amg::SymMatrixX & fullcovmat,
8176  bool onlylocal) const {
8177  //
8178  // Calculate track errors at each state, except scatterers and brems
8179  //
8180  ATH_MSG_DEBUG("CalculateTrackErrors");
8181 
8182  std::vector<std::unique_ptr<GXFTrackState>> & states = trajectory.trackStates();
8183  const int nstatesupstream = trajectory.numberOfUpstreamStates();
8184  std::vector < int >indices(states.size());
8185  GXFTrackState *prevstate = nullptr;
8186  int i = nstatesupstream;
8187  for (int j = 0; j < (int) states.size(); j++) {
8188  if (j < nstatesupstream) {
8189  i--;
8190  indices[j] = i;
8191  } else {
8192  indices[j] = j;
8193  }
8194  }
8195  for (int stateno = 0; stateno < (int) states.size(); stateno++) {
8196  if (stateno == 0 || stateno == nstatesupstream) {
8197  prevstate = nullptr;
8198  }
8199  const int index = indices[stateno];
8200  std::unique_ptr<GXFTrackState> & state = states[index];
8201  if (state->materialEffects() != nullptr) {
8202  prevstate = state.get();
8203  continue;
8204  }
8205 
8206  if (!state->hasTrackCovariance()) {
8207  state->zeroTrackCovariance();
8208  }
8209  AmgMatrix(5, 5) & trackerrmat = state->trackCovariance();
8210 
8211  if ((prevstate != nullptr) &&
8214  && !onlylocal) {
8215  Eigen::Matrix<double, 5, 5> & jac = state->jacobian();
8216  const AmgMatrix(5, 5)& prevcov = states[indices[stateno - 1]]->trackCovariance();
8217 
8218  trackerrmat = jac * prevcov * jac.transpose();
8219  } else {
8220  Amg::MatrixX & derivatives = state->derivatives();
8221 
8222  trackerrmat = derivatives * fullcovmat * derivatives.transpose();
8223  }
8224 
8225  if (!onlylocal) {
8226  const MeasurementBase *measurement = state->measurement();
8227  const Amg::MatrixX & meascov = measurement->localCovariance();
8228  int j = 0;
8229  int indices[5] = {
8230  -1, -1, -1, -1, -1
8231  };
8232  bool errorok = true;
8233  for (int i = 0; i < 5; i++) {
8235  if (state->getStateType(TrackStateOnSurface::Measurement)
8236  && trackerrmat(i, i) > meascov(j, j)) {
8237  errorok = false;
8238  const double scale = std::sqrt(meascov(j, j) / trackerrmat(i, i));
8239  trackerrmat(i, i) = meascov(j, j);
8240  for (int k = 0; k < 5; k++) {
8241  if (k != i) {
8242  trackerrmat(k, i) *= scale;
8243  }
8244  }
8245  indices[i] = j;
8246  }
8247  j++;
8248  }
8249  }
8250  for (int i = 0; i < 5; i++) {
8251  if (indices[i] == -1) {
8252  continue;
8253  }
8254  for (int j = 0; j < 5; j++) {
8255  if (indices[j] == -1) {
8256  continue;
8257  }
8258  trackerrmat(i, j) = meascov(indices[i], indices[j]);
8259  }
8260  }
8261  if (trajectory.m_straightline) {
8262  trackerrmat(4, 4) = 1e-20;
8263  }
8264 
8265  const TrackParameters *tmptrackpar =
8266  state->trackParameters();
8267 
8268  std::optional<AmgMatrix(5, 5)> trkerrmat;
8269 
8270  if (state->hasTrackCovariance()) {
8271  trkerrmat = (state->trackCovariance());
8272  } else {
8273  trkerrmat = std::nullopt;
8274  }
8275 
8276  const AmgVector(5) & tpars = tmptrackpar->parameters();
8277  std::unique_ptr<const TrackParameters> trackpar(
8278  tmptrackpar->associatedSurface().createUniqueTrackParameters(tpars[0],
8279  tpars[1],
8280  tpars[2],
8281  tpars[3],
8282  tpars[4],
8283  std::move(trkerrmat))
8284  );
8285  state->setTrackParameters(std::move(trackpar));
8286  FitQualityOnSurface fitQual{};
8287  if (state->getStateType(TrackStateOnSurface::Measurement)) {
8288  if (errorok && trajectory.nDOF() > 0) {
8289  fitQual = m_updator->fullStateFitQuality(
8290  *state->trackParameters(),
8291  measurement->localParameters(),
8292  measurement->localCovariance()
8293  );
8294  } else {
8295  fitQual = FitQualityOnSurface(0, state->numberOfMeasuredParameters());
8296  }
8297  }
8298  state->setFitQuality(fitQual);
8299  }
8300  prevstate = state.get();
8301  }
8302  }
8303 
8304  std::optional<TransportJacobian>
8306  const EventContext& ctx,
8307  const TrackParameters* prevpar,
8308  const Surface & surf,
8309  PropDirection propdir,
8310  const MagneticFieldProperties& fieldprop) const
8311  {
8312  double J[25] = {
8313  1, 0, 0, 0, 0,
8314  0, 1, 0, 0, 0,
8315  0, 0, 1, 0, 0,
8316  0, 0, 0, 1, 0,
8317  0, 0, 0, 0, 1
8318  };
8319  std::optional<TransportJacobian> jac = std::make_optional<TransportJacobian>(J);
8320  const TrackParameters *tmpprevpar = prevpar;
8321  double eps[5] = {
8322  0.01, 0.01, 0.00001, 0.00001, 0.000000001
8323  };
8324 
8325  const AmgVector(5) & vec = tmpprevpar->parameters();
8326 
8327  const bool cylsurf = surf.type() == Trk::SurfaceType::Cylinder;
8328  const bool discsurf = surf.type() == Trk::SurfaceType::Disc;
8329  const Surface & previousSurface = tmpprevpar->associatedSurface();
8330  const bool thiscylsurf = previousSurface.type() == Trk::SurfaceType::Cylinder;
8331  const bool thisdiscsurf = previousSurface.type() == Trk::SurfaceType::Disc;
8332 
8333  for (int i = 0; i < 5; i++) {
8334  AmgVector(5) vecpluseps = vec, vecminuseps = vec;
8335 
8336  if (thisdiscsurf && i == 1) {
8337  eps[i] /= vec[0];
8338  }
8339 
8340  vecpluseps[Trk::ParamDefsAccessor::pardef[i]] += eps[i];
8341  vecminuseps[Trk::ParamDefsAccessor::pardef[i]] -= eps[i];
8342  if (i == 0 && thiscylsurf) {
8343  vecminuseps[i] = -std::remainder(-vecminuseps[i], 2 * M_PI * previousSurface.bounds().r());
8344  } else if (i == 1 && thisdiscsurf) {
8345  vecpluseps[i] = -std::remainder(-vecpluseps[i], 2 * M_PI);
8346  }
8347  correctAngles(vecminuseps[Trk::phi], vecminuseps[Trk::theta]);
8348  correctAngles(vecpluseps[Trk::phi], vecpluseps[Trk::theta]);
8349 
8350  std::unique_ptr<const TrackParameters> parpluseps(
8352  vecpluseps[0],
8353  vecpluseps[1],
8354  vecpluseps[2],
8355  vecpluseps[3],
8356  vecpluseps[4],
8357  std::nullopt
8358  )
8359  );
8360  const std::unique_ptr<const TrackParameters> parminuseps(
8362  vecminuseps[0],
8363  vecminuseps[1],
8364  vecminuseps[2],
8365  vecminuseps[3],
8366  vecminuseps[4],
8367  std::nullopt
8368  )
8369  );
8370 
8371  std::unique_ptr<const TrackParameters> newparpluseps(
8372  m_propagator->propagateParameters(
8373  ctx,
8374  *parpluseps,
8375  surf,
8376  propdir,
8377  false,
8378  fieldprop,
8380  )
8381  );
8382  std::unique_ptr<const TrackParameters> newparminuseps(
8383  m_propagator->propagateParameters(
8384  ctx,
8385  *parminuseps,
8386  surf,
8387  propdir,
8388  false,
8389  fieldprop,
8391  )
8392  );
8393 
8394  const PropDirection propdir2 =
8395  (propdir ==
8397  if (newparpluseps == nullptr) {
8398  newparpluseps =
8399  m_propagator->propagateParameters(
8400  ctx,
8401  *parpluseps,
8402  surf,
8403  propdir2,
8404  false,
8405  fieldprop,
8407  );
8408  }
8409  if (newparminuseps == nullptr) {
8410  newparminuseps =
8411  m_propagator->propagateParameters(
8412  ctx,
8413  *parminuseps,
8414  surf,
8415  propdir2,
8416  false,
8417  fieldprop,
8419  );
8420  }
8421  if ((newparpluseps == nullptr) || (newparminuseps == nullptr)) {
8422  return nullptr;
8423  }
8424 
8425  for (int j = 0; j < 5; j++) {
8426  double diff = newparpluseps->parameters()[Trk::ParamDefsAccessor::pardef[j]] -
8427  newparminuseps->parameters()[Trk::ParamDefsAccessor::pardef[j]];
8428 
8429  if (j == 0 && cylsurf) {
8430  diff = -std::remainder(-diff, 2 * M_PI * surf.bounds().r());
8431  } else if (j == 1 && discsurf) {
8432  diff = -std::remainder(-diff, 2 * M_PI);
8433  }
8434 
8435  (*jac) (j, i) = diff / (2 * eps[i]);
8436  }
8437 
8438  }
8439  return jac;
8440  }
8441 
8442  int
8444  return 0;
8445  } void
8448  ("Configure the minimum number of Iterations via jobOptions");
8449  }
8450 
8451  bool
8453  if (theta > M_PI) {
8454  theta = M_PI - theta;
8455  phi += M_PI;
8456  }
8457  if (theta < 0) {
8458  theta = -theta;
8459  phi += M_PI;
8460  }
8461 
8462  phi = -std::remainder(-phi, 2 * M_PI);
8463 
8464  return theta >= 0 && theta <= M_PI && phi >= -M_PI && phi <= M_PI;
8465  }
8466 
8467  bool
8468  GlobalChi2Fitter::isMuonTrack(const Track & intrk1) const {
8469  const auto *pDataVector = intrk1.measurementsOnTrack();
8470  auto nmeas1 = pDataVector->size();
8471  const auto *pLastValue = (*pDataVector)[nmeas1 - 1];
8472  //
8473  const bool lastMeasIsRIO = pLastValue->type(Trk::MeasurementBaseType::RIO_OnTrack);
8474  const bool lastMeasIsCompetingRIO = pLastValue->type(Trk::MeasurementBaseType::CompetingRIOsOnTrack);
8475  //we only need the RIO on track pointer to be valid to identify
8476  const RIO_OnTrack *testrot{};
8477  //
8478  if (lastMeasIsRIO){
8479  testrot = static_cast<const RIO_OnTrack *>(pLastValue);
8480  } else {
8481  if (lastMeasIsCompetingRIO){
8482  const auto *testcrot = static_cast<const CompetingRIOsOnTrack*>(pLastValue);
8483  testrot = &testcrot->rioOnTrack(0);
8484  }
8485  }
8486  //still undefined, so try penultimate measurement as well
8487  if (testrot == nullptr) {
8488  const auto *pPenultimate = (*pDataVector)[nmeas1 - 2];
8489  const bool penultimateIsRIO = pPenultimate->type(Trk::MeasurementBaseType::RIO_OnTrack);
8490  const bool penultimateIsCompetingRIO = pPenultimate->type(Trk::MeasurementBaseType::CompetingRIOsOnTrack);
8491  if(penultimateIsRIO){
8492  testrot = static_cast<const RIO_OnTrack *>(pPenultimate);
8493  } else {
8494  if (penultimateIsCompetingRIO){
8495  const auto *testcrot = static_cast<const CompetingRIOsOnTrack*>(pPenultimate);
8496  testrot = &testcrot->rioOnTrack(0);
8497  }
8498  }
8499  }
8500  //check: we've successfully got a valid RIO on track; it's not the inner detector;
8501  //it's really the muon detector (question: doesn't that make the previous check redundant?)
8502  return (
8503  (testrot != nullptr) &&
8504  !m_DetID->is_indet(testrot->identify()) &&
8505  m_DetID->is_muon(testrot->identify())
8506  );
8507  }
8508 
8509  void
8510  GlobalChi2Fitter::initFieldCache(const EventContext& ctx, Cache& cache)
8511  const
8512  {
8515  ctx
8516  );
8517 
8518  const AtlasFieldCacheCondObj * cond_obj(*rh);
8519 
8520  if (cond_obj == nullptr) {
8521  ATH_MSG_ERROR("Failed to create AtlasFieldCacheCondObj!");
8522  return;
8523  }
8524 
8525  cond_obj->getInitializedCache(cache.m_field_cache);
8526  }
8527 
8529  std::stringstream msg;
8530  msg << "Failed to get conditions data " << m_trackingGeometryReadKey.key() << ".";
8531  throw std::runtime_error(msg.str());
8532  }
8533 
8534  bool GlobalChi2Fitter::ensureValidEntranceCalo(const EventContext& ctx, Cache& cache) const {
8535  if (cache.m_caloEntrance == nullptr) {
8536  const TrackingGeometry *geometry = trackingGeometry(cache, ctx);
8537 
8538  if (geometry != nullptr) {
8539  cache.m_caloEntrance = geometry->trackingVolume("InDet::Containers::InnerDetector");
8540  } else {
8541  ATH_MSG_ERROR("Tracking Geometry not available");
8542  }
8543 
8544  /*
8545  * Check, if we managed to find an entrance.
8546  */
8547  if (cache.m_caloEntrance == nullptr) {
8548  ATH_MSG_ERROR("calo entrance not available");
8549  }
8550  }
8551 
8552  return cache.m_caloEntrance != nullptr;
8553  }
8554 
8555  bool GlobalChi2Fitter::ensureValidEntranceMuonSpectrometer(const EventContext& ctx, Cache& cache) const {
8556  if (cache.m_msEntrance == nullptr) {
8557  const TrackingGeometry *geometry = trackingGeometry(cache, ctx);
8558 
8559  if (geometry != nullptr) {
8560  cache.m_msEntrance = geometry->trackingVolume("MuonSpectrometerEntrance");
8561  } else {
8562  ATH_MSG_ERROR("Tracking Geometry not available");
8563  }
8564 
8565  /*
8566  * Check, if we managed to find an entrance.
8567  */
8568  if (cache.m_msEntrance == nullptr) {
8569  ATH_MSG_ERROR("MS entrance not available");
8570  }
8571  }
8572 
8573  return cache.m_msEntrance != nullptr;
8574  }
8575 }
Trk::GXFTrajectory::numberOfUpstreamScatterers
int numberOfUpstreamScatterers() const
Definition: GXFTrajectory.cxx:472
python.PyKernel.retrieve
def retrieve(aClass, aKey=None)
Definition: PyKernel.py:110
Trk::GXFTrackState::sinStereo
double sinStereo() const
Definition: GXFTrackState.cxx:173
AtlasDetectorID::is_pixel
bool is_pixel(Identifier id) const
Definition: AtlasDetectorID.h:767
Trk::GXFMaterialEffects::deltaTheta
double deltaTheta() const
Definition: GXFMaterialEffects.cxx:119
Trk::GlobalChi2Fitter::Cache::m_derivmat
Amg::MatrixX m_derivmat
Definition: GlobalChi2Fitter.h:230
Trk::anyDirection
@ anyDirection
Definition: PropDirection.h:22
Trk::GlobalChi2Fitter::makePerigee
std::unique_ptr< const TrackParameters > makePerigee(Cache &, const TrackParameters &, const ParticleHypothesis) const
Definition: GlobalChi2Fitter.cxx:4471
Trk::GlobalChi2Fitter::Cache::m_calomat
bool m_calomat
Definition: GlobalChi2Fitter.h:207
Trk::GlobalChi2Fitter::S_LOW_MOMENTUM
@ S_LOW_MOMENTUM
Definition: GlobalChi2Fitter.h:185
TrapezoidBounds.h
AllowedVariables::e
e
Definition: AsgElectronSelectorTool.cxx:37
make_hlt_rep.pars
pars
Definition: make_hlt_rep.py:90
Trk::GlobalChi2Fitter::Cache::m_msEntrance
const TrackingVolume * m_msEntrance
Definition: GlobalChi2Fitter.h:205
Trk::y
@ y
Definition: ParamDefs.h:56
Trk::GXFTrajectory::setMass
void setMass(double)
Definition: GXFTrajectory.cxx:626
beamspotman.r
def r
Definition: beamspotman.py:674
Trk::LocalParameters
Definition: LocalParameters.h:98
Trk::GlobalChi2Fitter::makeProtoState
void makeProtoState(Cache &, GXFTrajectory &, const TrackStateOnSurface *, int index=-1) const
Definition: GlobalChi2Fitter.cxx:2557
Trk::TrackStateOnSurface::trackParameters
const TrackParameters * trackParameters() const
return ptr to trackparameters const overload
plotBeamSpotCompare.x1
x1
Definition: plotBeamSpotCompare.py:215
EstimatedBremOnTrack.h
Trk::TrackStateOnSurface::CaloDeposit
@ CaloDeposit
This TSOS contains a CaloEnergy object.
Definition: TrackStateOnSurface.h:135
EnergyLoss.h
Trk::GXFTrajectory::numberOfUpstreamStates
int numberOfUpstreamStates() const
Definition: GXFTrajectory.cxx:468
Trk::TrackState::Vertex
@ Vertex
Definition: TrackStateDefs.h:36
TileDCSDataPlotter.dp
dp
Definition: TileDCSDataPlotter.py:842
Trk::proton
@ proton
Definition: ParticleHypothesis.h:34
Trk::TrackInfo
Contains information about the 'fitter' of this track.
Definition: Tracking/TrkEvent/TrkTrack/TrkTrack/TrackInfo.h:32
AtlasDetectorID::is_rpc
bool is_rpc(Identifier id) const
Definition: AtlasDetectorID.h:882
Trk::TrackStateOnSurface::Perigee
@ Perigee
This represents a perigee, and so will contain a Perigee object only.
Definition: TrackStateOnSurface.h:117
Trk::AmgMatrix
AmgMatrix(3, 3) NeutralParticleParameterCalculator
Definition: NeutralParticleParameterCalculator.cxx:233
Trk::GlobalChi2Fitter::m_createSummary
Gaudi::Property< bool > m_createSummary
Definition: GlobalChi2Fitter.h:1187
Trk::FitterStatusCode::MatrixInversionFailure
@ MatrixInversionFailure
Definition: FitterStatusCode.h:54
PlotCalibFromCool.norm
norm
Definition: PlotCalibFromCool.py:100
ScatteringAngles.h
Trk::GXFTrajectory::numberOfScatterers
int numberOfScatterers() const
Definition: GXFTrajectory.cxx:449
Trk::TrackState::RPC
@ RPC
Definition: TrackStateDefs.h:33
Trk::GlobalChi2Fitter::Cache::m_matTempStore
std::vector< std::unique_ptr< const std::vector< const TrackStateOnSurface * >, void(*)(const std::vector< const TrackStateOnSurface * > *) > > m_matTempStore
Definition: GlobalChi2Fitter.h:235
ATH_MSG_FATAL
#define ATH_MSG_FATAL(x)
Definition: AthMsgStreamMacros.h:34
DataModel_detail::const_iterator
Const iterator class for DataVector/DataList.
Definition: DVLIterator.h:82
Trk::Layer::fullUpdateMaterialProperties
const MaterialProperties * fullUpdateMaterialProperties(const TrackParameters &par) const
getting the MaterialProperties back - for full update
Definition: Layer.cxx:169
Trk::TrackState::Pixel
@ Pixel
Definition: TrackStateDefs.h:28
Trk::PrepRawDataSet
std::vector< const PrepRawData * > PrepRawDataSet
vector of clusters and drift circles
Definition: FitterTypes.h:26
Trk::Track::fitQuality
const FitQuality * fitQuality() const
return a pointer to the fit quality const-overload
Amg::VectorX
Eigen::Matrix< double, Eigen::Dynamic, 1 > VectorX
Dynamic Vector - dynamic allocation.
Definition: EventPrimitives.h:30
Trk::GlobalChi2Fitter::m_navigator
ToolHandle< INavigator > m_navigator
Definition: GlobalChi2Fitter.h:1095
Amg::MatrixX
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic > MatrixX
Dynamic Matrix - dynamic allocation.
Definition: EventPrimitives.h:27
Trk::GXFTrackState::isRecalibrated
bool isRecalibrated()
Definition: GXFTrackState.h:176
Trk::MeasurementBase::clone
virtual MeasurementBase * clone() const =0
Pseudo-Constructor.
inline_hints.h
python.SystemOfUnits.mm
float mm
Definition: SystemOfUnits.py:98
DeMoUpdate.tmp2
string tmp2
Definition: DeMoUpdate.py:1168
Trk::GlobalChi2Fitter::fillResidualsAndErrors
void fillResidualsAndErrors(const EventContext &ctx, const Cache &cache, GXFTrajectory &trajectory, const int it, Amg::VectorX &b, int &bremno_maxbrempull, GXFTrackState *&state_maxbrempull) const
Definition: GlobalChi2Fitter.cxx:5073
StraightLineSurface.h
DiscBounds.h
TrackParameters.h
Trk::BoundaryCheckResult::DeadElement
@ DeadElement
outside the element
Trk::GlobalChi2Fitter::m_outlcut
Gaudi::Property< double > m_outlcut
Definition: GlobalChi2Fitter.h:1190
Trk::z
@ z
global position (cartesian)
Definition: ParamDefs.h:57
Trk::TrackState::TRT
@ TRT
Definition: TrackStateDefs.h:30
Trk::GXFTrajectory::numberOfFitParameters
int numberOfFitParameters() const
Definition: GXFTrajectory.cxx:487
Trk::GXFTrajectory::brems
std::vector< double > & brems()
Definition: GXFTrajectory.cxx:543
Trk::GlobalChi2Fitter::ensureValidEntranceMuonSpectrometer
bool ensureValidEntranceMuonSpectrometer(const EventContext &ctx, Cache &cache) const
Definition: GlobalChi2Fitter.cxx:8555
Trk::GlobalChi2Fitter::m_numderiv
Gaudi::Property< bool > m_numderiv
Definition: GlobalChi2Fitter.h:1182
SurfaceConsistencyCheck.h
SG::ReadCondHandle
Definition: ReadCondHandle.h:44
Trk::MagneticFieldProperties
Definition: MagneticFieldProperties.h:31
Trk::GXFTrajectory::numberOfTRTPrecHits
int numberOfTRTPrecHits() const
Definition: GXFTrajectory.cxx:437
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
Trk::GlobalChi2Fitter::m_calotool
ToolHandle< IMaterialEffectsOnTrackProvider > m_calotool
Definition: GlobalChi2Fitter.h:1098
PerigeeSurface.h
Trk::locX
@ locX
Definition: ParamDefs.h:37
find
std::string find(const std::string &s)
return a remapped string
Definition: hcg.cxx:135
Trk::GlobalChi2Fitter::m_matupdator
ToolHandle< IMaterialEffectsUpdator > m_matupdator
Definition: GlobalChi2Fitter.h:1093
AtlasDetectorID::is_csc
bool is_csc(Identifier id) const
Definition: AtlasDetectorID.h:898
CompetingRIOsOnTrack.h
Trk::locY
@ locY
local cartesian
Definition: ParamDefs.h:38
Trk::BoundaryCheckResult
BoundaryCheckResult
Definition: IBoundaryCheckTool.h:14
Trk::Track
The ATLAS Track class.
Definition: Tracking/TrkEvent/TrkTrack/TrkTrack/Track.h:73
AtlasFieldCacheCondObj
Definition: AtlasFieldCacheCondObj.h:19
Trk::TrackState::Segment
@ Segment
Definition: TrackStateDefs.h:37
Base_Fragment.mass
mass
Definition: Sherpa_i/share/common/Base_Fragment.py:59
perp
Scalar perp() const
perp method - perpenticular length
Definition: AmgMatrixBasePlugin.h:44
Trk::DistanceSolution
Definition: DistanceSolution.h:25
Trk::TrackingVolume::closestMaterialLayer
LayerIntersection< Amg::Vector3D > closestMaterialLayer(const Amg::Vector3D &gp, const Amg::Vector3D &dir, PropDirection pDir=alongMomentum, const BoundaryCheck &bchk=true) const
Return the closest layer with material description.
Definition: TrackingVolume.cxx:445
MaterialProperties.h
Trk::Volume::inside
bool inside(const Amg::Vector3D &gp, double tol=0.) const
Inside() method for checks.
Definition: Volume.cxx:72
Trk::TrackStateOnSurface::surface
const Trk::Surface & surface() const
return associated surface
Definition: TrackStateOnSurface.cxx:188
Trk::LocalParameters::parameterKey
int parameterKey() const
Identifier key for matrix expansion/reduction.
Trk::GlobalChi2Fitter::m_holeSearch
Gaudi::Property< bool > m_holeSearch
Definition: GlobalChi2Fitter.h:1188
MagField::AtlasFieldCache::getFieldZR
void getFieldZR(const double *ATH_RESTRICT xyz, double *ATH_RESTRICT bxyz, double *ATH_RESTRICT deriv=nullptr)
get B field valaue on the z-r plane at given position works only inside the solenoid.
Definition: AtlasFieldCache.cxx:86
WriteCellNoiseToCool.src
src
Definition: WriteCellNoiseToCool.py:513
Trk::PerigeeSurface
Definition: PerigeeSurface.h:43
AtlasDetectorID::is_sct
bool is_sct(Identifier id) const
Definition: AtlasDetectorID.h:777
PixelCluster.h
Trk::ParametersBase::position
const Amg::Vector3D & position() const
Access method for the position.
Trk::GXFTrajectory::addMeasurementState
bool addMeasurementState(std::unique_ptr< GXFTrackState >, int index=-1)
Definition: GXFTrajectory.cxx:166
AtlasFieldCacheCondObj.h
Trk::oppositeMomentum
@ oppositeMomentum
Definition: PropDirection.h:21
Trk::GXFTrajectory::addBasicState
void addBasicState(std::unique_ptr< GXFTrackState >, int index=-1)
Definition: GXFTrajectory.cxx:266
Trk::DistanceSolution::numberOfSolutions
int numberOfSolutions() const
Number of intersection solutions.
SG::ReadHandle
Definition: StoreGate/StoreGate/ReadHandle.h:67
index
Definition: index.py:1
xAODP4Helpers.h
Trk::ParametersBase::associatedSurface
virtual const Surface & associatedSurface() const override=0
Access to the Surface associated to the Parameters.
Trk::GlobalChi2Fitter::runIteration
FitterStatusCode runIteration(const EventContext &ctx, Cache &cache, GXFTrajectory &trajectory, const int it, Amg::SymMatrixX &a, Amg::VectorX &b, Amg::SymMatrixX &lu, bool &doDeriv) const
Definition: GlobalChi2Fitter.cxx:5994
Trk::Surface::straightLineDistanceEstimate
virtual DistanceSolution straightLineDistanceEstimate(const Amg::Vector3D &pos, const Amg::Vector3D &dir) const =0
fast straight line distance evaluation to Surface
Trk::numberOfSCTDeadSensors
@ numberOfSCTDeadSensors
number of TRT hits
Definition: Tracking/TrkEvent/TrkTrackSummary/TrkTrackSummary/TrackSummary.h:76
hist_file_dump.d
d
Definition: hist_file_dump.py:142
Trk::Track::trackStateOnSurfaces
const Trk::TrackStates * trackStateOnSurfaces() const
return a pointer to a const DataVector of const TrackStateOnSurfaces.
max
constexpr double max()
Definition: ap_fixedTest.cxx:33
Trk::ParametersT
Dummy class used to allow special convertors to be called for surfaces owned by a detector element.
Definition: EMErrorDetail.h:25
xAOD::deltaPhi
setSAddress setEtaMS setDirPhiMS setDirZMS setBarrelRadius setEndcapAlpha setEndcapRadius setInterceptInner setEtaMap setEtaBin setIsTgcFailure setDeltaPt deltaPhi
Definition: L2StandAloneMuon_v1.cxx:161
Trk::Track::info
const TrackInfo & info() const
Returns a const ref to info of a const tracks.
Trk::GlobalChi2Fitter::GlobalChi2Fitter
GlobalChi2Fitter(const std::string &, const std::string &, const IInterface *)
Definition: GlobalChi2Fitter.cxx:200
Trk::GlobalChi2Fitter::isMuonTrack
bool isMuonTrack(const Track &) const
Definition: GlobalChi2Fitter.cxx:8468
Trk::GXFTrajectory::numberOfPerigeeParameters
int numberOfPerigeeParameters() const
Definition: GXFTrajectory.cxx:483
mat
GeoMaterial * mat
Definition: LArDetectorConstructionTBEC.cxx:55
min
constexpr double min()
Definition: ap_fixedTest.cxx:26
Trk::GXFTrackState::measurement
const MeasurementBase * measurement(void)
Definition: GXFTrackState.cxx:142
Trk::TrackState::MDT
@ MDT
Definition: TrackStateDefs.h:31
Trk::TrackInfo::BremFitSuccessful
@ BremFitSuccessful
A brem fit was performed on this track and this fit was successful.
Definition: Tracking/TrkEvent/TrkTrack/TrkTrack/TrackInfo.h:81
Trk::BoundaryCheckResult::Candidate
@ Candidate
Trk::GlobalChi2Fitter::m_redoderivs
Gaudi::Property< bool > m_redoderivs
Definition: GlobalChi2Fitter.h:1179
Trk::indices
std::pair< long int, long int > indices
Definition: AlSymMatBase.h:24
Trk::GlobalChi2Fitter::S_FITS
@ S_FITS
Definition: GlobalChi2Fitter.h:177
Trk::GlobalChi2Fitter::m_straightlineprop
Gaudi::Property< bool > m_straightlineprop
Definition: GlobalChi2Fitter.h:1170
Trk::GXFTrackState::getStateType
bool getStateType(TrackStateOnSurface::TrackStateOnSurfaceType type) const
Retrieve the value of a specific type bit.
Definition: GXFTrackState.cxx:282
plotBeamSpotCompare.x2
x2
Definition: plotBeamSpotCompare.py:217
Trk::Surface::associatedDetectorElementIdentifier
Identifier associatedDetectorElementIdentifier() const
return Identifier of the associated Detector Element
Trk::GlobalChi2Fitter::fillAfromScatterers
static void fillAfromScatterers(GXFTrajectory &trajectory, Amg::SymMatrixX &a)
Definition: GlobalChi2Fitter.cxx:5773
Trk::RIO_OnTrack::globalPosition
virtual const Amg::Vector3D & globalPosition() const override=0
Interface method to get the global Position.
Trk::GlobalChi2Fitter::setMinIterations
virtual void setMinIterations(int)
Definition: GlobalChi2Fitter.cxx:8446
plotBeamSpotVxVal.covmat
covmat
Definition: plotBeamSpotVxVal.py:205
Trk::GXFTrajectory::numberOfTRTTubeHits
int numberOfTRTTubeHits() const
Definition: GXFTrajectory.cxx:441
Trk::locRPhi
@ locRPhi
Definition: ParamDefs.h:40
Trk::GXFTrajectory::residuals
Amg::VectorX & residuals()
Definition: GXFTrajectory.cxx:586
Trk::MaterialProperties::thicknessInX0
float thicknessInX0() const
Return the radiationlength fraction.
Trk::GXFTrajectory::prefit
int prefit() const
Definition: GXFTrajectory.cxx:417
module_driven_slicing.layers
layers
Definition: module_driven_slicing.py:113
Trk::LocalParameters::contains
bool contains(ParamDefs par) const
The simple check for the clients whether the parameter is contained.
Trk::GXFTrajectory::setNumberOfPerigeeParameters
void setNumberOfPerigeeParameters(int)
Definition: GXFTrajectory.cxx:342
skel.it
it
Definition: skel.GENtoEVGEN.py:407
AtlasDetectorID::is_mm
bool is_mm(Identifier id) const
Definition: AtlasDetectorID.h:920
python.SystemOfUnits.second
float second
Definition: SystemOfUnits.py:135
Trk::GlobalChi2Fitter::calculateTrackParametersPropagate
PropagationResult calculateTrackParametersPropagate(const EventContext &, const TrackParameters &, const GXFTrackState &, PropDirection, const MagneticFieldProperties &, bool, bool) const
Propagate onto a track state, collecting new track parameters, and optionally the Jacobian and possib...
Definition: GlobalChi2Fitter.cxx:7752
Trk::GlobalChi2Fitter::fillAfromMeasurements
static void fillAfromMeasurements(const Cache &cache, GXFTrajectory &trajectory, Amg::SymMatrixX &a)
Definition: GlobalChi2Fitter.cxx:5750
Trk::GlobalChi2Fitter::m_ROTcreator
ToolHandle< IRIO_OnTrackCreator > m_ROTcreator
Definition: GlobalChi2Fitter.h:1087
python.AthDsoLogger.out
out
Definition: AthDsoLogger.py:70
Trk::GlobalChi2Fitter::S_PROPAGATION_FAIL
@ S_PROPAGATION_FAIL
Definition: GlobalChi2Fitter.h:181
DiscLayer.h
Trk::EnergyLoss::sigmaDeltaE
double sigmaDeltaE() const
returns the symmatric error
M_PI
#define M_PI
Definition: ActiveFraction.h:11
LayerSort.h
Trk::GXFMaterialEffects::setMaterialProperties
void setMaterialProperties(const MaterialProperties *)
Set the material properties of this material effects instance.
Definition: GXFMaterialEffects.cxx:237
Trk::GlobalChi2Fitter::tryToWeightAfromMaterial
static bool tryToWeightAfromMaterial(Cache &cache, GXFTrajectory &trajectory, Amg::SymMatrixX &a, const bool doDeriv, const int it, const double oldRedChi2, const double newRedChi2)
Definition: GlobalChi2Fitter.cxx:5821
PlotCalibFromCool.ib
ib
Definition: PlotCalibFromCool.py:419
Trk::GlobalChi2Fitter::m_extrapolator
ToolHandle< IExtrapolator > m_extrapolator
Definition: GlobalChi2Fitter.h:1090
Trk::GlobalChi2Fitter::Cache::m_fit_status
std::array< unsigned int, S_MAX_VALUE > m_fit_status
Definition: GlobalChi2Fitter.h:241
mc.diff
diff
Definition: mc.SFGenPy8_MuMu_DD.py:14
Trk::GlobalChi2Fitter::myfit
Track * myfit(const EventContext &ctx, Cache &, GXFTrajectory &, const TrackParameters &, const RunOutlierRemoval runOutlier=false, const ParticleHypothesis matEffects=nonInteracting) const
Definition: GlobalChi2Fitter.cxx:4509
ParticleTest.tp
tp
Definition: ParticleTest.py:25
Trk::GlobalChi2Fitter::m_decomposesegments
Gaudi::Property< bool > m_decomposesegments
Definition: GlobalChi2Fitter.h:1175
Trk::z0
@ z0
Definition: ParamDefs.h:64
VolumeBounds.h
HomogeneousLayerMaterial.h
Trk::GXFTrajectory::totalEnergyLoss
double totalEnergyLoss() const
Definition: GXFTrajectory.cxx:616
Trk::ScatteringAngles
represents a deflection of the track caused through multiple scattering in material.
Definition: ScatteringAngles.h:26
xAOD::P4Helpers::deltaPhi
double deltaPhi(double phiA, double phiB)
delta Phi in range [-pi,pi[
Definition: xAODP4Helpers.h:69
Trk::TrackStateOnSurface::measurementOnTrack
const MeasurementBase * measurementOnTrack() const
returns MeasurementBase const overload
Trk::GlobalChi2Fitter::m_propagator
ToolHandle< IPropagator > m_propagator
Definition: GlobalChi2Fitter.h:1094
Trk::GXFMaterialEffects::setScatteringSigmas
void setScatteringSigmas(double, double)
Definition: GXFMaterialEffects.cxx:98
Trk::loc2
@ loc2
generic first and second local coordinate
Definition: ParamDefs.h:35
Trk::GlobalChi2Fitter::runTrackCleanerTRT
void runTrackCleanerTRT(Cache &, GXFTrajectory &, Amg::SymMatrixX &, Amg::VectorX &, Amg::SymMatrixX &, bool, bool, int, const EventContext &ctx) const
Definition: GlobalChi2Fitter.cxx:6341
Trk::CylinderSurface::bounds
virtual const CylinderBounds & bounds() const override final
This method returns the CylinderBounds by reference (NoBounds is not possible for cylinder)
Layer.h
Trk::GXFTrajectory::numberOfHits
int numberOfHits() const
Definition: GXFTrajectory.cxx:421
Trk::LayerMaterialProperties::oppositePostFactor
double oppositePostFactor() const
Return method for post update material description of the Layer along normalvector.
Definition: LayerMaterialProperties.h:150
Trk::MaterialEffectsBase::thicknessInX0
double thicknessInX0() const
returns the actually traversed material .
UploadAMITag.l
list l
Definition: UploadAMITag.larcaf.py:157
IPropagator.h
Trk::GlobalChi2Fitter::addMaterialUpdateTrajectory
void addMaterialUpdateTrajectory(Cache &cache, GXFTrajectory &track, int offset, std::vector< std::pair< const Layer *, const Layer * >> &layers, const TrackParameters *ref1, const TrackParameters *ref2, ParticleHypothesis mat) const
Given layer information, probe those layers for scatterers and add them to a track.
Definition: GlobalChi2Fitter.cxx:3074
Trk::RIO_OnTrack
Definition: RIO_OnTrack.h:70
Trk::GXFTrajectory
Internal representation of the track, used in the track fit.
Definition: GXFTrajectory.h:31
Trk::GXFMaterialEffects::setSigmaDeltaE
void setSigmaDeltaE(double)
Definition: GXFMaterialEffects.cxx:158
Trk::alongMomentum
@ alongMomentum
Definition: PropDirection.h:20
Trk::TrkDetElementBase
Definition: TrkDetElementBase.h:52
Trk::DiscSurface
Definition: DiscSurface.h:54
vec
std::vector< size_t > vec
Definition: CombinationsGeneratorTest.cxx:9
Trk::TrackState::TGC
@ TGC
Definition: TrackStateDefs.h:34
Trk::GXFTrackState::measurementType
TrackState::MeasurementType measurementType()
Definition: GXFTrackState.h:168
Trk::GXFTrackState::position
Amg::Vector3D position()
Definition: GXFTrackState.cxx:229
AtlasDetectorID::is_trt
bool is_trt(Identifier id) const
Definition: AtlasDetectorID.h:789
ReadOfcFromCool.field
field
Definition: ReadOfcFromCool.py:48
Trk::GXFTrackState::setRecalibrated
void setRecalibrated(bool)
Definition: GXFTrackState.cxx:255
read_hist_ntuple.t
t
Definition: read_hist_ntuple.py:5
drawFromPickle.cos
cos
Definition: drawFromPickle.py:36
Trk::GlobalChi2Fitter::holesearchExtrapolation
std::vector< std::unique_ptr< TrackParameters > > holesearchExtrapolation(const EventContext &ctx, const TrackParameters &src, const GXFTrackState &dst, PropDirection propdir) const
Helper method which performs an extrapolation with additional logic for hole search.
Definition: GlobalChi2Fitter.cxx:7662
Trk::DistanceSolution::first
double first() const
Distance to first intersection solution along direction.
IdDictManager.h
TransportJacobian.h
Trk::TrkDetElementBase::identify
virtual Identifier identify() const =0
Identifier.
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
Trk::GlobalChi2Fitter::Cache::m_lastmeasurement
std::vector< int > m_lastmeasurement
Definition: GlobalChi2Fitter.h:219
InDetAccessor::qOverP
@ qOverP
perigee
Definition: InDetAccessor.h:35
Trk::GlobalChi2Fitter::m_broadROTcreator
ToolHandle< IRIO_OnTrackCreator > m_broadROTcreator
Definition: GlobalChi2Fitter.h:1088
Trk::MaterialEffectsBase
base class to integrate material effects on Trk::Track in a flexible way.
Definition: MaterialEffectsBase.h:35
GXF::LayerSort
Definition: LayerSort.h:11
Trk::GlobalChi2Fitter::makeTrackFindPerigeeParameters
std::unique_ptr< const TrackParameters > makeTrackFindPerigeeParameters(const EventContext &, Cache &, GXFTrajectory &, const ParticleHypothesis) const
Definition: GlobalChi2Fitter.cxx:7039
Trk::GXFTrajectory::referenceParameters
const TrackParameters * referenceParameters()
Definition: GXFTrajectory.cxx:334
Trk::Surface::center
const Amg::Vector3D & center() const
Returns the center position of the Surface.
SG::VarHandleKey::empty
bool empty() const
Test if the key is blank.
Definition: AthToolSupport/AsgDataHandles/Root/VarHandleKey.cxx:150
MagField::AtlasFieldCache::toroidOn
bool toroidOn() const
yodamerge_tmp.scale
scale
Definition: yodamerge_tmp.py:138
Trk::GlobalChi2Fitter::m_maxoutliers
Gaudi::Property< int > m_maxoutliers
Definition: GlobalChi2Fitter.h:1196
Trk::GXFTrackState::setMeasurementErrors
void setMeasurementErrors(const double *)
Definition: GXFTrackState.cxx:164
Trk::GlobalChi2Fitter::Cache::m_posdiscs
std::vector< const Trk::Layer * > m_posdiscs
Definition: GlobalChi2Fitter.h:222
Trk::TrackState::unidentified
@ unidentified
Definition: TrackStateDefs.h:27
Trk::numberOfSCTHoles
@ numberOfSCTHoles
number of Holes in both sides of a SCT module
Definition: Tracking/TrkEvent/TrkTrackSummary/TrkTrackSummary/TrackSummary.h:73
Trk::GlobalChi2Fitter::m_idVolume
Trk::Volume m_idVolume
Definition: GlobalChi2Fitter.h:1210
ReweightUtils.message
message
Definition: ReweightUtils.py:15
Identifier::is_valid
bool is_valid() const
Check if id is in a valid state.
Trk::DiscBounds::rMax
double rMax() const
This method returns outer radius.
Trk::GlobalChi2Fitter::m_trackingGeometryReadKey
SG::ReadCondHandleKey< TrackingGeometry > m_trackingGeometryReadKey
Definition: GlobalChi2Fitter.h:1150
Trk::GlobalChi2Fitter::m_field_cache_key
SG::ReadCondHandleKey< AtlasFieldCacheCondObj > m_field_cache_key
Definition: GlobalChi2Fitter.h:1157
Trk::GXFTrajectory::upstreamMaterialLayers
std::vector< std::pair< const Layer *, const Layer * > > & upstreamMaterialLayers()
Definition: GXFTrajectory.cxx:635
Trk::GlobalChi2Fitter::m_boundaryCheckTool
ToolHandle< IBoundaryCheckTool > m_boundaryCheckTool
Definition: GlobalChi2Fitter.h:1100
Trk::u
@ u
Enums for curvilinear frames.
Definition: ParamDefs.h:77
PrepRawData.h
Trk::GlobalChi2Fitter::calculateTrackParameters
FitterStatusCode calculateTrackParameters(const EventContext &ctx, GXFTrajectory &, bool) const
Definition: GlobalChi2Fitter.cxx:7778
python.Utilities.clone
clone
Definition: Utilities.py:134
Trk::GXFTrajectory::setOutlier
void setOutlier(int, bool isoutlier=true)
Definition: GXFTrajectory.cxx:347
Trk::GXFTrajectory::nDOF
int nDOF() const
Definition: GXFTrajectory.cxx:510
makeTRTBarrelCans.y1
tuple y1
Definition: makeTRTBarrelCans.py:15
Trk::GXFTrajectory::setPrefit
void setPrefit(int)
Definition: GXFTrajectory.cxx:395
Trk::TrackState::MM
@ MM
Definition: TrackStateDefs.h:42
Trk::GlobalChi2Fitter::m_fixbrem
Gaudi::Property< int > m_fixbrem
Definition: GlobalChi2Fitter.h:1199
Trk::RunOutlierRemoval
bool RunOutlierRemoval
switch to toggle quality processing after fit
Definition: FitterTypes.h:22
Trk::GlobalChi2Fitter::fillBfromMeasurements
static void fillBfromMeasurements(const Cache &cache, GXFTrajectory &trajectory, Amg::VectorX &b)
Definition: GlobalChi2Fitter.cxx:5706
Trk::Segment::numberOfMeasurementBases
unsigned int numberOfMeasurementBases() const
Return the number of contained Trk::MeasurementBase (s)
Definition: Tracking/TrkEvent/TrkSegment/TrkSegment/Segment.h:193
mergePhysValFiles.end
end
Definition: DataQuality/DataQualityUtils/scripts/mergePhysValFiles.py:92
TrackSegment.h
Trk::GXFTrajectory::updateTRTHitCount
void updateTRTHitCount(int index, float oldError)
Definition: GXFTrajectory.cxx:379
Trk::DefinedParameter
std::pair< double, ParamDefs > DefinedParameter
Definition: DefinedParameter.h:27
Trk::GlobalChi2Fitter::initFieldCache
void initFieldCache(const EventContext &ctx, Cache &cache) const
Initialize a field cache inside a fit cache object.
Definition: GlobalChi2Fitter.cxx:8510
DeMoUpdate.reverse
reverse
Definition: DeMoUpdate.py:563
Trk::MaterialEffectsBase::MATERIAL_EFFECTS_ON_TRACK
@ MATERIAL_EFFECTS_ON_TRACK
Definition: MaterialEffectsBase.h:39
python.SystemOfUnits.MeV
float MeV
Definition: SystemOfUnits.py:172
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
Trk::RIO_OnTrack::type
virtual bool type(MeasurementBaseType::Type type) const override final
Extended method checking the type.
Definition: RIO_OnTrack.h:110
dqt_zlumi_pandas.weight
int weight
Definition: dqt_zlumi_pandas.py:190
Track.h
Trk::GXFTrajectory::setPrevChi2
void setPrevChi2(double)
Definition: GXFTrajectory.cxx:506
Trk::GlobalChi2Fitter::updateSystemWithMaxBremPull
void updateSystemWithMaxBremPull(GXFTrajectory &trajectory, const int bremno_maxbrempull, GXFTrackState *state_maxbrempull, Amg::SymMatrixX &a) const
Definition: GlobalChi2Fitter.cxx:5445
Trk::TrackingVolume::confinedLayers
const LayerArray * confinedLayers() const
Return the subLayer array.
Trk::GlobalChi2Fitter::m_maxit
Gaudi::Property< int > m_maxit
Definition: GlobalChi2Fitter.h:1197
Trk::GXFTrajectory::numberOfSiliconHits
int numberOfSiliconHits() const
Definition: GXFTrajectory.cxx:429
Trk::MaterialProperties::thickness
float thickness() const
Return the thickness in mm.
Trk::TrackInfo::StraightTrack
@ StraightTrack
A straight track.
Definition: Tracking/TrkEvent/TrkTrack/TrkTrack/TrackInfo.h:84
Trk::GXFTrackState::trackParameters
const TrackParameters * trackParameters(void) const
Definition: GXFTrackState.h:160
pdg_comparison.X0
X0
Definition: pdg_comparison.py:314
Trk::AmgSymMatrix
AmgSymMatrix(5) &GXFTrackState
Definition: GXFTrackState.h:156
Trk::FitQualityOnSurface
Definition: FitQualityOnSurface.h:19
Trk::ParticleHypothesis
ParticleHypothesis
Definition: ParticleHypothesis.h:28
Trk::GXFMaterialEffects::x0
double x0() const
Definition: GXFMaterialEffects.cxx:103
Trk::GXFMaterialEffects::deltaPhi
double deltaPhi() const
Definition: GXFMaterialEffects.cxx:111
Trk::TrackInfo::SlimmedTrack
@ SlimmedTrack
A slimmed track.
Definition: Tracking/TrkEvent/TrkTrack/TrkTrack/TrackInfo.h:87
CxxUtils::vec
typename vecDetail::vec_typedef< T, N >::type vec
Define a nice alias for the vectorized type.
Definition: vec.h:207
Trk::MaterialEffectsOnTrack
represents the full description of deflection and e-loss of a track in material.
Definition: MaterialEffectsOnTrack.h:40
Trk::TrackStateOnSurface::type
bool type(const TrackStateOnSurfaceType type) const
Use this method to find out if the TSoS is of a certain type: i.e.
CylinderVolumeBounds.h
Trk::GlobalChi2Fitter::Cache::m_barrelcylinders
std::vector< const Trk::Layer * > m_barrelcylinders
Definition: GlobalChi2Fitter.h:223
AtlasDetectorID.h
This class provides an interface to generate or decode an identifier for the upper levels of the dete...
Trk::GXFTrackState::associatedSurface
const Surface & associatedSurface() const
Definition: GXFTrackState.cxx:183
uint
unsigned int uint
Definition: LArOFPhaseFill.cxx:20
Trk::GlobalChi2Fitter::Cache::m_firstmeasurement
std::vector< int > m_firstmeasurement
Definition: GlobalChi2Fitter.h:218
Trk::CompetingRIOsOnTrack::rioOnTrack
virtual const RIO_OnTrack & rioOnTrack(unsigned int) const =0
returns the RIO_OnTrack (also known as ROT) objects depending on the integer.
Trk::GlobalChi2Fitter::m_residualPullCalculator
ToolHandle< IResidualPullCalculator > m_residualPullCalculator
Definition: GlobalChi2Fitter.h:1096
Trk::DiscBounds::rMin
double rMin() const
This method returns inner radius.
beamspotnt.cols
list cols
Definition: bin/beamspotnt.py:1113
Volume.h
Trk::GlobalChi2Fitter::holeSearchStates
std::vector< std::reference_wrapper< GXFTrackState > > holeSearchStates(GXFTrajectory &trajectory) const
Extracts a collection of track states which are important for hole search.
Definition: GlobalChi2Fitter.cxx:7315
Trk::GXFTrackState::jacobian
Eigen::Matrix< double, 5, 5 > & jacobian()
Definition: GXFTrackState.h:148
Trk::GlobalChi2Fitter::addMaterialGetLayers
static void addMaterialGetLayers(Cache &cache, std::vector< std::pair< const Layer *, const Layer * >> &layers, std::vector< std::pair< const Layer *, const Layer * >> &uplayers, const std::vector< std::unique_ptr< GXFTrackState >> &states, GXFTrackState &first, GXFTrackState &last, const TrackParameters *refpar, bool hasmat)
Collect all possible layers that a given track could have passed through.
Definition: GlobalChi2Fitter.cxx:3285
Trk::GlobalChi2Fitter::makeTrackFillDerivativeMatrix
static void makeTrackFillDerivativeMatrix(Cache &, GXFTrajectory &)
Definition: GlobalChi2Fitter.cxx:6990
Trk::PropDirection
PropDirection
Definition: PropDirection.h:19
Trk::SurfaceBounds::type
virtual BoundsType type() const =0
Return the bounds type - for persistency optimization.
Trk::GlobalChi2Fitter::Cache::m_asymeloss
bool m_asymeloss
Definition: GlobalChi2Fitter.h:215
Trk::GXFTrajectory::scatteringSigmas
std::vector< std::pair< double, double > > & scatteringSigmas()
Definition: GXFTrajectory.cxx:536
AtlasFieldCacheCondObj::getInitializedCache
void getInitializedCache(MagField::AtlasFieldCache &cache) const
get B field cache for evaluation as a function of 2-d or 3-d position.
Definition: AtlasFieldCacheCondObj.h:32
Trk::GlobalChi2Fitter::S_MAT_INV_FAIL
@ S_MAT_INV_FAIL
Definition: GlobalChi2Fitter.h:179
python.utils.AtlRunQueryDQUtils.p
p
Definition: AtlRunQueryDQUtils.py:209
Trk::GlobalChi2Fitter::m_caloMaterialProvider
ToolHandle< Trk::ITrkMaterialProviderTool > m_caloMaterialProvider
Definition: GlobalChi2Fitter.h:1097
Trk::GlobalChi2Fitter::Cache::m_lastiter
int m_lastiter
Definition: GlobalChi2Fitter.h:227
Trk::GXFTrajectory::numberOfBrems
int numberOfBrems() const
Definition: GXFTrajectory.cxx:460
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
Trk::GXFMaterialEffects::setKink
void setKink(bool)
Definition: GXFMaterialEffects.cxx:186
Trk::Layer::surfaceRepresentation
virtual const Surface & surfaceRepresentation() const =0
Transforms the layer into a Surface representation for extrapolation.
Prompt::getDistance
double getDistance(const xAOD::Vertex *vtx1, const xAOD::Vertex *vtx2)
Definition: PromptUtils.cxx:41
Trk::GlobalChi2Fitter::Cache::m_caloEntrance
const TrackingVolume * m_caloEntrance
Definition: GlobalChi2Fitter.h:204
Trk::locZ
@ locZ
local cylindrical
Definition: ParamDefs.h:42
ParticleGun_FastCalo_ChargeFlip_Config.energy
energy
Definition: ParticleGun_FastCalo_ChargeFlip_Config.py:78
EventPrimitivesToStringConverter.h
Trk::GXFTrajectory::setConverged
void setConverged(bool)
Definition: GXFTrajectory.cxx:399
dqt_zlumi_pandas.err
err
Definition: dqt_zlumi_pandas.py:183
GXFMaterialEffects.h
Trk::GlobalChi2Fitter::m_elosstool
ToolHandle< IEnergyLossUpdator > m_elosstool
Definition: GlobalChi2Fitter.h:1092
lumiFormat.i
int i
Definition: lumiFormat.py:85
Trk::LayerIndex
Definition: LayerIndex.h:37
Trk::MeasurementBaseType::CompetingRIOsOnTrack
@ CompetingRIOsOnTrack
Definition: MeasurementBase.h:50
Trk::Surface::createUniqueTrackParameters
virtual ChargedTrackParametersUniquePtr createUniqueTrackParameters(double l1, double l2, double phi, double theat, double qop, std::optional< AmgSymMatrix(5)> cov=std::nullopt) const =0
Use the Surface as a ParametersBase constructor, from local parameters - charged.
Trk::GXFTrajectory::m_straightline
bool m_straightline
Definition: GXFTrajectory.h:111
Trk::TrackStateOnSurface::materialEffectsOnTrack
const MaterialEffectsBase * materialEffectsOnTrack() const
return material effects const overload
Trk::GlobalChi2Fitter::mainCombinationStrategy
Track * mainCombinationStrategy(const EventContext &ctx, Cache &, const Track &, const Track &, GXFTrajectory &, std::vector< MaterialEffectsOnTrack > &) const
Definition: GlobalChi2Fitter.cxx:582
Trk::GlobalChi2Fitter::Cache::m_field_cache
MagField::AtlasFieldCache m_field_cache
Definition: GlobalChi2Fitter.h:237
Trk::TrackState::Pseudo
@ Pseudo
Definition: TrackStateDefs.h:35
ATH_FLATTEN
#define ATH_FLATTEN
Definition: inline_hints.h:52
mergePhysValFiles.errors
list errors
Definition: DataQuality/DataQualityUtils/scripts/mergePhysValFiles.py:42
Trk::GlobalChi2Fitter::iterationsOfLastFit
virtual int iterationsOfLastFit() const
Definition: GlobalChi2Fitter.cxx:8443
AtlasDetectorID::is_tgc
bool is_tgc(Identifier id) const
Definition: AtlasDetectorID.h:909
beamspotman.n
n
Definition: beamspotman.py:729
Trk::theta
@ theta
Definition: ParamDefs.h:66
Trk::GXFTrajectory::totalX0
double totalX0() const
Definition: GXFTrajectory.cxx:611
Trk::IPropagator
Definition: IPropagator.h:55
Trk::TrackingGeometry
Definition: TrackingGeometry.h:67
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
Trk::electron
@ electron
Definition: ParticleHypothesis.h:30
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
xAOD::covMatrix
covMatrix
Definition: TrackMeasurement_v1.cxx:19
Trk::GXFMaterialEffects::sigmaDeltaPhi
double sigmaDeltaPhi() const
Definition: GXFMaterialEffects.cxx:123
Trk::CylinderSurface
Definition: CylinderSurface.h:55
AmgVector
AmgVector(4) T2BSTrackFilterTool
Definition: T2BSTrackFilterTool.cxx:114
urldecode::states
states
Definition: urldecode.h:39
Trk::CylinderBounds
Definition: CylinderBounds.h:46
TRT::Hit::layer
@ layer
Definition: HitInfo.h:79
Trk::GlobalChi2Fitter::m_domeastrackpar
Gaudi::Property< bool > m_domeastrackpar
Definition: GlobalChi2Fitter.h:1177
Trk::DistanceSolution::second
double second() const
Distance to second intersection solution along direction (for a cylinder surface)
makeTRTBarrelCans.y2
tuple y2
Definition: makeTRTBarrelCans.py:18
Trk::driftRadius
@ driftRadius
trt, straws
Definition: ParamDefs.h:53
Trk::GlobalChi2Fitter::Cache::m_fastmat
bool m_fastmat
Definition: GlobalChi2Fitter.h:225
Trk::GlobalChi2Fitter::S_INVALID_ANGLES
@ S_INVALID_ANGLES
Definition: GlobalChi2Fitter.h:182
Trk::numberOfPixelDeadSensors
@ numberOfPixelDeadSensors
number of pixel hits with broad errors (width/sqrt(12))
Definition: Tracking/TrkEvent/TrkTrackSummary/TrkTrackSummary/TrackSummary.h:65
Trk::GlobalChi2Fitter::TrackHoleCount
Definition: GlobalChi2Fitter.h:168
Trk::pion
@ pion
Definition: ParticleHypothesis.h:32
VertexOnTrack.h
Trk::GXFTrackState
Definition: GXFTrackState.h:30
Amg::Transform3D
Eigen::Affine3d Transform3D
Definition: GeoPrimitives.h:46
Trk::GlobalChi2Fitter::Cache::m_fiteloss
bool m_fiteloss
Definition: GlobalChi2Fitter.h:214
Trk::Segment
Definition: Tracking/TrkEvent/TrkSegment/TrkSegment/Segment.h:56
Trk::GXFMaterialEffects::sigmaDeltaTheta
double sigmaDeltaTheta() const
Definition: GXFMaterialEffects.cxx:127
Trk::FitterStatusCode::Success
@ Success
fit successfull
Definition: FitterStatusCode.h:38
Trk::GlobalChi2Fitter::m_DetID
const AtlasDetectorID * m_DetID
Definition: GlobalChi2Fitter.h:1164
Trk::DiscSurface::bounds
const SurfaceBounds & bounds() const override final
This method returns the bounds by reference.
Trk::GlobalChi2Fitter::calculateTrackParametersPropagateHelper
PropagationResult calculateTrackParametersPropagateHelper(const EventContext &, const TrackParameters &, const GXFTrackState &, PropDirection, const MagneticFieldProperties &, bool, bool) const
Helper method that encapsulates calls to the propagator tool in the calculateTrackParameters() method...
Definition: GlobalChi2Fitter.cxx:7713
res
std::pair< std::vector< unsigned int >, bool > res
Definition: JetGroupProductTest.cxx:11
Trk::GlobalChi2Fitter::alignmentFit
virtual Track * alignmentFit(AlignmentCache &, const Track &, const RunOutlierRemoval runOutlier=false, const ParticleHypothesis matEffects=Trk::nonInteracting) const override
Definition: GlobalChi2Fitter.cxx:1819
CylinderSurface.h
Trk::CompetingRIOsOnTrack
Base class for all CompetingRIOsOnTack implementations, extends the common MeasurementBase.
Definition: CompetingRIOsOnTrack.h:64
chi2
double chi2(TH1 *h0, TH1 *h1)
Definition: comparitor.cxx:525
AtlasFieldCache.h
Trk::EnergyLoss::deltaE
double deltaE() const
returns the
Trk::GlobalChi2Fitter::addMaterialFindIntersectionDisc
static std::optional< std::pair< Amg::Vector3D, double > > addMaterialFindIntersectionDisc(Cache &cache, const DiscSurface &surface, const TrackParameters &param1, const TrackParameters &param2, const ParticleHypothesis mat)
Find the intersection of a set of track parameters onto a disc surface.
Definition: GlobalChi2Fitter.cxx:2950
BindingsTest.cut
cut
This script demonstrates how to call a C++ class from Python Also how to use PyROOT is shown.
Definition: BindingsTest.py:13
PseudoMeasurementOnTrack.h
Trk::TrackState::MeasurementType
MeasurementType
enum describing the flavour of MeasurementBase
Definition: TrackStateDefs.h:26
sign
int sign(int a)
Definition: TRT_StrawNeighbourSvc.h:107
Trk::GXFMaterialEffects::sigmaDeltaEPos
double sigmaDeltaEPos() const
Definition: GXFMaterialEffects.cxx:143
Trk::GlobalChi2Fitter::Cache
Definition: GlobalChi2Fitter.h:189
Trk::FitterStatusCode::ExtrapolationFailure
@ ExtrapolationFailure
extrapolation failed
Definition: FitterStatusCode.h:44
Trk::GlobalChi2Fitter::throwFailedToGetTrackingGeomtry
void throwFailedToGetTrackingGeomtry() const
Definition: GlobalChi2Fitter.cxx:8528
Trk::FitterStatusCode
Status codes for track fitters.
Definition: FitterStatusCode.h:34
Trk::Surface::normal
virtual const Amg::Vector3D & normal() const
Returns the normal vector of the Surface (i.e.
Trk::GlobalChi2Fitter::S_NOT_CONVERGENT
@ S_NOT_CONVERGENT
Definition: GlobalChi2Fitter.h:183
LArG4GenerateShowerLib.geometry
geometry
Definition: LArG4GenerateShowerLib.py:19
Trk::GXFTrackState::setMeasurement
void setMeasurement(std::unique_ptr< const MeasurementBase >)
Definition: GXFTrackState.cxx:137
Trk::Segment::measurement
const MeasurementBase * measurement(unsigned int) const
returns the Trk::MeasurementBase objects depending on the integer
Definition: Tracking/TrkEvent/TrkSegment/TrkSegment/Segment.h:184
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
Trk::GlobalChi2Fitter::Cache::m_negdiscs
std::vector< const Trk::Layer * > m_negdiscs
Definition: GlobalChi2Fitter.h:221
Trk::GlobalChi2Fitter::m_fiteloss
Gaudi::Property< bool > m_fiteloss
Definition: GlobalChi2Fitter.h:1183
Trk::GlobalChi2Fitter::holeSearchProcess
std::optional< GlobalChi2Fitter::TrackHoleCount > holeSearchProcess(const EventContext &ctx, const std::vector< std::reference_wrapper< GXFTrackState >> &states) const
Conduct a hole search between a list of states, possibly reusing existing information.
Definition: GlobalChi2Fitter.cxx:7390
Trk::GlobalChi2Fitter::correctAngles
static bool correctAngles(double &, double &)
Definition: GlobalChi2Fitter.cxx:8452
Trk::GXFMaterialEffects
class that is similar to MaterialEffectsOnTrack, but has 'set' methods for more flexibility during tr...
Definition: GXFMaterialEffects.h:24
Trk::MeasurementBase::type
virtual bool type(MeasurementBaseType::Type type) const =0
Interface method checking the type.
CylinderLayer.h
Trk::GlobalChi2Fitter::addMaterialFindIntersectionCyl
static std::optional< std::pair< Amg::Vector3D, double > > addMaterialFindIntersectionCyl(Cache &cache, const CylinderSurface &surface, const TrackParameters &param1, const TrackParameters &param2, const ParticleHypothesis mat)
Find the intersection of a set of track parameters onto a cylindrical surface.
Definition: GlobalChi2Fitter.cxx:2995
Trk::GlobalChi2Fitter::m_extensioncuts
Gaudi::Property< bool > m_extensioncuts
Definition: GlobalChi2Fitter.h:1171
Trk::GlobalChi2Fitter::holeSearchHelper
void holeSearchHelper(const std::vector< std::unique_ptr< TrackParameters >> &hc, std::set< Identifier > &id_set, std::set< Identifier > &sct_set, TrackHoleCount &rv, bool count_holes, bool count_dead) const
Helper method for the hole search that does the actual counting of holes and dead modules.
Definition: GlobalChi2Fitter.cxx:7205
Trk::GlobalChi2Fitter::trackingGeometry
const TrackingGeometry * trackingGeometry(Cache &cache, const EventContext &ctx) const
Definition: GlobalChi2Fitter.h:1132
Trk::LayerMaterialProperties::alongPostFactor
double alongPostFactor() const
Return method for post update material description of the Layer along normalvector.
Definition: LayerMaterialProperties.h:142
Trk::GlobalChi2Fitter::m_calotoolparam
ToolHandle< IMaterialEffectsOnTrackProvider > m_calotoolparam
Definition: GlobalChi2Fitter.h:1099
Trk::DiscLayer
Definition: DiscLayer.h:45
drawFromPickle.tan
tan
Definition: drawFromPickle.py:36
Trk::GlobalChi2Fitter::calculateTrackErrors
void calculateTrackErrors(GXFTrajectory &, Amg::SymMatrixX &, bool) const
Definition: GlobalChi2Fitter.cxx:8174
TrackSummary.h
Trk::GlobalChi2Fitter::makeTrackFindPerigee
std::unique_ptr< GXFTrackState > makeTrackFindPerigee(const EventContext &, Cache &, GXFTrajectory &, const ParticleHypothesis) const
Definition: GlobalChi2Fitter.cxx:7188
Trk::TrackInfo::BremFit
@ BremFit
A brem fit was performed on this track.
Definition: Tracking/TrkEvent/TrkTrack/TrkTrack/TrackInfo.h:78
Trk::ParametersBase
Definition: ParametersBase.h:55
Trk::TrackingVolume::boundarySurfaces
std::vector< std::shared_ptr< BoundarySurface< TrackingVolume > > > & boundarySurfaces()
Method to return the BoundarySurfaces.
Definition: TrackingVolume.cxx:809
SG::VarHandleKey::initialize
StatusCode initialize(bool used=true)
If this object is used as a property, then this should be called during the initialize phase.
Definition: AthToolSupport/AsgDataHandles/Root/VarHandleKey.cxx:103
Trk::GlobalChi2Fitter::Cache::m_miniter
int m_miniter
Definition: GlobalChi2Fitter.h:228
DeMoUpdate.tmp
string tmp
Definition: DeMoUpdate.py:1167
Trk::muon
@ muon
Definition: ParticleHypothesis.h:31
Trk::GlobalChi2Fitter::Cache::m_fullcovmat
Amg::SymMatrixX m_fullcovmat
Definition: GlobalChi2Fitter.h:231
Trk::FitterStatusCode::ExtrapolationFailureDueToSmallMomentum
@ ExtrapolationFailureDueToSmallMomentum
extrapolation failed due to small momentum
Definition: FitterStatusCode.h:45
Trk::GXFTrajectory::setReferenceParameters
void setReferenceParameters(std::unique_ptr< const TrackParameters >)
Definition: GXFTrajectory.cxx:274
imax
int imax(int i, int j)
Definition: TileLaserTimingTool.cxx:33
Trk::GXFTrajectory::mass
double mass() const
Definition: GXFTrajectory.cxx:621
Trk::LayerMaterialProperties::oppositePreFactor
double oppositePreFactor() const
Return method for pre update material description of the Layer along normalvector.
Definition: LayerMaterialProperties.h:146
Trk::GlobalChi2Fitter::Cache::incrementFitStatus
void incrementFitStatus(enum FitterStatusType status)
Definition: GlobalChi2Fitter.h:268
Trk::LayerIndex::value
int value() const
layerIndex expressed in an integer
Definition: LayerIndex.h:71
ReadFromCoolCompare.os
os
Definition: ReadFromCoolCompare.py:231
Trk::GlobalChi2Fitter::m_fillderivmatrix
Gaudi::Property< bool > m_fillderivmatrix
Definition: GlobalChi2Fitter.h:1169
Trk::BinnedArray::arrayObjects
virtual std::span< T *const > arrayObjects()=0
Return all objects of the Array non-const we can still modify the T.
Trk::GlobalChi2Fitter::tryToConverge
void tryToConverge(const Cache &cache, GXFTrajectory &trajectory, const int it) const
Definition: GlobalChi2Fitter.cxx:5404
Trk::GlobalChi2Fitter::m_scattool
ToolHandle< IMultipleScatteringUpdator > m_scattool
Definition: GlobalChi2Fitter.h:1091
Trk::GlobalChi2Fitter::makeTrack
std::unique_ptr< Track > makeTrack(const EventContext &ctx, Cache &, GXFTrajectory &, const ParticleHypothesis) const
Definition: GlobalChi2Fitter.cxx:7531
MagField::AtlasFieldCache::solenoidOn
bool solenoidOn() const
status of the magnets
Trk::FullField
@ FullField
Field is set to be realistic, but within a given Volume.
Definition: MagneticFieldMode.h:21
SG::ReadHandle::isValid
virtual bool isValid() override final
Can the handle be successfully dereferenced?
Trk::GlobalChi2Fitter::PropagationResult
Definition: GlobalChi2Fitter.h:157
Trk::GlobalChi2Fitter::processTrkVolume
bool processTrkVolume(Cache &, const Trk::TrackingVolume *tvol) const
Definition: GlobalChi2Fitter.cxx:2833
Trk::GXFTrackState::measurementErrors
double * measurementErrors()
Definition: GXFTrackState.cxx:159
Trk::MeasurementBase::localCovariance
const Amg::MatrixX & localCovariance() const
Interface method to get the localError.
Definition: MeasurementBase.h:138
Trk::TrackStateOnSurface::BremPoint
@ BremPoint
This represents a brem point on the track, and so will contain TrackParameters and MaterialEffectsBas...
Definition: TrackStateOnSurface.h:109
Trk::GlobalChi2Fitter::S_NOT_ENOUGH_MEAS
@ S_NOT_ENOUGH_MEAS
Definition: GlobalChi2Fitter.h:180
Trk::GlobalChi2Fitter::numericalDerivatives
std::optional< TransportJacobian > numericalDerivatives(const EventContext &ctx, const TrackParameters *, const Surface &, PropDirection, const MagneticFieldProperties &) const
Definition: GlobalChi2Fitter.cxx:8305
Trk::numberOfPixelHoles
@ numberOfPixelHoles
number of pixels which have a ganged ambiguity.
Definition: Tracking/TrkEvent/TrkTrackSummary/TrkTrackSummary/TrackSummary.h:59
Trk::MeasurementSet
std::vector< const MeasurementBase * > MeasurementSet
vector of fittable measurements
Definition: FitterTypes.h:30
Trk::CylinderLayer
Definition: CylinderLayer.h:43
Trk::GlobalChi2Fitter::m_acceleration
Gaudi::Property< bool > m_acceleration
Definition: GlobalChi2Fitter.h:1181
Trk::PrepRawData
Definition: PrepRawData.h:62
Trk::MeasurementBase
Definition: MeasurementBase.h:58
Trk::Track::trackParameters
const DataVector< const TrackParameters > * trackParameters() const
Return a pointer to a vector of TrackParameters.
Definition: Tracking/TrkEvent/TrkTrack/src/Track.cxx:97
Trk::ParticleMasses::mass
constexpr double mass[PARTICLEHYPOTHESES]
the array of masses
Definition: ParticleHypothesis.h:56
Trk::MeasurementBaseType::Segment
@ Segment
Definition: MeasurementBase.h:47
Trk::NoField
@ NoField
Field is set to 0., 0., 0.,.
Definition: MagneticFieldMode.h:18
python.PyKernel.detStore
detStore
Definition: PyKernel.py:41
Trk::CylinderVolumeBounds
Definition: CylinderVolumeBounds.h:70
Trk::Track::perigeeParameters
const Perigee * perigeeParameters() const
return Perigee.
Definition: Tracking/TrkEvent/TrkTrack/src/Track.cxx:163
Trk::GXFTrajectory::setBrems
void setBrems(std::vector< double > &)
Definition: GXFTrajectory.cxx:565
Trk
Ensure that the ATLAS eigen extensions are properly loaded.
Definition: FakeTrackBuilder.h:9
Trk::ParametersBase::pT
double pT() const
Access method for transverse momentum.
Trk::SurfaceType::Perigee
@ Perigee
Trk::GlobalChi2Fitter::addMaterial
void addMaterial(const EventContext &ctx, Cache &, GXFTrajectory &, const TrackParameters *, ParticleHypothesis) const
Definition: GlobalChi2Fitter.cxx:3634
GXF::LayerSort2
Definition: LayerSort.h:18
Trk::TrackStateOnSurface
represents the track state (measurement, material, fit parameters and quality) at a surface.
Definition: TrackStateOnSurface.h:71
Trk::GlobalChi2Fitter::updatePixelROTs
void updatePixelROTs(GXFTrajectory &, Amg::SymMatrixX &, Amg::VectorX &, const EventContext &evtctx) const
Update the Pixel ROT using the current trajectory/local track parameters.
Definition: GlobalChi2Fitter.cxx:6221
python.EventInfoMgtInit.release
release
Definition: EventInfoMgtInit.py:23
WriteBchToCool.beg
beg
Definition: WriteBchToCool.py:69
TauJetParameters::discriminant
@ discriminant
Definition: TauJetParameters.h:166
remainder
std::vector< std::string > remainder(const std::vector< std::string > &v1, const std::vector< std::string > &v2)
Definition: compareFlatTrees.cxx:44
Trk::Surface::bounds
virtual const SurfaceBounds & bounds() const =0
Surface Bounds method.
Trk::GlobalChi2Fitter::Cache::m_phiweight
std::vector< double > m_phiweight
Definition: GlobalChi2Fitter.h:217
Trk::MeasurementBase::associatedSurface
virtual const Surface & associatedSurface() const =0
Interface method to get the associated Surface.
Trk::d0
@ d0
Definition: ParamDefs.h:63
Trk::GlobalChi2Fitter::Cache::m_fittercode
FitterStatusCode m_fittercode
Definition: GlobalChi2Fitter.h:239
RIO_OnTrack.h
ActsTrk::to_string
std::string to_string(const DetectorType &type)
Definition: GeometryDefs.h:34
plotBeamSpotMon.b
b
Definition: plotBeamSpotMon.py:76
Trk::GXFMaterialEffects::delta_p
double delta_p() const
Definition: GXFMaterialEffects.cxx:178
Trk::PrepRawDataType::PixelCluster
@ PixelCluster
Trk::TrackStateOnSurface::InertMaterial
@ InertMaterial
This represents inert material, and so will contain MaterialEffectsBase.
Definition: TrackStateOnSurface.h:105
Trk::GlobalChi2Fitter::runTrackCleanerSilicon
GXFTrajectory * runTrackCleanerSilicon(const EventContext &ctx, Cache &, GXFTrajectory &, Amg::SymMatrixX &, Amg::SymMatrixX &, Amg::VectorX &, bool) const
Definition: GlobalChi2Fitter.cxx:6511
Trk::nonInteracting
@ nonInteracting
Definition: ParticleHypothesis.h:28
Trk::GXFMaterialEffects::isKink
bool isKink() const
Definition: GXFMaterialEffects.cxx:190
AtlasDetectorID::is_indet
bool is_indet(Identifier id) const
Definition: AtlasDetectorID.h:690
charge
double charge(const T &p)
Definition: AtlasPID.h:986
Trk::GlobalChi2Fitter::m_chi2cut
Gaudi::Property< double > m_chi2cut
Definition: GlobalChi2Fitter.h:1192
InDetDD::SiDetectorElement
Definition: SiDetectorElement.h:109
Trk::FitterStatusCode::NoConvergence
@ NoConvergence
Definition: FitterStatusCode.h:55
MaterialLayer.h
Trk::MeasurementBase::globalPosition
virtual const Amg::Vector3D & globalPosition() const =0
Interface method to get the global Position.
SG::CondHandleKey::initialize
StatusCode initialize(bool used=true)
Trk::GXFTrajectory::scatteringAngles
std::vector< std::pair< double, double > > & scatteringAngles()
Definition: GXFTrajectory.cxx:514
Trk::GXFTrajectory::errors
Amg::VectorX & errors()
Definition: GXFTrajectory.cxx:593
Trk::SurfaceBounds::Trapezoid
@ Trapezoid
Definition: SurfaceBounds.h:67
Amg::Vector3D
Eigen::Matrix< double, 3, 1 > Vector3D
Definition: GeoPrimitives.h:47
Trk::RIO_OnTrack::prepRawData
virtual const Trk::PrepRawData * prepRawData() const =0
returns the PrepRawData (also known as RIO) object to which this RIO_OnTrack is associated.
Trk::MeasurementBaseType::RIO_OnTrack
@ RIO_OnTrack
Definition: MeasurementBase.h:49
Trk::MeasurementBaseType::VertexOnTrack
@ VertexOnTrack
Definition: MeasurementBase.h:52
Trk::GlobalChi2Fitter::updateFitParameters
FitterStatusCode updateFitParameters(GXFTrajectory &, const Amg::VectorX &, const Amg::SymMatrixX &) const
Method to update peregee parameters, scattering angles, and brems.
Definition: GlobalChi2Fitter.cxx:6126
dq_make_web_display.rv
def rv
Definition: dq_make_web_display.py:218
ParticleGun_SamplingFraction.radius
radius
Definition: ParticleGun_SamplingFraction.py:96
Trk::kaon
@ kaon
Definition: ParticleHypothesis.h:33
SiDetectorElement.h
python.LumiBlobConversion.pos
pos
Definition: LumiBlobConversion.py:16
Trk::GlobalChi2Fitter::finalize
virtual StatusCode finalize() override
Definition: GlobalChi2Fitter.cxx:289
Trk::GlobalChi2Fitter::Cache::m_acceleration
bool m_acceleration
Definition: GlobalChi2Fitter.h:213
Trk::GlobalChi2Fitter::S_SUCCESSFUL_FITS
@ S_SUCCESSFUL_FITS
Definition: GlobalChi2Fitter.h:178
Trk::MeasurementBase::localParameters
const LocalParameters & localParameters() const
Interface method to get the LocalParameters.
Definition: MeasurementBase.h:132
Trk::GlobalChi2Fitter::initialize
virtual StatusCode initialize() override
Definition: GlobalChi2Fitter.cxx:210
Trk::GlobalChi2Fitter::compensatePhiWeights
static void compensatePhiWeights(Cache &cache, GXFTrajectory &trajectory, Amg::SymMatrixX &a)
Definition: GlobalChi2Fitter.cxx:5953
InDet::PixelCluster
Definition: InnerDetector/InDetRecEvent/InDetPrepRawData/InDetPrepRawData/PixelCluster.h:49
DataVector::end
const_iterator end() const noexcept
Return a const_iterator pointing past the end of the collection.
Trk::FitterStatusCode::InvalidAngles
@ InvalidAngles
Definition: FitterStatusCode.h:56
Trk::Track::measurementsOnTrack
const DataVector< const MeasurementBase > * measurementsOnTrack() const
return a pointer to a vector of MeasurementBase (NOT including any that come from outliers).
Definition: Tracking/TrkEvent/TrkTrack/src/Track.cxx:178
Trk::pixelCluster
@ pixelCluster
Definition: MeasurementType.h:22
Trk::GlobalChi2Fitter::Cache::m_getmaterialfromtrack
bool m_getmaterialfromtrack
Definition: GlobalChi2Fitter.h:210
Trk::Surface::associatedLayer
const Trk::Layer * associatedLayer() const
return the associated Layer
CylinderBounds.h
Trk::ParametersBase::momentum
const Amg::Vector3D & momentum() const
Access method for the momentum.
Trk::GXFTrajectory::addMaterialState
void addMaterialState(std::unique_ptr< GXFTrackState >, int index=-1)
Definition: GXFTrajectory.cxx:224
Trk::GlobalChi2Fitter::backupCombinationStrategy
Track * backupCombinationStrategy(const EventContext &ctx, Cache &, const Track &, const Track &, GXFTrajectory &, std::vector< MaterialEffectsOnTrack > &) const
Definition: GlobalChi2Fitter.cxx:1242
Trk::vertex
@ vertex
Definition: MeasurementType.h:21
DeMoScan.index
string index
Definition: DeMoScan.py:362
Trk::MaterialProperties
Definition: MaterialProperties.h:40
TrackingVolume.h
Trk::ResidualPull::Biased
@ Biased
RP with track state including the hit.
Definition: ResidualPull.h:55
a
TList * a
Definition: liststreamerinfos.cxx:10
Trk::MaterialEffectsOnTrack::energyLoss
const EnergyLoss * energyLoss() const
returns the energy loss object.
Trk::PerigeeSurface::createUniqueTrackParameters
virtual Surface::ChargedTrackParametersUniquePtr createUniqueTrackParameters(double l1, double l2, double phi, double theta, double qop, std::optional< AmgSymMatrix(5)> cov=std::nullopt) const override final
Use the Surface as a ParametersBase constructor, from local parameters - charged.
Definition: PerigeeSurface.cxx:98
AtlasDetectorID::is_muon
bool is_muon(Identifier id) const
Definition: AtlasDetectorID.h:708
python.CaloAddPedShiftConfig.int
int
Definition: CaloAddPedShiftConfig.py:45
Trk::SurfaceBounds::Disc
@ Disc
Definition: SurfaceBounds.h:63
Trk::TrackInfo::GlobalChi2Fitter
@ GlobalChi2Fitter
Track's from Thijs' global chi^2 fitter.
Definition: Tracking/TrkEvent/TrkTrack/TrkTrack/TrackInfo.h:56
Trk::GXFMaterialEffects::sigmaDeltaE
double sigmaDeltaE() const
Definition: GXFMaterialEffects.cxx:139
Trk::GlobalChi2Fitter::makeProtoStateFromMeasurement
void makeProtoStateFromMeasurement(Cache &, GXFTrajectory &, const MeasurementBase *, const TrackParameters *trackpar=nullptr, bool isoutlier=false, int index=-1) const
Definition: GlobalChi2Fitter.cxx:2660
Trk::GlobalChi2Fitter::m_p
Gaudi::Property< double > m_p
Definition: GlobalChi2Fitter.h:1191
CSV_InDetExporter.old
old
Definition: CSV_InDetExporter.py:145
Trk::GXFTrajectory::findFirstLastMeasurement
std::pair< GXFTrackState *, GXFTrackState * > findFirstLastMeasurement(void)
Definition: GXFTrajectory.cxx:639
Amg::intersect
std::optional< double > intersect(const AmgVector(N)&posA, const AmgVector(N)&dirA, const AmgVector(N)&posB, const AmgVector(N)&dirB)
Calculates the point B' along the line B that's closest to a second line A.
Definition: GeoPrimitivesHelpers.h:347
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
Trk::GXFTrajectory::hasKink
bool hasKink(void)
Definition: GXFTrajectory.cxx:659
Trk::PlaneSurface
Definition: PlaneSurface.h:64
Trk::GXFTrackState::setTrackParameters
void setTrackParameters(std::unique_ptr< const TrackParameters >)
Definition: GXFTrackState.cxx:146
Amg::RotationMatrix3D
Eigen::Matrix< double, 3, 3 > RotationMatrix3D
Definition: GeoPrimitives.h:49
PlaneSurface.h
Trk::GXFMaterialEffects::materialProperties
const MaterialProperties * materialProperties() const
Definition: GXFMaterialEffects.cxx:233
eFEXNTuple.delta_phi
def delta_phi(phi1, phi2)
Definition: eFEXNTuple.py:15
Trk::GlobalChi2Fitter::m_maxitPixelROT
Gaudi::Property< int > m_maxitPixelROT
Definition: GlobalChi2Fitter.h:1200
Trk::TrackingVolume::confinedVolumes
const TrackingVolumeArray * confinedVolumes() const
Return the subLayer array.
Trk::GXFTrackState::hasTrackCovariance
bool hasTrackCovariance(void) const
Definition: GXFTrackState.cxx:259
DeMoScan.first
bool first
Definition: DeMoScan.py:534
Trk::RIO_OnTrack::identify
Identifier identify() const
return the identifier -extends MeasurementBase
Definition: RIO_OnTrack.h:152
Trk::MaterialEffectsOnTrack::scatteringAngles
const ScatteringAngles * scatteringAngles() const
returns the MCS-angles object.
Trk::GXFTrajectory::prevchi2
double prevchi2() const
Definition: GXFTrajectory.cxx:498
Trk::GlobalChi2Fitter::fitIm
Track * fitIm(const EventContext &ctx, Cache &cache, const Track &inputTrack, const RunOutlierRemoval runOutlier, const ParticleHypothesis matEffects) const
Definition: GlobalChi2Fitter.cxx:1849
Trk::unique_clone
std::unique_ptr< T > unique_clone(const T *v)
Definition: unique_clone.h:8
Trk::qOverP
@ qOverP
perigee
Definition: ParamDefs.h:67
Trk::SurfaceType::Disc
@ Disc
Trk::GlobalChi2Fitter::m_scalefactor
Gaudi::Property< double > m_scalefactor
Definition: GlobalChi2Fitter.h:1193
Trk::TrackState::CSC
@ CSC
Definition: TrackStateDefs.h:32
Trk::SurfaceType::Cylinder
@ Cylinder
Trk::GXFTrackState::derivatives
Amg::MatrixX & derivatives()
Definition: GXFTrackState.h:152
get
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
Definition: hcg.cxx:127
Trk::Layer::layerMaterialProperties
const LayerMaterialProperties * layerMaterialProperties() const
getting the LayerMaterialProperties including full/pre/post update
Trk::GXFTrackState::materialEffects
GXFMaterialEffects * materialEffects()
Definition: GXFTrackState.h:164
Trk::TrackStateOnSurface::Scatterer
@ Scatterer
This represents a scattering point on the track, and so will contain TrackParameters and MaterialEffe...
Definition: TrackStateOnSurface.h:113
DiscSurface.h
python.SystemOfUnits.s
float s
Definition: SystemOfUnits.py:147
GlobalChi2Fitter.h
Trk::GlobalChi2Fitter::m_updator
ToolHandle< IUpdator > m_updator
Definition: GlobalChi2Fitter.h:1089
Trk::GlobalChi2Fitter::addIDMaterialFast
void addIDMaterialFast(const EventContext &ctx, Cache &cache, GXFTrajectory &track, const TrackParameters *parameters, ParticleHypothesis part) const
A faster strategy for adding scatter material to tracks, works only for inner detector tracks.
Definition: GlobalChi2Fitter.cxx:3465
Trk::GlobalChi2Fitter::fit
virtual std::unique_ptr< Track > fit(const EventContext &ctx, const PrepRawDataSet &, const TrackParameters &, const RunOutlierRemoval runOutlier=false, const ParticleHypothesis matEffects=nonInteracting) const override final
Definition: GlobalChi2Fitter.cxx:2180
physics_parameters.parameters
parameters
Definition: physics_parameters.py:144
Trk::MeasurementBaseType::PseudoMeasurementOnTrack
@ PseudoMeasurementOnTrack
Definition: MeasurementBase.h:51
Trk::FitQuality::chiSquared
double chiSquared() const
returns the of the overall track fit
Definition: FitQuality.h:56
Trk::GXFTrajectory::numberOfTRTHits
int numberOfTRTHits() const
Definition: GXFTrajectory.cxx:433
AtlasDetectorID::is_stgc
bool is_stgc(Identifier id) const
Definition: AtlasDetectorID.h:931
beamspotman.qual
qual
Definition: beamspotman.py:479
Track
Definition: TriggerChamberClusterOnTrackCreator.h:21
Trk::SurfaceType::Plane
@ Plane
Trk::GlobalChi2Fitter::m_calomat
Gaudi::Property< bool > m_calomat
Definition: GlobalChi2Fitter.h:1167
Trk::GXFTrajectory::setChi2
void setChi2(double)
Definition: GXFTrajectory.cxx:502
Trk::phi
@ phi
Definition: ParamDefs.h:75
Trk::GlobalChi2Fitter::m_rejectLargeNScat
Gaudi::Property< bool > m_rejectLargeNScat
Definition: GlobalChi2Fitter.h:1186
Trk::GXFMaterialEffects::setDeltaE
void setDeltaE(double)
Definition: GXFMaterialEffects.cxx:170
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::GlobalChi2Fitter::fillFirstLastMeasurement
static void fillFirstLastMeasurement(Cache &cache, GXFTrajectory &trajectory)
Definition: GlobalChi2Fitter.cxx:5646
Trk::GlobalChi2Fitter::m_trtrecal
Gaudi::Property< bool > m_trtrecal
Definition: GlobalChi2Fitter.h:1173
Trk::RIO_OnTrack::associatedSurface
virtual const Surface & associatedSurface() const override=0
returns the surface for the local to global transformation
Trk::GXFTrajectory::setNumberOfScatterers
void setNumberOfScatterers(int)
Definition: GXFTrajectory.cxx:456
Trk::ClusterSplitProbabilityContainer::splitProbability
const ProbabilityInfo & splitProbability(const PrepRawData *cluster) const
Definition: ClusterSplitProbabilityContainer.h:35
xAOD::track
@ track
Definition: TrackingPrimitives.h:513
Trk::GXFTrajectory::setNumberOfBrems
void setNumberOfBrems(int)
Definition: GXFTrajectory.cxx:464
Trk::GXFTrajectory::reset
void reset()
Definition: GXFTrajectory.cxx:403
Trk::TrackState::SCT
@ SCT
Definition: TrackStateDefs.h:29
Trk::nonInteractingMuon
@ nonInteractingMuon
Definition: ParticleHypothesis.h:39
Trk::BinnedArray
Definition: BinnedArray.h:36
Trk::GXFTrajectory::m_fieldprop
MagneticFieldProperties m_fieldprop
Definition: GXFTrajectory.h:112
Trk::ParamDefsAccessor::pardef
static constexpr std::array< ParamDefs, 6 > pardef
Constructor.
Definition: ParamDefs.h:94
drawFromPickle.sin
sin
Definition: drawFromPickle.py:36
PowhegControl_ttFCNC_NLO.params
params
Definition: PowhegControl_ttFCNC_NLO.py:226
Trk::LayerMaterialProperties::alongPreFactor
double alongPreFactor() const
Return method for pre update material description of the Layer along normalvector.
Definition: LayerMaterialProperties.h:138
Trk::x
@ x
Definition: ParamDefs.h:55
Trk::SurfaceType::Line
@ Line
Trk::consistentSurfaces
bool consistentSurfaces(U)
Definition: SurfaceConsistencyCheck.h:17
Trk::GlobalChi2Fitter::S_HIGH_CHI2
@ S_HIGH_CHI2
Definition: GlobalChi2Fitter.h:184
FitQuality.h
Trk::MaterialEffectsBase::derivedType
virtual MaterialEffectsDerivedType derivedType() const =0
Returns the concrete derived type.
Trk::GlobalChi2Fitter::Cache::m_idmat
bool m_idmat
Definition: GlobalChi2Fitter.h:208
python.CaloScaleNoiseConfig.ts
ts
Definition: CaloScaleNoiseConfig.py:87
Trk::loc1
@ loc1
Definition: ParamDefs.h:34
Trk::Surface
Definition: Tracking/TrkDetDescr/TrkSurfaces/TrkSurfaces/Surface.h:79
Trk::GXFTrajectory::weightedResidualDerivatives
Amg::MatrixX & weightedResidualDerivatives()
Definition: GXFTrajectory.cxx:600
Trk::TrackInfo::trackFitter
const TrackFitter & trackFitter() const
Access methods for track fitter.
Trk::GXFMaterialEffects::deltaE
double deltaE() const
Definition: GXFMaterialEffects.cxx:131
Trk::GlobalChi2Fitter::Cache::m_sirecal
bool m_sirecal
Definition: GlobalChi2Fitter.h:209
pow
constexpr int pow(int base, int exp) noexcept
Definition: ap_fixedTest.cxx:15
Trk::numberOfSCTDoubleHoles
@ numberOfSCTDoubleHoles
Definition: Tracking/TrkEvent/TrkTrackSummary/TrkTrackSummary/TrackSummary.h:75
Trk::TrackingVolume
Definition: TrackingVolume.h:119
error
Definition: IImpactPoint3dEstimator.h:70
Trk::GXFTrajectory::setScatteringAngles
void setScatteringAngles(std::vector< std::pair< double, double > > &)
Definition: GXFTrajectory.cxx:549
Amg::distance
float distance(const Amg::Vector3D &p1, const Amg::Vector3D &p2)
calculates the distance between two point in 3D space
Definition: GeoPrimitivesHelpers.h:54
Trk::Surface::transform
const Amg::Transform3D & transform() const
Returns HepGeom::Transform3D by reference.
unique_clone.h
Trk::GlobalChi2Fitter::Cache::m_matfilled
bool m_matfilled
Definition: GlobalChi2Fitter.h:212
Trk::GXFMaterialEffects::associatedSurface
const Surface & associatedSurface() const
Definition: GXFMaterialEffects.cxx:202
DataVector::size
size_type size() const noexcept
Returns the number of elements in the collection.
Trk::TrackState::STGC
@ STGC
Definition: TrackStateDefs.h:41
Trk::GlobalChi2Fitter::Cache::m_extmat
bool m_extmat
Definition: GlobalChi2Fitter.h:207
python.ParticleTypeUtil.info
def info
Definition: ParticleTypeUtil.py:87
Trk::MaterialEffectsBase::associatedSurface
const Surface & associatedSurface() const
returns the surface to which these m.eff. are associated.
Trk::TrackInfo::trackProperties
bool trackProperties(const TrackProperties &property) const
Access methods for track properties.
python.AutoConfigFlags.msg
msg
Definition: AutoConfigFlags.py:7
Trk::GXFTrajectory::converged
bool converged() const
Definition: GXFTrajectory.cxx:413
Trk::GlobalChi2Fitter::ensureValidEntranceCalo
bool ensureValidEntranceCalo(const EventContext &ctx, Cache &cache) const
Definition: GlobalChi2Fitter.cxx:8534
Trk::Surface::type
constexpr virtual SurfaceType type() const =0
Returns the Surface type to avoid dynamic casts.
mag
Scalar mag() const
mag method
Definition: AmgMatrixBasePlugin.h:26
Trk::GlobalChi2Fitter::updateEnergyLoss
std::variant< std::unique_ptr< const TrackParameters >, FitterStatusCode > updateEnergyLoss(const Surface &, const GXFMaterialEffects &, const TrackParameters &, double, int) const
Definition: GlobalChi2Fitter.cxx:7960
DataVector::empty
bool empty() const noexcept
Returns true if the collection is empty.
Trk::GXFTrajectory::numberOfOutliers
int numberOfOutliers() const
Definition: GXFTrajectory.cxx:425
Trk::phi0
@ phi0
Definition: ParamDefs.h:65
Trk::TrackStateOnSurface::Measurement
@ Measurement
This is a measurement, and will at least contain a Trk::MeasurementBase.
Definition: TrackStateOnSurface.h:101
Trk::GlobalChi2Fitter::calculateDerivatives
static void calculateDerivatives(GXFTrajectory &)
Definition: GlobalChi2Fitter.cxx:8002
Trk::GXFTrajectory::trackStates
const std::vector< std::unique_ptr< GXFTrackState > > & trackStates() const
Definition: GXFTrajectory.cxx:578
TrackStateOnSurface.h
IDTPM::nSiHits
float nSiHits(const U &p)
Definition: TrackParametersHelper.h:427
Trk::TrackInfo::particleHypothesis
ParticleHypothesis particleHypothesis() const
Returns the particle hypothesis used for Track fitting.
Trk::StraightLineSurface
Definition: StraightLineSurface.h:51
DataVector::begin
const_iterator begin() const noexcept
Return a const_iterator pointing at the beginning of the collection.
AtlasDetectorID::is_mdt
bool is_mdt(Identifier id) const
Definition: AtlasDetectorID.h:866
fitman.k
k
Definition: fitman.py:528
Trk::DiscBounds
Definition: DiscBounds.h:44
Trk::ParametersBase::clone
virtual ParametersBase< DIM, T > * clone() const override=0
clone method for polymorphic deep copy
Trk::GXFTrajectory::numberOfUpstreamBrems
int numberOfUpstreamBrems() const
Definition: GXFTrajectory.cxx:479
Trk::CylinderBounds::halflengthZ
double halflengthZ() const
This method returns the halflengthZ.
Trk::GlobalChi2Fitter::m_useCaloTG
Gaudi::Property< bool > m_useCaloTG
Definition: GlobalChi2Fitter.h:1185
Trk::GlobalChi2Fitter::fillDerivatives
void fillDerivatives(GXFTrajectory &traj) const
Definition: GlobalChi2Fitter.cxx:5497
Trk::SurfaceBounds::Cylinder
@ Cylinder
Definition: SurfaceBounds.h:61
Trk::CylinderBounds::r
virtual double r() const override final
This method returns the radius.
Trk::FitterStatusCode::OutlierLogicFailure
@ OutlierLogicFailure
outlier logic failed
Definition: FitterStatusCode.h:48
Trk::PerigeeSurface::straightLineDistanceEstimate
virtual DistanceSolution straightLineDistanceEstimate(const Amg::Vector3D &pos, const Amg::Vector3D &dir) const override final
fast straight line distance evaluation to Surface
Definition: PerigeeSurface.cxx:269
Trk::Layer
Definition: Layer.h:72
python.LArMinBiasAlgConfig.float
float
Definition: LArMinBiasAlgConfig.py:65
Trk::GlobalChi2Fitter::m_clusterSplitProbContainer
SG::ReadHandleKey< Trk::ClusterSplitProbabilityContainer > m_clusterSplitProbContainer
Definition: GlobalChi2Fitter.h:1202
Trk::GXFTrackState::setSinStereo
void setSinStereo(double)
Definition: GXFTrackState.cxx:178
Trk::GXFTrajectory::chi2
double chi2() const
Definition: GXFTrajectory.cxx:494
Amg::SymMatrixX
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic > SymMatrixX
Definition: EventPrimitives.h:28
Trk::TrackInfo::Unknown
@ Unknown
Track fitter not defined.
Definition: Tracking/TrkEvent/TrkTrack/TrkTrack/TrackInfo.h:41
Trk::GlobalChi2Fitter::Cache::m_reintoutl
bool m_reintoutl
Definition: GlobalChi2Fitter.h:211
Identifier
Definition: IdentifierFieldParser.cxx:14
Trk::SurfaceBounds::r
virtual double r() const =0
Interface method for the maximal extension or the radius.