ATLAS Offline Software
Loading...
Searching...
No Matches
MuonR4::SegmentFit::SegmentLineFitter Class Reference

The SegmentLineFitter is a standalone module to fit a straight line to calibrated muon space points. More...

#include <SegmentLineFitter.h>

Inheritance diagram for MuonR4::SegmentFit::SegmentLineFitter:
Collaboration diagram for MuonR4::SegmentFit::SegmentLineFitter:

Classes

struct  ConfigSwitches
 Configuration object of the ATLAS implementation. More...
struct  Config
 Full configuration object. More...

Public Types

using Fitter_t = Acts::Experimental::CompositeSpacePointLineFitter
 Abrivation of the actual line fitter.
using LinePar_t = Fitter_t::ParamVec_t
 Abrivation of the fitted line parameters.
using Hit_t = Segment::MeasType
 Abrivation of the space point type to use.
using HitVec_t = std::vector<Hit_t>
 Collection of space points.
using FitPars_t = Fitter_t::FitParameters
 Abrivation of the fit parameters.
using Result_t = Fitter_t::FitResult<HitVec_t>
 Abrivation of the fit result.
using FitOpts_t = Fitter_t::FitOptions<HitVec_t, ISpacePointCalibrator>
 Abrivation of the fit options.
using Selector_t = Fitter_t::Selector_t<CalibratedSpacePoint>
 Abrivation of the hit selector to choose valid hits.
using HitState = CalibratedSpacePoint::State
 Abrivation of the fit state flag.

Public Member Functions

 SegmentLineFitter (const std::string &name, Config &&config)
 Standard constructor.
std::unique_ptr< SegmentfitSegment (const EventContext &ctx, const SegmentSeed *parent, const LinePar_t &startPars, const Amg::Transform3D &localToGlobal, HitVec_t &&calibHits) const
 Fit a set of measurements to a straight segment line.
bool msgLvl (const MSG::Level lvl) const
 Test the output level.
MsgStream & msg () const
 The standard message stream.
MsgStream & msg (const MSG::Level lvl) const
 The standard message stream.
void setLevel (MSG::Level lvl)
 Change the current logging level.

Private Member Functions

Result_t callLineFit (const Acts::CalibrationContext &cctx, const Parameters &startPars, const Amg::Transform3D &localToGlobal, HitVec_t &&calibHits) const
 Calls the underlying line fitter to determine the segment parameters.
bool removeOutliers (const Acts::CalibrationContext &cctx, const SegmentSeed &seed, const Amg::Transform3D &localToGlobal, const LinePar_t &startPars, Result_t &fitResult) const
 Cleans the fitted segment from the most outlier hit and then attempts to refit the segment.
bool plugHoles (const Acts::CalibrationContext &cctx, const SegmentSeed &seed, const Amg::Transform3D &localToGlobal, Result_t &toRecover) const
 Recovery of missed hits.
void eraseWrongHits (Result_t &candidate) const
 Removes all hits from the segment which are obvious outliers.
void cleanStripLayers (HitVec_t &hits) const
 Marks duplicate hits on a strip layer as outliers to avoid competing contributions from the same layers in the fit.
bool betterResult (const Result_t &newResult, const Result_t &oldResult) const
 Returns whether the new fit result is better than the one from the previous iteration.
std::unique_ptr< SegmentconvertToSegment (const Amg::Transform3D &locToGlobTrf, const SegmentSeed *parentSeed, Result_t &&toConvert) const
 Converts the fit result into a segment object.
void initMessaging () const
 Initialize our message level and MessageSvc.

Private Attributes

Fitter_t m_fitter
 Actual implementation of the straight line fit.
ConfigSwitches m_cfg {}
 Configuration switches of the ATLAS fitter implementation.
Selector_t m_goodHitSel {}
 Selector to identify the valid hits.
std::string m_nm
 Message source name.
boost::thread_specific_ptr< MsgStream > m_msg_tls
 MsgStream instance (a std::cout like with print-out levels).
std::atomic< IMessageSvc * > m_imsg { nullptr }
 MessageSvc pointer.
std::atomic< MSG::Level > m_lvl { MSG::NIL }
 Current logging level.
std::atomic_flag m_initialized ATLAS_THREAD_SAFE = ATOMIC_FLAG_INIT
 Messaging initialized (initMessaging).

Detailed Description

The SegmentLineFitter is a standalone module to fit a straight line to calibrated muon space points.

The CompositeSpacePointLineFitter from the ACTS toolkit is used to perform the actual fit to the measurements. The SegmentLineFitter is a wrapper class taking care of relaunching fits of poor quality but with cleaned measurements and also to put back meaurements on the line that have been missed by the initial line fit.

Definition at line 28 of file SegmentLineFitter.h.

Member Typedef Documentation

◆ FitOpts_t

Abrivation of the fit options.

Definition at line 43 of file SegmentLineFitter.h.

◆ FitPars_t

using MuonR4::SegmentFit::SegmentLineFitter::FitPars_t = Fitter_t::FitParameters

Abrivation of the fit parameters.

Definition at line 39 of file SegmentLineFitter.h.

◆ Fitter_t

using MuonR4::SegmentFit::SegmentLineFitter::Fitter_t = Acts::Experimental::CompositeSpacePointLineFitter

Abrivation of the actual line fitter.

Definition at line 31 of file SegmentLineFitter.h.

◆ Hit_t

Abrivation of the space point type to use.

Definition at line 35 of file SegmentLineFitter.h.

◆ HitState

Abrivation of the fit state flag.

Definition at line 47 of file SegmentLineFitter.h.

◆ HitVec_t

