Warning, file /acts/Plugins/Detray/src/DetrayGeometryConverter.cpp was not indexed
or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/Plugins/Detray/DetrayGeometryConverter.hpp"
0010
0011 #include "Acts/Detector/Detector.hpp"
0012 #include "Acts/Detector/DetectorVolume.hpp"
0013 #include "Acts/Detector/Portal.hpp"
0014 #include "Acts/Navigation/PortalNavigation.hpp"
0015 #include "Acts/Plugins/Json/DetrayJsonHelper.hpp"
0016 #include "Acts/Surfaces/CylinderBounds.hpp"
0017 #include "Acts/Surfaces/CylinderSurface.hpp"
0018 #include "Acts/Surfaces/DiscSurface.hpp"
0019 #include "Acts/Surfaces/RadialBounds.hpp"
0020 #include "Acts/Surfaces/RegularSurface.hpp"
0021 #include "Acts/Surfaces/Surface.hpp"
0022 #include "Acts/Surfaces/SurfaceBounds.hpp"
0023
0024 #include <algorithm>
0025 #include <ranges>
0026
0027 #include <detray/io/frontend/detector_writer.hpp>
0028
0029 using namespace detray;
0030
0031 detray::io::transform_payload Acts::DetrayGeometryConverter::convertTransform(
0032 const Transform3& t) {
0033 detray::io::transform_payload tfPayload;
0034 Vector3 translation = t.translation();
0035 tfPayload.tr = {translation.x(), translation.y(), translation.z()};
0036 RotationMatrix3 rotation = t.rotation().transpose();
0037 tfPayload.rot = {rotation(0, 0), rotation(0, 1), rotation(0, 2),
0038 rotation(1, 0), rotation(1, 1), rotation(1, 2),
0039 rotation(2, 0), rotation(2, 1), rotation(2, 2)};
0040 return tfPayload;
0041 }
0042
0043 detray::io::mask_payload Acts::DetrayGeometryConverter::convertMask(
0044 const Acts::SurfaceBounds& bounds, bool portal) {
0045 detray::io::mask_payload maskPayload;
0046 auto [shape, boundaries] = DetrayJsonHelper::maskFromBounds(bounds, portal);
0047 maskPayload.shape = static_cast<io::mask_payload::mask_shape>(shape);
0048 maskPayload.boundaries = static_cast<std::vector<real_io>>(boundaries);
0049
0050
0051 return maskPayload;
0052 }
0053
0054 detray::io::surface_payload Acts::DetrayGeometryConverter::convertSurface(
0055 const GeometryContext& gctx, const Surface& surface, bool portal) {
0056 detray::io::surface_payload surfacePayload;
0057
0058 surfacePayload.transform = convertTransform(surface.transform(gctx));
0059 surfacePayload.source = surface.geometryId().value();
0060 surfacePayload.barcode = std::nullopt;
0061 surfacePayload.type = static_cast<detray::surface_id>(
0062 portal ? surface_id::e_portal
0063 : (surface.geometryId().sensitive() > 0
0064 ? detray::surface_id::e_sensitive
0065 : detray::surface_id::e_passive));
0066 surfacePayload.mask = convertMask(surface.bounds());
0067 return surfacePayload;
0068 }
0069
0070 std::vector<detray::io::surface_payload>
0071 Acts::DetrayGeometryConverter::convertPortal(
0072 DetrayConversionUtils::Cache& cCache, const GeometryContext& gctx,
0073 const Experimental::Portal& portal, std::size_t ip,
0074 const Experimental::DetectorVolume& volume,
0075 const std::vector<Acts::OrientedSurface>& orientedSurfaces) {
0076 std::vector<detray::io::surface_payload> portals{};
0077
0078 const RegularSurface& surface = portal.surface();
0079 const auto& volumeLinks = portal.portalNavigation();
0080
0081
0082 std::size_t outside = 1u;
0083
0084
0085
0086 if (surface.type() != Acts::Surface::SurfaceType::Cylinder) {
0087
0088 const auto volumeCenter = volume.transform(gctx).translation();
0089 const auto surfaceCenter = surface.center(gctx);
0090 const auto surfaceNormal = surface.normal(gctx, surfaceCenter);
0091
0092 const auto volumeToSurface = surfaceCenter - volumeCenter;
0093 if (volumeToSurface.dot(surfaceNormal) < 0.) {
0094 outside = 0u;
0095 }
0096 } else {
0097
0098 if (ip == 3u) {
0099 outside = 0u;
0100 }
0101 }
0102
0103 const auto& outsideLink = volumeLinks[outside];
0104
0105
0106 const auto* instance = outsideLink.instance();
0107
0108 auto singleLink =
0109 dynamic_cast<const Acts::Experimental::SingleDetectorVolumeNavigation*>(
0110 instance);
0111
0112 auto [surfaceAdjusted, insidePointer] = orientedSurfaces[ip];
0113
0114 surfaceAdjusted->assignGeometryId(surface.geometryId());
0115
0116
0117
0118 if (singleLink != nullptr) {
0119
0120 std::size_t vLink = cCache.volumeIndex(singleLink->object());
0121 auto portalPayload = convertSurface(gctx, *surfaceAdjusted, true);
0122 portalPayload.mask.volume_link.link = vLink;
0123 portals.push_back(portalPayload);
0124 } else {
0125
0126 auto multiLink1D =
0127 dynamic_cast<const Experimental::BoundVolumesGrid1Navigation*>(
0128 instance);
0129 if (multiLink1D != nullptr) {
0130
0131 auto boundaries =
0132 multiLink1D->indexedUpdater.grid.axes()[0u]->getBinEdges();
0133 const auto& cast = multiLink1D->indexedUpdater.casts[0u];
0134 const auto& transform = multiLink1D->indexedUpdater.transform;
0135 const auto& volumes = multiLink1D->indexedUpdater.extractor.dVolumes;
0136
0137
0138 double gCorr = VectorHelpers::cast(transform.translation(), cast);
0139 std::ranges::for_each(boundaries, [&gCorr](double& b) { b -= gCorr; });
0140
0141
0142 auto surfaceType = surfaceAdjusted->type();
0143 std::vector<unsigned int> vIndices = {};
0144 for (const auto& v : volumes) {
0145 vIndices.push_back(cCache.volumeIndex(v));
0146 }
0147
0148
0149 std::array<double, 2u> clipRange = {0., 0.};
0150 std::vector<double> boundValues = surfaceAdjusted->bounds().values();
0151 if (surfaceType == Surface::SurfaceType::Cylinder &&
0152 cast == AxisDirection::AxisZ) {
0153 double zPosition = surfaceAdjusted->center(gctx).z();
0154 clipRange = {
0155 zPosition - boundValues[CylinderBounds::BoundValues::eHalfLengthZ],
0156 zPosition + boundValues[CylinderBounds::BoundValues::eHalfLengthZ]};
0157 } else if (surfaceType == Surface::SurfaceType::Disc &&
0158 cast == AxisDirection::AxisR) {
0159 clipRange = {boundValues[RadialBounds::BoundValues::eMinR],
0160 boundValues[RadialBounds::BoundValues::eMaxR]};
0161 } else {
0162 throw std::runtime_error(
0163 "PortalDetrayGeometryConverter: surface type not (yet) supported "
0164 "for "
0165 "detray "
0166 "conversion, only cylinder and disc are currently supported.");
0167 }
0168
0169
0170 std::vector<unsigned int> clippedIndices = {};
0171 std::vector<double> clippedBoundaries = {};
0172 clippedBoundaries.push_back(clipRange[0u]);
0173 for (const auto [ib, b] : enumerate(boundaries)) {
0174 if (ib > 0) {
0175 unsigned int vI = vIndices[ib - 1u];
0176 double highEdge = boundaries[ib];
0177 if (boundaries[ib - 1] >= clipRange[1u]) {
0178 break;
0179 }
0180 if (highEdge <= clipRange[0u] ||
0181 std::abs(highEdge - clipRange[0u]) < 1e-5) {
0182 continue;
0183 }
0184 if (highEdge > clipRange[1u]) {
0185 highEdge = clipRange[1u];
0186 }
0187 clippedIndices.push_back(vI);
0188 clippedBoundaries.push_back(highEdge);
0189 }
0190 }
0191
0192
0193
0194 if (surfaceType == Surface::SurfaceType::Cylinder) {
0195 for (auto [ib, b] : enumerate(clippedBoundaries)) {
0196 if (ib > 0) {
0197
0198 std::array<double, CylinderBounds::BoundValues::eSize>
0199 subBoundValues = {};
0200 for (auto [ibv, bv] : enumerate(boundValues)) {
0201 subBoundValues[ibv] = bv;
0202 }
0203 subBoundValues[CylinderBounds::BoundValues::eHalfLengthZ] =
0204 0.5 * (b - clippedBoundaries[ib - 1u]);
0205 auto subBounds = std::make_shared<CylinderBounds>(subBoundValues);
0206 auto subTransform = Transform3::Identity();
0207 subTransform.pretranslate(Vector3(
0208 0., 0.,
0209 clippedBoundaries[ib - 1u] +
0210 subBoundValues[CylinderBounds::BoundValues::eHalfLengthZ]));
0211
0212 auto subSurface =
0213 Surface::makeShared<CylinderSurface>(subTransform, subBounds);
0214 subSurface->assignGeometryId(surface.geometryId());
0215
0216 auto portalPayload = convertSurface(gctx, *subSurface, true);
0217 portalPayload.mask.volume_link.link = clippedIndices[ib - 1u];
0218 portals.push_back(portalPayload);
0219 }
0220 }
0221 } else {
0222 for (auto [ib, b] : enumerate(clippedBoundaries)) {
0223 if (ib > 0) {
0224
0225 std::array<double, RadialBounds::BoundValues::eSize>
0226 subBoundValues = {};
0227 for (auto [ibv, bv] : enumerate(boundValues)) {
0228 subBoundValues[ibv] = bv;
0229 }
0230 subBoundValues[RadialBounds::BoundValues::eMinR] =
0231 clippedBoundaries[ib - 1u];
0232 subBoundValues[RadialBounds::BoundValues::eMaxR] = b;
0233 auto subBounds = std::make_shared<RadialBounds>(subBoundValues);
0234 auto subSurface = Surface::makeShared<DiscSurface>(
0235 portal.surface().transform(gctx), subBounds);
0236
0237 subSurface->assignGeometryId(surface.geometryId());
0238 auto portalPayload = convertSurface(gctx, *subSurface, true);
0239 portalPayload.mask.volume_link.link = clippedIndices[ib - 1u];
0240 portals.push_back(portalPayload);
0241 }
0242 }
0243 }
0244
0245 } else {
0246
0247 auto portalPayload = convertSurface(gctx, *surfaceAdjusted, true);
0248 using NavigationLink =
0249 typename DetrayHostDetector::surface_type::navigation_link;
0250 portalPayload.mask.volume_link.link =
0251 std::numeric_limits<NavigationLink>::max();
0252
0253 portals.push_back(portalPayload);
0254 }
0255 }
0256 return portals;
0257 }
0258
0259 detray::io::volume_payload Acts::DetrayGeometryConverter::convertVolume(
0260 DetrayConversionUtils::Cache& cCache, const GeometryContext& gctx,
0261 const Acts::Experimental::DetectorVolume& volume,
0262 const Acts::Logger& logger) {
0263 ACTS_DEBUG("DetrayGeometryConverter: converting volume "
0264 << volume.name() << " with " << volume.surfaces().size()
0265 << " surfaces and " << volume.portals().size() << " portals");
0266
0267 detray::io::volume_payload volumePayload;
0268 std::size_t volumeIndex = cCache.volumeIndex(&volume);
0269 volumePayload.name = volume.name();
0270 volumePayload.index.link = volumeIndex;
0271 volumePayload.transform = convertTransform(volume.transform(gctx));
0272
0273
0274 cCache.volumeLinks[volume.geometryId()] = volumePayload.index.link;
0275
0276 std::multimap<GeometryIdentifier, unsigned long> localSurfaceLinks;
0277
0278
0279 std::size_t sIndex = 0;
0280 for (const auto surface : volume.surfaces()) {
0281 io::surface_payload surfacePayload = convertSurface(gctx, *surface, false);
0282
0283 surfacePayload.index_in_coll = sIndex++;
0284 localSurfaceLinks.insert(
0285 {surface->geometryId(), surfacePayload.index_in_coll.value()});
0286
0287 surfacePayload.mask.volume_link.link =
0288 volumePayload.index.link;
0289 volumePayload.surfaces.push_back(surfacePayload);
0290 }
0291
0292 auto orientedSurfaces =
0293 volume.volumeBounds().orientedSurfaces(volume.transform(gctx));
0294
0295
0296 int portalCounter = 0;
0297 for (const auto& [ip, p] : enumerate(volume.portals())) {
0298 auto portals =
0299 convertPortal(cCache, gctx, *p, ip, volume, orientedSurfaces);
0300 ACTS_VERBOSE(" > portal " << ip << " split into " << portals.size()
0301 << " surfaces");
0302 GeometryIdentifier geoID = p->surface().geometryId();
0303 std::ranges::for_each(portals, [&](auto& portalPayload) {
0304
0305 portalPayload.index_in_coll = sIndex++;
0306 localSurfaceLinks.insert({geoID, portalPayload.index_in_coll.value()});
0307
0308 volumePayload.surfaces.push_back(portalPayload);
0309 portalCounter++;
0310 });
0311 }
0312 cCache.localSurfaceLinks[volumeIndex] = localSurfaceLinks;
0313 ACTS_DEBUG(" > " << volume.portals().size()
0314 << " initial ACTS portals split into final " << portalCounter
0315 << " detray portals");
0316 ACTS_VERBOSE(" > Local surface link cache has " << localSurfaceLinks.size()
0317 << " entries");
0318
0319 return volumePayload;
0320 }
0321
0322 detray::io::detector_payload Acts::DetrayGeometryConverter::convertDetector(
0323 DetrayConversionUtils::Cache& cCache, const GeometryContext& gctx,
0324 const Acts::Experimental::Detector& detector, const Acts::Logger& logger) {
0325 ACTS_DEBUG("DetrayGeometryConverter: converting detector"
0326 << detector.name() << " with " << detector.volumes().size()
0327 << " volumes.");
0328
0329
0330 detray::io::detector_payload detectorPayload;
0331
0332 for (const auto volume : detector.volumes()) {
0333 detectorPayload.volumes.push_back(
0334 convertVolume(cCache, gctx, *volume, logger));
0335 }
0336
0337 return detectorPayload;
0338 }