Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-11 09:40:21

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 #pragma once
0010 
0011 #include "Acts/Geometry/Extent.hpp"
0012 #include "Acts/Geometry/GeometryContext.hpp"
0013 #include "Acts/Geometry/GeometryHierarchyMap.hpp"
0014 #include "Acts/Navigation/InternalNavigation.hpp"
0015 #include "Acts/Navigation/NavigationDelegates.hpp"
0016 #include "Acts/Utilities/Enumerate.hpp"
0017 #include "Acts/Utilities/Grid.hpp"
0018 #include "Acts/Utilities/GridAxisGenerators.hpp"
0019 #include "Acts/Utilities/TypeList.hpp"
0020 #include "ActsPlugins/ActSVG/GridSvgConverter.hpp"
0021 #include "ActsPlugins/ActSVG/SurfaceSvgConverter.hpp"
0022 #include "ActsPlugins/ActSVG/SvgUtils.hpp"
0023 #include <actsvg/core.hpp>
0024 #include <actsvg/meta.hpp>
0025 
0026 #include <tuple>
0027 #include <vector>
0028 
0029 namespace ActsPlugins::Svg {
0030 
0031 using ProtoSurface = actsvg::proto::surface<std::vector<Acts::Vector3>>;
0032 using ProtoSurfaces = std::vector<ProtoSurface>;
0033 using ProtoGrid = actsvg::proto::grid;
0034 using ProtoAssociations = std::vector<std::vector<std::size_t>>;
0035 
0036 using ProtoIndexedSurfaceGrid =
0037     std::tuple<ProtoSurfaces, ProtoGrid, ProtoAssociations>;
0038 
0039 namespace IndexedSurfacesConverter {
0040 /// Nested options struct
0041 struct Options {
0042   /// Hierarchy map of styles
0043   Acts::GeometryHierarchyMap<Style> surfaceStyles;
0044   /// The Grid converter options
0045   GridConverter::Options gridOptions;
0046 };
0047 
0048 /// Convert a surface array into needed constituents
0049 ///
0050 /// @note actual conversion implementation, bottom of unrolling loop
0051 ///
0052 /// @param gtcx is the geometry context of the conversion call
0053 /// @param surfaces the container of surfaces
0054 /// @param indexGrid the indexGrid delegate
0055 /// @param cOptions the conversion options
0056 ///
0057 /// @return a collection of proto surface object and a grid, and associations
0058 template <typename surface_container, typename index_grid>
0059 ProtoIndexedSurfaceGrid convertImpl(const Acts::GeometryContext& gctx,
0060                                     const surface_container& surfaces,
0061                                     const index_grid& indexGrid,
0062                                     const Options& cOptions) {
0063   // The return surfaces
0064   ProtoSurfaces pSurfaces;
0065   pSurfaces.reserve(surfaces.size());
0066 
0067   // Make a local copy of the grid Options, in case we have to estimate
0068   // an additional bound
0069   GridConverter::Options gridOptions = cOptions.gridOptions;
0070   Acts::Extent constrain;
0071 
0072   // Estimate the radial extension
0073   // - for 1D phi
0074   // - for 2D z-phi or phi-z
0075   bool estimateR = (index_grid::grid_type::DIM == 1 &&
0076                     indexGrid.casts[0u] == Acts::AxisDirection::AxisPhi) ||
0077                    (index_grid::grid_type::DIM == 2 &&
0078                     (indexGrid.casts[0u] == Acts::AxisDirection::AxisPhi ||
0079                      indexGrid.casts[1u] == Acts::AxisDirection::AxisPhi));
0080 
0081   for (auto [is, s] : Acts::enumerate(surfaces)) {
0082     // Create the surface converter options
0083     SurfaceConverter::Options sOptions;
0084     // Try to see if you have predefined surface styles
0085     auto sfIter = cOptions.surfaceStyles.find(s->geometryId());
0086     if (sfIter != cOptions.surfaceStyles.end()) {
0087       sOptions.style = *sfIter;
0088     }
0089     auto pSurface = SurfaceConverter::convert(gctx, *s, sOptions);
0090     // Run the r estimation
0091     if (estimateR) {
0092       auto sExtent = s->polyhedronRepresentation(gctx, 4u).extent();
0093       if constexpr (index_grid::grid_type::DIM == 2u) {
0094         pSurface._radii[0u] =
0095             static_cast<float>(sExtent.medium(Acts::AxisDirection::AxisR));
0096       }
0097       constrain.extend(sExtent, {Acts::AxisDirection::AxisR});
0098     }
0099     // Add center info
0100     std::string centerInfo = " - center = (";
0101     const Acts::Vector3& center = s->center(gctx);
0102     centerInfo +=
0103         std::to_string(Acts::VectorHelpers::cast(center, indexGrid.casts[0u]));
0104     if (indexGrid.casts.size() > 1u) {
0105       centerInfo += ", ";
0106       centerInfo += std::to_string(
0107           Acts::VectorHelpers::cast(center, indexGrid.casts[1u]));
0108       centerInfo += ")";
0109     }
0110     pSurface._aux_info["center"] = {centerInfo};
0111     // Add the center info
0112     pSurfaces.push_back(pSurface);
0113   }
0114 
0115   // Adjust the grid options
0116   if constexpr (index_grid::grid_type::DIM == 1u) {
0117     if (indexGrid.casts[0u] == Acts::AxisDirection::AxisPhi) {
0118       auto estRangeR = constrain.range(Acts::AxisDirection::AxisR);
0119       std::array<double, 2u> rRange = {estRangeR.min(), estRangeR.max()};
0120       gridOptions.optionalBound = {rRange, Acts::AxisDirection::AxisR};
0121     }
0122   }
0123 
0124   // Create the grid
0125   ProtoGrid pGrid =
0126       GridConverter::convert(indexGrid.grid, indexGrid.casts, gridOptions);
0127 
0128   auto axes = indexGrid.grid.axes();
0129 
0130   // Specify the highlight indices
0131   ProtoAssociations highlightIndices;
0132 
0133   // 1D connections
0134   if constexpr (index_grid::grid_type::DIM == 1u) {
0135     const auto& binEdges = axes[0u]->getBinEdges();
0136     for (unsigned int ib0 = 1u; ib0 <= axes[0u]->getNBins(); ++ib0) {
0137       typename index_grid::grid_type::index_t lbin;
0138       lbin[0u] = ib0;
0139       highlightIndices.push_back(indexGrid.grid.atLocalBins(lbin));
0140       // Register the bin naming
0141       std::string binInfo =
0142           std::string("- bin : [") + std::to_string(ib0) + std::string("]");
0143       double binCenter = 0.5 * (binEdges[ib0] + binEdges[ib0 - 1u]);
0144       binInfo += "\n - center : (" + std::to_string(binCenter) + ")";
0145       pGrid._bin_ids.push_back(binInfo);
0146     }
0147   }
0148   // 2D connections
0149   if constexpr (index_grid::grid_type::DIM == 2u) {
0150     const auto& binEdges0 = axes[0u]->getBinEdges();
0151     const auto& binEdges1 = axes[1u]->getBinEdges();
0152     for (unsigned int ib0 = 1u; ib0 <= axes[0u]->getNBins(); ++ib0) {
0153       for (unsigned int ib1 = 1u; ib1 <= axes[1u]->getNBins(); ++ib1) {
0154         typename index_grid::grid_type::index_t lbin;
0155         lbin[0u] = ib0;
0156         lbin[1u] = ib1;
0157         highlightIndices.push_back(indexGrid.grid.atLocalBins(lbin));
0158         // Register the bin naming
0159         std::string binInfo = std::string("- bin : [") + std::to_string(ib0) +
0160                               std::string(", ") + std::to_string(ib1) +
0161                               std::string("]");
0162         double binCenter0 = 0.5 * (binEdges0[ib0] + binEdges0[ib0 - 1u]);
0163         double binCenter1 = 0.5 * (binEdges1[ib1] + binEdges1[ib1 - 1u]);
0164         binInfo += "\n - center : (" + std::to_string(binCenter0) + ", " +
0165                    std::to_string(binCenter1) + ")";
0166         pGrid._bin_ids.push_back(binInfo);
0167         if (estimateR) {
0168           pGrid._reference_r =
0169               static_cast<float>(constrain.medium(Acts::AxisDirection::AxisR));
0170         }
0171       }
0172     }
0173   }
0174   return {pSurfaces, pGrid, highlightIndices};
0175 }
0176 
0177 /// @brief Convert the single delegate if it is of the type of the reference
0178 ///
0179 /// @note It will do nothing if the type does not match
0180 ///
0181 /// @tparam surface_container the surfaces to be drawn
0182 /// @tparam instance_type the reference instance type
0183 ///
0184 /// @param gctx The Geometry context of this operation
0185 /// @param surfaces The surfaces to be converted
0186 /// @param cOptions the conversion options
0187 /// @param sgi [in,out] the proto indexed grid to be converted
0188 /// @param delegate the delegate to be translated
0189 /// @param refInstance the reference input type from the reference Axes
0190 template <typename surface_container, typename instance_type>
0191 void convert(const Acts::GeometryContext& gctx,
0192              const surface_container& surfaces, const Options& cOptions,
0193              ProtoIndexedSurfaceGrid& sgi,
0194              const Acts::Experimental::InternalNavigationDelegate& delegate,
0195              [[maybe_unused]] const instance_type& refInstance) {
0196   using GridType =
0197       typename instance_type::template grid_type<std::vector<std::size_t>>;
0198   // Defining a Delegate type
0199   using DelegateType = Acts::Experimental::IndexedSurfacesAllPortalsNavigation<
0200       GridType, Acts::Experimental::IndexedSurfacesNavigation>;
0201   using SubDelegateType =
0202       Acts::Experimental::IndexedSurfacesNavigation<GridType>;
0203 
0204   // Get the instance
0205   const auto* instance = delegate.instance();
0206   auto castedDelegate = dynamic_cast<const DelegateType*>(instance);
0207   if (castedDelegate != nullptr) {
0208     // Get the surface updator
0209     auto indexedSurfaces = std::get<SubDelegateType>(castedDelegate->updators);
0210     auto [pSurfaces, pGrid, pIndices] =
0211         convertImpl(gctx, surfaces, indexedSurfaces, cOptions);
0212     std::get<0u>(sgi) = pSurfaces;
0213     std::get<1u>(sgi) = pGrid;
0214     std::get<2u>(sgi) = pIndices;
0215   }
0216 }
0217 
0218 /// @brief Unrolling function for catching the right instance
0219 ///
0220 /// @note parameters are as of the `convertImpl` method
0221 template <typename surface_container, typename... Args>
0222 void unrollConvert(
0223     const Acts::GeometryContext& gctx, const surface_container& surfaces,
0224     const Options& cOptions, ProtoIndexedSurfaceGrid& sgi,
0225     const Acts::Experimental::InternalNavigationDelegate& delegate,
0226     Acts::TypeList<Args...> /*unused*/) {
0227   (convert(gctx, surfaces, cOptions, sgi, delegate, Args{}), ...);
0228 }
0229 
0230 /// Convert a surface array into needed constituents
0231 ///
0232 /// @param gtcx is the geometry context of the conversion call
0233 /// @param surfaces the container of surfaces
0234 /// @param indexGrid the indexGrid delegate
0235 /// @param cOptions the conversion options
0236 ///
0237 /// @note this is the entry point of the conversion, i.e. top of the
0238 /// unrolling loop
0239 ///
0240 /// @return a collection of proto surface object and a grid, and associations
0241 template <typename surface_container>
0242 ProtoIndexedSurfaceGrid convert(
0243     const Acts::GeometryContext& gctx, const surface_container& surfaces,
0244     const Acts::Experimental::InternalNavigationDelegate& delegate,
0245     const Options& cOptions) {
0246   // Prep work what is to be filled
0247   ProtoSurfaces pSurfaces;
0248   ProtoGrid pGrid;
0249   ProtoAssociations indices;
0250   ProtoIndexedSurfaceGrid sgi = {pSurfaces, pGrid, indices};
0251   // Convert if dynamic cast happens to work
0252   unrollConvert(gctx, surfaces, cOptions, sgi, delegate,
0253                 Acts::GridAxisGenerators::PossibleAxes{});
0254   // Return the newly filled ones
0255   return sgi;
0256 }
0257 
0258 }  // namespace IndexedSurfacesConverter
0259 
0260 namespace View {
0261 
0262 /// Convert into an ActsPlugins::Svg::object with an XY view
0263 ///
0264 /// @param pIndexGrid is the proto object
0265 /// @param identification is the to be translated id_ for actsvg
0266 ///
0267 /// @return an svg object that can be written out directly
0268 static inline actsvg::svg::object xy(const ProtoIndexedSurfaceGrid& pIndexGrid,
0269                                      const std::string& identification) {
0270   auto [pSurfaces, pGrid, pIndices] = pIndexGrid;
0271 
0272   // Create the master object
0273   actsvg::svg::object xyIndexedGrid;
0274   xyIndexedGrid._id = identification;
0275   xyIndexedGrid._tag = "g";
0276 
0277   // The surfaces
0278   std::vector<actsvg::svg::object> sObs;
0279   for (const auto& s : pSurfaces) {
0280     if (pGrid._type == ProtoGrid::e_z_phi) {
0281       sObs.push_back(zrphi(s, s._name));
0282     } else {
0283       sObs.push_back(xy(s, s._name));
0284     }
0285   }
0286 
0287   // The grid as provided
0288   auto gOb =
0289       actsvg::display::grid(identification + std::string("_grid"), pGrid);
0290 
0291   // The connectors
0292   actsvg::connectors::connect_action(gOb._sub_objects, sObs, pIndices);
0293 
0294   // Add them all
0295   xyIndexedGrid.add_objects(sObs);
0296 
0297   auto xmax = xyIndexedGrid._x_range[1u];
0298   // The association info boxes
0299   for (auto [ig, gTile] : Acts::enumerate(gOb._sub_objects)) {
0300     // Target surface text
0301     std::vector<std::string> binText;
0302     binText.push_back("Source:");
0303     binText.push_back(pGrid._bin_ids[ig]);
0304     binText.push_back("Target:");
0305     for (const auto [is, sis] : Acts::enumerate(pIndices[ig])) {
0306       const auto& ps = pSurfaces[sis];
0307       std::string oInfo = std::string("- object: ") + std::to_string(sis);
0308       if (ps._aux_info.contains("center")) {
0309         for (const auto& ci : ps._aux_info.at("center")) {
0310           oInfo += ci;
0311         }
0312       }
0313       binText.push_back(oInfo);
0314     }
0315     // Make the connected text
0316     std::string cTextId =
0317         identification + std::string("_ct_") + std::to_string(ig);
0318     auto cText = actsvg::draw::connected_text(
0319         cTextId, {static_cast<actsvg::scalar>(1.1 * xmax), 0}, binText,
0320         actsvg::style::font{}, actsvg::style::transform{}, gTile);
0321     xyIndexedGrid.add_object(cText);
0322   }
0323   xyIndexedGrid.add_object(gOb);
0324   // Return the grid
0325   return xyIndexedGrid;
0326 }
0327 
0328 /// Fake zphi method, delegate to xy
0329 ///
0330 /// @param pIndexGrid is the proto object
0331 /// @param identification is the to be translated id_ for actsvg
0332 ///
0333 /// @note this works, because the actual display at the end is 2D
0334 /// in an x-y plane and the parameters are appropriately defined
0335 ///
0336 /// @return an svg object that can be written out directly
0337 static inline actsvg::svg::object zphi(
0338     const ProtoIndexedSurfaceGrid& pIndexGrid,
0339     const std::string& identification) {
0340   return xy(pIndexGrid, identification);
0341 }
0342 
0343 }  // namespace View
0344 }  // namespace ActsPlugins::Svg