Collection of space points.

Definition at line 37 of file SegmentLineFitter.h.

◆ LinePar_t

Abrivation of the fitted line parameters.

Definition at line 33 of file SegmentLineFitter.h.

◆ Result_t

Abrivation of the fit result.

Definition at line 41 of file SegmentLineFitter.h.

◆ Selector_t

Abrivation of the hit selector to choose valid hits.

Definition at line 45 of file SegmentLineFitter.h.

Constructor & Destructor Documentation

◆ SegmentLineFitter()

MuonR4::SegmentFit::SegmentLineFitter::SegmentLineFitter ( const std::string & name,
Config && config )

Standard constructor.

Parameters
nameName to be printed in the messaging
configFit configuration parameters

Definition at line 78 of file SegmentLineFitter.cxx.

78 :
81 m_cfg{config} {
82 m_goodHitSel.connect<isGoodHit>();
83 }
std::unique_ptr< const Acts::Logger > makeActsAthenaLogger(IMessageSvc *svc, const std::string &name, int level, std::optional< std::string > parent_name)
AthMessaging(IMessageSvc *msgSvc, const std::string &name)
Constructor.
Selector_t m_goodHitSel
Selector to identify the valid hits.
ConfigSwitches m_cfg
Configuration switches of the ATLAS fitter implementation.
Fitter_t m_fitter
Actual implementation of the straight line fit.
bool isGoodHit(const CalibratedSpacePoint &hit)
Returns whether the calibrated spacepoint is valid and therefore suitable to be used in the segment f...

Member Function Documentation

◆ betterResult()

bool MuonR4::SegmentFit::SegmentLineFitter::betterResult ( const Result_t & newResult,
const Result_t & oldResult ) const
inlineprivate

Returns whether the new fit result is better than the one from the previous iteration.

Selection criterion is the chi2 estimation for the same number of degrees of freedom and then the one which has more degree of freedom but still remains under the good segment threshold

Parameters
newResultThe first fit result
oldResultThe second fit result

Definition at line 405 of file SegmentLineFitter.cxx.

405 {
406 if (!newResult.converged) {
407 ATH_MSG_VERBOSE(__func__<<"() "<<__LINE__<<" The new result did not converge");
408 return false;
409 }
410 const double redChi2New = calcRedChi2(newResult);
411 const double redChi2Old = calcRedChi2(oldResult);
412 ATH_MSG_VERBOSE(__func__<<"() "<<__LINE__<<" Compare results -- old chi2: "<<redChi2Old<<", nDoF: "
413 <<oldResult.nDoF<<" vs. new chi2: "<<redChi2New<<", nDoF: "<<newResult.nDoF
414 <<" -- outlier removal: "<<m_cfg.outlierRemovalCut);
415 if (newResult.nDoF == oldResult.nDoF) {
416 return redChi2New < redChi2Old;
417 }
418 return (redChi2New < m_cfg.outlierRemovalCut && newResult.nDoF > oldResult.nDoF) ||
419 (redChi2New > m_cfg.outlierRemovalCut && redChi2New < redChi2Old);
420 }
#define ATH_MSG_VERBOSE(x)

◆ callLineFit()

Result_t MuonR4::SegmentFit::SegmentLineFitter::callLineFit ( const Acts::CalibrationContext & cctx,
const Parameters & startPars,
const Amg::Transform3D & localToGlobal,
HitVec_t && calibHits ) const
private

Calls the underlying line fitter to determine the segment parameters.

Parameters
cctxCalibration context to fetch later the measurement's calib constants from StoreGate (It's a packed EventContext*)
startParsInitial line parameters guess
localToGlobalTransform to align the segment's station inside ATLAS (Mainly neede if the time is fit)
calibHitsList of hits that will be fitted

Check whether a beamspot constraint should be appended

placeholder for a very generous beam spot: 300mm in X,Y (tracking volume), 20000 along Z

Recall that the time is not the same in Acts & Athena

Fit the measurements

Convert back to athena time units

Cache the chi2 terms of the measurements w.r.t. the segment

Definition at line 84 of file SegmentLineFitter.cxx.

