ATLAS Offline Software
Loading...
Searching...
No Matches
MuonStauRecoTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include "MuonStauRecoTool.h"
6
7#include <memory>
8
10#include "GaudiKernel/ConcurrencyFlags.h"
29
30namespace {
31 constexpr double inverseSpeedOfLight = 1 / Gaudi::Units::c_light; // need 1/299.792458 inside calculateTof()/calculateBeta()
32
33}
34using namespace Muon::MuonStationIndex;
35namespace MuonCombined {
36
38 std::ostringstream sout;
39 sout << " sector " << intersection.layerSurface.sector << " "
40 << Muon::MuonStationIndex::regionName(intersection.layerSurface.regionIndex) << " "
41 << Muon::MuonStationIndex::layerName(intersection.layerSurface.layerIndex);
42 return sout.str();
43 }
44
45 MuonStauRecoTool::MuonStauRecoTool(const std::string& type, const std::string& name, const IInterface* parent) :
46 AthAlgTool(type, name, parent) {}
47
49 ATH_CHECK(m_idHelperSvc.retrieve());
50 ATH_CHECK(m_printer.retrieve());
51 ATH_CHECK(m_edmHelperSvc.retrieve());
52 ATH_CHECK(m_segmentMaker.retrieve());
56 ATH_CHECK(m_hitTimingTool.retrieve());
59 ATH_CHECK(m_mdtCreator.retrieve());
60 ATH_CHECK(m_mdtCreatorStau.retrieve());
62 ATH_CHECK(m_updator.retrieve());
63 ATH_CHECK(m_calibDbKey.initialize());
65
66 if (m_doTruth) {
67 // add pdgs from jobO to set
68 for (auto pdg : m_pdgsToBeConsidered.value()) { m_selectedPdgs.insert(pdg); }
69 }
70 return StatusCode::SUCCESS;
71 }
72
75 TrackCollection* meTracks, Trk::SegmentCollection* segments, const EventContext& ctx) const {
76 // Maybe we'll need this later, I wouldn't be surprised if the PRDs are retrieved somewhere down the chain
77 // For now it's just a placeholder though
78 if (!prdData.mdtPrds) ATH_MSG_DEBUG("empty PRDs passed");
79 extend(inDetCandidates, tagMap, combTracks, meTracks, segments, ctx);
80 }
81
83 TrackCollection* combTracks, TrackCollection* meTracks, Trk::SegmentCollection* segments,
84 const EventContext& ctx) const {
85 ATH_MSG_DEBUG(" extending " << inDetCandidates.size());
86
87 if (meTracks) ATH_MSG_DEBUG("Not currently creating ME tracks for staus");
88 for (const InDetCandidate* it : inDetCandidates) { handleCandidate(ctx, *it, tagMap, combTracks, segments); }
89 }
90
91 std::unique_ptr<MuonStauRecoTool::TruthInfo>
92 MuonStauRecoTool::getTruth(const xAOD::TrackParticle& indetTrackParticle) const {
93 // in case we are using the truth, check if the truth link is set and create the TruthInfo object
95 truthParticleLinkAcc("truthParticleLink");
96 if (m_doTruth && truthParticleLinkAcc.isAvailable(indetTrackParticle)) {
97 const ElementLink<xAOD::TruthParticleContainer>& truthLink = truthParticleLinkAcc(indetTrackParticle);
98 if (truthLink.isValid()) {
99 return std::make_unique<TruthInfo>((*truthLink)->pdgId(), (*truthLink)->m(), (*truthLink)->p4().Beta());
100 }
101 }
102 return nullptr;
103 }
104
105 void MuonStauRecoTool::handleCandidate(const EventContext& ctx, const InDetCandidate& indetCandidate, InDetCandidateToTagMap* tagMap,
106 TrackCollection* combTracks, Trk::SegmentCollection* segments) const {
107 if (m_ignoreSiAssocated && indetCandidate.isSiliconAssociated()) {
108 ATH_MSG_DEBUG(" skip silicon associated track for extension ");
109 return;
110 }
111
115
116 // get TrackParticle and apply the kinematic selection
117 const xAOD::TrackParticle& indetTrackParticle = indetCandidate.indetTrackParticle();
118 if (!indetTrackParticle.track() || indetTrackParticle.pt() < m_ptThreshold) return;
119
120 // get truth info (will be zero pointer if running on data or m_doTruth == false)
121 std::unique_ptr<TruthInfo> truthInfo(getTruth(indetTrackParticle));
122
123 // if truth based reconstruction is enabled, check whether to accept the given pdgId
124 if (!selectTruth(truthInfo.get())) {
125 ATH_MSG_DEBUG("Truth reconstruction enabled: skipping ID track with pdgId: " << (truthInfo ? truthInfo->pdgId : 0));
126 return;
127 }
128
129 // get intersections which precision layers in the muon system
130 const Muon::MuonSystemExtension* muonSystemExtension = indetCandidate.getExtension();
131
132 // summary for selected ID track
133 if (m_doSummary || msgLvl(MSG::DEBUG)) {
134 msg(MSG::INFO) << " ID track: pt " << indetTrackParticle.pt() << " eta " << indetTrackParticle.eta() << " phi "
135 << indetTrackParticle.phi();
136 if (truthInfo) msg(MSG::INFO) << truthInfo->toString();
137 if (!muonSystemExtension) msg(MSG::INFO) << " failed muonSystemExtension";
138 msg(MSG::INFO) << endmsg;
139 }
140
141 // exit if no MuonSystemExtension was found
142 if (!muonSystemExtension) { return; }
143
144 // fill validation content
145 if (!m_recoValidationTool.empty()) m_recoValidationTool->addTrackParticle(indetTrackParticle, *muonSystemExtension);
149
150 AssociatedData associatedData;
151 if (!extractTimeMeasurements(ctx, *muonSystemExtension, associatedData)) { return; }
152
156
157 CandidateVec candidates;
158 if (!createCandidates(associatedData, candidates)) { return; }
159
160 if (!m_recoValidationTool.empty()) addCandidatesToNtuple(indetTrackParticle, candidates, 0);
161
165
166 if (!refineCandidates(ctx, candidates)) { return; }
167
168 if (!m_recoValidationTool.empty()) addCandidatesToNtuple(indetTrackParticle, candidates, 1);
169
173
174 if (!combineCandidates(ctx, indetTrackParticle, candidates)) { return; }
175
176 if (!m_recoValidationTool.empty()) addCandidatesToNtuple(indetTrackParticle, candidates, 2);
180
181 if (!resolveAmbiguities(candidates)) { return; }
182
183 if (!m_recoValidationTool.empty()) addCandidatesToNtuple(indetTrackParticle, candidates, 3);
187 addTag(indetCandidate, *candidates.front(), tagMap, combTracks, segments);
188 }
189
190 bool MuonStauRecoTool::refineCandidates(const EventContext& ctx, MuonStauRecoTool::CandidateVec& candidates) const {
191 // keep track of candidates for which segments are found
192 CandidateVec refinedCandidates;
193
194 // loop over candidates and redo segments using beta estimate from candidate
195 ATH_MSG_DEBUG("Refining candidates " << candidates.size());
196 for (auto& candidate : candidates) {
197 ATH_MSG_DEBUG(" candidate: betaseed beta" << candidate->betaSeed.beta << ", error" << candidate->betaSeed.error
198 << " layerDataVec size" << candidate->layerDataVec.size() << " hits size"
199 << candidate->hits.size());
200
201 float beta = candidate->betaFitResult.beta;
202 // loop over layers and perform segment finding, collect segments per layer
203 for (const auto& layerData : candidate->layerDataVec) {
204 // store segments in layer
205 std::vector<std::shared_ptr<const Muon::MuonSegment>> segments;
206
207 // loop over maxima
208 for (const auto& maximumData : layerData.maximumDataVec) {
209 // find segments for intersection
210 findSegments(layerData.intersection, *maximumData, segments, m_muonPRDSelectionToolStau, m_segmentMaker, beta);
211 }
212
213 // skip if no segment were found
214 if (segments.empty()) continue;
215
216 // fill validation content
217 if (!m_recoValidationTool.empty()) {
218 for (const auto& seg : segments) m_recoValidationTool->add(layerData.intersection, *seg, 2);
219 }
220
221 // match segments to intersection, store the ones that match
222 std::vector<std::shared_ptr<const Muon::MuonSegment>> selectedSegments;
223 m_segmentMatchingTool->select(ctx, layerData.intersection, segments, selectedSegments);
224 // fill validation content
225 if (!m_recoValidationTool.empty()) {
226 for (const auto& seg : selectedSegments) m_recoValidationTool->add(layerData.intersection, *seg, 3);
227 }
228
229 // add layer list
230 candidate->allLayers.emplace_back(layerData.intersection, std::move(selectedSegments));
231 }
232
233 // keep candidate if any segments were found
234 if (!candidate->allLayers.empty()) refinedCandidates.push_back(candidate);
235 }
236
237 // set candidates to the refinedCandidates
238 candidates = refinedCandidates;
239
240 // print results afer refineCandidate
241 if (m_doSummary || msgLvl(MSG::DEBUG)) {
242 msg(MSG::INFO) << " Summary::refineCandidates ";
243 if (candidates.empty())
244 msg(MSG::INFO) << " No candidated found ";
245 else
246 msg(MSG::INFO) << " candidates " << candidates.size();
247
248 for (const auto& candidate : candidates) {
249 msg(MSG::INFO) << std::endl
250 << " candidate: beta fit result: beta " << candidate->betaFitResult.beta << " chi2/ndof "
251 << candidate->betaFitResult.chi2PerDOF() << " layers with segments" << candidate->allLayers.size();
252 for (const auto& layer : candidate->allLayers)
253 msg(MSG::INFO) << std::endl
254 << " " << printIntersectionToString(layer.intersection) << " segments " << layer.segments.size();
255 }
256 msg(MSG::INFO) << endmsg;
257 }
258
259 return !candidates.empty();
260 }
261
263 Candidate& candidate) const {
264
266 if (!mdtCalibConstants.isValid()) {
267 ATH_MSG_FATAL("Failed to retrieve calibration constants "<<m_calibDbKey.fullKey());
268 throw std::runtime_error("Failed to retrieve calibration constants");
269 }
270 ATH_MSG_VERBOSE("extractTimeMeasurementsFromTrack for candidate: beta seed " << candidate.betaSeed.beta);
271 Trk::Track* combinedTrack = candidate.combinedTrack.get();
272 if (!combinedTrack) return;
273
274 // select around seed
275 float betaSeed = candidate.betaFitResult.beta;
276
277 // fitter + hits
280
281 // loop over track and calculate residuals
282 const Trk::TrackStates* states = combinedTrack->trackStateOnSurfaces();
283 if (!states) {
284 ATH_MSG_WARNING(" track without states, cannot extractTimeMeasurementsFromTrack ");
285 return;
286 }
287
288 ATH_MSG_VERBOSE("Track : " << (*combinedTrack));
289
290 // store RPC prds for clustering
291 typedef std::vector<const Muon::MuonClusterOnTrack*> RpcClVec;
292 using RpcClPerChMap = std::map<Identifier, std::tuple<const Trk::TrackParameters*, RpcClVec, RpcClVec>>;
293 RpcClPerChMap rpcPrdsPerChamber;
294
295 using MdtTubeData = std::pair<const Trk::TrackParameters*, const Muon::MdtDriftCircleOnTrack*>;
296 using MdtTubeDataVec = std::vector<MdtTubeData>;
297 using MdtChamberLayerData = std::map<int, MdtTubeDataVec>;
298 MdtChamberLayerData mdtDataPerChamberLayer;
299
300 // loop over TSOSs
301 Trk::TrackStates::const_iterator tsit = states->begin();
302 Trk::TrackStates::const_iterator tsit_end = states->end();
303 for (; tsit != tsit_end; ++tsit) {
304 const Trk::TrackParameters* pars = (*tsit)->trackParameters();
305 if (!pars) continue;
306
307 // check whether state is a measurement
308 const Trk::MeasurementBase* meas = (*tsit)->measurementOnTrack();
309 if (!meas || (*tsit)->type(Trk::TrackStateOnSurface::Outlier)) continue;
310
311 // get Identifier and skip pseudo measurements, ID hits and all but MDT/RPC hits
312 Identifier id = m_edmHelperSvc->getIdentifier(*meas);
313 if (!id.is_valid() || !m_idHelperSvc->isMuon(id)) continue;
314
315 // extract time measurements for RPCs
316 if (m_idHelperSvc->isMdt(id)) {
317 // MDTs
318 const Muon::MdtDriftCircleOnTrack* mdt = dynamic_cast<const Muon::MdtDriftCircleOnTrack*>(meas);
319 if (!mdt) continue;
320
321 if (m_segmentMDTT) {
322 int chIndexWithBIR = toInt(m_idHelperSvc->chamberIndex(mdt->identify()));
323 if (chIndexWithBIR == toInt(ChIndex::BIL)) {
324 std::string stName = m_idHelperSvc->chamberNameString(id);
325 if (stName[2] == 'R') { chIndexWithBIR += 1000; }
326 }
327 mdtDataPerChamberLayer[chIndexWithBIR].push_back(std::make_pair(pars, mdt));
328 } else {
330 float distance = pars->position().mag();
331 float time = 0.;
332
333 float ix = pars->position().x();
334 float iy = pars->position().y();
335 float iz = pars->position().z();
336 float ie = 0.;
337 float er = -1;
338 float sh = 0;
339 bool isEta = !m_idHelperSvc->measuresPhi(id);
340 float propTime = 0;
341 float tof = calculateTof(1, distance);
342
343 // use inverted RT relation together with track prediction to get estimate of drift time
344 float driftTime = mdt->driftTime(); // we need to add beta seed as it was subtracted when calibrating the hits
345 float locR = pars->parameters()[Trk::locR];
346 float errR = pars->covariance() ? Amg::error(*pars->covariance(), Trk::locR) : 0.3;
347 auto data = mdtCalibConstants->getCalibData(id, msgStream());
348 const auto& rtRelation = data->rtRelation;
349 float drdt = rtRelation->rt()->driftVelocity(driftTime);
350 float rres = rtRelation->rtRes()->resolution(driftTime);
351 float tres = rres / drdt;
352 float TlocR = rtRelation->tr()->driftTime(std::abs(locR)).value_or(0.);
353 float trackTimeRes = errR / drdt;
354 float tofShiftFromBeta = calculateTof(betaSeed, distance) - tof;
355 er = std::sqrt(tres * tres + trackTimeRes * trackTimeRes);
356 mdtTimeCalibration(id, driftTime, er);
357 time = driftTime - TlocR + tofShiftFromBeta;
358 propTime = driftTime;
359 ie = trackTimeRes;
360 // try removal of hit from fit
361 if (!m_updator.empty()) {
362 std::unique_ptr<const Trk::TrackParameters> unbiasedPars(
363 m_updator->removeFromState(*pars, meas->localParameters(), meas->localCovariance()));
364 if (unbiasedPars) {
365 float locRu = unbiasedPars->parameters()[Trk::locR];
366 float TlocRu = rtRelation->tr()->driftTime(std::abs(locRu)).value_or(0.);
367 float errRu = unbiasedPars->covariance() ? Amg::error(*unbiasedPars->covariance(), Trk::locR) : 0.3;
368 float trackTimeResu = errRu / drdt;
369 sh = TlocR - TlocRu;
370 time = driftTime - TlocRu + tofShiftFromBeta;
371 er = std::sqrt(tres * tres + trackTimeResu * trackTimeResu);
372 ie = trackTimeResu;
373 ATH_MSG_VERBOSE(" Got unbiased parameters: r " << locR << " ur " << locRu << " err " << errR << " uerr "
374 << errRu << " terr " << trackTimeRes << " terru "
375 << trackTimeResu);
376 }
377 }
378
379 ATH_MSG_VERBOSE(" MDT " << mdt->driftRadius() << " locR " << locR << " err " << errR << " drift time " << driftTime
380 << " TlocR " << TlocR << " diff " << driftTime - TlocR << " tofShift " << tofShiftFromBeta
381 << " time " << time << " err " << er << " intrinsic " << tres << " track " << trackTimeRes);
382
383 float beta = calculateBeta(time + tof, distance);
384 ATH_MSG_VERBOSE(" adding " << m_idHelperSvc->toString(id) << " distance " << distance << " time " << time << " beta"
385 << beta << " diff " << std::abs(beta - betaSeed));
386 if (std::abs(beta - betaSeed) > m_mdttBetaAssociationCut) {
387 // write out hits that don't pass the beta association cut but don't use them
388 candidate.stauHits.emplace_back(MuGirlNS::StauHit(tech, time + tof, ix, iy, iz, id, ie, er, sh, isEta, propTime, false));
390 float iadc = mdt->prepRawData()->adc();
391 float irdrift = mdt->driftRadius();
392 candidate.stauMDTHitExtras.emplace_back(MuGirlNS::StauMDTHitExtra(iadc, irdrift));
393 }
394 continue;
395 }
396
397 // only store hits for future use if they pass the beta association cut
398 hits.emplace_back(Muon::TimePointBetaFitter::Hit(distance, time, er));
399 candidate.stauHits.emplace_back(MuGirlNS::StauHit(tech, time + tof, ix, iy, iz, id, ie, er, sh, isEta, propTime, true));
400
402 float iadc = mdt->prepRawData()->adc();
403 float irdrift = mdt->driftRadius();
404 candidate.stauMDTHitExtras.emplace_back(MuGirlNS::StauMDTHitExtra(iadc, irdrift));
405 }
406 }
407 } else if (m_idHelperSvc->isRpc(id)) {
408 // treat CompetingMuonClustersOnTrack differently than RpcClusterOnTrack
409 std::vector<const Muon::MuonClusterOnTrack*> clusters;
410 const Muon::CompetingMuonClustersOnTrack* crot = dynamic_cast<const Muon::CompetingMuonClustersOnTrack*>(meas);
411 if (crot) {
412 std::ranges::transform(crot->containedROTs(), std::back_inserter(clusters),
413 [](const auto& rot){
414 return rot.get();
415 });
416 } else {
417 const Muon::RpcClusterOnTrack* rpc = dynamic_cast<const Muon::RpcClusterOnTrack*>(meas);
418 if (rpc) clusters.push_back(rpc);
419 }
420 Identifier chamberId = m_idHelperSvc->chamberId(id);
421 bool measuresPhi = m_idHelperSvc->measuresPhi(id);
422 auto pos = rpcPrdsPerChamber.find(chamberId);
423 if (pos == rpcPrdsPerChamber.end()) {
424 if (measuresPhi)
425 rpcPrdsPerChamber[chamberId] = std::make_tuple(pars, clusters, RpcClVec());
426 else
427 rpcPrdsPerChamber[chamberId] = std::make_tuple(pars, RpcClVec(), clusters);
428 } else {
429 RpcClVec& clVec = measuresPhi ? std::get<1>(pos->second) : std::get<2>(pos->second);
430 clVec.insert(clVec.end(), clusters.begin(), clusters.end());
431 }
432 } else if (m_idHelperSvc->isCsc(id)) {
433 const Muon::CscClusterOnTrack* csc = dynamic_cast<const Muon::CscClusterOnTrack*>(meas);
434
436 float distance = pars->position().mag();
437 float time = csc->prepRawData()->time();
438
439 float ix = pars->position().x();
440 float iy = pars->position().y();
441 float iz = pars->position().z();
442 float ie = 0.;
443 float er = -1;
444 float sh = 0;
445 bool isEta = !m_idHelperSvc->measuresPhi(id);
446 float propTime = 0;
447 float tof = calculateTof(1, distance);
448 candidate.stauHits.push_back(MuGirlNS::StauHit(tech, time + tof, ix, iy, iz, id, ie, er, sh, isEta, propTime));
449 }
450 }
451
452 auto insertRpcs = [betaSeed, this](const Trk::TrackParameters& pars, const RpcClVec& clusters,
454 if (clusters.empty()) return;
455
456 std::vector<const Muon::MuonClusterOnTrack*> calibratedClusters;
457 for (const auto* cluster : clusters) {
458 const Muon::MuonClusterOnTrack* cl = m_muonPRDSelectionTool->calibrateAndSelect(pars, *cluster->prepRawData());
459 if (cl) calibratedClusters.push_back(cl);
460 }
461 if (calibratedClusters.empty()) return;
462
463 Muon::IMuonHitTimingTool::TimingResult result = m_hitTimingTool->calculateTimingResult(calibratedClusters);
464 for (const auto* cl : calibratedClusters) delete cl;
465 if (!result.valid) return;
466
467 Identifier id = clusters.front()->identify();
468
470 float distance = pars.position().mag();
471 float time = result.time;
472 float ix = pars.position().x();
473 float iy = pars.position().y();
474 float iz = pars.position().z();
475 float ie = 0.;
476 float er = result.error;
477 rpcTimeCalibration(id, time, er);
478 float sh = 0;
479 bool isEta = !m_idHelperSvc->measuresPhi(id);
480 if (isEta) tech = MuGirlNS::RPCETA_STAU_HIT;
481 float propTime = 0;
482 float tof = calculateTof(1, distance);
483 float beta = calculateBeta(time + tof, distance);
484 ATH_MSG_VERBOSE(" adding " << m_idHelperSvc->toString(id) << " distance " << distance << " time " << time << " beta" << beta
485 << " diff " << std::abs(beta - betaSeed));
486
487 if (std::abs(beta - betaSeed) > m_mdttBetaAssociationCut) return;
488
489 hits.push_back(Muon::TimePointBetaFitter::Hit(distance, time, er));
490 candidate.stauHits.push_back(MuGirlNS::StauHit(tech, time + tof, ix, iy, iz, id, ie, er, sh, isEta, propTime));
491 };
492
493 // get RPC timing per chamber
494 RpcClPerChMap::const_iterator chit = rpcPrdsPerChamber.begin();
495 RpcClPerChMap::const_iterator chit_end = rpcPrdsPerChamber.end();
496 ATH_MSG_VERBOSE("RPCs per chamber " << rpcPrdsPerChamber.size());
497
498 for (; chit != chit_end; ++chit) {
499 const Trk::TrackParameters* pars = std::get<0>(chit->second);
500 const RpcClVec& phiClusters = std::get<1>(chit->second);
501 const RpcClVec& etaClusters = std::get<2>(chit->second);
502 insertRpcs(*pars, phiClusters, candidate, hits);
503 insertRpcs(*pars, etaClusters, candidate, hits);
504 }
505
506 // get timing per MDT chamber, use segment error strategy (errors of the RT relation
508 Muon::MuonDriftCircleErrorStrategy calibrationStrategy(bits);
511
514 segmentFinder.setMaxDropDepth(2);
515 segmentFinder.setChi2DropCut(5);
516 segmentFinder.setDeltaCut(3);
517
518 MdtChamberLayerData::const_iterator mit = mdtDataPerChamberLayer.begin();
519 MdtChamberLayerData::const_iterator mit_end = mdtDataPerChamberLayer.end();
520 for (; mit != mit_end; ++mit) {
521 ATH_MSG_VERBOSE(" new station layer " << Muon::MuonStationIndex::chName((Muon::MuonStationIndex::ChIndex)(mit->first % 1000))
522 << " hits " << mit->second.size());
523 if (mit->second.size() < 4) continue;
524
525 // get RE element for first hit
526 const MuonGM::MdtReadoutElement* detEl = mit->second.front().second->detectorElement();
527 const Trk::PlaneSurface* surf = dynamic_cast<const Trk::PlaneSurface*>(&detEl->surface());
528 if (!surf) {
529 ATH_MSG_WARNING("MdtReadoutElement should always have a PlaneSurface as reference surface");
530 continue;
531 }
532 Amg::Transform3D gToStation = detEl->GlobalToAmdbLRSTransform();
533
534 // get TrackParameters and SL intersect the DetEl surface (above a few GeV SL intersection is accurate enough)
535 const Trk::TrackParameters& firstPars = *mit->second.front().first;
536 Trk::Intersection slIntersection = surf->straightLineIntersection(firstPars.position(), firstPars.momentum(), false, false);
537
538 // calculate seed position and direction
539 Trk::LocalDirection seedLocDir;
540 surf->globalToLocalDirection(firstPars.momentum(), seedLocDir);
541 Amg::Vector3D seedLocPos = gToStation * slIntersection.position;
542 TrkDriftCircleMath::LocVec2D seedPos(seedLocPos.y(), seedLocPos.z());
543 TrkDriftCircleMath::Line seedLine(seedPos, seedLocDir.angleYZ());
545
546 std::vector<std::pair<std::shared_ptr<const Muon::MdtDriftCircleOnTrack>, const Trk::TrackParameters*>> indexLookUp;
547 unsigned index = 0;
548 for (const auto& entry : mit->second) {
549 const Trk::TrackParameters& pars = *entry.first;
550 const Muon::MdtDriftCircleOnTrack& mdt = *entry.second;
551 Identifier id = mdt.identify();
552 // calibrate MDT
553 std::unique_ptr<const Muon::MdtDriftCircleOnTrack> calibratedMdt(
554 m_mdtCreatorStau->correct(*mdt.prepRawData(), pars, &calibrationStrategy, betaSeed));
555 if (!calibratedMdt) {
556 ATH_MSG_WARNING("Failed to recalibrate existing MDT on track " << m_idHelperSvc->toString(id));
557 continue;
558 }
559 ATH_MSG_VERBOSE(" recalibrated MDT " << m_idHelperSvc->toString(id) << " r " << calibratedMdt->driftRadius() << " "
560 << Amg::error(calibratedMdt->localCovariance(), Trk::locR) << " old r "
561 << mdt.driftRadius() << " " << Amg::error(mdt.localCovariance(), Trk::locR)
562 << " r_track " << pars.parameters()[Trk::locR] << " residual "
563 << std::abs(mdt.driftRadius()) - std::abs(pars.parameters()[Trk::locR]));
564
565 // calculate tube position taking into account the second coordinate
566 Amg::Vector2D lp(0., pars.parameters()[Trk::locZ]);
567 Amg::Vector3D gpos;
568 mdt.associatedSurface().localToGlobal(lp, pars.momentum(), gpos);
569
570 // calculate local AMDB position
571 Amg::Vector3D locPos = gToStation * gpos;
572 TrkDriftCircleMath::LocVec2D lpos(locPos.y(), locPos.z());
573
574 double r = std::abs(calibratedMdt->driftRadius());
575 double dr = Amg::error(calibratedMdt->localCovariance(), Trk::locR);
576
577 // create identifier
578 TrkDriftCircleMath::MdtId mdtid(m_idHelperSvc->mdtIdHelper().isBarrel(id), m_idHelperSvc->mdtIdHelper().multilayer(id) - 1,
579 m_idHelperSvc->mdtIdHelper().tubeLayer(id) - 1, m_idHelperSvc->mdtIdHelper().tube(id) - 1);
580
581 // create new DriftCircle
583 TrkDriftCircleMath::DCOnTrack dcOnTrack(dc, 1., 1.);
584
585 dcs.push_back(dcOnTrack);
586 indexLookUp.emplace_back(std::move(calibratedMdt), &pars);
587 ++index;
588 }
589
590 // now loop over the hits and fit the segment taking out each of the hits individually
591 for (unsigned int i = 0; i < dcs.size(); ++i) {
593 selection[i] = 1;
595 if (!mdtFitter.fit(result, seedLine, dcs, selection)) {
596 ATH_MSG_DEBUG("Fit failed ");
597 continue;
598 }
599 TrkDriftCircleMath::Segment segment = result;
600 segment.hitsOnTrack(dcs.size());
601 unsigned int ndofFit = segment.ndof();
602 if (ndofFit < 1) continue;
603 double chi2NdofSegmentFit = segment.chi2() / ndofFit;
604 bool hasDropHit = false;
605 unsigned int dropDepth = 0;
606 if (!segmentFinder.dropHits(segment, hasDropHit, dropDepth)) {
607 ATH_MSG_DEBUG("DropHits failed, fit chi2/ndof " << chi2NdofSegmentFit);
608 if (msgLvl(MSG::VERBOSE)) {
609 segmentFinder.debugLevel(20);
610 segment = result;
611 segmentFinder.dropHits(segment, hasDropHit, dropDepth);
612 segmentFinder.debugLevel(0);
613 }
614 continue;
615 }
616 if (i >= segment.dcs().size()) continue;
618 const TrkDriftCircleMath::DCOnTrack& dc = segment.dcs()[i];
619 double res = dc.residual();
620 double err = std::sqrt(dc.dr() * dc.dr() + dc.errorTrack() * dc.errorTrack());
621 double pull = res / err;
622 double rline = toLine.toLineY(dc.position());
623 int index = dc.index();
624 if (index < 0 || index >= (int)indexLookUp.size()) {
625 ATH_MSG_WARNING(" lookup of TrackParameters and MdtDriftCircleOnTrack failed " << index << " range: 0 - "
626 << indexLookUp.size() - 1);
627 continue;
628 }
629 const Trk::TrackParameters* pars = indexLookUp[dc.index()].second;
630 const Muon::MdtDriftCircleOnTrack* mdt = indexLookUp[dc.index()].first.get();
631 Identifier id = mdt->identify();
632
633 // calibrate MDT with nominal timing
634 std::shared_ptr<const Muon::MdtDriftCircleOnTrack> calibratedMdt(
635 m_mdtCreator->correct(*mdt->prepRawData(), *pars, &calibrationStrategy, betaSeed));
636 if (!calibratedMdt.get()) {
637 ATH_MSG_WARNING("Failed to recalibrate existing MDT on track " << m_idHelperSvc->toString(id));
638 continue;
639 }
640 float distance = pars->position().mag();
641 float time = 0.;
642
643 float ix = pars->position().x();
644 float iy = pars->position().y();
645 float iz = pars->position().z();
646 float ie = 0.;
647 float er = -1;
648 float sh = 0;
649 bool isEta = !m_idHelperSvc->measuresPhi(id);
650 float propTime = 0;
651 float tof = calculateTof(1, distance);
652
653 float iadc = mdt->prepRawData()->adc();
654 float irdrift = mdt->driftRadius();
655
656 // use inverted RT relation together with track prediction to get estimate of drift time
657 float driftTime = calibratedMdt->driftTime(); // we need to add beta seed as it was subtracted when calibrating the hits
658 float locR = rline;
659 float errR = dc.errorTrack();
660 auto data = mdtCalibConstants->getCalibData(id, msgStream());
661 const auto& rtRelation = data->rtRelation;
662 float drdt = rtRelation->rt()->driftVelocity(driftTime);
663 float rres = rtRelation->rtRes()->resolution(driftTime);
664 float tres = rres / drdt;
665 float TlocR = rtRelation->tr()->driftTime(std::abs(locR)).value_or(0.);
666 float trackTimeRes = errR / drdt;
667 float tofShiftFromBeta = 0.; // muonBetaCalculationUtils.calculateTof(betaSeed,distance)-tof;
668 er = std::sqrt(tres * tres + trackTimeRes * trackTimeRes);
669 mdtTimeCalibration(id, driftTime, er);
670 time = driftTime - TlocR + tofShiftFromBeta;
671 propTime = driftTime;
672 ie = trackTimeRes;
673
674 const float beta = calculateBeta(time + tof, distance);
675 bool isSelected = std::abs(beta - betaSeed) < m_mdttBetaAssociationCut;
676
677 if (msgLvl(MSG::DEBUG)) {
678 msg(MSG::DEBUG) << m_idHelperSvc->toString(id) << std::setprecision(2) << " segment: after fit " << std::setw(5)
679 << chi2NdofSegmentFit << " ndof " << std::setw(2) << ndofFit;
680 if (segment.ndof() != ndofFit)
681 msg(MSG::DEBUG) << " after outlier " << std::setw(5) << chi2NdofSegmentFit << " ndof " << std::setw(2) << ndofFit;
682 msg(MSG::DEBUG) << " driftR " << std::setw(4) << dc.r() << " rline " << std::setw(5) << rline << " residual "
683 << std::setw(5) << res << " pull " << std::setw(4) << pull << " time " << std::setw(3) << time
684 << " beta" << std::setw(2) << beta << " err " << std::setw(3) << er << " intrinsic " << std::setw(3)
685 << tres << " track " << std::setw(3) << trackTimeRes;
686 if (!isSelected) msg(MSG::DEBUG) << " outlier";
687 msg(MSG::DEBUG) << std::setprecision(5) << endmsg;
688 }
689
690 if (!isSelected) {
691 // write out hits that don't pass the beta association cut but still store them
692 candidate.stauHits.emplace_back(MuGirlNS::StauHit(MuGirlNS::MDTT_STAU_HIT, time + tof, ix, iy, iz, id, ie, er, sh, isEta, propTime, false));
694 float iadc = mdt->prepRawData()->adc();
695 float irdrift = mdt->driftRadius();
696 candidate.stauMDTHitExtras.emplace_back(MuGirlNS::StauMDTHitExtra(iadc, irdrift));
697 }
698 continue;
699 }
700
701 // only store hits for future use if they pass the beta association cut
702 hits.emplace_back(distance, time, er);
703 candidate.stauHits.emplace_back(MuGirlNS::MDTT_STAU_HIT, time + tof, ix, iy, iz, id, ie, er, sh, isEta, propTime, true);
705 candidate.stauMDTHitExtras.emplace_back(MuGirlNS::StauMDTHitExtra(iadc, irdrift));
706 }
707 }
708 }
709 // fit data
710 Muon::TimePointBetaFitter::FitResult betaFitResult = fitter.fitWithOutlierLogic(hits);
711 ATH_MSG_DEBUG(" extractTimeMeasurementsFromTrack: extracted " << candidate.stauHits.size() << " time measurements "
712 << " status fit " << betaFitResult.status << " beta "
713 << betaFitResult.beta << " chi2/ndof " << betaFitResult.chi2PerDOF());
714
715 candidate.finalBetaFitResult = betaFitResult;
716 }
717
718 void MuonStauRecoTool::addTag(const InDetCandidate& indetCandidate,
720 InDetCandidateToTagMap* tagMap,
721 TrackCollection* combTracks,
722 Trk::SegmentCollection* segments) const {
723 // get combined track and the segments
724 combTracks->push_back(candidate.combinedTrack.release());
725 ElementLink<TrackCollection> comblink(*combTracks, combTracks->size() - 1);
726 std::vector<ElementLink<Trk::SegmentCollection>> segmentLinks;
727 for (const auto& layer : candidate.allLayers) {
728 for (const auto& segment : layer.segments) {
729 segments->push_back(segment->clone());
730 ElementLink<Trk::SegmentCollection> segLink(*segments, segments->size() - 1);
731 segmentLinks.push_back(segLink);
732 }
733 }
734
735 // create tag
736 MuonCombined::MuGirlLowBetaTag* tag = new MuonCombined::MuGirlLowBetaTag(comblink, segmentLinks);
737
738 // add additional info
739 tag->setMuBeta(candidate.betaFitResult.beta);
740
741 // add StauExtras
742 std::unique_ptr<MuGirlNS::StauExtras> stauExtras = std::make_unique<MuGirlNS::StauExtras>();
743 stauExtras->betaAll = candidate.betaFitResult.beta;
744 stauExtras->betaAllt = candidate.finalBetaFitResult.beta;
745 stauExtras->hits = candidate.stauHits;
746 // TODO: ALEXIS ADD FLAG
748 stauExtras->extraMDTHitInfo = candidate.stauMDTHitExtras;
749 }
750
751 tag->setStauExtras(std::move(stauExtras));
752
753 // print results afer refineCandidate
754 if (m_doSummary || msgLvl(MSG::DEBUG)) {
755 msg(MSG::INFO) << " Summary::addTag ";
756 msg(MSG::INFO) << std::endl
757 << " candidate: beta fit result: beta " << candidate.betaFitResult.beta << " chi2/ndof "
758 << candidate.betaFitResult.chi2PerDOF() << " segments" << segmentLinks.size();
759 for (const auto& segment : segmentLinks) msg(MSG::INFO) << std::endl << " " << m_printer->print(**segment);
760 if (*comblink)
761 msg(MSG::INFO) << std::endl
762 << " track " << m_printer->print(**comblink) << std::endl
763 << m_printer->printStations(**comblink);
764 msg(MSG::INFO) << endmsg;
765 }
766
767 // add tag to IndetCandidate
768 tagMap->addEntry(&indetCandidate, tag);
769 }
770
772 ATH_MSG_DEBUG("Resolving ambiguities: candidates " << candidates.size());
773
774 // push tracks into a collection and run ambi-solver
776 std::map<const Trk::Track*, std::shared_ptr<Candidate>> trackCandidateLookup;
777 for (const auto& candidate : candidates) {
778 Trk::Track* track = candidate->combinedTrack.get();
779 if (track) {
780 tracks.push_back(track);
781 trackCandidateLookup[track] = candidate;
782 }
783 }
784
785 // first handle easy cases of zero or one track
786 if (tracks.empty()) return false;
787 if (tracks.size() == 1) return true;
788
789 // more than 1 track call ambiguity solver and select first track
790 std::unique_ptr<const TrackCollection> resolvedTracks(m_trackAmbibuityResolver->process(&tracks));
791 if (!resolvedTracks || resolvedTracks->empty()) {
792 ATH_MSG_WARNING("No track survived the ambiguity solving");
793 return false;
794 }
795 const Trk::Track* selectedTrack = resolvedTracks->front();
796
797 // get candidate
798 auto pos = trackCandidateLookup.find(selectedTrack);
799 if (pos == trackCandidateLookup.end()) {
800 ATH_MSG_WARNING("candidate lookup failed, this should not happen");
801 return false;
802 }
803
804 // remove all candidates that were not combined
805 std::shared_ptr<Candidate> candidate = pos->second;
806 candidates.clear();
807 candidates.push_back(candidate);
808
809 // print results afer resolveAmbiguities
810 if (m_doSummary || msgLvl(MSG::DEBUG)) {
811 msg(MSG::INFO) << " Summary::resolveAmbiguities ";
812 msg(MSG::INFO) << std::endl
813 << " candidate: beta fit result: beta " << candidate->betaFitResult.beta << " chi2/ndof "
814 << candidate->betaFitResult.chi2PerDOF() << " layers with segments" << candidate->allLayers.size() << std::endl
815 << " track " << m_printer->print(*candidate->combinedTrack) << std::endl
816 << m_printer->printStations(*candidate->combinedTrack);
817 msg(MSG::INFO) << endmsg;
818 }
819
820 return true;
821 }
822
823 bool MuonStauRecoTool::combineCandidates(const EventContext& ctx, const xAOD::TrackParticle& indetTrackParticle,
824 MuonStauRecoTool::CandidateVec& candidates) const {
825 // keep track of candidates that have a successfull fit
826 CandidateVec combinedCandidates;
827
828 // loop over candidates and redo segments using beta estimate from candidate
829 ATH_MSG_DEBUG("Combining candidates " << candidates.size());
830 for (auto& candidate : candidates) {
831 // find best matching track
832 std::pair<std::unique_ptr<const Muon::MuonCandidate>, std::unique_ptr<Trk::Track>> result =
833 m_insideOutRecoTool->findBestCandidate(ctx, indetTrackParticle, candidate->allLayers);
834
835 if (result.first && result.second) {
836 ATH_MSG_DEBUG(" combined track found " << std::endl
837 << m_printer->print(*result.second) << std::endl
838 << m_printer->printStations(*result.second));
839 // add segments and track pointer to the candidate
840 candidate->muonCandidate = std::move(result.first);
841 candidate->combinedTrack = std::move(result.second);
842
843 // extract times form track
844 extractTimeMeasurementsFromTrack(ctx, *candidate);
845 combinedCandidates.push_back(candidate);
846 if (!m_recoValidationTool.empty()) m_recoValidationTool->addTimeMeasurements(indetTrackParticle, candidate->stauHits);
847 }
848 }
849
850 // remove all candidates that were not combined
851 candidates = combinedCandidates;
852
853 // print results afer combineCandidate
854 if (m_doSummary || msgLvl(MSG::DEBUG)) {
855 msg(MSG::INFO) << " Summary::combineCandidates ";
856 if (candidates.empty())
857 msg(MSG::INFO) << " No candidated found ";
858 else
859 msg(MSG::INFO) << " candidates " << candidates.size();
860
861 for (const auto& candidate : candidates) {
862 msg(MSG::INFO) << std::endl
863 << " candidate: beta fit result: " << candidate->betaFitResult.beta << " chi2/ndof "
864 << candidate->betaFitResult.chi2PerDOF();
865 if (candidate->finalBetaFitResult.status != 0)
866 msg(MSG::INFO) << " MDTT beta fit result: " << candidate->finalBetaFitResult.beta << " chi2/ndof "
867 << candidate->finalBetaFitResult.chi2PerDOF();
868 msg(MSG::INFO) << " layers with segments" << candidate->allLayers.size() << std::endl
869 << " track " << m_printer->print(*candidate->combinedTrack) << std::endl
870 << m_printer->printStations(*candidate->combinedTrack);
871 }
872 msg(MSG::INFO) << endmsg;
873 }
874
875 return !candidates.empty();
876 }
877
879 CandidateVec& candidates) const {
880 // loop over layers and select seed maxima
881 MaximumDataVec seedMaximumDataVec;
882 LayerDataVec::const_iterator it = associatedData.layerData.begin();
883 LayerDataVec::const_iterator it_end = associatedData.layerData.end();
884 for (; it != it_end; ++it) {
885 // loop over maximumDataVec
886 for (const auto& maximumData : it->maximumDataVec) {
887 // add all maximumData that have a time measurement
888 if (!maximumData->betaSeeds.empty()) seedMaximumDataVec.push_back(maximumData);
889 }
890 }
891 ATH_MSG_DEBUG("Creating candidates from seeds " << seedMaximumDataVec.size());
892
893 if (seedMaximumDataVec.empty()) {
894 if (m_doSummary || msgLvl(MSG::DEBUG)) msg(MSG::INFO) << " Summary::createCandidates, no seeds found " << endmsg;
895 return false;
896 }
897
898 // sorting lambda for MaximumData seeds
899 auto SortMaximumDataVec = [](const std::shared_ptr<MaximumData>& max1, const std::shared_ptr<MaximumData>& max2) {
900 return max1->maximum->max < max2->maximum->max;
901 };
902 std::stable_sort(seedMaximumDataVec.begin(), seedMaximumDataVec.end(), SortMaximumDataVec);
903
904 // loop over seeds and create candidates
906 std::set<const MaximumData*> usedMaximumData;
907 MaximumDataVec::iterator sit = seedMaximumDataVec.begin();
908 MaximumDataVec::iterator sit_end = seedMaximumDataVec.end();
909 for (; sit != sit_end; ++sit) {
910 // only use once
911 if (usedMaximumData.count(sit->get())) continue;
912 usedMaximumData.insert(sit->get());
913
914 // create new candidates from the beta seeds of the maximum
915 CandidateVec newCandidates;
916 for (const auto& betaSeed : (*sit)->betaSeeds) { newCandidates.push_back(std::make_shared<Candidate>(betaSeed)); }
917 // extend the candidates
918 extendCandidates(newCandidates, usedMaximumData, associatedData.layerData.begin(), associatedData.layerData.end());
919
920 // loop over the candidates and fit them
921 for (auto& newCandidate : newCandidates) {
922 // fit data
923 newCandidate->betaFitResult = fitter.fitWithOutlierLogic(newCandidate->hits);
924 ATH_MSG_DEBUG(" New candidate: time measurements "
925 << newCandidate->hits.size() << " status " << newCandidate->betaFitResult.status << " beta "
926 << newCandidate->betaFitResult.beta << " chi2/ndof " << newCandidate->betaFitResult.chi2PerDOF());
927 // if the fit was successfull add the candidate to the candidate vector
928 if (newCandidate->betaFitResult.status != 0) {
929 newCandidate->combinedTrack = nullptr; // no track exists at this stage
930 candidates.push_back(newCandidate);
931 }
932 }
933 }
934
935 // print results afer createCandidate
936 if (m_doSummary || msgLvl(MSG::DEBUG)) {
937 msg(MSG::INFO) << " Summary::createCandidates ";
938 if (candidates.empty())
939 msg(MSG::INFO) << " No candidated found ";
940 else
941 msg(MSG::INFO) << " candidates " << candidates.size();
942
943 for (const auto& candidate : candidates) {
944 msg(MSG::INFO) << std::endl
945 << " candidate: beta seed " << candidate->betaSeed.beta << " beta fit result: beta "
946 << candidate->betaFitResult.beta << " chi2/ndof " << candidate->betaFitResult.chi2PerDOF() << " layers "
947 << candidate->layerDataVec.size();
948 for (const auto& layerData : candidate->layerDataVec)
949 msg(MSG::INFO) << std::endl
950 << " " << printIntersectionToString(layerData.intersection) << " maximumDataVec "
951 << layerData.maximumDataVec.size();
952 }
953 msg(MSG::INFO) << endmsg;
954 }
955
956 return !candidates.empty();
957 }
958
959 void MuonStauRecoTool::extendCandidates(MuonStauRecoTool::CandidateVec& candidates, std::set<const MaximumData*>& usedMaximumData,
960 MuonStauRecoTool::LayerDataVec::const_iterator it,
961 MuonStauRecoTool::LayerDataVec::const_iterator it_end) const {
962 // get current layer and move forward the
963 const LayerData& layerData = *it;
964 ATH_MSG_DEBUG(" extendCandidates: " << printIntersectionToString(layerData.intersection) << " maxima "
965 << layerData.maximumDataVec.size());
966
967 CandidateVec newCandidates; // store new candidates
968 for (auto& candidate : candidates) {
969 // keep track of how often we extend this candidate
970 unsigned int nextensions = 0;
971
972 // copy content of the candidate for reference
973 LayerDataVec layerDataVec = candidate->layerDataVec;
974 Muon::TimePointBetaFitter::HitVec hits = candidate->hits;
975
976 // loop over maximumDataVec of the layer
977 for (const auto& maximumData : layerData.maximumDataVec) {
978 // create new hit vector
979 Muon::TimePointBetaFitter::HitVec newhits; // create new hits vector and add the ones from the maximum
980 if (extractTimeHits(*maximumData, newhits, &candidate->betaSeed)) {
981 // decide which candidate to update, create a new candidate if a maximum was already selected in the layer
982 Candidate* theCandidate = nullptr;
983 if (nextensions == 0)
984 theCandidate = candidate.get();
985 else {
986 std::shared_ptr<Candidate> newCandidate = std::make_shared<Candidate>(candidate->betaSeed);
987 newCandidate->layerDataVec = layerDataVec;
988 newCandidate->hits = hits;
989 theCandidate = newCandidate.get();
990 newCandidates.emplace_back(std::move(newCandidate));
991 }
992
993 // create a LayerData object to add to the selected candidate
994 LayerData newLayerData(layerData.intersection);
995 newLayerData.maximumDataVec.push_back(maximumData);
996
997 // update the candidate
998 theCandidate->hits.insert(theCandidate->hits.end(), newhits.begin(), newhits.end());
999 theCandidate->layerDataVec.push_back(newLayerData);
1000 usedMaximumData.insert(maximumData.get());
1001
1002 ATH_MSG_DEBUG(" adding maximumData: candidate hits " << theCandidate->hits.size() << " LayerDataVec "
1003 << theCandidate->layerDataVec.size() << " nextensions "
1004 << nextensions);
1005
1006 ++nextensions;
1007 }
1008 }
1009 }
1010 ATH_MSG_DEBUG(" extendCandidates done, new candidates " << newCandidates.size());
1011
1012 // add the new candidates
1013 candidates.insert(candidates.end(), newCandidates.begin(), newCandidates.end());
1014
1015 // move to the next layer, if we haven't reached the last layer, continue recursion
1016 ++it;
1017 if (it != it_end) extendCandidates(candidates, usedMaximumData, it, it_end);
1018 }
1019
1020 bool MuonStauRecoTool::extractTimeMeasurements(const EventContext& ctx,
1021 const Muon::MuonSystemExtension& muonSystemExtension,
1022 AssociatedData& associatedData) const {
1023 // get layer intersections
1024 // find RPC time measurements and segments to seed the beta fit using t0 fitting
1025 for (const Muon::MuonSystemExtension::Intersection& iSect: muonSystemExtension.layerIntersections()) {
1026 // create layer data object and add maxima
1027 LayerData layerData{iSect};
1028 associateHoughMaxima(ctx, layerData);
1029
1030 // skip layer of not maxima are associated
1031 if (layerData.maximumDataVec.empty()) continue;
1032
1033 associatedData.layerData.push_back(layerData);
1034
1035 // loop over associated maxima
1036 for (auto& maximum : layerData.maximumDataVec) {
1037 // extract RPC timing
1038 extractRpcTimingFromMaximum(iSect, *maximum);
1039
1040 // find segments for intersection
1041 std::vector<std::shared_ptr<const Muon::MuonSegment>> t0fittedSegments;
1042 findSegments(iSect, *maximum, t0fittedSegments, m_muonPRDSelectionTool, m_segmentMakerT0Fit);
1043 if (t0fittedSegments.empty()) continue;
1044
1045 // match segments to intersection, store the ones that match
1046 m_segmentMatchingTool->select(ctx, iSect, t0fittedSegments, maximum->t0fittedSegments);
1047
1048 // get beta seeds for Maximum
1049 getBetaSeeds(*maximum);
1050 }
1051 }
1052
1053 // print results afer extractTimeMeasurements
1054 if (m_doSummary || msgLvl(MSG::DEBUG)) {
1055 msg(MSG::INFO) << " Summary::extractTimeMeasurements ";
1056 if (associatedData.layerData.empty())
1057 msg(MSG::INFO) << " No layers associated ";
1058 else
1059 msg(MSG::INFO) << " Associated layers " << associatedData.layerData.size();
1060
1061 for (const auto& layerData : associatedData.layerData) {
1062 unsigned int nmaxWithBeta = 0;
1063 for (const auto& maximumData : layerData.maximumDataVec) {
1064 if (!maximumData->betaSeeds.empty()) ++nmaxWithBeta;
1065 }
1066 msg(MSG::INFO) << std::endl
1067 << " layer " << printIntersectionToString(layerData.intersection) << " associated maxima "
1068 << layerData.maximumDataVec.size() << " maxima with beta seeds " << nmaxWithBeta;
1069 }
1070 msg(MSG::INFO) << endmsg;
1071 }
1072
1073 // return false if no layers were associated
1074 return !associatedData.layerData.empty();
1075 }
1076
1078 const BetaSeed* seed) const {
1079 unsigned int nstart = hits.size();
1080
1081 auto addHit = [&](float distance, float time, float error, float cut) {
1082 if (seed) {
1083 float beta = calculateBeta(time + calculateTof(1, distance), distance);
1084 ATH_MSG_VERBOSE(" matching hit: distance " << distance << " time " << time << " beta" << beta << " diff "
1085 << std::abs(beta - seed->beta));
1086 if (std::abs(beta - seed->beta) > cut) return;
1087 } else {
1088 ATH_MSG_VERBOSE(" addHit: distance " << distance << " time " << time << " beta"
1089 << calculateBeta(time + calculateTof(1, distance), distance));
1090 }
1091 if (error != 0.) hits.emplace_back(distance, time, error);
1092 };
1093
1094 // add rpc measurements
1095 for (const auto& rpc : maximumData.rpcTimeMeasurements) {
1096 float time = rpc.time;
1097 float error = rpc.error;
1098 rpcTimeCalibration(rpc.rpcClusters.front()->identify(), time, error);
1099 addHit(rpc.rpcClusters.front()->globalPosition().mag(), time, error, m_rpcBetaAssociationCut);
1100 }
1101
1102 // add segment t0 fits
1103 // if not seeded take all segments
1104 if (!seed) {
1105 for (const auto& seg : maximumData.t0fittedSegments) {
1106 if (!seg->hasFittedT0()) continue;
1107 float time = seg->time();
1108 float error = seg->errorTime();
1109 Identifier id = m_edmHelperSvc->chamberId(*seg);
1110 segmentTimeCalibration(id, time, error);
1111 addHit(seg->globalPosition().mag(), time, error, m_segmentBetaAssociationCut);
1112 }
1113 } else {
1114 // pick the best match
1115 const Muon::MuonSegment* bestSegment = nullptr;
1116 float smallestResidual = FLT_MAX;
1117 for (const auto& seg : maximumData.t0fittedSegments) {
1118 if (!seg->hasFittedT0()) continue;
1119 float distance = seg->globalPosition().mag();
1120 float time = seg->time();
1121 float beta = calculateBeta(time + calculateTof(1, distance), distance);
1122 float residual = std::abs(beta - seed->beta);
1123
1124 if (residual < smallestResidual) {
1125 smallestResidual = residual;
1126 bestSegment = seg.get();
1127 }
1128 }
1129 if (bestSegment) {
1130 addHit(bestSegment->globalPosition().mag(), bestSegment->time(), bestSegment->errorTime(), m_segmentBetaAssociationCut);
1131 ATH_MSG_VERBOSE(" adding best segment: " << m_printer->print(*bestSegment));
1132 }
1133 }
1134 ATH_MSG_VERBOSE(" extractTimeHits done: added " << hits.size() - nstart << " hits");
1135
1136 return nstart != hits.size();
1137 }
1138
1140 // skip maximumData if no timing information is available
1141 if (maximumData.rpcTimeMeasurements.empty() && maximumData.t0fittedSegments.empty()) return;
1142
1143 // fitter + hits
1146 extractTimeHits(maximumData, hits);
1147
1148 Muon::TimePointBetaFitter::FitResult result = fitter.fitWithOutlierLogic(hits);
1149 float chi2ndof = result.chi2PerDOF();
1150
1151 ATH_MSG_DEBUG(" fitting beta for maximum: time measurements " << hits.size() << " status " << result.status << " beta "
1152 << result.beta << " chi2/ndof " << chi2ndof);
1153 if (result.status != 0) maximumData.betaSeeds.emplace_back(result.beta, 1.);
1154 }
1155
1157 std::vector<std::shared_ptr<const Muon::MuonSegment>>& segments,
1158 const ToolHandle<Muon::IMuonPRDSelectionTool>& muonPRDSelectionTool,
1159 const ToolHandle<Muon::IMuonSegmentMaker>& segmentMaker,
1160 float beta) const {
1161 const MuonHough::MuonLayerHough::Maximum& maximum = *maximumData.maximum;
1162 const std::vector<std::shared_ptr<const Muon::MuonClusterOnTrack>>& phiClusterOnTracks = maximumData.phiClusterOnTracks;
1163
1164 // lambda to handle calibration and selection of MDTs
1165 auto handleMdt = [intersection, muonPRDSelectionTool](const Muon::MdtPrepData& prd,
1166 std::vector<const Muon::MdtDriftCircleOnTrack*>& mdts,
1167 float beta) {
1168 const Muon::MdtDriftCircleOnTrack* mdt = muonPRDSelectionTool->calibrateAndSelect(intersection, prd, beta);
1169 if (mdt) mdts.push_back(mdt);
1170 };
1171
1172 // lambda to handle calibration and selection of clusters
1173 auto handleCluster = [intersection, muonPRDSelectionTool](const Muon::MuonCluster& prd,
1174 std::vector<const Muon::MuonClusterOnTrack*>& clusters) {
1175 const Muon::MuonClusterOnTrack* cluster = muonPRDSelectionTool->calibrateAndSelect(intersection, prd);
1176 if (cluster) clusters.push_back(cluster);
1177 };
1178
1179 // loop over hits in maximum and add them to the hit list
1180 std::vector<const Muon::MdtDriftCircleOnTrack*> mdts;
1181 std::vector<const Muon::MuonClusterOnTrack*> clusters;
1182
1183 // insert phi hits, clone them
1184 clusters.reserve(phiClusterOnTracks.size());
1185
1186 for (const auto& phiClusterOnTrack : phiClusterOnTracks) { clusters.push_back(phiClusterOnTrack->clone()); }
1187
1188 ATH_MSG_DEBUG("About to loop over Hough::Hits");
1189
1190 MuonHough::HitVec::const_iterator hit = maximum.hits.begin();
1191 MuonHough::HitVec::const_iterator hit_end = maximum.hits.end();
1192 for (; hit != hit_end; ++hit) {
1193 ATH_MSG_DEBUG("hit x,y_min,y_max,w = " << (*hit)->x << "," << (*hit)->ymin << "," << (*hit)->ymax << "," << (*hit)->w);
1194 // treat the case that the hit is a composite TGC hit
1195 if ((*hit)->tgc) {
1196 for (const auto& prd : (*hit)->tgc->etaCluster) handleCluster(*prd, clusters);
1197 } else if ((*hit)->prd) {
1198 Identifier id = (*hit)->prd->identify();
1199 if (m_idHelperSvc->isMdt(id))
1200 handleMdt(static_cast<const Muon::MdtPrepData&>(*(*hit)->prd), mdts, beta);
1201 else
1202 handleCluster(static_cast<const Muon::MuonCluster&>(*(*hit)->prd), clusters);
1203 }
1204 }
1205
1206 ATH_MSG_DEBUG("About to loop over calibrated hits");
1207
1208 ATH_MSG_DEBUG("Dumping MDTs");
1209 for (const auto* it : mdts) ATH_MSG_DEBUG(*it);
1210
1211 ATH_MSG_DEBUG("Dumping clusters");
1212 for (const auto* it : clusters) ATH_MSG_DEBUG(*it);
1213
1214 // require at least 2 MDT hits
1215 if (mdts.size() > 2) {
1216 // run segment finder
1217 auto segColl = std::make_unique<Trk::SegmentCollection>(SG::VIEW_ELEMENTS);
1218 segmentMaker->find(intersection.trackParameters->position(), intersection.trackParameters->momentum(), mdts, clusters,
1219 !clusters.empty(), segColl.get(), intersection.trackParameters->momentum().mag(), 0, beta);
1220 if (segColl) {
1221 Trk::SegmentCollection::iterator sit = segColl->begin();
1222 Trk::SegmentCollection::iterator sit_end = segColl->end();
1223 for (; sit != sit_end; ++sit) {
1224 Trk::Segment* tseg = *sit;
1225 Muon::MuonSegment* mseg = static_cast<Muon::MuonSegment*>(tseg);
1226 assert(dynamic_cast<Muon::MuonSegment*>(tseg) != nullptr);
1227 ATH_MSG_DEBUG("Segment: " << m_printer->print(*mseg));
1228 segments.push_back(std::shared_ptr<const Muon::MuonSegment>(mseg));
1229 }
1230 }
1231 }
1232 // clean-up memory
1233 for (const auto* hit : mdts) delete hit;
1234 for (const auto* hit : clusters) delete hit;
1235 }
1236
1238 MaximumData& maximumData) const {
1239 // extract trigger hits per chamber
1240 const MuonHough::MuonLayerHough::Maximum& maximum = *maximumData.maximum;
1241 std::map<Identifier, std::vector<const Muon::RpcPrepData*>> rpcPrdsPerChamber;
1242
1243 // lambda to add the PRD
1244 auto addRpc = [&rpcPrdsPerChamber, this](const Trk::PrepRawData* prd) {
1245 const Muon::RpcPrepData* rpcPrd = dynamic_cast<const Muon::RpcPrepData*>(prd);
1246 if (rpcPrd) {
1247 Identifier chamberId = m_idHelperSvc->chamberId(rpcPrd->identify());
1248 rpcPrdsPerChamber[chamberId].push_back(rpcPrd);
1249 }
1250 };
1251
1252 // extract eta hits
1253 MuonHough::HitVec::const_iterator hit = maximum.hits.begin();
1254 MuonHough::HitVec::const_iterator hit_end = maximum.hits.end();
1255 for (; hit != hit_end; ++hit) {
1256 if ((*hit)->tgc || !(*hit)->prd || !m_idHelperSvc->isRpc((*hit)->prd->identify())) continue;
1257 addRpc((*hit)->prd);
1258 }
1259
1260 // extract phi hits
1261 for (const auto& rot : maximumData.phiClusterOnTracks) { addRpc(rot->prepRawData()); }
1262
1263 // exit if no hits are found
1264 if (rpcPrdsPerChamber.empty()) return;
1265
1266 std::map<Identifier, std::vector<const Muon::RpcPrepData*>>::iterator chit = rpcPrdsPerChamber.begin();
1267 std::map<Identifier, std::vector<const Muon::RpcPrepData*>>::iterator chit_end = rpcPrdsPerChamber.end();
1268 for (; chit != chit_end; ++chit) {
1269 // cluster hits
1270 Muon::RpcHitClusteringObj clustering(&m_idHelperSvc->rpcIdHelper());
1271 if (!clustering.cluster(chit->second)) {
1272 ATH_MSG_WARNING("Clustering failed");
1273 return;
1274 }
1275
1276 ATH_MSG_DEBUG(" " << m_idHelperSvc->toStringChamber(chit->first) << " clustered RPCs: " << chit->second.size()
1277 << " eta clusters " << clustering.clustersEta.size() << " phi clusters " << clustering.clustersPhi.size());
1280 }
1281 }
1282
1284 const std::vector<Muon::RpcClusterObj>& clusterObjects,
1285 MuonStauRecoTool::RpcTimeMeasurementVec& rpcTimeMeasurements) const {
1286 // loop over the clusters
1287 for (const auto& cluster : clusterObjects) {
1288 if (cluster.hitList.empty() || !cluster.hitList.front()) {
1289 ATH_MSG_WARNING("Cluster without hits: " << cluster.hitList.size());
1290 continue;
1291 }
1292 ATH_MSG_DEBUG(" new cluster: " << m_idHelperSvc->toString(cluster.hitList.front()->identify()) << " size "
1293 << cluster.hitList.size());
1294
1295 // create the ROTs
1296 std::vector<const Muon::MuonClusterOnTrack*> clusters;
1297 for (const auto* rpc : cluster.hitList) {
1298 const Muon::MuonClusterOnTrack* rot(m_muonPRDSelectionTool->calibrateAndSelect(intersection, *rpc));
1299 if (rot) {
1300 clusters.push_back(rot);
1301 ATH_MSG_DEBUG(" strip " << m_idHelperSvc->toString(rot->identify()) << " time "
1302 << static_cast<const Muon::RpcClusterOnTrack*>(rot)->time());
1303 }
1304 }
1305 // get the timing result for the cluster
1306 Muon::IMuonHitTimingTool::TimingResult result = m_hitTimingTool->calculateTimingResult(clusters);
1307 if (result.valid) {
1308 // add the result
1309 RpcTimeMeasurement rpcTimeMeasurement;
1310 rpcTimeMeasurement.time = result.time;
1311 rpcTimeMeasurement.error = result.error;
1312 for (const auto* cl : clusters) {
1313 const Muon::RpcClusterOnTrack* rcl = dynamic_cast<const Muon::RpcClusterOnTrack*>(cl);
1314 if (rcl) rpcTimeMeasurement.rpcClusters.push_back(std::shared_ptr<const Muon::RpcClusterOnTrack>(rcl));
1315 }
1316 rpcTimeMeasurements.push_back(rpcTimeMeasurement);
1317 } else {
1318 // if no time measurement was created we need to clean up the memory
1319 for (const auto* cl : clusters) delete cl;
1320 }
1321 }
1322 }
1323
1324 void MuonStauRecoTool::associateHoughMaxima(const EventContext& ctx,
1325 MuonStauRecoTool::LayerData& layerData) const {
1326
1327 if (m_houghDataPerSectorVecKey.empty()) return;
1328 // get intersection and layer identifiers
1330 int sector = intersection.layerSurface.sector;
1331 Muon::MuonStationIndex::DetectorRegionIndex regionIndex = intersection.layerSurface.regionIndex;
1332 Muon::MuonStationIndex::LayerIndex layerIndex = intersection.layerSurface.layerIndex;
1333
1334 // get hough data
1335 SG::ReadHandle houghDataPerSectorVec{m_houghDataPerSectorVecKey,ctx};
1336 if (!houghDataPerSectorVec.isValid()) {
1337 ATH_MSG_ERROR("Hough data per sector vector not found");
1338 return;
1339 }
1340
1341 // sanity check
1342 if (static_cast<int>(houghDataPerSectorVec->vec.size()) <= sector - 1) {
1343 ATH_MSG_WARNING(" sector " << sector
1344 << " larger than the available sectors in the Hough tool: " << houghDataPerSectorVec->vec.size());
1345 return;
1346 }
1347
1348 // get hough maxima in the layer
1349 unsigned int layHash = Muon::MuonStationIndex::sectorLayerHash(regionIndex, layerIndex);
1350 const Muon::MuonLayerHoughTool::HoughDataPerSector& houghDataPerSector = houghDataPerSectorVec->vec[sector - 1];
1351
1352 // sanity check
1353 if (houghDataPerSector.maxVec.size() <= layHash) {
1354 ATH_MSG_WARNING(" houghDataPerSector.maxVec.size() smaller than hash " << houghDataPerSector.maxVec.size() << " hash "
1355 << layHash);
1356 return;
1357 }
1358 const Muon::MuonLayerHoughTool::MaximumVec& maxVec = houghDataPerSector.maxVec[layHash];
1359 if (maxVec.empty()) return;
1360
1361 // get local coordinates in the layer frame
1362 bool barrelLike = intersection.layerSurface.regionIndex == DetectorRegionIndex::Barrel;
1363
1364 // in the endcaps take the r in the sector frame from the local position of the extrapolation
1365 float phi = intersection.trackParameters->position().phi();
1366 float r = barrelLike ? m_muonSectorMapping.transformRToSector(intersection.trackParameters->position().perp(), phi,
1367 intersection.layerSurface.sector, true)
1368 : intersection.trackParameters->parameters()[Trk::locX];
1369
1370 float z = intersection.trackParameters->position().z();
1371 float errx = intersection.trackParameters->covariance() ?
1372 Amg::error(*intersection.trackParameters->covariance(), Trk::locX) : 0.;
1373 float x = barrelLike ? z : r;
1374 float y = barrelLike ? r : z;
1375 float theta = std::atan2(y, x);
1376
1377 // get phi hits
1378 const Muon::MuonLayerHoughTool::PhiMaximumVec& phiMaxVec = houghDataPerSector.phiMaxVec[toInt(regionIndex)];
1379 ATH_MSG_DEBUG(" Got Phi Hough maxima " << phiMaxVec.size() << " phi " << phi);
1380
1381 // lambda to handle calibration and selection of clusters
1382 auto handleCluster = [intersection, this](const Muon::MuonCluster& prd,
1383 std::vector<std::shared_ptr<const Muon::MuonClusterOnTrack>>& clusters) {
1384 std::unique_ptr<const Muon::MuonClusterOnTrack> cluster{m_muonPRDSelectionTool->calibrateAndSelect(intersection, prd)};
1385 if (cluster) clusters.push_back(std::move(cluster));
1386 };
1387
1388 // loop over maxima and associate phi hits with the extrapolation, should optimize this but calculating the residual with the phi
1389 // maximum
1390 std::vector<std::shared_ptr<const Muon::MuonClusterOnTrack>> phiClusterOnTracks;
1391 Muon::MuonLayerHoughTool::PhiMaximumVec::const_iterator pit = phiMaxVec.begin();
1392 Muon::MuonLayerHoughTool::PhiMaximumVec::const_iterator pit_end = phiMaxVec.end();
1393 for (; pit != pit_end; ++pit) {
1394 const MuonHough::MuonPhiLayerHough::Maximum& maximum = **pit;
1395 for (const std::shared_ptr<MuonHough::PhiHit>& hit : maximum.hits) {
1396 // treat the case that the hit is a composite TGC hit
1397 if (hit->tgc) {
1398 Identifier id = hit->tgc->phiCluster.front()->identify();
1399 if (m_idHelperSvc->layerIndex(id) != intersection.layerSurface.layerIndex) continue;
1400 for (const Muon::MuonCluster* prd : hit->tgc->phiCluster) handleCluster(*prd, phiClusterOnTracks);
1401 } else if (hit->prd && !(hit->prd->type(Trk::PrepRawDataType::sTgcPrepData) ||
1402 hit->prd->type(Trk::PrepRawDataType::MMPrepData))) {
1403 const Identifier id = hit->prd->identify();
1404 if (m_idHelperSvc->layerIndex(id) != intersection.layerSurface.layerIndex) continue;
1405 handleCluster(static_cast<const Muon::MuonCluster&>(*hit->prd), phiClusterOnTracks);
1406 }
1407 }
1408 }
1409
1410 ATH_MSG_DEBUG(" associateHoughMaxima: " << printIntersectionToString(intersection) << " maxima " << maxVec.size() << " x,y=(" << x
1411 << "," << y << ") errorx " << errx << " "
1412 << " angle " << theta);
1413
1414 // loop over maxima and associate them to the extrapolation
1415 for (const auto& mit : maxVec) {
1416 const MuonHough::MuonLayerHough::Maximum& maximum = *mit;
1417 if (std::find_if(maximum.hits.begin(),maximum.hits.end(),
1418 [](const std::shared_ptr<MuonHough::Hit>& hit){
1419 return hit->prd && (hit->prd->type(Trk::PrepRawDataType::sTgcPrepData) ||
1420 hit->prd->type(Trk::PrepRawDataType::MMPrepData));
1421 }) != maximum.hits.end()) continue;
1422 float residual = maximum.pos - x;
1423 float residualTheta = maximum.theta - theta;
1424 float refPos = (maximum.hough != nullptr) ? maximum.hough->m_descriptor.referencePosition : 0;
1425 float maxwidth = (maximum.binposmax - maximum.binposmin);
1426
1427 if (maximum.hough){
1428 maxwidth *= maximum.hough->m_binsize;
1429 }
1430 const float pullUncert = std::sqrt(errx * errx + maxwidth * maxwidth / 12.);
1431 float pull = residual / (pullUncert > std::numeric_limits<float>::epsilon() ? pullUncert : 1.) ;
1432
1433 ATH_MSG_DEBUG(" Hough maximum " << maximum.max << " position (" << refPos << "," << maximum.pos << ") residual " << residual
1434 << " pull " << pull << " angle " << maximum.theta << " residual " << residualTheta);
1435
1436 // fill validation content
1437
1438 // select maximum and add it to LayerData
1439 if (std::abs(pull) > 5) continue;
1440 layerData.maximumDataVec.emplace_back(std::make_shared<MaximumData>(intersection, &maximum, phiClusterOnTracks));
1441 }
1442 }
1443 void MuonStauRecoTool::mdtTimeCalibration(const Identifier& /*id*/, float& time, float& error) const {
1444 time -= 1.5;
1445 error *= 1.;
1446 }
1447 void MuonStauRecoTool::rpcTimeCalibration(const Identifier& /*id*/, float& time, float& error) const {
1448 time -= 0;
1449 error *= 0.5;
1450 }
1451 void MuonStauRecoTool::segmentTimeCalibration(const Identifier& /*id*/, float& time, float& error) const {
1452 time -= 1.5;
1453 error *= 1.;
1454 }
1455
1456 float MuonStauRecoTool::calculateTof(const float beta, const float dist) const {
1457 return std::abs(beta) > 0 ? dist * inverseSpeedOfLight / beta : 1.e12;
1458 }
1459
1461 float MuonStauRecoTool::calculateBeta(const float time, const float dist) const {
1462 return time != 0. ? dist * inverseSpeedOfLight / time : 20.;
1463 }
1465 const MuonStauRecoTool::CandidateVec& candidates, int stage) const {
1466 if (Gaudi::Concurrency::ConcurrencyFlags::numThreads() > 1) {
1467 ATH_MSG_WARNING("You are calling the non thread-safe MuonRecoValidationTool with multiple threads, will most likely crash");
1468 }
1469 if (m_recoValidationTool.empty()) return;
1470
1471 ATH_MSG_DEBUG("add candidates to ntuple, stage " << stage);
1472 for (const auto& candidate : candidates) {
1473 int ntimes = 0;
1474 float beta = -1.;
1475 float chi2ndof = -1.;
1476 if (candidate->finalBetaFitResult.status != 0) {
1477 ntimes = candidate->stauHits.size();
1478 beta = candidate->finalBetaFitResult.beta;
1479 chi2ndof = candidate->finalBetaFitResult.chi2PerDOF();
1480 } else if (candidate->betaFitResult.status != 0) {
1481 ntimes = candidate->hits.size();
1482 beta = candidate->betaFitResult.beta;
1483 chi2ndof = candidate->betaFitResult.chi2PerDOF();
1484 } else {
1485 ntimes = 1;
1486 beta = candidate->betaSeed.beta;
1487 chi2ndof = 0;
1488 }
1489 if (candidate->combinedTrack) ATH_MSG_DEBUG("candidate has combined track");
1490 m_recoValidationTool->addMuonCandidate(indetTrackParticle, candidate->muonCandidate.get(), candidate->combinedTrack.get(),
1491 ntimes, beta, chi2ndof, stage);
1492 }
1493 }
1494
1495} // namespace MuonCombined
Scalar phi() const
phi method
Scalar theta() const
theta method
#define endmsg
#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_WARNING(x)
#define ATH_MSG_DEBUG(x)
Helper class to provide constant type-safe access to aux data.
char data[hepevt_bytes_allocation_ATLAS]
Definition HepEvt.cxx:11
DataVector< MuonCombined::InDetCandidate > InDetCandidateCollection
This typedef represents a collection of InDetCandidate objects.
std::pair< std::vector< unsigned int >, bool > res
DataVector< Trk::Track > TrackCollection
This typedef represents a collection of Trk::Track objects.
#define y
#define x
#define z
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
bool msgLvl(const MSG::Level lvl) const
MsgStream & msg() const
DataModel_detail::const_iterator< DataVector > const_iterator
Definition DataVector.h:838
value_type push_back(value_type pElem)
Add an element to the end of the collection.
DataModel_detail::iterator< DataVector > iterator
Definition DataVector.h:842
size_type size() const noexcept
Returns the number of elements in the collection.
bool empty() const noexcept
Returns true if the collection is empty.
void addEntry(const InDetCandidate *idcand, TagBase *tag)
bool isSiliconAssociated() const
Returns true if this candidate was formed from a special far forward InDet track.
const xAOD::TrackParticle & indetTrackParticle() const
access TrackParticle
const Muon::MuonSystemExtension * getExtension() const
TagBase implementation for a combined fit.
void addTag(const InDetCandidate &inDetCandidate, Candidate &candidate, InDetCandidateToTagMap *tagMap, TrackCollection *combTracks, Trk::SegmentCollection *segments) const
create final tag object and add it to the inDetCandidate
bool extractTimeHits(const MaximumData &maximumData, Muon::TimePointBetaFitter::HitVec &hits, const BetaSeed *seed=0) const
extract hits for the beta fit, returns true if hits were added
bool refineCandidates(const EventContext &ctx, CandidateVec &candidates) const
refine candidates: find segments for the given beta
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
ServiceHandle< Muon::IMuonEDMHelperSvc > m_edmHelperSvc
bool combineCandidates(const EventContext &ctx, const xAOD::TrackParticle &indetTrackParticle, CandidateVec &candidates) const
combine reconstruction
ToolHandle< Trk::ITrackAmbiguityProcessorTool > m_trackAmbibuityResolver
ToolHandle< Muon::IMuonPRDSelectionTool > m_muonPRDSelectionToolStau
void rpcTimeCalibration(const Identifier &id, float &time, float &error) const
virtual void extendWithPRDs(const InDetCandidateCollection &inDetCandidates, InDetCandidateToTagMap *tagMap, IMuonCombinedInDetExtensionTool::MuonPrdData prdData, TrackCollection *combTracks, TrackCollection *meTracks, Trk::SegmentCollection *segments, const EventContext &ctx) const override
void extractTimeMeasurementsFromTrack(const EventContext &ctx, Candidate &candidate) const
extract time measurements from the track associated with the candidate
ToolHandle< Muon::IMuonSegmentMaker > m_segmentMaker
ToolHandle< Muon::IMuonRecoValidationTool > m_recoValidationTool
Gaudi::Property< double > m_ptThreshold
std::vector< std::shared_ptr< Candidate > > CandidateVec
Gaudi::Property< bool > m_doSummary
virtual StatusCode initialize() override
Gaudi::Property< double > m_mdttBetaAssociationCut
PublicToolHandle< Muon::MuonEDMPrinterTool > m_printer
ToolHandle< Muon::IMuonSegmentMaker > m_segmentMakerT0Fit
void handleCandidate(const EventContext &ctx, const InDetCandidate &inDetCandidate, InDetCandidateToTagMap *tagMap, TrackCollection *combTracks, Trk::SegmentCollection *segments) const
handle a single candidate
virtual void extend(const InDetCandidateCollection &inDetCandidates, InDetCandidateToTagMap *tagMap, TrackCollection *combTracks, TrackCollection *meTracks, Trk::SegmentCollection *segments, const EventContext &ctx) const override
IMuonCombinedInDetExtensionTool interface: extend ID candidate.
void getBetaSeeds(MaximumData &maximumData) const
calculate the beta seeds for a give MaximumData
bool createCandidates(const AssociatedData &associatedData, CandidateVec &candidates) const
create candidates from the beta seeds
Gaudi::Property< bool > m_segmentMDTT
ToolHandle< Trk::IUpdator > m_updator
ToolHandle< Muon::IMuonLayerSegmentMatchingTool > m_segmentMatchingTool
SG::ReadHandleKey< Muon::HoughDataPerSectorVec > m_houghDataPerSectorVecKey
storegate
ToolHandle< Muon::IMdtDriftCircleOnTrackCreator > m_mdtCreator
bool extractTimeMeasurements(const EventContext &ctx, const Muon::MuonSystemExtension &muonSystemExtension, AssociatedData &associatedData) const
associate Hough maxima and associate time measurements
void extractRpcTimingFromMaximum(const Muon::MuonSystemExtension::Intersection &intersection, MaximumData &maximumData) const
extract RPC hit timing
ToolHandle< Muon::IMdtDriftCircleOnTrackCreator > m_mdtCreatorStau
std::unique_ptr< TruthInfo > getTruth(const xAOD::TrackParticle &indetTrackParticle) const
extract truth from the indetTrackParticle
Gaudi::Property< double > m_segmentBetaAssociationCut
void extendCandidates(CandidateVec &candidates, std::set< const MaximumData * > &usedMaximumData, LayerDataVec::const_iterator it, LayerDataVec::const_iterator it_end) const
extend a CandidateVec with the next LayerData
Muon::MuonSectorMapping m_muonSectorMapping
Gaudi::Property< bool > m_doTruth
void associateHoughMaxima(const EventContext &ctx, LayerData &layerData) const
associate Hough maxima to intersection
void findSegments(const Muon::MuonSystemExtension::Intersection &intersection, MaximumData &maximumData, std::vector< std::shared_ptr< const Muon::MuonSegment > > &t0fittedSegments, const ToolHandle< Muon::IMuonPRDSelectionTool > &muonPRDSelectionTool, const ToolHandle< Muon::IMuonSegmentMaker > &segmentMaker, float beta=1.) const
find segments for a given maximum
ToolHandle< MuonCombined::MuonInsideOutRecoTool > m_insideOutRecoTool
MuonStauRecoTool(const std::string &type, const std::string &name, const IInterface *parent)
Default AlgTool functions.
ToolHandle< Muon::IMuonHitTimingTool > m_hitTimingTool
void segmentTimeCalibration(const Identifier &id, float &time, float &error) const
std::vector< std::shared_ptr< MaximumData > > MaximumDataVec
Gaudi::Property< bool > m_ignoreSiAssocated
float calculateTof(const float beta, const float dist) const
Calcualte for zero betas.
bool resolveAmbiguities(CandidateVec &candidates) const
resolve ambiguities between the candidates
void mdtTimeCalibration(const Identifier &id, float &time, float &error) const
void createRpcTimeMeasurementsFromClusters(const Muon::MuonSystemExtension::Intersection &intersection, const std::vector< Muon::RpcClusterObj > &clusterObjects, RpcTimeMeasurementVec &rpcTimeMeasurements) const
create Rpc hit timing for a set of clusters
Gaudi::Property< std::vector< int > > m_pdgsToBeConsidered
std::vector< LayerData > LayerDataVec
bool selectTruth(const TruthInfo *truthInfo) const
if truth tracking is enabled, return whether the pdg is selected
ToolHandle< Muon::IMuonPRDSelectionTool > m_muonPRDSelectionTool
Gaudi::Property< bool > m_addMDTExtrasMuGirlLowBeta
Gaudi::Property< double > m_rpcBetaAssociationCut
SG::ReadCondHandleKey< MuonCalib::MdtCalibDataContainer > m_calibDbKey
std::vector< RpcTimeMeasurement > RpcTimeMeasurementVec
float calculateBeta(const float time, const float dist) const
In cases of invalid times just return an phyisical value of 20 times the speed of light The subsequen...
void addCandidatesToNtuple(const xAOD::TrackParticle &indetTrackParticle, const CandidateVec &candidates, int stage) const
helper function to add Candidate to ntuple
virtual const Trk::Surface & surface() const override final
Return surface associated with this detector element.
Class for competing MuonClusters, it extends the Trk::CompetingRIOsOnTrack base class.
const std::vector< std::unique_ptr< const MuonClusterOnTrack > > & containedROTs() const
returns the vector of SCT_ClusterOnTrack objects .
Class to represent the calibrated clusters created from CSC strips.
virtual const CscPrepData * prepRawData() const override final
Returns the CscPrepData - is a CscPrepData in this scope.
double time() const
Returns the time.
This class represents the corrected MDT measurements, where the corrections include the effects of wi...
double driftRadius() const
Returns the value of the drift radius.
double driftTime() const
Returns the value of the drift time used to obtain the drift radius.
virtual const Trk::StraightLineSurface & associatedSurface() const override final
Returns the surface on which this measurement was taken.
virtual const MdtPrepData * prepRawData() const override final
Returns the PrepRawData used to create this corrected measurement.
Class to represent measurements from the Monitored Drift Tubes.
Definition MdtPrepData.h:33
int adc() const
Returns the ADC (typically range is 0 to 250).
Base class for Muon cluster RIO_OnTracks.
void setStrategy(Strategy)
Select the strategy to be used - only one can be set at a time.
void setParameter(CreationParameter, bool value)
HoughDataPerSec HoughDataPerSector
HoughDataPerSec::PhiMaximumVec PhiMaximumVec
HoughDataPerSec::MaximumVec MaximumVec
This is the common class for 3D segments used in the muon spectrometer.
virtual const Amg::Vector3D & globalPosition() const override final
global position
Tracking class to hold the extrapolation from a particle from the calo entry to the end of muon syste...
const std::vector< Intersection > & layerIntersections() const
access to the intersections with the layers.
Class to represent calibrated clusters formed from RPC strips.
float time() const
Return the time (ns).
Class to represent RPC measurements.
Definition RpcPrepData.h:35
Helper class to provide constant type-safe access to aux data.
bool isAvailable(const ELT &e) const
Test to see if this variable exists in the store.
virtual bool isValid() override final
Can the handle be successfully dereferenced?
class representing a drift circle meaurement on segment
Definition DCOnTrack.h:16
void residual(double res)
set residual
Definition DCOnTrack.h:35
void errorTrack(double error)
set track error
Definition DCOnTrack.h:41
virtual bool fit(Segment &result, const Line &line, const DCOnTrackVec &dcs, double t0Seed=-99999.) const
This class represents a drift time measurement.
Definition DriftCircle.h:22
unsigned int index() const
Definition DriftCircle.h:99
double r() const
access to drift radius
Definition DriftCircle.h:86
const LocVec2D & position() const
access to local position
Definition DriftCircle.h:74
double dr() const
access to error drift radius
Definition DriftCircle.h:89
@ InTime
drift time too small to be compatible with drift spectrum
Definition DriftCircle.h:27
Implementation of 2 dimensional vector class.
Definition LocVec2D.h:16
bool dropHits(Segment &segment, bool &hasDroppedHit, unsigned int &dropDepth) const
void debugLevel(int debugLevel)
double toLineY(const LocVec2D &pos) const
represents the three-dimensional global direction with respect to a planar surface frame.
double angleYZ() const
access method for angle of local YZ projection
This class is the pure abstract base class for all fittable tracking measurements.
const LocalParameters & localParameters() const
Interface method to get the LocalParameters.
virtual bool type(MeasurementBaseType::Type type) const =0
Interface method checking the type.
const Amg::MatrixX & localCovariance() const
Interface method to get the localError.
const Amg::Vector3D & momentum() const
Access method for the momentum.
const Amg::Vector3D & position() const
Access method for the position.
Class for a planaer rectangular or trapezoidal surface in the ATLAS detector.
virtual Intersection straightLineIntersection(const Amg::Vector3D &pos, const Amg::Vector3D &dir, bool forceDir, Trk::BoundaryCheck bchk) const override final
fast straight line intersection schema - standard: provides closest intersection and (signed) path le...
void globalToLocalDirection(const Amg::Vector3D &glodir, Trk::LocalDirection &locdir) const
This method transforms the global direction to a local direction wrt the plane.
Identifier identify() const
return the identifier
Identifier identify() const
return the identifier -extends MeasurementBase
Base class for all TrackSegment implementations, extends the common MeasurementBase.
float errorTime() const
access to the error on the measured time
float time() const
access to the measured time
virtual void localToGlobal(const Amg::Vector2D &locp, const Amg::Vector3D &mom, Amg::Vector3D &glob) const override final
Specified for StraightLineSurface: LocalToGlobal method without dynamic memory allocation.
@ Outlier
This TSoS contains an outlier, that is, it contains a MeasurementBase/RIO_OnTrack which was not used ...
const Trk::Track * track() const
Returns a pointer (which can be NULL) to the Trk::Track which was used to make this TrackParticle.
virtual double phi() const override final
The azimuthal angle ( ) of the particle (has range to .).
virtual double pt() const override final
The transverse momentum ( ) of the particle.
virtual double eta() const override final
The pseudorapidity ( ) of the particle.
std::vector< std::string > intersection(std::vector< std::string > &v1, std::vector< std::string > &v2)
const std::string selection
int r
Definition globals.cxx:22
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 ...
Eigen::Affine3d Transform3D
Eigen::Matrix< double, 2, 1 > Vector2D
Eigen::Matrix< double, 3, 1 > Vector3D
The MuonTagToSegMap is an auxillary construct that links the MuonSegments associated with a combined ...
std::string printIntersectionToString(const Muon::MuonSystemExtension::Intersection &intersection)
const std::string & layerName(LayerIndex index)
convert LayerIndex into a string
DetectorRegionIndex
enum to classify the different layers in the muon spectrometer
constexpr int toInt(const EnumType enumVal)
unsigned int sectorLayerHash(DetectorRegionIndex detectorRegionIndex, LayerIndex layerIndex)
create a hash out of region and layer
LayerIndex
enum to classify the different layers in the muon spectrometer
const std::string & stName(StIndex index)
convert StIndex into a string
const std::string & chName(ChIndex index)
convert ChIndex into a string
const std::string & regionName(DetectorRegionIndex index)
convert DetectorRegionIndex into a string
ChIndex
enum to classify the different chamber layers in the muon spectrometer
std::bitset< 23 > MuonDriftCircleErrorStrategyInput
@ VIEW_ELEMENTS
this data object is a view, it does not own its elmts
std::vector< bool > HitSelection
Definition HitSelection.h:9
std::vector< DCOnTrack > DCOnTrackVec
Definition DCOnTrack.h:59
DataVector< const Trk::TrackStateOnSurface > TrackStates
DataVector< Trk::Segment > SegmentCollection
@ locX
Definition ParamDefs.h:37
@ locR
Definition ParamDefs.h:44
@ locZ
local cylindrical
Definition ParamDefs.h:42
ParametersBase< TrackParametersDim, Charged > TrackParameters
Definition index.py:1
void stable_sort(DataModel_detail::iterator< DVL > beg, DataModel_detail::iterator< DVL > end)
Specialization of stable_sort for DataVector/List.
TrackParticle_v1 TrackParticle
Reference the current persistent version:
Muon::TimePointBetaFitter::HitVec hits
Muon::TimePointBetaFitter::FitResult betaFitResult
std::unique_ptr< Trk::Track > combinedTrack
std::vector< Muon::MuonLayerRecoData > allLayers
MuGirlNS::StauMDTHitExtras stauMDTHitExtras
Muon::TimePointBetaFitter::FitResult finalBetaFitResult
Muon::MuonSystemExtension::Intersection intersection
std::vector< std::shared_ptr< const Muon::MuonSegment > > t0fittedSegments
std::vector< std::shared_ptr< const Muon::MuonClusterOnTrack > > phiClusterOnTracks
const MuonHough::MuonLayerHough::Maximum * maximum
std::vector< std::shared_ptr< const Muon::RpcClusterOnTrack > > rpcClusters
struct representing the maximum in the hough space
RegionDescriptor m_descriptor
RegionPhiMaximumVec phiMaxVec
RegionMaximumVec maxVec
simple struct holding the result of the tool
std::vector< RpcClusterObj > clustersEta
bool cluster(const std::vector< const RpcPrepData * > &col)
std::vector< RpcClusterObj > clustersPhi
simple struct holding the fit result
float chi2PerDOF() const
chi2/ndof, return 0 if ndof == 0 or status == 0
float beta
status flag (0 = failed, 1 = ok)
simple struct holding the input to the fit
Amg::Vector3D position