File indexing completed on 2025-01-18 10:14:10
0001
0002
0003
0004 #ifndef VECGEOM_VOLUMES_QUADRILATERALS_H_
0005 #define VECGEOM_VOLUMES_QUADRILATERALS_H_
0006
0007 #include "VecGeom/base/Global.h"
0008
0009 #include "VecGeom/base/Array.h"
0010 #include "VecGeom/base/AOS3D.h"
0011 #include "VecGeom/base/SOA3D.h"
0012 #include "VecGeom/base/Vector3D.h"
0013 #include "VecGeom/base/RNG.h"
0014 #include "VecGeom/volumes/kernel/GenericKernels.h"
0015 #include "VecGeom/volumes/Planes.h"
0016
0017
0018
0019
0020 namespace vecgeom {
0021
0022 VECGEOM_DEVICE_FORWARD_DECLARE(class Quadrilaterals;);
0023 VECGEOM_DEVICE_DECLARE_CONV(class, Quadrilaterals);
0024
0025 inline namespace VECGEOM_IMPL_NAMESPACE {
0026
0027 class Quadrilaterals {
0028
0029 private:
0030 Planes fPlanes;
0031 Planes fSideVectors[4];
0032
0033
0034
0035 AOS3D<Precision> fCorners[4];
0036
0037
0038 public:
0039 typedef Planes Sides_t[4];
0040 typedef AOS3D<Precision> Corners_t[4];
0041
0042 VECCORE_ATT_HOST_DEVICE
0043 Quadrilaterals(int size, bool convex = true);
0044
0045 VECCORE_ATT_HOST_DEVICE
0046 ~Quadrilaterals();
0047
0048 VECCORE_ATT_HOST_DEVICE
0049 Quadrilaterals(Quadrilaterals const &other);
0050
0051 VECCORE_ATT_HOST_DEVICE
0052 Quadrilaterals &operator=(Quadrilaterals const &other);
0053
0054
0055 VECCORE_ATT_HOST_DEVICE
0056 VECGEOM_FORCE_INLINE
0057 int size() const;
0058
0059 VECCORE_ATT_HOST_DEVICE
0060 VECGEOM_FORCE_INLINE
0061 Planes const &GetPlanes() const;
0062
0063 VECCORE_ATT_HOST_DEVICE
0064 VECGEOM_FORCE_INLINE
0065 SOA3D<Precision> const &GetNormals() const;
0066
0067 VECCORE_ATT_HOST_DEVICE
0068 VECGEOM_FORCE_INLINE
0069 Vector3D<Precision> GetNormal(int i) const;
0070
0071 VECCORE_ATT_HOST_DEVICE
0072 VECGEOM_FORCE_INLINE
0073 Array<Precision> const &GetDistances() const;
0074
0075 VECCORE_ATT_HOST_DEVICE
0076 VECGEOM_FORCE_INLINE
0077 Precision GetDistance(int i) const;
0078
0079 VECCORE_ATT_HOST_DEVICE
0080 VECGEOM_FORCE_INLINE
0081 Sides_t const &GetSideVectors() const;
0082
0083 VECCORE_ATT_HOST_DEVICE
0084 VECGEOM_FORCE_INLINE
0085 Corners_t const &GetCorners() const;
0086
0087 VECCORE_ATT_HOST_DEVICE
0088 VECGEOM_FORCE_INLINE
0089 Precision GetTriangleArea(int index, int iCorner1, int iCorner2) const;
0090
0091 VECCORE_ATT_HOST_DEVICE
0092 VECGEOM_FORCE_INLINE
0093 Precision GetQuadrilateralArea(int index) const;
0094
0095 VECCORE_ATT_HOST_DEVICE
0096 VECGEOM_FORCE_INLINE
0097 Vector3D<Precision> GetPointOnTriangle(int index, int iCorner0, int iCorner1, int iCorner2) const;
0098
0099 VECCORE_ATT_HOST_DEVICE
0100 VECGEOM_FORCE_INLINE
0101 Vector3D<Precision> GetPointOnFace(int index) const;
0102
0103 VECCORE_ATT_HOST_DEVICE
0104 VECGEOM_FORCE_INLINE
0105 bool RayHitsQuadrilateral(int index, Vector3D<Precision> const &intersection) const
0106 {
0107 bool valid = true;
0108 for (int j = 0; j < 4; ++j) {
0109 valid &=
0110 intersection.Dot(fSideVectors[j].GetNormal(index)) + fSideVectors[j].GetDistances()[index] >= -kTolerance;
0111 if (vecCore::MaskEmpty(valid)) break;
0112 }
0113 return valid;
0114 }
0115
0116
0117
0118
0119
0120
0121 VECCORE_ATT_HOST_DEVICE
0122 void Set(int index, Vector3D<Precision> const &corner0, Vector3D<Precision> const &corner1,
0123 Vector3D<Precision> const &corner2, Vector3D<Precision> const &corner3);
0124
0125
0126 VECCORE_ATT_HOST_DEVICE
0127 void FlipSign(int index);
0128
0129 template <typename Real_v>
0130 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE vecCore::Mask_v<Real_v> Contains(Vector3D<Real_v> const &point) const;
0131
0132 template <typename Real_v, typename Inside_v>
0133 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE Inside_v Inside(Vector3D<Real_v> const &point) const;
0134
0135 template <typename Real_v, typename Inside_v>
0136 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE Inside_v Inside(Vector3D<Real_v> const &point, int i) const;
0137
0138 template <typename Real_v, bool behindPlanesT>
0139 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE Real_v DistanceToIn(Vector3D<Real_v> const &point,
0140 Vector3D<Real_v> const &direction) const;
0141
0142 template <typename Real_v>
0143 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE Real_v DistanceToOut(Vector3D<Real_v> const &point,
0144 Vector3D<Real_v> const &direction, Precision zMin,
0145 Precision zMax) const;
0146
0147 template <typename Real_v>
0148 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE Real_v DistanceToOut(Vector3D<Real_v> const &point,
0149 Vector3D<Real_v> const &direction) const;
0150
0151
0152 VECGEOM_FORCE_INLINE
0153 VECCORE_ATT_HOST_DEVICE
0154 Precision ScalarDistanceSquared(int index, Vector3D<Precision> const &point) const;
0155
0156 VECCORE_ATT_HOST_DEVICE
0157 void Print() const;
0158
0159 };
0160
0161 VECCORE_ATT_HOST_DEVICE
0162 VECGEOM_FORCE_INLINE
0163 int Quadrilaterals::size() const
0164 {
0165 return fPlanes.size();
0166 }
0167
0168 VECCORE_ATT_HOST_DEVICE
0169 VECGEOM_FORCE_INLINE
0170 Planes const &Quadrilaterals::GetPlanes() const
0171 {
0172 return fPlanes;
0173 }
0174
0175 VECCORE_ATT_HOST_DEVICE
0176 SOA3D<Precision> const &Quadrilaterals::GetNormals() const
0177 {
0178 return fPlanes.GetNormals();
0179 }
0180
0181 VECCORE_ATT_HOST_DEVICE
0182 Vector3D<Precision> Quadrilaterals::GetNormal(int i) const
0183 {
0184 return fPlanes.GetNormal(i);
0185 }
0186
0187 VECCORE_ATT_HOST_DEVICE
0188 Array<Precision> const &Quadrilaterals::GetDistances() const
0189 {
0190 return fPlanes.GetDistances();
0191 }
0192
0193 VECCORE_ATT_HOST_DEVICE
0194 Precision Quadrilaterals::GetDistance(int i) const
0195 {
0196 return fPlanes.GetDistance(i);
0197 }
0198
0199 VECCORE_ATT_HOST_DEVICE
0200 Quadrilaterals::Sides_t const &Quadrilaterals::GetSideVectors() const
0201 {
0202 return fSideVectors;
0203 }
0204
0205 VECCORE_ATT_HOST_DEVICE
0206 Quadrilaterals::Corners_t const &Quadrilaterals::GetCorners() const
0207 {
0208 return fCorners;
0209 }
0210
0211 VECCORE_ATT_HOST_DEVICE
0212 Precision Quadrilaterals::GetTriangleArea(int index, int iCorner1, int iCorner2) const
0213 {
0214 Precision fArea = 0.;
0215 Vector3D<Precision> vec1 = fCorners[iCorner1][index] - fCorners[0][index];
0216 Vector3D<Precision> vec2 = fCorners[iCorner2][index] - fCorners[0][index];
0217
0218 fArea = 0.5 * (vec1.Cross(vec2)).Mag();
0219 return fArea;
0220 }
0221
0222 VECCORE_ATT_HOST_DEVICE
0223 Precision Quadrilaterals::GetQuadrilateralArea(int index) const
0224 {
0225 Precision fArea = 0.;
0226
0227 fArea = GetTriangleArea(index, 1, 2) + GetTriangleArea(index, 2, 3);
0228 return fArea;
0229 }
0230
0231 VECCORE_ATT_HOST_DEVICE
0232 Vector3D<Precision> Quadrilaterals::GetPointOnTriangle(int index, int iCorner0, int iCorner1, int iCorner2) const
0233 {
0234 Precision r1 = RNG::Instance().uniform(0.0, 1.0);
0235 Precision r2 = RNG::Instance().uniform(0.0, 1.0);
0236 if (r1 + r2 > 1.) {
0237 r1 = 1. - r1;
0238 r2 = 1. - r2;
0239 }
0240 Vector3D<Precision> vec1 = fCorners[iCorner1][index] - fCorners[iCorner0][index];
0241 Vector3D<Precision> vec2 = fCorners[iCorner2][index] - fCorners[iCorner0][index];
0242 return fCorners[iCorner0][index] + r1 * vec1 + r2 * vec2;
0243 }
0244
0245 VECCORE_ATT_HOST_DEVICE
0246 Vector3D<Precision> Quadrilaterals::GetPointOnFace(int index) const
0247 {
0248
0249
0250 int nvert = 0;
0251 int iCorners[4];
0252 for (int i = 0; i < 4; ++i) {
0253 if ((fCorners[(i + 1) % 4][index] - fCorners[i % 4][index]).Mag2() > kTolerance) {
0254 iCorners[nvert++] = i;
0255 }
0256 }
0257 if (nvert == 1) return fCorners[0][index];
0258 if (nvert == 2) return GetPointOnTriangle(index, iCorners[0], iCorners[0], iCorners[1]);
0259 if (nvert == 3) return GetPointOnTriangle(index, iCorners[0], iCorners[1], iCorners[2]);
0260 Precision choice = RNG::Instance().uniform(0, 1.0);
0261 if (choice < 0.5) {
0262 return GetPointOnTriangle(index, 0, 1, 2);
0263 } else {
0264 return GetPointOnTriangle(index, 0, 2, 3);
0265 }
0266 }
0267
0268 template <typename Real_v>
0269 VECCORE_ATT_HOST_DEVICE vecCore::Mask_v<Real_v> Quadrilaterals::Contains(Vector3D<Real_v> const &point) const
0270 {
0271 return fPlanes.Contains<Real_v>(point);
0272 }
0273
0274 template <typename Real_v, typename Inside_v>
0275 VECCORE_ATT_HOST_DEVICE Inside_v Quadrilaterals::Inside(Vector3D<Real_v> const &point) const
0276 {
0277 return fPlanes.Inside<Real_v, Inside_v>(point);
0278 }
0279
0280 template <typename Real_v, typename Inside_v>
0281 VECCORE_ATT_HOST_DEVICE Inside_v Quadrilaterals::Inside(Vector3D<Real_v> const &point, int i) const
0282 {
0283 return fPlanes.Inside<Real_v, Inside_v>(point, i);
0284 }
0285
0286 namespace {
0287
0288 template <class Real_v>
0289 struct AcceleratedDistanceToIn {
0290 template <bool behindPlanesT>
0291 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void VectorLoop(
0292 int & , const int , Planes const & , Planes const (&)[4],
0293 Vector3D<Real_v> const & , Vector3D<Real_v> const & , Real_v & )
0294 {
0295
0296 return;
0297 }
0298 };
0299
0300 #if defined(VECGEOM_VC) && defined(VECGEOM_QUADRILATERALS_VC)
0301 template <>
0302 struct AcceleratedDistanceToIn<Precision> {
0303
0304 template <bool behindPlanesT>
0305 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void VectorLoop(int &i, const int n, Planes const &planes,
0306 Planes const (&sideVectors)[4],
0307 Vector3D<Precision> const &point,
0308 Vector3D<Precision> const &direction,
0309 Precision &distance)
0310 {
0311
0312
0313 for (; i <= n - kVectorSize; i += kVectorSize) {
0314 Vector3D<VcPrecision> plane(VcPrecision(planes.GetNormals().x() + i), VcPrecision(planes.GetNormals().y() + i),
0315 VcPrecision(planes.GetNormals().z() + i));
0316 VcPrecision dPlane(&planes.GetDistances()[0] + i);
0317 VcPrecision distanceTest = plane.Dot(point) + dPlane;
0318
0319
0320 VcBool valid = Flip<behindPlanesT>::FlipSign(distanceTest) > -kTolerance;
0321 if (vecCore::MaskEmpty(valid)) continue;
0322
0323 VcPrecision directionProjection = plane.Dot(direction);
0324 valid &= Flip<!behindPlanesT>::FlipSign(directionProjection) > 0;
0325 if (vecCore::MaskEmpty(valid)) continue;
0326 VcPrecision tiny = Vc::copysign(VcPrecision(1E-20), directionProjection);
0327 distanceTest /= -(directionProjection + tiny);
0328 Vector3D<VcPrecision> intersection = Vector3D<VcPrecision>(direction) * distanceTest + point;
0329
0330 for (int j = 0; j < 4; ++j) {
0331 Vector3D<VcPrecision> sideVector(VcPrecision(sideVectors[j].GetNormals().x() + i),
0332 VcPrecision(sideVectors[j].GetNormals().y() + i),
0333 VcPrecision(sideVectors[j].GetNormals().z() + i));
0334 VcPrecision dSide(&sideVectors[j].GetDistances()[i]);
0335 valid &= sideVector.Dot(intersection) + dSide >= -kTolerance;
0336
0337 if (vecCore::MaskEmpty(valid)) goto distanceToInVcContinueOuter;
0338 }
0339
0340
0341 distanceTest(!valid) = InfinityLength<Precision>();
0342 distance = Max(distanceTest.min(), Precision(0.));
0343 i = n;
0344 return;
0345
0346 distanceToInVcContinueOuter:;
0347 }
0348 return;
0349 }
0350 };
0351 #endif
0352
0353 }
0354
0355 template <typename Real_v, bool behindPlanesT>
0356 VECCORE_ATT_HOST_DEVICE Real_v Quadrilaterals::DistanceToIn(Vector3D<Real_v> const &point,
0357 Vector3D<Real_v> const &direction) const
0358 {
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368
0369
0370
0371
0372 using Bool_v = vecCore::Mask_v<Real_v>;
0373
0374 Real_v bestDistance = InfinityLength<Real_v>();
0375
0376 int i = 0;
0377 const int n = size();
0378 AcceleratedDistanceToIn<Real_v>::template VectorLoop<behindPlanesT>(i, n, fPlanes, fSideVectors, point, direction,
0379 bestDistance);
0380
0381
0382 for (; i < n; ++i) {
0383 Vector3D<Precision> normal = fPlanes.GetNormal(i);
0384 Real_v distance = point.Dot(normal) + fPlanes.GetDistance(i);
0385
0386
0387 Bool_v valid = Flip<behindPlanesT>::FlipSign(distance) > -kTolerance;
0388 if (vecCore::MaskEmpty(valid)) continue;
0389 Real_v directionProjection = direction.Dot(normal);
0390 valid &= Flip<!behindPlanesT>::FlipSign(directionProjection) > 0;
0391 if (vecCore::MaskEmpty(valid)) continue;
0392 distance /= -(directionProjection + CopySign(Real_v(1E-20), directionProjection));
0393 Vector3D<Real_v> intersection = point + direction * distance;
0394 for (int j = 0; j < 4; ++j) {
0395 valid &= intersection.Dot(fSideVectors[j].GetNormal(i)) + fSideVectors[j].GetDistances()[i] >= -kTolerance;
0396 if (vecCore::MaskEmpty(valid)) break;
0397 }
0398 vecCore::MaskedAssign(bestDistance, valid, distance);
0399
0400
0401 if (vecCore::MaskFull(bestDistance < InfinityLength<Real_v>())) break;
0402 }
0403
0404 return Max(Real_v(0.), bestDistance);
0405 }
0406
0407 namespace {
0408
0409 template <typename Real_v>
0410 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE void AcceleratedDistanceToOut(
0411 int & , const int , Planes const & , Planes const (&)[4],
0412 const Precision , const Precision , Vector3D<Real_v> const & ,
0413 Vector3D<Real_v> const & , Real_v & )
0414 {
0415
0416 return;
0417 }
0418
0419 #if defined(VECGEOM_VC) && defined(VECGEOM_QUADRILATERALS_VC)
0420 template <>
0421 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE void AcceleratedDistanceToOut<Precision>(
0422 int &i, const int n, Planes const &planes, Planes const (&sideVectors)[4], const Precision zMin,
0423 const Precision zMax, Vector3D<Precision> const &point, Vector3D<Precision> const &direction, Precision &distance)
0424 {
0425
0426
0427 for (; i <= n - kVectorSize; i += kVectorSize) {
0428 Vector3D<VcPrecision> plane(VcPrecision(planes.GetNormals().x() + i), VcPrecision(planes.GetNormals().y() + i),
0429 VcPrecision(planes.GetNormals().z() + i));
0430 VcPrecision dPlane(&planes.GetDistances()[0] + i);
0431 VcPrecision distanceTest = plane.Dot(point) + dPlane;
0432
0433 VcBool valid = distanceTest < kTolerance;
0434 if (vecCore::MaskEmpty(valid)) continue;
0435 VcPrecision directionProjection = plane.Dot(direction);
0436
0437
0438 valid &= directionProjection > 0;
0439 if (vecCore::MaskEmpty(valid)) continue;
0440 distanceTest /= -NonZero(directionProjection);
0441 valid &= distanceTest < distance;
0442 if (vecCore::MaskEmpty(valid)) continue;
0443
0444 if (zMin == zMax) {
0445
0446 Vector3D<VcPrecision> intersection = Vector3D<VcPrecision>(direction) * distanceTest + point;
0447 for (int j = 0; j < 4; ++j) {
0448 Vector3D<VcPrecision> sideVector(VcPrecision(sideVectors[j].GetNormals().x() + i),
0449 VcPrecision(sideVectors[j].GetNormals().y() + i),
0450 VcPrecision(sideVectors[j].GetNormals().z() + i));
0451 VcPrecision dSide(&sideVectors[j].GetDistances()[i]);
0452 valid &= sideVector.Dot(intersection) + dSide >= -kTolerance;
0453
0454 if (vecCore::MaskEmpty(valid)) goto distanceToOutVcContinueOuter;
0455 }
0456 } else {
0457 VcPrecision zProjection = distanceTest * direction[2] + point[2];
0458 valid &= zProjection >= zMin && zProjection < zMax;
0459 }
0460 distanceToOutVcContinueOuter:
0461 if (vecCore::MaskEmpty(valid)) continue;
0462 distanceTest(!valid) = InfinityLength<Precision>();
0463 distance = distanceTest.min();
0464 }
0465 distance = Max(Precision(0.), distance);
0466 return;
0467 }
0468 #endif
0469
0470 }
0471
0472 template <typename Real_v>
0473 VECCORE_ATT_HOST_DEVICE Real_v Quadrilaterals::DistanceToOut(Vector3D<Real_v> const &point,
0474 Vector3D<Real_v> const &direction, Precision zMin,
0475 Precision zMax) const
0476 {
0477
0478
0479
0480
0481
0482
0483
0484
0485
0486 using Bool_v = vecCore::Mask_v<Real_v>;
0487
0488 Real_v bestDistance = InfinityLength<Real_v>();
0489
0490 int i = 0;
0491 const int n = size();
0492 AcceleratedDistanceToOut<Real_v>(i, n, fPlanes, fSideVectors, zMin, zMax, point, direction, bestDistance);
0493
0494 for (; i < n; ++i) {
0495 Vector3D<Precision> normal = fPlanes.GetNormal(i);
0496 Real_v distanceTest = point.Dot(normal) + fPlanes.GetDistance(i);
0497
0498 Bool_v valid = distanceTest < kTolerance;
0499 if (vecCore::MaskEmpty(valid)) continue;
0500 Real_v directionProjection = direction.Dot(normal);
0501
0502
0503 valid &= directionProjection > 0;
0504 if (vecCore::MaskEmpty(valid)) continue;
0505 distanceTest /= -directionProjection;
0506 valid &= distanceTest < bestDistance;
0507 if (vecCore::MaskEmpty(valid)) continue;
0508
0509
0510 if (zMin == zMax) {
0511
0512
0513 Vector3D<Real_v> intersection = point + distanceTest * direction;
0514
0515 valid = RayHitsQuadrilateral(i, intersection);
0516
0517 } else {
0518 Real_v zProjection = point[2] + distanceTest * direction[2];
0519 valid &= (zProjection >= zMin - kTolerance) && (zProjection < zMax + kTolerance);
0520 }
0521 if (vecCore::MaskEmpty(valid)) continue;
0522 vecCore::MaskedAssign(bestDistance, valid, distanceTest);
0523 }
0524
0525 if (bestDistance > -kTolerance) bestDistance = Max(bestDistance, Precision(0.));
0526 return bestDistance;
0527 }
0528
0529 template <typename Real_v>
0530 VECCORE_ATT_HOST_DEVICE Real_v Quadrilaterals::DistanceToOut(Vector3D<Real_v> const &point,
0531 Vector3D<Real_v> const &direction) const
0532 {
0533 return DistanceToOut<Real_v>(point, direction, -InfinityLength<Real_v>(), InfinityLength<Real_v>());
0534 }
0535
0536 VECCORE_ATT_HOST_DEVICE
0537 Precision Quadrilaterals::ScalarDistanceSquared(int i, Vector3D<Precision> const &point) const
0538 {
0539
0540
0541
0542
0543
0544
0545 assert(i < size());
0546
0547 Vector3D<Precision> planeNormal = fPlanes.GetNormal(i);
0548 Precision distance = point.Dot(planeNormal) + fPlanes.GetDistance(i);
0549
0550
0551
0552 Vector3D<Precision> intersection = point - distance * planeNormal;
0553
0554 bool withinBound[4];
0555 for (int j = 0; j < 4; ++j) {
0556
0557
0558 withinBound[j] = intersection[0] * fSideVectors[j].GetNormals().x(i) +
0559 intersection[1] * fSideVectors[j].GetNormals().y(i) +
0560 intersection[2] * fSideVectors[j].GetNormals().z(i) + fSideVectors[j].GetDistances()[i] >=
0561 0;
0562 }
0563 if (withinBound[0] && withinBound[1] && withinBound[2] && withinBound[3]) {
0564 return distance * distance;
0565 }
0566
0567
0568
0569
0570
0571
0572
0573
0574
0575
0576
0577
0578
0579
0580
0581
0582
0583
0584
0585
0586
0587
0588
0589
0590
0591
0592
0593
0594
0595
0596
0597 Precision distancesq = InfinityLength<Precision>();
0598 for (int j = 0; j < 4; ++j) {
0599 if (!withinBound[j]) {
0600 distance = DistanceToLineSegmentSquared1<Precision>(fCorners[j][i], fCorners[(j + 1) % 4][i], point);
0601 if (distance < distancesq) distancesq = distance;
0602 }
0603 }
0604 return distancesq;
0605 }
0606
0607 std::ostream &operator<<(std::ostream &os, Quadrilaterals const &quads);
0608
0609 }
0610
0611 }
0612
0613 #endif