87 {
88
90 bool appendsBS = m_cfg.doBeamSpot && countPhiHits(calibHits) > 0;
91
92
94 //check the degrees of freedom before try the fit
95 if (const std::size_t nPars = m_fitter.config().parsToUse.size(); nPars > 0ul) {
96 auto dOF = m_fitter.countDoF(calibHits, m_goodHitSel);
97 if (dOF.bending + dOF.nonBending < nPars) {
98 return result;
99 }
100 // check that there are at least two crossing stereo measurements
101 if (dOF.nonBending == 0ul && nPars == 4ul){
102 bool foundU{false}, foundV{false};
103 for (const HitVec_t::value_type& hit : calibHits) {
104 if (hit->type() != xAOD::UncalibMeasType::MMClusterType || !isGoodHit(*hit)) {
105 continue;
106 }
107 const auto* mmClust = dynamic_cast<const xAOD::MMCluster*>(hit->spacePoint()->primaryMeasurement());
108 assert(mmClust != nullptr);
109 const auto& design = mmClust->readoutElement()->stripLayer(mmClust->layerHash()).design();
110 if (!design.hasStereoAngle()) {
111 continue;
112 }
113 if (design.stereoAngle() > 0.) {
114 foundU = true;
115 } else {
116 foundV = true;
117 }
118 if (foundU && foundV) {
119 break;
120 }
121 }
122 if (!foundU || !foundV) {
123 result.measurements = std::move(calibHits);
124 result.parameters = startPars;
125 return result;
126 }
127 if (m_cfg.doBeamSpot) {
128 appendsBS = true;
129 }
130 }
131 }
132 if (appendsBS) {
133 const Amg::Transform3D globToLoc{localToGlobal.inverse()};
134 Amg::Vector3D beamSpot{globToLoc.translation()};
135 Amg::Vector3D beamLine{globToLoc.linear().col(2)};
136 SpacePoint::Cov_t covariance{};
137 covariance[toUnderlying(AxisDefs::etaCov)] = square(m_cfg.beamSpotRadius);
138 covariance[toUnderlying(AxisDefs::phiCov)] = square(m_cfg.beamSpotLength);
140 auto beamSpotSP = std::make_unique<CalibratedSpacePoint>(nullptr, std::move(beamSpot));
141 beamSpotSP->setBeamDirection(std::move(beamLine));
142 beamSpotSP->setCovariance(std::move(covariance));
143 ATH_MSG_VERBOSE(__func__<<"() - "<<__LINE__<<": Beam spot constraint "
144 <<Amg::toString(beamSpotSP->localPosition())<<", "<<beamSpotSP->covariance());
145 calibHits.emplace_back(std::move(beamSpotSP));
146 }
147 ATH_MSG_VERBOSE(__func__<<"() - "<<__LINE__ <<": Start segment fit with parameters "
148 <<toString(startPars) <<", plane location: "<<Amg::toString(localToGlobal)
149 <<std::endl<<print(calibHits));
150
151 FitOpts_t fitOpts{};
152 fitOpts.calibContext = cctx;
153 fitOpts.calibrator = m_cfg.calibrator;
154 fitOpts.selector = m_goodHitSel;
155
156 fitOpts.measurements = std::move(calibHits);
157 fitOpts.localToGlobal = localToGlobal;
158 fitOpts.startParameters = startPars;
160 constexpr auto t0idx = toUnderlying(ParamDefs::t0);
161 fitOpts.startParameters[t0idx] = ActsTrk::timeToActs(fitOpts.startParameters[t0idx]);
163 result = m_fitter.fit(std::move(fitOpts));
165 if (m_fitter.config().fitT0) {
166 result.parameters[t0idx] = ActsTrk::timeToAthena(result.parameters[t0idx]);
167 result.covariance(t0idx, t0idx) = Acts::square(ActsTrk::timeToAthena(1.)) * result.covariance(t0idx, t0idx);
168 for (ParamDefs p : {ParamDefs::x0, ParamDefs::y0, ParamDefs::phi, ParamDefs::theta}) {
169 auto pidx = toUnderlying(p);
170 result.covariance(t0idx, pidx) = ActsTrk::timeToAthena(result.covariance(t0idx, pidx));
171 result.covariance(pidx, t0idx) = ActsTrk::timeToAthena(result.covariance(pidx, t0idx));
172 }
173 }
175 {
176 const auto[segPos, segDir] = makeLine(result.parameters);
177 for (Hit_t& hit : result.measurements) {
178 hit->setChi2Term(SeedingAux::chi2Term(segPos, segDir, *hit));
179 }
180 }
181 return result;
182 }
Segment::MeasType Hit_t
Abrivation of the space point type to use.
Fitter_t::FitResult< HitVec_t > Result_t
Abrivation of the fit result.
Fitter_t::FitOptions< HitVec_t, ISpacePointCalibrator > FitOpts_t
Abrivation of the fit options.
std::array< double, 3 > Cov_t
Abrivation of the covariance type.
constexpr double timeToAthena(const double actsT)
Converts a time unit from Acts to Athena units.
constexpr double timeToActs(const double athenaT)
Converts a time unit from Athena to Acts units.
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
Eigen::Affine3d Transform3D
Eigen::Matrix< double, 3, 1 > Vector3D
SeedingAux::FitParIndex ParamDefs
Use the same parameter indices as used by the CompSpacePointAuxiliaries.
std::pair< Amg::Vector3D, Amg::Vector3D > makeLine(const Parameters &pars)
Returns the parsed parameters into an Eigen line parametrization.
std::string toString(const Parameters &pars)
Dumps the parameters into a string with labels in front of each number.
std::string print(const cont_t &container)
Print a space point container to string.
AthConfigFlags beamSpot(AthConfigFlags flags, str instanceName, str recoMode)
MMCluster_v1 MMCluster

◆ cleanStripLayers()

void MuonR4::SegmentFit::SegmentLineFitter::cleanStripLayers ( HitVec_t & hits) const
inlineprivate

Marks duplicate hits on a strip layer as outliers to avoid competing contributions from the same layers in the fit.

Hits on the same layer are sorted by their chi2 and the worse ones are rejected if they don't provide additional information

Parameters
hitsList of hit measurements to clean

We need to sort out strip hits on the same layer

Loop over the hits to mark the less compatible hits on the layer as outlier

Both hits measure eta. They've been sorted by lower chi2 -> reject b

Definition at line 337 of file SegmentLineFitter.cxx.

