ATLAS Offline Software
Loading...
Searching...
No Matches
GeometryRealmConvTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
6
9
11// ACTS
12#include "Acts/Surfaces/StrawSurface.hpp"
13#include "Acts/Surfaces/PerigeeSurface.hpp"
14#include "Acts/Surfaces/PlaneSurface.hpp"
15
16#include "Acts/Surfaces/RectangleBounds.hpp"
17#include "Acts/Surfaces/TrapezoidBounds.hpp"
18#include "Acts/Surfaces/CylinderBounds.hpp"
19#include "Acts/Surfaces/DiscBounds.hpp"
20#include "Acts/Surfaces/LineBounds.hpp"
21#include "Acts/Surfaces/RadialBounds.hpp"
22#include "Acts/Surfaces/DiamondBounds.hpp"
23
24#include "Acts/Definitions/Units.hpp"
25#include "Acts/EventData/BoundTrackParameters.hpp"
26#include "Acts/EventData/VectorTrackContainer.hpp"
27#include "Acts/EventData/TransformationHelpers.hpp"
28#include "Acts/Geometry/TrackingGeometry.hpp"
29#include "Acts/Propagator/detail/JacobianEngine.hpp"
30#include "Acts/Surfaces/detail/PlanarHelper.hpp"
31
33#include "Acts/EventData/TrackStatePropMask.hpp"
34#include "Acts/EventData/SourceLink.hpp"
35
46
48
49using namespace Acts::UnitLiterals;
50using SurfacePtr_t = ActsTrk::GeometryRealmConvTool::SurfacePtr_t;
51
52namespace ActsTrk{
55 if (parent() != toolSvc()) {
56 ATH_MSG_ERROR("The tool is initialized as a private tool but should be public");
57 return StatusCode::FAILURE;
58 }
59 ATH_CHECK(m_ctxProvider.initialize());
61 m_trackingGeometrySvc->trackingGeometry()->visitSurfaces([&](const Acts::Surface *surface) {
62 // find acts surface with the same detector element ID
63 if (!surface->isSensitive()) {
64 return;
65 }
66 const auto *actsElement = dynamic_cast<const ISurfacePlacement*>(surface->surfacePlacement());
67 if (!actsElement) {
68 return;
69 }
70 // Conversion from Acts to ATLAS surface impossible for the TRT so the TRT
71 // surfaces are not stored in this map
72 if (actsElement->detectorType() == DetectorType::Trt) {
73 return;
74 }
75 auto [it, ok] = m_actsSurfaceMap.insert(std::make_pair(actsElement->identify(), surface->getSharedPtr()));
76 if (!ok) {
77 ATH_MSG_WARNING("ATLAS ID " << actsElement->identify()
78 << " has two ACTS surfaces: "
79 << it->second->geometryId() << " and "
80 << surface->geometryId());
81 }
82 });
84 return StatusCode::SUCCESS;
85 }
86 std::shared_ptr<Trk::SurfaceBounds>
87 GeometryRealmConvTool::translateBounds(const Acts::SurfaceBounds& bounds) const {
88 switch (bounds.type()) {
89 using enum Acts::SurfaceBounds::BoundsType;
90 case eRectangle:{
91 using ParEnum_t = Acts::RectangleBounds::BoundValues;
92 const auto& cBounds = static_cast<const Acts::RectangleBounds&>(bounds);
93 return std::make_shared<Trk::RectangleBounds>(cBounds.get(ParEnum_t::eMaxX),
94 cBounds.get(ParEnum_t::eMaxY));
95 } case eTrapezoid: {
96 using ParEnum_t = Acts::TrapezoidBounds::BoundValues;
97 const auto& cBounds = static_cast<const Acts::TrapezoidBounds&>(bounds);
98 return std::make_shared<Trk::TrapezoidBounds>(cBounds.get(ParEnum_t::eHalfLengthXnegY),
99 cBounds.get(ParEnum_t::eHalfLengthXposY),
100 cBounds.get(ParEnum_t::eHalfLengthY));
101 } case eDisc: {
102 using ParEnum_t = Acts::RadialBounds::BoundValues;
103 const auto& cBounds = static_cast<const Acts::RadialBounds&>(bounds);
104 return std::make_shared<Trk::DiscBounds>(cBounds.get(ParEnum_t::eMinR),
105 cBounds.get(ParEnum_t::eMaxR),
106 cBounds.get(ParEnum_t::eAveragePhi),
107 cBounds.get(ParEnum_t::eHalfPhiSector));
108 } case eCylinder: {
109 using ParEnum_t = Acts::CylinderBounds::BoundValues;
110 const auto& cBounds = static_cast<const Acts::CylinderBounds&>(bounds);
111 return std::make_shared<Trk::CylinderBounds>(cBounds.get(ParEnum_t::eR),
112 cBounds.get(ParEnum_t::eHalfPhiSector),
113 cBounds.get(ParEnum_t::eAveragePhi),
114 cBounds.get(ParEnum_t::eHalfLengthZ));
115 } case eLine: {
116 using ParEnum_t = Acts::LineBounds::BoundValues;
117 const auto& cBounds = static_cast<const Acts::LineBounds&>(bounds);
118 return std::make_shared<Trk::CylinderBounds>(cBounds.get(ParEnum_t::eR),
119 cBounds.get(ParEnum_t::eHalfLengthZ));
120 } case eDiamond: {
121 using ParEnum_t = Acts::DiamondBounds::BoundValues;
122 const auto& cBounds = static_cast<const Acts::DiamondBounds&>(bounds);
123 return std::make_shared<Trk::DiamondBounds>(cBounds.get(ParEnum_t::eHalfLengthXnegY),
124 cBounds.get(ParEnum_t::eHalfLengthXzeroY),
125 cBounds.get(ParEnum_t::eHalfLengthXposY),
126 cBounds.get(ParEnum_t::eHalfLengthYneg),
127 cBounds.get(ParEnum_t::eHalfLengthYpos));
128 } case eBoundless:{
129 return nullptr;
130 } default:
131 break;
132 }
133 THROW_EXCEPTION("The bounds "<<bounds<<" cannot be translated");
134 return nullptr;
135 }
137 const Acts::Surface& surface) const {
138 const Acts::GeometryContext tgContext = m_ctxProvider.getGeometryContext(ctx);
139 const Amg::Transform3D& trf{surface.localToGlobalTransform(tgContext)};
140 switch (surface.type()) {
141 using enum Acts::Surface::SurfaceType;
142 case Plane:
143 return SurfacePtr_t{new Trk::PlaneSurface(trf, translateBounds(surface.bounds()))};
144 case Cylinder:
145 return SurfacePtr_t{new Trk::CylinderSurface(trf,
146 std::dynamic_pointer_cast<Trk::CylinderBounds>(translateBounds(surface.bounds())))};
147 case Perigee:
148 return SurfacePtr_t{new Trk::PerigeeSurface(trf)};
149 case Disc:
150 return SurfacePtr_t{new Trk::DiscSurface(trf,
151 std::dynamic_pointer_cast<Trk::DiscBounds>(translateBounds(surface.bounds())))};
152 case Straw: {
153 auto bounds = std::dynamic_pointer_cast<Trk::CylinderBounds>(translateBounds(surface.bounds()));
154 return SurfacePtr_t{new Trk::StraightLineSurface(trf, bounds->r(), bounds->halflengthZ())};
155 } default:
156 break;
157 }
158 THROW_EXCEPTION("ActsToTrkConverterTool() - Surface cannot be translated "
159 <<surface.toString(tgContext));
160
161 return nullptr;
162 }
163
165 const Acts::Surface& actsSurface) const{
166 const auto *placement = dynamic_cast<const ISurfacePlacement*>(actsSurface.surfacePlacement());
167 if (!placement) {
168 return translateFreeSurface(ctx, actsSurface);
169 }
170 switch (placement->detectorType()) {
171 using enum DetectorType;
172 case Pixel:
173 case Sct:
174 case Hgtd:
175 case Trt: {
176 const auto* actsElement = getActsDetectorElement(actsSurface);
177 if (actsElement) {
178 return SurfacePtr_t{&actsElement->atlasSurface()};
179 }
180 break;
181 } case Mdt:
182 case Rpc:
183 case Tgc:
184 case Csc:
185 case sTgc:
186 case Mm: {
187 const MuonGM::MuonDetectorManager* detMgr{nullptr};
188 if (!SG::get(detMgr, m_muonMgrKey, ctx).isSuccess() || !detMgr) {
189 THROW_EXCEPTION("Failed to retrieve the muon detector manager");
190 }
191 return SurfacePtr_t{&detMgr->getReadoutElement(placement->identify())->surface(placement->identify())};
192 } default:
193 break;
194 }
196 return translateFreeSurface(ctx, actsSurface);
197 }
198 std::shared_ptr<const Acts::Surface> GeometryRealmConvTool::convertSurfaceToActs(const Trk::Surface& atlasSurface) const {
199 Identifier atlasID = atlasSurface.associatedDetectorElementIdentifier();
200 auto it = m_actsSurfaceMap.find(atlasID);
201 if (it != m_actsSurfaceMap.end()) {
202 return it->second;
203 }
204 const Amg::Transform3D& trf{atlasSurface.transform()};
205 switch (atlasSurface.type()){
206 using enum Trk::SurfaceType;
207 case Plane:
208 return Acts::Surface::makeShared<Acts::PlaneSurface>(trf);
209 case Perigee:
210 return Acts::Surface::makeShared<Acts::PerigeeSurface>(trf);
211 case Line:
212 return Acts::Surface::makeShared<Acts::StrawSurface>(trf);
213 // TODO - implement the missing types?
214 default: {
215 break;
216 }
217 }
218 std::stringstream surfStr{};
219 atlasSurface.dump(surfStr);
220 throw std::domain_error(std::format("Failed to translate surface {:}", surfStr.str()));
221 }
222
223 Acts::BoundTrackParameters
225 const Trk::TrackParameters& atlasParameter,
226 Trk::ParticleHypothesis hypothesis) const {
227 std::shared_ptr<const Acts::Surface> actsSurface{};
228 Acts::BoundVector params{};
229 const Acts::GeometryContext tgContext = m_ctxProvider.getGeometryContext(ctx);
230
231 // get the associated surface
232 try {
233 actsSurface = convertSurfaceToActs(atlasParameter.associatedSurface());
234 } catch (const std::exception &e) {
235 ATH_MSG_ERROR("Could not find ACTS detector surface for this TrackParameter:");
236 ATH_MSG_ERROR(atlasParameter);
237 throw; // Nothing we can do, so just pass exception on...
238 }
239
240 // Construct track parameters
241 const auto& atlasParam{atlasParameter.parameters()};
242 if (actsSurface->bounds().type() == Acts::SurfaceBounds::BoundsType::eAnnulus) {
243 // Annulus surfaces are constructed differently in Acts/Trk so we need to
244 // convert local coordinates
245 const Amg::Vector3D& position{atlasParameter.position()};
246 auto result = actsSurface->globalToLocal(tgContext, position, atlasParameter.momentum());
247 if (result.ok()) {
248 params << (*result)[0], (*result)[1], atlasParam[Trk::phi0],
249 atlasParam[Trk::theta],
250 atlasParameter.charge() / (atlasParameter.momentum().mag() * 1_MeV),
251 0.;
252 } else {
253 ATH_MSG_WARNING("Unable to convert annulus surface - globalToLocal failed");
254 }
255 } else {
256 params << atlasParam[Trk::locX], atlasParam[Trk::locY],
257 atlasParam[Trk::phi0], atlasParam[Trk::theta],
258 atlasParameter.charge() / (atlasParameter.momentum().mag() * 1_MeV), 0.;
259 }
260
261 std::optional<Acts::BoundMatrix> cov{};
262 if (atlasParameter.covariance()) {
263 cov = Acts::BoundMatrix::Identity();
264 cov->topLeftCorner(5, 5) = *atlasParameter.covariance();
265
266 // Convert the covariance matrix from MeV
267 // FIXME: This needs to handle the annulus case as well - currently the cov
268 // is wrong for annulus surfaces
269 for (int i = 0; i < cov->rows(); ++i) {
270 (*cov)(i, 4) = (*cov)(i, 4) / 1_MeV;
271 }
272 for (int i = 0; i < cov->cols(); ++i) {
273 (*cov)(4, i) = (*cov)(4, i) / 1_MeV;
274 }
275 }
276 return Acts::BoundTrackParameters{std::move(actsSurface), params, std::move(cov),
277 ParticleHypothesis::convert(hypothesis)};
278 }
279 std::unique_ptr<Trk::TrackParameters>
281 const Acts::BoundTrackParameters& actsParameter) const {
282
283
284 std::optional<AmgSymMatrix(5)> cov = std::nullopt;
285 if (actsParameter.covariance()) {
286 AmgSymMatrix(5) newcov(actsParameter.covariance()->topLeftCorner<5, 5>());
287 // Convert the covariance matrix to GeV
288 for (int i = 0; i < newcov.rows(); i++) {
289 newcov(i, 4) = newcov(i, 4) * 1_MeV;
290 }
291 for (int i = 0; i < newcov.cols(); i++) {
292 newcov(4, i) = newcov(4, i) * 1_MeV;
293 }
294 cov = newcov;
295 }
296
297 const Acts::Surface &actsSurface = actsParameter.referenceSurface();
298 SurfacePtr_t trkSurface = convertSurfaceToTrk(ctx, actsSurface);
299 switch (actsSurface.type()) {
300 case Acts::Surface::SurfaceType::Cone: {
301 const auto &coneSurface = static_cast<const Trk::ConeSurface&>(*trkSurface);
302 return std::make_unique<Trk::AtaCone>(
303 actsParameter.get<Acts::eBoundLoc0>(),
304 actsParameter.get<Acts::eBoundLoc1>(),
305 actsParameter.get<Acts::eBoundPhi>(),
306 actsParameter.get<Acts::eBoundTheta>(),
307 actsParameter.get<Acts::eBoundQOverP>() * 1_MeV, coneSurface, cov);
308 } case Acts::Surface::SurfaceType::Cylinder: {
309 const auto &cylSurface{static_cast<const Trk::CylinderSurface&>(*trkSurface)};
310 return std::make_unique<Trk::AtaCylinder>(
311 actsParameter.get<Acts::eBoundLoc0>(),
312 actsParameter.get<Acts::eBoundLoc1>(),
313 actsParameter.get<Acts::eBoundPhi>(),
314 actsParameter.get<Acts::eBoundTheta>(),
315 actsParameter.get<Acts::eBoundQOverP>() * 1_MeV, cylSurface, cov);
316 } case Acts::Surface::SurfaceType::Disc: {
317 if (trkSurface->type() == Trk::SurfaceType::Disc) {
318 const auto& discSurface{static_cast<const Trk::DiscSurface&>(*trkSurface)};
319 return std::make_unique<Trk::AtaDisc>(
320 actsParameter.get<Acts::eBoundLoc0>(),
321 actsParameter.get<Acts::eBoundLoc1>(),
322 actsParameter.get<Acts::eBoundPhi>(),
323 actsParameter.get<Acts::eBoundTheta>(),
324 actsParameter.get<Acts::eBoundQOverP>() * 1_MeV, discSurface, cov);
325 } else if (trkSurface->type() == Trk::SurfaceType::Plane) {
326 const Acts::GeometryContext tgContext = m_ctxProvider.getGeometryContext(ctx);
327 auto& planeSurface{static_cast<const Trk::PlaneSurface&>(*trkSurface)};
328 // need to convert to plane position on plane surface (annulus bounds)
329 auto helperSurface = Acts::Surface::makeShared<Acts::PlaneSurface>(planeSurface.transform());
330
331 auto covpc = actsParameter.covariance().value();
333 Acts::FreeVector freePars = Acts::transformBoundToFreeParameters(actsSurface, tgContext,
334 actsParameter.parameters());
335
337 Acts::BoundVector targetPars = Acts::transformFreeToBoundParameters(freePars,
338 *helperSurface, tgContext).value();
339
340
341 Acts::FreeMatrix freeTransportJacobian{Acts::FreeMatrix::Identity()};
342
343 Acts::FreeVector freeToPathDerivatives{Acts::FreeVector::Zero()};
344 freeToPathDerivatives.head<3>() = freePars.segment<3>(Acts::eFreeDir0);
345
346 auto boundToFreeJacobian = actsSurface.boundToFreeJacobian(tgContext,
347 freePars.segment<3>(Acts::eFreePos0),
348 freePars.segment<3>(Acts::eFreeDir0));
349
350 Acts::BoundMatrix boundToBoundJac =
351 Acts::detail::boundToBoundTransportJacobian(tgContext, freePars,
352 boundToFreeJacobian, freeTransportJacobian,
353 freeToPathDerivatives, *helperSurface);
354
355 Acts::BoundMatrix targetCov{boundToBoundJac * covpc * boundToBoundJac.transpose()};
356
357 return std::make_unique<Trk::AtaPlane>(
358 targetPars[Acts::eBoundLoc0], targetPars[Acts::eBoundLoc1],
359 targetPars[Acts::eBoundPhi], targetPars[Acts::eBoundTheta],
360 targetPars[Acts::eBoundQOverP] * 1_MeV, planeSurface,
361 targetCov.topLeftCorner<5, 5>());
362 } else {
363 throw std::domain_error("Acts::DiscSurface is not associated with ATLAS disc or plane surface");
364 }
365 break;
366 } case Acts::Surface::SurfaceType::Perigee: {
367 const auto& perSurface = static_cast<const Trk::PerigeeSurface&>(*trkSurface);
368 return std::make_unique<Trk::Perigee>(
369 actsParameter.get<Acts::eBoundLoc0>(),
370 actsParameter.get<Acts::eBoundLoc1>(),
371 actsParameter.get<Acts::eBoundPhi>(),
372 actsParameter.get<Acts::eBoundTheta>(),
373 actsParameter.get<Acts::eBoundQOverP>() * 1_MeV, perSurface, cov);
374 } case Acts::Surface::SurfaceType::Plane: {
375 auto &plaSurface{static_cast<const Trk::PlaneSurface&>(*trkSurface)};
376 return std::make_unique<Trk::AtaPlane>(
377 actsParameter.get<Acts::eBoundLoc0>(),
378 actsParameter.get<Acts::eBoundLoc1>(),
379 actsParameter.get<Acts::eBoundPhi>(),
380 actsParameter.get<Acts::eBoundTheta>(),
381 actsParameter.get<Acts::eBoundQOverP>() * 1_MeV, plaSurface, cov);
382 } case Acts::Surface::SurfaceType::Straw: {
383 auto& lineSurface{static_cast<const Trk::StraightLineSurface&>(*trkSurface)};
384 return std::make_unique<Trk::AtaStraightLine>(
385 actsParameter.get<Acts::eBoundLoc0>(),
386 actsParameter.get<Acts::eBoundLoc1>(),
387 actsParameter.get<Acts::eBoundPhi>(),
388 actsParameter.get<Acts::eBoundTheta>(),
389 actsParameter.get<Acts::eBoundQOverP>() * 1_MeV, lineSurface, cov);
390 } case Acts::Surface::SurfaceType::Curvilinear: {
391 const Acts::GeometryContext tgContext = m_ctxProvider.getGeometryContext(ctx);
392 return std::make_unique<Trk::CurvilinearParameters>(
393 actsParameter.position(tgContext), actsParameter.get<Acts::eBoundPhi>(),
394 actsParameter.get<Acts::eBoundTheta>(),
395 actsParameter.get<Acts::eBoundQOverP>() * 1_MeV, cov);
396 } case Acts::Surface::SurfaceType::Point:
397 case Acts::Surface::SurfaceType::Other: {
398 break;
399 }
400 }
401 throw std::domain_error("Surface type not found");
402 }
403}
const ActsDetectorElement * getActsDetectorElement(const Acts::Surface &surf)
Attempts to retrieve the ActsDetectorElement associated to the passed ActsSurface.
Scalar mag() const
mag method
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_WARNING(x,...)
#define AmgSymMatrix(dim)
ActsTrk::GeometryRealmConvTool::SurfacePtr_t SurfacePtr_t
virtual std::shared_ptr< const Acts::Surface > convertSurfaceToActs(const Trk::Surface &atlasSurface) const override final
Translate the parsed Trk surface into an Acts surface.
virtual Acts::BoundTrackParameters convertTrackParametersToActs(const EventContext &ctx, const Trk::TrackParameters &atlasParameter, Trk::ParticleHypothesis hypothesis=Trk::pion) const override final
Translates the Trk track parameters into bound Acts track parameters with a particle hypothesis.
SurfacePtr_t translateFreeSurface(const EventContext &ctx, const Acts::Surface &surface) const
Translate a surface that is not associated with any detector element.
virtual std::unique_ptr< Trk::TrackParameters > convertTrackParametersToTrk(const EventContext &ctx, const Acts::BoundTrackParameters &actsParameters) const override final
Translates the bounded Acts track parameters to Trk parameters.
SG::ReadCondHandleKey< MuonGM::MuonDetectorManager > m_muonMgrKey
Detector manager to fetch the legacy Trk surfaces.
std::shared_ptr< Trk::SurfaceBounds > translateBounds(const Acts::SurfaceBounds &bounds) const
Translate the Acts surface bounds to its equivalent in the Trk realm.
ServiceHandle< ActsTrk::ITrackingGeometrySvc > m_trackingGeometrySvc
Gaudi::Property< bool > m_extractMuonSurfaces
virtual SurfacePtr_t convertSurfaceToTrk(const EventContext &ctx, const Acts::Surface &actsSurface) const override final
Translates the parsed Acts surface into a Trk::Surface via associated detector element.
ActsTrk::ContextUtility m_ctxProvider
Context provider for geometry, magnetic field and calibration contexts.
std::unordered_map< Identifier, std::shared_ptr< const Acts::Surface > > m_actsSurfaceMap
virtual StatusCode initialize() override final
Extension of the interface of the Acts::SurfacePlacementBase for ATLAS.
The MuonDetectorManager stores the transient representation of the Muon Spectrometer geometry and pro...
const MuonReadoutElement * getReadoutElement(const Identifier &id) const
Get any read out element.
Class for a conical surface in the ATLAS detector.
Definition ConeSurface.h:52
Class for a CylinderSurface in the ATLAS detector.
Class for a DiscSurface in the ATLAS detector.
Definition DiscSurface.h:54
const Amg::Vector3D & momentum() const
Access method for the momentum.
const Amg::Vector3D & position() const
Access method for the position.
double charge() const
Returns the charge.
virtual const Surface & associatedSurface() const =0
Access to the Surface associated to the Parameters.
Class describing the Line to which the Perigee refers to.
Class for a planaer rectangular or trapezoidal surface in the ATLAS detector.
Class for a StraightLineSurface in the ATLAS detector to describe dirft tube and straw like detectors...
Abstract Base Class for tracking surfaces.
Definition Surface.h:79
virtual MsgStream & dump(MsgStream &sl) const
Output Method for MsgStream, to be overloaded by child classes.
Definition Surface.cxx:157
const Amg::Transform3D & transform() const
Returns HepGeom::Transform3D by reference.
Identifier associatedDetectorElementIdentifier() const
return Identifier of the associated Detector Element
virtual constexpr SurfaceType type() const =0
Returns the Surface type to avoid dynamic casts.
virtual const Surface & surface() const =0
Return surface associated with this detector element.
xAOD::ParticleHypothesis convert(Acts::ParticleHypothesis h)
The AlignStoreProviderAlg loads the rigid alignment corrections and pipes them through the readout ge...
DetectorType
Simple enum to Identify the Type of the ACTS sub detector.
@ Mm
Maybe not needed in the migration.
@ Tgc
Resitive Plate Chambers.
@ sTgc
Micromegas (NSW).
@ Rpc
Monitored Drift Tubes.
@ Csc
Thin gap champers.
@ Mdt
MuonSpectrometer.
Eigen::Affine3d Transform3D
Eigen::Matrix< double, 3, 1 > Vector3D
const T * get(const ReadCondHandleKey< T > &key, const EventContext &ctx)
Convenience function to retrieve an object given a ReadCondHandleKey.
SurfaceType
This enumerator simplifies the persistency & calculations,.
@ locY
local cartesian
Definition ParamDefs.h:38
@ locX
Definition ParamDefs.h:37
@ phi0
Definition ParamDefs.h:65
@ theta
Definition ParamDefs.h:66
ParticleHypothesis
Enumeration for Particle hypothesis respecting the interaction with material.
ParametersBase< TrackParametersDim, Charged > TrackParameters
#define THROW_EXCEPTION(MESSAGE)
Definition throwExcept.h:10