ATLAS Offline Software
Loading...
Searching...
No Matches
PatternVisualizationTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
5
11
15
21
22#include "Acts/Utilities/Helpers.hpp"
23#include "Acts/Definitions/Units.hpp"
24#include "Acts/Surfaces/RectangleBounds.hpp"
25#include "Acts/Surfaces/TrapezoidBounds.hpp"
26#include "Acts/Surfaces/PlaneSurface.hpp"
27#include "Acts/Surfaces/StrawSurface.hpp"
28#include "Acts/Visualization/GeometryView3D.hpp"
29
30
31#include <format>
32#include <sstream>
33#include <filesystem>
34
35
36#include "TH1F.h"
37#include "TH2F.h"
38#include "TMarker.h"
39#include "TColor.h"
40
41
42namespace {
43 constexpr int truthColor = kOrange +2;
44 constexpr int parLineColor = kRed;
45 using SpacePointSet = std::unordered_set<const MuonR4::SpacePoint*>;
46}
47
48using namespace Acts::UnitLiterals;
49
50namespace MuonValR4 {
51 using namespace MuonR4;
52 using namespace SegmentFit;
54
56 if (m_canvasLimit > 0) {
57 m_clientToken.canvasLimit = m_canvasLimit;
58 m_clientToken.preFixName = m_canvasPrefix;
59 m_clientToken.saveSinglePlots = m_saveSinglePDFs;
60 m_clientToken.saveSummaryPlot = m_saveSummaryPDF;
61 m_clientToken.subDirectory = m_subDir;
62 ATH_CHECK(m_visualSvc.retrieve());
63 ATH_CHECK(m_visualSvc->registerClient(m_clientToken));
64 } else {
65 m_plotsDone = true;
66 }
67 ATH_CHECK(m_prepContainerKeys.initialize(!m_truthSegLinks.empty()));
69 ATH_MSG_INFO("Hits linked to the following segment decorations are considered as truth");
70 for (const std::string& decorName : m_truthSegLinks) {
71 ATH_MSG_INFO(" **** "<<decorName);
72 if (decorName.empty()) {
73 ATH_MSG_FATAL("Decoration must not be empty");
74 return StatusCode::FAILURE;
75 }
77 m_truthLinkDecorKeys.emplace_back(key, decorName);
78 m_truthLinkDecors.push_back(SegLinkDecor_t{decorName});
79 }
80 }
81 ATH_CHECK(m_truthLinkDecorKeys.initialize());
82 m_displayOnlyTruth.value() &= !m_truthLinkDecorKeys.empty();
83
84 ATH_CHECK(m_idHelperSvc.retrieve());
85 ATH_CHECK(m_geoCtxKey.initialize());
86 ATH_CHECK(detStore()->retrieve(m_detMgr));
87 return StatusCode::SUCCESS;
88 }
90 return isLabeled(*hit.primaryMeasurement()) ||
91 (hit.secondaryMeasurement() && isLabeled(*hit.secondaryMeasurement()));
92 }
94 return std::find_if(m_truthLinkDecors.begin(), m_truthLinkDecors.end(),
95 [&hit](const SegLinkDecor_t& decor){
96 return !decor(hit).empty();
97 }) != m_truthLinkDecors.end();
98 }
99
100 LabeledSegmentSet PatternVisualizationTool::getLabeledSegments(const std::vector<const MuonR4::SpacePoint*>& hits) const {
101 std::vector<const xAOD::UncalibratedMeasurement*> measurements{};
102 measurements.reserve(2* hits.size());
103 for (const SpacePoint* hit: hits) {
104 measurements.push_back(hit->primaryMeasurement());
105 if(hit->secondaryMeasurement()) {
106 measurements.push_back(hit->secondaryMeasurement());
107 }
108 }
109 return getLabeledSegments(measurements);
110 }
111 LabeledSegmentSet PatternVisualizationTool::getLabeledSegments(const std::vector<const xAOD::UncalibratedMeasurement*>& hits) const {
112 LabeledSegmentSet truthSegs{};
113 for (const xAOD::UncalibratedMeasurement* hit : hits) {
114 for (const SegLinkDecor_t& decor: m_truthLinkDecors) {
115 for (const SegLink_t& link : decor(*hit)) {
116 truthSegs.insert(*link);
117 }
118 }
119 }
120 return truthSegs;
121 }
123 const MuonR4::HoughPlane& accumulator,
124 const Acts::HoughTransformUtils::HoughAxisRanges& axisRanges,
125 const MaximumVec& maxima,
126 const std::string& extraLabel) const {
127 PrimitiveVec primitives{};
128 visualizeAccumulator(ctx, accumulator, axisRanges, maxima, extraLabel, std::move(primitives));
129 }
131 const MuonR4::HoughPlane& accumulator,
132 const Acts::HoughTransformUtils::HoughAxisRanges& axisRanges,
133 const MaximumVec& maxima,
134 const std::string& extraLabel,
135 PrimitiveVec&& primitives) const {
136
138 if (m_plotsDone) {
139 return;
140 }
141
142 ATH_MSG_VERBOSE("Visualize accumulator");
143
144 if (accumulator.getNonEmptyBins().empty()) {
145 ATH_MSG_WARNING("Hough accumulator is empty");
146 return;
147 }
148
149 auto accHisto = std::make_unique<TH2F>("AccumulatorHisto", "histo",
150 accumulator.nBinsX(), axisRanges.xMin, axisRanges.xMax,
151 accumulator.nBinsY(), axisRanges.yMin, axisRanges.yMax);
152 accHisto->SetDirectory(nullptr);
153
154 std::vector<const SpacePoint*> spacePointsInAcc{};
155 for (const std::size_t bin : accumulator.getNonEmptyBins()) {
156 const auto [xBin, yBin] = accumulator.axisBins(bin);
157 auto hitIds = accumulator.hitIds(xBin, yBin);
158 spacePointsInAcc.insert(spacePointsInAcc.end(),hitIds.begin(), hitIds.end());
159 accHisto->SetBinContent(xBin+1, yBin+1, accumulator.nHits(bin));
160 }
161
162 const LabeledSegmentSet truthSegs{getLabeledSegments(spacePointsInAcc)};
163 if (truthSegs.empty() && m_displayOnlyTruth) {
164 ATH_MSG_VERBOSE("visualizeAccumulator skipped: no truth segments found and displayOnlyTruth=true");
165 return;
166 }
167
168 auto canvas = m_visualSvc->prepareCanvas(ctx, m_clientToken, extraLabel);
169 if (!canvas){
170 m_plotsDone = true;
171 return;
172 }
173
174
175 const double maxBins = std::max(accumulator.nBinsX(), accumulator.nBinsY());
176 double markerTextSize = 0.035;
177 // Scale down for large accumulators
178 markerTextSize *= 25. / std::max(25., maxBins);
179 // Avoid absurdly tiny/large text
180 markerTextSize = std::clamp(markerTextSize, 0.006, 0.035);
181 accHisto->SetMarkerSize(markerTextSize);
182 accHisto->SetMarkerColor(kBlack);
183 accHisto->SetMinimum(0.);
184
185 canvas->expandPad(axisRanges.xMin, axisRanges.yMin);
186 canvas->expandPad(axisRanges.xMax, axisRanges.yMax);
187 canvas->setAxisTitles(std::format("tan#{}", m_accumlIsEta ? "beta" : "#alpha"),
188 std::format("{:}_{{0}} [mm]", m_accumlIsEta ? "y" : "x"));
189 canvas->add(std::move(accHisto), "HIST SAME");
190
191 // Draw explicit bin labels at bin centers. This is more robust than TH2 TEXT
192 // when plotting into the visualization service's prebuilt frame.
193 const double binLabelPx = std::clamp(1.2 * 500. / maxBins, 7.0, 18.0);
194 for (const std::size_t bin : accumulator.getNonEmptyBins()) {
195 const auto [xBin, yBin] = accumulator.axisBins(bin);
196 const double xCenter = axisRanges.xMin + (xBin + 0.5) * (axisRanges.xMax - axisRanges.xMin) / accumulator.nBinsX();
197 const double yCenter = axisRanges.yMin + (yBin + 0.5) * (axisRanges.yMax - axisRanges.yMin) / accumulator.nBinsY();
198
199 //Extract number of entries in the bin with no decimal precision just int
200 std::string binLabel = std::format("{:0}", int(accumulator.nHits(bin)));
201
202 auto binTxt = drawLabel(binLabel, xCenter, yCenter, binLabelPx, false, kBlack);
203 binTxt->SetTextAlign(22);
204 canvas->add(std::move(binTxt));
205 }
206
207 int iseg = 0;
208 for (const xAOD::MuonSegment* segment : truthSegs) {
209 const auto [pos, dir] = makeLine(localSegmentPars(*segment));
210 const double tan = m_accumlIsEta ? houghTanBeta(dir) : houghTanAlpha(dir);
211 const double icept = pos[m_accumlIsEta ? objViewEta : objViewPhi];
212 auto truthMarker = std::make_unique<TMarker>(tan, icept, kFullCrossX);
213 truthMarker->SetMarkerColor(truthColor);
214 truthMarker->SetMarkerSize(4);
215 canvas->add(std::move(truthMarker));
216 canvas->add(drawLabel(std::format("true parameters: {:}",
217 makeLabel(localSegmentPars(*segment))),0.2, 0.9 - 0.05*iseg));
218 iseg += 1;
219 }
220 for (const auto& maximum : maxima) {
221 auto maxMarker = std::make_unique<TMarker>(maximum.x, maximum.y, kFullTriangleUp);
222 maxMarker->SetMarkerColor(parLineColor);
223 maxMarker->SetMarkerSize(4);
224 canvas->add(std::move(maxMarker));
225
226 // Draw a bounding box around the maximum island center (x,y) and widths (wx,wy).
227 const double xMin = maximum.x - maximum.wx;
228 const double xMax = maximum.x + maximum.wx;
229 const double yMin = maximum.y - maximum.wy;
230 const double yMax = maximum.y + maximum.wy;
231
232 auto maxBox = drawBox(xMin, yMin, xMax, yMax, parLineColor, hollowFilling);
233 maxBox->SetLineStyle(kDashed);
234 maxBox->SetLineWidth(2);
235 canvas->add(std::move(maxBox));
236 }
237
238 canvas->add(std::move(primitives));
239 }
240 void PatternVisualizationTool::paintSimHits(const EventContext& ctx,
241 const xAOD::MuonSegment& truthSeg,
242 Canvas_t& canvas,
243 const int view) const {
244 if (!m_paintTruthHits) {
245 return;
246 }
247 auto truthHits = getMatchingSimHits(truthSeg);
248 const ActsTrk::GeometryContext* geoCtx{nullptr};
249 if (!SG::get(geoCtx, m_geoCtxKey, ctx).isSuccess()) {
250 return;
251 }
252 for (const xAOD::MuonSimHit* simHit : truthHits) {
253 const MuonGMR4::MuonReadoutElement* re = m_detMgr->getReadoutElement(simHit->identify());
254 const IdentifierHash hash = re->detectorType() == ActsTrk::DetectorType::Mdt ?
255 re->measurementHash(simHit->identify()) :
256 re->layerHash(simHit->identify());
257 const Acts::Transform3 trf = re->msSector()->globalToLocalTransform(*geoCtx) *
258 re->localToGlobalTransform(*geoCtx, hash);
259 const Amg::Vector3D locPos = trf * xAOD::toEigen(simHit->localPosition());
260 const Amg::Vector3D locDir = trf.linear() * xAOD::toEigen(simHit->localDirection());
261 canvas.add(drawArrow(locPos, locDir, truthColor, kDashed, view));
262 }
263 }
264 void PatternVisualizationTool::visualizeSeed(const EventContext& ctx,
265 const MuonR4::SegmentSeed& seed,
266 const std::string& extraLabel) const {
267 PrimitiveVec primitives{};
268 visualizeSeed(ctx, seed, extraLabel, std::move(primitives));
269 }
270 void PatternVisualizationTool::visualizeSeed(const EventContext& ctx,
271 const MuonR4::SegmentSeed& seed,
272 const std::string& extraLabel,
273 PrimitiveVec&& primitives) const {
274
275 ATH_MSG_VERBOSE("Visualizing seed with " << seed.getHitsInMax().size() << " hits");
277 if (m_plotsDone) {
278 ATH_MSG_VERBOSE("visualizeSeed skipped: canvas quota already exhausted for " << extraLabel);
279 return;
280 }
281 const LabeledSegmentSet truthSegs{getLabeledSegments(seed.getHitsInMax())};
282 if (truthSegs.empty() && m_displayOnlyTruth) {
283 ATH_MSG_VERBOSE("visualizeSeed skipped: no truth segments found and displayOnlyTruth=true");
284 return;
285 }
286 for (const int view : {objViewEta, objViewPhi}) {
287 if ((view == objViewEta && !m_doEtaBucketViews) ||
288 (view == objViewPhi && !m_doPhiBucketViews)){
289 continue;
290 }
291
292 std::string_view viewName = view == objViewEta ? "eta" : "phi";
293
294 auto canvas = m_visualSvc->prepareCanvas(ctx, m_clientToken, std::format("{}_{}", extraLabel, viewName));
295
296 if (!canvas) {
297 m_plotsDone = true;
298 return;
299 }
300
301 DynamicLegend legend;
302 canvas->add(clone(primitives));
303
304 canvas->setAxisTitles(std::format("{:} [mm]", view == objViewEta ? 'y' : 'x'), "z [mm]");
305
306 if (!drawHits(*seed.parentBucket(), seed.getHitsInMax(), *canvas, legend, view)) {
307 continue;
308 }
309 for (const xAOD::MuonSegment* segment : truthSegs) {
310 canvas->add(drawLine(localSegmentPars(*segment),
311 canvas->corner(Edges::yLow), canvas->corner(Edges::yHigh),
312 truthColor, kDotted, view));
313 paintSimHits(ctx,*segment, *canvas, view);
314 }
315 canvas->add(drawLine(seed.parameters(), canvas->corner(Edges::yLow),
316 canvas->corner(Edges::yHigh), parLineColor, kDashed, view));
317
318 writeChi2(seed.parameters(), seed.getHitsInMax(), *canvas);
319
320 std::string legendLabel = std::format("Event: {:}, chamber : {:}, #{:}-view ({:})",
321 ctx.eventID().event_number(),
322 m_idHelperSvc->toStringChamber(seed.getHitsInMax().front()->identify()),
323 view ==objViewEta ? "eta" : "phi",
324 extraLabel);
325 canvas->add(drawLabel(legendLabel, 0.1, 0.96));
326 canvas->add(drawLabel( "Seed parameters: " + makeLabel(seed.parameters()),0.25, 0.89));
327 }
328 }
329
330 void PatternVisualizationTool::visualizeBucket(const EventContext& ctx,
331 const MuonR4::SpacePointBucket& bucket,
332 const std::string& extraLabel) const {
333 PrimitiveVec primitives{};
334 visualizeBucket(ctx, bucket, extraLabel, std::move(primitives));
335 }
336 void PatternVisualizationTool::visualizeBucket(const EventContext& ctx,
337 const MuonR4::SpacePointBucket& bucket,
338 const std::string& extraLabel,
339 PrimitiveVec&& primitives) const {
341 if (m_plotsDone) {
342 return;
343 }
344 ATH_MSG_VERBOSE("visualizeBucket called for " << extraLabel);
345
346 LabeledSegmentSet truthSegs{getLabeledSegments(Acts::unpackConstSmartPointers(bucket))};
347 if (truthSegs.empty() && m_displayOnlyTruth) {
348 ATH_MSG_VERBOSE("visualizeBucket skipped: no truth segments found and displayOnlyTruth=true");
349 return;
350 }
351
352 for (const int view : {objViewEta, objViewPhi}) {
353 if ((view == objViewEta && !m_doEtaBucketViews) ||
354 (view == objViewPhi && !m_doPhiBucketViews)){
355 continue;
356 }
357
358 const std::string_view viewName = view == objViewEta ? "eta" : "phi";
359
360 auto canvas = m_visualSvc->prepareCanvas( ctx, m_clientToken, std::format("{}_{}view", extraLabel, viewName));
361
362
363 if (!canvas) {
364 m_plotsDone = true;
365 return;
366 }
367
368 DynamicLegend legend(0.8, 0.2, 0.95, 0.5);
369
370 canvas->add(clone(primitives));
371
373 if (!drawHits(bucket, bucket, *canvas, legend, view)) {
374 canvas->trash();
375 continue;
376 }
377 bool drawnTrueLabel{false};
378 for (const xAOD::MuonSegment* segment : truthSegs) {
379
380 auto truthLine = drawLine(localSegmentPars(*segment), canvas->corner(Edges::yLow), canvas->corner(Edges::yHigh), truthColor, kDotted, view);
381 TLine* line = static_cast<TLine*>(truthLine.get());
382 canvas->add( std::move(truthLine) );
383 legend.addOnce( LegendItem::TruthSegmentLine, line, "Truth Segment", "l" );
384
385 if (!drawnTrueLabel) {
386 canvas->add(drawLabel(std::format("true parameters: {:}",makeLabel(localSegmentPars(*segment))),0.2, 0.89));
387 drawnTrueLabel = true;
388 }
389 paintSimHits(ctx,*segment, *canvas, view);
390 }
391
392 std::string legendLabel = std::format("Event: {:}, chamber : {:}, #{:}-view ({:})",
393 ctx.eventID().event_number(),
394 bucket.msSector()->identString(),
395 view ==objViewEta ? "eta" : "phi",
396 extraLabel);
397 canvas->add(drawLabel(legendLabel, 0.15, 0.96));
398
399 canvas->setAxisTitles(std::format("{:} [mm]", view == objViewEta ? 'y' : 'x'), "z [mm]");
400
401 if (!legend.empty()) {
402 canvas->add(legend.release(), "same");
403 }
404
405 }
406 }
407
408 void PatternVisualizationTool::visualizeSegment(const EventContext& ctx,
409 const MuonR4::Segment& segment,
410 const std::string& extraLabel) const {
411 PrimitiveVec primitives{};
412 visualizeSegment(ctx, segment,extraLabel, std::move(primitives));
413 }
414
415 void PatternVisualizationTool::visualizeSegment(const EventContext& ctx,
416 const MuonR4::Segment& segment,
417 const std::string& extraLabel,
418 PrimitiveVec&& primitives) const {
420 if (m_plotsDone) {
421 return;
422 }
423
424 ATH_MSG_VERBOSE("Visualizing segment with " << segment.measurements().size() << " hits");
425
426 const LabeledSegmentSet truthSegs{getLabeledSegments(segment.parent()->getHitsInMax())};
427 if (truthSegs.empty() && m_displayOnlyTruth) {
428 return;
429 }
430 const ActsTrk::GeometryContext* geoCtx{nullptr};
431 if (!SG::get(geoCtx, m_geoCtxKey, ctx).isSuccess()) {
432 return;
433 }
434
435
436 const Parameters segPars = SegmentFit::localSegmentPars(*geoCtx, segment);
437
438 for (const int view : {objViewEta, objViewPhi}) {
439 if ((view == objViewEta && !m_doEtaBucketViews) ||
440 (view == objViewPhi && !m_doPhiBucketViews)){
441 continue;
442 }
443
444 const std::string_view viewName = view == objViewEta ? "eta" : "phi";
445
446 auto canvas = m_visualSvc->prepareCanvas(ctx, m_clientToken, std::format("{}_{}view", extraLabel, viewName));
447 if (!canvas) {
448 m_plotsDone = true;
449 return;
450 }
451 canvas->setAxisTitles(std::format("{:} [mm]", view == objViewEta ? 'y' : 'x'), "z [mm]");
452 canvas->add(clone(primitives));
453
454 DynamicLegend legend(0.8, 0.2, 0.95, 0.5);
455
456
457 ATH_MSG_DEBUG("Drawing hits!");
458 if (!drawHits(*segment.parent()->parentBucket(), segment.measurements(),
459 *canvas, legend, view)) {
460 canvas->trash();
461 continue;
462 }
463
464 ATH_MSG_DEBUG("Drawing chi2!");
465 writeChi2(segPars, segment.measurements(), *canvas);
466
467
468 {
469 auto segmentline = drawLine(segPars, canvas->corner(Edges::yLow), canvas->corner(Edges::yHigh), parLineColor, kDashed, view);
470 legend.addOnce(LegendItem::RecoSegmentLine, segmentline.get(), "Reco Segment", "l");
471 canvas->add(std::move(segmentline));
472
473 }
474 bool drawnTrueLabel{false};
475 for (const xAOD::MuonSegment* segment : truthSegs) {
476 auto truthLine = drawLine(localSegmentPars(*segment), canvas->corner(Edges::yLow), canvas->corner(Edges::yHigh), truthColor, kDotted, view);
477 legend.addOnce( LegendItem::TruthSegmentLine, truthLine.get(), "Truth Segment", "l" );
478 canvas->add( std::move(truthLine) );
479 using namespace Acts::detail::LineHelper;
480 const Acts::Vector3 bsExtp = lineIntersect<3>(Amg::Vector3D::Zero(), Amg::Vector3D::UnitZ(),
481 segment->position(), segment->direction()).position();
482 if (!drawnTrueLabel) {
483 canvas->add(drawLabel(std::format("true parameters: {:}, d_{{0}}={:.2f}, z_{{0}}={:.2f}",
484 makeLabel(localSegmentPars(*segment)), bsExtp.perp(),
485 std::abs(bsExtp.z()) ) , 0.1, 0.05));
486 drawnTrueLabel = true;
487 }
488 paintSimHits(ctx,*segment, *canvas, view);
489 }
490
491 const Identifier canvasId{segment.parent()->getHitsInMax().front()->identify()};
492 std::string legendLabel=std::format("Event: {:}, chamber: {:}, #chi^{{2}} / nDoF: {:.2f} ({:d}), #{:}-view (:)",
493 ctx.eventID().event_number(), m_idHelperSvc->toStringChamber(canvasId),
494 segment.chi2() /std::max(1u, segment.nDoF()), segment.nDoF(),
495 view ==objViewEta ? "eta" : "phi", extraLabel);
496
497 canvas->add(drawLabel(legendLabel, 0.2, 0.96));
498 canvas->add(drawLabel(makeLabel(segPars),0.25, 0.91));
499
500 if (!legend.empty()) {
501 canvas->add(legend.release(), "same");
502 }
503 }
504 }
505
506 template<class SpacePointType>
507 const SpacePoint*
508 PatternVisualizationTool::drawHit(const SpacePointType& hit, Canvas_t& canvas, DynamicLegend& legend,
509 const unsigned int view,
510 unsigned int fillStyle) const {
511
513 if ((view == objViewEta && !hit.measuresEta()) || (view == objViewPhi && !hit.measuresPhi())) {
514 return nullptr;
515 }
516
517 if (hit.type() != xAOD::UncalibMeasType::Other) {
518 canvas.expandPad(hit.localPosition()[view] - hit.driftRadius(),
519 hit.localPosition().z() - hit.driftRadius());
520 canvas.expandPad(hit.localPosition()[view] + hit.driftRadius(),
521 hit.localPosition().z() + hit.driftRadius());
522 }
523
524 const SpacePoint* underlyingSp{nullptr};
526 constexpr int invalidCalibFill = 3305;
527 if constexpr (std::is_same_v<SpacePointType, SpacePoint>) {
528 ATH_MSG_VERBOSE("drawHit called with SpacePoint");
529 underlyingSp = &hit;
531 const auto* dc = static_cast<const xAOD::MdtDriftCircle*>(hit.primaryMeasurement());
532 if (dc && dc->status() != Muon::MdtDriftCircleStatus::MdtStatusDriftTime) {
533 fillStyle = invalidCalibFill;
534 }
535 }
536 } else if constexpr(std::is_same_v<SpacePointType, CalibratedSpacePoint>) {
537 ATH_MSG_VERBOSE("drawHit called with CalibratedSpacePoint");
538 underlyingSp = hit.spacePoint();
539 if (hit.fitState() == CalibratedSpacePoint::State::Valid) {
540 fillStyle = fullFilling;
541 } else if (hit.fitState() == CalibratedSpacePoint::State::FailedCalib) {
542 fillStyle = invalidCalibFill;
543 } else {
544 fillStyle = hatchedFilling;
545 }
546 }
547 else{
548 ATH_MSG_VERBOSE("drawHit called with unsupported SpacePointType");
549 }
550
551 //TODO: investigate MuonSegmentFittingAlg.PatternVisualizationTool throws seg fault without check but the calibrated space point should have reference space point no?
552 if (!underlyingSp){
553 ATH_MSG_VERBOSE("Underlying space point not found, skipping hit");
554 return nullptr;
555 }
556
557 const auto* primaryMeas = underlyingSp->primaryMeasurement();
558 const auto* secondaryMeas = underlyingSp->secondaryMeasurement();
559
560 //If there is a secondary measurement and it is not matched, choose a different colour to the cases where we have primary and it is matched
561 //Need to cast secondary measurement to the respective det type?
562 auto labeledColor = (secondaryMeas && !isLabeled(*secondaryMeas)) ? kOrange - 3 : truthColor;
563
564 const auto covarianceWidth = [&]() -> double {
565 const double variance = std::max(0., underlyingSp->covariance()[view]);
566 //In case of strip it would be too small to visualize the hit, so we set a minimum width of 5 mm, should we add sqrt(12) to get the full width of the strip?
567 return std::max(5. * Gaudi::Units::mm, std::sqrt(variance));
568 };
569
570 const auto addLabeledOutline = [&](const double boxWidth, const double boxHeight) {
571 if (!isLabeled(*primaryMeas)) {
572 return;
573 }
574 // Draw a dedicated hollow overlay so the truth-color border is always visible.
575 auto outline = drawBox(hit.localPosition(), boxWidth, boxHeight, labeledColor, hollowFilling, view);
576 outline->SetFillStyle(hollowFilling);
577 outline->SetLineColor(labeledColor);
578 TObject* p_outline = outline.get();
579 canvas.add(std::move(outline), "l");
580 legend.addOnce(LegendItem::LabeledBox, p_outline, "TrueSimHitMatch", "f");
581 };
582
583 // Add the hit to the legend depending on the fill style (outlier, full, or hatched)
584 const auto addHitLegendByFill = [&](TObject* object,
585 const LegendItem bucketItem,
586 const char* bucketLabel,
587 const LegendItem onObjectItem,
588 const char* onObjectLabel, const char* option = "f") {
589
590 if (fillStyle == hatchedFilling) {
591 legend.addOnce(LegendItem::OutlierHit, object, "Outlier", option);
592 return;
593 }
594 if (fillStyle == fullFilling) {
595 legend.addOnce(onObjectItem, object, onObjectLabel, option);
596 return;
597 }
598
599 // Hits in the bucket with a hollow filling
600 legend.addOnce(bucketItem, object, bucketLabel, option);
601 };
602
603 switch(hit.type()) {
605 const auto* dc = static_cast<const xAOD::MdtDriftCircle*>(primaryMeas);
606 canvas.add(drawDriftCircle(hit.localPosition(), dc->readoutElement()->innerTubeRadius(), kBlack, hollowFilling));
607 auto driftCircle = drawDriftCircle(hit.localPosition(), hit.driftRadius(), kBlue, fillStyle);
608 TObject* p_driftCircle = driftCircle.get();
609 canvas.add(std::move(driftCircle));
610
611 //Unforunately the legend will be a box ... to have a point we could make TGraph with a point and add it to the legend but then we would have to draw the hit as a TGrapg as well, so for now we keep it as a box
612 addHitLegendByFill(p_driftCircle,
614 "MDT inBucket",
616 "MDT onObject", "f");
617
618 //In case the hit is also a truth hit, change the line colour to indicate that
619 if (isLabeled(*dc)) {
620 auto labeledDriftCircle = drawDriftCircle(hit.localPosition(), hit.driftRadius(), labeledColor, hollowFilling);
621 TObject* p_labeledDriftCircle = labeledDriftCircle.get();
622 canvas.add(std::move(labeledDriftCircle));
623 legend.addOnce( LegendItem::LabeledTube, p_labeledDriftCircle, "TrueSimMdtHitMatch", "f");
624 }
625 break;
627 const auto* meas{static_cast<const xAOD::RpcMeasurement*>(primaryMeas)};
628 const double boxWidth = 0.5*std::sqrt(12)*std::sqrt(underlyingSp->covariance()[view]);
629 auto rpcBox = drawBox(hit.localPosition(), boxWidth, 0.5*meas->readoutElement()->gasGapPitch(),
630 kGreen + 2, fillStyle);
631 TObject* p_rpcBox = rpcBox.get();
632 canvas.add(std::move(rpcBox));
633 addHitLegendByFill(p_rpcBox,
635 "RPC inBucket",
637 "RPC onObject");
638 addLabeledOutline(boxWidth, 0.5*meas->readoutElement()->gasGapPitch());
639 break;
641 const auto* meas{static_cast<const xAOD::TgcStrip*>(primaryMeas)};
642 const double boxWidth = 0.5*std::sqrt(12)*std::sqrt(underlyingSp->covariance()[view]);
643 auto tgcBox = drawBox(hit.localPosition(), boxWidth, 0.5*meas->readoutElement()->gasGapPitch(),
644 kCyan + 2, fillStyle);
645 TObject* p_tgcBox = tgcBox.get();
646 canvas.add(std::move(tgcBox));
647 addHitLegendByFill(p_tgcBox,
649 "TGC inBucket",
651 "TGC onObject");
652 addLabeledOutline(boxWidth, 0.5*meas->readoutElement()->gasGapPitch());
653 break;
655 const double boxWidth = covarianceWidth();
656 constexpr double boxHeight = 10.*Gaudi::Units::mm;
657 auto mmBox = drawBox(hit.localPosition(), boxWidth, boxHeight, kAquamarine, fillStyle, view);
658 TObject* p_mmBox = mmBox.get();
659 canvas.add(std::move(mmBox));
660
661 addHitLegendByFill(p_mmBox,
663 "MMG inBucket",
665 "MMG onObject");
666 addLabeledOutline(boxWidth, boxHeight);
667 break;
669 break;
671 const double boxWidth = covarianceWidth();
672 const double boxHeight = 10.*Gaudi::Units::mm;
673 auto stgcBox = drawBox(hit.localPosition(), boxWidth, boxHeight, kTeal, fillStyle, view);
674
675
676 //In case of pad use a transparent filling to see the underlying strip or wire
677 //TODO: do more splitting into strip+wire, strip+pad, wire+pad, strip+wire+pad and add legend accordingly?
679 const auto* primary = static_cast<const xAOD::sTgcMeasurement*>( primaryMeas );
680 if (primary && primary->channelType() == xAOD::sTgcMeasurement::sTgcChannelTypes::Pad) {
681 stgcBox->SetFillColorAlpha(kTeal, 0.1);
682 legendType = LegendItem::StgcPadHit;
683 }
684 TObject* p_stgcBox = stgcBox.get();
685
686 canvas.add(std::move(stgcBox));
687 if (legendType == LegendItem::StgcPadHit) {
688 addHitLegendByFill(p_stgcBox,
690 "sTGCp inBucket",
692 "sTGCp onObject");
693 } else {
694 addHitLegendByFill(p_stgcBox,
696 "sTGCs+w inBucket",
698 "sTGCs+w onObject");
699 }
700 addLabeledOutline(boxWidth, boxHeight);
701 break;
702 } default: {
703 ATH_MSG_WARNING("Please implement proper drawings of the new small wheel.. "<<__FILE__<<":"<<__LINE__);
704 break;
705 }
706 }
707 return underlyingSp;
708 }
709
710 template<class SpacePointType>
712 const std::vector<SpacePointType>& hitsToDraw,
713 Canvas_t& canvas, DynamicLegend& legend,
714 unsigned int view) const {
715
716 SpacePointSet drawnPoints{};
717
718 for (const SpacePointType& hit : hitsToDraw) {
719 drawnPoints.insert(drawHit(*hit, canvas, legend, view, fullFilling));
720 }
721 if (m_displayBucket) {
722 for (const SpacePointBucket::value_type& hit : bucket) {
723 // Don't redraw the other points
724 if (drawnPoints.count(hit.get())) {
725 continue;
726 }
727
728 drawHit(*hit, canvas, legend, view, hollowFilling);
729 }
730 }
731 return drawnPoints.size() - drawnPoints.count(nullptr) > 0;
732 }
733 template<class SpacePointType>
735 const std::vector<SpacePointType>& hits,
736 Canvas_t& canvas,
737 const double legX, double startLegY,
738 const double endLegY) const {
739 const auto [pos, dir] = makeLine(pars);
740
741 unsigned int nHits = 0;
742 for (const SpacePointType& hit : hits) {
743 const SpacePoint* underlyingSp{nullptr};
744 bool displayChi2{true};
745 if constexpr(std::is_same_v<SpacePointType, Segment::MeasType>) {
746 underlyingSp = hit->spacePoint();
747 displayChi2 = (hit->fitState() == CalibratedSpacePoint::State::Valid);
748 } else {
749 underlyingSp = hit;
750 }
751
752 ATH_MSG_VERBOSE("Writing chi2 for hit " << nHits << " of type " << hit->type());
753
754 const Identifier hitId = underlyingSp ? underlyingSp->identify(): Identifier{};
755 std::string legendstream{};
756 switch(hit->type()) {
758 const int driftSign{SeedingAux::strawSign(pos, dir, *hit)};
759 const MdtIdHelper& idHelper{m_idHelperSvc->mdtIdHelper()};
760 legendstream = std::format("ML: {:1d}, TL: {:1d}, T: {:3d}, {:}",
761 idHelper.multilayer(hitId), idHelper.tubeLayer(hitId),
762 idHelper.tube(hitId), driftSign == -1 ? "L" : "R");
763 break;
765 const RpcIdHelper& idHelper{m_idHelperSvc->rpcIdHelper()};
766 legendstream= std::format("DR: {:1d}, DZ: {:1d}, GAP: {:1d}, #eta/#phi: {:}/{:}",
767 idHelper.doubletR(hitId), idHelper.doubletZ(hitId), idHelper.gasGap(hitId),
768 hit->measuresEta() ? "si" : "nay", hit->measuresPhi() ? "si" : "nay");
769 break;
771 const TgcIdHelper& idHelper{m_idHelperSvc->tgcIdHelper()};
772 legendstream = std::format("ST: {:}, GAP: {:1d}, #eta/#phi: {:}/{:}",
773 m_idHelperSvc->stationNameString(hitId), idHelper.gasGap(hitId),
774 hit->measuresEta() ? "si" : "nay", hit->measuresPhi() ? "si" : "nay");
775 break;
777 const MmIdHelper& idHelper{m_idHelperSvc->mmIdHelper()};
778 const auto* clus = static_cast<const xAOD::MMCluster*>(underlyingSp->primaryMeasurement());
779 const MuonGMR4::StripDesign& design = clus->readoutElement()->stripLayer(clus->layerHash()).design();
780 legendstream = std::format("ML: {:1d}, GAP: {:1d}, {:}", idHelper.multilayer(hitId), idHelper.gasGap(hitId),
781 !design.hasStereoAngle() ? "X" : design.stereoAngle() > 0 ? "U" :"V");
782 break;
784 const sTgcIdHelper& idHelper{m_idHelperSvc->stgcIdHelper()};
785 legendstream = std::format("ML: {:1d}, GAP: {:1d}, #eta/#phi: {:}/{:}",
786 idHelper.multilayer(hitId), idHelper.gasGap(hitId),
787 hit->measuresEta() ? "si" : "nay", hit->measuresPhi() ? "si" : "nay");
788 break;
790 legendstream = "Ext. constaint";
791 }
792 default:
793 break;
794 }
795 if (displayChi2) {
796 //Make thi chi2 view specific?
797 const double chi2 = SeedingAux::chi2Term(pos, dir,*hit);
798 legendstream+=std::format(", #chi^{{2}}: {:.2f}", chi2);
799 } else {
800 legendstream+=", NotValidState";
801 }
802
803
804 ++nHits;
805
806 canvas.add(drawLabel(legendstream, legX, startLegY, 8));
807 startLegY -= 0.02;
808 if (startLegY<= endLegY) {
809 break;
810 }
811 }
812 }
813
814}
const std::regex re(r_e)
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_WARNING(x,...)
#define ATH_MSG_VERBOSE(x,...)
#define ATH_MSG_INFO(x,...)
#define ATH_MSG_FATAL(x,...)
bool hit(const Container &ids, int pdgId)
static const uint32_t nHits
This is a "hash" representation of an Identifier.
int multilayer(const Identifier &id) const
Access to components of the ID.
int tube(const Identifier &id) const
int tubeLayer(const Identifier &id) const
int gasGap(const Identifier &id) const override
get the hashes
int multilayer(const Identifier &id) const
MuonReadoutElement is an abstract class representing the geometry of a muon detector.
std::string identString() const
Returns a string encoding the chamber index & the sector of the MS sector.
double stereoAngle() const
Returns the value of the stereo angle.
bool hasStereoAngle() const
Returns whether a stereo angle is defined.
Representation of a segment seed (a fully processed hough maximum) produced by the hough transform.
Definition SegmentSeed.h:14
const std::vector< HitType > & getHitsInMax() const
Returns the list of assigned hits.
const SpacePointBucket * parentBucket() const
Returns the bucket out of which the seed was formed.
Placeholder for what will later be the muon segment EDM representation.
unsigned int nDoF() const
Returns the number of degrees of freedom.
const SegmentSeed * parent() const
Returns the seed out of which the segment was built.
const MeasVec & measurements() const
Returns the associated measurements.
const Amg::Vector3D & position() const
Returns the global segment position.
const Amg::Vector3D & direction() const
Returns the global segment direction.
: 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
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.
const Identifier & identify() const
: Identifier of the primary measurement
Gaudi::Property< std::string > m_subDir
Define the subdirectory in which the plots shall be saved.
Gaudi::Property< bool > m_doEtaBucketViews
Switch to visualize the eta view of the bucket event.
ActsTrk::GeoContextReadKey_t m_geoCtxKey
Geometry context key to retrieve the alignment.
virtual StatusCode initialize() override final
Gaudi::Property< bool > m_accumlIsEta
Swtich toggling whether the accumulator view are in the eta or phi plane.
virtual void visualizeAccumulator(const EventContext &ctx, const MuonR4::HoughPlane &accumulator, const Acts::HoughTransformUtils::HoughAxisRanges &axisRanges, const MaximumVec &maxima, const std::string &extraLabel) const override final
SG::ConstAccessor< SegLinkVec_t > SegLinkDecor_t
virtual void visualizeSegment(const EventContext &ctx, const MuonR4::Segment &segment, const std::string &extraLabel) const override final
Gaudi::Property< unsigned int > m_canvasLimit
Maximum canvases to draw.
Gaudi::Property< bool > m_displayBucket
Display the surrounding hits from the bucket not part of the seed.
Gaudi::Property< std::string > m_canvasPrefix
Prefix of the individual canvas file names <MANDATORY>.
bool drawHits(const MuonR4::SpacePointBucket &bucket, const std::vector< SpacePointType > &hitsToDraw, Canvas_t &canvasDim, DynamicLegend &legend, unsigned int view) const
Translates the Spacepoint information into TObjects that are dawn on the canvas & evaluates the size ...
virtual void visualizeBucket(const EventContext &ctx, const MuonR4::SpacePointBucket &bucket, const std::string &extraLabel) const override final
Gaudi::Property< bool > m_saveSinglePDFs
If set to true each canvas is saved into a dedicated pdf file.
std::unordered_set< const xAOD::MuonSegment * > LabeledSegmentSet
virtual void visualizeSeed(const EventContext &ctx, const MuonR4::SegmentSeed &seed, const std::string &extraLabel) const override final
IRootVisualizationService::ClientToken m_clientToken
Token to present to the visualization service such that the display froms this tool are grouped toget...
std::vector< SegLinkDecor_t > m_truthLinkDecors
Gaudi::Property< bool > m_doPhiBucketViews
Switch to visualize the phi view of the bucket event.
SG::ReadDecorHandleKeyArray< xAOD::UncalibratedMeasurementContainer > m_truthLinkDecorKeys
Declaration of the dependency on the decorations.
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
Service Handle to the IMuonIdHelperSvc.
SG::ReadHandleKeyArray< xAOD::UncalibratedMeasurementContainer > m_prepContainerKeys
Declare dependency on the prep data containers.
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.
IRootVisualizationService::ICanvasObject Canvas_t
Gaudi::Property< std::set< std::string > > m_truthSegLinks
List of truth segment links to fetch.
void paintSimHits(const EventContext &ctx, const xAOD::MuonSegment &truthSeg, Canvas_t &canvas, const int view) const
Paints the truth sim hits associated with the segment.
ElementLink< xAOD::MuonSegmentContainer > SegLink_t
ServiceHandle< IRootVisualizationService > m_visualSvc
Service handle of the visualization service.
const MuonR4::SpacePoint * drawHit(const SpacePointType &hit, Canvas_t &canvas, DynamicLegend &legend, const unsigned int view, unsigned int fillStyle) const
Converts a Hit into a particular TBox/ TEllipse for drawing.
virtual bool isLabeled(const MuonR4::SpacePoint &hit) const override final
Fetches all labeled (e.g.
Gaudi::Property< bool > m_saveSummaryPDF
If set to true a summary Canvas is created.
void writeChi2(const MuonR4::SegmentFit::Parameters &pars, const std::vector< SpacePointType > &hits, Canvas_t &canvas, const double legX=0.2, double startLegY=0.8, const double endLegY=0.3) const
Writes the chi2 of the hits onto the Canvas.
const MuonGMR4::MuonDetectorManager * m_detMgr
pointer to the Detector manager
Gaudi::Property< bool > m_paintTruthHits
Switch to visualize the truth hits.
std::atomic< bool > m_plotsDone
Flag toggling whether all Canvases have been exhausted.
int gasGap(const Identifier &id) const override
get the hashes
int doubletR(const Identifier &id) const
int doubletZ(const Identifier &id) const
Property holding a SG store/key/clid from which a ReadHandle is made.
int gasGap(const Identifier &id) const override
get the hashes
int multilayer(const Identifier &id) const
int gasGap(const Identifier &id) const override
get the hashes
double chi2(TH1 *h0, TH1 *h1)
@ Mdt
MuonSpectrometer.
Eigen::Matrix< double, 3, 1 > Vector3D
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.
double houghTanBeta(const Amg::Vector3D &v)
Returns the hough tanBeta [y] / [z].
std::unordered_set< const xAOD::MuonSimHit * > getMatchingSimHits(const xAOD::MuonSegment &segment)
: Returns all sim hits matched to a xAOD::MuonSegment
MuonValR4::IPatternVisualizationTool::PrimitiveVec PrimitiveVec
Acts::HoughTransformUtils::HoughPlane< HoughHitType > HoughPlane
double houghTanAlpha(const Amg::Vector3D &v)
: Returns the hough tanAlpha [x] / [z]
Lightweight algorithm to read xAOD MDT sim hits and (fast-digitised) drift circles from SG and fill a...
constexpr int objViewEta
ObjectView.
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
constexpr int objViewPhi
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.
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
UncalibratedMeasurement_v1 UncalibratedMeasurement
Define the version of the uncalibrated measurement class.
MuonSimHit_v1 MuonSimHit
Defined the version of the MuonSimHit.
Definition MuonSimHit.h:12
TgcStrip_v1 TgcStrip
Definition TgcStripFwd.h:9
RpcMeasurement_v1 RpcMeasurement
MMCluster_v1 MMCluster
sTgcMeasurement_v1 sTgcMeasurement
MuonSegment_v1 MuonSegment
Reference the current persistent version: