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  ATH_MSG_DEBUG("combinedFit:: fail with MS removed by cleaner"); //Used to be: 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 the unique_ptr has been moved, it will be nullptr after
554  //cppcheck-suppress accessMoved
555  if (frontParameters) {
556  trackStateOnSurfaces->push_back(
557  new Trk::TrackStateOnSurface(in_meas->uniqueClone(), std::move(frontParameters), nullptr, typeP));
558  } else if (in_meas == midMeasurement) {
559  trackStateOnSurfaces->push_back(
560  new Trk::TrackStateOnSurface(in_meas->uniqueClone(), std::move(midParameters), nullptr, typeP));
561  } else if (backParameters && in_meas == spectrometerMeasurements.back()) {
562  trackStateOnSurfaces->push_back(
563  new Trk::TrackStateOnSurface(in_meas->uniqueClone(), std::move(backParameters), nullptr, typeP));
564  } else {
565  trackStateOnSurfaces->push_back(
566  new Trk::TrackStateOnSurface(in_meas->uniqueClone(), nullptr, nullptr, typeM));
567  }
568  }
569 
571 
572  Trk::Track muonTrack(trackInfo, std::move(trackStateOnSurfaces), nullptr);
573  if (msgLevel(MSG::DEBUG)) countAEOTs(muonTrack, " in detExtension muonTrack ");
574  // perform combined fit
575  ATH_MSG_VERBOSE("Calling combinedFit from " << __func__ << " at line " << __LINE__);
576  std::unique_ptr<Trk::Track> combinedTrack{combinedFit(ctx, indetTrack, muonTrack, muonTrack)};
577  return combinedTrack;
578  }
579  std::unique_ptr<Trk::Track> CombinedMuonTrackBuilder::standaloneFit(const EventContext& ctx, const Trk::Track& inputSpectrometerTrack,
580  const Amg::Vector3D& origin, const Trk::Vertex* inputVertex) const {
581  MagField::AtlasFieldCache fieldCache;
582  // Get field cache object
583 
584  if (!loadMagneticField(ctx, fieldCache)) return nullptr;
585 
586  // no SA fit with vertex constraint for Toroid off data
587  if (m_trackQuery->isLineFit(inputSpectrometerTrack) && !fieldCache.toroidOn()) { return nullptr; }
588 
589  ATH_MSG_DEBUG(" standaloneFit beam position bs_x " << origin << " inputVertex "
590  << inputVertex);
591 
592  if (msgLvl(MSG::VERBOSE)) {
593  msg(MSG::VERBOSE) << endmsg << "==== Start of standaloneFit:: " << std::setiosflags(std::ios::fixed);
594 
595  if (m_trackQuery->isExtrapolated(inputSpectrometerTrack, ctx)) {
596  if (m_trackQuery->isLineFit(inputSpectrometerTrack)) {
597  msg(MSG::VERBOSE) << "extrapolated has lineFit";
598  } else {
599  msg(MSG::VERBOSE) << "extrapolated momentum " << std::setprecision(1)
600  << inputSpectrometerTrack.perigeeParameters()->momentum().mag() / Gaudi::Units::GeV << " (GeV)";
601  }
602 
603  msg(MSG::VERBOSE) << " at eta " << std::setw(6) << std::setprecision(3)
604  << inputSpectrometerTrack.perigeeParameters()->momentum().eta() << " phi " << std::setw(6)
605  << std::setprecision(3) << inputSpectrometerTrack.perigeeParameters()->momentum().phi();
606 
607  } else if (!m_trackQuery->isProjective(inputSpectrometerTrack)) {
608  msg(MSG::VERBOSE) << "spectrometer track does not project";
609  } else if (inputSpectrometerTrack.perigeeParameters()) {
610  if (m_trackQuery->isLineFit(inputSpectrometerTrack)) {
611  msg(MSG::VERBOSE) << "spectrometer has lineFit";
612  } else {
613  msg(MSG::VERBOSE) << "spectrometer momentum " << std::setprecision(1)
614  << inputSpectrometerTrack.perigeeParameters()->momentum().mag() / Gaudi::Units::GeV << " (GeV)";
615  }
616 
617  msg(MSG::VERBOSE) << " at eta " << std::setw(6) << std::setprecision(3)
618  << inputSpectrometerTrack.perigeeParameters()->position().eta() << " phi " << std::setw(6)
619  << std::setprecision(3) << inputSpectrometerTrack.perigeeParameters()->position().phi();
620 
621  if (inputSpectrometerTrack.perigeeParameters()->covariance()) {
622  msg(MSG::VERBOSE) << " hasCov";
623  } else {
624  msg(MSG::VERBOSE) << " noCov ";
625  }
626  } else {
627  msg(MSG::VERBOSE) << " spectrometer track without PerigeeParameters";
628  }
629 
630  if (inputSpectrometerTrack.fitQuality()) {
631  msg(MSG::VERBOSE) << " fit: chi2 /DoF " << std::setprecision(2) << normalizedChi2(inputSpectrometerTrack) << " /"
632  << std::setw(2) << inputSpectrometerTrack.fitQuality()->numberDoF();
633  }
634 
635  if (m_trackQuery->numberPseudoMeasurements(inputSpectrometerTrack)) {
636  msg(MSG::VERBOSE) << " pseudo " << m_trackQuery->numberPseudoMeasurements(inputSpectrometerTrack);
637  }
638 
639  msg(MSG::VERBOSE) << endmsg;
640  }
641 
642  // check input vertex OK
643  const Trk::RecVertex* vertex = dynamic_cast<const Trk::RecVertex*>(inputVertex);
644  if (inputVertex && !vertex) {
645  // input vertex fails dynamic_cast
646  m_messageHelper->printWarning(6);
647  return nullptr;
648  }
649 
650  // fail input tracks with insufficient measurements or inconsistent structure
651  const Trk::FitQuality* fitQuality = inputSpectrometerTrack.fitQuality();
652  const Trk::TrackStates* tsos = inputSpectrometerTrack.trackStateOnSurfaces();
653 
654  if (!fitQuality || !inputSpectrometerTrack.trackStateOnSurfaces() ||
655  static_cast<int>(inputSpectrometerTrack.trackStateOnSurfaces()->size()) < fitQuality->numberDoF()) {
656  // count measurements
657  int measurements = 0;
658  for (const Trk::TrackStateOnSurface* s : *tsos) {
660  }
661  // insufficient measurements
662  if (measurements < 4) {
663  m_messageHelper->printWarning(48);
664  ATH_MSG_VERBOSE(" SA::failed (1)");
665  return nullptr;
666  }
667 
668  // inconsistent TSOS on input track
669  if (fitQuality && measurements < fitQuality->numberDoF() + 4) {
670  m_messageHelper->printWarning(49);
671  ATH_MSG_VERBOSE(" SA::failed (2)");
672  return nullptr;
673  }
674  }
675 
676  // check the track is roughly projective in phi
677  const bool is_extrapolated = m_trackQuery->isExtrapolated(inputSpectrometerTrack, ctx);
678  if (!is_extrapolated && !m_trackQuery->isProjective(inputSpectrometerTrack)) {
679  ATH_MSG_VERBOSE(" SA::failed (3)");
680  return nullptr;
681  }
682 
683  // possibly refit the spectrometer track with material reallocation
684  double spectrometerFitChi2 = normalizedChi2(inputSpectrometerTrack);
685  std::unique_ptr<Trk::Track> spectrometerFit = std::make_unique<Trk::Track>(inputSpectrometerTrack);
686  if (!vertex && (m_reallocateMaterial || is_extrapolated)) {
687  spectrometerFit = reallocateMaterial(ctx, inputSpectrometerTrack);
688  if (!spectrometerFit) {
689  ATH_MSG_VERBOSE(" SA::failed (4)");
690  return nullptr;
691  }
692  }
693 
694  const Trk::Track& spectrometerTrack = *spectrometerFit;
695 
696  // require a Perigee from the spectrometer track
697  const Trk::Perigee* measuredPerigee = spectrometerTrack.perigeeParameters();
698 
699  if (!measuredPerigee || !measuredPerigee->covariance()) {
700  // missing MeasuredPerigee for spectrometer track
701  m_messageHelper->printWarning(7);
702 
703  ATH_MSG_VERBOSE(" SA::failed (5)");
704  return nullptr;
705  }
706 
707  // set measured momentum error and starting parameters
708  bool badlyDeterminedCurvature = false;
709 
710  if (!Amg::hasPositiveDiagElems(*measuredPerigee->covariance())) {
711  ATH_MSG_WARNING("standaloneFit: measuredPerigee has non-positive-definite covariance ");
712  ATH_MSG_VERBOSE(" SA::failed (5.5)");
714  return nullptr;
715  }
716 
717  double errorP = std::sqrt(measuredPerigee->momentum().mag2() * (*measuredPerigee->covariance())(Trk::qOverP, Trk::qOverP));
718 
719  std::unique_ptr<Trk::RecVertex> mvertex = std::make_unique<Trk::RecVertex>(*m_vertex);
720  std::unique_ptr<Trk::RecVertex> mbeamAxis = std::make_unique<Trk::RecVertex>(*m_beamAxis);
721  std::unique_ptr<Trk::PerigeeSurface> mperigeeSurface = std::make_unique<Trk::PerigeeSurface>(*m_perigeeSurface);
722 
723  std::unique_ptr<const Trk::TrackParameters> parameters;
724 
725  if (vertex) {
726  // vertex association only makes sense for magnet-on tracks with measured curvature
727  if (!fieldCache.toroidOn() || m_trackQuery->isLineFit(spectrometerTrack) || errorP > m_largeMomentumError) {
728  ATH_MSG_VERBOSE("standaloneFit: vertex fit not attempted as curvature badly measured");
729  ATH_MSG_VERBOSE(" SA::failed (6)");
730  return nullptr;
731  }
732  parameters = std::make_unique<Trk::Perigee>(*spectrometerTrack.perigeeParameters());
733  } else {
734  //
735  // update -if needed vertex and beam axis positions
736  //
737  if ((origin - mvertex->position()).mag() > 0.001) {
738  // recreate beamAxis and vertexRegion for constrained (projective) track fits
739 
740  mperigeeSurface = std::make_unique<Trk::PerigeeSurface>(origin);
741 
742  AmgSymMatrix(3) beamAxisCovariance;
743  beamAxisCovariance.setZero();
744  (beamAxisCovariance)(0, 0) = m_vertex2DSigmaRPhi * m_vertex2DSigmaRPhi;
745  (beamAxisCovariance)(1, 1) = m_vertex2DSigmaRPhi * m_vertex2DSigmaRPhi;
746  (beamAxisCovariance)(2, 2) = m_vertex2DSigmaZ * m_vertex2DSigmaZ;
747  mbeamAxis = std::make_unique<Trk::RecVertex>(origin, beamAxisCovariance);
748 
749  AmgSymMatrix(3) vertexRegionCovariance;
750  vertexRegionCovariance.setZero();
751  (vertexRegionCovariance)(0, 0) = m_vertex3DSigmaRPhi * m_vertex3DSigmaRPhi;
752  (vertexRegionCovariance)(1, 1) = m_vertex3DSigmaRPhi * m_vertex3DSigmaRPhi;
753  (vertexRegionCovariance)(2, 2) = m_vertex3DSigmaZ * m_vertex3DSigmaZ;
754  mvertex = std::make_unique<Trk::RecVertex>(origin, vertexRegionCovariance);
755  }
756 
757  parameters = extrapolatedParameters(ctx, badlyDeterminedCurvature, spectrometerTrack, mvertex.get(), mperigeeSurface.get());
758  }
759 
760  if (!parameters) {
761  ATH_MSG_VERBOSE(" SA::failed (7)");
762  return nullptr;
763  }
764 
765  // create the spectrometer TSOS's for the extrapolated fit
766  std::vector<std::unique_ptr<const Trk::TrackStateOnSurface>> spectrometerTSOS = createSpectrometerTSOS(ctx, spectrometerTrack);
767 
768  if (spectrometerTSOS.empty()) {
769  ATH_MSG_VERBOSE(" SA::failed (8)");
770  return nullptr;
771  }
772  const Trk::TrackParameters* caloParameters = nullptr;
773 
774  Trk::ParticleHypothesis particleHypothesis = Trk::muon;
775 
776  bool haveFitWithVertex = false;
777  bool performPrefit = false;
778 
779  if (m_redoRots) {
780  for (const Trk::TrackStateOnSurface* s : *spectrometerTrack.trackStateOnSurfaces()) {
781  if (s->measurementOnTrack() && !s->trackParameters()) {
782  performPrefit = true;
783  break;
784  }
785  }
786  }
787 
788  // badly defined tracks use weak vertex constraint with prefit before calo association
789  std::unique_ptr<Trk::Track> prefit;
790 
791  const Trk::RecVertex* vertexInFit = vertex;
792 
793  if (!vertexInFit) {
794  double errorPhi = std::sqrt((*measuredPerigee->covariance())(Trk::phi0, Trk::phi0));
795 
796  bool inCSCregion = std::abs(measuredPerigee->momentum().eta()) > 2.0;
797 
798  // FIXME: missing prefit case for excessive spectrometer eloss WARNING
799  // spot from line starting approx from vertex??
800  if (inCSCregion || m_trackQuery->numberPseudoMeasurements(spectrometerTrack) ||
801  (fieldCache.toroidOn() &&
802  (badlyDeterminedCurvature || errorPhi > m_largePhiError || measuredPerigee->momentum().mag() < m_lowMomentum))) {
803  performPrefit = true;
804  vertexInFit = (badlyDeterminedCurvature || inCSCregion) ? mvertex.get() : mbeamAxis.get();
805 
806  if (msgLvl(MSG::DEBUG)) {
807  unsigned numberPseudo = m_trackQuery->numberPseudoMeasurements(spectrometerTrack);
808  if (errorPhi > s_sigmaPhiSector) { ++numberPseudo; }
809 
810  if (badlyDeterminedCurvature) {
811  ATH_MSG_DEBUG(" prefit with vertex: " << std::setiosflags(std::ios::fixed) << " momentum " << std::setprecision(1)
812  << measuredPerigee->momentum().mag() / Gaudi::Units::GeV << " (GeV), zFirst "
813  << std::setprecision(1) << std::abs(parameters->position().z())
814  << ", phiError " << std::setprecision(2) << errorPhi << ", momentumError "
815  << std::setprecision(2) << errorP << ", numberPseudo " << numberPseudo);
816  } else {
817  ATH_MSG_DEBUG(" prefit with beamAxis: "
818  << std::setiosflags(std::ios::fixed) << " momentum " << std::setprecision(1)
819  << measuredPerigee->momentum().mag() / Gaudi::Units::GeV << " (GeV), zFirst " << std::setprecision(1)
820  << std::abs(parameters->position().z()) << ", phiError " << std::setprecision(2) << errorPhi
821  << ", momentumError " << std::setprecision(2) << errorP << ", numberPseudo " << numberPseudo);
822  }
823  }
824  }
825  }
826 
827  std::unique_ptr<const Trk::Perigee> prefitResult;
828 
829  // prefit to stabilize calo look-up and/or provide trackParameters
830  if (performPrefit) {
831  if (!vertexInFit) { ATH_MSG_VERBOSE(" prefit without vertex"); }
832 
833  if (vertexInFit) { haveFitWithVertex = true; }
834 
835  if (badlyDeterminedCurvature && parameters->momentum().mag() > m_lowMomentum) { particleHypothesis = Trk::nonInteracting; }
836 
837  ATH_MSG_VERBOSE("Calling createExtrapolatedTrack from " << __func__ << " at line " << __LINE__);
838  prefit = createExtrapolatedTrack(ctx, spectrometerTrack, *parameters, particleHypothesis, false, spectrometerTSOS, vertexInFit,
839  mbeamAxis.get(), mperigeeSurface.get());
840 
841  // demand prefit success
842  if (!prefit || !prefit->fitQuality() || !prefit->perigeeParameters()) {
843  ATH_MSG_DEBUG(" prefit failure ");
844  prefit.reset();
845  }
846 
847  if (prefit) {
848  dumpCaloEloss(prefit.get(), " prefit ");
849  bool hasCov = prefit->perigeeParameters() ? (prefit->perigeeParameters()->covariance() != nullptr) : false;
850  ATH_MSG_VERBOSE(" got prefit " << m_printer->print(*prefit) << " hasCov " << hasCov);
851 
852  if (prefit->perigeeParameters()) { prefitResult.reset(prefit->perigeeParameters()->clone()); }
853  const Trk::TrackStateOnSurface* ms_entrance = nullptr;
854  for (const Trk::TrackStateOnSurface* s : *prefit->trackStateOnSurfaces()) {
855  // look for first measured TSOS in muon volume
856  if (!s->trackParameters() || !s->trackParameters()->covariance()) { continue; }
857  if (m_calorimeterVolume->inside(s->trackParameters()->position())) { continue; }
858 
859  // check that it is a measurement
861  ATH_MSG_DEBUG("Found first parameters in MS " << s->trackParameters()->position().perp() << " z "
862  << s->trackParameters()->position().z());
863  ms_entrance = s;
864  break;
865  }
866  }
867 
868  if (ms_entrance && ms_entrance != prefit->trackStateOnSurfaces()->front() && ms_entrance->trackParameters()) {
869  parameters.reset(ms_entrance->trackParameters()->clone());
870  caloParameters = parameters.get();
871  } else {
872  // prefit: no parameter extrapolation to calo
873  m_messageHelper->printWarning(9);
874  }
875  }
876 
877  // give up if prefit fails
878  spectrometerTSOS.clear();
879 
880  if (!prefit) {
881  ATH_MSG_VERBOSE(" SA::failed (9)");
882  return nullptr;
883  }
884  const Trk::TrackStates* prefit_tsos = prefit->trackStateOnSurfaces();
885  // create spectrometerTSOS corresponding to prefit
886  // skip start perigee, then preferentially take everything following MS perigee,
887  // otherwise (if no MS perigee) rely on VolumesSvc,
888  // but be aware that by design there are inconsistencies wrt tracking geometry
890  std::find_if(prefit_tsos->begin() + 1, prefit_tsos->end(), [this](const Trk::TrackStateOnSurface* tsos) -> bool {
891  return (tsos->trackParameters() && !m_calorimeterVolume->inside(tsos->trackParameters()->position())) ||
892  tsos->type(Trk::TrackStateOnSurface::Perigee);
893  });
894 
895  if (s != prefit_tsos->end() && (*s)->type(Trk::TrackStateOnSurface::Perigee)) ++s;
896 
897  for (; s != prefit_tsos->end(); ++s) { spectrometerTSOS.emplace_back((*s)->clone()); }
898  }
899 
900  if (m_redoRots) {
901  // recalibration: correct rots
902  for (std::unique_ptr<const Trk::TrackStateOnSurface>& t : spectrometerTSOS) {
903  if (!t->measurementOnTrack() || !t->trackParameters()) { continue; } // end of if
904 
905  const Trk::RIO_OnTrack* rot = dynamic_cast<const Trk::RIO_OnTrack*>(t->measurementOnTrack());
906 
907  if (!rot) continue;
908  Identifier id = rot->identify();
909 
910  if (!m_idHelperSvc->isMuon(id)) continue;
911 
912  std::unique_ptr<Trk::RIO_OnTrack> updatedRot;
913  if (!m_cscRotCreator.empty() && m_idHelperSvc->isCsc(id)) {
914  updatedRot.reset(m_cscRotCreator->correct(*rot->prepRawData(), *(*t).trackParameters(), ctx));
915  } else if (!m_mdtRotCreator.empty() && m_idHelperSvc->isMdt(id)) {
916  updatedRot.reset(m_mdtRotCreator->correct(*rot->prepRawData(), *(*t).trackParameters(), ctx));
917  } else if (!m_muClusterRotCreator.empty() && (m_idHelperSvc->isMM(id) || m_idHelperSvc->issTgc(id))) {
918  updatedRot.reset(m_muClusterRotCreator->correct(*rot->prepRawData(), *(*t).trackParameters(), ctx));
919  }
920 
921  if (updatedRot) {
922  t = Muon::MuonTSOSHelper::createMeasTSOS(std::move(updatedRot), t->trackParameters()->uniqueClone(),
924  }
925  }
926  }
927 
928  // extrapolate and fit track
929  particleHypothesis = Trk::muon;
930  bool returnAfterCleaner = !fieldCache.toroidOn();
931 
932  ATH_MSG_VERBOSE("Calling createExtrapolatedTrack from " << __func__ << " at line " << __LINE__);
933  std::unique_ptr<Trk::Track> extrapolated(createExtrapolatedTrack(ctx, spectrometerTrack, *parameters, particleHypothesis,
934  m_cleanStandalone, spectrometerTSOS, vertexInFit, mbeamAxis.get(),
935  mperigeeSurface.get(), prefitResult.get()));
936 
937  if (extrapolated) dumpCaloEloss(extrapolated.get(), " extrapolated ");
938 
939  // fit problem: try fixup using vertex region or prefit
940  if (!extrapolated || !extrapolated->fitQuality()) {
941  if (extrapolated && !haveFitWithVertex && !vertexInFit) {
942  ATH_MSG_DEBUG(" bad fitQuality: retry with vertex ");
943  std::unique_ptr<Trk::Track> badfit(std::move(extrapolated));
944 
945  auto trackStateOnSurfaces = std::make_unique<Trk::TrackStates>();
946  trackStateOnSurfaces->reserve(badfit->trackStateOnSurfaces()->size() + 1);
947 
948  std::bitset<Trk::TrackStateOnSurface::NumberOfTrackStateOnSurfaceTypes> type{};
950  std::unique_ptr<Trk::PseudoMeasurementOnTrack> vertexInFit =
951  vertexOnTrack(*badfit->perigeeParameters(), mvertex.get(), mbeamAxis.get());
952 
953  if (vertexInFit) type.set(Trk::TrackStateOnSurface::Measurement);
954 
955  trackStateOnSurfaces->push_back(new Trk::TrackStateOnSurface(
956  std::move(vertexInFit), badfit->perigeeParameters()->uniqueClone(), nullptr, type));
957 
959  s != badfit->trackStateOnSurfaces()->end(); ++s) {
960  trackStateOnSurfaces->push_back((**s).clone());
961  }
962 
963  std::unique_ptr<Trk::Track> track =
964  std::make_unique<Trk::Track>(spectrometerTrack.info(), std::move(trackStateOnSurfaces), nullptr);
965  extrapolated = fit(ctx, *track, m_cleanStandalone, particleHypothesis);
966  }
967 
968  // restart from prefit without cleaning
969  if (!extrapolated || !extrapolated->fitQuality()) {
970  if (prefit && prefit->fitQuality() && caloParameters) {
971  ATH_MSG_DEBUG(" restarting from prefit as back extrapolation fit failed");
972  spectrometerTSOS.clear();
973  // create spectrometerTSOS corresponding to prefit
975 
976  while (m_calorimeterVolume->inside((**s).trackParameters()->position()) ||
977  (**s).type(Trk::TrackStateOnSurface::Perigee)) {
978  ++s;
979  } // end of while
980 
981  for (; s != prefit->trackStateOnSurfaces()->end(); ++s) { spectrometerTSOS.emplace_back((**s).clone()); }
982 
983  ATH_MSG_VERBOSE("Calling createExtrapolatedTrack from " << __func__ << " at line " << __LINE__);
984  extrapolated =
985  createExtrapolatedTrack(ctx, spectrometerTrack, *caloParameters, particleHypothesis, false, spectrometerTSOS,
986  vertexInFit, mbeamAxis.get(), mperigeeSurface.get(), prefitResult.get());
987  returnAfterCleaner = true;
988  }
989 
990  if (!extrapolated || !extrapolated->fitQuality()) {
991  bool hasFQ = extrapolated ? (extrapolated->fitQuality() != nullptr) : false;
992  ATH_MSG_DEBUG("fail track as back extrapolation fit failed " << extrapolated.get() << " hasFQ " << hasFQ);
993 
994  ATH_MSG_VERBOSE(" SA::failed (10)");
995  return nullptr;
996  }
997  }
998  }
999 
1000  // keep statistics for successful fits
1002  if (vertexInFit == mbeamAxis.get()) ++m_countBeamAxis;
1003  if (vertexInFit == mvertex.get()) ++m_countVertexRegion;
1004 
1005  // refit when there's been a significant momentum change (parameters at last calo scatterer)
1006  double momentum = parameters->momentum().mag();
1007 
1008  bool allowRefit = !badlyDeterminedCurvature;
1009  double pRatio = 1.;
1010 
1011  const Trk::TrackParameters* params_pRat = parameters.get();
1012  if (returnAfterCleaner) {
1013  allowRefit = false;
1014  } else {
1015  // pRatio is the ratio of fitted to start momentum value at calo exit
1016  // find parameters at calo exit
1017  const Trk::TrackParameters* params_pRat = nullptr;
1018  auto s = extrapolated->trackStateOnSurfaces()->begin();
1019  while (!(**s).trackParameters() || m_calorimeterVolume->inside((**s).trackParameters()->position())) {
1020  if ((**s).trackParameters() && !(**s).type(Trk::TrackStateOnSurface::Perigee)) params_pRat = (**s).trackParameters();
1021  ++s;
1022  }
1023 
1024  // extrapolated fit with missing calo parameters - this should never happen!
1025  if (params_pRat) {
1026  pRatio = momentum / parameters->momentum().mag();
1027  } else {
1028  // extrapolated track missing TrackParameters at calo scatterer
1029  m_messageHelper->printWarning(10);
1030  allowRefit = false;
1031  }
1032  }
1033 
1034  // in case of a significant momentum change: iterate (re-associate calo and refit)
1035  std::unique_ptr<Trk::Track> track;
1036 
1037  if (allowRefit && std::abs(pRatio - 1.) > m_largeMomentumChange) {
1038  if (msgLvl(MSG::VERBOSE)) {
1039  double sinTheta = params_pRat->momentum().perp() / params_pRat->momentum().mag();
1040 
1041  ATH_MSG_VERBOSE(" iterate as significant momentum change after fit "
1042  << pRatio << ", pT before " << momentum * sinTheta / Gaudi::Units::GeV << ", after "
1043  << params_pRat->momentum().perp() / Gaudi::Units::GeV << " GeV");
1044  }
1045 
1046  spectrometerTSOS.clear();
1047  for (const Trk::TrackStateOnSurface* s : *extrapolated->trackStateOnSurfaces()) {
1048  if (!s->type(Trk::TrackStateOnSurface::Perigee)) spectrometerTSOS.emplace_back(s->clone());
1049  }
1050 
1051  ATH_MSG_VERBOSE("Calling createExtrapolatedTrack from " << __func__ << " at line " << __LINE__);
1052 
1053  track = createExtrapolatedTrack(ctx, spectrometerTrack, *parameters, particleHypothesis, m_cleanStandalone, spectrometerTSOS,
1054  vertexInFit, mbeamAxis.get(), mperigeeSurface.get(), extrapolated->perigeeParameters());
1055 
1056  if (track) {
1057  double extrapChi2 = normalizedChi2(*extrapolated);
1058  double fitChi2 = normalizedChi2(*track);
1059  if (fitChi2 < m_badFitChi2 || fitChi2 < extrapChi2 + 0.5) { extrapolated.reset(); }
1060  }
1061  }
1062  if (extrapolated) { track.swap(extrapolated); }
1063 
1064  if (!m_trackQuery->isCaloAssociated(*track, ctx)) { // still want to perform this check probably though
1065  // fail as calo incorrectly described
1066  m_messageHelper->printWarning(12);
1067  ATH_MSG_VERBOSE(" SA::failed (12)");
1068  return nullptr;
1069  }
1070 
1071  int improvementsFailed = 0; // count the number of times the fit fails after improvements
1072 
1074  ATH_MSG_VERBOSE("Refining Calorimeter TSOS in StandAlone Fit ...");
1075 
1076  m_materialUpdator->updateCaloTSOS(*track);
1077 
1078  std::unique_ptr<Trk::Track> refinedTrack(fit(ctx, *track, false, Trk::muon));
1079  if (checkTrack("refineFit", refinedTrack.get())) {
1080  ATH_MSG_VERBOSE(__FILE__<<":"<<__LINE__<<"refined track checks out");
1081  track.swap(refinedTrack);
1082  } else {
1083  ATH_MSG_VERBOSE("refined track fit failed");
1084  ++improvementsFailed;
1085  }
1086  }
1087 
1088  // adds uncertainties
1089  // We will either have nullptr or a new Track.
1090  // What we pass stays untouched.
1091  std::unique_ptr<Trk::Track> newTrack = addIDMSerrors(track.get());
1092  // newTrack will not be used after this block, either
1093  // we updated the track or kept the track as it was
1094  if (newTrack) {
1095  if (msgLevel(MSG::DEBUG)) countAEOTs(*newTrack, " SA track after addIDMSerrors ");
1096  dumpCaloEloss(newTrack.get(), "SA input TSOS after refine IDMS ");
1097 
1098  // Don't run the outliers anymore at this stage
1099  std::unique_ptr<Trk::Track> refittedTrack(fit(ctx, *newTrack, false, Trk::muon));
1100  if (msgLevel(MSG::DEBUG)) { countAEOTs(*refittedTrack, " SA track after refit "); }
1101  dumpCaloEloss(refittedTrack.get(), " SA refit after refine IDMS ");
1102  if (checkTrack("standaloneFit", refittedTrack.get())) {
1103  // Here we swap
1104  track.swap(refittedTrack);
1105  } else {
1106  ++improvementsFailed;
1107  }
1108  } else {
1109  ++improvementsFailed;
1110  }
1111 
1112  // hole recovery, error optimization, attach TrackSummary
1113  finalTrackBuild(ctx, track);
1114 
1115  if (track) {
1116  dumpCaloEloss(track.get(), " finalTrackBuild ");
1117 
1118  // report when extrapolated fit quality significantly worse than spectrometer quality
1119  double fitChi2 = normalizedChi2(*track);
1120  if (fitChi2 > m_badFitChi2 && fitChi2 > spectrometerFitChi2 + 0.5) {
1121  ATH_MSG_DEBUG("standaloneFit: fit quality degraded wrt spectrometer alone. "
1122  << " Chi2/DoF= " << fitChi2);
1123 
1125  if (improvementsFailed >= 2) {
1126  ATH_MSG_DEBUG("reject track, quality degraded and improvements failed");
1127  return nullptr;
1128  }
1129  }
1130  }
1131  ATH_MSG_VERBOSE(" SA::ok ");
1132  return track;
1133  }
1134  std::unique_ptr<Trk::Track> CombinedMuonTrackBuilder::standaloneRefit(const EventContext& ctx, const Trk::Track& combinedTrack,
1135  const Amg::Vector3D& origin) const {
1136  //
1137  // update -if needed vertex and beam axis positions
1138  //
1139 
1140  if (msgLevel(MSG::DEBUG)) countAEOTs(combinedTrack, " in standalone Refit input combinedTrack ");
1141 
1142  MagField::AtlasFieldCache fieldCache;
1143  // Get field cache object
1144 
1145  if (!loadMagneticField(ctx, fieldCache)) return nullptr;
1146 
1147  if (!fieldCache.toroidOn()) {
1148  // no standalone refit for Toroid off
1149  return nullptr;
1150  }
1151 
1152  ATH_MSG_DEBUG(" StandaloneRefit beam position bs_x " << origin);
1153 
1154  // vertex will change track by track
1155  AmgSymMatrix(3) vertexRegionCovariance{AmgSymMatrix(3)::Zero()};
1156 
1157  double error2d0 = m_vertex3DSigmaRPhi * m_vertex3DSigmaRPhi;
1158  double error2z0 = m_vertex3DSigmaZ * m_vertex3DSigmaZ;
1159  const Trk::Perigee* measuredPerigee = combinedTrack.perigeeParameters();
1160 
1161  if (measuredPerigee && measuredPerigee->covariance() && m_useRefitTrackError) {
1162  error2d0 = (*measuredPerigee->covariance())(Trk::d0, Trk::d0);
1163  error2z0 = (*measuredPerigee->covariance())(Trk::z0, Trk::z0);
1164  ATH_MSG_DEBUG(" StandaloneRefit new vertex d0 error " << std::sqrt(error2d0) << " new vertex z0 error "
1165  << std::sqrt(error2z0));
1166  }
1167 
1168  (vertexRegionCovariance)(0, 0) = error2d0;
1169  (vertexRegionCovariance)(1, 1) = error2d0;
1170  (vertexRegionCovariance)(2, 2) = error2z0;
1171 
1172  std::unique_ptr<Trk::RecVertex> vertex = std::make_unique<Trk::RecVertex>(origin, vertexRegionCovariance);
1173 
1174  ATH_MSG_DEBUG(" StandaloneRefit new vertex position x " << vertex->position().x() << " y " << vertex->position().y() << " z "
1175  << vertex->position().z());
1176 
1177  bool addPhiPseudo = false;
1178  // release 21
1179  unsigned spectrometerPhiQuality = m_trackQuery->spectrometerPhiQuality(combinedTrack, ctx);
1180  if (spectrometerPhiQuality > 1) { addPhiPseudo = true; }
1181 
1182  ATH_MSG_VERBOSE("standaloneRefit: using vertex region constraint with "
1183  << "spectrometerPhiQuality " << spectrometerPhiQuality);
1184 
1185  // create standalone track TSOS vector
1186  auto trackStateOnSurfaces = std::make_unique<Trk::TrackStates>();
1187 
1188  // size will allow for perigee + all TSOS outside indet
1189  unsigned size = combinedTrack.trackStateOnSurfaces()->size() + 3 + addPhiPseudo;
1190 
1191  trackStateOnSurfaces->reserve(size);
1192 
1193  // position TSOS iterator to be just after the indet
1194  bool haveCaloDeposit = false;
1195 
1196  Trk::TrackStates::const_iterator s = combinedTrack.trackStateOnSurfaces()->begin();
1197  const Trk::TrackStates::const_iterator cmb_end_itr = combinedTrack.trackStateOnSurfaces()->end();
1198  do {
1199  ++s;
1200  if (s == cmb_end_itr) {
1201  // fail track as no TSOS with type CaloDeposit
1202  m_messageHelper->printWarning(13);
1203  return nullptr;
1204  }
1205  if ((*s)->type(Trk::TrackStateOnSurface::CaloDeposit)) {
1206  haveCaloDeposit = true;
1207  --s;
1208  }
1209  } while (!haveCaloDeposit);
1211  const Trk::TrackStateOnSurface* const cmb_inner_tsos = (*s);
1212  // inner calo scatterer - keep scattering angles for vertex constraint
1213  // Amg::Vector3D direction;
1214  const Trk::ScatteringAngles* innerScattering = nullptr;
1215  std::unique_ptr<Trk::TrackStateOnSurface> innerTSOS;
1216  const Trk::MaterialEffectsBase* materialEffects = cmb_inner_tsos->materialEffectsOnTrack();
1217  const Trk::TrackParameters* middleParameters = nullptr;
1218  const Trk::ScatteringAngles* outerScattering = nullptr;
1219  const Trk::TrackParameters* parameters = cmb_inner_tsos->trackParameters();
1220  std::unique_ptr<Trk::TrackParameters> param_owner;
1221  if (materialEffects && parameters && m_calorimeterVolume->inside(parameters->position())) {
1222  // keep scattering angles when vertex constrained
1223  // in r21, addVertexRegion is always true
1224 
1225  innerTSOS.reset(cmb_inner_tsos->clone());
1226  const Trk::MaterialEffectsOnTrack* meot = dynamic_cast<const Trk::MaterialEffectsOnTrack*>(materialEffects);
1227 
1228  if (!meot) {
1229  // innerScattering dynamic_cast failed
1230  m_messageHelper->printWarning(16);
1231  return nullptr;
1232  }
1233  innerScattering = meot->scatteringAngles();
1236  if (s != cmb_end_itr && !(*s)->type(Trk::TrackStateOnSurface::CaloDeposit)) { ++s; }
1237 
1239  if (s != cmb_end_itr) {
1240  const Trk::TrackStateOnSurface* const cmb_middle_tsos = (*s);
1241  materialEffects = cmb_middle_tsos->materialEffectsOnTrack();
1242  parameters = cmb_middle_tsos->trackParameters();
1243  middleParameters = parameters;
1244  } else {
1245  // no TSOS of type CaloDeposit found
1246  m_messageHelper->printWarning(17);
1247  materialEffects = nullptr;
1248  parameters = nullptr;
1249  }
1250 
1251  } else {
1252  // no inner material or parameters
1253  if (!materialEffects) m_messageHelper->printWarning(14);
1254  if (!parameters) m_messageHelper->printWarning(15);
1255  }
1256 
1257  if (!innerTSOS) {
1258  // no inner scattering TSOS found
1259  m_messageHelper->printWarning(18);
1260  return nullptr;
1261  }
1262 
1263  // middle calo scatterer (for energy deposit)
1264  double energyDeposit{0.};
1265 
1266  std::unique_ptr<Trk::TrackStateOnSurface> middleTSOS;
1267 
1268  if (materialEffects && parameters && m_calorimeterVolume->inside(parameters->position())) {
1269  const Trk::TrackStateOnSurface* const cmb_middle_tsos = (*s);
1270  middleTSOS.reset(cmb_middle_tsos->clone());
1271  const Trk::MaterialEffectsOnTrack* meot = dynamic_cast<const Trk::MaterialEffectsOnTrack*>(materialEffects);
1272 
1273  if (meot && meot->energyLoss()) energyDeposit = meot->energyLoss()->deltaE();
1275 
1276  ++s;
1277  if (s != cmb_end_itr) {
1278  const Trk::TrackStateOnSurface* const cmb_outer_tsos = (*s);
1279  materialEffects = cmb_outer_tsos->materialEffectsOnTrack();
1280  parameters = cmb_outer_tsos->trackParameters();
1281  } else {
1282  materialEffects = nullptr;
1283  parameters = nullptr;
1284  }
1285  } else {
1286  // no middle material or parameters
1287  if (!materialEffects) m_messageHelper->printWarning(19);
1288  if (!parameters) m_messageHelper->printWarning(20);
1289  }
1290 
1291  if (!middleTSOS) {
1292  // no CaloDeposit TSOS found
1293  m_messageHelper->printWarning(21);
1294  return nullptr;
1295  }
1296 
1297  // outer calo scatterer
1298  std::unique_ptr<Trk::TrackStateOnSurface> outerTSOS;
1299 
1300  double pInner{0.}, pOuter{0.};
1301  if (materialEffects && parameters && m_calorimeterVolume->inside(parameters->position())) {
1302  const Trk::TrackStateOnSurface* const cmb_outer_tsos = (*s);
1303  pOuter = parameters->momentum().mag();
1304 
1305  outerTSOS.reset(cmb_outer_tsos->clone());
1306 
1307  const Trk::MaterialEffectsOnTrack* meot = dynamic_cast<const Trk::MaterialEffectsOnTrack*>(materialEffects);
1308 
1309  if (!meot) {
1310  // outerScattering dynamic_cast failed
1311  m_messageHelper->printWarning(24);
1312  return nullptr;
1313  }
1314  outerScattering = meot->scatteringAngles();
1315 
1316  // Go to the next surface
1317  ++s;
1318 
1319  // get parameters at middleSurface for energy correction,
1320  // start with parameters from middle surface when vertex in fit
1321  if (outerScattering && middleTSOS) {
1322  parameters = middleTSOS->trackParameters();
1323  } else {
1324  // otherwise extrapolate outer to middleSurface without scattering correction
1325  param_owner = m_propagator->propagate(ctx, *parameters, middleTSOS->trackParameters()->associatedSurface(),
1327  parameters = param_owner.get();
1328  }
1330  if (parameters) {
1332  if (!param_owner) param_owner = parameters->uniqueClone();
1333  // corrected parameters (include unfitted calo energy deposit),
1334  // inner momentum = outer momentum plus energy deposit
1335  pInner = pOuter + energyDeposit;
1336  momentumUpdate(param_owner, pInner);
1338  parameters = param_owner.get();
1339  }
1340  } else {
1341  // no outer material or parameters
1342  if (!materialEffects) m_messageHelper->printWarning(22);
1343  if (!parameters) m_messageHelper->printWarning(23);
1344  }
1345 
1346  // fail track if missing any calo surface or extrapolation failure
1347  if (!innerTSOS || !middleTSOS || !outerTSOS || !parameters) { return nullptr; }
1349  parameters = nullptr;
1350 
1352  param_owner = m_propagator->propagate(ctx, *param_owner, innerTSOS->trackParameters()->associatedSurface(), Trk::oppositeMomentum,
1354 
1356  if (innerScattering) { momentumUpdate(param_owner, pInner, true, -innerScattering->deltaPhi(), -innerScattering->deltaTheta()); }
1357 
1358  std::unique_ptr<Trk::TrackParameters> perigee_owner;
1359  if (param_owner) {
1360  perigee_owner = m_propagator->propagate(ctx, *param_owner, *m_perigeeSurface, Trk::oppositeMomentum, false,
1363  if (perigee_owner && perigee_owner->surfaceType() != Trk::SurfaceType::Perigee) { perigee_owner.reset(); }
1364  }
1365 
1366  // in case of problem above: clone combined perigee
1367  if (!perigee_owner) { perigee_owner = combinedTrack.perigeeParameters()->uniqueClone(); }
1368  // track back out to the 3 calo surfaces applying small correction for non-linearity
1369  param_owner = m_propagator->propagate(ctx, *perigee_owner, innerTSOS->trackParameters()->associatedSurface(), Trk::alongMomentum,
1371  if (!param_owner) {
1372  // failed propagation to innerTSOS
1373  m_messageHelper->printWarning(26);
1374  } else {
1375  if (innerScattering) { momentumUpdate(param_owner, pInner, true, innerScattering->deltaPhi(), innerScattering->deltaTheta()); }
1376 
1377  param_owner = m_propagator->propagate(ctx, *param_owner, middleParameters->associatedSurface(), Trk::alongMomentum, false,
1379 
1380  if (!param_owner) {
1381  // failed propagation to middleTSOS
1382  m_messageHelper->printWarning(27);
1383  } else {
1384  momentumUpdate(param_owner, pOuter);
1385  param_owner = m_propagator->propagate(ctx, *param_owner, outerTSOS->trackParameters()->associatedSurface(),
1387  }
1388  }
1389 
1390  if (!param_owner) { return nullptr; }
1391 
1392  if (outerScattering) { momentumUpdate(param_owner, pOuter, true, outerScattering->deltaPhi(), outerScattering->deltaTheta()); }
1393 
1394  // small correction term
1395  const double deltaPhi = xAOD::P4Helpers::deltaPhi(outerTSOS->trackParameters()->momentum().phi(), param_owner->momentum().phi());
1396  const double deltaTheta = outerTSOS->trackParameters()->momentum().theta() - param_owner->momentum().theta();
1397 
1398  momentumUpdate(perigee_owner, pInner, true, deltaPhi, deltaTheta);
1399 
1400  std::unique_ptr<Trk::RecVertex> mbeamAxis = std::make_unique<Trk::RecVertex>(*m_beamAxis);
1402  std::unique_ptr<Trk::PseudoMeasurementOnTrack> vertexInFit{vertexOnTrack(*perigee_owner, vertex.get(), mbeamAxis.get())};
1403 
1404  // create perigee TSOS
1405  trackStateOnSurfaces->push_back(Muon::MuonTSOSHelper::createPerigeeTSOS(std::move(perigee_owner)));
1406 
1407  // including vertex region pseudoMeas if requested: in r21, this is always requested
1408  if (vertexInFit) {
1409  trackStateOnSurfaces->push_back(Muon::MuonTSOSHelper::createMeasTSOS(std::move(vertexInFit), nullptr, Trk::TrackStateOnSurface::Measurement));
1410  }
1411 
1412  if (m_addElossID) {
1413  double Eloss{0.}, sigmaEloss{0.}, X0tot{0.}, sigmaDeltaPhitot2{0.}, sigmaDeltaThetatot2{0.};
1414 
1415  std::vector<const Trk::TrackStateOnSurface*> scatter_tsos;
1416  scatter_tsos.reserve(combinedTrack.trackStateOnSurfaces()->size());
1417 
1418  for (const Trk::TrackStateOnSurface* comb_tsos : *combinedTrack.trackStateOnSurfaces()) {
1419  if (!comb_tsos->trackParameters()) continue;
1420  if (!m_indetVolume->inside(comb_tsos->trackParameters()->position())) break;
1421  if (!comb_tsos->materialEffectsOnTrack()) { continue; }
1422  const double X0 = comb_tsos->materialEffectsOnTrack()->thicknessInX0();
1423  X0tot += X0;
1424  const Trk::MaterialEffectsOnTrack* meot =
1425  dynamic_cast<const Trk::MaterialEffectsOnTrack*>(comb_tsos->materialEffectsOnTrack());
1426 
1427  if (!meot) { continue; }
1428  const Trk::EnergyLoss* energyLoss = meot->energyLoss();
1429  if (!energyLoss) { continue; }
1430  Eloss += energyLoss->deltaE();
1431  sigmaEloss += energyLoss->sigmaDeltaE();
1432 
1433  ATH_MSG_DEBUG("CombinedMuonFit ID Eloss found r " << (comb_tsos->trackParameters())->position().perp() << " z "
1434  << (comb_tsos->trackParameters())->position().z() << " value "
1435  << energyLoss->deltaE() << " Eloss " << Eloss << " sigma Eloss "
1436  << energyLoss->sigmaDeltaE() << " X0 " << X0);
1437 
1438  const Trk::ScatteringAngles* scat = meot->scatteringAngles();
1439  if (scat) {
1440  double sigmaDeltaPhi = scat->sigmaDeltaPhi();
1441  double sigmaDeltaTheta = scat->sigmaDeltaTheta();
1442  sigmaDeltaPhitot2 += sigmaDeltaPhi * sigmaDeltaPhi;
1443  sigmaDeltaThetatot2 += sigmaDeltaTheta * sigmaDeltaTheta;
1444  scatter_tsos.push_back(comb_tsos);
1445  }
1446  }
1447 
1448  ATH_MSG_DEBUG("standaloneRefit Total ID Eloss " << Eloss << " sigma Eloss " << sigmaEloss << " X0 " << X0tot
1449  << " sigma scat phi " << std::sqrt(sigmaDeltaPhitot2) << " sigma scat theta "
1450  << std::sqrt(sigmaDeltaThetatot2));
1451  if (!scatter_tsos.empty()) {
1452  const int itsosMiddle = scatter_tsos.size() / 2;
1453  const Trk::TrackStateOnSurface* mid_scatter = scatter_tsos[itsosMiddle];
1454 
1455  std::unique_ptr<Trk::EnergyLoss> energyLossNew = std::make_unique<Trk::EnergyLoss>(Eloss, sigmaEloss, sigmaEloss, sigmaEloss);
1456 
1457  const Trk::Surface& surfNew = mid_scatter->trackParameters()->associatedSurface();
1458  Trk::ScatteringAngles scatNew{0., 0., std::sqrt(sigmaDeltaPhitot2), std::sqrt(sigmaDeltaThetatot2)};
1459 
1460  std::bitset<Trk::MaterialEffectsBase::NumberOfMaterialEffectsTypes> meotPattern(0);
1463 
1464  ATH_MSG_DEBUG(" itsosMiddle " << itsosMiddle << " tsosnr size " << scatter_tsos.size());
1465 
1466  std::unique_ptr<Trk::MaterialEffectsOnTrack> meotNew = std::make_unique<Trk::MaterialEffectsOnTrack>(X0tot, scatNew, std::move(energyLossNew), surfNew, meotPattern);
1467 
1468  std::unique_ptr<Trk::TrackParameters> parsNew = mid_scatter->trackParameters()->uniqueClone();
1469  std::bitset<Trk::TrackStateOnSurface::NumberOfTrackStateOnSurfaceTypes> typePatternScat(0);
1470  typePatternScat.set(Trk::TrackStateOnSurface::Scatterer);
1471 
1472  std::unique_ptr<Trk::TrackStateOnSurface> newTSOS =
1473  std::make_unique<Trk::TrackStateOnSurface>(nullptr, std::move(parsNew), std::move(meotNew), typePatternScat);
1474 
1475  trackStateOnSurfaces->push_back(std::move(newTSOS));
1476  ATH_MSG_DEBUG(" add new TSOS for ID ");
1477  }
1478 
1479  } // end m_addElossID
1480 
1481  // add the 3 surface calo model
1482  trackStateOnSurfaces->push_back(std::move(innerTSOS));
1483  trackStateOnSurfaces->push_back(std::move(middleTSOS));
1484  trackStateOnSurfaces->push_back(std::move(outerTSOS));
1485  const Trk::TrackParameters* outerTSOSParam = trackStateOnSurfaces->back()->trackParameters();
1486  // MS entrance perigee
1488  std::unique_ptr<Trk::TrackStateOnSurface> entranceTSOS = entrancePerigee(ctx, outerTSOSParam);
1489  if (entranceTSOS) trackStateOnSurfaces->push_back(std::move(entranceTSOS));
1490  }
1491 
1492  // leading spectrometer material
1493  bool haveLeadingMaterial = false;
1494 
1496  for (; mat_it != cmb_end_itr; ++mat_it) {
1497  if ((*mat_it)->type(Trk::TrackStateOnSurface::Measurement)) break;
1498  haveLeadingMaterial = true;
1499  }
1500 
1501  // protection against overruning the end of the vector
1502  if (mat_it == cmb_end_itr) {
1503  ATH_MSG_WARNING("At end of TSOS vector");
1504  return nullptr;
1505  }
1506 
1507  if (haveLeadingMaterial) appendSelectedTSOS(*trackStateOnSurfaces, s, ++mat_it);
1508 
1509  // insert phi pseudo measurement if necessary
1510  if (addPhiPseudo) {
1511  std::unique_ptr<Trk::TrackStateOnSurface> tsos = createPhiPseudoMeasurement(ctx, combinedTrack);
1512  if (tsos) trackStateOnSurfaces->push_back(std::move(tsos));
1513  }
1514 
1515  // then append the remaining TSOS from the input track
1516  appendSelectedTSOS(*trackStateOnSurfaces, mat_it, cmb_end_itr);
1517 
1518  // create track for refit
1519  std::unique_ptr<Trk::Track> standaloneTrack =
1520  std::make_unique<Trk::Track>(combinedTrack.info(), std::move(trackStateOnSurfaces), nullptr);
1522  if (m_trackQuery->isCombined(*standaloneTrack, ctx)) { ATH_MSG_WARNING(" This should not happen standalone Track has ID hits "); }
1523 
1524  if (msgLevel(MSG::DEBUG)) countAEOTs(*standaloneTrack, " in standalone Refit standaloneTrack track before fit ");
1525 
1526  std::unique_ptr<Trk::Track> refittedTrack{fit(ctx, *standaloneTrack, false, Trk::muon)};
1527  if (!checkTrack("standaloneRefit", refittedTrack.get())) { return nullptr; }
1528 
1529  // eventually this whole tool will use unique_ptrs
1530  // in the meantime, this allows the MuonErrorOptimisationTool and MuonRefitTool to use them
1531  if (refittedTrack) {
1532  if (!refittedTrack->fitQuality()) { return nullptr; }
1533 
1534  if (!m_trackQuery->isCaloAssociated(*refittedTrack, ctx)) {
1535  // fail as calo incorrectly described
1536  m_messageHelper->printWarning(28);
1537  return nullptr;
1538  }
1539 
1540  if (msgLevel(MSG::DEBUG)) countAEOTs(*refittedTrack, " standaloneRefit final refittedTrack ");
1541 
1542  // fit with optimized spectrometer errors
1543  // this should also be inside the "if(refittedTrack) statement
1544  if (!m_muonErrorOptimizer.empty() && !refittedTrack->info().trackProperties(Trk::TrackInfo::StraightTrack) &&
1545  countAEOTs(*refittedTrack, " before optimize ") == 0) {
1546  ATH_MSG_VERBOSE(" perform spectrometer error optimization after cleaning ");
1547  std::unique_ptr<Trk::Track> optimizedTrack = m_muonErrorOptimizer->optimiseErrors(*refittedTrack, ctx);
1548 
1549  if (checkTrack("standaloneRefitOpt", optimizedTrack.get())) {
1550  refittedTrack.swap(optimizedTrack);
1551  if (msgLevel(MSG::DEBUG)) countAEOTs(*refittedTrack, " standaloneRefit alignment errors Track ");
1552  }
1553  }
1554  }
1555 
1556  // have to release it until the whole tool is migrated to unique_ptr
1557  return refittedTrack;
1558  }
1559 
1560  std::unique_ptr<Trk::Track> CombinedMuonTrackBuilder::addIDMSerrors(const Trk::Track* track) const {
1561  //
1562  // take track and correct the two scattering planes in the Calorimeter
1563  // to take into account m_IDMS_rzSigma and m_IDMS_xySigma
1564  //
1565  // returns a new Track or nullptr does not modify the input in any way
1566  //
1567  if (!m_addIDMSerrors) { return nullptr; }
1568 
1569  ATH_MSG_DEBUG(" CombinedMuonTrackBuilder addIDMSerrors to track ");
1570 
1572  const Trk::TrackStateOnSurface* id_exit = nullptr;
1573  const Trk::TrackStateOnSurface* calo_entrance = nullptr;
1574  const Trk::TrackStateOnSurface* calo_exit = nullptr;
1575  const Trk::TrackStateOnSurface* ms_entrance = nullptr;
1576 
1577  m_alignUncertTool_theta->get_track_state_measures(track, id_exit, calo_entrance, calo_exit, ms_entrance);
1579  if (!calo_entrance || !calo_exit || !ms_entrance) {
1580  ATH_MSG_DEBUG(" addIDMSerrors keep original track ");
1581  return nullptr;
1582  }
1583 
1584  auto trackStateOnSurfaces = std::make_unique<Trk::TrackStates>();
1585  trackStateOnSurfaces->reserve(track->trackStateOnSurfaces()->size());
1586 
1587  for (const Trk::TrackStateOnSurface* trk_srf : *track->trackStateOnSurfaces()) {
1588  if (calo_entrance == trk_srf || calo_entrance == trk_srf) {
1589  if (!trk_srf->materialEffectsOnTrack()) {
1590  ATH_MSG_DEBUG("No material effect on track");
1591  continue;
1592  }
1593  const Trk::MaterialEffectsOnTrack* meot =
1594  dynamic_cast<const Trk::MaterialEffectsOnTrack*>(trk_srf->materialEffectsOnTrack());
1595  if (!meot) {
1596  ATH_MSG_WARNING(" This should not happen: no MaterialEffectsOnTrack for scatterer ");
1597  continue;
1598  }
1599  const Trk::ScatteringAngles* scat = meot->scatteringAngles();
1600  if (!scat) {
1601  ATH_MSG_WARNING(" This should not happen: no Scattering Angles for scatterer ");
1602  continue;
1603  }
1604 
1605  float sigmaDeltaPhi = std::hypot(scat->sigmaDeltaPhi(), m_alignUncertTool_phi->get_uncertainty(track));
1606  float sigmaDeltaTheta = std::hypot(scat->sigmaDeltaTheta(), m_alignUncertTool_theta->get_uncertainty(track));
1607  float X0 = trk_srf->materialEffectsOnTrack()->thicknessInX0();
1608  //
1609  auto energyLossNew = std::make_unique<Trk::EnergyLoss>(0., 0., 0., 0.);
1610  auto scatNew = Trk::ScatteringAngles(0., 0., sigmaDeltaPhi, sigmaDeltaTheta);
1611 
1612  const Trk::Surface& surfNew = trk_srf->trackParameters()->associatedSurface();
1613 
1614  std::bitset<Trk::MaterialEffectsBase::NumberOfMaterialEffectsTypes> meotPattern(0);
1617 
1618  auto meotNew = std::make_unique<Trk::MaterialEffectsOnTrack>(
1619  X0,
1620  scatNew,
1621  std::move(energyLossNew),
1622  surfNew,
1623  meotPattern);
1624  auto parsNew = trk_srf->trackParameters()->uniqueClone();
1625 
1626  std::bitset<Trk::TrackStateOnSurface::NumberOfTrackStateOnSurfaceTypes> typePatternScat(0);
1627  typePatternScat.set(Trk::TrackStateOnSurface::Scatterer);
1628 
1629  const Trk::TrackStateOnSurface* newTSOS =
1630  new Trk::TrackStateOnSurface(nullptr, std::move(parsNew), std::move(meotNew), typePatternScat);
1631  trackStateOnSurfaces->push_back(newTSOS);
1632 
1633  ATH_MSG_DEBUG(" old Calo scatterer had sigmaDeltaPhi mrad " << scat->sigmaDeltaPhi() * 1000 << " sigmaDeltaTheta mrad "
1634  << scat->sigmaDeltaTheta() * 1000 << " X0 " << X0);
1635 
1636  ATH_MSG_DEBUG(" new Calo scatterer made with sigmaDeltaPhi mrad " << sigmaDeltaPhi * 1000 << " sigmaDeltaTheta mrad "
1637  << sigmaDeltaTheta * 1000);
1638 
1639  } else {
1640  // skip AEOTs
1641  if (trk_srf->alignmentEffectsOnTrack()) {
1642  ATH_MSG_DEBUG(" addIDMSerrors alignmentEffectsOnTrack() found on track ");
1643  continue;
1644  }
1645  trackStateOnSurfaces->push_back(trk_srf->clone());
1646  }
1647  }
1648  ATH_MSG_DEBUG(" trackStateOnSurfaces on input track " << track->trackStateOnSurfaces()->size() << " trackStateOnSurfaces found "
1649  << trackStateOnSurfaces->size());
1650 
1651  std::unique_ptr<Trk::Track> newTrack = std::make_unique<Trk::Track>(track->info(), std::move(trackStateOnSurfaces), nullptr);
1652  return newTrack;
1653  }
1654 
1657  // spectrometer measurement selection
1658  std::vector<const Trk::Surface*> measurementSurfaces;
1659  measurementSurfaces.reserve(trackStateOnSurfaces.size());
1660  const Trk::Surface* previousSurface = nullptr;
1661 
1663  for (; s != end; ++s) {
1664  const Trk::TrackStateOnSurface& tsos = **s;
1665  if (tsos.alignmentEffectsOnTrack()) {
1666  ATH_MSG_VERBOSE("appendSelectedTSOS:: alignmentEffectsOnTrack ");
1667  }
1668  // skip non-understood features in iPatFitter
1669  if (!tsos.measurementOnTrack() && !tsos.materialEffectsOnTrack()) {
1671  ATH_MSG_VERBOSE("appendSelectedTSOS:: skip a perigee without material and measuremet "<<tsos);
1672  continue;
1673  } else if (!tsos.type(Trk::TrackStateOnSurface::Hole) || !tsos.trackParameters()) {
1674  ATH_MSG_VERBOSE("appendSelectedTSOS:: skip unrecognized TSOS " << tsos.dumpType());
1675  continue;
1676  }
1677  }
1678 
1679  if (tsos.measurementOnTrack()) {
1680  // skip any pseudo measurements
1681  if (dynamic_cast<const Trk::PseudoMeasurementOnTrack*>(tsos.measurementOnTrack())) { continue; }
1682 
1683  // skip duplicate measurements on same surface
1684  const Trk::Surface* surface = &tsos.measurementOnTrack()->associatedSurface();
1685  if (previousSurface &&
1686  std::find(measurementSurfaces.begin(), measurementSurfaces.end(), surface) != measurementSurfaces.end()) {
1687  // skip duplicate measurement
1688  m_messageHelper->printWarning(34, m_idHelperSvc->toString(m_edmHelperSvc->getIdentifier(*(tsos.measurementOnTrack()))));
1689  continue;
1690  }
1691 
1692  measurementSurfaces.push_back(surface);
1693  previousSurface = surface;
1694  }
1695  trackStateOnSurfaces.push_back(tsos.clone());
1696  }
1697  }
1698 
1700  const Trk::TrackParameters*& combinedEnergyParameters,
1701  const Trk::TrackParameters*& muonEnergyParameters) const {
1702  // will also set the caloEnergyParameters (from both combinedTrack and muonTrack)
1703  combinedEnergyParameters = nullptr;
1704  muonEnergyParameters = nullptr;
1705 
1706  // quit if missing track
1707  if (!combinedTrack || !muonTrack) return nullptr;
1708 
1709  // muonTrack: get parameters at CaloDeposit
1711 
1712  while (!(**s).type(Trk::TrackStateOnSurface::CaloDeposit)) {
1713  if (++s == muonTrack->trackStateOnSurfaces()->end()) {
1714  // muonTrack without caloEnergy association
1715  m_messageHelper->printWarning(35);
1716  return nullptr;
1717  }
1718  }
1719  muonEnergyParameters = (**s).trackParameters();
1720 
1721  // find corresponding parameters from combinedTrack
1722  s = combinedTrack->trackStateOnSurfaces()->begin();
1723  while (!(**s).type(Trk::TrackStateOnSurface::CaloDeposit)) {
1724  if (++s == combinedTrack->trackStateOnSurfaces()->end()) {
1725  // combinedTrack without caloEnergy association
1726  m_messageHelper->printWarning(36);
1727  return nullptr;
1728  }
1729  }
1730 
1731  combinedEnergyParameters = (**s).trackParameters();
1732  if (muonEnergyParameters && combinedEnergyParameters) {
1733  ATH_MSG_DEBUG("muon and combined EnergyParameters: " << muonEnergyParameters->momentum().mag() << " "
1734  << combinedEnergyParameters->momentum().mag());
1735  }
1736  // success!
1737  return m_trackQuery->caloEnergy(*combinedTrack);
1738  }
1739 
1741  const EventContext& ctx, const Trk::Track& spectrometerTrack, const Trk::TrackParameters& parameters,
1742  Trk::ParticleHypothesis particleHypothesis, Trk::RunOutlierRemoval runOutlier,
1743  const std::vector<std::unique_ptr<const Trk::TrackStateOnSurface>>& spectrometerTSOS, const Trk::RecVertex* vertex,
1744  const Trk::RecVertex* mbeamAxis, const Trk::PerigeeSurface* mperigeeSurface, const Trk::Perigee* seedParameters) const {
1745  ATH_MSG_DEBUG(" createExtrapolatedTrack() - " << __LINE__ << ": pt " << parameters.momentum().perp() << " r "
1746  << parameters.position().perp() << " z " << parameters.position().z() << " cov "
1747  << parameters.covariance() << " muonfit " << (particleHypothesis == Trk::muon));
1748 
1749  std::vector<std::unique_ptr<const Trk::TrackStateOnSurface>> caloTSOS, leadingTSOS;
1750 
1751  std::unique_ptr<const Trk::TrackParameters> track_param_owner;
1752  const Trk::TrackParameters* trackParameters{nullptr};
1753  const Trk::Perigee* perigee{nullptr};
1754 
1755  if (vertex && m_indetVolume->inside(parameters.position())) { perigee = dynamic_cast<const Trk::Perigee*>(&parameters); }
1756  if (perigee) {
1757  ATH_MSG_DEBUG("createExtrapolatedTrack(): Got a perigee ");
1758  trackParameters = perigee;
1759  } else {
1760  ATH_MSG_DEBUG("createExtrapolatedTrack(): no perigee");
1761  // extrapolate backwards to associate leading material in spectrometer
1762  // (provided material has already been allocated between measurements)
1763  const Trk::TrackParameters* leadingParameters = &parameters;
1764  if (particleHypothesis == Trk::muon) {
1765  bool haveMaterial{false}, haveLeadingMaterial{false}, firstMSHit{false};
1766 
1767  for (const std::unique_ptr<const Trk::TrackStateOnSurface>& s : spectrometerTSOS) {
1768  if (s->materialEffectsOnTrack()) {
1769  haveMaterial = true;
1770  if (!firstMSHit) haveLeadingMaterial = true;
1771  }
1772 
1773  if (s->measurementOnTrack() && !firstMSHit) { firstMSHit = true; }
1774 
1775  if (haveMaterial && firstMSHit) { break; }
1776  }
1777 
1778  // only add leading material if there is no material in fron of first muon measurement
1779 
1780  if (!m_materialAllocator.empty() && haveMaterial && !haveLeadingMaterial) {
1781  // protect the momentum to avoid excessive Eloss
1782  Amg::VectorX parameterVector = parameters.parameters();
1783 
1784  constexpr double Emax = 50000.;
1785 
1786  if (parameterVector[Trk::qOverP] == 0.) {
1787  parameterVector[Trk::qOverP] = 1. / Emax;
1788  } else {
1789  if (std::abs(parameterVector[Trk::qOverP]) * Emax < 1) {
1790  parameterVector[Trk::qOverP] = parameters.charge() / Emax;
1791  }
1792  }
1793  std::unique_ptr<Trk::TrackParameters> correctedParameters{parameters.associatedSurface().createUniqueTrackParameters(
1794  parameterVector[Trk::loc1], parameterVector[Trk::loc2], parameterVector[Trk::phi], parameterVector[Trk::theta],
1795  parameterVector[Trk::qOverP], std::nullopt)};
1796 
1798  std::unique_ptr<std::vector<const Trk::TrackStateOnSurface*>> lead_tsos_from_alloc{
1799  m_materialAllocator->leadingSpectrometerTSOS(*correctedParameters, garbage)};
1800  if (lead_tsos_from_alloc) {
1801  for (const Trk::TrackStateOnSurface* l_tsos : *lead_tsos_from_alloc) leadingTSOS.emplace_back(l_tsos);
1802  }
1803  if (!leadingTSOS.empty() && leadingTSOS.front()->trackParameters()) {
1804  leadingParameters = leadingTSOS.front()->trackParameters();
1805  }
1806  }
1807  }
1808 
1809  // extrapolate backwards to associate calorimeter material effects
1810  bool caloAssociated = false;
1811 
1812  if (particleHypothesis == Trk::muon) {
1813  ATH_MSG_VERBOSE(" Retrieving Calorimeter TSOS from " << __func__ << " at line " << __LINE__);
1814  if (m_useCaloTG) {
1815  caloTSOS = getCaloTSOSfromMatProvider(*leadingParameters, spectrometerTrack);
1816  // Dump CaloTSOS
1817  //
1818  if (msgLevel(MSG::DEBUG)) {
1819  for (std::unique_ptr<const Trk::TrackStateOnSurface>& m : caloTSOS) {
1820  if (!m->materialEffectsOnTrack()) continue;
1821  const Trk::MaterialEffectsOnTrack* meot =
1822  dynamic_cast<const Trk::MaterialEffectsOnTrack*>(m->materialEffectsOnTrack());
1823  double pcalo{0.}, deltaP{0.};
1824  if (!meot) continue;
1825  if (meot->thicknessInX0() <= 20) { continue; }
1826  const Trk::ScatteringAngles* scatAngles = meot->scatteringAngles();
1827 
1828  ATH_MSG_DEBUG(" Calorimeter X0 " << meot->thicknessInX0() << " pointer scat " << scatAngles);
1829 
1830  if (!scatAngles) { continue; }
1831  pcalo = m->trackParameters()->momentum().mag();
1832 
1833  const double pullPhi = scatAngles->deltaPhi() / scatAngles->sigmaDeltaPhi();
1834  const double pullTheta = scatAngles->deltaTheta() / scatAngles->sigmaDeltaTheta();
1835 
1836  ATH_MSG_DEBUG(" Calorimeter scatterer deltaPhi " << scatAngles->deltaPhi() << " pull " << pullPhi
1837  << " deltaTheta " << scatAngles->deltaTheta() << " pull "
1838  << pullTheta);
1839 
1840  const Trk::EnergyLoss* energyLoss = meot->energyLoss();
1841  if (!energyLoss) continue;
1842 
1843  if (m->trackParameters()) {
1844  ATH_MSG_DEBUG("Eloss found r " << (m->trackParameters())->position().perp() << " z "
1845  << (m->trackParameters())->position().z() << " deltaE "
1846  << energyLoss->deltaE());
1847  }
1848 
1850  double caloEloss = std::abs(energyLoss->deltaE());
1851  if (m->trackParameters()) { deltaP = m->trackParameters()->momentum().mag() - pcalo; }
1852 
1853  ATH_MSG_DEBUG(" Calorimeter Deposit " << caloEloss << " pcalo Entrance " << pcalo << " deltaP " << deltaP);
1854  }
1855  }
1856  }
1857  } else {
1858  caloTSOS = m_caloTSOS->caloTSOS(ctx, *leadingParameters);
1859  }
1860 
1861  if (caloTSOS.size() > 2) {
1862  caloAssociated = true;
1863  } else {
1864  ATH_MSG_VERBOSE("Failed to associated calorimeter");
1865  }
1866  } else {
1867  // TDDO Run2 Calo TG
1868  std::unique_ptr<const Trk::TrackStateOnSurface> tsos = m_caloTSOS->innerTSOS(ctx, parameters);
1869  if (tsos) {
1870  caloTSOS.push_back(std::move(tsos));
1871  tsos = m_caloTSOS->outerTSOS(ctx, *caloTSOS.back()->trackParameters());
1872  if (tsos) {
1873  caloAssociated = true;
1874  caloTSOS.push_back(std::move(tsos));
1875  }
1876  }
1877  ATH_MSG_VERBOSE("Special non-muon case for calo: " << caloAssociated);
1878  }
1879 
1880  // if association OK, create perigee surface and back-track to it
1881  if (caloAssociated) {
1882  MagField::AtlasFieldCache fieldCache;
1883  // Get field cache object
1884  if (!loadMagneticField(ctx, fieldCache)) return nullptr;
1885 
1886  if (fieldCache.toroidOn()) {
1887  const Trk::TrackParameters* oldParameters = caloTSOS.front()->trackParameters();
1888 
1889  if (oldParameters){
1890  if(not oldParameters->covariance()) { ATH_MSG_VERBOSE(" createExtrapolatedTrack: no cov (0)"); }
1891  // chickened out of sorting out ownership
1892  track_param_owner = m_propagator->propagate(ctx, *oldParameters, *mperigeeSurface, Trk::oppositeMomentum, false,
1894  }
1895  } else {
1896  track_param_owner = m_propagatorSL->propagate(ctx, parameters, *mperigeeSurface, Trk::oppositeMomentum, false,
1898  }
1899  trackParameters = track_param_owner.get();
1900 
1901  // only accept when perigee in indet tracking volume
1902  if (trackParameters && !m_indetVolume->inside(trackParameters->position())) {
1903  ATH_MSG_DEBUG(" back extrapolation problem: probably outside indet volume ");
1904  caloAssociated = false;
1905  }
1906 
1907  if (trackParameters && !trackParameters->covariance()) { ATH_MSG_VERBOSE(" createExtrapolatedTrack: no cov (1)"); }
1908 
1909  if (trackParameters) {
1910  ATH_MSG_VERBOSE(" Seed parameter: r " << trackParameters->position().perp() << " z " << trackParameters->position().z()
1911  << " pt " << trackParameters->momentum().perp());
1912  }
1913 
1914  } // if (caloAssociated) {
1915  // start from vertex in case of calo association problem
1916  else if (vertex) {
1917  ATH_MSG_DEBUG(" back extrapolation problem: retry with tracking out from vertex ");
1918  // delete any existing calo objects
1919  caloTSOS.clear();
1920 
1921  // track out from vertex
1922  const Amg::Vector3D momentum = parameters.position().unit() * Gaudi::Units::TeV;
1923 
1924  track_param_owner = std::make_unique<Trk::Perigee>(vertex->position(), momentum, 1., *mperigeeSurface);
1925  trackParameters = track_param_owner.get();
1926  particleHypothesis = Trk::nonInteracting;
1927  runOutlier = false;
1928 
1929  ATH_MSG_VERBOSE(" Retriving Calorimeter TSOS from " << __func__ << " at line " << __LINE__);
1930 
1931  if (m_useCaloTG) {
1932  caloTSOS = getCaloTSOSfromMatProvider(*trackParameters, spectrometerTrack);
1933  } else {
1934  std::unique_ptr<const Trk::TrackStateOnSurface> tsos = m_caloTSOS->innerTSOS(ctx, *trackParameters);
1935  if (tsos) {
1936  caloTSOS.push_back(std::move(tsos));
1937  tsos = m_caloTSOS->outerTSOS(ctx, *trackParameters);
1938  if (tsos) {
1939  caloTSOS.push_back(std::move(tsos));
1940  } else {
1941  track_param_owner.reset();
1942  }
1943  }
1944  }
1945  trackParameters = track_param_owner.get();
1946  }
1947 
1948  // failure in calo association and/or extrapolation to indet
1949  if (!trackParameters || caloTSOS.empty()) {
1950  ATH_MSG_DEBUG(" perigee back-extrapolation fails ");
1951  return nullptr;
1952  }
1953  } // if (perigee) {
1954 
1955  // set seed if provided
1956  if (seedParameters) { trackParameters = seedParameters; }
1957 
1958  // append TSOS objects into DataVector
1959  // reserve allows for perigee + vertex + calo + entrancePerigee + spectrometer TSOS
1960  const unsigned int size = spectrometerTSOS.size() + 3 + caloTSOS.size() + leadingTSOS.size();
1961 
1962  auto trackStateOnSurfaces = std::make_unique<Trk::TrackStates>();
1963  trackStateOnSurfaces->reserve(size);
1964 
1965  // start with perigee TSOS (this just carries the perigee parameters)
1966 
1967  if (trackParameters && !trackParameters->covariance()) { ATH_MSG_VERBOSE(" createExtrapolatedTrack: no cov (2)"); }
1968 
1969  if (trackParameters) {
1970  if (trackParameters->surfaceType() != Trk::SurfaceType::Perigee) {
1971  ATH_MSG_DEBUG("createExtrapolatedTrack() - Track parameters are not perigee " << (*trackParameters));
1972  }
1973  trackStateOnSurfaces->push_back(Muon::MuonTSOSHelper::createPerigeeTSOS(trackParameters->uniqueClone()));
1974  }
1975 
1976  // optionally append a pseudoMeasurement describing the vertex
1977  if (vertex && trackParameters) {
1978  std::unique_ptr<Trk::PseudoMeasurementOnTrack> vertexInFit = vertexOnTrack(*trackParameters, vertex, mbeamAxis);
1979  if (vertexInFit) {
1980  ATH_MSG_VERBOSE("Adding vertex constraint ");
1981  trackStateOnSurfaces->push_back(Muon::MuonTSOSHelper::createMeasTSOS(std::move(vertexInFit), nullptr, Trk::TrackStateOnSurface::Measurement));
1982  }
1983  }
1984 
1985  // append calo TSOS
1986  for (std::unique_ptr<const Trk::TrackStateOnSurface>& c_tsos : caloTSOS) { trackStateOnSurfaces->push_back(std::move(c_tsos)); }
1987  caloTSOS.clear();
1988  // MS entrance perigee
1990  ATH_MSG_DEBUG("adding perigee at spectrometer entrance");
1991  const Trk::TrackParameters* mstrackParameters = trackStateOnSurfaces->back()->trackParameters();
1992 
1993  if (!mstrackParameters) { mstrackParameters = spectrometerTSOS.front()->trackParameters(); }
1994 
1995  if (mstrackParameters) {
1996  std::unique_ptr<Trk::TrackStateOnSurface> entranceTSOS = entrancePerigee(ctx, mstrackParameters);
1997  if (entranceTSOS) { trackStateOnSurfaces->push_back(std::move(entranceTSOS)); }
1998  }
1999  }
2000 
2001  // append leading MS material TSOS
2002  for (std::unique_ptr<const Trk::TrackStateOnSurface>& c_tsos : leadingTSOS) {
2003  if (c_tsos->materialEffectsOnTrack()) { trackStateOnSurfaces->push_back(std::move(c_tsos)); }
2004  }
2005  leadingTSOS.clear();
2006 
2007  // append the remaining spectrometer TSOS
2008  for (const auto& s : spectrometerTSOS) {
2009  if (!s->type(Trk::TrackStateOnSurface::Perigee)) {
2011  trackStateOnSurfaces->push_back(s->clone());
2012  }
2013 
2014  if (s->measurementOnTrack() && dynamic_cast<const Trk::PseudoMeasurementOnTrack*>(s->measurementOnTrack())) {
2015  ATH_MSG_VERBOSE(" MS Pseudo");
2016  }
2017  }
2018 
2019  // create track
2020  std::unique_ptr<Trk::Track> track =
2021  std::make_unique<Trk::Track>(spectrometerTrack.info(), std::move(trackStateOnSurfaces), nullptr);
2022 
2023  if (!track->perigeeParameters()) {
2024  ATH_MSG_DEBUG("Reject track without perigee.");
2025  return nullptr;
2026  }
2027  dumpCaloEloss(track.get(), " createExtrapolatedTrack ");
2028  if (msgLevel(MSG::DEBUG)) countAEOTs(*track, " createExtrapolatedTrack before fit ");
2029 
2030  // remove material when curvature badly determined (to remove energy loss uncertainty)
2031  if (particleHypothesis == Trk::nonInteracting) {
2032  ATH_MSG_VERBOSE(" remove spectrometer material ");
2034  }
2035 
2036  // fit the track
2037  ATH_MSG_VERBOSE(" fit SA track with " << track->trackStateOnSurfaces()->size() << " TSOS"
2038  << (particleHypothesis == Trk::nonInteracting ? " using nonInteracting hypothesis"
2039  : "usig interacting hypothesis"));
2040 
2041  std::unique_ptr<Trk::Track> fittedTrack{fit(ctx, *track, runOutlier, particleHypothesis)};
2042  if (fittedTrack) {
2043  if (msgLevel(MSG::DEBUG)) countAEOTs(*fittedTrack, " createExtrapolatedTrack after fit");
2044 
2045  // only accept when perigee in indet tracking volume
2046  if (fittedTrack->perigeeParameters() && !m_indetVolume->inside(fittedTrack->perigeeParameters()->position())) {
2047  ATH_MSG_DEBUG(" back extrapolation problem: fitted perigee outside indet volume ");
2048  return nullptr;
2049  }
2050 
2051  // limit momentum for future energy loss allocation
2052  if (particleHypothesis != Trk::muon) {
2053  ATH_MSG_VERBOSE(" set momentum limit ");
2054  removeSpectrometerMaterial(fittedTrack);
2055  }
2056 
2057  ATH_MSG_VERBOSE(" found track " << m_printer->print(*fittedTrack));
2058  return fittedTrack;
2059  }
2060  // return the unfitted track in case of problem
2061  return track;
2062  }
2063 
2065  const Trk::TrackStates* tsos) const {
2066  // create indet track TSOS vector
2067  auto trackStateOnSurfaces = std::make_unique<Trk::TrackStates>();
2070 
2071 
2072  // set end iterator to be the first TSOS after the indet
2073  unsigned size = 1;
2074 
2076 
2077  std::unique_ptr<Trk::TrackStateOnSurface> perigeeTSOS {(**s).clone()};
2078 
2079  ++s; // keep start perigee where-ever!
2080  for (; s != end; ++s) {
2081  ++size;
2082  if (!m_indetVolume->inside((**s).trackParameters()->position())) { break; }
2083  }
2084  end = s;
2085 
2086  trackStateOnSurfaces->reserve(size);
2087  trackStateOnSurfaces->push_back(std::move(perigeeTSOS));
2088 
2089  // then append selected TSOS
2090  appendSelectedTSOS(*trackStateOnSurfaces, begin, end);
2091 
2092  return std::make_unique<Trk::Track>(info, std::move(trackStateOnSurfaces), nullptr);
2093  }
2094 
2095  std::unique_ptr<Trk::Track> CombinedMuonTrackBuilder::createMuonTrack(const EventContext& ctx, const Trk::Track& muonTrack,
2096  const Trk::TrackParameters* parameters, std::unique_ptr<CaloEnergy> caloEnergy,
2097  const Trk::TrackStates* tsos) const{
2100  size_t size = tsos->size();
2101 
2102  if (msgLevel(MSG::DEBUG)) countAEOTs(muonTrack, " createMuonTrack ");
2103 
2104  // set iterator to current TSOS on input track to be after the indet
2105  const Trk::TrackParameters* lastIDtp = nullptr;
2107  while ((**s).trackParameters() &&
2108  (m_indetVolume->inside((**s).trackParameters()->position()) || (**s).type(Trk::TrackStateOnSurface::Perigee))) {
2109  if (m_indetVolume->inside((**s).trackParameters()->position())) { lastIDtp = (**s).trackParameters(); }
2110  ++s;
2111  --size;
2112  }
2113 
2114  // create muon track TSOS vector
2115  auto trackStateOnSurfaces = std::make_unique<Trk::TrackStates>();
2116 
2117  // redo calo association from inside if requested
2118  bool redoCaloAssoc = false;
2119  if (parameters) {
2120  redoCaloAssoc = true;
2121 
2122  // move current TSOS iterator to be outside the calorimeter
2123  while ((**s).trackParameters() &&
2124  (m_calorimeterVolume->inside((**s).trackParameters()->position()) || (**s).type(Trk::TrackStateOnSurface::Perigee))) {
2125  ++s;
2126  --size;
2127  }
2128 
2129  // associate calo by extrapolation from last ID parameters
2130  std::vector<std::unique_ptr<const Trk::TrackStateOnSurface>> caloTSOS;
2131  if (m_useCaloTG) {
2132  if (!lastIDtp) { lastIDtp = parameters; }
2133  ATH_MSG_VERBOSE(" Retriving Calorimeter TSOS from " << __func__ << " at line " << __LINE__);
2134  caloTSOS = getCaloTSOSfromMatProvider(*lastIDtp, muonTrack);
2135  } else {
2136  caloTSOS = m_caloTSOS->caloTSOS(ctx, *parameters);
2137  }
2138 
2139  if (caloTSOS.size() < 3) {
2140  ATH_MSG_DEBUG(" muonTrack: parameters fail to fully intersect the calorimeter");
2141  return nullptr;
2142  }
2143 
2144  size += caloTSOS.size();
2145  trackStateOnSurfaces->reserve(size + 1);
2146 
2147  // start with the calo TSOS
2148  for (std::unique_ptr<const Trk::TrackStateOnSurface>& c_tsos : caloTSOS) { trackStateOnSurfaces->push_back(std::move(c_tsos)); }
2149 
2150  } else {
2151  trackStateOnSurfaces->reserve(size + 1);
2152  }
2153 
2154  // if requested, replace caloEnergy on appropriate TSOS
2156  if (caloEnergy && (**s).trackParameters() && m_calorimeterVolume->inside((**s).trackParameters()->position())) {
2157  const Trk::TrackStateOnSurface* TSOS = (**s).clone();
2158  trackStateOnSurfaces->push_back(TSOS);
2159  ++s;
2160 
2161  // create MEOT owning CaloEnergy
2162  if ((**s).trackParameters() && m_calorimeterVolume->inside((**s).trackParameters()->position())) {
2163  std::bitset<Trk::MaterialEffectsBase::NumberOfMaterialEffectsTypes> typePattern;
2165 
2166  std::unique_ptr<Trk::MaterialEffectsOnTrack> materialEffects =
2167  std::make_unique<Trk::MaterialEffectsOnTrack>(0., std::move(caloEnergy), (**s).trackParameters()->associatedSurface(), typePattern);
2168 
2169  // create TSOS
2170 
2171  std::bitset<Trk::TrackStateOnSurface::NumberOfTrackStateOnSurfaceTypes> type;
2173 
2174  TSOS = new Trk::TrackStateOnSurface(nullptr, (**s).trackParameters()->uniqueClone(),std::move(materialEffects), type);
2175  trackStateOnSurfaces->push_back(TSOS);
2176  ++s;
2177  } else {
2178  // should never happen: FSR caloEnergy delete
2179  m_messageHelper->printWarning(37);
2180  }
2181  }
2182 
2183  // MS entrance perigee
2184  bool hasAlreadyPerigee = false;
2186  // copy calorimeter TSOS
2187  while ((**s).trackParameters() && m_calorimeterVolume->inside((**s).trackParameters()->position())) {
2188  if (!(**s).type(Trk::TrackStateOnSurface::Perigee)) {
2189  const Trk::TrackStateOnSurface* TSOS = (**s).clone();
2190  trackStateOnSurfaces->push_back(TSOS);
2191  }
2192  ++s;
2193  }
2194 
2195  // add entrance TSOS if not already present
2196  std::unique_ptr<Trk::TrackStateOnSurface> entranceTSOS;
2197 
2198  if ((**s).type(Trk::TrackStateOnSurface::Perigee)) { hasAlreadyPerigee = true; }
2199 
2200  if (!hasAlreadyPerigee) {
2201  if ((**s).trackParameters()) {
2202  entranceTSOS = entrancePerigee(ctx, (**s).trackParameters());
2203  } else {
2204  entranceTSOS = entrancePerigee(ctx, trackStateOnSurfaces->back()->trackParameters());
2205  }
2206  if (entranceTSOS) {
2207  double distance = (entranceTSOS->trackParameters()->position() - (**s).trackParameters()->position()).mag();
2208 
2209  if (distance > 2000) {
2210  ATH_MSG_DEBUG(" Added Muon Entrance "
2211  << " r " << entranceTSOS->trackParameters()->position().perp() << " z "
2212  << entranceTSOS->trackParameters()->position().z() << " track pars r "
2213  << (**s).trackParameters()->position().perp() << " z " << (**s).trackParameters()->position().z());
2214  }
2215  trackStateOnSurfaces->push_back(std::move(entranceTSOS));
2216  hasAlreadyPerigee = true;
2217  }
2218  }
2219  }
2220 
2221 
2222  // then append selected TSOS from the extrapolated or spectrometer track
2223  appendSelectedTSOS(*trackStateOnSurfaces, s, end);
2225  if (!hasAlreadyPerigee && std::find_if(trackStateOnSurfaces->begin(), trackStateOnSurfaces->end(),
2226  [] (const Trk::TrackStateOnSurface* tsos){
2227  return tsos->type(Trk::TrackStateOnSurface::Perigee);
2228  }) == trackStateOnSurfaces->end() && muonTrack.perigeeParameters() ){
2229  trackStateOnSurfaces->push_back( Muon::MuonTSOSHelper::createPerigeeTSOS(muonTrack.perigeeParameters()->uniqueClone()));
2231  std::stable_sort(trackStateOnSurfaces->begin(),trackStateOnSurfaces->end(),
2233  return a->type(Trk::TrackStateOnSurface::Perigee) > b->type(Trk::TrackStateOnSurface::Perigee);
2234  });
2235  ATH_MSG_DEBUG(__FILE__<<":"<<__LINE__<<" No track perigee parameters were added. Copy the existing ones from the muon track");
2236  }
2237  std::unique_ptr<Trk::Track> newMuonTrack = std::make_unique<Trk::Track>(muonTrack.info(), std::move(trackStateOnSurfaces), nullptr);
2238  unsigned int num_ms{0}, num_precMS{0};
2239  for (const Trk::MeasurementBase* meas : *newMuonTrack->measurementsOnTrack()) {
2240  const Trk::RIO_OnTrack* rio = dynamic_cast<const Trk::RIO_OnTrack*>(meas);
2241  if (!rio || !m_idHelperSvc->isMuon(rio->identify())) continue;
2242  ++num_ms;
2243  num_precMS += !m_idHelperSvc->measuresPhi(rio->identify());
2244  }
2245  if (num_precMS < 3 || num_ms < 5) {
2246  ATH_MSG_VERBOSE(__FILE__":"<<__LINE__<<" MS track with too few meausrements constructed "<<std::endl<<
2247  m_printer->print(newMuonTrack->measurementsOnTrack()->stdcont()) );
2248  return nullptr;
2249  }
2250  // Updates the calo TSOS with the ones from TG+corrections (if needed)
2251  if (m_updateWithCaloTG && !m_useCaloTG && redoCaloAssoc) {
2252  ATH_MSG_VERBOSE("Updating Calorimeter TSOS in CreateMuonTrack ...");
2253  m_materialUpdator->updateCaloTSOS(*newMuonTrack, parameters);
2254  }
2255 
2256  return newMuonTrack;
2257  }
2258 
2259  std::unique_ptr<Trk::TrackStateOnSurface> CombinedMuonTrackBuilder::createPhiPseudoMeasurement(const EventContext& ctx,
2260  const Trk::Track& track) const {
2261  auto parameters = m_trackQuery->spectrometerParameters(track, ctx);
2262  Amg::MatrixX covarianceMatrix(1, 1);
2263  covarianceMatrix.setZero();
2264  covarianceMatrix(0, 0) = s_sigmaPhiSector * s_sigmaPhiSector * parameters->position().perp2();
2265 
2266  std::unique_ptr<Trk::PseudoMeasurementOnTrack> pseudo = std::make_unique<Trk::PseudoMeasurementOnTrack>(
2268  std::move(covarianceMatrix),
2269  parameters->associatedSurface());
2270 
2272  }
2273 
2274  std::vector<std::unique_ptr<const Trk::TrackStateOnSurface>> CombinedMuonTrackBuilder::createSpectrometerTSOS(const EventContext& ctx,
2275  const Trk::Track& spectrometerTrack) const {
2276  const Trk::Perigee* measuredPerigee = spectrometerTrack.perigeeParameters();
2277  std::vector<std::unique_ptr<const Trk::TrackStateOnSurface>> spectrometerTSOS;
2278 
2279  if (!measuredPerigee || !measuredPerigee->covariance() || !Amg::hasPositiveDiagElems(*measuredPerigee->covariance())) {
2280  // missing MeasuredPerigee for spectrometer track
2281  if (!measuredPerigee)
2282  m_messageHelper->printWarning(38);
2283  else if (!measuredPerigee->covariance())
2284  m_messageHelper->printWarning(38);
2285  else
2286  ATH_MSG_DEBUG("createSpectrometerTSOS::perigee covariance not valid");
2287  return spectrometerTSOS;
2288  }
2289 
2290  double errorPhi = std::sqrt((*measuredPerigee->covariance())(Trk::phi0, Trk::phi0));
2291 
2292  // create the spectrometer TSOS's for the extrapolated fit
2293  spectrometerTSOS.reserve(spectrometerTrack.trackStateOnSurfaces()->size());
2294 
2295  // start with a 'phi sector constraint' pseudomeasurement when necessary
2296  unsigned numberPseudo = m_trackQuery->numberPseudoMeasurements(spectrometerTrack);
2297  if (errorPhi > s_sigmaPhiSector) { ++numberPseudo; }
2298 
2299  if (numberPseudo > 1 && !m_trackQuery->isSectorOverlap(spectrometerTrack)) {
2300  ATH_MSG_VERBOSE("standaloneFit: add pseudo to constrain phi sector");
2301 
2302  std::unique_ptr<Trk::TrackStateOnSurface> tsos = {createPhiPseudoMeasurement(ctx, spectrometerTrack)};
2303  if (tsos) { spectrometerTSOS.emplace_back(std::move(tsos)); }
2304  }
2305 
2306  // make a measurement selection to fixup non-standard TSOS's
2307  double deltaZ = 0.;
2308  bool haveMeasurement = false;
2309 
2310  std::vector<const Trk::Surface*> measurementSurfaces;
2311  measurementSurfaces.reserve(spectrometerTrack.trackStateOnSurfaces()->size());
2312 
2313  unsigned numberMaterial{0}, numberParameters{0};
2314 
2315  const Trk::Surface* previousSurface = nullptr;
2316  std::unique_ptr<const Trk::TrackStateOnSurface> previousTSOS;
2317 
2318  for (const Trk::TrackStateOnSurface* s : *spectrometerTrack.trackStateOnSurfaces()) {
2319  // skip any leading material
2320  if (!haveMeasurement) {
2321  if (s->measurementOnTrack()) {
2322  haveMeasurement = true;
2323  } else if (s->materialEffectsOnTrack()) {
2324  continue;
2325  }
2326  }
2327 
2328  // input statistics for VERBOSE
2329  const Trk::TrackParameters* trackParameters = s->trackParameters();
2330  if (msgLvl(MSG::VERBOSE)) {
2331  if (s->materialEffectsOnTrack()) ++numberMaterial;
2332  if (trackParameters) ++numberParameters;
2333  }
2334 
2335  // skip unwanted TSOS and non-understood features in iPatFitter
2336  if (!s->measurementOnTrack() && !s->materialEffectsOnTrack()) {
2337  // remove holes as they will be reallocated
2338  if (s->type(Trk::TrackStateOnSurface::Hole)) continue;
2339 
2340  // same for MS perigee
2341  if (s->type(Trk::TrackStateOnSurface::Perigee)) continue;
2342 
2343  if (s->trackParameters()) {
2344  ATH_MSG_DEBUG("createSpectrometerTSOS:: skip unrecognized TSOS " << s->dumpType() << " r "
2345  << s->trackParameters()->position().perp() << " z "
2346  << s->trackParameters()->position().z());
2347  } else {
2348  // skip unrecognized TSOS without TrackParameters
2349  m_messageHelper->printWarning(39, s->dumpType());
2350  }
2351  continue;
2352  }
2353 
2354  // several checks applied to measurements:
2355  bool trapezoid = false;
2356  bool rotatedTrap = false;
2357  if (s->measurementOnTrack()) {
2358  // skip pseudo
2359  if (dynamic_cast<const Trk::PseudoMeasurementOnTrack*>(s->measurementOnTrack())) {
2360  continue;
2361  }
2362  // careful with trapezoid ordering (put trapezoid before
2363  // rotatedTrapezoid)
2364  const Trk::Surface* surface = &s->measurementOnTrack()->associatedSurface();
2365 
2366  if (previousSurface) { deltaZ = std::abs(previousSurface->center().z() - surface->center().z()); }
2367 
2368  if (dynamic_cast<const Trk::PlaneSurface*>(surface)) {
2369  if (dynamic_cast<const Trk::TrapezoidBounds*>(&surface->bounds())) {
2370  trapezoid = true;
2371  } else if (dynamic_cast<const Trk::RotatedTrapezoidBounds*>(&surface->bounds())) {
2372  rotatedTrap = true;
2373  }
2374  }
2375 
2376  // skip duplicate measurements on same surface
2377  if (previousSurface &&
2378  std::find(measurementSurfaces.begin(), measurementSurfaces.end(), surface) != measurementSurfaces.end()) {
2379  // skip duplicate measurement
2380  m_messageHelper->printWarning(40, m_idHelperSvc->toString(m_edmHelperSvc->getIdentifier(*(s->measurementOnTrack()))));
2381  continue;
2382  }
2383  measurementSurfaces.push_back(surface);
2384  previousSurface = surface;
2385 
2386  } else if (previousTSOS) {
2387  spectrometerTSOS.emplace_back(std::move(previousTSOS));
2388  }
2389 
2390  // trapezoid precedes rotatedTrapezoid
2391  std::unique_ptr<const Trk::TrackStateOnSurface> TSOS(s->clone());
2392  //cppcheck-suppress accessMoved
2393  if (previousTSOS) {
2394  if (trapezoid && deltaZ < 1. * Gaudi::Units::mm) {
2395  spectrometerTSOS.emplace_back(std::move(TSOS));
2396  TSOS = std::move(previousTSOS);
2397  } else {
2398  spectrometerTSOS.emplace_back(std::move(previousTSOS));
2399  }
2400  }
2401 
2402  if (rotatedTrap) {
2403  previousTSOS.swap(TSOS);
2404  continue;
2405  }
2406 
2407  spectrometerTSOS.emplace_back(std::move(TSOS));
2408  }
2409 
2410  if (previousTSOS) spectrometerTSOS.emplace_back(std::move(previousTSOS));
2411 
2412  ATH_MSG_VERBOSE(" input spectrometer track with " << spectrometerTrack.trackStateOnSurfaces()->size() << " TSOS, of which "
2413  << numberMaterial << " have MaterialEffects and " << numberParameters
2414  << " have TrackParameters");
2415 
2416  return spectrometerTSOS;
2417  }
2418 
2419  std::unique_ptr<Trk::TrackStateOnSurface> CombinedMuonTrackBuilder::entrancePerigee(const EventContext& ctx, const Trk::TrackParameters* parameters) const {
2420  // make sure the spectrometer entrance volume is available
2421  if (!parameters) return nullptr;
2422  const Trk::TrackingVolume* spectrometerEntrance = getVolume(ctx, "MuonSpectrometerEntrance");
2423  if (!spectrometerEntrance) return nullptr;
2424 
2425  std::unique_ptr<Trk::TrackParameters> entranceParameters{
2426  m_extrapolator->extrapolateToVolume(ctx, *parameters, *spectrometerEntrance, Trk::anyDirection, Trk::nonInteracting)};
2427 
2428  if (!entranceParameters) return nullptr;
2429 
2430  Trk::PerigeeSurface surface(entranceParameters->position());
2431  std::unique_ptr<Trk::TrackParameters> trackParameters{m_extrapolator->extrapolateDirectly(ctx, *entranceParameters, surface)};
2432 
2433  if (!trackParameters) return nullptr;
2434 
2435  std::unique_ptr<Trk::Perigee> perigee =
2436  std::make_unique<Trk::Perigee>(trackParameters->position(), trackParameters->momentum(), trackParameters->charge(), std::move(surface));
2437  return std::unique_ptr<Trk::TrackStateOnSurface>(Muon::MuonTSOSHelper::createPerigeeTSOS(std::move(perigee)));
2438  }
2439 
2440  std::unique_ptr<Trk::TrackParameters> CombinedMuonTrackBuilder::extrapolatedParameters(
2441  const EventContext& ctx, bool& badlyDeterminedCurvature, const Trk::Track& spectrometerTrack, const Trk::RecVertex* mvertex,
2442  const Trk::PerigeeSurface* mperigeeSurface) const {
2443  badlyDeterminedCurvature = false;
2444  const Trk::Perigee* measuredPerigee = spectrometerTrack.perigeeParameters();
2445 
2446  if (!measuredPerigee || !measuredPerigee->covariance()) {
2447  // missing MeasuredPerigee for spectrometer track
2448  m_messageHelper->printWarning(42);
2449  return nullptr;
2450  }
2451 
2452  // set starting parameters and measured momentum error
2453  auto parameters = m_trackQuery->spectrometerParameters(spectrometerTrack, ctx);
2454  if (!parameters || !parameters->covariance()) {
2455  // missing spectrometer parameters on spectrometer track
2456  m_messageHelper->printWarning(43);
2457  return nullptr;
2458  }
2459 
2460  double errorP = std::sqrt(measuredPerigee->momentum().mag2() * (*measuredPerigee->covariance())(Trk::qOverP, Trk::qOverP));
2461 
2462  // corrected parameters ensure the track fitting starts with a projective approximation
2463  std::unique_ptr<Trk::TrackParameters> correctedParameters{};
2464  Amg::VectorX parameterVector = parameters->parameters();
2465  double trackEnergy = 1. / std::abs(parameterVector[Trk::qOverP]);
2466 
2467  // careful: need to reset parameters to have a sensible energy if starting from a lineFit
2468  if (m_trackQuery->isLineFit(spectrometerTrack)) {
2469  trackEnergy = m_lineMomentum;
2470  parameterVector[Trk::qOverP] = parameters->charge() / trackEnergy;
2471 
2472  parameters = parameters->associatedSurface().createUniqueTrackParameters(
2473  parameterVector[Trk::loc1], parameterVector[Trk::loc2], parameterVector[Trk::phi], parameterVector[Trk::theta],
2474  parameterVector[Trk::qOverP], AmgSymMatrix(5)(*parameters->covariance()));
2475  }
2476 
2477  // check if the track curvature is well determined (with sufficient energy to penetrate material)
2478  // (i.e. field off or small momentum error, starting parameters upstream of endcap toroid)
2479  bool curvatureOK = false;
2480 
2481  const Trk::IPropagator* propagator = m_propagator.get();
2482  MagField::AtlasFieldCache fieldCache;
2483  // Get field cache object
2484  if (!loadMagneticField(ctx, fieldCache)) return nullptr;
2485  if (!fieldCache.toroidOn()) {
2486  curvatureOK = true;
2487  propagator = m_propagatorSL.get();
2488  } else if (std::abs(parameters->position().z()) < m_zECToroid &&
2489  (!m_trackQuery->isLineFit(spectrometerTrack) && errorP < m_largeMomentumError)) {
2490  curvatureOK = true;
2491  }
2492 
2493  if (curvatureOK) {
2494  // TDDO Run2 Calo TG
2495  // energy loss correction
2496  std::unique_ptr<CaloEnergy> caloEnergy{
2497  m_caloEnergyParam->energyLoss(ctx, trackEnergy, parameters->position().eta(), parameters->position().phi())};
2498 
2499  if (trackEnergy + caloEnergy->deltaE() < m_minEnergy) {
2500  ATH_MSG_DEBUG("standaloneFit: trapped in calorimeter");
2501  return nullptr;
2502  }
2503 
2504  parameterVector[Trk::qOverP] = parameters->charge() / (trackEnergy + caloEnergy->deltaE());
2505  correctedParameters = parameters->associatedSurface().createUniqueTrackParameters(
2506  parameterVector[Trk::loc1], parameterVector[Trk::loc2], parameterVector[Trk::phi], parameterVector[Trk::theta],
2507  parameterVector[Trk::qOverP], AmgSymMatrix(5)(*parameters->covariance()));
2508 
2509  // protect against spectrometer track with unrealistic energy loss
2510  // check material in spectrometer is not vastly greater than in the calo
2511  // (there are some very dense spectrometer regions)
2512  double spectrometerEnergyLoss = 0.;
2513 
2515  Trk::TrackStates::const_iterator sEnd = spectrometerTrack.trackStateOnSurfaces()->end();
2516  for (; s != sEnd; ++s) {
2517  if (!(**s).materialEffectsOnTrack()) { continue; }
2518 
2519  const Trk::MaterialEffectsOnTrack* meot = dynamic_cast<const Trk::MaterialEffectsOnTrack*>((**s).materialEffectsOnTrack());
2520 
2521  if (meot && meot->energyLoss()) { spectrometerEnergyLoss += meot->energyLoss()->deltaE(); }
2522  }
2523 
2524  if (std::abs(spectrometerEnergyLoss) > 1.5 * std::abs(caloEnergy->deltaE())) {
2525  curvatureOK = false;
2526  ATH_MSG_DEBUG("standaloneFit: excessive energy loss in spectrometer "
2527  << std::abs(spectrometerEnergyLoss / Gaudi::Units::GeV) << " GeV"
2528  << " in calo " << std::abs(caloEnergy->deltaE() / Gaudi::Units::GeV) << " GeV");
2529  }
2530  }
2531 
2532  // check perigee in indet volume when the curvature is well determined
2533  // otherwise will assume projectivity for starting parameters
2534  if (curvatureOK) {
2535  std::unique_ptr<Trk::TrackParameters> perigee{propagator->propagate(
2536  ctx, *correctedParameters, *mperigeeSurface, Trk::oppositeMomentum, false, m_magFieldProperties, Trk::nonInteracting)};
2537 
2538  if (!perigee) {
2539  ATH_MSG_DEBUG("standaloneFit: failed back extrapolation to perigee");
2540  return nullptr;
2541  }
2542 
2543  // large impact: set phi to be projective (note iteration)
2544  if (std::abs(perigee->parameters()[Trk::d0]) < m_largeImpact || !fieldCache.toroidOn()) {
2545  ATH_MSG_DEBUG("Track d0 perigee: " << std::abs(perigee->parameters()[Trk::d0]) << " which is smaller than "
2546  << m_largeImpact);
2547  } else {
2548  Amg::Vector3D position = correctedParameters->position();
2549 
2550  double deltaPhi = 0.;
2551  double deltaR = (position - perigee->position()).perp();
2552 
2553  if (std::abs(deltaR * M_PI) > std::abs(perigee->parameters()[Trk::d0])) {
2554  deltaPhi = perigee->parameters()[Trk::d0] / deltaR;
2555  }
2556 
2557  ATH_MSG_DEBUG("standaloneFit: large perigee impact " << perigee->parameters()[Trk::d0] << " deltaR, deltaPhi " << deltaR
2558  << ", " << deltaPhi);
2559 
2560  parameterVector[Trk::phi0] += deltaPhi;
2561 
2562  if (parameterVector[Trk::phi0] > M_PI) {
2563  parameterVector[Trk::phi0] -= 2. * M_PI;
2564  } else if (parameterVector[Trk::phi0] < -M_PI) {
2565  parameterVector[Trk::phi0] += 2. * M_PI;
2566  }
2567 
2568  correctedParameters = parameters->associatedSurface().createUniqueTrackParameters(
2569  parameterVector[Trk::loc1], parameterVector[Trk::loc2], parameterVector[Trk::phi], parameterVector[Trk::theta],
2570  parameterVector[Trk::qOverP], AmgSymMatrix(5)(*parameters->covariance()));
2571 
2572  perigee = propagator->propagate(ctx, *correctedParameters, *mperigeeSurface, Trk::oppositeMomentum, false,
2574 
2575  if (perigee) {
2576  deltaPhi = 0.;
2577  deltaR = (position - perigee->position()).perp();
2578 
2579  if (std::abs(deltaR * M_PI) > std::abs(perigee->parameters()[Trk::d0])) {
2580  deltaPhi = perigee->parameters()[Trk::d0] / deltaR;
2581  }
2582 
2583  ATH_MSG_VERBOSE("standaloneFit: corrected perigee impact " << perigee->parameters()[Trk::d0] << " deltaR, deltaPhi "
2584  << deltaR << ", " << deltaPhi);
2585 
2586  parameterVector[Trk::phi0] += deltaPhi;
2587  if (parameterVector[Trk::phi0] > M_PI) {
2588  parameterVector[Trk::phi0] -= 2. * M_PI;
2589  } else if (parameterVector[Trk::phi0] < -M_PI) {
2590  parameterVector[Trk::phi0] += 2. * M_PI;
2591  }
2592  correctedParameters = parameters->associatedSurface().createUniqueTrackParameters(
2593  parameterVector[Trk::loc1], parameterVector[Trk::loc2], parameterVector[Trk::phi], parameterVector[Trk::theta],
2594  parameterVector[Trk::qOverP], AmgSymMatrix(5)(*parameters->covariance()));
2595 
2596  perigee = propagator->propagate(ctx, *correctedParameters, *mperigeeSurface, Trk::oppositeMomentum, false,
2598  }
2599 
2600  if (perigee) {
2601  ATH_MSG_VERBOSE("standaloneFit: restart with impact " << perigee->parameters()[Trk::d0] << " phi0 "
2602  << perigee->parameters()[Trk::phi0]);
2603  }
2604  parameterVector[Trk::qOverP] = parameters->charge() / trackEnergy;
2605  correctedParameters = parameters->associatedSurface().createUniqueTrackParameters(
2606  parameterVector[Trk::loc1], parameterVector[Trk::loc2], parameterVector[Trk::phi], parameterVector[Trk::theta],
2607  parameterVector[Trk::qOverP], AmgSymMatrix(5)(*parameters->covariance()));
2608 
2609  parameters = std::move(correctedParameters);
2610  }
2611 
2612  // cut if perigee outside indet (but keep endcap halo)
2613  if (!perigee || !m_indetVolume->inside(perigee->position())) {
2614  if (perigee && perigee->position().z() * perigee->momentum().z() < 0. && perigee->momentum().eta() > 2.0) {
2615  ATH_MSG_DEBUG("standaloneFit: halo candidate, perigee at R " << perigee->position().perp() << " Z "
2616  << perigee->position().z());
2617  } else {
2618  ATH_MSG_DEBUG("standaloneFit: perigee outside indet volume");
2620  return nullptr;
2621  }
2622  }
2623  } else {
2624  // otherwise track out from origin (fix bug #54820)
2625  badlyDeterminedCurvature = true;
2626  Amg::Vector3D momentum = parameters->position().unit() * Gaudi::Units::TeV;
2627 
2628  std::unique_ptr<const Trk::TrackParameters> trigParameters{m_trackQuery->triggerStationParameters(spectrometerTrack, ctx)};
2629 
2630  if (trigParameters) { momentum = trigParameters->position().unit() * Gaudi::Units::TeV; }
2631 
2632  if (msgLvl(MSG::VERBOSE)) {
2633  if (trigParameters) {
2634  ATH_MSG_VERBOSE("standaloneFit: imprecise curvature measurement -"
2635  << " start with line from origin to 1st trigger station ");
2636  } else {
2637  ATH_MSG_VERBOSE("standaloneFit: imprecise curvature measurement -"
2638  << " start with line from origin to 1st measurement ");
2639  }
2640  }
2641 
2642  std::unique_ptr<Trk::TrackParameters> perigee =
2643  std::make_unique<Trk::Perigee>(mvertex->position(), momentum, 1., *mperigeeSurface);
2644 
2645  parameters = m_propagator->propagate(ctx, *perigee, perigee->associatedSurface(), Trk::alongMomentum, false,
2647 
2648  if (!parameters) {
2649  ATH_MSG_DEBUG("standaloneFit: failed back extrapolation to perigee");
2650  return nullptr;
2651  }
2652  }
2653 
2654  return parameters;
2655  }
2656 
2657  void CombinedMuonTrackBuilder::finalTrackBuild(const EventContext& ctx, std::unique_ptr<Trk::Track>& track) const {
2658  // as a final step:
2659  // refit the track if any holes can be recovered,
2660  // refit with optimization of the spectrometer hit errors,
2661  // add the corresponding TrackSummary to the track
2662  if (msgLevel(MSG::DEBUG)) countAEOTs(*track, " finalTrackBuilt input ");
2663  if (!m_muonHoleRecovery.empty()) {
2664  // chi2 before recovery
2665  double chi2Before = normalizedChi2(*track);
2666 
2667  ATH_MSG_VERBOSE(" perform spectrometer hole recovery procedure... ");
2668 
2669  std::unique_ptr<Trk::Track> recoveredTrack{m_muonHoleRecovery->recover(*track, ctx)};
2670 
2671  // if (!checkTrack("finalTrackBuild1", recoveredTrack.get())) {
2672  // final track lost, this should not happen
2673  // m_messageHelper->printWarning(44);
2674  // As discussed in ATLASRECTS-7603, we want to suppress this until we can work on it
2675  // Keeping it here so we don't forget.
2676  // FIXME!
2677 
2678  if (checkTrack("finalTrackBuild1", recoveredTrack.get())) {
2679  double chi2After = normalizedChi2(*recoveredTrack);
2680  if (chi2After < m_badFitChi2 || chi2After < chi2Before + 0.1) {
2681  track.swap(recoveredTrack);
2682  } else {
2683  ATH_MSG_VERBOSE(" track rejected by recovery as chi2 " << chi2After << " compared to " << chi2Before);
2684 
2685  if (chi2Before > m_badFitChi2) {
2686  track.reset();
2687  return;
2688  }
2689  }
2690  }
2691  ATH_MSG_VERBOSE(" finished hole recovery procedure ");
2692  }
2693  /*
2694  * DO NOT REMOVE THIS CODE BLOCK AS IT WILL BE NEEDED IN A FUTURE MR!
2695  if (!m_muonHoleRecovery.empty()) {
2696  ATH_MSG_VERBOSE(" perform spectrometer hole recovery procedure... ");
2697  using MSTrackRecovery = Muon::IMuonHoleRecoveryTool::MSTrackRecovery;
2698  MSTrackRecovery recoverResult{};
2699  constexpr unsigned int max_itr = 3;
2700  unsigned int num_itr{0};
2701  do {
2702  const double chi2Before = normalizedChi2(*track);
2703  recoverResult = m_muonHoleRecovery->recover(ctx,*track);
2704  if (!recoverResult.track) {
2705  ATH_MSG_WARNING(__FILE__<<":"<<__LINE__<<" track got lost during hole recovery. That should not happen");
2706  break;
2707  }
2708  if (!checkTrack("holeRecovery", recoverResult.track.get())){
2709  m_messageHelper->printWarning(44);
2710  break;
2711  }
2712  if (recoverResult.new_meas) {
2713  recoverResult.track = fit(ctx, *recoverResult.track, true, Trk::muon);
2714  if (!recoverResult.track) {
2715  ATH_MSG_VERBOSE(__FILE__<<":"<<__LINE__<<" track got lost during refit of recovery.");
2716  break;
2717  }
2718  const double chi2After = normalizedChi2(*recoverResult.track);
2719  if (chi2After < chi2Before) {
2720  track.swap(recoverResult.track);
2721  ATH_MSG_VERBOSE("Recovered track has better quality... old chi2:"<<chi2Before<<". New chi2: "<<chi2After
2722  <<std::endl<<m_printer->printMeasurements(*recoverResult.track)<<std::endl
2723  <<std::endl<<m_printer->printMeasurements(*track));
2724  } else break;
2725  } else {
2726  track.swap(recoverResult.track);
2727  }
2728  } while(recoverResult.new_meas && (++num_itr) <= max_itr);
2729  ATH_MSG_VERBOSE(" finished hole recovery procedure ");
2730  }
2731  */
2732  // final fit with optimized spectrometer errors
2733  if (!m_muonErrorOptimizer.empty() && !track->info().trackProperties(Trk::TrackInfo::StraightTrack) &&
2734  countAEOTs(*track, " before optimize ") == 0) {
2735  ATH_MSG_VERBOSE(" perform spectrometer error optimization... ");
2736  std::unique_ptr<Trk::Track> optimizedTrack = m_muonErrorOptimizer->optimiseErrors(*track, ctx);
2737  if (checkTrack("finalTrackBuild2", optimizedTrack.get())) {
2738  track.swap(optimizedTrack);
2739  if (msgLevel(MSG::DEBUG)) countAEOTs(*track, " finalTrackBuilt alignment errors Track ");
2740  }
2741  }
2742 
2743  // add the track summary
2744  m_trackSummary->updateTrack(ctx, *track);
2745  }
2746  void CombinedMuonTrackBuilder::momentumUpdate(std::unique_ptr<Trk::TrackParameters>& parameters, double updatedP,
2747  bool directionUpdate, double deltaPhi, double deltaTheta) const {
2748  if (!parameters) return;
2749 
2750  std::unique_ptr<Trk::TrackParameters> updatedParameters;
2751 
2752  // update for angle change
2753  Amg::Vector3D direction = parameters->momentum().unit();
2754 
2755  if (directionUpdate) {
2756  double cosDeltaPhi = 0.;
2757  double sinDeltaPhi = std::sin(deltaPhi);
2758 
2759  if (std::abs(sinDeltaPhi) < 1.) { cosDeltaPhi = std::sqrt(1. - sinDeltaPhi * sinDeltaPhi); }
2760 
2761  double cosDeltaTheta = 0.;
2762  double sinDeltaTheta = std::sin(deltaTheta);
2763 
2764  if (std::abs(sinDeltaTheta) < 1.) { cosDeltaTheta = std::sqrt(1. - sinDeltaTheta * sinDeltaTheta); }
2765 
2766  double cosTheta = direction.z() * cosDeltaTheta - direction.perp() * sinDeltaTheta;
2767  if (std::abs(cosTheta) < 1.) {
2768  direction = Amg::Vector3D(direction.x() * cosDeltaPhi - direction.y() * sinDeltaPhi,
2769  direction.y() * cosDeltaPhi + direction.x() * sinDeltaPhi,
2770  direction.perp() * cosTheta / std::sqrt(1. - cosTheta * cosTheta));
2771 
2772  } else {
2773  direction = Amg::Vector3D(0., 0., cosTheta);
2774  }
2775  direction = direction.unit();
2776  }
2777 
2778  // update for momentum (magnitude) change
2779  Amg::Vector3D momentum = updatedP * direction;
2780 
2781  // create updated parameters
2782  double charge = parameters->charge();
2783  Amg::Vector3D position = parameters->position();
2784  std::optional<AmgSymMatrix(5)> covariance =
2785  parameters->covariance() ? std::optional<AmgSymMatrix(5)>(*(parameters->covariance())) : std::nullopt;
2786  const Trk::Surface* surface = &(parameters->associatedSurface());
2787  updatedParameters = surface->createUniqueTrackParameters(position, momentum, charge, covariance);
2788 
2789  if (updatedParameters) {
2790  parameters = std::move(updatedParameters);
2791  } else {
2792  // update failed, keeping original value
2793  m_messageHelper->printWarning(45);
2794  }
2795  }
2796  std::unique_ptr<Trk::Track> CombinedMuonTrackBuilder::reallocateMaterial(const EventContext& ctx,
2797  const Trk::Track& spectrometerTrack) const {
2798  // build MeasurementSet for the spectrometer
2799  const Trk::TrackParameters* perigeeStartValue = nullptr;
2800  double perigeeDistance = 0.;
2801 
2802  Trk::MeasurementSet spectrometerMeasurements;
2803 
2805  auto sEnd = spectrometerTrack.trackStateOnSurfaces()->end();
2806  for (; s != sEnd; ++s) {
2807  if ((**s).measurementOnTrack() && !(**s).type(Trk::TrackStateOnSurface::Outlier)) {
2808  // skip pseudo measurement(s)
2809  // FIXME - need phi pseudo in some cases
2810  if (dynamic_cast<const Trk::PseudoMeasurementOnTrack*>((**s).measurementOnTrack())) { continue; }
2811 
2812  spectrometerMeasurements.push_back((**s).measurementOnTrack()->clone());
2813  if (!(**s).trackParameters() || (perigeeStartValue && (**s).trackParameters()->position().mag() > perigeeDistance)) {
2814  continue;
2815  }
2816 
2817  perigeeDistance = (**s).trackParameters()->position().mag();
2818  perigeeStartValue = (**s).trackParameters();
2819  }
2820  }
2821 
2822  // check perigeeStartValue defined
2823  if (!perigeeStartValue) {
2824  // FIXME: use spectrometerTrack.perigeeParameters()
2825  // null perigeeStartValue
2826  m_messageHelper->printWarning(46);
2827  return nullptr;
2828  }
2829 
2830  // fit with various recovery strategies
2831  std::unique_ptr<Trk::Track> spectrometerFit = fit(ctx, spectrometerMeasurements, *perigeeStartValue, true, Trk::muon);
2832  if (!spectrometerFit) {
2833  spectrometerFit = fit(ctx, spectrometerMeasurements, *perigeeStartValue, false, Trk::muon);
2834 
2835  if (!spectrometerFit) {
2836  spectrometerFit = fit(ctx, spectrometerMeasurements, *perigeeStartValue, false, Trk::nonInteracting);
2837 
2838  if (!spectrometerFit) {
2839  // spectrometer refit fails
2840  m_messageHelper->printWarning(47);
2841  }
2842  }
2843  }
2844 
2845  if (spectrometerFit) { spectrometerFit->info().addPatternReco(spectrometerTrack.info()); }
2846 
2847  Trk::MeasurementSet::iterator m = spectrometerMeasurements.begin();
2848  auto mEnd = spectrometerMeasurements.end();
2849  for (; m != mEnd; ++m) { delete *m; }
2850 
2851  return spectrometerFit;
2852  }
2853 
2854  void CombinedMuonTrackBuilder::removeSpectrometerMaterial(std::unique_ptr<Trk::Track>& track) const {
2855  // limit momentum to avoid refit allocating excessive energy loss
2856  bool limitMomentum = false;
2857  double momentum = track->perigeeParameters()->momentum().mag();
2858  double qOverP = 0.;
2859 
2860  if (momentum > m_lowMomentum) {
2861  const Trk::Perigee* measuredPerigee = track->perigeeParameters();
2862 
2863  if (measuredPerigee) {
2864  Trk::TrackStates::const_reverse_iterator r = track->trackStateOnSurfaces()->rbegin();
2865 
2866  while (!(**r).trackParameters()) { --r; }
2867 
2868  limitMomentum = true;
2869 
2870  if (!measuredPerigee->covariance()) {
2871  ATH_MSG_DEBUG("measuredPerigee has no covariance, qOverP not set");
2872  qOverP = (**r).trackParameters()->parameters()[Trk::qOverP];
2873  } else {
2874  qOverP = (**r).trackParameters()->parameters()[Trk::qOverP] +
2875  measuredPerigee->charge() * std::sqrt((*measuredPerigee->covariance())(Trk::qOverP, Trk::qOverP));
2876 
2877  ATH_MSG_DEBUG(" limit momentum to " << 1. / std::abs(qOverP * Gaudi::Units::GeV) << " from original value "
2879  }
2880  }
2881  }
2882 
2883  // remove spectrometer material from track
2884  std::bitset<Trk::TrackStateOnSurface::NumberOfTrackStateOnSurfaceTypes> defaultType;
2885  std::bitset<Trk::TrackStateOnSurface::NumberOfTrackStateOnSurfaceTypes> type = defaultType;
2886  auto trackStateOnSurfaces = std::make_unique<Trk::TrackStates>();
2887 
2888  trackStateOnSurfaces->reserve(track->trackStateOnSurfaces()->size());
2889  bool is_first{true};
2890  for (const Trk::TrackStateOnSurface* tsos : *track->trackStateOnSurfaces()) {
2891  // limit perigee
2892  if (tsos->trackParameters()) {
2893  if (limitMomentum && is_first && tsos->trackParameters()->covariance() &&
2894  tsos->trackParameters()->surfaceType() == Trk::SurfaceType::Perigee) {
2895  Amg::VectorX parameterVector = tsos->trackParameters()->parameters();
2896  parameterVector[Trk::qOverP] = qOverP;
2897 
2899  std::unique_ptr<Trk::TrackParameters> parameters =
2900  tsos->trackParameters()->associatedSurface().createUniqueTrackParameters(
2901  parameterVector[Trk::loc1], parameterVector[Trk::loc2], parameterVector[Trk::phi], parameterVector[Trk::theta],
2902  parameterVector[Trk::qOverP], *tsos->trackParameters()->covariance());
2903 
2904  type = defaultType;
2906 
2907  std::unique_ptr<Trk::MeasurementBase> measurementBase;
2908  if (tsos->measurementOnTrack()) {
2909  measurementBase = tsos->measurementOnTrack()->uniqueClone();
2911  }
2912  trackStateOnSurfaces->push_back(
2913  new Trk::TrackStateOnSurface(std::move(measurementBase), std::move(parameters), nullptr, type));
2914  } else {
2915  trackStateOnSurfaces->push_back(tsos->clone());
2916  }
2917  is_first = false;
2918  continue;
2919  }
2920  is_first = false;
2921 
2922  // material in spectrometer
2923  if (tsos->materialEffectsOnTrack() &&
2924  !m_calorimeterVolume->inside(tsos->materialEffectsOnTrack()->associatedSurface().globalReferencePoint())) {
2925  if (tsos->measurementOnTrack()) {
2926  Amg::VectorX parameterVector = tsos->trackParameters()->parameters();
2927  if (limitMomentum) { parameterVector[Trk::qOverP] = qOverP; }
2928  std::unique_ptr<Trk::TrackParameters> trackParameters =
2929  tsos->trackParameters()->associatedSurface().createUniqueTrackParameters(
2930  parameterVector[Trk::loc1], parameterVector[Trk::loc2], parameterVector[Trk::phi], parameterVector[Trk::theta],
2931  parameterVector[Trk::qOverP],
2932  tsos->trackParameters()->covariance() ? std::optional<AmgSymMatrix(5)>(*tsos->trackParameters()->covariance())
2933  : std::nullopt);
2934 
2935  type = defaultType;
2937 
2939  std::unique_ptr<Trk::MeasurementBase> measurementBase;
2940  measurementBase = tsos->measurementOnTrack()->uniqueClone();
2941  trackStateOnSurfaces->push_back(
2942  new Trk::TrackStateOnSurface(std::move(measurementBase), std::move(trackParameters), nullptr, type));
2943  }
2944  continue;
2945  } else if (!tsos->measurementOnTrack() && tsos->trackParameters() &&
2946  !m_calorimeterVolume->inside(tsos->trackParameters()->position())) {
2947  continue;
2948  }
2949 
2950  if (limitMomentum && tsos->trackParameters()) {
2951  Amg::VectorX parameterVector = tsos->trackParameters()->parameters();
2952  parameterVector[Trk::qOverP] = qOverP;
2953  std::unique_ptr<Trk::TrackParameters> trackParameters =
2954  tsos->trackParameters()->associatedSurface().createUniqueTrackParameters(
2955  parameterVector[Trk::loc1], parameterVector[Trk::loc2], parameterVector[Trk::phi], parameterVector[Trk::theta],
2956  parameterVector[Trk::qOverP],
2957  tsos->trackParameters()->covariance() ? std::optional<AmgSymMatrix(5)>(*tsos->trackParameters()->covariance())
2958  : std::nullopt);
2959 
2960  type = defaultType;
2961 
2962  std::unique_ptr<Trk::MeasurementBase> measurementBase;
2963  if (tsos->measurementOnTrack()) {
2965 
2967 
2968  measurementBase = tsos->measurementOnTrack()->uniqueClone();
2969  }
2970 
2971  std::unique_ptr<Trk::MaterialEffectsBase> materialEffects;
2972  if (tsos->materialEffectsOnTrack()) {
2975 
2976  materialEffects = tsos->materialEffectsOnTrack()->uniqueClone();
2977  }
2978  trackStateOnSurfaces->push_back(new Trk::TrackStateOnSurface(std::move(measurementBase), std::move(trackParameters),
2979  std::move(materialEffects), type));
2980  } else {
2981  trackStateOnSurfaces->push_back(tsos->clone());
2982  }
2983  }
2984 
2985  // replace track
2986  Trk::TrackInfo trackInfo = track->info();
2987  std::unique_ptr<Trk::FitQuality> fitQuality = nullptr;
2988  if (track->fitQuality()) { fitQuality = std::make_unique<Trk::FitQuality>(*track->fitQuality()); }
2989 
2990  track = std::make_unique<Trk::Track>(trackInfo, std::move(trackStateOnSurfaces), std::move(fitQuality));
2991  }
2992 
2993  std::unique_ptr<Trk::PseudoMeasurementOnTrack> CombinedMuonTrackBuilder::vertexOnTrack(const Trk::TrackParameters& parameters,
2994  const Trk::RecVertex* vertex,
2995  const Trk::RecVertex* mbeamAxis) {
2996  // create the corresponding PerigeeSurface, localParameters and covarianceMatrix
2997  const Trk::PerigeeSurface surface(vertex->position());
2998  Trk::LocalParameters localParameters;
2999  Amg::MatrixX covarianceMatrix;
3000  covarianceMatrix.setZero();
3001 
3002  // transform Cartesian (x,y,z) to beam axis or perigee
3003  Amg::Vector2D localPosition(0, 0);
3004  double ptInv = 1. / parameters.momentum().perp();
3005 
3006  if (vertex == mbeamAxis) {
3007  Trk::DefinedParameter d0(localPosition[Trk::locX], Trk::locX);
3008  localParameters = Trk::LocalParameters(d0);
3009 
3010  Amg::MatrixX jacobian(1, 3);
3011  jacobian.setZero();
3012  jacobian(0, 0) = -ptInv * parameters.momentum().y();
3013  jacobian(0, 1) = ptInv * parameters.momentum().x();
3014 
3015  const Amg::MatrixX& cov = vertex->covariancePosition();
3016  covarianceMatrix = cov.similarity(jacobian);
3017  } else {
3018  localParameters = Trk::LocalParameters(localPosition);
3019 
3020  Amg::MatrixX jacobian(2, 3);
3021  jacobian.setZero();
3022  jacobian(0, 0) = -ptInv * parameters.momentum().y();
3023  jacobian(0, 1) = ptInv * parameters.momentum().x();
3024  jacobian(1, 2) = 1.0;
3025 
3026  const Amg::MatrixX& cov = vertex->covariancePosition();
3027  covarianceMatrix = cov.similarity(jacobian);
3028  }
3029 
3030  return std::make_unique<Trk::PseudoMeasurementOnTrack>(std::move(localParameters),
3031  std::move(covarianceMatrix),
3032  surface);
3033  }
3034 
3035  void CombinedMuonTrackBuilder::dumpCaloEloss(const Trk::Track* track, const std::string& txt) const {
3036  // will refit if extrapolated track was definitely bad
3037  if (!track || !msgLevel(MSG::DEBUG)) return;
3038  if (!m_trackQuery->isCaloAssociated(*track, Gaudi::Hive::currentContext())) {
3039  ATH_MSG_DEBUG(txt << " no TSOS in Calorimeter ");
3040  return;
3041  }
3042 
3043  const Trk::Track& originalTrack = *track;
3044  const CaloEnergy* caloEnergy = m_trackQuery->caloEnergy(originalTrack);
3045  if (caloEnergy) {
3046  ATH_MSG_DEBUG(txt << " Calorimeter Eloss " << caloEnergy->deltaE());
3047  } else {
3048  ATH_MSG_DEBUG(txt << " No Calorimeter Eloss");
3049  }
3050 
3051  const Trk::TrackStates* trackTSOS = track->trackStateOnSurfaces();
3052 
3053  double Eloss = 0.;
3054  double idEloss = 0.;
3055  double caloEloss = 0.;
3056  double msEloss = 0.;
3057  double deltaP = 0.;
3058  double pcalo = 0.;
3059  double pstart = 0.;
3060  double eta = 0.;
3061  double pMuonEntry = 0.;
3062 
3063  for (const auto* m : *trackTSOS) {
3064  const Trk::MeasurementBase* mot = m->measurementOnTrack();
3065 
3066  if (m->trackParameters()) { pMuonEntry = m->trackParameters()->momentum().mag(); }
3067 
3068  if (mot) {
3070  if (id.is_valid()) {
3071  // skip after first Muon hit
3072  if (m_idHelperSvc->isMuon(id)) { break; }
3073  }
3074  }
3075 
3076  if (pstart == 0 && m->trackParameters()) {
3077  pstart = m->trackParameters()->momentum().mag();
3078  eta = m->trackParameters()->momentum().eta();
3079 
3080  ATH_MSG_DEBUG("Start pars found eta " << eta << " r " << (m->trackParameters())->position().perp() << " z "
3081  << (m->trackParameters())->position().z() << " pstart " << pstart);
3082  }
3083 
3084  if (m->materialEffectsOnTrack()) {
3085  const Trk::MaterialEffectsOnTrack* meot = dynamic_cast<const Trk::MaterialEffectsOnTrack*>(m->materialEffectsOnTrack());
3086 
3087  if (meot) {
3088  if (meot->thicknessInX0() > 20) {
3089  const Trk::ScatteringAngles* scatAngles = meot->scatteringAngles();
3090 
3091  ATH_MSG_DEBUG(" Calorimeter X0 " << meot->thicknessInX0() << " pointer scat " << scatAngles);
3092 
3093  if (scatAngles) {
3094  pcalo = m->trackParameters()->momentum().mag();
3095  double pullPhi = scatAngles->deltaPhi() / scatAngles->sigmaDeltaPhi();
3096  double pullTheta = scatAngles->deltaTheta() / scatAngles->sigmaDeltaTheta();
3097 
3098  ATH_MSG_DEBUG(" Calorimeter scatterer deltaPhi (mrad) "
3099  << 1000 * scatAngles->deltaPhi() << " sigma " << 1000 * scatAngles->sigmaDeltaPhi() << " pull "
3100  << pullPhi << " deltaTheta (mrad) " << 1000 * scatAngles->deltaTheta() << " sigma "
3101  << 1000 * scatAngles->sigmaDeltaTheta() << " pull " << pullTheta);
3102  }
3103  }
3104 
3105  const Trk::EnergyLoss* energyLoss = meot->energyLoss();
3106  if (energyLoss) {
3107  if (m->trackParameters()) {
3108  ATH_MSG_DEBUG("Eloss found r " << (m->trackParameters())->position().perp() << " z "
3109  << (m->trackParameters())->position().z() << " value " << energyLoss->deltaE()
3110  << " Eloss " << Eloss);
3111  }
3112 
3114  idEloss = Eloss;
3115  caloEloss = std::abs(energyLoss->deltaE());
3116  Eloss = 0.;
3117 
3118  if (m->trackParameters()) { deltaP = m->trackParameters()->momentum().mag() - pcalo; }
3119 
3120  const Trk::Surface& surface = m->surface();
3121 
3122  ATH_MSG_DEBUG(" Calorimeter surface " << surface);
3123  ATH_MSG_DEBUG(txt << " Calorimeter delta p " << deltaP << " deltaE " << caloEloss
3124  << " delta pID = pcaloEntry-pstart " << pcalo - pstart);
3125 
3126  } else {
3127  Eloss += std::abs(energyLoss->deltaE());
3128  }
3129  }
3130  }
3131  }
3132  }
3133 
3134  msEloss = Eloss;
3135  Eloss = idEloss + caloEloss + msEloss;
3136 
3137  ATH_MSG_DEBUG(txt << " eta " << eta << " pstart " << pstart / Gaudi::Units::GeV << " Eloss on TSOS idEloss " << idEloss
3138  << " caloEloss " << caloEloss << " msEloss " << msEloss << " Total " << Eloss << " pstart - pMuonEntry "
3139  << pstart - pMuonEntry);
3140 
3141  return;
3142  }
3143 
3144  const Trk::TrackingVolume* CombinedMuonTrackBuilder::getVolume(const EventContext& ctx, const std::string&& vol_name) const {
3147  if (!handle.isValid()) {
3148  ATH_MSG_WARNING("Could not retrieve a valid tracking geometry");
3149  return nullptr;
3150  }
3151  return handle.cptr()->trackingVolume(vol_name);
3152  }
3153  std::vector<std::unique_ptr<const Trk::TrackStateOnSurface>> CombinedMuonTrackBuilder::getCaloTSOSfromMatProvider(
3154  const Trk::TrackParameters& track_params, const Trk::Track& me_track) const {
3155  std::vector<std::unique_ptr<const Trk::TrackStateOnSurface>> to_ret;
3156  std::unique_ptr<std::vector<const Trk::TrackStateOnSurface*>> tsos_vec{m_materialUpdator->getCaloTSOS(track_params, me_track)};
3157  if (tsos_vec) {
3158  to_ret.reserve(tsos_vec->size());
3159  for (const Trk::TrackStateOnSurface* tsos : *tsos_vec) to_ret.emplace_back(tsos);
3160  }
3161  return to_ret;
3162  }
3163 
3164 } // 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:3144
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:2259
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
GeV
#define GeV
Definition: PhysicsAnalysis/TauID/TauAnalysisTools/Root/HelperFunctions.cxx:17
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:2993
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:30
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:104
Amg::MatrixX
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic > MatrixX
Dynamic Matrix - dynamic allocation.
Definition: EventPrimitives.h:27
Rec::CombinedMuonTrackBuilder::addIDMSerrors
std::unique_ptr< Trk::Track > addIDMSerrors(const Trk::Track *track) const
Definition: CombinedMuonTrackBuilder.cxx:1560
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:2419
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:2095
Trk::locX
@ locX
Definition: ParamDefs.h:37
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:38
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:44
Rec::CombinedMuonTrackBuilder::removeSpectrometerMaterial
void removeSpectrometerMaterial(std::unique_ptr< Trk::Track > &track) const
Definition: CombinedMuonTrackBuilder.cxx:2854
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
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:1699
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:1740
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:1655
Rec::CombinedMuonTrackFitter::m_updateWithCaloTG
Gaudi::Property< bool > m_updateWithCaloTG
Definition: CombinedMuonTrackFitter.h:147
skel.it
it
Definition: skel.GENtoEVGEN.py:396
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:206
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:64
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:35
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:3035
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:2796
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:50
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
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
Trk::theta
@ theta
Definition: ParamDefs.h:66
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:2064
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:228
Trk::MeasurementBase::associatedSurface
virtual const Surface & associatedSurface() const =0
Interface method to get the associated Surface.
Trk::d0
@ d0
Definition: ParamDefs.h:63
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:756
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:2440
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:1134
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:2746
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:3153
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:2657
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:21
python.CaloScaleNoiseConfig.type
type
Definition: CaloScaleNoiseConfig.py:78
Rec::CombinedMuonTrackBuilder::m_vertex
std::unique_ptr< const Trk::RecVertex > m_vertex
Definition: CombinedMuonTrackBuilder.h:242
Trk::RIO_OnTrack::identify
Identifier identify() const
return the identifier -extends MeasurementBase
Definition: RIO_OnTrack.h:152
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:67
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:75
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:2274
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:579
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:34
Trk::Surface
Definition: Tracking/TrkDetDescr/TrkSurfaces/TrkSurfaces/Surface.h:75
Rec::CombinedMuonTrackFitter::m_printer
PublicToolHandle< Muon::MuonEDMPrinterTool > m_printer
Definition: CombinedMuonTrackFitter.h:109
Trk::TrackingVolume
Definition: TrackingVolume.h:121
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:26
Trk::phi0
@ phi0
Definition: ParamDefs.h:65
Trk::TrackStateOnSurface::Measurement
@ Measurement
This is a measurement, and will at least contain a Trk::MeasurementBase.
Definition: TrackStateOnSurface.h:101
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
Identifier
Definition: IdentifierFieldParser.cxx:14