File indexing completed on 2025-12-16 09:24:16
0001
0002
0003
0004
0005
0006
0007
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 }
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
0113 std::vector binValues = gridLookup->binningValues();
0114 if (binValues.empty()) {
0115
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
0134 DetraySurfaceGrid gridPayload;
0135
0136
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
0142
0143
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
0152 if (i < binValues.size()) {
0153 axisPayload.label =
0154 DetrayConversionUtils::convertAxisDirection(binValues[i]);
0155 } else {
0156
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
0193 detray::io::grid_bin_payload<std::size_t> binPayload{{{di, dj}},
0194 surfaceIndices};
0195 gridPayload.bins.push_back(binPayload);
0196 };
0197
0198
0199
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
0214
0215
0216
0217 return [](unsigned int i) { return i; };
0218 }
0219
0220
0221
0222
0223
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& , const GeometryContext& , \
0247 const SurfaceLookupFunction& , 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 }