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);
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);
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);
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);
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);
2427  } else {
2428  rot = m_ROTcreator->correct(*prd, *trackparForCorrect);
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  return per;
4619  }
4620 
4622  const EventContext& ctx,
4623  Cache & cache,
4624  GXFTrajectory & trajectory,
4625  const TrackParameters & param,
4626  const RunOutlierRemoval runOutlier,
4627  const ParticleHypothesis matEffects
4628  ) const {
4629  ATH_MSG_DEBUG("--> entering GlobalChi2Fitter::myfit_helper");
4631  trajectory.m_straightline = m_straightlineprop;
4632 
4633  if (!trajectory.m_straightline) {
4634  if (trajectory.numberOfSiliconHits() + trajectory.numberOfTRTHits() == trajectory.numberOfHits()) {
4635  trajectory.m_straightline = !cache.m_field_cache.solenoidOn();
4636  } else if ((trajectory.prefit() == 0) && trajectory.numberOfSiliconHits() + trajectory.numberOfTRTHits() == 0) {
4637  trajectory.m_straightline = !cache.m_field_cache.toroidOn();
4638  } else {
4639  trajectory.m_straightline = (!cache.m_field_cache.solenoidOn() && !cache.m_field_cache.toroidOn());
4640  }
4641  }
4642 
4643  trajectory.m_fieldprop = trajectory.m_straightline ? Trk::NoField : Trk::FullField;
4644  cache.m_lastiter = 0;
4645 
4646  Amg::SymMatrixX lu;
4647 
4648  if (trajectory.numberOfPerigeeParameters() == -1) {
4649  cache.incrementFitStatus(S_FITS);
4650  if (trajectory.m_straightline) {
4651  trajectory.setNumberOfPerigeeParameters(4);
4652  } else {
4653  trajectory.setNumberOfPerigeeParameters(5);
4654  }
4655  }
4656 
4657  if (trajectory.nDOF() < 0) {
4658  ATH_MSG_DEBUG("Not enough measurements, reject track");
4659  return nullptr;
4660  }
4661 
4662  cache.m_phiweight.clear();
4663  cache.m_firstmeasurement.clear();
4664  cache.m_lastmeasurement.clear();
4665 
4666  if (matEffects != nonInteracting && param.parameters()[Trk::qOverP] == 0 && m_p == 0) {
4667  ATH_MSG_WARNING("Attempt to apply material corrections with q/p=0, reject track");
4668  return nullptr;
4669  }
4670 
4671  if (matEffects == Trk::electron && trajectory.m_straightline) {
4672  ATH_MSG_WARNING("Electron fit requires helix track model");
4673  return nullptr;
4674  }
4675 
4676  double mass = Trk::ParticleMasses::mass[matEffects];
4677  trajectory.setMass(mass);
4678 
4679  ATH_MSG_DEBUG("start param: " << param << " pos: " << param.position() << " pt: " << param.pT());
4680 
4681  std::unique_ptr<const TrackParameters> per = makePerigee(cache, param, matEffects);
4682 
4683  if (!cache.m_acceleration && (per == nullptr)) {
4686  ATH_MSG_DEBUG("Propagation to perigee failed 1");
4687  return nullptr;
4688  }
4689 
4690  if (matEffects != Trk::nonInteracting && !cache.m_matfilled) {
4691  if (
4692  cache.m_fastmat &&
4693  cache.m_acceleration &&
4694  trajectory.numberOfSiliconHits() + trajectory.numberOfTRTHits() == trajectory.numberOfHits() &&
4695  (m_matupdator.empty() || (m_trackingGeometryReadKey.key().empty()))
4696  ) {
4697  ATH_MSG_WARNING("Tracking Geometry Service and/or Material Updator Tool not configured");
4698  ATH_MSG_WARNING("Falling back to slow material collection");
4699 
4700  cache.m_fastmat = false;
4701  }
4702 
4703  if (
4704  !cache.m_fastmat ||
4705  !cache.m_acceleration ||
4706  trajectory.numberOfSiliconHits() + trajectory.numberOfTRTHits() != trajectory.numberOfHits()
4707  ) {
4708  addMaterial(ctx, cache, trajectory, per != nullptr ? per.get() : &param, matEffects);
4709  } else {
4711  ctx, cache, trajectory, per != nullptr ? per.get() : &param, matEffects);
4712  }
4713  }
4714 
4715  if (cache.m_acceleration && (trajectory.referenceParameters() == nullptr) && (per == nullptr)) {
4717 
4718  if (trajectory.numberOfScatterers() >= 2) {
4719  GXFTrackState *scatstate = nullptr;
4720  GXFTrackState *scatstate2 = nullptr;
4721  int scatindex = 0;
4722 
4723  for (std::vector<std::unique_ptr<GXFTrackState>>::iterator it =
4724  trajectory.trackStates().begin();
4725  it != trajectory.trackStates().end();
4726  ++it) {
4727  if ((**it).getStateType(TrackStateOnSurface::Scatterer)) {
4728  if (
4729  scatindex == trajectory.numberOfScatterers() / 2 ||
4730  (**it).materialEffects()->deltaE() == 0
4731  ) {
4732  scatstate2 = (*it).get();
4733  break;
4734  }
4735 
4736  scatindex++;
4737  scatstate = (*it).get();
4738  }
4739  }
4740 
4741  // @TODO coverity complains about a possible null pointer dereferencing in scatstate->... or scatstate2->...
4742  // it seems to me that if (**it).materialEffects()->deltaE()==0 of the first scatterer
4743  // than scatstate will be NULL.
4744  if ((scatstate == nullptr) || (scatstate2 == nullptr)) {
4745  throw std::logic_error("Invalid scatterer");
4746  }
4747 
4748  vertex = .49 * (scatstate->position() + scatstate2->position());
4749  } else {
4750  int nstates = (int) trajectory.trackStates().size();
4751  vertex = .49 * (
4752  trajectory.trackStates()[nstates / 2 - 1]->position() +
4753  trajectory.trackStates()[nstates / 2]->position()
4754  );
4755  }
4756 
4757  PerigeeSurface persurf(vertex);
4758  std::unique_ptr<const TrackParameters> nearestpar;
4759  double mindist = 99999;
4760  std::vector < GXFTrackState * >mymatvec;
4761 
4762  for (auto & it : trajectory.trackStates()) {
4763  if ((*it).trackParameters() == nullptr) {
4764  continue;
4765  }
4766 
4767  double distance = persurf
4769  (*it).trackParameters()->position(),
4770  (*it).trackParameters()->momentum().unit())
4771  .first();
4772 
4773  bool insideid = (
4774  (cache.m_caloEntrance == nullptr) ||
4775  cache.m_caloEntrance->inside((*it).trackParameters()->position())
4776  );
4777 
4778  if (
4779  (((*it).measurement() != nullptr) && insideid) || (
4780  ((*it).materialEffects() != nullptr) &&
4781  distance > 0 && (
4782  (*it).materialEffects()->deltaE() == 0 ||
4783  ((*it).materialEffects()->sigmaDeltaPhi() == 0 &&
4784  !insideid) ||
4785  (*it).materialEffects()->deltaPhi() != 0
4786  )
4787  )
4788  ) {
4789  double dist = ((*it).trackParameters()->position() - vertex).perp();
4790  if (dist < mindist) {
4791  mindist = dist;
4792  nearestpar = unique_clone((*it).trackParameters());
4793  mymatvec.clear();
4794  continue;
4795  }
4796  }
4797 
4798  if (((*it).materialEffects() != nullptr) && distance > 0) {
4799  mymatvec.push_back(it.get());
4800  }
4801  }
4802 
4803  if (nearestpar == nullptr) {
4804  nearestpar = unique_clone(&param);
4805  }
4806 
4807  for (auto & state : mymatvec) {
4809  const Surface &matsurf = state->associatedSurface();
4811  nearestpar->position(), nearestpar->momentum().unit());
4812 
4813  double distance = getDistance(distsol);
4814 
4815  if (distance < 0 && distsol.numberOfSolutions() > 0) {
4816  propdir = oppositeMomentum;
4817  }
4818 
4819  std::unique_ptr<const TrackParameters> tmppar(m_propagator->propagateParameters(
4820  ctx,
4821  *nearestpar,
4822  matsurf,
4823  propdir,
4824  false,
4825  trajectory.m_fieldprop,
4827  ));
4828 
4829  if (tmppar == nullptr) {
4830  propdir = (propdir == oppositeMomentum) ? alongMomentum : oppositeMomentum;
4831  tmppar = m_propagator->propagateParameters(
4832  ctx,
4833  *nearestpar,
4834  matsurf,
4835  propdir,
4836  false,
4837  trajectory.m_fieldprop,
4839  );
4840 
4841  if (tmppar == nullptr) {
4844 
4845  ATH_MSG_DEBUG("Propagation to perigee failed 2");
4846 
4847  return nullptr;
4848  }
4849  }
4850 
4851  AmgVector(5) newpars = tmppar->parameters();
4852 
4853  if (state->materialEffects()->sigmaDeltaE() > 0) {
4854  newpars[Trk::qOverP] += .001 * state->materialEffects()->delta_p();
4855  } else if (newpars[Trk::qOverP] != 0) {
4856  double sign = (newpars[Trk::qOverP] > 0) ? 1 : -1;
4857  double de = std::abs(state->materialEffects()->deltaE());
4858  double oldp = std::abs(1 / newpars[Trk::qOverP]);
4859  double newp2 = oldp * oldp - 2 * de * std::sqrt(mass * mass + oldp * oldp) + de * de;
4860  if (newp2 > 0) {
4861  newpars[Trk::qOverP] = sign / std::sqrt(newp2);
4862  }
4863  }
4864 
4865  nearestpar = tmppar->associatedSurface().createUniqueTrackParameters(
4866  newpars[0], newpars[1], newpars[2], newpars[3], newpars[4], std::nullopt
4867  );
4868  }
4869 
4870  std::unique_ptr<Trk::TrackParameters> tmpPars(m_propagator->propagateParameters(
4871  ctx,
4872  *nearestpar,
4873  persurf,
4875  false,
4876  trajectory.m_fieldprop,
4878  ));
4879 
4880  // Parameters are at a Perigee surface so they are perigee parameters
4881  if (tmpPars != nullptr) {
4882  per.reset(static_cast < const Perigee *>(tmpPars.release()));
4883  }
4884 
4885  if ((per != nullptr) && (matEffects == Trk::proton || matEffects == Trk::kaon)) {
4886  double sign = (per->parameters()[Trk::qOverP] < 0) ? -1. : 1.;
4887  double oldp = 1. / std::abs(per->parameters()[Trk::qOverP]);
4888  double toteloss = std::abs(trajectory.totalEnergyLoss());
4889  double newp = std::sqrt(oldp * oldp + 2 * toteloss * std::sqrt(oldp * oldp + mass * mass) + toteloss * toteloss);
4890  AmgVector(5) params = per->parameters();
4891  params[Trk::qOverP] = sign / newp;
4892 
4893  per = per->associatedSurface().createUniqueTrackParameters(
4894  params[0], params[1], params[2], params[3], params[4], std::nullopt
4895  );
4896  }
4897 
4898  if (per == nullptr) {
4901  ATH_MSG_DEBUG("Propagation to perigee failed 3");
4902 
4903  return nullptr;
4904  }
4905 
4906  PerigeeSurface persurf2(per->position());
4907  per = persurf2.createUniqueTrackParameters(
4908  0,
4909  0,
4910  per->parameters()[Trk::phi],
4911  per->parameters()[Trk::theta],
4912  per->parameters()[Trk::qOverP],
4913  std::nullopt
4914  );
4915  } else if (per == nullptr) {
4916  per = makePerigee(cache, param, matEffects);
4917  }
4918 
4919  if ((per == nullptr) && (trajectory.referenceParameters() == nullptr)) {
4922  ATH_MSG_DEBUG("Propagation to perigee failed 4");
4923 
4924  return nullptr;
4925  }
4926 
4927  if (trajectory.m_straightline && (per != nullptr)) {
4928  if (trajectory.numberOfPerigeeParameters() == -1) {
4929  trajectory.setNumberOfPerigeeParameters(4);
4930  }
4931 
4932  const AmgVector(5) & pars = per->parameters();
4933  per = per->associatedSurface().createUniqueTrackParameters(
4934  pars[0], pars[1], pars[2], pars[3], 0, std::nullopt
4935  );
4936  } else if (trajectory.numberOfPerigeeParameters() == -1) {
4937  trajectory.setNumberOfPerigeeParameters(5);
4938  }
4939 
4940  if (per != nullptr) {
4941  trajectory.setReferenceParameters(std::move(per));
4942  }
4943 
4944  int nfitpar = trajectory.numberOfFitParameters();
4945  int nperpars = trajectory.numberOfPerigeeParameters();
4946  int nscat = trajectory.numberOfScatterers();
4947  int nbrem = trajectory.numberOfBrems();
4948 
4949  Eigen::MatrixXd a;
4950  Eigen::MatrixXd a_inv;
4951  a.resize(nfitpar, nfitpar);
4952 
4953  Amg::VectorX b(nfitpar);
4954 
4955  Amg::MatrixX derivPool(5, nfitpar);
4956  derivPool.setZero();
4957 
4958  for (std::unique_ptr<GXFTrackState> & state : trajectory.trackStates()) {
4959  if (state->materialEffects() != nullptr) {
4960  continue;
4961  }
4962  state->setDerivatives(derivPool);
4963  }
4964 
4965  bool doderiv = true;
4966  int it = 0;
4967  int tmpminiter = cache.m_miniter;
4968 
4969  for (; it < m_maxit; ++it) {
4970  cache.m_lastiter = it;
4971 
4972  if (it >= m_maxit - 1) {
4973  ATH_MSG_DEBUG("Fit did not converge");
4976  cache.m_miniter = tmpminiter;
4977  return nullptr;
4978  }
4979 
4980  if (!trajectory.converged()) {
4981  cache.m_fittercode =
4982  runIteration(ctx, cache, trajectory, it, a, b, lu, doderiv);
4983  if (cache.m_fittercode != FitterStatusCode::Success) {
4986  } else if (cache.m_fittercode == FitterStatusCode::InvalidAngles) {
4990  }
4991  cache.m_miniter = tmpminiter;
4992  return nullptr;
4993  }
4994 
4995  int nhits = trajectory.numberOfHits();
4996  int ntrthits = trajectory.numberOfTRTHits();
4997  int nsihits = trajectory.numberOfSiliconHits();
4998  double redchi2 = (trajectory.nDOF() > 0) ? trajectory.chi2() / trajectory.nDOF() : 0;
4999  double prevredchi2 = (trajectory.nDOF() > 0) ? trajectory.prevchi2() / trajectory.nDOF() : 0;
5000 
5001 
5002  if( nsihits > 0 && it > 0 && it < m_maxitPixelROT )
5003  updatePixelROTs( trajectory, a, b );
5004 
5005  if (
5006  it > 0 &&
5007  it < 4 && (
5008  (redchi2 < prevredchi2 &&
5009  (redchi2 > prevredchi2 - 1 || redchi2 < 2)) ||
5010  nsihits + ntrthits == nhits
5011  ) &&
5012  (runOutlier || m_trtrecal) &&
5013  ntrthits > 0
5014  ) {
5015  if (it != 1 || nsihits != 0 || trajectory.nDOF() <= 0 || trajectory.chi2() / trajectory.nDOF() <= 3) {
5016  ATH_MSG_DEBUG("Running TRT cleaner");
5017  runTrackCleanerTRT(cache, trajectory, a, b, lu, runOutlier, m_trtrecal, it);
5018  if (cache.m_fittercode != FitterStatusCode::Success) {
5019  ATH_MSG_DEBUG("TRT cleaner failed, returning null...");
5020  cache.m_miniter = tmpminiter;
5021  return nullptr;
5022  }
5023  }
5024  }
5025 
5026  // PHF cut at iteration 3 (to save CPU time)
5027  int ntrtprechits = trajectory.numberOfTRTPrecHits();
5028  int ntrttubehits = trajectory.numberOfTRTTubeHits();
5029  float phf = 1.;
5030  if (ntrtprechits+ntrttubehits) {
5031  phf = float(ntrtprechits)/float(ntrtprechits+ntrttubehits);
5032  }
5033  if (phf<m_minphfcut && it>=3) {
5034  if ((ntrtprechits+ntrttubehits)>=15) {
5035  return nullptr;
5036  }
5037  }
5038  ATH_MSG_DEBUG("Iter = " << it << " | nTRTStates = " << ntrthits
5039  << " | nTRTPrecHits = " << ntrtprechits
5040  << " | nTRTTubeHits = " << ntrttubehits
5041  << " | nOutliers = "
5042  << trajectory.numberOfOutliers());
5043 
5044  if (!trajectory.converged()) {
5045  cache.m_fittercode = updateFitParameters(trajectory, b, lu);
5046  if (cache.m_fittercode != FitterStatusCode::Success) {
5049  }
5050  cache.m_miniter = tmpminiter;
5051  return nullptr;
5052  }
5053  }
5054  } else {
5055  break;
5056  }
5057  }
5058 
5059  cache.m_miniter = tmpminiter;
5060 
5061  if (trajectory.prefit() == 0) {
5062  // Solve assuming the matrix is SPD.
5063  // Cholesky Decomposition is used -- could use LDLT
5064 
5065  Eigen::LLT < Eigen::MatrixXd > lltOfW(a);
5066  if (lltOfW.info() == Eigen::Success) {
5067  // Solve for x where Wx = I
5068  // this is cheaper than invert as invert makes no assumptions about the
5069  // matrix being symmetric
5070  int ncols = a.cols();
5071  Amg::MatrixX weightInvAMG = Amg::MatrixX::Identity(ncols, ncols);
5072  a_inv = lltOfW.solve(weightInvAMG);
5073  } else {
5074  ATH_MSG_DEBUG("matrix inversion failed!");
5077  return nullptr;
5078  }
5079  }
5080 
5081  GXFTrajectory *finaltrajectory = &trajectory;
5082  if (
5083  (runOutlier || cache.m_sirecal) &&
5084  trajectory.numberOfSiliconHits() == trajectory.numberOfHits()
5085  ) {
5086  calculateTrackErrors(trajectory, a_inv, true);
5087  finaltrajectory = runTrackCleanerSilicon(ctx,cache, trajectory, a, a_inv, b, runOutlier);
5088  }
5089 
5090  if (cache.m_fittercode != FitterStatusCode::Success) {
5091  ATH_MSG_DEBUG("Silicon cleaner failed, returning null...");
5092  if (finaltrajectory != &trajectory) {
5093  // cppcheck-suppress autovarInvalidDeallocation; false positive
5094  delete finaltrajectory;
5095  }
5096  return nullptr;
5097  }
5098 
5099  if (m_domeastrackpar && (finaltrajectory->prefit() == 0)) {
5100  calculateTrackErrors(*finaltrajectory, a_inv, false);
5101  }
5102 
5103  if (!cache.m_acceleration && (finaltrajectory->prefit() == 0)) {
5104  if (nperpars == 5) {
5105  for (int i = 0; i < a.cols(); i++) {
5106  a_inv(4, i) *= .001;
5107  a_inv(i, 4) *= .001;
5108  }
5109  }
5110 
5111  int scatterPos = nperpars + 2 * nscat;
5112  for (int bremno = 0; bremno < nbrem; bremno++, scatterPos++) {
5113  for (int i = 0; i < a.cols(); i++) {
5114  a_inv(scatterPos, i) *= .001;
5115  a_inv(i, scatterPos) *= .001;
5116  }
5117  }
5118 
5119  AmgSymMatrix(5) errmat;
5120  errmat.setZero();
5121  int nperparams = finaltrajectory->numberOfPerigeeParameters();
5122  for (int i = 0; i < nperparams; i++) {
5123  for (int j = 0; j < nperparams; j++) {
5124  (errmat) (j, i) = a_inv(j, i);
5125  }
5126  }
5127 
5128  if (trajectory.m_straightline) {
5129  (errmat) (4, 4) = 1e-20;
5130  }
5131 
5132  const AmgVector(5) & perpars = finaltrajectory->referenceParameters()->parameters();
5133  std::unique_ptr<const TrackParameters> measper(
5135  perpars[0], perpars[1], perpars[2], perpars[3], perpars[4], std::move(errmat)
5136  )
5137  );
5138 
5139  finaltrajectory->setReferenceParameters(std::move(measper));
5140  if (m_fillderivmatrix) {
5141  cache.m_fullcovmat = a_inv;
5142  }
5143  }
5144 
5145  std::unique_ptr<Track> track = nullptr;
5146 
5147  if (finaltrajectory->prefit() > 0) {
5148  if (finaltrajectory != &trajectory) {
5149  delete finaltrajectory;
5150  }
5151  return nullptr;
5152  }
5153 
5154  if (finaltrajectory->numberOfOutliers() <= m_maxoutliers || !runOutlier) {
5155  track = makeTrack(ctx,cache, *finaltrajectory, matEffects);
5156  } else {
5159  }
5160 
5161  double cut = (finaltrajectory->numberOfSiliconHits() ==
5162  finaltrajectory->numberOfHits())
5163  ? 999.0
5164  : m_chi2cut.value();
5165 
5166  if (
5167  runOutlier &&
5168  (track != nullptr) && (
5169  track->fitQuality()->numberDoF() != 0 &&
5170  track->fitQuality()->chiSquared() / track->fitQuality()->numberDoF() > cut
5171  )
5172  ) {
5173  track.reset(nullptr);
5175  }
5176 
5177  if (track == nullptr) {
5178  ATH_MSG_DEBUG("Track rejected");
5179  }
5180 
5181  if (finaltrajectory != &trajectory) {
5182  delete finaltrajectory;
5183  }
5184 
5185  return track.release();
5186  }
5187 
5189  const EventContext& ctx,
5190  Cache & cache,
5191  GXFTrajectory & trajectory,
5192  int it,
5193  Amg::SymMatrixX & a,
5194  Amg::VectorX & b,
5195  Amg::SymMatrixX & lu_m,
5196  bool &doderiv
5197  ) const {
5198  ATH_MSG_DEBUG("fillResiduals");
5199 
5200  std::vector<std::unique_ptr<GXFTrackState>> & states = trajectory.trackStates();
5201  double chi2 = 0;
5202  int scatno = 0;
5203  int bremno = 0;
5204  int measno = 0;
5205  int nbrem = trajectory.numberOfBrems();
5206  int nperpars = trajectory.numberOfPerigeeParameters();
5207  int nfitpars = trajectory.numberOfFitParameters();
5208 
5209  Amg::VectorX & res = trajectory.residuals();
5210  Amg::MatrixX & weightderiv = trajectory.weightedResidualDerivatives();
5211  int nidhits = trajectory.numberOfSiliconHits() + trajectory.numberOfTRTHits();
5212  int nsihits = trajectory.numberOfSiliconHits();
5213  int ntrthits = trajectory.numberOfTRTHits();
5214  int nhits = trajectory.numberOfHits();
5215  int nmeas = (int) res.size();
5216  Amg::VectorX & error = trajectory.errors();
5217  ParamDefsAccessor paraccessor;
5218  bool scatwasupdated = false;
5219 
5220  GXFTrackState *state_maxbrempull = nullptr;
5221  int bremno_maxbrempull = 0;
5222  double maxbrempull = 0;
5223 
5224  for (int hitno = 0; hitno < (int) states.size(); hitno++) {
5225  std::unique_ptr<GXFTrackState> & state = states[hitno];
5226  const TrackParameters *currenttrackpar = state->trackParameters();
5227  TrackState::MeasurementType hittype = state->measurementType();
5228  const MeasurementBase *measbase = state->measurement();
5229 
5230  if (state->getStateType(TrackStateOnSurface::Measurement)) {
5231  if (
5232  hittype == TrackState::Pseudo &&
5233  it <= 100 &&
5234  it > 1 &&
5235  trajectory.nDOF() != 0 &&
5236  std::abs((trajectory.prevchi2() - trajectory.chi2()) / trajectory.nDOF()) < 15 &&
5237  !state->associatedSurface().isFree() &&
5238  nidhits < trajectory.numberOfHits() &&
5239  (nperpars == 0 || nidhits > 0) &&
5240  (!state->isRecalibrated())
5241  ) {
5242  Amg::MatrixX covMatrix(1, 1);
5243  covMatrix(0, 0) = 100;
5244 
5245  std::unique_ptr<const PseudoMeasurementOnTrack> newpseudo = std::make_unique<const PseudoMeasurementOnTrack>(
5246  LocalParameters(DefinedParameter(currenttrackpar->parameters()[Trk::locY], Trk::locY)),
5247  std::move(covMatrix),
5248  currenttrackpar->associatedSurface()
5249  );
5250 
5251  state->setMeasurement(std::move(newpseudo));
5252  measbase = state->measurement();
5253  }
5254 
5255  double *errors = state->measurementErrors();
5256 
5257  std::array<double,5> residuals = m_residualPullCalculator->residuals(measbase, currenttrackpar, ResidualPull::Biased, hittype);
5258 
5259  for (int i = 0; i < 5; i++) {
5260  if (
5261  !measbase->localParameters().contains(paraccessor.pardef[i]) ||
5262  (i > 0 && (hittype == TrackState::SCT || hittype == TrackState::TGC))
5263  ) {
5264  continue;
5265  }
5266 
5267  error[measno] =
5268  (trajectory.prefit() > 0 && (hittype == TrackState::MDT || (hittype == TrackState::CSC && !state->measuresPhi()))) ?
5269  2 :
5270  errors[i];
5271 
5272  res[measno] = residuals[i];
5273 
5274  if (i == 2 && std::abs(std::abs(res[measno]) - 2 * M_PI) < std::abs(res[measno])) {
5275  if (res[measno] < 0) {
5276  res[measno] += 2 * M_PI;
5277  } else {
5278  res[measno] -= 2 * M_PI;
5279  }
5280  }
5281  measno++;
5282  }
5283  } else if (state->getStateType(TrackStateOnSurface::Outlier)) {
5284  double *errors = state->measurementErrors();
5285  for (int i = 0; i < 5; i++) {
5286  if (errors[i] > 0) {
5287  error[measno] = errors[i];
5288  measno++;
5289  }
5290  }
5291  }
5292 
5293  if (
5294  state->getStateType(TrackStateOnSurface::Scatterer) &&
5295  ((trajectory.prefit() == 0) || state->materialEffects()->deltaE() == 0)
5296  ) {
5297  double deltaphi = state->materialEffects()->deltaPhi();
5298  double measdeltaphi = state->materialEffects()->measuredDeltaPhi();
5299  double sigmadeltaphi = state->materialEffects()->sigmaDeltaPhi();
5300  double deltatheta = state->materialEffects()->deltaTheta();
5301  double sigmadeltatheta = state->materialEffects()->sigmaDeltaTheta();
5302 
5303  if (trajectory.prefit() != 1) {
5304  b[nperpars + 2 * scatno] -= (deltaphi - measdeltaphi) / (sigmadeltaphi * sigmadeltaphi);
5305  b[nperpars + 2 * scatno + 1] -= deltatheta / (sigmadeltatheta * sigmadeltatheta);
5306  } else {
5307  b[nperpars + scatno] -= deltatheta / (sigmadeltatheta * sigmadeltatheta);
5308  }
5309 
5310  chi2 += (
5311  deltaphi * deltaphi / (sigmadeltaphi * sigmadeltaphi) +
5312  deltatheta * deltatheta / (sigmadeltatheta * sigmadeltatheta)
5313  );
5314 
5315  scatno++;
5316  }
5317 
5318  if ((state->materialEffects() != nullptr) && state->materialEffects()->sigmaDeltaE() > 0) {
5319  double averagenergyloss = std::abs(state->materialEffects()->deltaE());
5320  const double qoverpbrem = limitInversePValue(1000 * states[hitno]->trackParameters()->parameters()[Trk::qOverP]);
5321  const double qoverp = limitInversePValue(qoverpbrem - state->materialEffects()->delta_p());
5322  const double pbrem = 1. / std::abs(qoverpbrem);
5323  const double p = 1. / std::abs(qoverp);
5324  const double mass = .001 * trajectory.mass();
5325  const double energy = std::sqrt(p * p + mass * mass);
5326  const double bremEnergy = std::sqrt(pbrem * pbrem + mass * mass);
5327 
5328  res[nmeas - nbrem + bremno] = .001 * averagenergyloss - energy + bremEnergy;
5329 
5330  double sigde = state->materialEffects()->sigmaDeltaE();
5331  double sigdepos = state->materialEffects()->sigmaDeltaEPos();
5332  double sigdeneg = state->materialEffects()->sigmaDeltaENeg();
5333 
5334  error[nmeas - nbrem + bremno] = .001 * state->materialEffects()->sigmaDeltaE();
5335 
5336  if (state->materialEffects()->isKink()) {
5337  maxbrempull = -999999999;
5338  state_maxbrempull = nullptr;
5339  }
5340 
5341  if (
5342  cache.m_asymeloss &&
5343  it > 0 &&
5344  (trajectory.prefit() == 0) &&
5345  sigde > 0 &&
5346  sigde != sigdepos &&
5347  sigde != sigdeneg
5348  ) {
5349  double elosspull = res[nmeas - nbrem + bremno] / (.001 * sigde);
5350 
5351  if (trajectory.mass() > 100) {
5352  if (elosspull < -1) {
5353  state->materialEffects()->setSigmaDeltaE(sigdepos);
5354  } else if (elosspull > 1) {
5355  state->materialEffects()->setSigmaDeltaE(sigdeneg);
5356  }
5357 
5358  error[nmeas - nbrem + bremno] = .001 * state->materialEffects()->sigmaDeltaE();
5359  } else if ((trajectory.numberOfTRTHits() == 0) || it >= 3) {
5360  if (
5361  !state->materialEffects()->isKink() && (
5362  (elosspull < -.2 && m_fixbrem == -1 && elosspull < maxbrempull) ||
5363  (m_fixbrem >= 0 && bremno == m_fixbrem)
5364  )
5365  ) {
5366  bremno_maxbrempull = bremno;
5367  state_maxbrempull = state.get();
5368  maxbrempull = elosspull;
5369  }
5370  }
5371  }
5372 
5373  if (
5374  it > 0 &&
5375  hitno >= 2 &&
5376  !m_calotoolparam.empty() &&
5377  (trajectory.prefit() == 0) &&
5378  state->materialEffects()->sigmaDeltaPhi() == 0 &&
5379  state->materialEffects()->isMeasuredEloss() &&
5380  res[nmeas - nbrem + bremno] / (.001 * state->materialEffects()->sigmaDeltaEAve()) > 2.5
5381  ) {
5382  const TrackParameters* parforcalo =
5383  trajectory.prefit() != 0 ? trajectory.referenceParameters()
5384  : states[hitno - 2]->trackParameters();
5385  const IPropagator* prop = &*m_propagator;
5386 
5387  std::vector<MaterialEffectsOnTrack> calomeots =
5388  m_calotoolparam->extrapolationSurfacesAndEffects(
5389  *m_navigator->highestVolume(ctx),
5390  *prop,
5391  *parforcalo,
5392  parforcalo->associatedSurface(),
5394  Trk::muon);
5395 
5396  if (calomeots.size() == 3) {
5397  averagenergyloss = std::abs(calomeots[1].energyLoss()->deltaE());
5398  double newres = .001 * averagenergyloss - energy + bremEnergy;
5399  double newerr = .001 * calomeots[1].energyLoss()->sigmaDeltaE();
5400 
5401  if (std::abs(newres / newerr) < std::abs(res[nmeas - nbrem + bremno] / error[nmeas - nbrem + bremno])) {
5402  ATH_MSG_DEBUG("Changing from measured to parametrized energy loss");
5403 
5404  state->materialEffects()->setEloss(std::unique_ptr<EnergyLoss>(calomeots[1].energyLoss()->clone()));
5405  state->materialEffects()->setSigmaDeltaE(calomeots[1].energyLoss()->sigmaDeltaE());
5406  res[nmeas - nbrem + bremno] = newres;
5407  error[nmeas - nbrem + bremno] = newerr;
5408  }
5409  }
5410 
5411  state->materialEffects()->setMeasuredEloss(false);
5412  }
5413  bremno++;
5414  }
5415  }
5416 
5417  measno = 0;
5418 
5419  for (; measno < nmeas; measno++) {
5420  if (error[measno] == 0) {
5421  continue;
5422  }
5423 
5424  chi2 += res[measno] * (1. / (error[measno] * error[measno])) * res[measno];
5425 
5426  }
5427  if (!doderiv && (scatwasupdated)) {
5428  lu_m = a;
5429  }
5430 
5431  double oldchi2 = trajectory.chi2();
5432  trajectory.setPrevChi2(oldchi2);
5433  trajectory.setChi2(chi2);
5434 
5435  double oldredchi2 = (trajectory.nDOF() > 0) ? oldchi2 / trajectory.nDOF() : 0;
5436  double newredchi2 = (trajectory.nDOF() > 0) ? chi2 / trajectory.nDOF() : 0;
5437 
5438  if (
5439  trajectory.prefit() > 0 && (
5440  (newredchi2 < 2 && it != 0) ||
5441  (newredchi2 < oldredchi2 + .1 && std::abs(newredchi2 - oldredchi2) < 1 && it != 1)
5442  )
5443  ) {
5444  trajectory.setConverged(true);
5445  }
5446 
5447  double maxdiff = (nsihits != 0 && nsihits + ntrthits == nhits && chi2 < oldchi2) ? 200 : 1.;
5448  maxdiff = 1;
5449  int miniter = (nsihits != 0 && nsihits + ntrthits == nhits) ? 1 : 2;
5450 
5451  if (miniter < cache.m_miniter) {
5452  miniter = cache.m_miniter;
5453  }
5454 
5455  if (it >= miniter && std::abs(oldchi2 - chi2) < maxdiff) {
5456  trajectory.setConverged(true);
5457  }
5458 
5459  if ((state_maxbrempull != nullptr) && trajectory.converged()) {
5460  state_maxbrempull->materialEffects()->setSigmaDeltaE(
5461  10 * state_maxbrempull->materialEffects()->sigmaDeltaEPos()
5462  );
5463 
5464  state_maxbrempull->materialEffects()->setKink(true);
5465  trajectory.setConverged(false);
5466 
5467  double olderror = error[nmeas - nbrem + bremno_maxbrempull];
5468  double newerror = .001 * state_maxbrempull->materialEffects()->sigmaDeltaE();
5469  error[nmeas - nbrem + bremno_maxbrempull] = .001 * state_maxbrempull->materialEffects()->sigmaDeltaE();
5470 
5471  if (a.cols() != nfitpars) {
5472  ATH_MSG_ERROR("Your assumption is wrong!!!!");
5473  }
5474 
5475  for (int i = 0; i < nfitpars; i++) {
5476  if (weightderiv(nmeas - nbrem + bremno_maxbrempull, i) == 0) {
5477  continue;
5478  }
5479 
5480  for (int j = i; j < nfitpars; j++) {
5481  a.fillSymmetric(
5482  i, j,
5483  a(i, j) - (
5484  weightderiv(nmeas - nbrem + bremno_maxbrempull, i) *
5485  weightderiv(nmeas - nbrem + bremno_maxbrempull, j) *
5486  (1 - olderror * olderror / (newerror * newerror))
5487  )
5488  );
5489  }
5490  weightderiv(nmeas - nbrem + bremno_maxbrempull, i) *= olderror / newerror;
5491  }
5492  lu_m = a;
5493  trajectory.setChi2(1e15);
5494  doderiv = true;
5495  }
5496  }
5497 
5499  GXFTrajectory & trajectory,
5500  bool onlybrem
5501  ) const {
5502  ATH_MSG_DEBUG("fillDerivatives");
5503 
5504  std::vector<std::unique_ptr<GXFTrackState>> & states = trajectory.trackStates();
5505  int scatno = 0;
5506  int bremno = 0;
5507  int measno = 0;
5508  int nscatupstream = trajectory.numberOfUpstreamScatterers();
5509  int nbremupstream = trajectory.numberOfUpstreamBrems();
5510  int nscat = trajectory.numberOfScatterers();
5511  int nbrem = trajectory.numberOfBrems();
5512  int nperparams = trajectory.numberOfPerigeeParameters();
5513 
5514  Amg::MatrixX & weightderiv = trajectory.weightedResidualDerivatives();
5515  Amg::VectorX & error = trajectory.errors();
5516 
5517  int nmeas = (int) weightderiv.rows();
5518 
5519  ParamDefsAccessor paraccessor;
5520 
5521  for (std::unique_ptr<GXFTrackState> & state : states) {
5522  if (
5523  onlybrem &&
5524  ((state->materialEffects() == nullptr) || state->materialEffects()->sigmaDeltaE() <= 0)
5525  ) {
5526  continue;
5527  }
5528 
5529  TrackState::MeasurementType hittype = state->measurementType();
5530  const MeasurementBase *measbase = state->measurement();
5531  const auto [scatmin, scatmax] = std::minmax(scatno, nscatupstream);
5532  const auto [bremmin, bremmax] = std::minmax(bremno, nbremupstream);
5533  if (state->getStateType(TrackStateOnSurface::Measurement)) {
5534  Amg::MatrixX & derivatives = state->derivatives();
5535  double sinstereo = 0;
5536 
5537  if (hittype == TrackState::SCT || hittype == TrackState::TGC) {
5538  sinstereo = state->sinStereo();
5539  }
5540 
5541  double cosstereo = (sinstereo == 0) ? 1. : std::sqrt(1 - sinstereo * sinstereo);
5542 
5543  for (int i = 0; i < 5; i++) {
5544  if (
5545  !measbase->localParameters().contains(paraccessor.pardef[i]) ||
5546  (i > 0 && (hittype == TrackState::SCT || hittype == TrackState::TGC))
5547  ) {
5548  continue;
5549  }
5550 
5551  if (trajectory.numberOfPerigeeParameters() > 0) {
5552  int cols = trajectory.m_straightline ? 4 : 5;
5553 
5554  if (i == 0) {
5555  weightderiv.row(measno).head(cols) =
5556  (derivatives.row(0).head(cols) * cosstereo +
5557  sinstereo * derivatives.row(1).head(cols)) /
5558  error[measno];
5559  } else {
5560  weightderiv.row(measno).head(cols) = derivatives.row(i).head(cols) / error[measno];
5561  }
5562  }
5563 
5564  for (int j = scatmin; j < scatmax; j++) {
5565  int index = nperparams + ((trajectory.prefit() != 1) ? 2 * j : j);
5566  double thisderiv = 0;
5567  double sign = 1;
5568  //
5569 
5570  if (i == 0 && sinstereo != 0) {
5571  thisderiv = sign * (derivatives(0, index) * cosstereo + sinstereo * derivatives(1, index));
5572  } else {
5573  thisderiv = sign * derivatives(i, index);
5574  }
5575 
5576  weightderiv(measno, index) = thisderiv / error[measno];
5577 
5578  if (trajectory.prefit() != 1) {
5579  index++;
5580 
5581  if (i == 0 && sinstereo != 0) {
5582  thisderiv = sign * (derivatives(0, index) * cosstereo + sinstereo * derivatives(1, index));
5583  } else {
5584  thisderiv = sign * derivatives(i, index);
5585  }
5586 
5587  weightderiv(measno, index) = thisderiv / error[measno];
5588  }
5589  }
5590 
5591  for (int j = bremmin; j < bremmax; j++) {
5592  double thisderiv = 0;
5593  int index = j + nperparams + 2 * nscat;
5594  if (i == 0 && sinstereo != 0) {
5595  thisderiv = derivatives(0, index) * cosstereo + sinstereo * derivatives(1, index);
5596  } else {
5597  thisderiv = derivatives(i, index);
5598  }
5599  weightderiv(measno, index) = thisderiv / error[measno];
5600  }
5601 
5602  measno++;
5603  }
5604  } else if (state->getStateType(TrackStateOnSurface::Outlier)) {
5605  double *errors = state->measurementErrors();
5606  for (int i = 0; i < 5; i++) {
5607  if (errors[i] > 0) {
5608  measno++;
5609  }
5610  }
5611  } else if (
5612  state->getStateType(TrackStateOnSurface::Scatterer) &&
5613  ((trajectory.prefit() == 0) || state->materialEffects()->deltaE() == 0)
5614  ) {
5615  scatno++;
5616  }
5617 
5618  if ((state->materialEffects() != nullptr) && state->materialEffects()->sigmaDeltaE() > 0) {
5619  //limit values to avoid FPE overflow or div by zero
5620  double qoverpbrem = limitInversePValue(1000 * state->trackParameters()->parameters()[Trk::qOverP]);
5621  double qoverp = limitInversePValue(qoverpbrem - state->materialEffects()->delta_p());
5622 
5623  double mass = .001 * trajectory.mass();
5624 
5625  const auto thisMeasurementIdx{nmeas - nbrem + bremno};
5626  //references (courtesy of Christos Anastopoulos):
5627  //https://inspirehep.net/files/a810ad0047a22af32fbff587c6c98ce5
5628  //https://its.cern.ch/jira/browse/ATLASRECTS-6213
5629  auto multiplier = [] (double mass, double qOverP){
5630  return std::copysign(1./(qOverP * qOverP * std::sqrt(1. + mass * mass * qOverP * qOverP)), qOverP);
5631  };
5632  const auto qoverpTerm {multiplier(mass, qoverp) / error[thisMeasurementIdx]};
5633  const auto qoverpBremTerm {multiplier(mass, qoverpbrem) / error[thisMeasurementIdx]};
5634 
5635  if (trajectory.numberOfPerigeeParameters() > 0) {
5636  weightderiv(thisMeasurementIdx, 4) = qoverpBremTerm - qoverpTerm;
5637  }
5638  //
5639  const auto bremNoBase = nperparams + 2 * nscat;
5640  if (bremno < nbremupstream) {
5641  weightderiv(thisMeasurementIdx, bremNoBase + bremno) = qoverpTerm;
5642  for (int bremno2 = bremno + 1; bremno2 < nbremupstream; bremno2++) {
5643  weightderiv(thisMeasurementIdx, bremNoBase + bremno2) = qoverpTerm - qoverpBremTerm;
5644  }
5645  } else {
5646  weightderiv(thisMeasurementIdx, bremNoBase + bremno) = qoverpBremTerm;
5647  for (int bremno2 = nbremupstream; bremno2 < bremno; bremno2++) {
5648  weightderiv(thisMeasurementIdx, bremNoBase + bremno2) = qoverpBremTerm - qoverpTerm;
5649  }
5650  }
5651  bremno++;
5652  }
5653  }
5654  }
5655 
5657  const EventContext& ctx,
5658  Cache & cache,
5659  GXFTrajectory & trajectory,
5660  int it,
5661  Amg::SymMatrixX & a,
5662  Amg::VectorX & b,
5663  Amg::SymMatrixX & lu,
5664  bool &doderiv
5665  ) const {
5666  int measno = 0;
5667  int nfitpars = trajectory.numberOfFitParameters();
5668  int nperpars = trajectory.numberOfPerigeeParameters();
5669  int scatpars = 2 * trajectory.numberOfScatterers();
5670  int nupstreamstates = trajectory.numberOfUpstreamStates();
5671  int nbrem = trajectory.numberOfBrems();
5672  double oldchi2 = trajectory.chi2();
5673  double oldredchi2 = (trajectory.nDOF() > 0) ? oldchi2 / trajectory.nDOF() : 0;
5674  int nsihits = trajectory.numberOfSiliconHits();
5675  int ntrthits = trajectory.numberOfTRTHits();
5676  int nhits = trajectory.numberOfHits();
5677 
5678  if (cache.m_phiweight.empty()) {
5679  cache.m_phiweight.assign(trajectory.trackStates().size(), 1);
5680  }
5681 
5682  FitterStatusCode fsc = calculateTrackParameters(ctx,trajectory, doderiv);
5683 
5684  if (fsc != FitterStatusCode::Success) {
5685  return fsc;
5686  }
5687 
5688  b.setZero();
5689 
5690  fillResiduals(ctx, cache, trajectory, it, a, b, lu, doderiv);
5691 
5692  double newredchi2 = (trajectory.nDOF() > 0) ? trajectory.chi2() / trajectory.nDOF() : 0;
5693 
5694  ATH_MSG_DEBUG("old chi2: " << oldchi2 << "/" << trajectory.nDOF() <<
5695  "=" << oldredchi2 << " new chi2: " << trajectory.chi2() << "/" <<
5696  trajectory.nDOF() << "=" << newredchi2);
5697 
5698  if (trajectory.prefit() > 0 && trajectory.converged()) {
5700  }
5701 
5702  Amg::VectorX & res = trajectory.residuals();
5703  Amg::VectorX & error = trajectory.errors();
5704  std::vector < std::pair < double, double >>&scatsigmas = trajectory.scatteringSigmas();
5705 
5706  int nmeas = (int) res.size();
5707 
5708  const Amg::MatrixX & weight_deriv = trajectory.weightedResidualDerivatives();
5709 
5710  if (doderiv) {
5711  calculateDerivatives(trajectory);
5712  fillDerivatives(trajectory, !doderiv);
5713  }
5714 
5715  if (cache.m_firstmeasurement.empty()) {
5716  cache.m_firstmeasurement.resize(nfitpars);
5717  cache.m_lastmeasurement.resize(nfitpars);
5718  for (int i = 0; i < nperpars; i++) {
5719  cache.m_firstmeasurement[i] = 0;
5720  cache.m_lastmeasurement[i] = nmeas - nbrem;
5721  }
5722  measno = 0;
5723  int scatno = 0;
5724  int bremno = 0;
5725  for (int i = 0; i < (int) trajectory.trackStates().size(); i++) {
5726  std::unique_ptr<GXFTrackState> & state = trajectory.trackStates()[i];
5727  GXFMaterialEffects *meff = state->materialEffects();
5728  if (meff == nullptr) {
5729  measno += state->numberOfMeasuredParameters();
5730  }
5731  if (meff != nullptr) {
5732  if (meff->sigmaDeltaTheta() != 0
5733  && ((trajectory.prefit() == 0) || meff->deltaE() == 0)) {
5734  int scatterPos = nperpars + 2 * scatno;
5735  if (i < nupstreamstates) {
5736  cache.m_lastmeasurement[scatterPos] =
5737  cache.m_lastmeasurement[scatterPos + 1] = measno;
5738  cache.m_firstmeasurement[scatterPos] =
5739  cache.m_firstmeasurement[scatterPos + 1] = 0;
5740  } else {
5741  cache.m_lastmeasurement[scatterPos] =
5742  cache.m_lastmeasurement[scatterPos + 1] = nmeas - nbrem;
5743  cache.m_firstmeasurement[scatterPos] =
5744  cache.m_firstmeasurement[scatterPos + 1] = measno;
5745  }
5746  scatno++;
5747  }
5748  if (meff->sigmaDeltaE() > 0) {
5749  if (i < nupstreamstates) {
5750  cache.m_firstmeasurement[nperpars + scatpars + bremno] = 0;
5751  cache.m_lastmeasurement[nperpars + scatpars + bremno] = measno;
5752  } else {
5753  cache.m_firstmeasurement[nperpars + scatpars + bremno] = measno;
5754  cache.m_lastmeasurement[nperpars + scatpars + bremno] =
5755  nmeas - nbrem;
5756  }
5757 
5758  bremno++;
5759  }
5760  }
5761  }
5762  }
5763 
5764  if (a.cols() != nfitpars) {
5765  ATH_MSG_ERROR("Your assumption is wrong!!!!");
5766  }
5767 
5768  for (int k = 0; k < nfitpars; k++) {
5769  int minmeas = 0;
5770  int maxmeas = nmeas - nbrem;
5771  maxmeas = cache.m_lastmeasurement[k];
5772  minmeas = cache.m_firstmeasurement[k];
5773 
5774  for (measno = minmeas; measno < maxmeas; measno++) {
5775  double tmp =
5776  res[measno] * (1. / error[measno]) * weight_deriv(measno, k);
5777  b[k] += tmp;
5778  }
5779 
5780  if (k == 4 || k >= nperpars + scatpars) {
5781  for (measno = nmeas - nbrem; measno < nmeas; measno++) {
5782  b[k] += res[measno] * (1. / error[measno]) * weight_deriv(measno, k);
5783  }
5784  }
5785 
5786  if (doderiv) {
5787  for (int l = k; l < nfitpars; l++) {
5788  maxmeas =
5790  minmeas =
5791  std::max(cache.m_firstmeasurement[k],
5792  cache.m_firstmeasurement[l]);
5793  double tmp = 0;
5794  for (measno = minmeas; measno < maxmeas; measno++) {
5795  tmp += weight_deriv(measno, k) * weight_deriv(measno, l);
5796  }
5797  a.fillSymmetric(l, k, tmp);
5798  }
5799  }
5800  }
5801 
5802  if (doderiv) {
5803  int scatno = 0;
5804 
5805  for (int k = nperpars; k < nperpars + scatpars; k += 2) {
5806  a(k, k) += 1. / (scatsigmas[scatno].first * scatsigmas[scatno].first);
5807  a(k + 1, k + 1) += 1. / (scatsigmas[scatno].second * scatsigmas[scatno].second);
5808  scatno++;
5809  }
5810 
5811  for (int measno = nmeas - nbrem; measno < nmeas; measno++) {
5812  for (int k = 4; k < nfitpars; k++) {
5813  if (k == 5) {
5814  k = nperpars + scatpars;
5815  }
5816 
5817  for (int l = k; l < nfitpars; l++) {
5818  if (l == 5) {
5819  l = nperpars + scatpars;
5820  }
5821  double tmp = a(l, k) + weight_deriv(measno, k) * weight_deriv(measno, l);
5822  a.fillSymmetric(l, k, tmp);
5823  }
5824  }
5825  }
5826  }
5827 
5828  unsigned int scatno = 0;
5829  bool weightchanged = false;
5830 
5831  for (std::unique_ptr<GXFTrackState> & thisstate : trajectory.trackStates()) {
5832  GXFMaterialEffects *meff = thisstate->materialEffects();
5833 
5834  if (meff != nullptr) {
5835  const PlaneSurface *plsurf = nullptr;
5836 
5837  if (thisstate->associatedSurface().type() == Trk::SurfaceType::Plane)
5838  plsurf = static_cast < const PlaneSurface *>(&thisstate->associatedSurface());
5839  if (meff->deltaE() == 0 || ((trajectory.prefit() == 0) && (plsurf != nullptr))) {
5840  weightchanged = true;
5841 
5842  if (a.cols() != nfitpars) {
5843  ATH_MSG_ERROR("Your assumption is wrong!!!!");
5844  }
5845 
5846  int scatNoIndex = 2 * scatno + nperpars;
5847 
5848  if (trajectory.prefit() == 0) {
5849  if (thisstate->materialEffects()->sigmaDeltaPhi() != 0) {
5850  if (scatno >= cache.m_phiweight.size()) {
5851  std::stringstream message;
5852  message << "scatno is out of range " << scatno << " !< " << cache.m_phiweight.size();
5853  throw std::range_error(message.str());
5854  }
5855 
5856  if (!doderiv) {
5857  a(scatNoIndex, scatNoIndex) /= cache.m_phiweight[scatno];
5858  }
5859 
5860  if (it == 0) {
5861  cache.m_phiweight[scatno] = 1.00000001;
5862  } else if (it == 1) {
5863  cache.m_phiweight[scatno] = 1.0000001;
5864  } else if (it <= 3) {
5865  cache.m_phiweight[scatno] = 1.0001;
5866  } else if (it <= 6) {
5867  cache.m_phiweight[scatno] = 1.01;
5868  } else {
5869  cache.m_phiweight[scatno] = 1.1;
5870  }
5871 
5872  a(scatNoIndex, scatNoIndex) *= cache.m_phiweight[scatno];
5873  }
5874  }
5875 
5876  else if (trajectory.prefit() >= 2) {
5877  if (newredchi2 > oldredchi2 - 1 && newredchi2 < oldredchi2) {
5878  a(scatNoIndex, scatNoIndex) *= 1.0001;
5879  a(scatNoIndex + 1, scatNoIndex + 1) *= 1.0001;
5880  } else if (newredchi2 > oldredchi2 - 25 && newredchi2 < oldredchi2) {
5881  a(scatNoIndex, scatNoIndex) *= 1.001;
5882  a(scatNoIndex + 1, scatNoIndex + 1) *= 1.0001;
5883  } else {
5884  a(scatNoIndex, scatNoIndex) *= 1.1;
5885  a(scatNoIndex + 1, scatNoIndex + 1) *= 1.001;
5886  }
5887  }
5888  }
5889 
5890  if (
5891  thisstate->materialEffects()->sigmaDeltaPhi() != 0 &&
5892  ((trajectory.prefit() == 0) || thisstate->materialEffects()->deltaE() == 0)
5893  ) {
5894  scatno++;
5895  }
5896  }
5897  }
5898 
5899  if (
5900  (trajectory.prefit() == 2) &&
5901  doderiv &&
5902  trajectory.numberOfBrems() > 0 &&
5903  (newredchi2 < oldredchi2 - 25 || newredchi2 > oldredchi2)
5904  ) {
5905  a(4, 4) *= 1.001;
5906  }
5907 
5908  if (doderiv || weightchanged) {
5909  lu = a;
5910  }
5911 
5912  if (trajectory.converged()) {
5913  if ((trajectory.prefit() == 0) && nsihits + ntrthits != nhits) {
5914  unsigned int scatno = 0;
5915 
5916  if (a.cols() != nfitpars) {
5917  ATH_MSG_ERROR("Your assumption is wrong!!!!");
5918  }
5919 
5920  for (std::unique_ptr<GXFTrackState> & thisstate : trajectory.trackStates()) {
5921  if ((thisstate->materialEffects() != nullptr) && thisstate->materialEffects()->sigmaDeltaPhi() != 0) {
5922  if (scatno >= cache.m_phiweight.size()) {
5923  std::stringstream message;
5924  message << "scatno is out of range " << scatno << " !< " << cache.m_phiweight.size();
5925  throw std::range_error(message.str());
5926  }
5927 
5928  const PlaneSurface *plsurf = nullptr;
5929 
5930  if (thisstate->associatedSurface().type() == Trk::SurfaceType::Plane)
5931  plsurf = static_cast<const PlaneSurface *>(&thisstate->associatedSurface());
5932 
5933  if (thisstate->materialEffects()->deltaE() == 0 || (plsurf != nullptr)) {
5934  int scatNoIndex = 2 * scatno + nperpars;
5935  a(scatNoIndex, scatNoIndex) /= cache.m_phiweight[scatno];
5936  cache.m_phiweight[scatno] = 1;
5937  }
5938 
5939  if (thisstate->materialEffects()->sigmaDeltaPhi() != 0) {
5940  scatno++;
5941  }
5942  }
5943  }
5944  lu = a;
5945  }
5947  }
5948 
5949  if (
5950  !m_redoderivs &&
5951  it < 5 &&
5952  (newredchi2 < 2 || (newredchi2 < oldredchi2 && newredchi2 > oldredchi2 - .5)) &&
5953  (trajectory.prefit() == 0)
5954  ) {
5955  doderiv = false;
5956  }
5957 
5959  }
5960 
5962  GXFTrajectory & trajectory,
5963  Amg::VectorX & b,
5964  const Amg::SymMatrixX & lu_m
5965  ) const {
5966  ATH_MSG_DEBUG("UpdateFitParameters");
5967 
5968  const TrackParameters *refpar = trajectory.referenceParameters();
5969  double d0 = refpar->parameters()[Trk::d0];
5970  double z0 = refpar->parameters()[Trk::z0];
5971  double phi = refpar->parameters()[Trk::phi0];
5972  double theta = refpar->parameters()[Trk::theta];
5973  double qoverp = refpar->parameters()[Trk::qOverP];
5974  int nscat = trajectory.numberOfScatterers();
5975  int nbrem = trajectory.numberOfBrems();
5976  int nperparams = trajectory.numberOfPerigeeParameters();
5977 
5978  Eigen::LLT<Eigen::MatrixXd> llt(lu_m);
5980 
5981  if (llt.info() == Eigen::Success) {
5982  result = llt.solve(b);
5983  } else {
5984  result = Eigen::VectorXd::Zero(b.size());
5985  }
5986 
5987  if (trajectory.numberOfPerigeeParameters() > 0) {
5988  d0 += result[0];
5989  z0 += result[1];
5990  phi += result[2];
5991  theta += result[3];
5992  qoverp = (trajectory.m_straightline) ? 0 : .001 * result[4] + qoverp;
5993  }
5994 
5995  if (!correctAngles(phi, theta)) {
5996  ATH_MSG_DEBUG("angles out of range: " << theta << " " << phi);
5997  ATH_MSG_DEBUG("Fit failed");
5999  }
6000 
6001  std::vector < std::pair < double, double >>&scatangles = trajectory.scatteringAngles();
6002  std::vector < double >&delta_ps = trajectory.brems();
6003 
6004  for (int i = 0; i < nscat; i++) {
6005  scatangles[i].first += result[2 * i + nperparams];
6006  scatangles[i].second += result[2 * i + nperparams + 1];
6007  }
6008 
6009  for (int i = 0; i < nbrem; i++) {
6010  delta_ps[i] += result[nperparams + 2 * nscat + i];
6011  }
6012 
6013  std::unique_ptr<const TrackParameters> newper(
6015  d0, z0, phi, theta, qoverp, std::nullopt
6016  )
6017  );
6018 
6019  trajectory.setReferenceParameters(std::move(newper));
6020  trajectory.setScatteringAngles(scatangles);
6021  trajectory.setBrems(delta_ps);
6022 
6024  }
6025 
6027  GXFTrajectory & trajectory,
6028  Amg::SymMatrixX & a,
6029  Amg::VectorX & b
6030  ) const{
6031  if ( trajectory.numberOfSiliconHits() == 0) {
6032  return;
6033  }
6034 
6036  return;
6037  }
6038 
6039  const EventContext &evtctx = Gaudi::Hive::currentContext();
6040 
6042  if (!splitProbContainer.isValid()) {
6043  ATH_MSG_FATAL("Failed to get cluster splitting probability container " << m_clusterSplitProbContainer);
6044  }
6045 
6046  std::vector<std::unique_ptr<GXFTrackState>> & states = trajectory.trackStates();
6047  Amg::VectorX & res = trajectory.residuals();
6048  Amg::VectorX & err = trajectory.errors();
6049  Amg::MatrixX & weightderiv = trajectory.weightedResidualDerivatives();
6050  int nfitpars = trajectory.numberOfFitParameters();
6051 
6052  int measno = 0;
6053  for (size_t stateno = 0; stateno < states.size(); stateno++) {
6054 
6055  // Increment the measurement counter everytime we have crossed a measurement/outlier surface
6056  if ( stateno > 0 && ( states[stateno-1]->getStateType(TrackStateOnSurface::Measurement) ||
6057  states[stateno-1]->getStateType(TrackStateOnSurface::Outlier) ) ) {
6058  measno += states[stateno-1]->numberOfMeasuredParameters();
6059  }
6060 
6061  std::unique_ptr<GXFTrackState> & state = states[stateno];
6062  if (!state->getStateType(TrackStateOnSurface::Measurement)) {
6063  continue;
6064  }
6065 
6066  TrackState::MeasurementType hittype = state->measurementType();
6067  if (hittype != TrackState::Pixel) {
6068  continue;
6069  }
6070 
6071  const PrepRawData *prd{};
6072  if (const auto *const pMeas = state->measurement(); pMeas->type(Trk::MeasurementBaseType::RIO_OnTrack)){
6073  const auto *const rot = static_cast<const RIO_OnTrack *>(pMeas);
6074  prd = rot->prepRawData();
6075  }
6076 
6077  if(!prd)
6078  continue;
6079 
6080  if(!prd->type(Trk::PrepRawDataType::PixelCluster)){
6081  continue;
6082  }
6083  const InDet::PixelCluster* pixelCluster = static_cast<const InDet::PixelCluster*> ( prd );
6084  const auto &splitProb = splitProbContainer->splitProbability(pixelCluster);
6085  if (!splitProb.isSplit()) {
6086  ATH_MSG_DEBUG( "Pixel cluster is not split so no need to update" );
6087  continue;
6088  }
6089 
6090  std::unique_ptr < const RIO_OnTrack > newrot;
6091  double *olderror = state->measurementErrors();
6092  const TrackParameters *trackpars = state->trackParameters();
6093 
6094  double newerror[5] = {-1,-1,-1,-1,-1};
6095  double newres[2] = {-1,-1};
6096 
6097  newrot.reset(m_ROTcreator->correct(*prd, *trackpars));
6098 
6099  if(!newrot)
6100  continue;
6101 
6102  const Amg::MatrixX & covmat = newrot->localCovariance();
6103 
6104  newerror[0] = std::sqrt(covmat(0, 0));
6105  newres[0] = newrot->localParameters()[Trk::locX] - trackpars->parameters()[Trk::locX];
6106  newerror[1] = std::sqrt(covmat(1, 1));
6107  newres[1] = newrot->localParameters()[Trk::locY] - trackpars->parameters()[Trk::locY];
6108 
6109  if (a.cols() != nfitpars) {
6110  ATH_MSG_ERROR("Your assumption is wrong!!!!");
6111  }
6112 
6113  //loop over both measurements -- treated as uncorrelated
6114  for( int k =0; k<2; k++ ){
6115  double oldres = res[measno+k];
6116  res[measno+k] = newres[k];
6117  err[measno+k] = newerror[k];
6118 
6119  for (int i = 0; i < nfitpars; i++) {
6120  if (weightderiv(measno+k, i) == 0) {
6121  continue;
6122  }
6123 
6124  b[i] -= weightderiv(measno+k, i) * (oldres / olderror[k] - (newres[k] * olderror[k]) / (newerror[k] * newerror[k]));
6125 
6126  for (int j = i; j < nfitpars; j++) {
6127  a.fillSymmetric(
6128  i, j,
6129  a(i, j) + (
6130  weightderiv(measno+k, i) *
6131  weightderiv(measno+k, j) *
6132  ((olderror[k] * olderror[k]) / (newerror[k] * newerror[k]) - 1)
6133  )
6134  );
6135  }
6136  weightderiv(measno+k, i) *= olderror[k] / newerror[k];
6137  }
6138  }
6139 
6140  state->setMeasurement(std::move(newrot));
6141  state->setMeasurementErrors(newerror);
6142 
6143  }// end for
6144  }
6145 
6146 
6148  Cache & cache,
6149  GXFTrajectory & trajectory,
6150  Amg::SymMatrixX & a,
6151  Amg::VectorX & b,
6152  Amg::SymMatrixX & lu_m,
6153  bool runOutlier,
6154  bool trtrecal,
6155  int it
6156  ) const {
6157  double scalefactor = m_scalefactor;
6158 
6159  if (it == 1 && trajectory.numberOfSiliconHits() + trajectory.numberOfTRTHits() == trajectory.numberOfHits()) {
6160  scalefactor *= 2;
6161  }
6162 
6163  std::vector<std::unique_ptr<GXFTrackState>> & states = trajectory.trackStates();
6164  Amg::VectorX & res = trajectory.residuals();
6165  Amg::VectorX & err = trajectory.errors();
6166  Amg::MatrixX & weightderiv = trajectory.weightedResidualDerivatives();
6167  int nfitpars = trajectory.numberOfFitParameters();
6168 
6169  if (a.cols() != nfitpars) {
6170  ATH_MSG_ERROR("Your assumption is wrong!!!!");
6171  }
6172 
6173  int nperpars = trajectory.numberOfPerigeeParameters();
6174  int nscats = trajectory.numberOfScatterers();
6175  int hitno = 0;
6176  int measno = 0;
6177  bool outlierremoved = false;
6178  bool hitrecalibrated = false;
6179 
6180  for (int stateno = 0; stateno < (int) states.size(); stateno++) {
6181  std::unique_ptr<GXFTrackState> & state = states[stateno];
6182 
6183  if (state->getStateType(TrackStateOnSurface::Measurement)) { // Hit is not (yet) an outlier
6184  TrackState::MeasurementType hittype = state->measurementType();
6185 
6186  if (hittype == TrackState::TRT) {
6187  if (
6188  runOutlier &&
6189  std::abs(state->trackParameters()->parameters()[Trk::driftRadius]) > 1.05 * state->associatedSurface().bounds().r()
6190  ) {
6191  ATH_MSG_DEBUG("Removing TRT hit #" << hitno);
6192 
6193  trajectory.setOutlier(stateno);
6194  outlierremoved = true;
6195 
6196  double *errors = state->measurementErrors();
6197  double olderror = errors[0];
6198 
6199  trajectory.updateTRTHitCount(stateno, olderror);
6200 
6201  for (int i = 0; i < nfitpars; i++) {
6202  if (weightderiv(measno, i) == 0) {
6203  continue;
6204  }
6205 
6206  b[i] -= res[measno] * weightderiv(measno, i) / olderror;
6207 
6208  for (int j = i; j < nfitpars; j++) {
6209  a.fillSymmetric(
6210  i, j,
6211  a(i, j) - weightderiv(measno, i) * weightderiv(measno, j)
6212  );
6213  }
6214  weightderiv(measno, i) = 0;
6215  }
6216 
6217  res[measno] = 0;
6218  } else if (trtrecal) {
6219  double *errors = state->measurementErrors();
6220  double olderror = errors[0];
6221  const Trk::RIO_OnTrack * oldrot{};
6222  const auto *const thisMeasurement{state->measurement()};
6223  if ( not thisMeasurement->type(Trk::MeasurementBaseType::RIO_OnTrack)){
6224  continue;
6225  }
6226  oldrot = static_cast<const Trk::RIO_OnTrack *>(thisMeasurement);
6227  double oldradius = oldrot->localParameters()[Trk::driftRadius];
6228  if (oldrot->prepRawData() != nullptr) {
6229  double dcradius = oldrot->prepRawData()->localPosition()[Trk::driftRadius];
6230  double dcerror = std::sqrt(oldrot->prepRawData()->localCovariance()(Trk::driftRadius, Trk::driftRadius));
6231  double trackradius = state->trackParameters()->parameters()[Trk::driftRadius];
6232 
6233  std::unique_ptr<const Trk::RIO_OnTrack> newrot = nullptr;
6234  double distance = std::abs(std::abs(trackradius) - dcradius);
6235 
6236  if (distance < scalefactor * dcerror && (olderror > 1. || trackradius * oldradius < 0)) {
6237  newrot.reset(m_ROTcreator->correct(*oldrot->prepRawData(), *state->trackParameters()));
6238  } else if (distance > scalefactor * dcerror && olderror < 1.) {
6239  newrot.reset(m_broadROTcreator->correct(*oldrot->prepRawData(), *state->trackParameters()));
6240  }
6241 
6242  if (newrot != nullptr) {
6243  ATH_MSG_DEBUG("Recalibrating TRT hit #" << hitno);
6244  hitrecalibrated = true;
6245  double newradius = newrot->localParameters()[Trk::driftRadius];
6246  double newerror = std::sqrt(newrot->localCovariance()(Trk::driftRadius, Trk::driftRadius));
6247 
6248  if ((measno < 0) or (measno >= (int) res.size())) {
6249  throw std::runtime_error(
6250  "'res' array index out of range in TrkGlobalChi2Fitter/src/GlobalChi2Fitter.cxx:" + std::to_string(__LINE__)
6251  );
6252  }
6253 
6254  double oldres = res[measno];
6255  double newres = newradius - state->trackParameters()->parameters()[Trk::driftRadius];
6256  errors[0] = newerror;
6257  state->setMeasurement(std::move(newrot));
6258 
6259  trajectory.updateTRTHitCount(stateno, olderror);
6260 
6261  for (int i = 0; i < nfitpars; i++) {
6262  if (weightderiv(measno, i) == 0) {
6263  continue;
6264  }
6265 
6266  b[i] -= weightderiv(measno, i) * (oldres / olderror - (newres * olderror) / (newerror * newerror));
6267 
6268  for (int j = i; j < nfitpars; j++) {
6269  double weight = 1;
6270 
6271  if (
6272  !cache.m_phiweight.empty() &&
6273  i == j &&
6274  i >= nperpars &&
6275  i < nperpars + 2 * nscats &&
6276  (i - nperpars) % 2 == 0
6277  ) {
6278  weight = cache.m_phiweight[(i - nperpars) / 2];
6279  }
6280 
6281  a.fillSymmetric(
6282  i, j,
6283  a(i, j) + weightderiv(measno, i) * weightderiv(measno, j) * ((olderror * olderror) / (newerror * newerror) - 1) * weight
6284  );
6285  }
6286  weightderiv(measno, i) *= olderror / newerror;
6287  }
6288 
6289  res[measno] = newres;
6290  err[measno] = newerror;
6291  }
6292  }
6293  }
6294  }
6295  }
6296 
6297  if (state->getStateType(TrackStateOnSurface::Measurement) || state->getStateType(TrackStateOnSurface::Outlier)) {
6298  hitno++;
6299  measno += state->numberOfMeasuredParameters();
6300  }
6301  }
6302 
6303  if (trajectory.nDOF() < 0) {
6306  }
6307 
6308  if (outlierremoved || hitrecalibrated) {
6309  lu_m = a;
6310  trajectory.setConverged(false);
6311 
6312  cache.m_miniter = it + 2;
6313  }
6314  }
6315 
6317  const EventContext& ctx,
6318  Cache & cache,
6319  GXFTrajectory &trajectory,
6320  Amg::SymMatrixX & a,
6321  Amg::SymMatrixX &fullcov,
6322  Amg::VectorX & b,
6323  bool runoutlier
6324  ) const {
6325  bool trackok = false;
6326  GXFTrajectory *oldtrajectory = &trajectory;
6327  std::unique_ptr < GXFTrajectory > cleanup_oldtrajectory;
6328  GXFTrajectory *newtrajectory = nullptr;
6329  std::unique_ptr < GXFTrajectory > cleanup_newtrajectory;
6330 
6331  // the oldtrajectory will be returned, so in case newtrajectory==oldtrajectory
6332  // the cleanup_newtrajectory == NULL and cleanup_oldtrajectory = oldtrajectory, otherwise
6333  // cleanup_newtrajectory will destroy the object oldtrajectory is pointing to.
6334 
6335  while (!trackok && oldtrajectory->nDOF() > 0) {
6336  trackok = true;
6337  std::vector<std::unique_ptr<GXFTrackState>> & states = oldtrajectory->trackStates();
6338  Amg::VectorX & res = oldtrajectory->residuals();
6339  Amg::VectorX & err = oldtrajectory->errors();
6340  Amg::MatrixX & weightderiv = oldtrajectory->weightedResidualDerivatives();
6341  int nfitpars = oldtrajectory->numberOfFitParameters();
6342  int nhits = oldtrajectory->numberOfHits();
6343  int nsihits = oldtrajectory->numberOfSiliconHits();
6344 
6345  if (nhits != nsihits) {
6346  return &trajectory;
6347  }
6348 
6349  double maxsipull = -1;
6350  int hitno = 0;
6351  int hitno_maxsipull = -1;
6352  int measno_maxsipull = -1;
6353  int stateno_maxsipull = 0;
6354  GXFTrackState *state_maxsipull = nullptr;
6355  int measno = 0;
6356  int n3sigma = 0;
6357  double cut = m_outlcut;
6358  double cut2 = m_outlcut - 1.;
6359  int noutl = oldtrajectory->numberOfOutliers();
6360 
6361  if (noutl > 0) {
6362  cut2 = cut - 1.25;
6363  }
6364 
6365  for (int stateno = 0; stateno < (int) states.size(); stateno++) {
6366  std::unique_ptr<GXFTrackState> & state = states[stateno];
6367 
6368  if (state->getStateType(TrackStateOnSurface::Measurement)) {
6369  TrackState::MeasurementType hittype = state->measurementType();
6370 
6371  if ((hittype == TrackState::Pixel || hittype == TrackState::SCT) && state->hasTrackCovariance()) {
6372  double *errors = state->measurementErrors();
6373  AmgSymMatrix(5) & trackcov = state->trackCovariance();
6374  const Amg::MatrixX & hitcov = state->measurement()->localCovariance();
6375  double sinstereo = state->sinStereo();
6376  double cosstereo = (sinstereo == 0) ? 1 : std::sqrt(1 - sinstereo * sinstereo);
6377  double weight1 = -1;
6378 
6379  if (hitcov(0, 0) > trackcov(0, 0)) {
6380  if (sinstereo == 0) {
6381  weight1 = errors[0] * errors[0] - trackcov(0, 0);
6382  } else {
6383  weight1 = errors[0] * errors[0] - (
6384  trackcov(0, 0) * cosstereo * cosstereo + 2 *
6385  trackcov(1, 0) * cosstereo * sinstereo + trackcov(1, 1) * sinstereo * sinstereo
6386  );
6387  }
6388  }
6389 
6390  double weight2 = (
6391  hittype == TrackState::Pixel && hitcov(1, 1) > trackcov(1, 1) ?
6392  errors[1] * errors[1] - trackcov(1, 1) :
6393  -1
6394  );
6395 
6396  double sipull1 = weight1 > 0 ? std::abs(res[measno] / std::sqrt(weight1)) : -1;
6397  double sipull2 = (
6398  hittype == TrackState::Pixel && weight2 > 0 ?
6399  std::abs(res[measno + 1] / std::sqrt(weight2)) :
6400  -1
6401  );
6402  sipull1 = std::max(sipull1, sipull2);
6403 
6404  if (sipull1 > maxsipull) {
6405  maxsipull = sipull1;
6406  measno_maxsipull = measno;
6407  state_maxsipull = state.get();
6408  stateno_maxsipull = stateno;
6409  hitno_maxsipull = hitno;
6410  }
6411 
6412  if (hittype == TrackState::Pixel && sipull1 > cut2) {
6413  n3sigma++;
6414  }
6415  }
6416  }
6417 
6418  if (state->getStateType(TrackStateOnSurface::Measurement) || state->getStateType(TrackStateOnSurface::Outlier)) {
6419  hitno++;
6420  measno += state->numberOfMeasuredParameters();
6421  }
6422  }
6423 
6424  double maxpull = maxsipull;
6425 
6426  ATH_MSG_DEBUG(" maxsipull: " << maxsipull << " hitno_maxsipull: " <<
6427  hitno_maxsipull << " n3sigma: " << n3sigma << " cut: " << cut << " cut2: " << cut2);
6428 
6429  Amg::SymMatrixX * newap = &a;
6430  Amg::VectorX * newbp = &b;
6431  Amg::SymMatrixX newa(nfitpars, nfitpars);
6432  Amg::VectorX newb(nfitpars);
6433 
6434  if (
6435  maxpull > 2 &&
6436  oldtrajectory->chi2() / oldtrajectory->nDOF() > .25 * m_chi2cut
6437  ) {
6438  state_maxsipull = oldtrajectory->trackStates()[stateno_maxsipull].get();
6439  const PrepRawData *prd{};
6440  if (const auto *const pMeas = state_maxsipull->measurement(); pMeas->type(Trk::MeasurementBaseType::RIO_OnTrack)){
6441  const auto *const rot = static_cast<const RIO_OnTrack *>(pMeas);
6442  prd = rot->prepRawData();
6443  }
6444  std::unique_ptr < const RIO_OnTrack > broadrot;
6445  double *olderror = state_maxsipull->measurementErrors();
6446  TrackState::MeasurementType hittype_maxsipull = state_maxsipull->measurementType();
6447  const TrackParameters *trackpar_maxsipull = state_maxsipull->trackParameters();
6448 
6449  Amg::VectorX parameterVector = trackpar_maxsipull->parameters();
6450  std::unique_ptr<const TrackParameters> trackparForCorrect(
6451  trackpar_maxsipull->associatedSurface().createUniqueTrackParameters(
6452  parameterVector[Trk::loc1],
6453  parameterVector[Trk::loc2],
6454  parameterVector[Trk::phi],
6455  parameterVector[Trk::theta],
6456  parameterVector[Trk::qOverP],
6457  state_maxsipull->hasTrackCovariance()
6458  ? std::optional<AmgSymMatrix(5)>(
6459  state_maxsipull->trackCovariance())
6460  : std::nullopt));
6461 
6462  double newerror[5];
6463  newerror[0] = newerror[1] = newerror[2] = newerror[3] = newerror[4] = -1;
6464  double newpull = -1;
6465  double newpull1 = -1;
6466  double newpull2 = -1;
6467  double newres1 = -1;
6468  double newres2 = -1;
6469  double newsinstereo = 0;
6470 
6471  if (
6472  (prd != nullptr) &&
6473  !state_maxsipull->isRecalibrated() &&
6474  maxpull > 2.5 &&
6475  oldtrajectory->chi2() / trajectory.nDOF() > .3 * m_chi2cut &&
6476  cache.m_sirecal
6477  ) {
6478  broadrot.reset(m_broadROTcreator->correct(*prd, *trackparForCorrect));
6479  }
6480 
6481  if (broadrot) {
6482  const Amg::MatrixX & covmat = broadrot->localCovariance();
6483  newerror[0] = std::sqrt(covmat(0, 0));
6484 
6485  if (state_maxsipull->sinStereo() != 0) {
6486  double v0 = 0.5 * (
6487  covmat(0, 0) + covmat(1, 1) -
6488  std::sqrt(
6489  (covmat(0, 0) + covmat(1, 1)) * (covmat(0, 0) + covmat(1, 1)) -
6490  4 * (covmat(0, 0) * covmat(1, 1) - covmat(0, 1) * covmat(0, 1))
6491  )
6492  );
6493 
6494  double v1 = 0.5 * (
6495  covmat(0, 0) + covmat(1, 1) +
6496  std::sqrt(
6497  (covmat(0, 0) + covmat(1, 1)) * (covmat(0, 0) + covmat(1, 1)) -
6498  4 * (covmat(0, 0) * covmat(1, 1) - covmat(0, 1) * covmat(0, 1))
6499  )
6500  );
6501 
6502  newsinstereo = std::sin(0.5 * std::asin(2 * covmat(0, 1) / (v0 - v1)));
6503  newerror[0] = std::sqrt(v0);
6504  }
6505 
6506  double cosstereo = (newsinstereo == 0) ? 1. : std::sqrt(1 - newsinstereo * newsinstereo);
6507 
6508  if (cosstereo != 1.) {
6509  newres1 = (
6510  cosstereo * (broadrot->localParameters()[Trk::locX] - trackpar_maxsipull->parameters()[Trk::locX]) +
6511  newsinstereo * (broadrot->localParameters()[Trk::locY] - trackpar_maxsipull->parameters()[Trk::locY])
6512  );
6513  } else {
6514  newres1 = broadrot->localParameters()[Trk::locX] - trackpar_maxsipull->parameters()[Trk::locX];
6515  }
6516 
6517  if (newerror[0] == 0.0) {
6518  ATH_MSG_WARNING("Measurement error is zero or negative, treating as outlier");
6519  newpull1 = 9999.;
6520  }
6521  else {
6522  newpull1 = std::abs(newres1 / newerror[0]);
6523  }
6524 
6525  if (hittype_maxsipull == TrackState::Pixel) {
6526  newerror[1] = std::sqrt(covmat(1, 1));
6527  newres2 = broadrot->localParameters()[Trk::locY] - trackpar_maxsipull->parameters()[Trk::locY];
6528  newpull2 = std::abs(newres2 / newerror[1]);
6529  }
6530 
6531  newpull = std::max(newpull1, newpull2);
6532  }
6533 
6534  if (
6535  broadrot &&
6536  newpull < m_outlcut &&
6537  (newerror[0] > 1.5 * olderror[0] || newerror[1] > 1.5 * std::abs(olderror[1]))
6538  ) {
6539  if ((measno_maxsipull < 0) or(measno_maxsipull >= (int) res.size())) {
6540  throw std::runtime_error(
6541  "'res' array index out of range in TrkGlobalChi2Fitter/src/GlobalChi2Fitter.cxx:" + std::to_string(__LINE__)
6542  );
6543  }
6544 
6545  trackok = false;
6546  newtrajectory = oldtrajectory;
6547 
6548  if (a.cols() != nfitpars) {
6549  ATH_MSG_ERROR("Your assumption is wrong!!!!");
6550  }
6551 
6552  double oldres1 = res[measno_maxsipull];
6553  res[measno_maxsipull] = newres1;
6554  err[measno_maxsipull] = newerror[0];
6555 
6556  for (int i = 0; i < nfitpars; i++) {
6557  if (weightderiv(measno_maxsipull, i) == 0) {
6558  continue;
6559  }
6560 
6561  b[i] -= weightderiv(measno_maxsipull, i) * (oldres1 / olderror[0] - (newres1 * olderror[0]) / (newerror[0] * newerror[0]));
6562 
6563  for (int j = i; j < nfitpars; j++) {
6564  a.fillSymmetric(
6565  i, j,
6566  a(i, j) + (
6567  weightderiv(measno_maxsipull, i) *
6568  weightderiv(measno_maxsipull, j) *
6569  ((olderror[0] * olderror[0]) / (newerror[0] * newerror[0]) - 1)
6570  )
6571  );
6572  }
6573  weightderiv(measno_maxsipull, i) *= olderror[0] / newerror[0];
6574  }
6575 
6576  if (hittype_maxsipull == TrackState::Pixel) {
6577  double oldres2 = res[measno_maxsipull + 1];
6578  res[measno_maxsipull + 1] = newres2;
6579  err[measno_maxsipull + 1] = newerror[1];
6580 
6581  for (int i = 0; i < nfitpars; i++) {
6582  if (weightderiv(measno_maxsipull + 1, i) == 0) {
6583  continue;
6584  }
6585 
6586  b[i] -= weightderiv(measno_maxsipull + 1, i) * (oldres2 / olderror[1] - (newres2 * olderror[1]) / (newerror[1] * newerror[1]));
6587 
6588  for (int j = i; j < nfitpars; j++) {
6589  a.fillSymmetric(
6590  i, j,
6591  a(i, j) + (
6592  weightderiv(measno_maxsipull + 1, i) *
6593  weightderiv(measno_maxsipull + 1, j) *
6594  ((olderror[1] * olderror[1]) / (newerror[1] * newerror[1]) - 1)
6595  )
6596  );
6597  }
6598 
6599  weightderiv(measno_maxsipull + 1, i) *= olderror[1] / newerror[1];
6600  }
6601  }
6602 
6603  ATH_MSG_DEBUG(
6604  "Recovering outlier, hitno=" << hitno_maxsipull << " measno=" <<
6605  measno_maxsipull << " pull=" << maxsipull << " olderror_0=" <<
6606  olderror[0] << " newerror_0=" << newerror[0] << " olderror_1=" <<
6607  olderror[1] << " newerror_1=" << newerror[1]
6608  );
6609 
6610  state_maxsipull->setMeasurement(std::move(broadrot));
6611  state_maxsipull->setSinStereo(newsinstereo);
6612  state_maxsipull->setMeasurementErrors(newerror);
6613  } else if (
6614  (
6615  (
6616  ((n3sigma < 2 && maxsipull > cut2 && maxsipull < cut) || n3sigma > 1) &&
6617  (oldtrajectory->chi2() / oldtrajectory->nDOF() > .3 * m_chi2cut || noutl > 1)
6618  ) ||
6619  maxsipull > cut
6620  ) &&
6621  (oldtrajectory->nDOF() > 1 || hittype_maxsipull == TrackState::SCT) &&
6622  runoutlier
6623  ) {
6624  trackok = false;
6625  ATH_MSG_DEBUG(
6626  "Removing outlier, hitno=" << hitno_maxsipull << ", measno=" <<
6627  measno_maxsipull << " pull=" << maxsipull
6628  );
6629 
6630  newa = a;
6631  newb = b;
6632  newap = &newa;
6633  newbp = &newb;
6634  cleanup_newtrajectory = std::make_unique<GXFTrajectory>(*oldtrajectory);
6635  newtrajectory = cleanup_newtrajectory.get();
6636 
6637  if (newa.cols() != nfitpars) {
6638  ATH_MSG_ERROR("Your assumption is wrong!!!!");
6639  }
6640 
6641  Amg::VectorX & newres = newtrajectory->residuals();
6642  Amg::MatrixX & newweightderiv = newtrajectory->weightedResidualDerivatives();
6643  if ((measno_maxsipull < 0) or(measno_maxsipull >= (int) res.size())) {
6644  throw std::runtime_error(
6645  "'res' array index out of range in TrkGlobalChi2Fitter/src/GlobalChi2Fitter.cxx:" + std::to_string(__LINE__)
6646  );
6647  }
6648 
6649  double oldres1 = res[measno_maxsipull];
6650  newres[measno_maxsipull] = 0;
6651 
6652  for (int i = 0; i < nfitpars; i++) {
6653  if (weightderiv(measno_maxsipull, i) == 0) {
6654  continue;
6655  }
6656 
6657  newb[i] -= weightderiv(measno_maxsipull, i) * oldres1 / olderror[0];
6658 
6659  for (int j = i; j < nfitpars; j++) {
6660  newa.fillSymmetric(
6661  i, j,
6662  newa(i, j) - (
6663  weightderiv(measno_maxsipull, i) *
6664  weightderiv(measno_maxsipull, j)
6665  )
6666  );
6667  }
6668  newweightderiv(measno_maxsipull, i) = 0;
6669  }
6670 
6671  if (hittype_maxsipull == TrackState::Pixel) {
6672  double oldres2 = res[measno_maxsipull + 1];
6673  newres[measno_maxsipull + 1] = 0;
6674 
6675  for (int i = 0; i < nfitpars; i++) {
6676  if (weightderiv(measno_maxsipull + 1, i) == 0) {
6677  continue;
6678  }
6679 
6680  newb[i] -= weightderiv(measno_maxsipull + 1, i) * oldres2 / olderror[1];
6681 
6682  for (int j = i; j < nfitpars; j++) {
6683  if (weightderiv(measno_maxsipull + 1, j) == 0) {
6684  continue;
6685  }
6686 
6687  newa.fillSymmetric(
6688  i, j,
6689  newa(i, j) - (
6690  weightderiv(measno_maxsipull + 1, i) *
6691  weightderiv(measno_maxsipull + 1, j)
6692  )
6693  );
6694  }
6695  newweightderiv(measno_maxsipull + 1, i) = 0;
6696  }
6697  }
6698 
6699  newtrajectory->setOutlier(stateno_maxsipull);
6700  }
6701  }
6702 
6703  if (!trackok) {
6704  Amg::SymMatrixX lu_m = *newap;
6705  newtrajectory->setConverged(false);
6706  bool doderiv = m_redoderivs;
6707  cache.m_fittercode = updateFitParameters(*newtrajectory, *newbp, lu_m);
6708  if (cache.m_fittercode != FitterStatusCode::Success) {
6710  return nullptr;
6711  }
6712 
6713  for (int it = 0; it < m_maxit; ++it) {
6714  if (it == m_maxit - 1) {
6715  ATH_MSG_DEBUG("Fit did not converge");
6718  return nullptr;
6719  }
6720 
6721  if (!newtrajectory->converged()) {
6722  cache.m_fittercode = runIteration(
6723  ctx, cache, *newtrajectory, it, *newap, *newbp, lu_m, doderiv);
6724 
6725  if (cache.m_fittercode != FitterStatusCode::Success) {
6727  return nullptr;
6728  }
6729 
6730  if (!newtrajectory->converged()) {
6731  cache.m_fittercode = updateFitParameters(*newtrajectory, *newbp, lu_m);
6732  if (cache.m_fittercode != FitterStatusCode::Success) {
6734 
6735  return nullptr;
6736  }
6737  }
6738  } else {
6739  double oldchi2 = oldtrajectory->chi2() / oldtrajectory->nDOF();
6740  double newchi2 = (newtrajectory->nDOF() > 0) ? newtrajectory->chi2() / newtrajectory->nDOF() : 0;
6741  double mindiff = 0;
6742 
6743  if (newtrajectory->nDOF() != oldtrajectory->nDOF() && maxsipull > cut2) {
6744  mindiff = (oldchi2 > .33 * m_chi2cut || noutl > 0) ? .8 : 1.;
6745 
6746  if (noutl == 0 && maxsipull < cut - .5 && oldchi2 < .5 * m_chi2cut) {
6747  mindiff = 2.;
6748  }
6749  }
6750 
6751  if (newchi2 > oldchi2 || (newchi2 > oldchi2 - mindiff && newchi2 > .33 * oldchi2)) {
6752  ATH_MSG_DEBUG("Outlier not confirmed, keeping old trajectory");
6753 
6754  if (oldchi2 > m_chi2cut) {
6757  return nullptr;
6758  }
6759 
6760  (void)cleanup_oldtrajectory.release();
6761  return oldtrajectory;
6762  }
6763  if (oldtrajectory != newtrajectory) {
6764  cleanup_oldtrajectory = std::move(cleanup_newtrajectory);
6765  oldtrajectory = newtrajectory;
6766  a = newa;
6767  b = newb;
6768  }
6769 
6770  // Solve assuming the matrix is SPD.
6771  // Cholesky Decomposition is used
6772  Eigen::LLT < Eigen::MatrixXd > lltOfW(a);
6773  if (lltOfW.info() == Eigen::Success) {
6774  // Solve for x where Wx = I
6775  // this is cheaper than invert as invert makes no assumptions about the
6776  // matrix being symmetric
6777  int ncols = a.cols();
6778  Amg::MatrixX weightInvAMG = Amg::MatrixX::Identity(ncols, ncols);
6779  fullcov = lltOfW.solve(weightInvAMG);
6780  } else {
6781  ATH_MSG_DEBUG("matrix inversion failed!");
6784  return nullptr;
6785  }
6786  break;
6787  }
6788  }
6789  }
6790 
6791  if (!trackok) {
6792  calculateTrackErrors(*oldtrajectory, fullcov, true);
6793  }
6794  }
6795 
6796  if (
6797  oldtrajectory->nDOF() > 0 &&
6798  oldtrajectory->chi2() / oldtrajectory->nDOF() > m_chi2cut &&
6799  runoutlier
6800  ) {
6803  return nullptr;
6804  }
6805 
6806  (void)cleanup_oldtrajectory.release();
6807  return oldtrajectory;
6808  }
6809 
6811  Cache &cache,
6812  GXFTrajectory &oldtrajectory
6813  ) {
6814  Amg::MatrixX & derivs = oldtrajectory.weightedResidualDerivatives();
6815  Amg::VectorX & errors = oldtrajectory.errors();
6816  int nrealmeas = 0;
6817 
6818  for (auto & hit : oldtrajectory.trackStates()) {
6819  if (const auto *pMeas{hit->measurement()};
6820  hit->getStateType(TrackStateOnSurface::Measurement) and (
6823  )
6824  ) {
6825  nrealmeas += hit->numberOfMeasuredParameters();
6826  }
6827  }
6828  cache.m_derivmat.resize(nrealmeas, oldtrajectory.numberOfFitParameters());
6829  cache.m_derivmat.setZero();
6830  int measindex = 0;
6831  int measindex2 = 0;
6832  int nperpars = oldtrajectory.numberOfPerigeeParameters();
6833  int nscat = oldtrajectory.numberOfScatterers();
6834  for (auto & hit : oldtrajectory.trackStates()) {
6835  if (const auto *pMeas{hit->measurement()};
6836  hit->getStateType(TrackStateOnSurface::Measurement) and (
6839  )
6840  ) {
6841  for (int i = measindex; i < measindex + hit->numberOfMeasuredParameters(); i++) {
6842  for (int j = 0; j < oldtrajectory.numberOfFitParameters(); j++) {
6843  cache.m_derivmat(i, j) = derivs(measindex2, j) * errors[measindex2];
6844  if ((j == 4 && !oldtrajectory.m_straightline) || j >= nperpars + 2 * nscat) {
6845  cache.m_derivmat(i, j) *= 1000;
6846  }
6847  }
6848 
6849  measindex2++;
6850  }
6851 
6852  measindex += hit->numberOfMeasuredParameters();
6853  } else if (hit->materialEffects() == nullptr) {
6854  measindex2 += hit->numberOfMeasuredParameters();
6855  }
6856  }
6857  }
6858 
6859  std::unique_ptr<const TrackParameters> GlobalChi2Fitter::makeTrackFindPerigeeParameters(
6860  const EventContext & ctx,
6861  Cache &cache,
6862  GXFTrajectory &oldtrajectory,
6863  const ParticleHypothesis matEffects
6864  ) const {
6865  GXFTrackState *firstmeasstate = nullptr, *lastmeasstate = nullptr;
6866  std::tie(firstmeasstate, lastmeasstate) = oldtrajectory.findFirstLastMeasurement();
6867  std::unique_ptr<const TrackParameters> per(nullptr);
6868 
6869  if (cache.m_acceleration && !m_matupdator.empty()) {
6870  std::unique_ptr<const TrackParameters> prevpar(
6871  firstmeasstate->trackParameters() != nullptr ?
6872  firstmeasstate->trackParameters()->clone() :
6873  nullptr
6874  );
6875  std::vector<std::pair<const Layer *, const Layer *>> & upstreamlayers = oldtrajectory.upstreamMaterialLayers();
6876  bool first = true;
6877 
6878  for (int i = (int)upstreamlayers.size() - 1; i >= 0; i--) {
6879  if (prevpar == nullptr) {
6880  break;
6881  }
6882 
6883  PropDirection propdir = oppositeMomentum;
6884  const Layer *layer = upstreamlayers[i].first;
6885 
6886  if (layer == nullptr) {
6887  layer = upstreamlayers[i].second;
6888  }
6889 
6890  DistanceSolution distsol = layer->surfaceRepresentation().straightLineDistanceEstimate(
6891  prevpar->position(), prevpar->momentum().unit()
6892  );
6893  double distance = getDistance(distsol);
6894 
6895  if (distsol.numberOfSolutions() == 2) {
6896  if (std::abs(distance) < 0.01) {
6897  continue;
6898  }
6899 
6900  if (distsol.first() * distsol.second() < 0 && !first) {
6901  continue;
6902  }
6903  }
6904 
6905  if (first && distance > 0) {
6906  propdir = alongMomentum;
6907  }
6908 
6909  std::unique_ptr<const TrackParameters> layerpar(
6910  m_propagator->propagate(
6911  ctx,
6912  *prevpar,
6913  layer->surfaceRepresentation(),
6914  propdir,
6915  true,
6916  oldtrajectory.m_fieldprop,
6918  )
6919  );
6920 
6921  if (layerpar == nullptr) {
6922  continue;
6923  }
6924 
6925  if (layer->surfaceRepresentation().bounds().inside(layerpar->localPosition())) {
6926  layerpar = m_matupdator->update(layerpar.get(), *layer, oppositeMomentum, matEffects);
6927  }
6928 
6929  prevpar = std::move(layerpar);
6930  first = false;
6931  }
6932 
6933  const Layer *startlayer = firstmeasstate->trackParameters()->associatedSurface().associatedLayer();
6934 
6935  if ((startlayer != nullptr) && (startlayer->layerMaterialProperties() != nullptr)) {
6936  double startfactor = startlayer->layerMaterialProperties()->alongPostFactor();
6937  const Surface & discsurf = startlayer->surfaceRepresentation();
6938 
6939  if (discsurf.type() == Trk::SurfaceType::Disc && discsurf.center().z() * discsurf.normal().z() < 0) {
6940  startfactor = startlayer->layerMaterialProperties()->oppositePostFactor();
6941  }
6942  if (startfactor > 0.5) {
6943  std::unique_ptr<const TrackParameters> updatedpar = m_matupdator->update(
6944  firstmeasstate->trackParameters(), *startlayer, oppositeMomentum, matEffects
6945  );
6946 
6947  if (updatedpar != nullptr) {
6948  firstmeasstate->setTrackParameters(std::move(updatedpar));
6949  }
6950  }
6951  }
6952 
6953  // @TODO Coverity complains about a possible NULL pointer dereferencing in lastmeasstate->...
6954  // Now an exception is thrown if there is no firstmeastate. Thus if the code here is
6955  // reached then there should be a firstmeasstate and a lastmeasstate
6956 
6957  const Layer *endlayer = lastmeasstate->trackParameters()->associatedSurface().associatedLayer();
6958 
6959  if ((endlayer != nullptr) && (endlayer->layerMaterialProperties() != nullptr)) {
6960  double endfactor = endlayer->layerMaterialProperties()->alongPreFactor();
6961  const Surface & discsurf = endlayer->surfaceRepresentation();
6962 
6963  if (discsurf.type() == Trk::SurfaceType::Disc && discsurf.center().z() * discsurf.normal().z() < 0) {
6964  endfactor = endlayer->layerMaterialProperties()->oppositePreFactor();
6965  }
6966 
6967  if (endfactor > 0.5) {
6968  std::unique_ptr<const TrackParameters> updatedpar = m_matupdator->update(
6969  lastmeasstate->trackParameters(), *endlayer, alongMomentum, matEffects
6970  );
6971 
6972  if (updatedpar != nullptr) {
6973  lastmeasstate->setTrackParameters(std::move(updatedpar));
6974  }
6975  }
6976  }
6977 
6978  if (prevpar != nullptr) {
6979  per = m_propagator->propagate(
6980  ctx,
6981  *prevpar,
6982  PerigeeSurface(Amg::Vector3D(0, 0, 0)),
6984  false,
6985  oldtrajectory.m_fieldprop,
6987  );
6988  }
6989 
6990  if (per == nullptr) {
6991  ATH_MSG_DEBUG("Failed to extrapolate to perigee, returning 0");
6994  return nullptr;
6995  }
6996  } else if (cache.m_acceleration && (firstmeasstate->trackParameters() != nullptr)) {
6997  per = m_extrapolator->extrapolate(ctx,
6998  *firstmeasstate->trackParameters(),
6999  PerigeeSurface(Amg::Vector3D(0, 0, 0)),
7001  false,
7002  matEffects);
7003  } else {
7004  per.reset(oldtrajectory.referenceParameters()->clone());
7005  }
7006 
7007  return per;
7008  }
7009 
7010  std::unique_ptr<GXFTrackState>
7012  const EventContext & ctx,
7013  Cache &cache,
7014  GXFTrajectory &oldtrajectory,
7015  const ParticleHypothesis matEffects
7016  ) const {
7017  std::unique_ptr<const TrackParameters> per = makeTrackFindPerigeeParameters(ctx, cache, oldtrajectory, matEffects);
7018 
7019  if (per == nullptr) {
7020  return nullptr;
7021  }
7022 
7023  ATH_MSG_DEBUG("Final perigee: " << *per << " pos: " << per->position() << " pT: " << per->pT());
7024 
7025  return std::make_unique<GXFTrackState>(std::move(per), TrackStateOnSurface::Perigee);
7026  }
7027 
7029  const std::vector<std::unique_ptr<TrackParameters>> & hc,
7030  std::set<Identifier> & id_set,
7031  std::set<Identifier> & sct_set,
7032  TrackHoleCount & rv,
7033  bool count_holes,
7034  bool count_dead
7035  ) const {
7036  /*
7037  * Our input is a list of track states, which we are iterating over. We
7038  * need to examine each one and update the values in our track hole count
7039  * accordingly.
7040  */
7041  for (const std::unique_ptr<TrackParameters> & tp : hc) {
7042  /*
7043  * It is possible, expected even, for some of these pointers to be null.
7044  * In those cases, it would be dangerous to continue, so we need to make
7045  * sure we skip them.
7046  */
7047  if (tp == nullptr) {
7048  continue;
7049  }
7050 
7051  /*
7052  * Extract the detector element of the track parameter surface for
7053  * examination. If for whatever reason there is none (i.e. the surface
7054  * is not a detector at all), we can skip it and continue.
7055  */
7056  const TrkDetElementBase * de = tp->associatedSurface().associatedDetectorElement();
7057 
7058  if (de == nullptr) {
7059  continue;
7060  }
7061 
7062  Identifier id = de->identify();
7063 
7064  /*
7065  * If, for whatever reason, we have already visited this detector, we do
7066  * not want to visit it again. Otherwise we might end up with modules
7067  * counted twice, and that would be very bad.
7068  */
7069  if (id_set.find(id) != id_set.end()) {
7070  continue;
7071  }
7072 
7073  /*
7074  * This is the meat of the pudding, we use the boundary checking tool
7075  * to see whether this set of parameters is a hole candidate, a dead
7076  * module, or not a hole at all.
7077  */
7078  BoundaryCheckResult bc = m_boundaryCheckTool->boundaryCheck(*tp);
7079 
7080  if (bc == BoundaryCheckResult::DeadElement && count_dead) {
7081  /*
7082  * If the module is dead, our job is very simple. We just check
7083  * whether it is a Pixel or an SCT and increment the appropriate
7084  * counter. We also insert the module into our set of visited elements.
7085  */
7086  if (m_DetID->is_pixel(id)) {
7087  ++rv.m_pixel_dead;
7088  } else if (m_DetID->is_sct(id)) {
7089  ++rv.m_sct_dead;
7090  }
7091  id_set.insert(id);
7092  } else if (bc == BoundaryCheckResult::Candidate && count_holes) {
7093  /*
7094  * If the module is a candidate, it's much the same, but we also need
7095  * to handle double SCT holes.
7096  */
7097  if (m_DetID->is_pixel(id)) {
7098  ++rv.m_pixel_hole;
7099  } else if (m_DetID->is_sct(id)) {
7100  ++rv.m_sct_hole;
7101 
7102  /*
7103  * To check for SCT double holes, we need to first fetch the other
7104  * side of the current SCT. Thankfully, the detector description
7105  * makes this very easy.
7106  */
7107  const InDetDD::SiDetectorElement* e = dynamic_cast<const InDetDD::SiDetectorElement *>(de);
7108  const Identifier os = e->otherSide()->identify();
7109 
7110  /*
7111  * We keep a special set containing only SCT hole IDs. We simply
7112  * check whether the ID of the other side of the SCT is in this set
7113  * to confirm that we have a double hole. Note that the first side
7114  * in a double hole will be counted as a SCT hole only, and the
7115  * second side will count as another hole as well as a double hole,
7116  * which is exactly the behaviour we would expect to see.
7117  */
7118  if (sct_set.find(os) != sct_set.end()) {
7119  ++rv.m_sct_double_hole;
7120  }
7121 
7122  /*
7123  * We need to add our SCT to the SCT identifier set if it is a
7124  * candidate hit, otherwise known as a hole in this context.
7125  */
7126  sct_set.insert(id);
7127  }
7128 
7129  /*
7130  * SCTs are also added to the set of all identifiers to avoid double
7131  * counting them.
7132  */
7133  id_set.insert(id);
7134  }
7135  }
7136  }
7137 
7138  std::vector<std::reference_wrapper<GXFTrackState>> GlobalChi2Fitter::holeSearchStates(
7139  GXFTrajectory & trajectory
7140  ) const {
7141  /*
7142  * Firstly, we will need to find the last measurement state on our track.
7143  * This will allow us to break the main loop later once we are done with
7144  * our work.
7145  */
7146  GXFTrackState * lastmeas = nullptr;
7147 
7148  for (const std::unique_ptr<GXFTrackState> & s : trajectory.trackStates()) {
7149  if (s->getStateType(TrackStateOnSurface::Measurement)) {
7150  lastmeas = s.get();
7151  }
7152  }
7153 
7154  /*
7155  * We create a vector of reference wrappers and reserve at least enough
7156  * space to contain the entire trajectory. This is perhaps a little
7157  * wasteful since we will never need this much space, but it may be more
7158  * efficient than taking the resizing pentalty on the chin.
7159  */
7160  std::vector<std::reference_wrapper<GXFTrackState>> rv;
7161  rv.reserve(trajectory.trackStates().size());
7162 
7163  /*
7164  * The main body of our method now. We iterate over all track states in
7165  * the track, at least until we find the last measurement state as found
7166  * above.
7167  */
7168  for (const std::unique_ptr<GXFTrackState> & s : trajectory.trackStates()) {
7169  /*
7170  * We are only interested in collecting measurements, perigees, and any
7171  * outlier states.
7172  */
7173  if (
7174  s->getStateType(TrackStateOnSurface::Measurement) ||
7175  s->getStateType(TrackStateOnSurface::Perigee) ||
7176  s->getStateType(TrackStateOnSurface::Outlier)
7177  ) {
7178  /*
7179  * We store a reference to the current track state in our return value
7180  * vector.
7181  */
7182  rv.emplace_back(*s);
7183 
7184  /*
7185  * We want to make sure we do not collect any TRT results or other
7186  * non-SCT and non-Pixel detector types. For that, we need to access
7187  * the details of the detector element and determine the detector type.
7188  */
7189  const TrkDetElementBase * de = s->trackParameters()->associatedSurface().associatedDetectorElement();
7190 
7191  if (de != nullptr) {
7192  Identifier id = de->identify();
7193 
7194  if (!m_DetID->is_pixel(id) && !m_DetID->is_sct(id)) {
7195  break;
7196  }
7197  }
7198 
7199  /*
7200  * We also have no interest in going past the final measurement, so we
7201  * break out of the loop if we find it.
7202  */
7203  //cppcheck-suppress iterators3
7204  if (s.get() == lastmeas) {
7205  break;
7206  }
7207  }
7208  }
7209 
7210  return rv;
7211  }
7212 
7213  std::optional<GlobalChi2Fitter::TrackHoleCount> GlobalChi2Fitter::holeSearchProcess(
7214  const EventContext & ctx,
7215  const std::vector<std::reference_wrapper<GXFTrackState>> & states
7216  ) const {
7217  /*
7218  * Firstly, we need to guard against tracks having too few measurement
7219  * states to perform a good hole search. This is a mechanism that we
7220  * inherit from the reference hole search. If we have too few states, we
7221  * return a non-extant result to indicate an error state.
7222  *
7223  * TODO: The minimum value of 3 is also borrowed from the reference
7224  * implementation. It's hardcoded for now, but could be a parameter in the
7225  * future.
7226  */
7227  constexpr uint min_meas = 3;
7228  if (std::count_if(states.begin(), states.end(), [](const GXFTrackState & s){ return s.getStateType(TrackStateOnSurface::Measurement); }) < min_meas) {
7229  return {};
7230  }
7231 
7232  bool seen_meas = false;
7234  std::set<Identifier> id_set;
7235  std::set<Identifier> sct_set;
7236 
7237  /*
7238  * Using an old-school integer-based for loop because we need to iterate
7239  * over successive pairs of states to do an extrapolation between.
7240  */
7241  for (std::size_t i = 0; i < states.size() - 1; i++) {
7242  /*
7243  * Gather references to the state at the beginning of the extrapolation,
7244  * named beg, and the end, named end.
7245  */
7246  GXFTrackState & beg = states[i];
7247  GXFTrackState & end = states[i + 1];
7248 
7249  /*
7250  * Update the boolean keeping track of whether we have seen a measurement
7251  * or outlier yet. Once we see one, this will remain true forever, but
7252  * it helps us make sure we don't collect holes before the first
7253  * measurement.
7254  */
7255  seen_meas |= beg.getStateType(TrackStateOnSurface::Measurement) || beg.getStateType(TrackStateOnSurface::Outlier);
7256 
7257  /*
7258  * Calculate the distance between the position of the starting parameters
7259  * and the end parameters. If this distance is sufficiently small, there
7260  * can be no elements between them (for example, between two SCTs), and
7261  * we don't need to do an extrapolation. This can easily save us a few
7262  * microseconds.
7263  */
7264  double dist = (beg.trackParameters()->position() - end.trackParameters()->position()).norm();
7265 
7266  /*
7267  * Only proceed to count holes if we have seen a measurement before (this
7268  * may include the starting track state, if it is a measurement) and the
7269  * distance between start and end is at least 2.5 millimeters.
7270  */
7271  if (seen_meas && dist >= 2.5) {
7272  /*
7273  * First, we retrieve the hole data stored in the beginning state. Note
7274  * that this may very well be non-extant, but it is possible for the
7275  * fitter to have deposited some hole information into the track state
7276  * earlier on in the fitting process.
7277  */
7278  std::optional<std::vector<std::unique_ptr<TrackParameters>>> & hc = beg.getHoles();
7279  std::vector<std::unique_ptr<TrackParameters>> states;
7280 
7281  /*
7282  * Gather the track states between the start and end of the
7283  * extrapolation. If the track state contained hole search information,
7284  * we simply move that out and use it. If there was no information, we
7285  * do a fresh extrapolation. This can be a CPU hog!
7286  */
7287  if (hc.has_value()) {
7288  states = std::move(*hc);
7289  } else {
7290  states = holesearchExtrapolation(ctx, *beg.trackParameters(), end, alongMomentum);
7291  }
7292 
7293  /*
7294  * Finally, we process the collected hole candidate states, checking
7295  * them for liveness and other properties. This helper function will
7296  * increment the values in rv accordingly.
7297  */
7298  holeSearchHelper(states, id_set, sct_set, rv, true, true);
7299  }
7300  }
7301 
7302  /*
7303  * Once we are done processing our measurements, we also need to do a
7304  * final blind extrapolation to collect and dead modules (but not holes)
7305  * behind the last measurement. For this, we do a blind extrapolation
7306  * from the final state.
7307  */
7308  GXFTrackState & last = states.back();
7309 
7310  /*
7311  * To do the blind extrapolation, we need to have a set of track parameters
7312  * for our last measurement state. We also check whether the position of
7313  * the last measurement is still inside the inner detector. If it is not,
7314  * we don't need to blindly extrapolate because we're only interested in
7315  * collecting inner detector dead modules. This check saves us a few tens
7316  * of microseconds.
7317  */
7318  if (
7319  last.trackParameters() != nullptr &&
7321  ) {
7322  /*
7323  * Simply conduct the blind extrapolation, and then use the helper tool
7324  * to ensure that the hole counts are updated.
7325  */
7326  std::vector<std::unique_ptr<Trk::TrackParameters>> bl = m_extrapolator->extrapolateBlindly(
7327  ctx,
7328  *last.trackParameters(),
7330  false,
7331  Trk::pion,
7332  &m_idVolume
7333  );
7334 
7335  /*
7336  * Note that we have flipped one of the boolean parameters of the helper
7337  * method here to make sure it only collects dead modules, not hole
7338  * candidates.
7339  */
7340  holeSearchHelper(bl, id_set, sct_set, rv, false, true);
7341  }
7342 
7343  return rv;
7344  }
7345 
7346  std::unique_ptr<Track> GlobalChi2Fitter::makeTrack(
7347  const EventContext & ctx,
7348  Cache & cache,
7349  GXFTrajectory & oldtrajectory,
7350  ParticleHypothesis matEffects
7351  ) const {
7352  // Convert internal trajectory into track
7353  auto trajectory = std::make_unique<Trk::TrackStates>();
7354 
7355  if (m_fillderivmatrix) {
7356  makeTrackFillDerivativeMatrix(cache, oldtrajectory);
7357  }
7358 
7359  GXFTrajectory tmptrajectory(oldtrajectory);
7360 
7361  std::unique_ptr<GXFTrackState> perigee_ts = makeTrackFindPerigee(ctx, cache, oldtrajectory, matEffects);
7362 
7363  if (perigee_ts == nullptr) {
7364  return nullptr;
7365  }
7366 
7367  tmptrajectory.addBasicState(std::move(perigee_ts), cache.m_acceleration ? 0 : tmptrajectory.numberOfUpstreamStates());
7368  //reserve the ouput size
7369  trajectory->reserve(tmptrajectory.trackStates().size());
7370  for (auto & hit : tmptrajectory.trackStates()) {
7371  if (
7372  hit->measurementType() == TrackState::Pseudo &&
7373  hit->getStateType(TrackStateOnSurface::Outlier)
7374  ) {
7375  hit->resetTrackCovariance();
7376  continue;
7377  }
7378 
7379  if (!Trk::consistentSurfaces (hit->trackParameters(),
7380  hit->measurement(),
7381  hit->materialEffects()))
7382  {
7383  return nullptr;
7384  }
7385 
7386  //should check hit->isSane() here with better equality check(other than ptr comparison)
7387  auto trackState = hit->trackStateOnSurface();
7388  hit->resetTrackCovariance();
7389  trajectory->emplace_back(trackState.release());
7390  }
7391 
7392  auto qual = std::make_unique<FitQuality>(tmptrajectory.chi2(), tmptrajectory.nDOF());
7393 
7394 
7395  TrackInfo info;
7396 
7397  if (matEffects != electron) {
7399  } else {
7401  info.setTrackProperties(TrackInfo::BremFit);
7402 
7403  if (matEffects == electron && tmptrajectory.hasKink()) {
7404  info.setTrackProperties(TrackInfo::BremFitSuccessful);
7405  }
7406  }
7407 
7408  if (tmptrajectory.m_straightline) {
7409  info.setTrackProperties(TrackInfo::StraightTrack);
7410  }
7411 
7412  std::unique_ptr<Track> rv = std::make_unique<Track>(info, std::move(trajectory), std::move(qual));
7413 
7414  /*
7415  * Here, we create a track summary and attach it to our newly created
7416  * track. Note that this code only runs if the m_createSummary Gaudi
7417  * property is set. In cases where having a track summary on the track is
7418  * not desired, such as for compatibility with other tools, this can be
7419  * turned off.
7420  */
7421  if (m_createSummary.value()) {
7422  std::unique_ptr<TrackSummary> ts = std::make_unique<TrackSummary>();
7423 
7424  /*
7425  * This segment determines the hole search behaviour of the track fitter.
7426  * It is only invoked if the DoHoleSearch parameter is set, but it can
7427  * take a significant amount of CPU time, since the hole search is rather
7428  * expensive. Beware of that!
7429  */
7430  if (m_holeSearch.value()) {
7431  std::optional<TrackHoleCount> hole_count;
7432 
7433  /*
7434  * First, we collect a list of states that will act as our hole search
7435  * extrapolation states. This will serve as our source of truth in
7436  * regards to which track states we need to extrapolate between.
7437  */
7438  std::vector<std::reference_wrapper<GXFTrackState>> states = holeSearchStates(tmptrajectory);
7439 
7440  /*
7441  * Then, collect the actual hole search infomation using our state list
7442  * from before. This is the expensive operation, as it will invoke a
7443  * series of extrapolations if not all states have existing hole
7444  * information! It will also check all the hole candidates to see if
7445  * they are actually holes or not.
7446  */
7447  hole_count = holeSearchProcess(ctx, states);
7448 
7449  /*
7450  * Note that the hole search is not guaranteed to return a useful set
7451  * of values. It can, for example, reach an error state if the number
7452  * of measurements on a track is below a certain threshold. In that
7453  * case, a non-extant result will be returned, which we must guard
7454  * against. In that case, the hole counts will remain unset.
7455  */
7456  if (hole_count.has_value()) {
7457  /*
7458  * If the hole search did return good results, we can proceed to
7459  * simply copy the numerical values in the track summary.
7460  */
7461  ts->update(Trk::numberOfPixelHoles, hole_count->m_pixel_hole);
7462  ts->update(Trk::numberOfSCTHoles, hole_count->m_sct_hole);
7463  ts->update(Trk::numberOfSCTDoubleHoles, hole_count->m_sct_double_hole);
7464  ts->update(Trk::numberOfPixelDeadSensors, hole_count->m_pixel_dead);
7465  ts->update(Trk::numberOfSCTDeadSensors, hole_count->m_sct_dead);
7466  }
7467  }
7468 
7469  rv->setTrackSummary(std::move(ts));
7470  }
7471 
7472  return rv;
7473  }
7474 
7475  GlobalChi2Fitter::~GlobalChi2Fitter() = default;
7476 
7477  std::vector<std::unique_ptr<TrackParameters>> GlobalChi2Fitter::holesearchExtrapolation(
7478  const EventContext & ctx,
7479  const TrackParameters & src,
7480  const GXFTrackState & dst,
7481  PropDirection propdir
7482  ) const {
7483  /*
7484  * First, we conduct a bog standard stepwise extrapolation. This will
7485  * yield some unwanted results, but we will filter those later.
7486  */
7487  std::vector<std::unique_ptr<TrackParameters>> rv = m_extrapolator->extrapolateStepwise(
7488  ctx, src, dst.associatedSurface(), propdir, false
7489  );
7490 
7491  /*
7492  * It is possible for the first returned track parameter to be on the same
7493  * surface as we started on. That's probably due to some rounding errors.
7494  * We check for this possibility, and set the pointer to null if it
7495  * occurs. Note that this leaves some null pointers in the returned vector
7496  * but this is more performant compared to removing them properly.
7497  */
7498  if (
7499  !rv.empty() && (
7500  &rv.front()->associatedSurface() == &dst.associatedSurface() ||
7501  &rv.front()->associatedSurface() == &src.associatedSurface() ||
7502  trackParametersClose(*rv.front(), src, 0.001) ||
7503  trackParametersClose(*rv.front(), *dst.trackParameters(), 0.001)
7504  )
7505  ) {
7506  rv.front().reset(nullptr);
7507  }
7508 
7509  /*
7510  * Same logic, but for the last returned element. In that case, we get a
7511  * set of parameters on the destination surface, which we also do not
7512  * want.
7513  */
7514  if (
7515  rv.size() > 1 && (
7516  &rv.back()->associatedSurface() == &dst.associatedSurface() ||
7517  &rv.back()->associatedSurface() == &src.associatedSurface() ||
7518  trackParametersClose(*rv.back(), src, 0.001) ||
7519  trackParametersClose(*rv.back(), *dst.trackParameters(), 0.001)
7520  )
7521  ) {
7522  rv.back().reset(nullptr);
7523  }
7524 
7525  return rv;
7526  }
7527 
7529  const EventContext & ctx,
7530  const TrackParameters & prev,
7531  const GXFTrackState & ts,
7532  PropDirection propdir,
7533  const MagneticFieldProperties& bf,
7534  bool calcderiv,
7535  bool holesearch
7536  ) const {
7537  std::unique_ptr<const TrackParameters> rv;
7538  std::optional<TransportJacobian> jac{};
7539 
7540  if (calcderiv && !m_numderiv) {
7541  rv = m_propagator->propagateParameters(
7542  ctx, prev, ts.associatedSurface(), propdir, false, bf, jac, Trk::nonInteracting, false
7543  );
7544  } else {
7545  rv = m_propagator->propagateParameters(
7546  ctx, prev, ts.associatedSurface(), propdir, false, bf, Trk::nonInteracting, false
7547  );
7548 
7549  if (rv != nullptr && calcderiv) {
7550  jac = numericalDerivatives(ctx, &prev, ts.associatedSurface(), propdir, bf);
7551  }
7552  }
7553 
7554  std::optional<std::vector<std::unique_ptr<TrackParameters>>> extrapolation;
7555 
7556  if (holesearch) {
7557  extrapolation = holesearchExtrapolation(ctx, prev, ts, propdir);
7558  }
7559 
7560  return PropagationResult {
7561  std::move(rv),
7562  std::move(jac),
7563  std::move(extrapolation)
7564  };
7565  }
7566 
7568  const EventContext & ctx,
7569  const TrackParameters & prev,
7570  const GXFTrackState & ts,
7571  PropDirection propdir,
7572  const MagneticFieldProperties& bf,
7573  bool calcderiv,
7574  bool holesearch
7575  ) const {
7577 
7579  ctx, prev, ts, propdir, bf, calcderiv, holesearch
7580  );
7581 
7582  if (rv.m_parameters == nullptr) {
7583  propdir = invertPropdir(propdir);
7584 
7586  ctx, prev, ts, propdir, bf, calcderiv, holesearch
7587  );
7588  }
7589 
7590  return rv;
7591  }
7592 
7594  const EventContext& ctx,
7595  GXFTrajectory & trajectory,
7596  bool calcderiv
7597  ) const {
7598  // Loop over states, calculate track parameters and (optionally) jacobian at each state
7599  ATH_MSG_DEBUG("CalculateTrackParameters");
7600 
7601  std::vector<std::unique_ptr<GXFTrackState>> & states = trajectory.trackStates();
7602  int nstatesupstream = trajectory.numberOfUpstreamStates();
7603  const TrackParameters *prevtrackpar = trajectory.referenceParameters();
7604  std::unique_ptr<const TrackParameters> tmptrackpar;
7605 
7606  for (int hitno = nstatesupstream - 1; hitno >= 0; hitno--) {
7607  const Surface &surf1 = states[hitno]->associatedSurface();
7609 
7611  prevtrackpar->position(), prevtrackpar->momentum().unit()
7612  );
7613 
7614  double distance = getDistance(distsol);
7615 
7616  if (
7617  distance > 0 &&
7618  distsol.numberOfSolutions() > 0 &&
7619  prevtrackpar != trajectory.referenceParameters()
7620  ) {
7621  propdir = Trk::alongMomentum;
7622  }
7623 
7625  ctx,
7626  *prevtrackpar,
7627  *states[hitno],
7628  propdir,
7629  trajectory.m_fieldprop,
7630  calcderiv,
7631  false
7632  );
7633 
7634  if (
7635  propdir == Trk::alongMomentum &&
7636  (rv.m_parameters != nullptr) &&
7637  (prevtrackpar->position() - rv.m_parameters->position()).mag() > 5 * mm
7638  ) {
7639  ATH_MSG_DEBUG("Propagation in wrong direction");
7640 
7641  }
7642 
7643  if (rv.m_parameters == nullptr) {
7644  ATH_MSG_DEBUG("propagation failed, prev par: " << *prevtrackpar <<
7645  " pos: " << prevtrackpar->position() << " destination surface: " << surf1);
7647  }
7648 
7649  states[hitno]->setTrackParameters(std::move(rv.m_parameters));
7650  const TrackParameters *currenttrackpar = states[hitno]->trackParameters();
7651  const Surface &surf = states[hitno]->associatedSurface();
7652 
7653  if (rv.m_jacobian != std::nullopt) {
7654  if (
7655  states[hitno]->materialEffects() != nullptr &&
7656  states[hitno]->materialEffects()->deltaE() != 0 &&
7657  states[hitno]->materialEffects()->sigmaDeltaE() <= 0 &&
7658  !trajectory.m_straightline
7659  ) {
7660  double p = 1. / std::abs(currenttrackpar->parameters()[Trk::qOverP]);
7661  double de = std::abs(states[hitno]->materialEffects()->deltaE());
7662  double mass = trajectory.mass();
7663  double newp = std::sqrt(p * p + 2 * de * std::sqrt(mass * mass + p * p) + de * de);
7664  (*rv.m_jacobian) (4, 4) = ((p + p * de / std::sqrt(p * p + mass * mass)) / newp) * p * p / (newp * newp);
7665  }
7666 
7667  states[hitno]->setJacobian(*rv.m_jacobian);
7668  } else if (calcderiv) {
7669  ATH_MSG_WARNING("Jacobian is null");
7671  }
7672 
7673  GXFMaterialEffects *meff = states[hitno]->materialEffects();
7674 
7675  if (meff != nullptr && hitno != 0) {
7676  std::variant<std::unique_ptr<const TrackParameters>, FitterStatusCode> r = updateEnergyLoss(
7677  surf, *meff, *states[hitno]->trackParameters(), trajectory.mass(), -1
7678  );
7679 
7680  if (std::holds_alternative<FitterStatusCode>(r)) {
7681  return std::get<FitterStatusCode>(r);
7682  }
7683 
7684  tmptrackpar = std::move(std::get<std::unique_ptr<const TrackParameters>>(r));
7685  prevtrackpar = tmptrackpar.get();
7686  } else {
7687  prevtrackpar = currenttrackpar;
7688  }
7689  }
7690 
7691  prevtrackpar = trajectory.referenceParameters();
7692 
7693  for (int hitno = nstatesupstream; hitno < (int) states.size(); hitno++) {
7694  const Surface &surf = states[hitno]->associatedSurface();
7696  DistanceSolution distsol = surf.straightLineDistanceEstimate(prevtrackpar->position(), prevtrackpar->momentum().unit());
7697 
7698  double distance = getDistance(distsol);
7699 
7700  if (distance < 0 && distsol.numberOfSolutions() > 0 && prevtrackpar != trajectory.referenceParameters()) {
7701  propdir = Trk::oppositeMomentum;
7702  }
7703 
7705  ctx,
7706  *prevtrackpar,
7707  *states[hitno],
7708  propdir,
7709  trajectory.m_fieldprop,
7710  calcderiv,
7711  false
7712  );
7713 
7714  if (
7715  (rv.m_parameters != nullptr) &&
7716  propdir == Trk::oppositeMomentum &&
7717  (prevtrackpar->position() - rv.m_parameters->position()).mag() > 5 * mm
7718  ) {
7719  ATH_MSG_DEBUG("Propagation in wrong direction");
7720  }
7721 
7722  if (rv.m_parameters == nullptr) {
7723  ATH_MSG_DEBUG("propagation failed, prev par: " << *prevtrackpar <<
7724  " pos: " << prevtrackpar->
7725  position() << " destination surface: " << surf);
7727  }
7728 
7729  if (rv.m_jacobian != std::nullopt) {
7730  if (
7731  states[hitno]->materialEffects() != nullptr &&
7732  states[hitno]->materialEffects()->deltaE() != 0 &&
7733  states[hitno]->materialEffects()->sigmaDeltaE() <= 0 &&
7734  !trajectory.m_straightline
7735  ) {
7736  double p = 1 / std::abs(rv.m_parameters->parameters()[Trk::qOverP]);
7737  double de = std::abs(states[hitno]->materialEffects()->deltaE());
7738  double mass = trajectory.mass();
7739  double newp = p * p - 2 * de * std::sqrt(mass * mass + p * p) + de * de;
7740 
7741  if (newp > 0) {
7742  newp = std::sqrt(newp);
7743  }
7744 
7745  (*rv.m_jacobian) (4, 4) = ((p - p * de / std::sqrt(p * p + mass * mass)) / newp) * p * p / (newp * newp);
7746  }
7747 
7748  states[hitno]->setJacobian(*rv.m_jacobian);
7749  } else if (calcderiv) {
7750  ATH_MSG_WARNING("Jacobian is null");
7752  }
7753 
7754  GXFMaterialEffects *meff = states[hitno]->materialEffects();
7755 
7756  if (meff != nullptr) {
7757  std::variant<std::unique_ptr<const TrackParameters>, FitterStatusCode> r = updateEnergyLoss(
7758  surf, *meff, *rv.m_parameters, trajectory.mass(), +1
7759  );
7760 
7761  if (std::holds_alternative<FitterStatusCode>(r)) {
7762  return std::get<FitterStatusCode>(r);
7763  }
7764 
7765  rv.m_parameters = std::move(std::get<std::unique_ptr<const TrackParameters>>(r));
7766  }
7767 
7768  states[hitno]->setTrackParameters(std::move(rv.m_parameters));
7769  prevtrackpar = states[hitno]->trackParameters();
7770  }
7771 
7773  }
7774 
7775  std::variant<std::unique_ptr<const TrackParameters>, FitterStatusCode> GlobalChi2Fitter::updateEnergyLoss(
7776  const Surface & surf,
7777  const GXFMaterialEffects & meff,
7778  const TrackParameters & param,
7779  double mass,
7780  int sign
7781  ) const {
7782  const AmgVector(5) & old = param.parameters();
7783 
7784  double newphi = old[Trk::phi0] + sign * meff.deltaPhi();
7785  double newtheta = old[Trk::theta] + sign * meff.deltaTheta();
7786 
7787  if (!correctAngles(newphi, newtheta)) {
7788  ATH_MSG_DEBUG("Angles out of range, phi: " << newphi << " theta: " << newtheta);
7790  }
7791 
7792  double newqoverp = 0;
7793 
7794  if (meff.sigmaDeltaE() <= 0) {
7795  if (std::abs(old[Trk::qOverP]) < 1.e-12) {
7796  newqoverp = 0.;
7797  } else {
7798  double oldp = std::abs(1 / old[Trk::qOverP]);
7799  double newp2 = oldp * oldp - sign * 2 * std::abs(meff.deltaE()) * std::sqrt(mass * mass + oldp * oldp) + meff.deltaE() * meff.deltaE();
7800 
7801  if (newp2 < 0) {
7802  ATH_MSG_DEBUG("Track killed by energy loss update");
7804  }
7805 
7806  newqoverp = std::copysign(1 / std::sqrt(newp2), old[Trk::qOverP]);
7807  }
7808  } else {
7809  newqoverp = old[Trk::qOverP] + sign * .001 * meff.delta_p();
7810  }
7811 
7812  return surf.createUniqueTrackParameters(
7813  old[0], old[1], newphi, newtheta, newqoverp, std::nullopt
7814  );
7815  }
7816 
7818  int nstatesupstream = trajectory.numberOfUpstreamStates();
7819  int nscatupstream = trajectory.numberOfUpstreamScatterers();
7820  int nbremupstream = trajectory.numberOfUpstreamBrems();
7821  int nscats = trajectory.numberOfScatterers();
7822  int nperpars = trajectory.numberOfPerigeeParameters();
7823  int nfitpars = trajectory.numberOfFitParameters();
7824 
7825  using Matrix55 = Eigen::Matrix<double, 5, 5>;
7826 
7827  Matrix55 initialjac;
7828  initialjac.setZero();
7829  initialjac(4, 4) = 1;
7830 
7831  Matrix55 jacvertex(initialjac);
7832 
7833  std::vector<Matrix55, Eigen::aligned_allocator<Matrix55>> jacscat(trajectory.numberOfScatterers(), initialjac);
7834  std::vector<Matrix55, Eigen::aligned_allocator<Matrix55>> jacbrem(trajectory.numberOfBrems(), initialjac);
7835 
7836  std::vector<std::unique_ptr<GXFTrackState>> & states = trajectory.trackStates();
7837  GXFTrackState *prevstate = nullptr, *state = nullptr;
7838 
7839  int hit_begin = 0, hit_end = 0, scatno = 0, bremno = 0;
7840 
7841  for (bool forward : {false, true}) {
7842  if (forward) {
7843  hit_begin = nstatesupstream;
7844  hit_end = (int) states.size();
7845  scatno = nscatupstream;
7846  bremno = nbremupstream;
7847  } else {
7848  hit_begin = nstatesupstream - 1;
7849  hit_end = 0;
7850  scatno = trajectory.numberOfUpstreamScatterers() - 1;
7851  bremno = trajectory.numberOfUpstreamBrems() - 1;
7852  }
7853 
7854  for (
7855  int hitno = hit_begin;
7856  forward ? (hitno < hit_end) : (hitno >= hit_end);
7857  hitno += (forward ? 1 : -1)
7858  ) {
7859 
7860  state = states[hitno].get();
7861 
7862  bool fillderivmat = (!state->getStateType(TrackStateOnSurface::Scatterer) && !state->getStateType(TrackStateOnSurface::BremPoint));
7863 
7864  if (fillderivmat && state->derivatives().cols() != nfitpars) {
7865  state->derivatives().resize(5, nfitpars);
7866  state->derivatives().setZero();
7867  }
7868 
7869  int jminscat = 0, jmaxscat = 4, jminbrem = 0, jmaxbrem = 4;
7870 
7871  if (hitno == (forward ? hit_end - 1 : 0)) {
7872  if (!fillderivmat) {
7873  break;
7874  }
7875  jminscat = 2;
7876  jmaxscat = 3;
7877  jminbrem = 4;
7878  }
7879 
7880  Eigen::Matrix<double, 5, 5> & jac = state->jacobian();
7881 
7882  if (hitno == nstatesupstream + (forward ? 0 : -1)) {
7883  jacvertex.block<4, 5>(0, 0) = jac.block<4, 5>(0, 0);
7884  jacvertex(4, 4) = jac(4, 4);
7885  } else {
7886  int jmin = 0, jmax = 0, jcnt = 0;
7887  int lp_bgn = 0, lp_end = 0;
7888 
7889  jmin = jminscat;
7890  jmax = jmaxscat;
7891  jcnt = jmax - jmin + 1;
7892 
7893  lp_bgn = forward ? nscatupstream : nscatupstream - 1;
7894  lp_end = scatno;
7895 
7896  for (int i = lp_bgn; forward ? (i < lp_end) : (i > lp_end); i += (forward ? 1 : -1)) {
7897  if (
7898  i == scatno + (forward ? -1 : 1) &&
7899  prevstate != nullptr &&
7901  (!trajectory.prefit() || prevstate->materialEffects()->deltaE() == 0)
7902  ) {
7903  jacscat[i].block(0, jmin, 4, jcnt) = jac.block(0, jmin, 4, jcnt);
7904  jacscat[i](4, 4) = jac(4, 4);
7905  } else {
7906  calculateJac(jac, jacscat[i], jmin, jmax);
7907  }
7908 
7909  if (fillderivmat) {
7910  Eigen::MatrixXd & derivmat = state->derivatives();
7911  int scatterPos = nperpars + 2 * i;
7912 
7913  derivmat.block<4, 2>(0, scatterPos) = (forward ? 1 : -1) * jacscat[i].block<4, 2>(0, 2);
7914  }
7915  }
7916 
7917  jmin = jminbrem;
7918  jmax = jmaxbrem;
7919  jcnt = jmax - jmin + 1;
7920 
7921  lp_bgn = forward ? nbremupstream : nbremupstream - 1;
7922  lp_end = bremno;
7923 
7924  for (int i = lp_bgn; forward ? (i < lp_end) : (i > lp_end); i += (forward ? 1 : -1)) {
7925  if (
7926  i == bremno + (forward ? -1 : 1) &&
7927  prevstate &&
7928  prevstate->materialEffects() &&
7929  prevstate->materialEffects()->sigmaDeltaE() > 0
7930  ) {
7931  jacbrem[i].block(0, jmin, 4, jcnt) = jac.block(0, jmin, 4, jcnt);
7932  jacbrem[i](4, 4) = jac(4, 4);
7933  } else {
7934  calculateJac(jac, jacbrem[i], jmin, jmax);
7935  }
7936 
7937  if (fillderivmat) {
7938  Eigen::MatrixXd & derivmat = state->derivatives();
7939  int scatterPos = nperpars + 2 * nscats + i;
7940 
7941  derivmat.block<5, 1>(0, scatterPos) = (forward ? .001 : -.001) * jacbrem[i].block<5, 1>(0, 4);
7942  }
7943  }
7944 
7945  calculateJac(jac, jacvertex, 0, 4);
7946  }
7947 
7948  if (fillderivmat) {
7949  Eigen::MatrixXd & derivmat = state->derivatives();
7950  derivmat.block(0, 0, 4, nperpars) = jacvertex.block(0, 0, 4, nperpars);
7951 
7952  if (nperpars == 5) {
7953  derivmat.col(4).segment(0, 4) *= .001;
7954  derivmat(4, 4) = .001 * jacvertex(4, 4);
7955  }
7956  }
7957 
7958  if (
7959  state->getStateType(TrackStateOnSurface::Scatterer) &&
7960  (!trajectory.prefit() || states[hitno]->materialEffects()->deltaE() == 0)
7961  ) {
7962  scatno += (forward ? 1 : -1);
7963  }
7964 
7965  if (
7966  states[hitno]->materialEffects() &&
7967  states[hitno]->materialEffects()->sigmaDeltaE() > 0
7968  ) {
7969  bremno += (forward ? 1 : -1);
7970  }
7971 
7972  prevstate = states[hitno].get();
7973  }
7974  }
7975  }
7976 
7977  void
7978 
7980  Amg::SymMatrixX & fullcovmat,
7981  bool onlylocal) const {
7982  //
7983  // Calculate track errors at each state, except scatterers and brems
7984  //
7985  ATH_MSG_DEBUG("CalculateTrackErrors");
7986 
7987  std::vector<std::unique_ptr<GXFTrackState>> & states = trajectory.trackStates();
7988  int nstatesupstream = trajectory.numberOfUpstreamStates();
7989  std::vector < int >indices(states.size());
7990  GXFTrackState *prevstate = nullptr;
7991  int i = nstatesupstream;
7992  for (int j = 0; j < (int) states.size(); j++) {
7993  if (j < nstatesupstream) {
7994  i--;
7995  indices[j] = i;
7996  } else {
7997  indices[j] = j;
7998  }
7999  }
8000  for (int stateno = 0; stateno < (int) states.size(); stateno++) {
8001  if (stateno == 0 || stateno == nstatesupstream) {
8002  prevstate = nullptr;
8003  }
8004  int index = indices[stateno];
8005  std::unique_ptr<GXFTrackState> & state = states[index];
8006  if (state->materialEffects() != nullptr) {
8007  prevstate = state.get();
8008  continue;
8009  }
8010 
8011  if (!state->hasTrackCovariance()) {
8012  state->zeroTrackCovariance();
8013  }
8014  AmgMatrix(5, 5) & trackerrmat = state->trackCovariance();
8015 
8016  if ((prevstate != nullptr) &&
8019  && !onlylocal) {
8020  Eigen::Matrix<double, 5, 5> & jac = state->jacobian();
8021  AmgMatrix(5, 5) & prevcov = states[indices[stateno - 1]]->trackCovariance();
8022 
8023  trackerrmat = jac * prevcov * jac.transpose();
8024  } else {
8025  Amg::MatrixX & derivatives = state->derivatives();
8026 
8027  trackerrmat = derivatives * fullcovmat * derivatives.transpose();
8028  }
8029 
8030  if (!onlylocal) {
8031  const MeasurementBase *measurement = state->measurement();
8032  const Amg::MatrixX & meascov = measurement->localCovariance();
8033  int j = 0;
8034  ParamDefsAccessor paraccessor;
8035  int indices[5] = {
8036  -1, -1, -1, -1, -1
8037  };
8038  bool errorok = true;
8039  for (int i = 0; i < 5; i++) {
8040  if (measurement->localParameters().contains(paraccessor.pardef[i])) {
8041  if (state->getStateType(TrackStateOnSurface::Measurement)
8042  && trackerrmat(i, i) > meascov(j, j)) {
8043  errorok = false;
8044  double scale = std::sqrt(meascov(j, j) / trackerrmat(i, i));
8045  trackerrmat(i, i) = meascov(j, j);
8046  for (int k = 0; k < 5; k++) {
8047  if (k != i) {
8048  trackerrmat(k, i) *= scale;
8049  }
8050  }
8051  indices[i] = j;
8052  }
8053  j++;
8054  }
8055  }
8056  for (int i = 0; i < 5; i++) {
8057  if (indices[i] == -1) {
8058  continue;
8059  }
8060  for (int j = 0; j < 5; j++) {
8061  if (indices[j] == -1) {
8062  continue;
8063  }
8064  trackerrmat(i, j) = meascov(indices[i], indices[j]);
8065  }
8066  }
8067  if (trajectory.m_straightline) {
8068  trackerrmat(4, 4) = 1e-20;
8069  }
8070 
8071  const TrackParameters *tmptrackpar =
8072  state->trackParameters();
8073 
8074  std::optional<AmgMatrix(5, 5)> trkerrmat;
8075 
8076  if (state->hasTrackCovariance()) {
8077  trkerrmat = (state->trackCovariance());
8078  } else {
8079  trkerrmat = std::nullopt;
8080  }
8081 
8082  const AmgVector(5) & tpars = tmptrackpar->parameters();
8083  std::unique_ptr<const TrackParameters> trackpar(
8084  tmptrackpar->associatedSurface().createUniqueTrackParameters(tpars[0],
8085  tpars[1],
8086  tpars[2],
8087  tpars[3],
8088  tpars[4],
8089  std::move(trkerrmat))
8090  );
8091  state->setTrackParameters(std::move(trackpar));
8092  FitQualityOnSurface fitQual{};
8093  if (state->getStateType(TrackStateOnSurface::Measurement)) {
8094  if (errorok && trajectory.nDOF() > 0) {
8095  fitQual = m_updator->fullStateFitQuality(
8096  *state->trackParameters(),
8097  measurement->localParameters(),
8098  measurement->localCovariance()
8099  );
8100  } else {
8101  fitQual = FitQualityOnSurface(0, state->numberOfMeasuredParameters());
8102  }
8103  }
8104  state->setFitQuality(fitQual);
8105  }
8106  prevstate = state.get();
8107  }
8108  }
8109 
8110  std::optional<TransportJacobian>
8112  const EventContext& ctx,
8113  const TrackParameters* prevpar,
8114  const Surface & surf,
8115  PropDirection propdir,
8116  const MagneticFieldProperties& fieldprop) const
8117  {
8118  ParamDefsAccessor paraccessor;
8119  double J[25] = {
8120  1, 0, 0, 0, 0,
8121  0, 1, 0, 0, 0,
8122  0, 0, 1, 0, 0,
8123  0, 0, 0, 1, 0,
8124  0, 0, 0, 0, 1
8125  };
8126  std::optional<TransportJacobian> jac = std::make_optional<TransportJacobian>(J);
8127  const TrackParameters *tmpprevpar = prevpar;
8128  double eps[5] = {
8129  0.01, 0.01, 0.00001, 0.00001, 0.000000001
8130  };
8131 
8132  const AmgVector(5) & vec = tmpprevpar->parameters();
8133 
8134  bool cylsurf = surf.type() == Trk::SurfaceType::Cylinder;
8135  bool discsurf = surf.type() == Trk::SurfaceType::Disc;
8136  const Surface & previousSurface = tmpprevpar->associatedSurface();
8137  bool thiscylsurf = previousSurface.type() == Trk::SurfaceType::Cylinder;
8138  bool thisdiscsurf = previousSurface.type() == Trk::SurfaceType::Disc;
8139 
8140  for (int i = 0; i < 5; i++) {
8141  AmgVector(5) vecpluseps = vec, vecminuseps = vec;
8142 
8143  if (thisdiscsurf && i == 1) {
8144  eps[i] /= vec[0];
8145  }
8146 
8147  vecpluseps[paraccessor.pardef[i]] += eps[i];
8148  vecminuseps[paraccessor.pardef[i]] -= eps[i];
8149  if (thiscylsurf && i == 0) {
8150  if (vecpluseps[0] / previousSurface.bounds().r() > M_PI) {
8151  vecpluseps[0] -= 2 * M_PI * previousSurface.bounds().r();
8152  }
8153  if (vecminuseps[0] / previousSurface.bounds().r() < -M_PI) {
8154  vecminuseps[0] += 2 * M_PI * previousSurface.bounds().r();
8155  }
8156  }
8157  if (thisdiscsurf && i == 1) {
8158  if (vecpluseps[i] > M_PI) {
8159  vecpluseps[i] -= 2 * M_PI;
8160  }
8161  if (vecminuseps[i] < -M_PI) {
8162  vecminuseps[i] += 2 * M_PI;
8163  }
8164  }
8165  correctAngles(vecminuseps[Trk::phi], vecminuseps[Trk::theta]);
8166  correctAngles(vecpluseps[Trk::phi], vecpluseps[Trk::theta]);
8167 
8168  std::unique_ptr<const TrackParameters> parpluseps(
8170  vecpluseps[0],
8171  vecpluseps[1],
8172  vecpluseps[2],
8173  vecpluseps[3],
8174  vecpluseps[4],
8175  std::nullopt
8176  )
8177  );
8178  std::unique_ptr<const TrackParameters> parminuseps(
8180  vecminuseps[0],
8181  vecminuseps[1],
8182  vecminuseps[2],
8183  vecminuseps[3],
8184  vecminuseps[4],
8185  std::nullopt
8186  )
8187  );
8188 
8189  std::unique_ptr<const TrackParameters> newparpluseps(
8190  m_propagator->propagateParameters(
8191  ctx,
8192  *parpluseps,
8193  surf,
8194  propdir,
8195  false,
8196  fieldprop,
8198  )
8199  );
8200  std::unique_ptr<const TrackParameters> newparminuseps(
8201  m_propagator->propagateParameters(
8202  ctx,
8203  *parminuseps,
8204  surf,
8205  propdir,
8206  false,
8207  fieldprop,
8209  )
8210  );
8211 
8212  PropDirection propdir2 =
8213  (propdir ==
8215  if (newparpluseps == nullptr) {
8216  newparpluseps =
8217  m_propagator->propagateParameters(
8218  ctx,
8219  *parpluseps,
8220  surf,
8221  propdir2,
8222  false,
8223  fieldprop,
8225  );
8226  }
8227  if (newparminuseps == nullptr) {
8228  newparminuseps =
8229  m_propagator->propagateParameters(
8230  ctx,
8231  *parminuseps,
8232  surf,
8233  propdir2,
8234  false,
8235  fieldprop,
8237  );
8238  }
8239  if ((newparpluseps == nullptr) || (newparminuseps == nullptr)) {
8240  return nullptr;
8241  }
8242 
8243  for (int j = 0; j < 5; j++) {
8244  double diff = newparpluseps->parameters()[paraccessor.pardef[j]] -
8245  newparminuseps->parameters()[paraccessor.pardef[j]];
8246  if (cylsurf && j == 0) {
8247  double length = 2 * M_PI * surf.bounds().r();
8248  if (std::abs(std::abs(diff) - length) < std::abs(diff)) {
8249  if (diff > 0) {
8250  diff -= length;
8251  } else {
8252  diff += length;
8253  }
8254  }
8255  }
8256  if (discsurf && j == 1) {
8257  if (std::abs(std::abs(diff) - 2 * M_PI) < std::abs(diff)) {
8258  if (diff > 0) {
8259  diff -= 2 * M_PI;
8260  } else {
8261  diff += 2 * M_PI;
8262  }
8263  }
8264  }
8265 
8266  (*jac) (j, i) = diff / (2 * eps[i]);
8267  }
8268 
8269  }
8270  return jac;
8271  }
8272 
8273  int
8275  return 0;
8276  } void
8279  ("Configure the minimum number of Iterations via jobOptions");
8280  }
8281 
8282  bool
8284  if (theta > M_PI) {
8285  theta = M_PI - theta;
8286  phi += M_PI;
8287  }
8288  if (theta < 0) {
8289  theta = -theta;
8290  phi += M_PI;
8291  }
8292  if (phi > M_PI) {
8293  phi -= 2 * M_PI;
8294  }
8295  if (phi < -M_PI) {
8296  phi += 2 * M_PI;
8297  }
8298  return theta >= 0 && theta <= M_PI && phi >= -M_PI && phi <= M_PI;
8299  }
8300 
8301  bool
8302  GlobalChi2Fitter::isMuonTrack(const Track & intrk1) const {
8303  const auto *pDataVector = intrk1.measurementsOnTrack();
8304  auto nmeas1 = pDataVector->size();
8305  const auto *pLastValue = (*pDataVector)[nmeas1 - 1];
8306  //
8307  const bool lastMeasIsRIO = pLastValue->type(Trk::MeasurementBaseType::RIO_OnTrack);
8308  const bool lastMeasIsCompetingRIO = pLastValue->type(Trk::MeasurementBaseType::CompetingRIOsOnTrack);
8309  //we only need the RIO on track pointer to be valid to identify
8310  const RIO_OnTrack *testrot{};
8311  //
8312  if (lastMeasIsRIO){
8313  testrot = static_cast<const RIO_OnTrack *>(pLastValue);
8314  } else {
8315  if (lastMeasIsCompetingRIO){
8316  const auto *testcrot = static_cast<const CompetingRIOsOnTrack*>(pLastValue);
8317  testrot = &testcrot->rioOnTrack(0);
8318  }
8319  }
8320  //still undefined, so try penultimate measurement as well
8321  if (testrot == nullptr) {
8322  const auto *pPenultimate = (*pDataVector)[nmeas1 - 2];
8323  const bool penultimateIsRIO = pPenultimate->type(Trk::MeasurementBaseType::RIO_OnTrack);
8324  const bool penultimateIsCompetingRIO = pPenultimate->type(Trk::MeasurementBaseType::CompetingRIOsOnTrack);
8325  if(penultimateIsRIO){
8326  testrot = static_cast<const RIO_OnTrack *>(pPenultimate);
8327  } else {
8328  if (penultimateIsCompetingRIO){
8329  const auto *testcrot = static_cast<const CompetingRIOsOnTrack*>(pPenultimate);
8330  testrot = &testcrot->rioOnTrack(0);
8331  }
8332  }
8333  }
8334  //check: we've successfully got a valid RIO on track; it's not the inner detector;
8335  //it's really the muon detector (question: doesn't that make the previous check redundant?)
8336  return (
8337  (testrot != nullptr) &&
8338  !m_DetID->is_indet(testrot->identify()) &&
8339  m_DetID->is_muon(testrot->identify())
8340  );
8341  }
8342 
8343  void
8344  GlobalChi2Fitter::initFieldCache(const EventContext& ctx, Cache& cache)
8345  const
8346  {
8349  ctx
8350  );
8351 
8352  const AtlasFieldCacheCondObj * cond_obj(*rh);
8353 
8354  if (cond_obj == nullptr) {
8355  ATH_MSG_ERROR("Failed to create AtlasFieldCacheCondObj!");
8356  return;
8357  }
8358 
8359  cond_obj->getInitializedCache(cache.m_field_cache);
8360  }
8361 
8363  std::stringstream msg;
8364  msg << "Failed to get conditions data " << m_trackingGeometryReadKey.key() << ".";
8365  throw std::runtime_error(msg.str());
8366  }
8367 }
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
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:62
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:960
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:32
Trk::GlobalChi2Fitter::m_navigator
ToolHandle< INavigator > m_navigator
Definition: GlobalChi2Fitter.h:897
Amg::MatrixX
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic > MatrixX
Dynamic Matrix - dynamic allocation.
Definition: EventPrimitives.h:29
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
python.PerfMonSerializer.p
def p
Definition: PerfMonSerializer.py:743
max
#define max(a, b)
Definition: cfImp.cxx:41
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:963
Trk::z
@ z
global position (cartesian)
Definition: ParamDefs.h:63
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:64
Trk::GlobalChi2Fitter::m_numderiv
Gaudi::Property< bool > m_numderiv
Definition: GlobalChi2Fitter.h:955
SurfaceConsistencyCheck.h
Trk::GlobalChi2Fitter::runIteration
FitterStatusCode runIteration(const EventContext &ctx, Cache &, GXFTrajectory &, int, Amg::SymMatrixX &, Amg::VectorX &, Amg::SymMatrixX &, bool &) const
Definition: GlobalChi2Fitter.cxx:5656
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:900
PerigeeSurface.h
Trk::locX
@ locX
Definition: ParamDefs.h:43
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:895
AtlasDetectorID::is_csc
bool is_csc(Identifier id) const
Definition: AtlasDetectorID.h:891
CompetingRIOsOnTrack.h
Trk::locY
@ locY
local cartesian
Definition: ParamDefs.h:44
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
perp
Scalar perp() const
perp method - perpenticular length
Definition: AmgMatrixBasePlugin.h:35
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:961
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.
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:8302
Trk::GXFTrajectory::numberOfPerigeeParameters
int numberOfPerigeeParameters() const
Definition: GXFTrajectory.cxx:492
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:952
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:943
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:8277
plotBeamSpotVxVal.covmat
covmat
Definition: plotBeamSpotVxVal.py:206
Trk::GXFTrajectory::numberOfTRTTubeHits
int numberOfTRTTubeHits() const
Definition: GXFTrajectory.cxx:450
Trk::locRPhi
@ locRPhi
Definition: ParamDefs.h:46
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:423
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:7567
Trk::GlobalChi2Fitter::m_ROTcreator
ToolHandle< IRIO_OnTrackCreator > m_ROTcreator
Definition: GlobalChi2Fitter.h:889
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:892
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:4621
ParticleTest.tp
tp
Definition: ParticleTest.py:25
Trk::GlobalChi2Fitter::m_decomposesegments
Gaudi::Property< bool > m_decomposesegments
Definition: GlobalChi2Fitter.h:948
Trk::z0
@ z0
Definition: ParamDefs.h:70
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:896
Trk::GXFMaterialEffects::setScatteringSigmas
void setScatteringSigmas(double, double)
Definition: GXFMaterialEffects.cxx:98
Trk::loc2
@ loc2
generic first and second local coordinate
Definition: ParamDefs.h:41
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:7477
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.
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:890
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:6859
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:969
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:983
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:923
Trk::GlobalChi2Fitter::m_field_cache_key
SG::ReadCondHandleKey< AtlasFieldCacheCondObj > m_field_cache_key
Definition: GlobalChi2Fitter.h:930
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:902
Trk::u
@ u
Enums for curvilinear frames.
Definition: ParamDefs.h:83
PrepRawData.h
Trk::GlobalChi2Fitter::calculateTrackParameters
FitterStatusCode calculateTrackParameters(const EventContext &ctx, GXFTrajectory &, bool) const
Definition: GlobalChi2Fitter.cxx:7593
python.Utilities.clone
clone
Definition: Utilities.py:134
dqt_zlumi_pandas.mass
mass
Definition: dqt_zlumi_pandas.py:170
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:972
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: 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:8344
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:200
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:970
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:898
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:7138
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:6810
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 (solenoid) or 3-d (toroid) position.
Definition: AtlasFieldCacheCondObj.h:52
Trk::GlobalChi2Fitter::S_MAT_INV_FAIL
@ S_MAT_INV_FAIL
Definition: GlobalChi2Fitter.h:179
Trk::GlobalChi2Fitter::m_caloMaterialProvider
ToolHandle< Trk::ITrkMaterialProviderTool > m_caloMaterialProvider
Definition: GlobalChi2Fitter.h:899
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:48
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:5498
dqt_zlumi_pandas.err
err
Definition: dqt_zlumi_pandas.py:193
GXFMaterialEffects.h
parseMapping.v0
def v0
Definition: parseMapping.py:149
Trk::GlobalChi2Fitter::m_elosstool
ToolHandle< IEnergyLossUpdator > m_elosstool
Definition: GlobalChi2Fitter.h:894
lumiFormat.i
int i
Definition: lumiFormat.py:92
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
Identifier
Definition: DetectorDescription/Identifier/Identifier/Identifier.h:32
Trk::GlobalChi2Fitter::iterationsOfLastFit
virtual int iterationsOfLastFit() const
Definition: GlobalChi2Fitter.cxx:8274
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:72
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:950
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:59
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: 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:937
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:7528
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:522
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:127
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:8362
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: 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:956
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:7213
Trk::GlobalChi2Fitter::correctAngles
static bool correctAngles(double &, double &)
Definition: GlobalChi2Fitter.cxx:8283
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:944
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:7028
Trk::GlobalChi2Fitter::trackingGeometry
const TrackingGeometry * trackingGeometry(Cache &cache, const EventContext &ctx) const
Definition: GlobalChi2Fitter.h:905
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:901
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:7979
TrackSummary.h
Trk::GlobalChi2Fitter::makeTrackFindPerigee
std::unique_ptr< GXFTrackState > makeTrackFindPerigee(const EventContext &, Cache &, GXFTrajectory &, const ParticleHypothesis) const
Definition: GlobalChi2Fitter.cxx:7011
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:942
Trk::GlobalChi2Fitter::m_scattool
ToolHandle< IMultipleScatteringUpdator > m_scattool
Definition: GlobalChi2Fitter.h:893
Trk::GlobalChi2Fitter::makeTrack
std::unique_ptr< Track > makeTrack(const EventContext &ctx, Cache &, GXFTrajectory &, const ParticleHypothesis) const
Definition: GlobalChi2Fitter.cxx:7346
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:8111
min
#define min(a, b)
Definition: cfImp.cxx:40
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:954
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
Trk::GlobalChi2Fitter::runTrackCleanerTRT
void runTrackCleanerTRT(Cache &, GXFTrajectory &, Amg::SymMatrixX &, Amg::VectorX &, Amg::SymMatrixX &, bool, bool, int) const
Definition: GlobalChi2Fitter.cxx:6147
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
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:69
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:6316
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:494
Trk::GlobalChi2Fitter::m_chi2cut
Gaudi::Property< double > m_chi2cut
Definition: GlobalChi2Fitter.h:965
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:98
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:362
Trk::MaterialProperties
Definition: MaterialProperties.h:40
TrackingVolume.h
Trk::ResidualPull::Biased
@ Biased
RP with track state including the hit.
Definition: ResidualPull.h:55
DiTauMassTools::MaxHistStrategyV2::e
e
Definition: PhysicsAnalysis/TauID/DiTauMassTools/DiTauMassTools/HelperFunctions.h:26
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:964
CSV_InDetExporter.old
old
Definition: CSV_InDetExporter.py:145
Trk::GlobalChi2Fitter::updateFitParameters
FitterStatusCode updateFitParameters(GXFTrajectory &, Amg::VectorX &, const Amg::SymMatrixX &) const
Definition: GlobalChi2Fitter.cxx:5961
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 closest approach of two lines.
Definition: GeoPrimitivesHelpers.h:302
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:973
Trk::TrackingVolume::confinedVolumes
const TrackingVolumeArray * confinedVolumes() const
Return the subLayer array.
Trk::GXFTrackState::hasTrackCovariance
bool hasTrackCovariance(void) const
Definition: GXFTrackState.cxx:259
DeMoScan.first
bool first
Definition: DeMoScan.py:534
Trk::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:73
Trk::SurfaceType::Disc
@ Disc
Trk::GlobalChi2Fitter::m_scalefactor
Gaudi::Property< double > m_scalefactor
Definition: GlobalChi2Fitter.h:966
Trk::TrackState::CSC
@ CSC
Definition: TrackStateDefs.h:32
Trk::RIO_OnTrack::identify
virtual Identifier identify() const final
return the identifier -extends MeasurementBase
Definition: RIO_OnTrack.h:155
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
Trk::GlobalChi2Fitter::updatePixelROTs
void updatePixelROTs(GXFTrajectory &, Amg::SymMatrixX &, Amg::VectorX &) const
Update the Pixel ROT using the current trajectory/local track parameters.
Definition: GlobalChi2Fitter.cxx:6026
DiscSurface.h
GlobalChi2Fitter.h
Trk::GlobalChi2Fitter::m_updator
ToolHandle< IUpdator > m_updator
Definition: GlobalChi2Fitter.h:891
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:940
Trk::GXFTrajectory::setChi2
void setChi2(double)
Definition: GXFTrajectory.cxx:511
Trk::phi
@ phi
Definition: ParamDefs.h:81
Trk::GlobalChi2Fitter::m_rejectLargeNScat
Gaudi::Property< bool > m_rejectLargeNScat
Definition: GlobalChi2Fitter.h:959
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:946
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
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:61
Trk::SurfaceType::Line
@ Line
Trk::ParamDefsAccessor::pardef
const std::array< ParamDefs, 6 > pardef
Constructor.
Definition: ParamDefs.h:100
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:40
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:25
Trk::GlobalChi2Fitter::updateEnergyLoss
std::variant< std::unique_ptr< const TrackParameters >, FitterStatusCode > updateEnergyLoss(const Surface &, const GXFMaterialEffects &, const TrackParameters &, double, int) const
Definition: GlobalChi2Fitter.cxx:7775
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:71
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:7817
Trk::GlobalChi2Fitter::Cache::m_fit_status
std::array< std::atomic< unsigned int >, __S_MAX_VALUE > m_fit_status
Definition: GlobalChi2Fitter.h:245
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:958
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:975
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:5188
Amg::SymMatrixX
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic > SymMatrixX
Definition: EventPrimitives.h:30
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
Trk::SurfaceBounds::r
virtual double r() const =0
Interface method for the maximal extension or the radius.