337 {
338 const SpacePointPerLayerSorter sorter{};
340 std::ranges::sort(hits, [&](const Hit_t&a ,const Hit_t& b){
341 if (a->isStraw() || b->isStraw()) {
342 return !a->isStraw();
343 }
344 if (a->type() == xAOD::UncalibMeasType::Other ||
345 b->type() == xAOD::UncalibMeasType::Other) {
346 return a->type() != xAOD::UncalibMeasType::Other;
347 }
348 const unsigned lay_a = sorter.sectorLayerNum(*a->spacePoint());
349 const unsigned lay_b = sorter.sectorLayerNum(*b->spacePoint());
350 if (lay_a != lay_b) {
351 return lay_a < lay_b;
352 }
353 const double chi2a = a->chi2Term();
354 const double chi2b = b->chi2Term();
355 /* Do not accept pad hits even though they've smaller chi2
356 * than the neighbouring strip */
358 const auto* sTgcA = static_cast<const xAOD::sTgcMeasurement*>(a->spacePoint()->primaryMeasurement());
359 const auto* sTgcB = static_cast<const xAOD::sTgcMeasurement*>(b->spacePoint()->primaryMeasurement());
360 if (sTgcA->channelType() == xAOD::sTgcMeasurement::sTgcChannelTypes::Pad &&
361 sTgcB->channelType() == xAOD::sTgcMeasurement::sTgcChannelTypes::Strip) {
362 return chi2b > m_cfg.recoveryPull;
363 } else if (sTgcB->channelType() == xAOD::sTgcMeasurement::sTgcChannelTypes::Pad &&
364 sTgcA->channelType() == xAOD::sTgcMeasurement::sTgcChannelTypes::Strip) {
365 return chi2a < m_cfg.recoveryPull;
366 }
367 }
368 return chi2a < chi2b;
369 });
370
371 ATH_MSG_VERBOSE(__func__<<"() - "<<__LINE__ <<": Check for duplicate strip hits");
373 for (HitVec_t::iterator itr = hits.begin(); itr != hits.end(); ++itr) {
374 const Hit_t& hit_a{*itr};
375 if (hit_a->isStraw()){
376 break;
377 }
378 if(hit_a->fitState() == HitState::Duplicate ||
379 hit_a->type() == xAOD::UncalibMeasType::Other) {
380 continue;
381 }
382 const unsigned lay_a = sorter.sectorLayerNum(*hit_a->spacePoint());
384 for (HitVec_t::iterator itr2 = itr + 1; itr2 != hits.end(); ++itr2) {
385 const Hit_t& hit_b{*itr2};
386 if (hit_b->type() == xAOD::UncalibMeasType::Other ||
387 hit_b->fitState() == HitState::Duplicate) {
388 continue;
389 }
390 if (lay_a != sorter.sectorLayerNum(*hit_b->spacePoint())) {
391 break;
392 }
394 if ((hit_a->measuresEta() && hit_b->measuresEta()) ||
395 (hit_a->measuresPhi() && hit_b->measuresPhi())) {
396 ATH_MSG_VERBOSE(__func__<<"() - "<<__LINE__ <<": Duplicate hit on same layer"<<std::endl
397 <<" -- reject: "<<(*hit_b)<<std::endl
398 <<" -- accept: "<<(*hit_a));
399 hit_b->setFitState(HitState::Duplicate);
400 }
401 }
402 }
403 }
static Double_t a
sTgcMeasurement_v1 sTgcMeasurement

◆ convertToSegment()

std::unique_ptr< Segment > MuonR4::SegmentFit::SegmentLineFitter::convertToSegment ( const Amg::Transform3D & locToGlobTrf,
const SegmentSeed * parentSeed,
Result_t && toConvert ) const
private

Converts the fit result into a segment object.

Parameters
locToGlobTrfLocal to global transform to translate the segment parameters into global parameters
parentSeedSegment seed from which the segment was built
toConvertFitted segment that needs conversion

Definition at line 218 of file SegmentLineFitter.cxx.

220 {
221 const auto [locPos, locDir] = makeLine(data.parameters);
222 Amg::Vector3D globPos = locToGlob * locPos;
223 Amg::Vector3D globDir = locToGlob.linear()* locDir;
224
225 std::ranges::sort(data.measurements, [](const Hit_t& a, const Hit_t& b){
226 return a->localPosition().z() < b->localPosition().z();
227 });
228 ATH_MSG_VERBOSE(__func__<<"() - "<<__LINE__ <<": Create new segment "
229 <<toString(data.parameters)<<" in "<<patternSeed->msSector()->identString()
230 <<"built from:\n"<<print(data.measurements));
231
232 auto finalSeg = std::make_unique<Segment>(std::move(globPos), std::move(globDir),
233 patternSeed, std::move(data.measurements),
234 data.chi2, data.nDoF);
235 finalSeg->setCallsToConverge(data.nIter);
236 finalSeg->setParUncertainties(std::move(data.covariance));
237 if (m_fitter.config().fitT0) {
238 finalSeg->setSegmentT0(data.parameters[toUnderlying(ParamDefs::t0)]);
239 }
240 return finalSeg;
241 }
char data[hepevt_bytes_allocation_ATLAS]
Definition HepEvt.cxx:11

◆ eraseWrongHits()

void MuonR4::SegmentFit::SegmentLineFitter::eraseWrongHits ( Result_t & candidate) const
private

Removes all hits from the segment which are obvious outliers.

E.g. tubes which cannot be crossed by the segment.

Parameters
candidateReference of the segment candidate to prune.

The segment has never crossed the tube

Definition at line 315 of file SegmentLineFitter.cxx.

315 {
316 auto [segPos, segDir] = makeLine(candidate.parameters);
317 cleanStripLayers(candidate.measurements);
318 candidate.measurements.erase(std::remove_if(candidate.measurements.begin(),
319 candidate.measurements.end(),
320 [&](const HitVec_t::value_type& hit){
321 if (hit->fitState() == HitState::Valid) {
322 return false;
323 } else if (hit->fitState() == HitState::Duplicate) {
324 return true;
325 }
328 const double dist = Amg::lineDistance(segPos, segDir,
329 hit->localPosition(),
330 hit->sensorDirection());
331 const auto* dc = static_cast<const xAOD::MdtDriftCircle*>(hit->spacePoint()->primaryMeasurement());
332 return dist >= dc->readoutElement()->innerTubeRadius();
333 }
334 return false;
335 }), candidate.measurements.end());
336 }
if(pathvar)
void cleanStripLayers(HitVec_t &hits) const
Marks duplicate hits on a strip layer as outliers to avoid competing contributions from the same laye...
DataModel_detail::iterator< DVL > remove_if(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end, Predicate pred)
Specialization of remove_if for DataVector/List.

◆ fitSegment()

std::unique_ptr< Segment > MuonR4::SegmentFit::SegmentLineFitter::fitSegment ( const EventContext & ctx,
const SegmentSeed * parent,
const LinePar_t & startPars,
const Amg::Transform3D & localToGlobal,
HitVec_t && calibHits ) const

Fit a set of measurements to a straight segment line.

Badish initial fits are cleaned and then holes are put filled back Returns a nullptr if the fit failed

Parameters
ctxEventContext to access the calibration constants
parentPointer to the seed from which the hits to fit are taken. The seed gives also access to the parent bucket to recover lost hits
startParsList of parameters serving as an initial guess
localToGlobalTransform to align the segment's station inside ATLAS (Mainly neede if the time is fit)
calibHitsList of hits that will be fitted

Definition at line 184 of file SegmentLineFitter.cxx.

188 {
189
190 const Acts::CalibrationContext cctx = ActsTrk::getCalibrationContext(ctx);
191 if (m_cfg.visionTool) {
192 Result_t preFit{};
193 preFit.parameters = startPars;
194 preFit.measurements = calibHits;
195 auto seedCopy = convertToSegment(localToGlobal, parent, std::move(preFit));
196 m_cfg.visionTool->visualizeSegment(ctx, *seedCopy, "Prefit");
197 }
198 Result_t segFit = callLineFit(cctx, startPars, localToGlobal, std::move(calibHits));
199 if (m_cfg.visionTool && segFit.converged) {
200 auto seedCopy = convertToSegment(localToGlobal, parent, Result_t{segFit});
201 m_cfg.visionTool->visualizeSegment(ctx, *seedCopy, "Intermediate fit");
202 }
203 if (!removeOutliers(cctx, *parent, localToGlobal,
204 segFit.converged? segFit.parameters : startPars,
205 segFit)) {
206 return nullptr;
207 }
208 if (!plugHoles(cctx, *parent, localToGlobal, segFit)) {
209 return nullptr;
210 }
211 auto finalSeg = convertToSegment(localToGlobal, parent, std::move(segFit));
212 if (m_cfg.visionTool) {
213 m_cfg.visionTool->visualizeSegment(ctx, *finalSeg, "Final fit");
214 }
215 return finalSeg;
216 }
bool plugHoles(const Acts::CalibrationContext &cctx, const SegmentSeed &seed, const Amg::Transform3D &localToGlobal, Result_t &toRecover) const
Recovery of missed hits.
Result_t callLineFit(const Acts::CalibrationContext &cctx, const Parameters &startPars, const Amg::Transform3D &localToGlobal, HitVec_t &&calibHits) const
Calls the underlying line fitter to determine the segment parameters.
std::unique_ptr< Segment > convertToSegment(const Amg::Transform3D &locToGlobTrf, const SegmentSeed *parentSeed, Result_t &&toConvert) const
Converts the fit result into a segment object.
bool removeOutliers(const Acts::CalibrationContext &cctx, const SegmentSeed &seed, const Amg::Transform3D &localToGlobal, const LinePar_t &startPars, Result_t &fitResult) const
Cleans the fitted segment from the most outlier hit and then attempts to refit the segment.
Acts::CalibrationContext getCalibrationContext(const EventContext &ctx)
The Acts::Calibration context is piped through the Acts fitters to (re)calibrate the Acts::SourceLink...

◆ initMessaging()

void AthMessaging::initMessaging ( ) const
privateinherited

Initialize our message level and MessageSvc.

This method should only be called once.

Definition at line 39 of file AthMessaging.cxx.

40{
42 // If user did not set an explicit level, set a default
43 if (m_lvl == MSG::NIL) {
44 m_lvl = m_imsg ?
45 static_cast<MSG::Level>( m_imsg.load()->outputLevel(m_nm) ) :
46 MSG::INFO;
47 }
48}
std::string m_nm
Message source name.
std::atomic< IMessageSvc * > m_imsg
MessageSvc pointer.
std::atomic< MSG::Level > m_lvl
Current logging level.
IMessageSvc * getMessageSvc(bool quiet=false)

◆ msg() [1/2]

MsgStream & AthMessaging::msg ( ) const
inlineinherited

The standard message stream.

Returns a reference to the default message stream May not be invoked before sysInitialize() has been invoked.

Definition at line 167 of file AthMessaging.h.

168{
169 MsgStream* ms = m_msg_tls.get();
170 if (!ms) {
171 if (!m_initialized.test_and_set()) initMessaging();
172 ms = new MsgStream(m_imsg,m_nm);
173 m_msg_tls.reset( ms );
174 }
175
176 ms->setLevel (m_lvl);
177 return *ms;
178}
boost::thread_specific_ptr< MsgStream > m_msg_tls
MsgStream instance (a std::cout like with print-out levels).
void initMessaging() const
Initialize our message level and MessageSvc.

◆ msg() [2/2]

MsgStream & AthMessaging::msg ( const MSG::Level lvl) const
inlineinherited

The standard message stream.

Returns a reference to the default message stream May not be invoked before sysInitialize() has been invoked.

Definition at line 182 of file AthMessaging.h.

