ATLAS Offline Software
CombinedMuonTrackBuilder.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3 */
4 
6 // CombinedMuonTrackBuilder
7 // AlgTool gathering material effects along a combined muon track, in
8 // particular the TSOS'es representing the calorimeter energy deposit and
9 // Coulomb scattering.
10 // The resulting track is fitted at the IP
11 //
13 
15 
16 #include <cmath>
17 #include <iomanip>
18 #include <memory>
20 #include "AthenaKernel/Units.h"
41 #include "TrkSurfaces/Surface.h"
43 #include "TrkTrack/Track.h"
47 #include "VxVertex/RecVertex.h"
48 #include "muonEvent/CaloEnergy.h"
50 
51 namespace {
53  const double s_sigmaPhiSector = std::tan(0.125 * M_PI / std::sqrt(12.));
54 
55 }
56 namespace Rec {
58  CombinedMuonTrackBuilder::CombinedMuonTrackBuilder(const std::string& type, const std::string& name, const IInterface* parent) :
60  declareInterface<ICombinedMuonTrackBuilder>(this);
61  }
62 
65  ATH_MSG_DEBUG("Initializing CombinedMuonTrackBuilder.");
66  ATH_CHECK(m_caloEnergyParam.retrieve());
67  ATH_MSG_DEBUG("Retrieved tool " << m_caloEnergyParam);
68 
69  m_redoRots = !m_cscRotCreator.empty() || !m_muClusterRotCreator.empty() || !m_mdtRotCreator.empty();
70  ATH_CHECK(m_cscRotCreator.retrieve(DisableTool{m_cscRotCreator.empty()}));
71  ATH_CHECK(m_muClusterRotCreator.retrieve(DisableTool{m_muClusterRotCreator.empty()}));
72  ATH_CHECK(m_mdtRotCreator.retrieve(DisableTool{m_mdtRotCreator.empty()}));
73 
74  ATH_CHECK(m_materialAllocator.retrieve(DisableTool{m_materialAllocator.empty()}));
75  ATH_CHECK(m_extrapolator.retrieve());
76  ATH_MSG_DEBUG("Retrieved tool " << m_extrapolator);
77 
78  ATH_CHECK(m_muonHoleRecovery.retrieve(DisableTool{m_muonHoleRecovery.empty()}));
79 
80 
81  ATH_CHECK(m_propagator.retrieve());
82  ATH_MSG_DEBUG("Retrieved tool " << m_propagator);
83  ATH_CHECK(m_propagatorSL.retrieve());
84  ATH_MSG_DEBUG("Retrieved tool " << m_propagatorSL);
85 
86 
88 
89 
90  // create beamAxis and vertexRegion for constrained (projective) track fits
91  Amg::Vector3D origin(0., 0., 0.);
92  m_perigeeSurface = std::make_unique<Trk::PerigeeSurface>(origin);
93 
94  AmgSymMatrix(3) beamAxisCovariance;
95  beamAxisCovariance.setZero();
96  (beamAxisCovariance)(0, 0) = m_vertex2DSigmaRPhi * m_vertex2DSigmaRPhi;
97  (beamAxisCovariance)(1, 1) = m_vertex2DSigmaRPhi * m_vertex2DSigmaRPhi;
98  (beamAxisCovariance)(2, 2) = m_vertex2DSigmaZ * m_vertex2DSigmaZ;
99  m_beamAxis = std::make_unique<Trk::RecVertex>(origin, beamAxisCovariance);
100 
101  AmgSymMatrix(3) vertexRegionCovariance;
102  vertexRegionCovariance.setZero();
103  (vertexRegionCovariance)(0, 0) = m_vertex3DSigmaRPhi * m_vertex3DSigmaRPhi;
104  (vertexRegionCovariance)(1, 1) = m_vertex3DSigmaRPhi * m_vertex3DSigmaRPhi;
105  (vertexRegionCovariance)(2, 2) = m_vertex3DSigmaZ * m_vertex3DSigmaZ;
106  m_vertex = std::make_unique<Trk::RecVertex>(origin, vertexRegionCovariance);
107  ATH_CHECK(m_alignUncertTool_theta.retrieve(DisableTool{!m_addIDMSerrors}));
108  ATH_CHECK(m_alignUncertTool_phi.retrieve(DisableTool{!m_addIDMSerrors}));
109 
110 #ifndef NDEBUG
111  ATH_MSG_DEBUG(" vertex region: ");
112  m_vertex->dump(msg(MSG::DEBUG));
113 #endif
114  return StatusCode::SUCCESS;
115  }
116 
119  double norm = 100. / static_cast<double>(m_countAcceptedStandaloneFit);
120  ATH_MSG_INFO("Finalizing CombinedMuonTrackBuilder:"
121  << endmsg << " " << std::setiosflags(std::ios::fixed) << std::setw(4) << std::setprecision(2)
122  << norm * static_cast<double>(m_countBeamAxis) << "% with beamAxis constraint" << endmsg << " " << std::setw(4)
123  << std::setprecision(2) << norm * static_cast<double>(m_countVertexRegion) << "% with vertexRegion constraint"
124  << endmsg << " " << m_countDegradedStandaloneFit << " degraded standalone fit-chi2 ");
125  }
127  }
128  std::unique_ptr<Trk::Track> CombinedMuonTrackBuilder::combinedFit(const EventContext& ctx, const Trk::Track& indetTrack, const Trk::Track& extrapolatedTrack,
129  const Trk::Track&) const {
130  ATH_MSG_VERBOSE("===== Start of combinedFit:: ");
131 
132  if (msgLevel(MSG::DEBUG)) countAEOTs(extrapolatedTrack, " extrapolatedTrack start combinedFit ");
133 
134  // require MeasuredPerigee for indetTrack
135  const Trk::Perigee* indetPerigee = indetTrack.perigeeParameters();
136  if (!indetPerigee) {
137  // missing MeasuredPerigee for indet track
138  m_messageHelper->printWarning(0);
139  return nullptr;
140  }
141 
142  // take inner calorimeter scattering surface from extrapolated track
143  const Trk::Surface* surface = nullptr;
144  if (m_trackQuery->isCaloAssociated(extrapolatedTrack, ctx)) {
145  for (const Trk::TrackStateOnSurface* it : *extrapolatedTrack.trackStateOnSurfaces()) {
146  if (!it->materialEffectsOnTrack()) continue;
147 
148  const Amg::Vector3D& position = it->materialEffectsOnTrack()->associatedSurface().globalReferencePoint();
149 
150  if (m_indetVolume->inside(position)) continue;
151  if (!m_calorimeterVolume->inside(position)) break;
152 
153  surface = &it->materialEffectsOnTrack()->associatedSurface();
154  break;
155  }
156  }
157 
158  // match extrapolated indet track to inner calorimeter scattering surface
159  // provided momentum defined (solenoid on)
160  MagField::AtlasFieldCache fieldCache;
161  // Get field cache object
162  if (!loadMagneticField(ctx, fieldCache)) return nullptr;
163 
164  if (surface && fieldCache.solenoidOn() && !m_updateWithCaloTG) {
165  std::unique_ptr<const Trk::TrackStateOnSurface> innerTSOS;
166  if (m_useCaloTG) {
167  ATH_MSG_VERBOSE(" Retrieving Calorimeter TSOS from " << __func__ << " at line " << __LINE__);
168  std::vector<std::unique_ptr<const Trk::TrackStateOnSurface>> caloTSOS =
169  getCaloTSOSfromMatProvider(*indetTrack.perigeeParameters(), extrapolatedTrack);
170  if (!caloTSOS.empty()) { innerTSOS.swap(caloTSOS.front()); }
171  } else {
172  innerTSOS = m_caloTSOS->innerTSOS(ctx, *indetTrack.perigeeParameters());
173  }
174 
175  if (!innerTSOS) {
176  ATH_MSG_DEBUG(" indet track fails to intersect the calorimeter ");
177  return nullptr;
178  }
179 
180  // will re-associate the calorimeter if they are not the same surface
181  double surfaceOffset =
183 
184  if (surfaceOffset > 1. * Gaudi::Units::mm) {
185  ATH_MSG_DEBUG(" different inner-calo-surface obtained from indet extrapolation, "
186  << "surface reference " << surface->globalReferencePoint() << " with offset " << surfaceOffset
187  << "mm. Re-evaluate the caloTSOS ");
188 
189  surface = nullptr;
190  }
191  }
192 
193  std::unique_ptr<Trk::Track> muonTrack;
194  if (!fieldCache.toroidOn()) {
195  ATH_MSG_VERBOSE(" SL MS track: Calling createMuonTrack from " << __func__ << " at line " << __LINE__);
196  muonTrack =
197  createMuonTrack(ctx, indetTrack, indetTrack.perigeeParameters(), nullptr, extrapolatedTrack.trackStateOnSurfaces());
198  } else {
199  // create a muon track without perigee in case of non-optimal precision -
200  // such as need to replace calorimeter material or presence of pseudomeasurements
201  if (!surface) { // extrapolate outwards to associate calorimeter material effects
202  ATH_MSG_VERBOSE("Calling createMuonTrack from " << __func__ << " at line " << __LINE__);
203  muonTrack = createMuonTrack(
204  ctx, extrapolatedTrack, indetTrack.perigeeParameters(), nullptr, extrapolatedTrack.trackStateOnSurfaces());
205  } else if (m_trackQuery->numberPseudoMeasurements(extrapolatedTrack) > 1) { // remove pseudo meas
206  ATH_MSG_VERBOSE("Calling createMuonTrack from " << __func__ << " at line " << __LINE__);
207  muonTrack = createMuonTrack(ctx, extrapolatedTrack,
208  nullptr, nullptr, extrapolatedTrack.trackStateOnSurfaces());
209  } else { // otherwise can just copy the extrapolated track
210  ATH_MSG_VERBOSE("Calling createMuonTrack from " << __func__ << " at line " << __LINE__);
211  muonTrack =
212  createMuonTrack(ctx, extrapolatedTrack, extrapolatedTrack.perigeeParameters(), nullptr,
213  extrapolatedTrack.trackStateOnSurfaces());
214  }
215  }
216 
217  // no combined muon when failure to intersect calo
218  if (!muonTrack) return nullptr;
219 
220  if (msgLevel(MSG::DEBUG)) countAEOTs(*muonTrack, " muonTrack track before fit ");
221 
222  // combined track fit
223  std::unique_ptr<Trk::Track> combinedTrack{fit(ctx, indetTrack, *muonTrack, m_cleanCombined, Trk::muon)};
224 
225  // quit if fit failure or all MS measurements removed by fit or perigee outside indet
226  bool haveMS {false}, perigeeOutside{false};
227 
228  if (combinedTrack) {
229  if (msgLevel(MSG::DEBUG)) countAEOTs(*combinedTrack, " combinedTrack track after fit ");
230  ATH_MSG_VERBOSE(" combined track " << m_printer->print(*combinedTrack) << std::endl
231  << m_printer->printStations(*combinedTrack));
232 
233  auto rit = combinedTrack->trackStateOnSurfaces()->rbegin();
234  auto ritEnd = combinedTrack->trackStateOnSurfaces()->rend();
235  for (; rit != ritEnd; ++rit) {
236  if (!(**rit).measurementOnTrack() || !(**rit).trackParameters()) continue;
237  if (m_calorimeterVolume->inside((**rit).trackParameters()->position())) break;
238  if (!(**rit).type(Trk::TrackStateOnSurface::Outlier)) haveMS = true;
239  }
240 
241  if (!haveMS) {
242  // combinedTrack fails: MS removed by cleaner
243  m_messageHelper->printWarning(1);
244  }
245 
246  if (!combinedTrack->perigeeParameters() || !m_indetVolume->inside(combinedTrack->perigeeParameters()->position())) {
247  if (!combinedTrack->perigeeParameters()) {
248  ATH_MSG_DEBUG(" no perigee");
249  } else {
250  ATH_MSG_DEBUG(" position: r " << combinedTrack->perigeeParameters()->position().perp() << " z "
251  << combinedTrack->perigeeParameters()->position().z());
252  }
253  // combinedTrack fails as perigee outside indet
254  m_messageHelper->printWarning(2);
255  perigeeOutside = true;
256  }
257  }
258 
259  if (!combinedTrack || !combinedTrack->fitQuality() || !haveMS || perigeeOutside) {
260  bool hasFitQ = combinedTrack ? (combinedTrack->fitQuality() != nullptr) : false;
261  ATH_MSG_DEBUG("combinedTrack fails with bad fit" << combinedTrack.get() << " " << hasFitQ << " " << haveMS << " "
262  << perigeeOutside);
263 
264  return nullptr;
265  }
266 
267  // Get parameters at calo position
268  const Trk::TrackParameters* combinedEnergyParameters{nullptr}, *muonEnergyParameters{nullptr};
269  const CaloEnergy* caloEnergy {caloEnergyParameters(combinedTrack.get(), muonTrack.get(), combinedEnergyParameters, muonEnergyParameters)};
270 
271  if (!caloEnergy) {
272  // combinedTrack fails with missing caloEnergy
273  m_messageHelper->printWarning(3);
274  return nullptr;
275  }
276 
277  // if significant momentum change: re-evaluate calo energy and refit
278  double pRatio = muonEnergyParameters->momentum().mag() / combinedEnergyParameters->momentum().mag();
279  if (std::abs(pRatio - 1.) > m_largeMomentumChange || m_iterateCombinedTrackFit) {
281  ATH_MSG_DEBUG(" iterate combined fit to recollect calorimeter material as significant momentum change after fit "
282  << pRatio << ", pT before " << muonEnergyParameters->momentum().perp() / Gaudi::Units::GeV << ", after "
283  << combinedEnergyParameters->momentum().perp() / Gaudi::Units::GeV << " GeV");
284  } else {
285  ATH_MSG_DEBUG(" iterate combined fit to recollect calorimeter material");
286  }
287 
288  const Trk::TrackStates* combinedTSOS = combinedTrack->trackStateOnSurfaces();
289 
290  std::unique_ptr<Trk::Track> indetNewTrack{createIndetTrack(indetTrack.info(), combinedTSOS)};
291 
292  std::unique_ptr<Trk::Track> oldTrack(std::move(muonTrack));
293 
294  ATH_MSG_VERBOSE("Calling createMuonTrack from " << __func__ << " at line " << __LINE__);
295  muonTrack = createMuonTrack(ctx, extrapolatedTrack, combinedEnergyParameters, nullptr, combinedTSOS);
296 
297  if (indetNewTrack && muonTrack) {
298  std::unique_ptr<Trk::Track> refittedTrack{fit(ctx, *indetNewTrack, *muonTrack, m_cleanCombined, Trk::muon)};
299  caloEnergy = caloEnergyParameters(refittedTrack.get(), muonTrack.get(), combinedEnergyParameters, muonEnergyParameters);
300 
301  if (caloEnergy) {
302  combinedTrack.swap(refittedTrack);
303  } else {
304  // why does the refit fail? This shouldn't really be necessary
305  muonTrack.swap(oldTrack);
306  caloEnergy = caloEnergyParameters(combinedTrack.get(), muonTrack.get(), combinedEnergyParameters, muonEnergyParameters);
307  }
308  }
309  }
310 
311  // tracks with caloEnergy type 'tail' can arise from an incorrect categorization as isolated
312  // in case of significant energy gain, switch to parametrization and reclassify as NotIsolated
313  if (muonTrack && caloEnergy->energyLossType() == CaloEnergy::Tail && (!m_updateWithCaloTG || m_useCaloTG)) {
314  double tolerance = 0;
315 
316  if (!indetPerigee->covariance()) {
317  ATH_MSG_WARNING(" indetPerigee has no covariance tolerance left as zero. ");
318  } else {
319  tolerance = m_numberSigmaFSR * Amg::error((*indetPerigee->covariance()), Trk::qOverP);
320  }
321 
322  double indetMaxE = 1. / (std::abs(indetPerigee->parameters()[Trk::qOverP]) - tolerance);
323  double energyBalance = combinedEnergyParameters->momentum().mag() + caloEnergy->deltaE() - indetMaxE;
324 
325  // get parametrised eloss if large energy imbalance and refit track
326  std::unique_ptr<CaloEnergy> paramEnergy;
327  if (indetMaxE > 0. && energyBalance > m_numberSigmaFSR * caloEnergy->sigmaMinusDeltaE()) {
328  // parametrized energy deposition
329  // run-2 schema, update default eloss with parametrised value
330  if (m_useCaloTG) {
331  paramEnergy.reset(m_materialUpdator->getParamCaloELoss(muonTrack.get()));
332  } else {
333  // run-1 schema, recalculate parametrised eloss
334  paramEnergy = m_caloEnergyParam->energyLoss(ctx, combinedEnergyParameters->momentum().mag(),
335  combinedEnergyParameters->position().eta(),
336  combinedEnergyParameters->position().phi());
337  }
339  }
340 
341  // FIXME: add criterion on energy-balance significance param vs tail ?
342  if (paramEnergy) {
343  ATH_MSG_DEBUG(" FSR check: energyBalance "
344  << energyBalance / Gaudi::Units::GeV << " signif " << energyBalance / caloEnergy->sigmaMinusDeltaE()
345  << " indet max E " << indetMaxE / Gaudi::Units::GeV << std::endl
346  << " param CaloEnergy: " << paramEnergy->deltaE() / Gaudi::Units::GeV << " + "
347  << paramEnergy->sigmaPlusDeltaE() / Gaudi::Units::GeV << " for P "
348  << combinedEnergyParameters->momentum().mag() / Gaudi::Units::GeV << " eta "
349  << combinedEnergyParameters->position().eta() << " phi " << combinedEnergyParameters->position().phi()
350  << endmsg << " tail-param energy diff "
351  << (caloEnergy->deltaE() - paramEnergy->deltaE()) / Gaudi::Units::GeV);
352 
353  ATH_MSG_VERBOSE("Calling createMuonTrack from " << __func__ << " at line " << __LINE__);
354  muonTrack =
355  createMuonTrack(ctx, extrapolatedTrack, nullptr, std::move(paramEnergy), muonTrack->trackStateOnSurfaces());
356 
357  if (muonTrack) {
358  std::unique_ptr<Trk::Track> refittedTrack{fit(ctx, indetTrack, *muonTrack, m_cleanCombined, Trk::muon)};
359  if (refittedTrack) { combinedTrack.swap(refittedTrack); }
360  }
361  }
362  }
363 
364  // in case of the unexpected ...
365  if (!combinedTrack) {
366  // final combined track lost, this should not happen
367  m_messageHelper->printWarning(4);
368  return nullptr;
369  }
370 
372  ATH_MSG_VERBOSE("Refining Calorimeter TSOS in Muon Combined Fit ...");
373  m_materialUpdator->updateCaloTSOS(*combinedTrack);
374  }
375 
376  // adds uncertainties and removes AEOTs
377  // We will either have nullptr or a new Track.
378  // What we pass stays untouched.
379  std::unique_ptr<Trk::Track> newTrack = addIDMSerrors(combinedTrack.get());
380  // recollect eloss for combined track and refit
381  // newTrack will not be used after this block, either
382  // we updated the combined or kept the combined as it was
383  if (newTrack) {
384  if (msgLevel(MSG::DEBUG)) countAEOTs(*newTrack, " combinedTrack after addIDMSerrors ");
385  // Don't run the outliers anymore at this stage
386  dumpCaloEloss(newTrack.get(), "CB input TSOS after refine IDMS ");
387  std::unique_ptr<Trk::Track> refittedTrack{fit(ctx, *newTrack, false, Trk::muon)};
388  if (refittedTrack){
389  if (msgLevel(MSG::DEBUG)) countAEOTs(*refittedTrack, " CB fit after refit ");
390  dumpCaloEloss(refittedTrack.get(), "CB refit after refine IDMS ");
392  if (checkTrack("combinedFit", refittedTrack.get())) {
393  // Make the combined point to the refitted
394  combinedTrack.swap(refittedTrack);
395  }
396  }
397  }
398 
400  if (!checkTrack("addIDMS failed", combinedTrack.get())) {
401  ATH_MSG_DEBUG("addIDMS errors failed and original track does not pass checkTrack");
402  return nullptr;
403  }
404  // hole recovery, error optimization, attach TrackSummary
406 
407  return combinedTrack;
408  }
409  std::unique_ptr<Trk::Track> CombinedMuonTrackBuilder::indetExtension(const EventContext& ctx,
410  const Trk::Track& indetTrack,
411  const Trk::MeasurementSet& spectrometerMeasurements,
412  std::unique_ptr<Trk::TrackParameters> innerParameters,
413  std::unique_ptr<Trk::TrackParameters> middleParameters,
414  std::unique_ptr<Trk::TrackParameters> outerParameters) const {
415  if (msgLvl(MSG::VERBOSE)) {
416  msg(MSG::VERBOSE) << endmsg << "indetExtension fit:: " << std::setiosflags(std::ios::fixed);
417 
418  if (innerParameters || middleParameters || outerParameters) {
419  msg(MSG::VERBOSE) << " parameters at R,Z ";
420 
421  if (innerParameters) {
422  msg(MSG::VERBOSE) << "I:" << std::setw(5) << std::setprecision(0) << innerParameters->position().perp() << ","
423  << std::setw(5) << std::setprecision(0) << innerParameters->position().z() << " ";
424  }
425 
426  if (middleParameters) {
427  msg(MSG::VERBOSE) << "M:" << std::setw(5) << std::setprecision(0) << middleParameters->position().perp() << ","
428  << std::setw(5) << std::setprecision(0) << middleParameters->position().z() << " ";
429  }
430 
431  if (outerParameters) {
432  msg(MSG::VERBOSE) << "O:" << std::setw(6) << std::setprecision(0) << outerParameters->position().perp() << ","
433  << std::setw(5) << std::setprecision(0) << outerParameters->position().z();
434  }
435 
436  msg(MSG::VERBOSE) << " with P ";
437 
438  if (innerParameters) {
439  msg(MSG::VERBOSE) << std::setw(9) << std::setprecision(3) << innerParameters->momentum().mag() / Gaudi::Units::GeV;
440  }
441 
442  if (middleParameters) {
443  msg(MSG::VERBOSE) << std::setw(9) << std::setprecision(3) << middleParameters->momentum().mag() / Gaudi::Units::GeV;
444  }
445 
446  if (outerParameters) {
447  msg(MSG::VERBOSE) << std::setw(9) << std::setprecision(3) << outerParameters->momentum().mag() / Gaudi::Units::GeV;
448  }
449 
450  msg(MSG::VERBOSE) << " (GeV)" << endmsg;
451  } else {
452  msg(MSG::VERBOSE) << " without parameters" << endmsg;
453  }
454  }
455 
456  // propagate appropriate trackParameters to front, back and middle measurements
457  // fail when solenoid off and toroid on (as extrapolation from ID is not the correct strategy)
458  const Trk::IPropagator* propagator = m_propagatorSL.get();
459 
460  MagField::AtlasFieldCache fieldCache;
461  // Get field cache object
462  if (!loadMagneticField(ctx, fieldCache)) return nullptr;
463  if (fieldCache.toroidOn()) {
464  // fail when solenoid off and toroid on - as extrapolation from ID is not the correct strategy
465  // for material effects, fit starting value etc
466  if (!fieldCache.solenoidOn()) {
467  ATH_MSG_VERBOSE("indetExtension: method switched off when solenoid 'off' / toroid 'on'");
468  return nullptr;
469  }
470 
473  propagator = m_propagator.get();
474  }
475 
476  std::unique_ptr<Trk::TrackParameters> frontParameters, backParameters;
477 
478  if (innerParameters) {
479  if (innerParameters->associatedSurface() == spectrometerMeasurements.front()->associatedSurface()) {
480  frontParameters = innerParameters->uniqueClone();
481  } else {
482  // TSoS will own this
483  frontParameters = propagator->propagate(ctx, *innerParameters, spectrometerMeasurements.front()->associatedSurface(),
485  }
486  } else if (middleParameters) {
487  if (middleParameters->associatedSurface() == spectrometerMeasurements.front()->associatedSurface()) {
488  frontParameters = middleParameters->uniqueClone();
489  } else {
490  // TSoS will own this
491  frontParameters = propagator->propagate(ctx, *middleParameters, spectrometerMeasurements.front()->associatedSurface(),
493  }
494  }
495 
496  if (outerParameters) {
497  if (outerParameters->associatedSurface() == spectrometerMeasurements.back()->associatedSurface()) {
498  backParameters = outerParameters->uniqueClone();
499  } else {
500  // TSoS will own this
501  backParameters = propagator->propagate(ctx, *outerParameters, spectrometerMeasurements.back()->associatedSurface(),
503  }
504  } else if (middleParameters) {
505  if (middleParameters->associatedSurface() == spectrometerMeasurements.back()->associatedSurface()) {
506  backParameters = middleParameters->uniqueClone();
507  } else {
508  // TSoS will own this
509  backParameters = propagator->propagate(ctx, *middleParameters, spectrometerMeasurements.back()->associatedSurface(),
511  }
512  }
513 
514  // find middle measurement
515  std::unique_ptr<Trk::TrackParameters> midParameters;
516  const Trk::MeasurementBase* midMeasurement = nullptr;
517 
518  if (middleParameters && innerParameters && outerParameters) {
519  Amg::Vector3D direction = (outerParameters->position() - innerParameters->position()).unit();
520  double midDistance = 0.5 * direction.dot(outerParameters->position() - innerParameters->position());
521  double previousDistance = 0.;
522 
523  Trk::MeasurementSet::const_iterator m = spectrometerMeasurements.begin();
524  for (++m; m != spectrometerMeasurements.end(); ++m) {
525  double distance = direction.dot((**m).globalPosition() - innerParameters->position());
526  if (distance < midDistance) {
527  previousDistance = distance;
528  } else {
529  if (midDistance - previousDistance < distance - midDistance) --m;
530  // TSoS will own this
531  midParameters = m_propagator->propagate(ctx, *middleParameters, (**m).associatedSurface(), Trk::anyDirection, false,
533 
534  if (midParameters) midMeasurement = *m;
535  break;
536  }
537  }
538  }
539 
540  // create muon track from spectrometer measurements
541  std::bitset<Trk::TrackStateOnSurface::NumberOfTrackStateOnSurfaceTypes> typeM;
543  std::bitset<Trk::TrackStateOnSurface::NumberOfTrackStateOnSurfaceTypes> typeP;
546 
547  auto trackStateOnSurfaces = std::make_unique<Trk::TrackStates>();
548 
549  trackStateOnSurfaces->reserve(spectrometerMeasurements.size());
550 
551  // append the spectrometer measurements
552  for (const Trk::MeasurementBase* const in_meas : spectrometerMeasurements) {
553  if (frontParameters) {
554  trackStateOnSurfaces->push_back(
555  new Trk::TrackStateOnSurface(in_meas->uniqueClone(), std::move(frontParameters), nullptr, typeP));
556  } else if (in_meas == midMeasurement) {
557  trackStateOnSurfaces->push_back(
558  new Trk::TrackStateOnSurface(in_meas->uniqueClone(), std::move(midParameters), nullptr, typeP));
559  } else if (backParameters && in_meas == spectrometerMeasurements.back()) {
560  trackStateOnSurfaces->push_back(
561  new Trk::TrackStateOnSurface(in_meas->uniqueClone(), std::move(backParameters), nullptr, typeP));
562  } else {
563  trackStateOnSurfaces->push_back(
564  new Trk::TrackStateOnSurface(in_meas->uniqueClone(), nullptr, nullptr, typeM));
565  }
566  }
567 
569 
570  Trk::Track muonTrack(trackInfo, std::move(trackStateOnSurfaces), nullptr);
571  if (msgLevel(MSG::DEBUG)) countAEOTs(muonTrack, " in detExtension muonTrack ");
572  // perform combined fit
573  ATH_MSG_VERBOSE("Calling combinedFit from " << __func__ << " at line " << __LINE__);
574  std::unique_ptr<Trk::Track> combinedTrack{combinedFit(ctx, indetTrack, muonTrack, muonTrack)};
575  return combinedTrack;
576  }
577  std::unique_ptr<Trk::Track> CombinedMuonTrackBuilder::standaloneFit(const EventContext& ctx, const Trk::Track& inputSpectrometerTrack,
578  const Amg::Vector3D& origin, const Trk::Vertex* inputVertex) const {
579  MagField::AtlasFieldCache fieldCache;
580  // Get field cache object
581 
582  if (!loadMagneticField(ctx, fieldCache)) return nullptr;
583 
584  // no SA fit with vertex constraint for Toroid off data
585  if (m_trackQuery->isLineFit(inputSpectrometerTrack) && !fieldCache.toroidOn()) { return nullptr; }
586 
587  ATH_MSG_DEBUG(" standaloneFit beam position bs_x " << origin << " inputVertex "
588  << inputVertex);
589 
590  if (msgLvl(MSG::VERBOSE)) {
591  msg(MSG::VERBOSE) << endmsg << "==== Start of standaloneFit:: " << std::setiosflags(std::ios::fixed);
592 
593  if (m_trackQuery->isExtrapolated(inputSpectrometerTrack, ctx)) {
594  if (m_trackQuery->isLineFit(inputSpectrometerTrack)) {
595  msg(MSG::VERBOSE) << "extrapolated has lineFit";
596  } else {
597  msg(MSG::VERBOSE) << "extrapolated momentum " << std::setprecision(1)
598  << inputSpectrometerTrack.perigeeParameters()->momentum().mag() / Gaudi::Units::GeV << " (GeV)";
599  }
600 
601  msg(MSG::VERBOSE) << " at eta " << std::setw(6) << std::setprecision(3)
602  << inputSpectrometerTrack.perigeeParameters()->momentum().eta() << " phi " << std::setw(6)
603  << std::setprecision(3) << inputSpectrometerTrack.perigeeParameters()->momentum().phi();
604 
605  } else if (!m_trackQuery->isProjective(inputSpectrometerTrack)) {
606  msg(MSG::VERBOSE) << "spectrometer track does not project";
607  } else if (inputSpectrometerTrack.perigeeParameters()) {
608  if (m_trackQuery->isLineFit(inputSpectrometerTrack)) {
609  msg(MSG::VERBOSE) << "spectrometer has lineFit";
610  } else {
611  msg(MSG::VERBOSE) << "spectrometer momentum " << std::setprecision(1)
612  << inputSpectrometerTrack.perigeeParameters()->momentum().mag() / Gaudi::Units::GeV << " (GeV)";
613  }
614 
615  msg(MSG::VERBOSE) << " at eta " << std::setw(6) << std::setprecision(3)
616  << inputSpectrometerTrack.perigeeParameters()->position().eta() << " phi " << std::setw(6)
617  << std::setprecision(3) << inputSpectrometerTrack.perigeeParameters()->position().phi();
618 
619  if (inputSpectrometerTrack.perigeeParameters()->covariance()) {
620  msg(MSG::VERBOSE) << " hasCov";
621  } else {
622  msg(MSG::VERBOSE) << " noCov ";
623  }
624  } else {
625  msg(MSG::VERBOSE) << " spectrometer track without PerigeeParameters";
626  }
627 
628  if (inputSpectrometerTrack.fitQuality()) {
629  msg(MSG::VERBOSE) << " fit: chi2 /DoF " << std::setprecision(2) << normalizedChi2(inputSpectrometerTrack) << " /"
630  << std::setw(2) << inputSpectrometerTrack.fitQuality()->numberDoF();
631  }
632 
633  if (m_trackQuery->numberPseudoMeasurements(inputSpectrometerTrack)) {
634  msg(MSG::VERBOSE) << " pseudo " << m_trackQuery->numberPseudoMeasurements(inputSpectrometerTrack);
635  }
636 
637  msg(MSG::VERBOSE) << endmsg;
638  }
639 
640  // check input vertex OK
641  const Trk::RecVertex* vertex = dynamic_cast<const Trk::RecVertex*>(inputVertex);
642  if (inputVertex && !vertex) {
643  // input vertex fails dynamic_cast
644  m_messageHelper->printWarning(6);
645  return nullptr;
646  }
647 
648  // fail input tracks with insufficient measurements or inconsistent structure
649  const Trk::FitQuality* fitQuality = inputSpectrometerTrack.fitQuality();
650  const Trk::TrackStates* tsos = inputSpectrometerTrack.trackStateOnSurfaces();
651 
652  if (!fitQuality || !inputSpectrometerTrack.trackStateOnSurfaces() ||
653  static_cast<int>(inputSpectrometerTrack.trackStateOnSurfaces()->size()) < fitQuality->numberDoF()) {
654  // count measurements
655  int measurements = 0;
656  for (const Trk::TrackStateOnSurface* s : *tsos) {
658  }
659  // insufficient measurements
660  if (measurements < 4) {
661  m_messageHelper->printWarning(48);
662  ATH_MSG_VERBOSE(" SA::failed (1)");
663  return nullptr;
664  }
665 
666  // inconsistent TSOS on input track
667  if (fitQuality && measurements < fitQuality->numberDoF() + 4) {
668  m_messageHelper->printWarning(49);
669  ATH_MSG_VERBOSE(" SA::failed (2)");
670  return nullptr;
671  }
672  }
673 
674  // check the track is roughly projective in phi
675  const bool is_extrapolated = m_trackQuery->isExtrapolated(inputSpectrometerTrack, ctx);
676  if (!is_extrapolated && !m_trackQuery->isProjective(inputSpectrometerTrack)) {
677  ATH_MSG_VERBOSE(" SA::failed (3)");
678  return nullptr;
679  }
680 
681  // possibly refit the spectrometer track with material reallocation
682  double spectrometerFitChi2 = normalizedChi2(inputSpectrometerTrack);
683  std::unique_ptr<Trk::Track> spectrometerFit = std::make_unique<Trk::Track>(inputSpectrometerTrack);
684  if (!vertex && (m_reallocateMaterial || is_extrapolated)) {
685  spectrometerFit = reallocateMaterial(ctx, inputSpectrometerTrack);
686  if (!spectrometerFit) {
687  ATH_MSG_VERBOSE(" SA::failed (4)");
688  return nullptr;
689  }
690  }
691 
692  const Trk::Track& spectrometerTrack = *spectrometerFit;
693 
694  // require a Perigee from the spectrometer track
695  const Trk::Perigee* measuredPerigee = spectrometerTrack.perigeeParameters();
696 
697  if (!measuredPerigee || !measuredPerigee->covariance()) {
698  // missing MeasuredPerigee for spectrometer track
699  m_messageHelper->printWarning(7);
700 
701  ATH_MSG_VERBOSE(" SA::failed (5)");
702  return nullptr;
703  }
704 
705  // set measured momentum error and starting parameters
706  bool badlyDeterminedCurvature = false;
707 
708  if (!Amg::hasPositiveDiagElems(*measuredPerigee->covariance())) {
709  ATH_MSG_WARNING("standaloneFit: measuredPerigee has non-positive-definite covariance ");
710  ATH_MSG_VERBOSE(" SA::failed (5.5)");
712  return nullptr;
713  }
714 
715  double errorP = std::sqrt(measuredPerigee->momentum().mag2() * (*measuredPerigee->covariance())(Trk::qOverP, Trk::qOverP));
716 
717  std::unique_ptr<Trk::RecVertex> mvertex = std::make_unique<Trk::RecVertex>(*m_vertex);
718  std::unique_ptr<Trk::RecVertex> mbeamAxis = std::make_unique<Trk::RecVertex>(*m_beamAxis);
719  std::unique_ptr<Trk::PerigeeSurface> mperigeeSurface = std::make_unique<Trk::PerigeeSurface>(*m_perigeeSurface);
720 
721  std::unique_ptr<const Trk::TrackParameters> parameters;
722 
723  if (vertex) {
724  // vertex association only makes sense for magnet-on tracks with measured curvature
725  if (!fieldCache.toroidOn() || m_trackQuery->isLineFit(spectrometerTrack) || errorP > m_largeMomentumError) {
726  ATH_MSG_VERBOSE("standaloneFit: vertex fit not attempted as curvature badly measured");
727  ATH_MSG_VERBOSE(" SA::failed (6)");
728  return nullptr;
729  }
730  parameters = std::make_unique<Trk::Perigee>(*spectrometerTrack.perigeeParameters());
731  } else {
732  //
733  // update -if needed vertex and beam axis positions
734  //
735  if ((origin - mvertex->position()).mag() > 0.001) {
736  // recreate beamAxis and vertexRegion for constrained (projective) track fits
737 
738  mperigeeSurface = std::make_unique<Trk::PerigeeSurface>(origin);
739 
740  AmgSymMatrix(3) beamAxisCovariance;
741  beamAxisCovariance.setZero();
742  (beamAxisCovariance)(0, 0) = m_vertex2DSigmaRPhi * m_vertex2DSigmaRPhi;
743  (beamAxisCovariance)(1, 1) = m_vertex2DSigmaRPhi * m_vertex2DSigmaRPhi;
744  (beamAxisCovariance)(2, 2) = m_vertex2DSigmaZ * m_vertex2DSigmaZ;
745  mbeamAxis = std::make_unique<Trk::RecVertex>(origin, beamAxisCovariance);
746 
747  AmgSymMatrix(3) vertexRegionCovariance;
748  vertexRegionCovariance.setZero();
749  (vertexRegionCovariance)(0, 0) = m_vertex3DSigmaRPhi * m_vertex3DSigmaRPhi;
750  (vertexRegionCovariance)(1, 1) = m_vertex3DSigmaRPhi * m_vertex3DSigmaRPhi;
751  (vertexRegionCovariance)(2, 2) = m_vertex3DSigmaZ * m_vertex3DSigmaZ;
752  mvertex = std::make_unique<Trk::RecVertex>(origin, vertexRegionCovariance);
753  }
754 
755  parameters = extrapolatedParameters(ctx, badlyDeterminedCurvature, spectrometerTrack, mvertex.get(), mperigeeSurface.get());
756  }
757 
758  if (!parameters) {
759  ATH_MSG_VERBOSE(" SA::failed (7)");
760  return nullptr;
761  }
762 
763  // create the spectrometer TSOS's for the extrapolated fit
764  std::vector<std::unique_ptr<const Trk::TrackStateOnSurface>> spectrometerTSOS = createSpectrometerTSOS(ctx, spectrometerTrack);
765 
766  if (spectrometerTSOS.empty()) {
767  ATH_MSG_VERBOSE(" SA::failed (8)");
768  return nullptr;
769  }
770  const Trk::TrackParameters* caloParameters = nullptr;
771 
772  Trk::ParticleHypothesis particleHypothesis = Trk::muon;
773 
774  bool haveFitWithVertex = false;
775  bool performPrefit = false;
776 
777  if (m_redoRots) {
778  for (const Trk::TrackStateOnSurface* s : *spectrometerTrack.trackStateOnSurfaces()) {
779  if (s->measurementOnTrack() && !s->trackParameters()) {
780  performPrefit = true;
781  break;
782  }
783  }
784  }
785 
786  // badly defined tracks use weak vertex constraint with prefit before calo association
787  std::unique_ptr<Trk::Track> prefit;
788 
789  const Trk::RecVertex* vertexInFit = vertex;
790 
791  if (!vertexInFit) {
792  double errorPhi = std::sqrt((*measuredPerigee->covariance())(Trk::phi0, Trk::phi0));
793 
794  bool inCSCregion = std::abs(measuredPerigee->momentum().eta()) > 2.0;
795 
796  // FIXME: missing prefit case for excessive spectrometer eloss WARNING
797  // spot from line starting approx from vertex??
798  if (inCSCregion || m_trackQuery->numberPseudoMeasurements(spectrometerTrack) ||
799  (fieldCache.toroidOn() &&
800  (badlyDeterminedCurvature || errorPhi > m_largePhiError || measuredPerigee->momentum().mag() < m_lowMomentum))) {
801  performPrefit = true;
802  vertexInFit = (badlyDeterminedCurvature || inCSCregion) ? mvertex.get() : mbeamAxis.get();
803 
804  if (msgLvl(MSG::DEBUG)) {
805  unsigned numberPseudo = m_trackQuery->numberPseudoMeasurements(spectrometerTrack);
806  if (errorPhi > s_sigmaPhiSector) { ++numberPseudo; }
807 
808  if (badlyDeterminedCurvature) {
809  ATH_MSG_DEBUG(" prefit with vertex: " << std::setiosflags(std::ios::fixed) << " momentum " << std::setprecision(1)
810  << measuredPerigee->momentum().mag() / Gaudi::Units::GeV << " (GeV), zFirst "
811  << std::setprecision(1) << std::abs(parameters->position().z())
812  << ", phiError " << std::setprecision(2) << errorPhi << ", momentumError "
813  << std::setprecision(2) << errorP << ", numberPseudo " << numberPseudo);
814  } else {
815  ATH_MSG_DEBUG(" prefit with beamAxis: "
816  << std::setiosflags(std::ios::fixed) << " momentum " << std::setprecision(1)
817  << measuredPerigee->momentum().mag() / Gaudi::Units::GeV << " (GeV), zFirst " << std::setprecision(1)
818  << std::abs(parameters->position().z()) << ", phiError " << std::setprecision(2) << errorPhi
819  << ", momentumError " << std::setprecision(2) << errorP << ", numberPseudo " << numberPseudo);
820  }
821  }
822  }
823  }
824 
825  std::unique_ptr<const Trk::Perigee> prefitResult;
826 
827  // prefit to stabilize calo look-up and/or provide trackParameters
828  if (performPrefit) {
829  if (!vertexInFit) { ATH_MSG_VERBOSE(" prefit without vertex"); }
830 
831  if (vertexInFit) { haveFitWithVertex = true; }
832 
833  if (badlyDeterminedCurvature && parameters->momentum().mag() > m_lowMomentum) { particleHypothesis = Trk::nonInteracting; }
834 
835  ATH_MSG_VERBOSE("Calling createExtrapolatedTrack from " << __func__ << " at line " << __LINE__);
836  prefit = createExtrapolatedTrack(ctx, spectrometerTrack, *parameters, particleHypothesis, false, spectrometerTSOS, vertexInFit,
837  mbeamAxis.get(), mperigeeSurface.get());
838 
839  // demand prefit success
840  if (!prefit || !prefit->fitQuality() || !prefit->perigeeParameters()) {
841  ATH_MSG_DEBUG(" prefit failure ");
842  prefit.reset();
843  }
844 
845  if (prefit) {
846  dumpCaloEloss(prefit.get(), " prefit ");
847  bool hasCov = prefit->perigeeParameters() ? (prefit->perigeeParameters()->covariance() != nullptr) : false;
848  ATH_MSG_VERBOSE(" got prefit " << m_printer->print(*prefit) << " hasCov " << hasCov);
849 
850  if (prefit->perigeeParameters()) { prefitResult.reset(prefit->perigeeParameters()->clone()); }
851  const Trk::TrackStateOnSurface* ms_entrance = nullptr;
852  for (const Trk::TrackStateOnSurface* s : *prefit->trackStateOnSurfaces()) {
853  // look for first measured TSOS in muon volume
854  if (!s->trackParameters() || !s->trackParameters()->covariance()) { continue; }
855  if (m_calorimeterVolume->inside(s->trackParameters()->position())) { continue; }
856 
857  // check that it is a measurement
859  ATH_MSG_DEBUG("Found first parameters in MS " << s->trackParameters()->position().perp() << " z "
860  << s->trackParameters()->position().z());
861  ms_entrance = s;
862  break;
863  }
864  }
865 
866  if (ms_entrance && ms_entrance != prefit->trackStateOnSurfaces()->front() && ms_entrance->trackParameters()) {
867  parameters.reset(ms_entrance->trackParameters()->clone());
868  caloParameters = parameters.get();
869  } else {
870  // prefit: no parameter extrapolation to calo
871  m_messageHelper->printWarning(9);
872  }
873  }
874 
875  // give up if prefit fails
876  spectrometerTSOS.clear();
877 
878  if (!prefit) {
879  ATH_MSG_VERBOSE(" SA::failed (9)");
880  return nullptr;
881  }
882  const Trk::TrackStates* prefit_tsos = prefit->trackStateOnSurfaces();
883  // create spectrometerTSOS corresponding to prefit
884  // skip start perigee, then preferentially take everything following MS perigee,
885  // otherwise (if no MS perigee) rely on VolumesSvc,
886  // but be aware that by design there are inconsistencies wrt tracking geometry
888  std::find_if(prefit_tsos->begin() + 1, prefit_tsos->end(), [this](const Trk::TrackStateOnSurface* tsos) -> bool {
889  return (tsos->trackParameters() && !m_calorimeterVolume->inside(tsos->trackParameters()->position())) ||
890  tsos->type(Trk::TrackStateOnSurface::Perigee);
891  });
892 
893  if (s != prefit_tsos->end() && (*s)->type(Trk::TrackStateOnSurface::Perigee)) ++s;
894 
895  for (; s != prefit_tsos->end(); ++s) { spectrometerTSOS.emplace_back((*s)->clone()); }
896  }
897 
898  if (m_redoRots) {
899  // recalibration: correct rots
900  for (std::unique_ptr<const Trk::TrackStateOnSurface>& t : spectrometerTSOS) {
901  if (!t->measurementOnTrack() || !t->trackParameters()) { continue; } // end of if
902 
903  const Trk::RIO_OnTrack* rot = dynamic_cast<const Trk::RIO_OnTrack*>(t->measurementOnTrack());
904 
905  if (!rot) continue;
906  Identifier id = rot->identify();
907 
908  if (!m_idHelperSvc->isMuon(id)) continue;
909 
910  std::unique_ptr<Trk::RIO_OnTrack> updatedRot;
911  if (!m_cscRotCreator.empty() && m_idHelperSvc->isCsc(id)) {
912  updatedRot.reset(m_cscRotCreator->correct(*rot->prepRawData(), *(*t).trackParameters()));
913  } else if (!m_mdtRotCreator.empty() && m_idHelperSvc->isMdt(id)) {
914  updatedRot.reset(m_mdtRotCreator->correct(*rot->prepRawData(), *(*t).trackParameters()));
915  } else if (!m_muClusterRotCreator.empty() && (m_idHelperSvc->isMM(id) || m_idHelperSvc->issTgc(id))) {
916  updatedRot.reset(m_muClusterRotCreator->correct(*rot->prepRawData(), *(*t).trackParameters()));
917  }
918 
919  if (updatedRot) {
920  t = Muon::MuonTSOSHelper::createMeasTSOS(std::move(updatedRot), t->trackParameters()->uniqueClone(),
922  }
923  }
924  }
925 
926  // extrapolate and fit track
927  particleHypothesis = Trk::muon;
928  bool returnAfterCleaner = !fieldCache.toroidOn();
929 
930  ATH_MSG_VERBOSE("Calling createExtrapolatedTrack from " << __func__ << " at line " << __LINE__);
931  std::unique_ptr<Trk::Track> extrapolated(createExtrapolatedTrack(ctx, spectrometerTrack, *parameters, particleHypothesis,
932  m_cleanStandalone, spectrometerTSOS, vertexInFit, mbeamAxis.get(),
933  mperigeeSurface.get(), prefitResult.get()));
934 
935  if (extrapolated) dumpCaloEloss(extrapolated.get(), " extrapolated ");
936 
937  // fit problem: try fixup using vertex region or prefit
938  if (!extrapolated || !extrapolated->fitQuality()) {
939  if (extrapolated && !haveFitWithVertex && !vertexInFit) {
940  ATH_MSG_DEBUG(" bad fitQuality: retry with vertex ");
941  std::unique_ptr<Trk::Track> badfit(std::move(extrapolated));
942 
943  auto trackStateOnSurfaces = std::make_unique<Trk::TrackStates>();
944  trackStateOnSurfaces->reserve(badfit->trackStateOnSurfaces()->size() + 1);
945 
946  std::bitset<Trk::TrackStateOnSurface::NumberOfTrackStateOnSurfaceTypes> type{};
948  std::unique_ptr<Trk::PseudoMeasurementOnTrack> vertexInFit =
949  vertexOnTrack(*badfit->perigeeParameters(), mvertex.get(), mbeamAxis.get());
950 
951  if (vertexInFit) type.set(Trk::TrackStateOnSurface::Measurement);
952 
953  trackStateOnSurfaces->push_back(new Trk::TrackStateOnSurface(
954  std::move(vertexInFit), badfit->perigeeParameters()->uniqueClone(), nullptr, type));
955 
957  s != badfit->trackStateOnSurfaces()->end(); ++s) {
958  trackStateOnSurfaces->push_back((**s).clone());
959  }
960 
961  std::unique_ptr<Trk::Track> track =
962  std::make_unique<Trk::Track>(spectrometerTrack.info(), std::move(trackStateOnSurfaces), nullptr);
963  extrapolated = fit(ctx, *track, m_cleanStandalone, particleHypothesis);
964  }
965 
966  // restart from prefit without cleaning
967  if (!extrapolated || !extrapolated->fitQuality()) {
968  if (prefit && prefit->fitQuality() && caloParameters) {
969  ATH_MSG_DEBUG(" restarting from prefit as back extrapolation fit failed");
970  spectrometerTSOS.clear();
971  // create spectrometerTSOS corresponding to prefit
973 
974  while (m_calorimeterVolume->inside((**s).trackParameters()->position()) ||
975  (**s).type(Trk::TrackStateOnSurface::Perigee)) {
976  ++s;
977  } // end of while
978 
979  for (; s != prefit->trackStateOnSurfaces()->end(); ++s) { spectrometerTSOS.emplace_back((**s).clone()); }
980 
981  ATH_MSG_VERBOSE("Calling createExtrapolatedTrack from " << __func__ << " at line " << __LINE__);
982  extrapolated =
983  createExtrapolatedTrack(ctx, spectrometerTrack, *caloParameters, particleHypothesis, false, spectrometerTSOS,
984  vertexInFit, mbeamAxis.get(), mperigeeSurface.get(), prefitResult.get());
985  returnAfterCleaner = true;
986  }
987 
988  if (!extrapolated || !extrapolated->fitQuality()) {
989  bool hasFQ = extrapolated ? (extrapolated->fitQuality() != nullptr) : false;
990  ATH_MSG_DEBUG("fail track as back extrapolation fit failed " << extrapolated.get() << " hasFQ " << hasFQ);
991 
992  ATH_MSG_VERBOSE(" SA::failed (10)");
993  return nullptr;
994  }
995  }
996  }
997 
998  // keep statistics for successful fits
1000  if (vertexInFit == mbeamAxis.get()) ++m_countBeamAxis;
1001  if (vertexInFit == mvertex.get()) ++m_countVertexRegion;
1002 
1003  // refit when there's been a significant momentum change (parameters at last calo scatterer)
1004  double momentum = parameters->momentum().mag();
1005 
1006  bool allowRefit = !badlyDeterminedCurvature;
1007  double pRatio = 1.;
1008 
1009  const Trk::TrackParameters* params_pRat = parameters.get();
1010  if (returnAfterCleaner) {
1011  allowRefit = false;
1012  } else {
1013  // pRatio is the ratio of fitted to start momentum value at calo exit
1014  // find parameters at calo exit
1015  const Trk::TrackParameters* params_pRat = nullptr;
1016  auto s = extrapolated->trackStateOnSurfaces()->begin();
1017  while (!(**s).trackParameters() || m_calorimeterVolume->inside((**s).trackParameters()->position())) {
1018  if ((**s).trackParameters() && !(**s).type(Trk::TrackStateOnSurface::Perigee)) params_pRat = (**s).trackParameters();
1019  ++s;
1020  }
1021 
1022  // extrapolated fit with missing calo parameters - this should never happen!
1023  if (params_pRat) {
1024  pRatio = momentum / parameters->momentum().mag();
1025  } else {
1026  // extrapolated track missing TrackParameters at calo scatterer
1027  m_messageHelper->printWarning(10);
1028  allowRefit = false;
1029  }
1030  }
1031 
1032  // in case of a significant momentum change: iterate (re-associate calo and refit)
1033  std::unique_ptr<Trk::Track> track;
1034 
1035  if (allowRefit && std::abs(pRatio - 1.) > m_largeMomentumChange) {
1036  if (msgLvl(MSG::VERBOSE)) {
1037  double sinTheta = params_pRat->momentum().perp() / params_pRat->momentum().mag();
1038 
1039  ATH_MSG_VERBOSE(" iterate as significant momentum change after fit "
1040  << pRatio << ", pT before " << momentum * sinTheta / Gaudi::Units::GeV << ", after "
1041  << params_pRat->momentum().perp() / Gaudi::Units::GeV << " GeV");
1042  }
1043 
1044  spectrometerTSOS.clear();
1045  for (const Trk::TrackStateOnSurface* s : *extrapolated->trackStateOnSurfaces()) {
1046  if (!s->type(Trk::TrackStateOnSurface::Perigee)) spectrometerTSOS.emplace_back(s->clone());
1047  }
1048 
1049  ATH_MSG_VERBOSE("Calling createExtrapolatedTrack from " << __func__ << " at line " << __LINE__);
1050 
1051  track = createExtrapolatedTrack(ctx, spectrometerTrack, *parameters, particleHypothesis, m_cleanStandalone, spectrometerTSOS,
1052  vertexInFit, mbeamAxis.get(), mperigeeSurface.get(), extrapolated->perigeeParameters());
1053 
1054  if (track) {
1055  double extrapChi2 = normalizedChi2(*extrapolated);
1056  double fitChi2 = normalizedChi2(*track);
1057  if (fitChi2 < m_badFitChi2 || fitChi2 < extrapChi2 + 0.5) { extrapolated.reset(); }
1058  }
1059  }
1060  if (extrapolated) { track.swap(extrapolated); }
1061 
1062  if (!m_trackQuery->isCaloAssociated(*track, ctx)) { // still want to perform this check probably though
1063  // fail as calo incorrectly described
1064  m_messageHelper->printWarning(12);
1065  ATH_MSG_VERBOSE(" SA::failed (12)");
1066  return nullptr;
1067  }
1068 
1069  int improvementsFailed = 0; // count the number of times the fit fails after improvements
1070 
1072  ATH_MSG_VERBOSE("Refining Calorimeter TSOS in StandAlone Fit ...");
1073 
1074  m_materialUpdator->updateCaloTSOS(*track);
1075 
1076  std::unique_ptr<Trk::Track> refinedTrack(fit(ctx, *track, false, Trk::muon));
1077  if (checkTrack("refineFit", refinedTrack.get())) {
1078  ATH_MSG_VERBOSE(__FILE__<<":"<<__LINE__<<"refined track checks out");
1079  track.swap(refinedTrack);
1080  } else {
1081  ATH_MSG_VERBOSE("refined track fit failed");
1082  ++improvementsFailed;
1083  }
1084  }
1085 
1086  // adds uncertainties
1087  // We will either have nullptr or a new Track.
1088  // What we pass stays untouched.
1089  std::unique_ptr<Trk::Track> newTrack = addIDMSerrors(track.get());
1090  // newTrack will not be used after this block, either
1091  // we updated the track or kept the track as it was
1092  if (newTrack) {
1093  if (msgLevel(MSG::DEBUG)) countAEOTs(*newTrack, " SA track after addIDMSerrors ");
1094  dumpCaloEloss(newTrack.get(), "SA input TSOS after refine IDMS ");
1095 
1096  // Don't run the outliers anymore at this stage
1097  std::unique_ptr<Trk::Track> refittedTrack(fit(ctx, *newTrack, false, Trk::muon));
1098  if (msgLevel(MSG::DEBUG)) { countAEOTs(*refittedTrack, " SA track after refit "); }
1099  dumpCaloEloss(refittedTrack.get(), " SA refit after refine IDMS ");
1100  if (checkTrack("standaloneFit", refittedTrack.get())) {
1101  // Here we swap
1102  track.swap(refittedTrack);
1103  } else {
1104  ++improvementsFailed;
1105  }
1106  } else {
1107  ++improvementsFailed;
1108  }
1109 
1110  // hole recovery, error optimization, attach TrackSummary
1111  finalTrackBuild(ctx, track);
1112 
1113  if (track) {
1114  dumpCaloEloss(track.get(), " finalTrackBuild ");
1115 
1116  // report when extrapolated fit quality significantly worse than spectrometer quality
1117  double fitChi2 = normalizedChi2(*track);
1118  if (fitChi2 > m_badFitChi2 && fitChi2 > spectrometerFitChi2 + 0.5) {
1119  ATH_MSG_DEBUG("standaloneFit: fit quality degraded wrt spectrometer alone. "
1120  << " Chi2/DoF= " << fitChi2);
1121 
1123  if (improvementsFailed >= 2) {
1124  ATH_MSG_DEBUG("reject track, quality degraded and improvements failed");
1125  return nullptr;
1126  }
1127  }
1128  }
1129  ATH_MSG_VERBOSE(" SA::ok ");
1130  return track;
1131  }
1132  std::unique_ptr<Trk::Track> CombinedMuonTrackBuilder::standaloneRefit(const EventContext& ctx, const Trk::Track& combinedTrack,
1133  const Amg::Vector3D& origin) const {
1134  //
1135  // update -if needed vertex and beam axis positions
1136  //
1137 
1138  if (msgLevel(MSG::DEBUG)) countAEOTs(combinedTrack, " in standalone Refit input combinedTrack ");
1139 
1140  MagField::AtlasFieldCache fieldCache;
1141  // Get field cache object
1142 
1143  if (!loadMagneticField(ctx, fieldCache)) return nullptr;
1144 
1145  if (!fieldCache.toroidOn()) {
1146  // no standalone refit for Toroid off
1147  return nullptr;
1148  }
1149 
1150  ATH_MSG_DEBUG(" StandaloneRefit beam position bs_x " << origin);
1151 
1152  // vertex will change track by track
1153  AmgSymMatrix(3) vertexRegionCovariance{AmgSymMatrix(3)::Zero()};
1154 
1155  double error2d0 = m_vertex3DSigmaRPhi * m_vertex3DSigmaRPhi;
1156  double error2z0 = m_vertex3DSigmaZ * m_vertex3DSigmaZ;
1157  const Trk::Perigee* measuredPerigee = combinedTrack.perigeeParameters();
1158 
1159  if (measuredPerigee && measuredPerigee->covariance() && m_useRefitTrackError) {
1160  error2d0 = (*measuredPerigee->covariance())(Trk::d0, Trk::d0);
1161  error2z0 = (*measuredPerigee->covariance())(Trk::z0, Trk::z0);
1162  ATH_MSG_DEBUG(" StandaloneRefit new vertex d0 error " << std::sqrt(error2d0) << " new vertex z0 error "
1163  << std::sqrt(error2z0));
1164  }
1165 
1166  (vertexRegionCovariance)(0, 0) = error2d0;
1167  (vertexRegionCovariance)(1, 1) = error2d0;
1168  (vertexRegionCovariance)(2, 2) = error2z0;
1169 
1170  std::unique_ptr<Trk::RecVertex> vertex = std::make_unique<Trk::RecVertex>(origin, vertexRegionCovariance);
1171 
1172  ATH_MSG_DEBUG(" StandaloneRefit new vertex position x " << vertex->position().x() << " y " << vertex->position().y() << " z "
1173  << vertex->position().z());
1174 
1175  bool addPhiPseudo = false;
1176  // release 21
1177  unsigned spectrometerPhiQuality = m_trackQuery->spectrometerPhiQuality(combinedTrack, ctx);
1178  if (spectrometerPhiQuality > 1) { addPhiPseudo = true; }
1179 
1180  ATH_MSG_VERBOSE("standaloneRefit: using vertex region constraint with "
1181  << "spectrometerPhiQuality " << spectrometerPhiQuality);
1182 
1183  // create standalone track TSOS vector
1184  auto trackStateOnSurfaces = std::make_unique<Trk::TrackStates>();
1185 
1186  // size will allow for perigee + all TSOS outside indet
1187  unsigned size = combinedTrack.trackStateOnSurfaces()->size() + 3 + addPhiPseudo;
1188 
1189  trackStateOnSurfaces->reserve(size);
1190 
1191  // position TSOS iterator to be just after the indet
1192  bool haveCaloDeposit = false;
1193 
1194  Trk::TrackStates::const_iterator s = combinedTrack.trackStateOnSurfaces()->begin();
1195  const Trk::TrackStates::const_iterator cmb_end_itr = combinedTrack.trackStateOnSurfaces()->end();
1196  do {
1197  ++s;
1198  if (s == cmb_end_itr) {
1199  // fail track as no TSOS with type CaloDeposit
1200  m_messageHelper->printWarning(13);
1201  return nullptr;
1202  }
1203  if ((*s)->type(Trk::TrackStateOnSurface::CaloDeposit)) {
1204  haveCaloDeposit = true;
1205  --s;
1206  }
1207  } while (!haveCaloDeposit);
1209  const Trk::TrackStateOnSurface* const cmb_inner_tsos = (*s);
1210  // inner calo scatterer - keep scattering angles for vertex constraint
1211  // Amg::Vector3D direction;
1212  const Trk::ScatteringAngles* innerScattering = nullptr;
1213  std::unique_ptr<Trk::TrackStateOnSurface> innerTSOS;
1214  const Trk::MaterialEffectsBase* materialEffects = cmb_inner_tsos->materialEffectsOnTrack();
1215  const Trk::TrackParameters* middleParameters = nullptr;
1216  const Trk::ScatteringAngles* outerScattering = nullptr;
1217  const Trk::TrackParameters* parameters = cmb_inner_tsos->trackParameters();
1218  std::unique_ptr<Trk::TrackParameters> param_owner;
1219  if (materialEffects && parameters && m_calorimeterVolume->inside(parameters->position())) {
1220  // keep scattering angles when vertex constrained
1221  // in r21, addVertexRegion is always true
1222 
1223  innerTSOS.reset(cmb_inner_tsos->clone());
1224  const Trk::MaterialEffectsOnTrack* meot = dynamic_cast<const Trk::MaterialEffectsOnTrack*>(materialEffects);
1225 
1226  if (!meot) {
1227  // innerScattering dynamic_cast failed
1228  m_messageHelper->printWarning(16);
1229  return nullptr;
1230  }
1231  innerScattering = meot->scatteringAngles();
1234  if (s != cmb_end_itr && !(*s)->type(Trk::TrackStateOnSurface::CaloDeposit)) { ++s; }
1235 
1237  if (s != cmb_end_itr) {
1238  const Trk::TrackStateOnSurface* const cmb_middle_tsos = (*s);
1239  materialEffects = cmb_middle_tsos->materialEffectsOnTrack();
1240  parameters = cmb_middle_tsos->trackParameters();
1241  middleParameters = parameters;
1242  } else {
1243  // no TSOS of type CaloDeposit found
1244  m_messageHelper->printWarning(17);
1245  materialEffects = nullptr;
1246  parameters = nullptr;
1247  }
1248 
1249  } else {
1250  // no inner material or parameters
1251  if (!materialEffects) m_messageHelper->printWarning(14);
1252  if (!parameters) m_messageHelper->printWarning(15);
1253  }
1254 
1255  if (!innerTSOS) {
1256  // no inner scattering TSOS found
1257  m_messageHelper->printWarning(18);
1258  return nullptr;
1259  }
1260 
1261  // middle calo scatterer (for energy deposit)
1262  double energyDeposit{0.};
1263 
1264  std::unique_ptr<Trk::TrackStateOnSurface> middleTSOS;
1265 
1266  if (materialEffects && parameters && m_calorimeterVolume->inside(parameters->position())) {
1267  const Trk::TrackStateOnSurface* const cmb_middle_tsos = (*s);
1268  middleTSOS.reset(cmb_middle_tsos->clone());
1269  const Trk::MaterialEffectsOnTrack* meot = dynamic_cast<const Trk::MaterialEffectsOnTrack*>(materialEffects);
1270 
1271  if (meot && meot->energyLoss()) energyDeposit = meot->energyLoss()->deltaE();
1273 
1274  ++s;
1275  if (s != cmb_end_itr) {
1276  const Trk::TrackStateOnSurface* const cmb_outer_tsos = (*s);
1277  materialEffects = cmb_outer_tsos->materialEffectsOnTrack();
1278  parameters = cmb_outer_tsos->trackParameters();
1279  } else {
1280  materialEffects = nullptr;
1281  parameters = nullptr;
1282  }
1283  } else {
1284  // no middle material or parameters
1285  if (!materialEffects) m_messageHelper->printWarning(19);
1286  if (!parameters) m_messageHelper->printWarning(20);
1287  }
1288 
1289  if (!middleTSOS) {
1290  // no CaloDeposit TSOS found
1291  m_messageHelper->printWarning(21);
1292  return nullptr;
1293  }
1294 
1295  // outer calo scatterer
1296  std::unique_ptr<Trk::TrackStateOnSurface> outerTSOS;
1297 
1298  double pInner{0.}, pOuter{0.};
1299  if (materialEffects && parameters && m_calorimeterVolume->inside(parameters->position())) {
1300  const Trk::TrackStateOnSurface* const cmb_outer_tsos = (*s);
1301  pOuter = parameters->momentum().mag();
1302 
1303  outerTSOS.reset(cmb_outer_tsos->clone());
1304 
1305  const Trk::MaterialEffectsOnTrack* meot = dynamic_cast<const Trk::MaterialEffectsOnTrack*>(materialEffects);
1306 
1307  if (!meot) {
1308  // outerScattering dynamic_cast failed
1309  m_messageHelper->printWarning(24);
1310  return nullptr;
1311  }
1312  outerScattering = meot->scatteringAngles();
1313 
1314  // Go to the next surface
1315  ++s;
1316 
1317  // get parameters at middleSurface for energy correction,
1318  // start with parameters from middle surface when vertex in fit
1319  if (outerScattering && middleTSOS) {
1320  parameters = middleTSOS->trackParameters();
1321  } else {
1322  // otherwise extrapolate outer to middleSurface without scattering correction
1323  param_owner = m_propagator->propagate(ctx, *parameters, middleTSOS->trackParameters()->associatedSurface(),
1325  parameters = param_owner.get();
1326  }
1328  if (parameters) {
1330  if (!param_owner) param_owner = parameters->uniqueClone();
1331  // corrected parameters (include unfitted calo energy deposit),
1332  // inner momentum = outer momentum plus energy deposit
1333  pInner = pOuter + energyDeposit;
1334  momentumUpdate(param_owner, pInner);
1336  parameters = param_owner.get();
1337  }
1338  } else {
1339  // no outer material or parameters
1340  if (!materialEffects) m_messageHelper->printWarning(22);
1341  if (!parameters) m_messageHelper->printWarning(23);
1342  }
1343 
1344  // fail track if missing any calo surface or extrapolation failure
1345  if (!innerTSOS || !middleTSOS || !outerTSOS || !parameters) { return nullptr; }
1347  parameters = nullptr;
1348 
1350  param_owner = m_propagator->propagate(ctx, *param_owner, innerTSOS->trackParameters()->associatedSurface(), Trk::oppositeMomentum,
1352 
1354  if (innerScattering) { momentumUpdate(param_owner, pInner, true, -innerScattering->deltaPhi(), -innerScattering->deltaTheta()); }
1355 
1356  std::unique_ptr<Trk::TrackParameters> perigee_owner;
1357  if (param_owner) {
1358  perigee_owner = m_propagator->propagate(ctx, *param_owner, *m_perigeeSurface, Trk::oppositeMomentum, false,
1361  if (perigee_owner && perigee_owner->surfaceType() != Trk::SurfaceType::Perigee) { perigee_owner.reset(); }
1362  }
1363 
1364  // in case of problem above: clone combined perigee
1365  if (!perigee_owner) { perigee_owner = combinedTrack.perigeeParameters()->uniqueClone(); }
1366  // track back out to the 3 calo surfaces applying small correction for non-linearity
1367  param_owner = m_propagator->propagate(ctx, *perigee_owner, innerTSOS->trackParameters()->associatedSurface(), Trk::alongMomentum,
1369  if (!param_owner) {
1370  // failed propagation to innerTSOS
1371  m_messageHelper->printWarning(26);
1372  } else {
1373  if (innerScattering) { momentumUpdate(param_owner, pInner, true, innerScattering->deltaPhi(), innerScattering->deltaTheta()); }
1374 
1375  param_owner = m_propagator->propagate(ctx, *param_owner, middleParameters->associatedSurface(), Trk::alongMomentum, false,
1377 
1378  if (!param_owner) {
1379  // failed propagation to middleTSOS
1380  m_messageHelper->printWarning(27);
1381  } else {
1382  momentumUpdate(param_owner, pOuter);
1383  param_owner = m_propagator->propagate(ctx, *param_owner, outerTSOS->trackParameters()->associatedSurface(),
1385  }
1386  }
1387 
1388  if (!param_owner) { return nullptr; }
1389 
1390  if (outerScattering) { momentumUpdate(param_owner, pOuter, true, outerScattering->deltaPhi(), outerScattering->deltaTheta()); }
1391 
1392  // small correction term
1393  const double deltaPhi = xAOD::P4Helpers::deltaPhi(outerTSOS->trackParameters()->momentum().phi(), param_owner->momentum().phi());
1394  const double deltaTheta = outerTSOS->trackParameters()->momentum().theta() - param_owner->momentum().theta();
1395 
1396  momentumUpdate(perigee_owner, pInner, true, deltaPhi, deltaTheta);
1397 
1398  std::unique_ptr<Trk::RecVertex> mbeamAxis = std::make_unique<Trk::RecVertex>(*m_beamAxis);
1400  std::unique_ptr<Trk::PseudoMeasurementOnTrack> vertexInFit{vertexOnTrack(*perigee_owner, vertex.get(), mbeamAxis.get())};
1401 
1402  // create perigee TSOS
1403  trackStateOnSurfaces->push_back(Muon::MuonTSOSHelper::createPerigeeTSOS(std::move(perigee_owner)));
1404 
1405  // including vertex region pseudoMeas if requested: in r21, this is always requested
1406  if (vertexInFit) {
1407  trackStateOnSurfaces->push_back(Muon::MuonTSOSHelper::createMeasTSOS(std::move(vertexInFit), nullptr, Trk::TrackStateOnSurface::Measurement));
1408  }
1409 
1410  if (m_addElossID) {
1411  double Eloss{0.}, sigmaEloss{0.}, X0tot{0.}, sigmaDeltaPhitot2{0.}, sigmaDeltaThetatot2{0.};
1412 
1413  std::vector<const Trk::TrackStateOnSurface*> scatter_tsos;
1414  scatter_tsos.reserve(combinedTrack.trackStateOnSurfaces()->size());
1415 
1416  for (const Trk::TrackStateOnSurface* comb_tsos : *combinedTrack.trackStateOnSurfaces()) {
1417  if (!comb_tsos->trackParameters()) continue;
1418  if (!m_indetVolume->inside(comb_tsos->trackParameters()->position())) break;
1419  if (!comb_tsos->materialEffectsOnTrack()) { continue; }
1420  const double X0 = comb_tsos->materialEffectsOnTrack()->thicknessInX0();
1421  X0tot += X0;
1422  const Trk::MaterialEffectsOnTrack* meot =
1423  dynamic_cast<const Trk::MaterialEffectsOnTrack*>(comb_tsos->materialEffectsOnTrack());
1424 
1425  if (!meot) { continue; }
1426  const Trk::EnergyLoss* energyLoss = meot->energyLoss();
1427  if (!energyLoss) { continue; }
1428  Eloss += energyLoss->deltaE();
1429  sigmaEloss += energyLoss->sigmaDeltaE();
1430 
1431  ATH_MSG_DEBUG("CombinedMuonFit ID Eloss found r " << (comb_tsos->trackParameters())->position().perp() << " z "
1432  << (comb_tsos->trackParameters())->position().z() << " value "
1433  << energyLoss->deltaE() << " Eloss " << Eloss << " sigma Eloss "
1434  << energyLoss->sigmaDeltaE() << " X0 " << X0);
1435 
1436  const Trk::ScatteringAngles* scat = meot->scatteringAngles();
1437  if (scat) {
1438  double sigmaDeltaPhi = scat->sigmaDeltaPhi();
1439  double sigmaDeltaTheta = scat->sigmaDeltaTheta();
1440  sigmaDeltaPhitot2 += sigmaDeltaPhi * sigmaDeltaPhi;
1441  sigmaDeltaThetatot2 += sigmaDeltaTheta * sigmaDeltaTheta;
1442  scatter_tsos.push_back(comb_tsos);
1443  }
1444  }
1445 
1446  ATH_MSG_DEBUG("standaloneRefit Total ID Eloss " << Eloss << " sigma Eloss " << sigmaEloss << " X0 " << X0tot
1447  << " sigma scat phi " << std::sqrt(sigmaDeltaPhitot2) << " sigma scat theta "
1448  << std::sqrt(sigmaDeltaThetatot2));
1449  if (!scatter_tsos.empty()) {
1450  const int itsosMiddle = scatter_tsos.size() / 2;
1451  const Trk::TrackStateOnSurface* mid_scatter = scatter_tsos[itsosMiddle];
1452 
1453  std::unique_ptr<Trk::EnergyLoss> energyLossNew = std::make_unique<Trk::EnergyLoss>(Eloss, sigmaEloss, sigmaEloss, sigmaEloss);
1454 
1455  const Trk::Surface& surfNew = mid_scatter->trackParameters()->associatedSurface();
1456  Trk::ScatteringAngles scatNew{0., 0., std::sqrt(sigmaDeltaPhitot2), std::sqrt(sigmaDeltaThetatot2)};
1457 
1458  std::bitset<Trk::MaterialEffectsBase::NumberOfMaterialEffectsTypes> meotPattern(0);
1461 
1462  ATH_MSG_DEBUG(" itsosMiddle " << itsosMiddle << " tsosnr size " << scatter_tsos.size());
1463 
1464  std::unique_ptr<Trk::MaterialEffectsOnTrack> meotNew = std::make_unique<Trk::MaterialEffectsOnTrack>(X0tot, scatNew, std::move(energyLossNew), surfNew, meotPattern);
1465 
1466  std::unique_ptr<Trk::TrackParameters> parsNew = mid_scatter->trackParameters()->uniqueClone();
1467  std::bitset<Trk::TrackStateOnSurface::NumberOfTrackStateOnSurfaceTypes> typePatternScat(0);
1468  typePatternScat.set(Trk::TrackStateOnSurface::Scatterer);
1469 
1470  std::unique_ptr<Trk::TrackStateOnSurface> newTSOS =
1471  std::make_unique<Trk::TrackStateOnSurface>(nullptr, std::move(parsNew), std::move(meotNew), typePatternScat);
1472 
1473  trackStateOnSurfaces->push_back(std::move(newTSOS));
1474  ATH_MSG_DEBUG(" add new TSOS for ID ");
1475  }
1476 
1477  } // end m_addElossID
1478 
1479  // add the 3 surface calo model
1480  trackStateOnSurfaces->push_back(std::move(innerTSOS));
1481  trackStateOnSurfaces->push_back(std::move(middleTSOS));
1482  trackStateOnSurfaces->push_back(std::move(outerTSOS));
1483  const Trk::TrackParameters* outerTSOSParam = trackStateOnSurfaces->back()->trackParameters();
1484  // MS entrance perigee
1486  std::unique_ptr<Trk::TrackStateOnSurface> entranceTSOS = entrancePerigee(ctx, outerTSOSParam);
1487  if (entranceTSOS) trackStateOnSurfaces->push_back(std::move(entranceTSOS));
1488  }
1489 
1490  // leading spectrometer material
1491  bool haveLeadingMaterial = false;
1492 
1494  for (; mat_it != cmb_end_itr; ++mat_it) {
1495  if ((*mat_it)->type(Trk::TrackStateOnSurface::Measurement)) break;
1496  haveLeadingMaterial = true;
1497  }
1498 
1499  // protection against overruning the end of the vector
1500  if (mat_it == cmb_end_itr) {
1501  ATH_MSG_WARNING("At end of TSOS vector");
1502  return nullptr;
1503  }
1504 
1505  if (haveLeadingMaterial) appendSelectedTSOS(*trackStateOnSurfaces, s, ++mat_it);
1506 
1507  // insert phi pseudo measurement if necessary
1508  if (addPhiPseudo) {
1509  std::unique_ptr<Trk::TrackStateOnSurface> tsos = createPhiPseudoMeasurement(ctx, combinedTrack);
1510  if (tsos) trackStateOnSurfaces->push_back(std::move(tsos));
1511  }
1512 
1513  // then append the remaining TSOS from the input track
1514  appendSelectedTSOS(*trackStateOnSurfaces, mat_it, cmb_end_itr);
1515 
1516  // create track for refit
1517  std::unique_ptr<Trk::Track> standaloneTrack =
1518  std::make_unique<Trk::Track>(combinedTrack.info(), std::move(trackStateOnSurfaces), nullptr);
1520  if (m_trackQuery->isCombined(*standaloneTrack, ctx)) { ATH_MSG_WARNING(" This should not happen standalone Track has ID hits "); }
1521 
1522  if (msgLevel(MSG::DEBUG)) countAEOTs(*standaloneTrack, " in standalone Refit standaloneTrack track before fit ");
1523 
1524  std::unique_ptr<Trk::Track> refittedTrack{fit(ctx, *standaloneTrack, false, Trk::muon)};
1525  if (!checkTrack("standaloneRefit", refittedTrack.get())) { return nullptr; }
1526 
1527  // eventually this whole tool will use unique_ptrs
1528  // in the meantime, this allows the MuonErrorOptimisationTool and MuonRefitTool to use them
1529  if (refittedTrack) {
1530  if (!refittedTrack->fitQuality()) { return nullptr; }
1531 
1532  if (!m_trackQuery->isCaloAssociated(*refittedTrack, ctx)) {
1533  // fail as calo incorrectly described
1534  m_messageHelper->printWarning(28);
1535  return nullptr;
1536  }
1537 
1538  if (msgLevel(MSG::DEBUG)) countAEOTs(*refittedTrack, " standaloneRefit final refittedTrack ");
1539 
1540  // fit with optimized spectrometer errors
1541  // this should also be inside the "if(refittedTrack) statement
1542  if (!m_muonErrorOptimizer.empty() && !refittedTrack->info().trackProperties(Trk::TrackInfo::StraightTrack) &&
1543  countAEOTs(*refittedTrack, " before optimize ") == 0) {
1544  ATH_MSG_VERBOSE(" perform spectrometer error optimization after cleaning ");
1545  std::unique_ptr<Trk::Track> optimizedTrack = m_muonErrorOptimizer->optimiseErrors(*refittedTrack, ctx);
1546 
1547  if (checkTrack("standaloneRefitOpt", optimizedTrack.get())) {
1548  refittedTrack.swap(optimizedTrack);
1549  if (msgLevel(MSG::DEBUG)) countAEOTs(*refittedTrack, " standaloneRefit alignment errors Track ");
1550  }
1551  }
1552  }
1553 
1554  // have to release it until the whole tool is migrated to unique_ptr
1555  return refittedTrack;
1556  }
1557 
1558  std::unique_ptr<Trk::Track> CombinedMuonTrackBuilder::addIDMSerrors(const Trk::Track* track) const {
1559  //
1560  // take track and correct the two scattering planes in the Calorimeter
1561  // to take into account m_IDMS_rzSigma and m_IDMS_xySigma
1562  //
1563  // returns a new Track or nullptr does not modify the input in any way
1564  //
1565  if (!m_addIDMSerrors) { return nullptr; }
1566 
1567  ATH_MSG_DEBUG(" CombinedMuonTrackBuilder addIDMSerrors to track ");
1568 
1570  const Trk::TrackStateOnSurface* id_exit = nullptr;
1571  const Trk::TrackStateOnSurface* calo_entrance = nullptr;
1572  const Trk::TrackStateOnSurface* calo_exit = nullptr;
1573  const Trk::TrackStateOnSurface* ms_entrance = nullptr;
1574 
1575  m_alignUncertTool_theta->get_track_state_measures(track, id_exit, calo_entrance, calo_exit, ms_entrance);
1577  if (!calo_entrance || !calo_exit || !ms_entrance) {
1578  ATH_MSG_DEBUG(" addIDMSerrors keep original track ");
1579  return nullptr;
1580  }
1581 
1582  auto trackStateOnSurfaces = std::make_unique<Trk::TrackStates>();
1583  trackStateOnSurfaces->reserve(track->trackStateOnSurfaces()->size());
1584 
1585  for (const Trk::TrackStateOnSurface* trk_srf : *track->trackStateOnSurfaces()) {
1586  if (calo_entrance == trk_srf || calo_entrance == trk_srf) {
1587  if (!trk_srf->materialEffectsOnTrack()) {
1588  ATH_MSG_DEBUG("No material effect on track");
1589  continue;
1590  }
1591  const Trk::MaterialEffectsOnTrack* meot =
1592  dynamic_cast<const Trk::MaterialEffectsOnTrack*>(trk_srf->materialEffectsOnTrack());
1593  if (!meot) {
1594  ATH_MSG_WARNING(" This should not happen: no MaterialEffectsOnTrack for scatterer ");
1595  continue;
1596  }
1597  const Trk::ScatteringAngles* scat = meot->scatteringAngles();
1598  if (!scat) {
1599  ATH_MSG_WARNING(" This should not happen: no Scattering Angles for scatterer ");
1600  continue;
1601  }
1602 
1603  float sigmaDeltaPhi = std::hypot(scat->sigmaDeltaPhi(), m_alignUncertTool_phi->get_uncertainty(track));
1604  float sigmaDeltaTheta = std::hypot(scat->sigmaDeltaTheta(), m_alignUncertTool_theta->get_uncertainty(track));
1605  float X0 = trk_srf->materialEffectsOnTrack()->thicknessInX0();
1606  //
1607  auto energyLossNew = std::make_unique<Trk::EnergyLoss>(0., 0., 0., 0.);
1608  auto scatNew = Trk::ScatteringAngles(0., 0., sigmaDeltaPhi, sigmaDeltaTheta);
1609 
1610  const Trk::Surface& surfNew = trk_srf->trackParameters()->associatedSurface();
1611 
1612  std::bitset<Trk::MaterialEffectsBase::NumberOfMaterialEffectsTypes> meotPattern(0);
1615 
1616  auto meotNew = std::make_unique<Trk::MaterialEffectsOnTrack>(
1617  X0,
1618  scatNew,
1619  std::move(energyLossNew),
1620  surfNew,
1621  meotPattern);
1622  auto parsNew = trk_srf->trackParameters()->uniqueClone();
1623 
1624  std::bitset<Trk::TrackStateOnSurface::NumberOfTrackStateOnSurfaceTypes> typePatternScat(0);
1625  typePatternScat.set(Trk::TrackStateOnSurface::Scatterer);
1626 
1627  const Trk::TrackStateOnSurface* newTSOS =
1628  new Trk::TrackStateOnSurface(nullptr, std::move(parsNew), std::move(meotNew), typePatternScat);
1629  trackStateOnSurfaces->push_back(newTSOS);
1630 
1631  ATH_MSG_DEBUG(" old Calo scatterer had sigmaDeltaPhi mrad " << scat->sigmaDeltaPhi() * 1000 << " sigmaDeltaTheta mrad "
1632  << scat->sigmaDeltaTheta() * 1000 << " X0 " << X0);
1633 
1634  ATH_MSG_DEBUG(" new Calo scatterer made with sigmaDeltaPhi mrad " << sigmaDeltaPhi * 1000 << " sigmaDeltaTheta mrad "
1635  << sigmaDeltaTheta * 1000);
1636 
1637  } else {
1638  // skip AEOTs
1639  if (trk_srf->alignmentEffectsOnTrack()) {
1640  ATH_MSG_DEBUG(" addIDMSerrors alignmentEffectsOnTrack() found on track ");
1641  continue;
1642  }
1643  trackStateOnSurfaces->push_back(trk_srf->clone());
1644  }
1645  }
1646  ATH_MSG_DEBUG(" trackStateOnSurfaces on input track " << track->trackStateOnSurfaces()->size() << " trackStateOnSurfaces found "
1647  << trackStateOnSurfaces->size());
1648 
1649  std::unique_ptr<Trk::Track> newTrack = std::make_unique<Trk::Track>(track->info(), std::move(trackStateOnSurfaces), nullptr);
1650  return newTrack;
1651  }
1652 
1655  // spectrometer measurement selection
1656  std::vector<const Trk::Surface*> measurementSurfaces;
1657  measurementSurfaces.reserve(trackStateOnSurfaces.size());
1658  const Trk::Surface* previousSurface = nullptr;
1659 
1661  for (; s != end; ++s) {
1662  const Trk::TrackStateOnSurface& tsos = **s;
1663  if (tsos.alignmentEffectsOnTrack()) {
1664  ATH_MSG_VERBOSE("appendSelectedTSOS:: alignmentEffectsOnTrack ");
1665  }
1666  // skip non-understood features in iPatFitter
1667  if (!tsos.measurementOnTrack() && !tsos.materialEffectsOnTrack()) {
1669  ATH_MSG_VERBOSE("appendSelectedTSOS:: skip a perigee without material and measuremet "<<tsos);
1670  continue;
1671  } else if (!tsos.type(Trk::TrackStateOnSurface::Hole) || !tsos.trackParameters()) {
1672  ATH_MSG_VERBOSE("appendSelectedTSOS:: skip unrecognized TSOS " << tsos.dumpType());
1673  continue;
1674  }
1675  }
1676 
1677  if (tsos.measurementOnTrack()) {
1678  // skip any pseudo measurements
1679  if (dynamic_cast<const Trk::PseudoMeasurementOnTrack*>(tsos.measurementOnTrack())) { continue; }
1680 
1681  // skip duplicate measurements on same surface
1682  const Trk::Surface* surface = &tsos.measurementOnTrack()->associatedSurface();
1683  if (previousSurface &&
1684  std::find(measurementSurfaces.begin(), measurementSurfaces.end(), surface) != measurementSurfaces.end()) {
1685  // skip duplicate measurement
1686  m_messageHelper->printWarning(34, m_idHelperSvc->toString(m_edmHelperSvc->getIdentifier(*(tsos.measurementOnTrack()))));
1687  continue;
1688  }
1689 
1690  measurementSurfaces.push_back(surface);
1691  previousSurface = surface;
1692  }
1693  trackStateOnSurfaces.push_back(tsos.clone());
1694  }
1695  }
1696 
1698  const Trk::TrackParameters*& combinedEnergyParameters,
1699  const Trk::TrackParameters*& muonEnergyParameters) const {
1700  // will also set the caloEnergyParameters (from both combinedTrack and muonTrack)
1701  combinedEnergyParameters = nullptr;
1702  muonEnergyParameters = nullptr;
1703 
1704  // quit if missing track
1705  if (!combinedTrack || !muonTrack) return nullptr;
1706 
1707  // muonTrack: get parameters at CaloDeposit
1709 
1710  while (!(**s).type(Trk::TrackStateOnSurface::CaloDeposit)) {
1711  if (++s == muonTrack->trackStateOnSurfaces()->end()) {
1712  // muonTrack without caloEnergy association
1713  m_messageHelper->printWarning(35);
1714  return nullptr;
1715  }
1716  }
1717  muonEnergyParameters = (**s).trackParameters();
1718 
1719  // find corresponding parameters from combinedTrack
1720  s = combinedTrack->trackStateOnSurfaces()->begin();
1721  while (!(**s).type(Trk::TrackStateOnSurface::CaloDeposit)) {
1722  if (++s == combinedTrack->trackStateOnSurfaces()->end()) {
1723  // combinedTrack without caloEnergy association
1724  m_messageHelper->printWarning(36);
1725  return nullptr;
1726  }
1727  }
1728 
1729  combinedEnergyParameters = (**s).trackParameters();
1730  if (muonEnergyParameters && combinedEnergyParameters) {
1731  ATH_MSG_DEBUG("muon and combined EnergyParameters: " << muonEnergyParameters->momentum().mag() << " "
1732  << combinedEnergyParameters->momentum().mag());
1733  }
1734  // success!
1735  return m_trackQuery->caloEnergy(*combinedTrack);
1736  }
1737 
1739  const EventContext& ctx, const Trk::Track& spectrometerTrack, const Trk::TrackParameters& parameters,
1740  Trk::ParticleHypothesis particleHypothesis, Trk::RunOutlierRemoval runOutlier,
1741  const std::vector<std::unique_ptr<const Trk::TrackStateOnSurface>>& spectrometerTSOS, const Trk::RecVertex* vertex,
1742  const Trk::RecVertex* mbeamAxis, const Trk::PerigeeSurface* mperigeeSurface, const Trk::Perigee* seedParameters) const {
1743  ATH_MSG_DEBUG(" createExtrapolatedTrack() - " << __LINE__ << ": pt " << parameters.momentum().perp() << " r "
1744  << parameters.position().perp() << " z " << parameters.position().z() << " cov "
1745  << parameters.covariance() << " muonfit " << (particleHypothesis == Trk::muon));
1746 
1747  std::vector<std::unique_ptr<const Trk::TrackStateOnSurface>> caloTSOS, leadingTSOS;
1748 
1749  std::unique_ptr<const Trk::TrackParameters> track_param_owner;
1750  const Trk::TrackParameters* trackParameters{nullptr};
1751  const Trk::Perigee* perigee{nullptr};
1752 
1753  if (vertex && m_indetVolume->inside(parameters.position())) { perigee = dynamic_cast<const Trk::Perigee*>(&parameters); }
1754  if (perigee) {
1755  ATH_MSG_DEBUG("createExtrapolatedTrack(): Got a perigee ");
1756  trackParameters = perigee;
1757  } else {
1758  ATH_MSG_DEBUG("createExtrapolatedTrack(): no perigee");
1759  // extrapolate backwards to associate leading material in spectrometer
1760  // (provided material has already been allocated between measurements)
1761  const Trk::TrackParameters* leadingParameters = &parameters;
1762  if (particleHypothesis == Trk::muon) {
1763  bool haveMaterial{false}, haveLeadingMaterial{false}, firstMSHit{false};
1764 
1765  for (const std::unique_ptr<const Trk::TrackStateOnSurface>& s : spectrometerTSOS) {
1766  if (s->materialEffectsOnTrack()) {
1767  haveMaterial = true;
1768  if (!firstMSHit) haveLeadingMaterial = true;
1769  }
1770 
1771  if (s->measurementOnTrack() && !firstMSHit) { firstMSHit = true; }
1772 
1773  if (haveMaterial && firstMSHit) { break; }
1774  }
1775 
1776  // only add leading material if there is no material in fron of first muon measurement
1777 
1778  if (!m_materialAllocator.empty() && haveMaterial && !haveLeadingMaterial) {
1779  // protect the momentum to avoid excessive Eloss
1780  Amg::VectorX parameterVector = parameters.parameters();
1781 
1782  constexpr double Emax = 50000.;
1783 
1784  if (parameterVector[Trk::qOverP] == 0.) {
1785  parameterVector[Trk::qOverP] = 1. / Emax;
1786  } else {
1787  if (std::abs(parameterVector[Trk::qOverP]) * Emax < 1) {
1788  parameterVector[Trk::qOverP] = parameters.charge() / Emax;
1789  }
1790  }
1791  std::unique_ptr<Trk::TrackParameters> correctedParameters{parameters.associatedSurface().createUniqueTrackParameters(
1792  parameterVector[Trk::loc1], parameterVector[Trk::loc2], parameterVector[Trk::phi], parameterVector[Trk::theta],
1793  parameterVector[Trk::qOverP], std::nullopt)};
1794 
1796  std::unique_ptr<std::vector<const Trk::TrackStateOnSurface*>> lead_tsos_from_alloc{
1797  m_materialAllocator->leadingSpectrometerTSOS(*correctedParameters, garbage)};
1798  if (lead_tsos_from_alloc) {
1799  for (const Trk::TrackStateOnSurface* l_tsos : *lead_tsos_from_alloc) leadingTSOS.emplace_back(l_tsos);
1800  }
1801  if (!leadingTSOS.empty() && leadingTSOS.front()->trackParameters()) {
1802  leadingParameters = leadingTSOS.front()->trackParameters();
1803  }
1804  }
1805  }
1806 
1807  // extrapolate backwards to associate calorimeter material effects
1808  bool caloAssociated = false;
1809 
1810  if (particleHypothesis == Trk::muon) {
1811  ATH_MSG_VERBOSE(" Retrieving Calorimeter TSOS from " << __func__ << " at line " << __LINE__);
1812  if (m_useCaloTG) {
1813  caloTSOS = getCaloTSOSfromMatProvider(*leadingParameters, spectrometerTrack);
1814  // Dump CaloTSOS
1815  //
1816  if (msgLevel(MSG::DEBUG)) {
1817  for (std::unique_ptr<const Trk::TrackStateOnSurface>& m : caloTSOS) {
1818  if (!m->materialEffectsOnTrack()) continue;
1819  const Trk::MaterialEffectsOnTrack* meot =
1820  dynamic_cast<const Trk::MaterialEffectsOnTrack*>(m->materialEffectsOnTrack());
1821  double pcalo{0.}, deltaP{0.};
1822  if (!meot) continue;
1823  if (meot->thicknessInX0() <= 20) { continue; }
1824  const Trk::ScatteringAngles* scatAngles = meot->scatteringAngles();
1825 
1826  ATH_MSG_DEBUG(" Calorimeter X0 " << meot->thicknessInX0() << " pointer scat " << scatAngles);
1827 
1828  if (!scatAngles) { continue; }
1829  pcalo = m->trackParameters()->momentum().mag();
1830 
1831  const double pullPhi = scatAngles->deltaPhi() / scatAngles->sigmaDeltaPhi();
1832  const double pullTheta = scatAngles->deltaTheta() / scatAngles->sigmaDeltaTheta();
1833 
1834  ATH_MSG_DEBUG(" Calorimeter scatterer deltaPhi " << scatAngles->deltaPhi() << " pull " << pullPhi
1835  << " deltaTheta " << scatAngles->deltaTheta() << " pull "
1836  << pullTheta);
1837 
1838  const Trk::EnergyLoss* energyLoss = meot->energyLoss();
1839  if (!energyLoss) continue;
1840 
1841  if (m->trackParameters()) {
1842  ATH_MSG_DEBUG("Eloss found r " << (m->trackParameters())->position().perp() << " z "
1843  << (m->trackParameters())->position().z() << " deltaE "
1844  << energyLoss->deltaE());
1845  }
1846 
1848  double caloEloss = std::abs(energyLoss->deltaE());
1849  if (m->trackParameters()) { deltaP = m->trackParameters()->momentum().mag() - pcalo; }
1850 
1851  ATH_MSG_DEBUG(" Calorimeter Deposit " << caloEloss << " pcalo Entrance " << pcalo << " deltaP " << deltaP);
1852  }
1853  }
1854  }
1855  } else {
1856  caloTSOS = m_caloTSOS->caloTSOS(ctx, *leadingParameters);
1857  }
1858 
1859  if (caloTSOS.size() > 2) {
1860  caloAssociated = true;
1861  } else {
1862  ATH_MSG_VERBOSE("Failed to associated calorimeter");
1863  }
1864  } else {
1865  // TDDO Run2 Calo TG
1866  std::unique_ptr<const Trk::TrackStateOnSurface> tsos = m_caloTSOS->innerTSOS(ctx, parameters);
1867  if (tsos) {
1868  caloTSOS.push_back(std::move(tsos));
1869  tsos = m_caloTSOS->outerTSOS(ctx, *caloTSOS.back()->trackParameters());
1870  if (tsos) {
1871  caloAssociated = true;
1872  caloTSOS.push_back(std::move(tsos));
1873  }
1874  }
1875  ATH_MSG_VERBOSE("Special non-muon case for calo: " << caloAssociated);
1876  }
1877 
1878  // if association OK, create perigee surface and back-track to it
1879  if (caloAssociated) {
1880  MagField::AtlasFieldCache fieldCache;
1881  // Get field cache object
1882  if (!loadMagneticField(ctx, fieldCache)) return nullptr;
1883 
1884  if (fieldCache.toroidOn()) {
1885  const Trk::TrackParameters* oldParameters = caloTSOS.front()->trackParameters();
1886 
1887  if (oldParameters){
1888  if(not oldParameters->covariance()) { ATH_MSG_VERBOSE(" createExtrapolatedTrack: no cov (0)"); }
1889  // chickened out of sorting out ownership
1890  track_param_owner = m_propagator->propagate(ctx, *oldParameters, *mperigeeSurface, Trk::oppositeMomentum, false,
1892  }
1893  } else {
1894  track_param_owner = m_propagatorSL->propagate(ctx, parameters, *mperigeeSurface, Trk::oppositeMomentum, false,
1896  }
1897  trackParameters = track_param_owner.get();
1898 
1899  // only accept when perigee in indet tracking volume
1900  if (trackParameters && !m_indetVolume->inside(trackParameters->position())) {
1901  ATH_MSG_DEBUG(" back extrapolation problem: probably outside indet volume ");
1902  caloAssociated = false;
1903  }
1904 
1905  if (trackParameters && !trackParameters->covariance()) { ATH_MSG_VERBOSE(" createExtrapolatedTrack: no cov (1)"); }
1906 
1907  if (trackParameters) {
1908  ATH_MSG_VERBOSE(" Seed parameter: r " << trackParameters->position().perp() << " z " << trackParameters->position().z()
1909  << " pt " << trackParameters->momentum().perp());
1910  }
1911 
1912  } // if (caloAssociated) {
1913  // start from vertex in case of calo association problem
1914  else if (vertex) {
1915  ATH_MSG_DEBUG(" back extrapolation problem: retry with tracking out from vertex ");
1916  // delete any existing calo objects
1917  caloTSOS.clear();
1918 
1919  // track out from vertex
1920  const Amg::Vector3D momentum = parameters.position().unit() * Gaudi::Units::TeV;
1921 
1922  track_param_owner = std::make_unique<Trk::Perigee>(vertex->position(), momentum, 1., *mperigeeSurface);
1923  trackParameters = track_param_owner.get();
1924  particleHypothesis = Trk::nonInteracting;
1925  runOutlier = false;
1926 
1927  ATH_MSG_VERBOSE(" Retriving Calorimeter TSOS from " << __func__ << " at line " << __LINE__);
1928 
1929  if (m_useCaloTG) {
1930  caloTSOS = getCaloTSOSfromMatProvider(*trackParameters, spectrometerTrack);
1931  } else {
1932  std::unique_ptr<const Trk::TrackStateOnSurface> tsos = m_caloTSOS->innerTSOS(ctx, *trackParameters);
1933  if (tsos) {
1934  caloTSOS.push_back(std::move(tsos));
1935  tsos = m_caloTSOS->outerTSOS(ctx, *trackParameters);
1936  if (tsos) {
1937  caloTSOS.push_back(std::move(tsos));
1938  } else {
1939  track_param_owner.reset();
1940  }
1941  }
1942  }
1943  trackParameters = track_param_owner.get();
1944  }
1945 
1946  // failure in calo association and/or extrapolation to indet
1947  if (!trackParameters || caloTSOS.empty()) {
1948  ATH_MSG_DEBUG(" perigee back-extrapolation fails ");
1949  return nullptr;
1950  }
1951  } // if (perigee) {
1952 
1953  // set seed if provided
1954  if (seedParameters) { trackParameters = seedParameters; }
1955 
1956  // append TSOS objects into DataVector
1957  // reserve allows for perigee + vertex + calo + entrancePerigee + spectrometer TSOS
1958  const unsigned int size = spectrometerTSOS.size() + 3 + caloTSOS.size() + leadingTSOS.size();
1959 
1960  auto trackStateOnSurfaces = std::make_unique<Trk::TrackStates>();
1961  trackStateOnSurfaces->reserve(size);
1962 
1963  // start with perigee TSOS (this just carries the perigee parameters)
1964 
1965  if (trackParameters && !trackParameters->covariance()) { ATH_MSG_VERBOSE(" createExtrapolatedTrack: no cov (2)"); }
1966 
1967  if (trackParameters) {
1968  if (trackParameters->surfaceType() != Trk::SurfaceType::Perigee) {
1969  ATH_MSG_DEBUG("createExtrapolatedTrack() - Track parameters are not perigee " << (*trackParameters));
1970  }
1971  trackStateOnSurfaces->push_back(Muon::MuonTSOSHelper::createPerigeeTSOS(trackParameters->uniqueClone()));
1972  }
1973 
1974  // optionally append a pseudoMeasurement describing the vertex
1975  if (vertex && trackParameters) {
1976  std::unique_ptr<Trk::PseudoMeasurementOnTrack> vertexInFit = vertexOnTrack(*trackParameters, vertex, mbeamAxis);
1977  if (vertexInFit) {
1978  ATH_MSG_VERBOSE("Adding vertex constraint ");
1979  trackStateOnSurfaces->push_back(Muon::MuonTSOSHelper::createMeasTSOS(std::move(vertexInFit), nullptr, Trk::TrackStateOnSurface::Measurement));
1980  }
1981  }
1982 
1983  // append calo TSOS
1984  for (std::unique_ptr<const Trk::TrackStateOnSurface>& c_tsos : caloTSOS) { trackStateOnSurfaces->push_back(std::move(c_tsos)); }
1985  caloTSOS.clear();
1986  // MS entrance perigee
1988  ATH_MSG_DEBUG("adding perigee at spectrometer entrance");
1989  const Trk::TrackParameters* mstrackParameters = trackStateOnSurfaces->back()->trackParameters();
1990 
1991  if (!mstrackParameters) { mstrackParameters = spectrometerTSOS.front()->trackParameters(); }
1992 
1993  if (mstrackParameters) {
1994  std::unique_ptr<Trk::TrackStateOnSurface> entranceTSOS = entrancePerigee(ctx, mstrackParameters);
1995  if (entranceTSOS) { trackStateOnSurfaces->push_back(std::move(entranceTSOS)); }
1996  }
1997  }
1998 
1999  // append leading MS material TSOS
2000  for (std::unique_ptr<const Trk::TrackStateOnSurface>& c_tsos : leadingTSOS) {
2001  if (c_tsos->materialEffectsOnTrack()) { trackStateOnSurfaces->push_back(std::move(c_tsos)); }
2002  }
2003  leadingTSOS.clear();
2004 
2005  // append the remaining spectrometer TSOS
2006  for (const auto& s : spectrometerTSOS) {
2007  if (!s->type(Trk::TrackStateOnSurface::Perigee)) {
2009  trackStateOnSurfaces->push_back(s->clone());
2010  }
2011 
2012  if (s->measurementOnTrack() && dynamic_cast<const Trk::PseudoMeasurementOnTrack*>(s->measurementOnTrack())) {
2013  ATH_MSG_VERBOSE(" MS Pseudo");
2014  }
2015  }
2016 
2017  // create track
2018  std::unique_ptr<Trk::Track> track =
2019  std::make_unique<Trk::Track>(spectrometerTrack.info(), std::move(trackStateOnSurfaces), nullptr);
2020 
2021  if (!track->perigeeParameters()) {
2022  ATH_MSG_DEBUG("Reject track without perigee.");
2023  return nullptr;
2024  }
2025  dumpCaloEloss(track.get(), " createExtrapolatedTrack ");
2026  if (msgLevel(MSG::DEBUG)) countAEOTs(*track, " createExtrapolatedTrack before fit ");
2027 
2028  // remove material when curvature badly determined (to remove energy loss uncertainty)
2029  if (particleHypothesis == Trk::nonInteracting) {
2030  ATH_MSG_VERBOSE(" remove spectrometer material ");
2032  }
2033 
2034  // fit the track
2035  ATH_MSG_VERBOSE(" fit SA track with " << track->trackStateOnSurfaces()->size() << " TSOS"
2036  << (particleHypothesis == Trk::nonInteracting ? " using nonInteracting hypothesis"
2037  : "usig interacting hypothesis"));
2038 
2039  std::unique_ptr<Trk::Track> fittedTrack{fit(ctx, *track, runOutlier, particleHypothesis)};
2040  if (fittedTrack) {
2041  if (msgLevel(MSG::DEBUG)) countAEOTs(*fittedTrack, " createExtrapolatedTrack after fit");
2042 
2043  // only accept when perigee in indet tracking volume
2044  if (fittedTrack->perigeeParameters() && !m_indetVolume->inside(fittedTrack->perigeeParameters()->position())) {
2045  ATH_MSG_DEBUG(" back extrapolation problem: fitted perigee outside indet volume ");
2046  return nullptr;
2047  }
2048 
2049  // limit momentum for future energy loss allocation
2050  if (particleHypothesis != Trk::muon) {
2051  ATH_MSG_VERBOSE(" set momentum limit ");
2052  removeSpectrometerMaterial(fittedTrack);
2053  }
2054 
2055  ATH_MSG_VERBOSE(" found track " << m_printer->print(*fittedTrack));
2056  return fittedTrack;
2057  }
2058  // return the unfitted track in case of problem
2059  return track;
2060  }
2061 
2063  const Trk::TrackStates* tsos) const {
2064  // create indet track TSOS vector
2065  auto trackStateOnSurfaces = std::make_unique<Trk::TrackStates>();
2068 
2069 
2070  // set end iterator to be the first TSOS after the indet
2071  unsigned size = 1;
2072 
2074 
2075  std::unique_ptr<Trk::TrackStateOnSurface> perigeeTSOS {(**s).clone()};
2076 
2077  ++s; // keep start perigee where-ever!
2078  for (; s != end; ++s) {
2079  ++size;
2080  if (!m_indetVolume->inside((**s).trackParameters()->position())) { break; }
2081  }
2082  end = s;
2083 
2084  trackStateOnSurfaces->reserve(size);
2085  trackStateOnSurfaces->push_back(std::move(perigeeTSOS));
2086 
2087  // then append selected TSOS
2088  appendSelectedTSOS(*trackStateOnSurfaces, begin, end);
2089 
2090  return std::make_unique<Trk::Track>(info, std::move(trackStateOnSurfaces), nullptr);
2091  }
2092 
2093  std::unique_ptr<Trk::Track> CombinedMuonTrackBuilder::createMuonTrack(const EventContext& ctx, const Trk::Track& muonTrack,
2094  const Trk::TrackParameters* parameters, std::unique_ptr<CaloEnergy> caloEnergy,
2095  const Trk::TrackStates* tsos) const{
2098  size_t size = tsos->size();
2099 
2100  if (msgLevel(MSG::DEBUG)) countAEOTs(muonTrack, " createMuonTrack ");
2101 
2102  // set iterator to current TSOS on input track to be after the indet
2103  const Trk::TrackParameters* lastIDtp = nullptr;
2105  while ((**s).trackParameters() &&
2106  (m_indetVolume->inside((**s).trackParameters()->position()) || (**s).type(Trk::TrackStateOnSurface::Perigee))) {
2107  if (m_indetVolume->inside((**s).trackParameters()->position())) { lastIDtp = (**s).trackParameters(); }
2108  ++s;
2109  --size;
2110  }
2111 
2112  // create muon track TSOS vector
2113  auto trackStateOnSurfaces = std::make_unique<Trk::TrackStates>();
2114 
2115  // redo calo association from inside if requested
2116  bool redoCaloAssoc = false;
2117  if (parameters) {
2118  redoCaloAssoc = true;
2119 
2120  // move current TSOS iterator to be outside the calorimeter
2121  while ((**s).trackParameters() &&
2122  (m_calorimeterVolume->inside((**s).trackParameters()->position()) || (**s).type(Trk::TrackStateOnSurface::Perigee))) {
2123  ++s;
2124  --size;
2125  }
2126 
2127  // associate calo by extrapolation from last ID parameters
2128  std::vector<std::unique_ptr<const Trk::TrackStateOnSurface>> caloTSOS;
2129  if (m_useCaloTG) {
2130  if (!lastIDtp) { lastIDtp = parameters; }
2131  ATH_MSG_VERBOSE(" Retriving Calorimeter TSOS from " << __func__ << " at line " << __LINE__);
2132  caloTSOS = getCaloTSOSfromMatProvider(*lastIDtp, muonTrack);
2133  } else {
2134  caloTSOS = m_caloTSOS->caloTSOS(ctx, *parameters);
2135  }
2136 
2137  if (caloTSOS.size() < 3) {
2138  ATH_MSG_DEBUG(" muonTrack: parameters fail to fully intersect the calorimeter");
2139  return nullptr;
2140  }
2141 
2142  size += caloTSOS.size();
2143  trackStateOnSurfaces->reserve(size + 1);
2144 
2145  // start with the calo TSOS
2146  for (std::unique_ptr<const Trk::TrackStateOnSurface>& c_tsos : caloTSOS) { trackStateOnSurfaces->push_back(std::move(c_tsos)); }
2147 
2148  } else {
2149  trackStateOnSurfaces->reserve(size + 1);
2150  }
2151 
2152  // if requested, replace caloEnergy on appropriate TSOS
2154  if (caloEnergy && (**s).trackParameters() && m_calorimeterVolume->inside((**s).trackParameters()->position())) {
2155  const Trk::TrackStateOnSurface* TSOS = (**s).clone();
2156  trackStateOnSurfaces->push_back(TSOS);
2157  ++s;
2158 
2159  // create MEOT owning CaloEnergy
2160  if ((**s).trackParameters() && m_calorimeterVolume->inside((**s).trackParameters()->position())) {
2161  std::bitset<Trk::MaterialEffectsBase::NumberOfMaterialEffectsTypes> typePattern;
2163 
2164  std::unique_ptr<Trk::MaterialEffectsOnTrack> materialEffects =
2165  std::make_unique<Trk::MaterialEffectsOnTrack>(0., std::move(caloEnergy), (**s).trackParameters()->associatedSurface(), typePattern);
2166 
2167  // create TSOS
2168 
2169  std::bitset<Trk::TrackStateOnSurface::NumberOfTrackStateOnSurfaceTypes> type;
2171 
2172  TSOS = new Trk::TrackStateOnSurface(nullptr, (**s).trackParameters()->uniqueClone(),std::move(materialEffects), type);
2173  trackStateOnSurfaces->push_back(TSOS);
2174  ++s;
2175  } else {
2176  // should never happen: FSR caloEnergy delete
2177  m_messageHelper->printWarning(37);
2178  }
2179  }
2180 
2181  // MS entrance perigee
2182  bool hasAlreadyPerigee = false;
2184  // copy calorimeter TSOS
2185  while ((**s).trackParameters() && m_calorimeterVolume->inside((**s).trackParameters()->position())) {
2186  if (!(**s).type(Trk::TrackStateOnSurface::Perigee)) {
2187  const Trk::TrackStateOnSurface* TSOS = (**s).clone();
2188  trackStateOnSurfaces->push_back(TSOS);
2189  }
2190  ++s;
2191  }
2192 
2193  // add entrance TSOS if not already present
2194  std::unique_ptr<Trk::TrackStateOnSurface> entranceTSOS;
2195 
2196  if ((**s).type(Trk::TrackStateOnSurface::Perigee)) { hasAlreadyPerigee = true; }
2197 
2198  if (!hasAlreadyPerigee) {
2199  if ((**s).trackParameters()) {
2200  entranceTSOS = entrancePerigee(ctx, (**s).trackParameters());
2201  } else {
2202  entranceTSOS = entrancePerigee(ctx, trackStateOnSurfaces->back()->trackParameters());
2203  }
2204  if (entranceTSOS) {
2205  double distance = (entranceTSOS->trackParameters()->position() - (**s).trackParameters()->position()).mag();
2206 
2207  if (distance > 2000) {
2208  ATH_MSG_DEBUG(" Added Muon Entrance "
2209  << " r " << entranceTSOS->trackParameters()->position().perp() << " z "
2210  << entranceTSOS->trackParameters()->position().z() << " track pars r "
2211  << (**s).trackParameters()->position().perp() << " z " << (**s).trackParameters()->position().z());
2212  }
2213  trackStateOnSurfaces->push_back(std::move(entranceTSOS));
2214  hasAlreadyPerigee = true;
2215  }
2216  }
2217  }
2218 
2219 
2220  // then append selected TSOS from the extrapolated or spectrometer track
2221  appendSelectedTSOS(*trackStateOnSurfaces, s, end);
2223  if (!hasAlreadyPerigee && std::find_if(trackStateOnSurfaces->begin(), trackStateOnSurfaces->end(),
2224  [] (const Trk::TrackStateOnSurface* tsos){
2225  return tsos->type(Trk::TrackStateOnSurface::Perigee);
2226  }) == trackStateOnSurfaces->end() && muonTrack.perigeeParameters() ){
2227  trackStateOnSurfaces->push_back( Muon::MuonTSOSHelper::createPerigeeTSOS(muonTrack.perigeeParameters()->uniqueClone()));
2229  std::stable_sort(trackStateOnSurfaces->begin(),trackStateOnSurfaces->end(),
2231  return a->type(Trk::TrackStateOnSurface::Perigee) > b->type(Trk::TrackStateOnSurface::Perigee);
2232  });
2233  ATH_MSG_DEBUG(__FILE__<<":"<<__LINE__<<" No track perigee parameters were added. Copy the existing ones from the muon track");
2234  }
2235  std::unique_ptr<Trk::Track> newMuonTrack = std::make_unique<Trk::Track>(muonTrack.info(), std::move(trackStateOnSurfaces), nullptr);
2236  unsigned int num_ms{0}, num_precMS{0};
2237  for (const Trk::MeasurementBase* meas : *newMuonTrack->measurementsOnTrack()) {
2238  const Trk::RIO_OnTrack* rio = dynamic_cast<const Trk::RIO_OnTrack*>(meas);
2239  if (!rio || !m_idHelperSvc->isMuon(rio->identify())) continue;
2240  ++num_ms;
2241  num_precMS += !m_idHelperSvc->measuresPhi(rio->identify());
2242  }
2243  if (num_precMS < 3 || num_ms < 5) {
2244  ATH_MSG_VERBOSE(__FILE__":"<<__LINE__<<" MS track with too few meausrements constructed "<<std::endl<<
2245  m_printer->print(newMuonTrack->measurementsOnTrack()->stdcont()) );
2246  return nullptr;
2247  }
2248  // Updates the calo TSOS with the ones from TG+corrections (if needed)
2249  if (m_updateWithCaloTG && !m_useCaloTG && redoCaloAssoc) {
2250  ATH_MSG_VERBOSE("Updating Calorimeter TSOS in CreateMuonTrack ...");
2251  m_materialUpdator->updateCaloTSOS(*newMuonTrack, parameters);
2252  }
2253 
2254  return newMuonTrack;
2255  }
2256 
2257  std::unique_ptr<Trk::TrackStateOnSurface> CombinedMuonTrackBuilder::createPhiPseudoMeasurement(const EventContext& ctx,
2258  const Trk::Track& track) const {
2259  auto parameters = m_trackQuery->spectrometerParameters(track, ctx);
2260  Amg::MatrixX covarianceMatrix(1, 1);
2261  covarianceMatrix.setZero();
2262  covarianceMatrix(0, 0) = s_sigmaPhiSector * s_sigmaPhiSector * parameters->position().perp2();
2263 
2264  std::unique_ptr<Trk::PseudoMeasurementOnTrack> pseudo = std::make_unique<Trk::PseudoMeasurementOnTrack>(
2266  std::move(covarianceMatrix),
2267  parameters->associatedSurface());
2268 
2270  }
2271 
2272  std::vector<std::unique_ptr<const Trk::TrackStateOnSurface>> CombinedMuonTrackBuilder::createSpectrometerTSOS(const EventContext& ctx,
2273  const Trk::Track& spectrometerTrack) const {
2274  const Trk::Perigee* measuredPerigee = spectrometerTrack.perigeeParameters();
2275  std::vector<std::unique_ptr<const Trk::TrackStateOnSurface>> spectrometerTSOS;
2276 
2277  if (!measuredPerigee || !measuredPerigee->covariance() || !Amg::hasPositiveDiagElems(*measuredPerigee->covariance())) {
2278  // missing MeasuredPerigee for spectrometer track
2279  if (!measuredPerigee)
2280  m_messageHelper->printWarning(38);
2281  else if (!measuredPerigee->covariance())
2282  m_messageHelper->printWarning(38);
2283  else
2284  ATH_MSG_DEBUG("createSpectrometerTSOS::perigee covariance not valid");
2285  return spectrometerTSOS;
2286  }
2287 
2288  double errorPhi = std::sqrt((*measuredPerigee->covariance())(Trk::phi0, Trk::phi0));
2289 
2290  // create the spectrometer TSOS's for the extrapolated fit
2291  spectrometerTSOS.reserve(spectrometerTrack.trackStateOnSurfaces()->size());
2292 
2293  // start with a 'phi sector constraint' pseudomeasurement when necessary
2294  unsigned numberPseudo = m_trackQuery->numberPseudoMeasurements(spectrometerTrack);
2295  if (errorPhi > s_sigmaPhiSector) { ++numberPseudo; }
2296 
2297  if (numberPseudo > 1 && !m_trackQuery->isSectorOverlap(spectrometerTrack)) {
2298  ATH_MSG_VERBOSE("standaloneFit: add pseudo to constrain phi sector");
2299 
2300  std::unique_ptr<Trk::TrackStateOnSurface> tsos = {createPhiPseudoMeasurement(ctx, spectrometerTrack)};
2301  if (tsos) { spectrometerTSOS.emplace_back(std::move(tsos)); }
2302  }
2303 
2304  // make a measurement selection to fixup non-standard TSOS's
2305  double deltaZ = 0.;
2306  bool haveMeasurement = false;
2307 
2308  std::vector<const Trk::Surface*> measurementSurfaces;
2309  measurementSurfaces.reserve(spectrometerTrack.trackStateOnSurfaces()->size());
2310 
2311  unsigned numberMaterial{0}, numberParameters{0};
2312 
2313  const Trk::Surface* previousSurface = nullptr;
2314  std::unique_ptr<const Trk::TrackStateOnSurface> previousTSOS;
2315 
2316  for (const Trk::TrackStateOnSurface* s : *spectrometerTrack.trackStateOnSurfaces()) {
2317  // skip any leading material
2318  if (!haveMeasurement) {
2319  if (s->measurementOnTrack()) {
2320  haveMeasurement = true;
2321  } else if (s->materialEffectsOnTrack()) {
2322  continue;
2323  }
2324  }
2325 
2326  // input statistics for VERBOSE
2327  const Trk::TrackParameters* trackParameters = s->trackParameters();
2328  if (msgLvl(MSG::VERBOSE)) {
2329  if (s->materialEffectsOnTrack()) ++numberMaterial;
2330  if (trackParameters) ++numberParameters;
2331  }
2332 
2333  // skip unwanted TSOS and non-understood features in iPatFitter
2334  if (!s->measurementOnTrack() && !s->materialEffectsOnTrack()) {
2335  // remove holes as they will be reallocated
2336  if (s->type(Trk::TrackStateOnSurface::Hole)) continue;
2337 
2338  // same for MS perigee
2339  if (s->type(Trk::TrackStateOnSurface::Perigee)) continue;
2340 
2341  if (s->trackParameters()) {
2342  ATH_MSG_DEBUG("createSpectrometerTSOS:: skip unrecognized TSOS " << s->dumpType() << " r "
2343  << s->trackParameters()->position().perp() << " z "
2344  << s->trackParameters()->position().z());
2345  } else {
2346  // skip unrecognized TSOS without TrackParameters
2347  m_messageHelper->printWarning(39, s->dumpType());
2348  }
2349  continue;
2350  }
2351 
2352  // several checks applied to measurements:
2353  bool trapezoid = false;
2354  bool rotatedTrap = false;
2355  if (s->measurementOnTrack()) {
2356  // skip pseudo
2357  if (dynamic_cast<const Trk::PseudoMeasurementOnTrack*>(s->measurementOnTrack())) {
2358  continue;
2359  }
2360  // careful with trapezoid ordering (put trapezoid before
2361  // rotatedTrapezoid)
2362  const Trk::Surface* surface = &s->measurementOnTrack()->associatedSurface();
2363 
2364  if (previousSurface) { deltaZ = std::abs(previousSurface->center().z() - surface->center().z()); }
2365 
2366  if (dynamic_cast<const Trk::PlaneSurface*>(surface)) {
2367  if (dynamic_cast<const Trk::TrapezoidBounds*>(&surface->bounds())) {
2368  trapezoid = true;
2369  } else if (dynamic_cast<const Trk::RotatedTrapezoidBounds*>(&surface->bounds())) {
2370  rotatedTrap = true;
2371  }
2372  }
2373 
2374  // skip duplicate measurements on same surface
2375  if (previousSurface &&
2376  std::find(measurementSurfaces.begin(), measurementSurfaces.end(), surface) != measurementSurfaces.end()) {
2377  // skip duplicate measurement
2378  m_messageHelper->printWarning(40, m_idHelperSvc->toString(m_edmHelperSvc->getIdentifier(*(s->measurementOnTrack()))));
2379  continue;
2380  }
2381  measurementSurfaces.push_back(surface);
2382  previousSurface = surface;
2383 
2384  } else if (previousTSOS) {
2385  spectrometerTSOS.emplace_back(std::move(previousTSOS));
2386  }
2387 
2388  // trapezoid precedes rotatedTrapezoid
2389  std::unique_ptr<const Trk::TrackStateOnSurface> TSOS(s->clone());
2390  if (previousTSOS) {
2391  if (trapezoid && deltaZ < 1. * Gaudi::Units::mm) {
2392  spectrometerTSOS.emplace_back(std::move(TSOS));
2393  TSOS = std::move(previousTSOS);
2394  } else {
2395  spectrometerTSOS.emplace_back(std::move(previousTSOS));
2396  }
2397  }
2398 
2399  if (rotatedTrap) {
2400  previousTSOS.swap(TSOS);
2401  continue;
2402  }
2403 
2404  spectrometerTSOS.emplace_back(std::move(TSOS));
2405  }
2406 
2407  if (previousTSOS) spectrometerTSOS.emplace_back(std::move(previousTSOS));
2408 
2409  ATH_MSG_VERBOSE(" input spectrometer track with " << spectrometerTrack.trackStateOnSurfaces()->size() << " TSOS, of which "
2410  << numberMaterial << " have MaterialEffects and " << numberParameters
2411  << " have TrackParameters");
2412 
2413  return spectrometerTSOS;
2414  }
2415 
2416  std::unique_ptr<Trk::TrackStateOnSurface> CombinedMuonTrackBuilder::entrancePerigee(const EventContext& ctx, const Trk::TrackParameters* parameters) const {
2417  // make sure the spectrometer entrance volume is available
2418  if (!parameters) return nullptr;
2419  const Trk::TrackingVolume* spectrometerEntrance = getVolume(ctx, "MuonSpectrometerEntrance");
2420  if (!spectrometerEntrance) return nullptr;
2421 
2422  std::unique_ptr<Trk::TrackParameters> entranceParameters{
2423  m_extrapolator->extrapolateToVolume(ctx, *parameters, *spectrometerEntrance, Trk::anyDirection, Trk::nonInteracting)};
2424 
2425  if (!entranceParameters) return nullptr;
2426 
2427  Trk::PerigeeSurface surface(entranceParameters->position());
2428  std::unique_ptr<Trk::TrackParameters> trackParameters{m_extrapolator->extrapolateDirectly(ctx, *entranceParameters, surface)};
2429 
2430  if (!trackParameters) return nullptr;
2431 
2432  std::unique_ptr<Trk::Perigee> perigee =
2433  std::make_unique<Trk::Perigee>(trackParameters->position(), trackParameters->momentum(), trackParameters->charge(), std::move(surface));
2434  return std::unique_ptr<Trk::TrackStateOnSurface>(Muon::MuonTSOSHelper::createPerigeeTSOS(std::move(perigee)));
2435  }
2436 
2437  std::unique_ptr<Trk::TrackParameters> CombinedMuonTrackBuilder::extrapolatedParameters(
2438  const EventContext& ctx, bool& badlyDeterminedCurvature, const Trk::Track& spectrometerTrack, const Trk::RecVertex* mvertex,
2439  const Trk::PerigeeSurface* mperigeeSurface) const {
2440  badlyDeterminedCurvature = false;
2441  const Trk::Perigee* measuredPerigee = spectrometerTrack.perigeeParameters();
2442 
2443  if (!measuredPerigee || !measuredPerigee->covariance()) {
2444  // missing MeasuredPerigee for spectrometer track
2445  m_messageHelper->printWarning(42);
2446  return nullptr;
2447  }
2448 
2449  // set starting parameters and measured momentum error
2450  auto parameters = m_trackQuery->spectrometerParameters(spectrometerTrack, ctx);
2451  if (!parameters || !parameters->covariance()) {
2452  // missing spectrometer parameters on spectrometer track
2453  m_messageHelper->printWarning(43);
2454  return nullptr;
2455  }
2456 
2457  double errorP = std::sqrt(measuredPerigee->momentum().mag2() * (*measuredPerigee->covariance())(Trk::qOverP, Trk::qOverP));
2458 
2459  // corrected parameters ensure the track fitting starts with a projective approximation
2460  std::unique_ptr<Trk::TrackParameters> correctedParameters{};
2461  Amg::VectorX parameterVector = parameters->parameters();
2462  double trackEnergy = 1. / std::abs(parameterVector[Trk::qOverP]);
2463 
2464  // careful: need to reset parameters to have a sensible energy if starting from a lineFit
2465  if (m_trackQuery->isLineFit(spectrometerTrack)) {
2466  trackEnergy = m_lineMomentum;
2467  parameterVector[Trk::qOverP] = parameters->charge() / trackEnergy;
2468 
2469  parameters = parameters->associatedSurface().createUniqueTrackParameters(
2470  parameterVector[Trk::loc1], parameterVector[Trk::loc2], parameterVector[Trk::phi], parameterVector[Trk::theta],
2471  parameterVector[Trk::qOverP], AmgSymMatrix(5)(*parameters->covariance()));
2472  }
2473 
2474  // check if the track curvature is well determined (with sufficient energy to penetrate material)
2475  // (i.e. field off or small momentum error, starting parameters upstream of endcap toroid)
2476  bool curvatureOK = false;
2477 
2478  const Trk::IPropagator* propagator = m_propagator.get();
2479  MagField::AtlasFieldCache fieldCache;
2480  // Get field cache object
2481  if (!loadMagneticField(ctx, fieldCache)) return nullptr;
2482  if (!fieldCache.toroidOn()) {
2483  curvatureOK = true;
2484  propagator = m_propagatorSL.get();
2485  } else if (std::abs(parameters->position().z()) < m_zECToroid &&
2486  (!m_trackQuery->isLineFit(spectrometerTrack) && errorP < m_largeMomentumError)) {
2487  curvatureOK = true;
2488  }
2489 
2490  if (curvatureOK) {
2491  // TDDO Run2 Calo TG
2492  // energy loss correction
2493  std::unique_ptr<CaloEnergy> caloEnergy{
2494  m_caloEnergyParam->energyLoss(ctx, trackEnergy, parameters->position().eta(), parameters->position().phi())};
2495 
2496  if (trackEnergy + caloEnergy->deltaE() < m_minEnergy) {
2497  ATH_MSG_DEBUG("standaloneFit: trapped in calorimeter");
2498  return nullptr;
2499  }
2500 
2501  parameterVector[Trk::qOverP] = parameters->charge() / (trackEnergy + caloEnergy->deltaE());
2502  correctedParameters = parameters->associatedSurface().createUniqueTrackParameters(
2503  parameterVector[Trk::loc1], parameterVector[Trk::loc2], parameterVector[Trk::phi], parameterVector[Trk::theta],
2504  parameterVector[Trk::qOverP], AmgSymMatrix(5)(*parameters->covariance()));
2505 
2506  // protect against spectrometer track with unrealistic energy loss
2507  // check material in spectrometer is not vastly greater than in the calo
2508  // (there are some very dense spectrometer regions)
2509  double spectrometerEnergyLoss = 0.;
2510 
2512  Trk::TrackStates::const_iterator sEnd = spectrometerTrack.trackStateOnSurfaces()->end();
2513  for (; s != sEnd; ++s) {
2514  if (!(**s).materialEffectsOnTrack()) { continue; }
2515 
2516  const Trk::MaterialEffectsOnTrack* meot = dynamic_cast<const Trk::MaterialEffectsOnTrack*>((**s).materialEffectsOnTrack());
2517 
2518  if (meot && meot->energyLoss()) { spectrometerEnergyLoss += meot->energyLoss()->deltaE(); }
2519  }
2520 
2521  if (std::abs(spectrometerEnergyLoss) > 1.5 * std::abs(caloEnergy->deltaE())) {
2522  curvatureOK = false;
2523  ATH_MSG_DEBUG("standaloneFit: excessive energy loss in spectrometer "
2524  << std::abs(spectrometerEnergyLoss / Gaudi::Units::GeV) << " GeV"
2525  << " in calo " << std::abs(caloEnergy->deltaE() / Gaudi::Units::GeV) << " GeV");
2526  }
2527  }
2528 
2529  // check perigee in indet volume when the curvature is well determined
2530  // otherwise will assume projectivity for starting parameters
2531  if (curvatureOK) {
2532  std::unique_ptr<Trk::TrackParameters> perigee{propagator->propagate(
2533  ctx, *correctedParameters, *mperigeeSurface, Trk::oppositeMomentum, false, m_magFieldProperties, Trk::nonInteracting)};
2534 
2535  if (!perigee) {
2536  ATH_MSG_DEBUG("standaloneFit: failed back extrapolation to perigee");
2537  return nullptr;
2538  }
2539 
2540  // large impact: set phi to be projective (note iteration)
2541  if (std::abs(perigee->parameters()[Trk::d0]) < m_largeImpact || !fieldCache.toroidOn()) {
2542  ATH_MSG_DEBUG("Track d0 perigee: " << std::abs(perigee->parameters()[Trk::d0]) << " which is smaller than "
2543  << m_largeImpact);
2544  } else {
2545  Amg::Vector3D position = correctedParameters->position();
2546 
2547  double deltaPhi = 0.;
2548  double deltaR = (position - perigee->position()).perp();
2549 
2550  if (std::abs(deltaR * M_PI) > std::abs(perigee->parameters()[Trk::d0])) {
2551  deltaPhi = perigee->parameters()[Trk::d0] / deltaR;
2552  }
2553 
2554  ATH_MSG_DEBUG("standaloneFit: large perigee impact " << perigee->parameters()[Trk::d0] << " deltaR, deltaPhi " << deltaR
2555  << ", " << deltaPhi);
2556 
2557  parameterVector[Trk::phi0] += deltaPhi;
2558 
2559  if (parameterVector[Trk::phi0] > M_PI) {
2560  parameterVector[Trk::phi0] -= 2. * M_PI;
2561  } else if (parameterVector[Trk::phi0] < -M_PI) {
2562  parameterVector[Trk::phi0] += 2. * M_PI;
2563  }
2564 
2565  correctedParameters = parameters->associatedSurface().createUniqueTrackParameters(
2566  parameterVector[Trk::loc1], parameterVector[Trk::loc2], parameterVector[Trk::phi], parameterVector[Trk::theta],
2567  parameterVector[Trk::qOverP], AmgSymMatrix(5)(*parameters->covariance()));
2568 
2569  perigee = propagator->propagate(ctx, *correctedParameters, *mperigeeSurface, Trk::oppositeMomentum, false,
2571 
2572  if (perigee) {
2573  deltaPhi = 0.;
2574  deltaR = (position - perigee->position()).perp();
2575 
2576  if (std::abs(deltaR * M_PI) > std::abs(perigee->parameters()[Trk::d0])) {
2577  deltaPhi = perigee->parameters()[Trk::d0] / deltaR;
2578  }
2579 
2580  ATH_MSG_VERBOSE("standaloneFit: corrected perigee impact " << perigee->parameters()[Trk::d0] << " deltaR, deltaPhi "
2581  << deltaR << ", " << deltaPhi);
2582 
2583  parameterVector[Trk::phi0] += deltaPhi;
2584  if (parameterVector[Trk::phi0] > M_PI) {
2585  parameterVector[Trk::phi0] -= 2. * M_PI;
2586  } else if (parameterVector[Trk::phi0] < -M_PI) {
2587  parameterVector[Trk::phi0] += 2. * M_PI;
2588  }
2589  correctedParameters = parameters->associatedSurface().createUniqueTrackParameters(
2590  parameterVector[Trk::loc1], parameterVector[Trk::loc2], parameterVector[Trk::phi], parameterVector[Trk::theta],
2591  parameterVector[Trk::qOverP], AmgSymMatrix(5)(*parameters->covariance()));
2592 
2593  perigee = propagator->propagate(ctx, *correctedParameters, *mperigeeSurface, Trk::oppositeMomentum, false,
2595  }
2596 
2597  if (perigee) {
2598  ATH_MSG_VERBOSE("standaloneFit: restart with impact " << perigee->parameters()[Trk::d0] << " phi0 "
2599  << perigee->parameters()[Trk::phi0]);
2600  }
2601  parameterVector[Trk::qOverP] = parameters->charge() / trackEnergy;
2602  correctedParameters = parameters->associatedSurface().createUniqueTrackParameters(
2603  parameterVector[Trk::loc1], parameterVector[Trk::loc2], parameterVector[Trk::phi], parameterVector[Trk::theta],
2604  parameterVector[Trk::qOverP], AmgSymMatrix(5)(*parameters->covariance()));
2605 
2606  parameters = std::move(correctedParameters);
2607  }
2608 
2609  // cut if perigee outside indet (but keep endcap halo)
2610  if (!perigee || !m_indetVolume->inside(perigee->position())) {
2611  if (perigee && perigee->position().z() * perigee->momentum().z() < 0. && perigee->momentum().eta() > 2.0) {
2612  ATH_MSG_DEBUG("standaloneFit: halo candidate, perigee at R " << perigee->position().perp() << " Z "
2613  << perigee->position().z());
2614  } else {
2615  ATH_MSG_DEBUG("standaloneFit: perigee outside indet volume");
2617  return nullptr;
2618  }
2619  }
2620  } else {
2621  // otherwise track out from origin (fix bug #54820)
2622  badlyDeterminedCurvature = true;
2623  Amg::Vector3D momentum = parameters->position().unit() * Gaudi::Units::TeV;
2624 
2625  std::unique_ptr<const Trk::TrackParameters> trigParameters{m_trackQuery->triggerStationParameters(spectrometerTrack, ctx)};
2626 
2627  if (trigParameters) { momentum = trigParameters->position().unit() * Gaudi::Units::TeV; }
2628 
2629  if (msgLvl(MSG::VERBOSE)) {
2630  if (trigParameters) {
2631  ATH_MSG_VERBOSE("standaloneFit: imprecise curvature measurement -"
2632  << " start with line from origin to 1st trigger station ");
2633  } else {
2634  ATH_MSG_VERBOSE("standaloneFit: imprecise curvature measurement -"
2635  << " start with line from origin to 1st measurement ");
2636  }
2637  }
2638 
2639  std::unique_ptr<Trk::TrackParameters> perigee =
2640  std::make_unique<Trk::Perigee>(mvertex->position(), momentum, 1., *mperigeeSurface);
2641 
2642  parameters = m_propagator->propagate(ctx, *perigee, perigee->associatedSurface(), Trk::alongMomentum, false,
2644 
2645  if (!parameters) {
2646  ATH_MSG_DEBUG("standaloneFit: failed back extrapolation to perigee");
2647  return nullptr;
2648  }
2649  }
2650 
2651  return parameters;
2652  }
2653 
2654  void CombinedMuonTrackBuilder::finalTrackBuild(const EventContext& ctx, std::unique_ptr<Trk::Track>& track) const {
2655  // as a final step:
2656  // refit the track if any holes can be recovered,
2657  // refit with optimization of the spectrometer hit errors,
2658  // add the corresponding TrackSummary to the track
2659  if (msgLevel(MSG::DEBUG)) countAEOTs(*track, " finalTrackBuilt input ");
2660  if (!m_muonHoleRecovery.empty()) {
2661  // chi2 before recovery
2662  double chi2Before = normalizedChi2(*track);
2663 
2664  ATH_MSG_VERBOSE(" perform spectrometer hole recovery procedure... ");
2665 
2666  std::unique_ptr<Trk::Track> recoveredTrack{m_muonHoleRecovery->recover(*track, ctx)};
2667 
2668  if (!checkTrack("finalTrackBuild1", recoveredTrack.get())) {
2669  // final track lost, this should not happen
2670  m_messageHelper->printWarning(44);
2671 
2672  } else {
2673  double chi2After = normalizedChi2(*recoveredTrack);
2674  if (chi2After < m_badFitChi2 || chi2After < chi2Before + 0.1) {
2675  track.swap(recoveredTrack);
2676  } else {
2677  ATH_MSG_VERBOSE(" track rejected by recovery as chi2 " << chi2After << " compared to " << chi2Before);
2678 
2679  if (chi2Before > m_badFitChi2) {
2680  track.reset();
2681  return;
2682  }
2683  }
2684  }
2685  ATH_MSG_VERBOSE(" finished hole recovery procedure ");
2686  }
2687  /*
2688  * DO NOT REMOVE THIS CODE BLOCK AS IT WILL BE NEEDED IN A FUTURE MR!
2689  if (!m_muonHoleRecovery.empty()) {
2690  ATH_MSG_VERBOSE(" perform spectrometer hole recovery procedure... ");
2691  using MSTrackRecovery = Muon::IMuonHoleRecoveryTool::MSTrackRecovery;
2692  MSTrackRecovery recoverResult{};
2693  constexpr unsigned int max_itr = 3;
2694  unsigned int num_itr{0};
2695  do {
2696  const double chi2Before = normalizedChi2(*track);
2697  recoverResult = m_muonHoleRecovery->recover(ctx,*track);
2698  if (!recoverResult.track) {
2699  ATH_MSG_WARNING(__FILE__<<":"<<__LINE__<<" track got lost during hole recovery. That should not happen");
2700  break;
2701  }
2702  if (!checkTrack("holeRecovery", recoverResult.track.get())){
2703  m_messageHelper->printWarning(44);
2704  break;
2705  }
2706  if (recoverResult.new_meas) {
2707  recoverResult.track = fit(ctx, *recoverResult.track, true, Trk::muon);
2708  if (!recoverResult.track) {
2709  ATH_MSG_VERBOSE(__FILE__<<":"<<__LINE__<<" track got lost during refit of recovery.");
2710  break;
2711  }
2712  const double chi2After = normalizedChi2(*recoverResult.track);
2713  if (chi2After < chi2Before) {
2714  track.swap(recoverResult.track);
2715  ATH_MSG_VERBOSE("Recovered track has better quality... old chi2:"<<chi2Before<<". New chi2: "<<chi2After
2716  <<std::endl<<m_printer->printMeasurements(*recoverResult.track)<<std::endl
2717  <<std::endl<<m_printer->printMeasurements(*track));
2718  } else break;
2719  } else {
2720  track.swap(recoverResult.track);
2721  }
2722  } while(recoverResult.new_meas && (++num_itr) <= max_itr);
2723  ATH_MSG_VERBOSE(" finished hole recovery procedure ");
2724  }
2725  */
2726  // final fit with optimized spectrometer errors
2727  if (!m_muonErrorOptimizer.empty() && !track->info().trackProperties(Trk::TrackInfo::StraightTrack) &&
2728  countAEOTs(*track, " before optimize ") == 0) {
2729  ATH_MSG_VERBOSE(" perform spectrometer error optimization... ");
2730  std::unique_ptr<Trk::Track> optimizedTrack = m_muonErrorOptimizer->optimiseErrors(*track, ctx);
2731  if (checkTrack("finalTrackBuild2", optimizedTrack.get())) {
2732  track.swap(optimizedTrack);
2733  if (msgLevel(MSG::DEBUG)) countAEOTs(*track, " finalTrackBuilt alignment errors Track ");
2734  }
2735  }
2736 
2737  // add the track summary
2738  m_trackSummary->updateTrack(ctx, *track);
2739  }
2740  void CombinedMuonTrackBuilder::momentumUpdate(std::unique_ptr<Trk::TrackParameters>& parameters, double updatedP,
2741  bool directionUpdate, double deltaPhi, double deltaTheta) const {
2742  if (!parameters) return;
2743 
2744  std::unique_ptr<Trk::TrackParameters> updatedParameters;
2745 
2746  // update for angle change
2747  Amg::Vector3D direction = parameters->momentum().unit();
2748 
2749  if (directionUpdate) {
2750  double cosDeltaPhi = 0.;
2751  double sinDeltaPhi = std::sin(deltaPhi);
2752 
2753  if (std::abs(sinDeltaPhi) < 1.) { cosDeltaPhi = std::sqrt(1. - sinDeltaPhi * sinDeltaPhi); }
2754 
2755  double cosDeltaTheta = 0.;
2756  double sinDeltaTheta = std::sin(deltaTheta);
2757 
2758  if (std::abs(sinDeltaTheta) < 1.) { cosDeltaTheta = std::sqrt(1. - sinDeltaTheta * sinDeltaTheta); }
2759 
2760  double cosTheta = direction.z() * cosDeltaTheta - direction.perp() * sinDeltaTheta;
2761  if (std::abs(cosTheta) < 1.) {
2762  direction = Amg::Vector3D(direction.x() * cosDeltaPhi - direction.y() * sinDeltaPhi,
2763  direction.y() * cosDeltaPhi + direction.x() * sinDeltaPhi,
2764  direction.perp() * cosTheta / std::sqrt(1. - cosTheta * cosTheta));
2765 
2766  } else {
2767  direction = Amg::Vector3D(0., 0., cosTheta);
2768  }
2769  direction = direction.unit();
2770  }
2771 
2772  // update for momentum (magnitude) change
2773  Amg::Vector3D momentum = updatedP * direction;
2774 
2775  // create updated parameters
2776  double charge = parameters->charge();
2777  Amg::Vector3D position = parameters->position();
2778  std::optional<AmgSymMatrix(5)> covariance =
2779  parameters->covariance() ? std::optional<AmgSymMatrix(5)>(*(parameters->covariance())) : std::nullopt;
2780  const Trk::Surface* surface = &(parameters->associatedSurface());
2781  updatedParameters = surface->createUniqueTrackParameters(position, momentum, charge, covariance);
2782 
2783  if (updatedParameters) {
2784  parameters = std::move(updatedParameters);
2785  } else {
2786  // update failed, keeping original value
2787  m_messageHelper->printWarning(45);
2788  }
2789  }
2790  std::unique_ptr<Trk::Track> CombinedMuonTrackBuilder::reallocateMaterial(const EventContext& ctx,
2791  const Trk::Track& spectrometerTrack) const {
2792  // build MeasurementSet for the spectrometer
2793  const Trk::TrackParameters* perigeeStartValue = nullptr;
2794  double perigeeDistance = 0.;
2795 
2796  Trk::MeasurementSet spectrometerMeasurements;
2797 
2799  auto sEnd = spectrometerTrack.trackStateOnSurfaces()->end();
2800  for (; s != sEnd; ++s) {
2801  if ((**s).measurementOnTrack() && !(**s).type(Trk::TrackStateOnSurface::Outlier)) {
2802  // skip pseudo measurement(s)
2803  // FIXME - need phi pseudo in some cases
2804  if (dynamic_cast<const Trk::PseudoMeasurementOnTrack*>((**s).measurementOnTrack())) { continue; }
2805 
2806  spectrometerMeasurements.push_back((**s).measurementOnTrack()->clone());
2807  if (!(**s).trackParameters() || (perigeeStartValue && (**s).trackParameters()->position().mag() > perigeeDistance)) {
2808  continue;
2809  }
2810 
2811  perigeeDistance = (**s).trackParameters()->position().mag();
2812  perigeeStartValue = (**s).trackParameters();
2813  }
2814  }
2815 
2816  // check perigeeStartValue defined
2817  if (!perigeeStartValue) {
2818  // FIXME: use spectrometerTrack.perigeeParameters()
2819  // null perigeeStartValue
2820  m_messageHelper->printWarning(46);
2821  return nullptr;
2822  }
2823 
2824  // fit with various recovery strategies
2825  std::unique_ptr<Trk::Track> spectrometerFit = fit(ctx, spectrometerMeasurements, *perigeeStartValue, true, Trk::muon);
2826  if (!spectrometerFit) {
2827  spectrometerFit = fit(ctx, spectrometerMeasurements, *perigeeStartValue, false, Trk::muon);
2828 
2829  if (!spectrometerFit) {
2830  spectrometerFit = fit(ctx, spectrometerMeasurements, *perigeeStartValue, false, Trk::nonInteracting);
2831 
2832  if (!spectrometerFit) {
2833  // spectrometer refit fails
2834  m_messageHelper->printWarning(47);
2835  }
2836  }
2837  }
2838 
2839  if (spectrometerFit) { spectrometerFit->info().addPatternReco(spectrometerTrack.info()); }
2840 
2841  Trk::MeasurementSet::iterator m = spectrometerMeasurements.begin();
2842  auto mEnd = spectrometerMeasurements.end();
2843  for (; m != mEnd; ++m) { delete *m; }
2844 
2845  return spectrometerFit;
2846  }
2847 
2848  void CombinedMuonTrackBuilder::removeSpectrometerMaterial(std::unique_ptr<Trk::Track>& track) const {
2849  // limit momentum to avoid refit allocating excessive energy loss
2850  bool limitMomentum = false;
2851  double momentum = track->perigeeParameters()->momentum().mag();
2852  double qOverP = 0.;
2853 
2854  if (momentum > m_lowMomentum) {
2855  const Trk::Perigee* measuredPerigee = track->perigeeParameters();
2856 
2857  if (measuredPerigee) {
2858  Trk::TrackStates::const_reverse_iterator r = track->trackStateOnSurfaces()->rbegin();
2859 
2860  while (!(**r).trackParameters()) { --r; }
2861 
2862  limitMomentum = true;
2863 
2864  if (!measuredPerigee->covariance()) {
2865  ATH_MSG_DEBUG("measuredPerigee has no covariance, qOverP not set");
2866  qOverP = (**r).trackParameters()->parameters()[Trk::qOverP];
2867  } else {
2868  qOverP = (**r).trackParameters()->parameters()[Trk::qOverP] +
2869  measuredPerigee->charge() * std::sqrt((*measuredPerigee->covariance())(Trk::qOverP, Trk::qOverP));
2870 
2871  ATH_MSG_DEBUG(" limit momentum to " << 1. / std::abs(qOverP * Gaudi::Units::GeV) << " from original value "
2873  }
2874  }
2875  }
2876 
2877  // remove spectrometer material from track
2878  std::bitset<Trk::TrackStateOnSurface::NumberOfTrackStateOnSurfaceTypes> defaultType;
2879  std::bitset<Trk::TrackStateOnSurface::NumberOfTrackStateOnSurfaceTypes> type = defaultType;
2880  auto trackStateOnSurfaces = std::make_unique<Trk::TrackStates>();
2881 
2882  trackStateOnSurfaces->reserve(track->trackStateOnSurfaces()->size());
2883  bool is_first{true};
2884  for (const Trk::TrackStateOnSurface* tsos : *track->trackStateOnSurfaces()) {
2885  // limit perigee
2886  if (tsos->trackParameters()) {
2887  if (limitMomentum && is_first && tsos->trackParameters()->covariance() &&
2888  tsos->trackParameters()->surfaceType() == Trk::SurfaceType::Perigee) {
2889  Amg::VectorX parameterVector = tsos->trackParameters()->parameters();
2890  parameterVector[Trk::qOverP] = qOverP;
2891 
2893  std::unique_ptr<Trk::TrackParameters> parameters =
2894  tsos->trackParameters()->associatedSurface().createUniqueTrackParameters(
2895  parameterVector[Trk::loc1], parameterVector[Trk::loc2], parameterVector[Trk::phi], parameterVector[Trk::theta],
2896  parameterVector[Trk::qOverP], *tsos->trackParameters()->covariance());
2897 
2898  type = defaultType;
2900 
2901  std::unique_ptr<Trk::MeasurementBase> measurementBase;
2902  if (tsos->measurementOnTrack()) {
2903  measurementBase = tsos->measurementOnTrack()->uniqueClone();
2905  }
2906  trackStateOnSurfaces->push_back(
2907  new Trk::TrackStateOnSurface(std::move(measurementBase), std::move(parameters), nullptr, type));
2908  } else {
2909  trackStateOnSurfaces->push_back(tsos->clone());
2910  }
2911  is_first = false;
2912  continue;
2913  }
2914  is_first = false;
2915 
2916  // material in spectrometer
2917  if (tsos->materialEffectsOnTrack() &&
2918  !m_calorimeterVolume->inside(tsos->materialEffectsOnTrack()->associatedSurface().globalReferencePoint())) {
2919  if (tsos->measurementOnTrack()) {
2920  Amg::VectorX parameterVector = tsos->trackParameters()->parameters();
2921  if (limitMomentum) { parameterVector[Trk::qOverP] = qOverP; }
2922  std::unique_ptr<Trk::TrackParameters> trackParameters =
2923  tsos->trackParameters()->associatedSurface().createUniqueTrackParameters(
2924  parameterVector[Trk::loc1], parameterVector[Trk::loc2], parameterVector[Trk::phi], parameterVector[Trk::theta],
2925  parameterVector[Trk::qOverP],
2926  tsos->trackParameters()->covariance() ? std::optional<AmgSymMatrix(5)>(*tsos->trackParameters()->covariance())
2927  : std::nullopt);
2928 
2929  type = defaultType;
2931 
2933  std::unique_ptr<Trk::MeasurementBase> measurementBase;
2934  measurementBase = tsos->measurementOnTrack()->uniqueClone();
2935  trackStateOnSurfaces->push_back(
2936  new Trk::TrackStateOnSurface(std::move(measurementBase), std::move(trackParameters), nullptr, type));
2937  }
2938  continue;
2939  } else if (!tsos->measurementOnTrack() && tsos->trackParameters() &&
2940  !m_calorimeterVolume->inside(tsos->trackParameters()->position())) {
2941  continue;
2942  }
2943 
2944  if (limitMomentum && tsos->trackParameters()) {
2945  Amg::VectorX parameterVector = tsos->trackParameters()->parameters();
2946  parameterVector[Trk::qOverP] = qOverP;
2947  std::unique_ptr<Trk::TrackParameters> trackParameters =
2948  tsos->trackParameters()->associatedSurface().createUniqueTrackParameters(
2949  parameterVector[Trk::loc1], parameterVector[Trk::loc2], parameterVector[Trk::phi], parameterVector[Trk::theta],
2950  parameterVector[Trk::qOverP],
2951  tsos->trackParameters()->covariance() ? std::optional<AmgSymMatrix(5)>(*tsos->trackParameters()->covariance())
2952  : std::nullopt);
2953 
2954  type = defaultType;
2955 
2956  std::unique_ptr<Trk::MeasurementBase> measurementBase;
2957  if (tsos->measurementOnTrack()) {
2959 
2961 
2962  measurementBase = tsos->measurementOnTrack()->uniqueClone();
2963  }
2964 
2965  std::unique_ptr<Trk::MaterialEffectsBase> materialEffects;
2966  if (tsos->materialEffectsOnTrack()) {
2969 
2970  materialEffects = tsos->materialEffectsOnTrack()->uniqueClone();
2971  }
2972  trackStateOnSurfaces->push_back(new Trk::TrackStateOnSurface(std::move(measurementBase), std::move(trackParameters),
2973  std::move(materialEffects), type));
2974  } else {
2975  trackStateOnSurfaces->push_back(tsos->clone());
2976  }
2977  }
2978 
2979  // replace track
2980  Trk::TrackInfo trackInfo = track->info();
2981  std::unique_ptr<Trk::FitQuality> fitQuality = nullptr;
2982  if (track->fitQuality()) { fitQuality = std::make_unique<Trk::FitQuality>(*track->fitQuality()); }
2983 
2984  track = std::make_unique<Trk::Track>(trackInfo, std::move(trackStateOnSurfaces), std::move(fitQuality));
2985  }
2986 
2987  std::unique_ptr<Trk::PseudoMeasurementOnTrack> CombinedMuonTrackBuilder::vertexOnTrack(const Trk::TrackParameters& parameters,
2988  const Trk::RecVertex* vertex,
2989  const Trk::RecVertex* mbeamAxis) {
2990  // create the corresponding PerigeeSurface, localParameters and covarianceMatrix
2991  const Trk::PerigeeSurface surface(vertex->position());
2992  Trk::LocalParameters localParameters;
2993  Amg::MatrixX covarianceMatrix;
2994  covarianceMatrix.setZero();
2995 
2996  // transform Cartesian (x,y,z) to beam axis or perigee
2997  Amg::Vector2D localPosition(0, 0);
2998  double ptInv = 1. / parameters.momentum().perp();
2999 
3000  if (vertex == mbeamAxis) {
3001  Trk::DefinedParameter d0(localPosition[Trk::locX], Trk::locX);
3002  localParameters = Trk::LocalParameters(d0);
3003 
3004  Amg::MatrixX jacobian(1, 3);
3005  jacobian.setZero();
3006  jacobian(0, 0) = -ptInv * parameters.momentum().y();
3007  jacobian(0, 1) = ptInv * parameters.momentum().x();
3008 
3009  const Amg::MatrixX& cov = vertex->covariancePosition();
3010  covarianceMatrix = cov.similarity(jacobian);
3011  } else {
3012  localParameters = Trk::LocalParameters(localPosition);
3013 
3014  Amg::MatrixX jacobian(2, 3);
3015  jacobian.setZero();
3016  jacobian(0, 0) = -ptInv * parameters.momentum().y();
3017  jacobian(0, 1) = ptInv * parameters.momentum().x();
3018  jacobian(1, 2) = 1.0;
3019 
3020  const Amg::MatrixX& cov = vertex->covariancePosition();
3021  covarianceMatrix = cov.similarity(jacobian);
3022  }
3023 
3024  return std::make_unique<Trk::PseudoMeasurementOnTrack>(std::move(localParameters),
3025  std::move(covarianceMatrix),
3026  surface);
3027  }
3028 
3029  void CombinedMuonTrackBuilder::dumpCaloEloss(const Trk::Track* track, const std::string& txt) const {
3030  // will refit if extrapolated track was definitely bad
3031  if (!track || !msgLevel(MSG::DEBUG)) return;
3032  if (!m_trackQuery->isCaloAssociated(*track, Gaudi::Hive::currentContext())) {
3033  ATH_MSG_DEBUG(txt << " no TSOS in Calorimeter ");
3034  return;
3035  }
3036 
3037  const Trk::Track& originalTrack = *track;
3038  const CaloEnergy* caloEnergy = m_trackQuery->caloEnergy(originalTrack);
3039  if (caloEnergy) {
3040  ATH_MSG_DEBUG(txt << " Calorimeter Eloss " << caloEnergy->deltaE());
3041  } else {
3042  ATH_MSG_DEBUG(txt << " No Calorimeter Eloss");
3043  }
3044 
3045  const Trk::TrackStates* trackTSOS = track->trackStateOnSurfaces();
3046 
3047  double Eloss = 0.;
3048  double idEloss = 0.;
3049  double caloEloss = 0.;
3050  double msEloss = 0.;
3051  double deltaP = 0.;
3052  double pcalo = 0.;
3053  double pstart = 0.;
3054  double eta = 0.;
3055  double pMuonEntry = 0.;
3056 
3057  for (const auto* m : *trackTSOS) {
3058  const Trk::MeasurementBase* mot = m->measurementOnTrack();
3059 
3060  if (m->trackParameters()) { pMuonEntry = m->trackParameters()->momentum().mag(); }
3061 
3062  if (mot) {
3064  if (id.is_valid()) {
3065  // skip after first Muon hit
3066  if (m_idHelperSvc->isMuon(id)) { break; }
3067  }
3068  }
3069 
3070  if (pstart == 0 && m->trackParameters()) {
3071  pstart = m->trackParameters()->momentum().mag();
3072  eta = m->trackParameters()->momentum().eta();
3073 
3074  ATH_MSG_DEBUG("Start pars found eta " << eta << " r " << (m->trackParameters())->position().perp() << " z "
3075  << (m->trackParameters())->position().z() << " pstart " << pstart);
3076  }
3077 
3078  if (m->materialEffectsOnTrack()) {
3079  const Trk::MaterialEffectsOnTrack* meot = dynamic_cast<const Trk::MaterialEffectsOnTrack*>(m->materialEffectsOnTrack());
3080 
3081  if (meot) {
3082  if (meot->thicknessInX0() > 20) {
3083  const Trk::ScatteringAngles* scatAngles = meot->scatteringAngles();
3084 
3085  ATH_MSG_DEBUG(" Calorimeter X0 " << meot->thicknessInX0() << " pointer scat " << scatAngles);
3086 
3087  if (scatAngles) {
3088  pcalo = m->trackParameters()->momentum().mag();
3089  double pullPhi = scatAngles->deltaPhi() / scatAngles->sigmaDeltaPhi();
3090  double pullTheta = scatAngles->deltaTheta() / scatAngles->sigmaDeltaTheta();
3091 
3092  ATH_MSG_DEBUG(" Calorimeter scatterer deltaPhi (mrad) "
3093  << 1000 * scatAngles->deltaPhi() << " sigma " << 1000 * scatAngles->sigmaDeltaPhi() << " pull "
3094  << pullPhi << " deltaTheta (mrad) " << 1000 * scatAngles->deltaTheta() << " sigma "
3095  << 1000 * scatAngles->sigmaDeltaTheta() << " pull " << pullTheta);
3096  }
3097  }
3098 
3099  const Trk::EnergyLoss* energyLoss = meot->energyLoss();
3100  if (energyLoss) {
3101  if (m->trackParameters()) {
3102  ATH_MSG_DEBUG("Eloss found r " << (m->trackParameters())->position().perp() << " z "
3103  << (m->trackParameters())->position().z() << " value " << energyLoss->deltaE()
3104  << " Eloss " << Eloss);
3105  }
3106 
3108  idEloss = Eloss;
3109  caloEloss = std::abs(energyLoss->deltaE());
3110  Eloss = 0.;
3111 
3112  if (m->trackParameters()) { deltaP = m->trackParameters()->momentum().mag() - pcalo; }
3113 
3114  const Trk::Surface& surface = m->surface();
3115 
3116  ATH_MSG_DEBUG(" Calorimeter surface " << surface);
3117  ATH_MSG_DEBUG(txt << " Calorimeter delta p " << deltaP << " deltaE " << caloEloss
3118  << " delta pID = pcaloEntry-pstart " << pcalo - pstart);
3119 
3120  } else {
3121  Eloss += std::abs(energyLoss->deltaE());
3122  }
3123  }
3124  }
3125  }
3126  }
3127 
3128  msEloss = Eloss;
3129  Eloss = idEloss + caloEloss + msEloss;
3130 
3131  ATH_MSG_DEBUG(txt << " eta " << eta << " pstart " << pstart / Gaudi::Units::GeV << " Eloss on TSOS idEloss " << idEloss
3132  << " caloEloss " << caloEloss << " msEloss " << msEloss << " Total " << Eloss << " pstart - pMuonEntry "
3133  << pstart - pMuonEntry);
3134 
3135  return;
3136  }
3137 
3138  const Trk::TrackingVolume* CombinedMuonTrackBuilder::getVolume(const EventContext& ctx, const std::string&& vol_name) const {
3141  if (!handle.isValid()) {
3142  ATH_MSG_WARNING("Could not retrieve a valid tracking geometry");
3143  return nullptr;
3144  }
3145  return handle.cptr()->trackingVolume(vol_name);
3146  }
3147  std::vector<std::unique_ptr<const Trk::TrackStateOnSurface>> CombinedMuonTrackBuilder::getCaloTSOSfromMatProvider(
3148  const Trk::TrackParameters& track_params, const Trk::Track& me_track) const {
3149  std::vector<std::unique_ptr<const Trk::TrackStateOnSurface>> to_ret;
3150  std::unique_ptr<std::vector<const Trk::TrackStateOnSurface*>> tsos_vec{m_materialUpdator->getCaloTSOS(track_params, me_track)};
3151  if (tsos_vec) {
3152  to_ret.reserve(tsos_vec->size());
3153  for (const Trk::TrackStateOnSurface* tsos : *tsos_vec) to_ret.emplace_back(tsos);
3154  }
3155  return to_ret;
3156  }
3157 
3158 } // namespace Rec
grepfile.info
info
Definition: grepfile.py:38
xAOD::iterator
JetConstituentVector::iterator iterator
Definition: JetConstituentVector.cxx:68
Rec::CombinedMuonTrackBuilder::m_beamAxis
std::unique_ptr< const Trk::RecVertex > m_beamAxis
Definition: CombinedMuonTrackBuilder.h:239
Muon::MuonTSOSHelper::createPerigeeTSOS
static std::unique_ptr< Trk::TrackStateOnSurface > createPerigeeTSOS(std::unique_ptr< Trk::TrackParameters > perigee)
create a perigee TSOS, takes ownership of the Perigee
Definition: MuonTSOSHelper.h:54
CaloEnergy::Tail
@ Tail
Definition: CaloEnergy.h:43
Trk::ScatteringAngles::deltaPhi
double deltaPhi() const
returns the
Definition: ScatteringAngles.h:82
Trk::anyDirection
@ anyDirection
Definition: PropDirection.h:22
RecVertex.h
TrapezoidBounds.h
Rec::CombinedMuonTrackBuilder::getVolume
const Trk::TrackingVolume * getVolume(const EventContext &ctx, const std::string &&vol_name) const
Definition: CombinedMuonTrackBuilder.cxx:3138
beamspotman.r
def r
Definition: beamspotman.py:676
Trk::LocalParameters
Definition: LocalParameters.h:98
Trk::TrackStateOnSurface::trackParameters
const TrackParameters * trackParameters() const
return ptr to trackparameters const overload
Trk::Vertex
Definition: Tracking/TrkEvent/VxVertex/VxVertex/Vertex.h:26
Rec::CombinedMuonTrackBuilder::createPhiPseudoMeasurement
std::unique_ptr< Trk::TrackStateOnSurface > createPhiPseudoMeasurement(const EventContext &ctx, const Trk::Track &track) const
Definition: CombinedMuonTrackBuilder.cxx:2257
Trk::TrackStateOnSurface::CaloDeposit
@ CaloDeposit
This TSOS contains a CaloEnergy object.
Definition: TrackStateOnSurface.h:135
EnergyLoss.h
Trk::TrackInfo
Contains information about the 'fitter' of this track.
Definition: Tracking/TrkEvent/TrkTrack/TrkTrack/TrackInfo.h:32
Trk::TrackStateOnSurface::Perigee
@ Perigee
This represents a perigee, and so will contain a Perigee object only.
Definition: TrackStateOnSurface.h:117
PlotCalibFromCool.norm
norm
Definition: PlotCalibFromCool.py:100
ScatteringAngles.h
Rec::CombinedMuonTrackBuilder::m_largeMomentumChange
Gaudi::Property< double > m_largeMomentumChange
Definition: CombinedMuonTrackBuilder.h:221
DataModel_detail::const_iterator
Const iterator class for DataVector/DataList.
Definition: DVLIterator.h:82
Rec::CombinedMuonTrackBuilder::m_edmHelperSvc
ServiceHandle< Muon::IMuonEDMHelperSvc > m_edmHelperSvc
Definition: CombinedMuonTrackBuilder.h:199
Rec::CombinedMuonTrackBuilder::m_alignUncertTool_theta
PublicToolHandle< Muon::IMuonAlignmentUncertTool > m_alignUncertTool_theta
ToolHandles to retrieve the uncertainties for theta and phi for the scattering uncertainties.
Definition: CombinedMuonTrackBuilder.h:193
Trk::Track::fitQuality
const FitQuality * fitQuality() const
return a pointer to the fit quality const-overload
Rec::CombinedMuonTrackBuilder::vertexOnTrack
static std::unique_ptr< Trk::PseudoMeasurementOnTrack > vertexOnTrack(const Trk::TrackParameters &parameters, const Trk::RecVertex *vertex, const Trk::RecVertex *mbeamAxis)
Definition: CombinedMuonTrackBuilder.cxx:2987
python.SystemOfUnits.s
int s
Definition: SystemOfUnits.py:131
Amg::VectorX
Eigen::Matrix< double, Eigen::Dynamic, 1 > VectorX
Dynamic Vector - dynamic allocation.
Definition: EventPrimitives.h:32
Amg::hasPositiveDiagElems
bool hasPositiveDiagElems(const AmgSymMatrix(N) &mat)
Returns true if all diagonal elements of the covariance matrix are finite aka sane in the above defin...
Definition: EventPrimitivesCovarianceHelpers.h:96
tolerance
constexpr double tolerance
Definition: runMdtGeoComparison.cxx:105
Amg::MatrixX
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic > MatrixX
Dynamic Matrix - dynamic allocation.
Definition: EventPrimitives.h:29
Rec::CombinedMuonTrackBuilder::addIDMSerrors
std::unique_ptr< Trk::Track > addIDMSerrors(const Trk::Track *track) const
Definition: CombinedMuonTrackBuilder.cxx:1558
Rec::CombinedMuonTrackBuilder::m_trackingGeometryReadKey
SG::ReadCondHandleKey< Trk::TrackingGeometry > m_trackingGeometryReadKey
Definition: CombinedMuonTrackBuilder.h:205
python.SystemOfUnits.m
int m
Definition: SystemOfUnits.py:91
TrackParameters.h
Rec::CombinedMuonTrackBuilder::m_countBeamAxis
std::atomic_uint m_countBeamAxis
Definition: CombinedMuonTrackBuilder.h:246
Rec::CombinedMuonTrackBuilder::m_refineELossStandAloneTrackFit
Gaudi::Property< bool > m_refineELossStandAloneTrackFit
Definition: CombinedMuonTrackBuilder.h:253
MeasurementBase.h
Rec::CombinedMuonTrackBuilder::entrancePerigee
std::unique_ptr< Trk::TrackStateOnSurface > entrancePerigee(const EventContext &ctx, const Trk::TrackParameters *parameters) const
Definition: CombinedMuonTrackBuilder.cxx:2416
HitType::extrapolated
@ extrapolated
SG::ReadCondHandle
Definition: ReadCondHandle.h:44
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
Rec::CombinedMuonTrackBuilder::m_numberSigmaFSR
Gaudi::Property< double > m_numberSigmaFSR
Definition: CombinedMuonTrackBuilder.h:228
PerigeeSurface.h
CaloEnergy
class extending the basic Trk::EnergyLoss to describe the measured or parameterised muon energy loss ...
Definition: CaloEnergy.h:28
Rec::CombinedMuonTrackBuilder::createMuonTrack
std::unique_ptr< Trk::Track > createMuonTrack(const EventContext &ctx, const Trk::Track &muonTrack, const Trk::TrackParameters *parameters, std::unique_ptr< CaloEnergy > caloEnergy, const Trk::TrackStates *tsos) const
Summarizes the available information about the ID track, the deposited calorimeter energies and the t...
Definition: CombinedMuonTrackBuilder.cxx:2093
Trk::locX
@ locX
Definition: ParamDefs.h:43
find
std::string find(const std::string &s)
return a remapped string
Definition: hcg.cxx:135
MuonTrackSummary.h
CompetingRIOsOnTrack.h
Trk::locY
@ locY
local cartesian
Definition: ParamDefs.h:44
Surface.h
Trk::Track
The ATLAS Track class.
Definition: Tracking/TrkEvent/TrkTrack/TrkTrack/Track.h:73
Rec::CombinedMuonTrackBuilder::m_muClusterRotCreator
ToolHandle< Muon::IMuonClusterOnTrackCreator > m_muClusterRotCreator
Definition: CombinedMuonTrackBuilder.h:157
perp
Scalar perp() const
perp method - perpenticular length
Definition: AmgMatrixBasePlugin.h:35
Rec::CombinedMuonTrackBuilder::removeSpectrometerMaterial
void removeSpectrometerMaterial(std::unique_ptr< Trk::Track > &track) const
Definition: CombinedMuonTrackBuilder.cxx:2848
Trk::PerigeeSurface
Definition: PerigeeSurface.h:43
Trk::TrackStateOnSurface::clone
virtual TrackStateOnSurface * clone() const
Pseudo-constructor: needed to avoid excessive RTTI.
CaloEnergy::set_energyLossType
void set_energyLossType(const CaloEnergy::EnergyLossType lossType)
set methods
Definition: CaloEnergy.h:102
eta
Scalar eta() const
pseudorapidity method
Definition: AmgMatrixBasePlugin.h:79
Trk::ParametersBase::position
const Amg::Vector3D & position() const
Access method for the position.
Amg::Vector2D
Eigen::Matrix< double, 2, 1 > Vector2D
Definition: GeoPrimitives.h:48
Trk::oppositeMomentum
@ oppositeMomentum
Definition: PropDirection.h:21
xAODP4Helpers.h
Trk::ParametersBase::associatedSurface
virtual const Surface & associatedSurface() const override=0
Access to the Surface associated to the Parameters.
Rec::CombinedMuonTrackFitter::m_messageHelper
std::unique_ptr< MessageHelper > m_messageHelper
Definition: CombinedMuonTrackFitter.h:155
Trk::ParametersBase::uniqueClone
std::unique_ptr< ParametersBase< DIM, T > > uniqueClone() const
clone method for polymorphic deep copy returning unique_ptr; it is not overriden, but uses the existi...
Definition: ParametersBase.h:97
Rec::CombinedMuonTrackFitter::fit
virtual std::unique_ptr< Trk::Track > fit(const EventContext &ctx, const Trk::Track &track, const Trk::RunOutlierRemoval runOutlier, const Trk::ParticleHypothesis particleHypothesis) const override
Definition: CombinedMuonTrackFitter.cxx:154
CombinedMuonTrackBuilder.h
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
xAOD::deltaPhi
setSAddress setEtaMS setDirPhiMS setDirZMS setBarrelRadius setEndcapAlpha setEndcapRadius setInterceptInner setEtaMap setEtaBin setIsTgcFailure setDeltaPt deltaPhi
Definition: L2StandAloneMuon_v1.cxx:160
Trk::Track::info
const TrackInfo & info() const
Returns a const ref to info of a const tracks.
Trk::RotatedTrapezoidBounds
Definition: RotatedTrapezoidBounds.h:45
Rec::CombinedMuonTrackBuilder::caloEnergyParameters
const CaloEnergy * caloEnergyParameters(const Trk::Track *combinedTrack, const Trk::Track *muonTrack, const Trk::TrackParameters *&combinedEnergyParameters, const Trk::TrackParameters *&muonEnergyParameters) const
Definition: CombinedMuonTrackBuilder.cxx:1697
Rec::CombinedMuonTrackBuilder::createExtrapolatedTrack
std::unique_ptr< Trk::Track > createExtrapolatedTrack(const EventContext &ctx, const Trk::Track &spectrometerTrack, const Trk::TrackParameters &parameters, Trk::ParticleHypothesis particleHypothesis, Trk::RunOutlierRemoval runOutlier, const std::vector< std::unique_ptr< const Trk::TrackStateOnSurface >> &trackStateOnSurfaces, const Trk::RecVertex *vertex, const Trk::RecVertex *mbeamAxis, const Trk::PerigeeSurface *mperigeeSurface, const Trk::Perigee *seedParameter=nullptr) const
Definition: CombinedMuonTrackBuilder.cxx:1738
Rec::CombinedMuonTrackBuilder::m_addElossID
Gaudi::Property< bool > m_addElossID
Definition: CombinedMuonTrackBuilder.h:254
EventPrimitivesHelpers.h
Trk::ParametersBase::surfaceType
constexpr virtual SurfaceType surfaceType() const override=0
Returns the Surface Type enum for the surface used to define the derived class.
PlotCalibFromCool.begin
begin
Definition: PlotCalibFromCool.py:94
Rec::CombinedMuonTrackBuilder::appendSelectedTSOS
void appendSelectedTSOS(Trk::TrackStates &trackStateOnSurfaces, Trk::TrackStates::const_iterator begin, Trk::TrackStates::const_iterator end) const
Definition: CombinedMuonTrackBuilder.cxx:1653
Rec::CombinedMuonTrackFitter::m_updateWithCaloTG
Gaudi::Property< bool > m_updateWithCaloTG
Definition: CombinedMuonTrackFitter.h:147
skel.it
it
Definition: skel.GENtoEVGEN.py:423
Rec::CombinedMuonTrackBuilder::m_refineELossCombinedTrackFit
Gaudi::Property< bool > m_refineELossCombinedTrackFit
Definition: CombinedMuonTrackBuilder.h:252
plotBeamSpotVxVal.cov
cov
Definition: plotBeamSpotVxVal.py:201
Trk::TrackInfo::MuidStandaloneRefit
@ MuidStandaloneRefit
Standalone muon that was obtained by refitting a combined muon using the calorimeter information of t...
Definition: Tracking/TrkEvent/TrkTrack/TrkTrack/TrackInfo.h:233
Trk::EnergyLoss::sigmaDeltaE
double sigmaDeltaE() const
returns the symmatric error
CompetingMuonClustersOnTrack.h
M_PI
#define M_PI
Definition: ActiveFraction.h:11
SG::ReadCondHandle::isValid
bool isValid()
Definition: ReadCondHandle.h:205
Rec::CombinedMuonTrackFitter::m_badFitChi2
Gaudi::Property< double > m_badFitChi2
Definition: CombinedMuonTrackFitter.h:144
Rec::CombinedMuonTrackFitter::m_muonErrorOptimizer
ToolHandle< Muon::IMuonErrorOptimisationTool > m_muonErrorOptimizer
Definition: CombinedMuonTrackFitter.h:104
Rec::CombinedMuonTrackBuilder::m_lowMomentum
Gaudi::Property< double > m_lowMomentum
Definition: CombinedMuonTrackBuilder.h:225
Rec::CombinedMuonTrackFitter::initialize
virtual StatusCode initialize() override
Definition: CombinedMuonTrackFitter.cxx:56
Trk::TrackStateOnSurface::dumpType
std::string dumpType() const
returns a string with the expanded type of the object (i.e.
Definition: TrackStateOnSurface.cxx:147
Trk::z0
@ z0
Definition: ParamDefs.h:70
AthCommonMsg< AlgTool >::msgLvl
bool msgLvl(const MSG::Level lvl) const
Definition: AthCommonMsg.h:30
Trk::ScatteringAngles
represents a deflection of the track caused through multiple scattering in material.
Definition: ScatteringAngles.h:26
xAOD::P4Helpers::deltaPhi
double deltaPhi(double phiA, double phiB)
delta Phi in range [-pi,pi[
Definition: xAODP4Helpers.h:69
Trk::TrackStateOnSurface::measurementOnTrack
const MeasurementBase * measurementOnTrack() const
returns MeasurementBase const overload
Trk::loc2
@ loc2
generic first and second local coordinate
Definition: ParamDefs.h:41
python.sizes.txt
string txt
Definition: sizes.py:141
Rec::CombinedMuonTrackBuilder::m_vertex3DSigmaRPhi
Gaudi::Property< double > m_vertex3DSigmaRPhi
Definition: CombinedMuonTrackBuilder.h:232
Trk::MaterialEffectsBase::thicknessInX0
double thicknessInX0() const
returns the actually traversed material .
Trk::RIO_OnTrack
Definition: RIO_OnTrack.h:70
python.SystemOfUnits.TeV
int TeV
Definition: SystemOfUnits.py:158
Trk::alongMomentum
@ alongMomentum
Definition: PropDirection.h:20
Rec::CombinedMuonTrackBuilder::dumpCaloEloss
void dumpCaloEloss(const Trk::Track *track, const std::string &txt) const
Definition: CombinedMuonTrackBuilder.cxx:3029
Trk::Surface::globalReferencePoint
virtual const Amg::Vector3D & globalReferencePoint() const
Returns a global reference point on the surface, for PlaneSurface, StraightLineSurface,...
read_hist_ntuple.t
t
Definition: read_hist_ntuple.py:5
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
MdtDriftCircleOnTrack.h
InDetAccessor::qOverP
@ qOverP
perigee
Definition: InDetAccessor.h:35
Rec::CombinedMuonTrackBuilder::reallocateMaterial
std::unique_ptr< Trk::Track > reallocateMaterial(const EventContext &ctx, const Trk::Track &spectrometerTrack) const
Definition: CombinedMuonTrackBuilder.cxx:2790
Trk::MaterialEffectsBase
base class to integrate material effects on Trk::Track in a flexible way.
Definition: MaterialEffectsBase.h:35
Trk::Surface::center
const Amg::Vector3D & center() const
Returns the center position of the Surface.
MagField::AtlasFieldCache::toroidOn
bool toroidOn() const
Trk::combinedTrack
void combinedTrack(long int ICH, double *pv0, double *covi, double BMAG, double *par, double *covo)
Definition: XYZtrp.cxx:113
AmgSymMatrix
#define AmgSymMatrix(dim)
Definition: EventPrimitives.h:52
Trk::MaterialEffectsBase::uniqueClone
std::unique_ptr< MaterialEffectsBase > uniqueClone() const
NVI uniqueClone.
Definition: MaterialEffectsBase.h:87
Rec::CombinedMuonTrackBuilder::indetExtension
virtual std::unique_ptr< Trk::Track > indetExtension(const EventContext &ctx, const Trk::Track &indetTrack, const Trk::MeasurementSet &spectrometerMeas, std::unique_ptr< Trk::TrackParameters > innerParameters, std::unique_ptr< Trk::TrackParameters > middleParameters, std::unique_ptr< Trk::TrackParameters > outerParameters) const override
ICombinedMuonTrackBuilder interface: build and fit indet track extended to include MS Measurement set...
Definition: CombinedMuonTrackBuilder.cxx:409
Rec::CombinedMuonTrackFitter::m_printer
ToolHandle< Muon::MuonEDMPrinterTool > m_printer
Definition: CombinedMuonTrackFitter.h:109
Trk::RecVertex
Trk::RecVertex inherits from Trk::Vertex.
Definition: RecVertex.h:44
Trk::RunOutlierRemoval
bool RunOutlierRemoval
switch to toggle quality processing after fit
Definition: FitterTypes.h:22
Trk::energyDeposit
@ energyDeposit
Definition: MeasurementType.h:32
mergePhysValFiles.end
end
Definition: DataQuality/DataQualityUtils/scripts/mergePhysValFiles.py:93
Trk::DefinedParameter
std::pair< double, ParamDefs > DefinedParameter
Definition: DefinedParameter.h:27
IdentifierExtractor.h
MessageHelper.h
Trk::TrackStateOnSurface::Outlier
@ Outlier
This TSoS contains an outlier, that is, it contains a MeasurementBase/RIO_OnTrack which was not used ...
Definition: TrackStateOnSurface.h:122
Track.h
Rec::CombinedMuonTrackBuilder::m_lineMomentum
Gaudi::Property< double > m_lineMomentum
Definition: CombinedMuonTrackBuilder.h:224
MaterialEffectsOnTrack.h
Trk::TrackInfo::StraightTrack
@ StraightTrack
A straight track.
Definition: Tracking/TrkEvent/TrkTrack/TrkTrack/TrackInfo.h:84
Rec::CombinedMuonTrackBuilder::m_countAcceptedStandaloneFit
std::atomic_uint m_countAcceptedStandaloneFit
Definition: CombinedMuonTrackBuilder.h:245
Trk::PseudoMeasurementOnTrack
Class to handle pseudo-measurements in fitters and on track objects.
Definition: PseudoMeasurementOnTrack.h:44
Rec::CombinedMuonTrackBuilder::m_cleanCombined
Gaudi::Property< bool > m_cleanCombined
Definition: CombinedMuonTrackBuilder.h:212
pdg_comparison.X0
X0
Definition: pdg_comparison.py:314
Trk::ParticleHypothesis
ParticleHypothesis
Definition: ParticleHypothesis.h:25
Rec::CombinedMuonTrackBuilder::m_propagator
ToolHandle< Trk::IPropagator > m_propagator
Definition: CombinedMuonTrackBuilder.h:179
python.setupRTTAlg.size
int size
Definition: setupRTTAlg.py:39
Rec::CombinedMuonTrackBuilder::m_mdtRotCreator
ToolHandle< Muon::IMdtDriftCircleOnTrackCreator > m_mdtRotCreator
Definition: CombinedMuonTrackBuilder.h:169
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.
Rec::CombinedMuonTrackFitter::checkTrack
bool checkTrack(std::string_view txt, const Trk::Track *newTrack) const
Definition: CombinedMuonTrackFitter.cxx:603
Trk::TrackInfo::addPatternReco
void addPatternReco(const TrackInfo &)
A method adding just pattern recognition info without adding the actual properties.
MuonTSOSHelper.h
Trk::ScatteringAngles::sigmaDeltaTheta
double sigmaDeltaTheta() const
returns the
Definition: ScatteringAngles.h:100
Rec::CombinedMuonTrackBuilder::m_vertex2DSigmaRPhi
Gaudi::Property< double > m_vertex2DSigmaRPhi
Definition: CombinedMuonTrackBuilder.h:230
Rec::CombinedMuonTrackFitter::loadMagneticField
bool loadMagneticField(const EventContext &ctx, MagField::AtlasFieldCache &field_cache) const
Definition: CombinedMuonTrackFitter.cxx:537
EventPrimitivesToStringConverter.h
ParticleGun_EoverP_Config.momentum
momentum
Definition: ParticleGun_EoverP_Config.py:63
Trk::TrackStateOnSurface::Hole
@ Hole
A hole on the track - this is defined in the following way.
Definition: TrackStateOnSurface.h:128
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.
Rec::CombinedMuonTrackFitter
Definition: CombinedMuonTrackFitter.h:43
Trk::TrackStateOnSurface::materialEffectsOnTrack
const MaterialEffectsBase * materialEffectsOnTrack() const
return material effects const overload
Rec::CombinedMuonTrackBuilder::CombinedMuonTrackBuilder
CombinedMuonTrackBuilder(const std::string &type, const std::string &name, const IInterface *parent)
Definition: CombinedMuonTrackBuilder.cxx:58
Rec
Name: MuonSpContainer.h Package : offline/Reconstruction/MuonIdentification/muonEvent.
Definition: FakeTrackBuilder.h:10
Rec::CombinedMuonTrackBuilder::m_countVertexRegion
std::atomic_uint m_countVertexRegion
Definition: CombinedMuonTrackBuilder.h:248
Identifier
Definition: DetectorDescription/Identifier/Identifier/Identifier.h:32
Trk::theta
@ theta
Definition: ParamDefs.h:72
Rec::CombinedMuonTrackFitter::m_trackSummary
ToolHandle< Trk::ITrackSummaryTool > m_trackSummary
Definition: CombinedMuonTrackFitter.h:119
Trk::IPropagator
Definition: IPropagator.h:55
Rec::CombinedMuonTrackFitter::m_indetVolume
std::unique_ptr< const Trk::Volume > m_indetVolume
Definition: CombinedMuonTrackFitter.h:151
Trk::MeasurementBase::uniqueClone
std::unique_ptr< MeasurementBase > uniqueClone() const
NVI Clone giving up unique pointer.
Definition: MeasurementBase.h:77
Rec::CombinedMuonTrackBuilder::m_addIDMSerrors
Gaudi::Property< bool > m_addIDMSerrors
Definition: CombinedMuonTrackBuilder.h:255
endmsg
#define endmsg
Definition: AnalysisConfig_Ntuple.cxx:63
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
Rec::CombinedMuonTrackBuilder::createIndetTrack
std::unique_ptr< Trk::Track > createIndetTrack(const Trk::TrackInfo &info, const Trk::TrackStates *tsos) const
Definition: CombinedMuonTrackBuilder.cxx:2062
Rec::CombinedMuonTrackBuilder::m_magFieldProperties
Trk::MagneticFieldProperties m_magFieldProperties
Definition: CombinedMuonTrackBuilder.h:209
Muon::MuonTSOSHelper::createMeasTSOS
static std::unique_ptr< Trk::TrackStateOnSurface > createMeasTSOS(std::unique_ptr< Trk::MeasurementBase > meas, std::unique_ptr< Trk::TrackParameters > pars, Trk::TrackStateOnSurface::TrackStateOnSurfaceType type)
create a TSOS with a measurement, takes ownership of the pointers
Definition: MuonTSOSHelper.h:62
CylinderSurface.h
Trk::EnergyLoss::deltaE
double deltaE() const
returns the
TRT::Track::d0
@ d0
Definition: InnerDetector/InDetCalibEvent/TRT_CalibData/TRT_CalibData/TrackInfo.h:62
DataVector::front
const T * front() const
Access the first element in the collection as an rvalue.
PseudoMeasurementOnTrack.h
Trk::MaterialEffectsBase::ScatteringEffects
@ ScatteringEffects
contains material effects due to multiple scattering
Definition: MaterialEffectsBase.h:45
test_pyathena.parent
parent
Definition: test_pyathena.py:15
Trk::IMaterialAllocator::Garbage_t
std::vector< std::unique_ptr< const TrackStateOnSurface > > Garbage_t
Definition: IMaterialAllocator.h:40
Rec::CombinedMuonTrackFitter::m_calorimeterVolume
std::unique_ptr< const Trk::Volume > m_calorimeterVolume
Definition: CombinedMuonTrackFitter.h:152
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
Rec::CombinedMuonTrackFitter::m_trackQuery
ToolHandle< Rec::IMuonTrackQuery > m_trackQuery
Definition: CombinedMuonTrackFitter.h:114
Rec::CombinedMuonTrackBuilder::m_muonHoleRecovery
ToolHandle< Muon::IMuonHoleRecoveryTool > m_muonHoleRecovery
Definition: CombinedMuonTrackBuilder.h:174
Rec::CombinedMuonTrackBuilder::m_largeImpact
Gaudi::Property< double > m_largeImpact
Definition: CombinedMuonTrackBuilder.h:219
drawFromPickle.tan
tan
Definition: drawFromPickle.py:36
Trk::FitQuality
Class to represent and store fit qualities from track reconstruction in terms of and number of degre...
Definition: FitQuality.h:97
TrackSummary.h
Trk::ParametersBase
Definition: ParametersBase.h:55
Rec::CombinedMuonTrackFitter::m_caloTSOS
ToolHandle< Rec::IMuidCaloTrackStateOnSurface > m_caloTSOS
Definition: CombinedMuonTrackFitter.h:99
Trk::Vertex::position
const Amg::Vector3D & position() const
return position of vertex
Definition: Vertex.cxx:72
Trk::FitQualityOnSurface::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::muon
@ muon
Definition: ParticleHypothesis.h:28
DataVector< const Trk::TrackStateOnSurface >
Rec::CombinedMuonTrackBuilder::m_perigeeSurface
std::unique_ptr< const Trk::PerigeeSurface > m_perigeeSurface
Definition: CombinedMuonTrackBuilder.h:240
Trk::TrackStateOnSurface::Parameter
@ Parameter
This TSOS contains a Trk::ParameterBase.
Definition: TrackStateOnSurface.h:140
Rec::CombinedMuonTrackBuilder::m_largeMomentumError
Gaudi::Property< double > m_largeMomentumError
Definition: CombinedMuonTrackBuilder.h:222
Rec::CombinedMuonTrackBuilder::m_extrapolator
ToolHandle< Trk::IExtrapolator > m_extrapolator
Definition: CombinedMuonTrackBuilder.h:159
Rec::CombinedMuonTrackBuilder::m_materialAllocator
ToolHandle< Trk::IMaterialAllocator > m_materialAllocator
Definition: CombinedMuonTrackBuilder.h:164
trackInfo
Definition: TrigInDetUtils.h:13
MagField::AtlasFieldCache::solenoidOn
bool solenoidOn() const
status of the magnets
Rec::CombinedMuonTrackBuilder::m_countDegradedStandaloneFit
std::atomic_uint m_countDegradedStandaloneFit
Definition: CombinedMuonTrackBuilder.h:247
Rec::CombinedMuonTrackBuilder::m_cleanStandalone
Gaudi::Property< bool > m_cleanStandalone
Definition: CombinedMuonTrackBuilder.h:213
Rec::CombinedMuonTrackFitter::m_idHelperSvc
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
Definition: CombinedMuonTrackFitter.h:129
Trk::MeasurementSet
std::vector< const MeasurementBase * > MeasurementSet
vector of fittable measurements
Definition: FitterTypes.h:30
Trk::TrackStateOnSurface::alignmentEffectsOnTrack
const AlignmentEffectsOnTrack * alignmentEffectsOnTrack() const
return the the alignment effects const overload
tolerance
Definition: suep_shower.h:17
Trk::MeasurementBase
Definition: MeasurementBase.h:58
Rec::CombinedMuonTrackBuilder::m_iterateCombinedTrackFit
Gaudi::Property< bool > m_iterateCombinedTrackFit
Definition: CombinedMuonTrackBuilder.h:251
Trk::Track::perigeeParameters
const Perigee * perigeeParameters() const
return Perigee.
Definition: Tracking/TrkEvent/TrkTrack/src/Track.cxx:163
Rec::CombinedMuonTrackBuilder::m_alignUncertTool_phi
PublicToolHandle< Muon::IMuonAlignmentUncertTool > m_alignUncertTool_phi
Definition: CombinedMuonTrackBuilder.h:195
Trk::SurfaceType::Perigee
@ Perigee
Trk::TrackStateOnSurface
represents the track state (measurement, material, fit parameters and quality) at a surface.
Definition: TrackStateOnSurface.h:71
Trk::Surface::bounds
virtual const SurfaceBounds & bounds() const =0
Surface Bounds method.
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:195
Trk::MeasurementBase::associatedSurface
virtual const Surface & associatedSurface() const =0
Interface method to get the associated Surface.
Trk::d0
@ d0
Definition: ParamDefs.h:69
DataVector< const Trk::TrackStateOnSurface >::const_reverse_iterator
std::reverse_iterator< const_iterator > const_reverse_iterator
Standard const_reverse_iterator.
Definition: DataVector.h:846
plotBeamSpotMon.b
b
Definition: plotBeamSpotMon.py:77
Amg::error
double error(const Amg::MatrixX &mat, int index)
return diagonal error of the matrix caller should ensure the matrix is symmetric and the index is in ...
Definition: EventPrimitivesHelpers.h:40
Trk::nonInteracting
@ nonInteracting
Definition: ParticleHypothesis.h:25
Trk::EnergyLoss
This class describes energy loss material effects in the ATLAS tracking EDM.
Definition: EnergyLoss.h:34
charge
double charge(const T &p)
Definition: AtlasPID.h:494
DataVector::push_back
value_type push_back(value_type pElem)
Add an element to the end of the collection.
SG::CondHandleKey::initialize
StatusCode initialize(bool used=true)
Rec::CombinedMuonTrackBuilder::m_cscRotCreator
ToolHandle< Muon::IMuonClusterOnTrackCreator > m_cscRotCreator
Definition: CombinedMuonTrackBuilder.h:151
Rec::CombinedMuonTrackBuilder::m_redoRots
bool m_redoRots
Definition: CombinedMuonTrackBuilder.h:235
Units.h
Wrapper to avoid constant divisions when using units.
Rec::CombinedMuonTrackBuilder::finalize
virtual StatusCode finalize() override
Definition: CombinedMuonTrackBuilder.cxx:117
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.
Rec::CombinedMuonTrackBuilder::extrapolatedParameters
std::unique_ptr< Trk::TrackParameters > extrapolatedParameters(const EventContext &ctx, bool &badlyDeterminedCurvature, const Trk::Track &spectrometerTrack, const Trk::RecVertex *mvertex, const Trk::PerigeeSurface *mperigeeSurface) const
Definition: CombinedMuonTrackBuilder.cxx:2437
Trk::MaterialEffectsBase::EnergyLossEffects
@ EnergyLossEffects
contains energy loss corrections
Definition: MaterialEffectsBase.h:48
Trk::TrapezoidBounds
Definition: TrapezoidBounds.h:43
Rec::CombinedMuonTrackBuilder::standaloneRefit
virtual std::unique_ptr< Trk::Track > standaloneRefit(const EventContext &ctx, const Trk::Track &combinedTrack, const Amg::Vector3D &vec) const override
ICombinedMuonTrackBuilder interface: refit a track removing any indet measurements with optional addi...
Definition: CombinedMuonTrackBuilder.cxx:1132
Rec::CombinedMuonTrackBuilder::m_largePhiError
Gaudi::Property< double > m_largePhiError
Definition: CombinedMuonTrackBuilder.h:223
Rec::CombinedMuonTrackBuilder::m_vertex3DSigmaZ
Gaudi::Property< double > m_vertex3DSigmaZ
Definition: CombinedMuonTrackBuilder.h:233
Trk::GsfMeasurementUpdator::fitQuality
FitQualityOnSurface fitQuality(const MultiComponentState &, const MeasurementBase &)
Method for determining the chi2 of the multi-component state and the number of degrees of freedom.
Definition: GsfMeasurementUpdator.cxx:845
Rec::CombinedMuonTrackBuilder::momentumUpdate
void momentumUpdate(std::unique_ptr< Trk::TrackParameters > &parameters, double updatedP, bool directionUpdate=false, double deltaPhi=0., double deltaTheta=0.) const
Definition: CombinedMuonTrackBuilder.cxx:2740
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::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::IdentifierExtractor::extract
static void extract(std::vector< Identifier > &ids, const std::vector< const MeasurementBase * > &measurements)
Definition: IdentifierExtractor.cxx:13
EventPrimitivesCovarianceHelpers.h
Trk::ParametersBase::momentum
const Amg::Vector3D & momentum() const
Access method for the momentum.
Rec::CombinedMuonTrackBuilder::m_minEnergy
Gaudi::Property< double > m_minEnergy
Definition: CombinedMuonTrackBuilder.h:227
Trk::vertex
@ vertex
Definition: MeasurementType.h:21
TrackingVolume.h
Rec::CombinedMuonTrackBuilder::m_caloEnergyParam
ToolHandle< Rec::IMuidCaloEnergy > m_caloEnergyParam
Definition: CombinedMuonTrackBuilder.h:146
Rec::CombinedMuonTrackFitter::m_zECToroid
Gaudi::Property< double > m_zECToroid
Definition: CombinedMuonTrackFitter.h:146
Rec::CombinedMuonTrackBuilder::getCaloTSOSfromMatProvider
std::vector< std::unique_ptr< const Trk::TrackStateOnSurface > > getCaloTSOSfromMatProvider(const Trk::TrackParameters &track_params, const Trk::Track &me_track) const
Helper method to retrieve the CaloTSO from the Material provider in a memory safe way.
Definition: CombinedMuonTrackBuilder.cxx:3147
a
TList * a
Definition: liststreamerinfos.cxx:10
Rec::CombinedMuonTrackBuilder::m_vertex2DSigmaZ
Gaudi::Property< double > m_vertex2DSigmaZ
Definition: CombinedMuonTrackBuilder.h:231
Trk::MaterialEffectsOnTrack::energyLoss
const EnergyLoss * energyLoss() const
returns the energy loss object.
Rec::CombinedMuonTrackBuilder::finalTrackBuild
void finalTrackBuild(const EventContext &ctx, std::unique_ptr< Trk::Track > &track) const
Definition: CombinedMuonTrackBuilder.cxx:2654
Rec::CombinedMuonTrackBuilder::m_reallocateMaterial
Gaudi::Property< bool > m_reallocateMaterial
Definition: CombinedMuonTrackBuilder.h:216
Rec::CombinedMuonTrackBuilder::m_perigeeAtSpectrometerEntrance
Gaudi::Property< bool > m_perigeeAtSpectrometerEntrance
Definition: CombinedMuonTrackBuilder.h:215
Rec::CombinedMuonTrackBuilder::m_propagatorSL
ToolHandle< Trk::IPropagator > m_propagatorSL
Definition: CombinedMuonTrackBuilder.h:184
Trk::IPropagator::propagate
virtual std::unique_ptr< NeutralParameters > propagate(const NeutralParameters &parameters, const Surface &sf, PropDirection dir, const BoundaryCheck &bcheck, bool returnCurv=false) const =0
Main propagation method for NeutralParameters.
Rec::CombinedMuonTrackFitter::finalize
virtual StatusCode finalize() override
Definition: CombinedMuonTrackFitter.cxx:145
GlobalVariables.Emax
Emax
Definition: GlobalVariables.py:185
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
Trk::PlaneSurface
Definition: PlaneSurface.h:64
PlaneSurface.h
unit
const PlainObject unit() const
This is a plugin that makes Eigen look like CLHEP & defines some convenience methods.
Definition: AmgMatrixBasePlugin.h:20
python.CaloScaleNoiseConfig.type
type
Definition: CaloScaleNoiseConfig.py:78
Rec::CombinedMuonTrackBuilder::m_vertex
std::unique_ptr< const Trk::RecVertex > m_vertex
Definition: CombinedMuonTrackBuilder.h:242
DEBUG
#define DEBUG
Definition: page_access.h:11
CaloEnergy::NotIsolated
@ NotIsolated
Definition: CaloEnergy.h:43
Trk::MaterialEffectsOnTrack::scatteringAngles
const ScatteringAngles * scatteringAngles() const
returns the MCS-angles object.
AthCommonMsg< AlgTool >::msg
MsgStream & msg() const
Definition: AthCommonMsg.h:24
MagField::AtlasFieldCache
Local cache for magnetic field (based on MagFieldServices/AtlasFieldSvcTLS.h)
Definition: AtlasFieldCache.h:43
Trk::qOverP
@ qOverP
perigee
Definition: ParamDefs.h:73
Trk::RIO_OnTrack::identify
virtual Identifier identify() const final
return the identifier -extends MeasurementBase
Definition: RIO_OnTrack.h:155
Trk::TrackingGeometry::trackingVolume
const TrackingVolume * trackingVolume(const std::string &name) const
return the tracking Volume by name, 0 if it doesn't exist
Trk::ScatteringAngles::sigmaDeltaPhi
double sigmaDeltaPhi() const
returns the
Definition: ScatteringAngles.h:94
Trk::TrackStateOnSurface::Scatterer
@ Scatterer
This represents a scattering point on the track, and so will contain TrackParameters and MaterialEffe...
Definition: TrackStateOnSurface.h:113
physics_parameters.parameters
parameters
Definition: physics_parameters.py:144
TrackingGeometry.h
Trk::phi
@ phi
Definition: ParamDefs.h:81
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
Rec::CombinedMuonTrackBuilder::createSpectrometerTSOS
std::vector< std::unique_ptr< const Trk::TrackStateOnSurface > > createSpectrometerTSOS(const EventContext &ctx, const Trk::Track &spectrometerTrack) const
Definition: CombinedMuonTrackBuilder.cxx:2272
Rec::CombinedMuonTrackFitter::m_materialUpdator
ToolHandle< Trk::ITrkMaterialProviderTool > m_materialUpdator
Definition: CombinedMuonTrackFitter.h:124
xAOD::track
@ track
Definition: TrackingPrimitives.h:512
Rec::CombinedMuonTrackBuilder::standaloneFit
virtual std::unique_ptr< Trk::Track > standaloneFit(const EventContext &ctx, const Trk::Track &spectrometerTrack, const Amg::Vector3D &bs, const Trk::Vertex *vertex) const override
ICombinedMuonTrackBuilder interface: propagate to perigee adding calo energy-loss and material to MS ...
Definition: CombinedMuonTrackBuilder.cxx:577
Trk::TrackInfo::setPatternRecognitionInfo
void setPatternRecognitionInfo(const TrackPatternRecoInfo &patternReco)
Method setting the pattern recognition algorithm.
python.Constants.VERBOSE
int VERBOSE
Definition: Control/AthenaCommon/python/Constants.py:14
Trk::ScatteringAngles::deltaTheta
double deltaTheta() const
returns the
Definition: ScatteringAngles.h:88
drawFromPickle.sin
sin
Definition: drawFromPickle.py:36
makeComparison.deltaZ
int deltaZ
Definition: makeComparison.py:46
RotatedTrapezoidBounds.h
TrackSurfaceIntersection.h
Trk::loc1
@ loc1
Definition: ParamDefs.h:40
Trk::Surface
Definition: Tracking/TrkDetDescr/TrkSurfaces/TrkSurfaces/Surface.h:75
Trk::TrackingVolume
Definition: TrackingVolume.h:121
GeV
#define GeV
Definition: CaloTransverseBalanceVecMon.cxx:30
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
Rec::CombinedMuonTrackFitter::normalizedChi2
double normalizedChi2(const Trk::Track &track) const
Definition: CombinedMuonTrackFitter.cxx:524
makeComparison.deltaR
float deltaR
Definition: makeComparison.py:36
DataVector::size
size_type size() const noexcept
Returns the number of elements in the collection.
Trk::ParametersT::clone
virtual ParametersT< DIM, T, S > * clone() const override final
Virtual clone.
Trk::MaterialEffectsBase::associatedSurface
const Surface & associatedSurface() const
returns the surface to which these m.eff. are associated.
Trk::EnergyLoss::sigmaPlusDeltaE
double sigmaPlusDeltaE() const
returns the positive side
mag
Scalar mag() const
mag method
Definition: AmgMatrixBasePlugin.h:25
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
Rec::CombinedMuonTrackFitter::countAEOTs
unsigned int countAEOTs(const Trk::Track &track, const std::string &txt) const
Definition: CombinedMuonTrackFitter.cxx:649
Rec::CombinedMuonTrackBuilder::~CombinedMuonTrackBuilder
virtual ~CombinedMuonTrackBuilder()
Definition: CombinedMuonTrackBuilder.cxx:57
DataVector::begin
const_iterator begin() const noexcept
Return a const_iterator pointing at the beginning of the collection.
Rec::CombinedMuonTrackFitter::m_useCaloTG
Gaudi::Property< bool > m_useCaloTG
Definition: CombinedMuonTrackFitter.h:148
Trk::ParametersBase::clone
virtual ParametersBase< DIM, T > * clone() const override=0
clone method for polymorphic deep copy
Rec::CombinedMuonTrackBuilder::combinedFit
virtual std::unique_ptr< Trk::Track > combinedFit(const EventContext &ctx, const Trk::Track &indetTrack, const Trk::Track &extrapolatedTrack, const Trk::Track &spectrometerTrack) const override
ICombinedMuonTrackBuilder interface: build and fit combined ID/Calo/MS track.
Definition: CombinedMuonTrackBuilder.cxx:128
Rec::CombinedMuonTrackBuilder::m_useRefitTrackError
Gaudi::Property< bool > m_useRefitTrackError
Definition: CombinedMuonTrackBuilder.h:256
Rec::CombinedMuonTrackBuilder::initialize
virtual StatusCode initialize() override
Definition: CombinedMuonTrackBuilder.cxx:63
SG::ReadCondHandle::cptr
const_pointer_type cptr()
Definition: ReadCondHandle.h:67
CaloEnergy.h
Trk::TrackInfo::Unknown
@ Unknown
Track fitter not defined.
Definition: Tracking/TrkEvent/TrkTrack/TrkTrack/TrackInfo.h:41