Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-10-23 08:20:17

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/Geometry/Layer.hpp"
0010 
0011 #include "Acts/Material/IMaterialDecorator.hpp"
0012 #include "Acts/Propagator/NavigationTarget.hpp"
0013 #include "Acts/Propagator/Navigator.hpp"
0014 #include "Acts/Surfaces/BoundaryTolerance.hpp"
0015 #include "Acts/Surfaces/Surface.hpp"
0016 #include "Acts/Surfaces/SurfaceArray.hpp"
0017 #include "Acts/Utilities/Enumerate.hpp"
0018 #include "Acts/Utilities/Helpers.hpp"
0019 #include "Acts/Utilities/Intersection.hpp"
0020 
0021 #include <algorithm>
0022 #include <vector>
0023 
0024 namespace Acts {
0025 
0026 Layer::Layer(std::unique_ptr<SurfaceArray> surfaceArray, double thickness,
0027              std::unique_ptr<ApproachDescriptor> ades, LayerType laytyp)
0028     : m_nextLayers(NextLayers(nullptr, nullptr)),
0029       m_surfaceArray(surfaceArray.release()),
0030       m_layerThickness(thickness),
0031       m_approachDescriptor(nullptr),
0032       m_representingVolume(nullptr),
0033       m_layerType(laytyp),
0034       m_ssRepresentingSurface(1) {
0035   if (ades) {
0036     ades->registerLayer(*this);
0037     m_approachDescriptor = std::move(ades);
0038     m_ssApproachSurfaces = 1;  // indicates existence
0039   }
0040   // indicates existence of sensitive surfaces
0041   if (m_surfaceArray) {
0042     m_ssSensitiveSurfaces = 1;
0043   }
0044 }
0045 
0046 Layer::~Layer() noexcept = default;
0047 
0048 const ApproachDescriptor* Layer::approachDescriptor() const {
0049   return m_approachDescriptor.get();
0050 }
0051 
0052 ApproachDescriptor* Layer::approachDescriptor() {
0053   return const_cast<ApproachDescriptor*>(m_approachDescriptor.get());
0054 }
0055 
0056 void Layer::closeGeometry(const IMaterialDecorator* materialDecorator,
0057                           const GeometryIdentifier& layerID,
0058                           const GeometryIdentifierHook& hook,
0059                           const Logger& logger) {
0060   // set the volumeID of this
0061   assignGeometryId(layerID);
0062   // assign to the representing surface
0063   Surface* rSurface = const_cast<Surface*>(&surfaceRepresentation());
0064   if (materialDecorator != nullptr) {
0065     materialDecorator->decorate(*rSurface);
0066   }
0067   ACTS_DEBUG("layerID: " << layerID);
0068 
0069   rSurface->assignGeometryId(layerID);
0070 
0071   // also find out how the sub structure is defined
0072   if (surfaceRepresentation().hasMaterial()) {
0073     m_ssRepresentingSurface = 2;
0074   }
0075   // loop over the approach surfaces
0076   if (m_approachDescriptor) {
0077     // indicates the existence of approach surfaces
0078     m_ssApproachSurfaces = 1;
0079     // loop through the approachSurfaces and assign unique GeomeryID
0080     GeometryIdentifier::Value iasurface = 0;
0081     for (auto& aSurface : m_approachDescriptor->containedSurfaces()) {
0082       auto asurfaceID = GeometryIdentifier(layerID).withApproach(++iasurface);
0083       auto mutableASurface = const_cast<Surface*>(aSurface);
0084       mutableASurface->assignGeometryId(asurfaceID);
0085       if (materialDecorator != nullptr) {
0086         materialDecorator->decorate(*mutableASurface);
0087       }
0088       // if any of the approach surfaces has material
0089       if (aSurface->hasMaterial()) {
0090         m_ssApproachSurfaces = 2;
0091       }
0092     }
0093   }
0094   // check if you have sensitive surfaces
0095   if (m_surfaceArray) {
0096     // indicates the existence of sensitive surfaces
0097     m_ssSensitiveSurfaces = 1;
0098     // loop sensitive surfaces and assign unique GeometryIdentifier
0099     GeometryIdentifier::Value issurface = 0;
0100     for (auto& sSurface : m_surfaceArray->surfaces()) {
0101       auto ssurfaceID = GeometryIdentifier(layerID).withSensitive(++issurface);
0102       ssurfaceID = hook.decorateIdentifier(ssurfaceID, *sSurface);
0103       auto mutableSSurface = const_cast<Surface*>(sSurface);
0104       mutableSSurface->assignGeometryId(ssurfaceID);
0105       if (materialDecorator != nullptr) {
0106         materialDecorator->decorate(*mutableSSurface);
0107       }
0108       // if any of the sensitive surfaces has material
0109       if (sSurface->hasMaterial()) {
0110         m_ssSensitiveSurfaces = 2;
0111       }
0112     }
0113   }
0114 }
0115 
0116 boost::container::small_vector<NavigationTarget, 10> Layer::compatibleSurfaces(
0117     const GeometryContext& gctx, const Vector3& position,
0118     const Vector3& direction, const NavigationOptions<Surface>& options) const {
0119   // the list of valid intersection
0120   boost::container::small_vector<NavigationTarget, 10> surfaceIntersections;
0121 
0122   // fast exit - there is nothing to
0123   if (!m_surfaceArray || !m_approachDescriptor) {
0124     return surfaceIntersections;
0125   }
0126 
0127   double nearLimit = options.nearLimit;
0128   double farLimit = options.farLimit;
0129 
0130   auto isUnique = [&](const NavigationTarget& b) {
0131     return std::ranges::none_of(
0132         surfaceIntersections, [&b](const NavigationTarget& a) {
0133           return &a.surface() == &b.surface() &&
0134                  a.intersectionIndex() == b.intersectionIndex();
0135         });
0136   };
0137 
0138   // lemma 0 : accept the surface
0139   auto acceptSurface = [&options](const Surface& sf,
0140                                   bool sensitive = false) -> bool {
0141     // surface is sensitive and you're asked to resolve
0142     if (sensitive && options.resolveSensitive) {
0143       return true;
0144     }
0145     // next option: it's a material surface, and you want to have it
0146     if (options.resolveMaterial && sf.hasMaterial()) {
0147       return true;
0148     }
0149     // last option: resolve all
0150     return options.resolvePassive;
0151   };
0152 
0153   // lemma 1 : check and fill the surface
0154   auto processSurface = [&](const Surface& surface, bool sensitive = false) {
0155     // veto if it's start surface
0156     if (options.startObject == &surface) {
0157       return;
0158     }
0159     // veto if it doesn't fit the prescription
0160     if (!acceptSurface(surface, sensitive)) {
0161       return;
0162     }
0163     BoundaryTolerance boundaryTolerance = options.boundaryTolerance;
0164     if (auto extendedSurface =
0165             std::ranges::find(options.extendedSurfaces, surface.geometryId(),
0166                               [](const auto& e) { return e.first; });
0167         extendedSurface != options.extendedSurfaces.end()) {
0168       boundaryTolerance = extendedSurface->second;
0169     }
0170     // the surface intersection
0171     auto [intersection, intersectionIndex] =
0172         surface.intersect(gctx, position, direction, boundaryTolerance)
0173             .closestWithIndex();
0174     NavigationTarget surfaceIntersection(intersection, intersectionIndex,
0175                                          surface, boundaryTolerance);
0176     if (intersection.isValid() &&
0177         detail::checkPathLength(intersection.pathLength(), nearLimit,
0178                                 farLimit) &&
0179         isUnique(surfaceIntersection)) {
0180       surfaceIntersections.push_back(surfaceIntersection);
0181     }
0182   };
0183 
0184   // (A) approach descriptor section
0185   //
0186   // the approach surfaces are in principle always testSurfaces
0187   // - the surface on approach is excluded via the veto
0188   // - the surfaces are only collected if needed
0189   if (m_approachDescriptor &&
0190       (options.resolveMaterial || options.resolvePassive)) {
0191     // the approach surfaces
0192     const std::vector<const Surface*>& approachSurfaces =
0193         m_approachDescriptor->containedSurfaces();
0194     // we loop through and veto
0195     // - if the approach surface is the parameter surface
0196     // - if the surface is not compatible with the collect
0197     for (const Surface* aSurface : approachSurfaces) {
0198       processSurface(*aSurface);
0199     }
0200   }
0201 
0202   // (B) sensitive surface section
0203   //
0204   // check the sensitive surfaces if you have some
0205   if (m_surfaceArray && (options.resolveMaterial || options.resolvePassive ||
0206                          options.resolveSensitive)) {
0207     // get the candidates
0208     const auto sensitiveSurfaces =
0209         m_surfaceArray->neighbors(gctx, position, direction);
0210     // loop through and veto
0211     // - if the approach surface is the parameter surface
0212     // - if the surface is not compatible with the type(s) that are collected
0213     for (const Surface* sSurface : sensitiveSurfaces) {
0214       processSurface(*sSurface, true);
0215     }
0216   }
0217 
0218   // (C) representing surface section
0219   //
0220   // the layer surface itself is a testSurface
0221   const Surface* layerSurface = &surfaceRepresentation();
0222   processSurface(*layerSurface);
0223 
0224   return surfaceIntersections;
0225 }
0226 
0227 NavigationTarget Layer::surfaceOnApproach(
0228     const GeometryContext& gctx, const Vector3& position,
0229     const Vector3& direction, const NavigationOptions<Layer>& options) const {
0230   // resolve directive based by options
0231   // - options.resolvePassive is on -> always
0232   // - options.resolveSensitive is on -> always
0233   // - options.resolveMaterial is on
0234   //   && either sensitive or approach surfaces have material
0235   const bool resolvePS = options.resolveSensitive || options.resolvePassive;
0236   const bool resolveMS =
0237       options.resolveMaterial &&
0238       (m_ssSensitiveSurfaces > 1 || m_ssApproachSurfaces > 1 ||
0239        surfaceRepresentation().hasMaterial());
0240 
0241   // The Limits
0242   const double nearLimit = options.nearLimit;
0243   const double farLimit = options.farLimit;
0244 
0245   // Approach descriptor present and resolving is necessary
0246   if (m_approachDescriptor && (resolvePS || resolveMS)) {
0247     NavigationTarget aSurface = m_approachDescriptor->approachSurface(
0248         gctx, position, direction, options.boundaryTolerance, nearLimit,
0249         farLimit);
0250     return aSurface;
0251   }
0252 
0253   // Intersect and check the representing surface
0254   const Surface& layerSurface = surfaceRepresentation();
0255   const MultiIntersection3D multiIntersection = layerSurface.intersect(
0256       gctx, position, direction, options.boundaryTolerance);
0257   for (auto [intersectionIndex, intersection] :
0258        Acts::enumerate(multiIntersection)) {
0259     if (intersection.isValid() &&
0260         detail::checkPathLength(intersection.pathLength(), nearLimit,
0261                                 farLimit)) {
0262       return NavigationTarget(intersection, intersectionIndex, *this,
0263                               layerSurface, options.boundaryTolerance);
0264     }
0265   }
0266   return NavigationTarget::None();
0267 }
0268 
0269 }  // namespace Acts