7#include "Acts/Surfaces/PerigeeSurface.hpp"
8#include "Acts/Surfaces/PlaneSurface.hpp"
9#include "Acts/Surfaces/detail/PlanarHelper.hpp"
18#include "GaudiKernel/PhysicalConstants.h"
26#include "GaudiKernel/PhysicalConstants.h"
30#include <system_error>
32using namespace Acts::UnitLiterals;
33using namespace Acts::PlanarHelper;
63 Acts::TrackingGeometry::GeometryVersion::Gen3){
64 ATH_MSG_ERROR(
"The MS track fit requires the Gen 3 geometry format");
65 return StatusCode::FAILURE;
73 m_seeder = std::make_unique<MsTrackSeeder>(name(), std::move(seederCfg));
74 return StatusCode::SUCCESS;
80 ATH_MSG_VERBOSE(
"Run track finding in event "<<ctx.eventID().event_number());
88 const Acts::MagneticFieldContext mfContext =
m_extrapolationTool->getMagneticFieldContext(ctx);
92 Acts::VectorTrackContainer trackBackend{};
93 Acts::VectorMultiTrajectory trackStateBackend{};
95 std::move(trackStateBackend)};
97 cacheTrkContainer.addColumn<std::size_t>(
"parentSeed");
101 cacheTrkContainer)) {
105 auto lastTrack = cacheTrkContainer.getTrack(cacheTrkContainer.size() -1);
106 lastTrack.component<std::size_t, Acts::hashString(
"parentSeed")>() = seedIdx;
113 Acts::ConstVectorTrackContainer ctrackBackend{std::move(cacheTrkContainer.container())};
114 Acts::ConstVectorMultiTrajectory ctrackStateBackend{std::move(cacheTrkContainer.trackStateContainer())};
115 auto ctc = std::make_unique<ActsTrk::TrackContainer>(std::move(ctrackBackend),
116 std::move(ctrackStateBackend));
120 return StatusCode::SUCCESS;
123 std::unique_ptr<MsTrackSeedContainer>
127 auto seedContainer =
m_seeder->findTrackSeeds(ctx, segments);
132 return seedContainer;
137 const Acts::MagneticFieldContext& mfContext,
138 const Acts::CalibrationContext& calContext,
140 const EventContext& ctx{*calContext.get<
const EventContext*>()};
142 measurements.reserve(100);
149 if (
msgLvl(MSG::VERBOSE)) {
150 std::stringstream sstr{};
154 <<
", "<<m->numDimensions()<<
", "
155 <<
", "<<surf.geometryId()<<
" @ "<<
Amg::toString(surf.localToGlobalTransform(tgContext))<<std::endl;
158 <<
", direction: "<<
Amg::toString(segment->direction()) <<
" eta " << segment->direction().eta() <<
" phi " << segment->direction().phi() <<
"\n"<<sstr.str());
160 measurements.insert(measurements.end(),
161 std::make_move_iterator(segMeasurements.begin()),
162 std::make_move_iterator(segMeasurements.end()));
165 if (!refSeg && !isNswSegment(*segment) &&
168 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Set reference segment");
174 if (isNswSegment(*segment) &&
177 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - NSW is the best what we have apparently....");
183 if (!refSeg || measurements.empty()) {
185 <<
" - No reference segment passing seeding quality "<<
186 (refSeg !=
nullptr)<<
" was found. #"<<measurements.size()<<
" measurements. ");
187 return std::make_pair(OptBoundPars_t::failure(std::make_error_code(std::errc::invalid_argument)),
188 std::vector<const xAOD::UncalibratedMeasurement_v1*>{});
190 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - "<<measurements.size()<<
" measurements");
194 <<
", dir: "<<
Amg::toString(seedDir) <<
" eta " << seedDir.eta() <<
" phi "
195 << (seedDir.phi() /Gaudi::Units::degree) );
201 <<
" - Failed to find tracking volume for any seed measurement");
202 return std::make_pair(OptBoundPars_t::failure(std::make_error_code(std::errc::invalid_argument)),
203 std::vector<const xAOD::UncalibratedMeasurement_v1*>{});
205 if (volume->motherVolume() && volume->motherVolume()->isAlignable()) {
206 volume = volume->motherVolume();
209 <<
" - Bounding volume "<<volume->volumeName()
210 <<
", trf: "<<
Amg::toString(volume->localToGlobalTransform(tgContext))
211 <<
", bounds: "<<volume->volumeBounds());
215 if (
const xAOD::MuonSegment* frontSegment = seed.segments().front(); frontSegment != refSeg) {
218 const Amg::Transform3D toFirstTrf = firstSurf.localToGlobalTransform(tgContext).inverse();
219 const Amg::Vector3D locFrontSegPos = toFirstTrf * frontSegPos;
220 if (!volume->inside(tgContext, frontSegPos)) {
222 <<
" not inside mother volume: "<<volume->volumeName()<<
", "
223 <<
Amg::toString(volume->globalToLocalTransform(tgContext)*frontSegPos)
224 <<
", bounds: "<<volume->volumeBounds()<<
", "
232 const Acts::MultiIntersection firstIsect = firstSurf.intersect(tgContext, seedPos, seedDir,
233 Acts::BoundaryTolerance::Infinite());
234 const Amg::Vector3D locAtFirst = toFirstTrf * firstIsect.at(0).position();
235 if (firstSurf.type() == Acts::Surface::SurfaceType::Straw) {
236 const auto& bounds =
static_cast<const Acts::LineBounds&
>(firstSurf.bounds());
237 using enum Acts::LineBounds::BoundValues;
240 const Amg::Vector3D locStartPos{locFrontSegPos.x(), locFrontSegPos.y(),
241 std::clamp(locAtFirst.z(), -bounds.get(eHalfLengthZ), bounds.get(eHalfLengthZ))};
242 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - The first surface is a straw "
244 seedPos = firstSurf.localToGlobalTransform(tgContext) * locStartPos;
245 }
else if (firstSurf.type() == Acts::Surface::SurfaceType::Plane) {
246 if (isNswSegment(*frontSegment)) {
247 seedPos = frontSegPos;
249 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - The first surface is a straw "
257 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Using seed measurement "
259 <<
" with volume id " << volId);
263 ATH_MSG_WARNING(__func__<<
"() "<<__LINE__<<
" - Failed to find boundary surface for tracking volume");
264 return std::make_pair(OptBoundPars_t::failure(std::make_error_code(std::errc::invalid_argument)),
265 std::vector<const xAOD::UncalibratedMeasurement_v1*>{});
267 std::shared_ptr<const Acts::Surface> targetSurf{};
269 auto propagteToBoundary = [&](
const Acts::Surface& volBoundary) -> Acts::Result<Amg::Vector3D> {
272 auto pIsect = intersectPlane(seedPos, seedDir, trf.linear().col(2), trf.translation());
274 if (pIsect.pathLength() > Acts::s_epsilon || !pIsect.isValid()) {
276 <<
" is forward "<<pIsect.pathLength()<<
" or invalid "<<(!pIsect.isValid())
277 <<
" within volume "<<volume->inside(tgContext, pIsect.position()));
278 return Acts::Result<Amg::Vector3D>::failure(std::make_error_code(std::errc::invalid_argument));
280 Acts::Result<Amg::Vector2D> locPos = volBoundary.globalToLocal(tgContext, pIsect.position(),
281 Amg::Vector3D::Zero());
283 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Intersection is not on surface "<<
285 return Acts::Result<Amg::Vector3D>::failure(std::make_error_code(std::errc::invalid_argument));
287 if (!volBoundary.insideBounds(*locPos)) {
288 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Intersection is outside the boundaries: "<<
290 return Acts::Result<Amg::Vector3D>::failure(std::make_error_code(std::errc::invalid_argument));
292 targetSurf = volBoundary.getSharedPtr();
293 return Acts::Result<Amg::Vector3D>::success(pIsect.position());
297 auto pIsect = propagteToBoundary(*boundSurf);
298 if (!pIsect.ok() && volume->isAlignable()) {
299 const Acts::VolumePlacementBase* placement = volume->volumePlacement();
300 for (std::size_t portal = 0; !pIsect.ok() && portal< placement->nPortalPlacements(); ++portal) {
301 pIsect = propagteToBoundary(placement->portalPlacement(portal)->surface());
305 ATH_MSG_WARNING(__func__<<
"() "<<__LINE__<<
" Cannot create valid start parameters from seed "<<seed);
307 return std::make_pair(OptBoundPars_t::failure(std::make_error_code(std::errc::invalid_argument)),
308 std::vector<const xAOD::UncalibratedMeasurement_v1*>{});
312 auto initialPars = Acts::BoundTrackParameters::create(tgContext, targetSurf, fourPos,
314 Acts::BoundMatrix::Identity(),
315 Acts::ParticleHypothesis::muon());
316 return std::make_pair(std::move(initialPars), std::move(measurements));
320 const Acts::MagneticFieldContext& mfContext,
321 const Acts::CalibrationContext& calContext,
325 ATH_MSG_DEBUG(__func__<<
"() "<<__LINE__<<
" - Attempt to fit a new track seed \n"<<seed);
326 const EventContext& ctx{*calContext.get<
const EventContext*>()};
327 const auto [initialPars, measurements] =
prepareFit(tgContext, mfContext, calContext, seed);
329 if (!initialPars.ok()) {
330 ATH_MSG_WARNING(__func__<<
"() "<<__LINE__<<
" - Failed to construct valid parameters for seed \n"<<seed);
337 tgContext, mfContext, calContext,
338 &(*initialPars).referenceSurface());
339 if (!fitTraject || fitTraject->size() == 0) {
340 ATH_MSG_DEBUG(__func__<<
"() "<<__LINE__<<
" - Fit failed. Seed was \n"<<seed);
347 ActsTrk::MutableTrackContainer::TrackProxy track = fitTraject->getTrack(0);
349 double pt = trkP4.perp() / 1000;
351 double chi2PerDoF = track.chi2() / (std::max(track.nDoF(), 1u));
352 ATH_MSG_DEBUG(
" ===cat dog: found low pt track candidate with pt "<<pt<<
" GeV chi2/ndof "<< chi2PerDoF <<
" chi2 "<< track.chi2() <<
" nDOF "<< track.nDoF() <<
"eta: "<<trkP4.eta());
354 track.container().trackStateContainer().visitBackwards(track.tipIndex(), [&](
const auto& state) {
355 if(state.hasUncalibratedSourceLink()){
356 const auto* uncalib = dynamic_cast<const xAOD::MuonMeasurement*>(ActsTrk::detail::xAODUncalibMeasCalibrator::unpack(state.getUncalibratedSourceLink()));
358 ATH_MSG_DEBUG(
" has meas: "<<m_idHelperSvc->toString(xAOD::identify(uncalib)) <<
" state " << state.typeFlags());
368 ATH_MSG_DEBUG(
"Track has " <<
static_cast<std::uint32_t
>(summary.nPrecisionStations()) <<
" precision layers with summary "<< summary);
369 if(summary.nPrecisionStations()<2) {
381 fitTraject->addColumn<std::vector<const xAOD::MuonSegment*>>(
"muonSegLinks");
382 fitTraject->getTrack(0).component<std::vector<const xAOD::MuonSegment*>>(
"muonSegLinks") = seed.segments();
384 outContainer.ensureDynamicColumns(*fitTraject);
385 auto destProxy = outContainer.getTrack(outContainer.addTrack());
386 destProxy.copyFrom(fitTraject->getTrack(0));
387 ATH_MSG_DEBUG(__func__<<
"() "<<__LINE__<<
" - Good track fit...");
388 if (m_visualizationTool.isEnabled()) {
389 m_visualizationTool->displayTrackSeedObj(ctx, seed,
390 destProxy.createParametersAtReference(),
"GoodFit");
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
ATLAS-specific HepMC functions.
const ServiceHandle< StoreGateSvc > & detStore() const
bool msgLvl(const MSG::Level lvl) const
Acts::Result< Acts::BoundTrackParameters > OptBoundPars_t
Gaudi::Property< double > m_seedHalfLength
Maximum search window to search segments for.
std::unique_ptr< MsTrackSeedContainer > findTrackSeeds(const EventContext &ctx, const xAOD::MuonSegmentContainer &segments) const
Iterates over the search tree and combines close-by segments to a track seed.
std::vector< const xAOD::UncalibratedMeasurement * > MeasVec_t
SG::WriteHandleKey< ActsTrk::TrackContainer > m_writeKey
Key to the output track container.
std::unique_ptr< MsTrackSeeder > m_seeder
Pointer to the actual seeder implementation.
SG::WriteHandleKey< MsTrackSeedContainer > m_msTrkSeedKey
Temporary container write handle to push the seeds to store gate for later efficiency analysis.
virtual StatusCode execute(const EventContext &ctx) const override final
Standard algorithm execution hook.
ToolHandle< ISpacePointCalibrator > m_calibTool
Calibration tool to fill the track states.
ToolHandle< MuonValR4::ITrackVisualizationTool > m_visualizationTool
Visualization tool to debug the track finding.
const MuonGMR4::MuonDetectorManager * m_detMgr
Pointer to the MuonDetectorManager.
virtual ~MsTrackFindingAlg()
ToolHandle< ActsTrk::IFitterTool > m_trackFitTool
Track fitting tool.
PublicToolHandle< ActsTrk::ITrackingGeometryTool > m_trackingGeometryTool
Tracking geometry tool.
virtual StatusCode initialize() override final
Standard algorithm hook to setup the extrapolator, retrieve the tools and declare algorithm's data de...
ToolHandle< ISegmentSelectionTool > m_segSelector
Segment selection tool to pick the good quality segments.
std::pair< OptBoundPars_t, MeasVec_t > prepareFit(const Acts::GeometryContext &tgContext, const Acts::MagneticFieldContext &mfContext, const Acts::CalibrationContext &calContext, const MsTrackSeed &seed) const
Prepares the input by the fit by collecting the measurements on the segment &.
ToolHandle< ActsTrk::IExtrapolationTool > m_extrapolationTool
Track extrapolation tool.
SG::ReadHandleKey< xAOD::MuonSegmentContainer > m_segmentKey
Declare the data dependency on the standard Mdt+Rpc+Tgc segment container & on the NSW segment contai...
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
IdHelperSvc to decode the Identifiers.
bool fitSeedCandidate(const Acts::GeometryContext &gCtx, const Acts::MagneticFieldContext &mCtx, const Acts::CalibrationContext &cCtx, const MsTrackSeed &seed, ActsTrk::MutableTrackContainer &outContainer) const
Attempts to fit the track seed candidate to a full track and returns whether the fit succeeded.
ToolHandle< MuonR4::ITrackSummaryTool > m_summaryTool
Handle to the muon summary tool.
const MeasVec & measurements() const
Returns the associated measurements.
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
Amg::Vector3D direction() const
Returns the direction as Amg::Vector.
::Muon::MuonStationIndex::TechnologyIndex technology() const
Returns the main technology of the segment.
::Muon::MuonStationIndex::ChIndex chamberIndex() const
Returns the chamber index.
constexpr double energyToActs(const double athenaE)
Converts an energy scalar from Athena to Acts units.
std::pair< Amg::Vector3D, double > convertMomFromActs(const Acts::Vector4 &actsMom)
Converts an Acts four-momentum vector into an pair of an Athena three-momentum and the paritcle's ene...
Acts::TrackContainer< MutableTrackBackend, MutableTrackStateBackend, Acts::detail::ValueHolder > MutableTrackContainer
Acts::CalibrationContext getCalibrationContext(const EventContext &ctx)
The Acts::Calibration context is piped through the Acts fitters to (re)calibrate the Acts::SourceLink...
Acts::Vector4 convertPosToActs(const Amg::Vector3D &athenaPos, const double athenaTime=0.)
Converts a position vector & time from Athena units into Acts units.
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
Eigen::Affine3d Transform3D
Eigen::Matrix< double, 3, 1 > Vector3D
const Acts::Surface * bottomBoundary(const Acts::TrackingVolume &volume)
Returns the boundary surface parallel to the x-y plane at negative local z.
Parameters localSegmentPars(const xAOD::MuonSegment &seg)
Returns the localSegPars decoration from a xAODMuon::Segment.
This header ties the generic definitions in this package.
std::string printID(const xAOD::MuonSegment &seg)
Print the chamber ID of a segment, e.g.
std::vector< const xAOD::UncalibratedMeasurement * > collectMeasurements(const xAOD::MuonSegment &segment, bool skipOutlier=true)
Helper function to extract the measurements from the segment.
Acts::GeometryIdentifier volumeId(const Acts::Surface &surface)
Returns the identifier of the volume in which the surface is embedded.
const xAOD::UncalibratedMeasurement * firstMeasurement(const xAOD::MuonSegment &segment, const bool skipOutlier=true)
Retrieves the first measurement associated with the segment.
Amg::Vector3D atFirstSurface(const Acts::GeometryContext &gctx, const xAOD::MuonSegment &segment, const bool skipOutlier=true)
Expresses the segment position on the surface of the first measurement.
std::string print(const cont_t &container)
Print a space point container to string.
const Segment * detailedSegment(const xAOD::MuonSegment &seg)
Helper function to navigate from the xAOD::MuonSegment to the MuonR4::Segment.
StIndex toStationIndex(ChIndex index)
convert ChIndex into StIndex
const T * get(const ReadCondHandleKey< T > &key, const EventContext &ctx)
Convenience function to retrieve an object given a ReadCondHandleKey.
UncalibratedMeasurement_v1 UncalibratedMeasurement
Define the version of the uncalibrated measurement class.
MuonSegmentContainer_v1 MuonSegmentContainer
Definition of the current "MuonSegment container version".
const Identifier & identify(const UncalibratedMeasurement *meas)
Returns the associated identifier from the muon measurement.
MuonSegment_v1 MuonSegment
Reference the current persistent version:
const Acts::Surface & muonSurface(const UncalibratedMeasurement *meas)
Returns the associated Acts surface to the measurement.
Summary struct to hold the hit counts on the track per MS layer.
const MuonGMR4::MuonDetectorManager * detMgr
Detector manager to fetch the sector enevelope transforms.
double seedHalfLength
Maximum separation of point on the cylinder to be picked up onto a seed.
const ISegmentSelectionTool * selector
Pointer to the segement selection tool which compares two segments for their compatibilitiy.