Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-11-23 09:33:26

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