Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-13 08:16:28

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().surfaceMaterial() != nullptr) {
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->surfaceMaterial() != nullptr) {
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->surfaceMaterial() != nullptr) {
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.surfaceMaterial() != nullptr) {
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 (rangeContainsValue(options.externalSurfaces, surface.geometryId())) {
0165       boundaryTolerance = BoundaryTolerance::Infinite();
0166     }
0167     // the surface intersection
0168     auto [intersection, intersectionIndex] =
0169         surface.intersect(gctx, position, direction, boundaryTolerance)
0170             .closestWithIndex();
0171     NavigationTarget surfaceIntersection(intersection, intersectionIndex,
0172                                          surface, boundaryTolerance);
0173     if (intersection.isValid() &&
0174         detail::checkPathLength(intersection.pathLength(), nearLimit,
0175                                 farLimit) &&
0176         isUnique(surfaceIntersection)) {
0177       surfaceIntersections.push_back(surfaceIntersection);
0178     }
0179   };
0180 
0181   // (A) approach descriptor section
0182   //
0183   // the approach surfaces are in principle always testSurfaces
0184   // - the surface on approach is excluded via the veto
0185   // - the surfaces are only collected if needed
0186   if (m_approachDescriptor &&
0187       (options.resolveMaterial || options.resolvePassive)) {
0188     // the approach surfaces
0189     const std::vector<const Surface*>& approachSurfaces =
0190         m_approachDescriptor->containedSurfaces();
0191     // we loop through and veto
0192     // - if the approach surface is the parameter surface
0193     // - if the surface is not compatible with the collect
0194     for (auto& aSurface : approachSurfaces) {
0195       processSurface(*aSurface);
0196     }
0197   }
0198 
0199   // (B) sensitive surface section
0200   //
0201   // check the sensitive surfaces if you have some
0202   if (m_surfaceArray && (options.resolveMaterial || options.resolvePassive ||
0203                          options.resolveSensitive)) {
0204     // get the candidates
0205     const std::vector<const Surface*>& sensitiveSurfaces =
0206         m_surfaceArray->neighbors(position, direction);
0207     // loop through and veto
0208     // - if the approach surface is the parameter surface
0209     // - if the surface is not compatible with the type(s) that are collected
0210     for (auto& sSurface : sensitiveSurfaces) {
0211       processSurface(*sSurface, true);
0212     }
0213   }
0214 
0215   // (C) representing surface section
0216   //
0217   // the layer surface itself is a testSurface
0218   const Surface* layerSurface = &surfaceRepresentation();
0219   processSurface(*layerSurface);
0220 
0221   return surfaceIntersections;
0222 }
0223 
0224 NavigationTarget Layer::surfaceOnApproach(
0225     const GeometryContext& gctx, const Vector3& position,
0226     const Vector3& direction, const NavigationOptions<Layer>& options) const {
0227   // resolve directive based by options
0228   // - options.resolvePassive is on -> always
0229   // - options.resolveSensitive is on -> always
0230   // - options.resolveMaterial is on
0231   //   && either sensitive or approach surfaces have material
0232   const bool resolvePS = options.resolveSensitive || options.resolvePassive;
0233   const bool resolveMS =
0234       options.resolveMaterial &&
0235       (m_ssSensitiveSurfaces > 1 || m_ssApproachSurfaces > 1 ||
0236        (surfaceRepresentation().surfaceMaterial() != nullptr));
0237 
0238   // The Limits
0239   const double nearLimit = options.nearLimit;
0240   const double farLimit = options.farLimit;
0241 
0242   // Approach descriptor present and resolving is necessary
0243   if (m_approachDescriptor && (resolvePS || resolveMS)) {
0244     NavigationTarget aSurface = m_approachDescriptor->approachSurface(
0245         gctx, position, direction, options.boundaryTolerance, nearLimit,
0246         farLimit);
0247     return aSurface;
0248   }
0249 
0250   // Intersect and check the representing surface
0251   const Surface& layerSurface = surfaceRepresentation();
0252   const MultiIntersection3D multiIntersection = layerSurface.intersect(
0253       gctx, position, direction, options.boundaryTolerance);
0254   for (auto [intersectionIndex, intersection] :
0255        Acts::enumerate(multiIntersection)) {
0256     if (intersection.isValid() &&
0257         detail::checkPathLength(intersection.pathLength(), nearLimit,
0258                                 farLimit)) {
0259       return NavigationTarget(intersection, intersectionIndex, *this,
0260                               layerSurface, options.boundaryTolerance);
0261     }
0262   }
0263   return NavigationTarget::None();
0264 }
0265 
0266 }  // namespace Acts