Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SurfaceArraySvgConverter.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file SurfaceArraySvgConverter.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2022 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
10 
15 
16 std::tuple<std::vector<Acts::Svg::ProtoSurfaces>, Acts::Svg::ProtoGrid,
17  std::vector<Acts::Svg::ProtoAssociations> >
19  const GeometryContext& gctx, const SurfaceArray& surfaceArray,
20  const SurfaceArrayConverter::Options& cOptions) {
21  // Prepare the return objects
22  ProtoSurfaces pSurfaces;
23  ProtoGrid pGrid;
24  ProtoAssociations pAssociations;
25 
26  const auto& surfaces = surfaceArray.surfaces();
27 
28  // The edges of the grid
29  auto binning = surfaceArray.binningValues();
30  auto axes = surfaceArray.getAxes();
31 
32  enum ViewType { cylinder, polar, planar, none };
33  ViewType vType = none;
34 
35  if (not binning.empty() and binning.size() == 2 and axes.size() == 2) {
36  // The endges values
37  std::vector<Acts::ActsScalar> edges0;
38  std::vector<Acts::ActsScalar> edges1;
39  // Helper method to convert from ACTS to Grid edges
40  auto convertGridEdges = [](const std::vector<Acts::ActsScalar>& actsEdges)
41  -> std::vector<actsvg::scalar> {
42  std::vector<actsvg::scalar> svgEdges;
43  svgEdges.reserve(actsEdges.size());
44  for (const auto ae : actsEdges) {
45  svgEdges.push_back(static_cast<actsvg::scalar>(ae));
46  }
47  return svgEdges;
48  };
49 
50  // Walk through the binning and translate
51  if (binning[0] == binPhi and binning[1] == binZ) {
52  vType = cylinder;
53  // flip to fit with actsvg convention
54  edges1 = axes[0]->getBinEdges();
55  edges0 = axes[1]->getBinEdges();
56  pGrid._type = actsvg::proto::grid::e_z_phi;
57  } else if (binning[0] == binPhi and binning[1] == binR) {
58  vType = polar;
59  // flip to fit with actsvg convention
60  edges1 = axes[0]->getBinEdges();
61  edges0 = axes[1]->getBinEdges();
62  pGrid._type = actsvg::proto::grid::e_r_phi;
63  } else if (binning[0] == binZ and binning[1] == binPhi) {
64  // good
65  vType = cylinder;
66  edges0 = axes[0]->getBinEdges();
67  edges1 = axes[1]->getBinEdges();
68  pGrid._type = actsvg::proto::grid::e_z_phi;
69  } else if (binning[0] == binR and binning[1] == binPhi) {
70  // good
71  vType = polar;
72  edges0 = axes[0]->getBinEdges();
73  edges1 = axes[1]->getBinEdges();
74  pGrid._type = actsvg::proto::grid::e_r_phi;
75  }
76  // Assign
77  pGrid._edges_0 = convertGridEdges(edges0);
78  pGrid._edges_1 = convertGridEdges(edges1);
79  }
80 
81  // Find the template surfaces & prepare template objects to be assigned
82  std::vector<actsvg::svg::object> templateObjects;
83  std::vector<const SurfaceBounds*> templateBounds;
84 
85  for (const auto& sf : surfaces) {
86  // Get bounds and check them
87  const SurfaceBounds& sBounds = sf->bounds();
88  // Helper to find bounds
89  auto sameBounds = [&](const SurfaceBounds* test) {
90  return ((*test) == sBounds);
91  };
92  // Check if you have this template object already
93  auto tBounds =
94  std::find_if(templateBounds.begin(), templateBounds.end(), sameBounds);
95  // New reference bounds and new reference object
96  if (tBounds == templateBounds.end()) {
97  // Let's get the right style
99  sOptions.templateSurface = true;
100  // Find a corresponding file in the playbook
101  auto sfStyle = cOptions.surfaceStyles.find(sf->geometryId());
102  if (sfStyle != cOptions.surfaceStyles.end()) {
103  sOptions.style = *sfStyle;
104  }
105 
106  // Create a referese surface and reference object from it
107  auto referenceSurface = SurfaceConverter::convert(gctx, *sf, sOptions);
108  auto referenceObject =
109  View::xy(referenceSurface,
110  "Template_" + std::to_string(templateObjects.size()));
111  templateBounds.push_back(&sBounds);
112  templateObjects.push_back(referenceObject);
113  }
114  }
115 
116  // Estimate a reference radius
117  ActsScalar radius = 0.;
118 
119  // Now draw the surfaces from the correct template
120  for (const auto& sf : surfaces) {
121  radius += Acts::VectorHelpers::perp(sf->center(gctx));
122 
123  // Let's get the right style
124  SurfaceConverter::Options sOptions;
125  sOptions.templateSurface = vType != cylinder;
126  // Find a corresponding file in the playbook
127  auto sfStyle = cOptions.surfaceStyles.find(sf->geometryId());
128  if (sfStyle != cOptions.surfaceStyles.end()) {
129  sOptions.style = *sfStyle;
130  }
131 
132  // Convert the surface from ACTS to actsvg
133  auto cSurface = Acts::Svg::SurfaceConverter::convert(gctx, *sf, sOptions);
134  cSurface._name = "Module_n_" + std::to_string(pSurfaces.size());
135 
136  cSurface._aux_info["grid_info"] = {
137  "* module " + std::to_string(pSurfaces.size()) +
138  ", surface = " + std::to_string(sf->geometryId().sensitive())};
139  // Assign the template for cylinder layers
140  if (vType == cylinder) {
141  const SurfaceBounds& sBounds = sf->bounds();
142  // Helper to find bounds
143  auto sameBounds = [&](const SurfaceBounds* test) {
144  return ((*test) == sBounds);
145  };
146  // Check if you have this template object already
147  auto tBounds = std::find_if(templateBounds.begin(), templateBounds.end(),
148  sameBounds);
149  // New reference bounds and new reference object
150  if (tBounds != templateBounds.end()) {
151  size_t tObject = std::distance(templateBounds.begin(), tBounds);
152  cSurface._template_object = templateObjects[tObject];
153  }
154  }
155  // Correct view transform for disc/planar layers
156  if (vType == planar or vType == polar) {
157  // Get the transform and estimate the rotation of phi
158  // Assumes x/y view
159  const auto& sTransform = sf->transform(gctx);
160  Vector3 localA = sTransform.rotation().col(0);
161  Vector3 localZ = sTransform.rotation().col(2);
162  // Find out orientation w.r.t. global transform
163  ActsScalar projZ = localZ.dot(Vector3(0., 0., 1.));
164  ActsScalar alpha = std::atan2(localA[1], localA[0]) / M_PI * 180.;
165  if (projZ < 0.) {
166  alpha += 180.;
167  }
168  auto surfaceCenter = sf->center(gctx);
169  // Set the transform for an eventual placement
170  cSurface._transform._tr = {static_cast<actsvg::scalar>(surfaceCenter[0]),
171  static_cast<actsvg::scalar>(surfaceCenter[1])};
172  cSurface._transform._rot = {static_cast<actsvg::scalar>(alpha), 0., 0.};
173  }
174 
175  pSurfaces.push_back(cSurface);
176  }
177  radius /= surfaces.size();
178 
179  // Create the bin associations
180  for (unsigned int il0 = 1; il0 < pGrid._edges_0.size(); ++il0) {
181  ActsScalar p0 = 0.5 * (pGrid._edges_0[il0] + pGrid._edges_0[il0 - 1]);
182  for (unsigned int il1 = 1; il1 < pGrid._edges_1.size(); ++il1) {
183  ActsScalar p1 = 0.5 * (pGrid._edges_1[il1] + pGrid._edges_1[il1 - 1]);
184  // Create the fitting bin center estimates
185  Vector3 bCenter;
186  if (vType == polar) {
187  bCenter = Vector3(p0 * std::cos(p1), p0 * std::sin(p1), 0.);
188  } else if (vType == cylinder) {
189  bCenter = Vector3(radius * std::cos(p1), radius * std::sin(p1), p0);
190  }
191  // Get all the bin entries and members
192  auto bSurfaces = surfaceArray.neighbors(bCenter);
193  std::vector<size_t> binnAssoc;
194  for (const auto& bs : bSurfaces) {
195  auto candidate = std::find(surfaces.begin(), surfaces.end(), bs);
196  if (candidate != surfaces.end()) {
197  binnAssoc.push_back(std::distance(surfaces.begin(), candidate));
198  }
199  }
200  pAssociations.push_back(binnAssoc);
201  }
202  }
203  // Return the surfaces and the grid
204  std::vector<ProtoSurfaces> pSurfaceBatches = {pSurfaces};
205  std::vector<ProtoAssociations> pAssociationBatchs = {pAssociations};
206  return std::tie(pSurfaceBatches, pGrid, pAssociationBatchs);
207 }