183{ return msg() << lvl; }
MsgStream & msg() const
The standard message stream.

◆ msgLvl()

bool AthMessaging::msgLvl ( const MSG::Level lvl) const
inlineinherited

Test the output level.

Parameters
lvlThe message level to test against
Returns
boolean Indicating if messages at given level will be printed
Return values
trueMessages at level "lvl" will be printed

Definition at line 151 of file AthMessaging.h.

152{
153 // If user did not set explicit message level we have to initialize
154 // the messaging and retrieve the default via the MessageSvc.
155 if (m_lvl==MSG::NIL && !m_initialized.test_and_set()) initMessaging();
156
157 if (m_lvl <= lvl) {
158 msg() << lvl;
159 return true;
160 } else {
161 return false;
162 }
163}

◆ plugHoles()

bool MuonR4::SegmentFit::SegmentLineFitter::plugHoles ( const Acts::CalibrationContext & cctx,
const SegmentSeed & seed,
const Amg::Transform3D & localToGlobal,
Result_t & toRecover ) const
private

Recovery of missed hits.

Hits in the space point bucket that are maximally <RecoveryPull> away from the fitted segment are put onto the segment candidate and the candidate is refitted. If the refitted candidate has a chi2/nDoF < <OutlierRemoval> the canidate is automatically choosen otherwise, its chi needs to be better.

Parameters
cctxCalibration context to fetch later the measurement's calib constants from StoreGate (It's a packed EventContext*)
seedParent seed from which the segment fit is actually triggered The seed is mainly used for visualization purposes
localToGlobalTransform to align the spectrometer sector within ATLAS mainly used for the t0 fit
fitResultPreviously achieved fit result to be checked. The measurements on the result and the paramters are updated accordingly

We've the first estimator of the segment fit

Setup a map to replace space points if they better suite

Loop over all hits in the parent bucket

Hit already used in the segment fit

If the hit is a phi measurement check at least if it can be hit by the segment

Use the pull of the uncalibrated measurement to estimate whether a calibration is actually worth

No extra hit has been found

Remove the beamspot constraint measurement

If the chi2 is less than 5, no outlier rejection is launched. So also accept any recovered segment below that threshold

Next check whether the recovery made measurements marked as outlier feasable to the hole recovery

Definition at line 421 of file SegmentLineFitter.cxx.

