Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-13 08:13:13

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