11#include "Acts/Utilities/Helpers.hpp"
12#include "Acts/Definitions/Tolerance.hpp"
13#include "Acts/Definitions/Units.hpp"
14#include "Acts/Geometry/TrackingGeometry.hpp"
16#include "Acts/Surfaces/LineBounds.hpp"
17#include "Acts/Surfaces/PlaneSurface.hpp"
23#include "GaudiKernel/PhysicalConstants.h"
26 using namespace Acts::UnitLiterals;
28 constexpr bool chargeAgree(
double PtimesQ1,
double PtimesQ2) {
29 return PtimesQ1 * PtimesQ2 > 0;
32 inline double momentumDev(
double PtimesQ1,
double PtimesQ2) {
33 const double denom {std::max(std::abs(PtimesQ1) + std::abs(PtimesQ2), Acts::s_epsilon)};
34 return std::abs(PtimesQ1 - PtimesQ2) /
denom;
42 return std::format(
"{:}, nPrecHits: {:}, nPhiHits: {:}",
MuonR4::printID(seg),
67 return StatusCode::FAILURE;
74 return StatusCode::SUCCESS;
77 Acts::Result<Acts::BoundTrackParameters>
80 const Acts::GeometryContext tgContext =
m_ctxProvider.getGeometryContext(ctx);
81 const Acts::MagneticFieldContext mfContext =
m_ctxProvider.getMagneticFieldContext(ctx);
86 Acts::BoundMatrix cov{Acts::BoundMatrix::Zero()};
94 if (!refSeg && !isNswSegment(*segment) &&
100 if (!boundPars.covariance()) {
103 for (
int i =0 ; i < cov.cols(); ++i) {
104 cov(i,i) += (*boundPars.covariance())(i,i);
111 if (isNswSegment(*segment) &&
114 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - NSW is the best what we have apparently....");
122 <<
" - No reference segment passing seeding quality was found.");
123 return Acts::Result<Acts::BoundTrackParameters>::failure(std::make_error_code(std::errc::invalid_argument));
128 <<
", dir: "<<
Amg::toString(seedDir) <<
" eta " << seedDir.eta() <<
" phi "
129 << (seedDir.phi() /Gaudi::Units::degree) );
134 const Acts::GeometryIdentifier volId =
volumeId(firstSurf);
141 <<
" - Failed to find tracking volume for seed measurement "<<volId);
142 return Acts::Result<Acts::BoundTrackParameters>::failure(std::make_error_code(std::errc::invalid_argument));
145 <<
" - Bounding volume "<<volume->volumeName()
146 <<
", trf: "<<
Amg::toString(volume->localToGlobalTransform(tgContext))
147 <<
", bounds: "<<volume->volumeBounds());
151 if (frontSegment != refSeg) {
153 const Amg::Transform3D toFirstTrf = firstSurf.localToGlobalTransform(tgContext).inverse();
154 const Amg::Vector3D locFrontSegPos = toFirstTrf * frontSegPos;
155 if (!volume->inside(tgContext, frontSegPos)) {
157 <<
" not inside mother volume: "<<volume->volumeName()<<
", "
158 <<
Amg::toString(volume->globalToLocalTransform(tgContext)*frontSegPos)
159 <<
", bounds: "<<volume->volumeBounds()<<
", "
167 seedDir = volume->localToGlobalTransform(tgContext).linear() *
168 Acts::makeDirectionFromAxisTangents(
houghTanAlpha(locSeedDir),
174 const Acts::MultiIntersection firstIsect = firstSurf.intersect(tgContext, seedPos, seedDir,
175 Acts::BoundaryTolerance::Infinite());
176 const Amg::Vector3D locAtFirst = toFirstTrf * firstIsect.at(0).position();
177 if (firstSurf.type() == Acts::Surface::SurfaceType::Straw) {
178 const auto& bounds =
static_cast<const Acts::LineBounds&
>(firstSurf.bounds());
179 using enum Acts::LineBounds::BoundValues;
182 const Amg::Vector3D locStartPos{locFrontSegPos.x(), locFrontSegPos.y(),
183 std::clamp(locAtFirst.z(), -bounds.get(eHalfLengthZ), bounds.get(eHalfLengthZ))};
184 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - The first surface is a straw "
185 <<bounds<<
", track seed @first: "<<
Amg::toString(locAtFirst)<<
" vs. segment @first: "
187 seedPos = firstSurf.localToGlobalTransform(tgContext) * locStartPos;
188 }
else if (firstSurf.type() == Acts::Surface::SurfaceType::Plane) {
189 if (isNswSegment(*frontSegment)) {
190 seedPos = frontSegPos;
192 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - The first surface is a straw "
195 ATH_MSG_WARNING(__func__<<
"() "<<__LINE__<<
" - Unexpected surface type "<<firstSurf.type());
196 return Acts::Result<Acts::BoundTrackParameters>::failure(std::make_error_code(std::errc::invalid_argument));
204 ATH_MSG_WARNING(__func__<<
"() "<<__LINE__<<
" - Failed to find boundary surface for tracking volume");
205 return Acts::Result<Acts::BoundTrackParameters>::failure(std::make_error_code(std::errc::invalid_argument));
207 std::shared_ptr<const Acts::Surface> targetSurf{};
212 auto propagateToBoundary = [&](
const Acts::Surface& volBoundary) -> Acts::Result<Amg::Vector3D> {
215 using namespace Acts::PlanarHelper;
216 auto pIsect = intersectPlane(seedPos, seedDir, trf.linear().col(
Amg::z), trf.translation());
218 if (pIsect.pathLength() > Acts::s_epsilon || !pIsect.isValid()) {
220 <<
" is forward "<<pIsect.pathLength()<<
" or invalid "<<(!pIsect.isValid())
221 <<
" within volume "<<volume->inside(tgContext, pIsect.position()));
222 return Acts::Result<Amg::Vector3D>::failure(std::make_error_code(std::errc::invalid_argument));
224 Acts::Result<Amg::Vector2D> locPos = volBoundary.globalToLocal(tgContext, pIsect.position(),
225 Amg::Vector3D::Zero());
227 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Intersection is not on surface "<<
229 return Acts::Result<Amg::Vector3D>::failure(std::make_error_code(std::errc::invalid_argument));
231 if (!volBoundary.insideBounds(*locPos)) {
232 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Intersection is outside the boundaries: "<<
234 return Acts::Result<Amg::Vector3D>::failure(std::make_error_code(std::errc::invalid_argument));
236 targetSurf = volBoundary.getSharedPtr();
237 return Acts::Result<Amg::Vector3D>::success(pIsect.position());
240 auto pIsect = propagateToBoundary(*boundSurf);
244 if (!pIsect.ok() && volume->isAlignable()) {
245 const Acts::VolumePlacementBase* placement = volume->volumePlacement();
246 for (std::size_t portal = 0; !pIsect.ok() && portal< placement->nPortalPlacements(); ++portal) {
247 pIsect = propagateToBoundary(placement->portalPlacement(portal)->surface());
251 ATH_MSG_WARNING(__func__<<
"() "<<__LINE__<<
" Cannot create valid start parameters from seed "<<seed<<
".");
252 return Acts::Result<Acts::BoundTrackParameters>::failure(std::make_error_code(std::errc::invalid_argument));
258 cov (Acts::eBoundQOverP, Acts::eBoundQOverP) = Acts::square(0.8 * qOverP);
259 return Acts::BoundTrackParameters::create(tgContext, targetSurf,
260 fourPos, seedDir, qOverP, cov,
261 Acts::ParticleHypothesis::muon());
268 for (std::size_t meas = 0; meas < nMeas; ++ meas) {
278 localToGlobalTransform(tgContext).linear().col(
Amg::x);
287 return Acts::PlanarHelper::intersectPlane(segment.
position(), wireDir,
288 planeNormal, Amg::Vector3D::Zero()).position();
304 <<
", direction: "<<
Amg::toString(dir)<<
" sector projector: " << sector
305 <<
" location: " << Acts::toUnderlying(loc));
310 if (Location::Barrel == loc) {
316 Acts::copySign(1.*
m_endcapDiscZ, projPos[1])).value_or(10. * Gaudi::Units::km);
320 return projPos + lambda * projDir;
339 std::span<const PosMomPair_t> circlePoints)
const {
340 const Acts::MagneticFieldContext mfContext =
m_ctxProvider.getMagneticFieldContext(ctx);
343 if (circlePoints.size() < 2 || circlePoints.size() > 3){
344 ATH_MSG_WARNING(__func__<<
"() "<<__LINE__<<
" - Invalid number of circle points passed: "<<circlePoints.size());
345 constexpr double straightLine = 10._TeV;
348 return circlePoints.size() == 3 ?
estimateQtimesP(planeNorm, circlePoints[0], circlePoints[1], circlePoints[2], magField)
349 :
estimateQtimesP(planeNorm, circlePoints[0], circlePoints[1], magField);
352 const PosMomPair_t& p1,
353 const PosMomPair_t& p2,
354 const PosMomPair_t& p3,
371 std::vector<Estimate> estimates{};
372 const double weightNorm {force12.mag() + force23.mag()};
374 estimates.emplace_back(
getPtimesQ(force12, p2.second - p1.second), force12.mag()/weightNorm, 0.);
375 estimates.emplace_back(
getPtimesQ(force23, p3.second - p2.second), force23.mag()/weightNorm, 0.);
377 const double weight13 {force13.mag()/weightNorm};
378 estimates.emplace_back(
getPtimesQ(force13, p3.second - p1.second), weight13, 0.);
381 estimates.emplace_back(
getPtimesQ(force13, t23 - t12), weight13, 0.);
383 for (std::size_t i {0}; i < estimates.size(); ++i) {
384 Estimate& est1 {estimates[i]};
385 for (std::size_t j {i+1}; j < estimates.size(); ++j) {
386 Estimate& est2 {estimates[j]};
388 double w {std::min(est1.weight, est2.weight)};
389 double chargeScore {chargeAgree(est1.PtimesQ, est2.PtimesQ) ? 1. : -1.};
390 double pDevPenalty {momentumDev(est1.PtimesQ, est2.PtimesQ)};
392 est1.score += w * (chargeScore - pDevPenalty);
393 est2.score += w * (chargeScore - pDevPenalty);
396 if (msgLvl(MSG::VERBOSE)) {
397 std::vector<std::string> names {
"Pair01",
"Pair12",
"Pair02Seg",
"Pair02Pos"};
398 for (
const auto& [i, est] : Acts::enumerate(estimates)) {
399 ATH_MSG_VERBOSE(__func__<<
"() Estimate "<<names[i]<<
": PtimesQ: "<<est.PtimesQ*1e-3
400 <<
", weight: "<<est.weight<<
", score: "<<est.score);
405 const Estimate& bestEstimate {*std::ranges::max_element(estimates,
406 std::ranges::less{}, &Estimate::score)};
407 const double charge {std::copysign(1., bestEstimate.PtimesQ)};
409 double totalSum {0.}, totalWeight {0.};
410 for (
const Estimate& est : estimates) {
411 if (chargeAgree(est.PtimesQ,
charge)) {
412 totalSum += est.PtimesQ * est.weight;
413 totalWeight += est.weight;
416 assert(totalWeight > Acts::s_epsilon);
417 return totalSum / totalWeight;
420 const PosMomPair_t& p1,
421 const PosMomPair_t& p2,
425 p2.second - p1.second);
428 const PosMomPair_t& point2,
431 const auto& [pos1, dir1] = point1;
432 const auto& [pos2, dir2] = point2;
439 const Amg::Vector3D extPos {(1. - fieldStep) * pos1 + fieldStep * pos2};
440 const Amg::Vector3D extDir {((1. - fieldStep) * dir1 + fieldStep * dir2).
unit()};
442 fieldCache.
getField(extPos.data(), locField.data());
443 const Amg::Vector3D locForce {locField.dot(planeNorm) * extDir.cross(planeNorm)};
444 accumForce += locForce;
448 <<
" --> local |B|: "<<locField.mag()*1e3 <<
" [T]"<<
", |Bnorm|: "<<locField.dot(planeNorm)*1e3
449 <<
" [T], local |v x Bnorm|: "<<locForce.mag()*1e3<<
" [T].");
453 return accumForce * dS;
457 const double PtimesQ {0.3 * Gaudi::Units::GeV * forceIntegral.mag2() / deltaDir.dot(forceIntegral)};
459 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - estimateQtimesP() force integral: "<<forceIntegral.mag()<<
" [T*m], deltaDir: "
460 <<deltaDir.mag()<<
", cos: "<<deltaDir.dot(forceIntegral)/ (deltaDir.mag() * forceIntegral.mag())
461 <<
", PtimesQ: "<<PtimesQ/Gaudi::Units::GeV <<
" [GeV].");
470 double deltaPhiAcc {0.};
471 std::optional<double> centralPhi {};
472 unsigned nSegsWithPhi{0};
474 if (segment->nPhiLayers() > 0) {
475 if (!centralPhi) centralPhi = segment->position().phi();
480 const double circPhi {nSegsWithPhi > 0
482 : seed.sector().phi()};
484 std::array<const xAOD::MuonSegment*, 3> segmentsToUse{};
493 segmentsToUse[0] = segment;
498 segmentsToUse[1] = segment;
503 segmentsToUse[2] = segment;
510 unsigned nSegments = std::ranges::count_if(segmentsToUse,
516 auto missingSeg = std::ranges::find(segmentsToUse,
nullptr);
522 assert(missingSeg != segmentsToUse.end());
523 *missingSeg = segment;
525 if (nSegments == 3) {
528 missingSeg = std::ranges::find(segmentsToUse,
nullptr);
531 if (!seg1 || !seg2) {
532 return seg1 !=
nullptr;
537 const Amg::Vector3D planeNorm {Acts::makeDirectionFromPhiTheta(circPhi + 90._degree, 90._degree)};
542 return nSegments == 3
543 ?
estimateQtimesP(planeNorm, point(segmentsToUse[0]), point(segmentsToUse[1]), point(segmentsToUse[2]), magField)
544 :
estimateQtimesP(planeNorm, point(segmentsToUse[0]), point(segmentsToUse[1]), magField);
551 const unsigned segSector = segment->
sector();
552 for (
const auto proj : {SectorProjector::leftOverlap,
553 SectorProjector::center,
554 SectorProjector::rightOverlap}) {
559 <<
" is not in sector "<<projSector);
567 std::array<double, 3> coords{Acts::filledArray<double, 3>(0.)};
572 coords[Acts::toUnderlying(
eDetSection)] = Acts::copySign(Acts::toUnderlying(loc), refPoint[1]);
574 coords[Acts::toUnderlying(
ePosOnCylinder)] = refPoint[Location::Barrel == loc];
576 <<
" with "<<coords<<
" to the search tree");
577 outContainer.emplace_back(std::move(coords), segment);
583 rawData.reserve(3*segments.
size());
585 appendSegment(tgContext, segment, Location::Barrel, rawData);
586 appendSegment(tgContext, segment, Location::Endcap, rawData);
588 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Create a new tree with "<<rawData.size()<<
" entries. ");
592 std::vector<MsTrackSeed>& outputSeeds)
const {
596 const Acts::GeometryContext tgContext =
m_ctxProvider.getGeometryContext(ctx);
600 for (
const auto& [coords, seedCandidate] : orderedSegs) {
603 if (!
m_segSelector->passSeedingQuality(ctx, *seedCandidate)){
604 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Segment "<<
::print(*seedCandidate)<<
" does not pass the seeding quality.");
608 SearchTree_t::range_t selectRange{};
617 selectRange[Acts::toUnderlying(
eSector)].shrink(coords[Acts::toUnderlying(
eSector)] -0.25,
618 coords[Acts::toUnderlying(
eSector)] +0.25);
623 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Search for compatible segments to "<<
::print(*seedCandidate)<<
".");
624 orderedSegs.rangeSearchMapDiscard(selectRange, [&](
625 const SearchTree_t::coordinate_t& ,
628 if (!
m_segSelector->compatibleForTrack(ctx, *seedCandidate, *extendWithMe)) {
633 return extendWithMe->chamberIndex() == onSeed->chamberIndex();
635 if (itr == newSeed.
segments().end()){
639 else if (reducedChi2(**itr) > reducedChi2(*extendWithMe) &&
640 (*itr)->nPhiLayers() <= extendWithMe->
nPhiLayers()) {
643 <<
::print(*extendWithMe)<<
" on seed due to better chi2.");
657 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Reject seed with segments in the same station.");
670 +
z * Amg::Vector3D::UnitZ();
673 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Add new seed "<<newSeed);
674 trackSeeds.emplace_back(std::move(newSeed));
676 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Found in total "<<trackSeeds.size()<<
" before overlap removal");
679 outputSeeds.insert(outputSeeds.end(), std::make_move_iterator(trackSeeds.begin()),
680 std::make_move_iterator(trackSeeds.end()));
681 return StatusCode::SUCCESS;
688 return a.segments().size() > b.segments().size();
691 outputSeeds.reserve(unresolved.size());
692 std::ranges::copy_if(std::move(unresolved), std::back_inserter(outputSeeds),
698 const std::size_t sharedSegs = std::ranges::count_if(testMe.
segments(),
700 return Acts::rangeContainsValue(good.segments(), segInTest);
702 if (sharedSegs == testMe.
segments().size()) {
709 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Found in total "<<outputSeeds.size()<<
" after overlap removal");
Scalar mag() const
mag method
const PlainObject unit() const
This is a plugin that makes Eigen look like CLHEP & defines some convenience methods.
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
double charge(const T &p)
void print(char *figname, TCanvas *c1)
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
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.
virtual xAOD::UncalibMeasType type() const =0
Returns the type of the measurement type as a simple enumeration.
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.
Amg::Vector3D projectDirOntoPlane(const Amg::Vector3D &direction, const Amg::Vector3D &planeNorm)
Project the direction vector onto the plane and renormalize to unity.
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.
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
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.
bool isNSW(const UncalibMeasType aodType)
Returns whether the measurement is a NSW measurement.
UncalibratedMeasurement_v1 UncalibratedMeasurement
Define the version of the uncalibrated measurement class.
MuonSegmentContainer_v1 MuonSegmentContainer
Definition of the current "MuonSegment container version".
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