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"
43 constexpr int truthColor = kOrange +2;
44 constexpr int parLineColor = kRed;
45 using SpacePointSet = std::unordered_set<const MuonR4::SpacePoint*>;
48using namespace Acts::UnitLiterals;
51 using namespace MuonR4;
69 ATH_MSG_INFO(
"Hits linked to the following segment decorations are considered as truth");
72 if (decorName.empty()) {
74 return StatusCode::FAILURE;
87 return StatusCode::SUCCESS;
96 return !decor(hit).empty();
101 std::vector<const xAOD::UncalibratedMeasurement*> measurements{};
102 measurements.reserve(2* hits.size());
104 measurements.push_back(
hit->primaryMeasurement());
105 if(
hit->secondaryMeasurement()) {
106 measurements.push_back(
hit->secondaryMeasurement());
116 truthSegs.insert(*link);
124 const Acts::HoughTransformUtils::HoughAxisRanges& axisRanges,
125 const MaximumVec& maxima,
126 const std::string& extraLabel)
const {
132 const Acts::HoughTransformUtils::HoughAxisRanges& axisRanges,
133 const MaximumVec& maxima,
134 const std::string& extraLabel,
144 if (accumulator.getNonEmptyBins().empty()) {
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);
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));
164 ATH_MSG_VERBOSE(
"visualizeAccumulator skipped: no truth segments found and displayOnlyTruth=true");
175 const double maxBins = std::max(accumulator.nBinsX(), accumulator.nBinsY());
176 double markerTextSize = 0.035;
178 markerTextSize *= 25. / std::max(25., maxBins);
180 markerTextSize = std::clamp(markerTextSize, 0.006, 0.035);
181 accHisto->SetMarkerSize(markerTextSize);
182 accHisto->SetMarkerColor(kBlack);
183 accHisto->SetMinimum(0.);
185 canvas->expandPad(axisRanges.xMin, axisRanges.yMin);
186 canvas->expandPad(axisRanges.xMax, axisRanges.yMax);
187 canvas->setAxisTitles(std::format(
"tan#{}",
m_accumlIsEta ?
"beta" :
"#alpha"),
189 canvas->add(std::move(accHisto),
"HIST SAME");
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();
200 std::string binLabel = std::format(
"{:0}",
int(accumulator.nHits(
bin)));
202 auto binTxt =
drawLabel(binLabel, xCenter, yCenter, binLabelPx,
false, kBlack);
203 binTxt->SetTextAlign(22);
204 canvas->add(std::move(binTxt));
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: {:}",
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));
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;
233 maxBox->SetLineStyle(kDashed);
234 maxBox->SetLineWidth(2);
235 canvas->add(std::move(maxBox));
238 canvas->add(std::move(primitives));
243 const int view)
const {
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));
266 const std::string& extraLabel)
const {
272 const std::string& extraLabel,
275 ATH_MSG_VERBOSE(
"Visualizing seed with " << seed.getHitsInMax().size() <<
" hits");
278 ATH_MSG_VERBOSE(
"visualizeSeed skipped: canvas quota already exhausted for " << extraLabel);
283 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);
471 canvas->add(std::move(segmentline));
474 bool drawnTrueLabel{
false};
476 auto truthLine =
drawLine(
localSegmentPars(*segment), canvas->corner(Edges::yLow), canvas->corner(Edges::yHigh), truthColor, kDotted, view);
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(),
482 if (!drawnTrueLabel) {
483 canvas->add(
drawLabel(std::format(
"true parameters: {:}, d_{{0}}={:.2f}, z_{{0}}={:.2f}",
485 std::abs(bsExtp.z()) ) , 0.1, 0.05));
486 drawnTrueLabel =
true;
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);
497 canvas->add(
drawLabel(legendLabel, 0.2, 0.96));
500 if (!legend.empty()) {
501 canvas->add(legend.release(),
"same");
506 template<
class SpacePo
intType>
509 const unsigned int view,
510 unsigned int fillStyle)
const {
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());
526 constexpr int invalidCalibFill = 3305;
527 if constexpr (std::is_same_v<SpacePointType, SpacePoint>) {
532 if (dc && dc->status() != Muon::MdtDriftCircleStatus::MdtStatusDriftTime) {
533 fillStyle = invalidCalibFill;
536 }
else if constexpr(std::is_same_v<SpacePointType, CalibratedSpacePoint>) {
538 underlyingSp =
hit.spacePoint();
539 if (
hit.fitState() == CalibratedSpacePoint::State::Valid) {
541 }
else if (
hit.fitState() == CalibratedSpacePoint::State::FailedCalib) {
542 fillStyle = invalidCalibFill;
562 auto labeledColor = (secondaryMeas && !
isLabeled(*secondaryMeas)) ? kOrange - 3 : truthColor;
564 const auto covarianceWidth = [&]() ->
double {
565 const double variance = std::max(0., underlyingSp->
covariance()[view]);
567 return std::max(5. * Gaudi::Units::mm, std::sqrt(variance));
570 const auto addLabeledOutline = [&](
const double boxWidth,
const double boxHeight) {
577 outline->SetLineColor(labeledColor);
578 TObject* p_outline = outline.get();
579 canvas.add(std::move(outline),
"l");
584 const auto addHitLegendByFill = [&](TObject* object,
586 const char* bucketLabel,
588 const char* onObjectLabel,
const char* option =
"f") {
595 legend.addOnce(onObjectItem,
object, onObjectLabel, option);
600 legend.addOnce(bucketItem,
object, bucketLabel, option);
608 TObject* p_driftCircle = driftCircle.get();
609 canvas.add(std::move(driftCircle));
612 addHitLegendByFill(p_driftCircle,
616 "MDT onObject",
"f");
621 TObject* p_labeledDriftCircle = labeledDriftCircle.get();
622 canvas.add(std::move(labeledDriftCircle));
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,
638 addLabeledOutline(boxWidth, 0.5*meas->readoutElement()->gasGapPitch());
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,
652 addLabeledOutline(boxWidth, 0.5*meas->readoutElement()->gasGapPitch());
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));
661 addHitLegendByFill(p_mmBox,
666 addLabeledOutline(boxWidth, boxHeight);
671 const double boxWidth = covarianceWidth();
672 const double boxHeight = 10.*Gaudi::Units::mm;
673 auto stgcBox =
drawBox(
hit.localPosition(), boxWidth, boxHeight, kTeal, fillStyle, view);
680 if (primary && primary->channelType() == xAOD::sTgcMeasurement::sTgcChannelTypes::Pad) {
681 stgcBox->SetFillColorAlpha(kTeal, 0.1);
684 TObject* p_stgcBox = stgcBox.get();
686 canvas.add(std::move(stgcBox));
688 addHitLegendByFill(p_stgcBox,
694 addHitLegendByFill(p_stgcBox,
700 addLabeledOutline(boxWidth, boxHeight);
703 ATH_MSG_WARNING(
"Please implement proper drawings of the new small wheel.. "<<__FILE__<<
":"<<__LINE__);
710 template<
class SpacePo
intType>
712 const std::vector<SpacePointType>& hitsToDraw,
714 unsigned int view)
const {
716 SpacePointSet drawnPoints{};
718 for (
const SpacePointType&
hit : hitsToDraw) {
722 for (
const SpacePointBucket::value_type&
hit : bucket) {
724 if (drawnPoints.count(
hit.get())) {
731 return drawnPoints.size() - drawnPoints.count(
nullptr) > 0;
733 template<
class SpacePo
intType>
735 const std::vector<SpacePointType>& hits,
737 const double legX,
double startLegY,
738 const double endLegY)
const {
739 const auto [pos, dir] =
makeLine(pars);
741 unsigned int nHits = 0;
742 for (
const SpacePointType&
hit : hits) {
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);
755 std::string legendstream{};
756 switch(
hit->type()) {
758 const int driftSign{SeedingAux::strawSign(pos, dir, *
hit)};
760 legendstream = std::format(
"ML: {:1d}, TL: {:1d}, T: {:3d}, {:}",
762 idHelper.
tube(hitId), driftSign == -1 ?
"L" :
"R");
766 legendstream= std::format(
"DR: {:1d}, DZ: {:1d}, GAP: {:1d}, #eta/#phi: {:}/{:}",
768 hit->measuresEta() ?
"si" :
"nay",
hit->measuresPhi() ?
"si" :
"nay");
772 legendstream = std::format(
"ST: {:}, GAP: {:1d}, #eta/#phi: {:}/{:}",
774 hit->measuresEta() ?
"si" :
"nay",
hit->measuresPhi() ?
"si" :
"nay");
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),
785 legendstream = std::format(
"ML: {:1d}, GAP: {:1d}, #eta/#phi: {:}/{:}",
787 hit->measuresEta() ?
"si" :
"nay",
hit->measuresPhi() ?
"si" :
"nay");
790 legendstream =
"Ext. constaint";
797 const double chi2 = SeedingAux::chi2Term(pos, dir,*
hit);
798 legendstream+=std::format(
", #chi^{{2}}: {:.2f}",
chi2);
800 legendstream+=
", NotValidState";
806 canvas.add(
drawLabel(legendstream, legX, startLegY, 8));
808 if (startLegY<= endLegY) {
#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,...)
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.
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
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::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: