21#include "Acts/Utilities/Helpers.hpp"
22#include "Acts/Surfaces/RectangleBounds.hpp"
23#include "Acts/Surfaces/TrapezoidBounds.hpp"
24#include "Acts/Surfaces/PlaneSurface.hpp"
25#include "Acts/Surfaces/StrawSurface.hpp"
26#include "Acts/Visualization/GeometryView3D.hpp"
41 constexpr int truthColor = kOrange +2;
42 constexpr int parLineColor = kRed;
43 using SpacePointSet = std::unordered_set<const MuonR4::SpacePoint*>;
48 using namespace MuonR4;
66 ATH_MSG_INFO(
"Hits linked to the following segment decorations are considered as truth");
69 if (decorName.empty()) {
71 return StatusCode::FAILURE;
84 return StatusCode::SUCCESS;
93 return !decor(hit).empty();
98 std::vector<const xAOD::UncalibratedMeasurement*> measurements{};
99 measurements.reserve(2* hits.size());
101 measurements.push_back(
hit->primaryMeasurement());
102 if(
hit->secondaryMeasurement()) {
103 measurements.push_back(
hit->secondaryMeasurement());
113 truthSegs.insert(*link);
121 const Acts::HoughTransformUtils::HoughAxisRanges& axisRanges,
122 const MaximumVec& maxima,
123 const std::string& extraLabel)
const {
129 const Acts::HoughTransformUtils::HoughAxisRanges& axisRanges,
130 const MaximumVec& maxima,
131 const std::string& extraLabel,
141 if (accumulator.getNonEmptyBins().empty()) {
146 auto accHisto = std::make_unique<TH2F>(
"AccumulatorHisto",
"histo",
147 accumulator.nBinsX(), axisRanges.xMin, axisRanges.xMax,
148 accumulator.nBinsY(), axisRanges.yMin, axisRanges.yMax);
149 accHisto->SetDirectory(
nullptr);
151 std::vector<const SpacePoint*> spacePointsInAcc{};
152 for (
const std::size_t
bin : accumulator.getNonEmptyBins()) {
153 const auto [xBin, yBin] = accumulator.axisBins(
bin);
154 auto hitIds = accumulator.hitIds(xBin, yBin);
155 spacePointsInAcc.insert(spacePointsInAcc.end(),hitIds.begin(), hitIds.end());
156 accHisto->SetBinContent(xBin+1, yBin+1, accumulator.nHits(
bin));
161 ATH_MSG_VERBOSE(
"visualizeAccumulator skipped: no truth segments found and displayOnlyTruth=true");
172 const double maxBins = std::max(accumulator.nBinsX(), accumulator.nBinsY());
173 double markerTextSize = 0.035;
175 markerTextSize *= 25. / std::max(25., maxBins);
177 markerTextSize = std::clamp(markerTextSize, 0.006, 0.035);
178 accHisto->SetMarkerSize(markerTextSize);
179 accHisto->SetMarkerColor(kBlack);
180 accHisto->SetMinimum(0.);
182 canvas->expandPad(axisRanges.xMin, axisRanges.yMin);
183 canvas->expandPad(axisRanges.xMax, axisRanges.yMax);
184 canvas->setAxisTitles(std::format(
"tan#{}",
m_accumlIsEta ?
"beta" :
"#alpha"),
186 canvas->add(std::move(accHisto),
"HIST SAME");
190 const double binLabelPx = std::clamp(1.2 * 500. / maxBins, 7.0, 18.0);
191 for (
const std::size_t
bin : accumulator.getNonEmptyBins()) {
192 const auto [xBin, yBin] = accumulator.axisBins(
bin);
193 const double xCenter = axisRanges.xMin + (xBin + 0.5) * (axisRanges.xMax - axisRanges.xMin) / accumulator.nBinsX();
194 const double yCenter = axisRanges.yMin + (yBin + 0.5) * (axisRanges.yMax - axisRanges.yMin) / accumulator.nBinsY();
197 std::string binLabel = std::format(
"{:0}",
int(accumulator.nHits(
bin)));
199 auto binTxt =
drawLabel(binLabel, xCenter, yCenter, binLabelPx,
false, kBlack);
200 binTxt->SetTextAlign(22);
201 canvas->add(std::move(binTxt));
209 auto truthMarker = std::make_unique<TMarker>(tan, icept, kFullCrossX);
210 truthMarker->SetMarkerColor(truthColor);
211 truthMarker->SetMarkerSize(4);
212 canvas->add(std::move(truthMarker));
213 canvas->add(
drawLabel(std::format(
"true parameters: {:}",
217 for (
const auto& maximum : maxima) {
218 auto maxMarker = std::make_unique<TMarker>(maximum.x, maximum.y, kFullTriangleUp);
219 maxMarker->SetMarkerColor(parLineColor);
220 maxMarker->SetMarkerSize(4);
221 canvas->add(std::move(maxMarker));
224 const double xMin = maximum.x - maximum.wx;
225 const double xMax = maximum.x + maximum.wx;
226 const double yMin = maximum.y - maximum.wy;
227 const double yMax = maximum.y + maximum.wy;
230 maxBox->SetLineStyle(kDashed);
231 maxBox->SetLineWidth(2);
232 canvas->add(std::move(maxBox));
235 canvas->add(std::move(primitives));
240 const int view)
const {
252 re->measurementHash(simHit->identify()) :
253 re->layerHash(simHit->identify());
255 re->localToGlobalTransform(*geoCtx, hash);
256 const Amg::Vector3D locPos = trf * xAOD::toEigen(simHit->localPosition());
257 const Amg::Vector3D locDir = trf.linear() * xAOD::toEigen(simHit->localDirection());
258 canvas.add(
drawArrow(locPos, locDir, truthColor, kDashed, view));
263 const std::string& extraLabel)
const {
269 const std::string& extraLabel,
272 ATH_MSG_VERBOSE(
"Visualizing seed with " << seed.getHitsInMax().size() <<
" hits");
275 ATH_MSG_VERBOSE(
"visualizeSeed skipped: canvas quota already exhausted for " << extraLabel);
280 ATH_MSG_VERBOSE(
"visualizeSeed skipped: no truth segments found and displayOnlyTruth=true");
292 std::string_view viewName = view ==
objViewEta ?
"eta" :
"phi";
302 canvas->add(
clone(primitives));
304 canvas->setAxisTitles(std::format(
"{:} [mm]", view ==
objViewEta ?
'y' :
'x'),
"z [mm]");
306 if (!
drawHits(*seed.parentBucket(), seed.getHitsInMax(), *canvas, legend, view)) {
311 canvas->corner(Edges::yLow), canvas->corner(Edges::yHigh),
312 truthColor, kDotted, view));
315 canvas->add(
drawLine(seed.parameters(), canvas->corner(Edges::yLow),
316 canvas->corner(Edges::yHigh), parLineColor, kDashed, view));
318 writeChi2(seed.parameters(), seed.getHitsInMax(), *canvas);
320 std::string legendLabel = std::format(
"Event: {:}, chamber : {:}, #{:}-view ({:})",
321 ctx.eventID().event_number(),
322 m_idHelperSvc->toStringChamber(seed.getHitsInMax().front()->identify()),
325 canvas->add(
drawLabel(legendLabel, 0.1, 0.96));
326 canvas->add(
drawLabel(
"Seed parameters: " +
makeLabel(seed.parameters()),0.25, 0.89));
332 const std::string& extraLabel)
const {
338 const std::string& extraLabel,
348 ATH_MSG_VERBOSE(
"visualizeBucket skipped: no truth segments found and displayOnlyTruth=true");
358 const std::string_view viewName = view ==
objViewEta ?
"eta" :
"phi";
370 canvas->add(
clone(primitives));
373 if (!
drawHits(bucket, bucket, *canvas, legend, view)) {
377 bool drawnTrueLabel{
false};
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) );
385 if (!drawnTrueLabel) {
387 drawnTrueLabel =
true;
392 std::string legendLabel = std::format(
"Event: {:}, chamber : {:}, #{:}-view ({:})",
393 ctx.eventID().event_number(),
397 canvas->add(
drawLabel(legendLabel, 0.15, 0.96));
399 canvas->setAxisTitles(std::format(
"{:} [mm]", view ==
objViewEta ?
'y' :
'x'),
"z [mm]");
401 if (!legend.empty()) {
402 canvas->add(legend.release(),
"same");
410 const std::string& extraLabel)
const {
417 const std::string& extraLabel,
444 const std::string_view viewName = view ==
objViewEta ?
"eta" :
"phi";
451 canvas->setAxisTitles(std::format(
"{:} [mm]", view ==
objViewEta ?
'y' :
'x'),
"z [mm]");
452 canvas->add(
clone(primitives));
459 *canvas, legend, view)) {
469 auto segmentline =
drawLine(segPars, canvas->corner(Edges::yLow), canvas->corner(Edges::yHigh), parLineColor, kDashed, view);
470 TLine *line =
static_cast<TLine*
>(segmentline.get());
471 canvas->add(std::move(segmentline));
476 if(!tru_segment)
continue;
478 auto truthLine =
drawLine(
localSegmentPars(*tru_segment), canvas->corner(Edges::yLow), canvas->corner(Edges::yHigh), truthColor, kDotted, view);
479 TLine* line =
static_cast<TLine*
>(truthLine.get());
480 canvas->add( std::move(truthLine) );
486 std::string legendLabel=std::format(
"Event: {:}, chamber: {:}, #chi^{{2}} / nDoF: {:.2f} ({:d}), #{:}-view (:)",
487 ctx.eventID().event_number(),
m_idHelperSvc->toStringChamber(canvasId),
488 segment.
chi2() /std::max(1u, segment.
nDoF()), segment.
nDoF(),
489 view ==
objViewEta ?
"eta" :
"phi", extraLabel);
491 canvas->add(
drawLabel(legendLabel, 0.2, 0.96));
494 if (!legend.empty()) {
495 canvas->add(legend.release(),
"same");
500 template<
class SpacePo
intType>
503 const unsigned int view,
504 unsigned int fillStyle)
const {
512 canvas.expandPad(
hit.localPosition()[view] -
hit.driftRadius(),
513 hit.localPosition().z() -
hit.driftRadius());
514 canvas.expandPad(
hit.localPosition()[view] +
hit.driftRadius(),
515 hit.localPosition().z() +
hit.driftRadius());
520 constexpr int invalidCalibFill = 3305;
521 if constexpr (std::is_same_v<SpacePointType, SpacePoint>) {
526 if (dc && dc->status() != Muon::MdtDriftCircleStatus::MdtStatusDriftTime) {
527 fillStyle = invalidCalibFill;
530 }
else if constexpr(std::is_same_v<SpacePointType, CalibratedSpacePoint>) {
532 underlyingSp =
hit.spacePoint();
533 if (
hit.fitState() == CalibratedSpacePoint::State::Valid) {
535 }
else if (
hit.fitState() == CalibratedSpacePoint::State::FailedCalib) {
536 fillStyle = invalidCalibFill;
556 auto labeledColor = (secondaryMeas && !
isLabeled(*secondaryMeas)) ? kOrange - 3 : truthColor;
558 const auto covarianceWidth = [&]() ->
double {
559 const double variance = std::max(0., underlyingSp->
covariance()[view]);
561 return std::max(5. * Gaudi::Units::mm, std::sqrt(variance));
564 const auto addLabeledOutline = [&](
const double boxWidth,
const double boxHeight) {
571 outline->SetLineColor(labeledColor);
572 TObject* p_outline = outline.get();
573 canvas.add(std::move(outline),
"l");
578 const auto addHitLegendByFill = [&](TObject* object,
580 const char* bucketLabel,
582 const char* onObjectLabel,
const char* option =
"f") {
589 legend.addOnce(onObjectItem,
object, onObjectLabel, option);
594 legend.addOnce(bucketItem,
object, bucketLabel, option);
602 TObject* p_driftCircle = driftCircle.get();
603 canvas.add(std::move(driftCircle));
606 addHitLegendByFill(p_driftCircle,
610 "MDT onObject",
"f");
615 TObject* p_labeledDriftCircle = labeledDriftCircle.get();
616 canvas.add(std::move(labeledDriftCircle));
622 const double boxWidth = 0.5*std::sqrt(12)*std::sqrt(underlyingSp->
covariance()[view]);
623 auto rpcBox =
drawBox(
hit.localPosition(), boxWidth, 0.5*meas->readoutElement()->gasGapPitch(),
624 kGreen + 2, fillStyle);
625 TObject* p_rpcBox = rpcBox.get();
626 canvas.add(std::move(rpcBox));
627 addHitLegendByFill(p_rpcBox,
632 addLabeledOutline(boxWidth, 0.5*meas->readoutElement()->gasGapPitch());
635 const auto* meas{
static_cast<const xAOD::TgcStrip*
>(primaryMeas)};
636 const double boxWidth = 0.5*std::sqrt(12)*std::sqrt(underlyingSp->
covariance()[view]);
637 auto tgcBox =
drawBox(
hit.localPosition(), boxWidth, 0.5*meas->readoutElement()->gasGapPitch(),
638 kCyan + 2, fillStyle);
639 TObject* p_tgcBox = tgcBox.get();
640 canvas.add(std::move(tgcBox));
641 addHitLegendByFill(p_tgcBox,
646 addLabeledOutline(boxWidth, 0.5*meas->readoutElement()->gasGapPitch());
649 const double boxWidth = covarianceWidth();
650 constexpr double boxHeight = 10.*Gaudi::Units::mm;
651 auto mmBox =
drawBox(
hit.localPosition(), boxWidth, boxHeight, kAquamarine, fillStyle, view);
652 TObject* p_mmBox = mmBox.get();
653 canvas.add(std::move(mmBox));
655 addHitLegendByFill(p_mmBox,
660 addLabeledOutline(boxWidth, boxHeight);
665 const double boxWidth = covarianceWidth();
666 const double boxHeight = 10.*Gaudi::Units::mm;
667 auto stgcBox =
drawBox(
hit.localPosition(), boxWidth, boxHeight, kTeal, fillStyle, view);
674 if (primary && primary->channelType() == xAOD::sTgcMeasurement::sTgcChannelTypes::Pad) {
675 stgcBox->SetFillColorAlpha(kTeal, 0.1);
678 TObject* p_stgcBox = stgcBox.get();
680 canvas.add(std::move(stgcBox));
682 addHitLegendByFill(p_stgcBox,
688 addHitLegendByFill(p_stgcBox,
694 addLabeledOutline(boxWidth, boxHeight);
697 ATH_MSG_WARNING(
"Please implement proper drawings of the new small wheel.. "<<__FILE__<<
":"<<__LINE__);
704 template<
class SpacePo
intType>
706 const std::vector<SpacePointType>& hitsToDraw,
708 unsigned int view)
const {
710 SpacePointSet drawnPoints{};
712 for (
const SpacePointType&
hit : hitsToDraw) {
716 for (
const SpacePointBucket::value_type&
hit : bucket) {
718 if (drawnPoints.count(
hit.get())) {
725 return drawnPoints.size() - drawnPoints.count(
nullptr) > 0;
727 template<
class SpacePo
intType>
729 const std::vector<SpacePointType>& hits,
731 const double legX,
double startLegY,
732 const double endLegY)
const {
733 const auto [pos, dir] =
makeLine(pars);
735 unsigned int nHits = 0;
736 for (
const SpacePointType&
hit : hits) {
738 bool displayChi2{
true};
739 if constexpr(std::is_same_v<SpacePointType, Segment::MeasType>) {
740 underlyingSp =
hit->spacePoint();
741 displayChi2 = (
hit->fitState() == CalibratedSpacePoint::State::Valid);
749 std::string legendstream{};
750 switch(
hit->type()) {
752 const int driftSign{SeedingAux::strawSign(pos, dir, *
hit)};
754 legendstream = std::format(
"ML: {:1d}, TL: {:1d}, T: {:3d}, {:}",
756 idHelper.
tube(hitId), driftSign == -1 ?
"L" :
"R");
760 legendstream= std::format(
"DR: {:1d}, DZ: {:1d}, GAP: {:1d}, #eta/#phi: {:}/{:}",
762 hit->measuresEta() ?
"si" :
"nay",
hit->measuresPhi() ?
"si" :
"nay");
766 legendstream = std::format(
"ST: {:}, GAP: {:1d}, #eta/#phi: {:}/{:}",
768 hit->measuresEta() ?
"si" :
"nay",
hit->measuresPhi() ?
"si" :
"nay");
773 const MuonGMR4::StripDesign& design = clus->readoutElement()->stripLayer(clus->layerHash()).design();
774 legendstream = std::format(
"ML: {:1d}, GAP: {:1d}, {:}", idHelper.
multilayer(hitId), idHelper.
gasGap(hitId),
779 legendstream = std::format(
"ML: {:1d}, GAP: {:1d}, #eta/#phi: {:}/{:}",
781 hit->measuresEta() ?
"si" :
"nay",
hit->measuresPhi() ?
"si" :
"nay");
784 legendstream =
"Ext. constaint";
791 const double chi2 = SeedingAux::chi2Term(pos, dir,*
hit);
792 legendstream+=std::format(
", #chi^{{2}}: {:.2f}",
chi2);
794 legendstream+=
", NotValidState";
800 canvas.add(
drawLabel(legendstream, legX, startLegY, 8));
802 if (startLegY<= endLegY) {
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
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.
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.
double chi2() const
Returns the chi2 of the segment fit.
: 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
const xAOD::MuonMeasurement * secondaryMeasurement() const
const xAOD::MuonMeasurement * primaryMeasurement() const
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)
Eigen::Affine3d Transform3D
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 ¢er, const double radius, const int color=kViolet, const int fillStyle=hollowFilling)
Create a TEllipse for drawing a drift circle.
@ StgcStripWireHitOnObject
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.
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
MdtDriftCircle_v1 MdtDriftCircle
UncalibratedMeasurement_v1 UncalibratedMeasurement
Define the version of the uncalibrated measurement class.
MuonSimHit_v1 MuonSimHit
Defined the version of the MuonSimHit.
RpcMeasurement_v1 RpcMeasurement
sTgcMeasurement_v1 sTgcMeasurement
MuonSegment_v1 MuonSegment
Reference the current persistent version: