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