Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ConeVolumeBounds.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file ConeVolumeBounds.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2016-2018 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 
24 
25 #include <algorithm>
26 #include <cmath>
27 #include <stdexcept>
28 #include <type_traits>
29 #include <utility>
30 
31 Acts::ConeVolumeBounds::ConeVolumeBounds(double innerAlpha, double innerOffsetZ,
32  double outerAlpha, double outerOffsetZ,
33  double halflengthZ, double averagePhi,
34  double halfPhiSector) noexcept(false)
35  : VolumeBounds(), m_values() {
36  m_values[eInnerAlpha] = innerAlpha;
37  m_values[eInnerOffsetZ] = innerOffsetZ;
38  m_values[eOuterAlpha] = outerAlpha;
39  m_values[eOuterOffsetZ] = outerOffsetZ;
40  m_values[eHalfLengthZ] = halflengthZ;
41  m_values[eAveragePhi] = averagePhi;
42  m_values[eHalfPhiSector] = halfPhiSector;
44  checkConsistency();
45 }
46 
48  double offsetZ, double halflengthZ,
49  double averagePhi,
50  double halfPhiSector) noexcept(false)
51  : VolumeBounds(), m_values() {
52  m_values[eInnerAlpha] = 0.;
53  m_values[eInnerOffsetZ] = 0.;
54  m_values[eOuterAlpha] = 0.;
55  m_values[eOuterOffsetZ] = 0.;
56  m_values[eHalfLengthZ] = halflengthZ;
57  m_values[eAveragePhi] = averagePhi;
58  m_values[eHalfPhiSector] = halfPhiSector;
59 
60  // Cone parameters
61  double tanAlpha = std::tan(alpha);
62  double zmin = offsetZ - halflengthZ;
63  double zmax = offsetZ + halflengthZ;
64  double rmin = std::abs(zmin) * tanAlpha;
65  double rmax = std::abs(zmax) * tanAlpha;
66 
67  if (rmin >= cylinderR) {
68  // Cylindrical cut-out of a cone
69  m_innerRmin = cylinderR;
70  m_innerRmax = cylinderR;
71  m_outerTanAlpha = tanAlpha;
72  m_outerRmin = rmin;
73  m_outerRmax = rmax;
74  m_values[eOuterAlpha] = alpha;
75  m_values[eOuterOffsetZ] = offsetZ;
76  } else if (rmax <= cylinderR) {
77  // Conical cut-out of a cylinder
78  m_outerRmin = cylinderR;
79  m_outerRmax = cylinderR;
80  m_innerTanAlpha = tanAlpha;
81  m_innerRmin = rmin;
82  m_innerRmax = rmax;
83  m_values[eInnerAlpha] = alpha;
84  m_values[eInnerOffsetZ] = offsetZ;
85  } else {
86  throw std::domain_error(
87  "Cylinder and Cone are intersecting, not possible.");
88  }
90  checkConsistency();
91 }
92 
94  const Transform3& transform) const {
95  OrientedSurfaces oSurfaces;
96  oSurfaces.reserve(6);
97 
98  // Create an inner Cone
99  if (m_innerConeBounds != nullptr) {
100  auto innerConeTrans = transform * Translation3(0., 0., -get(eInnerOffsetZ));
101  auto innerCone =
102  Surface::makeShared<ConeSurface>(innerConeTrans, m_innerConeBounds);
103  oSurfaces.push_back(
105  } else if (m_innerCylinderBounds != nullptr) {
106  // Or alternatively the inner Cylinder
107  auto innerCylinder =
108  Surface::makeShared<CylinderSurface>(transform, m_innerCylinderBounds);
109  oSurfaces.push_back(
110  OrientedSurface(std::move(innerCylinder), Direction::Forward));
111  }
112 
113  // Create an outer Cone
114  if (m_outerConeBounds != nullptr) {
115  auto outerConeTrans = transform * Translation3(0., 0., -get(eOuterOffsetZ));
116  auto outerCone =
117  Surface::makeShared<ConeSurface>(outerConeTrans, m_outerConeBounds);
118  oSurfaces.push_back(
120  } else if (m_outerCylinderBounds != nullptr) {
121  // or alternatively an outer Cylinder
122  auto outerCylinder =
123  Surface::makeShared<CylinderSurface>(transform, m_outerCylinderBounds);
124  oSurfaces.push_back(
126  }
127 
128  // Set a disc at Zmin
129  if (m_negativeDiscBounds != nullptr) {
130  auto negativeDiscTrans =
131  transform * Translation3(0., 0., -get(eHalfLengthZ));
132  auto negativeDisc = Surface::makeShared<DiscSurface>(negativeDiscTrans,
134  oSurfaces.push_back(
136  }
137 
138  // Set a disc at Zmax
139  auto positiveDiscTrans = transform * Translation3(0., 0., get(eHalfLengthZ));
140  auto positiveDisc =
141  Surface::makeShared<DiscSurface>(positiveDiscTrans, m_positiveDiscBounds);
142  oSurfaces.push_back(
144 
145  if (m_sectorBounds) {
146  RotationMatrix3 sectorRotation;
147  sectorRotation.col(0) = Vector3::UnitZ();
148  sectorRotation.col(1) = Vector3::UnitX();
149  sectorRotation.col(2) = Vector3::UnitY();
150 
151  Transform3 negSectorRelTrans{sectorRotation};
152  negSectorRelTrans.prerotate(
153  AngleAxis3(get(eAveragePhi) - get(eHalfPhiSector), Vector3::UnitZ()));
154  auto negSectorAbsTrans = transform * negSectorRelTrans;
155  auto negSectorPlane =
156  Surface::makeShared<PlaneSurface>(negSectorAbsTrans, m_sectorBounds);
157  oSurfaces.push_back(
158  OrientedSurface(std::move(negSectorPlane), Direction::Positive));
159 
160  Transform3 posSectorRelTrans{sectorRotation};
161  posSectorRelTrans.prerotate(
162  AngleAxis3(get(eAveragePhi) + get(eHalfPhiSector), Vector3::UnitZ()));
163  auto posSectorAbsTrans = transform * posSectorRelTrans;
164  auto posSectorPlane =
165  Surface::makeShared<PlaneSurface>(posSectorAbsTrans, m_sectorBounds);
166 
167  oSurfaces.push_back(
168  OrientedSurface(std::move(posSectorPlane), Direction::Negative));
169  }
170  return oSurfaces;
171 }
172 
174  if (innerRmin() > outerRmin() or innerRmax() > outerRmax()) {
175  throw std::invalid_argument("ConeVolumeBounds: invalid radial input.");
176  }
177  if (get(eHalfLengthZ) <= 0) {
178  throw std::invalid_argument(
179  "ConeVolumeBounds: invalid longitudinal input.");
180  }
181  if (get(eHalfPhiSector) < 0. or get(eHalfPhiSector) > M_PI) {
182  throw std::invalid_argument("ConeVolumeBounds: invalid phi sector setup.");
183  }
184  if (get(eAveragePhi) != detail::radian_sym(get(eAveragePhi))) {
185  throw std::invalid_argument("ConeVolumeBounds: invalid phi positioning.");
186  }
187  if (get(eInnerAlpha) == 0. and get(eOuterAlpha) == 0.) {
188  throw std::invalid_argument(
189  "ConeVolumeBounds: neither inner nor outer cone.");
190  }
191 }
192 
193 bool Acts::ConeVolumeBounds::inside(const Vector3& pos, double tol) const {
194  double z = pos.z();
195  double zmin = z + tol;
196  double zmax = z - tol;
197  // Quick check outside z
198  if (zmin < -get(eHalfLengthZ) or zmax > get(eHalfLengthZ)) {
199  return false;
200  }
201  double r = VectorHelpers::perp(pos);
202  if (std::abs(get(eHalfPhiSector) - M_PI) > s_onSurfaceTolerance) {
203  // need to check the phi sector - approximate phi tolerance
204  double phitol = tol / r;
205  double phi = VectorHelpers::phi(pos);
206  double phimin = phi - phitol;
207  double phimax = phi + phitol;
208  if (phimin < get(eAveragePhi) - get(eHalfPhiSector) or
209  phimax > get(eAveragePhi) + get(eHalfPhiSector)) {
210  return false;
211  }
212  }
213  // We are within phi sector check box r quickly
214  double rmin = r + tol;
215  double rmax = r - tol;
216  if (rmin > innerRmax() and rmax < outerRmin()) {
217  return true;
218  }
219  // Finally we need to check the cone
220  if (m_innerConeBounds != nullptr) {
221  double innerConeR = m_innerConeBounds->r(std::abs(z + get(eInnerOffsetZ)));
222  if (innerConeR > rmin) {
223  return false;
224  }
225  } else if (innerRmax() > rmin) {
226  return false;
227  }
228  // And the outer cone
229  if (m_outerConeBounds != nullptr) {
230  double outerConeR = m_outerConeBounds->r(std::abs(z + get(eOuterOffsetZ)));
231  if (outerConeR < rmax) {
232  return false;
233  }
234  } else if (outerRmax() < rmax) {
235  return false;
236  }
237  return true;
238 }
239 
241  // Build inner cone or inner cylinder
242  if (get(eInnerAlpha) > s_epsilon) {
243  m_innerTanAlpha = std::tan(get(eInnerAlpha));
244  double innerZmin = get(eInnerOffsetZ) - get(eHalfLengthZ);
245  double innerZmax = get(eInnerOffsetZ) + get(eHalfLengthZ);
246  m_innerRmin = std::abs(innerZmin) * m_innerTanAlpha;
247  m_innerRmax = std::abs(innerZmax) * m_innerTanAlpha;
248  m_innerConeBounds =
249  std::make_shared<ConeBounds>(get(eInnerAlpha), innerZmin, innerZmax,
250  get(eHalfPhiSector), get(eAveragePhi));
251  } else if (m_innerRmin == m_innerRmax and m_innerRmin > s_epsilon) {
252  m_innerCylinderBounds = std::make_shared<CylinderBounds>(
253  m_innerRmin, get(eHalfLengthZ), get(eHalfPhiSector), get(eAveragePhi));
254  }
255 
256  if (get(eOuterAlpha) > s_epsilon) {
257  m_outerTanAlpha = std::tan(get(eOuterAlpha));
258  double outerZmin = get(eOuterOffsetZ) - get(eHalfLengthZ);
259  double outerZmax = get(eOuterOffsetZ) + get(eHalfLengthZ);
260  m_outerRmin = std::abs(outerZmin) * m_outerTanAlpha;
261  m_outerRmax = std::abs(outerZmax) * m_outerTanAlpha;
262  m_outerConeBounds =
263  std::make_shared<ConeBounds>(get(eOuterAlpha), outerZmin, outerZmax,
264  get(eHalfPhiSector), get(eAveragePhi));
265 
266  } else if (m_outerRmin == m_outerRmax) {
267  m_outerCylinderBounds = std::make_shared<CylinderBounds>(
268  m_outerRmax, get(eHalfLengthZ), get(eHalfPhiSector), get(eAveragePhi));
269  }
270 
271  if (get(eHalfLengthZ) < std::max(get(eInnerOffsetZ), get(eOuterOffsetZ))) {
272  m_negativeDiscBounds = std::make_shared<RadialBounds>(
273  m_innerRmin, m_outerRmin, get(eHalfPhiSector), get(eAveragePhi));
274  }
275 
276  m_positiveDiscBounds = std::make_shared<RadialBounds>(
277  m_innerRmax, m_outerRmax, get(eHalfPhiSector), get(eAveragePhi));
278 
279  // Create the sector bounds
280  if (std::abs(get(eHalfPhiSector) - M_PI) > s_epsilon) {
281  // The 4 points building the sector
282  std::vector<Vector2> polyVertices = {{-get(eHalfLengthZ), m_innerRmin},
283  {get(eHalfLengthZ), m_innerRmax},
284  {get(eHalfLengthZ), m_outerRmax},
285  {-get(eHalfLengthZ), m_outerRmin}};
286  m_sectorBounds =
287  std::make_shared<ConvexPolygonBounds<4>>(std::move(polyVertices));
288  }
289 }
290 
291 // ostream operator overload
292 std::ostream& Acts::ConeVolumeBounds::toStream(std::ostream& sl) const {
293  return dumpT(sl);
294 }
295 
297  const Acts::Transform3* trf, const Vector3& envelope,
298  const Volume* entity) const {
299  Vector3 vmin(-outerRmax(), -outerRmax(), -0.5 * get(eHalfLengthZ));
300  Vector3 vmax(outerRmax(), outerRmax(), 0.5 * get(eHalfLengthZ));
301  Volume::BoundingBox box(entity, vmin - envelope, vmax + envelope);
302  return trf == nullptr ? box : box.transformed(*trf);
303 }