Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SupportHelper.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file SupportHelper.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2023 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 
19 
20 #include <algorithm>
21 #include <cmath>
22 #include <stdexcept>
23 #include <utility>
24 
25 std::vector<std::shared_ptr<Acts::Surface>>
27  const Transform3& transform, const std::array<ActsScalar, 6u>& bounds,
28  unsigned int splits) {
29  // Return vector preparation
30  std::vector<std::shared_ptr<Acts::Surface>> cSupport;
31  if (splits == 1u) {
32  // No splitting is done in this case
33  cSupport.push_back(Surface::makeShared<CylinderSurface>(
34  transform, std::make_shared<CylinderBounds>(bounds)));
35  } else {
36  // Split into n(splits) planar surfaces, prep work:
37  ActsScalar r = bounds[0u];
38  ActsScalar halfZ = bounds[1u];
39  ActsScalar minPhi = bounds[3u] - bounds[2u];
40  ActsScalar maxPhi = bounds[3u] + bounds[2u];
41  ActsScalar dHalfPhi = (maxPhi - minPhi) / (2 * splits);
42  ActsScalar cosPhiHalf = std::cos(dHalfPhi);
43  ActsScalar sinPhiHalf = std::sin(dHalfPhi);
44  ActsScalar planeR = r * cosPhiHalf;
45  ActsScalar planeHalfX = r * sinPhiHalf;
46  ActsScalar planeZ = transform.translation().z();
47 
48  auto sRectangle =
49  std::make_shared<Acts::RectangleBounds>(planeHalfX, halfZ);
50  // Now create the Trapezoids
51  for (unsigned int iphi = 0; iphi < splits; ++iphi) {
52  // Get the moduleTransform
53  ActsScalar phi = -M_PI + (iphi + 0.5) * 2 * dHalfPhi;
54  ActsScalar cosPhi = std::cos(phi);
55  ActsScalar sinPhi = std::sin(phi);
56  ActsScalar planeX = planeR * cosPhi;
57  ActsScalar planeY = planeR * sinPhi;
58 
59  Acts::Vector3 planeCenter(planeX, planeY, planeZ);
60  Acts::Vector3 planeAxisZ(cosPhi, sinPhi, 0.);
61  Acts::Vector3 planeAxisY(0., 0., 1.);
62  Acts::Vector3 planeAxisX = planeAxisY.cross(planeAxisZ);
63 
64  RotationMatrix3 planeRotation;
65  planeRotation.col(0) = planeAxisX;
66  planeRotation.col(1) = planeAxisY;
67  planeRotation.col(2) = planeAxisZ;
68 
69  Transform3 sTransform{planeRotation};
70  sTransform.pretranslate(planeCenter);
71  // Place it
72  cSupport.push_back(
73  Surface::makeShared<PlaneSurface>(sTransform, sRectangle));
74  }
75  }
76 
77  return cSupport;
78 }
79 
80 std::vector<std::shared_ptr<Acts::Surface>>
82  const Transform3& transform, const std::array<ActsScalar, 4u>& bounds,
83  unsigned int splits) {
84  // Return vector
85  std::vector<std::shared_ptr<Acts::Surface>> dSupport;
86  if (splits == 1u) {
87  // No splitting is done in this case
88  dSupport.push_back(Surface::makeShared<DiscSurface>(
89  transform, std::make_shared<RadialBounds>(bounds)));
90  } else {
91  // Split into n(splits) planar surfaces in phi, prep work:
92  ActsScalar minR = bounds[0u];
93  ActsScalar maxR = bounds[1u];
94  ActsScalar minPhi = bounds[3u] - bounds[2u];
95  ActsScalar maxPhi = bounds[3u] + bounds[2u];
96  ActsScalar dHalfPhi = (maxPhi - minPhi) / (2 * splits);
97  ActsScalar cosPhiHalf = std::cos(dHalfPhi);
98  ActsScalar sinPhiHalf = std::sin(dHalfPhi);
99  ActsScalar maxLocY = maxR * cosPhiHalf;
100  ActsScalar minLocY = minR * cosPhiHalf;
101  ActsScalar hR = 0.5 * (maxLocY + minLocY);
102  ActsScalar hY = 0.5 * (maxLocY - minLocY);
103  ActsScalar hXminY = minR * sinPhiHalf;
104  ActsScalar hXmaxY = maxR * sinPhiHalf;
105  // Split trapezoid
106  auto sTrapezoid =
107  std::make_shared<Acts::TrapezoidBounds>(hXminY, hXmaxY, hY);
108  Vector3 zAxis = transform.rotation().col(2);
109  ActsScalar zPosition = transform.translation().z();
110  // Now create the Trapezoids
111  for (unsigned int iphi = 0; iphi < splits; ++iphi) {
112  // Create the split module transform
113  ActsScalar phi = -M_PI + (iphi + 0.5) * 2 * dHalfPhi;
114  auto sTransform = Transform3(
115  Translation3(hR * std::cos(phi), hR * std::sin(phi), zPosition) *
116  AngleAxis3(phi - 0.5 * M_PI, zAxis));
117  // Place it
118  dSupport.push_back(
119  Surface::makeShared<PlaneSurface>(sTransform, sTrapezoid));
120  }
121  }
122  return dSupport;
123 }
124 
126  std::vector<std::shared_ptr<Surface>>& layerSurfaces,
127  std::vector<size_t>& assignToAll, const Extent& layerExtent,
128  Surface::SurfaceType layerRepresentation,
129  const std::array<ActsScalar, 5u>& layerSupportValues,
130  std::optional<Transform3> layerTransform, unsigned int supportSplits) {
131  // Cylinder and Disc section
132  if (layerRepresentation == Surface::SurfaceType::Cylinder or
133  layerRepresentation == Surface::SurfaceType::Disc) {
134  // Bail out if you have no measure of R, Z
135  if (not layerExtent.constrains(binZ) or not layerExtent.constrains(binR)) {
136  throw std::runtime_error(
137  "SupportHelper::addSupport(...) - z or phi are not constrained.");
138  }
140  ActsScalar minZ = layerExtent.min(binZ);
141  ActsScalar maxZ = layerExtent.max(binZ);
142  ActsScalar minR = layerExtent.min(binR);
143  ActsScalar maxR = layerExtent.max(binR);
144  ActsScalar minPhi = -M_PI;
145  ActsScalar maxPhi = M_PI;
146  bool sectoral = false;
147  bool concentric = false;
148  // Check if concentric
149  if (layerTransform.has_value() and
150  layerTransform.value().isApprox(Transform3::Identity())) {
151  concentric = true;
152  }
153  // Check if we are dealing with a sectoral setup
154  if (layerExtent.constrains(binPhi)) {
155  minPhi = layerExtent.min(binPhi);
156  maxPhi = layerExtent.max(binPhi);
157  sectoral = true;
158  }
159 
160  // Get the main support parameters:
161  // - doff .. offset (in r.z)
162  // - demin,d emax .. envelop min, max (in z,r)
163  // - dphimin, dphimin .. envelop min, max (in phi)
164  auto [doff, demin, demax, dphimin, dphimax] = layerSupportValues;
165  // phi treatment is common between the cylinders and discs
166  if (sectoral) {
167  minPhi -= std::abs(demin);
168  maxPhi += std::abs(demax);
169  }
170  // Average phi and half phi
171  ActsScalar avgPhi = 0.5 * (maxPhi + minPhi);
172  ActsScalar halfPhi = 0.5 * (maxPhi - minPhi);
173  // Now specify into Cylinder or disc
174  if (layerRepresentation == Surface::SurfaceType::Cylinder) {
175  ActsScalar layerR = doff < 0 ? minR + doff : maxR + doff;
176  minZ -= std::abs(demin);
177  maxZ += std::abs(demax);
178  ActsScalar midZ = 0.5 * (minZ + maxZ);
179  ActsScalar halfZ = 0.5 * (maxZ - minZ);
180  // midZ / halfZ are overwritten if the cylinder
181  // is chosen to be concentric
182  Transform3 sTransform = Transform3::Identity();
183  if (concentric) {
184  midZ = 0.;
185  halfZ = std::max(std::abs(minZ), std::abs(maxZ));
186  } else {
187  sTransform.pretranslate(Vector3(0., 0., midZ));
188  }
189  auto cSupport = SupportHelper::cylindricalSupport(
190  sTransform, {layerR, halfZ, halfPhi, avgPhi, 0., 0.}, supportSplits);
191  // Remember the surfaces to be assigned to all bins, once the
192  // support surfaces are split they enter the standard bin assignment
193  if (supportSplits == 1u and cSupport.size() == 1u) {
194  assignToAll.push_back(layerSurfaces.size());
195  }
196  // Add those to the layer surfaces
197  layerSurfaces.insert(layerSurfaces.end(), cSupport.begin(),
198  cSupport.end());
199 
200  } else {
201  // Disc section
202  ActsScalar layerZ = doff < 0 ? minZ + doff : maxZ + doff;
203  minR -= std::abs(demin);
204  maxR += std::abs(demax);
205  Transform3 sTransform = Transform3::Identity();
206  sTransform.pretranslate(Vector3(0., 0., layerZ));
207  auto dSupport = SupportHelper::discSupport(
208  sTransform, {minR, maxR, halfPhi, avgPhi}, supportSplits);
209  // Remember the surfaces to be assigned to all bins, once the
210  // support surfaces are split they enter the standard bin assignment
211  if (supportSplits == 1u and dSupport.size() == 1u) {
212  assignToAll.push_back(layerSurfaces.size());
213  }
214  // Add those to the layer surfaces
215  layerSurfaces.insert(layerSurfaces.end(), dSupport.begin(),
216  dSupport.end());
217  }
218  } else {
219  throw std::invalid_argument(
220  "SupportHelper: currently only cylindrical/disc support building "
221  "possible.");
222  }
223 }