File indexing completed on 2026-04-17 08:35:32
0001 #ifndef VECGEOM_SURFACE_CPUTYPES_H
0002 #define VECGEOM_SURFACE_CPUTYPES_H
0003
0004 #include <VecGeom/surfaces/base/CommonTypes.h>
0005 #include <VecGeom/surfaces/Model.h>
0006 #include <set>
0007
0008 namespace vgbrep {
0009
0010 template <typename T>
0011 VECGEOM_FORCE_INLINE char const *to_cstring(T type)
0012 {
0013 return nullptr;
0014 }
0015
0016 template <>
0017 VECGEOM_FORCE_INLINE char const *to_cstring<SurfaceType>(SurfaceType type)
0018 {
0019 static const char *const data[] = {"no_surf", "planar", "cylindrical", "conical",
0020 "spherical", "torus", "elliptical", "arb4"};
0021 VECGEOM_ASSERT(size_t(type) * sizeof(const char *) < sizeof(data));
0022 return data[static_cast<int>(type)];
0023 }
0024
0025 template <>
0026 VECGEOM_FORCE_INLINE char const *to_cstring<bool>(bool type)
0027 {
0028 if (type) return "true";
0029 return "false";
0030 }
0031
0032 template <>
0033 VECGEOM_FORCE_INLINE char const *to_cstring<FrameType>(FrameType type)
0034 {
0035 static const char *const data[] = {"no_frame", "rangeZ", "ring", "z_phi", "rangeSph", "window", "triangle", "quad"};
0036 VECGEOM_ASSERT(size_t(type) * sizeof(const char *) < sizeof(data));
0037 return data[static_cast<int>(type)];
0038 }
0039
0040 template <>
0041 VECGEOM_FORCE_INLINE char const *to_cstring<AxisType>(AxisType type)
0042 {
0043 static const char *const data[] = {"x-axis", "y-axis", "z-axis", "r-axis", "phi-axis", "xy-grid", "no-axis"};
0044 VECGEOM_ASSERT(size_t(type) * sizeof(const char *) < sizeof(data));
0045 return data[static_cast<int>(type)];
0046 }
0047
0048 using LogicExpressionCPU = std::vector<logic_int>;
0049
0050
0051
0052
0053
0054 struct VolumeShellCPU {
0055 std::vector<int> fSurfaces;
0056 std::vector<int> fExitingSurfaces;
0057 std::vector<int> fEnteringSurfaces;
0058 std::vector<int> fEnteringSurfacesPvol;
0059 std::vector<int> fEnteringSurfacesPvolTrans;
0060 std::vector<int> fEnteringSurfacesLvolIds;
0061 std::vector<int> fDaughterPvolIds;
0062 std::vector<int> fDaughterPvolTrans;
0063
0064 LogicExpressionCPU fLogic;
0065 bool fSimplified{false};
0066 int fBVH{0};
0067 };
0068
0069
0070
0071
0072
0073 struct SideDivisionCPU {
0074 using VecInt_t = std::vector<int>;
0075 double fStartU{0.};
0076 double fStepU{0.};
0077 double fStartV{0.};
0078 double fStepV{0.};
0079 unsigned short fNslices{0};
0080 unsigned short fNslicesU{0};
0081 unsigned short fNslicesV{1};
0082 AxisType fAxis{AxisType::kNoAxis};
0083 std::vector<VecInt_t> fSlices;
0084
0085
0086 SideDivisionCPU() = default;
0087 SideDivisionCPU(AxisType axis, double coord_min, double coord_max, int ncand)
0088 : fStartU(coord_min), fStepU((coord_max - coord_min) / ncand), fNslices(ncand), fAxis(axis)
0089 {
0090 fSlices.insert(fSlices.end(), ncand, {});
0091 }
0092
0093 SideDivisionCPU(AxisType axis, double coord_minU, double coord_maxU, double coord_minV, double coord_maxV, int ncand)
0094 : fAxis(axis)
0095 {
0096 fNslicesU = 1 + std::sqrt(static_cast<double>(ncand));
0097 fNslicesV = ncand / fNslicesU;
0098 fNslices = fNslicesU * fNslicesV;
0099 fStartU = coord_minU;
0100 fStepU = (coord_maxU - coord_minU) / fNslicesU;
0101 fStartV = coord_minV;
0102 fStepV = (coord_maxV - coord_minV) / fNslicesV;
0103 fSlices.insert(fSlices.end(), fNslices, {});
0104 }
0105
0106 void AddCandidate(int icand, double coord_min, double coord_max)
0107 {
0108 int istart = (coord_min - fStartU - vecgeom::kToleranceDist<double>) / fStepU;
0109 int iend = (coord_max - fStartU + vecgeom::kToleranceDist<double>) / fStepU;
0110 for (int i = istart; i <= iend && i < fNslices; ++i) {
0111 if (i < 0) continue;
0112 fSlices[i].push_back(icand);
0113 }
0114 }
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124 int GetNslices(Vector3D<double> const &amin, Vector3D<double> const &amax, int &umin, int &umax, int &vmin,
0125 int &vmax) const
0126 {
0127 umin = umax = vmin = vmax = 0;
0128 switch (fAxis) {
0129 case AxisType::kXY: {
0130 umin = std::max(0, int((amin[0] - fStartU) / fStepU));
0131 if (umin >= fNslicesU) return 0;
0132 umax = std::min(fNslicesU - 1, int((amax[0] - fStartU) / fStepU));
0133 if (umax < 0) return 0;
0134 vmin = std::max(0, int((amin[1] - fStartV) / fStepV));
0135 if (vmin >= fNslicesV) return 0;
0136 vmax = std::min(fNslicesV - 1, int((amax[1] - fStartV) / fStepV));
0137 if (vmax < 0) return 0;
0138 return (umax - umin + 1) * (vmax - vmin + 1);
0139 }
0140 case AxisType::kR: {
0141 auto rmin = amin[0];
0142 auto rmax = amax[0];
0143 umin = std::max(0, int((rmin - fStartU) / fStepU));
0144 if (umin >= fNslices) return 0;
0145 umax = std::min(fNslices - 1, int((rmax - fStartU) / fStepU));
0146 if (umax < 0) return 0;
0147 return (umax - umin + 1);
0148 }
0149 case AxisType::kPhi: {
0150 VECGEOM_LOG(error) << "GetNdlices not supported for phi division";
0151 return 0;
0152 }
0153 default:
0154 umin = std::max(0, int((amin[fAxis] - fStartU) / fStepU));
0155 if (umin >= fNslices) return 0;
0156 umax = std::min(fNslices - 1, int((amax[fAxis] - fStartU) / fStepU));
0157 if (umax < 0) return 0;
0158 return (umax - umin + 1);
0159 }
0160 }
0161
0162 void AddCandidate(int icand, double umin, double umax, double vmin, double vmax)
0163 {
0164 int istartU = (umin - fStartU - vecgeom::kToleranceDist<double>) / fStepU;
0165 int iendU = (umax - fStartU + vecgeom::kToleranceDist<double>) / fStepU;
0166 int istartV = (vmin - fStartV - vecgeom::kToleranceDist<double>) / fStepV;
0167 int iendV = (vmax - fStartV + vecgeom::kToleranceDist<double>) / fStepV;
0168 for (int i = istartU; i <= iendU && i < fNslicesU; ++i) {
0169 for (int j = istartV; j <= iendV && j < fNslicesV; ++j) {
0170 if (i < 0 || j < 0) continue;
0171 fSlices[i * fNslicesV + j].push_back(icand);
0172 }
0173 }
0174 }
0175
0176 const VecInt_t *GetSlice(int u, int v) const { return &fSlices[u * fNslicesV + v]; }
0177
0178 template <typename Real_t>
0179 void CopyTo(SideDivision<Real_t> &div, SliceCand *slices, int *candidates) const
0180 {
0181 div.fStartU = fStartU;
0182 div.fStepU = fStepU;
0183 div.fStartV = fStartV;
0184 div.fStepV = fStepV;
0185 div.fNslices = fNslices;
0186 div.fNslicesU = fNslicesU;
0187 div.fNslicesV = fNslicesV;
0188 div.fAxis = fAxis;
0189 div.fSlices = slices;
0190 auto cand = candidates;
0191 for (size_t i = 0; i < fSlices.size(); ++i) {
0192 slices[i].fNcand = fSlices[i].size();
0193 slices[i].fCandidates = cand;
0194 for (int j = 0; j < slices[i].fNcand; ++j)
0195 cand[j] = fSlices[i][j];
0196 cand += slices[i].fNcand;
0197 }
0198 }
0199
0200 template <typename Real_t>
0201 size_t GetSizeObject() const
0202 {
0203 return sizeof(SideDivision<Real_t>);
0204 }
0205
0206 template <typename Real_t>
0207 size_t GetSizeSlices() const
0208 {
0209 return fNslices * sizeof(SliceCand);
0210 }
0211
0212 size_t GetNcandidates() const
0213 {
0214 size_t size = 0;
0215 for (auto i = 0; i < fNslices; ++i)
0216 size += fSlices[i].size();
0217 return size;
0218 }
0219
0220 size_t GetSizeCandidates() const { return GetNcandidates() * sizeof(int); }
0221
0222 template <typename Real_t>
0223 size_t GetSize() const
0224 {
0225 size_t size = GetSizeObject<Real_t>() + GetSizeSlices<Real_t>() + GetSizeCandidates();
0226 return size;
0227 }
0228
0229 void Print() const
0230 {
0231 if (fAxis == AxisType::kXY) {
0232 std::cout << to_cstring(fAxis) << " division: fNslices = " << fNslices << ", fNslicesU = " << fNslicesU
0233 << ", fNslicesV = " << fNslicesV << ", fStartU = " << fStartU << ", fStepU = " << fStepU
0234 << ", fStartV = " << fStartV << ", fStepV = " << fStepV << ", efficiency = " << 100 * Efficiency()
0235 << " %\n";
0236 } else {
0237 std::cout << to_cstring(fAxis) << " division: fNslices = " << fNslices << ", fStart = " << fStartU
0238 << ", fStep = " << fStepU << ", efficiency = " << 100 * Efficiency() << " %\n";
0239 }
0240 for (auto i = 0; i < fNslices; ++i)
0241 std::cout << fSlices[i].size() << " ";
0242 std::cout << "\n";
0243 }
0244
0245 double Efficiency() const
0246 {
0247
0248 double average = 0;
0249 for (auto i = 0; i < fNslices; ++i)
0250 average += fSlices[i].size();
0251 average /= fNslices;
0252 double eff = (fNslices - average) / (average * (fNslices - 1));
0253 return eff;
0254 }
0255 };
0256
0257
0258 template <typename Real_t>
0259 struct CPUsurfData {
0260 using VecInt_t = std::vector<int>;
0261 using VecChar_t = std::vector<char>;
0262 using MultimapInt_t = std::multimap<long, int>;
0263 using SurfData_t = SurfData<Real_t>;
0264 using EllipData_t = EllipData<Real_t>;
0265 using TorusData_t = TorusData<Real_t>;
0266 using Arb4Data_t = Arb4Data<Real_t>;
0267 using WindowMask_t = WindowMask<Real_t>;
0268 using RingMask_t = RingMask<Real_t>;
0269 using ZPhiMask_t = ZPhiMask<Real_t>;
0270 using TriangleMask_t = TriangleMask<Real_t>;
0271 using QuadMask_t = QuadrilateralMask<Real_t>;
0272
0273 std::vector<WindowMask_t> fWindowMasks;
0274 std::vector<RingMask_t> fRingMasks;
0275 std::vector<ZPhiMask_t> fZPhiMasks;
0276 std::vector<TriangleMask_t> fTriangleMasks;
0277 std::vector<QuadMask_t> fQuadMasks;
0278
0279 std::vector<EllipData_t> fEllipData;
0280 std::vector<TorusData_t> fTorusData;
0281 std::vector<Arb4Data_t> fArb4Data;
0282 std::vector<TransformationMP<Real_t>> fPVolTrans;
0283 std::vector<FramedSurface<Real_t, TransformationMP<Real_t>>> fLocalSurfaces;
0284 std::vector<FramedSurface<Real_t, TransformationMP<Real_t>>> fFramedSurf;
0285 std::vector<CommonSurface<Real_t>> fCommonSurfaces;
0286 std::vector<VolumeShellCPU> fShells;
0287 std::vector<VolumeShellCPU> fSceneShells;
0288
0289 VecInt_t fSceneStartIndex;
0290 VecInt_t fSceneTouchables;
0291 std::vector<MultimapInt_t> fSurfHash;
0292
0293 std::vector<VecInt_t> fCandidatesEntering;
0294 std::vector<VecInt_t> fCandidatesExiting;
0295 std::vector<VecInt_t> fFrameIndEntering;
0296 std::vector<VecInt_t> fFrameIndExiting;
0297 std::vector<VecChar_t> fSidesEntering;
0298 std::vector<VecChar_t> fSidesExiting;
0299
0300 std::vector<SideDivisionCPU> fSideDivisions;
0301
0302 private:
0303 CPUsurfData() = default;
0304
0305 public:
0306 static VECGEOM_FORCE_INLINE CPUsurfData<Real_t> &Instance()
0307 {
0308 static CPUsurfData<Real_t> gCPUsurfdata;
0309 return gCPUsurfdata;
0310 }
0311
0312 void Clear()
0313 {
0314
0315 std::vector<WindowMask_t>().swap(fWindowMasks);
0316 std::vector<RingMask_t>().swap(fRingMasks);
0317 std::vector<ZPhiMask_t>().swap(fZPhiMasks);
0318 std::vector<TriangleMask_t>().swap(fTriangleMasks);
0319 std::vector<QuadMask_t>().swap(fQuadMasks);
0320 std::vector<EllipData_t>().swap(fEllipData);
0321 std::vector<TorusData_t>().swap(fTorusData);
0322 std::vector<TransformationMP<Real_t>>().swap(fPVolTrans);
0323 std::vector<FramedSurface<Real_t, TransformationMP<Real_t>>>().swap(fLocalSurfaces);
0324 std::vector<FramedSurface<Real_t, TransformationMP<Real_t>>>().swap(fFramedSurf);
0325 std::vector<CommonSurface<Real_t>>().swap(fCommonSurfaces);
0326 std::vector<VolumeShellCPU>().swap(fShells);
0327 std::vector<VolumeShellCPU>().swap(fSceneShells);
0328 VecInt_t().swap(fSceneStartIndex);
0329 VecInt_t().swap(fSceneTouchables);
0330 std::vector<MultimapInt_t>().swap(fSurfHash);
0331 std::vector<VecInt_t>().swap(fCandidatesEntering);
0332 std::vector<VecInt_t>().swap(fCandidatesExiting);
0333 std::vector<VecInt_t>().swap(fFrameIndEntering);
0334 std::vector<VecInt_t>().swap(fFrameIndExiting);
0335 std::vector<VecChar_t>().swap(fSidesEntering);
0336 std::vector<VecChar_t>().swap(fSidesExiting);
0337 std::vector<SideDivisionCPU>().swap(fSideDivisions);
0338 }
0339
0340 VecInt_t &GetCandidatesEntering(int scene_id, int state_id)
0341 {
0342 return fCandidatesEntering[fSceneStartIndex[scene_id] + state_id];
0343 }
0344
0345 VecInt_t &GetCandidatesExiting(int scene_id, int state_id)
0346 {
0347 return fCandidatesExiting[fSceneStartIndex[scene_id] + state_id];
0348 }
0349
0350 VecInt_t &GetFrameIndEntering(int scene_id, int state_id)
0351 {
0352 return fFrameIndEntering[fSceneStartIndex[scene_id] + state_id];
0353 }
0354
0355 VecInt_t &GetFrameIndExiting(int scene_id, int state_id)
0356 {
0357 return fFrameIndExiting[fSceneStartIndex[scene_id] + state_id];
0358 }
0359
0360 VecChar_t &GetSidesEntering(int scene_id, int state_id)
0361 {
0362 return fSidesEntering[fSceneStartIndex[scene_id] + state_id];
0363 }
0364
0365 VecChar_t &GetSidesExiting(int scene_id, int state_id)
0366 {
0367 return fSidesExiting[fSceneStartIndex[scene_id] + state_id];
0368 }
0369
0370 WindowMask_t const &GetWindowMask(int id) const { return fWindowMasks[id]; }
0371 RingMask_t const &GetRingMask(int id) const { return fRingMasks[id]; }
0372 ZPhiMask_t const &GetZPhiMask(int id) const { return fZPhiMasks[id]; }
0373 TriangleMask_t const &GetTriangleMask(int id) const { return fTriangleMasks[id]; }
0374 QuadMask_t const &GetQuadMask(int id) const { return fQuadMasks[id]; }
0375
0376 EllipData_t const &GetEllipData(int id) const { return fEllipData[id]; }
0377 TorusData_t const &GetTorusData(int id) const { return fTorusData[id]; }
0378 Arb4Data_t const &GetArb4Data(int id) const { return fArb4Data[id]; }
0379
0380
0381
0382
0383
0384 FrameIntersect CheckFrames(FramedSurface<Real_t, TransformationMP<Real_t>> const &f1,
0385 FramedSurface<Real_t, TransformationMP<Real_t>> const &f2,
0386 TransformationMP<Real_t> *tscene = nullptr)
0387 {
0388 auto log_not_supported = [&]() {
0389 VECGEOM_LOG(error) << "Embedding check " << to_cstring(f1.fFrame.type) << " - " << to_cstring(f2.fFrame.type)
0390 << " not supported";
0391 };
0392 TransformationMP<Real_t> t1 = f1.fTrans;
0393 TransformationMP<Real_t> t2 = f2.fTrans;
0394 if (tscene) t2 *= (*tscene);
0395 TransformationMP<Real_t> trans = t2 * t1.Inverse();
0396 trans.SetProperties();
0397
0398 switch (f1.fFrame.type) {
0399 case FrameType::kRing: {
0400 RingMask_t const mask1 = GetRingMask(f1.fFrame.id);
0401 switch (f2.fFrame.type) {
0402 case FrameType::kRing: {
0403 RingMask_t const mask2 = GetRingMask(f2.fFrame.id);
0404 return FrameChecker<Real_t, RingMask_t, RingMask_t>::CheckFrames(mask1, mask2, trans);
0405 }
0406 case FrameType::kWindow: {
0407 WindowMask_t const mask2 = GetWindowMask(f2.fFrame.id);
0408 return FrameChecker<Real_t, RingMask_t, WindowMask_t>::CheckFrames(mask1, mask2, trans);
0409 }
0410 case FrameType::kTriangle: {
0411 TriangleMask_t const mask2 = GetTriangleMask(f2.fFrame.id);
0412 return FrameChecker<Real_t, RingMask_t, TriangleMask_t>::CheckFrames(mask1, mask2, trans);
0413 }
0414 case FrameType::kQuadrilateral: {
0415 QuadMask_t const mask2 = GetQuadMask(f2.fFrame.id);
0416 return FrameChecker<Real_t, RingMask_t, QuadMask_t>::CheckFrames(mask1, mask2, trans);
0417 }
0418 default:
0419 log_not_supported();
0420 };
0421 break;
0422 }
0423 case FrameType::kZPhi: {
0424 ZPhiMask_t const mask1 = GetZPhiMask(f1.fFrame.id);
0425 switch (f2.fFrame.type) {
0426 case FrameType::kZPhi: {
0427 ZPhiMask_t const mask2 = GetZPhiMask(f2.fFrame.id);
0428 return FrameChecker<Real_t, ZPhiMask_t, ZPhiMask_t>::CheckFrames(mask1, mask2, trans);
0429 }
0430 default:
0431 log_not_supported();
0432 };
0433 break;
0434 }
0435 case FrameType::kWindow: {
0436 WindowMask_t const mask1 = GetWindowMask(f1.fFrame.id);
0437 switch (f2.fFrame.type) {
0438 case FrameType::kRing: {
0439 RingMask_t const mask2 = GetRingMask(f2.fFrame.id);
0440 return FrameChecker<Real_t, WindowMask_t, RingMask_t>::CheckFrames(mask1, mask2, trans);
0441 }
0442 case FrameType::kWindow: {
0443 WindowMask_t const mask2 = GetWindowMask(f2.fFrame.id);
0444 return FrameChecker<Real_t, WindowMask_t, WindowMask_t>::CheckFrames(mask1, mask2, trans);
0445 }
0446 case FrameType::kTriangle: {
0447 TriangleMask_t const mask2 = GetTriangleMask(f2.fFrame.id);
0448 return FrameChecker<Real_t, WindowMask_t, TriangleMask_t>::CheckFrames(mask1, mask2, trans);
0449 }
0450 case FrameType::kQuadrilateral: {
0451 QuadMask_t const mask2 = GetQuadMask(f2.fFrame.id);
0452 return FrameChecker<Real_t, WindowMask_t, QuadMask_t>::CheckFrames(mask1, mask2, trans);
0453 }
0454 default:
0455 log_not_supported();
0456 };
0457 break;
0458 }
0459 case FrameType::kTriangle: {
0460 TriangleMask_t const mask1 = GetTriangleMask(f1.fFrame.id);
0461 switch (f2.fFrame.type) {
0462 case FrameType::kRing: {
0463 RingMask_t const mask2 = GetRingMask(f2.fFrame.id);
0464 return FrameChecker<Real_t, TriangleMask_t, RingMask_t>::CheckFrames(mask1, mask2, trans);
0465 }
0466 case FrameType::kWindow: {
0467 WindowMask_t const mask2 = GetWindowMask(f2.fFrame.id);
0468 return FrameChecker<Real_t, TriangleMask_t, WindowMask_t>::CheckFrames(mask1, mask2, trans);
0469 }
0470 case FrameType::kTriangle: {
0471 TriangleMask_t const mask2 = GetTriangleMask(f2.fFrame.id);
0472 return FrameChecker<Real_t, TriangleMask_t, TriangleMask_t>::CheckFrames(mask1, mask2, trans);
0473 }
0474 case FrameType::kQuadrilateral: {
0475 QuadMask_t const mask2 = GetQuadMask(f2.fFrame.id);
0476 return FrameChecker<Real_t, TriangleMask_t, QuadMask_t>::CheckFrames(mask1, mask2, trans);
0477 }
0478 default:
0479 log_not_supported();
0480 };
0481 break;
0482 }
0483 case FrameType::kQuadrilateral: {
0484 QuadMask_t const mask1 = GetQuadMask(f1.fFrame.id);
0485 switch (f2.fFrame.type) {
0486 case FrameType::kRing: {
0487 RingMask_t const mask2 = GetRingMask(f2.fFrame.id);
0488 return FrameChecker<Real_t, QuadMask_t, RingMask_t>::CheckFrames(mask1, mask2, trans);
0489 }
0490 case FrameType::kWindow: {
0491 WindowMask_t const mask2 = GetWindowMask(f2.fFrame.id);
0492 return FrameChecker<Real_t, QuadMask_t, WindowMask_t>::CheckFrames(mask1, mask2, trans);
0493 }
0494 case FrameType::kTriangle: {
0495 TriangleMask_t const mask2 = GetTriangleMask(f2.fFrame.id);
0496 return FrameChecker<Real_t, QuadMask_t, TriangleMask_t>::CheckFrames(mask1, mask2, trans);
0497 }
0498 case FrameType::kQuadrilateral: {
0499 QuadMask_t const mask2 = GetQuadMask(f2.fFrame.id);
0500 return FrameChecker<Real_t, QuadMask_t, QuadMask_t>::CheckFrames(mask1, mask2, trans);
0501 }
0502 default:
0503 log_not_supported();
0504 };
0505 break;
0506 }
0507 default:
0508 log_not_supported();
0509 };
0510 return FrameIntersect::kNoIntersect;
0511 }
0512 };
0513
0514 }
0515
0516 #endif