ATLAS Offline Software
Loading...
Searching...
No Matches
FastRecoVisualizationTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
5
8
13
14#include "Acts/Utilities/Helpers.hpp"
15
16#include "TColor.h"
17
18namespace {
19 constexpr int truthColor = kOrange +2;
20 using SpacePointSet = std::unordered_set<const MuonR4::SpacePoint*>;
21
22 double inDegrees(double angle) {
23 return angle / Gaudi::Units::deg;
24 }
25}
26
27
28namespace MuonValR4 {
29 using namespace MuonR4;
30 using namespace SegmentFit;
31
33 if (m_canvasLimit > 0) {
34 m_clientToken.canvasLimit = m_canvasLimit;
35 m_clientToken.preFixName = m_canvasPrefix;
36 m_clientToken.saveSinglePlots = m_saveSinglePDFs;
37 m_clientToken.saveSummaryPlot = m_saveSummaryPDF;
38 m_clientToken.subDirectory = m_subDir;
39 ATH_CHECK(m_visualSvc.retrieve());
40 ATH_CHECK(m_visualSvc->registerClient(m_clientToken));
41 } else {
42 m_plotsDone = true;
43 }
44 ATH_CHECK(m_prepContainerKeys.initialize(!m_truthSegLinks.empty()));
46 ATH_MSG_INFO("Hits linked to the following segment decorations are considered as truth");
47 for (const std::string& decorName : m_truthSegLinks) {
48 ATH_MSG_INFO(" **** "<<decorName);
49 if (decorName.empty()) {
50 ATH_MSG_FATAL("Decoration must not be empty");
51 return StatusCode::FAILURE;
52 }
54 m_truthLinkDecorKeys.emplace_back(key, decorName);
55 m_truthLinkDecors.push_back(SegLinkDecor_t{decorName});
56 }
57 }
58 ATH_CHECK(m_truthLinkDecorKeys.initialize());
59 m_displayOnlyTruth.value() &= !m_truthLinkDecorKeys.empty();
60
61 ATH_CHECK(m_idHelperSvc.retrieve());
62 ATH_CHECK(m_geoCtxKey.initialize());
63 ATH_CHECK(detStore()->retrieve(m_detMgr));
65 ATH_MSG_ERROR("No bucket view enabled. Please enable at least one of the bucket views to visualize the buckets.");
66 return StatusCode::FAILURE;
67 }
69 ATH_MSG_ERROR("Multiple bucket views enabled. Please enable only one bucket view.");
70 return StatusCode::FAILURE;
71 }
72 return StatusCode::SUCCESS;
73 }
79 return std::find_if(m_truthLinkDecors.begin(), m_truthLinkDecors.end(),
80 [&hit](const SegLinkDecor_t& decor){
81 return !decor(hit).empty();
82 }) != m_truthLinkDecors.end();
83 }
84 FastRecoVisualizationTool::LabeledSegmentSet FastRecoVisualizationTool::getLabeledSegments(const std::vector<const MuonR4::SpacePoint*>& hits) const {
85 std::vector<const xAOD::UncalibratedMeasurement*> measurements{};
86 measurements.reserve(2* hits.size());
87 for (const SpacePoint* hit: hits) {
88 measurements.push_back(hit->primaryMeasurement());
89 if(hit->secondaryMeasurement()) {
90 measurements.push_back(hit->secondaryMeasurement());
91 }
92 }
93 return getLabeledSegments(measurements);
94 }
95 FastRecoVisualizationTool::LabeledSegmentSet FastRecoVisualizationTool::getLabeledSegments(const std::vector<const xAOD::UncalibratedMeasurement*>& hits) const {
96 LabeledSegmentSet truthSegs{};
97 for (const xAOD::UncalibratedMeasurement* hit : hits) {
98 for (const SegLinkDecor_t& decor: m_truthLinkDecors) {
99 for (const SegLink_t& link : decor(*hit)) {
100 truthSegs.insert(*link);
101 }
102 }
103 }
104 return truthSegs;
105 }
107 const std::string& extraLabel,
108 PatternHitVisualInfoVec&& patternVisualVec) const {
109 PrimitiveVec primitives{};
110 plotPatternBuckets(ctx, extraLabel, std::move(patternVisualVec), std::move(primitives));
111 }
113 const std::string& extraLabel,
114 PatternHitVisualInfoVec&& patternVisualVec,
115 PrimitiveVec&& primitives) const {
116 if (patternVisualVec.empty()) {
117 ATH_MSG_VERBOSE("No pattern visual info available. Do not create visualization.");
118 return;
119 }
121 unsigned sPatIdx{0u}, fPatIdx{0u}, oPatIdx{0u};
122 for (PatternHitVisualInfo& patVisual : patternVisualVec) {
123 PrimitiveVec primitivesCopy {clone(primitives)};
124 std::string label {};
125 switch(patVisual.status) {
126 case PatternHitVisualInfo::PatternStatus::eSuccessful:
127 label = std::format("s{}_{}", sPatIdx++, extraLabel);
128 break;
129 case PatternHitVisualInfo::PatternStatus::eFailed:
130 label = std::format("f{}_{}", fPatIdx++, extraLabel);
131 break;
132 case PatternHitVisualInfo::PatternStatus::eOverlap:
133 label = std::format("o{}_{}", oPatIdx++, extraLabel);
134 break;
135 }
136 plotPatternBuckets(ctx, label, std::move(patVisual), std::move(primitivesCopy));
137 }
138 }
140 const std::string& extraLabel,
141 PatternHitVisualInfo&& patternVisual) const {
142 PrimitiveVec primitives{};
143 plotPatternBuckets(ctx, extraLabel, std::move(patternVisual), std::move(primitives));
144 }
145
147 const std::string& extraLabel,
148 PatternHitVisualInfo&& patternVisual,
149 PrimitiveVec&& extraPaints) const {
150 for (const MuonR4::SpacePointBucket* bucket : patternVisual.parentBuckets) {
151 PatternHitVisualInfo patternVisualCopy {patternVisual};
152 PrimitiveVec extraPaintsCopy {clone(extraPaints)};
153 plotPatternBucket(ctx, extraLabel, *bucket, std::move(patternVisualCopy), std::move(extraPaintsCopy));
154 }
155 }
157 const std::string& extraLabel,
158 const MuonR4::SpacePointBucket& bucket,
159 PatternHitVisualInfo&& patternVisual,
160 PrimitiveVec&& extraPaints) const {
161 using PatternStatus = FastRecoVisualizationTool::PatternHitVisualInfo::PatternStatus;
162 using HitStatus = FastRecoVisualizationTool::PatternHitVisualInfo::HitStatus;
164 if (m_plotsDone) {
165 return;
166 }
168 LabeledSegmentSet truthSegs{getLabeledSegments(Acts::unpackConstSmartPointers(bucket))};
169 if (truthSegs.empty() && m_displayOnlyTruth) {
170 return;
171 }
173 PatternStatus patStatus{patternVisual.status};
174 if ((patStatus == PatternStatus::eSuccessful && !m_paintSuccessfullPatterns) ||
175 (patStatus == PatternStatus::eFailed && !m_paintFailedPatterns) ||
176 (patStatus == PatternStatus::eOverlap && !m_paintOverlapPatterns)) {
177 return;
178 }
180 std::vector<const MuonR4::SpacePoint*> patHitsInBucket{};
181 const MuonR4::GlobalPattern& pat {*patternVisual.patternCopy};
182 for (const Muon::MuonStationIndex::StIndex& station : pat.getStations()) {
183 for (const MuonR4::SpacePoint* hit : pat.hitsInStation(station)) {
184 if (std::ranges::find_if(bucket,
185 [hit](const std::shared_ptr<MuonR4::SpacePoint> sp) { return sp.get() == hit; }) != bucket.end()) {
186 patHitsInBucket.push_back(hit);
187 }
188 }
189 }
190 if (patHitsInBucket.empty() && m_displayOnlyWithPattern) {
191 return;
192 }
194 std::string nameTag = std::format("{}_{}_Bkt_{:d}", extraLabel, bucket.msSector()->identString(), bucket.bucketId());
195 auto canvas = m_visualSvc->prepareCanvas(ctx, m_clientToken, nameTag);
196 if (!canvas){
197 m_plotsDone = true;
198 return;
199 }
200 canvas->add(std::move(extraPaints));
201 const ActsTrk::GeometryContext* geoCtx{nullptr};
202 if (!SG::get(geoCtx, m_geoCtxKey, ctx).isSuccess()) {
203 throw std::runtime_error("Failed to retrieve GeometryContext from EventStore");
204 return;
205 }
208 const Amg::Transform3D& localToGlobalBucket{bucket.msSector()->localToGlobalTransform(*geoCtx)};
210 if (view == View::objViewZR && !bucket.msSector()->barrel()) {
211 view = View::objViewRZ;
212 }
213 switch (view) {
214 case View::objViewEta:
215 canvas->setAxisTitles("y [mm]", "z [mm]");
216 break;
217 case View::objViewPhi:
218 canvas->setAxisTitles("x [mm]", "z [mm]");
219 break;
220 case View::objViewZR:
221 canvas->setAxisTitles("z [mm]", "R [mm]");
222 break;
223 case View::objViewRZ:
224 canvas->setAxisTitles("R [mm]", "z [mm]");
225 break;
226 }
228 if (!drawHits(bucket, localToGlobalBucket, patHitsInBucket, *canvas, view)) {
229 return;
230 }
231
232 PrimitiveVec lines{};
233
235 drawSearchWindow(localToGlobalBucket, lines, patternVisual.thetaSearchMin, patternVisual.thetaSearchMax, *canvas, view);
236
238 for (const auto& sp : bucket) {
239 const MuonR4::SpacePoint* testHit {sp.get()};
241 if (patternVisual.hitLineInfo.find(testHit) == patternVisual.hitLineInfo.end()) {
242 continue;
243 }
245 const HitStatus hitStatus {std::ranges::find(patternVisual.discardedHits, testHit) != patternVisual.discardedHits.end() ? HitStatus::eDiscarded :
246 (std::ranges::find(patternVisual.replacedHits, testHit) != patternVisual.replacedHits.end() ? HitStatus::eReplaced : HitStatus::eKept)};
247
249 const auto& [lineSlope, deltaRWindow] = patternVisual.hitLineInfo.at(testHit);
250 drawLineResidual(*geoCtx, localToGlobalBucket, lines, patternVisual.seed, testHit, lineSlope, deltaRWindow, hitStatus, *canvas, view);
251 }
252
254 double yLegend{0.9};
255 auto printOnCanvas = [&lines, &yLegend](const std::string& text){
256 lines.push_back(drawLabel(text, 0.2, yLegend, 13));
257 yLegend-=0.03;
258 };
259
260 printOnCanvas(std::format("Seed hit: {}", m_idHelperSvc->toString(patternVisual.seed->identify())));
261 printOnCanvas(std::format("Chamber: {}", m_idHelperSvc->toStringChamber(bucket.front()->identify())));
262 printOnCanvas(std::format("nPrec: {:d}", pat.nPrecisionHits()));
263 printOnCanvas(std::format("nEtaNonPrec: {:d}", pat.nEtaNonPrecisionHits()));
264 printOnCanvas(std::format("nPhi: {:d}", pat.nPhiHits()));
265 printOnCanvas(std::format("theta: {:.2f}^{{#circ}}", inDegrees(pat.theta())));
266 printOnCanvas(std::format("phi: {:.2f}^{{#circ}}", inDegrees(pat.phi())));
267 printOnCanvas(std::format("MeanNormResidual: {:.2f}", pat.meanNormResidual2()));
268 printOnCanvas(std::format("Status: {}", patStatus == PatternStatus::eSuccessful ? "Success" : (patStatus == PatternStatus::eFailed ? "Fail" : "Overlap")));
269 printOnCanvas(std::format("Sector: {:d}", pat.sector()));
270 printOnCanvas(std::format("OverlapSector: {:d}", pat.isSectorOverlap() ? pat.secondarySector() : -1));
271
273 bool drawnTrueLabel{true};
274 for (const xAOD::MuonSegment* segment : truthSegs) {
275 drawSegment(*segment, localToGlobalBucket, lines, drawnTrueLabel, *canvas, view);
276 paintSimHits(*geoCtx, localToGlobalBucket, *segment, lines, view);
277 }
278 canvas->add(std::move(lines));
279
280 std::string legendLabel = std::format("Event: {:}, chamber : {:}, #{:}-view ({:})",
281 ctx.eventID().event_number(),
282 bucket.msSector()->identString(),
283 view ==View::objViewEta ? "eta" : (view ==View::objViewPhi ? "phi" : (view == View::objViewZR ? "ZR" : "RZ")),
284 nameTag);
285 canvas->add(drawLabel(legendLabel, 0.15, 0.96));
286 }
288 PrimitiveVec& outputContainer,
289 const double thetaMin,
290 const double thetaMax,
291 const Canvas_t& canvas,
292 const View view) const {
294 if (view == View::objViewPhi) {
295 return;
296 }
297 auto addSearchWindowLine = [&outputContainer, &localToGlobalBucket, &view, &canvas, this](const double globLineTheta){
298 constexpr double smallAngle {1e-3};
299 if (std::abs(globLineTheta) < smallAngle || std::abs(globLineTheta - M_PI) < smallAngle) {
301 throw std::runtime_error("Unexpected horizontal pattern search line in global frame. Cannot draw search window.");
302 return;
303 }
304 Amg::Vector3D lineDirection{};
305 Amg::Vector3D linePosition{};
306 double lowEnd{};
307 double upEnd{};
308 if (view == View::objViewZR || view == View::objViewRZ) {
310 lineDirection = Acts::makeDirectionFromAxisTangents(0., tan(globLineTheta));
311 linePosition = Amg::Vector3D::Zero();
312 lowEnd = view == View::objViewZR ? canvas.corner(Edges::yLow) : canvas.corner(Edges::xLow);
313 upEnd = view == View::objViewZR ? canvas.corner(Edges::yHigh) : canvas.corner(Edges::xHigh);
314 } else {
316 const double globLinePhi {localToGlobalBucket.translation().phi()};
317 const Amg::Vector3D globLineDir {Acts::makeDirectionFromPhiTheta(globLinePhi,globLineTheta)};
318 lineDirection = localToGlobalBucket.inverse().linear() * globLineDir;
319 linePosition = localToGlobalBucket.inverse() * Amg::Vector3D::Zero();
320 lowEnd = canvas.corner(Edges::yLow);
321 upEnd = canvas.corner(Edges::yHigh);
322 }
323 outputContainer.emplace_back(drawLine(lineDirection, linePosition,
324 lowEnd, upEnd, kOrange, kDashed, view));
325 };
326 addSearchWindowLine(thetaMin);
327 addSearchWindowLine(thetaMax);
328 }
330 const Amg::Transform3D& localToGlobalBucket,
331 PrimitiveVec& outputContainer,
332 const MuonR4::SpacePoint* seed,
333 const MuonR4::SpacePoint* testHit,
334 const double lineSlope,
335 const double Rwindow,
336 const PatternHitVisualInfo::HitStatus status,
337 const Canvas_t& canvas,
338 const View view) const {
339 using HitStatus = PatternHitVisualInfo::HitStatus;
341 if (view == View::objViewPhi) {
342 return;
343 }
344 if (std::abs(lineSlope) < std::numeric_limits<double>::epsilon()) {
346 return;
347 }
348 auto color {status == HitStatus::eKept ? kGreen : (status == HitStatus::eReplaced ? kPink : kGray)};
349 if (view == View::objViewZR || view == View::objViewRZ) {
351 const Amg::Vector3D lineDir {Acts::makeDirectionFromAxisTangents(0., lineSlope)};
352 const Amg::Vector3D seedGlobalPos {seed->msSector()->localToGlobalTransform(gctx) * seed->localPosition()};
353 const Amg::Vector3D linePos {seedGlobalPos.perp()* Amg::Vector3D::UnitY() + seedGlobalPos.z() * Amg::Vector3D::UnitZ()};
355 const double seedGlobalR {seedGlobalPos.perp()};
356 const double testGlobalR {(localToGlobalBucket * testHit->localPosition()).perp()};
357 const double testGlobalZ {(localToGlobalBucket * testHit->localPosition()).z()};
358 const double lineIntercept {linePos.y() - lineSlope * linePos.z()};
359 const double line2WindowInters {lineSlope*testGlobalZ + lineIntercept};
360 double lowLimit{};
361 double upLimit{};
362 if (seedGlobalR < testGlobalR) {
363 lowLimit = (seed->msSector() == testHit->msSector() ?
364 seedGlobalR : (view == View::objViewZR ? canvas.corner(Edges::yLow) : canvas.corner(Edges::xLow)));
365 upLimit = line2WindowInters;
366 } else {
367 upLimit = (seed->msSector() == testHit->msSector() ?
368 seedGlobalR : (view == View::objViewZR ? canvas.corner(Edges::yHigh) : canvas.corner(Edges::xHigh)));
369 lowLimit = line2WindowInters;
370 }
371 outputContainer.emplace_back(drawLine(lineDir, linePos,
372 lowLimit, upLimit, color, kDashed, view));
373
375 const Amg::Vector3D barLineDir {Amg::Vector3D::UnitY()};
376 const Amg::Vector3D barLinePos {testGlobalZ* Amg::Vector3D::UnitZ()};
377 lowLimit = testGlobalR - Rwindow;
378 upLimit = testGlobalR + Rwindow;
379 outputContainer.emplace_back(drawLine(barLineDir, barLinePos,
380 lowLimit, upLimit, color, kDotted, view));
381 } else {
383 const double globLineTheta { lineSlope > 0 ? atan(lineSlope) : atan(lineSlope) + M_PI };
384 const double globLinePhi {localToGlobalBucket.translation().phi()};
385 const Amg::Vector3D globLineDir {Acts::makeDirectionFromPhiTheta(globLinePhi,globLineTheta)};
386 const Amg::Vector3D locLineDir {localToGlobalBucket.inverse().linear() * globLineDir};
388 const Amg::Vector3D seedGlobalPos {seed->msSector()->localToGlobalTransform(gctx) * seed->localPosition()};
389 const Amg::Vector3D seedLocalPos {localToGlobalBucket.inverse() * seedGlobalPos};
391 const double& testLocalZ {testHit->localPosition().z()};
392 const double& testLocalY {testHit->localPosition().y()};
393 const double testGlobalR {(localToGlobalBucket * testHit->localPosition()).perp()};
394 double seedGlobalR {seedGlobalPos.perp()};
395 const bool isBarrel {seed->msSector()->barrel()};
396 const double line2WindowInters {isBarrel ? Acts::detail::LineHelper::lineIntersect<3>(seedLocalPos, locLineDir, testLocalY* Amg::Vector3D::UnitY(), Amg::Vector3D::UnitZ()).position().z()
397 : Acts::detail::LineHelper::lineIntersect<3>(seedLocalPos, locLineDir, testLocalZ* Amg::Vector3D::UnitZ(), Amg::Vector3D::UnitY()).position().z()};
398 double lowLimit{};
399 double upLimit{};
400 if (seedGlobalR < testGlobalR) {
401 lowLimit = (seed->msSector() == testHit->msSector() ? seedLocalPos.z() : canvas.corner(Edges::yLow));
402 upLimit = line2WindowInters;
403 } else {
404 upLimit = (seed->msSector() == testHit->msSector() ? seedLocalPos.z() : canvas.corner(Edges::yHigh));
405 lowLimit = line2WindowInters;
406 }
407 outputContainer.emplace_back(drawLine(locLineDir, seedLocalPos,
408 lowLimit, upLimit, color, kDashed, view));
409
411 const Amg::Vector3D barLineDir {isBarrel ? Amg::Vector3D::UnitZ() : Amg::Vector3D::UnitY()};
412 const Amg::Vector3D barLinePos {isBarrel ? testLocalY* Amg::Vector3D::UnitY() : testLocalZ* Amg::Vector3D::UnitZ()};
413 lowLimit = isBarrel ? testLocalZ - Rwindow : testLocalY - Rwindow;
414 upLimit = isBarrel ? testLocalZ + Rwindow : testLocalY + Rwindow;
415 outputContainer.emplace_back(drawLine(barLineDir, barLinePos,
416 lowLimit, upLimit, color, kDotted, view));
417 }
418 }
420 const Amg::Transform3D& localToGlobalBucket,
421 PrimitiveVec& outputContainer,
422 bool& drawnTrueLabel,
423 const Canvas_t& canvas,
424 const View view) const {
426 return;
427 }
428 auto [linePos, lineDir] = makeLine(localSegmentPars(segment));
429 double lowEnd{canvas.corner(Edges::yLow)};
430 double highEnd{canvas.corner(Edges::yHigh)};
431 if (view == View::objViewZR || view == View::objViewRZ){
433 const Amg::Vector3D globDir {localToGlobalBucket.linear() * lineDir};
434 const Amg::Vector3D globPos {localToGlobalBucket * linePos};
436 const double slopeRZ {(globPos.x()*globDir.x() + globPos.y()*globDir.y()) / (globPos.perp()*globDir.z())};
437 lineDir = Acts::makeDirectionFromAxisTangents(0., slopeRZ);
438 linePos = globPos.perp()* Amg::Vector3D::UnitY() + globPos.z() * Amg::Vector3D::UnitZ();
439 if (view == View::objViewRZ) {
440 lowEnd = canvas.corner(Edges::xLow);
441 highEnd = canvas.corner(Edges::xHigh);
442 }
443 }
444 outputContainer.emplace_back(drawLine(lineDir, linePos, lowEnd, highEnd,
445 truthColor, kDotted, view));
446 if (!drawnTrueLabel) {
447 outputContainer.emplace_back(drawLabel(std::format("true parameters: {:}",makeLabel(localSegmentPars(segment))),0.2, 0.89));
448 drawnTrueLabel = true;
449 }
450 }
452 const Amg::Transform3D& localToGlobalBucket,
453 const xAOD::MuonSegment& truthSeg,
454 PrimitiveVec& outputContainer,
455 const View view) const {
456 if (!m_paintTruthHits) {
457 return;
458 }
459 auto truthHits = getMatchingSimHits(truthSeg);
460 for (const xAOD::MuonSimHit* simHit : truthHits) {
461 const MuonGMR4::MuonReadoutElement* re = m_detMgr->getReadoutElement(simHit->identify());
462 const IdentifierHash hash = re->detectorType() == ActsTrk::DetectorType::Mdt ?
463 re->measurementHash(simHit->identify()) :
464 re->layerHash(simHit->identify());
465 const Amg::Transform3D trf = re->msSector()->globalToLocalTransform(gctx) *
466 re->localToGlobalTransform(gctx, hash);
467 const Amg::Vector3D locPos = trf * xAOD::toEigen(simHit->localPosition());
468 const Amg::Vector3D locDir = trf.linear() * xAOD::toEigen(simHit->localDirection());
469 if (view == View::objViewEta || view == View::objViewPhi){
470 outputContainer.emplace_back(drawArrow(locPos, locDir, truthColor, kDashed, static_cast<int>(view)));
471 } else {
472 constexpr double arrowLength = 2.*Gaudi::Units::cm;
474 const Amg::Vector3D globDir {localToGlobalBucket.linear() * locDir};
475 const Amg::Vector3D globPos {localToGlobalBucket * locPos};
476 const Amg::Vector3D end = globPos + (arrowLength / std::hypot(globDir.z(),globDir.perp()) ) * globDir;
477 auto arrow = view == View::objViewZR ? std::make_unique<TArrow>(globPos.z(), globPos.perp(), end.z(), end.perp(),0.01) :
478 std::make_unique<TArrow>(globPos.perp(), globPos.z(), end.perp(), end.z(),0.01);
479 arrow->SetLineColor(truthColor);
480 arrow->SetLineWidth(2);
481 arrow->SetLineStyle(kDashed);
482 outputContainer.emplace_back(std::move(arrow));
483 }
484 }
485 }
486 template<class SpacePointType>
487 const SpacePoint*
488 FastRecoVisualizationTool::drawHit(const SpacePointType& hit,
489 const Amg::Transform3D& localToGlobalBucket,
490 Canvas_t& canvas,
491 const View view,
492 unsigned int fillStyle) const {
493
495 const bool isEtaView {view == View::objViewEta || view == View::objViewRZ || view == View::objViewZR};
496 if ((isEtaView && !hit.measuresEta()) || (view == View::objViewPhi && !hit.measuresPhi())) {
497 return nullptr;
498 }
499 const Amg::Vector3D& localPos {hit.localPosition()};
500 const Amg::Vector3D globalPos {localToGlobalBucket * localPos};
501 const auto expand = [&canvas, &hit]( double centerX, double centerY) {
502 canvas.expandPad(centerX- hit.driftRadius(), centerY - hit.driftRadius());
503 canvas.expandPad(centerX+ hit.driftRadius(), centerY + hit.driftRadius());
504 };
505 if (hit.type() != xAOD::UncalibMeasType::Other) {
506 if (view == View::objViewEta || view == View::objViewPhi) {
507 expand(localPos[static_cast<int>(view)], localPos.z());
508 } else if (view == View::objViewZR) {
509 expand(globalPos.z(), globalPos.perp());
510 } else if (view == View::objViewRZ) {
511 expand(globalPos.perp(), globalPos.z());
512 }
513 }
514 const SpacePoint* underlyingSp{nullptr};
516 constexpr int invalidCalibFill = 3305;
517 if constexpr (std::is_same_v<SpacePointType, SpacePoint>) {
518 underlyingSp = &hit;
520 const auto* dc = static_cast<const xAOD::MdtDriftCircle*>(hit.primaryMeasurement());
521 if (dc->status() != Muon::MdtDriftCircleStatus::MdtStatusDriftTime) {
522 fillStyle = invalidCalibFill;
523 }
524 }
525 } else if constexpr(std::is_same_v<SpacePointType, CalibratedSpacePoint>) {
526 underlyingSp = hit.spacePoint();
527 if (hit.fitState() == CalibratedSpacePoint::State::Valid) {
528 fillStyle = fullFilling;
529 } else if (hit.fitState() == CalibratedSpacePoint::State::FailedCalib) {
530 fillStyle = invalidCalibFill;
531 } else {
532 fillStyle = hatchedFilling;
533 }
534 }
535 const Amg::Vector3D posInCanvas = [view, localPos, globalPos]() -> Amg::Vector3D{
536 switch (view) {
537 case View::objViewEta:
538 case View::objViewPhi:
539 return localPos;
540 case View::objViewZR:
541 return globalPos.z()* Amg::Vector3D::UnitY() + globalPos.perp() * Amg::Vector3D::UnitZ();
542 case View::objViewRZ:
543 return globalPos.z()* Amg::Vector3D::UnitZ() + globalPos.perp() * Amg::Vector3D::UnitY();
544 }
545 return Amg::Vector3D::Zero();
546 }();
547 const int covIdx {view == View::objViewPhi ? static_cast<int>(View::objViewPhi) : static_cast<int>(View::objViewEta)};
548 switch(hit.type()) {
550 const auto* dc = static_cast<const xAOD::MdtDriftCircle*>(underlyingSp->primaryMeasurement());
551 canvas.add(drawDriftCircle(posInCanvas, dc->readoutElement()->innerTubeRadius(),
552 kBlack, hollowFilling));
553
554 const int circColor = isLabeled(*dc) ? truthColor : kBlue;
555 canvas.add(drawDriftCircle(posInCanvas, hit.driftRadius(), circColor, fillStyle));
556 break;
558 const auto* meas{static_cast<const xAOD::RpcMeasurement*>(underlyingSp->primaryMeasurement())};
559 const int boxColor = isLabeled(*meas) ? truthColor : kGreen +2;
560 const double boxWidth = 0.5*std::sqrt(12)*std::sqrt(underlyingSp->covariance()[covIdx]);
561 canvas.add(drawBox(posInCanvas, boxWidth, 0.5*meas->readoutElement()->gasGapPitch(),
562 boxColor, fillStyle, covIdx));
563 break;
565 const auto* meas{static_cast<const xAOD::TgcStrip*>(underlyingSp->primaryMeasurement())};
566 const int boxColor = isLabeled(*meas) ? truthColor : kCyan + 2;
567 const double boxWidth = 0.5*std::sqrt(12)*std::sqrt(underlyingSp->covariance()[covIdx]);
568 canvas.add(drawBox(posInCanvas, boxWidth, 0.5*meas->readoutElement()->gasGapPitch(),
569 boxColor, fillStyle, covIdx));
570 break;
572 const int boxColor = isLabeled(*underlyingSp->primaryMeasurement()) ? truthColor : kAquamarine;
573 const double boxWidth = 5*Gaudi::Units::mm;
574 canvas.add(drawBox(posInCanvas, boxWidth, 10.*Gaudi::Units::mm, boxColor, fillStyle, covIdx));
575 break;
577 break;
579 const int boxColor = isLabeled(*underlyingSp->primaryMeasurement()) ? truthColor : kTeal;
580 const double boxWidth = 5*Gaudi::Units::mm;
581 canvas.add(drawBox(posInCanvas, boxWidth, 10.*Gaudi::Units::mm, boxColor, fillStyle, covIdx));
582 break;
583 } default: {
584 ATH_MSG_WARNING("Please implement proper drawings of the new small wheel.. "<<__FILE__<<":"<<__LINE__);
585 break;
586 }
587 }
588 return underlyingSp;
589 }
590
591 template<class SpacePointType>
593 const Amg::Transform3D& localToGlobalBucket,
594 const std::vector<SpacePointType>& hitsToDraw,
595 Canvas_t& canvas,
596 const View view) const {
597
598 SpacePointSet drawnPoints{};
599 for (const SpacePointType& hit : hitsToDraw) {
600 drawnPoints.insert(drawHit(*hit, localToGlobalBucket, canvas, view, fullFilling));
601 }
602 for (const SpacePointBucket::value_type& hit : bucket) {
603 // Don't redraw the other points
604 if (drawnPoints.count(hit.get())) {
605 continue;
606 }
607 drawHit(*hit, localToGlobalBucket, canvas, view, hollowFilling);
608 }
609 return drawnPoints.size() - drawnPoints.count(nullptr) > 1;
610 }
611 std::unique_ptr<TLine> FastRecoVisualizationTool::drawLine(const Amg::Vector3D& lineDirection,
612 const Amg::Vector3D& linePoint,
613 const double lowEnd,
614 const double highEnd,
615 const int color,
616 const int lineStyle,
617 const View view) const {
619 using ParamDefs = MuonR4::SpacePoint::SeedingAux::FitParIndex;
620 auto makeLine = [](const double x1, const double y1, const double x2, const double y2, const int color, const int style){
621 auto line = std::make_unique<TLine>(x1, y1, x2, y2);
622 line->SetLineColor(color);
623 line->SetLineWidth(2);
624 line->SetLineStyle(style);
625 return line;
626 };
627
628 if (view == View::objViewEta || view == View::objViewPhi){
630 if (std::abs(lineDirection.z()) < std::numeric_limits<double>::epsilon()) {
632 return makeLine(lowEnd, linePoint.z(), highEnd, linePoint.z(), color, lineStyle);
633 } else {
634 return MuonValR4::drawLine(linePoint + Amg::intersect<3>(linePoint,lineDirection,Amg::Vector3D::UnitZ(), lowEnd).value_or(0.)* lineDirection,
635 linePoint + Amg::intersect<3>(linePoint,lineDirection,Amg::Vector3D::UnitZ(), highEnd).value_or(0.)* lineDirection,
636 color, lineStyle, static_cast<int>(view));
637 }
638 } else {
640 if (std::abs(lineDirection.y()) < std::numeric_limits<double>::epsilon()) {
642 if (view == View::objViewZR) {
644 return makeLine(lowEnd, linePoint.y(), highEnd, linePoint.y(), color, lineStyle);
645 } else {
647 return makeLine(linePoint.y(), lowEnd, linePoint.y(), highEnd, color, lineStyle);
648 }
649 } else if (std::abs(lineDirection.z()) < std::numeric_limits<double>::epsilon()) {
651 if (view == View::objViewZR) {
653 return makeLine(linePoint.z(), lowEnd, linePoint.z(), highEnd, color, lineStyle);
654 } else {
656 return makeLine(lowEnd, linePoint.z(), highEnd, linePoint.z(), color, lineStyle);
657 }
658 } else {
659 const double slope {lineDirection.y() / lineDirection.z()};
660 const double intercept {linePoint.y() - slope * linePoint.z()};
661 const double Zlow {(lowEnd - intercept) / slope};
662 const double Zhigh {(highEnd - intercept) / slope};
663 if (view == View::objViewZR) {
665 return makeLine(Zlow, lowEnd, Zhigh, highEnd, color, lineStyle);
666 } else {
668 return makeLine(lowEnd, Zlow, highEnd, Zhigh, color, lineStyle);
669 }
670 }
671 }
672 }
673}
const boost::regex re(r_e)
#define M_PI
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
static Double_t sp
double angle(const GeoTrf::Vector2D &a, const GeoTrf::Vector2D &b)
This is a "hash" representation of an Identifier.
MuonReadoutElement is an abstract class representing the geometry of a muon detector.
bool barrel() const
Returns whether the sector is placed in the barrel.
const Amg::Transform3D & localToGlobalTransform(const ActsTrk::GeometryContext &gctx) const
Returns the local -> global tarnsformation from the sector.
std::string identString() const
Returns a string encoding the chamber index & the sector of the MS sector.
Data class to represent an eta maximum in hough space.
: The muon space point bucket represents a collection of points that will bre processed together in t...
const MuonGMR4::SpectrometerSector * msSector() const
returns th associated muonChamber
unsigned int bucketId() const
Returns the Identifier in the context of the MuonChamber.
The muon space point is the combination of two uncalibrated measurements one of them measures the eta...
const Cov_t & covariance() const
Returns the covariance array.
Gaudi::Property< std::set< std::string > > m_truthSegLinks
List of truth segment links to fetch.
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
Service Handle to the IMuonIdHelperSvc.
virtual StatusCode initialize() override final
std::unique_ptr< TLine > drawLine(const Amg::Vector3D &lineDirection, const Amg::Vector3D &linePoint, const double lowEnd, const double highEnd, const int color=kRed+1, const int lineStyle=kDashed, const View view=View::objViewEta) const
Draws a line given the parameters of the line in the local frame for Eta and Phi views and in the R-Z...
IRootVisualizationService::ClientToken m_clientToken
Token to present to the visualization service such that the display froms this tool are grouped toget...
BooleanProperty m_paintSuccessfullPatterns
Switch to visualize successfull patterns.
BooleanProperty m_paintOverlapPatterns
Switch to visualize overlap patterns.
const MuonR4::SpacePoint * drawHit(const SpacePointType &hit, const Amg::Transform3D &localToGlobalBucket, Canvas_t &canvas, const View view, unsigned int fillStyle) const
Converts a Hit into a particular TBox/ TEllipse for drawing.
SG::ReadDecorHandleKeyArray< xAOD::UncalibratedMeasurementContainer > m_truthLinkDecorKeys
Declaration of the dependency on the decorations.
virtual bool isLabeled(const MuonR4::SpacePoint &hit) const override final
Fetches all labeled (e.g.
void paintSimHits(const ActsTrk::GeometryContext &gctx, const Amg::Transform3D &localToGlobalBucket, const xAOD::MuonSegment &truthSeg, PrimitiveVec &outputContainer, const View view) const
Paints the truth sim hits associated with the segment.
void drawSearchWindow(const Amg::Transform3D &localToGlobalBucket, PrimitiveVec &outputContainer, const double thetaMin, const double thetaMax, const Canvas_t &canvas, const View view) const
Draw the search window lines in the local frame expressed by the Transform3D for eta views and in the...
BooleanProperty m_displayOnlyWithPattern
Toggle to print pattern buckets only if they contain pattern hits.
BooleanProperty m_saveSinglePDFs
If set to true each canvas is saved into a dedicated pdf file.
BooleanProperty m_paintFailedPatterns
Switch to visualize failed patterns.
SG::ReadHandleKey< ActsTrk::GeometryContext > m_geoCtxKey
Geometry context key to retrieve the alignment.
void plotPatternBucket(const EventContext &ctx, const std::string &extraLabel, const MuonR4::SpacePointBucket &bucket, PatternHitVisualInfo &&patternVisual, PrimitiveVec &&extraPaints) const
Plot a single pattern bucket.
StringProperty m_canvasPrefix
Prefix of the individual canvas file names <MANDATORY>.
BooleanProperty m_paintTruthSegment
Switch to visualize the truth segment.
BooleanProperty m_saveSummaryPDF
If set to true a summary Canvas is created.
void drawLineResidual(const ActsTrk::GeometryContext &gctx, const Amg::Transform3D &localToGlobalBucket, PrimitiveVec &outputContainer, const MuonR4::SpacePoint *seed, const MuonR4::SpacePoint *testHit, const double lineSlope, const double Rwindow, const PatternHitVisualInfo::HitStatus status, const Canvas_t &canvas, const View view) const
Draw the pattern line and acceptance window for the testHit used during pattern building in the local...
ElementLink< xAOD::MuonSegmentContainer > SegLink_t
ServiceHandle< IRootVisualizationService > m_visualSvc
Service handle of the visualization service.
BooleanProperty m_doPhiBucketViews
Switch to visualize the phi view of the bucket event.
BooleanProperty m_displayOnlyTruth
Toggle to print pattern buckets only if they contain truth hits.
SG::ReadHandleKeyArray< xAOD::UncalibratedMeasurementContainer > m_prepContainerKeys
Declare dependency on the prep data containers.
SG::AuxElement::ConstAccessor< SegLinkVec_t > SegLinkDecor_t
BooleanProperty m_doEtaBucketViews
Switch to visualize the eta view of the bucket event.
const MuonGMR4::MuonDetectorManager * m_detMgr
pointer to the Detector manager
void drawSegment(const xAOD::MuonSegment &segment, const Amg::Transform3D &localToGlobalBucket, PrimitiveVec &outputContainer, bool &drawnTrueLabel, const Canvas_t &canvas, const View view) const
Draw a segment on the canvas.
virtual LabeledSegmentSet getLabeledSegments(const std::vector< const MuonR4::SpacePoint * > &hits) const override final
Returns whether the hit has been used on the labeled segments we refer to (e.g.
BooleanProperty m_paintTruthHits
Switch to visualize the truth hits.
virtual void plotPatternBuckets(const EventContext &ctx, const std::string &extraLabel, PatternHitVisualInfoVec &&patternVisualVec) const override final
StringProperty m_subDir
Define the subdirectory in which the plots shall be saved.
IRootVisualizationService::ICanvasObject Canvas_t
std::vector< SegLinkDecor_t > m_truthLinkDecors
bool drawHits(const MuonR4::SpacePointBucket &bucket, const Amg::Transform3D &localToGlobalBucket, const std::vector< SpacePointType > &hitsToDraw, Canvas_t &canvasDim, const View view) const
Translates the Spacepoint information into TObjects that are dawn on the canvas & evaluates the size ...
UnsignedIntegerProperty m_canvasLimit
Maximum canvases to draw.
Property holding a SG store/key/clid from which a ReadHandle is made.
std::string label(const std::string &format, int i)
Definition label.h:19
@ Mdt
MuonSpectrometer.
std::optional< double > intersect(const AmgVector(N)&posA, const AmgVector(N)&dirA, const AmgVector(N)&posB, const AmgVector(N)&dirB)
Calculates the point B' along the line B that's closest to a second line A.
Eigen::Affine3d Transform3D
Eigen::Matrix< double, 3, 1 > Vector3D
SeedingAux::FitParIndex ParamDefs
Use the same parameter indices as used by the CompSpacePointAuxiliaries.
Parameters localSegmentPars(const xAOD::MuonSegment &seg)
Returns the localSegPars decoration from a xAODMuon::Segment.
std::pair< Amg::Vector3D, Amg::Vector3D > makeLine(const Parameters &pars)
Returns the parsed parameters into an Eigen line parametrization.
Acts::Experimental::CompositeSpacePointLineFitter::ParamVec_t Parameters
std::string makeLabel(const Parameters &pars)
Dumps the parameters into a string in the form of TLatex.
std::unordered_set< const xAOD::MuonSimHit * > getMatchingSimHits(const xAOD::MuonSegment &segment)
: Returns all sim hits matched to a xAOD::MuonSegment
MuonValR4::IPatternVisualizationTool::PrimitiveVec PrimitiveVec
Lightweight algorithm to read xAOD MDT sim hits and (fast-digitised) drift circles from SG and fill a...
PatternVisualizationTool::LabeledSegmentSet LabeledSegmentSet
constexpr int hollowFilling
Filling codes for hollow / fullFilling / hatched filling.
std::unique_ptr< TLine > drawLine(const MuonR4::SegmentFit::Parameters &pars, const double lowEnd, const double highEnd, const int color=kRed+1, const int lineStyle=kDashed, const int view=objViewEta)
Draws a line from the segment fit parameters.
constexpr int hatchedFilling
std::unique_ptr< TLatex > drawLabel(const std::string &text, const double xPos, const double yPos, const double textSize=18, const bool useNDC=true, const int color=kBlack)
Create a TLatex label,.
std::vector< std::unique_ptr< TObject > > clone(const std::vector< std::unique_ptr< TObject > > &cloneMe)
std::unique_ptr< TEllipse > drawDriftCircle(const Amg::Vector3D &center, const double radius, const int color=kViolet, const int fillStyle=hollowFilling)
Create a TEllipse for drawing a drift circle.
constexpr int fullFilling
std::unique_ptr< TArrow > drawArrow(const Amg::Vector3D &start, const Amg::Vector3D &dir, const int color=kRed+1, const int lineStyle=kDashed, const int view=objViewEta)
Draw an arror between two endpoints in the y-z or the x-z plane.
std::unique_ptr< TBox > drawBox(const Amg::Vector3D &boxCenter, const double boxWidth, const double boxHeight, const int color=kGreen+2, const int fillStyle=hollowFilling, const int view=objViewEta)
Creates a box for drawing, e.g strip measurements.
StIndex
enum to classify the different station layers in the muon spectrometer
bool isBarrel(const ChIndex index)
Returns true if the chamber index points to a barrel chamber.
const T * get(const ReadCondHandleKey< T > &key, const EventContext &ctx)
Convenience function to retrieve an object given a ReadCondHandleKey.
std::vector< const SpacePoint * > SpacePointSet
vector of space points
Definition FitterTypes.h:38
MdtDriftCircle_v1 MdtDriftCircle
MuonSimHit_v1 MuonSimHit
Defined the version of the MuonSimHit.
Definition MuonSimHit.h:12
TgcStrip_v1 TgcStrip
Definition TgcStripFwd.h:9
RpcMeasurement_v1 RpcMeasurement
MuonSegment_v1 MuonSegment
Reference the current persistent version:
UncalibratedMeasurement_v1 UncalibratedMeasurement
Define the version of the uncalibrated measurement class.