Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-05 08:10:14

0001 // This file is part of the Acts project.
0002 //
0003 // Copyright (C) 2023 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/Plugins/ActSVG/PortalSvgConverter.hpp"
0010 
0011 #include "Acts/Detector/Portal.hpp"
0012 #include "Acts/Navigation/DetectorVolumeUpdaters.hpp"
0013 #include "Acts/Surfaces/RegularSurface.hpp"
0014 
0015 namespace {
0016 
0017 /// Helper method to make a proto link implementation
0018 ///
0019 /// @param portalOptions are the options containing portal draw length and volume colour map
0020 /// @param position is the start position of the link
0021 /// @param direction is the direction of the link
0022 /// @param dVolume the volume this link is directing to
0023 ///
0024 /// @return a protoLink
0025 Acts::Svg::ProtoLink makeProtoLink(
0026     const Acts::Svg::PortalConverter::Options& portalOptions,
0027     const Acts::Vector3& position, const Acts::Vector3& direction,
0028     const Acts::Experimental::DetectorVolume* dVolume) {
0029   Acts::Svg::ProtoLink pLink;
0030   Acts::Vector3 end3 = position + portalOptions.linkLength * direction;
0031   pLink._start = {position.x(), position.y(), position.z()};
0032   pLink._end = {end3.x(), end3.y(), end3.z()};
0033   auto linkIndexCandidate = portalOptions.volumeIndices.find(dVolume);
0034   if (linkIndexCandidate != portalOptions.volumeIndices.end()) {
0035     pLink._link_index = linkIndexCandidate->second;
0036   }
0037   return pLink;
0038 }
0039 
0040 /// Helper method to convert a multi link
0041 ///
0042 /// @param gctx is the geometry context
0043 /// @param multiLink is the mulit link to be converted
0044 /// @param surface is the portal surface
0045 /// @param refPosition is the reference position which might be needed to decode
0046 /// @param portalOptions are the options containing portal draw length and volume colour map
0047 /// @param sign with respect to the normal vector
0048 ///
0049 /// @return it will return the proto links
0050 std::vector<Acts::Svg::ProtoLink> convertMultiLink(
0051     const Acts::GeometryContext& gctx,
0052     const Acts::Experimental::BoundVolumesGrid1Impl& multiLink,
0053     const Acts::Surface& surface, const Acts::Vector3& refPosition,
0054     const Acts::Svg::PortalConverter::Options& portalOptions,
0055     int sign) noexcept(false) {
0056   const auto* regSurface = dynamic_cast<const Acts::RegularSurface*>(&surface);
0057   if (regSurface == nullptr) {
0058     throw std::invalid_argument(
0059         "convertMultiLink: surface is not RegularSurface.");
0060   }
0061   // The return links
0062   std::vector<Acts::Svg::ProtoLink> pLinks;
0063   const auto& volumes = multiLink.indexedUpdater.extractor.dVolumes;
0064   const auto& casts = multiLink.indexedUpdater.casts;
0065 
0066   // Generate the proto-links of the multi-link
0067   for (auto [il, v] : Acts::enumerate(volumes)) {
0068     Acts::Vector3 position = refPosition;
0069     if constexpr (decltype(multiLink.indexedUpdater)::grid_type::DIM == 1u) {
0070       // Get the binning value
0071       Acts::BinningValue bValue = casts[0u];
0072       // Get the boundaries - take care, they are in local coordinates
0073       const auto& boundaries =
0074           multiLink.indexedUpdater.grid.axes()[0u]->getBinEdges();
0075 
0076       Acts::ActsScalar refC = 0.5 * (boundaries[il + 1u] + boundaries[il]);
0077 
0078       if (bValue == Acts::binR) {
0079         Acts::ActsScalar phi = Acts::VectorHelpers::phi(refPosition);
0080         position = Acts::Vector3(refC * std::cos(phi), refC * std::sin(phi),
0081                                  refPosition.z());
0082       } else if (bValue == Acts::binZ) {
0083         position[2] = refC;
0084         // correct to global
0085         refC += surface.transform(gctx).translation().z();
0086       } else if (bValue == Acts::binPhi) {
0087         Acts::ActsScalar r = Acts::VectorHelpers::perp(refPosition);
0088         position = Acts::Vector3(r * std::cos(refC), r * std::sin(refC),
0089                                  refPosition.z());
0090       } else {
0091         throw std::invalid_argument("convertMultiLink: incorrect binning.");
0092       }
0093       Acts::Vector3 direction = regSurface->normal(gctx, position);
0094       pLinks.push_back(makeProtoLink(portalOptions, position,
0095                                      Acts::Vector3(sign * direction), v));
0096     }
0097   }
0098   return pLinks;
0099 }
0100 
0101 }  // namespace
0102 
0103 Acts::Svg::ProtoPortal Acts::Svg::PortalConverter::convert(
0104     const GeometryContext& gctx, const Experimental::Portal& portal,
0105     const PortalConverter::Options& portalOptions) {
0106   ProtoPortal pPortal;
0107   // First convert the surface
0108   pPortal._surface = SurfaceConverter::convert(gctx, portal.surface(),
0109                                                portalOptions.surfaceOptions);
0110 
0111   // Reference point and direction
0112   Vector3 rPos(0., 0., 0);
0113   Vector3 rDir(0., 0., 1);
0114   const auto& surface = portal.surface();
0115   const auto surfaceTransform = portal.surface().transform(gctx);
0116   const auto surfaceTranslation = surfaceTransform.translation().eval();
0117   const auto surfaceType = surface.bounds().type();
0118   const auto& boundValues = surface.bounds().values();
0119   switch (surfaceType) {
0120     case SurfaceBounds::eCylinder: {
0121       // Get phi
0122       ActsScalar r = boundValues[0u];
0123       ActsScalar aphi = boundValues[3u];
0124       rPos = Vector3(r * std::cos(aphi), r * std::sin(aphi),
0125                      surfaceTranslation.z());
0126     } break;
0127     case SurfaceBounds::eDisc: {
0128       // Get phi
0129       ActsScalar r = 0.5 * (boundValues[0u] + boundValues[1u]);
0130       ActsScalar aphi = boundValues[3u];
0131       rPos = Vector3(r * std::cos(aphi), r * std::sin(aphi),
0132                      surfaceTranslation.z());
0133     } break;
0134     default: {
0135       rPos = surfaceTranslation;
0136     } break;
0137   }
0138   rDir = surface.normal(gctx, rPos);
0139 
0140   // Now convert the link objects
0141   const auto& updators = portal.detectorVolumeUpdaters();
0142 
0143   int sign = -1;
0144   for (const auto& dvu : updators) {
0145     // Get the instance and start the casting
0146     const auto* instance = dvu.instance();
0147     auto singleLink =
0148         dynamic_cast<const Experimental::SingleDetectorVolumeImpl*>(instance);
0149     if (singleLink != nullptr) {
0150       pPortal._volume_links.push_back(makeProtoLink(
0151           portalOptions, rPos, Vector3(sign * rDir), singleLink->dVolume));
0152     }
0153     auto multiLink =
0154         dynamic_cast<const Experimental::BoundVolumesGrid1Impl*>(instance);
0155     if (multiLink != nullptr) {
0156       auto pLinks = convertMultiLink(gctx, *multiLink, surface, rPos,
0157                                      portalOptions, sign);
0158 
0159       pPortal._volume_links.insert(pPortal._volume_links.end(), pLinks.begin(),
0160                                    pLinks.end());
0161     }
0162     // Switch to the other side
0163     sign += 2;
0164   }
0165 
0166   // Return the proto Portal
0167   return pPortal;
0168 }