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 inline double momentumDev(
double PtimesQ1,
double PtimesQ2) {
28 const double denom {std::max(std::abs(PtimesQ1) + std::abs(PtimesQ2), Acts::s_epsilon)};
29 return std::abs(PtimesQ1 - PtimesQ2) /
denom;
40 return angle / Gaudi::Units::deg;
56 return StatusCode::FAILURE;
63 return StatusCode::SUCCESS;
66 Acts::Result<Acts::BoundTrackParameters>
69 const Acts::GeometryContext tgContext =
m_ctxProvider.getGeometryContext(ctx);
70 const Acts::MagneticFieldContext mfContext =
m_ctxProvider.getMagneticFieldContext(ctx);
75 Acts::BoundMatrix cov{Acts::BoundMatrix::Zero()};
83 if (!refSeg && !isNswSegment(*segment) &&
89 if (!boundPars.covariance()) {
92 for (
int i =0 ; i < cov.cols(); ++i) {
93 cov(i,i) += (*boundPars.covariance())(i,i);
100 if (isNswSegment(*segment) &&
103 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - NSW is the best what we have apparently....");
111 <<
" - No reference segment passing the seeding quality was found.");
112 return Acts::Result<Acts::BoundTrackParameters>::failure(std::make_error_code(std::errc::invalid_argument));
117 <<
" theta/phi: "<<
inDeg(seedPos.theta())<<
" / "<<
inDeg(seedPos.phi())
119 <<
" theta/phi: "<<
inDeg(seedDir.theta())<<
" / "<<
inDeg(seedDir.phi()));
125 const Acts::GeometryIdentifier volId =
volumeId(firstSurf);
132 <<
" - Failed to find tracking volume for seed measurement "<<volId);
133 return Acts::Result<Acts::BoundTrackParameters>::failure(std::make_error_code(std::errc::invalid_argument));
136 <<
" - Bounding volume "<<volume->volumeName()
137 <<
", trf: "<<
Amg::toString(volume->localToGlobalTransform(tgContext))
138 <<
", bounds: "<<volume->volumeBounds());
142 if (frontSegment != refSeg) {
144 const Acts::Transform3 toFirstTrf = firstSurf.localToGlobalTransform(tgContext).inverse();
145 const Amg::Vector3D locFrontSegPos = toFirstTrf * frontSegPos;
146 if (!volume->inside(tgContext, frontSegPos)) {
148 <<
" not inside mother volume: "<<volume->volumeName()<<
", "
149 <<
Amg::toString(volume->globalToLocalTransform(tgContext)*frontSegPos)
150 <<
", bounds: "<<volume->volumeBounds()<<
", "
155 const Acts::Transform3& toLoc{volume->globalToLocalTransform(tgContext)};
158 seedDir = volume->localToGlobalTransform(tgContext).linear() *
159 Acts::makeDirectionFromAxisTangents(
houghTanAlpha(locSeedDir),
161 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Updated seed direction theta/phi: "
162 <<
inDeg(seedDir.theta())<<
" / "<<
inDeg(seedDir.phi()));
167 const Acts::MultiIntersection firstIsect = firstSurf.intersect(tgContext, seedPos, seedDir,
168 Acts::BoundaryTolerance::Infinite());
169 const Amg::Vector3D locSeedAtFirst = toFirstTrf * firstIsect.at(0).position();
170 if (firstSurf.type() == Acts::Surface::SurfaceType::Straw) {
171 const auto& bounds =
static_cast<const Acts::LineBounds&
>(firstSurf.bounds());
172 using enum Acts::LineBounds::BoundValues;
175 const Amg::Vector3D locStartPos{locFrontSegPos.x(), locFrontSegPos.y(),
176 std::clamp(locSeedAtFirst.z(), -bounds.get(eHalfLengthZ), bounds.get(eHalfLengthZ))};
177 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - The first surface is a straw "
178 <<bounds<<
", track seed @first: "<<
Amg::toString(locSeedAtFirst)<<
" vs. segment @first: "
180 seedPos = firstSurf.localToGlobalTransform(tgContext) * locStartPos;
181 }
else if (firstSurf.type() == Acts::Surface::SurfaceType::Plane) {
182 if (isNswSegment(*frontSegment)) {
183 seedPos = frontSegPos;
187 Acts::Vector2 locStartPos2D {locFrontSegPos.x(), locSeedAtFirst.y()};
188 const auto& bounds = firstSurf.bounds();
189 switch (bounds.type()) {
190 case Acts::SurfaceBounds::BoundsType::eRectangle:
191 if (!bounds.inside(locStartPos2D)) {
192 locStartPos2D = bounds.closestPoint(locStartPos2D, Acts::SquareMatrix2::Identity());
195 case Acts::SurfaceBounds::BoundsType::eTrapezoid:
196 case Acts::SurfaceBounds::BoundsType::eDiamond:
198 std::swap(locStartPos2D.x(), locStartPos2D.y());
199 if (!bounds.inside(locStartPos2D)) {
200 locStartPos2D = bounds.closestPoint(locStartPos2D, Acts::SquareMatrix2::Identity());
202 std::swap(locStartPos2D.x(), locStartPos2D.y());
205 ATH_MSG_WARNING(__func__<<
"() "<<__LINE__<<
" - Unexpected surface bounds type "
206 <<firstSurf.bounds().type());
207 return Acts::Result<Acts::BoundTrackParameters>::failure(std::make_error_code(std::errc::invalid_argument));
209 const Amg::Vector3D locStartPos {locStartPos2D.x(),locStartPos2D.y(), locFrontSegPos.z()};
211 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - The first surface is a plane with bounds "
212 <<firstSurf.bounds() <<
", track seed @first: "<<
Amg::toString(locSeedAtFirst)<<
" vs. segment @first: "
214 seedPos = firstSurf.localToGlobalTransform(tgContext) * locStartPos;
217 ATH_MSG_WARNING(__func__<<
"() "<<__LINE__<<
" - Unexpected surface type "<<firstSurf.type());
218 return Acts::Result<Acts::BoundTrackParameters>::failure(std::make_error_code(std::errc::invalid_argument));
221 <<
" theta/phi: "<<
inDeg(seedPos.theta())<<
" / "<<
inDeg(seedPos.phi()));
227 ATH_MSG_WARNING(__func__<<
"() "<<__LINE__<<
" - Failed to find boundary surface for tracking volume");
228 return Acts::Result<Acts::BoundTrackParameters>::failure(std::make_error_code(std::errc::invalid_argument));
230 std::shared_ptr<const Acts::Surface> targetSurf{};
235 auto propagateToBoundary = [&](
const Acts::Surface& volBoundary) -> Acts::Result<Amg::Vector3D> {
237 const Acts::Transform3& trf{volBoundary.localToGlobalTransform(tgContext)};
238 using namespace Acts::PlanarHelper;
239 auto pIsect = intersectPlane(seedPos, seedDir, trf.linear().col(
Amg::z), trf.translation());
241 if (pIsect.pathLength() > Acts::s_epsilon || !pIsect.isValid()) {
243 <<
" is forward "<<pIsect.pathLength()<<
" or invalid "<<(!pIsect.isValid())
244 <<
" within volume "<<volume->inside(tgContext, pIsect.position()));
245 return Acts::Result<Amg::Vector3D>::failure(std::make_error_code(std::errc::invalid_argument));
247 Acts::Result<Amg::Vector2D> locPos = volBoundary.globalToLocal(tgContext, pIsect.position(),
248 Amg::Vector3D::Zero());
250 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Intersection is not on surface "<<
252 return Acts::Result<Amg::Vector3D>::failure(std::make_error_code(std::errc::invalid_argument));
254 if (!volBoundary.insideBounds(*locPos)) {
255 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Intersection is outside the boundaries: "<<
257 return Acts::Result<Amg::Vector3D>::failure(std::make_error_code(std::errc::invalid_argument));
259 targetSurf = volBoundary.getSharedPtr();
260 return Acts::Result<Amg::Vector3D>::success(pIsect.position());
263 auto pIsect = propagateToBoundary(*boundSurf);
267 if (!pIsect.ok() && volume->isAlignable()) {
268 const Acts::VolumePlacementBase* placement = volume->volumePlacement();
269 for (std::size_t portal = 0; !pIsect.ok() && portal< placement->nPortalPlacements(); ++portal) {
270 pIsect = propagateToBoundary(placement->portalPlacement(portal)->surface());
274 ATH_MSG_WARNING(__func__<<
"() "<<__LINE__<<
" - Cannot create valid start parameters from seed "<<seed<<
".");
275 return Acts::Result<Acts::BoundTrackParameters>::failure(std::make_error_code(std::errc::invalid_argument));
278 <<
" eta/phi: "<<pIsect->eta()<<
" / "<<(
inDeg(pIsect->phi())));
284 cov (Acts::eBoundQOverP, Acts::eBoundQOverP) = Acts::square(momRes * qOverP);
286 return Acts::BoundTrackParameters::create(tgContext, targetSurf,
287 fourPos, seedDir, qOverP, cov,
288 Acts::ParticleHypothesis::muon());
296 for (std::size_t meas = 0; meas < nMeas; ++ meas) {
303 localToGlobalTransform(tgContext).linear().col(
Amg::x);
312 return Acts::PlanarHelper::intersectPlane(segment.
position(), wireDir,
313 planeNormal, Amg::Vector3D::Zero()).position();
329 <<
", direction: "<<
Amg::toString(dir)<<
" sector projector: " << sector
330 <<
" location: " << Acts::toUnderlying(loc));
335 if (Location::Barrel == loc) {
341 Acts::copySign(1.*
m_endcapDiscZ, projPos[1])).value_or(10. * Gaudi::Units::km);
345 return projPos + lambda * projDir;
382 std::vector<Estimate> estimates{};
383 const double weightNorm {force12.mag() + force23.mag()};
385 estimates.emplace_back(
getPtimesQ(force12, p2.second - p1.second), force12.mag()/weightNorm, 0.);
386 estimates.emplace_back(
getPtimesQ(force23, p3.second - p2.second), force23.mag()/weightNorm, 0.);
388 const double weight13 {force13.mag()/weightNorm};
389 estimates.emplace_back(
getPtimesQ(force13, p3.second - p1.second), weight13, 0.);
392 estimates.emplace_back(
getPtimesQ(force13, t23 - t12), weight13, 0.);
394 for (std::size_t i {0}; i < estimates.size(); ++i) {
395 Estimate& est1 {estimates[i]};
396 for (std::size_t j {i+1}; j < estimates.size(); ++j) {
397 Estimate& est2 {estimates[j]};
398 double agreementScore {std::copysign(1., est1.PtimesQ*est2.PtimesQ) -
399 momentumDev(est1.PtimesQ, est2.PtimesQ)};
402 est1.score += est2.weight * agreementScore;
403 est2.score += est1.weight * agreementScore;
408 const double minScore {std::ranges::min_element(estimates,
409 {}, &Estimate::score)->score};
410 for (Estimate& est : estimates) {
411 est.score -= minScore;
413 if (msgLvl(MSG::VERBOSE)) {
414 std::vector<std::string> names {
"Pair01",
"Pair12",
"Pair02Seg",
"Pair02Pos"};
415 for (
const auto [i, est] : Acts::enumerate(estimates)) {
416 ATH_MSG_VERBOSE(__func__<<
"() Estimate "<<names[i]<<
": PtimesQ: "<<est.PtimesQ*1e-3
417 <<
", weight: "<<est.weight<<
", score: "<<est.score);
422 const Estimate& bestEstimate {*std::ranges::max_element(estimates,
423 std::ranges::less{}, [](
const Estimate& est){
424 return est.score * est.weight;})};
425 const double charge {std::copysign(1., bestEstimate.PtimesQ)};
427 double totalSum {0.}, totalWeight {0.};
428 for (
const Estimate& est : estimates) {
431 if (&est == &estimates.back()) {
434 if (est.PtimesQ *
charge > 0.) {
435 totalSum += est.PtimesQ * est.weight;
436 totalWeight += est.weight;
439 assert(totalWeight > Acts::s_epsilon);
440 return totalSum / totalWeight;
448 p2.second - p1.second);
454 const auto& [pos1, dir1] = point1;
455 const auto& [pos2, dir2] = point2;
458 <<
inDeg(dir1.theta())<<
" / "<<
inDeg(dir1.phi())<<
" to "
459 <<
inDeg(dir2.theta())<<
" / "<<
inDeg(dir2.phi()));
464 const Amg::Vector3D extPos {(1. - fieldStep) * pos1 + fieldStep * pos2};
465 const Amg::Vector3D extDir {((1. - fieldStep) * dir1 + fieldStep * dir2).
unit()};
467 fieldCache.
getField(extPos.data(), locField.data());
468 const Amg::Vector3D locForce {locField.dot(planeNorm) * extDir.cross(planeNorm)};
469 accumForce += locForce;
473 <<
" / "<<
inDeg(extDir.phi())<<
" --> local |B|: "<<locField.mag()*1e3
474 <<
" [T]"<<
", |Bnorm|: "<<locField.dot(planeNorm)*Gaudi::Units::GeV
475 <<
" [T], local |v x Bnorm|: "<<locForce.mag()*Gaudi::Units::GeV<<
" [T].");
479 return accumForce * dS;
483 const double PtimesQ {0.3 * Gaudi::Units::GeV * forceIntegral.mag2() / deltaDir.dot(forceIntegral)};
485 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - estimateQtimesP() force integral: "<<forceIntegral.mag()<<
" [T*m], deltaDir: "
486 <<deltaDir.mag()<<
", cos: "<<deltaDir.dot(forceIntegral)/ (deltaDir.mag() * forceIntegral.mag())
487 <<
", PtimesQ: "<<PtimesQ/Gaudi::Units::GeV <<
" [GeV].");
496 double deltaPhiAcc {0.};
497 std::optional<double> centralPhi {};
498 unsigned nSegsWithPhi{0};
500 if (segment->nPhiLayers() > 0) {
501 const double segPhi {segment->position().phi()};
502 if (!centralPhi) centralPhi = segPhi;
507 const double circPhi {nSegsWithPhi > 0
509 : seed.sector().phi()};
511 <<
inDeg(circPhi)<<
" [deg], nSegsWithPhi: "<<nSegsWithPhi);
513 std::array<const xAOD::MuonSegment*, 3> segmentsToUse{};
522 segmentsToUse[0] = segment;
527 segmentsToUse[1] = segment;
532 segmentsToUse[2] = segment;
539 unsigned nSegments = std::ranges::count_if(segmentsToUse,
545 auto missingSeg = std::ranges::find(segmentsToUse,
nullptr);
551 assert(missingSeg != segmentsToUse.end());
552 *missingSeg = segment;
554 if (nSegments == 3) {
557 missingSeg = std::ranges::find(segmentsToUse,
nullptr);
560 if (!seg1 || !seg2) {
561 return seg1 !=
nullptr;
566 const Amg::Vector3D planeNorm {Acts::makeDirectionFromPhiTheta(circPhi + 90._degree, 90._degree)};
572 return std::make_pair(projSegPos,
573 Acts::makeDirectionFromPhiTheta(circPhi, seg->
direction().theta()));
577 const Acts::TrackingVolume* volume{
582 <<
" - Failed to find tracking volume for seed measurement "<<
volumeId(firstSurf));
583 return std::make_pair(projSegPos,
584 Acts::makeDirectionFromPhiTheta(circPhi, seg->
direction().theta()));
586 const Acts::Transform3& toLoc {volume->globalToLocalTransform(tgContext)};
592 const double tanAlpha {- (locNormal.y() * tanBeta + locNormal.z()) / locNormal.x()};
593 const Amg::Vector3D newDir = volume->localToGlobalTransform(tgContext).linear() *
594 Acts::makeDirectionFromAxisTangents(tanAlpha, tanBeta);
596 return std::make_pair(projSegPos, newDir);
601 point(segmentsToUse[1]), point(segmentsToUse[2]), magField);
603 return estimateQtimesP(planeNorm, point(segmentsToUse[0]), point(segmentsToUse[1]), magField);
607 return 6.*Gaudi::Units::TeV;
614 const unsigned segSector = segment->
sector();
615 for (
const auto proj : {SectorProjector::leftOverlap,
616 SectorProjector::center,
617 SectorProjector::rightOverlap}) {
622 <<
" is not in sector "<<projSector);
630 std::array<double, 3> coords{Acts::filledArray<double, 3>(0.)};
635 coords[Acts::toUnderlying(
eDetSection)] = Acts::copySign(Acts::toUnderlying(loc), refPoint[1]);
637 coords[Acts::toUnderlying(
ePosOnCylinder)] = refPoint[Location::Barrel == loc];
639 <<
" with "<<coords<<
" to the search tree");
640 outContainer.emplace_back(std::move(coords), segment);
646 rawData.reserve(3*segments.
size());
648 appendSegment(tgContext, segment, Location::Barrel, rawData);
649 appendSegment(tgContext, segment, Location::Endcap, rawData);
651 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Create a new tree with "<<rawData.size()<<
" entries. ");
655 std::vector<MsTrackSeed>& outputSeeds)
const {
659 const Acts::GeometryContext tgContext =
m_ctxProvider.getGeometryContext(ctx);
663 for (
const auto& [coords, seedingSeg] : orderedSegs) {
668 <<
" does not pass the seeding quality.");
672 SearchTree_t::range_t selectRange{};
681 selectRange[Acts::toUnderlying(
eSector)].shrink(coords[Acts::toUnderlying(
eSector)] -0.25,
682 coords[Acts::toUnderlying(
eSector)] +0.25);
690 orderedSegs.rangeSearchMapDiscard(selectRange, [&](
691 const SearchTree_t::coordinate_t& ,
694 if (!
m_segSelector->compatibleForTrack(ctx, *seedingSeg, *extendWithMe)) {
701 if (newSeed.
stations().size() < 2) {
713 +
z * Amg::Vector3D::UnitZ();
716 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Add new seed "<<newSeed);
717 trackSeeds.emplace_back(std::move(newSeed));
719 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Found in total "<<trackSeeds.size()<<
" before overlap removal");
722 outputSeeds.insert(outputSeeds.end(), std::make_move_iterator(trackSeeds.begin()),
723 std::make_move_iterator(trackSeeds.end()));
724 return StatusCode::SUCCESS;
728 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Check whether \n"<<seedCand
729 <<
"\n has two segments on the same station");
730 const auto seedSegments = seedCand.
segments();
732 if (seedSegments.size() == seedCand.
stations().size()) {
735 for (std::size_t seg = 1 ; seg < seedSegments.size(); ++seg) {
736 for (std::size_t seg1 = 0 ; seg1 < seg; ++seg1) {
737 if (seedSegments[seg]->chamberIndex() == seedSegments[seg1]->chamberIndex()) {
738 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Found two segments in the same station on the seed \n"
751 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Select the seeds amongst "
752 <<unsplitted.size()<<
" seed candidates which can be split");
754 std::ranges::copy_if(unsplitted, std::back_inserter(seedsToSplit),
759 if (seedsToSplit.empty()) {
763 auto [begin , end] = std::ranges::remove_if(unsplitted, [
this](
const MsTrackSeed& seedCand){
766 unsplitted.erase(begin, end);
770 std::vector<SegVec_t> splitSeedSegs{};
773 segsPerStation[Acts::toUnderlying(seg->
chamberIndex())].push_back(seg);
781 if (splitSeedSegs.empty()) {
783 splitSeedSegs.emplace_back(std::vector{seg});
788 else if (
vec.size() == 1) {
789 for (
SegVec_t& appendMe : splitSeedSegs) {
790 appendMe.push_back(
vec.front());
796 if (
a->nPrecisionHits() != b->nPrecisionHits()) {
797 return a->nPrecisionHits() > b->nPrecisionHits();
799 return a->nPhiLayers() > b->nPhiLayers();
802 std::vector<SegVec_t> expandMe{std::move(splitSeedSegs)};
803 splitSeedSegs.reserve(expandMe.size() *
vec.size());
805 for (
const SegVec_t& expand : expandMe) {
806 splitSeedSegs.emplace_back(expand).push_back(seg);
815 <<splitMe<<
"\n into "<<splitSeedSegs.size()<<
" seeds.");
816 for (
SegVec_t splitted : splitSeedSegs){
817 unsplitted.push_back(
MsTrackSeed{splitMe.location(), splitMe.sector()});
819 unsplitted.back().addSegment(seg);
821 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Created new "<<unsplitted.back());
823 splitSeedSegs.clear();
832 std::array<std::uint8_t, Acts::toUnderlying(StIndex::StIndexMax)> sharedCounter{};
838 for(std::size_t b{0}; shared == 0 && b< seedB.
segments().
size(); ++b){
844 std::uint8_t shared{0};
845 for (std::uint8_t n : sharedCounter) {
855 if (
a.index() == b.index()) {
856 return a.nPrecisionHits();
858 if (
a.chamberIndex() != b.chamberIndex() ||
a.sector() != b.sector() ||
859 a.etaIndex() != b.etaIndex()) {
862 if (
a.nPrecisionHits() > b.nPrecisionHits()) {
875 for (std::size_t hitB = 0 ; hitB <
nMeasurements(b); ++hitB) {
889 return a.segments().size() > b.segments().size();
891 auto [begin, end] = std::ranges::unique(unresolved,
893 const auto segsA =
a.segments();
894 const auto segsB = b.segments();
895 if (segsA.size() == segsB.size()) {
896 for (std::size_t s = 0 ; s < segsA.size(); ++s) {
897 if (segsA[s] != segsB[s]) {
902 }
else if (segsA.size() < segsB.size()) {
904 return Acts::rangeContainsValue(segsB, seg);
908 return Acts::rangeContainsValue(segsA, seg);
911 unresolved.erase(begin, end);
913 std::shared_ptr<std::uint8_t> overlapMarker{};
914 for (std::size_t seed = 0; seed < outputSeeds.size(); ++seed) {
916 for (std::size_t seed1 = seed +1 ;seed1 < outputSeeds.size(); ++seed1) {
917 unsigned shared =
countShared(outputSeeds.at(seed),
918 outputSeeds.at(seed1));
921 overlapMarker = std::make_shared<std::uint8_t>(0);
922 outputSeeds.at(seed).prepareOverlap(overlapMarker);
924 outputSeeds.at(seed1).prepareOverlap(overlapMarker);
927 overlapMarker.reset();
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)
std::vector< size_t > vec
detray::unit< scalar_t > unit
size_t size() const
Number of registered mappings.
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.
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 Muon::MuonStationIndex::StIndex > stations() const
The station indices of the associated sements.
std::span< const xAOD::MuonSegment *const > segments() const
Returns the vector of associated segments.
void setPosition(Amg::Vector3D &&pos)
set the seed's position
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.
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::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.
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
const xAOD::UncalibratedMeasurement * getMeasurement(const xAOD::MuonSegment &segment, const std::size_t n)
Returns the n-th uncalibrated measurement.
std::string printSegment(const xAOD::MuonSegment &seg)
Print the details of a segment.
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.
MsTrackSeederTool::SegVec_t SegVec_t
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.