File indexing completed on 2026-04-17 08:35:32
0001 #ifndef VECGEOM_SURFACE_EQUATIONS_H_
0002 #define VECGEOM_SURFACE_EQUATIONS_H_
0003
0004 #include <VecGeom/base/Vector3D.h>
0005 #include <VecGeom/base/Math.h>
0006
0007 #include <VecCore/VecCore>
0008 #include <VecGeom/surfaces/base/CommonTypes.h>
0009
0010 namespace vgbrep {
0011
0012 using namespace vecCore::math;
0013
0014 template <typename Real_t>
0015 using Vector3D = vecgeom::Vector3D<Real_t>;
0016
0017
0018 template <typename Real_t>
0019 struct QuadraticCoef {
0020 Real_t phalf{0};
0021 Real_t q{0};
0022 };
0023
0024
0025 template <typename Real_t>
0026 struct QuarticCoef {
0027 Real_t a{0};
0028 Real_t b{0};
0029 Real_t c{0};
0030 Real_t d{0};
0031 };
0032
0033
0034
0035
0036
0037
0038 template <typename Real_t>
0039 VECCORE_ATT_HOST_DEVICE void CylinderEq(Vector3D<Real_t> const &point, Vector3D<Real_t> const &dir, Real_t radius,
0040 QuadraticCoef<Real_t> &coef)
0041 {
0042
0043 Real_t rsq = point.Perp2();
0044 Real_t rdotn = point.x() * dir.x() + point.y() * dir.y();
0045 Real_t invnsq = static_cast<Real_t>(1.) / vecgeom::NonZero(dir.Perp2());
0046
0047 coef.phalf = invnsq * rdotn;
0048 coef.q = invnsq * (rsq - radius * radius);
0049 }
0050
0051
0052
0053
0054
0055
0056
0057 template <typename Real_t>
0058 VECCORE_ATT_HOST_DEVICE void ConeEq(Vector3D<Real_t> const &point, Vector3D<Real_t> const &dir, Real_t radius,
0059 Real_t slope, QuadraticCoef<Real_t> &coef)
0060 {
0061 Real_t rz = radius + point[2] * slope;
0062 Real_t rsq = point.Perp2();
0063 Real_t rdotn = point.x() * dir.x() + point.y() * dir.y() - slope * rz * dir.z();
0064 Real_t invnsq = static_cast<Real_t>(1.) / vecgeom::NonZero(dir.Perp2() - slope * slope * dir.z() * dir.z());
0065
0066 coef.phalf = invnsq * rdotn;
0067 coef.q = invnsq * (rsq - rz * rz);
0068 }
0069
0070
0071
0072
0073
0074
0075 template <typename Real_t>
0076 VECCORE_ATT_HOST_DEVICE void SphereEq(Vector3D<Real_t> const &point, Vector3D<Real_t> const &dir, Real_t radius,
0077 QuadraticCoef<Real_t> &coef)
0078 {
0079 Real_t rsq = point.Mag2();
0080 coef.phalf = point.Dot(dir);
0081 coef.q = rsq - radius * radius;
0082 }
0083
0084 template <typename Real_t>
0085 VECCORE_ATT_HOST_DEVICE void TorusEq(Vector3D<Real_t> const &pt, Vector3D<Real_t> const &dir, const Real_t radius_tor,
0086 const Real_t radius_tube, QuarticCoef<Real_t> &coef)
0087 {
0088
0089
0090
0091
0092
0093
0094 Real_t radius_tor2 = radius_tor * radius_tor;
0095 Real_t radius_tube2 = radius_tube * radius_tube;
0096
0097 Real_t r0sq = pt[0] * pt[0] + pt[1] * pt[1] + pt[2] * pt[2];
0098 Real_t rdotn = pt[0] * dir[0] + pt[1] * dir[1] + pt[2] * dir[2];
0099 Real_t rsumsq = radius_tor2 + radius_tube2;
0100 coef.a = 4. * rdotn;
0101 coef.b = 2. * (r0sq + 2. * rdotn * rdotn - rsumsq + 2. * radius_tor2 * dir[2] * dir[2]);
0102 coef.c = 4. * (r0sq * rdotn - rsumsq * rdotn + 2. * radius_tor2 * pt[2] * dir[2]);
0103 coef.d = r0sq * r0sq - 2. * r0sq * rsumsq + 4. * radius_tor2 * pt[2] * pt[2] +
0104 (radius_tor2 - radius_tube2) * (radius_tor2 - radius_tube2);
0105 };
0106
0107
0108
0109
0110
0111
0112 template <typename Real_t>
0113 VECCORE_ATT_HOST_DEVICE void QuadraticSolver(QuadraticCoef<Real_t> const &coef, Real_t *roots, int &numroots)
0114 {
0115 numroots = 0;
0116 Real_t delta = coef.phalf * coef.phalf - coef.q;
0117 if (delta < Real_t(0)) return;
0118 Real_t r1 = -coef.phalf - Sign(coef.phalf) * Sqrt(delta);
0119 Real_t r2 = coef.q / vecgeom::NonZero(r1);
0120 numroots += int(r1 > -vecgeom::kToleranceStrict<Real_t>) + int(r2 > -vecgeom::kToleranceStrict<Real_t>);
0121 roots[0] = Min(r1, r2);
0122 roots[1] = Max(r1, r2);
0123 if (numroots == 1) roots[0] = roots[1];
0124 }
0125
0126 template <typename Real_t>
0127 VECCORE_ATT_HOST_DEVICE unsigned int SolveCubic(Real_t a, Real_t b, Real_t c, Real_t *x)
0128 {
0129
0130
0131
0132
0133 const Real_t ott = 1. / 3.;
0134 const Real_t sq3 = Sqrt(3.);
0135 const Real_t inv6sq3 = 1. / (6. * sq3);
0136 unsigned int ireal = 1;
0137 Real_t p = b - a * a * ott;
0138 Real_t q = c - a * b * ott + 2. * a * a * a * ott * ott * ott;
0139 Real_t delta = 4 * p * p * p + 27. * q * q;
0140 Real_t t, u;
0141
0142 if (delta >= 0) {
0143 delta = Sqrt(delta);
0144 t = (-3 * q * sq3 + delta) * inv6sq3;
0145 u = (3 * q * sq3 + delta) * inv6sq3;
0146 x[0] = CopySign(Real_t(1.), t) * Cbrt(Abs(t)) - CopySign(Real_t(1.), u) * Cbrt(Abs(u)) - a * ott;
0147 } else {
0148 delta = Sqrt(-delta);
0149 t = -0.5 * q;
0150 u = delta * inv6sq3;
0151 x[0] = 2. * Pow(t * t + u * u, Real_t(0.5) * ott) * cos(ott * ATan2(u, t));
0152 x[0] -= a * ott;
0153 }
0154
0155 t = x[0] * x[0] + a * x[0] + b;
0156 u = a + x[0];
0157 delta = u * u - Real_t(4.) * t;
0158 if (delta >= 0) {
0159 ireal = 3;
0160 delta = Sqrt(delta);
0161 x[1] = Real_t(0.5) * (-u - delta);
0162 x[2] = Real_t(0.5) * (-u + delta);
0163 }
0164
0165 return ireal;
0166 }
0167
0168 template <typename Real_t, unsigned int i, unsigned int j>
0169 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE void CmpAndSwap(Real_t *array)
0170 {
0171 if (array[i] > array[j]) {
0172 Real_t c = array[j];
0173 array[j] = array[i];
0174 array[i] = c;
0175 }
0176 }
0177
0178
0179
0180
0181 template <typename Real_t>
0182 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE void Sort4(Real_t *array)
0183 {
0184 CmpAndSwap<Real_t, 0, 2>(array);
0185 CmpAndSwap<Real_t, 1, 3>(array);
0186 CmpAndSwap<Real_t, 0, 1>(array);
0187 CmpAndSwap<Real_t, 2, 3>(array);
0188 CmpAndSwap<Real_t, 1, 2>(array);
0189 }
0190
0191
0192
0193
0194 template <typename Real_t>
0195 VECCORE_ATT_HOST_DEVICE void QuarticSolver(QuarticCoef<Real_t> const &coef, Real_t *roots, int &numroots)
0196 {
0197
0198
0199
0200
0201 Real_t e = coef.b - 3. * coef.a * coef.a / 8.;
0202 Real_t f = coef.c + coef.a * coef.a * coef.a / 8. - 0.5 * coef.a * coef.b;
0203 Real_t g =
0204 coef.d - 3. * coef.a * coef.a * coef.a * coef.a / 256. + coef.a * coef.a * coef.b / 16. - coef.a * coef.c / 4.;
0205 Real_t xx[4] = {vecgeom::InfinityLength<Real_t>(), vecgeom::InfinityLength<Real_t>(),
0206 vecgeom::InfinityLength<Real_t>(), vecgeom::InfinityLength<Real_t>()};
0207 Real_t delta;
0208 Real_t h = 0.;
0209 numroots = 0;
0210
0211
0212 if (Abs(f) < 1E-6) {
0213 delta = e * e - 4. * g;
0214 if (delta < 0.) return;
0215 delta = Sqrt(delta);
0216 h = 0.5 * (-e - delta);
0217 if (h >= 0) {
0218 h = Sqrt(h);
0219 roots[numroots++] = -h - 0.25 * coef.a;
0220 roots[numroots++] = h - 0.25 * coef.a;
0221 }
0222 h = 0.5 * (-e + delta);
0223 if (h >= 0) {
0224 h = Sqrt(h);
0225 roots[numroots++] = -h - 0.25 * coef.a;
0226 roots[numroots++] = h - 0.25 * coef.a;
0227 }
0228 Sort4(roots);
0229 return;
0230 }
0231
0232 if (Abs(g) < 1E-6) {
0233 roots[numroots++] = -0.25 * coef.a;
0234
0235
0236 unsigned int ncubicroots = SolveCubic<Real_t>(0, e, f, xx);
0237
0238 for (unsigned int i = 0; i < ncubicroots; i++)
0239 roots[numroots++] = xx[i] - 0.25 * coef.a;
0240 Sort4(roots);
0241 return;
0242 }
0243
0244 numroots = SolveCubic<Real_t>(2. * e, e * e - 4. * g, -f * f, xx);
0245 if (numroots == 1) {
0246 if (xx[0] <= 0) return;
0247 h = Sqrt(xx[0]);
0248 } else {
0249
0250 for (unsigned int i = 0; i < 3; i++) {
0251 h = xx[i];
0252 if (h >= 0) break;
0253 }
0254 if (h <= 0) return;
0255 h = Sqrt(h);
0256 }
0257 Real_t j = 0.5 * (e + h * h - f / h);
0258 numroots = 0;
0259 delta = h * h - 4. * j;
0260 if (delta >= 0) {
0261 delta = Sqrt(delta);
0262 roots[numroots++] = 0.5 * (-h - delta) - 0.25 * coef.a;
0263 roots[numroots++] = 0.5 * (-h + delta) - 0.25 * coef.a;
0264 }
0265 delta = h * h - 4. * g / j;
0266 if (delta >= 0) {
0267 delta = Sqrt(delta);
0268 roots[numroots++] = 0.5 * (h - delta) - 0.25 * coef.a;
0269 roots[numroots++] = 0.5 * (h + delta) - 0.25 * coef.a;
0270 }
0271 Sort4(roots);
0272 return;
0273 }
0274
0275 }
0276 #endif