ATLAS Offline Software
Loading...
Searching...
No Matches
TrackVisualizationTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
5
12
13
14#include <filesystem>
15#include <format>
16
17#include "TMarker.h"
18#include "TROOT.h"
19#include "TStyle.h"
20#include "TLegend.h"
21#include "TH1F.h"
22
23namespace {
24 using namespace MuonR4;
25 using PrimitivesVec_t = MuonValR4::TrackVisualizationTool::PrimitivesVec_t;
26 constexpr int truthColor = kOrange +2;
27
28 constexpr int ColorBarrel = kRed;
29 constexpr int ColorEndcapA = kBlue;
30 constexpr int ColorEndcapC = kGreen +2;
31 constexpr double inM = 1./ Gaudi::Units::m;
32
33 constexpr double extraMargin = 50.*Gaudi::Units::cm * inM;
34
35 static const Muon::MuonSectorMapping sectorMap{};
36
37
38 std::unique_ptr<TMarker> drawMarker(const Amg::Vector2D& pos, const int mStyle, const int mColor, const int mSize = 2) {
39 auto marker = std::make_unique<TMarker>(pos.x(), pos.y(), mStyle);
40 marker->SetMarkerColor(mColor);
41 marker->SetMarkerSize(mSize);
42 return marker;
43 }
44
45 inline int stationMarkerSyle(const Muon::MuonStationIndex::ChIndex ch,
46 const bool openMarker, const bool onSeed) {
49 case Inner:
50 case BarrelExtended:
51 case Extended:
52 return onSeed ? (openMarker ? kOpenTriangleUp : kFullTriangleUp)
53 : (openMarker ? kOpenTriangleDown : kFullTriangleDown);
54 case Middle:
55 return onSeed ? (openMarker ? kOpenCrossX : kFullCrossX)
56 : (openMarker ? kOpenCross : kFullCross);
57 case Outer:
58 return onSeed ? (openMarker ? kOpenFourTrianglesX: kFullFourTrianglesX)
59 : (openMarker ? kOpenThreeTriangles : kFullThreeTriangles);
60 default:
61 return 0;
62 }
63 }
64}
65
66namespace MuonValR4{
67
68 void TrackVisualizationTool::PlotLegend::addColor(const int color, const std::string& label){
69 if (colors.find(color) != colors.end()) {
70 return;
71 }
72 auto box = MuonValR4::drawBox(-1.5,-1.5,-1.,-1., color, MuonValR4::fullFilling);
73 legend->AddEntry(box.get(), label.c_str(), "F");
74 colors.insert(std::make_pair(color, std::move(box)));
75 }
76 void TrackVisualizationTool::PlotLegend::addMarker(const int marker, const std::string& label){
77 if (markers.find(marker)!= markers.end()) {
78 return;
79 }
80 auto tMarker = drawMarker(Amg::Vector2D{2.*Gaudi::Units::km, 0.}, marker, kBlack);
81 legend->AddEntry(tMarker.get(), label.c_str(), "P");
82 markers.insert(std::make_pair(marker, std::move(tMarker)));
83 }
85 legend->SetBorderSize(0);
86 legend->SetNColumns(4);
87 canvas.add(std::move(legend));
88 for (auto&[i, obj] : colors){
89 canvas.add(std::move(obj));
90 }
91 for (auto&[i, obj]: markers) {
92 canvas.add(std::move(obj));
93 }
94 }
96 const Amg::Vector2D& posOnCylinder,
97 const DisplayView view) {
98 using enum DisplayView;
99 if (view == RZ) {
100 return Amg::Vector2D{ posOnCylinder[1]*inM, posOnCylinder[0]*inM};
101 }
102 const CxxUtils::sincos phi{phiV};
103 return posOnCylinder[0] * inM * Amg::Vector2D{phi.cs, phi.sn};
104 }
106 if (m_canvasLimit > 0) {
107 m_clientToken.canvasLimit = m_canvasLimit;
108 m_clientToken.preFixName = m_canvasPrefix;
109 m_clientToken.saveSinglePlots = m_saveSinglePDFs;
110 m_clientToken.saveSummaryPlot = m_saveSummaryPDF;
111 m_clientToken.subDirectory = m_subDir;
112 ATH_CHECK(m_visualSvc.retrieve());
113 ATH_CHECK(m_visualSvc->registerClient(m_clientToken));
114 } else {
115 m_plotsDone = true;
116 }
118 ATH_CHECK(m_geoCtxKey.initialize());
119 ATH_CHECK(m_extrapolationTool.retrieve(EnableTool{!m_extrapolationTool.empty()}));
120 return StatusCode::SUCCESS;
121 }
122 void TrackVisualizationTool::displaySeeds(const EventContext& ctx,
123 const MsTrackSeeder& seederObj,
124 const xAOD::MuonSegmentContainer& segments,
125 const MsTrackSeedContainer& seeds) const {
126 displaySeeds(ctx, seederObj, segments, seeds, PrimitivesVec_t{});
127 }
128 void TrackVisualizationTool::displaySeeds(const EventContext& ctx,
129 const MsTrackSeeder& seederObj,
130 const xAOD::MuonSegmentContainer& segments,
131 const MsTrackSeedContainer& seeds,
132 PrimitivesVec_t && extPrimitives) const {
133 if (m_plotsDone || segments.empty()) {
134 return;
135 }
136 displaySeeds(ctx, seederObj, DisplayView::RZ, segments, seeds, clone(extPrimitives));
137 displaySeeds(ctx, seederObj, DisplayView::XY, segments, seeds, std::move(extPrimitives));
138
139 }
140 void TrackVisualizationTool::displaySeeds(const EventContext& ctx,
141 const MsTrackSeeder& seeder,
142 const DisplayView view,
143 const xAOD::MuonSegmentContainer& segments,
144 const MsTrackSeedContainer& seeds,
145 PrimitivesVec_t&& extPrimitives) const{
146
147 auto canvas = m_visualSvc->prepareCanvas(ctx, m_clientToken, std::format("SeedDisplay{:}",
148 view == DisplayView::XY ? "XY" : "RZ" ));
149
150 if (!canvas) {
151 m_plotsDone = true;
152 return;
153 }
154 canvas->setAxisTitles(view == DisplayView::XY ? "x [m]" : "z [m]",
155 view == DisplayView::XY ? "y [m]" : "R [m]");
156
157 PlotLegend legend{0.005,0.005, 0.6,0.1};
159 fillTruthSeedPoints(ctx, seeder, view, legend, *canvas);
160
161 auto onSeed = [&seeds](const xAOD::MuonSegment* segment,
162 const Location loc) {
163 return std::ranges::any_of(seeds,[segment, loc](const MsTrackSeed& seed){
164 return seed.location() == loc && std::ranges::find(seed.segments(), segment) != seed.segments().end();
165 });
166 };
167
168 const ActsTrk::GeometryContext* gctx{nullptr};
169 if (!SG::get(gctx, m_geoCtxKey, ctx).isSuccess()) {
170 THROW_EXCEPTION("Failed to fetch the geometry context "<<m_geoCtxKey.fullKey());
171 }
172 bool drawnPoint{false};
173
174 for (const xAOD::MuonSegment* segment: segments) {
175 using enum Location;
177 using namespace Muon;
178 const MuonGMR4::SpectrometerSector* msSector = detailedSegment(*segment)->msSector();
179 const auto chIdx = segment->chamberIndex();
180 const int mColor = msSector->barrel() ? ColorBarrel : (msSector->side() > 0 ? ColorEndcapA : ColorEndcapC);
181
182 for (const auto secProj : {leftOverlap, center, rightOverlap}) {
183 if (!sectorMap.insideSector(segment->sector() + Acts::toUnderlying(secProj),
184 segment->position().phi())){
185 continue;
186 }
187
188 for (const Location loc : {Barrel, Endcap}) {
189 const Amg::Vector2D projPos{seeder.expressOnCylinder(*gctx, *segment, loc, secProj)};
190 if (!seeder.withinBounds(projPos, loc)) {
191 continue;
192 }
193 drawnPoint = true;
194 const bool isGood = onSeed(segment, loc);
195 const int mStyle = stationMarkerSyle(chIdx, false, isGood);
196 const double phi = seeder.projectedPhi(segment->sector(), secProj);
197 const Amg::Vector2D markerPos{viewVector(phi, projPos, view)};
198 extPrimitives.emplace_back(drawMarker(markerPos, mStyle, mColor));
199
200 if (view == DisplayView::XY) {
201 const double r = markerPos.mag() + extraMargin;
202 canvas->expandPad(r, r);
203 canvas->expandPad(-r, -r);
204 } else {
205 canvas->expandPad(markerPos[0] - extraMargin, markerPos[1] - extraMargin);
206 canvas->expandPad(markerPos[0] + extraMargin, markerPos[1] + extraMargin);
207 }
208 legend.addMarker(mStyle, std::format("{:}{:}", MuonStationIndex::layerName(MuonStationIndex::toLayerIndex(chIdx)),
209 isGood ? "" : " (discarded)"));
210 legend.addColor(mColor, msSector->barrel() ? "Barrel" : msSector->side() > 0 ? "Endcap A" : "Endcap C");
211 }
212 }
213 }
214 if (!drawnPoint) {
215 canvas->trash();
216 return;
217 }
218 for (const MsTrackSeed& seed : seeds) {
219 const Amg::Vector3D& pos{seed.position()};
220 canvas->add(drawMarker(viewVector(pos.phi(), Amg::Vector2D{pos.perp(), pos.z()}, view),
221 kFullDiamond, kBlack));
222 legend.addMarker(kFullDiamond, "track seed");
223 }
225 for (unsigned int s = 1; s<=16 ; ++s) {
226 if (view != DisplayView::XY) {
227 break;
228 }
229 const double phi = sectorMap.sectorPhi(s);
230 const double dPhi = sectorMap.sectorWidth(s);
231
232 const int lStyle = s%2 ? kDashed : kDotted;
233 const double r = canvas->corner(Edges::xHigh);
234 const CxxUtils::sincos phiM{phi-dPhi}, phiP{phi+dPhi};
235 const Amg::Vector2D e1{r * phiM.cs, r * phiM.sn};
236 const Amg::Vector2D e2{r * phiP.cs, r * phiP.sn};
237
238 auto theLine = std::make_unique<TLine>(0.,0., e1.x(), e1.y());
239 theLine->SetLineStyle(lStyle);
240 extPrimitives.insert(extPrimitives.begin(), std::move(theLine));
241 theLine = std::make_unique<TLine>(0.,0., e2.x(), e2.y());
242 theLine->SetLineStyle(lStyle);
243 extPrimitives.insert(extPrimitives.begin(), std::move(theLine));
244 theLine = std::make_unique<TLine>(e1.x(), e1.y(), e2.x(), e2.y());
245 theLine->SetLineStyle(lStyle);
246 extPrimitives.insert(extPrimitives.begin(), std::move(theLine));
247 }
248 legend.fillPrimitives(*canvas);
249 }
251 const MsTrackSeeder& seeder,
252 const DisplayView view,
253 PlotLegend& legend,
254 Canvas_t& canvas) const {
255 const xAOD::MuonSegmentContainer* truthSegs{nullptr};
256 if (!SG::get(truthSegs,m_truthSegKey, ctx).isSuccess()) {
257 THROW_EXCEPTION("Failed to fetch the truth segment container");
258 }
259 if (!truthSegs) {
260 return;
261 }
262 const ActsTrk::GeometryContext* gctx{nullptr};
263 if (!SG::get(gctx, m_geoCtxKey, ctx).isSuccess()) {
264 THROW_EXCEPTION("Failed to fetch the geometry context "<<m_geoCtxKey.fullKey());
265 }
266
267 bool addedEntry{false};
268 for (const xAOD::MuonSegment* segment: *truthSegs) {
269 const auto chIdx = segment->chamberIndex();
270 const int mStyle = stationMarkerSyle(chIdx, false, true);
271
272 using enum Location;
274 for (const auto secProj : {leftOverlap, center, rightOverlap}) {
275 if (!sectorMap.insideSector(segment->sector() + Acts::toUnderlying(secProj),
276 segment->position().phi())){
277 continue;
278 }
279 for (const Location loc : {Barrel, Endcap}) {
280 const Amg::Vector2D projected{seeder.expressOnCylinder(*gctx, *segment, loc, secProj)};
281 if (!seeder.withinBounds(projected, loc)) {
282 continue;
283 }
284 const double phi = MsTrackSeeder::projectedPhi(segment->sector(), secProj);
285 canvas.add(drawMarker(viewVector(phi, projected, view), mStyle, truthColor, 3));
287 addedEntry = true;
288 }
289 }
290 }
291 if (addedEntry) {
292 legend.addColor(truthColor, "truth");
293 }
294 }
296 const MuonR4::MsTrackSeed& seed,
297 const OptBoundPars_t& parsToExt,
298 const std::string& objName) const {
300 return;
301 }
302 const ActsTrk::GeometryContext* gctx{nullptr};
303 SG::get(gctx, m_geoCtxKey, ctx).ignore();
304
305 Acts::ObjVisualization3D visualHelper{};
306 const std::string subDir = std::format("./ObjDisplays/{:}/", m_subDir.value());
307 ensureDirectory(subDir);
308 if (parsToExt.ok() && m_extrapolationTool.isEnabled()) {
309 MuonValR4::drawPropagation(m_extrapolationTool->propagationSteps(ctx, *parsToExt).first,
310 visualHelper);
311 }
312 std::string segStr{removeNonAlphaNum(objName)};
313 for (const xAOD::MuonSegment* seg : seed.segments()) {
314 MuonValR4::drawSegmentMeasurements(*gctx,* seg, visualHelper);
315 MuonValR4::drawSegmentLine(*gctx,*seg, visualHelper);
316 segStr += std::format("_{:}", MuonR4::printID(*seg));
317 }
318
319 unsigned fileVersion{0};
320 std::string finalStr{};
321 while (finalStr.empty() || std::filesystem::exists(finalStr)) {
322 finalStr = std::format("{:}/{:}_{:}_{:}_{:}.obj", subDir,
323 m_clientToken.preFixName, ctx.eventID().event_number(), ++fileVersion, segStr);
324 }
325 visualHelper.write(finalStr);
326 ++m_objCounter;
327 }
328}
Scalar phi() const
phi method
#define ATH_CHECK
Evaluate an expression and check for errors.
bool empty() const noexcept
Returns true if the collection is empty.
A spectrometer sector forms the envelope of all chambers that are placed in the same MS sector & laye...
int8_t side() const
Returns the side of the MS-sector 1 -> A side ; -1 -> C side.
bool barrel() const
Returns whether the sector is placed in the barrel.
Helper class to group muon sgements that may belong to a muon trajectory.
bool withinBounds(const Amg::Vector2D &projPos, const Location loc) const
Returns whether the expression on the cylinder is within the surface bounds.
Amg::Vector2D expressOnCylinder(const ActsTrk::GeometryContext &gctx, const xAOD::MuonSegment &segment, const Location loc, const SectorProjector proj) const
Expresses the segment on the cylinder surface.
static double projectedPhi(const int sector, const SectorProjector proj)
Returns the projected phi for a given sector and projector.
SectorProjector
Enumeration to select the sector projection.
const MuonGMR4::SpectrometerSector * msSector() const
Returns the associated MS sector.
Gaudi::Property< unsigned > m_canvasLimit
Maximum canvases to draw.
virtual void displaySeeds(const EventContext &ctx, const MuonR4::MsTrackSeeder &seederObj, const xAOD::MuonSegmentContainer &segments, const MuonR4::MsTrackSeedContainer &seeds) const override final
Displays all segments on the representative cylinder in the R-Z & X-Y plane and draws the markers of ...
Gaudi::Property< std::string > m_canvasPrefix
Prefix of the individual canvas file names <MANDATORY>
ToolHandle< ActsTrk::IExtrapolationTool > m_extrapolationTool
Track extrapolation tool.
SG::ReadHandleKey< ActsTrk::GeometryContext > m_geoCtxKey
Dependency on the geometry alignment.
virtual StatusCode initialize() override final
std::atomic< unsigned > m_objCounter
How many obj have been produced.
ServiceHandle< IRootVisualizationService > m_visualSvc
Service handle of the visualization service.
std::atomic< bool > m_plotsDone
Flag toggling whether all Canvases have been exhausted.
virtual void displayTrackSeedObj(const EventContext &ctx, const MuonR4::MsTrackSeed &seed, const OptBoundPars_t &parsToExt, const std::string &objName="") const override final
Visualizes the measurements of the segments on the track seed together with their predicted local lin...
IRootVisualizationService::ClientToken m_clientToken
Token to present to the visualization service such that the display froms this tool are grouped toget...
IRootVisualizationService::ICanvasObject Canvas_t
static Amg::Vector2D viewVector(const double phi, const Amg::Vector2D &posOnCylinder, const DisplayView view)
Transforms the projected vector into the actual view, if it's xy then an external phi is needed to pl...
Gaudi::Property< bool > m_saveSinglePDFs
If set to true each canvas is saved into a dedicated pdf file.
Gaudi::Property< std::string > m_subDir
Define the subdirectory in which the plots shall be saved.
SG::ReadHandleKey< xAOD::MuonSegmentContainer > m_truthSegKey
Key to the truth segment selection to draw the segment parameters.
DisplayView
Enumeration to toggle whether the seeds shall be painted in x-y or R-z view.
Gaudi::Property< bool > m_saveSummaryPDF
If set to true a summary Canvas is created.
MuonR4::MsTrackSeed::Location Location
Enumeration to toggle whether the segment shall displayed on the barrel/endcap.
void fillTruthSeedPoints(const EventContext &ctx, const MuonR4::MsTrackSeeder &seeder, const DisplayView view, PlotLegend &legend, Canvas_t &canvas) const
Add the truth segments to the canvas.
double sectorPhi(int sector) const
returns the centeral phi position of a sector in radians
double sectorWidth(int sector) const
sector width (with overlap) in radians
bool insideSector(int sector, double phi) const
checks whether the phi position is consistent with sector
::Muon::MuonStationIndex::ChIndex chamberIndex() const
Returns the chamber index.
Amg::Vector3D position() const
Returns the position as Amg::Vector.
int r
Definition globals.cxx:22
std::string label(const std::string &format, int i)
Definition label.h:19
Eigen::Matrix< double, 2, 1 > Vector2D
Eigen::Matrix< double, 3, 1 > Vector3D
This header ties the generic definitions in this package.
std::vector< MsTrackSeed > MsTrackSeedContainer
Definition MsTrackSeed.h:63
std::string printID(const xAOD::MuonSegment &seg)
Print the chamber ID of a segment, e.g.
const Segment * detailedSegment(const xAOD::MuonSegment &seg)
Helper function to navigate from the xAOD::MuonSegment to the MuonR4::Segment.
Lightweight algorithm to read xAOD MDT sim hits and (fast-digitised) drift circles from SG and fill a...
void ensureDirectory(const std::string &path)
Ensures that the subdirectory in the path is created.
std::vector< std::unique_ptr< TObject > > clone(const std::vector< std::unique_ptr< TObject > > &cloneMe)
void drawPropagation(const std::vector< Acts::detail::Step > &steps, Acts::ObjVisualization3D &visualHelper, const Acts::ViewConfig &viewConfig=Acts::s_viewLine)
Draws the recorded propagation steps as a polygon line.
constexpr int fullFilling
std::string removeNonAlphaNum(std::string str)
Removes all non-alpha numerical characters from a string.
void drawSegmentMeasurements(const ActsTrk::GeometryContext &gctx, const xAOD::MuonSegment &segment, Acts::ObjVisualization3D &visualHelper, const Acts::ViewConfig &viewConfig=Acts::s_viewSensitive)
Draw all uncalibrated measurements associated to the segment.
void drawSegmentLine(const ActsTrk::GeometryContext &gctx, const xAOD::MuonSegment &segment, Acts::ObjVisualization3D &visualHelper, const Acts::ViewConfig &viewConfig=Acts::s_viewLine, const double standardLength=1.*Gaudi::Units::m)
Draw a segment line inside the obj file.
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 std::string & layerName(LayerIndex index)
convert LayerIndex into a string
LayerIndex toLayerIndex(ChIndex index)
convert ChIndex into LayerIndex
LayerIndex
enum to classify the different layers in the muon spectrometer
ChIndex
enum to classify the different chamber layers in the muon spectrometer
NRpcCablingAlg reads raw condition data and writes derived condition data to the condition store.
const T * get(const ReadCondHandleKey< T > &key, const EventContext &ctx)
Convenience function to retrieve an object given a ReadCondHandleKey.
MuonSegmentContainer_v1 MuonSegmentContainer
Definition of the current "MuonSegment container version".
MuonSegment_v1 MuonSegment
Reference the current persistent version:
Helper to simultaneously calculate sin and cos of the same angle.
Definition sincos.h:39
Helper struct to administer the markers & colors that are added to the legend.
void fillPrimitives(Canvas_t &canvas)
Add the primitives of the legend to the Canvas.
void addMarker(const int marker, const std::string &label)
Add new Marker style to the legend entry.
void addColor(const int color, const std::string &label)
Add new color legend entry.
#define THROW_EXCEPTION(MESSAGE)
Definition throwExcept.h:10