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 clusters = crot->containedROTs();
413 } else {
414 const Muon::RpcClusterOnTrack* rpc = dynamic_cast<const Muon::RpcClusterOnTrack*>(meas);
415 if (rpc) clusters.push_back(rpc);
416 }
417 Identifier chamberId = m_idHelperSvc->chamberId(id);
418 bool measuresPhi = m_idHelperSvc->measuresPhi(id);
419 auto pos = rpcPrdsPerChamber.find(chamberId);
420 if (pos == rpcPrdsPerChamber.end()) {
421 if (measuresPhi)
422 rpcPrdsPerChamber[chamberId] = std::make_tuple(pars, clusters, RpcClVec());
423 else
424 rpcPrdsPerChamber[chamberId] = std::make_tuple(pars, RpcClVec(), clusters);
425 } else {
426 RpcClVec& clVec = measuresPhi ? std::get<1>(pos->second) : std::get<2>(pos->second);
427 clVec.insert(clVec.end(), clusters.begin(), clusters.end());
428 }
429 } else if (m_idHelperSvc->isCsc(id)) {
430 const Muon::CscClusterOnTrack* csc = dynamic_cast<const Muon::CscClusterOnTrack*>(meas);
431
433 float distance = pars->position().mag();
434 float time = csc->prepRawData()->time();
435
436 float ix = pars->position().x();
437 float iy = pars->position().y();
438 float iz = pars->position().z();
439 float ie = 0.;
440 float er = -1;
441 float sh = 0;
442 bool isEta = !m_idHelperSvc->measuresPhi(id);
443 float propTime = 0;
444 float tof = calculateTof(1, distance);
445 candidate.stauHits.push_back(MuGirlNS::StauHit(tech, time + tof, ix, iy, iz, id, ie, er, sh, isEta, propTime));
446 }
447 }
448
449 auto insertRpcs = [betaSeed, this](const Trk::TrackParameters& pars, const RpcClVec& clusters,
451 if (clusters.empty()) return;
452
453 std::vector<const Muon::MuonClusterOnTrack*> calibratedClusters;
454 for (const auto* cluster : clusters) {
455 const Muon::MuonClusterOnTrack* cl = m_muonPRDSelectionTool->calibrateAndSelect(pars, *cluster->prepRawData());
456 if (cl) calibratedClusters.push_back(cl);
457 }
458 if (calibratedClusters.empty()) return;
459
460 Muon::IMuonHitTimingTool::TimingResult result = m_hitTimingTool->calculateTimingResult(calibratedClusters);
461 for (const auto* cl : calibratedClusters) delete cl;
462 if (!result.valid) return;
463
464 Identifier id = clusters.front()->identify();
465
467 float distance = pars.position().mag();
468 float time = result.time;
469 float ix = pars.position().x();
470 float iy = pars.position().y();
471 float iz = pars.position().z();
472 float ie = 0.;
473 float er = result.error;
474 rpcTimeCalibration(id, time, er);
475 float sh = 0;
476 bool isEta = !m_idHelperSvc->measuresPhi(id);
477 if (isEta) tech = MuGirlNS::RPCETA_STAU_HIT;
478 float propTime = 0;
479 float tof = calculateTof(1, distance);
480 float beta = calculateBeta(time + tof, distance);
481 ATH_MSG_VERBOSE(" adding " << m_idHelperSvc->toString(id) << " distance " << distance << " time " << time << " beta" << beta
482 << " diff " << std::abs(beta - betaSeed));
483
484 if (std::abs(beta - betaSeed) > m_mdttBetaAssociationCut) return;
485
486 hits.push_back(Muon::TimePointBetaFitter::Hit(distance, time, er));
487 candidate.stauHits.push_back(MuGirlNS::StauHit(tech, time + tof, ix, iy, iz, id, ie, er, sh, isEta, propTime));
488 };
489
490 // get RPC timing per chamber
491 RpcClPerChMap::const_iterator chit = rpcPrdsPerChamber.begin();
492 RpcClPerChMap::const_iterator chit_end = rpcPrdsPerChamber.end();
493 ATH_MSG_VERBOSE("RPCs per chamber " << rpcPrdsPerChamber.size());
494
495 for (; chit != chit_end; ++chit) {
496 const Trk::TrackParameters* pars = std::get<0>(chit->second);
497 const RpcClVec& phiClusters = std::get<1>(chit->second);
498 const RpcClVec& etaClusters = std::get<2>(chit->second);
499 insertRpcs(*pars, phiClusters, candidate, hits);
500 insertRpcs(*pars, etaClusters, candidate, hits);
501 }
502
503 // get timing per MDT chamber, use segment error strategy (errors of the RT relation
505 Muon::MuonDriftCircleErrorStrategy calibrationStrategy(bits);
508
511 segmentFinder.setMaxDropDepth(2);
512 segmentFinder.setChi2DropCut(5);
513 segmentFinder.setDeltaCut(3);
514
515 MdtChamberLayerData::const_iterator mit = mdtDataPerChamberLayer.begin();
516 MdtChamberLayerData::const_iterator mit_end = mdtDataPerChamberLayer.end();
517 for (; mit != mit_end; ++mit) {
518 ATH_MSG_VERBOSE(" new station layer " << Muon::MuonStationIndex::chName((Muon::MuonStationIndex::ChIndex)(mit->first % 1000))
519 << " hits " << mit->second.size());
520 if (mit->second.size() < 4) continue;
521
522 // get RE element for first hit
523 const MuonGM::MdtReadoutElement* detEl = mit->second.front().second->detectorElement();
524 const Trk::PlaneSurface* surf = dynamic_cast<const Trk::PlaneSurface*>(&detEl->surface());
525 if (!surf) {
526 ATH_MSG_WARNING("MdtReadoutElement should always have a PlaneSurface as reference surface");
527 continue;
528 }
529 Amg::Transform3D gToStation = detEl->GlobalToAmdbLRSTransform();
530
531 // get TrackParameters and SL intersect the DetEl surface (above a few GeV SL intersection is accurate enough)
532 const Trk::TrackParameters& firstPars = *mit->second.front().first;
533 Trk::Intersection slIntersection = surf->straightLineIntersection(firstPars.position(), firstPars.momentum(), false, false);
534
535 // calculate seed position and direction
536 Trk::LocalDirection seedLocDir;
537 surf->globalToLocalDirection(firstPars.momentum(), seedLocDir);
538 Amg::Vector3D seedLocPos = gToStation * slIntersection.position;
539 TrkDriftCircleMath::LocVec2D seedPos(seedLocPos.y(), seedLocPos.z());
540 TrkDriftCircleMath::Line seedLine(seedPos, seedLocDir.angleYZ());
542
543 std::vector<std::pair<std::shared_ptr<const Muon::MdtDriftCircleOnTrack>, const Trk::TrackParameters*>> indexLookUp;
544 unsigned index = 0;
545 for (const auto& entry : mit->second) {
546 const Trk::TrackParameters& pars = *entry.first;
547 const Muon::MdtDriftCircleOnTrack& mdt = *entry.second;
548 Identifier id = mdt.identify();
549 // calibrate MDT
550 std::unique_ptr<const Muon::MdtDriftCircleOnTrack> calibratedMdt(
551 m_mdtCreatorStau->correct(*mdt.prepRawData(), pars, &calibrationStrategy, betaSeed));
552 if (!calibratedMdt) {
553 ATH_MSG_WARNING("Failed to recalibrate existing MDT on track " << m_idHelperSvc->toString(id));
554 continue;
555 }
556 ATH_MSG_VERBOSE(" recalibrated MDT " << m_idHelperSvc->toString(id) << " r " << calibratedMdt->driftRadius() << " "
557 << Amg::error(calibratedMdt->localCovariance(), Trk::locR) << " old r "
558 << mdt.driftRadius() << " " << Amg::error(mdt.localCovariance(), Trk::locR)
559 << " r_track " << pars.parameters()[Trk::locR] << " residual "
560 << std::abs(mdt.driftRadius()) - std::abs(pars.parameters()[Trk::locR]));
561
562 // calculate tube position taking into account the second coordinate
563 Amg::Vector2D lp(0., pars.parameters()[Trk::locZ]);
564 Amg::Vector3D gpos;
565 mdt.associatedSurface().localToGlobal(lp, pars.momentum(), gpos);
566
567 // calculate local AMDB position
568 Amg::Vector3D locPos = gToStation * gpos;
569 TrkDriftCircleMath::LocVec2D lpos(locPos.y(), locPos.z());
570
571 double r = std::abs(calibratedMdt->driftRadius());
572 double dr = Amg::error(calibratedMdt->localCovariance(), Trk::locR);
573
574 // create identifier
575 TrkDriftCircleMath::MdtId mdtid(m_idHelperSvc->mdtIdHelper().isBarrel(id), m_idHelperSvc->mdtIdHelper().multilayer(id) - 1,
576 m_idHelperSvc->mdtIdHelper().tubeLayer(id) - 1, m_idHelperSvc->mdtIdHelper().tube(id) - 1);
577
578 // create new DriftCircle
580 TrkDriftCircleMath::DCOnTrack dcOnTrack(dc, 1., 1.);
581
582 dcs.push_back(dcOnTrack);
583 indexLookUp.emplace_back(std::move(calibratedMdt), &pars);
584 ++index;
585 }
586
587 // now loop over the hits and fit the segment taking out each of the hits individually
588 for (unsigned int i = 0; i < dcs.size(); ++i) {
590 selection[i] = 1;
592 if (!mdtFitter.fit(result, seedLine, dcs, selection)) {
593 ATH_MSG_DEBUG("Fit failed ");
594 continue;
595 }
597 segment.hitsOnTrack(dcs.size());
598 unsigned int ndofFit = segment.ndof();
599 if (ndofFit < 1) continue;
600 double chi2NdofSegmentFit = segment.chi2() / ndofFit;
601 bool hasDropHit = false;
602 unsigned int dropDepth = 0;
603 if (!segmentFinder.dropHits(segment, hasDropHit, dropDepth)) {
604 ATH_MSG_DEBUG("DropHits failed, fit chi2/ndof " << chi2NdofSegmentFit);
605 if (msgLvl(MSG::VERBOSE)) {
606 segmentFinder.debugLevel(20);
607 segment = result;
608 segmentFinder.dropHits(segment, hasDropHit, dropDepth);
609 segmentFinder.debugLevel(0);
610 }
611 continue;
612 }
613 if (i >= segment.dcs().size()) continue;
615 const TrkDriftCircleMath::DCOnTrack& dc = segment.dcs()[i];
616 double res = dc.residual();
617 double err = std::sqrt(dc.dr() * dc.dr() + dc.errorTrack() * dc.errorTrack());
618 double pull = res / err;
619 double rline = toLine.toLineY(dc.position());
620 int index = dc.index();
621 if (index < 0 || index >= (int)indexLookUp.size()) {
622 ATH_MSG_WARNING(" lookup of TrackParameters and MdtDriftCircleOnTrack failed " << index << " range: 0 - "
623 << indexLookUp.size() - 1);
624 continue;
625 }
626 const Trk::TrackParameters* pars = indexLookUp[dc.index()].second;
627 const Muon::MdtDriftCircleOnTrack* mdt = indexLookUp[dc.index()].first.get();
628 Identifier id = mdt->identify();
629
630 // calibrate MDT with nominal timing
631 std::shared_ptr<const Muon::MdtDriftCircleOnTrack> calibratedMdt(
632 m_mdtCreator->correct(*mdt->prepRawData(), *pars, &calibrationStrategy, betaSeed));
633 if (!calibratedMdt.get()) {
634 ATH_MSG_WARNING("Failed to recalibrate existing MDT on track " << m_idHelperSvc->toString(id));
635 continue;
636 }
637 float distance = pars->position().mag();
638 float time = 0.;
639
640 float ix = pars->position().x();
641 float iy = pars->position().y();
642 float iz = pars->position().z();
643 float ie = 0.;
644 float er = -1;
645 float sh = 0;
646 bool isEta = !m_idHelperSvc->measuresPhi(id);
647 float propTime = 0;
648 float tof = calculateTof(1, distance);
649
650 float iadc = mdt->prepRawData()->adc();
651 float irdrift = mdt->driftRadius();
652
653 // use inverted RT relation together with track prediction to get estimate of drift time
654 float driftTime = calibratedMdt->driftTime(); // we need to add beta seed as it was subtracted when calibrating the hits
655 float locR = rline;
656 float errR = dc.errorTrack();
657 auto data = mdtCalibConstants->getCalibData(id, msgStream());
658 const auto& rtRelation = data->rtRelation;
659 float drdt = rtRelation->rt()->driftVelocity(driftTime);
660 float rres = rtRelation->rtRes()->resolution(driftTime);
661 float tres = rres / drdt;
662 float TlocR = rtRelation->tr()->driftTime(std::abs(locR)).value_or(0.);
663 float trackTimeRes = errR / drdt;
664 float tofShiftFromBeta = 0.; // muonBetaCalculationUtils.calculateTof(betaSeed,distance)-tof;
665 er = std::sqrt(tres * tres + trackTimeRes * trackTimeRes);
666 mdtTimeCalibration(id, driftTime, er);
667 time = driftTime - TlocR + tofShiftFromBeta;
668 propTime = driftTime;
669 ie = trackTimeRes;
670
671 const float beta = calculateBeta(time + tof, distance);
672 bool isSelected = std::abs(beta - betaSeed) < m_mdttBetaAssociationCut;
673
674 if (msgLvl(MSG::DEBUG)) {
675 msg(MSG::DEBUG) << m_idHelperSvc->toString(id) << std::setprecision(2) << " segment: after fit " << std::setw(5)
676 << chi2NdofSegmentFit << " ndof " << std::setw(2) << ndofFit;
677 if (segment.ndof() != ndofFit)
678 msg(MSG::DEBUG) << " after outlier " << std::setw(5) << chi2NdofSegmentFit << " ndof " << std::setw(2) << ndofFit;
679 msg(MSG::DEBUG) << " driftR " << std::setw(4) << dc.r() << " rline " << std::setw(5) << rline << " residual "
680 << std::setw(5) << res << " pull " << std::setw(4) << pull << " time " << std::setw(3) << time
681 << " beta" << std::setw(2) << beta << " err " << std::setw(3) << er << " intrinsic " << std::setw(3)
682 << tres << " track " << std::setw(3) << trackTimeRes;
683 if (!isSelected) msg(MSG::DEBUG) << " outlier";
684 msg(MSG::DEBUG) << std::setprecision(5) << endmsg;
685 }
686
687 if (!isSelected) {
688 // write out hits that don't pass the beta association cut but still store them
689 candidate.stauHits.emplace_back(MuGirlNS::StauHit(MuGirlNS::MDTT_STAU_HIT, time + tof, ix, iy, iz, id, ie, er, sh, isEta, propTime, false));
691 float iadc = mdt->prepRawData()->adc();
692 float irdrift = mdt->driftRadius();
693 candidate.stauMDTHitExtras.emplace_back(MuGirlNS::StauMDTHitExtra(iadc, irdrift));
694 }
695 continue;
696 }
697
698 // only store hits for future use if they pass the beta association cut
699 hits.emplace_back(distance, time, er);
700 candidate.stauHits.emplace_back(MuGirlNS::MDTT_STAU_HIT, time + tof, ix, iy, iz, id, ie, er, sh, isEta, propTime, true);
702 candidate.stauMDTHitExtras.emplace_back(MuGirlNS::StauMDTHitExtra(iadc, irdrift));
703 }
704 }
705 }
706 // fit data
707 Muon::TimePointBetaFitter::FitResult betaFitResult = fitter.fitWithOutlierLogic(hits);
708 ATH_MSG_DEBUG(" extractTimeMeasurementsFromTrack: extracted " << candidate.stauHits.size() << " time measurements "
709 << " status fit " << betaFitResult.status << " beta "
710 << betaFitResult.beta << " chi2/ndof " << betaFitResult.chi2PerDOF());
711
712 candidate.finalBetaFitResult = betaFitResult;
713 }
714
715 void MuonStauRecoTool::addTag(const InDetCandidate& indetCandidate,
717 InDetCandidateToTagMap* tagMap,
718 TrackCollection* combTracks,
719 Trk::SegmentCollection* segments) const {
720 // get combined track and the segments
721 combTracks->push_back(candidate.combinedTrack.release());
722 ElementLink<TrackCollection> comblink(*combTracks, combTracks->size() - 1);
723 std::vector<ElementLink<Trk::SegmentCollection>> segmentLinks;
724 for (const auto& layer : candidate.allLayers) {
725 for (const auto& segment : layer.segments) {
726 segments->push_back(segment->clone());
727 ElementLink<Trk::SegmentCollection> segLink(*segments, segments->size() - 1);
728 segmentLinks.push_back(segLink);
729 }
730 }
731
732 // create tag
733 MuonCombined::MuGirlLowBetaTag* tag = new MuonCombined::MuGirlLowBetaTag(comblink, segmentLinks);
734
735 // add additional info
736 tag->setMuBeta(candidate.betaFitResult.beta);
737
738 // add StauExtras
739 std::unique_ptr<MuGirlNS::StauExtras> stauExtras = std::make_unique<MuGirlNS::StauExtras>();
740 stauExtras->betaAll = candidate.betaFitResult.beta;
741 stauExtras->betaAllt = candidate.finalBetaFitResult.beta;
742 stauExtras->hits = candidate.stauHits;
743 // TODO: ALEXIS ADD FLAG
745 stauExtras->extraMDTHitInfo = candidate.stauMDTHitExtras;
746 }
747
748 tag->setStauExtras(std::move(stauExtras));
749
750 // print results afer refineCandidate
751 if (m_doSummary || msgLvl(MSG::DEBUG)) {
752 msg(MSG::INFO) << " Summary::addTag ";
753 msg(MSG::INFO) << std::endl
754 << " candidate: beta fit result: beta " << candidate.betaFitResult.beta << " chi2/ndof "
755 << candidate.betaFitResult.chi2PerDOF() << " segments" << segmentLinks.size();
756 for (const auto& segment : segmentLinks) msg(MSG::INFO) << std::endl << " " << m_printer->print(**segment);
757 if (*comblink)
758 msg(MSG::INFO) << std::endl
759 << " track " << m_printer->print(**comblink) << std::endl
760 << m_printer->printStations(**comblink);
761 msg(MSG::INFO) << endmsg;
762 }
763
764 // add tag to IndetCandidate
765 tagMap->addEntry(&indetCandidate, tag);
766 }
767
769 ATH_MSG_DEBUG("Resolving ambiguities: candidates " << candidates.size());
770
771 // push tracks into a collection and run ambi-solver
773 std::map<const Trk::Track*, std::shared_ptr<Candidate>> trackCandidateLookup;
774 for (const auto& candidate : candidates) {
775 Trk::Track* track = candidate->combinedTrack.get();
776 if (track) {
777 tracks.push_back(track);
778 trackCandidateLookup[track] = candidate;
779 }
780 }
781
782 // first handle easy cases of zero or one track
783 if (tracks.empty()) return false;
784 if (tracks.size() == 1) return true;
785
786 // more than 1 track call ambiguity solver and select first track
787 std::unique_ptr<const TrackCollection> resolvedTracks(m_trackAmbibuityResolver->process(&tracks));
788 if (!resolvedTracks || resolvedTracks->empty()) {
789 ATH_MSG_WARNING("No track survived the ambiguity solving");
790 return false;
791 }
792 const Trk::Track* selectedTrack = resolvedTracks->front();
793
794 // get candidate
795 auto pos = trackCandidateLookup.find(selectedTrack);
796 if (pos == trackCandidateLookup.end()) {
797 ATH_MSG_WARNING("candidate lookup failed, this should not happen");
798 return false;
799 }
800
801 // remove all candidates that were not combined
802 std::shared_ptr<Candidate> candidate = pos->second;
803 candidates.clear();
804 candidates.push_back(candidate);
805
806 // print results afer resolveAmbiguities
807 if (m_doSummary || msgLvl(MSG::DEBUG)) {
808 msg(MSG::INFO) << " Summary::resolveAmbiguities ";
809 msg(MSG::INFO) << std::endl
810 << " candidate: beta fit result: beta " << candidate->betaFitResult.beta << " chi2/ndof "
811 << candidate->betaFitResult.chi2PerDOF() << " layers with segments" << candidate->allLayers.size() << std::endl
812 << " track " << m_printer->print(*candidate->combinedTrack) << std::endl
813 << m_printer->printStations(*candidate->combinedTrack);
814 msg(MSG::INFO) << endmsg;
815 }
816
817 return true;
818 }
819
820 bool MuonStauRecoTool::combineCandidates(const EventContext& ctx, const xAOD::TrackParticle& indetTrackParticle,
821 MuonStauRecoTool::CandidateVec& candidates) const {
822 // keep track of candidates that have a successfull fit
823 CandidateVec combinedCandidates;
824
825 // loop over candidates and redo segments using beta estimate from candidate
826 ATH_MSG_DEBUG("Combining candidates " << candidates.size());
827 for (auto& candidate : candidates) {
828 // find best matching track
829 std::pair<std::unique_ptr<const Muon::MuonCandidate>, std::unique_ptr<Trk::Track>> result =
830 m_insideOutRecoTool->findBestCandidate(ctx, indetTrackParticle, candidate->allLayers);
831
832 if (result.first && result.second) {
833 ATH_MSG_DEBUG(" combined track found " << std::endl
834 << m_printer->print(*result.second) << std::endl
835 << m_printer->printStations(*result.second));
836 // add segments and track pointer to the candidate
837 candidate->muonCandidate = std::move(result.first);
838 candidate->combinedTrack = std::move(result.second);
839
840 // extract times form track
841 extractTimeMeasurementsFromTrack(ctx, *candidate);
842 combinedCandidates.push_back(candidate);
843 if (!m_recoValidationTool.empty()) m_recoValidationTool->addTimeMeasurements(indetTrackParticle, candidate->stauHits);
844 }
845 }
846
847 // remove all candidates that were not combined
848 candidates = combinedCandidates;
849
850 // print results afer combineCandidate
851 if (m_doSummary || msgLvl(MSG::DEBUG)) {
852 msg(MSG::INFO) << " Summary::combineCandidates ";
853 if (candidates.empty())
854 msg(MSG::INFO) << " No candidated found ";
855 else
856 msg(MSG::INFO) << " candidates " << candidates.size();
857
858 for (const auto& candidate : candidates) {
859 msg(MSG::INFO) << std::endl
860 << " candidate: beta fit result: " << candidate->betaFitResult.beta << " chi2/ndof "
861 << candidate->betaFitResult.chi2PerDOF();
862 if (candidate->finalBetaFitResult.status != 0)
863 msg(MSG::INFO) << " MDTT beta fit result: " << candidate->finalBetaFitResult.beta << " chi2/ndof "
864 << candidate->finalBetaFitResult.chi2PerDOF();
865 msg(MSG::INFO) << " layers with segments" << candidate->allLayers.size() << std::endl
866 << " track " << m_printer->print(*candidate->combinedTrack) << std::endl
867 << m_printer->printStations(*candidate->combinedTrack);
868 }
869 msg(MSG::INFO) << endmsg;
870 }
871
872 return !candidates.empty();
873 }
874
876 CandidateVec& candidates) const {
877 // loop over layers and select seed maxima
878 MaximumDataVec seedMaximumDataVec;
879 LayerDataVec::const_iterator it = associatedData.layerData.begin();
880 LayerDataVec::const_iterator it_end = associatedData.layerData.end();
881 for (; it != it_end; ++it) {
882 // loop over maximumDataVec
883 for (const auto& maximumData : it->maximumDataVec) {
884 // add all maximumData that have a time measurement
885 if (!maximumData->betaSeeds.empty()) seedMaximumDataVec.push_back(maximumData);
886 }
887 }
888 ATH_MSG_DEBUG("Creating candidates from seeds " << seedMaximumDataVec.size());
889
890 if (seedMaximumDataVec.empty()) {
891 if (m_doSummary || msgLvl(MSG::DEBUG)) msg(MSG::INFO) << " Summary::createCandidates, no seeds found " << endmsg;
892 return false;
893 }
894
895 // sorting lambda for MaximumData seeds
896 auto SortMaximumDataVec = [](const std::shared_ptr<MaximumData>& max1, const std::shared_ptr<MaximumData>& max2) {
897 return max1->maximum->max < max2->maximum->max;
898 };
899 std::stable_sort(seedMaximumDataVec.begin(), seedMaximumDataVec.end(), SortMaximumDataVec);
900
901 // loop over seeds and create candidates
903 std::set<const MaximumData*> usedMaximumData;
904 MaximumDataVec::iterator sit = seedMaximumDataVec.begin();
905 MaximumDataVec::iterator sit_end = seedMaximumDataVec.end();
906 for (; sit != sit_end; ++sit) {
907 // only use once
908 if (usedMaximumData.count(sit->get())) continue;
909 usedMaximumData.insert(sit->get());
910
911 // create new candidates from the beta seeds of the maximum
912 CandidateVec newCandidates;
913 for (const auto& betaSeed : (*sit)->betaSeeds) { newCandidates.push_back(std::make_shared<Candidate>(betaSeed)); }
914 // extend the candidates
915 extendCandidates(newCandidates, usedMaximumData, associatedData.layerData.begin(), associatedData.layerData.end());
916
917 // loop over the candidates and fit them
918 for (auto& newCandidate : newCandidates) {
919 // fit data
920 newCandidate->betaFitResult = fitter.fitWithOutlierLogic(newCandidate->hits);
921 ATH_MSG_DEBUG(" New candidate: time measurements "
922 << newCandidate->hits.size() << " status " << newCandidate->betaFitResult.status << " beta "
923 << newCandidate->betaFitResult.beta << " chi2/ndof " << newCandidate->betaFitResult.chi2PerDOF());
924 // if the fit was successfull add the candidate to the candidate vector
925 if (newCandidate->betaFitResult.status != 0) {
926 newCandidate->combinedTrack = nullptr; // no track exists at this stage
927 candidates.push_back(newCandidate);
928 }
929 }
930 }
931
932 // print results afer createCandidate
933 if (m_doSummary || msgLvl(MSG::DEBUG)) {
934 msg(MSG::INFO) << " Summary::createCandidates ";
935 if (candidates.empty())
936 msg(MSG::INFO) << " No candidated found ";
937 else
938 msg(MSG::INFO) << " candidates " << candidates.size();
939
940 for (const auto& candidate : candidates) {
941 msg(MSG::INFO) << std::endl
942 << " candidate: beta seed " << candidate->betaSeed.beta << " beta fit result: beta "
943 << candidate->betaFitResult.beta << " chi2/ndof " << candidate->betaFitResult.chi2PerDOF() << " layers "
944 << candidate->layerDataVec.size();
945 for (const auto& layerData : candidate->layerDataVec)
946 msg(MSG::INFO) << std::endl
947 << " " << printIntersectionToString(layerData.intersection) << " maximumDataVec "
948 << layerData.maximumDataVec.size();
949 }
950 msg(MSG::INFO) << endmsg;
951 }
952
953 return !candidates.empty();
954 }
955
956 void MuonStauRecoTool::extendCandidates(MuonStauRecoTool::CandidateVec& candidates, std::set<const MaximumData*>& usedMaximumData,
957 MuonStauRecoTool::LayerDataVec::const_iterator it,
958 MuonStauRecoTool::LayerDataVec::const_iterator it_end) const {
959 // get current layer and move forward the
960 const LayerData& layerData = *it;
961 ATH_MSG_DEBUG(" extendCandidates: " << printIntersectionToString(layerData.intersection) << " maxima "
962 << layerData.maximumDataVec.size());
963
964 CandidateVec newCandidates; // store new candidates
965 for (auto& candidate : candidates) {
966 // keep track of how often we extend this candidate
967 unsigned int nextensions = 0;
968
969 // copy content of the candidate for reference
970 LayerDataVec layerDataVec = candidate->layerDataVec;
971 Muon::TimePointBetaFitter::HitVec hits = candidate->hits;
972
973 // loop over maximumDataVec of the layer
974 for (const auto& maximumData : layerData.maximumDataVec) {
975 // create new hit vector
976 Muon::TimePointBetaFitter::HitVec newhits; // create new hits vector and add the ones from the maximum
977 if (extractTimeHits(*maximumData, newhits, &candidate->betaSeed)) {
978 // decide which candidate to update, create a new candidate if a maximum was already selected in the layer
979 Candidate* theCandidate = nullptr;
980 if (nextensions == 0)
981 theCandidate = candidate.get();
982 else {
983 std::shared_ptr<Candidate> newCandidate = std::make_shared<Candidate>(candidate->betaSeed);
984 newCandidate->layerDataVec = layerDataVec;
985 newCandidate->hits = hits;
986 theCandidate = newCandidate.get();
987 newCandidates.emplace_back(std::move(newCandidate));
988 }
989
990 // create a LayerData object to add to the selected candidate
991 LayerData newLayerData(layerData.intersection);
992 newLayerData.maximumDataVec.push_back(maximumData);
993
994 // update the candidate
995 theCandidate->hits.insert(theCandidate->hits.end(), newhits.begin(), newhits.end());
996 theCandidate->layerDataVec.push_back(newLayerData);
997 usedMaximumData.insert(maximumData.get());
998
999 ATH_MSG_DEBUG(" adding maximumData: candidate hits " << theCandidate->hits.size() << " LayerDataVec "
1000 << theCandidate->layerDataVec.size() << " nextensions "
1001 << nextensions);
1002
1003 ++nextensions;
1004 }
1005 }
1006 }
1007 ATH_MSG_DEBUG(" extendCandidates done, new candidates " << newCandidates.size());
1008
1009 // add the new candidates
1010 candidates.insert(candidates.end(), newCandidates.begin(), newCandidates.end());
1011
1012 // move to the next layer, if we haven't reached the last layer, continue recursion
1013 ++it;
1014 if (it != it_end) extendCandidates(candidates, usedMaximumData, it, it_end);
1015 }
1016
1017 bool MuonStauRecoTool::extractTimeMeasurements(const EventContext& ctx,
1018 const Muon::MuonSystemExtension& muonSystemExtension,
1019 AssociatedData& associatedData) const {
1020 // get layer intersections
1021 // find RPC time measurements and segments to seed the beta fit using t0 fitting
1022 for (const Muon::MuonSystemExtension::Intersection& iSect: muonSystemExtension.layerIntersections()) {
1023 // create layer data object and add maxima
1024 LayerData layerData{iSect};
1025 associateHoughMaxima(ctx, layerData);
1026
1027 // skip layer of not maxima are associated
1028 if (layerData.maximumDataVec.empty()) continue;
1029
1030 associatedData.layerData.push_back(layerData);
1031
1032 // loop over associated maxima
1033 for (auto& maximum : layerData.maximumDataVec) {
1034 // extract RPC timing
1035 extractRpcTimingFromMaximum(iSect, *maximum);
1036
1037 // find segments for intersection
1038 std::vector<std::shared_ptr<const Muon::MuonSegment>> t0fittedSegments;
1039 findSegments(iSect, *maximum, t0fittedSegments, m_muonPRDSelectionTool, m_segmentMakerT0Fit);
1040 if (t0fittedSegments.empty()) continue;
1041
1042 // match segments to intersection, store the ones that match
1043 m_segmentMatchingTool->select(ctx, iSect, t0fittedSegments, maximum->t0fittedSegments);
1044
1045 // get beta seeds for Maximum
1046 getBetaSeeds(*maximum);
1047 }
1048 }
1049
1050 // print results afer extractTimeMeasurements
1051 if (m_doSummary || msgLvl(MSG::DEBUG)) {
1052 msg(MSG::INFO) << " Summary::extractTimeMeasurements ";
1053 if (associatedData.layerData.empty())
1054 msg(MSG::INFO) << " No layers associated ";
1055 else
1056 msg(MSG::INFO) << " Associated layers " << associatedData.layerData.size();
1057
1058 for (const auto& layerData : associatedData.layerData) {
1059 unsigned int nmaxWithBeta = 0;
1060 for (const auto& maximumData : layerData.maximumDataVec) {
1061 if (!maximumData->betaSeeds.empty()) ++nmaxWithBeta;
1062 }
1063 msg(MSG::INFO) << std::endl
1064 << " layer " << printIntersectionToString(layerData.intersection) << " associated maxima "
1065 << layerData.maximumDataVec.size() << " maxima with beta seeds " << nmaxWithBeta;
1066 }
1067 msg(MSG::INFO) << endmsg;
1068 }
1069
1070 // return false if no layers were associated
1071 return !associatedData.layerData.empty();
1072 }
1073
1075 const BetaSeed* seed) const {
1076 unsigned int nstart = hits.size();
1077
1078 auto addHit = [&](float distance, float time, float error, float cut) {
1079 if (seed) {
1080 float beta = calculateBeta(time + calculateTof(1, distance), distance);
1081 ATH_MSG_VERBOSE(" matching hit: distance " << distance << " time " << time << " beta" << beta << " diff "
1082 << std::abs(beta - seed->beta));
1083 if (std::abs(beta - seed->beta) > cut) return;
1084 } else {
1085 ATH_MSG_VERBOSE(" addHit: distance " << distance << " time " << time << " beta"
1086 << calculateBeta(time + calculateTof(1, distance), distance));
1087 }
1088 if (error != 0.) hits.emplace_back(distance, time, error);
1089 };
1090
1091 // add rpc measurements
1092 for (const auto& rpc : maximumData.rpcTimeMeasurements) {
1093 float time = rpc.time;
1094 float error = rpc.error;
1095 rpcTimeCalibration(rpc.rpcClusters.front()->identify(), time, error);
1096 addHit(rpc.rpcClusters.front()->globalPosition().mag(), time, error, m_rpcBetaAssociationCut);
1097 }
1098
1099 // add segment t0 fits
1100 // if not seeded take all segments
1101 if (!seed) {
1102 for (const auto& seg : maximumData.t0fittedSegments) {
1103 if (!seg->hasFittedT0()) continue;
1104 float time = seg->time();
1105 float error = seg->errorTime();
1106 Identifier id = m_edmHelperSvc->chamberId(*seg);
1107 segmentTimeCalibration(id, time, error);
1108 addHit(seg->globalPosition().mag(), time, error, m_segmentBetaAssociationCut);
1109 }
1110 } else {
1111 // pick the best match
1112 const Muon::MuonSegment* bestSegment = nullptr;
1113 float smallestResidual = FLT_MAX;
1114 for (const auto& seg : maximumData.t0fittedSegments) {
1115 if (!seg->hasFittedT0()) continue;
1116 float distance = seg->globalPosition().mag();
1117 float time = seg->time();
1118 float beta = calculateBeta(time + calculateTof(1, distance), distance);
1119 float residual = std::abs(beta - seed->beta);
1120
1121 if (residual < smallestResidual) {
1122 smallestResidual = residual;
1123 bestSegment = seg.get();
1124 }
1125 }
1126 if (bestSegment) {
1127 addHit(bestSegment->globalPosition().mag(), bestSegment->time(), bestSegment->errorTime(), m_segmentBetaAssociationCut);
1128 ATH_MSG_VERBOSE(" adding best segment: " << m_printer->print(*bestSegment));
1129 }
1130 }
1131 ATH_MSG_VERBOSE(" extractTimeHits done: added " << hits.size() - nstart << " hits");
1132
1133 return nstart != hits.size();
1134 }
1135
1137 // skip maximumData if no timing information is available
1138 if (maximumData.rpcTimeMeasurements.empty() && maximumData.t0fittedSegments.empty()) return;
1139
1140 // fitter + hits
1143 extractTimeHits(maximumData, hits);
1144
1145 Muon::TimePointBetaFitter::FitResult result = fitter.fitWithOutlierLogic(hits);
1146 float chi2ndof = result.chi2PerDOF();
1147
1148 ATH_MSG_DEBUG(" fitting beta for maximum: time measurements " << hits.size() << " status " << result.status << " beta "
1149 << result.beta << " chi2/ndof " << chi2ndof);
1150 if (result.status != 0) maximumData.betaSeeds.emplace_back(result.beta, 1.);
1151 }
1152
1154 std::vector<std::shared_ptr<const Muon::MuonSegment>>& segments,
1155 const ToolHandle<Muon::IMuonPRDSelectionTool>& muonPRDSelectionTool,
1156 const ToolHandle<Muon::IMuonSegmentMaker>& segmentMaker,
1157 float beta) const {
1158 const MuonHough::MuonLayerHough::Maximum& maximum = *maximumData.maximum;
1159 const std::vector<std::shared_ptr<const Muon::MuonClusterOnTrack>>& phiClusterOnTracks = maximumData.phiClusterOnTracks;
1160
1161 // lambda to handle calibration and selection of MDTs
1162 auto handleMdt = [intersection, muonPRDSelectionTool](const Muon::MdtPrepData& prd,
1163 std::vector<const Muon::MdtDriftCircleOnTrack*>& mdts,
1164 float beta) {
1165 const Muon::MdtDriftCircleOnTrack* mdt = muonPRDSelectionTool->calibrateAndSelect(intersection, prd, beta);
1166 if (mdt) mdts.push_back(mdt);
1167 };
1168
1169 // lambda to handle calibration and selection of clusters
1170 auto handleCluster = [intersection, muonPRDSelectionTool](const Muon::MuonCluster& prd,
1171 std::vector<const Muon::MuonClusterOnTrack*>& clusters) {
1172 const Muon::MuonClusterOnTrack* cluster = muonPRDSelectionTool->calibrateAndSelect(intersection, prd);
1173 if (cluster) clusters.push_back(cluster);
1174 };
1175
1176 // loop over hits in maximum and add them to the hit list
1177 std::vector<const Muon::MdtDriftCircleOnTrack*> mdts;
1178 std::vector<const Muon::MuonClusterOnTrack*> clusters;
1179
1180 // insert phi hits, clone them
1181 clusters.reserve(phiClusterOnTracks.size());
1182
1183 for (const auto& phiClusterOnTrack : phiClusterOnTracks) { clusters.push_back(phiClusterOnTrack->clone()); }
1184
1185 ATH_MSG_DEBUG("About to loop over Hough::Hits");
1186
1187 MuonHough::HitVec::const_iterator hit = maximum.hits.begin();
1188 MuonHough::HitVec::const_iterator hit_end = maximum.hits.end();
1189 for (; hit != hit_end; ++hit) {
1190 ATH_MSG_DEBUG("hit x,y_min,y_max,w = " << (*hit)->x << "," << (*hit)->ymin << "," << (*hit)->ymax << "," << (*hit)->w);
1191 // treat the case that the hit is a composite TGC hit
1192 if ((*hit)->tgc) {
1193 for (const auto& prd : (*hit)->tgc->etaCluster) handleCluster(*prd, clusters);
1194 } else if ((*hit)->prd) {
1195 Identifier id = (*hit)->prd->identify();
1196 if (m_idHelperSvc->isMdt(id))
1197 handleMdt(static_cast<const Muon::MdtPrepData&>(*(*hit)->prd), mdts, beta);
1198 else
1199 handleCluster(static_cast<const Muon::MuonCluster&>(*(*hit)->prd), clusters);
1200 }
1201 }
1202
1203 ATH_MSG_DEBUG("About to loop over calibrated hits");
1204
1205 ATH_MSG_DEBUG("Dumping MDTs");
1206 for (const auto* it : mdts) ATH_MSG_DEBUG(*it);
1207
1208 ATH_MSG_DEBUG("Dumping clusters");
1209 for (const auto* it : clusters) ATH_MSG_DEBUG(*it);
1210
1211 // require at least 2 MDT hits
1212 if (mdts.size() > 2) {
1213 // run segment finder
1214 auto segColl = std::make_unique<Trk::SegmentCollection>(SG::VIEW_ELEMENTS);
1215 segmentMaker->find(intersection.trackParameters->position(), intersection.trackParameters->momentum(), mdts, clusters,
1216 !clusters.empty(), segColl.get(), intersection.trackParameters->momentum().mag(), 0, beta);
1217 if (segColl) {
1218 Trk::SegmentCollection::iterator sit = segColl->begin();
1219 Trk::SegmentCollection::iterator sit_end = segColl->end();
1220 for (; sit != sit_end; ++sit) {
1221 Trk::Segment* tseg = *sit;
1222 Muon::MuonSegment* mseg = static_cast<Muon::MuonSegment*>(tseg);
1223 assert(dynamic_cast<Muon::MuonSegment*>(tseg) != nullptr);
1224 ATH_MSG_DEBUG("Segment: " << m_printer->print(*mseg));
1225 segments.push_back(std::shared_ptr<const Muon::MuonSegment>(mseg));
1226 }
1227 }
1228 }
1229 // clean-up memory
1230 for (const auto* hit : mdts) delete hit;
1231 for (const auto* hit : clusters) delete hit;
1232 }
1233
1235 MaximumData& maximumData) const {
1236 // extract trigger hits per chamber
1237 const MuonHough::MuonLayerHough::Maximum& maximum = *maximumData.maximum;
1238 std::map<Identifier, std::vector<const Muon::RpcPrepData*>> rpcPrdsPerChamber;
1239
1240 // lambda to add the PRD
1241 auto addRpc = [&rpcPrdsPerChamber, this](const Trk::PrepRawData* prd) {
1242 const Muon::RpcPrepData* rpcPrd = dynamic_cast<const Muon::RpcPrepData*>(prd);
1243 if (rpcPrd) {
1244 Identifier chamberId = m_idHelperSvc->chamberId(rpcPrd->identify());
1245 rpcPrdsPerChamber[chamberId].push_back(rpcPrd);
1246 }
1247 };
1248
1249 // extract eta hits
1250 MuonHough::HitVec::const_iterator hit = maximum.hits.begin();
1251 MuonHough::HitVec::const_iterator hit_end = maximum.hits.end();
1252 for (; hit != hit_end; ++hit) {
1253 if ((*hit)->tgc || !(*hit)->prd || !m_idHelperSvc->isRpc((*hit)->prd->identify())) continue;
1254 addRpc((*hit)->prd);
1255 }
1256
1257 // extract phi hits
1258 for (const auto& rot : maximumData.phiClusterOnTracks) { addRpc(rot->prepRawData()); }
1259
1260 // exit if no hits are found
1261 if (rpcPrdsPerChamber.empty()) return;
1262
1263 std::map<Identifier, std::vector<const Muon::RpcPrepData*>>::iterator chit = rpcPrdsPerChamber.begin();
1264 std::map<Identifier, std::vector<const Muon::RpcPrepData*>>::iterator chit_end = rpcPrdsPerChamber.end();
1265 for (; chit != chit_end; ++chit) {
1266 // cluster hits
1267 Muon::RpcHitClusteringObj clustering(&m_idHelperSvc->rpcIdHelper());
1268 if (!clustering.cluster(chit->second)) {
1269 ATH_MSG_WARNING("Clustering failed");
1270 return;
1271 }
1272
1273 ATH_MSG_DEBUG(" " << m_idHelperSvc->toStringChamber(chit->first) << " clustered RPCs: " << chit->second.size()
1274 << " eta clusters " << clustering.clustersEta.size() << " phi clusters " << clustering.clustersPhi.size());
1277 }
1278 }
1279
1281 const std::vector<Muon::RpcClusterObj>& clusterObjects,
1282 MuonStauRecoTool::RpcTimeMeasurementVec& rpcTimeMeasurements) const {
1283 // loop over the clusters
1284 for (const auto& cluster : clusterObjects) {
1285 if (cluster.hitList.empty() || !cluster.hitList.front()) {
1286 ATH_MSG_WARNING("Cluster without hits: " << cluster.hitList.size());
1287 continue;
1288 }
1289 ATH_MSG_DEBUG(" new cluster: " << m_idHelperSvc->toString(cluster.hitList.front()->identify()) << " size "
1290 << cluster.hitList.size());
1291
1292 // create the ROTs
1293 std::vector<const Muon::MuonClusterOnTrack*> clusters;
1294 for (const auto* rpc : cluster.hitList) {
1295 const Muon::MuonClusterOnTrack* rot(m_muonPRDSelectionTool->calibrateAndSelect(intersection, *rpc));
1296 if (rot) {
1297 clusters.push_back(rot);
1298 ATH_MSG_DEBUG(" strip " << m_idHelperSvc->toString(rot->identify()) << " time "
1299 << static_cast<const Muon::RpcClusterOnTrack*>(rot)->time());
1300 }
1301 }
1302 // get the timing result for the cluster
1303 Muon::IMuonHitTimingTool::TimingResult result = m_hitTimingTool->calculateTimingResult(clusters);
1304 if (result.valid) {
1305 // add the result
1306 RpcTimeMeasurement rpcTimeMeasurement;
1307 rpcTimeMeasurement.time = result.time;
1308 rpcTimeMeasurement.error = result.error;
1309 for (const auto* cl : clusters) {
1310 const Muon::RpcClusterOnTrack* rcl = dynamic_cast<const Muon::RpcClusterOnTrack*>(cl);
1311 if (rcl) rpcTimeMeasurement.rpcClusters.push_back(std::shared_ptr<const Muon::RpcClusterOnTrack>(rcl));
1312 }
1313 rpcTimeMeasurements.push_back(rpcTimeMeasurement);
1314 } else {
1315 // if no time measurement was created we need to clean up the memory
1316 for (const auto* cl : clusters) delete cl;
1317 }
1318 }
1319 }
1320
1321 void MuonStauRecoTool::associateHoughMaxima(const EventContext& ctx,
1322 MuonStauRecoTool::LayerData& layerData) const {
1323
1324 if (m_houghDataPerSectorVecKey.empty()) return;
1325 // get intersection and layer identifiers
1327 int sector = intersection.layerSurface.sector;
1328 Muon::MuonStationIndex::DetectorRegionIndex regionIndex = intersection.layerSurface.regionIndex;
1329 Muon::MuonStationIndex::LayerIndex layerIndex = intersection.layerSurface.layerIndex;
1330
1331 // get hough data
1332 SG::ReadHandle houghDataPerSectorVec{m_houghDataPerSectorVecKey,ctx};
1333 if (!houghDataPerSectorVec.isValid()) {
1334 ATH_MSG_ERROR("Hough data per sector vector not found");
1335 return;
1336 }
1337
1338 // sanity check
1339 if (static_cast<int>(houghDataPerSectorVec->vec.size()) <= sector - 1) {
1340 ATH_MSG_WARNING(" sector " << sector
1341 << " larger than the available sectors in the Hough tool: " << houghDataPerSectorVec->vec.size());
1342 return;
1343 }
1344
1345 // get hough maxima in the layer
1346 unsigned int layHash = Muon::MuonStationIndex::sectorLayerHash(regionIndex, layerIndex);
1347 const Muon::MuonLayerHoughTool::HoughDataPerSector& houghDataPerSector = houghDataPerSectorVec->vec[sector - 1];
1348
1349 // sanity check
1350 if (houghDataPerSector.maxVec.size() <= layHash) {
1351 ATH_MSG_WARNING(" houghDataPerSector.maxVec.size() smaller than hash " << houghDataPerSector.maxVec.size() << " hash "
1352 << layHash);
1353 return;
1354 }
1355 const Muon::MuonLayerHoughTool::MaximumVec& maxVec = houghDataPerSector.maxVec[layHash];
1356 if (maxVec.empty()) return;
1357
1358 // get local coordinates in the layer frame
1359 bool barrelLike = intersection.layerSurface.regionIndex == DetectorRegionIndex::Barrel;
1360
1361 // in the endcaps take the r in the sector frame from the local position of the extrapolation
1362 float phi = intersection.trackParameters->position().phi();
1363 float r = barrelLike ? m_muonSectorMapping.transformRToSector(intersection.trackParameters->position().perp(), phi,
1364 intersection.layerSurface.sector, true)
1365 : intersection.trackParameters->parameters()[Trk::locX];
1366
1367 float z = intersection.trackParameters->position().z();
1368 float errx = intersection.trackParameters->covariance() ?
1369 Amg::error(*intersection.trackParameters->covariance(), Trk::locX) : 0.;
1370 float x = barrelLike ? z : r;
1371 float y = barrelLike ? r : z;
1372 float theta = std::atan2(y, x);
1373
1374 // get phi hits
1375 const Muon::MuonLayerHoughTool::PhiMaximumVec& phiMaxVec = houghDataPerSector.phiMaxVec[toInt(regionIndex)];
1376 ATH_MSG_DEBUG(" Got Phi Hough maxima " << phiMaxVec.size() << " phi " << phi);
1377
1378 // lambda to handle calibration and selection of clusters
1379 auto handleCluster = [intersection, this](const Muon::MuonCluster& prd,
1380 std::vector<std::shared_ptr<const Muon::MuonClusterOnTrack>>& clusters) {
1381 std::unique_ptr<const Muon::MuonClusterOnTrack> cluster{m_muonPRDSelectionTool->calibrateAndSelect(intersection, prd)};
1382 if (cluster) clusters.push_back(std::move(cluster));
1383 };
1384
1385 // loop over maxima and associate phi hits with the extrapolation, should optimize this but calculating the residual with the phi
1386 // maximum
1387 std::vector<std::shared_ptr<const Muon::MuonClusterOnTrack>> phiClusterOnTracks;
1388 Muon::MuonLayerHoughTool::PhiMaximumVec::const_iterator pit = phiMaxVec.begin();
1389 Muon::MuonLayerHoughTool::PhiMaximumVec::const_iterator pit_end = phiMaxVec.end();
1390 for (; pit != pit_end; ++pit) {
1391 const MuonHough::MuonPhiLayerHough::Maximum& maximum = **pit;
1392 for (const std::shared_ptr<MuonHough::PhiHit>& hit : maximum.hits) {
1393 // treat the case that the hit is a composite TGC hit
1394 if (hit->tgc) {
1395 Identifier id = hit->tgc->phiCluster.front()->identify();
1396 if (m_idHelperSvc->layerIndex(id) != intersection.layerSurface.layerIndex) continue;
1397 for (const Muon::MuonCluster* prd : hit->tgc->phiCluster) handleCluster(*prd, phiClusterOnTracks);
1398 } else if (hit->prd && !(hit->prd->type(Trk::PrepRawDataType::sTgcPrepData) ||
1399 hit->prd->type(Trk::PrepRawDataType::MMPrepData))) {
1400 const Identifier id = hit->prd->identify();
1401 if (m_idHelperSvc->layerIndex(id) != intersection.layerSurface.layerIndex) continue;
1402 handleCluster(static_cast<const Muon::MuonCluster&>(*hit->prd), phiClusterOnTracks);
1403 }
1404 }
1405 }
1406
1407 ATH_MSG_DEBUG(" associateHoughMaxima: " << printIntersectionToString(intersection) << " maxima " << maxVec.size() << " x,y=(" << x
1408 << "," << y << ") errorx " << errx << " "
1409 << " angle " << theta);
1410
1411 // loop over maxima and associate them to the extrapolation
1412 for (const auto& mit : maxVec) {
1413 const MuonHough::MuonLayerHough::Maximum& maximum = *mit;
1414 if (std::find_if(maximum.hits.begin(),maximum.hits.end(),
1415 [](const std::shared_ptr<MuonHough::Hit>& hit){
1416 return hit->prd && (hit->prd->type(Trk::PrepRawDataType::sTgcPrepData) ||
1417 hit->prd->type(Trk::PrepRawDataType::MMPrepData));
1418 }) != maximum.hits.end()) continue;
1419 float residual = maximum.pos - x;
1420 float residualTheta = maximum.theta - theta;
1421 float refPos = (maximum.hough != nullptr) ? maximum.hough->m_descriptor.referencePosition : 0;
1422 float maxwidth = (maximum.binposmax - maximum.binposmin);
1423
1424 if (maximum.hough){
1425 maxwidth *= maximum.hough->m_binsize;
1426 }
1427 const float pullUncert = std::sqrt(errx * errx + maxwidth * maxwidth / 12.);
1428 float pull = residual / (pullUncert > std::numeric_limits<float>::epsilon() ? pullUncert : 1.) ;
1429
1430 ATH_MSG_DEBUG(" Hough maximum " << maximum.max << " position (" << refPos << "," << maximum.pos << ") residual " << residual
1431 << " pull " << pull << " angle " << maximum.theta << " residual " << residualTheta);
1432
1433 // fill validation content
1434
1435 // select maximum and add it to LayerData
1436 if (std::abs(pull) > 5) continue;
1437 layerData.maximumDataVec.emplace_back(std::make_shared<MaximumData>(intersection, &maximum, phiClusterOnTracks));
1438 }
1439 }
1440 void MuonStauRecoTool::mdtTimeCalibration(const Identifier& /*id*/, float& time, float& error) const {
1441 time -= 1.5;
1442 error *= 1.;
1443 }
1444 void MuonStauRecoTool::rpcTimeCalibration(const Identifier& /*id*/, float& time, float& error) const {
1445 time -= 0;
1446 error *= 0.5;
1447 }
1448 void MuonStauRecoTool::segmentTimeCalibration(const Identifier& /*id*/, float& time, float& error) const {
1449 time -= 1.5;
1450 error *= 1.;
1451 }
1452
1453 float MuonStauRecoTool::calculateTof(const float beta, const float dist) const {
1454 return std::abs(beta) > 0 ? dist * inverseSpeedOfLight / beta : 1.e12;
1455 }
1456
1458 float MuonStauRecoTool::calculateBeta(const float time, const float dist) const {
1459 return time != 0. ? dist * inverseSpeedOfLight / time : 20.;
1460 }
1462 const MuonStauRecoTool::CandidateVec& candidates, int stage) const {
1463 if (Gaudi::Concurrency::ConcurrencyFlags::numThreads() > 1) {
1464 ATH_MSG_WARNING("You are calling the non thread-safe MuonRecoValidationTool with multiple threads, will most likely crash");
1465 }
1466 if (m_recoValidationTool.empty()) return;
1467
1468 ATH_MSG_DEBUG("add candidates to ntuple, stage " << stage);
1469 for (const auto& candidate : candidates) {
1470 int ntimes = 0;
1471 float beta = -1.;
1472 float chi2ndof = -1.;
1473 if (candidate->finalBetaFitResult.status != 0) {
1474 ntimes = candidate->stauHits.size();
1475 beta = candidate->finalBetaFitResult.beta;
1476 chi2ndof = candidate->finalBetaFitResult.chi2PerDOF();
1477 } else if (candidate->betaFitResult.status != 0) {
1478 ntimes = candidate->hits.size();
1479 beta = candidate->betaFitResult.beta;
1480 chi2ndof = candidate->betaFitResult.chi2PerDOF();
1481 } else {
1482 ntimes = 1;
1483 beta = candidate->betaSeed.beta;
1484 chi2ndof = 0;
1485 }
1486 if (candidate->combinedTrack) ATH_MSG_DEBUG("candidate has combined track");
1487 m_recoValidationTool->addMuonCandidate(indetTrackParticle, candidate->muonCandidate.get(), candidate->combinedTrack.get(),
1488 ntimes, beta, chi2ndof, stage);
1489 }
1490 }
1491
1492} // 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< 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
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
LayerIndex
enum to classify the different layers in the muon spectrometer
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