ATLAS Offline Software
Loading...
Searching...
No Matches
MuonChamberHoleRecoveryTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7#include <map>
8
32#include "TrkVolumes/Volume.h"
33
34namespace {
35 struct PullCluster {
36 double pull{std::numeric_limits<double>::max()};
37 std::unique_ptr<Trk::TrackParameters> pars{};
38 std::unique_ptr<Muon::MuonClusterOnTrack> clus{};
39 };
40 using ClusterLayerMap = std::map<Identifier, PullCluster>;
41
42} // namespace
43namespace Muon {
45
46
49 return m_trk.trackStateOnSurfaces()->begin();
50 }
52 return m_trk.trackStateOnSurfaces()->end();
53 }
55 return m_curr_itr != end() ? (*m_curr_itr) : nullptr;
56 }
58 if (!m_nextCalled) {
59 m_nextCalled = true;
60 return true;
61 }
62 if (m_curr_itr == end()) return false;
63 return (++m_curr_itr) != end();
64 }
66 if (!m_copiedStates.insert(tsos()).second) return;
67 if (target == CopyTarget::GlobalTrkStates) m_newStates.emplace_back(tsos()->clone());
68 else chamberStates.emplace_back(tsos()->clone());
69 }
71 return chamberStates.empty() ? tsos()->trackParameters() : chamberStates[0]->trackParameters();
72 }
74 if (chamberStates.empty()) return;
76 m_newStates.insert(m_newStates.end(), std::make_move_iterator(chamberStates.begin()),
77 std::make_move_iterator(chamberStates.end()));
78 chamberStates.clear();
79 }
82 std::unique_ptr<Trk::TrackStates> outVec = std::make_unique<Trk::TrackStates>();
83 for (std::unique_ptr<const Trk::TrackStateOnSurface>& tsos : m_newStates){
84 outVec->push_back(std::move(tsos));
85 }
86 return outVec;
87 }
88
89 MuonChamberHoleRecoveryTool::MuonChamberHoleRecoveryTool(const std::string& ty, const std::string& na, const IInterface* pa) :
90 AthAlgTool(ty, na, pa) {
91 declareInterface<IMuonHoleRecoveryTool>(this);
92 }
93
95 ATH_CHECK(m_DetectorManagerKey.initialize());
96 ATH_CHECK(m_edmHelperSvc.retrieve());
97 ATH_CHECK(m_idHelperSvc.retrieve());
99 ATH_CHECK(m_printer.retrieve());
100 ATH_CHECK(m_extrapolator.retrieve());
101
102
103 ATH_CHECK(m_key_csc.initialize(!m_key_csc.empty()));
104 ATH_CHECK(m_key_stgc.initialize(!m_key_stgc.empty()));
105 ATH_CHECK(m_key_mm.initialize(!m_key_mm.empty()));
106
107 ATH_CHECK(m_key_mdt.initialize(!m_key_mdt.empty()));
108 ATH_CHECK(m_key_tgc.initialize(!m_key_tgc.empty()));
109 ATH_CHECK(m_key_rpc.initialize(!m_key_rpc.empty()));
110
111 ATH_CHECK(m_cscRotCreator.retrieve(DisableTool{m_key_csc.empty()}));
112
113 const bool hasClusKey = !m_key_stgc.empty() || !m_key_mm.empty() || !m_key_tgc.empty() || !m_key_rpc.empty();
114 ATH_CHECK(m_clusRotCreator.retrieve(EnableTool{hasClusKey}));
115 ATH_CHECK(m_mdtRotCreator.retrieve(EnableTool{!m_key_mdt.empty()}));
116 ATH_CHECK(m_pullCalculator.retrieve());
117
118 ATH_CHECK(m_chamberGeoKey.initialize());
119 return StatusCode::SUCCESS;
120 }
122 while(trkRecov.nextState()) {
123 const Trk::TrackParameters* pars = trkRecov.tsos()->trackParameters();
124 ATH_MSG_VERBOSE("Track parameters "<<(*pars));
127 if (msVol.inside(pars->position())) {
128 ATH_MSG_VERBOSE("Tracking parameters are inside the MS");
129 trkRecov.copyState(target);
130 continue;
131 }
132
133 if (trkRecov.tsos()->type(Trk::TrackStateOnSurface::Hole)) {
134 ATH_MSG_VERBOSE("Skip hole in MS");
135 continue;
136 }
138 const Trk::MeasurementBase* meas = trkRecov.tsos()->measurementOnTrack();
139 if (!meas) {
140 ATH_MSG_VERBOSE("The track state does not have an associated measurement");
141 trkRecov.copyState(target);
142 continue;
143 }
144 trkRecov.tsosId = m_edmHelperSvc->getIdentifier(*meas);
145 // Potentially a pseudo measurement. Anyway keep it
146 if (!trkRecov.tsosId.is_valid() || !m_idHelperSvc->isMuon(trkRecov.tsosId)) {
147 ATH_MSG_VERBOSE("No muon measurement");
148 trkRecov.copyState(target);
149 continue;
150 }
151 return true;
152 }
153 return false;
154 }
155
156 std::set<Identifier> MuonChamberHoleRecoveryTool::layersOnTrkIds(const Trk::Track& track) const {
157 std::set<Identifier> layerIds{};
158 for (const Trk::TrackStateOnSurface* tsos: *track.trackStateOnSurfaces()){
159 const Trk::MeasurementBase* meas = tsos->measurementOnTrack();
160 if (!meas) continue;
161 const Identifier measId = m_edmHelperSvc->getIdentifier(*meas);
162
163 if (!m_idHelperSvc->isMuon(measId)) continue;
164 layerIds.insert(measId);
165 layerIds.insert(m_idHelperSvc->layerId(measId));
166 // split competing ROTs into constituents
167 const CompetingMuonClustersOnTrack* comp = dynamic_cast<const CompetingMuonClustersOnTrack*>(meas);
168 if (!comp) { continue; }
169
170 for (const Muon::MuonClusterOnTrack* clust : comp->containedROTs()) {
171 layerIds.insert(m_idHelperSvc->layerId(clust->identify()));
172 }
173 }
174 return layerIds;
175 }
176
177 std::unique_ptr<Trk::Track> MuonChamberHoleRecoveryTool::recover(const Trk::Track& track, const EventContext& ctx) const {
178 ATH_MSG_DEBUG(" performing hole search track " << std::endl
179 << m_printer->print(track) << std::endl
180 << m_printer->printMeasurements(track));
181
182 RecoveryState recovState{track};
183 recovState.layersOnTrk = layersOnTrkIds(track);
184
188 recoverHitsInChamber(ctx, recovState);
189 std::unique_ptr<Trk::Track> newTrack = std::make_unique<Trk::Track>(track.info(), recovState.releaseStates(),
190 track.fitQuality() ? track.fitQuality()->uniqueClone() : nullptr);
191 return newTrack;
192 }
193 void MuonChamberHoleRecoveryTool::recoverHitsInChamber(const EventContext& ctx, RecoveryState& trkRecov) const {
194 const Muon::MuonStationIndex::ChIndex currStation = m_idHelperSvc->chamberIndex(trkRecov.tsosId);
196 std::set<Identifier> chambInStation{};
197 do {
198 if (currStation != m_idHelperSvc->chamberIndex(trkRecov.tsosId)) {
199 trkRecov.finalizeChamber();
200 recoverHitsInChamber(ctx, trkRecov);
201 return;
202 }
205 if (chambInStation.insert(m_idHelperSvc->chamberId(trkRecov.tsosId)).second) {
206 if (m_idHelperSvc->isMdt(trkRecov.tsosId)) {
207 recoverMdtHits(ctx, trkRecov.tsosId, *trkRecov.tsos()->trackParameters(),
208 trkRecov.chamberStates, trkRecov.layersOnTrk);
209 } else {
210 recoverClusterHits(ctx, trkRecov.tsosId, *trkRecov.tsos()->trackParameters(),
211 trkRecov.chamberStates, trkRecov.layersOnTrk);
212 }
213 }
215 trkRecov.finalizeChamber();
216 }
218 const Identifier& chId,
219 const Trk::TrackParameters& pars,
220 NewTrackStates& newStates, std::set<Identifier>& knownLayers) const {
221
222
223 std::set<Identifier> chHoles = holesInMdtChamber(ctx, pars.position(), pars.momentum().unit(), chId, knownLayers);
224 ATH_MSG_VERBOSE(" chamber " << m_idHelperSvc->toStringChamber(chId) << " has holes " << chHoles.size());
225 if (chHoles.empty()) return;
226
227 const std::vector<const MdtPrepData*> prdCandidates{loadPrepDataHits<MdtPrepData>(ctx, m_key_mdt, chHoles)};
228 bool addedState{false};
229 for (const MdtPrepData* mdtPrd : prdCandidates) {
230 const Trk::StraightLineSurface& surf{mdtPrd->detectorElement()->surface(mdtPrd->identify())};
231 std::unique_ptr<Trk::TrackParameters> exPars = m_extrapolator->extrapolateDirectly(ctx, pars, surf, Trk::anyDirection, false, Trk::muon);
232 if (!exPars) {
233 ATH_MSG_VERBOSE("Propagation to "<<m_idHelperSvc->toString(mdtPrd->identify())<<" failed.");
234 continue;
235 }
236
238 Amg::Vector2D locPos{Amg::Vector2D::Zero()};
239 if (!surf.globalToLocal(exPars->position(), exPars->momentum(), locPos)) {
240 ATH_MSG_DEBUG(" failed to calculate drift sign ");
241 continue;
242 }
243 if (!surf.insideBounds(locPos)) {
244 chHoles.erase(mdtPrd->identify());
245 continue;
246 }
247
248 // calibrate Mdt PRD
249 const Amg::Vector3D momentum = exPars->momentum();
250 std::unique_ptr<MdtDriftCircleOnTrack> mdtROT{m_mdtRotCreator->createRIO_OnTrack(*mdtPrd,
251 exPars->position(),
252 &momentum)};
253 if (!mdtROT) continue;
254
258 m_mdtRotCreator->updateSign(*mdtROT, side);
259
261 std::optional<const Trk::ResidualPull> resPull{m_pullCalculator->residualPull(mdtROT.get(),
262 exPars.get(),
264 if (!resPull) { continue; }
265
266 const double pull = resPull->pull().front();
267 const double radialResidual = std::abs(mdtROT->localParameters()[Trk::locR]) -
268 std::abs(exPars->parameters()[Trk::locR]);
269
270 unsigned int hitFlag = 1;
271 if (mdtPrd->adc() < m_adcCut || mdtPrd->status() != MdtStatusDriftTime)
272 hitFlag = 3; // noise
273 else if (std::abs(pull) < m_associationPullCutEta)
274 hitFlag = 0; // hit on track
275 else if (radialResidual > 0.)
276 hitFlag = 2; // out of time
277
278 ATH_MSG_VERBOSE(__func__<<"() - Recover "<<m_printer->print(*mdtROT)<<" pull: "<<pull<<" hitFlag: "<<hitFlag);
279 std::unique_ptr<Trk::TrackStateOnSurface> tsos = MuonTSOSHelper::createMeasTSOS(std::move(mdtROT),
280 std::move(exPars),
281 (hitFlag != 0 || !m_addMeasurements) ?
284
285 if (!addedState) {
286 newStates.emplace_back(std::move(tsos));
287 addedState = true;
288 } else {
289 const MdtDriftCircleOnTrack* prevDC = static_cast<const MdtDriftCircleOnTrack*>(newStates.back()->measurementOnTrack());
290 if (prevDC->identify() != mdtPrd->identify()) {
291 newStates.emplace_back(std::move(tsos));
292 } else {
293 ATH_MSG_DEBUG("Two hits recorded for the same tube "<<std::endl<<
294 " *** current: "<<m_printer->print(*tsos->measurementOnTrack())<<std::endl<<
295 " *** previous: "<<m_printer->print(*prevDC));
296 std::optional<Trk::ResidualPull> prevPullObj{m_pullCalculator->residualPull(prevDC,
297 tsos->trackParameters(),
299 const double prevPull = prevPullObj->pull().front();
301 if (std::abs(pull) < std::abs(prevPull) ||
303 newStates.back()->type(Trk::TrackStateOnSurface::Outlier))) {
304 newStates.back() = std::move(tsos);
305 }
306
307 }
308 }
309 chHoles.erase(mdtPrd->identify());
310 knownLayers.insert(mdtPrd->identify());
311 }
312
313 for (const Identifier& hole : chHoles) {
314 const Trk::Surface& surf{getDetectorElement(ctx, hole)->surface(hole)};
315 std::unique_ptr<Trk::TrackParameters> exPars = m_extrapolator->extrapolateDirectly(ctx, pars, surf, Trk::anyDirection, false, Trk::muon);
316 if (!exPars) {
317 ATH_MSG_VERBOSE("Propagation to "<<m_idHelperSvc->toString(hole)<<" failed.");
318 continue;
319 }
320 ATH_MSG_VERBOSE(__func__<<"() - Add hole "<<m_idHelperSvc->toString(hole));
321 newStates.emplace_back(MuonTSOSHelper::createHoleTSOS(std::move(exPars)));
322 }
323 }
325 const Identifier& chambId,
326 const Trk::TrackParameters& pars,
327 NewTrackStates& states, std::set<Identifier>& knownLayers) const {
328
329 NewTrackStates recovered{};
330 if (m_idHelperSvc->isRpc(chambId)) {
331 recovered = recoverChamberClusters(ctx, m_key_rpc, chambId, pars, knownLayers);
332 } else if (m_idHelperSvc->isTgc(chambId)) {
333 recovered = recoverChamberClusters(ctx, m_key_tgc, chambId, pars, knownLayers);
334 } else if (m_idHelperSvc->isCsc(chambId)) {
335 recovered = recoverChamberClusters(ctx, m_key_csc, chambId, pars, knownLayers);
336 } else if (m_idHelperSvc->isMM(chambId)) {
337 recovered = recoverChamberClusters(ctx, m_key_mm, chambId, pars, knownLayers);
338 } else if (m_idHelperSvc->issTgc(chambId)) {
339 recovered = recoverChamberClusters(ctx, m_key_stgc, chambId, pars, knownLayers);
340 }
341 states.insert(states.end(), std::make_move_iterator(recovered.begin()),
342 std::make_move_iterator(recovered.end()));
343 }
345 const EventContext& ctx,
346 const Trk::TrackParameters& pars,
347 std::set<Identifier>& layIds,
348 NewTrackStates& states) const {
349 ATH_MSG_VERBOSE(" performing holes search in chamber " << m_idHelperSvc->toString(detElId));
350 recoverClusterHits(ctx, detElId, pars, states, layIds);
351 }
352
353
355 const Identifier& detElId) const {
357 const MuonGM::MuonDetectorManager* MuonDetMgr{*DetectorManagerHandle};
358 if (!MuonDetMgr) {
359 ATH_MSG_ERROR("Null pointer to the read MuonDetectorManager conditions object");
360 return nullptr;
361 }
362 if (m_idHelperSvc->isMdt(detElId))
363 return MuonDetMgr->getMdtReadoutElement(detElId);
364 else if (m_idHelperSvc->isTgc(detElId))
365 return MuonDetMgr->getTgcReadoutElement(detElId);
366 else if (m_idHelperSvc->isRpc(detElId))
367 return MuonDetMgr->getRpcReadoutElement(detElId);
368 else if (m_idHelperSvc->isCsc(detElId))
369 return MuonDetMgr->getCscReadoutElement(detElId);
370 // New Small Wheel
371 else if (m_idHelperSvc->issTgc(detElId))
372 return MuonDetMgr->getsTgcReadoutElement(detElId);
373 else if (m_idHelperSvc->isMM(detElId))
374 return MuonDetMgr->getMMReadoutElement(detElId);
375 return nullptr;
376 }
377
378 std::set<Identifier> MuonChamberHoleRecoveryTool::holesInMdtChamber(const EventContext& ctx, const Amg::Vector3D& position, const Amg::Vector3D& direction,
379 const Identifier& chId, const std::set<Identifier>& tubeIds) const {
380
382 if (!interSectSvc.isValid()) {
383 ATH_MSG_ERROR("Failed to retrieve chamber intersection service");
384 throw std::runtime_error("No chamber intersection service");
385 }
386
388 const MuonGM::MuonDetectorManager* MuonDetMgr = detMgr.cptr();
389 const MuonGM::MdtReadoutElement* readoutEle = MuonDetMgr->getMdtReadoutElement(chId);
390
391 MuonStationIntersect intersect = interSectSvc->tubesCrossedByTrack(MuonDetMgr, chId, position, direction);
392
393 // clear hole vector
394 std::set<Identifier> holes;
395 for (unsigned int ii = 0; ii < intersect.tubeIntersects().size(); ++ii) {
396 const MuonTubeIntersect& tint = intersect.tubeIntersects()[ii];
397
398 if (tubeIds.count(tint.tubeId)) { continue; }
399 ATH_MSG_VERBOSE(" intersect " << m_idHelperSvc->toString(tint.tubeId) << " dist wire " << tint.rIntersect
400 << " dist to tube end " << tint.xIntersect);
401
402 if (std::abs(tint.rIntersect) > readoutEle->innerTubeRadius() || tint.xIntersect > -10.) {
403 ATH_MSG_VERBOSE(" not counted");
404 continue;
405 }
406 // check whether there is a hit in this tube
407 ATH_MSG_VERBOSE(" hole tube");
408 holes.insert(tint.tubeId);
409
410 }
411 return holes;
412 }
413 template <class Prd> std::vector<const Prd*> MuonChamberHoleRecoveryTool::loadPrepDataHits(const EventContext& ctx,
415 const std::set<Identifier>& gasGapIds) const {
416 std::vector<const Prd*> collectedHits{};
417 if (key.empty()) {
418 ATH_MSG_DEBUG("No container configured for "<<typeid(Prd).name());
419 return collectedHits;
420 }
421 SG::ReadHandle<MuonPrepDataContainerT<Prd>> prdContainer{key, ctx};
422 if (!prdContainer.isPresent()) {
423 ATH_MSG_FATAL("Failed to load prep data collection "<<key.fullKey());
424 throw std::runtime_error("Invalid prepdata container");
425 }
427 std::set<IdentifierHash> chamberIds{};
428 std::transform(gasGapIds.begin(), gasGapIds.end(),
429 std::inserter(chamberIds, chamberIds.end()),
430 [this](const Identifier& id){
431 return m_idHelperSvc->moduleHash(id);
432 });
433 for (const IdentifierHash& moduleHash : chamberIds) {
434 const MuonPrepDataCollection<Prd>* prdColl = prdContainer->indexFindPtr(moduleHash);
435 if (!prdColl) continue;
436 collectedHits.reserve(collectedHits.size() + prdColl->size());
437 for (const Prd* prd: *prdColl) {
438 bool appendPrd{false};
439 if constexpr (std::is_same<Prd, MdtPrepData>::value) {
440 appendPrd = gasGapIds.count(prd->identify());
441 } else {
442 appendPrd = gasGapIds.count(m_idHelperSvc->layerId(prd->identify()));
443 }
444 if (appendPrd) {
445 ATH_MSG_VERBOSE(__func__<<"() - Add prd candidate "<<m_printer->print(*prd));
446 collectedHits.push_back(prd);
447 }
448 }
449 }
452 if constexpr(std::is_same<Prd, MdtPrepData>::value) {
453 std::sort(collectedHits.begin(), collectedHits.end(), [](const Prd* a, const Prd* b){
454 return a->identify() < b->identify();
455 });
456 }
457 return collectedHits;
458 }
459 std::set<Identifier> MuonChamberHoleRecoveryTool::getHoleLayerIds(const Identifier& detElId,
460 const std::set<Identifier>& knownLayers) const {
461 std::set<Identifier> holeGaps{};
462 if (m_idHelperSvc->isMdt(detElId)) {
463 const MdtIdHelper& idHelper{m_idHelperSvc->mdtIdHelper()};
464 for (int ml = 1; ml <= idHelper.numberOfMultilayers(detElId); ++ml) {
465 for (int layer = idHelper.tubeLayerMin(detElId);
466 layer <= idHelper.tubeLayerMax(detElId); ++layer) {
467 const Identifier layerId = idHelper.channelID(detElId, ml, layer, 1);
468 if (!knownLayers.count(layerId)) holeGaps.insert(layerId);
469 }
470 }
471 } else if (m_idHelperSvc->isMM(detElId)) {
472 const MmIdHelper& idHelper{m_idHelperSvc->mmIdHelper()};
473 for (int ml : {1 ,2}) {
474 for (int gap = MmIdHelper::gasGapMin(); gap <= MmIdHelper::gasGapMax(); ++gap) {
475 const Identifier layerId = idHelper.channelID(detElId, ml, gap, 1);
476 if (!knownLayers.count(layerId)) holeGaps.insert(layerId);
477 }
478 }
479 } else if (m_idHelperSvc->issTgc(detElId)) {
480 const sTgcIdHelper& idHelper{m_idHelperSvc->stgcIdHelper()};
481 using channelType = sTgcIdHelper::sTgcChannelTypes;
482 for (int ml : {1, 2}) {
483 for (const channelType chType : {channelType::Strip,
484 channelType::Pad,
485 channelType::Wire}){
486 for (int gap = sTgcIdHelper::gasGapMin();
487 gap <= sTgcIdHelper::gasGapMax(); ++gap) {
488 const Identifier layerId = idHelper.channelID(detElId, ml, gap, chType, 1);
489 if (!knownLayers.count(layerId)) holeGaps.insert(layerId);
490 }
491 }
492 }
493 } else if (m_idHelperSvc->isTgc(detElId)) {
494 const TgcIdHelper& idHelper = m_idHelperSvc->tgcIdHelper();
495 const int gapMax{idHelper.gasGapMax(detElId)};
496 for (int gasgap = idHelper.gasGapMin(detElId);
497 gasgap < gapMax; ++gasgap){
498 for (int measPhi: {0,1}) {
500 if (gapMax == 3 && gasgap ==2 && measPhi == 1) continue;
501 const Identifier layerId = idHelper.channelID(detElId, gasgap, measPhi, 1);
502 if (!knownLayers.count(layerId)) holeGaps.insert(layerId);
503 }
504 }
505 } else if (m_idHelperSvc->isRpc(detElId)) {
506 const RpcIdHelper& idHelper = m_idHelperSvc->rpcIdHelper();
507 const int doubZ{idHelper.doubletZ(detElId)};
508 const int gapMax{idHelper.gasGapMax(detElId)};
509 for (int phiGap = idHelper.doubletPhi(detElId);
510 phiGap <= idHelper.doubletPhiMax(detElId); ++phiGap) {
511 for (int gap = idHelper.gasGapMin(detElId);
512 gap <= gapMax; ++gap) {
513 for (int measPhi: {0, 1}) {
514 const Identifier layerId = idHelper.channelID(detElId, doubZ, phiGap, gap, measPhi, 1);
515 if (!knownLayers.count(layerId)) holeGaps.insert(layerId);
516 }
517 }
518 }
519 } else if (m_idHelperSvc->isCsc(detElId)) {
520 const CscIdHelper& idHelper{m_idHelperSvc->cscIdHelper()};
521 for (int layer = 1; layer <= 4; ++ layer) {
522 for (bool measPhi: {false, true}) {
523 const Identifier layId = idHelper.channelID(detElId, 2, layer, measPhi, 1);
524 if (!knownLayers.count(layId)) holeGaps.insert(layId);
525 }
526 }
527 }
528 return holeGaps;
529 }
530 template <class Prd> NewTrackStates MuonChamberHoleRecoveryTool::recoverChamberClusters(const EventContext& ctx,
532 const Identifier& detElId,
533 const Trk::TrackParameters& parsInChamb,
534 std::set<Identifier>& knownLayers) const {
535 NewTrackStates recoveredStates{};
536 const std::set<Identifier> missingLayers = getHoleLayerIds(detElId, knownLayers);
537 std::vector<const Prd*> prdCandidates = loadPrepDataHits(ctx, prdKey, missingLayers);
539 using LayerParsMap = std::map<Identifier, std::unique_ptr<Trk::TrackParameters>>;
540 LayerParsMap parsAtSurfMap{};
541 for (const Identifier& holeId : missingLayers) {
542 const Trk::TrkDetElementBase* detEl = getDetectorElement(ctx, holeId);
543 const Trk::Surface& surf{detEl->surface(holeId)};
544 std::unique_ptr<Trk::TrackParameters> pars = m_extrapolator->extrapolateDirectly(ctx, parsInChamb, surf,
546 if (!pars) {
547 ATH_MSG_VERBOSE("Surface layer "<<m_idHelperSvc->toStringGasGap(holeId)<<" cannot be reached");
548 continue;
549 }
550 if (!Amg::hasPositiveDiagElems(*pars->covariance())) {
551 ATH_MSG_DEBUG("Uncertainties of extraploation to "<<m_idHelperSvc->toStringGasGap(holeId)<<" blew up");
552 continue;
553 }
554 const Amg::Vector2D locExPos{pars->parameters()[Trk::locX],
555 pars->parameters()[Trk::locY]};
556 bool inbounds{false};
557 if constexpr(std::is_same<Prd, MMPrepData>::value) {
558 inbounds = static_cast<const MuonGM::MMReadoutElement*>(detEl)->insideActiveBounds(holeId, locExPos, 10.,10.);
559 } else {
560 inbounds = surf.insideBounds(locExPos, 10., 10.);
561 }
563 if (!inbounds) {
564 ATH_MSG_VERBOSE("Extrapolation to layer "<<m_idHelperSvc->toStringGasGap(holeId)
565 <<" is outside of the chamber "<<Amg::toString(locExPos, 2));
566 continue;
567 }
568 parsAtSurfMap[holeId] = std::move(pars);
569 }
570 ClusterLayerMap bestClusterInLay;
572 for (const Prd* hit : prdCandidates) {
573 const Identifier layId = m_idHelperSvc->layerId(hit->identify());
575 LayerParsMap::const_iterator pars_itr = parsAtSurfMap.find(layId);
576 if (pars_itr == parsAtSurfMap.end()) {
577 continue;
578 }
579 const std::unique_ptr<Trk::TrackParameters>& parsInLay{pars_itr->second};
580 std::unique_ptr<MuonClusterOnTrack> calibClus{};
581 if constexpr(std::is_same<Prd, CscPrepData>::value) {
582 calibClus.reset(m_cscRotCreator->createRIO_OnTrack(*hit,
583 parsInLay->position(),
584 parsInLay->momentum().unit()));
585 } else {
586 calibClus.reset(m_clusRotCreator->createRIO_OnTrack(*hit,
587 parsInLay->position(),
588 parsInLay->momentum().unit()));
589 }
590 if (!calibClus) continue;
591
592 if constexpr (std::is_same<Prd, sTgcPrepData>::value) {
593 const sTgcIdHelper& idHelper{m_idHelperSvc->stgcIdHelper()};
594 if (idHelper.channelType(hit->identify()) == sTgcIdHelper::sTgcChannelTypes::Pad){
596 const Amg::Vector2D locExPos{parsInLay->parameters()[Trk::locX],
597 parsInLay->parameters()[Trk::locY]};
598
599 const MuonGM::MuonPadDesign* pad = hit->detectorElement()->getPadDesign(hit->identify());
600 const Amg::Vector2D padDist = pad->distanceToPad(locExPos, idHelper.channel(hit->identify()));
601
603 const double xCov = std::hypot(Amg::error(*parsInLay->covariance(), Trk::locX),
604 Amg::error(hit->localCovariance(), Trk::locX));
606 const double yCov =Amg::error(*parsInLay->covariance(), Trk::locY);
607
608 const double xPull = padDist.x() / xCov;
609 const double yPull = padDist.y() / yCov;
610
611 ATH_MSG_VERBOSE(__func__<<"() - check "<<m_printer->print(*calibClus)
612 <<" diff "<<Amg::toString(padDist, 2)
613 <<" covariance: ("<<xCov<<", "<<yCov<<")"
614 <<" pull: ("<<xPull<<","<<yPull<<").");
615
617 if (xPull > m_associationPullCutEta || yPull > m_associationPullCutPhi) continue;
618 const double pull = std::hypot(xPull, yPull);
619
621 PullCluster& bestClus = bestClusterInLay[layId];
622 if (bestClus.pull < pull) continue;
623 bestClus.pull = pull;
624 bestClus.clus = std::move(calibClus);
625 bestClus.pars = parsInLay->uniqueClone();
626 continue;
627 }
628 }
629
631 std::optional<const Trk::ResidualPull> resPull{
632 m_pullCalculator->residualPull(calibClus.get(), parsInLay.get(),
634 if (!resPull || resPull->pull().empty()) {
635 continue;
636 }
637
638 const double pull = std::abs(resPull->pull().front());
639 const double pullCut = m_idHelperSvc->measuresPhi(layId) ? m_associationPullCutPhi
641 if (pull > pullCut) continue;
642
643 PullCluster& bestClus = bestClusterInLay[layId];
644 if (bestClus.pull < pull) continue;
645 bestClus.pull = pull;
646 bestClus.clus = std::move(calibClus);
647 bestClus.pars = parsInLay->uniqueClone();
648
649 }
651 for (auto& [layerId, foundClus]: bestClusterInLay) {
652 ATH_MSG_VERBOSE(__func__<<"() recovered hit " << m_printer->print(*foundClus.clus)<<" pull: "<<foundClus.pull);
653 std::unique_ptr<Trk::TrackStateOnSurface> tsos = MuonTSOSHelper::createMeasTSOS(std::move(foundClus.clus),
654 std::move(foundClus.pars),
656 recoveredStates.emplace_back(std::move(tsos));
657 knownLayers.insert(layerId);
658 parsAtSurfMap[layerId].reset();
659 }
661 for (auto& [layerId, exPars] : parsAtSurfMap) {
662 if (!exPars) continue;
663 ATH_MSG_VERBOSE(__func__<<"() add new hole state "<<m_idHelperSvc->toStringGasGap(layerId));
664 recoveredStates.emplace_back(MuonTSOSHelper::createHoleTSOS(std::move(exPars)));
665 }
666 return recoveredStates;
667 }
668} // namespace Muon
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_DEBUG(x)
static Double_t a
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
Identifier channelID(int stationName, int stationEta, int stationPhi, int chamberLayer, int wireLayer, int measuresPhi, int strip) const
DataModel_detail::const_iterator< DataVector > const_iterator
Definition DataVector.h:838
size_type size() const noexcept
Returns the number of elements in the collection.
This is a "hash" representation of an Identifier.
bool is_valid() const
Check if id is in a valid state.
static int tubeLayerMax()
int numberOfMultilayers(const Identifier &id) const
static int tubeLayerMin()
Identifier channelID(int stationName, int stationEta, int stationPhi, int multilayer, int tubeLayer, int tube) const
Identifier channelID(int stationName, int stationEta, int stationPhi, int multilayer, int gasGap, int channel) const
static int gasGapMax()
static int gasGapMin()
An MMReadoutElement corresponds to a single STGC module; therefore typicaly a barrel muon station con...
double innerTubeRadius() const
Returns the inner tube radius excluding the aluminium walls.
The MuonDetectorManager stores the transient representation of the Muon Spectrometer geometry and pro...
const RpcReadoutElement * getRpcReadoutElement(const Identifier &id) const
access via extended identifier (requires unpacking)
const MdtReadoutElement * getMdtReadoutElement(const Identifier &id) const
access via extended identifier (requires unpacking)
const MMReadoutElement * getMMReadoutElement(const Identifier &id) const
access via extended identifier (requires unpacking)
const TgcReadoutElement * getTgcReadoutElement(const Identifier &id) const
access via extended identifier (requires unpacking)
const sTgcReadoutElement * getsTgcReadoutElement(const Identifier &id) const
access via extended identifier (requires unpacking)
const CscReadoutElement * getCscReadoutElement(const Identifier &id) const
access via extended identifier (requires unpacking)
Class for competing MuonClusters, it extends the Trk::CompetingRIOsOnTrack base class.
This class represents the corrected MDT measurements, where the corrections include the effects of wi...
Class to represent measurements from the Monitored Drift Tubes.
Definition MdtPrepData.h:33
SG::ReadHandleKey< Muon::RpcPrepDataContainer > m_key_rpc
SG::ReadHandleKey< Muon::TgcPrepDataContainer > m_key_tgc
void recoverClusterHits(const EventContext &ctx, const Identifier &chId, const Trk::TrackParameters &chambPars, NewTrackStates &newStates, std::set< Identifier > &knownLayers) const
ToolHandle< Trk::IExtrapolator > m_extrapolator
const Trk::TrkDetElementBase * getDetectorElement(const EventContext &ctx, const Identifier &id) const
Returns the detector element associated with the muon Identifier.
void recoverMdtHits(const EventContext &ctx, const Identifier &chId, const Trk::TrackParameters &pars, NewTrackStates &newStates, std::set< Identifier > &knownLayers) const
std::set< Identifier > layersOnTrkIds(const Trk::Track &track) const
Returns a set of all layer Identifiers of the associated track hits.
std::unique_ptr< Trk::Track > recover(const Trk::Track &track, const EventContext &ctx) const override
returns a new track with holes recovered
ServiceHandle< Muon::IMuonEDMHelperSvc > m_edmHelperSvc
void recoverHitsInChamber(const EventContext &ctx, RecoveryState &trkRecov) const
Loops over all muon hits in a muon chamber and tries to find missed ones by checking each tracking la...
std::set< Identifier > getHoleLayerIds(const Identifier &detElId, const std::set< Identifier > &knownLayers) const
Returns a set of all layer Identifiers (GasGap + channel orientation) in a muon chamber of type X exc...
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
SG::ReadHandleKey< Muon::MdtPrepDataContainer > m_key_mdt
SG::ReadHandleKey< Muon::sTgcPrepDataContainer > m_key_stgc
ToolHandle< Muon::IMuonClusterOnTrackCreator > m_clusRotCreator
std::set< Identifier > holesInMdtChamber(const EventContext &ctx, const Amg::Vector3D &position, const Amg::Vector3D &direction, const Identifier &chId, const std::set< Identifier > &tubeIds) const
calculate holes in a given chamber using local straight line extrapolation
std::vector< const Prd * > loadPrepDataHits(const EventContext &ctx, const SG::ReadHandleKey< MuonPrepDataContainerT< Prd > > &key, const std::set< Identifier > &layerIds) const
bool getNextMuonMeasurement(RecoveryState &trkRecov, RecoveryState::CopyTarget target) const
Increments the internal iterator of the RecoveryState until the next muon measurement on track is fou...
NewTrackStates recoverChamberClusters(const EventContext &ctx, const SG::ReadHandleKey< MuonPrepDataContainerT< Prd > > &prdKey, const Identifier &chambId, const Trk::TrackParameters &parsInChamb, std::set< Identifier > &knownLayers) const
Attempts to recover all missing hits in a chamber.
SG::ReadHandleKey< Muon::CscPrepDataContainer > m_key_csc
std::vector< std::unique_ptr< const Trk::TrackStateOnSurface > > NewTrackStates
ToolHandle< Muon::IMuonClusterOnTrackCreator > m_cscRotCreator
PublicToolHandle< Muon::MuonEDMPrinterTool > m_printer
SG::ReadCondHandleKey< MuonGM::MuonDetectorManager > m_DetectorManagerKey
SG::ReadCondHandleKey< Muon::MuonIntersectGeoData > m_chamberGeoKey
ToolHandle< Trk::IResidualPullCalculator > m_pullCalculator
ToolHandle< Muon::IMdtDriftCircleOnTrackCreator > m_mdtRotCreator
void createHoleTSOSsForClusterChamber(const Identifier &detElId, const EventContext &ctx, const Trk::TrackParameters &pars, std::set< Identifier > &layIds, NewTrackStates &states) const override
MuonChamberHoleRecoveryTool(const std::string &, const std::string &, const IInterface *)
ServiceHandle< Trk::ITrackingVolumesSvc > m_trackingVolumesSvc
SG::ReadHandleKey< Muon::MMPrepDataContainer > m_key_mm
Base class for Muon cluster RIO_OnTracks.
Template to hold collections of MuonPrepRawData objects.
static std::unique_ptr< Trk::TrackStateOnSurface > createHoleTSOS(std::unique_ptr< Trk::TrackParameters > pars)
create a hole TSOS, takes ownership of the pointers
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
Identifier channelID(int stationName, int stationEta, int stationPhi, int doubletR, int doubletZ, int doubletPhi, int gasGap, int measuresPhi, int strip) const
int gasGapMax() const
static int gasGapMin()
int doubletPhi(const Identifier &id) const
static int doubletPhiMax()
int doubletZ(const Identifier &id) const
const_pointer_type cptr()
Property holding a SG store/key/clid from which a ReadHandle is made.
bool isPresent() const
Is the referenced object present in SG?
static int gasGapMax(bool triplet)
static int gasGapMin()
Identifier channelID(int stationName, int stationEta, int stationPhi, int gasGap, int isStrip, int channel) const
@ MuonSpectrometerEntryLayer
Tracking Volume which defines the entrance surfaces of the MS.
This class is the pure abstract base class for all fittable tracking measurements.
Identifier identify() const
return the identifier -extends MeasurementBase
@ Unbiased
RP with track state that has measurement not included.
Class for a StraightLineSurface in the ATLAS detector to describe dirft tube and straw like detectors...
virtual bool globalToLocal(const Amg::Vector3D &glob, const Amg::Vector3D &mom, Amg::Vector2D &loc) const override final
Specified for StraightLineSurface: GlobalToLocal method without dynamic memory allocation This method...
virtual bool insideBounds(const Amg::Vector2D &locpos, double tol1=0., double tol2=0.) const override final
This surface calls the iside method of the bouns.
Abstract Base Class for tracking surfaces.
virtual bool insideBounds(const Amg::Vector2D &locpos, double tol1=0., double tol2=0.) const =0
virtual methods to be overwritten by the inherited surfaces
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
bool type(const TrackStateOnSurfaceType type) const
Use this method to find out if the TSoS is of a certain type: i.e.
@ Measurement
This is a measurement, and will at least contain a Trk::MeasurementBase.
@ Outlier
This TSoS contains an outlier, that is, it contains a MeasurementBase/RIO_OnTrack which was not used ...
@ Hole
A hole on the track - this is defined in the following way.
This is the base class for all tracking detector elements with read-out relevant information.
virtual const Surface & surface() const =0
Return surface associated with this detector element.
Base class for all volumes inside the tracking realm, it defines the interface for inherited Volume c...
Definition Volume.h:36
bool inside(const Amg::Vector3D &gp, double tol=0.) const
Inside() method for checks.
Definition Volume.cxx:72
static int gasGapMin()
int channelType(const Identifier &id) const
static int gasGapMax()
int channel(const Identifier &id) const override
Identifier channelID(int stationName, int stationEta, int stationPhi, int multilayer, int gasGap, int channelType, int channel) const
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
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 ...
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, 2, 1 > Vector2D
Eigen::Matrix< double, 3, 1 > Vector3D
ChIndex
enum to classify the different chamber layers in the muon spectrometer
NRpcCablingAlg reads raw condition data and writes derived condition data to the condition store.
MuonChamberHoleRecoveryTool::NewTrackStates NewTrackStates
MuonPrepDataContainer< MuonPrepDataCollection< PrdType > > MuonPrepDataContainerT
@ MdtStatusDriftTime
The tube produced a vaild measurement.
@ anyDirection
DriftCircleSide
Enumerates the 'side' of the wire on which the tracks passed (i.e.
@ RIGHT
the drift radius is positive (see Trk::AtaStraightLine)
@ LEFT
the drift radius is negative (see Trk::AtaStraightLine)
@ driftRadius
trt, straws
Definition ParamDefs.h:53
@ locY
local cartesian
Definition ParamDefs.h:38
@ locX
Definition ParamDefs.h:37
@ locR
Definition ParamDefs.h:44
ParametersBase< TrackParametersDim, Charged > TrackParameters
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
void stable_sort(DataModel_detail::iterator< DVL > beg, DataModel_detail::iterator< DVL > end)
Specialization of stable_sort for DataVector/List.
Parameters defining the design of the readout sTGC pads.
Amg::Vector2D distanceToPad(const Amg::Vector2D &pos, int channel) const
const Trk::TrackParameters * chamberPars() const
Track parameters of the chamber.
void finalizeChamber()
Sorts the hits accumulated in the current chamber using the first track parameters in that chamber.
std::set< Identifier > layersOnTrk
List of all measurement layers on track.
NewTrackStates chamberStates
Vector of the track states on surface in the current chamber.
Identifier tsosId
Identifier of the current trackStateOnSurface.
std::set< const Trk::TrackStateOnSurface * > m_copiedStates
CopyTarget
Switch indicating whether the track states are copied onto the global cache vector or onto the chambe...
std::unique_ptr< Trk::TrackStates > releaseStates()
Moves the recovered track states on surface onto a Trk::TrackStates to be piped into a new Trk::Track...