8#include "Acts/Utilities/Helpers.hpp"
9#include "Acts/Definitions/Tolerance.hpp"
10#include "Acts/Definitions/Units.hpp"
11#include "Acts/Geometry/TrackingGeometry.hpp"
13#include "Acts/Surfaces/LineBounds.hpp"
14#include "Acts/Surfaces/RectangleBounds.hpp"
15#include "Acts/Surfaces/DiamondBounds.hpp"
16#include "Acts/Surfaces/TrapezoidBounds.hpp"
17#include "Acts/Surfaces/PlaneSurface.hpp"
22#include "GaudiKernel/PhysicalConstants.h"
25 using namespace Acts::UnitLiterals;
27 constexpr bool chargeAgree(
double PtimesQ1,
double PtimesQ2) {
28 return PtimesQ1 * PtimesQ2 > 0;
31 inline double momentumDev(
double PtimesQ1,
double PtimesQ2) {
32 const double denom {std::max(std::abs(PtimesQ1) + std::abs(PtimesQ2), Acts::s_epsilon)};
33 return std::abs(PtimesQ1 - PtimesQ2) /
denom;
43 return std::format(
"{:}, nPrecHits: {:}, nPhiHits: {:}",
MuonR4::printID(seg),
57 bool hasInner{
false}, hasMiddle{
false}, hasOuter{
false};
58 unsigned int nExtended{0};
69 const unsigned int nIMO = hasInner + hasMiddle + hasOuter;
70 return nIMO + nExtended >= 2u;
75 return angle / Gaudi::Units::deg;
91 return StatusCode::FAILURE;
98 return StatusCode::SUCCESS;
101 Acts::Result<Acts::BoundTrackParameters>
104 const Acts::GeometryContext tgContext =
m_ctxProvider.getGeometryContext(ctx);
105 const Acts::MagneticFieldContext mfContext =
m_ctxProvider.getMagneticFieldContext(ctx);
110 Acts::BoundMatrix cov{Acts::BoundMatrix::Zero()};
118 if (!refSeg && !isNswSegment(*segment) &&
124 if (!boundPars.covariance()) {
127 for (
int i =0 ; i < cov.cols(); ++i) {
128 cov(i,i) += (*boundPars.covariance())(i,i);
135 if (isNswSegment(*segment) &&
138 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - NSW is the best what we have apparently....");
146 <<
" - No reference segment passing seeding quality was found.");
147 return Acts::Result<Acts::BoundTrackParameters>::failure(std::make_error_code(std::errc::invalid_argument));
152 <<
" theta/phi: "<<
inDeg(seedPos.theta())<<
" / "<<
inDeg(seedPos.phi())
154 <<
" theta/phi: "<<
inDeg(seedDir.theta())<<
" / "<<
inDeg(seedDir.phi()));
160 const Acts::GeometryIdentifier volId =
volumeId(firstSurf);
167 <<
" - Failed to find tracking volume for seed measurement "<<volId);
168 return Acts::Result<Acts::BoundTrackParameters>::failure(std::make_error_code(std::errc::invalid_argument));
171 <<
" - Bounding volume "<<volume->volumeName()
172 <<
", trf: "<<
Amg::toString(volume->localToGlobalTransform(tgContext))
173 <<
", bounds: "<<volume->volumeBounds());
177 if (frontSegment != refSeg) {
179 const Amg::Transform3D toFirstTrf = firstSurf.localToGlobalTransform(tgContext).inverse();
180 const Amg::Vector3D locFrontSegPos = toFirstTrf * frontSegPos;
181 if (!volume->inside(tgContext, frontSegPos)) {
183 <<
" not inside mother volume: "<<volume->volumeName()<<
", "
184 <<
Amg::toString(volume->globalToLocalTransform(tgContext)*frontSegPos)
185 <<
", bounds: "<<volume->volumeBounds()<<
", "
193 seedDir = volume->localToGlobalTransform(tgContext).linear() *
194 Acts::makeDirectionFromAxisTangents(
houghTanAlpha(locSeedDir),
196 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Updated seed direction theta/phi: "
197 <<
inDeg(seedDir.theta())<<
" / "<<
inDeg(seedDir.phi()));
202 const Acts::MultiIntersection firstIsect = firstSurf.intersect(tgContext, seedPos, seedDir,
203 Acts::BoundaryTolerance::Infinite());
204 const Amg::Vector3D locSeedAtFirst = toFirstTrf * firstIsect.at(0).position();
205 if (firstSurf.type() == Acts::Surface::SurfaceType::Straw) {
206 const auto& bounds =
static_cast<const Acts::LineBounds&
>(firstSurf.bounds());
207 using enum Acts::LineBounds::BoundValues;
210 const Amg::Vector3D locStartPos{locFrontSegPos.x(), locFrontSegPos.y(),
211 std::clamp(locSeedAtFirst.z(), -bounds.get(eHalfLengthZ), bounds.get(eHalfLengthZ))};
212 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - The first surface is a straw "
213 <<bounds<<
", track seed @first: "<<
Amg::toString(locSeedAtFirst)<<
" vs. segment @first: "
215 seedPos = firstSurf.localToGlobalTransform(tgContext) * locStartPos;
216 }
else if (firstSurf.type() == Acts::Surface::SurfaceType::Plane) {
217 if (isNswSegment(*frontSegment)) {
218 seedPos = frontSegPos;
222 Acts::Vector2 locStartPos2D {locFrontSegPos.x(), locSeedAtFirst.y()};
223 const auto& bounds = firstSurf.bounds();
224 switch (bounds.type()) {
225 case Acts::SurfaceBounds::BoundsType::eRectangle:
226 if (!bounds.inside(locStartPos2D)) {
227 locStartPos2D = bounds.closestPoint(locStartPos2D, Acts::SquareMatrix2::Identity());
230 case Acts::SurfaceBounds::BoundsType::eTrapezoid:
231 case Acts::SurfaceBounds::BoundsType::eDiamond:
233 std::swap(locStartPos2D.x(), locStartPos2D.y());
234 if (!bounds.inside(locStartPos2D)) {
235 locStartPos2D = bounds.closestPoint(locStartPos2D, Acts::SquareMatrix2::Identity());
237 std::swap(locStartPos2D.x(), locStartPos2D.y());
240 ATH_MSG_WARNING(__func__<<
"() "<<__LINE__<<
" - Unexpected surface bounds type "
241 <<firstSurf.bounds().type());
242 return Acts::Result<Acts::BoundTrackParameters>::failure(std::make_error_code(std::errc::invalid_argument));
244 const Amg::Vector3D locStartPos {locStartPos2D.x(),locStartPos2D.y(), locFrontSegPos.z()};
246 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - The first surface is a plane with bounds "
247 <<firstSurf.bounds() <<
", track seed @first: "<<
Amg::toString(locSeedAtFirst)<<
" vs. segment @first: "
249 seedPos = firstSurf.localToGlobalTransform(tgContext) * locStartPos;
252 ATH_MSG_WARNING(__func__<<
"() "<<__LINE__<<
" - Unexpected surface type "<<firstSurf.type());
253 return Acts::Result<Acts::BoundTrackParameters>::failure(std::make_error_code(std::errc::invalid_argument));
256 <<
" theta/phi: "<<
inDeg(seedPos.theta())<<
" / "<<
inDeg(seedPos.phi()));
262 ATH_MSG_WARNING(__func__<<
"() "<<__LINE__<<
" - Failed to find boundary surface for tracking volume");
263 return Acts::Result<Acts::BoundTrackParameters>::failure(std::make_error_code(std::errc::invalid_argument));
265 std::shared_ptr<const Acts::Surface> targetSurf{};
270 auto propagateToBoundary = [&](
const Acts::Surface& volBoundary) -> Acts::Result<Amg::Vector3D> {
273 using namespace Acts::PlanarHelper;
274 auto pIsect = intersectPlane(seedPos, seedDir, trf.linear().col(
Amg::z), trf.translation());
276 if (pIsect.pathLength() > Acts::s_epsilon || !pIsect.isValid()) {
278 <<
" is forward "<<pIsect.pathLength()<<
" or invalid "<<(!pIsect.isValid())
279 <<
" within volume "<<volume->inside(tgContext, pIsect.position()));
280 return Acts::Result<Amg::Vector3D>::failure(std::make_error_code(std::errc::invalid_argument));
282 Acts::Result<Amg::Vector2D> locPos = volBoundary.globalToLocal(tgContext, pIsect.position(),
283 Amg::Vector3D::Zero());
285 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Intersection is not on surface "<<
287 return Acts::Result<Amg::Vector3D>::failure(std::make_error_code(std::errc::invalid_argument));
289 if (!volBoundary.insideBounds(*locPos)) {
290 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Intersection is outside the boundaries: "<<
292 return Acts::Result<Amg::Vector3D>::failure(std::make_error_code(std::errc::invalid_argument));
294 targetSurf = volBoundary.getSharedPtr();
295 return Acts::Result<Amg::Vector3D>::success(pIsect.position());
298 auto pIsect = propagateToBoundary(*boundSurf);
302 if (!pIsect.ok() && volume->isAlignable()) {
303 const Acts::VolumePlacementBase* placement = volume->volumePlacement();
304 for (std::size_t portal = 0; !pIsect.ok() && portal< placement->nPortalPlacements(); ++portal) {
305 pIsect = propagateToBoundary(placement->portalPlacement(portal)->surface());
309 ATH_MSG_DEBUG(__func__<<
"() "<<__LINE__<<
" Cannot create valid start parameters from seed "<<seed<<
".");
310 return Acts::Result<Acts::BoundTrackParameters>::failure(std::make_error_code(std::errc::invalid_argument));
312 if (!canEstimateQtimesP(seed)) {
313 ATH_MSG_WARNING(__func__<<
"() "<<__LINE__<<
" Cannot estimate q*p from seed "<<seed
314 <<
" - insufficient inner/middle/outer layer coverage.");
315 return Acts::Result<Acts::BoundTrackParameters>::failure(std::make_error_code(std::errc::invalid_argument));
318 <<
" eta/phi: "<<pIsect->eta()<<
" / "<<(
inDeg(pIsect->phi())));
324 cov (Acts::eBoundQOverP, Acts::eBoundQOverP) = Acts::square(momRes * qOverP);
326 return Acts::BoundTrackParameters::create(tgContext, targetSurf,
327 fourPos, seedDir, qOverP, cov,
328 Acts::ParticleHypothesis::muon());
336 for (std::size_t meas = 0; meas < nMeas; ++ meas) {
343 localToGlobalTransform(tgContext).linear().col(
Amg::x);
352 return Acts::PlanarHelper::intersectPlane(segment.
position(), wireDir,
353 planeNormal, Amg::Vector3D::Zero()).position();
369 <<
", direction: "<<
Amg::toString(dir)<<
" sector projector: " << sector
370 <<
" location: " << Acts::toUnderlying(loc));
375 if (Location::Barrel == loc) {
381 Acts::copySign(1.*
m_endcapDiscZ, projPos[1])).value_or(10. * Gaudi::Units::km);
385 return projPos + lambda * projDir;
422 std::vector<Estimate> estimates{};
423 const double weightNorm {force12.mag() + force23.mag()};
425 estimates.emplace_back(
getPtimesQ(force12, p2.second - p1.second), force12.mag()/weightNorm, 0.);
426 estimates.emplace_back(
getPtimesQ(force23, p3.second - p2.second), force23.mag()/weightNorm, 0.);
428 const double weight13 {force13.mag()/weightNorm};
429 estimates.emplace_back(
getPtimesQ(force13, p3.second - p1.second), weight13, 0.);
432 estimates.emplace_back(
getPtimesQ(force13, t23 - t12), weight13, 0.);
434 for (std::size_t i {0}; i < estimates.size(); ++i) {
435 Estimate& est1 {estimates[i]};
436 for (std::size_t j {i+1}; j < estimates.size(); ++j) {
437 Estimate& est2 {estimates[j]};
438 double agreementScore {(chargeAgree(est1.PtimesQ, est2.PtimesQ) ? 1. : -1.) -
439 momentumDev(est1.PtimesQ, est2.PtimesQ)};
442 est1.score += est2.weight * agreementScore;
443 est2.score += est1.weight * agreementScore;
448 const double minScore {std::ranges::min_element(estimates,
449 {}, &Estimate::score)->score};
450 for (Estimate& est : estimates) {
451 est.score -= minScore;
453 if (msgLvl(MSG::VERBOSE)) {
454 std::vector<std::string> names {
"Pair01",
"Pair12",
"Pair02Seg",
"Pair02Pos"};
455 for (
const auto [i, est] : Acts::enumerate(estimates)) {
456 ATH_MSG_VERBOSE(__func__<<
"() Estimate "<<names[i]<<
": PtimesQ: "<<est.PtimesQ*1e-3
457 <<
", weight: "<<est.weight<<
", score: "<<est.score);
462 const Estimate& bestEstimate {*std::ranges::max_element(estimates,
463 std::ranges::less{}, [](
const Estimate& est){
464 return est.score * est.weight;})};
465 const double charge {std::copysign(1., bestEstimate.PtimesQ)};
467 double totalSum {0.}, totalWeight {0.};
468 for (
const Estimate& est : estimates) {
471 if (&est == &estimates.back()) {
474 if (chargeAgree(est.PtimesQ,
charge)) {
475 totalSum += est.PtimesQ * est.weight;
476 totalWeight += est.weight;
479 assert(totalWeight > Acts::s_epsilon);
480 return totalSum / totalWeight;
488 p2.second - p1.second);
494 const auto& [pos1, dir1] = point1;
495 const auto& [pos2, dir2] = point2;
498 <<
inDeg(dir1.theta())<<
" / "<<
inDeg(dir1.phi())<<
" to "
499 <<
inDeg(dir2.theta())<<
" / "<<
inDeg(dir2.phi()));
504 const Amg::Vector3D extPos {(1. - fieldStep) * pos1 + fieldStep * pos2};
505 const Amg::Vector3D extDir {((1. - fieldStep) * dir1 + fieldStep * dir2).
unit()};
507 fieldCache.
getField(extPos.data(), locField.data());
508 const Amg::Vector3D locForce {locField.dot(planeNorm) * extDir.cross(planeNorm)};
509 accumForce += locForce;
513 <<
" / "<<
inDeg(extDir.phi())<<
" --> local |B|: "<<locField.mag()*1e3
514 <<
" [T]"<<
", |Bnorm|: "<<locField.dot(planeNorm)*Gaudi::Units::GeV
515 <<
" [T], local |v x Bnorm|: "<<locForce.mag()*Gaudi::Units::GeV<<
" [T].");
519 return accumForce * dS;
523 const double PtimesQ {0.3 * Gaudi::Units::GeV * forceIntegral.mag2() / deltaDir.dot(forceIntegral)};
525 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - estimateQtimesP() force integral: "<<forceIntegral.mag()<<
" [T*m], deltaDir: "
526 <<deltaDir.mag()<<
", cos: "<<deltaDir.dot(forceIntegral)/ (deltaDir.mag() * forceIntegral.mag())
527 <<
", PtimesQ: "<<PtimesQ/Gaudi::Units::GeV <<
" [GeV].");
536 if (!canEstimateQtimesP(seed)) {
537 ATH_MSG_WARNING(__func__<<
"() "<<__LINE__<<
" Cannot estimate q*p from seed "<<seed
538 <<
" - insufficient inner/middle/outer layer coverage.");
543 double deltaPhiAcc {0.};
544 std::optional<double> centralPhi {};
545 unsigned nSegsWithPhi{0};
547 if (segment->nPhiLayers() > 0) {
548 const double segPhi {segment->position().phi()};
549 if (!centralPhi) centralPhi = segPhi;
554 const double circPhi {nSegsWithPhi > 0
556 : seed.sector().phi()};
558 <<
inDeg(circPhi)<<
" [deg], nSegsWithPhi: "<<nSegsWithPhi);
560 std::array<const xAOD::MuonSegment*, 3> segmentsToUse{};
569 segmentsToUse[0] = segment;
574 segmentsToUse[1] = segment;
579 segmentsToUse[2] = segment;
586 unsigned nSegments = std::ranges::count_if(segmentsToUse,
592 auto missingSeg = std::ranges::find(segmentsToUse,
nullptr);
598 assert(missingSeg != segmentsToUse.end());
599 *missingSeg = segment;
601 if (nSegments == 3) {
604 missingSeg = std::ranges::find(segmentsToUse,
nullptr);
607 if (!seg1 || !seg2) {
608 return seg1 !=
nullptr;
613 const Amg::Vector3D planeNorm {Acts::makeDirectionFromPhiTheta(circPhi + 90._degree, 90._degree)};
619 return std::make_pair(projSegPos,
620 Acts::makeDirectionFromPhiTheta(circPhi, seg->
direction().theta()));
624 const Acts::TrackingVolume* volume{
629 <<
" - Failed to find tracking volume for seed measurement "<<
volumeId(firstSurf));
630 return std::make_pair(projSegPos,
631 Acts::makeDirectionFromPhiTheta(circPhi, seg->
direction().theta()));
639 const double tanAlpha {- (locNormal.y() * tanBeta + locNormal.z()) / locNormal.x()};
640 const Amg::Vector3D newDir = volume->localToGlobalTransform(tgContext).linear() *
641 Acts::makeDirectionFromAxisTangents(tanAlpha, tanBeta);
643 return std::make_pair(projSegPos, newDir);
645 return nSegments == 3
646 ?
estimateQtimesP(planeNorm, point(segmentsToUse[0]), point(segmentsToUse[1]), point(segmentsToUse[2]), magField)
647 :
estimateQtimesP(planeNorm, point(segmentsToUse[0]), point(segmentsToUse[1]), magField);
654 const unsigned segSector = segment->
sector();
655 for (
const auto proj : {SectorProjector::leftOverlap,
656 SectorProjector::center,
657 SectorProjector::rightOverlap}) {
662 <<
" is not in sector "<<projSector);
670 std::array<double, 3> coords{Acts::filledArray<double, 3>(0.)};
675 coords[Acts::toUnderlying(
eDetSection)] = Acts::copySign(Acts::toUnderlying(loc), refPoint[1]);
677 coords[Acts::toUnderlying(
ePosOnCylinder)] = refPoint[Location::Barrel == loc];
679 <<
" with "<<coords<<
" to the search tree");
680 outContainer.emplace_back(std::move(coords), segment);
686 rawData.reserve(3*segments.
size());
688 appendSegment(tgContext, segment, Location::Barrel, rawData);
689 appendSegment(tgContext, segment, Location::Endcap, rawData);
691 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Create a new tree with "<<rawData.size()<<
" entries. ");
695 std::vector<MsTrackSeed>& outputSeeds)
const {
699 const Acts::GeometryContext tgContext =
m_ctxProvider.getGeometryContext(ctx);
703 for (
const auto& [coords, seedCandidate] : orderedSegs) {
706 if (!
m_segSelector->passSeedingQuality(ctx, *seedCandidate)){
707 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Segment "<<
::print(*seedCandidate)<<
" does not pass the seeding quality.");
711 SearchTree_t::range_t selectRange{};
720 selectRange[Acts::toUnderlying(
eSector)].shrink(coords[Acts::toUnderlying(
eSector)] -0.25,
721 coords[Acts::toUnderlying(
eSector)] +0.25);
726 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Search for compatible segments to "<<
::print(*seedCandidate)<<
".");
727 orderedSegs.rangeSearchMapDiscard(selectRange, [&](
728 const SearchTree_t::coordinate_t& ,
731 if (!
m_segSelector->compatibleForTrack(ctx, *seedCandidate, *extendWithMe)) {
736 return extendWithMe->chamberIndex() == onSeed->chamberIndex();
738 if (itr == newSeed.
segments().end()){
742 else if (reducedChi2(**itr) > reducedChi2(*extendWithMe) &&
743 (*itr)->nPhiLayers() <= extendWithMe->
nPhiLayers()) {
746 <<
::print(*extendWithMe)<<
" on seed due to better chi2.");
760 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Reject seed with segments in the same station.");
773 +
z * Amg::Vector3D::UnitZ();
776 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Add new seed "<<newSeed);
777 trackSeeds.emplace_back(std::move(newSeed));
779 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Found in total "<<trackSeeds.size()<<
" before overlap removal");
782 outputSeeds.insert(outputSeeds.end(), std::make_move_iterator(trackSeeds.begin()),
783 std::make_move_iterator(trackSeeds.end()));
784 return StatusCode::SUCCESS;
791 return a.segments().size() > b.segments().size();
794 outputSeeds.reserve(unresolved.size());
795 std::ranges::copy_if(std::move(unresolved), std::back_inserter(outputSeeds),
801 const std::size_t sharedSegs = std::ranges::count_if(testMe.
segments(),
803 return Acts::rangeContainsValue(good.segments(), segInTest);
805 if (sharedSegs == testMe.
segments().size()) {
812 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Found in total "<<outputSeeds.size()<<
" after overlap removal");
Scalar mag() const
mag method
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_WARNING(x,...)
#define ATH_MSG_VERBOSE(x,...)
double charge(const T &p)
detray::unit< scalar_t > unit
void print(char *figname, TCanvas *c1)
double angle(const GeoTrf::Vector2D &a, const GeoTrf::Vector2D &b)
constexpr float inDeg(const float rad)
size_type size() const noexcept
Returns the number of elements in the collection.
Local cache for magnetic field (based on MagFieldServices/AtlasFieldSvcTLS.h).
void getField(const double *ATH_RESTRICT xyz, double *ATH_RESTRICT bxyz, double *ATH_RESTRICT deriv=nullptr)
get B field value at given position xyz[3] is in mm, bxyz[3] is in kT if deriv[9] is given,...
A spectrometer sector forms the envelope of all chambers that are placed in the same MS sector & laye...
const Acts::PlaneSurface & surface() const
Returns the associated surface.
Amg::Vector3D normalDir() const
Returns the vector that is normal to the plane spanned by the expanded sector.
std::int8_t sector() const
Returns the expanded sector number.
bool isNeighbour(const ExpandedSector &other) const
Returns true if the expanded sector is a neighbour of the other.
Amg::Vector3D radialDir() const
Returns the vector pointing radially along the sector plane.
void addSegment(const xAOD::MuonSegment *seg)
Append a segment to the seed.
Location location() const
Returns the location of the seed.
ExpandedSector sector() const
Returns the seed's sector.
std::span< const xAOD::MuonSegment *const > segments() const
Returns the vector of associated segments.
void replaceSegment(const xAOD::MuonSegment *exist, const xAOD::MuonSegment *updated)
Replaces an already added segment in the seed with a better suited one.
void setPosition(Amg::Vector3D &&pos)
set the seed's position
float numberDoF() const
Returns the numberDoF.
Amg::Vector3D direction() const
Returns the direction as Amg::Vector.
std::uint8_t nPrecisionHits() const
Returns the number of precision hits.
::Muon::MuonStationIndex::TechnologyIndex technology() const
Returns the main technology of the segment.
::Muon::MuonStationIndex::ChIndex chamberIndex() const
Returns the chamber index.
Amg::Vector3D position() const
Returns the position as Amg::Vector.
int etaIndex() const
Returns the eta index, which corresponds to stationEta in the offline identifiers (and the ).
std::uint8_t nPhiLayers() const
Returns the number of trigger phi hits.
constexpr double energyToActs(const double athenaE)
Converts an energy scalar from Athena to Acts units.
Acts::Vector4 convertPosToActs(const Amg::Vector3D &athenaPos, const double athenaTime=0.)
Converts a position vector & time from Athena units into Acts units.
std::optional< double > intersect(const AmgVector(N)&posA, const AmgVector(N)&dirA, const AmgVector(N)&posB, const AmgVector(N)&dirB)
Calculates the point B' along the line B that's closest to a second line A.
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
Eigen::Affine3d Transform3D
Eigen::Matrix< double, 2, 1 > Vector2D
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.
const Acts::TrackingVolume * highestAlignable(const Acts::TrackingVolume *volume)
Returns the highest parent volume that is alignable.
float reducedChi2(const xAOD::MuonSegment &segment)
Acts::BoundTrackParameters boundSegmentPars(const ActsTrk::GeometryContext &gctx, const MuonGMR4::MuonDetectorManager &detMgr, const xAOD::MuonSegment &segment, const Acts::ParticleHypothesis hypot=Acts::ParticleHypothesis::muon())
Returns the segment parameters as boundTrackParameters.
Parameters localSegmentPars(const xAOD::MuonSegment &seg)
Returns the localSegPars decoration from a xAODMuon::Segment.
This header ties the generic definitions in this package.
std::vector< MsTrackSeed > MsTrackSeedContainer
std::string printID(const xAOD::MuonSegment &seg)
Print the chamber ID of a segment, e.g.
const xAOD::UncalibratedMeasurement * getMeasurement(const xAOD::MuonSegment &segment, const std::size_t n)
Returns the n-th uncalibrated measurement.
double houghTanBeta(const Amg::Vector3D &v)
Returns the hough tanBeta [y] / [z].
std::size_t nMeasurements(const xAOD::MuonSegment &segment)
Returns the number of associated Uncalibrated measurements.
Acts::GeometryIdentifier volumeId(const Acts::Surface &surface)
Returns the identifier of the volume in which the surface is embedded.
bool isOutlierMeasurement(const xAOD::MuonSegment &segment, const std::size_t n)
Returns whether the n-the uncalibrated measurement is an outlier.
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.
double houghTanAlpha(const Amg::Vector3D &v)
: Returns the hough tanAlpha [x] / [z]
MsTrackSeederTool::SearchTree_t SearchTree_t
constexpr float inDeg(const float rad)
ChIndex chIndex(const std::string &index)
convert ChIndex name string to enum
StIndex toStationIndex(ChIndex index)
convert ChIndex into StIndex
bool isBarrel(const ChIndex index)
Returns true if the chamber index points to a barrel chamber.
LayerIndex
enum to classify the different layers in the muon spectrometer
LayerIndex toLayerIndex(ChIndex index)
convert ChIndex into LayerIndex
ChIndex
enum to classify the different chamber layers in the muon spectrometer
double deltaPhi(double phiA, double phiB)
delta Phi in range [-pi,pi[
const T * get(const ReadCondHandleKey< T > &key, const EventContext &ctx)
Convenience function to retrieve an object given a ReadCondHandleKey.
void swap(ElementLinkVector< DOBJ > &lhs, ElementLinkVector< DOBJ > &rhs)
UncalibratedMeasurement_v1 UncalibratedMeasurement
Define the version of the uncalibrated measurement class.
MuonSegmentContainer_v1 MuonSegmentContainer
Definition of the current "MuonSegment container version".
bool isPrecisionHit(const UncalibratedMeasurement *meas)
Returns whether the measurement is a precision hit.
MuonSegment_v1 MuonSegment
Reference the current persistent version:
const Acts::Surface & muonSurface(const UncalibratedMeasurement *meas)
Returns the associated Acts surface to the measurement.
Tell the compiler to optimize assuming that FP may trap.
#define CXXUTILS_TRAPPING_FP