Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-11 07:46:55

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