ATLAS Offline Software
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
GlobalChi2Fitter.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3 */
7 
9 
14 #include "TrkSurfaces/DiscBounds.h"
19 
20 #include "TrkGeometry/Layer.h"
22 #include "TrkGeometry/DiscLayer.h"
25 
26 #include "TrkVolumes/Volume.h"
28 
30 
34 
38 #include "TrkTrack/Track.h"
41 
48 
50 
53 
56 
57 #include "CLHEP/Units/SystemOfUnits.h"
58 
61 
64 #include "CxxUtils/inline_hints.h"
65 
67 #include "LayerSort.h"
69 #include "cmath"
70 #include <Eigen/Dense>
71 #include <Eigen/StdVector>
72 
73 #include <exception>
74 #include <memory>
75 
76 using CLHEP::MeV;
77 using CLHEP::mm;
78 
79 namespace {
80  double getDistance(const Trk::DistanceSolution& distsol) {
81  if (distsol.numberOfSolutions() == 1) {
82  return distsol.first();
83  } if (distsol.numberOfSolutions() == 2) {
84  return (
85  std::abs(distsol.first()) < std::abs(distsol.second()) ?
86  distsol.first() :
87  distsol.second()
88  );
89  } else {
90  return 0;
91  }
92  }
93  //This function used to avoid FPE divide by zero or overflow by limiting the q/p values to a
94  //more limited range
95  double
96  limitInversePValue(double qOverP){
97  const double magnitude = std::abs(qOverP);
98  //limits found empirically to leave the 25-event q431 digest unchanged
99  constexpr double maxP{100.*10e6*MeV};
100  constexpr double minP{1.e-3*MeV};
101  constexpr double lo {1./maxP};
102  constexpr double hi {1./minP};
103  double limited = std::clamp(magnitude, lo, hi);
104  return std::copysign(limited, qOverP);
105  }
106 
107 
108  std::pair<const Trk::TrackParameters *, const Trk::TrackParameters *> getFirstLastIdPar(const Trk::Track & track) {
109  const Trk::TrackParameters *firstidpar = nullptr;
110  const Trk::TrackParameters *lastidpar = nullptr;
111 
112  DataVector<const Trk::TrackParameters>::const_iterator parit = track.trackParameters()->begin();
113 
114  while ((firstidpar == nullptr) && parit != track.trackParameters()->end()) {
115  if (
116  ((**parit).covariance() != nullptr) &&
117  (**parit).associatedSurface().type() == Trk::SurfaceType::Perigee)
118  {
119  firstidpar = *parit;
120  }
121 
122  ++parit;
123  }
124 
125  parit = track.trackParameters()->end();
126  do {
127  --parit;
128  if (
129  ((**parit).covariance() != nullptr) &&
130  (**parit).associatedSurface().type() == Trk::SurfaceType::Perigee)
131  {
132  lastidpar = *parit;
133  }
134  } while ((lastidpar == nullptr) && parit != track.trackParameters()->begin());
135 
136  return std::make_pair(firstidpar, lastidpar);
137  }
138 
139  Trk::PropDirection invertPropdir(Trk::PropDirection i) {
140  if (i == Trk::alongMomentum) {
141  return Trk::oppositeMomentum;
142  } else if (i == Trk::oppositeMomentum) {
143  return Trk::alongMomentum;
144  } else {
145  return Trk::anyDirection;
146  }
147  }
148 
149  bool trackParametersClose(const Trk::TrackParameters & a, const Trk::TrackParameters & b, double e) {
150  return (
151  std::abs(a.parameters()[0] - b.parameters()[0]) < e &&
152  std::abs(a.parameters()[1] - b.parameters()[1]) < e &&
153  std::abs(a.parameters()[2] - b.parameters()[2]) < e
154  );
155  }
156 
157 // We compile this package with optimization, even in debug builds; otherwise,
158 // the heavy use of Eigen makes it too slow. However, from here we may call
159 // to out-of-line Eigen code that is linked from other DSOs; in that case,
160 // it would not be optimized. Avoid this by forcing all Eigen code
161 // to be inlined here if possible.
163  void
164  calculateJac(Eigen::Matrix<double, 5, 5> &jac,
165  Eigen::Matrix<double, 5, 5> &out,
166  int jmin, int jmax) {
167  out = (jac * out);
168 
169  if (jmin > 0) {
170  out.block(0, 0, 4, jmin).setZero();
171  }
172 
173  if (jmax < 4) {
174  out.block(0, jmax + 1, 4, 5 - (jmax + 1)).setZero();
175  }
176 
177  out(4, 4) = jac(4, 4);
178  }
179 
180  /*
181  * Analyse a 2x2 covariance matrix and find
182  * - the smaller eigenvalue
183  * - the stereo angle
184  * This assumes, that the covariance matrix is valid, i.e. symmetric.
185  * TODO: Find a source for the stereo angle calculation
186  */
187  std::pair<double, double> principalComponentAnalysis2x2(const Amg::MatrixX & mat) {
188  const double trace = mat(0, 0) + mat(1, 1);
189  const double diagonalProduct = mat(0, 0) * mat(1, 1);
190  const double mat01Sq = mat(0, 1) * mat(0, 1);
191  const double discriminant = std::sqrt(trace * trace - 4. * (diagonalProduct - mat01Sq));
192 
193  const double eigenValueSmall = 0.5 * (trace - discriminant);
194  const double stereoAngle = 0.5 * std::asin(2 * mat(0, 1) / (-discriminant));
195 
196  return std::make_pair(eigenValueSmall, stereoAngle);
197  }
198 } //end of anonymous namespace
199 
200 namespace Trk {
202  const std::string & t,
203  const std::string & n,
204  const IInterface * p
205  ):
206  base_class(t, n, p),
207  m_idVolume(nullptr, std::make_unique<Trk::CylinderVolumeBounds>(560, 2750).release())
208  {
209  }
210 
213 
214  if (!m_ROTcreator.name().empty()) {
215  ATH_CHECK(m_ROTcreator.retrieve());
216  }
217 
218  if (!m_broadROTcreator.name().empty()) {
219  ATH_CHECK(m_broadROTcreator.retrieve());
220  }
221 
222  ATH_CHECK(m_updator.retrieve());
223  ATH_CHECK(m_extrapolator.retrieve());
224  ATH_CHECK(m_navigator.retrieve());
226  ATH_CHECK(m_propagator.retrieve());
227 
228  if (!m_boundaryCheckTool.name().empty()) {
229  ATH_CHECK(m_boundaryCheckTool.retrieve());
230  } else if (m_holeSearch.value()) {
231  ATH_MSG_ERROR("Hole search requested but no boundary check tool provided.");
232  return StatusCode::FAILURE;
233  }
234 
235  if (m_calomat) {
236  ATH_CHECK(m_calotool.retrieve());
237 
238  if (!m_calotoolparam.empty()) {
239  ATH_CHECK(m_calotoolparam.retrieve());
240  }
241  } else{
242  m_calotool.disable();
243  m_calotoolparam.disable();
244  }
245 
246  ATH_CHECK(m_scattool.retrieve());
247  ATH_CHECK(m_elosstool.retrieve());
248 
249  if (!m_matupdator.name().empty()) {
250  ATH_CHECK(m_matupdator.retrieve());
251  }
252 
253  // need an Atlas id-helper to identify sub-detectors, take the one from detStore
254  ATH_CHECK(detStore()->retrieve(m_DetID, "AtlasID"));
255 
257  ATH_MSG_WARNING("FillDerivativeMatrix option selected, switching off acceleration!");
258  m_acceleration = false;
259  }
260 
261  if (!m_trackingGeometryReadKey.key().empty()){
262  ATH_CHECK( m_trackingGeometryReadKey.initialize());
263  }
264  if (m_useCaloTG) {
265  ATH_CHECK(m_caloMaterialProvider.retrieve());
266  ATH_MSG_INFO(m_caloMaterialProvider << " retrieved ");
267  }
268  else{
269  m_caloMaterialProvider.disable();
270  }
271 
273 
274  /*
275  * Doing a hole search only makes sense if we are also creating a track
276  * summary, because the track summary is the only way for us to export the
277  * hole search information out of the fitter. For this reason, we disable
278  * the hole search in the case that track summaries are disabled.
279  */
280  if (m_holeSearch.value() && !m_createSummary.value()) {
281  ATH_MSG_ERROR("Hole search requested but track summaries are disabled.");
282  return StatusCode::FAILURE;
283  }
284 
285  ATH_MSG_INFO("fixed momentum: " << m_p);
286 
287  return StatusCode::SUCCESS;
288  }
289 
291 
292  ATH_MSG_INFO(m_fit_status[S_FITS] << " attempted track fits");
293  if (m_fit_status[S_FITS] > 0) {
294  ATH_MSG_INFO(m_fit_status[S_SUCCESSFUL_FITS] << " successful track fits");
295  ATH_MSG_INFO(m_fit_status[S_MAT_INV_FAIL]
296  << " track fits failed because of a matrix inversion failure");
297  ATH_MSG_INFO(m_fit_status[S_NOT_ENOUGH_MEAS]
298  << " tracks were rejected by the outlier logic");
299  ATH_MSG_INFO(m_fit_status[S_PROPAGATION_FAIL]
300  << " track fits failed because of a propagation failure");
301  ATH_MSG_INFO(m_fit_status[S_INVALID_ANGLES]
302  << " track fits failed because of an invalid angle (theta/phi)");
303  ATH_MSG_INFO(m_fit_status[S_NOT_CONVERGENT]
304  << " track fits failed because the fit did not converge");
305  ATH_MSG_INFO(m_fit_status[S_HIGH_CHI2]
306  << " tracks did not pass the chi^2 cut");
307  ATH_MSG_INFO(m_fit_status[S_LOW_MOMENTUM]
308  << " tracks were killed by the energy loss update");
309  }
310 
311  return StatusCode::SUCCESS;
312  }
313 
314  // combined fit of two tracks
315  // --------------------------------
316  std::unique_ptr<Track>
318  const EventContext& ctx,
319  const Track& intrk1,
320  const Track& intrk2,
321  const RunOutlierRemoval,
322  const ParticleHypothesis) const
323  {
324  ATH_MSG_DEBUG("--> entering GlobalChi2Fitter::fit(Track,Track,)");
325 
326  Cache cache(this);
327  initFieldCache(ctx,cache);
328 
329  GXFTrajectory trajectory;
330  if (!m_straightlineprop) {
331  trajectory.m_straightline = (
332  !cache.m_field_cache.solenoidOn() && !cache.m_field_cache.toroidOn()
333  );
334  }
335 
336  trajectory.m_fieldprop = trajectory.m_straightline ? Trk::NoField : Trk::FullField;
337 
338  bool firstismuon = isMuonTrack(intrk1);
339  const Track *indettrack = firstismuon ? &intrk2 : &intrk1;
340  const Track *muontrack = firstismuon ? &intrk1 : &intrk2;
341  bool muonisstraight = muontrack->info().trackProperties(TrackInfo::StraightTrack);
342  bool measphi = false;
343 
344  for (const auto *i : *(muontrack->measurementsOnTrack())) {
345  const RIO_OnTrack *rot = nullptr;
346 
348  const auto *const crot = static_cast<const CompetingRIOsOnTrack *>(i);
349  rot = &crot->rioOnTrack(0);
350  } else {
352  rot =static_cast<const RIO_OnTrack *>(i);
353  }
354  }
355  if ((rot != nullptr) && !m_DetID->is_mdt(rot->identify())) {
356  const Surface *surf = &rot->associatedSurface();
357  Amg::Vector3D measdir = surf->transform().rotation().col(0);
358  double dotprod1 = measdir.dot(Amg::Vector3D(0, 0, 1));
359  double dotprod2 = measdir.dot(
360  Amg::Vector3D(surf->center().x(), surf->center().y(), 0) /
361  surf->center().perp());
362  if (std::abs(dotprod1) < .5 && std::abs(dotprod2) < .5) {
363  measphi = true;
364  break;
365  }
366  }
367  }
368 
369  const IPropagator *prop = &*m_propagator;
370  auto [firstidpar, lastidpar] = getFirstLastIdPar(*indettrack);
371 
372  if ((firstidpar == nullptr) || (lastidpar == nullptr)) {
373  return nullptr;
374  }
375 
376  std::unique_ptr<const TrackParameters> parforcalo = unique_clone(firstismuon ? firstidpar : lastidpar);
377 
378  if (!cache.m_field_cache.solenoidOn()) {
379  const AmgVector(5) & newpars = parforcalo->parameters();
380 
381  parforcalo=parforcalo->associatedSurface().createUniqueTrackParameters(
382  newpars[0], newpars[1], newpars[2], newpars[3], 1 / 5000., std::nullopt
383  );
384  }
385 
386  std::vector < MaterialEffectsOnTrack > calomeots;
387  if (!m_useCaloTG) {
388  if (!m_calotool.empty()) {
389  calomeots = m_calotool->extrapolationSurfacesAndEffects(
390  *m_navigator->highestVolume(ctx),
391  *prop,
392  *parforcalo,
393  parforcalo->associatedSurface(),
395  Trk::muon
396  );
397  }
398  } else {
399  m_caloMaterialProvider->getCaloMEOT(*indettrack, *muontrack, calomeots);
400  }
401 
402  if (firstismuon) {
403  std::reverse(calomeots.begin(), calomeots.end());
404  }
405 
406  if (calomeots.empty()) {
407  ATH_MSG_WARNING("No calorimeter material collected, failing fit");
408  return nullptr;
409  }
410 
411  std::unique_ptr<Track> track;
412 
413  bool tmp = m_calomat;
414  cache.m_calomat = false;
415  bool tmp2 = cache.m_extmat;
416  bool tmp4 = cache.m_idmat;
417 
418  const TrackParameters *measperid = indettrack->perigeeParameters();
419  const TrackParameters *measpermuon = muontrack->perigeeParameters();
420 
421  double qoverpid = measperid != nullptr ? measperid->parameters()[Trk::qOverP] : 0;
422  double qoverpmuon = measpermuon != nullptr ? measpermuon->parameters()[Trk::qOverP] : 0;
423 
424  const AmgSymMatrix(5) * errmatid = measperid != nullptr ? measperid->covariance() : nullptr;
425  const AmgSymMatrix(5) * errmatmuon = measpermuon != nullptr ? measpermuon->covariance() : nullptr;
426 
427  if (
428  !firstismuon &&
429  (errmatid != nullptr) &&
430  (errmatmuon != nullptr) &&
431  qoverpmuon != 0 &&
432  !m_calotoolparam.empty() &&
433  !m_useCaloTG
434  ) {
435  double piderror = std::sqrt((*errmatid) (4, 4)) / (qoverpid * qoverpid);
436  double pmuonerror = std::sqrt((*errmatmuon) (4, 4)) / (qoverpmuon * qoverpmuon);
437  double energyerror = std::sqrt(
438  calomeots[1].energyLoss()->sigmaDeltaE() *
439  calomeots[1].energyLoss()->sigmaDeltaE() + piderror * piderror +
440  pmuonerror * pmuonerror
441  );
442 
443  if (
444  (std::abs(calomeots[1].energyLoss()->deltaE()) -
445  std::abs(1 / qoverpid) + std::abs(1 / qoverpmuon)
446  ) / energyerror > 5
447  ) {
448  ATH_MSG_DEBUG("Changing from measured to parametrized energy loss");
449  calomeots = m_calotoolparam->extrapolationSurfacesAndEffects(
450  *m_navigator->highestVolume(ctx),
451  *prop,
452  *parforcalo,
453  parforcalo->associatedSurface(),
455  Trk::muon
456  );
457 
458  if (calomeots.empty()) {
459  ATH_MSG_WARNING("No calorimeter material collected, failing fit");
460  return nullptr;
461  }
462  }
463  }
464 
465  int nfits = cache.m_fit_status[S_FITS];
466  bool firstfitwasattempted = false;
467 
468  const bool caloEntranceIsValid = ensureValidEntranceCalo(ctx, cache);
469  if (!caloEntranceIsValid) {
470  return nullptr;
471  }
472 
473  if (
474  (!cache.m_field_cache.toroidOn() && !cache.m_field_cache.solenoidOn()) ||
475  (
476  cache.m_getmaterialfromtrack &&
477  !muonisstraight &&
478  measphi &&
479  muontrack->info().trackFitter() != Trk::TrackInfo::Unknown &&
480  qoverpid * qoverpmuon > 0
481  )
482  ) {
483  track.reset(mainCombinationStrategy(ctx,cache, intrk1, intrk2, trajectory, calomeots));
484 
485  if (cache.m_fit_status[S_FITS] == (unsigned int) (nfits + 1)) {
486  firstfitwasattempted = true;
487  }
488  }
489 
490  if (
491  (track == nullptr) &&
492  !firstfitwasattempted &&
493  (cache.m_field_cache.toroidOn() || cache.m_field_cache.solenoidOn())
494  ) {
495  // Reset the trajectory
496  GXFTrajectory trajectory2;
497  trajectory2.m_straightline = trajectory.m_straightline;
498  trajectory2.m_fieldprop = trajectory.m_fieldprop;
499  trajectory = trajectory2;
500  track.reset(backupCombinationStrategy(ctx,cache, intrk1, intrk2, trajectory, calomeots));
501  }
502 
503  bool pseudoupdated = false;
504 
505  if (track != nullptr) {
506  for (std::unique_ptr<GXFTrackState> & pseudostate : trajectory.trackStates()) {
507  if (pseudostate == nullptr) {
508  continue;
509  }
510 
511  if (
512  pseudostate->measurementType() != TrackState::Pseudo ||
513  !pseudostate->getStateType(TrackStateOnSurface::Measurement)
514  ) {
515  continue;
516  }
517 
518  if ((pseudostate == nullptr) || pseudostate->fitQuality().chiSquared() < 10) {
519  continue;
520  }
521 
522  const TrackParameters *pseudopar = pseudostate->trackParameters();
523  std::unique_ptr<const TrackParameters> updpar(m_updator->removeFromState(
524  *pseudopar,
525  pseudostate->measurement()->localParameters(),
526  pseudostate->measurement()->localCovariance()
527  ));
528 
529  if (updpar == nullptr) {
530  continue;
531  }
532 
533  Amg::MatrixX covMatrix(1, 1);
534  covMatrix(0, 0) = 100;
535 
536  std::unique_ptr<const PseudoMeasurementOnTrack> newpseudo = std::make_unique<const PseudoMeasurementOnTrack>(
538  DefinedParameter(updpar->parameters()[Trk::locY], Trk::locY)
539  ),
540  std::move(covMatrix),
541  pseudopar->associatedSurface()
542  );
543 
544  pseudostate->setMeasurement(std::move(newpseudo));
545  double errors[5];
546  errors[0] = errors[2] = errors[3] = errors[4] = -1;
547  errors[1] = 10;
548  pseudostate->setMeasurementErrors(errors);
549  pseudoupdated = true;
550  }
551 
552  if (pseudoupdated) {
553  trajectory.setConverged(false);
554  cache.m_matfilled = true;
555 
556  track.reset(myfit(
557  ctx,
558  cache,
559  trajectory,
560  *track->perigeeParameters(),
561  false,
563  ));
564 
565  cache.m_matfilled = false;
566  }
567  }
568 
569  cache.m_fit_status[S_FITS] = nfits + 1;
570 
571  if (track != nullptr) {
572  track->info().addPatternReco(intrk1.info());
573  track->info().addPatternReco(intrk2.info());
575  }
576 
577  cache.m_calomat = tmp;
578  cache.m_extmat = tmp2;
579  cache.m_idmat = tmp4;
580  return track;
581  }
582 
584  const EventContext& ctx,
585  Cache & cache,
586  const Track & intrk1,
587  const Track & intrk2,
588  GXFTrajectory & trajectory,
589  std::vector<MaterialEffectsOnTrack> & calomeots
590  ) const {
591  ATH_MSG_DEBUG("--> entering GlobalChi2Fitter::mainCombinationStrategy");
592 
594 
595  bool firstismuon = isMuonTrack(intrk1);
596  const Track *indettrack = firstismuon ? &intrk2 : &intrk1;
597  const Track *muontrack = firstismuon ? &intrk1 : &intrk2;
598 
599  auto [tmpfirstidpar, tmplastidpar] = getFirstLastIdPar(*indettrack);
600  std::unique_ptr<const TrackParameters> firstidpar = unique_clone(tmpfirstidpar);
601  std::unique_ptr<const TrackParameters> lastidpar = unique_clone(tmplastidpar);
602 
603  if ((firstidpar == nullptr) || (lastidpar == nullptr)) {
604  return nullptr;
605  }
606 
607  if (muontrack->trackStateOnSurfaces()->empty()) {
608  return nullptr;
609  }
610 
612  firstismuon ?
613  muontrack->trackStateOnSurfaces()->end() - 1 :
614  muontrack->trackStateOnSurfaces()->begin();
615 
616  const MeasurementBase *closestmuonmeas = nullptr;
617  std::unique_ptr<const TrackParameters> tp_closestmuon = nullptr;
618 
619  while (closestmuonmeas == nullptr) {
620  closestmuonmeas = nullptr;
621  const TrackParameters *thispar = (**tsosit).trackParameters();
622 
623  if ((**tsosit).measurementOnTrack() != nullptr) {
624  closestmuonmeas = (**tsosit).measurementOnTrack();
625 
626  if (thispar != nullptr) {
627  const AmgVector(5) & parvec = thispar->parameters();
628  tp_closestmuon=thispar->associatedSurface().createUniqueTrackParameters(
629  parvec[0], parvec[1], parvec[2], parvec[3], parvec[4], std::nullopt
630  );
631  }
632  break;
633  }
634 
635  if (firstismuon) {
636  --tsosit;
637  } else {
638  ++tsosit;
639  }
640  }
641 
642  PropDirection propdir = firstismuon ? Trk::alongMomentum : oppositeMomentum;
643  std::unique_ptr<const TrackParameters> tmppar;
644 
645  const bool msEntranceIsValid = ensureValidEntranceMuonSpectrometer(ctx, cache);
646  if ((tp_closestmuon != nullptr) && msEntranceIsValid) {
647  tmppar = m_extrapolator->extrapolateToVolume(
648  ctx, *tp_closestmuon, *cache.m_msEntrance, propdir, nonInteracting);
649  }
650 
651  std::unique_ptr<const std::vector<const TrackStateOnSurface *>> matvec;
652 
653  if (tmppar != nullptr) {
654  const Surface & associatedSurface = tmppar->associatedSurface();
655  std::unique_ptr<Surface> muonsurf = nullptr;
656 
657  if (associatedSurface.type() == Trk::SurfaceType::Cylinder) {
658  if (associatedSurface.bounds().type() == Trk::SurfaceBounds::Cylinder) {
659  const CylinderBounds *cylbounds = static_cast <const CylinderBounds * >(&associatedSurface.bounds());
660  Amg::Transform3D trans = Amg::Transform3D(associatedSurface.transform());
661  double radius = cylbounds->r();
662  double hlength = cylbounds->halflengthZ();
663  muonsurf = std::make_unique<CylinderSurface>(trans, radius + 1, hlength);
664  }
665  } else if (associatedSurface.type() == Trk::SurfaceType::Disc) {
666  if (associatedSurface.bounds().type() == Trk::SurfaceBounds::Disc) {
667  double newz = (
668  associatedSurface.center().z() > 0 ?
669  associatedSurface.center().z() + 1 :
670  associatedSurface.center().z() - 1
671  );
672 
673  Amg::Vector3D newpos(
674  associatedSurface.center().x(),
675  associatedSurface.center().y(),
676  newz
677  );
678  Amg::Transform3D trans = associatedSurface.transform();
679  trans.translation() << newpos;
680 
681  const DiscBounds *discbounds = static_cast<const DiscBounds *>(&associatedSurface.bounds());
682  double rmin = discbounds->rMin();
683  double rmax = discbounds->rMax();
684  muonsurf = std::make_unique<DiscSurface>(trans, rmin, rmax);
685  }
686  }
687 
688  if (muonsurf != nullptr) {
689  matvec.reset(m_extrapolator->extrapolateM(
690  ctx,
691  *tp_closestmuon,
692  *muonsurf,
693  propdir,
694  false,
695  muon
696  ));
697  }
698  }
699 
700  std::vector<const TrackStateOnSurface *> tmp_matvec;
701 
702  if ((matvec != nullptr) && !matvec->empty()) {
703  tmp_matvec = *matvec;
704  delete tmp_matvec.back();
705  tmp_matvec.pop_back();
706 
707  for (auto & i : tmp_matvec) {
708  propdir = firstismuon ? Trk::alongMomentum : oppositeMomentum;
709  if (i->materialEffectsOnTrack()->derivedType() != MaterialEffectsBase::MATERIAL_EFFECTS_ON_TRACK){
710  continue;
711  }
712  const MaterialEffectsOnTrack *meff = static_cast<const MaterialEffectsOnTrack *>(i->materialEffectsOnTrack());
713 
714  const Surface *matsurf = &meff->associatedSurface();
715  tmppar = m_propagator->propagateParameters(
716  ctx,
717  *tp_closestmuon,
718  *matsurf,
719  propdir,
720  false,
721  trajectory.m_fieldprop,
723  );
724 
725 
726  if (tmppar == nullptr) {
727  propdir = !firstismuon ? Trk::alongMomentum : oppositeMomentum;
728  tmppar=m_propagator->propagateParameters(
729  ctx,
730  *tp_closestmuon,
731  *matsurf,
732  propdir,
733  false,
734  trajectory.m_fieldprop,
736  );
737 
738  }
739 
740  if (tmppar == nullptr) {
741  return nullptr;
742  }
743 
744  AmgVector(5) newpars = tmppar->parameters();
745 
746  if (newpars[Trk::qOverP] != 0) {
747  double sign = (newpars[Trk::qOverP] > 0) ? 1 : -1;
748  double de = std::abs(meff->energyLoss()->deltaE());
749  double oldp = std::abs(1 / newpars[Trk::qOverP]);
750  double newp2 = oldp * oldp + (!firstismuon ? 2 : -2) * de * std::sqrt(mass * mass + oldp * oldp) + de * de;
751 
752  if (newp2 > 0) {
753  newpars[Trk::qOverP] = sign / std::sqrt(newp2);
754  }
755  }
756 
757  tp_closestmuon=tmppar->associatedSurface().createUniqueTrackParameters(
758  newpars[0], newpars[1], newpars[2], newpars[3], newpars[4], std::nullopt
759  );
760  }
761 
762  if (!firstismuon) {
763  std::reverse(tmp_matvec.begin(), tmp_matvec.end());
764  }
765  }
766 
768  Trk::TrackStates::const_iterator itStates = beginStates;
769  Trk::TrackStates::const_iterator endState = firstismuon ? tsosit + 1 : intrk1.trackStateOnSurfaces()->end();
770  Trk::TrackStates::const_iterator beginStates2 = !firstismuon ? tsosit : intrk2.trackStateOnSurfaces()->begin();
771  Trk::TrackStates::const_iterator itStates2 = beginStates2;
773 
774  for (; itStates != endState; ++itStates) {
775  if (firstismuon && (*itStates)->measurementOnTrack()->type(Trk::MeasurementBaseType::PseudoMeasurementOnTrack)) {
776  continue;
777  }
778 
779  bool tmpgetmat = cache.m_getmaterialfromtrack;
780 
781  if ((*itStates)->materialEffectsOnTrack() != nullptr) {
782  if (firstismuon) {
783  cache.m_extmat = false;
784  } else {
785  cache.m_idmat = false;
786  }
787 
788  const auto *const pBaseMEOT = (*itStates)->materialEffectsOnTrack();
789  const bool itsAnMEOT = (pBaseMEOT->derivedType() == MaterialEffectsBase::MATERIAL_EFFECTS_ON_TRACK);
790 
791  if (itsAnMEOT ){
792  const auto *const pMEOT =static_cast<const MaterialEffectsOnTrack *>((*itStates)->materialEffectsOnTrack());
793  if ((pMEOT->scatteringAngles() == nullptr) or (pMEOT->energyLoss() == nullptr)) {
794  cache.m_getmaterialfromtrack = true; // always take calorimeter layers
795  }
796  }
797  }
798 
799  makeProtoState(cache, trajectory, *itStates);
800  cache.m_getmaterialfromtrack = tmpgetmat;
801  }
802 
803  if (
804  !firstismuon &&
806  ) {
807  trajectory.trackStates().back()->setTrackParameters(nullptr);
808  }
809 
810  std::unique_ptr<const TrackParameters> firstscatpar;
811  std::unique_ptr<const TrackParameters> lastscatpar;
812  const TrackParameters *origlastidpar = unique_clone(lastidpar).release();
813 
814  double newqoverpid = 0;
815 
816  if (!firstismuon) {
817  double de = std::abs(calomeots[1].energyLoss()->deltaE());
818  double sigmade = std::abs(calomeots[1].energyLoss()->sigmaDeltaE());
819 
820  double pbefore = std::abs(1 / firstidpar->parameters()[Trk::qOverP]);
821  double pafter = std::abs(1 / tp_closestmuon->parameters()[Trk::qOverP]);
822  double elosspull = (pbefore - pafter - de) / sigmade;
823 
824  if (std::abs(elosspull) > 10) {
825  if (elosspull > 10) {
826  newqoverpid = 1 / (de + pafter + 10 * sigmade);
827  } else {
828  newqoverpid = 1 / (de + pafter - 10 * sigmade);
829  }
830 
831  if (tp_closestmuon->parameters()[Trk::qOverP] * newqoverpid < 0) {
832  newqoverpid *= -1;
833  }
834 
835  const AmgVector(5) & newpar = firstidpar->parameters();
836  firstidpar=firstidpar->associatedSurface().createUniqueTrackParameters(
837  newpar[0], newpar[1], newpar[2], newpar[3], newqoverpid, std::nullopt
838  );
839  }
840 
841  lastidpar = m_extrapolator->extrapolateToVolume(
842  ctx, *firstidpar, *cache.m_caloEntrance, alongMomentum, Trk::muon);
843  }
844 
845  if (lastidpar == nullptr) {
846  lastidpar = unique_clone(origlastidpar);
847  }
848 
849  firstscatpar= m_propagator->propagateParameters(
850  ctx,
851  *(firstismuon ? tp_closestmuon.get() : lastidpar.get()),
852  calomeots[0].associatedSurface(),
854  false,
855  trajectory.m_fieldprop,
857  );
858 
859  if (firstscatpar == nullptr) {
860  return nullptr;
861  }
862 
863  lastscatpar = m_propagator->propagateParameters(
864  ctx,
865  *(firstismuon ? firstidpar : tp_closestmuon),
866  calomeots[2].associatedSurface(),
868  false,
869  trajectory.m_fieldprop,
871  );
872 
873  if (lastscatpar == nullptr) {
874  return nullptr;
875  }
876 
877  std::optional<TransportJacobian> jac1, 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  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  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  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  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  double idscatphi = xAOD::P4Helpers::deltaPhi(idscatpar->parameters()[Trk::phi], scat2->parameters()[Trk::phi] + dphi);
1037  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  Amg::Vector3D trackdir = startPar->momentum().unit();
1073  Amg::Vector3D curvZcrossT = -(trackdir.cross(Amg::Vector3D(0, 0, 1)));
1074  Amg::Vector3D curvU = curvZcrossT.unit();
1075  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 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  double pull1 = std::abs(firstscatphi / firstscatmeff->sigmaDeltaPhi());
1109  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 
1256  Trk::TrackStates::const_iterator itStates = beginStates;
1258  Trk::TrackStates::const_iterator beginStates2 = intrk2.trackStateOnSurfaces()->begin();
1259  Trk::TrackStates::const_iterator itStates2 = beginStates2;
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  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  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  double sign = (tmppar->parameters()[Trk::qOverP] < 0) ? -1 : 1;
1323 
1324  double oldp = std::abs(1 / tmppar->parameters()[Trk::qOverP]);
1325  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  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  double sign = (elosspar->parameters()[Trk::qOverP] < 0) ? -1 : 1;
1384  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>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  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  Amg::Vector3D measdir = surf->transform().rotation().col(0);
1493  double dotprod1 = measdir.dot(Amg::Vector3D(0, 0, 1));
1494  double dotprod2 = measdir.dot(Amg::Vector3D(surf->center().x(), surf->center().y(), 0) / surf->center().perp());
1495 
1496  bool measphi = std::abs(dotprod1) <= .5 && std::abs(dotprod2) <= .5;
1497  if (measphi) {
1498  nphi++;
1499  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  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  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  bool isPseudo = pMeasurement->type(Trk::MeasurementBaseType::PseudoMeasurementOnTrack);
1579  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 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 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  bool tmpacc = cache.m_acceleration;
1728  cache.m_acceleration = false;
1729  // @TODO eventually track created but not used why ?
1730  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  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  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  Amg::Vector3D measdir = surf->transform().rotation().col(0);
1946  double dotprod1 = measdir.dot(Amg::Vector3D(0, 0, 1));
1947  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  bool tmpacc = cache.m_acceleration;
2002  bool tmpfiteloss = m_fiteloss;
2003  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  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  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 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  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 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 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 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 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  Trk::TrackStates::const_iterator endState = inputTrack.trackStateOnSurfaces()->end();
2288 
2289  bool old_reintoutl = cache.m_reintoutl;
2290  cache.m_reintoutl = false;
2291  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  double oldqual =
2326  inputTrack.fitQuality()->numberDoF() != 0 ?
2327  inputTrack.fitQuality()->chiSquared() / inputTrack.fitQuality()->numberDoF() :
2328  -999;
2329 
2330  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>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 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 matprop(meff->thicknessInX0(), 1., 0., 0., 0., 0.);
2590 
2591  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 
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  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  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  Amg::Vector3D measdir = surf->transform().rotation().col(0);
2760  double dotprod1 = measdir.dot(Amg::Vector3D(0, 0, 1));
2761  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  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  double currentqoverp = (matEffects != Trk::electron) ? parforextrap.parameters()[Trk::qOverP] : refpar2.parameters()[Trk::qOverP];
2965  double sinphi = std::sin(parforextrap.parameters()[Trk::phi0]);
2966  double cosphi = std::cos(parforextrap.parameters()[Trk::phi0]);
2967  double sintheta = std::sin(parforextrap.parameters()[Trk::theta]);
2968  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  double r = (std::abs(currentqoverp) > 1e-10) ? -sintheta / (currentqoverp * 300. * field[2]) : 1e6;
2973  double xc = parforextrap.position().x() - r * sinphi;
2974  double yc = parforextrap.position().y() + r * cosphi;
2975  double phi0 = std::atan2(parforextrap.position().y() - yc, parforextrap.position().x() - xc);
2976  double z0 = parforextrap.position().z();
2977  double delta_s = (surf.center().z() - z0) / costheta;
2978  double delta_phi = delta_s * sintheta / r;
2979  double x = xc + std::abs(r) * std::cos(phi0 + delta_phi);
2980  double y = yc + std::abs(r) * std::sin(phi0 + delta_phi);
2981  Amg::Vector3D intersect = Amg::Vector3D(x, y, surf.center().z());
2982  double perp = intersect.perp();
2983  const DiscBounds *discbounds = (const DiscBounds *) (&surf.bounds());
2984 
2985  if (perp > discbounds->rMax() || perp < discbounds->rMin()) {
2986  return {};
2987  }
2988 
2989  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  double currentqoverp = (matEffects != Trk::electron) ? parforextrap.parameters()[Trk::qOverP] : refpar2.parameters()[Trk::qOverP];
3012  double sinphi = std::sin(parforextrap.parameters()[Trk::phi0]);
3013  double cosphi = std::cos(parforextrap.parameters()[Trk::phi0]);
3014  double sintheta = std::sin(parforextrap.parameters()[Trk::theta]);
3015  double costheta = std::cos(parforextrap.parameters()[Trk::theta]);
3016  double tantheta = std::tan(parforextrap.parameters()[Trk::theta]);
3017  double r = (std::abs(currentqoverp) > 1e-10) ? -sintheta / (currentqoverp * 300. * field[2]) : 1e6;
3018  double xc = parforextrap.position().x() - r * sinphi;
3019  double yc = parforextrap.position().y() + r * cosphi;
3020  double phi0 = std::atan2(parforextrap.position().y() - yc, parforextrap.position().x() - xc);
3021  double z0 = parforextrap.position().z();
3022  double d = xc * xc + yc * yc;
3023  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  double x1 = firstterm + secondterm;
3034  double x2 = firstterm - secondterm;
3035  firstterm = yc / 2 + (yc * (rcyl * rcyl - r * r)) / (2 * d);
3036  secondterm = (mysqrt * xc) / (2 * d);
3037  double y1 = firstterm - secondterm;
3038  double y2 = firstterm + secondterm;
3039  double x = parforextrap.position().x();
3040  double y = parforextrap.position().y();
3041  double dist1 = (x - x1) * (x - x1) + (y - y1) * (y - y1);
3042  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  double phi1 = std::atan2(y - yc, x - xc);
3053  double deltaphi = xAOD::P4Helpers::deltaPhi(phi1, phi0);
3054 
3055  double delta_z = r * deltaphi / tantheta;
3056  double z = z0 + delta_z;
3057 
3059 
3060  if (std::abs(z - surf.center().z()) > surf.bounds().halflengthZ()) {
3061  return {};
3062  }
3063 
3064  Amg::Vector3D normal(x, y, 0);
3065  double phidir = xAOD::P4Helpers::deltaPhi(parforextrap.parameters()[Trk::phi], -deltaphi);
3066 
3067  Amg::Vector3D trackdir(cos(phidir) * sintheta, std::sin(phidir) * sintheta, costheta);
3068 
3069  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  double rmeas = oldstates[i]->position().perp();
3107  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 = (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  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 = (const DiscSurface *) (&layer->surfaceRepresentation());
3166 
3167  if (oldstates[i]->trackParameters() != nullptr) {
3168  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  double X0 = matprop->thicknessInX0();
3201  double currentqoverp = (matEffects != Trk::electron)
3202  ? parforextrap->parameters()[Trk::qOverP]
3203  : refpar2->parameters()[Trk::qOverP];
3204  double actualx0 = X0 / costracksurf;
3205  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  double sintheta = std::sin(parforextrap->parameters()[Trk::theta]);
3212  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  double firstz = firstsistate.trackParameters()->position().z();
3306  double firstr = firstsistate.trackParameters()->position().perp();
3307  double firstz2 = hasmat ? lastsistate.trackParameters()->position().z() : firstsistate.trackParameters()->position().z();
3308  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  double lastz = laststate->position().z();
3318  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  double tantheta = std::tan(refpar->parameters()[Trk::theta]);
3325  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 = (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  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  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  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, lastmatindex = 0;
3522  std::vector<std::unique_ptr<GXFTrackState>> & oldstates = trajectory.trackStates();
3523 
3524  GXFTrackState *firstsistate = nullptr;
3525  GXFTrackState *lastsistate = nullptr;
3526 
3527  /*
3528  * This loop serves several purposes in one, because it's very efficient:
3529  *
3530  * 1. It detects whether there are already any materials on this track, and
3531  * if so where they are.
3532  * 2. It determines what the first and last silicon hits are.
3533  * 3. It calculates trackparameters for any states that might not have them
3534  * for whatever reason.
3535  */
3536  for (int i = 0; i < (int) oldstates.size(); i++) {
3537  if (oldstates[i]->materialEffects() != nullptr) {
3538  hasmat = true;
3539  lastmatindex = i;
3540  }
3541 
3542  if (
3543  oldstates[i]->measurementType() == TrackState::Pixel ||
3544  oldstates[i]->measurementType() == TrackState::SCT
3545  ) {
3546  if (firstsistate == nullptr) {
3547  if (oldstates[i]->trackParameters() == nullptr) {
3548  std::unique_ptr<const TrackParameters> tmppar(m_propagator->propagateParameters(
3549  ctx,
3550  *refpar,
3551  oldstates[i]->associatedSurface(),
3552  alongMomentum,
3553  false,
3554  trajectory.m_fieldprop,
3556  ));
3557 
3558  if (tmppar == nullptr) return;
3559 
3560  oldstates[i]->setTrackParameters(std::move(tmppar));
3561  }
3562  firstsistate = oldstates[i].get();
3563  }
3564  lastsistate = oldstates[i].get();
3565  }
3566  }
3567 
3568  /*
3569  * Only happens when there are no tracks, and that shouldn't happen in the
3570  * first place.
3571  */
3572  if (lastsistate == nullptr) {
3573  throw std::logic_error("No track state");
3574  }
3575 
3576  /*
3577  * Also try to generate a set of track parameters for the last silicon hit
3578  * if it doesn't have any. I don't really know when that would happen, but
3579  * I suppose it's possible. Anything is possible, if you believe hard
3580  * enough.
3581  */
3582  if (lastsistate->trackParameters() == nullptr) {
3583  std::unique_ptr<const TrackParameters> tmppar(m_propagator->propagateParameters(
3584  ctx,
3585  *refpar,
3586  lastsistate->associatedSurface(),
3587  alongMomentum, false,
3588  trajectory.m_fieldprop,
3590  ));
3591 
3592  if (tmppar == nullptr) return;
3593 
3594  lastsistate->setTrackParameters(std::move(tmppar));
3595  }
3596 
3597  /*
3598  * If we have found any materials on the track, we've presumably already
3599  * done a fit for that part of the track, so the reference parameters are
3600  * either the first or last silicon state's parameters.
3601  */
3602  if (hasmat) {
3603  refpar = lastsistate->trackParameters();
3604  indexoffset = lastmatindex;
3605  } else {
3606  refpar = firstsistate->trackParameters();
3607  }
3608 
3609  /*
3610  * These vectors will hold the layers. The types here are a little bit
3611  * strange, but the idea is that the right member is a disc surface and the
3612  * left member is a cylindrical surface. Could be more elegantly done using
3613  * polymorphism.
3614  *
3615  * The upstream layers may already be filled due to previous fits.
3616  *
3617  * TODO: Use polymorphism to get rid of these strange types.
3618  */
3619  std::vector<std::pair<const Layer *, const Layer *>> layers;
3620  std::vector<std::pair<const Layer *, const Layer *>> & upstreamlayers = trajectory.upstreamMaterialLayers();
3621 
3622  /*
3623  * Fill the aforementioned layer vectors with layers.
3624  */
3625  addMaterialGetLayers(cache, layers, upstreamlayers, oldstates, *firstsistate, *lastsistate, refpar, hasmat);
3626 
3627  /*
3628  * Finally, use that layer information to actually add states to the track.
3629  */
3630  addMaterialUpdateTrajectory(cache, trajectory, indexoffset, layers, refpar, refpar2, matEffects);
3631  }
3632 
3634  const EventContext& ctx,
3635  Cache & cache,
3636  GXFTrajectory & trajectory,
3637  const TrackParameters * refpar2,
3638  ParticleHypothesis matEffects
3639  ) const {
3640  if (refpar2 == nullptr) {
3641  return;
3642  }
3643  const MeasurementBase *firstmuonhit = nullptr;
3644  const MeasurementBase *lastmuonhit = nullptr;
3645  const MeasurementBase *firstidhit =
3646  nullptr;
3647  const MeasurementBase *lastidhit = nullptr;
3648  const MeasurementBase *firsthit = nullptr;
3649  const MeasurementBase *lasthit = nullptr;
3650  std::vector<std::unique_ptr<GXFTrackState>> & states = trajectory.trackStates();
3651  std::vector<std::unique_ptr<GXFTrackState>> matstates;
3652  std::unique_ptr< const std::vector < const TrackStateOnSurface *>,
3653  void (*)(const std::vector<const TrackStateOnSurface *> *) >
3654  matvec(nullptr,&Trk::GlobalChi2Fitter::Cache::objVectorDeleter<TrackStateOnSurface>);
3655  bool matvec_used=false;
3656  std::unique_ptr<TrackParameters> startmatpar1;
3657  std::unique_ptr<TrackParameters> startmatpar2;
3658  const TrackParameters *firstidpar = nullptr;
3659  const TrackParameters *lastidpar = nullptr;
3660  const TrackParameters *firstsiliconpar = nullptr;
3661  const TrackParameters *lastsiliconpar = nullptr;
3662  const TrackParameters *firstmatpar = nullptr;
3663  const TrackParameters *firstcalopar = nullptr;
3664  const TrackParameters *lastcalopar = nullptr;
3665  const TrackParameters *firstmuonpar = nullptr;
3666  const TrackParameters *lastmuonpar = nullptr;
3667 
3668  int npseudomuon1 = 0;
3669  int npseudomuon2 = 0;
3670 
3671  for (auto & state : states) {
3672  TrackState::MeasurementType meastype = state->measurementType();
3673  const TrackParameters *tp = state->trackParameters();
3674  GXFMaterialEffects *meff = state->materialEffects();
3675 
3676  if (meastype == TrackState::Pseudo) {
3677  if (firstidhit == nullptr) {
3678  npseudomuon1++;
3679  } else {
3680  npseudomuon2++;
3681  }
3682  continue;
3683  }
3684 
3685  if (state->getStateType(TrackStateOnSurface::Measurement) || state->getStateType(TrackStateOnSurface::Outlier)) {
3686  if (firsthit == nullptr) {
3687  firsthit = state->measurement();
3688  if (cache.m_acceleration) {
3689  if (tp == nullptr) {
3690  tp = m_extrapolator->extrapolate(
3691  ctx,
3692  *refpar2,
3693  state->associatedSurface(),
3694  alongMomentum,
3695  false,
3696  matEffects
3697  ).release();
3698 
3699  if (tp == nullptr) {
3700  return;
3701  }
3702 
3703  state->setTrackParameters(std::unique_ptr<const TrackParameters>(tp));
3704  }
3705  // When acceleration is enabled, material collection starts from first hit
3706  refpar2 = tp;
3707  }
3708  }
3709  lasthit = state->measurement();
3710  if (
3711  meastype == TrackState::Pixel ||
3712  meastype == TrackState::SCT ||
3713  meastype == TrackState::TRT
3714  ) {
3715  if (firstidhit == nullptr) {
3716  firstidhit = state->measurement();
3717  }
3718 
3719  if ((firstidpar == nullptr) && (tp != nullptr)) {
3720  firstidpar = tp;
3721  }
3722 
3723  lastidhit = state->measurement();
3724  if (tp != nullptr) {
3725  lastidpar = tp;
3726  }
3727 
3728  if ((tp != nullptr) && meastype != TrackState::TRT) {
3729  if (firstsiliconpar == nullptr) {
3730  firstsiliconpar = tp;
3731  }
3732  lastsiliconpar = tp;
3733  }
3734  }
3735 
3736  if (
3737  meastype == TrackState::RPC ||
3738  meastype == TrackState::CSC ||
3739  meastype == TrackState::TGC ||
3740  meastype == TrackState::MDT ||
3741  meastype == TrackState::MM ||
3742  meastype == TrackState::STGC
3743  ) {
3744  if (firstmuonhit == nullptr) {
3745  firstmuonhit = state->measurement();
3746  if (tp != nullptr) {
3747  firstmuonpar = tp;
3748  }
3749  }
3750  lastmuonhit = state->measurement();
3751  if (tp != nullptr) {
3752  lastmuonpar = tp;
3753  }
3754  }
3755  }
3756  if (state->getStateType(TrackStateOnSurface::Scatterer) || state->getStateType(TrackStateOnSurface::BremPoint)) {
3757  if (meff->deltaE() == 0) {
3758  if (firstcalopar == nullptr) {
3759  firstcalopar = state->trackParameters();
3760  }
3761  lastcalopar = state->trackParameters();
3762  }
3763  if (firstmatpar == nullptr) {
3764  firstmatpar = state->trackParameters();
3765  }
3766  }
3767  }
3768 
3769  std::unique_ptr<TrackParameters> refpar;
3770  AmgVector(5) newpars = refpar2->parameters();
3771 
3772  if (trajectory.m_straightline && m_p != 0) {
3773  newpars[Trk::qOverP] = 1 / m_p;
3774  }
3775 
3776  refpar = refpar2->associatedSurface().createUniqueTrackParameters(
3777  newpars[0], newpars[1], newpars[2], newpars[3], newpars[4], std::nullopt
3778  );
3779 
3780  if (firstmatpar != nullptr) {
3781  startmatpar1 = unique_clone(firstsiliconpar);
3782  startmatpar2 = unique_clone(lastsiliconpar);
3783  }
3784 
3785  if ((startmatpar1 == nullptr) || ((firstidhit != nullptr) && (firstmuonhit != nullptr))) {
3786  startmatpar1 = unique_clone(refpar);
3787  startmatpar2 = unique_clone(refpar);
3788 
3789  double mass = trajectory.mass();
3790  if (mass > 200 * MeV) {
3791  const AmgVector(5) & newpars = startmatpar2->parameters();
3792  double oldp = std::abs(1 / newpars[Trk::qOverP]);
3793  double sign = (newpars[Trk::qOverP] < 0) ? -1 : 1;
3794 
3795  startmatpar2 = startmatpar2->associatedSurface().createUniqueTrackParameters(
3796  newpars[0], newpars[1], newpars[2], newpars[3],
3797  sign / std::sqrt(oldp * oldp + 2 * 100 * MeV * std::sqrt(oldp * oldp + mass * mass) + 100 * MeV * 100 * MeV),
3798  std::nullopt
3799  );
3800  }
3801  } else if (trajectory.m_straightline && m_p != 0) {
3802  AmgVector(5) newpars = startmatpar1->parameters();
3803  newpars[Trk::qOverP] = 1 / m_p;
3804 
3805  startmatpar1 = startmatpar1->associatedSurface().createUniqueTrackParameters(
3806  newpars[0], newpars[1], newpars[2], newpars[3], newpars[4], std::nullopt
3807  );
3808 
3809  newpars = startmatpar2->parameters();
3810  newpars[Trk::qOverP] = 1 / m_p;
3811 
3812  startmatpar2 = startmatpar2->associatedSurface().createUniqueTrackParameters(
3813  newpars[0], newpars[1], newpars[2], newpars[3], newpars[4], std::nullopt
3814  );
3815  }
3816 
3817  if ((firstidhit != nullptr) && trajectory.numberOfSiliconHits() > 0 && cache.m_idmat) {
3818 
3820  refpar->position(),
3821  refpar->momentum().unit()
3822  );
3823 
3824  double distance = getDistance(distsol);
3825 
3826  if (distance < 0 && distsol.numberOfSolutions() > 0 && !cache.m_acceleration) {
3827  ATH_MSG_DEBUG("Obtaining upstream layers from Extrapolator");
3828 
3829  const Surface *destsurf = &firstidhit->associatedSurface();
3830  std::unique_ptr<const TrackParameters> tmppar;
3831 
3832  if (firstmuonhit != nullptr) {
3833  const bool caloEntranceIsValid = ensureValidEntranceCalo(ctx, cache);
3834  if (caloEntranceIsValid) {
3835  tmppar = m_extrapolator->extrapolateToVolume(ctx,
3836  *startmatpar1,
3837  *cache.m_caloEntrance,
3840 
3841  if (tmppar != nullptr) {
3842  destsurf = &tmppar->associatedSurface();
3843  }
3844  }
3845  }
3846 
3847  if (matvec_used) cache.m_matTempStore.push_back( std::move(matvec) );
3848  matvec.reset( m_extrapolator->extrapolateM(ctx,
3849  *startmatpar1,
3850  *destsurf,
3852  false, matEffects) );
3853  matvec_used=false;
3854 
3855  if (matvec && !matvec->empty()) {
3856  for (int i = (int)matvec->size() - 1; i > -1; i--) {
3857  const MaterialEffectsBase *meb = (*matvec)[i]->materialEffectsOnTrack();
3858  if (meb) {
3860  const MaterialEffectsOnTrack *meot = static_cast < const MaterialEffectsOnTrack * >(meb);
3861  std::unique_ptr<GXFMaterialEffects> meff = std::make_unique<GXFMaterialEffects>(*meot);
3862  const TrackParameters * newpars = (*matvec)[i]->trackParameters() != nullptr ? (*matvec)[i]->trackParameters()->clone() : nullptr;
3863  meff->setSigmaDeltaE(0);
3864  matstates.push_back(std::make_unique<GXFTrackState>(
3865  std::move(meff),
3866  std::unique_ptr<const TrackParameters>(newpars)
3867  ));
3868  matvec_used=true;
3869  }
3870  }
3871  }
3872  }
3873  }
3874  }
3875 
3876  if ((lastidhit != nullptr) && trajectory.numberOfSiliconHits() > 0 && cache.m_idmat) {
3878  refpar->position(),
3879  refpar->momentum().unit()
3880  );
3881 
3882  double distance = getDistance(distsol);
3883 
3884  if (distance > 0 && distsol.numberOfSolutions() > 0) {
3885  ATH_MSG_DEBUG("Obtaining downstream ID layers from Extrapolator");
3886  const Surface *destsurf = &lastidhit->associatedSurface();
3887  std::unique_ptr<const TrackParameters> tmppar;
3888  std::unique_ptr<Surface> calosurf;
3889  if (firstmuonhit != nullptr) {
3890  const bool caloEntranceIsValid = ensureValidEntranceCalo(ctx, cache);
3891  if (caloEntranceIsValid) {
3892  tmppar = m_extrapolator->extrapolateToVolume(ctx,
3893  *startmatpar2,
3894  *cache.m_caloEntrance,
3897  }
3898 
3899  if (tmppar != nullptr) {
3900  const CylinderSurface *cylcalosurf = nullptr;
3901 
3902  if (tmppar->associatedSurface().type() == Trk::SurfaceType::Cylinder)
3903  cylcalosurf = static_cast<const CylinderSurface *>(&tmppar->associatedSurface());
3904 
3905  const DiscSurface *disccalosurf = nullptr;
3906 
3907  if (tmppar->associatedSurface().type() == Trk::SurfaceType::Disc)
3908  disccalosurf = static_cast<const DiscSurface *>(&tmppar->associatedSurface());
3909 
3910  if (cylcalosurf != nullptr) {
3911  Amg::Transform3D trans = Amg::Transform3D(cylcalosurf->transform());
3912  const CylinderBounds & cylbounds = cylcalosurf->bounds();
3913  double radius = cylbounds.r();
3914  double hlength = cylbounds.halflengthZ();
3915  calosurf = std::make_unique<CylinderSurface>(trans, radius - 1, hlength);
3916  } else if (disccalosurf != nullptr) {
3917  double newz = (
3918  disccalosurf->center().z() > 0 ?
3919  disccalosurf->center().z() - 1 :
3920  disccalosurf->center().z() + 1
3921  );
3922 
3923  Amg::Vector3D newpos(
3924  disccalosurf->center().x(),
3925  disccalosurf->center().y(),
3926  newz
3927  );
3928 
3929  Amg::Transform3D trans = (disccalosurf->transform());
3930  trans.translation() << newpos;
3931 
3932  const DiscBounds *discbounds = static_cast<const DiscBounds *>(&disccalosurf->bounds());
3933  double rmin = discbounds->rMin();
3934  double rmax = discbounds->rMax();
3935  calosurf = std::make_unique<DiscSurface>(trans, rmin, rmax);
3936  }
3937  destsurf = calosurf.release();
3938  }
3939  }
3940 
3941  if (matvec_used) cache.m_matTempStore.push_back( std::move(matvec) );
3942  matvec.reset(m_extrapolator->extrapolateM(
3943  ctx, *startmatpar2, *destsurf, alongMomentum, false, matEffects));
3944  matvec_used = false;
3945 
3946  if (matvec && !matvec->empty()) {
3947  for (const auto & i : *matvec) {
3948  const Trk::MaterialEffectsBase * meb = i->materialEffectsOnTrack();
3949 
3950  if (meb) {
3952  const MaterialEffectsOnTrack *meot = static_cast<const MaterialEffectsOnTrack *>(meb);
3953  std::unique_ptr<GXFMaterialEffects> meff = std::make_unique<GXFMaterialEffects>(*meot);
3954  if (cache.m_fiteloss && (meot->energyLoss() != nullptr)) {
3955  meff->setSigmaDeltaE(meot->energyLoss()->sigmaDeltaE());
3956  }
3957 
3958  if (matEffects == electron && cache.m_asymeloss) {
3959  meff->setDeltaE(-5);
3960 
3961  if (trajectory.numberOfTRTHits() == 0) {
3962  meff->setScatteringSigmas(0, 0);
3963  }
3964 
3965  meff->setSigmaDeltaE(50);
3966  }
3967 
3968  const TrackParameters * newparams = i->trackParameters() != nullptr ? i->trackParameters()->clone() : nullptr;
3969 
3970  matstates.push_back(std::make_unique<GXFTrackState>(
3971  std::move(meff),
3972  std::unique_ptr<const TrackParameters>(newparams)
3973  ));
3974  matvec_used=true;
3975  }
3976  }
3977  }
3978  } else {
3979  ATH_MSG_WARNING("No material layers collected from Extrapolator");
3980  }
3981  }
3982  }
3983 
3984  if (cache.m_calomat && (firstmuonhit != nullptr) && (firstidhit != nullptr)) {
3985  const IPropagator *prop = &*m_propagator;
3986 
3987  std::vector<MaterialEffectsOnTrack> calomeots = m_calotool->extrapolationSurfacesAndEffects(
3988  *m_navigator->highestVolume(ctx),
3989  *prop,
3990  *lastidpar,
3991  firstmuonhit->associatedSurface(),
3992  alongMomentum,
3993  muon
3994  );
3995 
3996  if (calomeots.empty()) {
3997  ATH_MSG_WARNING("No material layers collected in calorimeter");
3998  return;
3999  }
4000 
4001  std::unique_ptr<const TrackParameters> prevtrackpars = unique_clone(lastidpar);
4002  if (lasthit == lastmuonhit) {
4003  for (int i = 0; i < (int) calomeots.size(); i++) {
4004  PropDirection propdir = alongMomentum;
4005 
4006  std::unique_ptr<const TrackParameters> layerpar(m_propagator->propagateParameters(
4007  ctx,
4008  *prevtrackpars,
4009  calomeots[i].associatedSurface(),
4010  propdir,
4011  false,
4012  trajectory.m_fieldprop,
4014  ));
4015 
4016  if (layerpar == nullptr) {
4018  return;
4019  }
4020 
4021  std::unique_ptr<GXFMaterialEffects> meff = std::make_unique<GXFMaterialEffects>(calomeots[i]);
4022 
4023  if (i == 2) {
4024  lastcalopar = layerpar.get();
4025  }
4026 
4027  if (i == 1) {
4028  double qoverp = layerpar->parameters()[Trk::qOverP];
4029  double qoverpbrem = 0;
4030 
4031  if (
4032  npseudomuon2 < 2 &&
4033  (firstmuonpar != nullptr) &&
4034  std::abs(firstmuonpar->parameters()[Trk::qOverP]) > 1.e-9
4035  ) {
4036  qoverpbrem = firstmuonpar->parameters()[Trk::qOverP];
4037  } else {
4038  double sign = (qoverp > 0) ? 1 : -1;
4039  qoverpbrem = sign / (1 / std::abs(qoverp) - std::abs(calomeots[i].energyLoss()->deltaE()));
4040  }
4041 
4042  const AmgVector(5) & newpar = layerpar->parameters();
4043 
4044  layerpar = layerpar->associatedSurface().createUniqueTrackParameters(
4045  newpar[0], newpar[1], newpar[2], newpar[3], qoverpbrem, std::nullopt
4046  );
4047  meff->setdelta_p(1000 * (qoverpbrem - qoverp));
4048  }
4049 
4050  matstates.push_back(std::make_unique<GXFTrackState>(
4051  std::move(meff),
4052  std::unique_ptr<const TrackParameters>(layerpar != nullptr ? layerpar->clone() : nullptr)
4053  ));
4054  prevtrackpars = std::move(layerpar);
4055  }
4056  }
4057 
4058  if (
4059  firsthit == firstmuonhit &&
4060  (!cache.m_getmaterialfromtrack || lasthit == lastidhit)
4061  ) {
4062  prevtrackpars = unique_clone(firstidpar);
4063  for (int i = 0; i < (int) calomeots.size(); i++) {
4064  PropDirection propdir = oppositeMomentum;
4065  std::unique_ptr<const TrackParameters> layerpar(m_propagator->propagateParameters(
4066  ctx,
4067  *prevtrackpars,
4068  calomeots[i].associatedSurface(),
4069  propdir,
4070  false,
4071  trajectory.m_fieldprop,
4073  ));
4074 
4075  if (layerpar == nullptr) {
4077  return;
4078  }
4079 
4080  std::unique_ptr<GXFMaterialEffects> meff = std::make_unique<GXFMaterialEffects>(calomeots[i]);
4081 
4082  if (i == 2) {
4083  firstcalopar = unique_clone(layerpar.get()).release();
4084  }
4085 
4086  prevtrackpars = unique_clone(layerpar.get());
4087 
4088  if (i == 1) {
4089  double qoverpbrem = layerpar->parameters()[Trk::qOverP];
4090  double qoverp = 0;
4091 
4092  if (
4093  npseudomuon1 < 2 &&
4094  (lastmuonpar != nullptr) &&
4095  std::abs(lastmuonpar->parameters()[Trk::qOverP]) > 1.e-9
4096  ) {
4097  qoverp = lastmuonpar->parameters()[Trk::qOverP];
4098  } else {
4099  double sign = (qoverpbrem > 0) ? 1 : -1;
4100  qoverp = sign / (1 / std::abs(qoverpbrem) + std::abs(calomeots[i].energyLoss()->deltaE()));
4101  }
4102 
4103  meff->setdelta_p(1000 * (qoverpbrem - qoverp));
4104  const AmgVector(5) & newpar = layerpar->parameters();
4105 
4106  prevtrackpars = layerpar->associatedSurface().createUniqueTrackParameters(
4107  newpar[0], newpar[1], newpar[2], newpar[3], qoverp, std::nullopt
4108  );
4109  }
4110 
4111  matstates.insert(matstates.begin(), std::make_unique<GXFTrackState>(std::move(meff), std::move(layerpar)));
4112  }
4113  }
4114  }
4115 
4116  if (lasthit == lastmuonhit && cache.m_extmat) {
4117  std::unique_ptr<const Trk::TrackParameters> muonpar1;
4118 
4119  if (lastcalopar != nullptr) {
4120  const bool msEntranceIsValid = ensureValidEntranceMuonSpectrometer(ctx, cache);
4121  if (msEntranceIsValid) {
4122  if (cache.m_msEntrance->inside(lastcalopar->position())) {
4123  muonpar1 = m_extrapolator->extrapolateToVolume(ctx,
4124  *lastcalopar,
4125  *cache.m_msEntrance,
4128 
4129  if (muonpar1 != nullptr) {
4130  Amg::Vector3D trackdir = muonpar1->momentum().unit();
4131  Amg::Vector3D curvZcrossT = -(trackdir.cross(Amg::Vector3D(0, 0, 1)));
4132  Amg::Vector3D curvU = curvZcrossT.unit();
4133  Amg::Vector3D curvV = trackdir.cross(curvU);
4134  Amg::RotationMatrix3D rot = Amg::RotationMatrix3D::Identity();
4135  rot.col(0) = curvU;
4136  rot.col(1) = curvV;
4137  rot.col(2) = trackdir;
4138  Amg::Transform3D trans;
4139  trans.linear().matrix() << rot;
4140  trans.translation() << muonpar1->position() - .1 * trackdir;
4141  PlaneSurface curvlinsurf(trans);
4142 
4143  std::unique_ptr<const TrackParameters> curvlinpar(m_extrapolator->extrapolateDirectly(
4144  ctx,
4145  *muonpar1,
4146  curvlinsurf,
4149  ));
4150 
4151  if (curvlinpar != nullptr) {
4152  muonpar1 = std::move(curvlinpar);
4153  }
4154  }
4155  } else {
4156  muonpar1 = std::unique_ptr<TrackParameters>(lastcalopar->clone());
4157  }
4158  }
4159  } else {
4160  muonpar1 = std::unique_ptr<TrackParameters>(refpar->clone());
4161  }
4162 
4163  DistanceSolution distsol;
4164 
4165  if (muonpar1 != nullptr) {
4166  distsol = lastmuonhit->associatedSurface().straightLineDistanceEstimate(
4167  muonpar1->position(),
4168  muonpar1->momentum().unit()
4169  );
4170  }
4171 
4172  double distance = getDistance(distsol);
4173 
4174  if ((distance > 0) and(distsol.numberOfSolutions() >
4175  0) and (firstmuonhit != nullptr)) {
4176  distsol = firstmuonhit->associatedSurface().straightLineDistanceEstimate(
4177  muonpar1->position(),
4178  muonpar1->momentum().unit()
4179  );
4180 
4181  distance = 0;
4182 
4183  if (distsol.numberOfSolutions() == 1) {
4184  distance = distsol.first();
4185  } else if (distsol.numberOfSolutions() == 2) {
4186  distance = (
4187  std::abs(distsol.first()) < std::abs(distsol.second()) ?
4188  distsol.first() :
4189  distsol.second()
4190  );
4191  }
4192 
4193  if (distance < 0 && distsol.numberOfSolutions() > 0 && (firstidhit == nullptr)) {
4194  if (firstmuonpar != nullptr) {
4195  AmgVector(5) newpars = firstmuonpar->parameters();
4196 
4197  if (trajectory.m_straightline && m_p != 0) {
4198  newpars[Trk::qOverP] = 1 / m_p;
4199  }
4200 
4201  muonpar1 = firstmuonpar->associatedSurface().createUniqueTrackParameters(
4202  newpars[0], newpars[1], newpars[2], newpars[3], newpars[4], std::nullopt
4203  );
4204  } else {
4205  std::unique_ptr<const TrackParameters> tmppar(m_propagator->propagateParameters(
4206  ctx,
4207  *muonpar1,
4208  firstmuonhit->associatedSurface(),
4210  false,
4211  trajectory.m_fieldprop,
4213  ));
4214 
4215  if (tmppar != nullptr) {
4216  muonpar1 = std::move(tmppar);
4217  }
4218  }
4219  }
4220 
4221  const TrackParameters *prevtp = muonpar1.get();
4222  ATH_MSG_DEBUG("Obtaining downstream layers from Extrapolator");
4223  if (matvec_used) cache.m_matTempStore.push_back( std::move(matvec) );
4224  matvec.reset(m_extrapolator->extrapolateM(ctx,
4225  *prevtp,
4226  states.back()->associatedSurface(),
4227  alongMomentum,
4228  false,
4230  matvec_used = false;
4231 
4232  if (matvec && matvec->size() > 1000 && m_rejectLargeNScat) {
4233  ATH_MSG_DEBUG("too many scatterers: " << matvec->size());
4234  return;
4235  }
4236 
4237  if (matvec && !matvec->empty()) {
4238  for (int j = 0; j < (int) matvec->size(); j++) {
4239  const MaterialEffectsBase *meb = (*matvec)[j]->materialEffectsOnTrack();
4240 
4241  if (meb) {
4242  if ((meb->derivedType() == MaterialEffectsBase::MATERIAL_EFFECTS_ON_TRACK) and (j < (int) matvec->size() - 1)) {
4243  const MaterialEffectsOnTrack *meot = static_cast<const MaterialEffectsOnTrack *>(meb);
4244  std::unique_ptr<GXFMaterialEffects> meff = std::make_unique<GXFMaterialEffects>(*meot);
4245 
4246  if (
4247  !trajectory.m_straightline &&
4248  (meot->energyLoss() != nullptr) &&
4249  std::abs(meff->deltaE()) > 25 &&
4250  std::abs((*matvec)[j]->trackParameters()->position().z()) < 13000
4251  ) {
4252  meff->setSigmaDeltaE(meot->energyLoss()->sigmaDeltaE());
4253  }
4254 
4255  const TrackParameters * newparams = (*matvec)[j]->trackParameters() != nullptr ? (*matvec)[j]->trackParameters()->clone() : nullptr;
4256 
4257  matstates.push_back(std::make_unique<GXFTrackState>(
4258  std::move(meff),
4259  std::unique_ptr<const TrackParameters>(newparams)
4260  ));
4261  matvec_used=true;
4262  }
4263  }
4264  }
4265  }
4266  }
4267  }
4268 
4269  if (firsthit == firstmuonhit && cache.m_extmat && (firstcalopar != nullptr)) {
4270  std::unique_ptr<const Trk::TrackParameters> muonpar1;
4271 
4272  const bool msEntranceIsValid = ensureValidEntranceMuonSpectrometer(ctx, cache);
4273  if (msEntranceIsValid) {
4274  if (cache.m_msEntrance->inside(firstcalopar->position())) {
4275  muonpar1 = m_extrapolator->extrapolateToVolume(ctx,
4276  *firstcalopar,
4277  *cache.m_msEntrance,
4280 
4281  if (muonpar1 != nullptr) {
4282  Amg::Vector3D trackdir = muonpar1->momentum().unit();
4283  Amg::Vector3D curvZcrossT = -(trackdir.cross(Amg::Vector3D(0, 0, 1)));
4284  Amg::Vector3D curvU = curvZcrossT.unit();
4285  Amg::Vector3D curvV = trackdir.cross(curvU);
4286  Amg::RotationMatrix3D rot = Amg::RotationMatrix3D::Identity();
4287  rot.col(0) = curvU;
4288  rot.col(1) = curvV;
4289  rot.col(2) = trackdir;
4290  Amg::Transform3D trans;
4291  trans.linear().matrix() << rot;
4292  trans.translation() << muonpar1->position() - .1 * trackdir;
4293  PlaneSurface curvlinsurf(trans);
4294 
4295  std::unique_ptr<const TrackParameters> curvlinpar(m_extrapolator->extrapolateDirectly(
4296  ctx,
4297  *muonpar1,
4298  curvlinsurf,
4301  ));
4302 
4303  if (curvlinpar != nullptr) {
4304  muonpar1 = std::move(curvlinpar);
4305  }
4306  }
4307  } else {
4308  muonpar1 = std::unique_ptr<const TrackParameters>(firstcalopar->clone());
4309  }
4310  }
4311 
4312  DistanceSolution distsol;
4313 
4314  if (muonpar1 != nullptr) {
4315  distsol = firstmuonhit->associatedSurface().straightLineDistanceEstimate(
4316  muonpar1->position(),
4317  muonpar1->momentum().unit()
4318  );
4319  }
4320 
4321  double distance = getDistance(distsol);
4322 
4323  if (distance < 0 && distsol.numberOfSolutions() > 0) {
4324  const TrackParameters *prevtp = muonpar1.get();
4325  ATH_MSG_DEBUG("Collecting upstream muon material from extrapolator");
4326  if (matvec_used) cache.m_matTempStore.push_back( std::move(matvec) );
4327  matvec.reset(m_extrapolator->extrapolateM(ctx,
4328  *prevtp,
4329  states[0]->associatedSurface(),
4331  false,
4333  matvec_used = false;
4334 
4335  if (matvec && !matvec->empty()) {
4336  ATH_MSG_DEBUG("Retrieved " << matvec->size() << " material states");
4337 
4338  for (int j = 0; j < (int) matvec->size(); j++) {
4339  const MaterialEffectsBase *meb = (*matvec)[j]->materialEffectsOnTrack();
4340 
4341  if (meb != nullptr) {
4342 
4343 
4344  if ((meb->derivedType() == MaterialEffectsBase::MATERIAL_EFFECTS_ON_TRACK) && j < (int) matvec->size() - 1) {
4345  const MaterialEffectsOnTrack *meot = static_cast<const MaterialEffectsOnTrack *>(meb);
4346  std::unique_ptr<GXFMaterialEffects> meff = std::make_unique<GXFMaterialEffects>(*meot);
4347 
4348  if (
4349  !trajectory.m_straightline &&
4350  (meot->energyLoss() != nullptr) &&
4351  std::abs(meff->deltaE()) > 25 &&
4352  std::abs((*matvec)[j]->trackParameters()->position().z()) < 13000
4353  ) {
4354  meff->setSigmaDeltaE(meot->energyLoss()->sigmaDeltaE());
4355  }
4356 
4357  const TrackParameters* tmpparams =
4358  (*matvec)[j]->trackParameters() != nullptr
4359  ? (*matvec)[j]->trackParameters()->clone()
4360  : nullptr;
4361 
4362  matstates.insert(matstates.begin(), std::make_unique<GXFTrackState>(
4363  std::move(meff),
4364  std::unique_ptr<const TrackParameters>(tmpparams)
4365  ));
4366  matvec_used=true;
4367  }
4368  }
4369  }
4370  }
4371  }
4372  }
4373 
4374  ATH_MSG_DEBUG("Number of layers: " << matstates.size());
4375 
4376  // Now insert the material states into the trajectory
4377  std::vector<std::unique_ptr<GXFTrackState>> & newstates = states;
4378  std::vector<std::unique_ptr<GXFTrackState>> oldstates = std::move(newstates);
4379 
4380  newstates.clear();
4381  newstates.reserve(oldstates.size() + matstates.size());
4382 
4383  int layerno = 0;
4384  int firstlayerno = -1;
4385 
4386  if (cache.m_acceleration) {
4387  trajectory.addBasicState(std::move(oldstates[0]));
4388  }
4389 
4390  double cosphi = std::cos(refpar->parameters()[Trk::phi0]);
4391  double sinphi = std::sin(refpar->parameters()[Trk::phi0]);
4392 
4393  for (int i = cache.m_acceleration ? 1 : 0; i < (int) oldstates.size(); i++) {
4394  bool addlayer = true;
4395 
4396  while (addlayer && layerno < (int) matstates.size()) {
4397  addlayer = false;
4398  const TrackParameters *layerpar = matstates[layerno]->trackParameters();
4399 
4400  DistanceSolution distsol = oldstates[i]->associatedSurface().straightLineDistanceEstimate(
4401  layerpar->position(),
4402  layerpar->momentum().unit()
4403  );
4404 
4405  double distance = getDistance(distsol);
4406 
4407  if (distance > 0 && distsol.numberOfSolutions() > 0) {
4408  addlayer = true;
4409  }
4410 
4411  if (layerpar->associatedSurface().type() == Trk::SurfaceType::Cylinder) {
4412  double cylinderradius = layerpar->associatedSurface().bounds().r();
4413  double trackimpact = std::abs(-refpar->position().x() * sinphi + refpar->position().y() * cosphi);
4414 
4415  if (trackimpact > cylinderradius - 5 * mm) {
4416  layerno++;
4417  continue;
4418  }
4419  }
4420 
4421  if (i == (int) oldstates.size() - 1) {
4422  addlayer = true;
4423  }
4424 
4425  if (addlayer) {
4426  GXFMaterialEffects *meff = matstates[layerno]->materialEffects();
4427 
4428  if (meff->sigmaDeltaPhi() > .4 || (meff->sigmaDeltaPhi() == 0 && meff->sigmaDeltaE() <= 0)) {
4429  if (meff->sigmaDeltaPhi() > .4) {
4430  ATH_MSG_DEBUG("Material state with excessive scattering, skipping it");
4431  }
4432 
4433  if (meff->sigmaDeltaPhi() == 0) {
4434  ATH_MSG_WARNING("Material state with zero scattering, skipping it");
4435  }
4436 
4437  layerno++;
4438  continue;
4439  }
4440 
4441  if (firstlayerno < 0) {
4442  firstlayerno = layerno;
4443  }
4444 
4445  trajectory.addMaterialState(std::move(matstates[layerno]));
4446 
4447  if ((layerpar != nullptr) && matEffects != pion && matEffects != muon) {
4448  const TrackingVolume *tvol = m_navigator->volume(ctx,layerpar->position());
4449  const Layer *lay = nullptr;
4450 
4451  if (tvol != nullptr) {
4452  lay = (tvol->closestMaterialLayer(layerpar->position(),layerpar->momentum().normalized())).object;
4453  }
4454 
4455  const MaterialProperties *matprop = lay != nullptr ? lay->fullUpdateMaterialProperties(*layerpar) : nullptr;
4456  meff->setMaterialProperties(matprop);
4457  }
4458 
4459  layerno++;
4460  }
4461  }
4462  trajectory.addBasicState(std::move(oldstates[i]));
4463  }
4464 
4465  ATH_MSG_DEBUG("Total X0: " << trajectory.totalX0() << " total eloss: " << trajectory.totalEnergyLoss());
4466 
4467  if (matvec_used) cache.m_matTempStore.push_back( std::move(matvec) );
4468  }
4469 
4470  std::unique_ptr<const TrackParameters> GlobalChi2Fitter::makePerigee(
4471  Cache & cache,
4472  const TrackParameters & param,
4473  ParticleHypothesis matEffects
4474  ) const {
4475  const PerigeeSurface *persurf = nullptr;
4476 
4478  persurf = static_cast<const PerigeeSurface *>(&param.associatedSurface());
4479 
4480  if ((persurf != nullptr) && (!cache.m_acceleration || persurf->center().perp() > 5)) {
4481  const AmgVector(5) & pars = param.parameters();
4483  pars[0], pars[1], pars[2], pars[3], pars[4], std::nullopt
4484  );
4485  }
4486 
4487  if (cache.m_acceleration) {
4488  return nullptr;
4489  }
4490 
4491  PerigeeSurface tmppersf;
4492  std::unique_ptr<const TrackParameters> per(m_extrapolator->extrapolate(
4493  Gaudi::Hive::currentContext(),param, tmppersf, oppositeMomentum, false, matEffects));
4494 
4495  if (per == nullptr) {
4496  ATH_MSG_DEBUG("Cannot make Perigee with starting parameters");
4497  return nullptr;
4498  }
4499 
4500  if(std::abs(per->position().z())>5000.) {
4501  ATH_MSG_WARNING("Pathological perigee well outside of tracking detector!! Returning nullptr");
4502  return nullptr;
4503  }
4504 
4505  return per;
4506  }
4507 
4509  const EventContext& ctx,
4510  Cache & cache,
4511  GXFTrajectory & trajectory,
4512  const TrackParameters & param,
4513  const RunOutlierRemoval runOutlier,
4514  const ParticleHypothesis matEffects
4515  ) const {
4516  ATH_MSG_DEBUG("--> entering GlobalChi2Fitter::myfit_helper");
4518  trajectory.m_straightline = m_straightlineprop;
4519 
4520  if (!trajectory.m_straightline) {
4521  if (trajectory.numberOfSiliconHits() + trajectory.numberOfTRTHits() == trajectory.numberOfHits()) {
4522  trajectory.m_straightline = !cache.m_field_cache.solenoidOn();
4523  } else if ((trajectory.prefit() == 0) && trajectory.numberOfSiliconHits() + trajectory.numberOfTRTHits() == 0) {
4524  trajectory.m_straightline = !cache.m_field_cache.toroidOn();
4525  } else {
4526  trajectory.m_straightline = (!cache.m_field_cache.solenoidOn() && !cache.m_field_cache.toroidOn());
4527  }
4528  }
4529 
4530  trajectory.m_fieldprop = trajectory.m_straightline ? Trk::NoField : Trk::FullField;
4531  cache.m_lastiter = 0;
4532 
4533  Amg::SymMatrixX lu;
4534 
4535  if (trajectory.numberOfPerigeeParameters() == -1) {
4536  cache.incrementFitStatus(S_FITS);
4537  if (trajectory.m_straightline) {
4538  trajectory.setNumberOfPerigeeParameters(4);
4539  } else {
4540  trajectory.setNumberOfPerigeeParameters(5);
4541  }
4542  }
4543 
4544  if (trajectory.nDOF() < 0) {
4545  ATH_MSG_DEBUG("Not enough measurements, reject track");
4546  return nullptr;
4547  }
4548 
4549  cache.m_phiweight.clear();
4550  cache.m_firstmeasurement.clear();
4551  cache.m_lastmeasurement.clear();
4552 
4553  if (matEffects != nonInteracting && param.parameters()[Trk::qOverP] == 0 && m_p == 0) {
4554  ATH_MSG_WARNING("Attempt to apply material corrections with q/p=0, reject track");
4555  return nullptr;
4556  }
4557 
4558  if (matEffects == Trk::electron && trajectory.m_straightline) {
4559  ATH_MSG_WARNING("Electron fit requires helix track model");
4560  return nullptr;
4561  }
4562 
4563  double mass = Trk::ParticleMasses::mass[matEffects];
4564  trajectory.setMass(mass);
4565 
4566  ATH_MSG_DEBUG("start param: " << param << " pos: " << param.position() << " pt: " << param.pT());
4567 
4568  std::unique_ptr<const TrackParameters> per = makePerigee(cache, param, matEffects);
4569 
4570  if (!cache.m_acceleration && (per == nullptr)) {
4573  ATH_MSG_DEBUG("Propagation to perigee failed 1");
4574  return nullptr;
4575  }
4576 
4577  if (matEffects != Trk::nonInteracting && !cache.m_matfilled) {
4578  if (
4579  cache.m_fastmat &&
4580  cache.m_acceleration &&
4581  trajectory.numberOfSiliconHits() + trajectory.numberOfTRTHits() == trajectory.numberOfHits() &&
4582  (m_matupdator.empty() || (m_trackingGeometryReadKey.key().empty()))
4583  ) {
4584  ATH_MSG_WARNING("Tracking Geometry Service and/or Material Updator Tool not configured");
4585  ATH_MSG_WARNING("Falling back to slow material collection");
4586 
4587  cache.m_fastmat = false;
4588  }
4589 
4590  if (
4591  !cache.m_fastmat ||
4592  !cache.m_acceleration ||
4593  trajectory.numberOfSiliconHits() + trajectory.numberOfTRTHits() != trajectory.numberOfHits()
4594  ) {
4595  addMaterial(ctx, cache, trajectory, per != nullptr ? per.get() : &param, matEffects);
4596  } else {
4598  ctx, cache, trajectory, per != nullptr ? per.get() : &param, matEffects);
4599  }
4600  }
4601 
4602  if (cache.m_acceleration && (trajectory.referenceParameters() == nullptr) && (per == nullptr)) {
4604 
4605  if (trajectory.numberOfScatterers() >= 2) {
4606  GXFTrackState *scatstate = nullptr;
4607  GXFTrackState *scatstate2 = nullptr;
4608  int scatindex = 0;
4609 
4610  for (const auto & state : trajectory.trackStates()) {
4611  if (state->getStateType(TrackStateOnSurface::Scatterer)) {
4612  if (
4613  scatindex == trajectory.numberOfScatterers() / 2 ||
4614  state->materialEffects()->deltaE() == 0
4615  ) {
4616  scatstate2 = state.get();
4617  break;
4618  }
4619 
4620  scatindex++;
4621  scatstate = state.get();
4622  }
4623  }
4624 
4625  // @TODO coverity complains about a possible null pointer dereferencing in scatstate->... or scatstate2->...
4626  // it seems to me that if (**it).materialEffects()->deltaE()==0 of the first scatterer
4627  // than scatstate will be NULL.
4628  if ((scatstate == nullptr) || (scatstate2 == nullptr)) {
4629  throw std::logic_error("Invalid scatterer");
4630  }
4631 
4632  vertex = .49 * (scatstate->position() + scatstate2->position());
4633  } else {
4634  int nstates = (int) trajectory.trackStates().size();
4635  vertex = .49 * (
4636  trajectory.trackStates()[nstates / 2 - 1]->position() +
4637  trajectory.trackStates()[nstates / 2]->position()
4638  );
4639  }
4640 
4641  PerigeeSurface persurf(vertex);
4642  std::unique_ptr<const TrackParameters> nearestpar;
4643  double mindist = 99999;
4644  std::vector < GXFTrackState * >mymatvec;
4645 
4646  for (auto & it : trajectory.trackStates()) {
4647  if ((*it).trackParameters() == nullptr) {
4648  continue;
4649  }
4650 
4651  double distance = persurf
4653  (*it).trackParameters()->position(),
4654  (*it).trackParameters()->momentum().unit())
4655  .first();
4656 
4657  bool insideid = (
4658  (cache.m_caloEntrance == nullptr) ||
4659  cache.m_caloEntrance->inside((*it).trackParameters()->position())
4660  );
4661 
4662  if (
4663  (((*it).measurement() != nullptr) && insideid) || (
4664  ((*it).materialEffects() != nullptr) &&
4665  distance > 0 && (
4666  (*it).materialEffects()->deltaE() == 0 ||
4667  ((*it).materialEffects()->sigmaDeltaPhi() == 0 &&
4668  !insideid) ||
4669  (*it).materialEffects()->deltaPhi() != 0
4670  )
4671  )
4672  ) {
4673  double dist = ((*it).trackParameters()->position() - vertex).perp();
4674  if (dist < mindist) {
4675  mindist = dist;
4676  nearestpar = unique_clone((*it).trackParameters());
4677  mymatvec.clear();
4678  continue;
4679  }
4680  }
4681 
4682  if (((*it).materialEffects() != nullptr) && distance > 0) {
4683  mymatvec.push_back(it.get());
4684  }
4685  }
4686 
4687  if (nearestpar == nullptr) {
4688  nearestpar = unique_clone(&param);
4689  }
4690 
4691  for (auto & state : mymatvec) {
4693  const Surface &matsurf = state->associatedSurface();
4695  nearestpar->position(), nearestpar->momentum().unit());
4696 
4697  double distance = getDistance(distsol);
4698 
4699  if (distance < 0 && distsol.numberOfSolutions() > 0) {
4700  propdir = oppositeMomentum;
4701  }
4702 
4703  std::unique_ptr<const TrackParameters> tmppar(m_propagator->propagateParameters(
4704  ctx,
4705  *nearestpar,
4706  matsurf,
4707  propdir,
4708  false,
4709  trajectory.m_fieldprop,
4711  ));
4712 
4713  if (tmppar == nullptr) {
4714  propdir = (propdir == oppositeMomentum) ? alongMomentum : oppositeMomentum;
4715  tmppar = m_propagator->propagateParameters(
4716  ctx,
4717  *nearestpar,
4718  matsurf,
4719  propdir,
4720  false,
4721  trajectory.m_fieldprop,
4723  );
4724 
4725  if (tmppar == nullptr) {
4728 
4729  ATH_MSG_DEBUG("Propagation to perigee failed 2");
4730 
4731  return nullptr;
4732  }
4733  }
4734 
4735  AmgVector(5) newpars = tmppar->parameters();
4736 
4737  if (state->materialEffects()->sigmaDeltaE() > 0) {
4738  newpars[Trk::qOverP] += .001 * state->materialEffects()->delta_p();
4739  } else if (newpars[Trk::qOverP] != 0) {
4740  double sign = (newpars[Trk::qOverP] > 0) ? 1 : -1;
4741  double de = std::abs(state->materialEffects()->deltaE());
4742  double oldp = std::abs(1 / newpars[Trk::qOverP]);
4743  double newp2 = oldp * oldp - 2 * de * std::sqrt(mass * mass + oldp * oldp) + de * de;
4744  if (newp2 > 0) {
4745  newpars[Trk::qOverP] = sign / std::sqrt(newp2);
4746  }
4747  }
4748 
4749  nearestpar = tmppar->associatedSurface().createUniqueTrackParameters(
4750  newpars[0], newpars[1], newpars[2], newpars[3], newpars[4], std::nullopt
4751  );
4752  }
4753 
4754  std::unique_ptr<Trk::TrackParameters> tmpPars(m_propagator->propagateParameters(
4755  ctx,
4756  *nearestpar,
4757  persurf,
4759  false,
4760  trajectory.m_fieldprop,
4762  ));
4763 
4764  // Parameters are at a Perigee surface so they are perigee parameters
4765  if (tmpPars != nullptr) {
4766  per.reset(static_cast < const Perigee *>(tmpPars.release()));
4767  }
4768 
4769  if ((per != nullptr) && (matEffects == Trk::proton || matEffects == Trk::kaon)) {
4770  double sign = (per->parameters()[Trk::qOverP] < 0) ? -1. : 1.;
4771  double oldp = 1. / std::abs(per->parameters()[Trk::qOverP]);
4772  double toteloss = std::abs(trajectory.totalEnergyLoss());
4773  double newp = std::sqrt(oldp * oldp + 2 * toteloss * std::sqrt(oldp * oldp + mass * mass) + toteloss * toteloss);
4774  AmgVector(5) params = per->parameters();
4775  params[Trk::qOverP] = sign / newp;
4776 
4777  per = per->associatedSurface().createUniqueTrackParameters(
4778  params[0], params[1], params[2], params[3], params[4], std::nullopt
4779  );
4780  }
4781 
4782  if (per == nullptr) {
4785  ATH_MSG_DEBUG("Propagation to perigee failed 3");
4786 
4787  return nullptr;
4788  }
4789 
4790  PerigeeSurface persurf2(per->position());
4791  per = persurf2.createUniqueTrackParameters(
4792  0,
4793  0,
4794  per->parameters()[Trk::phi],
4795  per->parameters()[Trk::theta],
4796  per->parameters()[Trk::qOverP],
4797  std::nullopt
4798  );
4799  } else if (per == nullptr) {
4800  per = makePerigee(cache, param, matEffects);
4801  }
4802 
4803  if ((per == nullptr) && (trajectory.referenceParameters() == nullptr)) {
4806  ATH_MSG_DEBUG("Propagation to perigee failed 4");
4807 
4808  return nullptr;
4809  }
4810 
4811  if (trajectory.m_straightline && (per != nullptr)) {
4812  if (trajectory.numberOfPerigeeParameters() == -1) {
4813  trajectory.setNumberOfPerigeeParameters(4);
4814  }
4815 
4816  const AmgVector(5) & pars = per->parameters();
4817  per = per->associatedSurface().createUniqueTrackParameters(
4818  pars[0], pars[1], pars[2], pars[3], 0, std::nullopt
4819  );
4820  } else if (trajectory.numberOfPerigeeParameters() == -1) {
4821  trajectory.setNumberOfPerigeeParameters(5);
4822  }
4823 
4824  if (per != nullptr) {
4825  trajectory.setReferenceParameters(std::move(per));
4826  }
4827 
4828  int nfitpar = trajectory.numberOfFitParameters();
4829  int nperpars = trajectory.numberOfPerigeeParameters();
4830  int nscat = trajectory.numberOfScatterers();
4831  int nbrem = trajectory.numberOfBrems();
4832 
4833  Eigen::MatrixXd a;
4834  Eigen::MatrixXd a_inv;
4835  a.resize(nfitpar, nfitpar);
4836 
4837  Amg::VectorX b(nfitpar);
4838 
4839  Amg::MatrixX derivPool(5, nfitpar);
4840  derivPool.setZero();
4841 
4842  for (std::unique_ptr<GXFTrackState> & state : trajectory.trackStates()) {
4843  if (state->materialEffects() != nullptr) {
4844  continue;
4845  }
4846  state->setDerivatives(derivPool);
4847  }
4848 
4849  bool doderiv = true;
4850  int tmpminiter = cache.m_miniter;
4851 
4852  for (int it = 0; it < m_maxit; ++it) {
4853  cache.m_lastiter = it;
4854 
4855  if (it >= m_maxit - 1) {
4856  ATH_MSG_DEBUG("Fit did not converge");
4859  cache.m_miniter = tmpminiter;
4860  return nullptr;
4861  }
4862 
4863  if (!trajectory.converged()) {
4864  cache.m_fittercode =
4865  runIteration(ctx, cache, trajectory, it, a, b, lu, doderiv);
4866  if (cache.m_fittercode != FitterStatusCode::Success) {
4869  } else if (cache.m_fittercode == FitterStatusCode::InvalidAngles) {
4873  }
4874  cache.m_miniter = tmpminiter;
4875  return nullptr;
4876  }
4877 
4878  int nhits = trajectory.numberOfHits();
4879  int ntrthits = trajectory.numberOfTRTHits();
4880  int nsihits = trajectory.numberOfSiliconHits();
4881  double redchi2 = (trajectory.nDOF() > 0) ? trajectory.chi2() / trajectory.nDOF() : 0;
4882  double prevredchi2 = (trajectory.nDOF() > 0) ? trajectory.prevchi2() / trajectory.nDOF() : 0;
4883 
4884 
4885  if( nsihits > 0 && it > 0 && it < m_maxitPixelROT )
4886  updatePixelROTs( trajectory, a, b, ctx);
4887 
4888  if (
4889  it > 0 &&
4890  it < 4 && (
4891  (redchi2 < prevredchi2 &&
4892  (redchi2 > prevredchi2 - 1 || redchi2 < 2)) ||
4893  nsihits + ntrthits == nhits
4894  ) &&
4895  (runOutlier || m_trtrecal) &&
4896  ntrthits > 0
4897  ) {
4898  if (it != 1 || nsihits != 0 || trajectory.nDOF() <= 0 || trajectory.chi2() / trajectory.nDOF() <= 3) {
4899  ATH_MSG_DEBUG("Running TRT cleaner");
4900  runTrackCleanerTRT(cache, trajectory, a, b, lu, runOutlier, m_trtrecal, it, ctx);
4901  if (cache.m_fittercode != FitterStatusCode::Success) {
4902  ATH_MSG_DEBUG("TRT cleaner failed, returning null...");
4903  cache.m_miniter = tmpminiter;
4904  return nullptr;
4905  }
4906  }
4907  }
4908 
4909  // PHF cut at iteration 3 (to save CPU time)
4910  int ntrtprechits = trajectory.numberOfTRTPrecHits();
4911  int ntrttubehits = trajectory.numberOfTRTTubeHits();
4912  float phf = 1.;
4913  if (ntrtprechits+ntrttubehits) {
4914  phf = float(ntrtprechits)/float(ntrtprechits+ntrttubehits);
4915  }
4916  if (phf<m_minphfcut && it>=3) {
4917  if ((ntrtprechits+ntrttubehits)>=15) {
4918  return nullptr;
4919  }
4920  }
4921  ATH_MSG_DEBUG("Iter = " << it << " | nTRTStates = " << ntrthits
4922  << " | nTRTPrecHits = " << ntrtprechits
4923  << " | nTRTTubeHits = " << ntrttubehits
4924  << " | nOutliers = "
4925  << trajectory.numberOfOutliers());
4926 
4927  if (!trajectory.converged()) {
4928  cache.m_fittercode = updateFitParameters(trajectory, b, lu);
4929  if (cache.m_fittercode != FitterStatusCode::Success) {
4932  }
4933  cache.m_miniter = tmpminiter;
4934  return nullptr;
4935  }
4936  }
4937  } else {
4938  break;
4939  }
4940  }
4941 
4942  cache.m_miniter = tmpminiter;
4943 
4944  if (trajectory.prefit() == 0) {
4945  // Solve assuming the matrix is SPD.
4946  // Cholesky Decomposition is used -- could use LDLT
4947 
4948  Eigen::LLT < Eigen::MatrixXd > lltOfW(a);
4949  if (lltOfW.info() == Eigen::Success) {
4950  // Solve for x where Wx = I
4951  // this is cheaper than invert as invert makes no assumptions about the
4952  // matrix being symmetric
4953  int ncols = a.cols();
4954  Amg::MatrixX weightInvAMG = Amg::MatrixX::Identity(ncols, ncols);
4955  a_inv = lltOfW.solve(weightInvAMG);
4956  } else {
4957  ATH_MSG_DEBUG("matrix inversion failed!");
4960  return nullptr;
4961  }
4962  }
4963 
4964  GXFTrajectory *finaltrajectory = &trajectory;
4965  if (
4966  (runOutlier || cache.m_sirecal) &&
4967  trajectory.numberOfSiliconHits() == trajectory.numberOfHits()
4968  ) {
4969  calculateTrackErrors(trajectory, a_inv, true);
4970  GXFTrajectory* traj = runTrackCleanerSilicon(ctx,cache, trajectory, a, a_inv, b, runOutlier);
4971 
4972  if (cache.m_fittercode != FitterStatusCode::Success) {
4973  ATH_MSG_DEBUG("Silicon cleaner failed, returning null...");
4974  if (traj != &trajectory) {
4975  delete traj;
4976  }
4977  return nullptr;
4978  }
4979  finaltrajectory = traj;
4980  }
4981 
4982  if (m_domeastrackpar && (finaltrajectory->prefit() == 0)) {
4983  calculateTrackErrors(*finaltrajectory, a_inv, false);
4984  }
4985 
4986  if (!cache.m_acceleration && (finaltrajectory->prefit() == 0)) {
4987  if (nperpars == 5) {
4988  for (int i = 0; i < a.cols(); i++) {
4989  a_inv(4, i) *= .001;
4990  a_inv(i, 4) *= .001;
4991  }
4992  }
4993 
4994  int scatterPos = nperpars + 2 * nscat;
4995  for (int bremno = 0; bremno < nbrem; bremno++, scatterPos++) {
4996  for (int i = 0; i < a.cols(); i++) {
4997  a_inv(scatterPos, i) *= .001;
4998  a_inv(i, scatterPos) *= .001;
4999  }
5000  }
5001 
5002  AmgSymMatrix(5) errmat;
5003  errmat.setZero();
5004  int nperparams = finaltrajectory->numberOfPerigeeParameters();
5005  for (int i = 0; i < nperparams; i++) {
5006  for (int j = 0; j < nperparams; j++) {
5007  (errmat) (j, i) = a_inv(j, i);
5008  }
5009  }
5010 
5011  if (trajectory.m_straightline) {
5012  (errmat) (4, 4) = 1e-20;
5013  }
5014 
5015  const AmgVector(5) & perpars = finaltrajectory->referenceParameters()->parameters();
5016  std::unique_ptr<const TrackParameters> measper(
5018  perpars[0], perpars[1], perpars[2], perpars[3], perpars[4], std::move(errmat)
5019  )
5020  );
5021 
5022  finaltrajectory->setReferenceParameters(std::move(measper));
5023  if (m_fillderivmatrix) {
5024  cache.m_fullcovmat = a_inv;
5025  }
5026  }
5027 
5028  std::unique_ptr<Track> track = nullptr;
5029 
5030  if (finaltrajectory->prefit() > 0) {
5031  if (finaltrajectory != &trajectory) {
5032  // cppcheck-suppress autovarInvalidDeallocation; false positive
5033  delete finaltrajectory;
5034  }
5035  return nullptr;
5036  }
5037 
5038  if (finaltrajectory->numberOfOutliers() <= m_maxoutliers || !runOutlier) {
5039  track = makeTrack(ctx,cache, *finaltrajectory, matEffects);
5040  } else {
5043  }
5044 
5045  double cut = (finaltrajectory->numberOfSiliconHits() ==
5046  finaltrajectory->numberOfHits())
5047  ? 999.0
5048  : m_chi2cut.value();
5049 
5050  if (
5051  runOutlier &&
5052  (track != nullptr) && (
5053  track->fitQuality()->numberDoF() != 0 &&
5054  track->fitQuality()->chiSquared() / track->fitQuality()->numberDoF() > cut
5055  )
5056  ) {
5057  track.reset(nullptr);
5059  }
5060 
5061  if (track == nullptr) {
5062  ATH_MSG_DEBUG("Track rejected");
5063  }
5064 
5065  if (finaltrajectory != &trajectory) {
5066  delete finaltrajectory;
5067  }
5068 
5069  return track.release();
5070  }
5071 
5073  const EventContext& ctx,
5074  const Cache & cache,
5075  GXFTrajectory & trajectory,
5076  const int it,
5077  Amg::VectorX & b,
5078  int & bremno_maxbrempull,
5079  GXFTrackState* & state_maxbrempull
5080  ) const {
5081  ATH_MSG_DEBUG("fillResidualsAndErrors");
5082 
5083  std::vector<std::unique_ptr<GXFTrackState>> & states = trajectory.trackStates();
5084 
5085  /*
5086  * The residual and error vectors, we want to fill in this function.
5087  */
5088  Amg::VectorX & res = trajectory.residuals();
5089  Amg::VectorX & error = trajectory.errors();
5090 
5091  /*
5092  * These variables are used inside the preprocessing loop for counting and
5093  * managing some quantities.
5094  */
5095  int scatno = 0;
5096  int bremno = 0;
5097  int measno = 0;
5098 
5099  /*
5100  * Total number of measurements, and brems and perigee parameters. This is
5101  * used later to fill the residual and error vector to find the offsets.
5102  */
5103  const int nmeas = (int) res.size();
5104  const int nbrem = trajectory.numberOfBrems();
5105  const int nperpars = trajectory.numberOfPerigeeParameters();
5106 
5107  /*
5108  * Under certain circumstances, we create new pseudo measurements. Here are
5109  * the static conditions. Later, we have also for each state a more
5110  * confining check.
5111  */
5112  const int nidhits = trajectory.numberOfSiliconHits() + trajectory.numberOfTRTHits();
5113  const int nDOF = trajectory.nDOF();
5114  const bool doNewPseudoMeasurements = (
5115  1 < it &&
5116  it <= 100 &&
5117  nDOF != 0 &&
5118  std::abs((trajectory.prevchi2() - trajectory.chi2()) / nDOF) < 15 &&
5119  nidhits < trajectory.numberOfHits() &&
5120  (nperpars == 0 || nidhits > 0)
5121  );
5122 
5123  /*
5124  * Temporary quantities.
5125  * - chi2 will be used later to set the new chi2.
5126  * - maxbrempull collects the elosspull for the kink with the largest
5127  * brems. It is initised to -0.2 to consider only definitely negative
5128  * pulls.
5129  */
5130  double chi2 = 0;
5131  double maxbrempull = -0.2;
5132 
5133  /*
5134  * Helper parameter accessor.
5135  */
5136  ParamDefsAccessor paraccessor;
5137 
5138  /*
5139  * Loop over all hits and do some preprocessing. In this step, we do:
5140  * - Get residuals
5141  * - Get errors
5142  * - Get scattering angles
5143  * - Fill b-vector and chi2 with scattering effects (others fill later)
5144  */
5145  for (int hitno = 0; hitno < (int) states.size(); hitno++) {
5146  std::unique_ptr<GXFTrackState> & state = states[hitno];
5147  const TrackParameters *currenttrackpar = state->trackParameters();
5148  TrackState::MeasurementType hittype = state->measurementType();
5149  const MeasurementBase *measbase = state->measurement();
5150 
5151  /*
5152  * Measurements and outliers.
5153  */
5154  if (state->getStateType(TrackStateOnSurface::Measurement)) {
5155  /*
5156  * Create new pseudo measurements when the static check (evaluated
5157  * outside the loop) and the dynamic checks both pass
5158  */
5159  if (
5160  doNewPseudoMeasurements &&
5161  hittype == TrackState::Pseudo &&
5162  !state->associatedSurface().isFree() &&
5163  !state->isRecalibrated()
5164  ) {
5165  Amg::MatrixX covMatrix(1, 1);
5166  covMatrix(0, 0) = 100;
5167 
5168  std::unique_ptr<const PseudoMeasurementOnTrack> newpseudo = std::make_unique<const PseudoMeasurementOnTrack>(
5169  LocalParameters(DefinedParameter(currenttrackpar->parameters()[Trk::locY], Trk::locY)),
5170  std::move(covMatrix),
5171  currenttrackpar->associatedSurface()
5172  );
5173 
5174  state->setMeasurement(std::move(newpseudo));
5175  measbase = state->measurement();
5176  }
5177 
5178  /*
5179  * Separate all parameters in the residuals and errors. We will handle
5180  * them separately, asuming them uncorrelated.
5181  */
5182  double *errors = state->measurementErrors();
5183  std::array<double,5> residuals = m_residualPullCalculator->residuals(measbase, currenttrackpar, ResidualPull::Biased, hittype);
5184  for (int i = 0; i < 5; i++) {
5185  /*
5186  * Skip the parameter, if there is no accessor for it.
5187  */
5188  if (!measbase->localParameters().contains(paraccessor.pardef[i])) {
5189  continue;
5190  }
5191 
5192  /*
5193  * SCT and TGC are 1-dimensional, so we can skip the other parameters.
5194  */
5195  if (i > 0 && (hittype == TrackState::SCT || hittype == TrackState::TGC)) {
5196  continue;
5197  }
5198 
5199  error[measno] =
5200  (trajectory.prefit() > 0 && (hittype == TrackState::MDT || (hittype == TrackState::CSC && !state->measuresPhi()))) ?
5201  2 :
5202  errors[i];
5203 
5204  res[measno] = residuals[i];
5205 
5206  /*
5207  * Ensure, that the phi-residual is mapped into the correct period.
5208  */
5209  if (i == 2) {
5210  res[measno] = -std::remainder(-res[measno], 2 * M_PI);
5211  }
5212 
5213  measno++;
5214  }
5215  } else if (state->getStateType(TrackStateOnSurface::Outlier)) {
5216  /*
5217  * NOTE: It seems the residuals are not set in this step. Why?
5218  */
5219  double *errors = state->measurementErrors();
5220  for (int i = 0; i < 5; i++) {
5221  if (errors[i] > 0) {
5222  error[measno] = errors[i];
5223  measno++;
5224  }
5225  }
5226  }
5227 
5228  /*
5229  * Scattering angles contribute to the b-vector and the chi2.
5230  */
5231  if (
5232  state->getStateType(TrackStateOnSurface::Scatterer) &&
5233  ((trajectory.prefit() == 0) || state->materialEffects()->deltaE() == 0)
5234  ) {
5235  const double deltaPhi = state->materialEffects()->deltaPhi();
5236  const double measDeltaPhi = state->materialEffects()->measuredDeltaPhi();
5237  const double sigma2deltaPhi = std::pow(state->materialEffects()->sigmaDeltaPhi(), 2);
5238  const double deltaTheta = state->materialEffects()->deltaTheta();
5239  const double sigma2deltaTheta = std::pow(state->materialEffects()->sigmaDeltaTheta(), 2);
5240 
5241  if (trajectory.prefit() != 1) {
5242  b[nperpars + 2 * scatno] -= (deltaPhi - measDeltaPhi) / sigma2deltaPhi;
5243  b[nperpars + 2 * scatno + 1] -= deltaTheta / sigma2deltaTheta;
5244  } else {
5245  b[nperpars + scatno] -= deltaTheta / sigma2deltaTheta;
5246  }
5247 
5248  chi2 += (
5249  deltaPhi * deltaPhi / sigma2deltaPhi +
5250  deltaTheta * deltaTheta / sigma2deltaTheta
5251  );
5252 
5253  scatno++;
5254  }
5255 
5256  /*
5257  * Energy loss will be considered in the form of a kink.
5258  */
5259  if ((state->materialEffects() != nullptr) && state->materialEffects()->sigmaDeltaE() > 0) {
5260  double averagenergyloss = std::abs(state->materialEffects()->deltaE());
5261  const double qoverpbrem = limitInversePValue(1000 * states[hitno]->trackParameters()->parameters()[Trk::qOverP]);
5262  const double qoverp = limitInversePValue(qoverpbrem - state->materialEffects()->delta_p());
5263  const double pbrem = 1. / std::abs(qoverpbrem);
5264  const double p = 1. / std::abs(qoverp);
5265  const double mass = .001 * trajectory.mass();
5266  const double energy = std::sqrt(p * p + mass * mass);
5267  const double bremEnergy = std::sqrt(pbrem * pbrem + mass * mass);
5268 
5269  const double resMaterial = .001 * averagenergyloss - energy + bremEnergy;
5270  res[nmeas - nbrem + bremno] = resMaterial;
5271 
5272  const double sigde = state->materialEffects()->sigmaDeltaE();
5273  const double sigdepos = state->materialEffects()->sigmaDeltaEPos();
5274  const double sigdeneg = state->materialEffects()->sigmaDeltaENeg();
5275 
5276  double errorMaterial = .001 * state->materialEffects()->sigmaDeltaE();
5277  error[nmeas - nbrem + bremno] = errorMaterial;
5278 
5279  /*
5280  * There is already a kink in the trajectory. No need to look for more.
5281  * - Set the maxbrempull to a small value, so no future candidate can
5282  * be found.
5283  * - Reset the pointer to the state, in case we have set one before.
5284  *
5285  * NOTE: I think, the new value of maxbrempull should be -inf since it
5286  * allows for some edge case pulls. Not sure if bug or feature.
5287  */
5288  if (state->materialEffects()->isKink()) {
5289  maxbrempull = -999999999;
5290  state_maxbrempull = nullptr;
5291  }
5292 
5293  if (
5294  cache.m_asymeloss &&
5295  it > 0 &&
5296  trajectory.prefit() == 0 &&
5297  sigde > 0 &&
5298  sigde != sigdepos &&
5299  sigde != sigdeneg
5300  ) {
5301  const double elosspull = resMaterial / errorMaterial;
5302 
5303  if (trajectory.mass() > 100) {
5304  /*
5305  * If the absolute energy loss pull is too large, update the
5306  * sigmaDeltaE of the state and also update the error/
5307  */
5308  if (std::abs(elosspull) > 1) {
5309  if (elosspull < -1) {
5310  state->materialEffects()->setSigmaDeltaE(sigdepos);
5311  } else {
5312  state->materialEffects()->setSigmaDeltaE(sigdeneg);
5313  }
5314 
5315  errorMaterial = .001 * state->materialEffects()->sigmaDeltaE();
5316  error[nmeas - nbrem + bremno] = errorMaterial;
5317  }
5318  } else if ((trajectory.numberOfTRTHits() == 0) || it >= 3) {
5319  /*
5320  * In case the state is not yet marked as a kink, we might want to
5321  * do so later. For this, we propose a maxbrempull state if either
5322  * - we did not provide an external kink with Gaudi and we want a
5323  * definitely negative elosspull.
5324  * or
5325  * - an external kink is given with Gaudi and we are on it now.
5326  */
5327  if (
5328  !state->materialEffects()->isKink() && (
5329  (m_fixbrem == -1 && elosspull < maxbrempull) ||
5330  (m_fixbrem >= 0 && bremno == m_fixbrem)
5331  )
5332  ) {
5333  bremno_maxbrempull = bremno;
5334  state_maxbrempull = state.get();
5335  maxbrempull = elosspull;
5336  }
5337  }
5338  }
5339 
5340  if (
5341  it > 0 &&
5342  hitno >= 2 &&
5343  !m_calotoolparam.empty() &&
5344  trajectory.prefit() == 0 &&
5345  state->materialEffects()->sigmaDeltaPhi() == 0 &&
5346  state->materialEffects()->isMeasuredEloss() &&
5347  resMaterial / (.001 * state->materialEffects()->sigmaDeltaEAve()) > 2.5
5348  ) {
5349  const TrackParameters* parforcalo = states[hitno - 2]->trackParameters();
5350  const IPropagator* prop = &*m_propagator;
5351 
5352  std::vector<MaterialEffectsOnTrack> calomeots =
5353  m_calotoolparam->extrapolationSurfacesAndEffects(
5354  *m_navigator->highestVolume(ctx),
5355  *prop,
5356  *parforcalo,
5357  parforcalo->associatedSurface(),
5359  Trk::muon);
5360 
5361  /*
5362  * Update energyLoss, sigma, residual, and error if the parametrised
5363  * energy loss results in a absolute smaller pull.
5364  */
5365  if (calomeots.size() == 3) {
5366  averagenergyloss = std::abs(calomeots[1].energyLoss()->deltaE());
5367  const double newres = .001 * averagenergyloss - energy + bremEnergy;
5368  const double newerr = .001 * calomeots[1].energyLoss()->sigmaDeltaE();
5369 
5370  const double oldPull = resMaterial / errorMaterial;
5371  const double newPull = newres / newerr;
5372 
5373  if (std::abs(newPull) < std::abs(oldPull)) {
5374  ATH_MSG_DEBUG("Changing from measured to parametrized energy loss");
5375 
5376  state->materialEffects()->setEloss(std::unique_ptr<EnergyLoss>(calomeots[1].energyLoss()->clone()));
5377  state->materialEffects()->setSigmaDeltaE(calomeots[1].energyLoss()->sigmaDeltaE());
5378  res[nmeas - nbrem + bremno] = newres;
5379  error[nmeas - nbrem + bremno] = newerr;
5380  }
5381  }
5382 
5383  state->materialEffects()->setMeasuredEloss(false);
5384  }
5385 
5386  bremno++;
5387  }
5388  }
5389 
5390  /*
5391  * Sum up the chi2 contributions from all measurements.
5392  */
5393  for (int imeas = 0; imeas < nmeas; imeas++) {
5394  if (error[imeas] == 0) {
5395  continue;
5396  }
5397 
5398  chi2 += std::pow(res[imeas] / error[imeas], 2);
5399  }
5400 
5401  /*
5402  * Update trajectory with previous and current chi2
5403  */
5404  trajectory.setPrevChi2(trajectory.chi2());
5405  trajectory.setChi2(chi2);
5406  }
5407 
5409  const Cache & cache,
5410  GXFTrajectory & trajectory,
5411  const int it
5412  ) const {
5413  ATH_MSG_DEBUG("tryToConverge");
5414 
5415  const double oldChi2 = trajectory.prevchi2();
5416  const double newChi2 = trajectory.chi2();
5417 
5418  /*
5419  * First convergence check
5420  */
5421  const double nDOF = trajectory.nDOF();
5422  const double oldRedChi2 = (nDOF > 0) ? oldChi2 / nDOF : 0;
5423  const double newRedChi2 = (nDOF > 0) ? newChi2 / nDOF : 0;
5424 
5425  if (
5426  trajectory.prefit() > 0 && (
5427  (newRedChi2 < 2 && it != 0) ||
5428  (newRedChi2 < oldRedChi2 + .1 && std::abs(newRedChi2 - oldRedChi2) < 1 && it != 1)
5429  )
5430  ) {
5431  trajectory.setConverged(true);
5432  }
5433 
5434  /*
5435  * Second convergence check
5436  */
5437  const int nsihits = trajectory.numberOfSiliconHits();
5438  const int ntrthits = trajectory.numberOfTRTHits();
5439  const int nhits = trajectory.numberOfHits();
5440 
5441  int miniter = (nsihits != 0 && nsihits + ntrthits == nhits) ? 1 : 2;
5442  miniter = std::max(miniter, cache.m_miniter);
5443 
5444  if (it >= miniter && std::abs(oldChi2 - newChi2) < 1) {
5445  trajectory.setConverged(true);
5446  }
5447  }
5448 
5450  GXFTrajectory & trajectory,
5451  const int bremno_maxbrempull,
5452  GXFTrackState* state_maxbrempull,
5453  Amg::SymMatrixX & a
5454  ) const {
5455  ATH_MSG_DEBUG("updateSystemWithMaxBremPull");
5456 
5457  if (state_maxbrempull == nullptr) {
5458  return;
5459  }
5460 
5461  state_maxbrempull->materialEffects()->setSigmaDeltaE(
5462  10 * state_maxbrempull->materialEffects()->sigmaDeltaEPos()
5463  );
5464 
5465  state_maxbrempull->materialEffects()->setKink(true);
5466 
5467  const int nbrem = trajectory.numberOfBrems();
5468  const Amg::VectorX & res = trajectory.residuals();
5469  const int nmeas = (int) res.size();
5470 
5471  Amg::VectorX & error = trajectory.errors();
5472  const double oldError = error[nmeas - nbrem + bremno_maxbrempull];
5473  const double newError = .001 * state_maxbrempull->materialEffects()->sigmaDeltaE();
5474  error[nmeas - nbrem + bremno_maxbrempull] = newError;
5475 
5476  const int nFitPars = trajectory.numberOfFitParameters();
5477  if (a.cols() != nFitPars) {
5478  ATH_MSG_ERROR("Your assumption is wrong!!!!");
5479  }
5480 
5481  const double errorRatio = oldError / newError;
5482  const double errorReductionRatio = 1 - std::pow(errorRatio, 2);
5483 
5484  Amg::MatrixX & weightderiv = trajectory.weightedResidualDerivatives();
5485  for (int i = 0; i < nFitPars; i++) {
5486  if (weightderiv(nmeas - nbrem + bremno_maxbrempull, i) == 0) {
5487  continue;
5488  }
5489 
5490  for (int j = i; j < nFitPars; j++) {
5491  const double newaij = a(i, j) - errorReductionRatio *
5492  weightderiv(nmeas - nbrem + bremno_maxbrempull, i) *
5493  weightderiv(nmeas - nbrem + bremno_maxbrempull, j);
5494 
5495  a.fillSymmetric(i, j, newaij);
5496  }
5497  weightderiv(nmeas - nbrem + bremno_maxbrempull, i) *= errorRatio;
5498  }
5499  }
5500 
5502  GXFTrajectory & trajectory
5503  ) const {
5504  ATH_MSG_DEBUG("fillDerivatives");
5505 
5506  std::vector<std::unique_ptr<GXFTrackState>> & states = trajectory.trackStates();
5507  int scatno = 0;
5508  int bremno = 0;
5509  int measno = 0;
5510  int nscatupstream = trajectory.numberOfUpstreamScatterers();
5511  int nbremupstream = trajectory.numberOfUpstreamBrems();
5512  int nscat = trajectory.numberOfScatterers();
5513  int nbrem = trajectory.numberOfBrems();
5514  int nperparams = trajectory.numberOfPerigeeParameters();
5515 
5516  Amg::MatrixX & weightderiv = trajectory.weightedResidualDerivatives();
5517  Amg::VectorX & error = trajectory.errors();
5518 
5519  int nmeas = (int) weightderiv.rows();
5520 
5521  ParamDefsAccessor paraccessor;
5522 
5523  for (std::unique_ptr<GXFTrackState> & state : states) {
5524  if (state->getStateType(TrackStateOnSurface::Measurement)) {
5525  TrackState::MeasurementType hittype = state->measurementType();
5526  const MeasurementBase *measbase = state->measurement();
5527  const auto [scatmin, scatmax] = std::minmax(scatno, nscatupstream);
5528  const auto [bremmin, bremmax] = std::minmax(bremno, nbremupstream);
5529 
5530  Amg::MatrixX & derivatives = state->derivatives();
5531 
5532  /*
5533  * Get the stereo angles for SCT and TGC.
5534  */
5535  const double sinStereo =
5536  hittype == TrackState::SCT || hittype == TrackState::TGC ?
5537  state->sinStereo() :
5538  0;
5539  const double cosStereo =
5540  sinStereo != 0 ?
5541  std::sqrt(1 - std::pow(sinStereo, 2)) :
5542  1.;
5543 
5544  /*
5545  * For SCT and TGC we need modified derivatives, taking into account
5546  * the orientation.This lambda chooses the correct accessor and rotates
5547  * the derivative accordingly.
5548  */
5549  auto getThisDeriv = [sinStereo, cosStereo, &derivatives](int i, int j) -> double {
5550  if (i == 0 && sinStereo != 0) {
5551  return derivatives(0, j) * cosStereo + sinStereo * derivatives(1, j);
5552  } else {
5553  return derivatives(i, j);
5554  }
5555  };
5556 
5557  for (int i = 0; i < 5; i++) {
5558  if (!measbase->localParameters().contains(paraccessor.pardef[i])) {
5559  continue;
5560  }
5561 
5562  /*
5563  * SCT and TGC have all information stored in the first parameter.
5564  */
5565  if ((hittype == TrackState::SCT || hittype == TrackState::TGC) && i > 0) {
5566  break;
5567  }
5568 
5569  if (trajectory.numberOfPerigeeParameters() > 0) {
5570  const int cols = trajectory.m_straightline ? 4 : 5;
5571 
5572  if (i == 0 && sinStereo != 0) {
5573  weightderiv.row(measno).head(cols) =
5574  (derivatives.row(0).head(cols) * cosStereo +
5575  sinStereo * derivatives.row(1).head(cols)) /
5576  error[measno];
5577  } else {
5578  weightderiv.row(measno).head(cols) = derivatives.row(i).head(cols) / error[measno];
5579  }
5580  }
5581 
5582  for (int j = scatmin; j < scatmax; j++) {
5583  if (trajectory.prefit() == 1) {
5584  const int index = nperparams + j;
5585  weightderiv(measno, index) = getThisDeriv(i, index) / error[measno];
5586  } else {
5587  const int index = nperparams + 2 * j;
5588  weightderiv(measno, index) = getThisDeriv(i, index) / error[measno];
5589  weightderiv(measno, index + 1) = getThisDeriv(i, index + 1) / error[measno];
5590  }
5591  }
5592 
5593  for (int j = bremmin; j < bremmax; j++) {
5594  const int index = j + nperparams + 2 * nscat;
5595  weightderiv(measno, index) = getThisDeriv(i, index) / error[measno];
5596  }
5597 
5598  measno++;
5599  }
5600  } else if (state->getStateType(TrackStateOnSurface::Outlier)) {
5601  double *errors = state->measurementErrors();
5602  for (int i = 0; i < 5; i++) {
5603  if (errors[i] > 0) {
5604  measno++;
5605  }
5606  }
5607  } else if (
5608  state->getStateType(TrackStateOnSurface::Scatterer) &&
5609  ((trajectory.prefit() == 0) || state->materialEffects()->deltaE() == 0)
5610  ) {
5611  scatno++;
5612  }
5613 
5614  if ((state->materialEffects() != nullptr) && state->materialEffects()->sigmaDeltaE() > 0) {
5615  //limit values to avoid FPE overflow or div by zero
5616  double qoverpbrem = limitInversePValue(1000 * state->trackParameters()->parameters()[Trk::qOverP]);
5617  double qoverp = limitInversePValue(qoverpbrem - state->materialEffects()->delta_p());
5618 
5619  double mass = .001 * trajectory.mass();
5620 
5621  const auto thisMeasurementIdx{nmeas - nbrem + bremno};
5622  //references (courtesy of Christos Anastopoulos):
5623  //https://inspirehep.net/files/a810ad0047a22af32fbff587c6c98ce5
5624  //https://its.cern.ch/jira/browse/ATLASRECTS-6213
5625  auto multiplier = [] (double mass, double qOverP){
5626  return std::copysign(1./(qOverP * qOverP * std::sqrt(1. + mass * mass * qOverP * qOverP)), qOverP);
5627  };
5628  const auto qoverpTerm {multiplier(mass, qoverp) / error[thisMeasurementIdx]};
5629  const auto qoverpBremTerm {multiplier(mass, qoverpbrem) / error[thisMeasurementIdx]};
5630 
5631  if (trajectory.numberOfPerigeeParameters() > 0) {
5632  weightderiv(thisMeasurementIdx, 4) = qoverpBremTerm - qoverpTerm;
5633  }
5634  //
5635  const auto bremNoBase = nperparams + 2 * nscat;
5636  if (bremno < nbremupstream) {
5637  weightderiv(thisMeasurementIdx, bremNoBase + bremno) = qoverpTerm;
5638  for (int bremno2 = bremno + 1; bremno2 < nbremupstream; bremno2++) {
5639  weightderiv(thisMeasurementIdx, bremNoBase + bremno2) = qoverpTerm - qoverpBremTerm;
5640  }
5641  } else {
5642  weightderiv(thisMeasurementIdx, bremNoBase + bremno) = qoverpBremTerm;
5643  for (int bremno2 = nbremupstream; bremno2 < bremno; bremno2++) {
5644  weightderiv(thisMeasurementIdx, bremNoBase + bremno2) = qoverpBremTerm - qoverpTerm;
5645  }
5646  }
5647  bremno++;
5648  }
5649  }
5650  }
5651 
5653  Cache & cache,
5654  GXFTrajectory & trajectory
5655  ) const {
5656  const int nFitPars = trajectory.numberOfFitParameters();
5657  const int nPerPars = trajectory.numberOfPerigeeParameters();
5658  const int nScatPars = 2 * trajectory.numberOfScatterers();
5659  const int nBrem = trajectory.numberOfBrems();
5660  const int nUpstreamStates = trajectory.numberOfUpstreamStates();
5661 
5662  const Amg::VectorX & res = trajectory.residuals();
5663  const int nMeas = (int) res.size();
5664 
5665  cache.m_firstmeasurement.resize(nFitPars);
5666  cache.m_lastmeasurement.resize(nFitPars);
5667 
5668  for (int i = 0; i < nPerPars; i++) {
5669  cache.m_firstmeasurement[i] = 0;
5670  cache.m_lastmeasurement[i] = nMeas - nBrem;
5671  }
5672 
5673  int measno = 0;
5674  int scatno = 0;
5675  int bremno = 0;
5676  for (int i = 0; i < (int) trajectory.trackStates().size(); i++) {
5677  const std::unique_ptr<GXFTrackState> & state = trajectory.trackStates()[i];
5678  const GXFMaterialEffects *meff = state->materialEffects();
5679 
5680  if (meff == nullptr) {
5681  measno += state->numberOfMeasuredParameters();
5682  continue;
5683  }
5684 
5685  const int firstMeasurement = i < nUpstreamStates ? 0 : measno;
5686  const int lastMeasurement = i < nUpstreamStates ? measno : nMeas - nBrem;
5687 
5688  if (meff->sigmaDeltaTheta() != 0
5689  && (trajectory.prefit() == 0 || meff->deltaE() == 0)) {
5690  const int scatterPos = nPerPars + 2 * scatno;
5691 
5692  cache.m_firstmeasurement[scatterPos] = firstMeasurement;
5693  cache.m_lastmeasurement[scatterPos] = lastMeasurement;
5694 
5695  cache.m_firstmeasurement[scatterPos + 1] = firstMeasurement;
5696  cache.m_lastmeasurement[scatterPos + 1] = lastMeasurement;
5697 
5698  scatno++;
5699  }
5700 
5701  if (meff->sigmaDeltaE() > 0) {
5702  const int bremPos = nPerPars + nScatPars + bremno;
5703 
5704  cache.m_firstmeasurement[bremPos] = firstMeasurement;
5705  cache.m_lastmeasurement[bremPos] = lastMeasurement;
5706 
5707  bremno++;
5708  }
5709  }
5710  }
5711 
5713  const Cache & cache,
5714  GXFTrajectory & trajectory,
5715  Amg::VectorX & b
5716  ) const {
5717  const int nFitPars = trajectory.numberOfFitParameters();
5718  const int nPerPars = trajectory.numberOfPerigeeParameters();
5719  const int nScatPars = 2 * trajectory.numberOfScatterers();
5720  const int nBrem = trajectory.numberOfBrems();
5721  const Amg::MatrixX & weightDeriv = trajectory.weightedResidualDerivatives();
5722 
5723  const Amg::VectorX & res = trajectory.residuals();
5724  const Amg::VectorX & error = trajectory.errors();
5725 
5726  const int nMeas = (int) res.size();
5727 
5728  for (int k = 0; k < nFitPars; k++) {
5729  const int minMeasK = cache.m_firstmeasurement[k];
5730  const int maxMeasK = cache.m_lastmeasurement[k];
5731 
5732  /*
5733  * NOTE: It is necessary to do r * invError * weight instead of doing
5734  * r / error * w. Otherwise, the implementation tests fail do to
5735  * numerical reasons.
5736  */
5737  for (int measno = minMeasK; measno < maxMeasK; measno++) {
5738  b[k] += res[measno] * (1. / error[measno]) * weightDeriv(measno, k);
5739  }
5740 
5741  /*
5742  * For qOverP and brems, we also have a contribution to brems elements.
5743  *
5744  * NOTE: It is necessary to do r * invError * weight instead of doing
5745  * r / error * w. Otherwise, the implementation tests fail do to
5746  * numerical reasons.
5747  */
5748  if (k == 4 || k >= nPerPars + nScatPars) {
5749  for (int measno = nMeas - nBrem; measno < nMeas; measno++) {
5750  b[k] += res[measno] * (1. / error[measno]) * weightDeriv(measno, k);
5751  }
5752  }
5753  }
5754  }
5755 
5757  const Cache & cache,
5758  GXFTrajectory & trajectory,
5759  Amg::SymMatrixX & a
5760  ) const {
5761  const int nFitPars = trajectory.numberOfFitParameters();
5762  const Amg::MatrixX & weightDeriv = trajectory.weightedResidualDerivatives();
5763 
5764  for (int k = 0; k < nFitPars; k++) {
5765  for (int l = k; l < nFitPars; l++) {
5766  const int minMeas = std::max(cache.m_firstmeasurement[k], cache.m_firstmeasurement[l]);
5767  const int maxMeas = std::min(cache.m_lastmeasurement[k], cache.m_lastmeasurement[l]);
5768 
5769  double a_kl = 0;
5770  for (int measno = minMeas; measno < maxMeas; measno++) {
5771  a_kl += weightDeriv(measno, k) * weightDeriv(measno, l);
5772  }
5773 
5774  a.fillSymmetric(l, k, a_kl);
5775  }
5776  }
5777  }
5778 
5780  GXFTrajectory & trajectory,
5781  Amg::SymMatrixX & a
5782  ) const {
5783  const int nFitPars = trajectory.numberOfFitParameters();
5784  const int nPerPars = trajectory.numberOfPerigeeParameters();
5785  const int nScatPars = 2 * trajectory.numberOfScatterers();
5786  const int nBrem = trajectory.numberOfBrems();
5787  const Amg::MatrixX & weightDeriv = trajectory.weightedResidualDerivatives();
5788 
5789  const Amg::VectorX & res = trajectory.residuals();
5790  const auto & scatSigmas = trajectory.scatteringSigmas();
5791 
5792  const int nMeas = (int) res.size();
5793 
5794  int scatno = 0;
5795 
5796  /*
5797  * Direct contribution on the diagonal from the scatterer itself.
5798  */
5799  for (int k = nPerPars; k < nPerPars + nScatPars; k += 2) {
5800  a(k, k) += 1. / std::pow(scatSigmas[scatno].first, 2);
5801  a(k + 1, k + 1) += 1. / std::pow(scatSigmas[scatno].second, 2);
5802 
5803  scatno++;
5804  }
5805 
5806  /*
5807  * Indirect contribution on the qOverP and brems derivatives.
5808  */
5809  for (int measno = nMeas - nBrem; measno < nMeas; measno++) {
5810  for (int k = 4; k < nFitPars; k++) {
5811  if (k == 5) {
5812  k = nPerPars + nScatPars;
5813  }
5814 
5815  for (int l = k; l < nFitPars; l++) {
5816  if (l == 5) {
5817  l = nPerPars + nScatPars;
5818  }
5819 
5820  const double a_kl = a(l, k) + weightDeriv(measno, k) * weightDeriv(measno, l);
5821  a.fillSymmetric(l, k, a_kl);
5822  }
5823  }
5824  }
5825  }
5826 
5828  Cache & cache,
5829  GXFTrajectory & trajectory,
5830  Amg::SymMatrixX & a,
5831  const bool doDeriv,
5832  const int it,
5833  const double oldRedChi2,
5834  const double newRedChi2
5835  ) const {
5836  const int nPerPars = trajectory.numberOfPerigeeParameters();
5837 
5838  /*
5839  * The return value collects, if any weights changed while looping over all
5840  * material states.
5841  */
5842  bool weightChanged = false;
5843 
5844  /*
5845  * The weights for the diagonal material components in the [a]-matrix
5846  * depend on how far we are in the iteration process (iteration number or
5847  * chi2 convergence).
5848  */
5849  double newPhiWeight = 1.1;
5850  double newThetaWeight = 1.001;
5851  if (trajectory.prefit() == 0) {
5852  /*
5853  * We do not consider theta at all in the prefit 0 case. Therefore, we do
5854  * not need to adjust the theta weights.
5855  */
5856  if (it == 0) {
5857  newPhiWeight = 1.00000001;
5858  } else if (it == 1) {
5859  newPhiWeight = 1.0000001;
5860  } else if (it <= 3) {
5861  newPhiWeight = 1.0001;
5862  } else if (it <= 6) {
5863  newPhiWeight = 1.01;
5864  }
5865  } else {
5866  if (newRedChi2 > oldRedChi2 - 1 && newRedChi2 < oldRedChi2) {
5867  newPhiWeight = 1.0001;
5868  newThetaWeight = 1.0001;
5869  } else if (newRedChi2 > oldRedChi2 - 25 && newRedChi2 < oldRedChi2) {
5870  newPhiWeight = 1.001;
5871  newThetaWeight = 1.0001;
5872  }
5873  }
5874 
5875  /*
5876  * Counter for the scattering states. We cannot directly loop over them.
5877  */
5878  std::size_t scatno = 0;
5879 
5880  /*
5881  * Loop over all track states. Skip states without material effects.
5882  */
5883  for (const auto & state : trajectory.trackStates()) {
5884  const GXFMaterialEffects *meff = state->materialEffects();
5885 
5886  if (meff == nullptr) {
5887  continue;
5888  }
5889 
5890  const bool isValidPlaneSurface =
5892  static_cast<const PlaneSurface *>(&state->associatedSurface()) != nullptr;
5893 
5894  /*
5895  * Modify the diagonal material elements in the [a]-matrix.
5896  */
5897  if (meff->deltaE() == 0 || (trajectory.prefit() == 0 && isValidPlaneSurface)) {
5898  weightChanged = true;
5899 
5900  const int scatNoIndex = 2 * scatno + nPerPars;
5901 
5902  if (trajectory.prefit() == 0 && meff->sigmaDeltaPhi() != 0) {
5903  if (scatno >= cache.m_phiweight.size()) {
5904  std::stringstream message;
5905  message << "scatno is out of range " << scatno << " !< " << cache.m_phiweight.size();
5906  throw std::range_error(message.str());
5907  }
5908 
5909  /*
5910  * In case, no derivative is necessary, the weight will be
5911  * effectively replaced by the relative weight change
5912  */
5913  if (!doDeriv) {
5914  a(scatNoIndex, scatNoIndex) /= cache.m_phiweight[scatno];
5915  }
5916 
5917  cache.m_phiweight[scatno] = newPhiWeight;
5918  a(scatNoIndex, scatNoIndex) *= newPhiWeight;
5919  } else if (trajectory.prefit() >= 2) {
5920  a(scatNoIndex, scatNoIndex) *= newPhiWeight;
5921  a(scatNoIndex + 1, scatNoIndex + 1) *= newThetaWeight;
5922  }
5923  }
5924 
5925  /*
5926  * The state is a valid scatterer even, if not considered in the
5927  * modification of the weights before. Therefore increment the count.
5928  *
5929  * NOTE: It is not clear, why this check is not at the beginning of the
5930  * loop. This way, a mismatch in the state counting could happen.
5931  */
5932  if (
5933  meff->sigmaDeltaPhi() != 0 &&
5934  (trajectory.prefit() == 0 || meff->deltaE() == 0)
5935  ) {
5936  scatno++;
5937  }
5938  }
5939 
5940  /*
5941  * Add a weight to the qOverP component of the [a]-matrix if a set of
5942  * pre-conditions are met and the reduced chi2 either
5943  * - converges very fast (e.g. at the beginning of the fit)
5944  * OR
5945  * - gets larger (e.g. moving away from minimum or overshooting by a lot)
5946  */
5947  if (
5948  trajectory.prefit() == 2 &&
5949  doDeriv &&
5950  trajectory.numberOfBrems() > 0 &&
5951  (newRedChi2 < oldRedChi2 - 25 || newRedChi2 > oldRedChi2)
5952  ) {
5953  a(4, 4) *= 1.001;
5954  }
5955 
5956  return weightChanged;
5957  }
5958 
5960  Cache & cache,
5961  GXFTrajectory & trajectory,
5962  Amg::SymMatrixX & a
5963  ) const {
5964  const int nPerPars = trajectory.numberOfPerigeeParameters();
5965  std::size_t scatno = 0;
5966 
5967  for (auto & state : trajectory.trackStates()) {
5968  const GXFMaterialEffects *meff = state->materialEffects();
5969 
5970  if (meff == nullptr || meff->sigmaDeltaPhi() == 0) {
5971  continue;
5972  }
5973 
5974  if (scatno >= cache.m_phiweight.size()) {
5975  std::stringstream message;
5976  message << "scatno is out of range " << scatno << " !< " << cache.m_phiweight.size();
5977  throw std::range_error(message.str());
5978  }
5979 
5980  const bool isValidPlaneSurface =
5981  state->associatedSurface().type() == Trk::SurfaceType::Plane &&
5982  static_cast<const PlaneSurface *>(&state->associatedSurface()) != nullptr;
5983 
5984  if (meff->deltaE() == 0 || isValidPlaneSurface) {
5985  const int scatNoIndex = 2 * scatno + nPerPars;
5986  a(scatNoIndex, scatNoIndex) /= cache.m_phiweight[scatno];
5987  cache.m_phiweight[scatno] = 1;
5988  }
5989 
5990  /*
5991  * NOTE: We already check for this in the beginning of the loop. Is
5992  * there any way, this can change?
5993  */
5994  if (meff->sigmaDeltaPhi() != 0) {
5995  scatno++;
5996  }
5997  }
5998  }
5999 
6001  const EventContext& ctx,
6002  Cache & cache,
6003  GXFTrajectory & trajectory,
6004  const int it,
6005  Amg::SymMatrixX & a,
6006  Amg::VectorX & b,
6007  Amg::SymMatrixX & lu,
6008  bool & doDeriv
6009  ) const {
6010  const int nDOFold = trajectory.nDOF();
6011  const double oldChi2 = trajectory.chi2();
6012  const double oldRedChi2 = nDOFold > 0 ? oldChi2 / nDOFold : 0;
6013 
6014  if (cache.m_phiweight.empty()) {
6015  cache.m_phiweight.assign(trajectory.trackStates().size(), 1);
6016  }
6017 
6018  FitterStatusCode fsc = calculateTrackParameters(ctx, trajectory, doDeriv);
6019 
6020  if (fsc != FitterStatusCode::Success) {
6021  return fsc;
6022  }
6023 
6024  /*
6025  * Reset the b-vector. We want to add to the components later.
6026  */
6027  b.setZero();
6028 
6029  /*
6030  * Here we store the information on where to find the maxbrempull, in case
6031  * we find any large ones during the residual calculation. We might need it
6032  * later to update our errors.
6033  */
6034  int bremno_maxbrempull = 0;
6035  GXFTrackState* state_maxbrempull = nullptr;
6036 
6037  fillResidualsAndErrors(ctx, cache, trajectory, it, b, bremno_maxbrempull, state_maxbrempull);
6038 
6039  /*
6040  * Check if we hit any convergence conditions.
6041  */
6042  tryToConverge(cache, trajectory, it);
6043 
6044  /*
6045  * In case we converged but have a state with maxbrempull (a kink) we want
6046  * to do more iterations. Therefore, reset the convergence flag and inflate
6047  * the chi2. Then update the error estimates using the state with the
6048  * maxbrempull.
6049  */
6050  if ((state_maxbrempull != nullptr) && trajectory.converged()) {
6051  trajectory.setConverged(false);
6052  trajectory.setChi2(1e15);
6053  doDeriv = true;
6054 
6055  updateSystemWithMaxBremPull(trajectory, bremno_maxbrempull, state_maxbrempull, a);
6056  lu = a;
6057  }
6058 
6059  const int nDOFnew = trajectory.nDOF();
6060  const double newChi2 = trajectory.chi2();
6061  const double newRedChi2 = nDOFnew > 0 ? newChi2 / nDOFnew : 0;
6062 
6063  ATH_MSG_DEBUG("old chi2: " << oldChi2 << "/" << nDOFold << "=" << oldRedChi2 <<
6064  ", new chi2: " << newChi2 << "/" << nDOFnew << "=" << newRedChi2);
6065 
6066  if (trajectory.prefit() > 0 && trajectory.converged()) {
6068  }
6069 
6070  if (doDeriv) {
6071  calculateDerivatives(trajectory);
6072  fillDerivatives(trajectory);
6073  }
6074 
6075  if (cache.m_firstmeasurement.empty()) {
6076  fillFirstLastMeasurement(cache, trajectory);
6077  }
6078 
6079  if (a.cols() != trajectory.numberOfFitParameters()) {
6080  ATH_MSG_ERROR("Your assumption is wrong!!!!");
6081  }
6082 
6083  fillBfromMeasurements(cache, trajectory, b);
6084 
6085  /*
6086  * The [a]-matrix does not depend on the residuals. We only need to change
6087  * it, if the derivatives have changed.
6088  */
6089  if (doDeriv) {
6090  fillAfromMeasurements(cache, trajectory, a);
6091  fillAfromScatterers(trajectory, a);
6092  }
6093 
6094  const bool weightChanged = tryToWeightAfromMaterial(cache, trajectory, a, doDeriv, it, oldRedChi2, newRedChi2);
6095 
6096  /*
6097  * Update the [lu]-matrix if we modified the [a]-matrix.
6098  */
6099  if (doDeriv || weightChanged) {
6100  lu = a;
6101  }
6102 
6103  /*
6104  * Special handling for prefit == 0:
6105  * - If we already converged, but there are hits apart from Si and TRT or
6106  * the numbers don't match, the applied phi weights need to be reset.
6107  * - If we got in an early iteration to a low reduced chi2 or converged
6108  * with the reduced chi2, we don't need to redo derivatives.
6109  */
6110  if (trajectory.prefit() == 0) {
6111  if (trajectory.converged()) {
6112  const int nSiHits = trajectory.numberOfSiliconHits();
6113  const int nTrtHits = trajectory.numberOfTRTHits();
6114  const int nHits = trajectory.numberOfHits();
6115 
6116  if (nSiHits + nTrtHits != nHits) {
6117  compensatePhiWeights(cache, trajectory, a);
6118  lu = a;
6119  }
6120  } else if (
6121  !m_redoderivs &&
6122  it < 5 &&
6123  (newRedChi2 < 2 || (newRedChi2 < oldRedChi2 && newRedChi2 > oldRedChi2 - .5))
6124  ) {
6125  doDeriv = false;
6126  }
6127  }
6128 
6130  }
6131 
6133  GXFTrajectory & trajectory,
6134  const Amg::VectorX & b,
6135  const Amg::SymMatrixX & lu_m
6136  ) const {
6137  ATH_MSG_DEBUG("UpdateFitParameters");
6138 
6139  /*
6140  * Compute the parameter update from [llt] * deltaParameters = b.
6141  * In case we cannot do a Cholesky decomposition, we do not update and
6142  * use an early return.
6143  * TODO: Investigate, if it is really Success, if we do not update.
6144  */
6145  Eigen::LLT<Eigen::MatrixXd> llt(lu_m);
6146 
6147  if (llt.info() != Eigen::Success) {
6149  }
6150 
6151  const Amg::VectorX deltaParameters = llt.solve(b);
6152 
6153  /*
6154  * Collect the number of each parameter type for the offsets in the
6155  * deltaParameters vector.
6156  */
6157  const int nscat = trajectory.numberOfScatterers();
6158  const int nbrem = trajectory.numberOfBrems();
6159  const int nperparams = trajectory.numberOfPerigeeParameters();
6160 
6161  /*
6162  * Update the perigee parameters.
6163  * The parameters are not modified in place. In case the angles are pushed
6164  * too far and cannot be corrected anymore, the parameters should not be
6165  * updated and the fit should fail.
6166  *
6167  * NOTE: It is not clear if the fit should fail for fitter reasons or
6168  * because the angle correction is not stable enough.
6169  */
6170  const TrackParameters *refpar = trajectory.referenceParameters();
6171  double d0 = refpar->parameters()[Trk::d0];
6172  double z0 = refpar->parameters()[Trk::z0];
6173  double phi = refpar->parameters()[Trk::phi0];
6174  double theta = refpar->parameters()[Trk::theta];
6175  double qoverp = refpar->parameters()[Trk::qOverP];
6176 
6177  if (nperparams > 0) {
6178  d0 += deltaParameters[0];
6179  z0 += deltaParameters[1];
6180  phi += deltaParameters[2];
6181  theta += deltaParameters[3];
6182  qoverp = (trajectory.m_straightline) ? 0 : .001 * deltaParameters[4] + qoverp;
6183  }
6184 
6185  if (!correctAngles(phi, theta)) {
6186  ATH_MSG_DEBUG("angles out of range: " << theta << " " << phi);
6187  ATH_MSG_DEBUG("Fit failed");
6189  }
6190 
6191  /*
6192  * Update the scattering angles.
6193  */
6194  std::vector < std::pair < double, double >>&scatangles = trajectory.scatteringAngles();
6195  for (int i = 0; i < nscat; i++) {
6196  scatangles[i].first += deltaParameters[2 * i + nperparams];
6197  scatangles[i].second += deltaParameters[2 * i + nperparams + 1];
6198  }
6199 
6200  /*
6201  * Update the brems.
6202  */
6203  std::vector < double >&delta_ps = trajectory.brems();
6204  for (int i = 0; i < nbrem; i++) {
6205  delta_ps[i] += deltaParameters[nperparams + 2 * nscat + i];
6206  }
6207 
6208  /*
6209  * Create new peregee parameters from the updated ones.
6210  */
6211  std::unique_ptr<const TrackParameters> newper(
6213  d0, z0, phi, theta, qoverp, std::nullopt
6214  )
6215  );
6216 
6217  /*
6218  * Apply all changes.
6219  */
6220  trajectory.setReferenceParameters(std::move(newper));
6221  trajectory.setScatteringAngles(scatangles);
6222  trajectory.setBrems(delta_ps);
6223 
6225  }
6226 
6228  GXFTrajectory & trajectory,
6229  Amg::SymMatrixX & a,
6230  Amg::VectorX & b,
6231  const EventContext& evtctx
6232  ) const{
6233  if ( trajectory.numberOfSiliconHits() == 0) {
6234  return;
6235  }
6236 
6238  return;
6239  }
6240 
6242  if (!splitProbContainer.isValid()) {
6243  ATH_MSG_FATAL("Failed to get cluster splitting probability container " << m_clusterSplitProbContainer);
6244  }
6245 
6246  std::vector<std::unique_ptr<GXFTrackState>> & states = trajectory.trackStates();
6247  Amg::VectorX & res = trajectory.residuals();
6248  Amg::VectorX & err = trajectory.errors();
6249  Amg::MatrixX & weightderiv = trajectory.weightedResidualDerivatives();
6250  int nfitpars = trajectory.numberOfFitParameters();
6251 
6252  int measno = 0;
6253  for (size_t stateno = 0; stateno < states.size(); stateno++) {
6254 
6255  // Increment the measurement counter everytime we have crossed a measurement/outlier surface
6256  if ( stateno > 0 && ( states[stateno-1]->getStateType(TrackStateOnSurface::Measurement) ||
6257  states[stateno-1]->getStateType(TrackStateOnSurface::Outlier) ) ) {
6258  measno += states[stateno-1]->numberOfMeasuredParameters();
6259  }
6260 
6261  std::unique_ptr<GXFTrackState> & state = states[stateno];
6262  if (!state->getStateType(TrackStateOnSurface::Measurement)) {
6263  continue;
6264  }
6265 
6266  TrackState::MeasurementType hittype = state->measurementType();
6267  if (hittype != TrackState::Pixel) {
6268  continue;
6269  }
6270 
6271  const PrepRawData *prd{};
6272  if (const auto *const pMeas = state->measurement(); pMeas->type(Trk::MeasurementBaseType::RIO_OnTrack)){
6273  const auto *const rot = static_cast<const RIO_OnTrack *>(pMeas);
6274  prd = rot->prepRawData();
6275  }
6276 
6277  if(!prd)
6278  continue;
6279 
6280  if(!prd->type(Trk::PrepRawDataType::PixelCluster)){
6281  continue;
6282  }
6283  const InDet::PixelCluster* pixelCluster = static_cast<const InDet::PixelCluster*> ( prd );
6284  const auto &splitProb = splitProbContainer->splitProbability(pixelCluster);
6285  if (!splitProb.isSplit()) {
6286  ATH_MSG_DEBUG( "Pixel cluster is not split so no need to update" );
6287  continue;
6288  }
6289 
6290  std::unique_ptr < const RIO_OnTrack > newrot;
6291  double *olderror = state->measurementErrors();
6292  const TrackParameters *trackpars = state->trackParameters();
6293 
6294  double newerror[5] = {-1,-1,-1,-1,-1};
6295  double newres[2] = {-1,-1};
6296 
6297  newrot.reset(m_ROTcreator->correct(*prd, *trackpars, evtctx));
6298 
6299  if(!newrot)
6300  continue;
6301 
6302  const Amg::MatrixX & covmat = newrot->localCovariance();
6303 
6304  newerror[0] = std::sqrt(covmat(0, 0));
6305  newres[0] = newrot->localParameters()[Trk::locX] - trackpars->parameters()[Trk::locX];
6306  newerror[1] = std::sqrt(covmat(1, 1));
6307  newres[1] = newrot->localParameters()[Trk::locY] - trackpars->parameters()[Trk::locY];
6308 
6309  if (a.cols() != nfitpars) {
6310  ATH_MSG_ERROR("Your assumption is wrong!!!!");
6311  }
6312 
6313  //loop over both measurements -- treated as uncorrelated
6314  for( int k =0; k<2; k++ ){
6315  double oldres = res[measno+k];
6316  res[measno+k] = newres[k];
6317  err[measno+k] = newerror[k];
6318 
6319  for (int i = 0; i < nfitpars; i++) {
6320  if (weightderiv(measno+k, i) == 0) {
6321  continue;
6322  }
6323 
6324  b[i] -= weightderiv(measno+k, i) * (oldres / olderror[k] - (newres[k] * olderror[k]) / (newerror[k] * newerror[k]));
6325 
6326  for (int j = i; j < nfitpars; j++) {
6327  a.fillSymmetric(
6328  i, j,
6329  a(i, j) + (
6330  weightderiv(measno+k, i) *
6331  weightderiv(measno+k, j) *
6332  ((olderror[k] * olderror[k]) / (newerror[k] * newerror[k]) - 1)
6333  )
6334  );
6335  }
6336  weightderiv(measno+k, i) *= olderror[k] / newerror[k];
6337  }
6338  }
6339 
6340  state->setMeasurement(std::move(newrot));
6341  state->setMeasurementErrors(newerror);
6342 
6343  }// end for
6344  }
6345 
6346 
6348  Cache & cache,
6349  GXFTrajectory & trajectory,
6350  Amg::SymMatrixX & a,
6351  Amg::VectorX & b,
6352  Amg::SymMatrixX & lu_m,
6353  bool runOutlier,
6354  bool trtrecal,
6355  int it,
6356  const EventContext& ctx
6357  ) const {
6358  double scalefactor = m_scalefactor;
6359 
6360  if (it == 1 && trajectory.numberOfSiliconHits() + trajectory.numberOfTRTHits() == trajectory.numberOfHits()) {
6361  scalefactor *= 2;
6362  }
6363 
6364  std::vector<std::unique_ptr<GXFTrackState>> & states = trajectory.trackStates();
6365  Amg::VectorX & res = trajectory.residuals();
6366  Amg::VectorX & err = trajectory.errors();
6367  Amg::MatrixX & weightderiv = trajectory.weightedResidualDerivatives();
6368  int nfitpars = trajectory.numberOfFitParameters();
6369 
6370  if (a.cols() != nfitpars) {
6371  ATH_MSG_ERROR("Your assumption is wrong!!!!");
6372  }
6373 
6374  int nperpars = trajectory.numberOfPerigeeParameters();
6375  int nscats = trajectory.numberOfScatterers();
6376  int hitno = 0;
6377  int measno = 0;
6378  bool outlierremoved = false;
6379  bool hitrecalibrated = false;
6380 
6381  for (int stateno = 0; stateno < (int) states.size(); stateno++) {
6382  std::unique_ptr<GXFTrackState> & state = states[stateno];
6383 
6384  if (state->getStateType(TrackStateOnSurface::Measurement)) { // Hit is not (yet) an outlier
6385  TrackState::MeasurementType hittype = state->measurementType();
6386 
6387  if (hittype == TrackState::TRT) {
6388  if (
6389  runOutlier &&
6390  std::abs(state->trackParameters()->parameters()[Trk::driftRadius]) > 1.05 * state->associatedSurface().bounds().r()
6391  ) {
6392  ATH_MSG_DEBUG("Removing TRT hit #" << hitno);
6393 
6394  trajectory.setOutlier(stateno);
6395  outlierremoved = true;
6396 
6397  double *errors = state->measurementErrors();
6398  double olderror = errors[0];
6399 
6400  trajectory.updateTRTHitCount(stateno, olderror);
6401 
6402  for (int i = 0; i < nfitpars; i++) {
6403  if (weightderiv(measno, i) == 0) {
6404  continue;
6405  }
6406 
6407  b[i] -= res[measno] * weightderiv(measno, i) / olderror;
6408 
6409  for (int j = i; j < nfitpars; j++) {
6410  a.fillSymmetric(
6411  i, j,
6412  a(i, j) - weightderiv(measno, i) * weightderiv(measno, j)
6413  );
6414  }
6415  weightderiv(measno, i) = 0;
6416  }
6417 
6418  res[measno] = 0;
6419  } else if (trtrecal) {
6420  double *errors = state->measurementErrors();
6421  double olderror = errors[0];
6422  const Trk::RIO_OnTrack * oldrot{};
6423  const auto *const thisMeasurement{state->measurement()};
6424  if ( not thisMeasurement->type(Trk::MeasurementBaseType::RIO_OnTrack)){
6425  continue;
6426  }
6427  oldrot = static_cast<const Trk::RIO_OnTrack *>(thisMeasurement);
6428  double oldradius = oldrot->localParameters()[Trk::driftRadius];
6429  if (oldrot->prepRawData() != nullptr) {
6430  double dcradius = oldrot->prepRawData()->localPosition()[Trk::driftRadius];
6431  double dcerror = std::sqrt(oldrot->prepRawData()->localCovariance()(Trk::driftRadius, Trk::driftRadius));
6432  double trackradius = state->trackParameters()->parameters()[Trk::driftRadius];
6433 
6434  std::unique_ptr<const Trk::RIO_OnTrack> newrot = nullptr;
6435  double distance = std::abs(std::abs(trackradius) - dcradius);
6436 
6437  if (distance < scalefactor * dcerror && (olderror > 1. || trackradius * oldradius < 0)) {
6438  newrot.reset(m_ROTcreator->correct(*oldrot->prepRawData(), *state->trackParameters(), ctx));
6439  } else if (distance > scalefactor * dcerror && olderror < 1.) {
6440  newrot.reset(m_broadROTcreator->correct(*oldrot->prepRawData(), *state->trackParameters(), ctx));
6441  }
6442 
6443  if (newrot != nullptr) {
6444  ATH_MSG_DEBUG("Recalibrating TRT hit #" << hitno);
6445  hitrecalibrated = true;
6446  double newradius = newrot->localParameters()[Trk::driftRadius];
6447  double newerror = std::sqrt(newrot->localCovariance()(Trk::driftRadius, Trk::driftRadius));
6448 
6449  if ((measno < 0) or (measno >= (int) res.size())) {
6450  throw std::runtime_error(
6451  "'res' array index out of range in TrkGlobalChi2Fitter/src/GlobalChi2Fitter.cxx:" + std::to_string(__LINE__)
6452  );
6453  }
6454 
6455  double oldres = res[measno];
6456  double newres = newradius - state->trackParameters()->parameters()[Trk::driftRadius];
6457  errors[0] = newerror;
6458  state->setMeasurement(std::move(newrot));
6459 
6460  trajectory.updateTRTHitCount(stateno, olderror);
6461 
6462  for (int i = 0; i < nfitpars; i++) {
6463  if (weightderiv(measno, i) == 0) {
6464  continue;
6465  }
6466 
6467  b[i] -= weightderiv(measno, i) * (oldres / olderror - (newres * olderror) / (newerror * newerror));
6468 
6469  for (int j = i; j < nfitpars; j++) {
6470  double weight = 1;
6471 
6472  if (
6473  !cache.m_phiweight.empty() &&
6474  i == j &&
6475  i >= nperpars &&
6476  i < nperpars + 2 * nscats &&
6477  (i - nperpars) % 2 == 0
6478  ) {
6479  weight = cache.m_phiweight[(i - nperpars) / 2];
6480  }
6481 
6482  a.fillSymmetric(
6483  i, j,
6484  a(i, j) + weightderiv(measno, i) * weightderiv(measno, j) * ((olderror * olderror) / (newerror * newerror) - 1) * weight
6485  );
6486  }
6487  weightderiv(measno, i) *= olderror / newerror;
6488  }
6489 
6490  res[measno] = newres;
6491  err[measno] = newerror;
6492  }
6493  }
6494  }
6495  }
6496  }
6497 
6498  if (state->getStateType(TrackStateOnSurface::Measurement) || state->getStateType(TrackStateOnSurface::Outlier)) {
6499  hitno++;
6500  measno += state->numberOfMeasuredParameters();
6501  }
6502  }
6503 
6504  if (trajectory.nDOF() < 0) {
6507  }
6508 
6509  if (outlierremoved || hitrecalibrated) {
6510  lu_m = a;
6511  trajectory.setConverged(false);
6512 
6513  cache.m_miniter = it + 2;
6514  }
6515  }
6516 
6518  const EventContext& ctx,
6519  Cache & cache,
6520  GXFTrajectory &trajectory,
6521  Amg::SymMatrixX & a,
6522  Amg::SymMatrixX &fullcov,
6523  Amg::VectorX & b,
6524  bool runoutlier
6525  ) const {
6526  bool trackok = false;
6527  GXFTrajectory *oldtrajectory = &trajectory;
6528  std::unique_ptr < GXFTrajectory > cleanup_oldtrajectory;
6529  GXFTrajectory *newtrajectory = nullptr;
6530  std::unique_ptr < GXFTrajectory > cleanup_newtrajectory;
6531 
6532  // the oldtrajectory will be returned, so in case newtrajectory==oldtrajectory
6533  // the cleanup_newtrajectory == NULL and cleanup_oldtrajectory = oldtrajectory, otherwise
6534  // cleanup_newtrajectory will destroy the object oldtrajectory is pointing to.
6535 
6536  while (!trackok && oldtrajectory->nDOF() > 0) {
6537  trackok = true;
6538  std::vector<std::unique_ptr<GXFTrackState>> & states = oldtrajectory->trackStates();
6539  Amg::VectorX & res = oldtrajectory->residuals();
6540  Amg::VectorX & err = oldtrajectory->errors();
6541  Amg::MatrixX & weightderiv = oldtrajectory->weightedResidualDerivatives();
6542  int nfitpars = oldtrajectory->numberOfFitParameters();
6543  int nhits = oldtrajectory->numberOfHits();
6544  int nsihits = oldtrajectory->numberOfSiliconHits();
6545 
6546  if (nhits != nsihits) {
6547  return &trajectory;
6548  }
6549 
6550  double maxsipull = -1;
6551  int hitno = 0;
6552  int hitno_maxsipull = -1;
6553  int measno_maxsipull = -1;
6554  int stateno_maxsipull = 0;
6555  GXFTrackState *state_maxsipull = nullptr;
6556  int measno = 0;
6557  int n3sigma = 0;
6558  double cut = m_outlcut;
6559  double cut2 = m_outlcut - 1.;
6560  int noutl = oldtrajectory->numberOfOutliers();
6561 
6562  if (noutl > 0) {
6563  cut2 = cut - 1.25;
6564  }
6565 
6566  for (int stateno = 0; stateno < (int) states.size(); stateno++) {
6567  std::unique_ptr<GXFTrackState> & state = states[stateno];
6568 
6569  if (state->getStateType(TrackStateOnSurface::Measurement)) {
6570  TrackState::MeasurementType hittype = state->measurementType();
6571 
6572  if ((hittype == TrackState::Pixel || hittype == TrackState::SCT) && state->hasTrackCovariance()) {
6573  double *errors = state->measurementErrors();
6574  AmgSymMatrix(5) & trackcov = state->trackCovariance();
6575  const Amg::MatrixX & hitcov = state->measurement()->localCovariance();
6576  double sinstereo = state->sinStereo();
6577  double cosstereo = (sinstereo == 0) ? 1 : std::sqrt(1 - sinstereo * sinstereo);
6578  double weight1 = -1;
6579 
6580  if (hitcov(0, 0) > trackcov(0, 0)) {
6581  if (sinstereo == 0) {
6582  weight1 = errors[0] * errors[0] - trackcov(0, 0);
6583  } else {
6584  weight1 = errors[0] * errors[0] - (
6585  trackcov(0, 0) * cosstereo * cosstereo + 2 *
6586  trackcov(1, 0) * cosstereo * sinstereo + trackcov(1, 1) * sinstereo * sinstereo
6587  );
6588  }
6589  }
6590 
6591  double weight2 = (
6592  hittype == TrackState::Pixel && hitcov(1, 1) > trackcov(1, 1) ?
6593  errors[1] * errors[1] - trackcov(1, 1) :
6594  -1
6595  );
6596 
6597  double sipull1 = weight1 > 0 ? std::abs(res[measno] / std::sqrt(weight1)) : -1;
6598  double sipull2 = (
6599  hittype == TrackState::Pixel && weight2 > 0 ?
6600  std::abs(res[measno + 1] / std::sqrt(weight2)) :
6601  -1
6602  );
6603  sipull1 = std::max(sipull1, sipull2);
6604 
6605  if (sipull1 > maxsipull) {
6606  maxsipull = sipull1;
6607  measno_maxsipull = measno;
6608  state_maxsipull = state.get();
6609  stateno_maxsipull = stateno;
6610  hitno_maxsipull = hitno;
6611  }
6612 
6613  if (hittype == TrackState::Pixel && sipull1 > cut2) {
6614  n3sigma++;
6615  }
6616  }
6617  }
6618 
6619  if (state->getStateType(TrackStateOnSurface::Measurement) || state->getStateType(TrackStateOnSurface::Outlier)) {
6620  hitno++;
6621  measno += state->numberOfMeasuredParameters();
6622  }
6623  }
6624 
6625  double maxpull = maxsipull;
6626 
6627  ATH_MSG_DEBUG(" maxsipull: " << maxsipull << " hitno_maxsipull: " <<
6628  hitno_maxsipull << " n3sigma: " << n3sigma << " cut: " << cut << " cut2: " << cut2);
6629 
6630  Amg::SymMatrixX * newap = &a;
6631  Amg::VectorX * newbp = &b;
6632  Amg::SymMatrixX newa(nfitpars, nfitpars);
6633  Amg::VectorX newb(nfitpars);
6634 
6635  if (
6636  maxpull > 2 &&
6637  oldtrajectory->chi2() / oldtrajectory->nDOF() > .25 * m_chi2cut
6638  ) {
6639  state_maxsipull = oldtrajectory->trackStates()[stateno_maxsipull].get();
6640  const PrepRawData *prd{};
6641  if (const auto *const pMeas = state_maxsipull->measurement(); pMeas->type(Trk::MeasurementBaseType::RIO_OnTrack)){
6642  const auto *const rot = static_cast<const RIO_OnTrack *>(pMeas);
6643  prd = rot->prepRawData();
6644  }
6645  std::unique_ptr < const RIO_OnTrack > broadrot;
6646  double *olderror = state_maxsipull->measurementErrors();
6647  TrackState::MeasurementType hittype_maxsipull = state_maxsipull->measurementType();
6648  const TrackParameters *trackpar_maxsipull = state_maxsipull->trackParameters();
6649 
6650  Amg::VectorX parameterVector = trackpar_maxsipull->parameters();
6651  std::unique_ptr<const TrackParameters> trackparForCorrect(
6652  trackpar_maxsipull->associatedSurface().createUniqueTrackParameters(
6653  parameterVector[Trk::loc1],
6654  parameterVector[Trk::loc2],
6655  parameterVector[Trk::phi],
6656  parameterVector[Trk::theta],
6657  parameterVector[Trk::qOverP],
6658  state_maxsipull->hasTrackCovariance()
6659  ? std::optional<AmgSymMatrix(5)>(
6660  state_maxsipull->trackCovariance())
6661  : std::nullopt));
6662 
6663  double newerror[5];
6664  newerror[0] = newerror[1] = newerror[2] = newerror[3] = newerror[4] = -1;
6665  double newpull = -1;
6666  double newpull1 = -1;
6667  double newpull2 = -1;
6668  double newres1 = -1;
6669  double newres2 = -1;
6670  double newsinstereo = 0;
6671 
6672  if (
6673  (prd != nullptr) &&
6674  !state_maxsipull->isRecalibrated() &&
6675  maxpull > 2.5 &&
6676  oldtrajectory->chi2() / trajectory.nDOF() > .3 * m_chi2cut &&
6677  cache.m_sirecal
6678  ) {
6679  broadrot.reset(m_broadROTcreator->correct(*prd, *trackparForCorrect, ctx));
6680  }
6681 
6682  if (broadrot) {
6683  const Amg::MatrixX & covmat = broadrot->localCovariance();
6684 
6685  if (state_maxsipull->sinStereo() != 0) {
6686  const auto [covEigenValueSmall, covStereoAngle] = principalComponentAnalysis2x2(covmat);
6687  newerror[0] = std::sqrt(covEigenValueSmall);
6688  newsinstereo = std::sin(covStereoAngle);
6689  } else {
6690  newerror[0] = std::sqrt(covmat(0, 0));
6691  }
6692 
6693  double cosstereo = (newsinstereo == 0) ? 1. : std::sqrt(1 - newsinstereo * newsinstereo);
6694 
6695  if (cosstereo != 1.) {
6696  newres1 = (
6697  cosstereo * (broadrot->localParameters()[Trk::locX] - trackpar_maxsipull->parameters()[Trk::locX]) +
6698  newsinstereo * (broadrot->localParameters()[Trk::locY] - trackpar_maxsipull->parameters()[Trk::locY])
6699  );
6700  } else {
6701  newres1 = broadrot->localParameters()[Trk::locX] - trackpar_maxsipull->parameters()[Trk::locX];
6702  }
6703 
6704  if (newerror[0] == 0.0) {
6705  ATH_MSG_WARNING("Measurement error is zero or negative, treating as outlier");
6706  newpull1 = 9999.;
6707  } else {
6708  newpull1 = std::abs(newres1 / newerror[0]);
6709  }
6710 
6711  if (hittype_maxsipull == TrackState::Pixel) {
6712  newerror[1] = std::sqrt(covmat(1, 1));
6713  newres2 = broadrot->localParameters()[Trk::locY] - trackpar_maxsipull->parameters()[Trk::locY];
6714  newpull2 = std::abs(newres2 / newerror[1]);
6715  }
6716 
6717  newpull = std::max(newpull1, newpull2);
6718  }
6719 
6720  if (
6721  broadrot &&
6722  newpull < m_outlcut &&
6723  (newerror[0] > 1.5 * olderror[0] || newerror[1] > 1.5 * std::abs(olderror[1]))
6724  ) {
6725  if ((measno_maxsipull < 0) or(measno_maxsipull >= (int) res.size())) {
6726  throw std::runtime_error(
6727  "'res' array index out of range in TrkGlobalChi2Fitter/src/GlobalChi2Fitter.cxx:" + std::to_string(__LINE__)
6728  );
6729  }
6730 
6731  trackok = false;
6732  newtrajectory = oldtrajectory;
6733 
6734  if (a.cols() != nfitpars) {
6735  ATH_MSG_ERROR("Your assumption is wrong!!!!");
6736  }
6737 
6738  double oldres1 = res[measno_maxsipull];
6739  res[measno_maxsipull] = newres1;
6740  err[measno_maxsipull] = newerror[0];
6741 
6742  for (int i = 0; i < nfitpars; i++) {
6743  if (weightderiv(measno_maxsipull, i) == 0) {
6744  continue;
6745  }
6746 
6747  b[i] -= weightderiv(measno_maxsipull, i) * (oldres1 / olderror[0] - (newres1 * olderror[0]) / (newerror[0] * newerror[0]));
6748 
6749  for (int j = i; j < nfitpars; j++) {
6750  a.fillSymmetric(
6751  i, j,
6752  a(i, j) + (
6753  weightderiv(measno_maxsipull, i) *
6754  weightderiv(measno_maxsipull, j) *
6755  ((olderror[0] * olderror[0]) / (newerror[0] * newerror[0]) - 1)
6756  )
6757  );
6758  }
6759  weightderiv(measno_maxsipull, i) *= olderror[0] / newerror[0];
6760  }
6761 
6762  if (hittype_maxsipull == TrackState::Pixel) {
6763  double oldres2 = res[measno_maxsipull + 1];
6764  res[measno_maxsipull + 1] = newres2;
6765  err[measno_maxsipull + 1] = newerror[1];
6766 
6767  for (int i = 0; i < nfitpars; i++) {
6768  if (weightderiv(measno_maxsipull + 1, i) == 0) {
6769  continue;
6770  }
6771 
6772  b[i] -= weightderiv(measno_maxsipull + 1, i) * (oldres2 / olderror[1] - (newres2 * olderror[1]) / (newerror[1] * newerror[1]));
6773 
6774  for (int j = i; j < nfitpars; j++) {
6775  a.fillSymmetric(
6776  i, j,
6777  a(i, j) + (
6778  weightderiv(measno_maxsipull + 1, i) *
6779  weightderiv(measno_maxsipull + 1, j) *
6780  ((olderror[1] * olderror[1]) / (newerror[1] * newerror[1]) - 1)
6781  )
6782  );
6783  }
6784 
6785  weightderiv(measno_maxsipull + 1, i) *= olderror[1] / newerror[1];
6786  }
6787  }
6788 
6789  ATH_MSG_DEBUG(
6790  "Recovering outlier, hitno=" << hitno_maxsipull << " measno=" <<
6791  measno_maxsipull << " pull=" << maxsipull << " olderror_0=" <<
6792  olderror[0] << " newerror_0=" << newerror[0] << " olderror_1=" <<
6793  olderror[1] << " newerror_1=" << newerror[1]
6794  );
6795 
6796  state_maxsipull->setMeasurement(std::move(broadrot));
6797  state_maxsipull->setSinStereo(newsinstereo);
6798  state_maxsipull->setMeasurementErrors(newerror);
6799  } else if (
6800  (
6801  (
6802  ((n3sigma < 2 && maxsipull > cut2 && maxsipull < cut) || n3sigma > 1) &&
6803  (oldtrajectory->chi2() / oldtrajectory->nDOF() > .3 * m_chi2cut || noutl > 1)
6804  ) ||
6805  maxsipull > cut
6806  ) &&
6807  (oldtrajectory->nDOF() > 1 || hittype_maxsipull == TrackState::SCT) &&
6808  runoutlier
6809  ) {
6810  trackok = false;
6811  ATH_MSG_DEBUG(
6812  "Removing outlier, hitno=" << hitno_maxsipull << ", measno=" <<
6813  measno_maxsipull << " pull=" << maxsipull
6814  );
6815 
6816  newa = a;
6817  newb = b;
6818  newap = &newa;
6819  newbp = &newb;
6820  cleanup_newtrajectory = std::make_unique<GXFTrajectory>(*oldtrajectory);
6821  newtrajectory = cleanup_newtrajectory.get();
6822 
6823  if (newa.cols() != nfitpars) {
6824  ATH_MSG_ERROR("Your assumption is wrong!!!!");
6825  }
6826 
6827  Amg::VectorX & newres = newtrajectory->residuals();
6828  Amg::MatrixX & newweightderiv = newtrajectory->weightedResidualDerivatives();
6829  if ((measno_maxsipull < 0) or(measno_maxsipull >= (int) res.size())) {
6830  throw std::runtime_error(
6831  "'res' array index out of range in TrkGlobalChi2Fitter/src/GlobalChi2Fitter.cxx:" + std::to_string(__LINE__)
6832  );
6833  }
6834 
6835  double oldres1 = res[measno_maxsipull];
6836  newres[measno_maxsipull] = 0;
6837 
6838  for (int i = 0; i < nfitpars; i++) {
6839  if (weightderiv(measno_maxsipull, i) == 0) {
6840  continue;
6841  }
6842 
6843  newb[i] -= weightderiv(measno_maxsipull, i) * oldres1 / olderror[0];
6844 
6845  for (int j = i; j < nfitpars; j++) {
6846  newa.fillSymmetric(
6847  i, j,
6848  newa(i, j) - (
6849  weightderiv(measno_maxsipull, i) *
6850  weightderiv(measno_maxsipull, j)
6851  )
6852  );
6853  }
6854  newweightderiv(measno_maxsipull, i) = 0;
6855  }
6856 
6857  if (hittype_maxsipull == TrackState::Pixel) {
6858  double oldres2 = res[measno_maxsipull + 1];
6859  newres[measno_maxsipull + 1] = 0;
6860 
6861  for (int i = 0; i < nfitpars; i++) {
6862  if (weightderiv(measno_maxsipull + 1, i) == 0) {
6863  continue;
6864  }
6865 
6866  newb[i] -= weightderiv(measno_maxsipull + 1, i) * oldres2 / olderror[1];
6867 
6868  for (int j = i; j < nfitpars; j++) {
6869  if (weightderiv(measno_maxsipull + 1, j) == 0) {
6870  continue;
6871  }
6872 
6873  newa.fillSymmetric(
6874  i, j,
6875  newa(i, j) - (
6876  weightderiv(measno_maxsipull + 1, i) *
6877  weightderiv(measno_maxsipull + 1, j)
6878  )
6879  );
6880  }
6881  newweightderiv(measno_maxsipull + 1, i) = 0;
6882  }
6883  }
6884 
6885  newtrajectory->setOutlier(stateno_maxsipull);
6886  }
6887  }
6888 
6889  if (!trackok) {
6890  Amg::SymMatrixX lu_m = *newap;
6891  newtrajectory->setConverged(false);
6892  bool doderiv = m_redoderivs;
6893  cache.m_fittercode = updateFitParameters(*newtrajectory, *newbp, lu_m);
6894  if (cache.m_fittercode != FitterStatusCode::Success) {
6896  return nullptr;
6897  }
6898 
6899  for (int it = 0; it < m_maxit; ++it) {
6900  if (it == m_maxit - 1) {
6901  ATH_MSG_DEBUG("Fit did not converge");
6904  return nullptr;
6905  }
6906 
6907  if (!newtrajectory->converged()) {
6908  cache.m_fittercode = runIteration(
6909  ctx, cache, *newtrajectory, it, *newap, *newbp, lu_m, doderiv);
6910 
6911  if (cache.m_fittercode != FitterStatusCode::Success) {
6913  return nullptr;
6914  }
6915 
6916  if (!newtrajectory->converged()) {
6917  cache.m_fittercode = updateFitParameters(*newtrajectory, *newbp, lu_m);
6918  if (cache.m_fittercode != FitterStatusCode::Success) {
6920 
6921  return nullptr;
6922  }
6923  }
6924  } else {
6925  double oldchi2 = oldtrajectory->chi2() / oldtrajectory->nDOF();
6926  double newchi2 = (newtrajectory->nDOF() > 0) ? newtrajectory->chi2() / newtrajectory->nDOF() : 0;
6927  double mindiff = 0;
6928 
6929  if (newtrajectory->nDOF() != oldtrajectory->nDOF() && maxsipull > cut2) {
6930  mindiff = (oldchi2 > .33 * m_chi2cut || noutl > 0) ? .8 : 1.;
6931 
6932  if (noutl == 0 && maxsipull < cut - .5 && oldchi2 < .5 * m_chi2cut) {
6933  mindiff = 2.;
6934  }
6935  }
6936 
6937  if (newchi2 > oldchi2 || (newchi2 > oldchi2 - mindiff && newchi2 > .33 * oldchi2)) {
6938  ATH_MSG_DEBUG("Outlier not confirmed, keeping old trajectory");
6939 
6940  if (oldchi2 > m_chi2cut) {
6943  return nullptr;
6944  }
6945 
6946  (void)cleanup_oldtrajectory.release();
6947  return oldtrajectory;
6948  }
6949  if (oldtrajectory != newtrajectory) {
6950  cleanup_oldtrajectory = std::move(cleanup_newtrajectory);
6951  oldtrajectory = newtrajectory;
6952  a = newa;
6953  b = newb;
6954  }
6955 
6956  // Solve assuming the matrix is SPD.
6957  // Cholesky Decomposition is used
6958  Eigen::LLT < Eigen::MatrixXd > lltOfW(a);
6959  if (lltOfW.info() == Eigen::Success) {
6960  // Solve for x where Wx = I
6961  // this is cheaper than invert as invert makes no assumptions about the
6962  // matrix being symmetric
6963  int ncols = a.cols();
6964  Amg::MatrixX weightInvAMG = Amg::MatrixX::Identity(ncols, ncols);
6965  fullcov = lltOfW.solve(weightInvAMG);
6966  } else {
6967  ATH_MSG_DEBUG("matrix inversion failed!");
6970  return nullptr;
6971  }
6972  break;
6973  }
6974  }
6975  }
6976 
6977  if (!trackok) {
6978  calculateTrackErrors(*oldtrajectory, fullcov, true);
6979  }
6980  }
6981 
6982  if (
6983  oldtrajectory->nDOF() > 0 &&
6984  oldtrajectory->chi2() / oldtrajectory->nDOF() > m_chi2cut &&
6985  runoutlier
6986  ) {
6989  return nullptr;
6990  }
6991 
6992  (void)cleanup_oldtrajectory.release();
6993  return oldtrajectory;
6994  }
6995 
6997  Cache &cache,
6998  GXFTrajectory &oldtrajectory
6999  ) {
7000  Amg::MatrixX & derivs = oldtrajectory.weightedResidualDerivatives();
7001  Amg::VectorX & errors = oldtrajectory.errors();
7002  int nrealmeas = 0;
7003 
7004  for (auto & hit : oldtrajectory.trackStates()) {
7005  if (const auto *pMeas{hit->measurement()};
7006  hit->getStateType(TrackStateOnSurface::Measurement) and (
7009  )
7010  ) {
7011  nrealmeas += hit->numberOfMeasuredParameters();
7012  }
7013  }
7014  cache.m_derivmat.resize(nrealmeas, oldtrajectory.numberOfFitParameters());
7015  cache.m_derivmat.setZero();
7016  int measindex = 0;
7017  int measindex2 = 0;
7018  int nperpars = oldtrajectory.numberOfPerigeeParameters();
7019  int nscat = oldtrajectory.numberOfScatterers();
7020  for (auto & hit : oldtrajectory.trackStates()) {
7021  if (const auto *pMeas{hit->measurement()};
7022  hit->getStateType(TrackStateOnSurface::Measurement) and (
7025  )
7026  ) {
7027  for (int i = measindex; i < measindex + hit->numberOfMeasuredParameters(); i++) {
7028  for (int j = 0; j < oldtrajectory.numberOfFitParameters(); j++) {
7029  cache.m_derivmat(i, j) = derivs(measindex2, j) * errors[measindex2];
7030  if ((j == 4 && !oldtrajectory.m_straightline) || j >= nperpars + 2 * nscat) {
7031  cache.m_derivmat(i, j) *= 1000;
7032  }
7033  }
7034 
7035  measindex2++;
7036  }
7037 
7038  measindex += hit->numberOfMeasuredParameters();
7039  } else if (hit->materialEffects() == nullptr) {
7040  measindex2 += hit->numberOfMeasuredParameters();
7041  }
7042  }
7043  }
7044 
7045  std::unique_ptr<const TrackParameters> GlobalChi2Fitter::makeTrackFindPerigeeParameters(
7046  const EventContext & ctx,
7047  Cache &cache,
7048  GXFTrajectory &oldtrajectory,
7049  const ParticleHypothesis matEffects
7050  ) const {
7051  GXFTrackState *firstmeasstate = nullptr, *lastmeasstate = nullptr;
7052  std::tie(firstmeasstate, lastmeasstate) = oldtrajectory.findFirstLastMeasurement();
7053  std::unique_ptr<const TrackParameters> per(nullptr);
7054 
7055  if (cache.m_acceleration && !m_matupdator.empty()) {
7056  std::unique_ptr<const TrackParameters> prevpar(
7057  firstmeasstate->trackParameters() != nullptr ?
7058  firstmeasstate->trackParameters()->clone() :
7059  nullptr
7060  );
7061  std::vector<std::pair<const Layer *, const Layer *>> & upstreamlayers = oldtrajectory.upstreamMaterialLayers();
7062  bool first = true;
7063 
7064  for (const auto & [layer1, layer2] : upstreamlayers | std::views::reverse) {
7065  if (prevpar == nullptr) {
7066  break;
7067  }
7068 
7069  PropDirection propdir = oppositeMomentum;
7070  const Layer *layer = layer1 != nullptr ? layer1 : layer2;
7071 
7072  DistanceSolution distsol = layer->surfaceRepresentation().straightLineDistanceEstimate(
7073  prevpar->position(), prevpar->momentum().unit()
7074  );
7075  double distance = getDistance(distsol);
7076 
7077  if (distsol.numberOfSolutions() == 2) {
7078  if (std::abs(distance) < 0.01) {
7079  continue;
7080  }
7081 
7082  if (distsol.first() * distsol.second() < 0 && !first) {
7083  continue;
7084  }
7085  }
7086 
7087  if (first && distance > 0) {
7088  propdir = alongMomentum;
7089  }
7090 
7091  std::unique_ptr<const TrackParameters> layerpar(
7092  m_propagator->propagate(
7093  ctx,
7094  *prevpar,
7095  layer->surfaceRepresentation(),
7096  propdir,
7097  true,
7098  oldtrajectory.m_fieldprop,
7100  )
7101  );
7102 
7103  if (layerpar == nullptr) {
7104  continue;
7105  }
7106 
7107  if (layer->surfaceRepresentation().bounds().inside(layerpar->localPosition())) {
7108  layerpar = m_matupdator->update(layerpar.get(), *layer, oppositeMomentum, matEffects);
7109  }
7110 
7111  prevpar = std::move(layerpar);
7112  first = false;
7113  }
7114 
7115  const Layer *startlayer = firstmeasstate->trackParameters()->associatedSurface().associatedLayer();
7116 
7117  if ((startlayer != nullptr) && (startlayer->layerMaterialProperties() != nullptr)) {
7118  double startfactor = startlayer->layerMaterialProperties()->alongPostFactor();
7119  const Surface & discsurf = startlayer->surfaceRepresentation();
7120 
7121  if (discsurf.type() == Trk::SurfaceType::Disc && discsurf.center().z() * discsurf.normal().z() < 0) {
7122  startfactor = startlayer->layerMaterialProperties()->oppositePostFactor();
7123  }
7124  if (startfactor > 0.5) {
7125  std::unique_ptr<const TrackParameters> updatedpar = m_matupdator->update(
7126  firstmeasstate->trackParameters(), *startlayer, oppositeMomentum, matEffects
7127  );
7128 
7129  if (updatedpar != nullptr) {
7130  firstmeasstate->setTrackParameters(std::move(updatedpar));
7131  }
7132  }
7133  }
7134 
7135  // @TODO Coverity complains about a possible NULL pointer dereferencing in lastmeasstate->...
7136  // Now an exception is thrown if there is no firstmeastate. Thus if the code here is
7137  // reached then there should be a firstmeasstate and a lastmeasstate
7138 
7139  const Layer *endlayer = lastmeasstate->trackParameters()->associatedSurface().associatedLayer();
7140 
7141  if ((endlayer != nullptr) && (endlayer->layerMaterialProperties() != nullptr)) {
7142  double endfactor = endlayer->layerMaterialProperties()->alongPreFactor();
7143  const Surface & discsurf = endlayer->surfaceRepresentation();
7144 
7145  if (discsurf.type() == Trk::SurfaceType::Disc && discsurf.center().z() * discsurf.normal().z() < 0) {
7146  endfactor = endlayer->layerMaterialProperties()->oppositePreFactor();
7147  }
7148 
7149  if (endfactor > 0.5) {
7150  std::unique_ptr<const TrackParameters> updatedpar = m_matupdator->update(
7151  lastmeasstate->trackParameters(), *endlayer, alongMomentum, matEffects
7152  );
7153 
7154  if (updatedpar != nullptr) {
7155  lastmeasstate->setTrackParameters(std::move(updatedpar));
7156  }
7157  }
7158  }
7159 
7160  if (prevpar != nullptr) {
7161  per = m_propagator->propagate(
7162  ctx,
7163  *prevpar,
7164  PerigeeSurface(Amg::Vector3D(0, 0, 0)),
7166  false,
7167  oldtrajectory.m_fieldprop,
7169  );
7170  }
7171 
7172  if (per == nullptr) {
7173  ATH_MSG_DEBUG("Failed to extrapolate to perigee, returning 0");
7176  return nullptr;
7177  }
7178  } else if (cache.m_acceleration && (firstmeasstate->trackParameters() != nullptr)) {
7179  per = m_extrapolator->extrapolate(ctx,
7180  *firstmeasstate->trackParameters(),
7181  PerigeeSurface(Amg::Vector3D(0, 0, 0)),
7183  false,
7184  matEffects);
7185  } else {
7186  per.reset(oldtrajectory.referenceParameters()->clone());
7187  }
7188 
7189  return per;
7190  }
7191 
7192  std::unique_ptr<GXFTrackState>
7194  const EventContext & ctx,
7195  Cache &cache,
7196  GXFTrajectory &oldtrajectory,
7197  const ParticleHypothesis matEffects
7198  ) const {
7199  std::unique_ptr<const TrackParameters> per = makeTrackFindPerigeeParameters(ctx, cache, oldtrajectory, matEffects);
7200 
7201  if (per == nullptr) {
7202  return nullptr;
7203  }
7204 
7205  ATH_MSG_DEBUG("Final perigee: " << *per << " pos: " << per->position() << " pT: " << per->pT());
7206 
7207  return std::make_unique<GXFTrackState>(std::move(per), TrackStateOnSurface::Perigee);
7208  }
7209 
7211  const std::vector<std::unique_ptr<TrackParameters>> & hc,
7212  std::set<Identifier> & id_set,
7213  std::set<Identifier> & sct_set,
7214  TrackHoleCount & rv,
7215  bool count_holes,
7216  bool count_dead
7217  ) const {
7218  /*
7219  * Our input is a list of track states, which we are iterating over. We
7220  * need to examine each one and update the values in our track hole count
7221  * accordingly.
7222  */
7223  for (const std::unique_ptr<TrackParameters> & tp : hc) {
7224  /*
7225  * It is possible, expected even, for some of these pointers to be null.
7226  * In those cases, it would be dangerous to continue, so we need to make
7227  * sure we skip them.
7228  */
7229  if (tp == nullptr) {
7230  continue;
7231  }
7232 
7233  /*
7234  * Extract the detector element of the track parameter surface for
7235  * examination. If for whatever reason there is none (i.e. the surface
7236  * is not a detector at all), we can skip it and continue.
7237  */
7238  const TrkDetElementBase * de = tp->associatedSurface().associatedDetectorElement();
7239 
7240  if (de == nullptr) {
7241  continue;
7242  }
7243 
7244  Identifier id = de->identify();
7245 
7246  /*
7247  * If, for whatever reason, we have already visited this detector, we do
7248  * not want to visit it again. Otherwise we might end up with modules
7249  * counted twice, and that would be very bad.
7250  */
7251  if (id_set.find(id) != id_set.end()) {
7252  continue;
7253  }
7254 
7255  /*
7256  * This is the meat of the pudding, we use the boundary checking tool
7257  * to see whether this set of parameters is a hole candidate, a dead
7258  * module, or not a hole at all.
7259  */
7260  BoundaryCheckResult bc = m_boundaryCheckTool->boundaryCheck(*tp);
7261 
7262  if (bc == BoundaryCheckResult::DeadElement && count_dead) {
7263  /*
7264  * If the module is dead, our job is very simple. We just check
7265  * whether it is a Pixel or an SCT and increment the appropriate
7266  * counter. We also insert the module into our set of visited elements.
7267  */
7268  if (m_DetID->is_pixel(id)) {
7269  ++rv.m_pixel_dead;
7270  } else if (m_DetID->is_sct(id)) {
7271  ++rv.m_sct_dead;
7272  }
7273  id_set.insert(id);
7274  } else if (bc == BoundaryCheckResult::Candidate && count_holes) {
7275  /*
7276  * If the module is a candidate, it's much the same, but we also need
7277  * to handle double SCT holes.
7278  */
7279  if (m_DetID->is_pixel(id)) {
7280  ++rv.m_pixel_hole;
7281  } else if (m_DetID->is_sct(id)) {
7282  ++rv.m_sct_hole;
7283 
7284  /*
7285  * To check for SCT double holes, we need to first fetch the other
7286  * side of the current SCT. Thankfully, the detector description
7287  * makes this very easy.
7288  */
7289  const InDetDD::SiDetectorElement* e = dynamic_cast<const InDetDD::SiDetectorElement *>(de);
7290  const Identifier os = e->otherSide()->identify();
7291 
7292  /*
7293  * We keep a special set containing only SCT hole IDs. We simply
7294  * check whether the ID of the other side of the SCT is in this set
7295  * to confirm that we have a double hole. Note that the first side
7296  * in a double hole will be counted as a SCT hole only, and the
7297  * second side will count as another hole as well as a double hole,
7298  * which is exactly the behaviour we would expect to see.
7299  */
7300  if (sct_set.find(os) != sct_set.end()) {
7301  ++rv.m_sct_double_hole;
7302  }
7303 
7304  /*
7305  * We need to add our SCT to the SCT identifier set if it is a
7306  * candidate hit, otherwise known as a hole in this context.
7307  */
7308  sct_set.insert(id);
7309  }
7310 
7311  /*
7312  * SCTs are also added to the set of all identifiers to avoid double
7313  * counting them.
7314  */
7315  id_set.insert(id);
7316  }
7317  }
7318  }
7319 
7320  std::vector<std::reference_wrapper<GXFTrackState>> GlobalChi2Fitter::holeSearchStates(
7321  GXFTrajectory & trajectory
7322  ) const {
7323  /*
7324  * Firstly, we will need to find the last measurement state on our track.
7325  * This will allow us to break the main loop later once we are done with
7326  * our work.
7327  */
7328  GXFTrackState * lastmeas = nullptr;
7329 
7330  for (const std::unique_ptr<GXFTrackState> & s : trajectory.trackStates()) {
7331  if (s->getStateType(TrackStateOnSurface::Measurement)) {
7332  lastmeas = s.get();
7333  }
7334  }
7335 
7336  /*
7337  * We create a vector of reference wrappers and reserve at least enough
7338  * space to contain the entire trajectory. This is perhaps a little
7339  * wasteful since we will never need this much space, but it may be more
7340  * efficient than taking the resizing pentalty on the chin.
7341  */
7342  std::vector<std::reference_wrapper<GXFTrackState>> rv;
7343  rv.reserve(trajectory.trackStates().size());
7344 
7345  /*
7346  * The main body of our method now. We iterate over all track states in
7347  * the track, at least until we find the last measurement state as found
7348  * above.
7349  */
7350  for (const std::unique_ptr<GXFTrackState> & s : trajectory.trackStates()) {
7351  /*
7352  * We are only interested in collecting measurements, perigees, and any
7353  * outlier states.
7354  */
7355  if (
7356  s->getStateType(TrackStateOnSurface::Measurement) ||
7357  s->getStateType(TrackStateOnSurface::Perigee) ||
7358  s->getStateType(TrackStateOnSurface::Outlier)
7359  ) {
7360  /*
7361  * We store a reference to the current track state in our return value
7362  * vector.
7363  */
7364  rv.emplace_back(*s);
7365 
7366  /*
7367  * We want to make sure we do not collect any TRT results or other
7368  * non-SCT and non-Pixel detector types. For that, we need to access
7369  * the details of the detector element and determine the detector type.
7370  */
7371  const TrkDetElementBase * de = s->trackParameters()->associatedSurface().associatedDetectorElement();
7372 
7373  if (de != nullptr) {
7374  Identifier id = de->identify();
7375 
7376  if (!m_DetID->is_pixel(id) && !m_DetID->is_sct(id)) {
7377  break;
7378  }
7379  }
7380 
7381  /*
7382  * We also have no interest in going past the final measurement, so we
7383  * break out of the loop if we find it.
7384  */
7385  //cppcheck-suppress iterators3
7386  if (s.get() == lastmeas) {
7387  break;
7388  }
7389  }
7390  }
7391 
7392  return rv;
7393  }
7394 
7395  std::optional<GlobalChi2Fitter::TrackHoleCount> GlobalChi2Fitter::holeSearchProcess(
7396  const EventContext & ctx,
7397  const std::vector<std::reference_wrapper<GXFTrackState>> & states
7398  ) const {
7399  /*
7400  * Firstly, we need to guard against tracks having too few measurement
7401  * states to perform a good hole search. This is a mechanism that we
7402  * inherit from the reference hole search. If we have too few states, we
7403  * return a non-extant result to indicate an error state.
7404  *
7405  * TODO: The minimum value of 3 is also borrowed from the reference
7406  * implementation. It's hardcoded for now, but could be a parameter in the
7407  * future.
7408  */
7409  constexpr uint min_meas = 3;
7410  if (std::count_if(states.begin(), states.end(), [](const GXFTrackState & s){ return s.getStateType(TrackStateOnSurface::Measurement); }) < min_meas) {
7411  return {};
7412  }
7413 
7414  bool seen_meas = false;
7416  std::set<Identifier> id_set;
7417  std::set<Identifier> sct_set;
7418 
7419  /*
7420  * Using an old-school integer-based for loop because we need to iterate
7421  * over successive pairs of states to do an extrapolation between.
7422  */
7423  for (std::size_t i = 0; i < states.size() - 1; i++) {
7424  /*
7425  * Gather references to the state at the beginning of the extrapolation,
7426  * named beg, and the end, named end.
7427  */
7428  GXFTrackState & beg = states[i];
7429  GXFTrackState & end = states[i + 1];
7430 
7431  /*
7432  * Update the boolean keeping track of whether we have seen a measurement
7433  * or outlier yet. Once we see one, this will remain true forever, but
7434  * it helps us make sure we don't collect holes before the first
7435  * measurement.
7436  */
7437  seen_meas |= beg.getStateType(TrackStateOnSurface::Measurement) || beg.getStateType(TrackStateOnSurface::Outlier);
7438 
7439  /*
7440  * Calculate the distance between the position of the starting parameters
7441  * and the end parameters. If this distance is sufficiently small, there
7442  * can be no elements between them (for example, between two SCTs), and
7443  * we don't need to do an extrapolation. This can easily save us a few
7444  * microseconds.
7445  */
7446  double dist = (beg.trackParameters()->position() - end.trackParameters()->position()).norm();
7447 
7448  bool zStartValid = std::abs(beg.trackParameters()->position().z())<10000.;
7449  if(!zStartValid){
7450  ATH_MSG_DEBUG("Pathological track parameter well outside of detector");
7451  ATH_MSG_DEBUG("Propagator might have issue with this, skipping");
7452  ATH_MSG_VERBOSE("dumping track parameters " << *(beg.trackParameters()));
7453  }
7454 
7455  /*
7456  * Only proceed to count holes if we have seen a measurement before (this
7457  * may include the starting track state, if it is a measurement) and the
7458  * distance between start and end is at least 2.5 millimeters
7459  * and the z position is valid
7460  */
7461  if (seen_meas && dist >= 2.5 && zStartValid) {
7462  /*
7463  * First, we retrieve the hole data stored in the beginning state. Note
7464  * that this may very well be non-extant, but it is possible for the
7465  * fitter to have deposited some hole information into the track state
7466  * earlier on in the fitting process.
7467  */
7468  std::optional<std::vector<std::unique_ptr<TrackParameters>>> & hc = beg.getHoles();
7469  std::vector<std::unique_ptr<TrackParameters>> states;
7470 
7471  /*
7472  * Gather the track states between the start and end of the
7473  * extrapolation. If the track state contained hole search information,
7474  * we simply move that out and use it. If there was no information, we
7475  * do a fresh extrapolation. This can be a CPU hog!
7476  */
7477  if (hc.has_value()) {
7478  states = std::move(*hc);
7479  } else {
7480  states = holesearchExtrapolation(ctx, *beg.trackParameters(), end, alongMomentum);
7481  }
7482 
7483  /*
7484  * Finally, we process the collected hole candidate states, checking
7485  * them for liveness and other properties. This helper function will
7486  * increment the values in rv accordingly.
7487  */
7488  holeSearchHelper(states, id_set, sct_set, rv, true, true);
7489  }
7490  }
7491 
7492  /*
7493  * Once we are done processing our measurements, we also need to do a
7494  * final blind extrapolation to collect and dead modules (but not holes)
7495  * behind the last measurement. For this, we do a blind extrapolation
7496  * from the final state.
7497  */
7498  GXFTrackState & last = states.back();
7499 
7500  /*
7501  * To do the blind extrapolation, we need to have a set of track parameters
7502  * for our last measurement state. We also check whether the position of
7503  * the last measurement is still inside the inner detector. If it is not,
7504  * we don't need to blindly extrapolate because we're only interested in
7505  * collecting inner detector dead modules. This check saves us a few tens
7506  * of microseconds.
7507  */
7508  if (
7509  last.trackParameters() != nullptr &&
7511  ) {
7512  /*
7513  * Simply conduct the blind extrapolation, and then use the helper tool
7514  * to ensure that the hole counts are updated.
7515  */
7516  std::vector<std::unique_ptr<Trk::TrackParameters>> bl = m_extrapolator->extrapolateBlindly(
7517  ctx,
7518  *last.trackParameters(),
7520  false,
7521  Trk::pion,
7522  &m_idVolume
7523  );
7524 
7525  /*
7526  * Note that we have flipped one of the boolean parameters of the helper
7527  * method here to make sure it only collects dead modules, not hole
7528  * candidates.
7529  */
7530  holeSearchHelper(bl, id_set, sct_set, rv, false, true);
7531  }
7532 
7533  return rv;
7534  }
7535 
7536  std::unique_ptr<Track> GlobalChi2Fitter::makeTrack(
7537  const EventContext & ctx,
7538  Cache & cache,
7539  GXFTrajectory & oldtrajectory,
7540  ParticleHypothesis matEffects
7541  ) const {
7542  // Convert internal trajectory into track
7543  auto trajectory = std::make_unique<Trk::TrackStates>();
7544 
7545  if (m_fillderivmatrix) {
7546  makeTrackFillDerivativeMatrix(cache, oldtrajectory);
7547  }
7548 
7549  GXFTrajectory tmptrajectory(oldtrajectory);
7550 
7551  std::unique_ptr<GXFTrackState> perigee_ts = makeTrackFindPerigee(ctx, cache, oldtrajectory, matEffects);
7552 
7553  if (perigee_ts == nullptr) {
7554  return nullptr;
7555  }
7556 
7557  tmptrajectory.addBasicState(std::move(perigee_ts), cache.m_acceleration ? 0 : tmptrajectory.numberOfUpstreamStates());
7558  //reserve the ouput size
7559  trajectory->reserve(tmptrajectory.trackStates().size());
7560  for (auto & hit : tmptrajectory.trackStates()) {
7561  if (
7562  hit->measurementType() == TrackState::Pseudo &&
7563  hit->getStateType(TrackStateOnSurface::Outlier)
7564  ) {
7565  hit->resetTrackCovariance();
7566  continue;
7567  }
7568 
7569  if (!Trk::consistentSurfaces (hit->trackParameters(),
7570  hit->measurement(),
7571  hit->materialEffects()))
7572  {
7573  return nullptr;
7574  }
7575 
7576  //should check hit->isSane() here with better equality check(other than ptr comparison)
7577  auto trackState = hit->trackStateOnSurface();
7578  hit->resetTrackCovariance();
7579  trajectory->emplace_back(trackState.release());
7580  }
7581 
7582  auto qual = std::make_unique<FitQuality>(tmptrajectory.chi2(), tmptrajectory.nDOF());
7583 
7584 
7585  TrackInfo info;
7586 
7587  if (matEffects != electron) {
7589  } else {
7591  info.setTrackProperties(TrackInfo::BremFit);
7592 
7593  if (matEffects == electron && tmptrajectory.hasKink()) {
7594  info.setTrackProperties(TrackInfo::BremFitSuccessful);
7595  }
7596  }
7597 
7598  if (tmptrajectory.m_straightline) {
7599  info.setTrackProperties(TrackInfo::StraightTrack);
7600  }
7601 
7602  std::unique_ptr<Track> rv = std::make_unique<Track>(info, std::move(trajectory), std::move(qual));
7603 
7604  /*
7605  * Here, we create a track summary and attach it to our newly created
7606  * track. Note that this code only runs if the m_createSummary Gaudi
7607  * property is set. In cases where having a track summary on the track is
7608  * not desired, such as for compatibility with other tools, this can be
7609  * turned off.
7610  */
7611  if (m_createSummary.value()) {
7612  std::unique_ptr<TrackSummary> ts = std::make_unique<TrackSummary>();
7613 
7614  /*
7615  * This segment determines the hole search behaviour of the track fitter.
7616  * It is only invoked if the DoHoleSearch parameter is set, but it can
7617  * take a significant amount of CPU time, since the hole search is rather
7618  * expensive. Beware of that!
7619  */
7620  if (m_holeSearch.value()) {
7621  std::optional<TrackHoleCount> hole_count;
7622 
7623  /*
7624  * First, we collect a list of states that will act as our hole search
7625  * extrapolation states. This will serve as our source of truth in
7626  * regards to which track states we need to extrapolate between.
7627  */
7628  std::vector<std::reference_wrapper<GXFTrackState>> states = holeSearchStates(tmptrajectory);
7629 
7630  /*
7631  * Then, collect the actual hole search infomation using our state list
7632  * from before. This is the expensive operation, as it will invoke a
7633  * series of extrapolations if not all states have existing hole
7634  * information! It will also check all the hole candidates to see if
7635  * they are actually holes or not.
7636  */
7637  hole_count = holeSearchProcess(ctx, states);
7638 
7639  /*
7640  * Note that the hole search is not guaranteed to return a useful set
7641  * of values. It can, for example, reach an error state if the number
7642  * of measurements on a track is below a certain threshold. In that
7643  * case, a non-extant result will be returned, which we must guard
7644  * against. In that case, the hole counts will remain unset.
7645  */
7646  if (hole_count.has_value()) {
7647  /*
7648  * If the hole search did return good results, we can proceed to
7649  * simply copy the numerical values in the track summary.
7650  */
7651  ts->update(Trk::numberOfPixelHoles, hole_count->m_pixel_hole);
7652  ts->update(Trk::numberOfSCTHoles, hole_count->m_sct_hole);
7653  ts->update(Trk::numberOfSCTDoubleHoles, hole_count->m_sct_double_hole);
7654  ts->update(Trk::numberOfPixelDeadSensors, hole_count->m_pixel_dead);
7655  ts->update(Trk::numberOfSCTDeadSensors, hole_count->m_sct_dead);
7656  }
7657  }
7658 
7659  rv->setTrackSummary(std::move(ts));
7660  }
7661 
7662  return rv;
7663  }
7664 
7665  GlobalChi2Fitter::~GlobalChi2Fitter() = default;
7666 
7667  std::vector<std::unique_ptr<TrackParameters>> GlobalChi2Fitter::holesearchExtrapolation(
7668  const EventContext & ctx,
7669  const TrackParameters & src,
7670  const GXFTrackState & dst,
7671  PropDirection propdir
7672  ) const {
7673  /*
7674  * First, we conduct a bog standard stepwise extrapolation. This will
7675  * yield some unwanted results, but we will filter those later.
7676  */
7677  std::vector<std::unique_ptr<TrackParameters>> rv = m_extrapolator->extrapolateStepwise(
7678  ctx, src, dst.associatedSurface(), propdir, false
7679  );
7680 
7681  /*
7682  * It is possible for the first returned track parameter to be on the same
7683  * surface as we started on. That's probably due to some rounding errors.
7684  * We check for this possibility, and set the pointer to null if it
7685  * occurs. Note that this leaves some null pointers in the returned vector
7686  * but this is more performant compared to removing them properly.
7687  */
7688  if (
7689  !rv.empty() && (
7690  &rv.front()->associatedSurface() == &dst.associatedSurface() ||
7691  &rv.front()->associatedSurface() == &src.associatedSurface() ||
7692  trackParametersClose(*rv.front(), src, 0.001) ||
7693  trackParametersClose(*rv.front(), *dst.trackParameters(), 0.001)
7694  )
7695  ) {
7696  rv.front().reset(nullptr);
7697  }
7698 
7699  /*
7700  * Same logic, but for the last returned element. In that case, we get a
7701  * set of parameters on the destination surface, which we also do not
7702  * want.
7703  */
7704  if (
7705  rv.size() > 1 && (
7706  &rv.back()->associatedSurface() == &dst.associatedSurface() ||
7707  &rv.back()->associatedSurface() == &src.associatedSurface() ||
7708  trackParametersClose(*rv.back(), src, 0.001) ||
7709  trackParametersClose(*rv.back(), *dst.trackParameters(), 0.001)
7710  )
7711  ) {
7712  rv.back().reset(nullptr);
7713  }
7714 
7715  return rv;
7716  }
7717 
7719  const EventContext & ctx,
7720  const TrackParameters & prev,
7721  const GXFTrackState & ts,
7722  PropDirection propdir,
7723  const MagneticFieldProperties& bf,
7724  bool calcderiv,
7725  bool holesearch
7726  ) const {
7727  std::unique_ptr<const TrackParameters> rv;
7728  std::optional<TransportJacobian> jac{};
7729 
7730  if (calcderiv && !m_numderiv) {
7731  rv = m_propagator->propagateParameters(
7732  ctx, prev, ts.associatedSurface(), propdir, false, bf, jac, Trk::nonInteracting, false
7733  );
7734  } else {
7735  rv = m_propagator->propagateParameters(
7736  ctx, prev, ts.associatedSurface(), propdir, false, bf, Trk::nonInteracting, false
7737  );
7738 
7739  if (rv != nullptr && calcderiv) {
7740  jac = numericalDerivatives(ctx, &prev, ts.associatedSurface(), propdir, bf);
7741  }
7742  }
7743 
7744  std::optional<std::vector<std::unique_ptr<TrackParameters>>> extrapolation;
7745 
7746  if (holesearch) {
7747  extrapolation = holesearchExtrapolation(ctx, prev, ts, propdir);
7748  }
7749 
7750  return PropagationResult {
7751  std::move(rv),
7752  std::move(jac),
7753  std::move(extrapolation)
7754  };
7755  }
7756 
7758  const EventContext & ctx,
7759  const TrackParameters & prev,
7760  const GXFTrackState & ts,
7761  PropDirection propdir,
7762  const MagneticFieldProperties& bf,
7763  bool calcderiv,
7764  bool holesearch
7765  ) const {
7767 
7769  ctx, prev, ts, propdir, bf, calcderiv, holesearch
7770  );
7771 
7772  if (rv.m_parameters == nullptr) {
7773  propdir = invertPropdir(propdir);
7774 
7776  ctx, prev, ts, propdir, bf, calcderiv, holesearch
7777  );
7778  }
7779 
7780  return rv;
7781  }
7782 
7784  const EventContext& ctx,
7785  GXFTrajectory & trajectory,
7786  bool calcderiv
7787  ) const {
7788  // Loop over states, calculate track parameters and (optionally) jacobian at each state
7789  ATH_MSG_DEBUG("CalculateTrackParameters");
7790 
7791  std::vector<std::unique_ptr<GXFTrackState>> & states = trajectory.trackStates();
7792  int nstatesupstream = trajectory.numberOfUpstreamStates();
7793  const TrackParameters *prevtrackpar = trajectory.referenceParameters();
7794  std::unique_ptr<const TrackParameters> tmptrackpar;
7795 
7796  for (int hitno = nstatesupstream - 1; hitno >= 0; hitno--) {
7797  const Surface &surf1 = states[hitno]->associatedSurface();
7799 
7801  prevtrackpar->position(), prevtrackpar->momentum().unit()
7802  );
7803 
7804  double distance = getDistance(distsol);
7805 
7806  if (
7807  distance > 0 &&
7808  distsol.numberOfSolutions() > 0 &&
7809  prevtrackpar != trajectory.referenceParameters()
7810  ) {
7811  propdir = Trk::alongMomentum;
7812  }
7813 
7815  ctx,
7816  *prevtrackpar,
7817  *states[hitno],
7818  propdir,
7819  trajectory.m_fieldprop,
7820  calcderiv,
7821  false
7822  );
7823 
7824  if (
7825  propdir == Trk::alongMomentum &&
7826  (rv.m_parameters != nullptr) &&
7827  (prevtrackpar->position() - rv.m_parameters->position()).mag() > 5 * mm
7828  ) {
7829  ATH_MSG_DEBUG("Propagation in wrong direction");
7830 
7831  }
7832 
7833  if (rv.m_parameters == nullptr) {
7834  ATH_MSG_DEBUG("propagation failed, prev par: " << *prevtrackpar <<
7835  " pos: " << prevtrackpar->position() << " destination surface: " << surf1);
7837  }
7838 
7839  states[hitno]->setTrackParameters(std::move(rv.m_parameters));
7840  const TrackParameters *currenttrackpar = states[hitno]->trackParameters();
7841  const Surface &surf = states[hitno]->associatedSurface();
7842 
7843  if (rv.m_jacobian != std::nullopt) {
7844  if (
7845  states[hitno]->materialEffects() != nullptr &&
7846  states[hitno]->materialEffects()->deltaE() != 0 &&
7847  states[hitno]->materialEffects()->sigmaDeltaE() <= 0 &&
7848  !trajectory.m_straightline
7849  ) {
7850  double p = 1. / std::abs(currenttrackpar->parameters()[Trk::qOverP]);
7851  double de = std::abs(states[hitno]->materialEffects()->deltaE());
7852  double mass = trajectory.mass();
7853  double newp = std::sqrt(p * p + 2 * de * std::sqrt(mass * mass + p * p) + de * de);
7854  (*rv.m_jacobian) (4, 4) = ((p + p * de / std::sqrt(p * p + mass * mass)) / newp) * p * p / (newp * newp);
7855  }
7856 
7857  states[hitno]->setJacobian(*rv.m_jacobian);
7858  } else if (calcderiv) {
7859  ATH_MSG_WARNING("Jacobian is null");
7861  }
7862 
7863  GXFMaterialEffects *meff = states[hitno]->materialEffects();
7864 
7865  if (meff != nullptr && hitno != 0) {
7866  std::variant<std::unique_ptr<const TrackParameters>, FitterStatusCode> r = updateEnergyLoss(
7867  surf, *meff, *states[hitno]->trackParameters(), trajectory.mass(), -1
7868  );
7869 
7870  if (std::holds_alternative<FitterStatusCode>(r)) {
7871  return std::get<FitterStatusCode>(r);
7872  }
7873 
7874  tmptrackpar = std::move(std::get<std::unique_ptr<const TrackParameters>>(r));
7875  prevtrackpar = tmptrackpar.get();
7876  } else {
7877  prevtrackpar = currenttrackpar;
7878  }
7879  }
7880 
7881  prevtrackpar = trajectory.referenceParameters();
7882 
7883  for (int hitno = nstatesupstream; hitno < (int) states.size(); hitno++) {
7884  const Surface &surf = states[hitno]->associatedSurface();
7886  DistanceSolution distsol = surf.straightLineDistanceEstimate(prevtrackpar->position(), prevtrackpar->momentum().unit());
7887 
7888  double distance = getDistance(distsol);
7889 
7890  if (distance < 0 && distsol.numberOfSolutions() > 0 && prevtrackpar != trajectory.referenceParameters()) {
7891  propdir = Trk::oppositeMomentum;
7892  }
7893 
7895  ctx,
7896  *prevtrackpar,
7897  *states[hitno],
7898  propdir,
7899  trajectory.m_fieldprop,
7900  calcderiv,
7901  false
7902  );
7903 
7904  if (
7905  (rv.m_parameters != nullptr) &&
7906  propdir == Trk::oppositeMomentum &&
7907  (prevtrackpar->position() - rv.m_parameters->position()).mag() > 5 * mm
7908  ) {
7909  ATH_MSG_DEBUG("Propagation in wrong direction");
7910  }
7911 
7912  if (rv.m_parameters == nullptr) {
7913  ATH_MSG_DEBUG("propagation failed, prev par: " << *prevtrackpar <<
7914  " pos: " << prevtrackpar->
7915  position() << " destination surface: " << surf);
7917  }
7918 
7919  if (rv.m_jacobian != std::nullopt) {
7920  if (
7921  states[hitno]->materialEffects() != nullptr &&
7922  states[hitno]->materialEffects()->deltaE() != 0 &&
7923  states[hitno]->materialEffects()->sigmaDeltaE() <= 0 &&
7924  !trajectory.m_straightline
7925  ) {
7926  double p = 1 / std::abs(rv.m_parameters->parameters()[Trk::qOverP]);
7927  double de = std::abs(states[hitno]->materialEffects()->deltaE());
7928  double mass = trajectory.mass();
7929  double newp = p * p - 2 * de * std::sqrt(mass * mass + p * p) + de * de;
7930 
7931  if (newp > 0) {
7932  newp = std::sqrt(newp);
7933  }
7934 
7935  (*rv.m_jacobian) (4, 4) = ((p - p * de / std::sqrt(p * p + mass * mass)) / newp) * p * p / (newp * newp);
7936  }
7937 
7938  states[hitno]->setJacobian(*rv.m_jacobian);
7939  } else if (calcderiv) {
7940  ATH_MSG_WARNING("Jacobian is null");
7942  }
7943 
7944  GXFMaterialEffects *meff = states[hitno]->materialEffects();
7945 
7946  if (meff != nullptr) {
7947  std::variant<std::unique_ptr<const TrackParameters>, FitterStatusCode> r = updateEnergyLoss(
7948  surf, *meff, *rv.m_parameters, trajectory.mass(), +1
7949  );
7950 
7951  if (std::holds_alternative<FitterStatusCode>(r)) {
7952  return std::get<FitterStatusCode>(r);
7953  }
7954 
7955  rv.m_parameters = std::move(std::get<std::unique_ptr<const TrackParameters>>(r));
7956  }
7957 
7958  states[hitno]->setTrackParameters(std::move(rv.m_parameters));
7959  prevtrackpar = states[hitno]->trackParameters();
7960  }
7961 
7963  }
7964 
7965  std::variant<std::unique_ptr<const TrackParameters>, FitterStatusCode> GlobalChi2Fitter::updateEnergyLoss(
7966  const Surface & surf,
7967  const GXFMaterialEffects & meff,
7968  const TrackParameters & param,
7969  double mass,
7970  int sign
7971  ) const {
7972  const AmgVector(5) & old = param.parameters();
7973 
7974  double newphi = old[Trk::phi0] + sign * meff.deltaPhi();
7975  double newtheta = old[Trk::theta] + sign * meff.deltaTheta();
7976 
7977  if (!correctAngles(newphi, newtheta)) {
7978  ATH_MSG_DEBUG("Angles out of range, phi: " << newphi << " theta: " << newtheta);
7980  }
7981 
7982  double newqoverp = 0;
7983 
7984  if (meff.sigmaDeltaE() <= 0) {
7985  if (std::abs(old[Trk::qOverP]) < 1.e-12) {
7986  newqoverp = 0.;
7987  } else {
7988  double oldp = std::abs(1 / old[Trk::qOverP]);
7989  double newp2 = oldp * oldp - sign * 2 * std::abs(meff.deltaE()) * std::sqrt(mass * mass + oldp * oldp) + meff.deltaE() * meff.deltaE();
7990 
7991  if (newp2 < 0) {
7992  ATH_MSG_DEBUG("Track killed by energy loss update");
7994  }
7995 
7996  newqoverp = std::copysign(1 / std::sqrt(newp2), old[Trk::qOverP]);
7997  }
7998  } else {
7999  newqoverp = old[Trk::qOverP] + sign * .001 * meff.delta_p();
8000  }
8001 
8002  return surf.createUniqueTrackParameters(
8003  old[0], old[1], newphi, newtheta, newqoverp, std::nullopt
8004  );
8005  }
8006 
8008  int nstatesupstream = trajectory.numberOfUpstreamStates();
8009  int nscatupstream = trajectory.numberOfUpstreamScatterers();
8010  int nbremupstream = trajectory.numberOfUpstreamBrems();
8011  int nscats = trajectory.numberOfScatterers();
8012  int nperpars = trajectory.numberOfPerigeeParameters();
8013  int nfitpars = trajectory.numberOfFitParameters();
8014 
8015  using Matrix55 = Eigen::Matrix<double, 5, 5>;
8016 
8017  Matrix55 initialjac;
8018  initialjac.setZero();
8019  initialjac(4, 4) = 1;
8020 
8021  Matrix55 jacvertex(initialjac);
8022 
8023  std::vector<Matrix55, Eigen::aligned_allocator<Matrix55>> jacscat(trajectory.numberOfScatterers(), initialjac);
8024  std::vector<Matrix55, Eigen::aligned_allocator<Matrix55>> jacbrem(trajectory.numberOfBrems(), initialjac);
8025 
8026  std::vector<std::unique_ptr<GXFTrackState>> & states = trajectory.trackStates();
8027  GXFTrackState *prevstate = nullptr, *state = nullptr;
8028 
8029  int hit_begin = 0, hit_end = 0, scatno = 0, bremno = 0;
8030 
8031  for (bool forward : {false, true}) {
8032  if (forward) {
8033  hit_begin = nstatesupstream;
8034  hit_end = (int) states.size();
8035  scatno = nscatupstream;
8036  bremno = nbremupstream;
8037  } else {
8038  hit_begin = nstatesupstream - 1;
8039  hit_end = 0;
8040  scatno = trajectory.numberOfUpstreamScatterers() - 1;
8041  bremno = trajectory.numberOfUpstreamBrems() - 1;
8042  }
8043 
8044  for (
8045  int hitno = hit_begin;
8046  forward ? (hitno < hit_end) : (hitno >= hit_end);
8047  hitno += (forward ? 1 : -1)
8048  ) {
8049 
8050  state = states[hitno].get();
8051 
8052  bool fillderivmat = (!state->getStateType(TrackStateOnSurface::Scatterer) && !state->getStateType(TrackStateOnSurface::BremPoint));
8053 
8054  if (fillderivmat && state->derivatives().cols() != nfitpars) {
8055  state->derivatives().resize(5, nfitpars);
8056  state->derivatives().setZero();
8057  }
8058 
8059  int jminscat = 0, jmaxscat = 4, jminbrem = 0, jmaxbrem = 4;
8060 
8061  if (hitno == (forward ? hit_end - 1 : 0)) {
8062  if (!fillderivmat) {
8063  break;
8064  }
8065  jminscat = 2;
8066  jmaxscat = 3;
8067  jminbrem = 4;
8068  }
8069 
8070  Eigen::Matrix<double, 5, 5> & jac = state->jacobian();
8071 
8072  if (hitno == nstatesupstream + (forward ? 0 : -1)) {
8073  jacvertex.block<4, 5>(0, 0) = jac.block<4, 5>(0, 0);
8074  jacvertex(4, 4) = jac(4, 4);
8075  } else {
8076  int jmin = 0, jmax = 0, jcnt = 0;
8077  int lp_bgn = 0, lp_end = 0;
8078 
8079  jmin = jminscat;
8080  jmax = jmaxscat;
8081  jcnt = jmax - jmin + 1;
8082 
8083  lp_bgn = forward ? nscatupstream : nscatupstream - 1;
8084  lp_end = scatno;
8085 
8086  for (int i = lp_bgn; forward ? (i < lp_end) : (i > lp_end); i += (forward ? 1 : -1)) {
8087  if (
8088  i == scatno + (forward ? -1 : 1) &&
8089  prevstate != nullptr &&
8091  (!trajectory.prefit() || prevstate->materialEffects()->deltaE() == 0)
8092  ) {
8093  jacscat[i].block(0, jmin, 4, jcnt) = jac.block(0, jmin, 4, jcnt);
8094  jacscat[i](4, 4) = jac(4, 4);
8095  } else {
8096  calculateJac(jac, jacscat[i], jmin, jmax);
8097  }
8098 
8099  if (fillderivmat) {
8100  Eigen::MatrixXd & derivmat = state->derivatives();
8101  int scatterPos = nperpars + 2 * i;
8102 
8103  derivmat.block<4, 2>(0, scatterPos) = (forward ? 1 : -1) * jacscat[i].block<4, 2>(0, 2);
8104  }
8105  }
8106 
8107  jmin = jminbrem;
8108  jmax = jmaxbrem;
8109  jcnt = jmax - jmin + 1;
8110 
8111  lp_bgn = forward ? nbremupstream : nbremupstream - 1;
8112  lp_end = bremno;
8113 
8114  for (int i = lp_bgn; forward ? (i < lp_end) : (i > lp_end); i += (forward ? 1 : -1)) {
8115  if (
8116  i == bremno + (forward ? -1 : 1) &&
8117  prevstate &&
8118  prevstate->materialEffects() &&
8119  prevstate->materialEffects()->sigmaDeltaE() > 0
8120  ) {
8121  jacbrem[i].block(0, jmin, 4, jcnt) = jac.block(0, jmin, 4, jcnt);
8122  jacbrem[i](4, 4) = jac(4, 4);
8123  } else {
8124  calculateJac(jac, jacbrem[i], jmin, jmax);
8125  }
8126 
8127  if (fillderivmat) {
8128  Eigen::MatrixXd & derivmat = state->derivatives();
8129  int scatterPos = nperpars + 2 * nscats + i;
8130 
8131  derivmat.block<5, 1>(0, scatterPos) = (forward ? .001 : -.001) * jacbrem[i].block<5, 1>(0, 4);
8132  }
8133  }
8134 
8135  calculateJac(jac, jacvertex, 0, 4);
8136  }
8137 
8138  if (fillderivmat) {
8139  Eigen::MatrixXd & derivmat = state->derivatives();
8140  derivmat.block(0, 0, 4, nperpars) = jacvertex.block(0, 0, 4, nperpars);
8141 
8142  if (nperpars == 5) {
8143  derivmat.col(4).segment(0, 4) *= .001;
8144  derivmat(4, 4) = .001 * jacvertex(4, 4);
8145  }
8146  }
8147 
8148  if (
8149  state->getStateType(TrackStateOnSurface::Scatterer) &&
8150  (!trajectory.prefit() || states[hitno]->materialEffects()->deltaE() == 0)
8151  ) {
8152  scatno += (forward ? 1 : -1);
8153  }
8154 
8155  if (
8156  states[hitno]->materialEffects() &&
8157  states[hitno]->materialEffects()->sigmaDeltaE() > 0
8158  ) {
8159  bremno += (forward ? 1 : -1);
8160  }
8161 
8162  prevstate = states[hitno].get();
8163  }
8164  }
8165  }
8166 
8167  void
8168 
8170  Amg::SymMatrixX & fullcovmat,
8171  bool onlylocal) const {
8172  //
8173  // Calculate track errors at each state, except scatterers and brems
8174  //
8175  ATH_MSG_DEBUG("CalculateTrackErrors");
8176 
8177  std::vector<std::unique_ptr<GXFTrackState>> & states = trajectory.trackStates();
8178  int nstatesupstream = trajectory.numberOfUpstreamStates();
8179  std::vector < int >indices(states.size());
8180  GXFTrackState *prevstate = nullptr;
8181  int i = nstatesupstream;
8182  for (int j = 0; j < (int) states.size(); j++) {
8183  if (j < nstatesupstream) {
8184  i--;
8185  indices[j] = i;
8186  } else {
8187  indices[j] = j;
8188  }
8189  }
8190  for (int stateno = 0; stateno < (int) states.size(); stateno++) {
8191  if (stateno == 0 || stateno == nstatesupstream) {
8192  prevstate = nullptr;
8193  }
8194  int index = indices[stateno];
8195  std::unique_ptr<GXFTrackState> & state = states[index];
8196  if (state->materialEffects() != nullptr) {
8197  prevstate = state.get();
8198  continue;
8199  }
8200 
8201  if (!state->hasTrackCovariance()) {
8202  state->zeroTrackCovariance();
8203  }
8204  AmgMatrix(5, 5) & trackerrmat = state->trackCovariance();
8205 
8206  if ((prevstate != nullptr) &&
8209  && !onlylocal) {
8210  Eigen::Matrix<double, 5, 5> & jac = state->jacobian();
8211  AmgMatrix(5, 5) & prevcov = states[indices[stateno - 1]]->trackCovariance();
8212 
8213  trackerrmat = jac * prevcov * jac.transpose();
8214  } else {
8215  Amg::MatrixX & derivatives = state->derivatives();
8216 
8217  trackerrmat = derivatives * fullcovmat * derivatives.transpose();
8218  }
8219 
8220  if (!onlylocal) {
8221  const MeasurementBase *measurement = state->measurement();
8222  const Amg::MatrixX & meascov = measurement->localCovariance();
8223  int j = 0;
8224  ParamDefsAccessor paraccessor;
8225  int indices[5] = {
8226  -1, -1, -1, -1, -1
8227  };
8228  bool errorok = true;
8229  for (int i = 0; i < 5; i++) {
8230  if (measurement->localParameters().contains(paraccessor.pardef[i])) {
8231  if (state->getStateType(TrackStateOnSurface::Measurement)
8232  && trackerrmat(i, i) > meascov(j, j)) {
8233  errorok = false;
8234  double scale = std::sqrt(meascov(j, j) / trackerrmat(i, i));
8235  trackerrmat(i, i) = meascov(j, j);
8236  for (int k = 0; k < 5; k++) {
8237  if (k != i) {
8238  trackerrmat(k, i) *= scale;
8239  }
8240  }
8241  indices[i] = j;
8242  }
8243  j++;
8244  }
8245  }
8246  for (int i = 0; i < 5; i++) {
8247  if (indices[i] == -1) {
8248  continue;
8249  }
8250  for (int j = 0; j < 5; j++) {
8251  if (indices[j] == -1) {
8252  continue;
8253  }
8254  trackerrmat(i, j) = meascov(indices[i], indices[j]);
8255  }
8256  }
8257  if (trajectory.m_straightline) {
8258  trackerrmat(4, 4) = 1e-20;
8259  }
8260 
8261  const TrackParameters *tmptrackpar =
8262  state->trackParameters();
8263 
8264  std::optional<AmgMatrix(5, 5)> trkerrmat;
8265 
8266  if (state->hasTrackCovariance()) {
8267  trkerrmat = (state->trackCovariance());
8268  } else {
8269  trkerrmat = std::nullopt;
8270  }
8271 
8272  const AmgVector(5) & tpars = tmptrackpar->parameters();
8273  std::unique_ptr<const TrackParameters> trackpar(
8274  tmptrackpar->associatedSurface().createUniqueTrackParameters(tpars[0],
8275  tpars[1],
8276  tpars[2],
8277  tpars[3],
8278  tpars[4],
8279  std::move(trkerrmat))
8280  );
8281  state->setTrackParameters(std::move(trackpar));
8282  FitQualityOnSurface fitQual{};
8283  if (state->getStateType(TrackStateOnSurface::Measurement)) {
8284  if (errorok && trajectory.nDOF() > 0) {
8285  fitQual = m_updator->fullStateFitQuality(
8286  *state->trackParameters(),
8287  measurement->localParameters(),
8288  measurement->localCovariance()
8289  );
8290  } else {
8291  fitQual = FitQualityOnSurface(0, state->numberOfMeasuredParameters());
8292  }
8293  }
8294  state->setFitQuality(fitQual);
8295  }
8296  prevstate = state.get();
8297  }
8298  }
8299 
8300  std::optional<TransportJacobian>
8302  const EventContext& ctx,
8303  const TrackParameters* prevpar,
8304  const Surface & surf,
8305  PropDirection propdir,
8306  const MagneticFieldProperties& fieldprop) const
8307  {
8308  ParamDefsAccessor paraccessor;
8309  double J[25] = {
8310  1, 0, 0, 0, 0,
8311  0, 1, 0, 0, 0,
8312  0, 0, 1, 0, 0,
8313  0, 0, 0, 1, 0,
8314  0, 0, 0, 0, 1
8315  };
8316  std::optional<TransportJacobian> jac = std::make_optional<TransportJacobian>(J);
8317  const TrackParameters *tmpprevpar = prevpar;
8318  double eps[5] = {
8319  0.01, 0.01, 0.00001, 0.00001, 0.000000001
8320  };
8321 
8322  const AmgVector(5) & vec = tmpprevpar->parameters();
8323 
8324  bool cylsurf = surf.type() == Trk::SurfaceType::Cylinder;
8325  bool discsurf = surf.type() == Trk::SurfaceType::Disc;
8326  const Surface & previousSurface = tmpprevpar->associatedSurface();
8327  bool thiscylsurf = previousSurface.type() == Trk::SurfaceType::Cylinder;
8328  bool thisdiscsurf = previousSurface.type() == Trk::SurfaceType::Disc;
8329 
8330  for (int i = 0; i < 5; i++) {
8331  AmgVector(5) vecpluseps = vec, vecminuseps = vec;
8332 
8333  if (thisdiscsurf && i == 1) {
8334  eps[i] /= vec[0];
8335  }
8336 
8337  vecpluseps[paraccessor.pardef[i]] += eps[i];
8338  vecminuseps[paraccessor.pardef[i]] -= eps[i];
8339  if (i == 0 && thiscylsurf) {
8340  vecminuseps[i] = -std::remainder(-vecminuseps[i], 2 * M_PI * previousSurface.bounds().r());
8341  } else if (i == 1 && thisdiscsurf) {
8342  vecpluseps[i] = -std::remainder(-vecpluseps[i], 2 * M_PI);
8343  }
8344  correctAngles(vecminuseps[Trk::phi], vecminuseps[Trk::theta]);
8345  correctAngles(vecpluseps[Trk::phi], vecpluseps[Trk::theta]);
8346 
8347  std::unique_ptr<const TrackParameters> parpluseps(
8349  vecpluseps[0],
8350  vecpluseps[1],
8351  vecpluseps[2],
8352  vecpluseps[3],
8353  vecpluseps[4],
8354  std::nullopt
8355  )
8356  );
8357  std::unique_ptr<const TrackParameters> parminuseps(
8359  vecminuseps[0],
8360  vecminuseps[1],
8361  vecminuseps[2],
8362  vecminuseps[3],
8363  vecminuseps[4],
8364  std::nullopt
8365  )
8366  );
8367 
8368  std::unique_ptr<const TrackParameters> newparpluseps(
8369  m_propagator->propagateParameters(
8370  ctx,
8371  *parpluseps,
8372  surf,
8373  propdir,
8374  false,
8375  fieldprop,
8377  )
8378  );
8379  std::unique_ptr<const TrackParameters> newparminuseps(
8380  m_propagator->propagateParameters(
8381  ctx,
8382  *parminuseps,
8383  surf,
8384  propdir,
8385  false,
8386  fieldprop,
8388  )
8389  );
8390 
8391  PropDirection propdir2 =
8392  (propdir ==
8394  if (newparpluseps == nullptr) {
8395  newparpluseps =
8396  m_propagator->propagateParameters(
8397  ctx,
8398  *parpluseps,
8399  surf,
8400  propdir2,
8401  false,
8402  fieldprop,
8404  );
8405  }
8406  if (newparminuseps == nullptr) {
8407  newparminuseps =
8408  m_propagator->propagateParameters(
8409  ctx,
8410  *parminuseps,
8411  surf,
8412  propdir2,
8413  false,
8414  fieldprop,
8416  );
8417  }
8418  if ((newparpluseps == nullptr) || (newparminuseps == nullptr)) {
8419  return nullptr;
8420  }
8421 
8422  for (int j = 0; j < 5; j++) {
8423  double diff = newparpluseps->parameters()[paraccessor.pardef[j]] -
8424  newparminuseps->parameters()[paraccessor.pardef[j]];
8425 
8426  if (j == 0 && cylsurf) {
8427  diff = -std::remainder(-diff, 2 * M_PI * surf.bounds().r());
8428  } else if (j == 1 && discsurf) {
8429  diff = -std::remainder(-diff, 2 * M_PI);
8430  }
8431 
8432  (*jac) (j, i) = diff / (2 * eps[i]);
8433  }
8434 
8435  }
8436  return jac;
8437  }
8438 
8439  int
8441  return 0;
8442  } void
8445  ("Configure the minimum number of Iterations via jobOptions");
8446  }
8447 
8448  bool
8450  if (theta > M_PI) {
8451  theta = M_PI - theta;
8452  phi += M_PI;
8453  }
8454  if (theta < 0) {
8455  theta = -theta;
8456  phi += M_PI;
8457  }
8458 
8459  phi = -std::remainder(-phi, 2 * M_PI);
8460 
8461  return theta >= 0 && theta <= M_PI && phi >= -M_PI && phi <= M_PI;
8462  }
8463 
8464  bool
8465  GlobalChi2Fitter::isMuonTrack(const Track & intrk1) const {
8466  const auto *pDataVector = intrk1.measurementsOnTrack();
8467  auto nmeas1 = pDataVector->size();
8468  const auto *pLastValue = (*pDataVector)[nmeas1 - 1];
8469  //
8470  const bool lastMeasIsRIO = pLastValue->type(Trk::MeasurementBaseType::RIO_OnTrack);
8471  const bool lastMeasIsCompetingRIO = pLastValue->type(Trk::MeasurementBaseType::CompetingRIOsOnTrack);
8472  //we only need the RIO on track pointer to be valid to identify
8473  const RIO_OnTrack *testrot{};
8474  //
8475  if (lastMeasIsRIO){
8476  testrot = static_cast<const RIO_OnTrack *>(pLastValue);
8477  } else {
8478  if (lastMeasIsCompetingRIO){
8479  const auto *testcrot = static_cast<const CompetingRIOsOnTrack*>(pLastValue);
8480  testrot = &testcrot->rioOnTrack(0);
8481  }
8482  }
8483  //still undefined, so try penultimate measurement as well
8484  if (testrot == nullptr) {
8485  const auto *pPenultimate = (*pDataVector)[nmeas1 - 2];
8486  const bool penultimateIsRIO = pPenultimate->type(Trk::MeasurementBaseType::RIO_OnTrack);
8487  const bool penultimateIsCompetingRIO = pPenultimate->type(Trk::MeasurementBaseType::CompetingRIOsOnTrack);
8488  if(penultimateIsRIO){
8489  testrot = static_cast<const RIO_OnTrack *>(pPenultimate);
8490  } else {
8491  if (penultimateIsCompetingRIO){
8492  const auto *testcrot = static_cast<const CompetingRIOsOnTrack*>(pPenultimate);
8493  testrot = &testcrot->rioOnTrack(0);
8494  }
8495  }
8496  }
8497  //check: we've successfully got a valid RIO on track; it's not the inner detector;
8498  //it's really the muon detector (question: doesn't that make the previous check redundant?)
8499  return (
8500  (testrot != nullptr) &&
8501  !m_DetID->is_indet(testrot->identify()) &&
8502  m_DetID->is_muon(testrot->identify())
8503  );
8504  }
8505 
8506  void
8507  GlobalChi2Fitter::initFieldCache(const EventContext& ctx, Cache& cache)
8508  const
8509  {
8512  ctx
8513  );
8514 
8515  const AtlasFieldCacheCondObj * cond_obj(*rh);
8516 
8517  if (cond_obj == nullptr) {
8518  ATH_MSG_ERROR("Failed to create AtlasFieldCacheCondObj!");
8519  return;
8520  }
8521 
8522  cond_obj->getInitializedCache(cache.m_field_cache);
8523  }
8524 
8526  std::stringstream msg;
8527  msg << "Failed to get conditions data " << m_trackingGeometryReadKey.key() << ".";
8528  throw std::runtime_error(msg.str());
8529  }
8530 
8531  bool GlobalChi2Fitter::ensureValidEntranceCalo(const EventContext& ctx, Cache& cache) const {
8532  if (cache.m_caloEntrance == nullptr) {
8533  const TrackingGeometry *geometry = trackingGeometry(cache, ctx);
8534 
8535  if (geometry != nullptr) {
8536  cache.m_caloEntrance = geometry->trackingVolume("InDet::Containers::InnerDetector");
8537  } else {
8538  ATH_MSG_ERROR("Tracking Geometry not available");
8539  }
8540 
8541  /*
8542  * Check, if we managed to find an entrance.
8543  */
8544  if (cache.m_caloEntrance == nullptr) {
8545  ATH_MSG_ERROR("calo entrance not available");
8546  }
8547  }
8548 
8549  return cache.m_caloEntrance != nullptr;
8550  }
8551 
8552  bool GlobalChi2Fitter::ensureValidEntranceMuonSpectrometer(const EventContext& ctx, Cache& cache) const {
8553  if (cache.m_msEntrance == nullptr) {
8554  const TrackingGeometry *geometry = trackingGeometry(cache, ctx);
8555 
8556  if (geometry != nullptr) {
8557  cache.m_msEntrance = geometry->trackingVolume("MuonSpectrometerEntrance");
8558  } else {
8559  ATH_MSG_ERROR("Tracking Geometry not available");
8560  }
8561 
8562  /*
8563  * Check, if we managed to find an entrance.
8564  */
8565  if (cache.m_msEntrance == nullptr) {
8566  ATH_MSG_ERROR("MS entrance not available");
8567  }
8568  }
8569 
8570  return cache.m_msEntrance != nullptr;
8571  }
8572 }
grepfile.info
info
Definition: grepfile.py:38
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:760
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:4470
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:676
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
python.SystemOfUnits.second
int second
Definition: SystemOfUnits.py:120
plotBeamSpotCompare.x1
x1
Definition: plotBeamSpotCompare.py:216
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:840
Trk::proton
@ proton
Definition: ParticleHypothesis.h:31
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:875
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:183
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
python.SystemOfUnits.s
int s
Definition: SystemOfUnits.py:131
TrackFitInputPreparator.h
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
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:5072
StraightLineSurface.h
Trk::GlobalChi2Fitter::tryToWeightAfromMaterial
bool tryToWeightAfromMaterial(Cache &cache, GXFTrajectory &trajectory, Amg::SymMatrixX &a, const bool doDeriv, const int it, const double oldRedChi2, const double newRedChi2) const
Definition: GlobalChi2Fitter.cxx:5827
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:8552
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:891
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:628
MaterialProperties.h
Trk::Volume::inside
bool inside(const Amg::Vector3D &gp, double tol=0.) const
Inside() method for checks.
Definition: Volume.cxx:90
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
make_unique
std::unique_ptr< T > make_unique(Args &&... args)
Definition: SkimmingToolEXOT5.cxx:23
AtlasDetectorID::is_sct
bool is_sct(Identifier id) const
Definition: AtlasDetectorID.h:770
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:6000
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:143
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:160
Trk::TrackingVolume::boundarySurfaces
std::vector< SharedObject< BoundarySurface< TrackingVolume > > > & boundarySurfaces()
Method to return the BoundarySurfaces.
Definition: TrackingVolume.cxx:982
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:201
Trk::GlobalChi2Fitter::isMuonTrack
bool isMuonTrack(const Track &) const
Definition: GlobalChi2Fitter.cxx:8465
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:218
Trk::Surface::associatedDetectorElementIdentifier
Identifier associatedDetectorElementIdentifier() const
return Identifier of the associated Detector Element
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:8443
plotBeamSpotVxVal.covmat
covmat
Definition: plotBeamSpotVxVal.py:206
Trk::GXFTrajectory::numberOfTRTTubeHits
int numberOfTRTTubeHits() const
Definition: GXFTrajectory.cxx:441
Trk::locRPhi
@ locRPhi
Definition: ParamDefs.h:40
python.SystemOfUnits.MeV
int MeV
Definition: SystemOfUnits.py:154
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:114
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:913
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:7757
Trk::GlobalChi2Fitter::m_ROTcreator
ToolHandle< IRIO_OnTrackCreator > m_ROTcreator
Definition: GlobalChi2Fitter.h:1087
python.AthDsoLogger.out
out
Definition: AthDsoLogger.py:71
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
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:4508
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
Trk::GlobalChi2Fitter::fillFirstLastMeasurement
void fillFirstLastMeasurement(Cache &cache, GXFTrajectory &trajectory) const
Definition: GlobalChi2Fitter.cxx:5652
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:6347
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:158
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:782
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:7667
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:7045
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:7783
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::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:93
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:8507
DeMoUpdate.reverse
reverse
Definition: DeMoUpdate.py:563
Trk::MaterialEffectsBase::MATERIAL_EFFECTS_ON_TRACK
@ MATERIAL_EFFECTS_ON_TRACK
Definition: MaterialEffectsBase.h:39
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:189
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:5449
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:25
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:1114
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:7320
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:6996
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:210
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::GlobalChi2Fitter::compensatePhiWeights
void compensatePhiWeights(Cache &cache, GXFTrajectory &trajectory, Amg::SymMatrixX &a) const
Definition: GlobalChi2Fitter.cxx:5959
Trk::GXFTrajectory::setConverged
void setConverged(bool)
Definition: GXFTrajectory.cxx:399
dqt_zlumi_pandas.err
err
Definition: dqt_zlumi_pandas.py:182
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:583
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:43
Trk::GlobalChi2Fitter::iterationsOfLastFit
virtual int iterationsOfLastFit() const
Definition: GlobalChi2Fitter.cxx:8440
AtlasDetectorID::is_tgc
bool is_tgc(Identifier id) const
Definition: AtlasDetectorID.h:902
beamspotman.n
n
Definition: beamspotman.py:731
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:27
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
python.LArMinBiasAlgConfig.int
int
Definition: LArMinBiasAlgConfig.py:59
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:29
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:7718
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:8525
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:7395
Trk::GlobalChi2Fitter::correctAngles
static bool correctAngles(double &, double &)
Definition: GlobalChi2Fitter.cxx:8449
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:7210
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:8169
TrackSummary.h
Trk::GlobalChi2Fitter::makeTrackFindPerigee
std::unique_ptr< GXFTrackState > makeTrackFindPerigee(const EventContext &, Cache &, GXFTrajectory &, const ParticleHypothesis) const
Definition: GlobalChi2Fitter.cxx:7193
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
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:28
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::GlobalChi2Fitter::tryToConverge
void tryToConverge(const Cache &cache, GXFTrajectory &trajectory, const int it) const
Definition: GlobalChi2Fitter.cxx:5408
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:7536
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:8301
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:53
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:3633
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:6227
python.EventInfoMgtInit.release
release
Definition: EventInfoMgtInit.py:24
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:77
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:6517
Trk::nonInteracting
@ nonInteracting
Definition: ParticleHypothesis.h:25
Trk::GXFMaterialEffects::isKink
bool isKink() const
Definition: GXFMaterialEffects.cxx:190
Trk::BinnedArray::arrayObjects
virtual BinnedArraySpan< T *const > arrayObjects()=0
Return all objects of the Array non-const we can still modify the T.
AtlasDetectorID::is_indet
bool is_indet(Identifier id) const
Definition: AtlasDetectorID.h:683
charge
double charge(const T &p)
Definition: AtlasPID.h:931
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::GlobalChi2Fitter::fillBfromMeasurements
void fillBfromMeasurements(const Cache &cache, GXFTrajectory &trajectory, Amg::VectorX &b) const
Definition: GlobalChi2Fitter.cxx:5712
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:6132
dq_make_web_display.rv
def rv
Definition: dq_make_web_display.py:219
ParticleGun_SamplingFraction.radius
radius
Definition: ParticleGun_SamplingFraction.py:96
Trk::kaon
@ kaon
Definition: ParticleHypothesis.h:30
SiDetectorElement.h
python.LumiBlobConversion.pos
pos
Definition: LumiBlobConversion.py:18
Trk::GlobalChi2Fitter::finalize
virtual StatusCode finalize() override
Definition: GlobalChi2Fitter.cxx:290
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:211
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.
python.SystemOfUnits.mm
int mm
Definition: SystemOfUnits.py:83
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::GlobalChi2Fitter::fillAfromMeasurements
void fillAfromMeasurements(const Cache &cache, GXFTrajectory &trajectory, Amg::SymMatrixX &a) const
Definition: GlobalChi2Fitter.cxx:5756
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::ParamDefsAccessor
Definition: ParamDefs.h:92
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:364
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:701
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:536
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
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
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:924
beamspotman.qual
qual
Definition: beamspotman.py:481
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::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:36
Trk::BinnedArray
Definition: BinnedArray.h:38
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:75
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:121
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
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:8531
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:7965
Trk::GlobalChi2Fitter::fillAfromScatterers
void fillAfromScatterers(GXFTrajectory &trajectory, Amg::SymMatrixX &a) const
Definition: GlobalChi2Fitter.cxx:5779
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:8007
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:859
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:5501
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:73
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.