Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-16 09:24:16

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 "ActsPlugins/Detray/DetrayPayloadConverter.hpp"
0010 //
0011 #include "Acts/Navigation/CylinderNavigationPolicy.hpp"
0012 #include "Acts/Navigation/MultiLayerNavigationPolicy.hpp"
0013 #include "Acts/Navigation/MultiNavigationPolicy.hpp"
0014 #include "Acts/Navigation/SurfaceArrayNavigationPolicy.hpp"
0015 #include "Acts/Navigation/TryAllNavigationPolicy.hpp"
0016 #include "Acts/Surfaces/SurfaceArray.hpp"
0017 #include "Acts/Utilities/AnyGridView.hpp"
0018 #include "Acts/Utilities/AxisDefinitions.hpp"
0019 #include "Acts/Utilities/Logger.hpp"
0020 #include "ActsPlugins/Detray/DetrayConversionUtils.hpp"
0021 
0022 #include <ranges>
0023 #include <sstream>
0024 #include <stdexcept>
0025 
0026 #include <detray/definitions/grid_axis.hpp>
0027 #include <detray/io/frontend/payloads.hpp>
0028 
0029 using namespace Acts;
0030 
0031 namespace ActsPlugins {
0032 
0033 using DetraySurfaceMaterial = DetrayPayloadConverter::DetraySurfaceMaterial;
0034 using DetraySurfaceGrid = DetrayPayloadConverter::DetraySurfaceGrid;
0035 
0036 namespace {
0037 
0038 detray::io::accel_id getDetrayAccelId(Surface::SurfaceType surfaceType) {
0039   using enum Surface::SurfaceType;
0040 
0041   switch (surfaceType) {
0042     case Cylinder:
0043       return detray::io::accel_id::concentric_cylinder2_grid;
0044     case Disc:
0045       return detray::io::accel_id::polar2_grid;
0046     case Plane:
0047       return detray::io::accel_id::cartesian2_grid;
0048     default:
0049       throw std::runtime_error(
0050           "SurfaceArrayNavigationPolicy: Unsupported surface type for detray "
0051           "conversion");
0052   }
0053 }
0054 
0055 }  // namespace
0056 
0057 std::optional<DetraySurfaceGrid> DetrayPayloadConverter::convertSurfaceArray(
0058     const SurfaceArrayNavigationPolicy& policy, const GeometryContext& gctx,
0059     const SurfaceLookupFunction& surfaceLookup, const Logger& logger) {
0060   const auto* gridLookup =
0061       dynamic_cast<const SurfaceArray::ISurfaceGridLookup*>(
0062           &policy.surfaceArray().gridLookup());
0063 
0064   if (gridLookup == nullptr) {
0065     throw std::runtime_error(
0066         "SurfaceArrayNavigationPolicy: The surface array does not provide a "
0067         "grid based lookup object. This is not currently convertible to "
0068         "detray");
0069   }
0070 
0071   AnyGridConstView gridView = [&] {
0072     auto r = gridLookup->getGridView();
0073     if (r == std::nullopt) {
0074       throw std::runtime_error(
0075           "SurfaceArrayNavigationPolicy: The surface array does not provide a "
0076           "grid view. This is not currently convertible to detray");
0077     }
0078     return r.value();
0079   }();
0080 
0081   const Surface* surface = gridLookup->surfaceRepresentation();
0082   if (surface == nullptr) {
0083     throw std::runtime_error(
0084         "SurfaceArrayNavigationPolicy: The surface array does not provide a "
0085         "surface representation. This is not currently convertible to detray");
0086   }
0087 
0088   const auto& transform = surface->transform(gctx);
0089 
0090   constexpr auto tolerance = s_onSurfaceTolerance;
0091 
0092   if ((transform.rotation().matrix() - RotationMatrix3::Identity()).norm() >
0093       tolerance) {
0094     throw std::invalid_argument(
0095         "SurfaceArrayNavigationPolicy: The surface array lookup reports a "
0096         "rotation. This is not currently convertible to detray");
0097   }
0098 
0099   ACTS_DEBUG("Converting surface array with " << gridView.dimensions()
0100                                               << " dims to detray payload");
0101   std::vector axes = gridLookup->getAxes();
0102 
0103   if (axes.size() != 2) {
0104     throw std::runtime_error(
0105         "SurfaceArrayNavigationPolicy: The surface array does not provide a "
0106         "2-dimensional grid. This is not currently convertible to detray");
0107   }
0108 
0109   const IAxis& axis0 = *axes.at(0);
0110   const IAxis& axis1 = *axes.at(1);
0111 
0112   // Get binning values to determine acceleration structure type
0113   std::vector binValues = gridLookup->binningValues();
0114   if (binValues.empty()) {
0115     // Fall back to default based on surface type
0116     switch (surface->type()) {
0117       using enum Surface::SurfaceType;
0118       case Cylinder:
0119         binValues = {AxisDirection::AxisPhi, AxisDirection::AxisZ};
0120         break;
0121       case Disc:
0122         binValues = {AxisDirection::AxisR, AxisDirection::AxisPhi};
0123         break;
0124       case Plane:
0125         binValues = {AxisDirection::AxisX, AxisDirection::AxisY};
0126         break;
0127       default:
0128         throw std::runtime_error(
0129             "SurfaceArrayNavigationPolicy: Unsupported surface type");
0130     }
0131   }
0132 
0133   // Create the detray surface grid payload
0134   DetraySurfaceGrid gridPayload;
0135 
0136   // Set up the grid link with appropriate acceleration structure type
0137   detray::io::accel_id accelId = getDetrayAccelId(surface->type());
0138   gridPayload.grid_link =
0139       detray::io::typed_link_payload<detray::io::accel_id>{accelId, 0u};
0140 
0141   // @FIXME: We might have to change the order of the axis based on the surface type
0142 
0143   // Convert the axes
0144   for (std::size_t i = 0; i < axes.size(); ++i) {
0145     const auto* axis = axes[i];
0146     ACTS_DEBUG("- Converting axis " << i << " (" << binValues[i]
0147                                     << "): " << *axis);
0148 
0149     auto axisPayload = DetrayConversionUtils::convertAxis(*axis);
0150 
0151     // Set axis label based on binning values
0152     if (i < binValues.size()) {
0153       axisPayload.label =
0154           DetrayConversionUtils::convertAxisDirection(binValues[i]);
0155     } else {
0156       // Default labels if binValues is insufficient
0157       axisPayload.label =
0158           (i == 0) ? detray::axis::label::e_x : detray::axis::label::e_y;
0159     }
0160 
0161     gridPayload.axes.push_back(axisPayload);
0162   }
0163 
0164   std::set<const Surface*> seenSurfaces;
0165 
0166   using index_type = std::pair<unsigned int, unsigned int>;
0167 
0168   auto fillGeneric = [&](const auto& mapi, const auto& mapj,
0169                          index_type indices) {
0170     auto [i, j] = indices;
0171 
0172     auto di = mapi(i);
0173     auto dj = mapj(j);
0174 
0175     const auto& surfaces = gridView.atLocalBins({i, j});
0176 
0177     std::vector<std::size_t> surfaceIndices;
0178 
0179     for (const auto* srf : surfaces) {
0180       try {
0181         std::size_t surfaceIndex = surfaceLookup(srf);
0182         surfaceIndices.push_back(surfaceIndex);
0183         seenSurfaces.insert(srf);
0184       } catch (const std::exception& e) {
0185         std::stringstream ss;
0186         ss << "Warning: Could not find surface index for surface "
0187            << srf->geometryId() << ": " << e.what();
0188         throw std::runtime_error{ss.str()};
0189       }
0190     }
0191 
0192     // Add the bin to the grid payload
0193     detray::io::grid_bin_payload<std::size_t> binPayload{{{di, dj}},
0194                                                          surfaceIndices};
0195     gridPayload.bins.push_back(binPayload);
0196   };
0197 
0198   // Depending on the axis boundary type, we need to skip over the
0199   // under/overflow bins, or include them. This needs to be decided by-axis.
0200   auto makeIndexRange = [](const IAxis& axis) {
0201     if (axis.getBoundaryType() == AxisBoundaryType::Open) {
0202       return std::views::iota(0u, axis.getNBins() + 2);
0203     }
0204     return std::views::iota(1u, axis.getNBins() + 1);
0205   };
0206 
0207   auto idx0 = makeIndexRange(axis0);
0208   auto idx1 = makeIndexRange(axis1);
0209 
0210   auto makeIndexMap =
0211       [&](const IAxis& axis) -> std::function<unsigned int(unsigned int)> {
0212     if (axis.getBoundaryType() == AxisBoundaryType::Open) {
0213       // In case of Open, we loop from [0, N+1], where N is the number of bins.
0214       // This includes under/overflow bins.
0215       // Detray also has under/overflow bins in this case, so we keep the
0216       // indices the same
0217       return [](unsigned int i) { return i; };
0218     }
0219 
0220     // For Closed/Bound, detray does not have under/overflow bins.
0221     // In ACTS, the bins a physically still present, so we only loop
0222     // [1, N]. Detray's indices however still go [0, N-1], so we subtract 1 from
0223     // the indices in the direction.
0224     return [](unsigned int i) { return i - 1; };
0225   };
0226 
0227   auto fill = std::bind_front(std::bind_front(fillGeneric, makeIndexMap(axis0)),
0228                               makeIndexMap(axis1));
0229 
0230   for (auto i : idx0) {
0231     for (auto j : idx1) {
0232       fill(index_type{i, j});
0233     }
0234   }
0235 
0236   ACTS_DEBUG("Filled surfaces " << seenSurfaces.size() << " into grid");
0237 
0238   ACTS_DEBUG("Created detray payload with " << gridPayload.bins.size()
0239                                             << " populated bins");
0240 
0241   return gridPayload;
0242 }
0243 
0244 #define NOOP_CONVERTER_IMPL_FULL(type, name)                                  \
0245   std::optional<DetraySurfaceGrid> DetrayPayloadConverter::convert##name(     \
0246       const type& /*policy*/, const GeometryContext& /*gctx*/,                \
0247       const SurfaceLookupFunction& /*surfaceLookup*/, const Logger& logger) { \
0248     ACTS_DEBUG(#name << " does not implement explicit detray conversion");    \
0249     return std::nullopt;                                                      \
0250   }
0251 
0252 #define NOOP_CONVERTER_IMPL(type) NOOP_CONVERTER_IMPL_FULL(type, type)
0253 
0254 NOOP_CONVERTER_IMPL(TryAllNavigationPolicy)
0255 NOOP_CONVERTER_IMPL(MultiNavigationPolicy)
0256 NOOP_CONVERTER_IMPL(CylinderNavigationPolicy)
0257 NOOP_CONVERTER_IMPL_FULL(Experimental::MultiLayerNavigationPolicy,
0258                          MultiLayerNavigationPolicy)
0259 
0260 }  // namespace ActsPlugins