ATLAS Offline Software
Loading...
Searching...
No Matches
SegmentLineFitter.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5// Compile this file assuming that FP operations may trap.
6// Prevents spurious FPEs in the clang build.
9
12
16
17#include <ActsInterop/Logger.h>
20
21
22#include <format>
23
27
28
29namespace MuonR4::SegmentFit{
30 using namespace Acts;
31 using namespace Acts::UnitLiterals;
32
36
37 namespace {
38
39 constexpr double calcRedChi2(const Result_t& result) {
40 return result.nDoF > 0ul ? result.chi2 / result.nDoF : result.chi2;
41 }
44 inline unsigned countPrecHits(const HitVec_t& hits) {
45 return std::ranges::count_if(hits, [](const Hit_t& hit){
46 return isPrecisionHit(*hit);
47 });
48 }
50 inline unsigned countPhiHits(const HitVec_t& hits) {
51 return std::ranges::count_if(hits, [](const Hit_t& hit){
52 return isGoodHit(*hit) && hit->measuresPhi();
53 });
54 }
58 inline void removeBeamSpot(HitVec_t& hits){
59 hits.erase(std::remove_if(hits.begin(), hits.end(),
60 [](const Hit_t& a){
61 return a->type() == xAOD::UncalibMeasType::Other;
62 }), hits.end());
63 }
64 }
65 SegmentLineFitter::Config::RangeArray
67 RangeArray rng{};
68 constexpr double spatRang = 10._m;
69 constexpr double timeTange = 50._ns;
70 using enum ParamDefs;
71 rng[toUnderlying(y0)] = std::array{-spatRang, spatRang};
72 rng[toUnderlying(x0)] = std::array{-spatRang, spatRang};
73 rng[toUnderlying(phi)] = std::array{-179._degree, 179._degree};
74 rng[toUnderlying(theta)] = std::array{0._degree, 175._degree};
75 rng[toUnderlying(t0)] = std::array{-timeTange, timeTange};
76 return rng;
77 }
78 SegmentLineFitter::SegmentLineFitter(const std::string& name, Config&& config):
79 AthMessaging{name},
80 m_fitter{config, makeActsAthenaLogger(this, name)},
81 m_cfg{config} {
82 m_goodHitSel.connect<isGoodHit>();
83 }
84 Result_t SegmentLineFitter::callLineFit(const Acts::CalibrationContext& cctx,
85 const Parameters& startPars,
86 const Amg::Transform3D& localToGlobal,
87 HitVec_t&& calibHits) const {
88
90 bool appendsBS = m_cfg.doBeamSpot && countPhiHits(calibHits) > 0;
91
92
93 Result_t result{};
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 }
183 std::unique_ptr<Segment>
184 SegmentLineFitter::fitSegment(const EventContext& ctx,
185 const SegmentSeed* parent,
186 const Parameters& startPars,
187 const Amg::Transform3D& localToGlobal,
188 HitVec_t&& calibHits) const {
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 }
217 std::unique_ptr<Segment>
219 const SegmentSeed* patternSeed,
220 Result_t&& data) const {
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 }
242
243 bool SegmentLineFitter::removeOutliers(const Acts::CalibrationContext& cctx,
244 const SegmentSeed& seed,
245 const Amg::Transform3D& localToGlobal,
246 const LinePar_t& startPars,
247 Result_t& fitResult) const {
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 }
314
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 }
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 }
404
405 inline bool SegmentLineFitter::betterResult(const Result_t& newResult, const Result_t& oldResult) const {
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 }
421 bool SegmentLineFitter::plugHoles(const Acts::CalibrationContext& cctx,
422 const SegmentSeed& seed,
423 const Amg::Transform3D& localToGlobal,
424 Result_t& toRecover) const {
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 }
578
579}
Scalar phi() const
phi method
Scalar theta() const
theta method
#define ATH_MSG_VERBOSE(x)
char data[hepevt_bytes_allocation_ATLAS]
Definition HepEvt.cxx:11
static Double_t sp
static Double_t a
static Double_t t0
if(pathvar)
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.
std::string identString() const
Returns a string encoding the chamber index & the sector of the MS sector.
The calibrated Space point is created during the calibration process.
Segment::MeasType Hit_t
Abrivation of the space point type to use.
bool plugHoles(const Acts::CalibrationContext &cctx, const SegmentSeed &seed, const Amg::Transform3D &localToGlobal, Result_t &toRecover) const
Recovery of missed hits.
Selector_t m_goodHitSel
Selector to identify the valid 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.
ConfigSwitches m_cfg
Configuration switches of the ATLAS fitter implementation.
Fitter_t::FitResult< HitVec_t > Result_t
Abrivation of the fit result.
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.
void cleanStripLayers(HitVec_t &hits) const
Marks duplicate hits on a strip layer as outliers to avoid competing contributions from the same laye...
std::unique_ptr< Segment > convertToSegment(const Amg::Transform3D &locToGlobTrf, const SegmentSeed *parentSeed, Result_t &&toConvert) const
Converts the fit result into a segment object.
Fitter_t::FitOptions< HitVec_t, ISpacePointCalibrator > FitOpts_t
Abrivation of the fit options.
std::unique_ptr< Segment > 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.
Fitter_t m_fitter
Actual implementation of the straight line fit.
Fitter_t::ParamVec_t LinePar_t
Abrivation of the fitted line parameters.
std::vector< Hit_t > HitVec_t
Collection of space points.
SegmentLineFitter(const std::string &name, Config &&config)
Standard constructor.
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.
Representation of a segment seed (a fully processed hough maximum) produced by the hough transform.
Definition SegmentSeed.h:14
const MuonGMR4::SpectrometerSector * msSector() const
Returns the associated chamber.
The SpacePointPerLayerSorter sort two given space points by their layer Identifier.
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.
Acts::CalibrationContext getCalibrationContext(const EventContext &ctx)
The Acts::Calibration context is piped through the Acts fitters to (re)calibrate the Acts::SourceLink...
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
SegmentLineFitter::Result_t Result_t
SegmentLineFitter::HitVec_t HitVec_t
SeedingAux::FitParIndex ParamDefs
Use the same parameter indices as used by the CompSpacePointAuxiliaries.
SegmentLineFitter::Hit_t Hit_t
std::pair< Amg::Vector3D, Amg::Vector3D > makeLine(const Parameters &pars)
Returns the parsed parameters into an Eigen line parametrization.
Acts::Experimental::CompositeSpacePointLineFitter::ParamVec_t Parameters
std::string toString(const Parameters &pars)
Dumps the parameters into a string with labels in front of each number.
bool isPrecisionHit(const SpacePoint &hit)
Returns whether the uncalibrated spacepoint is a precision hit (Mdt, micromegas, stgc strips).
std::string print(const cont_t &container)
Print a space point container to string.
bool isGoodHit(const CalibratedSpacePoint &hit)
Returns whether the calibrated spacepoint is valid and therefore suitable to be used in the segment f...
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.
MdtDriftCircle_v1 MdtDriftCircle
MMCluster_v1 MMCluster
sTgcMeasurement_v1 sTgcMeasurement
static RangeArray defaultRanges()
Function that returns a set of predefined ranges for testing.
Tell the compiler to optimize assuming that FP may trap.
#define CXXUTILS_TRAPPING_FP
Definition trapping_fp.h:24