File indexing completed on 2026-07-16 08:07:36
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include "Acts/Seeding/CompositeSpacePointLineSeeder.hpp"
0012
0013 #include "Acts/Definitions/Tolerance.hpp"
0014 #include "Acts/Surfaces/detail/LineHelper.hpp"
0015 #include "Acts/Utilities/Helpers.hpp"
0016
0017 #include <algorithm>
0018 #include <cassert>
0019
0020 namespace Acts::Experimental {
0021
0022 template <CompositeSpacePoint Sp_t>
0023 CompositeSpacePointLineSeeder::TwoCircleTangentPars
0024 CompositeSpacePointLineSeeder::constructTangentLine(const Sp_t& topHit,
0025 const Sp_t& bottomHit,
0026 const TangentAmbi ambi) {
0027 using namespace Acts::UnitLiterals;
0028 using namespace Acts::detail;
0029 TwoCircleTangentPars result{};
0030 result.ambi = ambi;
0031 const auto& [signTop, signBot] = s_signCombo[toUnderlying(ambi)];
0032
0033 const Vector& bottomPos{bottomHit.localPosition()};
0034 const Vector& topPos{topHit.localPosition()};
0035 const Vector& eY{bottomHit.toNextSensor()};
0036 const Vector& eZ{bottomHit.planeNormal()};
0037 const Vector D = topPos - bottomPos;
0038
0039 assert(Acts::abs(eY.dot(eZ)) < s_epsilon);
0040 assert(Acts::abs(bottomHit.sensorDirection().dot(eY)) < s_epsilon);
0041 assert(Acts::abs(bottomHit.sensorDirection().dot(eZ)) < s_epsilon);
0042 assert(topHit.isStraw() && bottomHit.isStraw());
0043
0044 const double dY = D.dot(eY);
0045 const double dZ = D.dot(eZ);
0046
0047 const double thetaTubes = std::atan2(dY, dZ);
0048 const double distTubes = fastHypot(dY, dZ);
0049 assert(distTubes > 1._mm);
0050 constexpr auto covIdx = toUnderlying(CovIdx::bending);
0051 const double combDriftUncert{topHit.covariance()[covIdx] +
0052 bottomHit.covariance()[covIdx]};
0053 const double R =
0054 -signBot * bottomHit.driftRadius() + signTop * topHit.driftRadius();
0055 result.theta = thetaTubes - std::asin(std::clamp(R / distTubes, -1., 1.));
0056
0057 const double cosTheta = std::cos(result.theta);
0058 const double sinTheta = std::sin(result.theta);
0059
0060 result.y0 = bottomPos.dot(eY) * cosTheta - bottomPos.dot(eZ) * sinTheta -
0061 signBot * bottomHit.driftRadius();
0062 assert(Acts::abs(topPos.dot(eY) * cosTheta - topPos.dot(eZ) * sinTheta -
0063 signTop * topHit.driftRadius() - result.y0) <
0064 std::numeric_limits<float>::epsilon());
0065 result.y0 /= cosTheta;
0066 const double denomSquare = 1. - Acts::pow(R / distTubes, 2);
0067 if (denomSquare < s_epsilon) {
0068 return result;
0069 }
0070 result.dTheta = combDriftUncert / std::sqrt(denomSquare) / distTubes;
0071 result.dY0 =
0072 Acts::fastHypot(
0073 bottomPos.dot(eY) * sinTheta + bottomPos.dot(eZ) * cosTheta, 1.) *
0074 result.dTheta;
0075
0076 return result;
0077 }
0078
0079 template <CompositeSpacePoint Sp_t>
0080 CompositeSpacePointLineSeeder::Vector
0081 CompositeSpacePointLineSeeder::makeDirection(const Sp_t& refHit,
0082 const double tanAngle) {
0083 const Vector& eY{refHit.toNextSensor()};
0084 const Vector& eZ{refHit.planeNormal()};
0085 const double cosTheta = std::cos(tanAngle);
0086 const double sinTheta = std::sin(tanAngle);
0087 return copySign<Vector, double>(sinTheta * eY + cosTheta * eZ, sinTheta);
0088 }
0089
0090 template <CompositeSpacePointContainer Cont_t>
0091 std::size_t CompositeSpacePointLineSeeder::countHits(
0092 const Cont_t& container, const Selector_t<Cont_t>& selector) const {
0093 if (m_cfg.busyLimitCountGood) {
0094 return std::ranges::count_if(
0095 container, [&](const auto& hit) { return selector(*hit); });
0096 }
0097 return container.size();
0098 }
0099
0100
0101
0102
0103 template <CompositeSpacePointContainer UnCalibCont_t,
0104 detail::CompositeSpacePointSorter<UnCalibCont_t> Splitter_t>
0105 CompositeSpacePointLineSeeder::SeedSolution<UnCalibCont_t,
0106 Splitter_t>::SpacePoint_t
0107 CompositeSpacePointLineSeeder::SeedSolution<UnCalibCont_t, Splitter_t>::getHit(
0108 const std::size_t idx) const {
0109 const auto& [layIdx, hitIdx] = m_seedHits.at(idx);
0110 const UnCalibCont_t& strawLayer = m_splitter.strawHits().at(layIdx);
0111 return *strawLayer.at(hitIdx);
0112 }
0113 template <CompositeSpacePointContainer UnCalibCont_t,
0114 detail::CompositeSpacePointSorter<UnCalibCont_t> Splitter_t>
0115 std::vector<int> CompositeSpacePointLineSeeder::SeedSolution<
0116 UnCalibCont_t, Splitter_t>::leftRightAmbiguity(const Vector& seedPos,
0117 const Vector& seedDir)
0118 const {
0119 std::vector<int> result{};
0120 result.reserve(size());
0121 std::ranges::transform(
0122 m_seedHits, std::back_inserter(result),
0123 [&](const std::pair<std::size_t, std::size_t>& indices) {
0124 const auto& [layIdx, hitIdx] = indices;
0125 const UnCalibCont_t& strawLayer = m_splitter.strawHits().at(layIdx);
0126 return detail::CompSpacePointAuxiliaries::strawSign(
0127 seedPos, seedDir, *strawLayer.at(hitIdx));
0128 });
0129 return result;
0130 }
0131 template <CompositeSpacePointContainer UnCalibCont_t,
0132 detail::CompositeSpacePointSorter<UnCalibCont_t> Splitter_t>
0133 void CompositeSpacePointLineSeeder::SeedSolution<
0134 UnCalibCont_t, Splitter_t>::append(const std::size_t layIdx,
0135 const std::size_t hitIdx) {
0136 assert(!rangeContainsValue(m_seedHits, std::make_pair(layIdx, hitIdx)));
0137 m_seedHits.emplace_back(layIdx, hitIdx);
0138 }
0139 template <CompositeSpacePointContainer UnCalibCont_t,
0140 detail::CompositeSpacePointSorter<UnCalibCont_t> Splitter_t>
0141 void CompositeSpacePointLineSeeder::SeedSolution<
0142 UnCalibCont_t, Splitter_t>::print(std::ostream& ostr) const {
0143 TwoCircleTangentPars::print(ostr);
0144 const std::size_t N = size();
0145 ostr << ", associated hits: " << N << std::endl;
0146 for (std::size_t h = 0; h < N; ++h) {
0147 ostr << " **** " << (h + 1ul) << ") " << Acts::toString(getHit(h))
0148 << std::endl;
0149 }
0150 }
0151
0152
0153
0154
0155 template <
0156 CompositeSpacePointContainer UncalibCont_t,
0157 CompositeSpacePointContainer CalibCont_t,
0158 detail::CompSpacePointSeederDelegate<UncalibCont_t, CalibCont_t> Delegate_t>
0159 void CompositeSpacePointLineSeeder::SeedingState<
0160 UncalibCont_t, CalibCont_t, Delegate_t>::print(std::ostream& ostr) const {
0161 const std::size_t nStraw = this->strawHits().size();
0162
0163 ostr << "Seed state:\n";
0164 ostr << "N strawLayers: " << nStraw
0165 << " N strip layers: " << this->stripHits().size() << "\n";
0166 ostr << "upperLayer " << m_upperLayer.value_or(nStraw - 1ul) << " lowerLayer "
0167 << m_lowerLayer.value_or(0u) << " upperHitIndex " << m_upperHitIndex
0168 << " lower layer hit index " << m_lowerHitIndex << " sign combo index "
0169 << toString(encodeAmbiguity(s_signCombo[m_signComboIndex][0],
0170 s_signCombo[m_signComboIndex][1]))
0171 << "\n";
0172 ostr << "Number of seeds " << nGenSeeds() << " nStrawCut " << m_nStrawCut
0173 << "\n";
0174 if (nGenSeeds() > 0ul) {
0175 for (const auto& seen : m_seenSolutions) {
0176 ostr << "################################################" << std::endl;
0177 ostr << seen << std::endl;
0178 ostr << "################################################" << std::endl;
0179 }
0180 }
0181 }
0182
0183 template <CompositeSpacePointContainer UnCalibCont_t>
0184 bool CompositeSpacePointLineSeeder::moveToNextHit(
0185 const UnCalibCont_t& hitVec, const Selector_t<UnCalibCont_t>& selector,
0186 std::size_t& hitIdx) const {
0187 ACTS_VERBOSE(__func__ << "() " << __LINE__
0188 << " - Moving to next good hit from index " << hitIdx
0189 << " in straw layer with " << hitVec.size()
0190 << " hits.");
0191 while (++hitIdx < hitVec.size()) {
0192 if (selector(*hitVec[hitIdx])) {
0193 ACTS_VERBOSE(__func__ << "() " << __LINE__ << " - Moved towards index "
0194 << hitIdx);
0195 return true;
0196 }
0197 }
0198 ACTS_VERBOSE(__func__ << "() " << __LINE__ << " - No good hit found.");
0199 return false;
0200 }
0201
0202 template <CompositeSpacePointContainer UnCalibCont_t>
0203 bool CompositeSpacePointLineSeeder::firstGoodHit(
0204 const UnCalibCont_t& hitVec, const Selector_t<UnCalibCont_t>& selector,
0205 std::size_t& hitIdx) const {
0206 hitIdx = 0;
0207 if (hitVec.empty()) {
0208 ACTS_VERBOSE(__func__ << "() " << __LINE__ << " - Layer is empty.");
0209 return false;
0210 }
0211 return selector(*hitVec[hitIdx]) || moveToNextHit(hitVec, selector, hitIdx);
0212 }
0213 template <CompositeSpacePointContainer UnCalibCont_t>
0214 bool CompositeSpacePointLineSeeder::nextLayer(
0215 const StrawLayers_t<UnCalibCont_t>& strawLayers,
0216 const Selector_t<UnCalibCont_t>& selector, const std::size_t boundary,
0217 std::optional<std::size_t>& layerIndex, std::size_t& hitIdx,
0218 bool moveForward) const {
0219 if (strawLayers.empty()) {
0220 ACTS_VERBOSE(__func__ << "() " << __LINE__ << " - No straw layers.");
0221 return false;
0222 }
0223
0224 if (!layerIndex.has_value()) {
0225 layerIndex = moveForward ? 0u : strawLayers.size() - 1u;
0226 const UnCalibCont_t& hitVec{strawLayers.at(layerIndex.value())};
0227 if (hitVec.size() <= m_cfg.busyLayerLimit &&
0228 firstGoodHit(hitVec, selector, hitIdx)) {
0229 ACTS_VERBOSE(__func__ << "() " << __LINE__ << " - Instantiated "
0230 << (moveForward ? "lower" : "upper") << " layer to "
0231 << layerIndex.value() << ".");
0232 return true;
0233 }
0234 }
0235 ACTS_VERBOSE(__func__ << "() " << __LINE__ << " - Move "
0236 << (moveForward ? "lower" : "upper") << " layer "
0237 << layerIndex.value() << " to next value.");
0238
0239 while ((moveForward ? (++layerIndex.value()) : (--layerIndex.value())) <
0240 strawLayers.size()) {
0241 const UnCalibCont_t& hitVec{strawLayers.at(layerIndex.value())};
0242
0243 if ((moveForward && layerIndex.value() >= boundary) ||
0244 (!moveForward && layerIndex.value() <= boundary)) {
0245 ACTS_VERBOSE(__func__ << "() " << __LINE__ << " - The "
0246 << (moveForward ? "lower" : "upper") << " index "
0247 << layerIndex.value()
0248 << " exceeds the boundary: " << boundary << ".");
0249 return false;
0250 }
0251
0252 if (const std::size_t nHits = countHits(hitVec, selector);
0253 nHits > m_cfg.busyLayerLimit) {
0254 ACTS_VERBOSE(__func__ << "() " << __LINE__ << " - The layer "
0255 << layerIndex.value()
0256 << " is too busy for seeding: " << nHits
0257 << ". Limit: " << m_cfg.busyLayerLimit << ".");
0258 continue;
0259 }
0260
0261
0262 if (firstGoodHit(strawLayers.at(layerIndex.value()), selector, hitIdx)) {
0263 ACTS_VERBOSE(__func__
0264 << "() " << __LINE__ << " - Loop over all hits in the "
0265 << layerIndex.value() << (moveForward ? "lower" : "upper")
0266 << " layer.");
0267 return true;
0268 }
0269 }
0270 return false;
0271 }
0272
0273 template <
0274 CompositeSpacePointContainer UncalibCont_t,
0275 CompositeSpacePointContainer CalibCont_t,
0276 detail::CompSpacePointSeederDelegate<UncalibCont_t, CalibCont_t> Delegate_t>
0277 std::optional<CompositeSpacePointLineSeeder::SegmentSeed<CalibCont_t>>
0278 CompositeSpacePointLineSeeder::nextSeed(
0279 const CalibrationContext& cctx,
0280 SeedingState<UncalibCont_t, CalibCont_t, Delegate_t>& state) const {
0281 const StrawLayers_t<UncalibCont_t>& strawLayers{state.strawHits()};
0282
0283 Selector_t<UncalibCont_t> selector{};
0284 selector.template connect<&Delegate_t::goodCandidate>(&state);
0285
0286 if (!state.m_upperLayer || !state.m_lowerLayer) {
0287 state.m_nStrawCut = m_cfg.nStrawHitCut;
0288
0289
0290 if (!state.m_patternSeedProduced &&
0291 (!m_cfg.startWithPattern ||
0292 std::ranges::any_of(strawLayers, [&](const UncalibCont_t& layerHits) {
0293 return countHits(layerHits, selector) > m_cfg.busyLayerLimit;
0294 }))) {
0295 state.m_patternSeedProduced = true;
0296 }
0297 if (!state.m_patternSeedProduced) {
0298 SegmentSeed<CalibCont_t> patternSeed{state.initialParameters(),
0299 state.newContainer(cctx)};
0300
0301 const auto [pos, dir] = makeLine(state.initialParameters());
0302 const double t0 = patternSeed.parameters[toUnderlying(ParIdx::t0)];
0303
0304 auto append = [&](const StrawLayers_t<UncalibCont_t>& hitLayers) {
0305 for (const auto& layer : hitLayers) {
0306 for (const auto& hit : layer) {
0307 state.append(cctx, pos, dir, t0, *hit, patternSeed.hits);
0308 }
0309 }
0310 };
0311 append(strawLayers);
0312 append(state.stripHits());
0313 state.m_patternSeedProduced = true;
0314 return patternSeed;
0315 }
0316 ACTS_DEBUG(__func__ << "() " << __LINE__ << " - Instantiate layers. ");
0317
0318 if (!nextLayer(strawLayers, selector, strawLayers.size(),
0319 state.m_lowerLayer, state.m_lowerHitIndex, true) ||
0320 !nextLayer(strawLayers, selector, state.m_lowerLayer.value(),
0321 state.m_upperLayer, state.m_upperHitIndex, false)) {
0322 ACTS_DEBUG(__func__ << "() " << __LINE__
0323 << " - No valid seed can be constructed. ");
0324 return std::nullopt;
0325 }
0326 }
0327
0328 while (state.m_lowerLayer.value() < state.m_upperLayer.value()) {
0329 auto seed = buildSeed(cctx, selector, state);
0330 moveToNextCandidate(selector, state);
0331 if (seed) {
0332 return seed;
0333 }
0334 }
0335
0336 return std::nullopt;
0337 }
0338 template <
0339 CompositeSpacePointContainer UncalibCont_t,
0340 CompositeSpacePointContainer CalibCont_t,
0341 detail::CompSpacePointSeederDelegate<UncalibCont_t, CalibCont_t> Delegate_t>
0342 void CompositeSpacePointLineSeeder::moveToNextCandidate(
0343 const Selector_t<UncalibCont_t>& selector,
0344 SeedingState<UncalibCont_t, CalibCont_t, Delegate_t>& state) const {
0345
0346 ++state.m_signComboIndex;
0347 if (state.m_signComboIndex < s_signCombo.size()) {
0348 return;
0349 }
0350
0351
0352 state.m_signComboIndex = 0;
0353
0354 const StrawLayers_t<UncalibCont_t>& strawLayers{state.strawHits()};
0355
0356 const UncalibCont_t& lower = strawLayers[state.m_lowerLayer.value()];
0357 const UncalibCont_t& upper = strawLayers[state.m_upperLayer.value()];
0358
0359
0360 ACTS_VERBOSE(__func__ << "() " << __LINE__ << " - Move to next lower hit.");
0361 if (moveToNextHit(lower, selector, state.m_lowerHitIndex)) {
0362 return;
0363 }
0364
0365
0366
0367 ACTS_VERBOSE(__func__ << "() " << __LINE__
0368 << " - All lower hits were tried increment upper hit.");
0369 if (firstGoodHit(lower, selector, state.m_lowerHitIndex) &&
0370 moveToNextHit(upper, selector, state.m_upperHitIndex)) {
0371 return;
0372 }
0373
0374 auto& layerToStay{state.m_moveUpLayer ? state.m_lowerLayer
0375 : state.m_upperLayer};
0376 auto& layerToMove{state.m_moveUpLayer ? state.m_upperLayer
0377 : state.m_lowerLayer};
0378 auto& hitToStay{state.m_moveUpLayer ? state.m_lowerHitIndex
0379 : state.m_upperHitIndex};
0380 auto& hitToMove{state.m_moveUpLayer ? state.m_upperHitIndex
0381 : state.m_lowerHitIndex};
0382 ACTS_VERBOSE(__func__ << "() " << __LINE__ << " - Move towards the next "
0383 << (state.m_moveUpLayer ? "upper" : "lower")
0384 << " layer. Current state: " << layerToMove.value());
0385
0386
0387 if (firstGoodHit(strawLayers[layerToStay.value()], selector, hitToStay) &&
0388 nextLayer(strawLayers, selector, layerToStay.value(), layerToMove,
0389 hitToMove, !state.m_moveUpLayer)) {
0390 state.m_moveUpLayer = !state.m_moveUpLayer;
0391 if (state.stopSeeding(state.m_lowerLayer.value(),
0392 state.m_upperLayer.value())) {
0393 state.m_lowerLayer.value() = state.m_upperLayer.value() + 1ul;
0394 }
0395 return;
0396 }
0397 }
0398
0399 template <
0400 CompositeSpacePointContainer UncalibCont_t,
0401 CompositeSpacePointContainer CalibCont_t,
0402 detail::CompSpacePointSeederDelegate<UncalibCont_t, CalibCont_t> Delegate_t>
0403 bool CompositeSpacePointLineSeeder::passSeedCuts(
0404 const Line_t& tangentSeed,
0405 SeedSolution<UncalibCont_t, Delegate_t>& newSolution,
0406 SeedingState<UncalibCont_t, CalibCont_t, Delegate_t>& state) const {
0407
0408 const auto& [seedPos, seedDir] = tangentSeed;
0409 const double hitCut =
0410 std::max(1.0 * state.m_nStrawCut,
0411 m_cfg.nStrawLayHitCut * state.strawHits().size());
0412 ACTS_VERBOSE(__func__ << "() " << __LINE__ << " - Found "
0413 << newSolution.nStrawHits
0414 << " compatible straw hits. Hit cut is " << hitCut);
0415 if (newSolution.nStrawHits < hitCut) {
0416 return false;
0417 }
0418 if (!m_cfg.overlapCorridor) {
0419 return true;
0420 }
0421 newSolution.solutionSigns = newSolution.leftRightAmbiguity(seedPos, seedDir);
0422 for (std::size_t a = 0ul; a < state.nGenSeeds(); ++a) {
0423 const auto& acceptedSol = state.m_seenSolutions[a];
0424 std::size_t nOverlap{0};
0425 const std::vector<int> corridor =
0426 acceptedSol.leftRightAmbiguity(seedPos, seedDir);
0427 for (std::size_t l = 0; l < acceptedSol.size(); ++l) {
0428 nOverlap += (corridor[l] == acceptedSol.solutionSigns[l]);
0429 }
0430 if (nOverlap == corridor.size() &&
0431 acceptedSol.size() >= newSolution.size()) {
0432 return false;
0433 }
0434 }
0435 if (m_cfg.tightenHitCut) {
0436 state.m_nStrawCut = std::max(state.m_nStrawCut, newSolution.nStrawHits);
0437 }
0438 return true;
0439 }
0440
0441 template <
0442 CompositeSpacePointContainer UncalibCont_t,
0443 CompositeSpacePointContainer CalibCont_t,
0444 detail::CompSpacePointSeederDelegate<UncalibCont_t, CalibCont_t> Delegate_t>
0445 std::optional<CompositeSpacePointLineSeeder::SegmentSeed<CalibCont_t>>
0446 CompositeSpacePointLineSeeder::buildSeed(
0447 const CalibrationContext& cctx, const Selector_t<UncalibCont_t>& selector,
0448 SeedingState<UncalibCont_t, CalibCont_t, Delegate_t>& state) const {
0449 const StrawLayers_t<UncalibCont_t>& strawLayers{state.strawHits()};
0450
0451 ACTS_DEBUG(__func__ << "() " << __LINE__ << " - Try to draw new seed from \n"
0452 << state << ".");
0453 const auto& upperHit =
0454 *strawLayers.at(state.m_upperLayer.value()).at(state.m_upperHitIndex);
0455 const auto& lowerHit =
0456 *strawLayers.at(state.m_lowerLayer.value()).at(state.m_lowerHitIndex);
0457 const auto ambi{static_cast<TangentAmbi>(state.m_signComboIndex)};
0458 ACTS_VERBOSE(__func__ << "() " << __LINE__ << " - " << toString(ambi)
0459 << "\n Top seed hit: " << Acts::toString(upperHit)
0460 << "\n Bottom seed hit:" << Acts::toString(lowerHit)
0461 << ".");
0462
0463 const TwoCircleTangentPars seedPars =
0464 constructTangentLine(lowerHit, upperHit, ambi);
0465 ACTS_VERBOSE(__func__ << "() " << __LINE__
0466 << " - Tangential parameters: " << seedPars);
0467 if (!isValidLine(seedPars)) {
0468 ACTS_VERBOSE(__func__ << "() " << __LINE__ << " - Reject seed.");
0469 return std::nullopt;
0470 }
0471
0472 if (std::ranges::any_of(state.m_seenSolutions, [&seedPars](const auto& seen) {
0473 const double deltaY = Acts::abs(seen.y0 - seedPars.y0);
0474 const double limitY = Acts::fastHypot(seen.dY0, seedPars.dY0);
0475 const double deltaTheta = Acts::abs(seen.theta - seedPars.theta);
0476 const double limitTheta = Acts::fastHypot(seen.dTheta, seedPars.dTheta);
0477 return deltaY < limitY && deltaTheta < limitTheta;
0478 })) {
0479 ACTS_VERBOSE(__func__ << "() " << __LINE__ << " - Reject seed.");
0480 return std::nullopt;
0481 }
0482
0483 const double t0 = state.initialParameters()[toUnderlying(ParIdx::t0)];
0484 SeedSolution<UncalibCont_t, Delegate_t> newSolution{seedPars, state};
0485
0486 ACTS_DEBUG(__func__ << "() " << __LINE__
0487 << " - Start looking for compatible hits");
0488
0489 const Line_t tangentSeed{seedPars.y0 * Vector3::UnitY(),
0490 makeDirection(lowerHit, seedPars.theta)};
0491 const auto& [seedPos, seedDir] = tangentSeed;
0492 const double maxPullSq{Acts::square(m_cfg.hitPullCut)};
0493 constexpr auto covIdx = Acts::toUnderlying(CovIdx::bending);
0494
0495 for (const auto& [layerNr, hitsInLayer] :
0496 Acts::enumerate(state.strawHits())) {
0497 bool hadGoodHit{false};
0498 for (const auto& [hitNr, testMe] : Acts::enumerate(hitsInLayer)) {
0499 using namespace Acts::detail::LineHelper;
0500 const double distance = Acts::abs(
0501 signedDistance(testMe->localPosition(), testMe->sensorDirection(),
0502 seedPos, seedDir));
0503
0504
0505
0506 const double rMax = state.strawRadius(*testMe);
0507 assert(rMax > Acts::s_epsilon);
0508 assert(testMe->covariance()[covIdx] > Acts::s_epsilon);
0509 if (distance < rMax) {
0510 const double pullSq =
0511 m_cfg.useSimpleStrawPull
0512 ? Acts::square(distance - Acts::abs(testMe->driftRadius())) /
0513 testMe->covariance()[covIdx]
0514 : state.candidateChi2(cctx, seedPos, seedDir, t0, *testMe);
0515
0516 if (pullSq < maxPullSq) {
0517 ACTS_VERBOSE(__func__
0518 << "() " << __LINE__ << " - layer,hit = (" << layerNr
0519 << "," << hitNr
0520 << ") -> spacePoint: " << Acts::toString(*testMe)
0521 << " is close enough: " << distance
0522 << ", pull: " << std::sqrt(pullSq));
0523 hadGoodHit = true;
0524 newSolution.append(layerNr, hitNr);
0525 newSolution.nStrawHits += selector(*testMe);
0526 continue;
0527 }
0528 }
0529 if (hadGoodHit) {
0530 break;
0531 }
0532 }
0533 }
0534 if (!passSeedCuts(tangentSeed, newSolution, state)) {
0535 return std::nullopt;
0536 }
0537 return consructSegmentSeed(cctx, tangentSeed, state, std::move(newSolution));
0538 }
0539
0540 template <
0541 CompositeSpacePointContainer UncalibCont_t,
0542 CompositeSpacePointContainer CalibCont_t,
0543 detail::CompSpacePointSeederDelegate<UncalibCont_t, CalibCont_t> Delegate_t>
0544 CompositeSpacePointLineSeeder::SegmentSeed<CalibCont_t>
0545 CompositeSpacePointLineSeeder::consructSegmentSeed(
0546 const CalibrationContext& cctx, const Line_t& tangentSeed,
0547 SeedingState<UncalibCont_t, CalibCont_t, Delegate_t>& state,
0548 SeedSolution<UncalibCont_t, Delegate_t>&& newSolution) const {
0549 ACTS_DEBUG(__func__ << "() " << __LINE__ << " Construct new seed from \n"
0550 << newSolution);
0551 SegmentSeed<CalibCont_t> finalSeed{
0552 combineWithPattern(tangentSeed, state.initialParameters()),
0553 state.newContainer(cctx)};
0554 const auto [seedPos, seedDir] = makeLine(finalSeed.parameters);
0555
0556 const double t0 = finalSeed.parameters[toUnderlying(ParIdx::t0)];
0557 for (std::size_t s = 0; s < newSolution.size(); ++s) {
0558 state.append(cctx, seedPos, seedDir, t0, newSolution.getHit(s),
0559 finalSeed.hits);
0560 }
0561
0562 state.m_seenSolutions.push_back(std::move(newSolution));
0563
0564 ACTS_DEBUG(__func__ << "() " << __LINE__
0565 << " - Associate the strip hits to the seed");
0566 for (const auto& stripLayerHits : state.stripHits()) {
0567 double bestChi2Loc0{m_cfg.hitPullCut};
0568 double bestChi2Loc1{m_cfg.hitPullCut};
0569 std::size_t bestIdxLoc0{stripLayerHits.size()};
0570 std::size_t bestIdxLoc1{stripLayerHits.size()};
0571
0572 for (const auto& [hitIdx, testMe] : Acts::enumerate(stripLayerHits)) {
0573 const double chi2 =
0574 state.candidateChi2(cctx, seedPos, seedDir, t0, *testMe);
0575 if (testMe->measuresLoc0() && chi2 < bestChi2Loc0) {
0576 bestChi2Loc0 = chi2;
0577 bestIdxLoc0 = hitIdx;
0578 }
0579 if (testMe->measuresLoc1() && chi2 < bestChi2Loc1) {
0580 bestChi2Loc1 = chi2;
0581 bestIdxLoc1 = hitIdx;
0582 }
0583 }
0584 if (bestIdxLoc0 < stripLayerHits.size()) {
0585 ACTS_VERBOSE(__func__ << "() " << __LINE__ << " - Append loc0 strip hit "
0586 << Acts::toString(*stripLayerHits.at(bestIdxLoc0))
0587 << ".");
0588 state.append(cctx, seedPos, seedDir, t0, *stripLayerHits.at(bestIdxLoc0),
0589 finalSeed.hits);
0590 }
0591 if (bestIdxLoc1 != bestIdxLoc0 && bestIdxLoc1 < stripLayerHits.size()) {
0592 ACTS_VERBOSE(__func__ << "() " << __LINE__ << " - Append loc1 strip hit "
0593 << Acts::toString(*stripLayerHits.at(bestIdxLoc1))
0594 << ".");
0595 state.append(cctx, seedPos, seedDir, t0, *stripLayerHits.at(bestIdxLoc1),
0596 finalSeed.hits);
0597 }
0598 }
0599 return finalSeed;
0600 }
0601 }