ATLAS Offline Software
Loading...
Searching...
No Matches
CombinedMuonTrackFitter.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// CombinedMuonTrackFitter
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>
19#include "AthenaKernel/Units.h"
39#include "TrkSurfaces/Surface.h"
41#include "TrkTrack/Track.h"
44#include "VxVertex/RecVertex.h"
46
47namespace Rec {
49
51 ATH_MSG_DEBUG("Initializing CombinedMuonTrackFitter.");
52 ATH_MSG_DEBUG(" with options: ");
53
54 if (m_allowCleanerVeto) ATH_MSG_DEBUG(" AllowCleanerVeto");
55 if (!m_muonErrorOptimizer.empty()) ATH_MSG_DEBUG(" ErrorOptimisation");
56
57 // fill WARNING messages
58 m_messageHelper->setMaxNumberOfMessagesPrinted(m_maxWarnings);
59 m_messageHelper->setMessage(0, "combinedFit:: missing MeasuredPerigee for indet track");
60 m_messageHelper->setMessage(1, "combinedFit:: fail with MS removed by cleaner");
61 m_messageHelper->setMessage(2, "combinedFit:: fail with perigee outside indet");
62 m_messageHelper->setMessage(3, "combinedFit:: fail with missing caloEnergy");
63 m_messageHelper->setMessage(4, "combinedFit:: final combined track lost, this should not happen");
64 m_messageHelper->setMessage(5, "indetExtension:: reject with insufficient MS measurements");
65 m_messageHelper->setMessage(6, "standaloneFit:: input vertex fails dynamic_cast");
66 m_messageHelper->setMessage(7, "standaloneFit:: missing MeasuredPerigee for spectrometer track");
67 m_messageHelper->setMessage(8, "standaloneFit:: missing TrackParameters on prefit");
68 m_messageHelper->setMessage(9, "standaloneFit:: prefit fails parameter extrapolation to calo");
69 m_messageHelper->setMessage(10, "standaloneFit:: extrapolated track missing TrackParameters at calo scatterer");
70 m_messageHelper->setMessage(11, "standaloneFit:: final track lost, this should not happen");
71 m_messageHelper->setMessage(12, "standaloneFit:: fail as calo incorrectly described");
72 m_messageHelper->setMessage(13, "standaloneRefit:: fail track as no TSOS with type CaloDeposit");
73 m_messageHelper->setMessage(14, "standaloneRefit:: no inner material");
74 m_messageHelper->setMessage(15, "standaloneRefit:: no inner parameters");
75 m_messageHelper->setMessage(16, "standaloneRefit:: innerScattering dynamic_cast failed");
76 m_messageHelper->setMessage(17, "standaloneRefit:: no TSOS of type CaloDeposit found");
77 m_messageHelper->setMessage(18, "standaloneRefit:: no inner scattering TSOS found");
78 m_messageHelper->setMessage(19, "standaloneRefit:: no middle material");
79 m_messageHelper->setMessage(20, "standaloneRefit:: no middle parameters");
80 m_messageHelper->setMessage(21, "standaloneRefit:: no CaloDeposit TSOS found");
81 m_messageHelper->setMessage(22, "standaloneRefit:: no outer material");
82 m_messageHelper->setMessage(23, "standaloneRefit:: no outer parameters");
83 m_messageHelper->setMessage(24, "standaloneRefit:: outerScattering dynamic_cast failed");
84 m_messageHelper->setMessage(25, "standaloneRefit:: no outerScattering or CaloDeposit TSOS found");
85 m_messageHelper->setMessage(26, "standaloneRefit:: failed propagation to innerTSOS");
86 m_messageHelper->setMessage(27, "standaloneRefit:: failed propagation to middleTSOS");
87 m_messageHelper->setMessage(28, "standaloneRefit:: fail as calo incorrectly described");
88 m_messageHelper->setMessage(29, "fit:: particle hypothesis must be 0 or 2 (nonInteracting or muon). Requested: ");
89 m_messageHelper->setMessage(30, "fit:: about to add the TSOS's describing calorimeter association to a combined muon");
90 m_messageHelper->setMessage(31, "fit:: particle hypothesis must be 0 or 2 (nonInteracting or muon). Requested: ");
91 m_messageHelper->setMessage(32, "fit:: particle hypothesis must be 0 or 2 (nonInteracting or muon). Requested: ");
92 m_messageHelper->setMessage(33, "fit:: combined muon track is missing the TSOS's describing calorimeter association");
93 m_messageHelper->setMessage(34, "appendSelectedTSOS:: skip duplicate measurement ");
94 m_messageHelper->setMessage(35, "caloEnergyParameters:: muonTrack without caloEnergy association");
95 m_messageHelper->setMessage(36, "caloEnergyParameters:: combinedTrack without caloEnergy association");
96 m_messageHelper->setMessage(37, "createMuonTrack:: should never happen: FSR caloEnergy delete");
97 m_messageHelper->setMessage(38, "createSpectrometerTSOS:: missing MeasuredPerigee for spectrometer track");
98 m_messageHelper->setMessage(39, "createSpectrometerTSOS:: skip unrecognized TSOS without TrackParameters. Type: ");
99 m_messageHelper->setMessage(40, "createSpectrometerTSOS:: skip duplicate measurement on same Surface. Type: ");
100 m_messageHelper->setMessage(41, "entrancePerigee:: missing TrackingGeometrySvc - no perigee will be added at MS entrance");
101 m_messageHelper->setMessage(42, "extrapolatedParameters:: missing MeasuredPerigee for spectrometer track");
102 m_messageHelper->setMessage(43, "extrapolatedParameters:: missing spectrometer parameters on spectrometer track");
103 m_messageHelper->setMessage(44, "final track lost, this should not happen");
104 m_messageHelper->setMessage(45, "momentumUpdate:: update failed, keeping original value");
105 m_messageHelper->setMessage(46, "reallocateMaterial:: null perigeeStartValue");
106 m_messageHelper->setMessage(47, "reallocateMaterial:: refit fails");
107 m_messageHelper->setMessage(48, "standaloneFit:: insufficient measurements on input spectrometer track");
108 m_messageHelper->setMessage(49, "standaloneFit:: inconsistent TSOS on input spectrometer track");
109
110 ATH_CHECK(m_printer.retrieve());
112 ATH_MSG_DEBUG("Setup handle for key " << m_fieldCacheCondObjInputKey);
113 ATH_CHECK(m_muonErrorOptimizer.retrieve(DisableTool{m_muonErrorOptimizer.empty()}));
114
115 ATH_CHECK(m_caloTSOS.retrieve());
116 ATH_MSG_DEBUG("Retrieved tool " << m_caloTSOS);
117 ATH_CHECK(m_cleaner.retrieve());
118 ATH_MSG_DEBUG("Retrieved tool " << m_cleaner);
119
120 ATH_CHECK(m_fitter.retrieve());
121 ATH_CHECK(m_fitterSL.retrieve());
122 ATH_CHECK(m_idHelperSvc.retrieve());
123
125 ATH_MSG_DEBUG("Retrieved Svc " << m_trackingVolumesSvc);
128
129 ATH_CHECK(m_trackQuery.retrieve());
130 ATH_MSG_DEBUG("Retrieved tool " << m_trackQuery);
131 ATH_CHECK(m_trackSummary.retrieve());
132 ATH_MSG_DEBUG("Retrieved tool " << m_trackSummary);
133 ATH_CHECK(m_materialUpdator.retrieve());
134 ATH_MSG_DEBUG("Retrieved tool " << m_materialUpdator);
135
136 return StatusCode::SUCCESS;
137 }
138
140 ATH_MSG_INFO("Finalizing CombinedMuonTrackFitter:"
141 << m_countStandaloneCleanerVeto << " standalone fits with cleaner veto" << endmsg << " "
142 << m_countExtensionCleanerVeto << " extension fits with cleaner veto" << endmsg << " "
143 << m_countCombinedCleanerVeto << " combined fits with cleaner veto");
144 // // summarize WARNINGs
145 m_messageHelper->printSummary();
146 return StatusCode::SUCCESS;
147 }
148 std::unique_ptr<Trk::Track> CombinedMuonTrackFitter::fit(const EventContext& ctx, const Trk::Track& track,
149 const Trk::RunOutlierRemoval runOutlier,
150 const Trk::ParticleHypothesis particleHypothesis) const {
151 ATH_MSG_VERBOSE(" fit() " << m_printer->print(track) << std::endl
152 << m_printer->printMeasurements(track) << std::endl
153 << m_printer->printStations(track));
154 // check valid particleHypothesis
155 if (particleHypothesis != Trk::muon && particleHypothesis != Trk::nonInteracting) {
156 // invalid particle hypothesis
157 std::stringstream ss;
158 ss << particleHypothesis;
159 m_messageHelper->printWarning(29, ss.str());
160 return nullptr;
161 }
162
163 // check if combined or subsystem track
164 bool isCombined = m_trackQuery->isCombined(track, ctx);
165 // select straightLine fitter when magnets downstream of leading measurement are off
166 const Trk::ITrackFitter* fitter = m_fitter.get();
167 MagField::AtlasFieldCache fieldCache;
168 // Get field cache object
169
170 if (!loadMagneticField(ctx, fieldCache)) return nullptr;
171
172 if (!fieldCache.toroidOn() && !(isCombined && fieldCache.solenoidOn())) {
173 fitter = m_fitterSL.get();
174 ATH_MSG_VERBOSE(" fit (track refit method): select SL fitter ");
175 }
176
177 // redo ROTs: ID, CROT and MDT specific treatments
178 // if (m_redoRots) redoRots(track);
179
180 // perform fit after ensuring calo is associated for combined tracks
181 // calo association for combined tracks (WARN if missing from input)
182 std::unique_ptr<Trk::Track> fittedTrack = std::make_unique<Trk::Track>(track);
183 if (isCombined && particleHypothesis == Trk::muon && !m_trackQuery->isCaloAssociated(*fittedTrack, ctx)) {
184 // about to add the TSOS's describing calorimeter association to a combined muon;
185 ATH_MSG_VERBOSE( "fit:: about to add the TSOS's describing calorimeter association to a combined muon" );
186
187 auto combinedTSOS = std::make_unique<Trk::TrackStates>();
188
189 combinedTSOS->reserve(fittedTrack->trackStateOnSurfaces()->size() + 3);
190 bool caloAssociated = false;
191
192 // run-2 schema, update default eloss with parametrised value
193 if (m_useCaloTG) {
194 ATH_MSG_VERBOSE("Updating Calorimeter TSOS in Muon Combined (re)Fit ...");
195 m_materialUpdator->updateCaloTSOS(*fittedTrack);
196 caloAssociated = true;
197 }
198
199 for (const Trk::TrackStateOnSurface* in_tsos : *fittedTrack->trackStateOnSurfaces()) {
200 if (caloAssociated) {
201 combinedTSOS->push_back(in_tsos->clone());
202 } else if ((in_tsos->measurementOnTrack() && m_indetVolume->inside(in_tsos->measurementOnTrack()->globalPosition())) ||
203 (in_tsos->trackParameters() && m_indetVolume->inside(in_tsos->trackParameters()->position()))) {
204 combinedTSOS->push_back(in_tsos->clone());
205 } else {
206 std::unique_ptr<const Trk::TrackStateOnSurface> tsos = m_caloTSOS->innerTSOS(ctx, *fittedTrack->perigeeParameters());
207 if (tsos) {
208 combinedTSOS->push_back(std::move(tsos));
209 const Trk::TrackParameters* parameters = combinedTSOS->back()->trackParameters();
210 if (in_tsos->type(Trk::TrackStateOnSurface::CaloDeposit)) {
211 combinedTSOS->push_back(in_tsos->clone());
212 tsos = m_caloTSOS->outerTSOS(ctx, *parameters);
213 if (tsos) combinedTSOS->push_back(std::move(tsos));
214 } else {
215 tsos = m_caloTSOS->middleTSOS(ctx, *parameters);
216 if (tsos) combinedTSOS->push_back(std::move(tsos));
217 tsos = m_caloTSOS->outerTSOS(ctx, *parameters);
218 if (tsos) combinedTSOS->push_back(std::move(tsos));
219 combinedTSOS->push_back(in_tsos->clone());
220 }
221 }
222 caloAssociated = true;
223 }
224 }
225
226 std::unique_ptr<Trk::Track> combinedTrack = std::make_unique<Trk::Track>(fittedTrack->info(), std::move(combinedTSOS), nullptr);
227
228 if (msgLevel(MSG::DEBUG)) countAEOTs(*combinedTrack, " combinedTrack track before fit ");
229
230 caloAssociated = m_trackQuery->isCaloAssociated(*combinedTrack, ctx);
231
232 // Updates the calo TSOS with the ones from TG+corrections
233 if (m_updateWithCaloTG && !m_useCaloTG && particleHypothesis == Trk::muon) {
234 ATH_MSG_VERBOSE("Updating Calorimeter TSOS in Muon Combined (re)Fit ...");
235 m_materialUpdator->updateCaloTSOS(*combinedTrack);
236 }
237 // FIT
238 fittedTrack = fitter->fit(ctx, *combinedTrack, false, particleHypothesis);
239 } else {
240 // Updates the calo TSOS with the ones from TG+corrections
241 if (m_updateWithCaloTG && !m_useCaloTG && particleHypothesis == Trk::muon) {
242 ATH_MSG_VERBOSE("Updating Calorimeter TSOS in Muon Standalone Fit ...");
243 m_materialUpdator->updateCaloTSOS(*fittedTrack);
244 }
245
246 // FIT
247 fittedTrack = fitter->fit(ctx, *fittedTrack, false, particleHypothesis);
248 }
249
250 // quit if fit has failed
251 if (!fittedTrack) return nullptr;
252
253
254 if (!checkTrack("fitInterface1", fittedTrack.get())) return nullptr;
255
256
257 // eventually this whole tool will use unique_ptrs
258 // in the meantime, this allows the MuonErrorOptimisationTool and MuonRefitTool to use them
259 // track cleaning
260 if (runOutlier) {
261 // fit with optimized spectrometer errors
262
263 const double chi2BeforeOptimizer = normalizedChi2(*fittedTrack);
264 if (!m_muonErrorOptimizer.empty() && !fittedTrack->info().trackProperties(Trk::TrackInfo::StraightTrack) &&
265 optimizeErrors(ctx, *fittedTrack)) {
266 ATH_MSG_VERBOSE(" perform spectrometer error optimization after cleaning ");
267 std::unique_ptr<Trk::Track> optimizedTrack = m_muonErrorOptimizer->optimiseErrors(*fittedTrack, ctx);
268 if (checkTrack("fitInterface1Opt", optimizedTrack.get()) && chi2BeforeOptimizer > normalizedChi2(*optimizedTrack)) {
269 fittedTrack.swap(optimizedTrack);
270 if (msgLevel(MSG::DEBUG)) countAEOTs(*fittedTrack, " re fit scaled errors Track ");
271 }
272 }
273
274 // chi2 before clean
275 const double chi2Before = normalizedChi2(*fittedTrack);
276
277 // muon cleaner
278 ATH_MSG_VERBOSE(__FILE__<<":"<<__LINE__<<" perform track cleaning... " << m_printer->print(*fittedTrack) << std::endl
279 << m_printer->printStations(*fittedTrack));
280
281 if (msgLevel(MSG::DEBUG)) countAEOTs(*fittedTrack, " refit: fitted track before cleaning ");
282
283 std::unique_ptr<Trk::Track> cleanTrack = m_cleaner->clean(*fittedTrack, ctx);
284
285 if (msgLevel(MSG::DEBUG)) countAEOTs(*cleanTrack, " refit: after cleaning");
286
287 if (!checkTrack("fitInterface1Cleaner", cleanTrack.get())) { cleanTrack.reset(); }
288
289 if (!cleanTrack) {
290 if (m_allowCleanerVeto && chi2Before > m_badFitChi2) {
291 ATH_MSG_DEBUG(" cleaner veto A "<<chi2Before<<" "<<m_badFitChi2<<" "<<m_printer->printMeasurements(*fittedTrack) );
293 fittedTrack.reset();
294 } else {
295 ATH_MSG_DEBUG(" keep original standalone track despite cleaner veto ");
296 }
297 } else if (!(*cleanTrack->perigeeParameters() == *fittedTrack->perigeeParameters())) {
298 double chi2After = normalizedChi2(*cleanTrack);
299
300 if (chi2After < m_badFitChi2 || chi2After < chi2Before) {
301 ATH_MSG_VERBOSE(" found and removed spectrometer outlier(s) ");
302 fittedTrack.swap(cleanTrack);
303 } else {
304 ATH_MSG_VERBOSE(" keep original track despite cleaning ");
305 }
306 }
307
308 // FIXME: provide indet cleaner
309 if (fittedTrack) {
310 ATH_MSG_VERBOSE(" finished track cleaning... " << m_printer->print(*fittedTrack) << std::endl
311 << m_printer->printStations(*fittedTrack));
312 }
313 }
314 return fittedTrack;
315 }
316
317 std::unique_ptr<Trk::Track> CombinedMuonTrackFitter::fit(const EventContext& ctx, const Trk::MeasurementSet& measurementSet,
318 const Trk::TrackParameters& perigeeStartValue,
319 const Trk::RunOutlierRemoval runOutlier,
320 const Trk::ParticleHypothesis particleHypothesis) const {
321 // check valid particleHypothesis
322 if (particleHypothesis != Trk::muon && particleHypothesis != Trk::nonInteracting) {
323 // invalid particle hypothesis
324 std::stringstream ss;
325 ss << particleHypothesis;
326 m_messageHelper->printWarning(31, ss.str());
327 return nullptr;
328 }
329
330 // select straightLine fitter when magnets downstream of leading measurement are off
331 MagField::AtlasFieldCache fieldCache;
332 // Get field cache object
333 if (!loadMagneticField(ctx, fieldCache)) return nullptr;
334
335 const Trk::ITrackFitter* fitter = m_fitter.get();
336 if (!fieldCache.toroidOn() || std::abs(perigeeStartValue.position().z()) > m_zECToroid) {
337 fitter = m_fitterSL.get();
338 ATH_MSG_VERBOSE(" fit (track refit method): select SL fitter ");
339 }
340
341 // redo ROTs: ID, CROT and MDT specific treatments
342 // if (m_redoRots) redoRots(track);
343
344 // calo association (if relevant)
345
346 // create Perigee if starting parameters given for a different surface type
347 std::unique_ptr<Trk::TrackParameters> perigee = perigeeStartValue.uniqueClone();
348 std::unique_ptr<Trk::PerigeeSurface> perigeeSurface;
349
350 if (perigee->surfaceType() != Trk::SurfaceType::Perigee) {
351 Amg::Vector3D origin(perigeeStartValue.position());
352 perigeeSurface = std::make_unique<Trk::PerigeeSurface>(origin);
353
354 perigee = std::make_unique<Trk::Perigee>(perigeeStartValue.position(), perigeeStartValue.momentum(), perigeeStartValue.charge(),
355 *perigeeSurface);
356 }
357
358 // FIT
359 std::unique_ptr<Trk::Track> fittedTrack(fitter->fit(ctx, measurementSet, *perigee, false, particleHypothesis));
360
361 if (!checkTrack("fitInterface2", fittedTrack.get())) { return nullptr; }
362
363 // eventually this whole tool will use unique_ptrs
364 // in the meantime, this allows the MuonErrorOptimisationTool and MuonRefitTool to use them
365
366 // track cleaning
367 if (runOutlier) {
368 // fit with optimized spectrometer errors
369
370 if (!m_muonErrorOptimizer.empty() && !fittedTrack->info().trackProperties(Trk::TrackInfo::StraightTrack) &&
371 optimizeErrors(ctx, *fittedTrack)) {
372 ATH_MSG_VERBOSE(" perform spectrometer error optimization after cleaning ");
373 std::unique_ptr<Trk::Track> optimizedTrack = m_muonErrorOptimizer->optimiseErrors(*fittedTrack, ctx);
374 if (checkTrack("fitInterface2Opt", optimizedTrack.get())) {
375 fittedTrack.swap(optimizedTrack);
376 if (msgLevel(MSG::DEBUG)) countAEOTs(*fittedTrack, " fit mstSet scaled errors Track ");
377 }
378
379 }
380
381 // chi2 before clean
382 double chi2Before = normalizedChi2(*fittedTrack);
383
384 // muon cleaner
385 ATH_MSG_VERBOSE(__FILE__<<":"<<__LINE__<<" perform track cleaning... ");
386
387 if (msgLevel(MSG::DEBUG)) countAEOTs(*fittedTrack, " fit mstSet before cleaning ");
388
389 std::unique_ptr<Trk::Track> cleanTrack = m_cleaner->clean(*fittedTrack, ctx);
390
391 if (msgLevel(MSG::DEBUG)) countAEOTs(*cleanTrack, " fit mstSet clean Track ");
392
393 if (!checkTrack("fitInterface2Cleaner", cleanTrack.get())) { cleanTrack.reset(); }
394
395 if (!cleanTrack) {
396 if (m_allowCleanerVeto && chi2Before > m_badFitChi2) {
397 ATH_MSG_DEBUG(" cleaner veto B");
399 fittedTrack.reset();
400 } else {
401 ATH_MSG_DEBUG(" keep original extension track despite cleaner veto ");
402 }
403 } else if (!(*cleanTrack->perigeeParameters() == *fittedTrack->perigeeParameters())) {
404 double chi2After = normalizedChi2(*cleanTrack);
405 if (chi2After < m_badFitChi2 || chi2After < chi2Before) {
406 ATH_MSG_VERBOSE(" found and removed spectrometer outlier(s) ");
407 fittedTrack.swap(cleanTrack);
408 } else {
409 ATH_MSG_VERBOSE(" keep original track despite cleaning ");
410 }
411 }
412
413 // FIXME: provide indet cleaner
414 ATH_MSG_VERBOSE(" Finished cleaning");
415 }
416 // have to use release until the whole code uses unique_ptr
417 return fittedTrack;
418 }
419
421 std::unique_ptr<Trk::Track> CombinedMuonTrackFitter::fit(const EventContext& ctx, const Trk::Track& indetTrack,
422 Trk::Track& extrapolatedTrack, const Trk::RunOutlierRemoval runOutlier,
423 const Trk::ParticleHypothesis particleHypothesis) const {
424 // check valid particleHypothesis
425 if (particleHypothesis != Trk::muon && particleHypothesis != Trk::nonInteracting) {
426 // invalid particle hypothesis
427 std::stringstream ss;
428 ss << particleHypothesis;
429 m_messageHelper->printWarning(32, ss.str());
430 return nullptr;
431 }
432
433 // select straightLine fitter when solenoid and toroid are off
434 const Trk::ITrackFitter* fitter = m_fitter.get();
435 MagField::AtlasFieldCache fieldCache;
436 // Get field cache object
437 if (!loadMagneticField(ctx, fieldCache)) return nullptr;
438
439 if (!fieldCache.toroidOn() && !fieldCache.solenoidOn()) {
440 fitter = m_fitterSL.get();
441 ATH_MSG_VERBOSE(" fit (combined muon fit method): select SL fitter ");
442 }
443
444 // redo ROTs: ID, CROT and MDT specific treatments
445
446 // calo association (for now just WARN if missing)
447 if (particleHypothesis == Trk::muon && !m_trackQuery->isCaloAssociated(extrapolatedTrack, ctx)) {
448 // combined muon track is missing the TSOS's describing calorimeter association
449 m_messageHelper->printWarning(33);
450 }
451
452 // Updates the calo TSOS with the ones from TG+corrections
453 if (m_updateWithCaloTG && !m_useCaloTG && particleHypothesis == Trk::muon) {
454 ATH_MSG_VERBOSE("Updating Calorimeter TSOS in Muon Combined Fit ...");
455 m_materialUpdator->updateCaloTSOS(indetTrack, extrapolatedTrack);
456 }
457
458 // FIT
459 ATH_MSG_VERBOSE(" perform combined fit... " << std::endl
460 << m_printer->print(indetTrack) << std::endl
461 << m_printer->print(extrapolatedTrack));
462
463 std::unique_ptr<Trk::Track> fittedTrack(fitter->fit(ctx, indetTrack, extrapolatedTrack, false, particleHypothesis));
464
465 if (!fittedTrack) return nullptr;
466 // track cleaning
467 if (runOutlier) {
468 // fit with optimized spectrometer errors
469
470 if (!m_muonErrorOptimizer.empty() && !fittedTrack->info().trackProperties(Trk::TrackInfo::StraightTrack) &&
471 optimizeErrors(ctx, *fittedTrack)) {
472 ATH_MSG_VERBOSE(" perform spectrometer error optimization after cleaning ");
473 std::unique_ptr<Trk::Track> optimizedTrack = m_muonErrorOptimizer->optimiseErrors(*fittedTrack, ctx);
474 if (checkTrack("Error opt", optimizedTrack.get()) &&
475 normalizedChi2(*optimizedTrack) < normalizedChi2(*fittedTrack)) {
476 fittedTrack.swap(optimizedTrack);
477 if (msgLevel(MSG::DEBUG)) countAEOTs(*fittedTrack, " cbfit scaled errors Track ");
478 }
479 }
480
481 // chi2 before clean
482 double chi2Before = normalizedChi2(*fittedTrack);
483
484 // muon cleaner
485 ATH_MSG_VERBOSE(__FILE__<<":"<<__LINE__<<" perform track cleaning... " << m_printer->print(*fittedTrack) << std::endl
486 << m_printer->printStations(*fittedTrack));
487
488 if (msgLevel(MSG::DEBUG)) { countAEOTs(*fittedTrack, " cb before clean Track "); }
489 std::unique_ptr<Trk::Track> cleanTrack = m_cleaner->clean(*fittedTrack, ctx);
490 if (cleanTrack && msgLevel(MSG::DEBUG)) { countAEOTs(*cleanTrack, " cb after clean Track "); }
491
492 if (!cleanTrack) {
493 if (m_allowCleanerVeto && chi2Before > m_badFitChi2) {
494 ATH_MSG_DEBUG("cleaner veto C "<<chi2Before<<" Cut: "<<m_badFitChi2);
496 fittedTrack.reset();
497 } else {
498 ATH_MSG_DEBUG(" keep original combined track despite cleaner veto ");
499 }
500 } else if (!(*cleanTrack->perigeeParameters() == *fittedTrack->perigeeParameters())) {
501 double chi2After = normalizedChi2(*cleanTrack);
502 if (chi2After < m_badFitChi2 || chi2After < chi2Before) {
503 ATH_MSG_VERBOSE(" found and removed spectrometer outlier(s) ");
504 fittedTrack.swap(cleanTrack);
505 } else {
506 ATH_MSG_VERBOSE(" keep original track despite cleaning ");
507 }
508 }
509
510 // FIXME: provide indet cleaner
511 ATH_MSG_VERBOSE(" finished cleaning");
512 }
513 // have to use release until the whole code uses unique_ptr
514 return fittedTrack;
515 }
516
517 /* private methods follow */
519 double chi2 = 999999.;
520 if (track.fitQuality()) {
521 if (track.fitQuality()->numberDoF()) {
522 chi2 = track.fitQuality()->chiSquared() / track.fitQuality()->doubleNumberDoF();
523 } else {
525 }
526 }
527
528 return chi2;
529 }
530
531 bool CombinedMuonTrackFitter::loadMagneticField(const EventContext& ctx, MagField::AtlasFieldCache& fieldCache) const {
533 if (!fieldCondObj.isValid()) {
534 ATH_MSG_ERROR("Failed to retrieve AtlasFieldCacheCondObj with key " << m_fieldCacheCondObjInputKey.key());
535 return false;
536 }
537 fieldCondObj->getInitializedCache(fieldCache);
538 return true;
539 }
540 bool CombinedMuonTrackFitter::optimizeErrors(const EventContext& ctx, Trk::Track& track) const {
541 const Trk::MuonTrackSummary* muonSummary = nullptr;
542 const Trk::TrackSummary* summary = track.trackSummary();
543
544 if (summary) {
545 muonSummary = summary->muonTrackSummary();
546 } else {
547 m_trackSummary->updateTrack(ctx, track);
548 summary = track.trackSummary();
549 muonSummary = summary->muonTrackSummary();
550 }
551
552 if (!muonSummary) return false;
553
554
555 unsigned int optimize{0},nBarrel{0}, nEndcap{0}, nSmall{0}, nLarge{0};
556
557 for (const Trk::MuonTrackSummary::ChamberHitSummary& summary : muonSummary->chamberHitSummary()) {
558 const Identifier& id = summary.chamberId();
559 bool isMdt = m_idHelperSvc->isMdt(id);
560 if (!isMdt) continue;
561
562 using namespace Muon::MuonStationIndex;
563
564 const ChIndex chIdx = m_idHelperSvc->chamberIndex(id);
565 const bool isSmall = m_idHelperSvc->isSmallChamber(id);
566 nBarrel += isBarrel(chIdx);
567 nEndcap += !isBarrel(chIdx);
568 nSmall+= isSmall;
569 nLarge += !isSmall;
570
571 if (chIdx == ChIndex::BIS &&
572 std::abs(m_idHelperSvc->stationEta(id)) > 6) {
573 optimize = 2;
574 } else if (chIdx == ChIndex::BEE) {
575 optimize = 1;
576 }
577 }
578
579 if (nBarrel > 0 && nEndcap > 0) { optimize += 10; }
580
581 if (nSmall > 0 && nLarge > 0) { optimize += 100; }
582
583 if (optimize > 0) { ATH_MSG_DEBUG(" OptimizeErrors with value " << optimize); }
584
585 return optimize > 0;
586 }
587
588 bool CombinedMuonTrackFitter::checkTrack(std::string_view txt, const Trk::Track* newTrack) const {
589 if (!newTrack) return false;
590
592 if (!pars || pars->empty() || !newTrack->fitQuality()) { return false; }
594
595 if ((*it)->position().dot((*it)->momentum()) < 0) {
596 return false;
597 ATH_MSG_DEBUG(txt <<" "<< __FILE__<<":"<<__LINE__<< " ALARM position " << (*it)->position() << " direction " << (*it)->momentum().unit());
598 } else {
599 ATH_MSG_DEBUG(txt <<" "<< __FILE__<<":"<<__LINE__<< " OK position " << (*it)->position() << " direction " << (*it)->momentum().unit());
600 }
601
602 for (const Trk::TrackParameters* par : *pars) {
603 if (!par->covariance()) { continue; }
604 if (!Amg::hasPositiveDiagElems(*par->covariance())) {
605 ATH_MSG_DEBUG(txt<<" "<<__FILE__<<":"<<__LINE__<< "covariance matrix has negative diagonal element, killing track "
606 <<std::endl<<Amg::toString(*par->covariance()));
607 return false;
608 }
609 }
610 unsigned int numberMS{0}, numberMSPrec{0};
614 for (; r != rEnd; ++r) {
615 const Trk::TrackStateOnSurface* tsos{*r};
616 if (tsos->trackParameters() && m_calorimeterVolume->inside(tsos->trackParameters()->position())) break;
617
618 if (tsos->measurementOnTrack()) {
619 ++numberMS;
620 const Trk::RIO_OnTrack* rot = dynamic_cast<const Trk::RIO_OnTrack*>(tsos->measurementOnTrack());
621 numberMSPrec+= rot && !m_idHelperSvc->measuresPhi(rot->identify());
622 }
623 }
624
625 ATH_MSG_VERBOSE( txt<< " "<<__FILE__<<":"<<__LINE__<<" "<< numberMS << "/"<< numberMSPrec<< " fitted MS measurements ");
626 // reject with insufficient MS measurements
627 if (numberMS < 5 || numberMSPrec < 3) {
628 return false;
629 }
630
631 return true;
632 }
633
634 unsigned int CombinedMuonTrackFitter::countAEOTs(const Trk::Track& track, const std::string& txt) const {
635 const Trk::TrackStates* trackTSOS = track.trackStateOnSurfaces();
636 unsigned int naeots = 0;
637
638 if (!trackTSOS){
639 ATH_MSG_ERROR("No trackStateOnSurfaces");
640 return naeots;
641 }
642
643 for (const auto* m : *trackTSOS) {
644 if (m && m->alignmentEffectsOnTrack()) naeots++;
645 }
646
647 ATH_MSG_DEBUG(" count AEOTs " << txt << " " << naeots);
648
649 // add VEBOSE for checking TSOS order
650
651
652 int tsos{0}, nperigee{0};
653 for ( const Trk::TrackStateOnSurface* it : *trackTSOS) {
654 tsos++;
655
656 if (it->type(Trk::TrackStateOnSurface::Perigee)) {
657 ATH_MSG_DEBUG("perigee");
658 nperigee++;
659 }
660
661 if (it->trackParameters()) {
662 ATH_MSG_VERBOSE(" check tsos " << tsos << " TSOS tp "
663 << " r " << it->trackParameters()->position().perp() << " z "
664 << it->trackParameters()->position().z() << " momentum "
665 << it->trackParameters()->momentum().mag());
666 } else if (it->measurementOnTrack()) {
667 ATH_MSG_VERBOSE(" check tsos " << tsos << " TSOS mst "
668 << " r " << it->measurementOnTrack()->associatedSurface().center().perp() << " z "
669 << it->measurementOnTrack()->associatedSurface().center().z());
670 } else if (it->materialEffectsOnTrack()) {
671 ATH_MSG_VERBOSE(" check tsos " << tsos << " TSOS mat "
672 << " r "
673 << it->materialEffectsOnTrack()->associatedSurface().globalReferencePoint().perp()
674 << " z " << it->materialEffectsOnTrack()->associatedSurface().globalReferencePoint().z());
675 } else {
676 ATH_MSG_VERBOSE(" check tsos other than above " << tsos);
677 }
678 }
679
680 ATH_MSG_VERBOSE(" track with number of TSOS perigees " << nperigee);
681
682 return naeots;
683 }
684} // namespace Rec
#define endmsg
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_DEBUG(x)
static Double_t ss
Wrapper to avoid constant divisions when using units.
Derived DataVector<T>.
Definition DataVector.h:795
DataModel_detail::const_iterator< DataVector > const_iterator
Standard const_iterator.
Definition DataVector.h:838
const_reverse_iterator rend() const noexcept
Return a const_reverse_iterator pointing at the beginning of the collection.
const_reverse_iterator rbegin() const noexcept
Return a const_reverse_iterator pointing past the end of the collection.
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition DataVector.h:847
bool fit(const LArSamples::AbsShape &data, const AbsShape &reference, double &k, double &deltaT, double &chi2, const ScaledErrorData *sed=0) const
Local cache for magnetic field (based on MagFieldServices/AtlasFieldSvcTLS.h)
bool solenoidOn() const
status of the magnets
SG::ReadCondHandleKey< AtlasFieldCacheCondObj > m_fieldCacheCondObjInputKey
ToolHandle< Muon::IMuonErrorOptimisationTool > m_muonErrorOptimizer
bool optimizeErrors(const EventContext &ctx, Trk::Track &track) const
ToolHandle< Trk::ITrkMaterialProviderTool > m_materialUpdator
Gaudi::Property< unsigned > m_maxWarnings
Gaudi::Property< double > m_badFitChi2
Gaudi::Property< double > m_zECToroid
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
virtual StatusCode initialize() override
std::unique_ptr< MessageHelper > m_messageHelper
ServiceHandle< Trk::ITrackingVolumesSvc > m_trackingVolumesSvc
ToolHandle< Trk::ITrackSummaryTool > m_trackSummary
ToolHandle< Muon::IMuonTrackCleaner > m_cleaner
ToolHandle< Trk::ITrackFitter > m_fitterSL
ToolHandle< Rec::IMuidCaloTrackStateOnSurface > m_caloTSOS
virtual std::unique_ptr< Trk::Track > fit(const EventContext &ctx, const Trk::Track &track, const Trk::RunOutlierRemoval runOutlier, const Trk::ParticleHypothesis particleHypothesis) const override
double normalizedChi2(const Trk::Track &track) const
unsigned int countAEOTs(const Trk::Track &track, const std::string &txt) const
std::unique_ptr< const Trk::Volume > m_calorimeterVolume
bool checkTrack(std::string_view txt, const Trk::Track *newTrack) const
ToolHandle< Trk::ITrackFitter > m_fitter
virtual StatusCode finalize() override
bool loadMagneticField(const EventContext &ctx, MagField::AtlasFieldCache &field_cache) const
PublicToolHandle< Muon::MuonEDMPrinterTool > m_printer
Gaudi::Property< bool > m_updateWithCaloTG
std::unique_ptr< const Trk::Volume > m_indetVolume
Gaudi::Property< bool > m_allowCleanerVeto
ToolHandle< Rec::IMuonTrackQuery > m_trackQuery
Provides the abstract interface for track fitting in the common ATLAS Tracking EDM.
@ CalorimeterEntryLayer
Tracking Volume which defines the entrance srufaces of the calorimeter.
@ MuonSpectrometerEntryLayer
Tracking Volume which defines the entrance surfaces of the MS.
Detailed track summary for the muon system Give access to hit counts per chamber.
const std::vector< ChamberHitSummary > & chamberHitSummary() const
access to the vector of chamber hit summaries on the track
const Amg::Vector3D & momentum() const
Access method for the momentum.
const Amg::Vector3D & position() const
Access method for the position.
double charge() const
Returns the charge.
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...
Class to handle RIO On Tracks ROT) for InDet and Muons, it inherits from the common MeasurementBase.
Definition RIO_OnTrack.h:70
Identifier identify() const
return the identifier -extends MeasurementBase
represents the track state (measurement, material, fit parameters and quality) at a surface.
const MeasurementBase * measurementOnTrack() const
returns MeasurementBase const overload
const TrackParameters * trackParameters() const
return ptr to trackparameters const overload
@ Perigee
This represents a perigee, and so will contain a Perigee object only.
@ CaloDeposit
This TSOS contains a CaloEnergy object.
A summary of the information contained by a track.
const Trk::TrackStates * trackStateOnSurfaces() const
return a pointer to a const DataVector of const TrackStateOnSurfaces.
const DataVector< const TrackParameters > * trackParameters() const
Return a pointer to a vector of TrackParameters.
const FitQuality * fitQuality() const
return a pointer to the fit quality const-overload
double chi2(TH1 *h0, TH1 *h1)
int r
Definition globals.cxx:22
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
bool hasPositiveDiagElems(const AmgSymMatrix(N) &mat)
Returns true if all diagonal elements of the covariance matrix are finite aka sane in the above defin...
Eigen::Matrix< double, 3, 1 > Vector3D
bool isSmall(const ChIndex index)
Returns true if the chamber index is in a small sector.
bool isBarrel(const ChIndex index)
Returns true if the chamber index points to a barrel chamber.
ChIndex
enum to classify the different chamber layers in the muon spectrometer
Gaudi Tools.
std::vector< const MeasurementBase * > MeasurementSet
vector of fittable measurements
Definition FitterTypes.h:30
DataVector< const Trk::TrackStateOnSurface > TrackStates
bool RunOutlierRemoval
switch to toggle quality processing after fit
Definition FitterTypes.h:22
ParticleHypothesis
Enumeration for Particle hypothesis respecting the interaction with material.
ParametersBase< TrackParametersDim, Charged > TrackParameters
structure to hold information per chamber in the muon system