Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-07-22 08:22:29

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 #include "Acts/Navigation/NavigationStream.hpp"
0010 
0011 #include "Acts/Propagator/NavigationTarget.hpp"
0012 #include "Acts/Surfaces/BoundaryTolerance.hpp"
0013 #include "Acts/Surfaces/Surface.hpp"
0014 #include "Acts/Utilities/Enumerate.hpp"
0015 
0016 #include <algorithm>
0017 
0018 namespace Acts {
0019 
0020 bool NavigationStream::initialize(const GeometryContext& gctx,
0021                                   const QueryPoint& queryPoint,
0022                                   const BoundaryTolerance& cTolerance,
0023                                   const double onSurfaceTolerance) {
0024   // Position and direction from the query point
0025   const Vector3& position = queryPoint.position;
0026   const Vector3& direction = queryPoint.direction;
0027 
0028   // De-duplicate by surface pointer first, so each surface is intersected only
0029   // once in this pass.
0030   std::ranges::stable_sort(
0031       m_candidates, [](const NavigationTarget& a, const NavigationTarget& b) {
0032         return &a.surface() < &b.surface();
0033       });
0034   auto initialDuplicates = std::ranges::unique(
0035       m_candidates.begin(), m_candidates.end(),
0036       [](const NavigationTarget& a, const NavigationTarget& b) {
0037         return &a.surface() == &b.surface();
0038       });
0039   m_candidates.erase(initialDuplicates.begin(), initialDuplicates.end());
0040 
0041   // Collect additional candidates for the second valid intersection.
0042   std::vector<NavigationTarget> additionalCandidates = {};
0043   for (auto& candidate : m_candidates) {
0044     // Get the surface from the object intersection
0045     const Surface& surface = candidate.surface();
0046     // Intersect the surface
0047     auto multiIntersection = surface.intersect(gctx, position, direction,
0048                                                cTolerance, onSurfaceTolerance);
0049 
0050     bool firstValid = multiIntersection.at(0).isValid();
0051     bool secondValid = multiIntersection.at(1).isValid();
0052     if (firstValid && !secondValid) {
0053       if (multiIntersection.at(0).pathLength() < -onSurfaceTolerance) {
0054         continue;
0055       }
0056       candidate.intersection() = multiIntersection.at(0);
0057       candidate.intersectionIndex() = 0;
0058     } else if (!firstValid && secondValid) {
0059       if (multiIntersection.at(1).pathLength() < -onSurfaceTolerance) {
0060         continue;
0061       }
0062       candidate.intersection() = multiIntersection.at(1);
0063       candidate.intersectionIndex() = 1;
0064     } else {
0065       // Split them into valid intersections, keep track of potentially
0066       // additional candidates
0067       bool originalCandidateUpdated = false;
0068       for (auto [intersectionIndex, intersection] :
0069            enumerate(multiIntersection)) {
0070         // Skip negative solutions, respecting the on surface tolerance
0071         if (intersection.pathLength() < -onSurfaceTolerance) {
0072           continue;
0073         }
0074         // Valid solution is either on surface or updates the distance
0075         if (intersection.isValid()) {
0076           if (!originalCandidateUpdated) {
0077             candidate.intersection() = intersection;
0078             candidate.intersectionIndex() = intersectionIndex;
0079             originalCandidateUpdated = true;
0080           } else {
0081             NavigationTarget additionalCandidate = candidate;
0082             additionalCandidate.intersection() = intersection;
0083             additionalCandidate.intersectionIndex() = intersectionIndex;
0084             additionalCandidates.emplace_back(additionalCandidate);
0085           }
0086         }
0087       }
0088     }
0089   }
0090 
0091   // Append the multi intersection candidates
0092   m_candidates.insert(m_candidates.end(), additionalCandidates.begin(),
0093                       additionalCandidates.end());
0094 
0095   // Sort the candidates by path length
0096   std::ranges::sort(m_candidates, NavigationTarget::pathLengthOrder);
0097 
0098   // If we have duplicates, we expect them to be close by in path length, so we
0099   // don't need to re-sort Remove duplicates on basis of the surface pointer
0100 
0101   /// But but but... What about the surfaces with multiple intersections?
0102   auto nonUniqueRange = std::ranges::unique(
0103       m_candidates.begin(), m_candidates.end(),
0104       [](const NavigationTarget& a, const NavigationTarget& b) {
0105         return &a.surface() == &b.surface();
0106       });
0107   m_candidates.erase(nonUniqueRange.begin(), nonUniqueRange.end());
0108 
0109   // The we find the first invalid candidate
0110   auto firstInvalid = std::ranges::find_if(
0111       m_candidates,
0112       [](const NavigationTarget& a) { return !a.intersection().isValid(); });
0113 
0114   // Set the range and initialize
0115   m_candidates.resize(std::distance(m_candidates.begin(), firstInvalid),
0116                       NavigationTarget::None());
0117 
0118   m_currentIndex = 0;
0119   if (m_candidates.empty()) {
0120     return false;
0121   }
0122   return true;
0123 }
0124 
0125 bool NavigationStream::update(const GeometryContext& gctx,
0126                               const QueryPoint& queryPoint,
0127                               double onSurfaceTolerance) {
0128   // Loop over the (currently valid) candidates and update
0129   for (; m_currentIndex < m_candidates.size(); ++m_currentIndex) {
0130     // Get the candidate, and resolve the tuple
0131     NavigationTarget& candidate = currentCandidate();
0132     // Get the surface from the object intersection
0133     const Surface& surface = candidate.surface();
0134     // (re-)Intersect the surface
0135     auto multiIntersection =
0136         surface.intersect(gctx, queryPoint.position, queryPoint.direction,
0137                           candidate.boundaryTolerance(), onSurfaceTolerance);
0138     // Split them into valid intersections
0139     for (auto [intersectionIndex, intersection] :
0140          enumerate(multiIntersection)) {
0141       // Skip wrong index solution
0142       if (intersectionIndex != candidate.intersectionIndex()) {
0143         continue;
0144       }
0145       // Valid solution is either on surface or updates the distance
0146       if (intersection.isValid()) {
0147         candidate.intersection() = intersection;
0148         return true;
0149       }
0150     }
0151   }
0152   // No candidate was reachable
0153   return false;
0154 }
0155 
0156 void NavigationStream::reset() {
0157   m_candidates.clear();
0158   m_currentIndex = 0;
0159 }
0160 
0161 void NavigationStream::addSurfaceCandidate(
0162     const Surface& surface, const BoundaryTolerance& bTolerance) {
0163   m_candidates.emplace_back(Intersection3D::Invalid(), 0, surface, bTolerance);
0164 }
0165 
0166 void NavigationStream::addSurfaceCandidates(
0167     std::span<const Surface*> surfaces, const BoundaryTolerance& bTolerance) {
0168   m_candidates.reserve(m_candidates.size() + surfaces.size());
0169   std::ranges::for_each(surfaces, [&](const Surface* surface) {
0170     m_candidates.emplace_back(Intersection3D::Invalid(), 0, *surface,
0171                               bTolerance);
0172   });
0173 }
0174 
0175 void NavigationStream::addPortalCandidate(const Portal& portal) {
0176   m_candidates.emplace_back(Intersection3D::Invalid(), 0, portal,
0177                             BoundaryTolerance::None());
0178 }
0179 
0180 AppendOnlyNavigationStream::AppendOnlyNavigationStream(NavigationStream& stream)
0181     : m_stream{&stream} {}
0182 
0183 void AppendOnlyNavigationStream::addPortalCandidate(const Portal& portal) {
0184   m_stream->addPortalCandidate(portal);
0185 }
0186 
0187 void AppendOnlyNavigationStream::addSurfaceCandidate(
0188     const Surface& surface, const BoundaryTolerance& bTolerance) {
0189   m_stream->addSurfaceCandidate(surface, bTolerance);
0190 }
0191 
0192 }  // namespace Acts