File indexing completed on 2025-09-17 09:18:24
0001
0002
0003
0004
0005 #ifndef VECGEOM_VOLUMES_KERNEL_SPHEREIMPLEMENTATION_H_
0006 #define VECGEOM_VOLUMES_KERNEL_SPHEREIMPLEMENTATION_H_
0007
0008 #include "VecGeom/base/Vector3D.h"
0009 #include "VecGeom/volumes/SphereStruct.h"
0010 #include "VecGeom/volumes/kernel/GenericKernels.h"
0011 #include <VecCore/VecCore>
0012 #include "VecGeom/volumes/kernel/OrbImplementation.h"
0013 #include "VecGeom/volumes/SphereUtilities.h"
0014
0015 #include <cstdio>
0016
0017 namespace vecgeom {
0018
0019 VECGEOM_DEVICE_FORWARD_DECLARE(struct SphereImplementation;);
0020 VECGEOM_DEVICE_DECLARE_CONV(struct, SphereImplementation);
0021
0022 inline namespace VECGEOM_IMPL_NAMESPACE {
0023
0024 class PlacedSphere;
0025 template <typename T>
0026 struct SphereStruct;
0027 class UnplacedSphere;
0028
0029 struct SphereImplementation {
0030
0031 using PlacedShape_t = PlacedSphere;
0032 using UnplacedStruct_t = SphereStruct<Precision>;
0033 using UnplacedVolume_t = UnplacedSphere;
0034
0035 VECCORE_ATT_HOST_DEVICE
0036 static void PrintType()
0037 {
0038
0039 }
0040
0041 template <typename Stream>
0042 static void PrintType(Stream &st, int transCodeT = translation::kGeneric, int rotCodeT = rotation::kGeneric)
0043 {
0044 st << "SpecializedSphere<" << transCodeT << "," << rotCodeT << ">";
0045 }
0046
0047 template <typename Stream>
0048 static void PrintImplementationType(Stream &st)
0049 {
0050 (void)st;
0051
0052 }
0053
0054 template <typename Stream>
0055 static void PrintUnplacedType(Stream &st)
0056 {
0057 (void)st;
0058
0059
0060 }
0061
0062 template <typename Real_v, typename Bool_v>
0063 VECGEOM_FORCE_INLINE
0064 VECCORE_ATT_HOST_DEVICE
0065 static void Contains(UnplacedStruct_t const &sphere, Vector3D<Real_v> const &point, Bool_v &inside)
0066 {
0067 Bool_v unused, outside;
0068 GenericKernelForContainsAndInside<Real_v, Bool_v, false>(sphere, point, unused, outside);
0069 inside = !outside;
0070 }
0071
0072
0073
0074 template <typename Real_v, typename Inside_t>
0075 VECGEOM_FORCE_INLINE
0076 VECCORE_ATT_HOST_DEVICE
0077 static void Inside(UnplacedStruct_t const &sphere, Vector3D<Real_v> const &point, Inside_t &inside)
0078 {
0079
0080 using Bool_v = vecCore::Mask_v<Real_v>;
0081 using InsideBool_v = vecCore::Mask_v<Inside_t>;
0082 Bool_v completelyinside, completelyoutside;
0083 GenericKernelForContainsAndInside<Real_v, Bool_v, true>(sphere, point, completelyinside, completelyoutside);
0084 inside = EInside::kSurface;
0085 vecCore::MaskedAssign(inside, (InsideBool_v)completelyoutside, Inside_t(EInside::kOutside));
0086 vecCore::MaskedAssign(inside, (InsideBool_v)completelyinside, Inside_t(EInside::kInside));
0087 }
0088
0089 template <typename Real_v, typename Bool_v, bool ForInside>
0090 VECGEOM_FORCE_INLINE
0091 VECCORE_ATT_HOST_DEVICE
0092 static void GenericKernelForContainsAndInside(UnplacedStruct_t const &sphere, Vector3D<Real_v> const &localPoint,
0093 Bool_v &completelyinside, Bool_v &completelyoutside)
0094 {
0095 Real_v rad2 = localPoint.Mag2();
0096
0097
0098
0099 if (sphere.fRmin)
0100 completelyinside = rad2 <= MakeMinusTolerantSquare<true>(sphere.fRmax) &&
0101 rad2 >= MakePlusTolerantSquare<true>(sphere.fRmin);
0102 else
0103 completelyinside = rad2 <= MakeMinusTolerantSquare<true>(sphere.fRmax);
0104
0105 if (sphere.fRmin)
0106 completelyoutside = rad2 >= MakePlusTolerantSquare<true>(sphere.fRmax) ||
0107 rad2 <= MakeMinusTolerantSquare<true>(sphere.fRmin);
0108 else
0109 completelyoutside = rad2 >= MakePlusTolerantSquare<true>(sphere.fRmax);
0110
0111
0112 if (!sphere.fFullPhiSphere) {
0113
0114 Bool_v completelyoutsidephi(false);
0115 Bool_v completelyinsidephi(false);
0116 sphere.fPhiWedge.GenericKernelForContainsAndInside<Real_v, ForInside>(localPoint, completelyinsidephi,
0117 completelyoutsidephi);
0118 completelyoutside |= completelyoutsidephi;
0119
0120 if (ForInside) completelyinside &= completelyinsidephi;
0121 }
0122
0123
0124
0125 if (!sphere.fFullThetaSphere) {
0126
0127 Bool_v completelyoutsidetheta(false);
0128 Bool_v completelyinsidetheta(false);
0129 sphere.fThetaCone.GenericKernelForContainsAndInside<Real_v, ForInside>(localPoint, completelyinsidetheta,
0130 completelyoutsidetheta);
0131 completelyoutside |= completelyoutsidetheta;
0132
0133 if (ForInside) completelyinside &= completelyinsidetheta;
0134 }
0135 return;
0136 }
0137
0138 template <typename Real_v>
0139 VECGEOM_FORCE_INLINE
0140 VECCORE_ATT_HOST_DEVICE
0141 static void DistanceToIn(UnplacedStruct_t const &sphere, Vector3D<Real_v> const &point,
0142 Vector3D<Real_v> const &direction, Real_v const & , Real_v &distance)
0143 {
0144 using Bool_v = vecCore::Mask_v<Real_v>;
0145 distance = kInfLength;
0146
0147 Bool_v done(false);
0148
0149 bool fullPhiSphere = sphere.fFullPhiSphere;
0150 bool fullThetaSphere = sphere.fFullThetaSphere;
0151
0152 Vector3D<Real_v> tmpPt;
0153
0154 Real_v rad2 = point.Mag2();
0155 Real_v pDotV3d = point.Dot(direction);
0156
0157 Real_v c = rad2 - sphere.fRmax * sphere.fRmax;
0158
0159 Bool_v cond = SphereUtilities::IsCompletelyInside<Real_v>(sphere, point);
0160 vecCore__MaskedAssignFunc(distance, cond, Real_v(-1.0));
0161 done |= cond;
0162 if (vecCore::MaskFull(done)) return;
0163
0164 cond = SphereUtilities::IsPointOnSurfaceAndMovingOut<Real_v, false>(sphere, point, direction);
0165 vecCore__MaskedAssignFunc(distance, !done && cond, Real_v(0.0));
0166 done |= cond;
0167 if (vecCore::MaskFull(done)) return;
0168
0169 Real_v sd1(kInfLength);
0170 Real_v sd2(kInfLength);
0171 Real_v d2 = (pDotV3d * pDotV3d - c);
0172 cond = (d2 < Real_v(0.) || ((c > Real_v(0.)) && (pDotV3d > Real_v(0.))));
0173 done |= cond;
0174 if (vecCore::MaskFull(done)) return;
0175
0176
0177 vecCore__MaskedAssignFunc(sd1, d2 >= Real_v(0.), (-pDotV3d - Sqrt(Abs(d2))));
0178
0179 Real_v outerDist(kInfLength);
0180 Real_v innerDist(kInfLength);
0181
0182 if (sphere.fFullSphere) {
0183 vecCore::MaskedAssign(outerDist, !done && (sd1 >= Real_v(-kTolerance)), sd1);
0184 } else {
0185 tmpPt = point + sd1 * direction;
0186 vecCore::MaskedAssign(outerDist,
0187 !done && (sd1 >= Real_v(-kTolerance) && sd1 < Real_v(kInfLength))
0188 && sphere.fPhiWedge.Contains<Real_v>(tmpPt)
0189 && sphere.fThetaCone.Contains<Real_v>(tmpPt),
0190 sd1);
0191 }
0192
0193 if (sphere.fRmin) {
0194 c = rad2 - sphere.fRmin * sphere.fRmin;
0195 d2 = pDotV3d * pDotV3d - c;
0196
0197 vecCore__MaskedAssignFunc(sd2, d2 >= Real_v(0.), (-pDotV3d + Sqrt(Abs(d2))));
0198
0199 if (sphere.fFullSphere) {
0200 vecCore::MaskedAssign(innerDist, !done && (sd2 >= Real_v(-kTolerance)), sd2);
0201 } else {
0202
0203 tmpPt = point + sd2 * direction;
0204 vecCore::MaskedAssign(innerDist,
0205 !done && (sd2 >= Real_v(-kTolerance) && sd2 < Real_v(kInfLength))
0206 && sphere.fPhiWedge.Contains<Real_v>(tmpPt)
0207 && sphere.fThetaCone.Contains<Real_v>(tmpPt),
0208 sd2);
0209 }
0210 }
0211
0212 distance = Min(outerDist, innerDist);
0213
0214 if (!fullPhiSphere) {
0215 GetMinDistFromPhi<Real_v, true>(sphere, point, direction, done, distance);
0216 }
0217
0218 Real_v distThetaMin(kInfLength);
0219
0220 if (!fullThetaSphere) {
0221 Bool_v intsect1(false);
0222 Bool_v intsect2(false);
0223 Real_v distTheta1(kInfLength);
0224 Real_v distTheta2(kInfLength);
0225
0226 sphere.fThetaCone.DistanceToIn<Real_v>(point, direction, distTheta1, distTheta2, intsect1,
0227 intsect2);
0228 Vector3D<Real_v> coneIntSecPt1 = point + distTheta1 * direction;
0229 Real_v distCone1 = coneIntSecPt1.Mag2();
0230
0231 Vector3D<Real_v> coneIntSecPt2 = point + distTheta2 * direction;
0232 Real_v distCone2 = coneIntSecPt2.Mag2();
0233
0234 Bool_v isValidCone1 =
0235 (distCone1 >= sphere.fRmin * sphere.fRmin && distCone1 <= sphere.fRmax * sphere.fRmax) && intsect1;
0236 Bool_v isValidCone2 =
0237 (distCone2 >= sphere.fRmin * sphere.fRmin && distCone2 <= sphere.fRmax * sphere.fRmax) && intsect2;
0238
0239 if (!fullPhiSphere) {
0240 isValidCone1 &= sphere.fPhiWedge.Contains<Real_v>(coneIntSecPt1);
0241 isValidCone2 &= sphere.fPhiWedge.Contains<Real_v>(coneIntSecPt2);
0242 }
0243 vecCore::MaskedAssign(distThetaMin, (!done && isValidCone2 && !isValidCone1), distTheta2);
0244 vecCore::MaskedAssign(distThetaMin, (!done && isValidCone1 && !isValidCone2), distTheta1);
0245 vecCore__MaskedAssignFunc(distThetaMin, (!done && isValidCone1 && isValidCone2), Min(distTheta1, distTheta2));
0246 }
0247
0248 distance = Min(distThetaMin, distance);
0249
0250 Vector3D<Real_v> directDir = (Vector3D<Real_v>(0., 0., 0.) - point);
0251 Real_v newDist = directDir.Mag();
0252 vecCore__MaskedAssignFunc(distance,
0253 Bool_v(sphere.fSTheta > kHalfTolerance || sphere.eTheta < (kPi - kHalfTolerance)) &&
0254 (Abs(directDir.Unit().x() - direction.x()) < kHalfTolerance) &&
0255 (Abs(directDir.Unit().y() - direction.y()) < kHalfTolerance) &&
0256 (Abs(directDir.Unit().z() - direction.z()) < kHalfTolerance),
0257 Min(distance, newDist));
0258 }
0259
0260 template <typename Real_v>
0261 VECGEOM_FORCE_INLINE
0262 VECCORE_ATT_HOST_DEVICE
0263 static void DistanceToOut(UnplacedStruct_t const &sphere, Vector3D<Real_v> const &point,
0264 Vector3D<Real_v> const &direction, Real_v const & , Real_v &distance)
0265 {
0266
0267 using Bool_v = typename vecCore::Mask_v<Real_v>;
0268
0269 distance = kInfLength;
0270 Bool_v done(false);
0271
0272 Real_v snxt(kInfLength);
0273
0274
0275 Vector3D<Real_v> intSecPt;
0276 Real_v d2(0.);
0277
0278 Real_v pDotV3d = point.Dot(direction);
0279
0280 Real_v rad2 = point.Mag2();
0281 Real_v c = rad2 - sphere.fRmax * sphere.fRmax;
0282
0283 Real_v sd1(kInfLength);
0284 Real_v sd2(kInfLength);
0285
0286 Bool_v cond = SphereUtilities::IsCompletelyOutside<Real_v>(sphere, point);
0287 vecCore__MaskedAssignFunc(distance, cond, Real_v(-1.0));
0288
0289 done |= cond;
0290 if (vecCore::MaskFull(done)) return;
0291
0292 cond = SphereUtilities::IsPointOnSurfaceAndMovingOut<Real_v, true>(sphere, point, direction);
0293 vecCore__MaskedAssignFunc(distance, !done && cond, Real_v(0.0));
0294 done |= cond;
0295 if (vecCore::MaskFull(done)) return;
0296
0297
0298 d2 = (pDotV3d * pDotV3d - c);
0299 vecCore__MaskedAssignFunc(sd1, (!done && (d2 >= Real_v(0.))), (-pDotV3d + Sqrt(Abs(d2))));
0300
0301 if (sphere.fRmin) {
0302 c = rad2 - sphere.fRmin * sphere.fRmin;
0303 d2 = (pDotV3d * pDotV3d - c);
0304 vecCore__MaskedAssignFunc(sd2, (!done && (d2 >= Real_v(0.)) && (pDotV3d < Real_v(0.))),
0305 (-pDotV3d - Sqrt(Abs(d2))));
0306 }
0307
0308 snxt = Min(sd1, sd2);
0309
0310 Bool_v condSemi = (Bool_v(sphere.fSTheta == 0. && sphere.eTheta == kPi / 2.) && direction.z() >= Real_v(0.)) ||
0311 (Bool_v(sphere.fSTheta == kPi / 2. && sphere.eTheta == kPi) && direction.z() <= Real_v(0.));
0312 vecCore::MaskedAssign(distance, !done && condSemi, snxt);
0313 done |= condSemi;
0314 if (vecCore::MaskFull(done)) return;
0315
0316 Real_v distThetaMin(kInfLength);
0317 Real_v distPhiMin(kInfLength);
0318
0319 if (!sphere.fFullThetaSphere) {
0320 Bool_v intsect1(false);
0321 Bool_v intsect2(false);
0322 Real_v distTheta1(kInfLength);
0323 Real_v distTheta2(kInfLength);
0324 sphere.fThetaCone.DistanceToOut<Real_v>(point, direction, distTheta1, distTheta2, intsect1, intsect2);
0325 vecCore::MaskedAssign(distThetaMin, (intsect2 && !intsect1), distTheta2);
0326 vecCore::MaskedAssign(distThetaMin, (!intsect2 && intsect1), distTheta1);
0327 vecCore__MaskedAssignFunc(distThetaMin, (intsect2 && intsect1), Min(distTheta1, distTheta2));
0328 }
0329
0330 distance = Min(distThetaMin, snxt);
0331
0332 if (!sphere.fFullPhiSphere) {
0333 if (sphere.fDPhi <= kPi) {
0334 Real_v distPhi1;
0335 Real_v distPhi2;
0336 sphere.fPhiWedge.DistanceToOut<Real_v>(point, direction, distPhi1, distPhi2);
0337 distPhiMin = Min(distPhi1, distPhi2);
0338 distance = Min(distPhiMin, distance);
0339 } else {
0340 GetMinDistFromPhi<Real_v, false>(sphere, point, direction, done, distance);
0341 }
0342 }
0343 }
0344
0345 template <typename Real_v, bool DistToIn>
0346 VECCORE_ATT_HOST_DEVICE
0347 static void GetMinDistFromPhi(UnplacedStruct_t const &sphere, Vector3D<Real_v> const &localPoint,
0348 Vector3D<Real_v> const &localDir, typename vecCore::Mask_v<Real_v> &done,
0349 Real_v &distance)
0350 {
0351 using Bool_v = typename vecCore::Mask_v<Real_v>;
0352 Real_v distPhi1(kInfLength);
0353 Real_v distPhi2(kInfLength);
0354 Real_v dist(kInfLength);
0355
0356 if (DistToIn)
0357 sphere.fPhiWedge.DistanceToIn<Real_v>(localPoint, localDir, distPhi1, distPhi2);
0358 else
0359 sphere.fPhiWedge.DistanceToOut<Real_v>(localPoint, localDir, distPhi1, distPhi2);
0360
0361 Bool_v containsCond1(false), containsCond2(false);
0362
0363 dist = Min(distPhi1, distPhi2);
0364 Vector3D<Real_v> tmpPt = localPoint + dist * localDir;
0365 Real_v rad2 = tmpPt.Mag2();
0366
0367 Bool_v tempCond(false);
0368 tempCond = ((dist == distPhi1) && sphere.fPhiWedge.IsOnSurfaceGeneric<Real_v, true>(tmpPt)) ||
0369 ((dist == distPhi2) && sphere.fPhiWedge.IsOnSurfaceGeneric<Real_v, false>(tmpPt));
0370
0371 containsCond1 = tempCond && (rad2 > sphere.fRmin * sphere.fRmin) && (rad2 < sphere.fRmax * sphere.fRmax) &&
0372 sphere.fThetaCone.Contains<Real_v>(tmpPt);
0373
0374 vecCore__MaskedAssignFunc(distance, !done && containsCond1, Min(dist, distance));
0375
0376
0377 dist = Max(distPhi1, distPhi2);
0378 tmpPt = localPoint + dist * localDir;
0379
0380 rad2 = tmpPt.Mag2();
0381 tempCond = Bool_v(false);
0382 tempCond = ((dist == distPhi1) && sphere.fPhiWedge.IsOnSurfaceGeneric<Real_v, true>(tmpPt)) ||
0383 ((dist == distPhi2) && sphere.fPhiWedge.IsOnSurfaceGeneric<Real_v, false>(tmpPt));
0384
0385 containsCond2 = tempCond && (rad2 > sphere.fRmin * sphere.fRmin) && (rad2 < sphere.fRmax * sphere.fRmax) &&
0386 sphere.fThetaCone.Contains<Real_v>(tmpPt);
0387 vecCore__MaskedAssignFunc(distance, ((!done) && (!containsCond1) && containsCond2), Min(dist, distance));
0388 }
0389
0390 template <typename Real_v>
0391 VECGEOM_FORCE_INLINE
0392 VECCORE_ATT_HOST_DEVICE
0393 static void SafetyToIn(UnplacedStruct_t const &sphere, Vector3D<Real_v> const &point, Real_v &safety)
0394 {
0395 using Bool_v = vecCore::Mask_v<Real_v>;
0396 Bool_v done(false);
0397
0398
0399 Real_v rad = point.Mag();
0400
0401 Real_v safeRMin(0.);
0402 Real_v safeRMax(0.);
0403
0404 Bool_v completelyinside(false), completelyoutside(false);
0405 GenericKernelForContainsAndInside<Real_v, Bool_v, true>(sphere, point, completelyinside, completelyoutside);
0406
0407 vecCore__MaskedAssignFunc(safety, completelyinside, Real_v(-1.0));
0408 done |= completelyinside;
0409 if (vecCore::MaskFull(done)) return;
0410
0411 Bool_v isOnSurface = !completelyinside && !completelyoutside;
0412 vecCore__MaskedAssignFunc(safety, !done && isOnSurface, Real_v(0.0));
0413 done |= isOnSurface;
0414 if (vecCore::MaskFull(done)) return;
0415
0416 if (sphere.fRmin) {
0417 safeRMin = sphere.fRmin - rad;
0418 safeRMax = rad - sphere.fRmax;
0419 safety = vecCore::Blend(!done && (safeRMin > safeRMax), safeRMin, safeRMax);
0420 } else {
0421 vecCore__MaskedAssignFunc(safety, !done, (rad - sphere.fRmax));
0422 }
0423
0424
0425
0426 if (!sphere.fFullPhiSphere) {
0427 Real_v safetyPhi = sphere.fPhiWedge.SafetyToIn<Real_v>(point);
0428 vecCore__MaskedAssignFunc(safety, !done, Max(safetyPhi, safety));
0429 }
0430
0431
0432 if (!sphere.fFullThetaSphere) {
0433 Real_v safetyTheta = sphere.fThetaCone.SafetyToIn<Real_v>(point);
0434 vecCore__MaskedAssignFunc(safety, !done, Max(safetyTheta, safety));
0435 }
0436 }
0437
0438 template <typename Real_v>
0439 VECGEOM_FORCE_INLINE
0440 VECCORE_ATT_HOST_DEVICE
0441 static void SafetyToOut(UnplacedStruct_t const &sphere, Vector3D<Real_v> const &point, Real_v &safety)
0442 {
0443
0444 using Bool_v = vecCore::Mask_v<Real_v>;
0445 Real_v rad = point.Mag();
0446
0447 Bool_v done(false);
0448
0449 Bool_v completelyinside(false), completelyoutside(false);
0450 GenericKernelForContainsAndInside<Real_v, Bool_v, true>(sphere, point, completelyinside, completelyoutside);
0451 vecCore__MaskedAssignFunc(safety, completelyoutside, Real_v(-1.0));
0452 done |= completelyoutside;
0453 if (vecCore::MaskFull(done)) return;
0454
0455 Bool_v isOnSurface = !completelyinside && !completelyoutside;
0456 vecCore__MaskedAssignFunc(safety, !done && isOnSurface, Real_v(0.0));
0457 done |= isOnSurface;
0458 if (vecCore::MaskFull(done)) return;
0459
0460
0461 if (sphere.fRmin) {
0462 Real_v safeRMin = (rad - sphere.fRmin);
0463 Real_v safeRMax = (sphere.fRmax - rad);
0464 safety = vecCore::Blend(!done && (safeRMin < safeRMax), safeRMin, safeRMax);
0465 } else {
0466 vecCore__MaskedAssignFunc(safety, !done, (sphere.fRmax - rad));
0467 }
0468
0469
0470 if (!sphere.fFullPhiSphere) {
0471 Real_v safetyPhi = sphere.fPhiWedge.SafetyToOut<Real_v>(point);
0472 vecCore__MaskedAssignFunc(safety, !done, Min(safetyPhi, safety));
0473 }
0474
0475
0476 Real_v safeTheta(0.);
0477 if (!sphere.fFullThetaSphere) {
0478 safeTheta = sphere.fThetaCone.SafetyToOut<Real_v>(point);
0479 vecCore__MaskedAssignFunc(safety, !done, Min(safeTheta, safety));
0480 }
0481 }
0482
0483
0484
0485
0486
0487
0488
0489
0490
0491 template <typename Real_v>
0492 VECCORE_ATT_HOST_DEVICE
0493 static Vector3D<Real_v> ApproxSurfaceNormalKernel(UnplacedStruct_t const &sphere, Vector3D<Real_v> const &point)
0494 {
0495 using vecCore::math::Min;
0496 Vector3D<Real_v> norm(0., 0., 0.);
0497 Real_v radius = point.Mag();
0498 Real_v distRMax = Abs(radius - sphere.fRmax);
0499 Real_v distRMin = InfinityLength<Real_v>();
0500 Real_v distPhi1 = InfinityLength<Real_v>();
0501 Real_v distPhi2 = InfinityLength<Real_v>();
0502 Real_v distTheta1 = InfinityLength<Real_v>();
0503 Real_v distTheta2 = InfinityLength<Real_v>();
0504 Real_v distMin = distRMax;
0505
0506 if (sphere.fRmin > 0.) {
0507 distRMin = Abs(sphere.fRmin - radius);
0508 distMin = Min(distRMin, distRMax);
0509 }
0510
0511 if (!sphere.fFullPhiSphere) {
0512 distPhi1 = Abs(point.x() * sphere.fPhiWedge.GetNormal1().x() + point.y() * sphere.fPhiWedge.GetNormal1().y());
0513 distPhi2 = Abs(point.x() * sphere.fPhiWedge.GetNormal2().x() + point.y() * sphere.fPhiWedge.GetNormal2().y());
0514 distMin = Min(distMin, distPhi1, distPhi2);
0515 }
0516
0517 if (!sphere.fFullThetaSphere) {
0518 Real_v rho = point.Perp();
0519 distTheta1 = sphere.fThetaCone.DistanceToLine<Real_v>(sphere.fThetaCone.GetSlope1(), rho, point.z());
0520 distTheta2 = sphere.fThetaCone.DistanceToLine<Real_v>(sphere.fThetaCone.GetSlope2(), rho, point.z());
0521 distMin = Min(distMin, distTheta1, distTheta2);
0522 }
0523
0524 vecCore__MaskedAssignFunc(norm, distMin == distRMax, point.Unit());
0525 vecCore__MaskedAssignFunc(norm, distMin == distRMin, -point.Unit());
0526
0527 Vector3D<Real_v> normal1 = sphere.fPhiWedge.GetNormal1();
0528 Vector3D<Real_v> normal2 = sphere.fPhiWedge.GetNormal2();
0529 vecCore__MaskedAssignFunc(norm, distMin == distPhi1, -normal1);
0530 vecCore__MaskedAssignFunc(norm, distMin == distPhi2, -normal2);
0531
0532 vecCore__MaskedAssignFunc(norm, distMin == distTheta1, norm + sphere.fThetaCone.GetNormal1<Real_v>(point));
0533 vecCore__MaskedAssignFunc(norm, distMin == distTheta2, norm + sphere.fThetaCone.GetNormal2<Real_v>(point));
0534
0535 return norm;
0536 }
0537
0538 template <typename Real_v>
0539 VECGEOM_FORCE_INLINE
0540 VECCORE_ATT_HOST_DEVICE
0541 static Vector3D<Real_v> Normal(UnplacedStruct_t const &sphere, Vector3D<Real_v> const &point,
0542 typename vecCore::Mask_v<Real_v> &valid)
0543 {
0544 Vector3D<Real_v> normal(0., 0., 0.);
0545 normal.Set(1e-30);
0546
0547 using Bool_v = vecCore::Mask_v<Real_v>;
0548
0549
0550
0551
0552
0553
0554
0555
0556
0557
0558
0559
0560
0561
0562
0563
0564
0565
0566
0567
0568
0569
0570
0571
0572
0573
0574
0575 Bool_v isPointOutside(false);
0576
0577
0578
0579
0580
0581
0582
0583
0584
0585
0586 Bool_v isPointInside(false);
0587 GenericKernelForContainsAndInside<Real_v, Bool_v, true>(sphere, point, isPointInside, isPointOutside);
0588 vecCore__MaskedAssignFunc(normal, isPointInside || isPointOutside,
0589 ApproxSurfaceNormalKernel<Real_v>(sphere, point));
0590
0591 valid = Bool_v(false);
0592
0593 Real_v noSurfaces(0.);
0594 Bool_v isPointOnOuterRadius = SphereUtilities::IsPointOnOuterRadius<Real_v>(sphere, point);
0595
0596 vecCore__MaskedAssignFunc(noSurfaces, isPointOnOuterRadius, noSurfaces + 1);
0597 vecCore__MaskedAssignFunc(normal, !isPointOutside && isPointOnOuterRadius, normal + (point.Unit()));
0598
0599 if (sphere.fRmin) {
0600 Bool_v isPointOnInnerRadius = SphereUtilities::IsPointOnInnerRadius<Real_v>(sphere, point);
0601 vecCore__MaskedAssignFunc(noSurfaces, isPointOnInnerRadius, noSurfaces + 1);
0602 vecCore__MaskedAssignFunc(normal, !isPointOutside && isPointOnInnerRadius, normal - point.Unit());
0603 }
0604
0605 if (!sphere.fFullPhiSphere) {
0606 Bool_v isPointOnStartPhi = SphereUtilities::IsPointOnStartPhi<Real_v>(sphere, point);
0607 Bool_v isPointOnEndPhi = SphereUtilities::IsPointOnEndPhi<Real_v>(sphere, point);
0608 vecCore__MaskedAssignFunc(noSurfaces, isPointOnStartPhi, noSurfaces + 1);
0609 vecCore__MaskedAssignFunc(noSurfaces, isPointOnEndPhi, noSurfaces + 1);
0610 vecCore__MaskedAssignFunc(normal, !isPointOutside && isPointOnStartPhi, normal - sphere.fPhiWedge.GetNormal1());
0611 vecCore__MaskedAssignFunc(normal, !isPointOutside && isPointOnEndPhi, normal - sphere.fPhiWedge.GetNormal2());
0612 }
0613
0614 if (!sphere.fFullThetaSphere) {
0615 Bool_v isPointOnStartTheta = SphereUtilities::IsPointOnStartTheta<Real_v>(sphere, point);
0616 Bool_v isPointOnEndTheta = SphereUtilities::IsPointOnEndTheta<Real_v>(sphere, point);
0617
0618 vecCore__MaskedAssignFunc(noSurfaces, isPointOnStartTheta, noSurfaces + 1);
0619 vecCore__MaskedAssignFunc(normal, !isPointOutside && isPointOnStartTheta,
0620 normal + sphere.fThetaCone.GetNormal1<Real_v>(point));
0621
0622 vecCore__MaskedAssignFunc(noSurfaces, isPointOnEndTheta, noSurfaces + 1);
0623 vecCore__MaskedAssignFunc(normal, !isPointOutside && isPointOnEndTheta,
0624 normal + sphere.fThetaCone.GetNormal2<Real_v>(point));
0625
0626 Vector3D<Real_v> tempNormal(0., 0., -1.);
0627 vecCore__MaskedAssignFunc(
0628 normal, !isPointOutside && isPointOnStartTheta && isPointOnEndTheta && (sphere.eTheta <= kPi / 2.),
0629 tempNormal);
0630 Vector3D<Real_v> tempNormal2(0., 0., 1.);
0631 vecCore__MaskedAssignFunc(
0632 normal, !isPointOutside && isPointOnStartTheta && isPointOnEndTheta && (sphere.fSTheta >= kPi / 2.),
0633 tempNormal2);
0634 }
0635
0636 normal.Normalize();
0637
0638 valid = (noSurfaces > Real_v(0.));
0639
0640 return normal;
0641 }
0642 };
0643 }
0644 }
0645
0646 #endif