424 {
426 ATH_MSG_VERBOSE(__func__<<"() - "<<__LINE__ <<": segment "<<toString(toRecover.parameters)
427 <<", chi2: "<< calcRedChi2(toRecover) <<", nDoF: "<<toRecover.nDoF);
429
430
431 std::unordered_set<const SpacePoint*> usedSpacePoints{};
432 for (auto& hit : toRecover.measurements) {
433 ATH_MSG_VERBOSE(__func__<<"() - "<<__LINE__ <<": "<<(*hit)<<" is known");
434 usedSpacePoints.insert(hit->spacePoint());
435 }
437 const EventContext& ctx{*cctx.get<const EventContext*>()};
438
439 const double timeOff = toRecover.parameters[toUnderlying(ParamDefs::t0)];
440 HitVec_t candidateHits{};
441 std::size_t hasCandidate{0};
442 const auto [locPos, locDir] = makeLine(toRecover.parameters);
443
445 for (const auto& hit : *seed.parentBucket()){
447 if (usedSpacePoints.count(hit.get())){
448 continue;
449 }
450 Hit_t calibHit{};
451 double pull{-1.};
452 if (hit->isStraw()) {
453 using namespace Acts::detail::LineHelper;
454 const double dist = signedDistance(locPos, locDir, hit->localPosition(), hit->sensorDirection());
455 const auto* dc = static_cast<const xAOD::MdtDriftCircle*>(hit->primaryMeasurement());
456 // Check whether the tube is crossed by the hit
457 if (Acts::abs(dist) >= dc->readoutElement()->innerTubeRadius()) {
458 continue;
459 }
460 } else {
462 if (!hit->measuresEta() &&
463 std::abs(hit->sensorDirection().dot(hit->localPosition() -
464 SeedingAux::extrapolateToPlane(locPos,locDir, *hit))) >
465 1.1*std::sqrt(hit->covariance()[toUnderlying(AxisDefs::etaCov)])){
466 continue;
467 }
470 pull = std::sqrt(SeedingAux::chi2Term(locPos, locDir, *hit));
471 if (pull > 1.1 * m_cfg.recoveryPull) {
472 continue;
473 }
474 }
475 calibHit = m_cfg.calibrator->calibrate(ctx, hit.get(), locPos, locDir, ActsTrk::timeToActs(timeOff));
476 calibHit->setChi2Term(SeedingAux::chi2Term(locPos, locDir, *calibHit));
477 if (calibHit->chi2Term() <= Acts::square(m_cfg.recoveryPull)) {
478 hasCandidate += calibHit->fitState() == HitState::Valid;
479 ATH_MSG_VERBOSE(__func__<<"() - "<<__LINE__<<": Candidate hit for recovery "
480 <<(*calibHit));
481 } else {
482 calibHit->setFitState(HitState::Outlier);
483 ATH_MSG_VERBOSE(__func__<<"() - "<<__LINE__<<": Outlier hit "
484 <<(*calibHit)<<" -> limit: "<<m_cfg.recoveryPull);
485 }
486 candidateHits.push_back(std::move(calibHit));
487 }
489 if (!hasCandidate) {
490 ATH_MSG_VERBOSE(__func__<<"() - "<<__LINE__<<": No space point candidates for recovery were found");
491 toRecover.measurements.insert(toRecover.measurements.end(),
492 std::make_move_iterator(candidateHits.begin()),
493 std::make_move_iterator(candidateHits.end()));
494 eraseWrongHits(toRecover);
495 return toRecover.nDoF > 0;
496 }
497 ATH_MSG_VERBOSE(__func__<<"() - "<<__LINE__<<": Found "<<hasCandidate<<" space points for recovery. ");
498
499
500 HitVec_t hitsForRecovery = toRecover.measurements;
502 if (m_cfg.doBeamSpot) {
503 removeBeamSpot(hitsForRecovery);
504 }
505
506 hitsForRecovery.insert(hitsForRecovery.end(),
507 candidateHits.begin(),
508 candidateHits.end());
509
510 cleanStripLayers(hitsForRecovery);
511
512 Result_t recovered = callLineFit(cctx, toRecover.parameters, localToGlobal,
513 std::move(hitsForRecovery));
514
517 if (betterResult(recovered, toRecover)) {
518 ATH_MSG_VERBOSE(__func__<<"() - "<<__LINE__<<": Accept segment with recovered "
519 <<(recovered.nDoF - toRecover.nDoF)<<" extra nDoF.");
520 recovered.nIter += toRecover.nIter;
521 toRecover = std::move(recovered);
522
523 std::vector<const CalibratedSpacePoint*> stripOutliers{};
524 stripOutliers.reserve(toRecover.measurements.size());
527 unsigned recovLoop{(candidateHits.size() != hasCandidate)*m_cfg.nRecoveryLoops};
528 while (++recovLoop <= m_cfg.nRecoveryLoops) {
529 ATH_MSG_VERBOSE(__func__<<"() - "<<__LINE__<<": Enter recovery loop "<<recovLoop<<".");
530 hitsForRecovery = toRecover.measurements;
531 // Remove the beamspot
532 if (m_cfg.doBeamSpot) {
533 removeBeamSpot(hitsForRecovery);
534 }
535 // Check whether an outlier can be lifted to on-track
536 for (HitVec_t::value_type& hit : hitsForRecovery) {
537 if (hit->fitState() != HitState::Outlier) {
538 continue;
539 }
540 if (hit->chi2Term() < Acts::square(m_cfg.recoveryPull)) {
541 ATH_MSG_VERBOSE(__func__<<"() - "<<__LINE__<<": Try to recover outlier "<<(*hit));
542 hit->setFitState(HitState::Valid);
543 stripOutliers.push_back(hit.get());
544 }
545 }
546 // Nothing to recover
547 if (stripOutliers.empty()) {
548 ATH_MSG_VERBOSE(__func__<<"() - "<<__LINE__<<": No additional measurement found");
549 break;
550 }
551 // Ensure that only one hit per layer is fit
552 cleanStripLayers(hitsForRecovery);
553 // Recovery turned out to be duplicates on the same layer
554 if (std::ranges::none_of(stripOutliers,[](const CalibratedSpacePoint* sp){
555 return sp->fitState() == HitState::Valid;
556 })) {
557 ATH_MSG_VERBOSE(__func__<<"() - "<<__LINE__<<": Outliers turned out to be duplicates.");
558 break;
559 }
560 ATH_MSG_VERBOSE(__func__<<"() - "<<__LINE__<<": Start fit without the outliers.");
561 stripOutliers.clear();
562 recovered = callLineFit(cctx, toRecover.parameters, localToGlobal, std::move(hitsForRecovery));
563 if (!betterResult(recovered, toRecover)) {
564 break;
565 }
566 recovered.nIter += toRecover.nIter;
567 toRecover = std::move(recovered);
568 }
569 } else{
570 for (HitVec_t::value_type& hit : candidateHits) {
571 hit->setFitState(HitState::Outlier);
572 toRecover.measurements.push_back(std::move(hit));
573 }
574 }
575 eraseWrongHits(toRecover);
576 return true;
577 }
static Double_t sp
bool betterResult(const Result_t &newResult, const Result_t &oldResult) const
Returns whether the new fit result is better than the one from the previous iteration.
void eraseWrongHits(Result_t &candidate) const
Removes all hits from the segment which are obvious outliers.
std::vector< Hit_t > HitVec_t
Collection of space points.
double signedDistance(const Amg::Vector3D &posA, const Amg::Vector3D &dirA, const Amg::Vector3D &posB, const Amg::Vector3D &dirB)
Calculates the signed distance between two lines in 3D space.
MdtDriftCircle_v1 MdtDriftCircle

◆ removeOutliers()

bool MuonR4::SegmentFit::SegmentLineFitter::removeOutliers ( const Acts::CalibrationContext & cctx,
const SegmentSeed & seed,
const Amg::Transform3D & localToGlobal,
const LinePar_t & startPars,
Result_t & fitResult ) const
private

Cleans the fitted segment from the most outlier hit and then attempts to refit the segment.

The outlier removal is not run if the segment has already a chi2 / nDoF better than <outlierRemovalCut>. Returns false if the recovery lead to the destruction of all nDoF

Parameters
cctxCalibration context to fetch later the measurement's calib constants from StoreGate (It's a packed EventContext*)
seedParent seed from which the segment fit is actually triggered The seed is mainly used for visualization purposes
localToGlobalTransform to align the spectrometer sector within ATLAS mainly used for the t0 fit
startParsThe initial parameters from which the fit shall be launched In case of out of bound parameters, the start parameters are returned otherwise the last obtained fit parameters
fitResultPreviously achieved fit result to be checked. The measurements on the result and the paramters are updated accordingly

Remove a priori the beamspot constaint as it never should pose any problem and another one will be added anyway in the next iteration

