Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:12:15

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 #include "Acts/Plugins/ActSVG/SurfaceArraySvgConverter.hpp"
0010 
0011 #include "Acts/Plugins/ActSVG/SurfaceSvgConverter.hpp"
0012 #include "Acts/Surfaces/Surface.hpp"
0013 #include "Acts/Surfaces/SurfaceArray.hpp"
0014 #include "Acts/Surfaces/SurfaceBounds.hpp"
0015 
0016 #include <algorithm>
0017 #include <numbers>
0018 
0019 std::tuple<std::vector<Acts::Svg::ProtoSurfaces>, Acts::Svg::ProtoGrid,
0020            std::vector<Acts::Svg::ProtoAssociations> >
0021 Acts::Svg::SurfaceArrayConverter::convert(
0022     const GeometryContext& gctx, const SurfaceArray& surfaceArray,
0023     const SurfaceArrayConverter::Options& cOptions) {
0024   // Prepare the return objects
0025   ProtoSurfaces pSurfaces;
0026   ProtoGrid pGrid;
0027   ProtoAssociations pAssociations;
0028 
0029   const auto& surfaces = surfaceArray.surfaces();
0030 
0031   // The edges of the grid
0032   auto binning = surfaceArray.binningValues();
0033   auto axes = surfaceArray.getAxes();
0034 
0035   enum ViewType { cylinder, polar, planar, none };
0036   ViewType vType = none;
0037 
0038   if (!binning.empty() && binning.size() == 2 && axes.size() == 2) {
0039     // The endges values
0040     std::vector<double> edges0;
0041     std::vector<double> edges1;
0042     // Helper method to convert from ACTS to Grid edges
0043     auto convertGridEdges = [](const std::vector<double>& actsEdges)
0044         -> std::vector<actsvg::scalar> {
0045       std::vector<actsvg::scalar> svgEdges;
0046       svgEdges.reserve(actsEdges.size());
0047       for (const auto ae : actsEdges) {
0048         svgEdges.push_back(static_cast<actsvg::scalar>(ae));
0049       }
0050       return svgEdges;
0051     };
0052 
0053     // Walk through the binning and translate
0054     if (binning[0] == AxisDirection::AxisPhi &&
0055         binning[1] == AxisDirection::AxisZ) {
0056       vType = cylinder;
0057       //  flip to fit with actsvg convention
0058       edges1 = axes[0]->getBinEdges();
0059       edges0 = axes[1]->getBinEdges();
0060       pGrid._type = actsvg::proto::grid::e_z_phi;
0061     } else if (binning[0] == AxisDirection::AxisPhi &&
0062                binning[1] == AxisDirection::AxisR) {
0063       vType = polar;
0064       //  flip to fit with actsvg convention
0065       edges1 = axes[0]->getBinEdges();
0066       edges0 = axes[1]->getBinEdges();
0067       pGrid._type = actsvg::proto::grid::e_r_phi;
0068     } else if (binning[0] == AxisDirection::AxisZ &&
0069                binning[1] == AxisDirection::AxisPhi) {
0070       // good
0071       vType = cylinder;
0072       edges0 = axes[0]->getBinEdges();
0073       edges1 = axes[1]->getBinEdges();
0074       pGrid._type = actsvg::proto::grid::e_z_phi;
0075     } else if (binning[0] == AxisDirection::AxisR &&
0076                binning[1] == AxisDirection::AxisPhi) {
0077       // good
0078       vType = polar;
0079       edges0 = axes[0]->getBinEdges();
0080       edges1 = axes[1]->getBinEdges();
0081       pGrid._type = actsvg::proto::grid::e_r_phi;
0082     }
0083     // Assign
0084     pGrid._edges_0 = convertGridEdges(edges0);
0085     pGrid._edges_1 = convertGridEdges(edges1);
0086   }
0087 
0088   // Find the template surfaces & prepare template objects to be assigned
0089   std::vector<actsvg::svg::object> templateObjects;
0090   std::vector<const SurfaceBounds*> templateBounds;
0091 
0092   for (const auto& sf : surfaces) {
0093     // Get bounds and check them
0094     const SurfaceBounds& sBounds = sf->bounds();
0095     // Helper to find bounds
0096     auto sameBounds = [&](const SurfaceBounds* test) {
0097       return ((*test) == sBounds);
0098     };
0099     // Check if you have this template object already before creating new
0100     // reference bounds and new reference object
0101     if (std::ranges::none_of(templateBounds, sameBounds)) {
0102       // Let's get the right style
0103       SurfaceConverter::Options sOptions;
0104       sOptions.templateSurface = true;
0105       // Find a corresponding file in the playbook
0106       auto sfStyle = cOptions.surfaceStyles.find(sf->geometryId());
0107       if (sfStyle != cOptions.surfaceStyles.end()) {
0108         sOptions.style = *sfStyle;
0109       }
0110 
0111       // Create a reference surface and reference object from it
0112       auto referenceSurface = SurfaceConverter::convert(gctx, *sf, sOptions);
0113       auto referenceObject =
0114           View::xy(referenceSurface,
0115                    "Template_" + std::to_string(templateObjects.size()));
0116       templateBounds.push_back(&sBounds);
0117       templateObjects.push_back(referenceObject);
0118     }
0119   }
0120 
0121   // Estimate a reference radius
0122   double radius = 0.;
0123 
0124   // Now draw the surfaces from the correct template
0125   for (const auto& sf : surfaces) {
0126     radius += Acts::VectorHelpers::perp(sf->center(gctx));
0127 
0128     // Let's get the right style
0129     SurfaceConverter::Options sOptions;
0130     sOptions.templateSurface = vType != cylinder;
0131     // Find a corresponding file in the playbook
0132     auto sfStyle = cOptions.surfaceStyles.find(sf->geometryId());
0133     if (sfStyle != cOptions.surfaceStyles.end()) {
0134       sOptions.style = *sfStyle;
0135     }
0136 
0137     // Convert the surface from ACTS to actsvg
0138     auto cSurface = Acts::Svg::SurfaceConverter::convert(gctx, *sf, sOptions);
0139     cSurface._name = "Module_n_" + std::to_string(pSurfaces.size());
0140 
0141     cSurface._aux_info["grid_info"] = {
0142         "* module " + std::to_string(pSurfaces.size()) +
0143         ", surface = " + std::to_string(sf->geometryId().sensitive())};
0144     // Assign the template for cylinder layers
0145     if (vType == cylinder) {
0146       const SurfaceBounds& sBounds = sf->bounds();
0147       // Helper to find bounds
0148       auto sameBounds = [&](const SurfaceBounds* test) {
0149         return ((*test) == sBounds);
0150       };
0151       // Check if you have this template object already
0152       auto tBounds = std::ranges::find_if(templateBounds, sameBounds);
0153       // New reference bounds and new reference object
0154       if (tBounds != templateBounds.end()) {
0155         std::size_t tObject = std::distance(templateBounds.begin(), tBounds);
0156         cSurface._template_object = templateObjects[tObject];
0157       }
0158     }
0159     // Correct view transform for disc/planar layers
0160     if (vType == planar || vType == polar) {
0161       // Get the transform and estimate the rotation of phi
0162       // Assumes x/y view
0163       const auto& sTransform = sf->transform(gctx);
0164       Vector3 localA = sTransform.rotation().col(0);
0165       Vector3 localZ = sTransform.rotation().col(2);
0166       // Find out orientation w.r.t. global transform
0167       double projZ = localZ.dot(Vector3(0., 0., 1.));
0168       double alpha = std::atan2(localA[1], localA[0]) / std::numbers::pi * 180.;
0169       if (projZ < 0.) {
0170         alpha += 180.;
0171       }
0172       auto surfaceCenter = sf->center(gctx);
0173       // Set the transform for an eventual placement
0174       cSurface._transform._tr = {static_cast<actsvg::scalar>(surfaceCenter[0]),
0175                                  static_cast<actsvg::scalar>(surfaceCenter[1])};
0176       cSurface._transform._rot = {static_cast<actsvg::scalar>(alpha), 0., 0.};
0177     }
0178 
0179     pSurfaces.push_back(cSurface);
0180   }
0181   radius /= surfaces.size();
0182 
0183   // Create the bin associations
0184   for (unsigned int il0 = 1; il0 < pGrid._edges_0.size(); ++il0) {
0185     double p0 = 0.5 * (pGrid._edges_0[il0] + pGrid._edges_0[il0 - 1]);
0186     for (unsigned int il1 = 1; il1 < pGrid._edges_1.size(); ++il1) {
0187       double p1 = 0.5 * (pGrid._edges_1[il1] + pGrid._edges_1[il1 - 1]);
0188       // Create the fitting bin center estimates
0189       Vector3 bCenter;
0190       if (vType == polar) {
0191         bCenter = Vector3(p0 * std::cos(p1), p0 * std::sin(p1), 0.);
0192       } else if (vType == cylinder) {
0193         bCenter = Vector3(radius * std::cos(p1), radius * std::sin(p1), p0);
0194       }
0195       // Get all the bin entries and members
0196       auto bSurfaces = surfaceArray.neighbors(bCenter);
0197       std::vector<std::size_t> binnAssoc;
0198       for (const auto& bs : bSurfaces) {
0199         auto candidate = std::ranges::find(surfaces, bs);
0200         if (candidate != surfaces.end()) {
0201           binnAssoc.push_back(std::distance(surfaces.begin(), candidate));
0202         }
0203       }
0204       pAssociations.push_back(binnAssoc);
0205     }
0206   }
0207   // Return the surfaces and the grid
0208   std::vector<ProtoSurfaces> pSurfaceBatches = {pSurfaces};
0209   std::vector<ProtoAssociations> pAssociationBatchs = {pAssociations};
0210   return {pSurfaceBatches, pGrid, pAssociationBatchs};
0211 }