Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-05 08:09:37

0001 // This file is part of the Acts project.
0002 //
0003 // Copyright (C) 2016-2018 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 http://mozilla.org/MPL/2.0/.
0008 
0009 #include "Acts/Geometry/Layer.hpp"
0010 
0011 #include "Acts/Definitions/Direction.hpp"
0012 #include "Acts/Definitions/Tolerance.hpp"
0013 #include "Acts/Material/IMaterialDecorator.hpp"
0014 #include "Acts/Propagator/Navigator.hpp"
0015 #include "Acts/Surfaces/Surface.hpp"
0016 
0017 #include <algorithm>
0018 #include <functional>
0019 #include <iterator>
0020 #include <vector>
0021 
0022 Acts::Layer::Layer(std::unique_ptr<SurfaceArray> surfaceArray, double thickness,
0023                    std::unique_ptr<ApproachDescriptor> ades, LayerType laytyp)
0024     : m_nextLayers(NextLayers(nullptr, nullptr)),
0025       m_surfaceArray(surfaceArray.release()),
0026       m_layerThickness(thickness),
0027       m_approachDescriptor(nullptr),
0028       m_representingVolume(nullptr),
0029       m_layerType(laytyp),
0030       m_ssRepresentingSurface(1) {
0031   if (ades) {
0032     ades->registerLayer(*this);
0033     m_approachDescriptor = std::move(ades);
0034     m_ssApproachSurfaces = 1;  // indicates existence
0035   }
0036   // indicates existence of sensitive surfaces
0037   if (m_surfaceArray) {
0038     m_ssSensitiveSurfaces = 1;
0039   }
0040 }
0041 
0042 const Acts::ApproachDescriptor* Acts::Layer::approachDescriptor() const {
0043   return m_approachDescriptor.get();
0044 }
0045 
0046 Acts::ApproachDescriptor* Acts::Layer::approachDescriptor() {
0047   return const_cast<ApproachDescriptor*>(m_approachDescriptor.get());
0048 }
0049 
0050 void Acts::Layer::closeGeometry(const IMaterialDecorator* materialDecorator,
0051                                 const GeometryIdentifier& layerID,
0052                                 const GeometryIdentifierHook& hook,
0053                                 const Logger& logger) {
0054   // set the volumeID of this
0055   assignGeometryId(layerID);
0056   // assign to the representing surface
0057   Surface* rSurface = const_cast<Surface*>(&surfaceRepresentation());
0058   if (materialDecorator != nullptr) {
0059     materialDecorator->decorate(*rSurface);
0060   }
0061   ACTS_DEBUG("layerID: " << layerID);
0062 
0063   rSurface->assignGeometryId(layerID);
0064 
0065   // also find out how the sub structure is defined
0066   if (surfaceRepresentation().surfaceMaterial() != nullptr) {
0067     m_ssRepresentingSurface = 2;
0068   }
0069   // loop over the approach surfaces
0070   if (m_approachDescriptor) {
0071     // indicates the existence of approach surfaces
0072     m_ssApproachSurfaces = 1;
0073     // loop through the approachSurfaces and assign unique GeomeryID
0074     GeometryIdentifier::Value iasurface = 0;
0075     for (auto& aSurface : m_approachDescriptor->containedSurfaces()) {
0076       auto asurfaceID = GeometryIdentifier(layerID).setApproach(++iasurface);
0077       auto mutableASurface = const_cast<Surface*>(aSurface);
0078       mutableASurface->assignGeometryId(asurfaceID);
0079       if (materialDecorator != nullptr) {
0080         materialDecorator->decorate(*mutableASurface);
0081       }
0082       // if any of the approach surfaces has material
0083       if (aSurface->surfaceMaterial() != nullptr) {
0084         m_ssApproachSurfaces = 2;
0085       }
0086     }
0087   }
0088   // check if you have sensitive surfaces
0089   if (m_surfaceArray) {
0090     // indicates the existence of sensitive surfaces
0091     m_ssSensitiveSurfaces = 1;
0092     // loop sensitive surfaces and assign unique GeometryIdentifier
0093     GeometryIdentifier::Value issurface = 0;
0094     for (auto& sSurface : m_surfaceArray->surfaces()) {
0095       auto ssurfaceID = GeometryIdentifier(layerID).setSensitive(++issurface);
0096       ssurfaceID = hook.decorateIdentifier(ssurfaceID, *sSurface);
0097       auto mutableSSurface = const_cast<Surface*>(sSurface);
0098       mutableSSurface->assignGeometryId(ssurfaceID);
0099       if (materialDecorator != nullptr) {
0100         materialDecorator->decorate(*mutableSSurface);
0101       }
0102       // if any of the sensitive surfaces has material
0103       if (sSurface->surfaceMaterial() != nullptr) {
0104         m_ssSensitiveSurfaces = 2;
0105       }
0106     }
0107   }
0108 }
0109 
0110 boost::container::small_vector<Acts::SurfaceIntersection, 10>
0111 Acts::Layer::compatibleSurfaces(
0112     const GeometryContext& gctx, const Vector3& position,
0113     const Vector3& direction, const NavigationOptions<Surface>& options) const {
0114   // the list of valid intersection
0115   boost::container::small_vector<SurfaceIntersection, 10> sIntersections;
0116 
0117   // fast exit - there is nothing to
0118   if (!m_surfaceArray || !m_approachDescriptor) {
0119     return sIntersections;
0120   }
0121 
0122   // (0) End surface check
0123   // @todo: - we might be able to skip this by use of options.pathLimit
0124   // check if you have to stop at the endSurface
0125   double nearLimit = options.nearLimit;
0126   double farLimit = options.farLimit;
0127   if (options.endObject != nullptr) {
0128     // intersect the end surface
0129     // - it is the final one don't use the boundary check at all
0130     SurfaceIntersection endInter =
0131         options.endObject
0132             ->intersect(gctx, position, direction, BoundaryCheck(true))
0133             .closest();
0134     // non-valid intersection with the end surface provided at this layer
0135     // indicates wrong direction or faulty setup
0136     // -> do not return compatible surfaces since they may lead you on a wrong
0137     // navigation path
0138     if (endInter) {
0139       farLimit = endInter.pathLength();
0140     } else {
0141       return sIntersections;
0142     }
0143   } else {
0144     // compatibleSurfaces() should only be called when on the layer,
0145     // i.e. the maximum path limit is given by the layer thickness times
0146     // path correction, we take a safety factor of 1.5
0147     // -> this avoids punch through for cylinders
0148     double pCorrection =
0149         surfaceRepresentation().pathCorrection(gctx, position, direction);
0150     farLimit = 1.5 * thickness() * pCorrection;
0151   }
0152 
0153   // lemma 0 : accept the surface
0154   auto acceptSurface = [&options](const Surface& sf,
0155                                   bool sensitive = false) -> bool {
0156     // surface is sensitive and you're asked to resolve
0157     if (sensitive && options.resolveSensitive) {
0158       return true;
0159     }
0160     // next option: it's a material surface and you want to have it
0161     if (options.resolveMaterial && sf.surfaceMaterial() != nullptr) {
0162       return true;
0163     }
0164     // last option: resolve all
0165     return options.resolvePassive;
0166   };
0167 
0168   // lemma 1 : check and fill the surface
0169   // [&sIntersections, &options, &parameters
0170   auto processSurface = [&](const Surface& sf, bool sensitive = false) {
0171     // veto if it's start or end surface
0172     if (options.startObject == &sf || options.endObject == &sf) {
0173       return;
0174     }
0175     // veto if it doesn't fit the prescription
0176     if (!acceptSurface(sf, sensitive)) {
0177       return;
0178     }
0179     bool boundaryCheck = options.boundaryCheck.isEnabled();
0180     if (std::find(options.externalSurfaces.begin(),
0181                   options.externalSurfaces.end(),
0182                   sf.geometryId()) != options.externalSurfaces.end()) {
0183       boundaryCheck = false;
0184     }
0185     // the surface intersection
0186     SurfaceMultiIntersection sfmi =
0187         sf.intersect(gctx, position, direction, BoundaryCheck(boundaryCheck));
0188     for (const auto& sfi : sfmi.split()) {
0189       // check if intersection is valid and pathLimit has not been exceeded
0190       if (sfi &&
0191           detail::checkIntersection(sfi.intersection(), nearLimit, farLimit)) {
0192         sIntersections.push_back(sfi);
0193       }
0194     }
0195   };
0196 
0197   // (A) approach descriptor section
0198   //
0199   // the approach surfaces are in principle always testSurfaces
0200   // - the surface on approach is excluded via the veto
0201   // - the surfaces are only collected if needed
0202   if (m_approachDescriptor &&
0203       (options.resolveMaterial || options.resolvePassive)) {
0204     // the approach surfaces
0205     const std::vector<const Surface*>& approachSurfaces =
0206         m_approachDescriptor->containedSurfaces();
0207     // we loop through and veto
0208     // - if the approach surface is the parameter surface
0209     // - if the surface is not compatible with the collect
0210     for (auto& aSurface : approachSurfaces) {
0211       processSurface(*aSurface);
0212     }
0213   }
0214 
0215   // (B) sensitive surface section
0216   //
0217   // check the sensitive surfaces if you have some
0218   if (m_surfaceArray && (options.resolveMaterial || options.resolvePassive ||
0219                          options.resolveSensitive)) {
0220     // get the candidates
0221     const std::vector<const Surface*>& sensitiveSurfaces =
0222         m_surfaceArray->neighbors(position);
0223     // loop through and veto
0224     // - if the approach surface is the parameter surface
0225     // - if the surface is not compatible with the type(s) that are collected
0226     for (auto& sSurface : sensitiveSurfaces) {
0227       processSurface(*sSurface, true);
0228     }
0229   }
0230 
0231   // (C) representing surface section
0232   //
0233   // the layer surface itself is a testSurface
0234   const Surface* layerSurface = &surfaceRepresentation();
0235   processSurface(*layerSurface);
0236 
0237   // Sort by object address
0238   std::sort(
0239       sIntersections.begin(), sIntersections.end(),
0240       [](const auto& a, const auto& b) { return a.object() < b.object(); });
0241   // Now look for duplicates. As we just sorted by path length, duplicates
0242   // should be subsequent
0243   auto it = std::unique(
0244       sIntersections.begin(), sIntersections.end(),
0245       [](const SurfaceIntersection& a, const SurfaceIntersection& b) -> bool {
0246         return a.object() == b.object();
0247       });
0248 
0249   // resize to remove all items that are past the unique range
0250   sIntersections.resize(std::distance(sIntersections.begin(), it),
0251                         SurfaceIntersection::invalid());
0252 
0253   // sort according to the path length
0254   std::sort(sIntersections.begin(), sIntersections.end(),
0255             SurfaceIntersection::pathLengthOrder);
0256 
0257   return sIntersections;
0258 }
0259 
0260 Acts::SurfaceIntersection Acts::Layer::surfaceOnApproach(
0261     const GeometryContext& gctx, const Vector3& position,
0262     const Vector3& direction, const NavigationOptions<Layer>& options) const {
0263   // resolve directive based by options
0264   // - options.resolvePassive is on -> always
0265   // - options.resolveSensitive is on -> always
0266   // - options.resolveMaterial is on
0267   //   && either sensitive or approach surfaces have material
0268   bool resolvePS = options.resolveSensitive || options.resolvePassive;
0269   bool resolveMS = options.resolveMaterial &&
0270                    (m_ssSensitiveSurfaces > 1 || m_ssApproachSurfaces > 1 ||
0271                     (surfaceRepresentation().surfaceMaterial() != nullptr));
0272 
0273   // The Limits: current path & overstepping
0274   double nearLimit = options.nearLimit;
0275   double farLimit = options.farLimit;
0276 
0277   // Helper function to find valid intersection
0278   auto findValidIntersection =
0279       [&](const SurfaceMultiIntersection& sfmi) -> SurfaceIntersection {
0280     for (const auto& sfi : sfmi.split()) {
0281       if (sfi &&
0282           detail::checkIntersection(sfi.intersection(), nearLimit, farLimit)) {
0283         return sfi;
0284       }
0285     }
0286 
0287     // Return an invalid one
0288     return SurfaceIntersection::invalid();
0289   };
0290 
0291   // Approach descriptor present and resolving is necessary
0292   if (m_approachDescriptor && (resolvePS || resolveMS)) {
0293     SurfaceIntersection aSurface = m_approachDescriptor->approachSurface(
0294         gctx, position, direction, options.boundaryCheck, nearLimit, farLimit);
0295     return aSurface;
0296   }
0297 
0298   // Intersect and check the representing surface
0299   const Surface& rSurface = surfaceRepresentation();
0300   auto sIntersection =
0301       rSurface.intersect(gctx, position, direction, options.boundaryCheck);
0302   return findValidIntersection(sIntersection);
0303 }