ATLAS Offline Software
CylinderVolumeBounds.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3 */
4 
6 // CylinderVolumeBounds.cxx, (c) ATLAS Detector software
8 
9 // Trk
12 // TrkSurfaces
15 #include "TrkSurfaces/DiscBounds.h"
19 // Gaudi
20 #include "GaudiKernel/MsgStream.h"
21 #include "GaudiKernel/SystemOfUnits.h"
22 
23 // STD
24 #include <cmath>
25 #include <iostream>
26 
28  10e-2 * Gaudi::Units::mm;
29 
31  : VolumeBounds()
32  , m_innerRadius(0.)
33  , m_outerRadius(0.)
34  , m_halfPhiSector(0.)
35  , m_halfZ(0.)
36  , m_boundaryAccessors()
37 {}
38 
40  : VolumeBounds()
41  , m_innerRadius(0.)
42  , m_outerRadius(std::abs(radius))
43  , m_halfPhiSector(M_PI)
44  , m_halfZ(std::abs(halez))
45  , m_boundaryAccessors()
46 {}
47 
49  double rinner,
50  double router,
51  double halez)
52  : VolumeBounds()
53  , m_innerRadius(std::abs(rinner))
54  , m_outerRadius(std::abs(router))
55  , m_halfPhiSector(M_PI)
56  , m_halfZ(std::abs(halez))
57  , m_boundaryAccessors()
58 {}
59 
61  double rinner,
62  double router,
63  double haphi,
64  double halez)
65  : VolumeBounds()
66  , m_innerRadius(std::abs(rinner))
67  , m_outerRadius(std::abs(router))
68  , m_halfPhiSector(haphi)
69  , m_halfZ(std::abs(halez))
70  , m_boundaryAccessors()
71 {}
72 
74  const Trk::CylinderVolumeBounds& cylbo)
75  : VolumeBounds()
76  , m_innerRadius(cylbo.m_innerRadius)
77  , m_outerRadius(cylbo.m_outerRadius)
78  , m_halfPhiSector(cylbo.m_halfPhiSector)
79  , m_halfZ(cylbo.m_halfZ)
80  , m_boundaryAccessors()
81 {}
82 
84 
87 {
88  if (this != &cylbo) {
89  m_innerRadius = cylbo.m_innerRadius;
90  m_outerRadius = cylbo.m_outerRadius;
91  m_halfPhiSector = cylbo.m_halfPhiSector;
92  m_halfZ = cylbo.m_halfZ;
93  }
94  return *this;
95 }
96 
97 std::vector<std::unique_ptr<Trk::Surface>>
100 {
101  auto retsf = std::vector<std::unique_ptr<Trk::Surface>>();
102  // memory optimisation --- reserve the maximum
103  retsf.reserve(6);
104 
105  // check if the transform is approximatively the identity
106  bool isConcentric = transform.isApprox(Amg::Transform3D::Identity());
107 
108  Amg::RotationMatrix3D discRot = transform.linear();
109  Amg::Vector3D cylCenter(transform.translation());
110 
111  // bottom Disc (negative z)
112  Amg::RotationMatrix3D bottomDiscRot;
113  bottomDiscRot.col(0) = discRot.col(1);
114  bottomDiscRot.col(1) = discRot.col(0);
115  bottomDiscRot.col(2) = -discRot.col(2);
116  retsf.push_back(std::make_unique<Trk::DiscSurface>(
118  transform * Amg::AngleAxis3D(M_PI, Amg::Vector3D(1., 0., 0.)) *
119  Amg::Translation3D(Amg::Vector3D(0., 0., halflengthZ()))),
120  bottomDiscBounds()));
121  // top Disc (positive z)
122  retsf.push_back(std::make_unique<Trk::DiscSurface>(
124  topDiscBounds()));
125  // outer Cylinder
126  if (!isConcentric)
127  retsf.push_back(std::make_unique<Trk::CylinderSurface>(
128  Amg::Transform3D(transform), outerCylinderBounds()));
129  else
130  retsf.push_back(std::make_unique<Trk::CylinderSurface>(outerCylinderBounds()));
131 
132  // innermost Cylinder
133  if (innerRadius() > s_numericalStable) {
134  if (!isConcentric)
135  retsf.push_back(std::make_unique<Trk::CylinderSurface>(
136  Amg::Transform3D(transform), innerCylinderBounds()));
137  else
138  retsf.push_back(std::make_unique<Trk::CylinderSurface>(innerCylinderBounds()));
139  }
140 
141  if (std::abs(halfPhiSector() - M_PI) > s_numericalStable) {
142  // sectorPlane 1 (negative phi)
143  retsf.push_back(std::make_unique<Trk::PlaneSurface>(
145  transform *
146  Amg::AngleAxis3D(-halfPhiSector(), Amg::Vector3D(0., 0., 1.)) *
147  Amg::Translation3D(Amg::Vector3D(mediumRadius(), 0., 0.)) *
148  Amg::AngleAxis3D(M_PI / 2, Amg::Vector3D(1., 0., 0.))),
149  sectorPlaneBounds()));
150  // sectorPlane 2 (positive phi)
151  retsf.push_back(std::make_unique<Trk::PlaneSurface>(
153  transform *
154  Amg::AngleAxis3D(halfPhiSector(), Amg::Vector3D(0., 0., 1.)) *
155  Amg::Translation3D(Amg::Vector3D(mediumRadius(), 0., 0.)) *
156  Amg::AngleAxis3D(-M_PI / 2, Amg::Vector3D(1., 0., 0.))),
157  sectorPlaneBounds()));
158  }
159  return retsf;
160 }
161 
164  const Amg::Vector3D& gp,
165  const Amg::Vector3D& dir,
166  bool) const
167 {
168  // the tube case - most likely
169  if (
170  m_innerRadius > s_numericalStable &&
171  std::abs(m_halfPhiSector - M_PI) < s_numericalStable) {
172  // prepare the data
173  double posZ = gp.z();
174  double posR = gp.perp();
175  // difference Vector
176  Amg::Vector3D diff(gp + dir);
177  // differences
178  double deltaZ = diff.z() - posZ;
179  double deltaR = diff.perp() - posR;
180 
181  // the isOnSurface cases + switchers (that change with the cases)
182  bool isOnFace = false;
183  bool intersectionIndicator = (deltaR > 0.);
184  bool choiceIndicator = false;
185 
186  // on surface or look-a-likes
187  // on zMin or slightly outside
188  if (
189  std::abs(posZ + m_halfZ) < s_numericalStable ||
190  (posZ < (-m_halfZ) && deltaZ > 0.)) {
191  isOnFace = true;
192  } else if (
193  std::abs(posZ - m_halfZ) < s_numericalStable ||
194  (posZ > m_halfZ && deltaZ < 0.)) {
195  // on zMax or slighly outside
196  isOnFace = true;
197  } else if (
198  std::abs(posR - m_innerRadius) < s_numericalStable ||
199  (posR < m_innerRadius && deltaR > 0.)) {
200  // on innerRadius or slightly outside
201  isOnFace = true;
202  choiceIndicator =
203  (deltaZ > 0.); // the side choice indicator <========== WRONG ==========
204  } else if (
205  std::abs(posR - m_outerRadius) < s_numericalStable ||
206  (posR > m_outerRadius && deltaR < 0.)) {
207  // on outRadius or slightly outside
208  isOnFace = true;
209  choiceIndicator =
210  (deltaZ > 0.); // the side choice indicator <========== WRONG ==========
211  }
212 
213  // the onSurface case
214  // =================================================================================
215  if (isOnFace) {
216  if (intersectionIndicator) {
217  // intersect the Rmax / with floatint point exception check
218  Trk::CylinderIntersector intersectRmax(
219  posR, posZ, deltaR != 0 ? deltaZ / deltaR : 0, m_outerRadius);
220  double zOfIntersect = intersectRmax.yOfX;
221  // now check if the intersect is inside m_halfZ
222  if (std::abs(zOfIntersect) <= m_halfZ)
223  return {(choiceIndicator || zOfIntersect > 0.)
224  ? m_boundaryAccessors.tubeAccessor(
226  : m_boundaryAccessors.tubeAccessor(
228  // if the intersect is outside
229  return {
230  (choiceIndicator || zOfIntersect > 0.)
231  ? m_boundaryAccessors.tubeAccessor(Trk::TubeZincreaseRincrease)
232  : m_boundaryAccessors.tubeAccessor(
234  }
235  // intersect the Rmin
236  Trk::CylinderIntersector intersectRmin(
237  posR, posZ, deltaR != 0 ? deltaZ / deltaR : 0, m_innerRadius);
238  double zOfIntersect = intersectRmin.yOfX;
239  // now check if the intersect is inside m_halfZ
240  if (std::abs(zOfIntersect) <= m_halfZ)
241  return {
242  (choiceIndicator || zOfIntersect > 0.)
243  ? m_boundaryAccessors.tubeAccessor(Trk::TubeRdecreaseZincrease)
244  : m_boundaryAccessors.tubeAccessor(
246  // if the intersect is outside
247  return {
248  (choiceIndicator || zOfIntersect > 0.)
249  ? m_boundaryAccessors.tubeAccessor(Trk::TubeZincreaseRdecrease)
250  : m_boundaryAccessors.tubeAccessor(Trk::TubeZdecreaseRdecrease)};
251  }
252  // =================================================================================================
253 
254  // ======================= the inside/outside part remains
255  // =========================================
256  // (a) outside cases
257  if (posR < m_innerRadius && deltaR < 0.)
258  return {m_boundaryAccessors.tubeAccessor(Trk::TubeOutsideRminRdecrease)};
259  if (posR > m_outerRadius && deltaR > 0.)
260  return {m_boundaryAccessors.tubeAccessor(Trk::TubeOutsideRmaxRincrease)};
261  if (posZ < -m_halfZ && deltaZ < 0.)
262  return {m_boundaryAccessors.tubeAccessor(Trk::TubeOutsideZminZdecrease)};
263  if (posZ > m_halfZ && deltaZ > 0.)
264  return {m_boundaryAccessors.tubeAccessor(Trk::TubeOutsideZmaxZincrease)};
265  // (b) inside cases
266  // the increase R case
267  if (deltaR > 0.) {
268  // solve the linear equation for the outer Radius - with floating point
269  // exception check
270  Trk::CylinderIntersector intersectRmax(
271  posR, posZ, deltaR != 0 ? deltaZ / deltaR : 0, m_outerRadius);
272  double zOfIntersect = intersectRmax.yOfX;
273 
274  if (std::abs(zOfIntersect) <= m_halfZ && zOfIntersect > 0.)
275  return {m_boundaryAccessors.tubeAccessor(Trk::TubeRincreaseZincrease)};
276  if (std::abs(zOfIntersect) <= m_halfZ && zOfIntersect < 0.)
277  return {m_boundaryAccessors.tubeAccessor(Trk::TubeRincreaseZdecrease)};
278  if (std::abs(zOfIntersect) > m_halfZ && zOfIntersect < 0.)
279  return {m_boundaryAccessors.tubeAccessor(Trk::TubeZdecreaseRincrease)};
280  if (std::abs(zOfIntersect) > m_halfZ && zOfIntersect > 0.)
281  return {m_boundaryAccessors.tubeAccessor(Trk::TubeZincreaseRincrease)};
282 
283  } else {
284  // solve the linear equation for the inner Radius with floating point
285  // exceptin check
286  Trk::CylinderIntersector intersectRmin(
287  posR, posZ, deltaR != 0 ? deltaZ / deltaR : 0, m_innerRadius);
288  double zOfIntersect = intersectRmin.yOfX;
289 
290  if (std::abs(zOfIntersect) <= m_halfZ && zOfIntersect > 0.)
291  return {m_boundaryAccessors.tubeAccessor(Trk::TubeRdecreaseZincrease)};
292  if (std::abs(zOfIntersect) <= m_halfZ && zOfIntersect < 0.)
293  return {m_boundaryAccessors.tubeAccessor(Trk::TubeRdecreaseZdecrease)};
294  if (std::abs(zOfIntersect) > m_halfZ && zOfIntersect > 0.)
295  return {m_boundaryAccessors.tubeAccessor(Trk::TubeZincreaseRdecrease)};
296  return {m_boundaryAccessors.tubeAccessor(Trk::TubeZdecreaseRdecrease)};
297  }
298  }
299  // the cylinder case
300  if (
301  m_innerRadius < s_numericalStable &&
302  std::abs(m_halfPhiSector - M_PI) < s_numericalStable) {
303 
304  // ----------------------------- z / r information
305  double posZ = gp.z();
306  double posR = gp.perp();
307 
308  // is on R case
309  bool isOnCylinder = (std::abs(posR - m_outerRadius) < s_numericalStable);
310 
311  // difference Vector
312  Amg::Vector3D diff(gp + dir);
313  // differences
314  double deltaZ = diff.z() - posZ;
315  double deltaR = diff.perp() - posR;
316  // take the sign of the intersect
317  int radiusSign = deltaR > 0. ? 1 : -1;
318 
319  // solve the linear equation for the cylinder Radius / with floating point
320  // exceptin check
321  Trk::CylinderIntersector intersectR(
322  posR,
323  posZ,
324  deltaR != 0 ? deltaZ / deltaR : 0,
325  radiusSign * m_outerRadius);
326 
327  // the intersection point - a little trick for the OnFace cases
328  double zOfIntersect = intersectR.yOfX;
329  // check if intersection exists
330  bool intersectsCylinder =
331  !isOnCylinder ? (zOfIntersect * zOfIntersect <= m_halfZ * m_halfZ)
332  : false;
333 
334  // return the cases for going through the cylinder
335  if (intersectsCylinder && zOfIntersect > 0.)
336  return {m_boundaryAccessors.cylinderAccessor(Trk::CylinderZincrease)};
337  if (intersectsCylinder && zOfIntersect <= 0.)
338  return {m_boundaryAccessors.cylinderAccessor(Trk::CylinderZdecrease)};
339  if (deltaZ > 0.)
340  return {m_boundaryAccessors.cylinderAccessor(Trk::CylinderPositiveFace)};
341  return {m_boundaryAccessors.cylinderAccessor(Trk::CylinderNegativeFace)};
342  }
343  // the sectoral cylinder case
344  if (m_innerRadius != 0. && std::abs(m_halfPhiSector - M_PI) > 10e-3)
345  return {m_boundaryAccessors.sectoralCylinderAccessor(
347  // it remains the sectoral tube case
348  return {m_boundaryAccessors.sectoralTubeAccessor(Trk::StandardSectoralTube)};
349 }
350 
351 std::shared_ptr<Trk::CylinderBounds>
353 {
354  return std::make_shared<Trk::CylinderBounds>(m_innerRadius, m_halfPhiSector, m_halfZ);
355 }
356 
357 std::shared_ptr<Trk::CylinderBounds>
359 {
360  return std::make_shared<Trk::CylinderBounds>(m_outerRadius, m_halfPhiSector, m_halfZ);
361 }
362 
363 std::shared_ptr<Trk::DiscBounds>
365 {
366  return std::make_shared<Trk::DiscBounds>(m_innerRadius, m_outerRadius, m_halfPhiSector);
367 }
368 
369 std::shared_ptr<Trk::RectangleBounds>
371 {
372  return std::make_shared<Trk::RectangleBounds>(
373  0.5 * (m_outerRadius - m_innerRadius), m_halfZ);
374 }
375 
376 // ostream operator overload
377 
378 MsgStream&
380 {
381  std::stringstream temp_sl;
382  temp_sl << std::setiosflags(std::ios::fixed);
383  temp_sl << std::setprecision(2);
384  temp_sl << "Trk::CylinderVolumeBounds: (rMin, rMax, halfPhi, halfZ) = ";
385  temp_sl << m_innerRadius << ", " << m_outerRadius << ", " << m_halfPhiSector
386  << ", " << m_halfZ;
387  sl << temp_sl.str();
388  return sl;
389 }
390 
391 std::ostream&
392 Trk::CylinderVolumeBounds::dump(std::ostream& sl) const
393 {
394  std::stringstream temp_sl;
395  temp_sl << std::setiosflags(std::ios::fixed);
396  temp_sl << std::setprecision(2);
397  temp_sl << "Trk::CylinderVolumeBounds: (rMin, rMax, halfPhi, halfZ) = ";
398  temp_sl << m_innerRadius << ", " << m_outerRadius << ", " << m_halfPhiSector
399  << ", " << m_halfZ;
400  sl << temp_sl.str();
401  return sl;
402 }
403 
Trk::CylinderVolumeBounds::~CylinderVolumeBounds
virtual ~CylinderVolumeBounds()
Destructor.
Trk::CylinderVolumeBounds::outerCylinderBounds
std::shared_ptr< CylinderBounds > outerCylinderBounds() const
This method returns the associated CylinderBounds of the outer CylinderSurfaces.
Definition: CylinderVolumeBounds.cxx:358
Trk::TubeRdecreaseZdecrease
@ TubeRdecreaseZdecrease
Accessor type [ 3,0,1,2 ].
Definition: CylinderVolumeBoundaryAccessors.h:33
AllowedVariables::e
e
Definition: AsgElectronSelectorTool.cxx:37
Trk::TubeOutsideRmaxRincrease
@ TubeOutsideRmaxRincrease
Accessor type [ 2,1,0,3 ] - inverse case.
Definition: CylinderVolumeBoundaryAccessors.h:37
python.SystemOfUnits.mm
float mm
Definition: SystemOfUnits.py:98
DiscBounds.h
RectangleBounds.h
Trk::CylinderVolumeBounds::sectorPlaneBounds
std::shared_ptr< RectangleBounds > sectorPlaneBounds() const
This method returns the associated PlaneBounds limiting a sectoral CylinderVolume.
Definition: CylinderVolumeBounds.cxx:370
Trk::TubeZdecreaseRdecrease
@ TubeZdecreaseRdecrease
Accessor type [ 0,3,1,2 ].
Definition: CylinderVolumeBoundaryAccessors.h:35
CylinderIntersector.h
Trk::CylinderVolumeBounds::m_halfZ
double m_halfZ
Definition: CylinderVolumeBounds.h:160
M_PI
#define M_PI
Definition: ActiveFraction.h:11
mc.diff
diff
Definition: mc.SFGenPy8_MuMu_DD.py:14
Trk::TubeOutsideZmaxZincrease
@ TubeOutsideZmaxZincrease
Accessor type [ 1,3,2,0 ] - inverse case.
Definition: CylinderVolumeBoundaryAccessors.h:39
Trk::CylinderVolumeBounds::dump
MsgStream & dump(MsgStream &sl) const override final
Output Method for MsgStream.
Definition: CylinderVolumeBounds.cxx:379
Trk::CylinderVolumeBounds::m_halfPhiSector
double m_halfPhiSector
Definition: CylinderVolumeBounds.h:159
Trk::TubeRincreaseZdecrease
@ TubeRincreaseZdecrease
Accessor type [ 2,0,1,3 ].
Definition: CylinderVolumeBoundaryAccessors.h:29
Trk::CylinderVolumeBounds::CylinderVolumeBounds
CylinderVolumeBounds()
Default Constructor.
Definition: CylinderVolumeBounds.cxx:30
Trk::VolumeBounds
Definition: VolumeBounds.h:45
Trk::StandardSectoralCylinder
@ StandardSectoralCylinder
Definition: CylinderVolumeBoundaryAccessors.h:46
CylinderVolumeBounds.h
Trk::CylinderVolumeBounds::m_outerRadius
double m_outerRadius
Definition: CylinderVolumeBounds.h:158
Trk::CylinderVolumeBounds::boundarySurfaceAccessor
ObjectAccessor boundarySurfaceAccessor(const Amg::Vector3D &gp, const Amg::Vector3D &dir, bool forceInside=false) const override final
Provide accessor for BoundarySurfaces.
Definition: CylinderVolumeBounds.cxx:163
Trk::CylinderIntersector
Definition: CylinderIntersector.h:20
Trk::CylinderVolumeBounds::bottomDiscBounds
std::shared_ptr< DiscBounds > bottomDiscBounds() const
This method returns the associated DiscBounds for the bottom/top DiscSurface.
Definition: CylinderVolumeBounds.cxx:364
beamspotman.posZ
posZ
Definition: beamspotman.py:1622
Amg::Transform3D
Eigen::Affine3d Transform3D
Definition: GeoPrimitives.h:46
Amg::transform
Amg::Vector3D transform(Amg::Vector3D &v, Amg::Transform3D &tr)
Transform a point from a Trasformation3D.
Definition: GeoPrimitivesHelpers.h:156
CylinderSurface.h
Trk::TubeZdecreaseRincrease
@ TubeZdecreaseRincrease
Accessor type [ 0,2,1,3 ].
Definition: CylinderVolumeBoundaryAccessors.h:31
Trk::CylinderZdecrease
@ CylinderZdecrease
Cylinder hit, the neg.
Definition: CylinderVolumeBoundaryAccessors.h:19
Trk::CylinderIntersector::yOfX
double yOfX
the result of x
Definition: CylinderIntersector.h:22
Trk::CylinderVolumeBounds::decomposeToSurfaces
virtual std::vector< std::unique_ptr< Trk::Surface > > decomposeToSurfaces(const Amg::Transform3D &transform) override final
Method to decompose the Bounds into boundarySurfaces.
Definition: CylinderVolumeBounds.cxx:99
Trk::TubeRdecreaseZincrease
@ TubeRdecreaseZincrease
Accessor type [ 3,1,0,2 ].
Definition: CylinderVolumeBoundaryAccessors.h:32
Trk::CylinderVolumeBounds::m_innerRadius
double m_innerRadius
Definition: CylinderVolumeBounds.h:157
beamspotman.dir
string dir
Definition: beamspotman.py:621
Trk::CylinderNegativeFace
@ CylinderNegativeFace
Neg.
Definition: CylinderVolumeBoundaryAccessors.h:21
Trk::CylinderVolumeBounds
Definition: CylinderVolumeBounds.h:70
Trk::StandardSectoralTube
@ StandardSectoralTube
Definition: CylinderVolumeBoundaryAccessors.h:51
Amg::Vector3D
Eigen::Matrix< double, 3, 1 > Vector3D
Definition: GeoPrimitives.h:47
Trk::TubeRincreaseZincrease
@ TubeRincreaseZincrease
Accessor type [ 2,1,0,3 ].
Definition: CylinderVolumeBoundaryAccessors.h:28
ParticleGun_SamplingFraction.radius
radius
Definition: ParticleGun_SamplingFraction.py:96
Trk::ObjectAccessor
Definition: ObjectAccessor.h:15
CylinderBounds.h
Trk::CylinderVolumeBounds::innerCylinderBounds
std::shared_ptr< CylinderBounds > innerCylinderBounds() const
This method returns the associated CylinderBounds of the inner CylinderSurfaces.
Definition: CylinderVolumeBounds.cxx:352
Amg::RotationMatrix3D
Eigen::Matrix< double, 3, 3 > RotationMatrix3D
Definition: GeoPrimitives.h:49
PlaneSurface.h
Trk::TubeZincreaseRdecrease
@ TubeZincreaseRdecrease
Accessor type [ 1,3,0,2 ].
Definition: CylinderVolumeBoundaryAccessors.h:34
Amg::Translation3D
Eigen::Translation< double, 3 > Translation3D
Definition: GeoPrimitives.h:44
DiscSurface.h
Trk::CylinderPositiveFace
@ CylinderPositiveFace
Pos.
Definition: CylinderVolumeBoundaryAccessors.h:20
Amg::AngleAxis3D
Eigen::AngleAxisd AngleAxis3D
Definition: GeoPrimitives.h:45
Trk::CylinderZincrease
@ CylinderZincrease
Cylinder hit, then pos.
Definition: CylinderVolumeBoundaryAccessors.h:18
Trk::CylinderVolumeBounds::s_numericalStable
static const double s_numericalStable
numerical stability
Definition: CylinderVolumeBounds.h:168
Trk::TubeOutsideRminRdecrease
@ TubeOutsideRminRdecrease
Accessor type [ 3,1,0,2] - inverse case.
Definition: CylinderVolumeBoundaryAccessors.h:36
makeComparison.deltaZ
int deltaZ
Definition: makeComparison.py:46
Trk::CylinderVolumeBounds::operator=
CylinderVolumeBounds & operator=(const CylinderVolumeBounds &cylbo)
Assignment operator.
Definition: CylinderVolumeBounds.cxx:86
Trk::TubeOutsideZminZdecrease
@ TubeOutsideZminZdecrease
Accessor type [ 0,3,2,1 ] - inverse case.
Definition: CylinderVolumeBoundaryAccessors.h:38
makeComparison.deltaR
float deltaR
Definition: makeComparison.py:36
Trk::TubeZincreaseRincrease
@ TubeZincreaseRincrease
Accessor type [ 1,2,0,3 ].
Definition: CylinderVolumeBoundaryAccessors.h:30