Next sort the measurements by ascending chi2

Move the outliers to the front

Refit the segment line without the measurement

Definition at line 243 of file SegmentLineFitter.cxx.

247 {
248
249
250 if (countPrecHits(fitResult.measurements) < m_cfg.nPrecHitCut || fitResult.nDoF == 0
251 || fitResult.nIter > m_fitter.config().maxIter) {
252 ATH_MSG_VERBOSE(__func__<<"() - "<<__LINE__
253 <<": No degree of freedom available. What shall be removed?!. nDoF: "
254 <<fitResult.nDoF<<", n-meas: "<<countPrecHits(fitResult.measurements)
255 <<std::endl<<print(fitResult.measurements));
256 return false;
257 }
258 if (fitResult.converged && calcRedChi2(fitResult) < m_cfg.outlierRemovalCut) {
259 ATH_MSG_VERBOSE(__func__<<"() - "<<__LINE__ <<": The segment "<<toString(fitResult.parameters)
260 <<" is already of good quality "<< calcRedChi2(fitResult)<<". Don't remove outliers");
261 return true;
262 }
263 if (fitResult.nDoF == 0u){
264 return false;
265 }
266 ATH_MSG_VERBOSE(__func__<<"() - "<<__LINE__ <<": Segment "
267 <<toString(fitResult.parameters)<<", nIter: "<<fitResult.nIter
268 <<" is of badish quality. "<<print(fitResult.measurements)
269 <<std::endl<<"Remove worst hit");
270
273 if (m_cfg.doBeamSpot) {
274 removeBeamSpot(fitResult.measurements);
275 }
276
278 std::ranges::sort(fitResult.measurements,
279 [](const HitVec_t::value_type& a, const HitVec_t::value_type& b){
281 if (isGoodHit(*a) != isGoodHit(*b)) {
282 return !isGoodHit(*a);
283 }
284 return a->chi2Term() < b->chi2Term();
285 });
286 fitResult.measurements.back()->setFitState(HitState::Outlier);
287 ATH_MSG_VERBOSE(__func__<<"() - "<<__LINE__<<" Mark "<<(*fitResult.measurements.back())<<" as outlier");
288
290 Result_t newAttempt = callLineFit(cctx, startPars, localToGlobal,
291 std::move(fitResult.measurements));
292 if (newAttempt.converged) {
293 ATH_MSG_VERBOSE(__func__<<"() - "<<__LINE__<<" The outlier removal converged.");
294 newAttempt.nIter+=fitResult.nIter;
295 fitResult = std::move(newAttempt);
296 if (m_cfg.visionTool) {
297 const EventContext& ctx{*cctx.get<const EventContext*>()};
298 auto seedCopy = convertToSegment(localToGlobal, &seed, Result_t{fitResult});
299 m_cfg.visionTool->visualizeSegment(ctx, *seedCopy, "Bad fit recovery");
300 }
301 } else {
302 ATH_MSG_VERBOSE(__func__<<"() - "<<__LINE__
303 <<" Outlier removal fit did not converge. Needed iterations: "<<newAttempt.nIter);
304 if (newAttempt.nIter == 0ul) {
305 return false;
306 }
307 fitResult.nIter+=newAttempt.nIter;
308 fitResult.measurements = std::move(newAttempt.measurements);
309 }
310 return removeOutliers(cctx, seed, localToGlobal,
311 fitResult.converged ? fitResult.parameters : startPars,
312 fitResult);
313 }

◆ setLevel()

void AthMessaging::setLevel ( MSG::Level lvl)
inherited

Change the current logging level.

Use this rather than msg().setLevel() for proper operation with MT.

Definition at line 28 of file AthMessaging.cxx.

29{
30 m_lvl = lvl;
31}

Member Data Documentation

◆ ATLAS_THREAD_SAFE

std::atomic_flag m_initialized AthMessaging::ATLAS_THREAD_SAFE = ATOMIC_FLAG_INIT
mutableprivateinherited

Messaging initialized (initMessaging).

Definition at line 141 of file AthMessaging.h.

◆ m_cfg

ConfigSwitches MuonR4::SegmentFit::SegmentLineFitter::m_cfg {}
private

Configuration switches of the ATLAS fitter implementation.

Definition at line 108 of file SegmentLineFitter.h.

108{};

◆ m_fitter

Fitter_t MuonR4::SegmentFit::SegmentLineFitter::m_fitter
private

Actual implementation of the straight line fit.

Definition at line 106 of file SegmentLineFitter.h.

◆ m_goodHitSel

Selector_t MuonR4::SegmentFit::SegmentLineFitter::m_goodHitSel {}
private

Selector to identify the valid hits.

Definition at line 110 of file SegmentLineFitter.h.

110{};

◆ m_imsg

std::atomic<IMessageSvc*> AthMessaging::m_imsg { nullptr }
mutableprivateinherited

MessageSvc pointer.

Definition at line 135 of file AthMessaging.h.

135{ nullptr };

◆ m_lvl

std::atomic<MSG::Level> AthMessaging::m_lvl { MSG::NIL }
mutableprivateinherited

Current logging level.

Definition at line 138 of file AthMessaging.h.

138{ MSG::NIL };

◆ m_msg_tls

boost::thread_specific_ptr<MsgStream> AthMessaging::m_msg_tls
mutableprivateinherited

MsgStream instance (a std::cout like with print-out levels).

Definition at line 132 of file AthMessaging.h.

◆ m_nm

std::string AthMessaging::m_nm
privateinherited

Message source name.

Definition at line 129 of file AthMessaging.h.


The documentation for this class was generated from the following files: