10#include "Acts/Utilities/Logger.hpp"
25 return angle / Gaudi::Units::deg;
30 using namespace Acts::UnitLiterals;
36 :
position{localToGlobal *
sp->localPosition()},
41 if (!
sp->measuresEta()) {
43 const Amg::Vector3D phiMeasDir {localToGlobal.rotation() * sp->toNextSensor()};
45 phiCov =
sp->covariance()[Acts::toUnderlying(CovIdx::phiCov)] *
46 Acts::square(phiMeasDir.dot(phiGradient(
position)));
49 const auto& surfLinearTrf =
xAOD::muonSurface(
sp->primaryMeasurement()).localToGlobalTransform(gctx).linear();
54 double& discCov = stripAngle;
55 discCov = Acts::square(
sp->driftRadius()) +
56 sp->covariance()[Acts::toUnderlying(CovIdx::etaCov)];
58 if (
sp->measuresPhi()) {
59 phiCov = discCov / Acts::square(position.perp()) +
60 Acts::square(sensorDir(gctx).
dot(phiGradient(position))) *
61 (
sp->covariance()[Acts::toUnderlying(CovIdx::phiCov)] - discCov);
63 }
else if (
sp->measuresPhi()) {
67 auto oneDimContribution = [&](CovIdx idx,
const Amg::Vector3D& measDir) ->
double {
68 return sp->covariance()[Acts::toUnderlying(idx)] *
69 Acts::square(measDir.dot(gradPhi));
74 const Amg::Vector3D etaMeasDir = localToGlobal.rotation() *
sp->toNextSensor();
77 const double c {etaMeasDir.dot(phiMeasDir)};
78 if (std::abs(c) > Acts::s_epsilon) {
79 stripAngle = std::atan2(etaMeasDir.dot(phiSensorDir), c);
80 nonOrthogonalStrips =
true;
82 phiCov = oneDimContribution(CovIdx::etaCov, etaMeasDir) +
83 oneDimContribution(CovIdx::phiCov, phiMeasDir);
86 phiCov = oneDimContribution(CovIdx::etaCov, etaMeasDir) +
87 oneDimContribution(CovIdx::phiCov, phiMeasDir);
92 const auto& surfLinearTrf =
96 return surfLinearTrf.col(
Amg::z);
102 return surfLinearTrf.col(
Amg::y);
108 const bool isProjected)
const {
112 assert(isProjected || std::abs(contractionVector.mag() - 1.0) < Acts::s_epsilon);
117 assert(
sp->measuresPhi());
118 const double vDotRsq {Acts::square(
sensorDir(gctx).
dot(contractionVector))};
119 return discCov * (1 - vDotRsq) +
120 vDotRsq *
spacePoint->covariance()[Acts::toUnderlying(CovIdx::phiCov)];
125 return discCov * contractionVector.mag2();
130 auto oneDimContribution = [&](CovIdx idx,
const Amg::Vector3D& measDir) ->
double {
131 return spacePoint->covariance()[Acts::toUnderlying(idx)] *
132 Acts::square(measDir.dot(contractionVector));
137 : surfLinearTrf.col(
Amg::x)};
139 return oneDimContribution(CovIdx::etaCov, etaMeasDir) +
140 oneDimContribution(CovIdx::phiCov, phiMeasDir);
143 return oneDimContribution(CovIdx::etaCov, etaMeasDir);
145 throw std::runtime_error(
"Phi only hits are not meant to be used for residual computation.");
153 const std::int8_t expSector,
155 const Acts::Logger*
logger)
165 hitsPerStation[Acts::toUnderlying(seed->station)].push_back(seed);
181 ACTS_VERBOSE(__func__<<
"() Test hit phi "<<testHit->
position.phi()
182 <<
" not compatible with "<<
brief(*
this));
191 double accWindow {
cfg->nResidualSigma *
res.sigma};
198 if (
res.residual < accWindow) {
199 res.result = decision;
203 std::make_pair(std::tan(
lineDir.theta()), accWindow);
213 ACTS_VERBOSE(__func__<<
"() Test hit is the same as last inserted hit - reject.");
217 ACTS_VERBOSE(__func__<<
"() Test hit on same layer as seed with no prior hits - reject.");
231 const auto& closestStIt = std::ranges::min_element(
hitsPerStation, std::ranges::less{},
232 [&refHit](
const auto& hits){
233 if (hits.empty() || hits.front()->station == refHit->
station) {
234 return std::numeric_limits<int>::max();
236 return std::abs(hits.front().globLayer - refHit.
globLayer);
240 const auto& hits {*closestStIt};
241 lineAnchorHit = *std::ranges::min_element(hits, std::ranges::less{},
257 leverArm < cfg->minHitDistance4Line;
268 ACTS_VERBOSE(__func__<<
"() Updated --> linePos R/z/theta: "<<
linePos.perp()<<
" / "<<
linePos.z()
283 const double KdotD {K.dot(
lineDir)};
286 res.residual = R.mag();
287 if (
res.residual < Acts::s_epsilon) {
289 res.residual = std::numeric_limits<double>::max();
295 const double alpha {KdotD /
leverArm};
298 double phiPlaneDerivativeAcc {0.};
300 double residualCovAcc {0.};
319 const double preFactor,
320 bool isProjected) ->
void {
323 residualCovAcc += Acts::square(preFactor) *
324 hit.residualVariance(gctx, resDir,
false);
328 const double projFactor {sensorDir.dot(resDir) /
332 residualCovAcc += Acts::square(preFactor)
333 *
hit.residualVariance(gctx, trfDir,
true);
334 phiPlaneDerivativeAcc += preFactor * pos.perp() * projFactor;
339 const double covS1 =
cfg->beamSpotLength * Acts::square(resDir.z()) +
340 cfg->beamSpotRadius * (1 - Acts::square(resDir.z()));
341 residualCovAcc += Acts::square(alpha - 1) * covS1;
351 covarianceTerm(*testHit, testPos, 1., projectTestHit);
353 res.sigma = std::sqrt(residualCovAcc + Acts::square(phiPlaneDerivativeAcc) *
patPhiCov);
355 ACTS_VERBOSE(__func__<<
"() "<<
brief(*
this)<<
"\nUse beamspot: "<<
useBeamspot
356 <<
", alpha: "<<alpha<<
", Residual: "<<
res.residual<<
" +- "<<
res.sigma
359 <<
", testPos R/theta/phi: "<<testPos.perp()<<
" / "<<
inDeg(testPos.theta())<<
" / "<<
inDeg(testPos.phi())
360 <<
", resDir theta/phi: "<<
inDeg(resDir.theta())<<
" / "<<
inDeg(resDir.phi())
361 <<
", hit pos sigma: "<<std::sqrt(residualCovAcc)
362 <<
", phi plane sigma: "<<std::abs(phiPlaneDerivativeAcc)*std::sqrt(
patPhiCov));
367 return Acts::PlanarHelper::intersectPlane(
hit.position,
hit.sensorDir(gctx),
378 ACTS_VERBOSE(__func__<<
"() No phi hits in the pattern, set pattern phi to "
382 double sumSin{0.}, sumCos{0.}, sumWeight{0.};
384 auto processPhiHit = [&sumSin, &sumCos, &sumWeight](
const HitPayload&
hit){
385 if (!
hit->measuresPhi()) {
388 if (
hit.phiCov < Acts::s_epsilon) {
389 std::stringstream
ss {};
390 ss <<
"Unexpected to have a phi hit with zero variance in phi direction: " << *
hit.spacePoint <<
"\n";
391 throw std::runtime_error(
ss.str());
393 const double w = 1./
hit.phiCov;
395 const double phi {
hit.position.phi()};
396 sumSin += w * std::sin(
phi);
397 sumCos += w * std::cos(
phi);
401 for (
const auto&
hit : hits) {
409 patPhi = std::atan2(sumSin, sumCos);
412 ACTS_VERBOSE(__func__<<
"() Updated pattern phi to "
419 const double testPhi {
hit.position.phi()};
421 const double deltaPhiSigma {std::sqrt(
patPhiCov +
hit.phiCov)};
423 if (std::abs(
deltaPhi) >
cfg->nPhiSigma * deltaPhiSigma) {
425 <<
" is not compatible with the test hit with phi "<<
inDeg(testPhi) <<
" +- "<<
inDeg(std::sqrt(
hit.phiCov)));
429 const unsigned sector1 {
expSect.msSector()};
430 const unsigned sector2 {
expSect.adjacentMsSector()};
431 const bool isCompatible {sector1 == sector2
435 ACTS_VERBOSE(__func__<<
"() The test hit with phi = "<<
inDeg(testPhi)
436 <<
" is not inside the pattern sectors: "<<sector1<<
" and "<<sector2);
443 const double residual,
444 const double resSigma) {
452 if (
hit.sp()->measuresPhi()) {
473 const double newResidual,
474 const double newResSigma) {
477 throw std::runtime_error(std::format(
478 "Trying to overwrite a hit in station/layer {}/{} with another one from station/layer {}/{}",
485 std::stringstream
ss {};
486 ss <<
"Trying to overwrite a hit with incompatible type\n";
489 throw std::runtime_error(
ss.str());
500 bool updatePhi {
false};
521 std::stringstream
ss {};
522 ss <<
"Trying to overwrite a hit that is not the last inserted hit in station/layer "
525 ss <<
"Last hit in station: " << **stHits.back();
526 throw std::runtime_error(
ss.str());
531 stHits.push_back(newHit);
541 return std::ranges::find_if(hits,
549 (!onlyGoodStations || hits.size() >=
cfg->minStationLayers)) {
564 std::vector<const SpacePointBucket*>
566 std::vector<const SpacePointBucket*> buckets{};
568 for (
const auto&
hit : hits) {
569 if (std::ranges::find(buckets,
hit->bucket) == buckets.end()) {
570 buckets.push_back(
hit->bucket);
577 ostr<<
"PatternState Exp Sector: "<<
static_cast<int>(
expSect.sector())
582 ostr<<
", Hit per station: \n";
585 if (hits.empty())
continue;
587 ostr<<
" Station "<<
static_cast<StIndex>(st)<<
" has "<<hits.size()<<
" hits ";
590 for (
const auto&
hit : hits) {
591 ostr<<
" "<<
hit<<
"\n";
602 ostr<<*
sp()<<
", glob Z/R/phi: "<<
hit->position.z()<<
" / "<<
hit->position.perp()<<
" / "
603 <<
inDeg(
hit->position.phi())<<
", st: " <<
hit->station <<
", loc/glob lay: "
604 <<
static_cast<int>(
hit->locLayer)<<
"/"<<
static_cast<int>(
globLayer);
Scalar deltaPhi(const MatrixBase< Derived > &vec) const
Scalar phi() const
phi method
Scalar theta() const
theta method
std::pair< std::vector< unsigned int >, bool > res
double angle(const GeoTrf::Vector2D &a, const GeoTrf::Vector2D &b)
constexpr float inDeg(const float rad)
static PatternPrintView brief(const PatternState &p)
Print the pattern state with brief information.
Muon::MuonStationIndex::StIndex StIndex
Type alias for the station index.
static const int s_nStations
Number of stations.
static PatternPrintView detailed(const PatternState &p)
Print the pattern state with detailed information.
: The muon space point bucket represents a collection of points that will bre processed together in t...
The muon space point is the combination of two uncalibrated measurements one of them measures the eta...
bool measuresPhi() const
: Does the space point contain a phi measurement
xAOD::UncalibMeasType type() const
bool measuresEta() const
: Does the space point contain an eta measurement
double sectorOverlapPhi(int sector1, int sector2) const
returns the phi position of the overlap between the two sectors (which have to be neighboring) in rad...
bool insideSector(int sector, double phi) const
checks whether the phi position is consistent with sector
Eigen::Affine3d Transform3D
Eigen::Matrix< double, 3, 1 > Vector3D
LineTestDecision
: Enum for possible outcomes of pattern line compatibility test
@ eBranchPattern
Test successfull with multiple pattern hits on same layer, branch the pattern.
@ eAddHit
Test successfull, add hit to pattern.
constexpr float inDeg(const float rad)
const std::string & stName(StIndex index)
convert StIndex into a string
double deltaPhi(double phiA, double phiB)
delta Phi in range [-pi,pi[
const Acts::Surface & muonSurface(const UncalibratedMeasurement *meas)
Returns the associated Acts surface to the measurement.
Small wrapper for candidate hits used to build patterns.
void print(std::ostream &ostr) const
uint8_t globLayer
Global measurement layer number.
const SpacePoint * sp() const
const HitPayload * hit
Pointer to the underlying hit.
Configuration object for the patter finder.
Base class for hit struct containing hit information.
Amg::Vector3D position
Global position.
bool nonOrthogonalStrips
Are the strips non-orthogonal.
double phiCov
Cached angular covariance [rad^2] of the hit in the phi angle.
HitPayload(const Acts::GeometryContext &gctx, const SpacePoint *sp, const SpacePointBucket *bucket, const Amg::Transform3D &localToGlobal)
Constructor with parameters.
const SpacePoint * spacePoint
Pointer to the underlying hit.
const SpacePointBucket * bucket
Pointer to the parent bucket.
bool isPrecision
Is precision hit.
double residualVariance(const Acts::GeometryContext &gctx, const Amg::Vector3D &contractionVector, const bool isProjected) const
Hit contribution contribution to the residual variance due to its intrinsic position uncertainty.
Amg::Vector3D sensorDir(const Acts::GeometryContext &gctx) const
Sensor direction.
StIndex station
Station index.
bool operator==(const HitPayload &other) const
Equal operator: it compares the underlying hit.
double stripAngle
Strip angle when the strips are non-orthogonal.
A view of the pattern state for printing purposes.
Pattern state object storing pattern information during construction.
PatternState(const CandidateHit &seed, const std::int8_t expSector, const Config *cfg, const Acts::Logger *logger)
Constructor taking the seed information.
void moveLineAnchorHit(const CandidateHit &refHit)
Move the line anchor hit given a reference hit.
double lastResidual
Residual & residual uncertainty of the last inserted hit (needed when replacing a hit).
double meanNormResidual2
Mean over eta hits of the square of their residual divided by residual uncertainty.
Amg::Vector3D projToPhiPlane(const Acts::GeometryContext &gctx, const HitPayload &hit) const
Project a certain hit position onto the bending plane where the pattern is defined.
bool isInPattern(const HitPayload &hit) const
Check wheter a hit is present in the pattern.
void updateLineParameters(const Acts::GeometryContext &gctx, const Amg::Vector3D &beamSpot)
Update the line parameters based on the current hits.
uint8_t nStations(const bool onlyGoodStations) const
Method returning the number of stations.
double patPhiCov
Covariance of the pattern phi.
Amg::Vector3D linePos
Position and direction of the pattern line.
bool useBeamspot
Whether we used the beamspot to compute the line parameters.
double leverArm
Distance between the two points defining the pattern line.
bool needLineUpdate
Whether we need to update the pattern line the next time we find a hit in a new layer.
std::vector< HitPayload > phiOnlyHits
Array holding phi-only hits.
ExpandedSector expSect
expanded MS sector
std::vector< const SpacePointBucket * > getParentBuckets() const
Get the buckets associated with the pattern.
bool isFinalized
Flag to indicate if the pattern has been finalized.
Amg::Vector3D bendPlaneNorm
Normal vector to the bending plane where the pattern lies.
uint8_t nBendingLayers() const
Return the number of layers in bending coordinate.
Acts::CloneablePtr< PatHitVisual > visualInfo
Pointer to Visual Information for pattern visualization.
CandidateHit prevLayerHit
Last hit in the second-to-last layer.
const Acts::Logger * m_logger
Logger.
void addHit(const CandidateHit &hit, const double residual, const double resSigma)
Add a hit to the pattern and update the internal state.
std::array< std::vector< CandidateHit >, s_nStations > hitsPerStation
Map collection of hits per station.
void print(std::ostream &ostr, bool detailed) const
Print the pattern candidate.
LineTestRes checkLineComp(const Acts::GeometryContext &gctx, const CandidateHit &testHit, const Amg::Vector3D &beamSpot)
Method checking line compatibility of a test hit against the pattern.
CandidateHit lineAnchorHit
Line anchor hit.
bool isPhiCompatible(const HitPayload &hit) const
Method to check the phi compatibility of a test hit with a given pattern.
void updatePatternPhi()
Helper method to update the pattern phi and bending plane normal.
const Config * cfg
Pointer to cfg option.
void overWriteHit(const CandidateHit &newHit, const double newResidual, const double newResSigma)
Overwrite the hits on the last layer with the new one.
double patPhi
Pattern phi, which is the phi of the bending plane where the pattern lies.
const Acts::Logger & logger() const
Return the logger.
uint8_t nPrecisionLayers
Counts of precision / non-precision / phi layers.
CandidateHit lastInsertedHit
Last inserted hit.
LineTestRes computeLineResidual(const Acts::GeometryContext &gctx, const CandidateHit &testHit) const
Method to compute the residual of a test hit against the pattern line.
double getMeanResidual2() const
Return the mean normalized residual squared.
double patTheta
Pattern theta, which is the value of the seed hit.
: Small struct to encapsulate the result of the line compatibility test