29 using namespace Acts::UnitLiterals;
45 return isGoodHit(hit) && (
47 hit.
type() == MdtDriftCircleType || hit.
type() == MMClusterType ||
49 (hit.
type() == sTgcStripType &&
51 sTgcIdHelper::sTgcChannelTypes::Strip)
57 return std::ranges::count_if(
hits, [](
const Hit_t& hit){
58 return isPrecisionHit(*hit);
63 return std::ranges::count_if(
hits, [](
const Hit_t& hit){
64 return isGoodHit(*hit) && hit->measuresPhi();
73 return a->type() == xAOD::UncalibMeasType::Other;
79 copied.reserve(
hits.size());
81 [](
const Hit_t& hit) {
82 return std::make_unique<CalibratedSpacePoint>(*hit);
89 static_cast<FitPars_t&
>(toRet) = toCopy;
90 toRet.measurements =
copy(toCopy.measurements);
95 SegmentLineFitter::Config::RangeArray
98 constexpr
double spatRang = 10._m;
99 constexpr
double timeTange = 25._ns;
112 m_goodHitSel.connect<isGoodHit>();
127 auto beamSpotSP = std::make_unique<CalibratedSpacePoint>(
nullptr, std::move(
beamSpot));
128 beamSpotSP->setBeamDirection(std::move(beamLine));
129 beamSpotSP->setCovariance(std::move(covariance));
131 <<
Amg::toString(beamSpotSP->localPosition())<<
", "<<beamSpotSP->covariance());
132 calibHits.push_back(std::move(beamSpotSP));
137 std::stringstream hitStream{};
138 for (
const Hit_t& hit : calibHits) {
139 hitStream<<
" **** "<< (*hit)<<
", pull: "
140 <<std::sqrt(SeedingAux::chi2Term(
pos,
dir, *hit)) <<std::endl;
142 ATH_MSG_VERBOSE(__func__<<
"() - "<<__LINE__ <<
": Start segment fit with parameters "
147 fitOpts.calibContext = cctx;
150 fitOpts.measurements = std::move(calibHits);
151 fitOpts.localToGlobal = localToGlobal;
152 fitOpts.startParameters = startPars;
162 std::unique_ptr<Segment>
172 preFit.parameters = startPars;
173 preFit.measurements =
copy(calibHits);
194 std::unique_ptr<Segment>
203 return a->localPosition().z() < b->localPosition().z();
206 std::stringstream sstr{};
208 sstr<<
" **** "<<(*h)<<
", pull: "
209 <<std::sqrt(SeedingAux::chi2Term(locPos,
locDir, *
h))<<std::endl;
215 auto finalSeg = std::make_unique<Segment>(std::move(globPos), std::move(globDir),
216 patternSeed, std::move(
data.measurements),
218 finalSeg->setCallsToConverge(
data.nIter);
219 finalSeg->setParUncertainties(std::move(
data.covariance));
233 if (fitResult.nDoF == 0 || countPrecHits(fitResult.measurements) <
m_cfg.
nPrecHitCut
234 || fitResult.nIter > 10000) {
236 <<
": No degree of freedom available. What shall be removed?!. nDoF: "
237 <<fitResult.nDoF<<
", n-meas: "<<countPrecHits(fitResult.measurements));
242 <<
" is already of good quality "<<fitResult.chi2 /fitResult.nDoF
243 <<
". Don't remove outliers");
247 <<
toString(fitResult.parameters)<<
" is of badish quality. Remove worst hit");
252 removeBeamSpot(fitResult.measurements);
254 const auto [segPos, segDir] =
makeLine(fitResult.parameters);
256 std::ranges::sort(fitResult.measurements,
257 [&segPos, &segDir](
const HitVec_t::value_type&
a,
const HitVec_t::value_type&
b){
258 const double chiSqA = isGoodHit(*a) ? SeedingAux::chi2Term(segPos, segDir, *a) : 0.;
259 const double chiSqB = isGoodHit(*b) ? SeedingAux::chi2Term(segPos, segDir, *b) : 0.;
260 return chiSqA < chiSqB;
266 localToGlobal, std::move(fitResult.measurements));
267 if (newAttempt.converged) {
268 newAttempt.nIter+=fitResult.nIter;
269 fitResult = std::move(newAttempt);
271 const EventContext& ctx{*cctx.get<
const EventContext*>()};
276 fitResult.nIter+=newAttempt.nIter;
277 fitResult.measurements = std::move(newAttempt.measurements);
283 auto [segPos, segDir] =
makeLine(candidate.parameters);
285 candidate.measurements.erase(std::remove_if(candidate.measurements.begin(),
286 candidate.measurements.end(),
287 [&](
const HitVec_t::value_type& hit){
288 if (hit->fitState() == HitState::Valid) {
295 const double dist = Amg::lineDistance(segPos, segDir,
296 hit->localPosition(),
297 hit->sensorDirection());
298 const auto* dc = static_cast<const xAOD::MdtDriftCircle*>(hit->spacePoint()->primaryMeasurement());
299 return dist >= dc->readoutElement()->innerTubeRadius();
302 }), candidate.measurements.end());
310 if (
a->isStraw() ||
b->isStraw()) {
311 return !a->isStraw();
315 return a->type() != xAOD::UncalibMeasType::Other;
317 const unsigned lay_a =
sorter.sectorLayerNum(*
a->spacePoint());
318 const unsigned lay_b =
sorter.sectorLayerNum(*
b->spacePoint());
319 if (lay_a != lay_b) {
320 return lay_a < lay_b;
322 return SeedingAux::chi2Term(linePos, lineDir, *
a) <
323 SeedingAux::chi2Term(linePos, lineDir, *
b);
327 const Hit_t& hit_a{*itr};
328 if (hit_a->isStraw()){
335 const unsigned lay_a =
sorter.sectorLayerNum(*hit_a->spacePoint());
338 const Hit_t& hit_b{*itr2};
342 if (lay_a !=
sorter.sectorLayerNum(*hit_b->spacePoint())) {
346 if ( (hit_a->measuresEta() && hit_b->measuresEta()) ||
347 (hit_a->measuresPhi() && hit_b->measuresPhi())) {
352 static std::atomic<unsigned> warnCounter{0};
355 <<
": Please check whether the overlap removal between "
369 <<
", chi2: "<<toRecover.chi2 /
std::max(toRecover.nDoF, 1
ul)
370 <<
", nDoF: "<<toRecover.nDoF);
374 std::unordered_set<const SpacePoint*> usedSpacePoints{};
375 for (
auto& hit : toRecover.measurements) {
376 ATH_MSG_VERBOSE(__func__<<
"() - "<<__LINE__ <<
": "<<(*hit)<<
" is known");
377 usedSpacePoints.insert(hit->spacePoint());
380 const EventContext& ctx{*cctx.get<
const EventContext*>()};
382 const double timeOff = toRecover.parameters[toUnderlying(
ParamDefs::t0)];
384 bool hasCandidate{
false};
388 for (
const auto& hit : *seed.parentBucket()){
390 if (usedSpacePoints.count(hit.get())){
395 if (hit->isStraw()) {
396 using namespace Acts::detail::LineHelper;
397 const double dist =
signedDistance(locPos,
locDir, hit->localPosition(), hit->sensorDirection());
400 if (Acts::abs(dist) >= dc->readoutElement()->innerTubeRadius()) {
405 if (!hit->measuresEta() &&
406 std::abs(hit->sensorDirection().dot(hit->localPosition() -
407 SeedingAux::extrapolateToPlane(locPos,
locDir, *hit))) >
413 pull = std::sqrt(SeedingAux::chi2Term(locPos,
locDir, *hit));
419 pull = std::sqrt(SeedingAux::chi2Term(locPos,
locDir, *calibHit));
425 ATH_MSG_VERBOSE(__func__<<
"() - "<<__LINE__<<
": Candidate hit for recovery "
426 <<seed.msSector()->idHelperSvc()->toString(hit->identify())<<
", pull: "<<
pull);
427 candidateHits.push_back(std::move(calibHit));
431 ATH_MSG_VERBOSE(__func__<<
"() - "<<__LINE__<<
": No space point candidates for recovery were found");
432 toRecover.measurements.insert(toRecover.measurements.end(),
433 std::make_move_iterator(candidateHits.begin()),
434 std::make_move_iterator(candidateHits.end()));
436 return toRecover.nDoF > 0;
444 removeBeamSpot(copied);
447 candidateHits.insert(candidateHits.end(),
448 std::make_move_iterator(copied.begin()),
449 std::make_move_iterator(copied.end()));
453 std::move(candidateHits));
454 if (!recovered.converged) {
458 if (recovered.nDoF <= toRecover.nDoF) {
459 for (HitVec_t::value_type& hit : copiedCandidates) {
461 toRecover.measurements.push_back(std::move(hit));
466 std::vector<const CalibratedSpacePoint*> stripOutliers{};
467 stripOutliers.reserve(toRecover.measurements.size());
468 ATH_MSG_VERBOSE(__func__<<
"() - "<<__LINE__<<
": Before - chi2: "<<toRecover.chi2
469 <<
", nDoF "<<toRecover.nDoF<<
" <=> after recovery - chi2: "
470 <<recovered.chi2<<
", nDoF: "<<recovered.nDoF);
472 double redChi2 = recovered.chi2 /
std::max(recovered.nDoF, 1
ul);
476 toRecover.nDoF == 0 || redChi2 < toRecover.chi2 / toRecover.nDoF) {
477 ATH_MSG_VERBOSE(
"Accept segment with recovered "<<(recovered.nDoF - toRecover.nDoF)<<
" hits.");
478 recovered.nIter += toRecover.nIter;
479 toRecover = std::move(recovered);
482 unsigned recovLoop{0
u};
484 copied =
copy(toRecover.measurements);
486 removeBeamSpot(copied);
488 const auto [beforePos, beforeDir] =
makeLine(toRecover.parameters);
490 for (HitVec_t::value_type& copyHit : copied) {
494 if (std::sqrt(SeedingAux::chi2Term(beforePos, beforeDir, *copyHit)) <
m_cfg.
recoveryPull) {
496 stripOutliers.push_back(copyHit.get());
500 if (stripOutliers.empty()) {
510 stripOutliers.clear();
511 recovered =
callLineFit(cctx, toRecover.parameters, localToGlobal, std::move(copied));
512 if (!recovered.converged) {
515 if (recovered.nDoF <= toRecover.nDoF) {
518 redChi2 = recovered.chi2 /
std::max(recovered.nDoF, 1
ul);
520 recovered.nIter += toRecover.nIter;
521 toRecover = std::move(recovered);
527 for (HitVec_t::value_type& hit : copiedCandidates) {
529 toRecover.measurements.push_back(std::move(hit));
536 if (std::ranges::any_of(
result.measurements,[](
const Hit_t&
h){
537 return h->measuresPhi();
539 ATH_MSG_VERBOSE(
"The segment has phi measurements. No centering needed");
543 const double nHits =
result.measurements.size();
544 std::ranges::for_each(
result.measurements, [&avgX, nHits](
const Hit_t& hit) {
545 return avgX += hit->localPosition().x() / nHits;
547 result.parameters[toUnderlying(ParamDefs::x0)] = avgX;