File indexing completed on 2026-09-08 09:28:17
0001
0002
0003
0004
0005
0006
0007 #ifndef VECGEOM_POLYHEDRONSTRUCT_H_
0008 #define VECGEOM_POLYHEDRONSTRUCT_H_
0009
0010 #include <ostream>
0011
0012 #include <VecCore/VecCore>
0013 #include "VecGeom/base/Vector3D.h"
0014 #include "VecGeom/volumes/Quadrilaterals.h"
0015 #include "VecGeom/volumes/Wedge_Evolution.h"
0016 #include "VecGeom/base/Array.h"
0017 #include "VecGeom/base/SOA3D.h"
0018 #include "VecGeom/volumes/TubeStruct.h"
0019
0020
0021
0022
0023 enum struct EInnerRadii { kFalse = -1, kGeneric = 0, kTrue = 1 };
0024 enum struct EPhiCutout { kFalse = -1, kGeneric = 0, kTrue = 1, kLarge = 2 };
0025
0026 namespace vecgeom {
0027
0028 VECGEOM_DEVICE_FORWARD_DECLARE(struct ZSegment;);
0029 VECGEOM_DEVICE_DECLARE_CONV(struct, ZSegment);
0030
0031
0032 namespace Polyhedron {
0033 using ::EInnerRadii;
0034 using ::EPhiCutout;
0035 }
0036
0037 inline namespace VECGEOM_IMPL_NAMESPACE {
0038
0039
0040
0041 struct ZSegment {
0042 Quadrilaterals outer;
0043 Quadrilaterals phi;
0044 Quadrilaterals inner;
0045
0046 VECCORE_ATT_HOST_DEVICE
0047 bool hasInnerRadius() const { return inner.size() > 0; }
0048
0049 VECCORE_ATT_HOST_DEVICE
0050 size_t aligned_sizeof_data(size_t nOuter, size_t nInner, size_t nPhi)
0051 {
0052 return Quadrilaterals::aligned_sizeof_data(nOuter) + Quadrilaterals::aligned_sizeof_data(nInner) +
0053 Quadrilaterals::aligned_sizeof_data(nPhi);
0054 }
0055
0056 ZSegment() = default;
0057
0058 VECCORE_ATT_HOST_DEVICE
0059 ZSegment(size_t nOuter, size_t nInner, size_t nPhi, AlignedAllocator &a, bool convex = true)
0060 : outer(nOuter, a), phi(nPhi, a, convex), inner(nInner, a)
0061 {
0062 }
0063 };
0064
0065
0066 template <typename T = double>
0067 struct PolyhedronStruct {
0068 size_t fSize{0};
0069 int fSideCount{0};
0070 bool fHasInnerRadii{false};
0071 bool fHasPhiCutout{false};
0072 bool fHasLargePhiCutout{false};
0073 T fPhiStart{0.};
0074 T fPhiDelta{0.};
0075 evolution::Wedge fPhiWedge;
0076 Array<ZSegment> fZSegments;
0077 Array<T> fZPlanes;
0078 Array<T> fRMin;
0079 Array<T> fRMax;
0080 Array<bool> fSameZ;
0081 SOA3D<T> fPhiSections;
0082
0083
0084
0085 TubeStruct<T> fBoundingTube;
0086
0087
0088 T fBoundingTubeOffset{0.};
0089
0090
0091
0092
0093 struct AreaStruct {
0094 Precision area = 0.;
0095 Precision top_area = 0.;
0096 Precision bottom_area = 0.;
0097 Precision *outer = nullptr;
0098 Precision *inner = nullptr;
0099 Precision *phi = nullptr;
0100
0101 AreaStruct(int nseg)
0102 {
0103 inner = new Precision[nseg];
0104 outer = new Precision[nseg];
0105 phi = new Precision[nseg];
0106 }
0107
0108 VECCORE_ATT_HOST_DEVICE
0109 ~AreaStruct()
0110 {
0111 delete[] inner;
0112 delete[] outer;
0113 delete[] phi;
0114 }
0115 };
0116
0117 mutable AreaStruct *fAreaStruct = nullptr;
0118 mutable Precision fCapacity = 0.;
0119
0120
0121 bool fContinuousInSlope;
0122 bool fConvexityPossible;
0123 bool fEqualRmax;
0124
0125 VECGEOM_FORCE_INLINE
0126 VECCORE_ATT_HOST_DEVICE
0127 static bool ApproxEqual(const Precision &x, const Precision &y) { return vecCore::math::Abs(x - y) < kTolerance; }
0128
0129 PolyhedronStruct() = default;
0130
0131 VECCORE_ATT_HOST_DEVICE
0132 PolyhedronStruct(Precision phiStart, Precision phiDelta, const int sideCount, const int zPlaneCount,
0133 Precision const zPlanes[], Precision const rMin[], Precision const rMax[])
0134 : fSideCount(sideCount), fHasInnerRadii(false), fHasPhiCutout(phiDelta < kTwoPi),
0135 fHasLargePhiCutout(phiDelta < kPi), fPhiStart(NormalizeAngle<kScalar>(phiStart)),
0136 fPhiDelta((phiDelta > kTwoPi) ? kTwoPi : phiDelta), fPhiWedge(fPhiDelta, fPhiStart),
0137 fZSegments(zPlaneCount - 1), fZPlanes(zPlaneCount), fRMin(zPlaneCount), fRMax(zPlaneCount), fSameZ(zPlaneCount),
0138 fPhiSections(sideCount + 1), fBoundingTube(0, 1, 1, fPhiStart, fPhiDelta), fContinuousInSlope(true),
0139 fConvexityPossible(true), fEqualRmax(true)
0140 {
0141
0142 Initialize(phiStart, phiDelta, sideCount, zPlaneCount, zPlanes, rMin, rMax);
0143 }
0144
0145 VECCORE_ATT_HOST_DEVICE
0146 PolyhedronStruct(Precision phiStart, Precision phiDelta, const int sideCount, const int zPlaneCount,
0147 Precision const zPlanes[], Precision const rMin[], Precision const rMax[], AlignedAllocator &a)
0148 : fSideCount(sideCount), fHasInnerRadii(false), fHasPhiCutout(phiDelta < kTwoPi),
0149 fHasLargePhiCutout(phiDelta < kPi), fPhiStart(NormalizeAngle<kScalar>(phiStart)),
0150 fPhiDelta((phiDelta > kTwoPi) ? kTwoPi : phiDelta), fPhiWedge(fPhiDelta, fPhiStart),
0151 fZSegments(zPlaneCount - 1, a), fZPlanes(zPlaneCount, a), fRMin(zPlaneCount, a), fRMax(zPlaneCount, a),
0152 fSameZ(zPlaneCount, a), fPhiSections(sideCount + 1), fBoundingTube(0, 1, 1, fPhiStart, fPhiDelta),
0153 fContinuousInSlope(true), fConvexityPossible(true), fEqualRmax(true)
0154 {
0155
0156 Initialize(phiStart, phiDelta, sideCount, zPlaneCount, zPlanes, rMin, rMax, a);
0157 }
0158
0159 PolyhedronStruct(Precision phiStart, Precision phiDelta, const int sideCount, const int verticesCount,
0160 Precision const r[], Precision const z[])
0161 : fSideCount(sideCount), fHasInnerRadii(false), fHasPhiCutout(phiDelta < kTwoPi),
0162 fHasLargePhiCutout(phiDelta < kPi), fPhiStart(NormalizeAngle<kScalar>(phiStart)),
0163 fPhiDelta((phiDelta > kTwoPi) ? kTwoPi : phiDelta), fPhiWedge(fPhiDelta, fPhiStart), fZSegments(), fZPlanes(),
0164 fRMin(), fRMax(), fSameZ(), fPhiSections(sideCount + 1), fBoundingTube(0, 1, 1, fPhiStart, fPhiDelta),
0165 fContinuousInSlope(true), fConvexityPossible(true), fEqualRmax(true)
0166 {
0167 if (verticesCount < 3) throw std::runtime_error("A Polyhedron needs at least 3 (rz) vertices");
0168
0169
0170
0171
0172
0173
0174 Precision area = 0;
0175 for (int i = 0; i < verticesCount; ++i) {
0176 int j = (i + 1) % verticesCount;
0177 area += r[i] * z[j] - r[j] * z[i];
0178 }
0179
0180 bool cw = (area < 0);
0181 int inc = cw ? -1 : 1;
0182 Precision zt = z[0];
0183 Precision zb = z[0];
0184
0185 for (int i = 0; i < verticesCount; ++i) {
0186 if (z[i] > zt) zt = z[i];
0187 if (z[i] < zb) zb = z[i];
0188 }
0189
0190
0191 Precision *rnew = new Precision[2 * verticesCount];
0192 Precision *znew = new Precision[2 * verticesCount];
0193 int verticesCount1 = 0;
0194 for (int i0 = 0; i0 < verticesCount; ++i0) {
0195 rnew[verticesCount1] = r[i0];
0196 znew[verticesCount1++] = z[i0];
0197
0198 if (vecCore::math::Abs(z[i0] - zt) < kTolerance || vecCore::math::Abs(z[i0] - zb) < kTolerance) {
0199 if (vecCore::math::Abs(z[i0] - z[(i0 + verticesCount - 1) % verticesCount]) > kTolerance &&
0200 vecCore::math::Abs(z[i0] - z[(i0 + 1) % verticesCount]) > kTolerance) {
0201 rnew[verticesCount1] = r[i0];
0202 znew[verticesCount1++] = z[i0];
0203 }
0204 }
0205 int i1 = (i0 + 1) % verticesCount;
0206 Precision dz = z[i1] - z[i0];
0207 if (vecCore::math::Abs(dz) < kTolerance) continue;
0208 Precision zmin = vecCore::math::Min(z[i0], z[i1]);
0209 Precision zmax = vecCore::math::Max(z[i0], z[i1]);
0210 for (int j = 0; j < verticesCount - 2; ++j) {
0211
0212 int k = (i0 - 1 - j + verticesCount) % verticesCount;
0213 if (z[k] > zmin + kTolerance && z[k] < zmax - kTolerance) {
0214
0215 Precision rp = r[i0] + (r[i1] - r[i0]) * (z[k] - z[i0]) / dz;
0216 VECGEOM_ASSERT(rp >= 0);
0217
0218 rnew[verticesCount1] = rp;
0219 znew[verticesCount1++] = z[k];
0220 }
0221 }
0222 }
0223
0224
0225 int i0 = -1;
0226 for (int i = 0; i < verticesCount1; ++i) {
0227 if (znew[i] == zb) {
0228 i0 = i;
0229 break;
0230 }
0231 }
0232 if (vecCore::math::Abs(zb - znew[(i0 + inc) % verticesCount1]) < kTolerance) i0 = (i0 + inc) % verticesCount1;
0233
0234 if (phiDelta <= 0 || phiDelta > kTwoPi - kAngTolerance) phiDelta = kTwoPi;
0235 Precision sidePhi = phiDelta / sideCount;
0236 Precision cosHalfDeltaPhi = cos(0.5 * sidePhi);
0237
0238
0239
0240 int Nz = verticesCount1 / 2;
0241 Precision *rMin = new Precision[Nz];
0242 Precision *rMax = new Precision[Nz];
0243 Precision *zArg = new Precision[Nz];
0244
0245 for (int i = 0; i < Nz; ++i) {
0246
0247 int j = (i0 + verticesCount1 + inc * i) % verticesCount1;
0248 int jsim = (i0 + verticesCount1 + inc * (verticesCount1 - 1 - i)) % verticesCount1;
0249 VECGEOM_ASSERT(znew[j] == znew[jsim]);
0250 zArg[i] = znew[j];
0251 rMax[i] = rnew[j] * cosHalfDeltaPhi;
0252 rMin[i] = rnew[jsim] * cosHalfDeltaPhi;
0253 VECGEOM_ASSERT(rMax[i] >= rMin[i] &&
0254 "UnplPolycone ERROR: r[] provided has problems of the Rmax < Rmin type, please check!\n");
0255 }
0256
0257
0258 fZSegments.Allocate(Nz - 1);
0259 fZPlanes.Allocate(Nz);
0260 fRMin.Allocate(Nz);
0261 fRMax.Allocate(Nz);
0262 fSameZ.Allocate(Nz);
0263
0264
0265 Initialize(phiStart, phiDelta, sideCount, Nz, zArg, rMin, rMax);
0266 delete[] rnew;
0267 delete[] znew;
0268 delete[] rMin;
0269 delete[] rMax;
0270 delete[] zArg;
0271 }
0272
0273 VECCORE_ATT_HOST_DEVICE
0274 ~PolyhedronStruct() { delete fAreaStruct; }
0275
0276 VECCORE_ATT_HOST_DEVICE
0277 VECGEOM_FORCE_INLINE
0278 static size_t aligned_sizeof_data(Precision , Precision phiDelta, const int sideCount,
0279 const int zPlaneCount, Precision const zPlanes[], Precision const rMin[],
0280 Precision const rMax[])
0281 {
0282 const bool hasPhiCutout = phiDelta < 2 * kPi;
0283 size_t aligned_size = (zPlaneCount - 1) * sizeof(ZSegment);
0284
0285 aligned_size += 5 * kAlignmentBoundary;
0286
0287 for (int i = 0; i < zPlaneCount - 1; ++i) {
0288
0289 VECGEOM_ASSERT(zPlanes[i] <= zPlanes[i + 1]);
0290 bool hasInnerRadius = rMin[i] > kTolerance || rMin[i + 1] > kTolerance;
0291 int multiplier = (ApproxEqual(zPlanes[i], zPlanes[i + 1]) && ApproxEqual(rMax[i], rMax[i + 1])) ? 0 : 1;
0292 aligned_size += Quadrilaterals::aligned_sizeof_data(sideCount * multiplier);
0293
0294 if (hasPhiCutout) {
0295 multiplier = (zPlanes[i] == zPlanes[i + 1]) ? 0 : 1;
0296 aligned_size += Quadrilaterals::aligned_sizeof_data(2 * multiplier);
0297 }
0298 multiplier = (zPlanes[i] == zPlanes[i + 1] && rMin[i] == rMin[i + 1]) ? 0 : 1;
0299 if (hasInnerRadius && multiplier > 0) {
0300 aligned_size += Quadrilaterals::aligned_sizeof_data(sideCount * multiplier);
0301 }
0302 }
0303
0304 aligned_size += 3 * Array<T>::aligned_sizeof_data(zPlaneCount);
0305
0306 aligned_size += Array<bool>::aligned_sizeof_data(zPlaneCount);
0307
0308 aligned_size += SOA3D<T>::aligned_sizeof_data(sideCount + 1);
0309 return aligned_size;
0310 }
0311
0312 VECCORE_ATT_HOST_DEVICE
0313 bool CheckContinuityInSlope(const Precision rOuter[], const Precision zPlane[], const unsigned int nz)
0314 {
0315 Precision prevSlope = kInfLength;
0316 for (unsigned int j = 0; j < nz - 1; ++j) {
0317 if (ApproxEqual(zPlane[j + 1], zPlane[j])) {
0318 if (!ApproxEqual(rOuter[j + 1], rOuter[j])) return false;
0319 } else {
0320 Precision currentSlope = (rOuter[j + 1] - rOuter[j]) / (zPlane[j + 1] - zPlane[j]);
0321 if (currentSlope > prevSlope) return false;
0322 prevSlope = currentSlope;
0323 }
0324 }
0325 return true;
0326 }
0327
0328 VECCORE_ATT_HOST_DEVICE
0329 void Dump()
0330 {
0331 auto dump_planes = [](Planes const &planes) {
0332 auto const &normals = planes.GetNormals();
0333 auto const &distances = planes.GetDistances();
0334 printf("[%d]: convex=%d normals[%p] distances[%p]", planes.size(), planes.IsConvex(), (void *)&normals,
0335 (void *)&distances);
0336 if (planes.size() == 0) printf(" : empty");
0337 printf("\n");
0338 for (size_t i = 0; i < planes.size(); ++i) {
0339 auto const &normal = normals[i];
0340 auto distance = distances[i];
0341 printf(" [%lu]: fNormal { %g, %g, %g } fDistance %g\n", i, normal[0], normal[1], normal[2], distance);
0342 }
0343 };
0344 printf("== PolyhedronStruct at: %p", (void *)this);
0345 printf(" side count: %d z_plane_count: %u phiStart: %g phiDelta: %g\n", fSideCount, fZPlanes.size(), fPhiStart,
0346 fPhiDelta);
0347 printf(" hasInnerRadii: %d hasPhiCutout: %d fHasLargePhiCutout: %d\n", fHasInnerRadii, fHasPhiCutout,
0348 fHasLargePhiCutout);
0349 for (size_t i = 0; i < fZSegments.size(); ++i) {
0350 printf(" ZSegments[%lu]:\n", i);
0351 auto const &zseg = fZSegments[i];
0352 printf(" outer\n");
0353 printf(" planes");
0354 dump_planes(zseg.outer.GetPlanes());
0355 for (size_t j = 0; j < 4; ++j) {
0356 printf(" side vectors[%lu]", j);
0357 dump_planes(zseg.outer.GetSideVectors()[j]);
0358 auto const &corners = zseg.outer.GetCorners()[j];
0359 if (corners.size()) printf(" corners[%lu]", j);
0360 for (size_t k = 0; k < corners.size(); ++k)
0361 printf(" %lu:{%g, %g, %g}", k, corners[k].x(), corners[k].y(), corners[k].z());
0362 if (corners.size()) printf("\n");
0363 }
0364 printf(" inner\n");
0365 printf(" planes");
0366 dump_planes(zseg.inner.GetPlanes());
0367 for (size_t j = 0; j < 4; ++j) {
0368 printf(" side vectors[%lu]", j);
0369 dump_planes(zseg.inner.GetSideVectors()[j]);
0370 auto const &corners = zseg.inner.GetCorners()[j];
0371 if (corners.size()) printf(" corners[%lu]", j);
0372 for (size_t k = 0; k < corners.size(); ++k)
0373 printf(" %lu:{%g, %g, %g}", k, corners[k].x(), corners[k].y(), corners[k].z());
0374 if (corners.size()) printf("\n");
0375 }
0376 printf(" phi\n");
0377 printf(" planes");
0378 dump_planes(zseg.phi.GetPlanes());
0379 for (size_t j = 0; j < 4; ++j) {
0380 printf(" side vectors[%lu]", j);
0381 dump_planes(zseg.phi.GetSideVectors()[j]);
0382 auto const &corners = zseg.phi.GetCorners()[j];
0383 if (corners.size()) printf(" corners[%lu]", j);
0384 for (size_t k = 0; k < corners.size(); ++k)
0385 printf(" %lu:{%g, %g, %g}", k, corners[k].x(), corners[k].y(), corners[k].z());
0386 if (corners.size()) printf("\n");
0387 }
0388 }
0389 printf("\n fZPlanes: ");
0390 for (size_t i = 0; i < fZPlanes.size(); ++i)
0391 printf(" %lu: %g", i, fZPlanes[i]);
0392 printf("\n fRMin: ");
0393 for (size_t i = 0; i < fRMin.size(); ++i)
0394 printf(" %lu: %g", i, fRMin[i]);
0395 printf("\n fRMax: ");
0396 for (size_t i = 0; i < fRMax.size(); ++i)
0397 printf(" %lu: %g", i, fRMax[i]);
0398 printf("\n fSameZ: ");
0399 for (size_t i = 0; i < fSameZ.size(); ++i)
0400 printf(" %lu: %d", i, fSameZ[i]);
0401 printf("\n fPhiSections: ");
0402 for (size_t i = 0; i < fPhiSections.size(); ++i)
0403 printf(" %lu: {%g, %g, %g}", i, fPhiSections[i].x(), fPhiSections[i].y(), fPhiSections[i].z());
0404 printf("\n");
0405 }
0406
0407
0408
0409 VECCORE_ATT_HOST_DEVICE
0410 void Initialize(Precision phiStart, Precision phiDelta, const int sideCount, const int zPlaneCount,
0411 Precision const zPlanes[], Precision const rMin[], Precision const rMax[])
0412 {
0413 typedef Vector3D<Precision> Vec_t;
0414
0415
0416 VECGEOM_ASSERT(zPlaneCount > 1);
0417 VECGEOM_ASSERT(fSideCount > 0);
0418 fSize = PolyhedronStruct<T>::aligned_sizeof_data(phiStart, phiDelta, sideCount, zPlaneCount, zPlanes, rMin, rMax);
0419
0420 for (auto i = 0; i < zPlaneCount; ++i) {
0421 fZPlanes[i] = 0.;
0422 fRMin[i] = 0.;
0423 fRMax[i] = 0.;
0424 fSameZ[i] = false;
0425 }
0426 copy(zPlanes, zPlanes + zPlaneCount, &fZPlanes[0]);
0427 copy(rMin, rMin + zPlaneCount, &fRMin[0]);
0428 copy(rMax, rMax + zPlaneCount, &fRMax[0]);
0429
0430 Precision startRmax = rMax[0];
0431 for (int i = 0; i < zPlaneCount; i++) {
0432 fConvexityPossible &= (rMin[i] < kTolerance);
0433 fEqualRmax &= (ApproxEqual(startRmax, rMax[i]));
0434 if (i > 0 && i < zPlaneCount - 2) {
0435 if (ApproxEqual(fZPlanes[i], fZPlanes[i + 1])) fSameZ[i] = true;
0436 }
0437 }
0438 fContinuousInSlope = CheckContinuityInSlope(rMax, zPlanes, zPlaneCount);
0439
0440
0441
0442
0443 for (int i = 0; i < zPlaneCount - 1; ++i) {
0444
0445 VECGEOM_ASSERT(zPlanes[i] <= zPlanes[i + 1]);
0446
0447 bool hasInnerRadius = rMin[i] > kTolerance || rMin[i + 1] > kTolerance;
0448
0449 int multiplier = (ApproxEqual(zPlanes[i], zPlanes[i + 1]) && ApproxEqual(rMax[i], rMax[i + 1])) ? 0 : 1;
0450
0451
0452 new (&fZSegments[i].outer) Quadrilaterals(sideCount * multiplier);
0453
0454
0455 if (fHasPhiCutout) {
0456 multiplier = (zPlanes[i] == zPlanes[i + 1]) ? 0 : 1;
0457 new (&fZSegments[i].phi) Quadrilaterals(2 * multiplier, phiDelta <= kPi);
0458 } else {
0459 new (&fZSegments[i].phi) Quadrilaterals(0);
0460 }
0461
0462 multiplier = (zPlanes[i] == zPlanes[i + 1] && rMin[i] == rMin[i + 1]) ? 0 : 1;
0463
0464 if (hasInnerRadius && multiplier > 0) {
0465 new (&fZSegments[i].inner) Quadrilaterals(sideCount * multiplier);
0466 fHasInnerRadii = true;
0467 } else {
0468 new (&fZSegments[i].inner) Quadrilaterals(0);
0469 }
0470 }
0471
0472
0473 if (phiDelta <= 0 || phiDelta > kTwoPi - kAngTolerance) phiDelta = kTwoPi;
0474 phiStart = NormalizeAngle<kScalar>(phiStart);
0475 if (phiDelta > kTwoPi) phiDelta = kTwoPi;
0476 Precision sidePhi = phiDelta / sideCount;
0477
0478 auto getPhi = [&](int side) {
0479 if (!fHasPhiCutout && side == sideCount) {
0480 side = 0;
0481 }
0482 return NormalizeAngle<kScalar>(phiStart + side * sidePhi);
0483 };
0484
0485 for (int i = 0, iMax = sideCount + 1; i < iMax; ++i) {
0486 Vector3D<Precision> cornerVector = Vec_t::FromCylindrical(1., getPhi(i), 0).Normalized().FixZeroes();
0487 fPhiSections.set(i, cornerVector.Normalized().Cross(Vector3D<Precision>(0, 0, -1)));
0488 }
0489
0490
0491
0492 Precision cosHalfDeltaPhi = cos(0.5 * sidePhi);
0493 Precision innerRadius = kInfLength, outerRadius = -kInfLength;
0494 for (int i = 0; i < zPlaneCount; ++i) {
0495
0496 if (rMin[i] < innerRadius) innerRadius = rMin[i];
0497 VECGEOM_ASSERT(rMin[i] >= 0 && rMax[i] >= 0);
0498
0499 if (rMax[i] > outerRadius) outerRadius = rMax[i];
0500 }
0501
0502
0503 outerRadius /= cosHalfDeltaPhi;
0504
0505
0506 Precision boundingTubeZ = 0.5 * (zPlanes[zPlaneCount - 1] - zPlanes[0]) + kTolerance;
0507
0508 const Precision kPhiTolerance = 100 * kTolerance;
0509
0510
0511
0512 Precision boundsPhiStart = !fHasPhiCutout ? 0 : phiStart - kPhiTolerance;
0513 Precision boundsPhiDelta = !fHasPhiCutout ? kTwoPi : phiDelta + 2 * kPhiTolerance;
0514
0515 fBoundingTube = TubeStruct<Precision>(innerRadius - kHalfTolerance, outerRadius + kHalfTolerance, boundingTubeZ,
0516 boundsPhiStart, boundsPhiDelta);
0517
0518
0519 fBoundingTubeOffset = 0.5 * (zPlanes[0] + zPlanes[zPlaneCount - 1]);
0520
0521 auto getVertexImpl = [&](Precision const r[], int i, int j) {
0522 if (!fHasPhiCutout && j == sideCount) {
0523 j = 0;
0524 }
0525 return Vec_t::FromCylindrical(r[i] / cosHalfDeltaPhi, getPhi(j), zPlanes[i]).FixZeroes();
0526 };
0527
0528 auto getInnerVertex = [&](int i, int j) { return getVertexImpl(rMin, i, j); };
0529 auto getOuterVertex = [&](int i, int j) { return getVertexImpl(rMax, i, j); };
0530
0531
0532 for (int iPlane = 0; iPlane < zPlaneCount - 1; ++iPlane) {
0533
0534 auto WrongNormal = [](Vector3D<Precision> const &normal, Vector3D<Precision> const &corner) {
0535 return normal[0] * corner[0] + normal[1] * corner[1] < 0;
0536 };
0537
0538
0539 for (int iSide = 0; iSide < fZSegments[iPlane].outer.size(); ++iSide) {
0540 fZSegments[iPlane].outer.Set(iSide, getOuterVertex(iPlane, iSide), getOuterVertex(iPlane, iSide + 1),
0541 getOuterVertex(iPlane + 1, iSide + 1), getOuterVertex(iPlane + 1, iSide));
0542
0543 if (WrongNormal(fZSegments[iPlane].outer.GetNormal(iSide), getOuterVertex(iPlane, iSide))) {
0544 fZSegments[iPlane].outer.FlipSign(iSide);
0545 }
0546 }
0547 for (int iSide = 0; iSide < fZSegments[iPlane].inner.size(); ++iSide) {
0548 fZSegments[iPlane].inner.Set(iSide, getInnerVertex(iPlane, iSide), getInnerVertex(iPlane, iSide + 1),
0549 getInnerVertex(iPlane + 1, iSide + 1), getInnerVertex(iPlane + 1, iSide));
0550
0551 if (WrongNormal(fZSegments[iPlane].inner.GetNormal(iSide), getInnerVertex(iPlane, iSide))) {
0552 fZSegments[iPlane].inner.FlipSign(iSide);
0553 }
0554 }
0555
0556 if (fHasPhiCutout && fZSegments[iPlane].phi.size() == 2) {
0557
0558
0559
0560 fZSegments[iPlane].phi.Set(0, getInnerVertex(iPlane, 0), getInnerVertex(iPlane + 1, 0),
0561 getOuterVertex(iPlane + 1, 0), getOuterVertex(iPlane, 0));
0562
0563 if (fZSegments[iPlane].phi.GetNormal(0).Dot(fPhiSections[0]) > 0) {
0564 fZSegments[iPlane].phi.FlipSign(0);
0565 }
0566 fZSegments[iPlane].phi.Set(1, getOuterVertex(iPlane, sideCount), getOuterVertex(iPlane + 1, sideCount),
0567 getInnerVertex(iPlane + 1, sideCount), getInnerVertex(iPlane, sideCount));
0568
0569 if (fZSegments[iPlane].phi.GetNormal(1).Dot(fPhiSections[fSideCount]) < 0) {
0570 fZSegments[iPlane].phi.FlipSign(1);
0571 }
0572 }
0573
0574 }
0575 }
0576
0577
0578
0579 VECCORE_ATT_HOST_DEVICE
0580 void Initialize(Precision phiStart, Precision phiDelta, const int sideCount, const int zPlaneCount,
0581 Precision const zPlanes[], Precision const rMin[], Precision const rMax[], AlignedAllocator &a)
0582 {
0583 typedef Vector3D<Precision> Vec_t;
0584
0585
0586 VECGEOM_ASSERT(zPlaneCount > 1);
0587 VECGEOM_ASSERT(fSideCount > 0);
0588
0589 for (auto i = 0; i < zPlaneCount; ++i) {
0590 fZPlanes[i] = 0.;
0591 fRMin[i] = 0.;
0592 fRMax[i] = 0.;
0593 fSameZ[i] = false;
0594 }
0595 copy(zPlanes, zPlanes + zPlaneCount, &fZPlanes[0]);
0596 copy(rMin, rMin + zPlaneCount, &fRMin[0]);
0597 copy(rMax, rMax + zPlaneCount, &fRMax[0]);
0598
0599 Precision startRmax = rMax[0];
0600 for (int i = 0; i < zPlaneCount; i++) {
0601 fConvexityPossible &= (rMin[i] < kTolerance);
0602 fEqualRmax &= (ApproxEqual(startRmax, rMax[i]));
0603 if (i > 0 && i < zPlaneCount - 2) {
0604 if (ApproxEqual(fZPlanes[i], fZPlanes[i + 1])) fSameZ[i] = true;
0605 }
0606 }
0607 fContinuousInSlope = CheckContinuityInSlope(rMax, zPlanes, zPlaneCount);
0608
0609
0610
0611
0612 for (int i = 0; i < zPlaneCount - 1; ++i) {
0613
0614 VECGEOM_ASSERT(zPlanes[i] <= zPlanes[i + 1]);
0615
0616 bool hasInnerRadius = rMin[i] > kTolerance || rMin[i + 1] > kTolerance;
0617 bool convex = phiDelta <= kPi;
0618
0619 int multiplier = (ApproxEqual(zPlanes[i], zPlanes[i + 1]) && ApproxEqual(rMax[i], rMax[i + 1])) ? 0 : 1;
0620 size_t nouter = sideCount * multiplier;
0621
0622
0623 size_t nphi = 0;
0624 if (fHasPhiCutout) {
0625 multiplier = (zPlanes[i] == zPlanes[i + 1]) ? 0 : 1;
0626 nphi = 2 * multiplier;
0627 }
0628
0629 multiplier = (zPlanes[i] == zPlanes[i + 1] && rMin[i] == rMin[i + 1]) ? 0 : 1;
0630 size_t ninner = 0;
0631
0632 if (hasInnerRadius && multiplier > 0) {
0633 ninner = sideCount * multiplier;
0634 fHasInnerRadii = true;
0635 }
0636
0637
0638 new (&fZSegments[i]) ZSegment(nouter, ninner, nphi, a, convex);
0639 }
0640
0641
0642 if (phiDelta <= 0 || phiDelta > kTwoPi - kAngTolerance) phiDelta = kTwoPi;
0643 phiStart = NormalizeAngle<kScalar>(phiStart);
0644 if (phiDelta > kTwoPi) phiDelta = kTwoPi;
0645 Precision sidePhi = phiDelta / sideCount;
0646
0647 auto getPhi = [&](int side) {
0648 if (!fHasPhiCutout && side == sideCount) {
0649 side = 0;
0650 }
0651 return NormalizeAngle<kScalar>(phiStart + side * sidePhi);
0652 };
0653
0654 for (int i = 0, iMax = sideCount + 1; i < iMax; ++i) {
0655 Vector3D<Precision> cornerVector = Vec_t::FromCylindrical(1., getPhi(i), 0).Normalized().FixZeroes();
0656 fPhiSections.set(i, cornerVector.Normalized().Cross(Vector3D<Precision>(0, 0, -1)));
0657 }
0658
0659
0660
0661 Precision cosHalfDeltaPhi = cos(0.5 * sidePhi);
0662 Precision innerRadius = kInfLength, outerRadius = -kInfLength;
0663 for (int i = 0; i < zPlaneCount; ++i) {
0664
0665 if (rMin[i] < innerRadius) innerRadius = rMin[i];
0666 VECGEOM_ASSERT(rMin[i] >= 0 && rMax[i] >= 0);
0667
0668 if (rMax[i] > outerRadius) outerRadius = rMax[i];
0669 }
0670
0671
0672 outerRadius /= cosHalfDeltaPhi;
0673
0674
0675 Precision boundingTubeZ = 0.5 * (zPlanes[zPlaneCount - 1] - zPlanes[0]) + kTolerance;
0676
0677 const Precision kPhiTolerance = 100 * kTolerance;
0678
0679
0680
0681 Precision boundsPhiStart = !fHasPhiCutout ? 0 : phiStart - kPhiTolerance;
0682 Precision boundsPhiDelta = !fHasPhiCutout ? kTwoPi : phiDelta + 2 * kPhiTolerance;
0683
0684 fBoundingTube = TubeStruct<Precision>(innerRadius - kHalfTolerance, outerRadius + kHalfTolerance, boundingTubeZ,
0685 boundsPhiStart, boundsPhiDelta);
0686
0687
0688 fBoundingTubeOffset = 0.5 * (zPlanes[0] + zPlanes[zPlaneCount - 1]);
0689
0690 auto getVertexImpl = [&](Precision const r[], int i, int j) {
0691 if (!fHasPhiCutout && j == sideCount) {
0692 j = 0;
0693 }
0694 return Vec_t::FromCylindrical(r[i] / cosHalfDeltaPhi, getPhi(j), zPlanes[i]).FixZeroes();
0695 };
0696
0697 auto getInnerVertex = [&](int i, int j) { return getVertexImpl(rMin, i, j); };
0698 auto getOuterVertex = [&](int i, int j) { return getVertexImpl(rMax, i, j); };
0699
0700
0701 for (int iPlane = 0; iPlane < zPlaneCount - 1; ++iPlane) {
0702
0703 auto WrongNormal = [](Vector3D<Precision> const &normal, Vector3D<Precision> const &corner) {
0704 return normal[0] * corner[0] + normal[1] * corner[1] < 0;
0705 };
0706
0707
0708 for (int iSide = 0; iSide < fZSegments[iPlane].outer.size(); ++iSide) {
0709 fZSegments[iPlane].outer.Set(iSide, getOuterVertex(iPlane, iSide), getOuterVertex(iPlane, iSide + 1),
0710 getOuterVertex(iPlane + 1, iSide + 1), getOuterVertex(iPlane + 1, iSide));
0711
0712 if (WrongNormal(fZSegments[iPlane].outer.GetNormal(iSide), getOuterVertex(iPlane, iSide))) {
0713 fZSegments[iPlane].outer.FlipSign(iSide);
0714 }
0715 }
0716 for (int iSide = 0; iSide < fZSegments[iPlane].inner.size(); ++iSide) {
0717 fZSegments[iPlane].inner.Set(iSide, getInnerVertex(iPlane, iSide), getInnerVertex(iPlane, iSide + 1),
0718 getInnerVertex(iPlane + 1, iSide + 1), getInnerVertex(iPlane + 1, iSide));
0719
0720 if (WrongNormal(fZSegments[iPlane].inner.GetNormal(iSide), getInnerVertex(iPlane, iSide))) {
0721 fZSegments[iPlane].inner.FlipSign(iSide);
0722 }
0723 }
0724
0725 if (fHasPhiCutout && fZSegments[iPlane].phi.size() == 2) {
0726
0727
0728
0729 fZSegments[iPlane].phi.Set(0, getInnerVertex(iPlane, 0), getInnerVertex(iPlane + 1, 0),
0730 getOuterVertex(iPlane + 1, 0), getOuterVertex(iPlane, 0));
0731
0732 if (fZSegments[iPlane].phi.GetNormal(0).Dot(fPhiSections[0]) > 0) {
0733 fZSegments[iPlane].phi.FlipSign(0);
0734 }
0735 fZSegments[iPlane].phi.Set(1, getOuterVertex(iPlane, sideCount), getOuterVertex(iPlane + 1, sideCount),
0736 getInnerVertex(iPlane + 1, sideCount), getInnerVertex(iPlane, sideCount));
0737
0738 if (fZSegments[iPlane].phi.GetNormal(1).Dot(fPhiSections[fSideCount]) < 0) {
0739 fZSegments[iPlane].phi.FlipSign(1);
0740 }
0741 }
0742
0743 }
0744 }
0745 };
0746 }
0747 }
0748
0749 #endif