File indexing completed on 2025-12-16 09:22:39
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 ResidualIdx = detail::CompSpacePointAuxiliaries::ResidualIdx;
0028 using namespace Acts::UnitLiterals;
0029 using namespace Acts::detail;
0030 TwoCircleTangentPars result{};
0031 result.ambi = ambi;
0032 const auto& [signTop, signBot] = s_signCombo[toUnderlying(ambi)];
0033
0034 const Vector& bottomPos{bottomHit.localPosition()};
0035 const Vector& topPos{topHit.localPosition()};
0036 const Vector& eY{bottomHit.toNextSensor()};
0037 const Vector& eZ{bottomHit.planeNormal()};
0038 const Vector D = topPos - bottomPos;
0039
0040 assert(Acts::abs(eY.dot(eZ)) < s_epsilon);
0041 assert(Acts::abs(bottomHit.sensorDirection().dot(eY)) < s_epsilon);
0042 assert(Acts::abs(bottomHit.sensorDirection().dot(eZ)) < s_epsilon);
0043 assert(topHit.isStraw() && bottomHit.isStraw());
0044
0045 const double dY = D.dot(eY);
0046 const double dZ = D.dot(eZ);
0047
0048 const double thetaTubes = std::atan2(dY, dZ);
0049 const double distTubes = Acts::fastHypot(dY, dZ);
0050 assert(distTubes > 1._mm);
0051 constexpr auto covIdx = Acts::toUnderlying(ResidualIdx::bending);
0052 const double combDriftUncert{topHit.covariance()[covIdx] +
0053 bottomHit.covariance()[covIdx]};
0054 const double R =
0055 -signBot * bottomHit.driftRadius() + signTop * topHit.driftRadius();
0056 result.theta = thetaTubes - std::asin(std::clamp(R / distTubes, -1., 1.));
0057
0058 const double cosTheta = std::cos(result.theta);
0059 const double sinTheta = std::sin(result.theta);
0060
0061 result.y0 = bottomPos.dot(eY) * cosTheta - bottomPos.dot(eZ) * sinTheta -
0062 signBot * bottomHit.driftRadius();
0063 assert(Acts::abs(topPos.dot(eY) * cosTheta - topPos.dot(eZ) * sinTheta -
0064 signTop * topHit.driftRadius() - result.y0) <
0065 std::numeric_limits<float>::epsilon());
0066 result.y0 /= cosTheta;
0067 const double denomSquare = 1. - Acts::pow(R / distTubes, 2);
0068 if (denomSquare < s_epsilon) {
0069 return result;
0070 }
0071 result.dTheta = combDriftUncert / std::sqrt(denomSquare) / distTubes;
0072 result.dY0 =
0073 Acts::fastHypot(
0074 bottomPos.dot(eY) * sinTheta + bottomPos.dot(eZ) * cosTheta, 1.) *
0075 result.dTheta;
0076
0077 return result;
0078 }
0079
0080 template <CompositeSpacePoint Sp_t>
0081 CompositeSpacePointLineSeeder::Vector
0082 CompositeSpacePointLineSeeder::makeDirection(const Sp_t& refHit,
0083 const double tanAngle) {
0084 const Vector& eY{refHit.toNextSensor()};
0085 const Vector& eZ{refHit.planeNormal()};
0086 const double cosTheta = std::cos(tanAngle);
0087 const double sinTheta = std::sin(tanAngle);
0088 return copySign<Vector, double>(sinTheta * eY + cosTheta * eZ, sinTheta);
0089 }
0090
0091 template <CompositeSpacePointContainer Cont_t>
0092 std::size_t CompositeSpacePointLineSeeder::countHits(
0093 const Cont_t& container, const Selector_t<Cont_t>& selector) const {
0094 if (m_cfg.busyLimitCountGood) {
0095 return std::ranges::count_if(
0096 container, [&](const auto& hit) { return selector(*hit); });
0097 }
0098 return container.size();
0099 }
0100
0101
0102
0103
0104 template <CompositeSpacePointContainer UnCalibCont_t,
0105 detail::CompositeSpacePointSorter<UnCalibCont_t> Splitter_t>
0106 CompositeSpacePointLineSeeder::SeedSolution<UnCalibCont_t,
0107 Splitter_t>::SpacePoint_t
0108 CompositeSpacePointLineSeeder::SeedSolution<UnCalibCont_t, Splitter_t>::getHit(
0109 const std::size_t idx) const {
0110 const auto& [layIdx, hitIdx] = m_seedHits.at(idx);
0111 const UnCalibCont_t& strawLayer = m_splitter.strawHits().at(layIdx);
0112 return *strawLayer.at(hitIdx);
0113 }
0114 template <CompositeSpacePointContainer UnCalibCont_t,
0115 detail::CompositeSpacePointSorter<UnCalibCont_t> Splitter_t>
0116 std::vector<int> CompositeSpacePointLineSeeder::SeedSolution<
0117 UnCalibCont_t, Splitter_t>::leftRightAmbiguity(const Vector& seedPos,
0118 const Vector& seedDir)
0119 const {
0120 std::vector<int> result{};
0121 result.reserve(size());
0122 std::ranges::transform(
0123 m_seedHits, std::back_inserter(result),
0124 [&](const std::pair<std::size_t, std::size_t>& indices) {
0125 const auto& [layIdx, hitIdx] = indices;
0126 const UnCalibCont_t& strawLayer = m_splitter.strawHits().at(layIdx);
0127 return detail::CompSpacePointAuxiliaries::strawSign(
0128 seedPos, seedDir, *strawLayer.at(hitIdx));
0129 });
0130 return result;
0131 }
0132 template <CompositeSpacePointContainer UnCalibCont_t,
0133 detail::CompositeSpacePointSorter<UnCalibCont_t> Splitter_t>
0134 void CompositeSpacePointLineSeeder::SeedSolution<
0135 UnCalibCont_t, Splitter_t>::append(const std::size_t layIdx,
0136 const std::size_t hitIdx) {
0137 assert(!rangeContainsValue(m_seedHits, std::make_pair(layIdx, hitIdx)));
0138 m_seedHits.emplace_back(layIdx, hitIdx);
0139 }
0140 template <CompositeSpacePointContainer UnCalibCont_t,
0141 detail::CompositeSpacePointSorter<UnCalibCont_t> Splitter_t>
0142 void CompositeSpacePointLineSeeder::SeedSolution<
0143 UnCalibCont_t, Splitter_t>::print(std::ostream& ostr) const {
0144 TwoCircleTangentPars::print(ostr);
0145 const std::size_t N = size();
0146 ostr << ", associated hits: " << N << std::endl;
0147 for (std::size_t h = 0; h < N; ++h) {
0148 ostr << " **** " << (h + 1ul) << ") " << Acts::toString(getHit(h))
0149 << std::endl;
0150 }
0151 }
0152
0153
0154
0155
0156 template <
0157 CompositeSpacePointContainer UncalibCont_t,
0158 CompositeSpacePointContainer CalibCont_t,
0159 detail::CompSpacePointSeederDelegate<UncalibCont_t, CalibCont_t> Delegate_t>
0160 void CompositeSpacePointLineSeeder::SeedingState<
0161 UncalibCont_t, CalibCont_t, Delegate_t>::print(std::ostream& ostr) const {
0162 const std::size_t nStraw = this->strawHits().size();
0163
0164 ostr << "Seed state:\n";
0165 ostr << "N strawLayers: " << nStraw
0166 << " N strip layers: " << this->stripHits().size() << "\n";
0167 ostr << "upperLayer " << m_upperLayer.value_or(nStraw - 1ul) << " lowerLayer "
0168 << m_lowerLayer.value_or(0u) << " upperHitIndex " << m_upperHitIndex
0169 << " lower layer hit index " << m_lowerHitIndex << " sign combo index "
0170 << toString(encodeAmbiguity(s_signCombo[m_signComboIndex][0],
0171 s_signCombo[m_signComboIndex][1]))
0172 << "\n";
0173 ostr << " start with pattern " << startWithPattern << " nGenSeeds "
0174 << nGenSeeds() << " nStrawCut " << m_nStrawCut << "\n";
0175 if (nGenSeeds() > 0ul) {
0176 for (const auto& seen : m_seenSolutions) {
0177 ostr << "################################################" << std::endl;
0178 ostr << seen << std::endl;
0179 ostr << "################################################" << std::endl;
0180 }
0181 }
0182 }
0183
0184 template <CompositeSpacePointContainer UnCalibCont_t>
0185 bool CompositeSpacePointLineSeeder::moveToNextHit(
0186 const UnCalibCont_t& hitVec, const Selector_t<UnCalibCont_t>& selector,
0187 std::size_t& hitIdx) const {
0188 ACTS_VERBOSE(__func__ << "() " << __LINE__
0189 << " - Moving to next good hit from index " << hitIdx
0190 << " in straw layer with " << hitVec.size()
0191 << " hits.");
0192 while (++hitIdx < hitVec.size()) {
0193 if (selector(*hitVec[hitIdx])) {
0194 ACTS_VERBOSE(__func__ << "() " << __LINE__ << " - Moved towards index "
0195 << hitIdx);
0196 return true;
0197 }
0198 }
0199 ACTS_VERBOSE(__func__ << "() " << __LINE__ << " - No good hit found.");
0200 return false;
0201 }
0202
0203 template <CompositeSpacePointContainer UnCalibCont_t>
0204 bool CompositeSpacePointLineSeeder::firstGoodHit(
0205 const UnCalibCont_t& hitVec, const Selector_t<UnCalibCont_t>& selector,
0206 std::size_t& hitIdx) const {
0207 hitIdx = 0;
0208 if (hitVec.empty()) {
0209 ACTS_VERBOSE(__func__ << "() " << __LINE__ << " - Layer is empty.");
0210 return false;
0211 }
0212 return selector(*hitVec[hitIdx]) || moveToNextHit(hitVec, selector, hitIdx);
0213 }
0214 template <CompositeSpacePointContainer UnCalibCont_t>
0215 bool CompositeSpacePointLineSeeder::nextLayer(
0216 const StrawLayers_t<UnCalibCont_t>& strawLayers,
0217 const Selector_t<UnCalibCont_t>& selector, const std::size_t boundary,
0218 std::optional<std::size_t>& layerIndex, std::size_t& hitIdx,
0219 bool moveForward) const {
0220 if (strawLayers.empty()) {
0221 ACTS_VERBOSE(__func__ << "() " << __LINE__ << " - No straw layers.");
0222 return false;
0223 }
0224
0225 if (!layerIndex.has_value()) {
0226 layerIndex = moveForward ? 0u : strawLayers.size() - 1u;
0227 const UnCalibCont_t& hitVec{strawLayers.at(layerIndex.value())};
0228 if (hitVec.size() <= m_cfg.busyLayerLimit &&
0229 firstGoodHit(hitVec, selector, hitIdx)) {
0230 ACTS_VERBOSE(__func__ << "() " << __LINE__ << " - Instantiated "
0231 << (moveForward ? "lower" : "upper") << " layer to "
0232 << layerIndex.value() << ".");
0233 return true;
0234 }
0235 }
0236 ACTS_VERBOSE(__func__ << "() " << __LINE__ << " - Move "
0237 << (moveForward ? "lower" : "upper") << " layer "
0238 << layerIndex.value() << " to next value.");
0239
0240 while ((moveForward ? (++layerIndex.value()) : (--layerIndex.value())) <
0241 strawLayers.size()) {
0242 const UnCalibCont_t& hitVec{strawLayers.at(layerIndex.value())};
0243
0244 if ((moveForward && layerIndex.value() >= boundary) ||
0245 (!moveForward && layerIndex.value() <= boundary)) {
0246 ACTS_VERBOSE(__func__ << "() " << __LINE__ << " - The "
0247 << (moveForward ? "lower" : "upper") << " index "
0248 << layerIndex.value()
0249 << " exceeds the boundary: " << boundary << ".");
0250 return false;
0251 }
0252
0253 if (const std::size_t nHits = countHits(hitVec, selector);
0254 nHits > m_cfg.busyLayerLimit) {
0255 ACTS_VERBOSE(__func__ << "() " << __LINE__ << " - The layer "
0256 << layerIndex.value()
0257 << " is too busy for seeding: " << nHits
0258 << ". Limit: " << m_cfg.busyLayerLimit << ".");
0259 continue;
0260 }
0261
0262
0263 if (firstGoodHit(strawLayers.at(layerIndex.value()), selector, hitIdx)) {
0264 ACTS_VERBOSE(__func__
0265 << "() " << __LINE__ << " - Loop over all hits in the "
0266 << layerIndex.value() << (moveForward ? "lower" : "upper")
0267 << " layer.");
0268 return true;
0269 }
0270 }
0271 return false;
0272 }
0273
0274 template <
0275 CompositeSpacePointContainer UncalibCont_t,
0276 CompositeSpacePointContainer CalibCont_t,
0277 detail::CompSpacePointSeederDelegate<UncalibCont_t, CalibCont_t> Delegate_t>
0278 std::optional<CompositeSpacePointLineSeeder::SegmentSeed<CalibCont_t>>
0279 CompositeSpacePointLineSeeder::nextSeed(
0280 const CalibrationContext& cctx,
0281 SeedingState<UncalibCont_t, CalibCont_t, Delegate_t>& state) const {
0282 const StrawLayers_t<UncalibCont_t>& strawLayers{state.strawHits()};
0283
0284 Selector_t<UncalibCont_t> selector{};
0285 selector.template connect<&Delegate_t::goodCandidate>(&state);
0286
0287 if (!state.m_upperLayer || !state.m_lowerLayer) {
0288 state.m_nStrawCut = m_cfg.nStrawHitCut;
0289
0290
0291 if (state.startWithPattern &&
0292 std::ranges::any_of(strawLayers, [&](const UncalibCont_t& layerHits) {
0293 return countHits(layerHits, selector) > m_cfg.busyLayerLimit;
0294 })) {
0295 state.startWithPattern = false;
0296 }
0297 if (state.startWithPattern) {
0298 SegmentSeed<CalibCont_t> patternSeed{state.patternParams,
0299 state.newContainer(cctx)};
0300
0301 const auto [pos, dir] = makeLine(state.patternParams);
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.startWithPattern = false;
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 if (state.strawRadius <= Acts::s_epsilon) {
0454 throw std::invalid_argument(
0455 "buildSeed() - Please configure the state's strawRadius");
0456 }
0457 const auto& upperHit =
0458 *strawLayers.at(state.m_upperLayer.value()).at(state.m_upperHitIndex);
0459 const auto& lowerHit =
0460 *strawLayers.at(state.m_lowerLayer.value()).at(state.m_lowerHitIndex);
0461 const auto ambi{static_cast<TangentAmbi>(state.m_signComboIndex)};
0462 ACTS_VERBOSE(__func__ << "() " << __LINE__ << " - " << toString(ambi)
0463 << "\n Top seed hit: " << Acts::toString(upperHit)
0464 << "\n Bottom seed hit:" << Acts::toString(lowerHit)
0465 << ".");
0466
0467 const TwoCircleTangentPars seedPars =
0468 constructTangentLine(lowerHit, upperHit, ambi);
0469 ACTS_VERBOSE(__func__ << "() " << __LINE__
0470 << " - Tangential parameters: " << seedPars);
0471 if (!isValidLine(seedPars)) {
0472 ACTS_VERBOSE(__func__ << "() " << __LINE__ << " - Reject seed.");
0473 return std::nullopt;
0474 }
0475
0476 if (std::ranges::any_of(state.m_seenSolutions, [&seedPars](const auto& seen) {
0477 const double deltaY = Acts::abs(seen.y0 - seedPars.y0);
0478 const double limitY = Acts::fastHypot(seen.dY0, seedPars.dY0);
0479 const double deltaTheta = Acts::abs(seen.theta - seedPars.theta);
0480 const double limitTheta = Acts::fastHypot(seen.dTheta, seedPars.dTheta);
0481 return deltaY < limitY && deltaTheta < limitTheta;
0482 })) {
0483 ACTS_VERBOSE(__func__ << "() " << __LINE__ << " - Reject seed.");
0484 return std::nullopt;
0485 }
0486
0487 const double t0 = state.patternParams[toUnderlying(ParIdx::t0)];
0488 SeedSolution<UncalibCont_t, Delegate_t> newSolution{seedPars, state};
0489
0490 ACTS_DEBUG(__func__ << "() " << __LINE__
0491 << " - Start looking for compatible hits");
0492
0493 const Line_t tangentSeed{seedPars.y0 * Vector3::UnitY(),
0494 makeDirection(lowerHit, seedPars.theta)};
0495 const auto& [seedPos, seedDir] = tangentSeed;
0496 for (const auto& [layerNr, hitsInLayer] :
0497 Acts::enumerate(state.strawHits())) {
0498 bool hadGoodHit{false};
0499 for (const auto& [hitNr, testMe] : Acts::enumerate(hitsInLayer)) {
0500 using namespace Acts::detail::LineHelper;
0501 const double distance = Acts::abs(
0502 signedDistance(testMe->localPosition(), testMe->sensorDirection(),
0503 seedPos, seedDir));
0504
0505
0506
0507 if (distance < state.strawRadius &&
0508 state.candidatePull(cctx, seedPos, seedDir, t0, *testMe) <
0509 Acts::pow(m_cfg.hitPullCut, 2u)) {
0510 ACTS_VERBOSE(__func__ << "() " << __LINE__ << " - layer,hit = ("
0511 << layerNr << "," << hitNr
0512 << ") -> spacePoint: " << Acts::toString(*testMe)
0513 << " is close enough: " << distance);
0514 hadGoodHit = true;
0515 newSolution.append(layerNr, hitNr);
0516 newSolution.nStrawHits += selector(*testMe);
0517 continue;
0518 }
0519 if (hadGoodHit) {
0520 break;
0521 }
0522 }
0523 }
0524 if (!passSeedCuts(tangentSeed, newSolution, state)) {
0525 return std::nullopt;
0526 }
0527 return consructSegmentSeed(cctx, tangentSeed, state, std::move(newSolution));
0528 }
0529
0530 template <
0531 CompositeSpacePointContainer UncalibCont_t,
0532 CompositeSpacePointContainer CalibCont_t,
0533 detail::CompSpacePointSeederDelegate<UncalibCont_t, CalibCont_t> Delegate_t>
0534 CompositeSpacePointLineSeeder::SegmentSeed<CalibCont_t>
0535 CompositeSpacePointLineSeeder::consructSegmentSeed(
0536 const CalibrationContext& cctx, const Line_t& tangentSeed,
0537 SeedingState<UncalibCont_t, CalibCont_t, Delegate_t>& state,
0538 SeedSolution<UncalibCont_t, Delegate_t>&& newSolution) const {
0539 ACTS_DEBUG(__func__ << "() " << __LINE__ << " Construct new seed from \n"
0540 << newSolution);
0541 SegmentSeed<CalibCont_t> finalSeed{
0542 combineWithPattern(tangentSeed, state.patternParams),
0543 state.newContainer(cctx)};
0544 const auto [seedPos, seedDir] = makeLine(finalSeed.parameters);
0545
0546 const double t0 = finalSeed.parameters[toUnderlying(ParIdx::t0)];
0547 for (std::size_t s = 0; s < newSolution.size(); ++s) {
0548 state.append(cctx, seedPos, seedDir, t0, newSolution.getHit(s),
0549 finalSeed.hits);
0550 }
0551
0552 state.m_seenSolutions.push_back(std::move(newSolution));
0553
0554 ACTS_DEBUG(__func__ << "() " << __LINE__
0555 << " - Associate the strip hits to the seed");
0556 for (const auto& stripLayerHits : state.stripHits()) {
0557 double bestChi2Loc0{m_cfg.hitPullCut};
0558 double bestChi2Loc1{m_cfg.hitPullCut};
0559 std::size_t bestIdxLoc0{stripLayerHits.size()};
0560 std::size_t bestIdxLoc1{stripLayerHits.size()};
0561
0562 for (const auto& [hitIdx, testMe] : Acts::enumerate(stripLayerHits)) {
0563 const double chi2 =
0564 state.candidatePull(cctx, seedPos, seedDir, t0, *testMe);
0565 if (testMe->measuresLoc0() && chi2 < bestChi2Loc0) {
0566 bestChi2Loc0 = chi2;
0567 bestIdxLoc0 = hitIdx;
0568 }
0569 if (testMe->measuresLoc1() && chi2 < bestChi2Loc1) {
0570 bestChi2Loc1 = chi2;
0571 bestIdxLoc1 = hitIdx;
0572 }
0573 }
0574 if (bestIdxLoc0 < stripLayerHits.size()) {
0575 ACTS_VERBOSE(__func__ << "() " << __LINE__ << " - Append loc0 strip hit "
0576 << Acts::toString(*stripLayerHits.at(bestIdxLoc0))
0577 << ".");
0578 state.append(cctx, seedPos, seedDir, t0, *stripLayerHits.at(bestIdxLoc0),
0579 finalSeed.hits);
0580 }
0581 if (bestIdxLoc1 != bestIdxLoc0 && bestIdxLoc1 < stripLayerHits.size()) {
0582 ACTS_VERBOSE(__func__ << "() " << __LINE__ << " - Append loc1 strip hit "
0583 << Acts::toString(*stripLayerHits.at(bestIdxLoc1))
0584 << ".");
0585 state.append(cctx, seedPos, seedDir, t0, *stripLayerHits.at(bestIdxLoc1),
0586 finalSeed.hits);
0587 }
0588 }
0589 return finalSeed;
0590 }
0591 }