File indexing completed on 2026-04-17 08:35:36
0001 #ifndef BVH_SURF_NAVIGATOR_H
0002 #define BVH_SURF_NAVIGATOR_H
0003
0004 #include <VecGeom/base/Vector3D.h>
0005 #include <VecGeom/base/BVH.h>
0006 #include <VecGeom/surfaces/Navigator.h>
0007
0008 namespace vgbrep {
0009 namespace protonav {
0010
0011
0012
0013 template <typename Real_t>
0014 VECCORE_ATT_HOST_DEVICE Real_t DistanceToLocalFS(vecgeom::Vector3D<Real_t> const &local,
0015 vecgeom::Vector3D<Real_t> const &localdir, int volId,
0016 SurfData<Real_t> const &surfdata,
0017 FramedSurface<Real_t, TransformationMP<Real_t>> const &framedsurf,
0018 bool exiting, bool &surfhit, Real_t &safety);
0019
0020 template <typename Real_t>
0021 VECCORE_ATT_HOST_DEVICE VECGEOM_FORCE_INLINE Real_t LocalLogicSafety(vecgeom::Vector3D<Real_t> const &localpoint,
0022 bool exiting, int lvol_id,
0023 SurfData<Real_t> const &surfdata,
0024 Real_t safe_max);
0025
0026 template <typename Real_t>
0027 VECCORE_ATT_HOST_DEVICE bool EnterCS(FSlocator &hit_frame, Vector3D<Real_t> const &point,
0028 Vector3D<Real_t> const &direction, Real_t hit_dist,
0029 Vector3D<Real_t> const &onsurf_local, FSlocator &out_frame);
0030
0031 template <typename Real_t>
0032 VECCORE_ATT_HOST_DEVICE bool ExitCS(FSlocator &hit_frame, bool is_hit, Vector3D<Real_t> const &point,
0033 Vector3D<Real_t> const &direction, Real_t hit_dist,
0034 Vector3D<Real_t> const &onsurf_local, FSlocator &hit_FS, FSlocator &out_frame);
0035
0036 template <typename Real_t>
0037 class BVHSurfNavigator {
0038 public:
0039 BVHSurfNavigator() = default;
0040 ~BVHSurfNavigator() = default;
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051 VECCORE_ATT_HOST_DEVICE
0052 static Real_t CandidateDistanceToIn(int lv_index, int index, Vector3D<Real_t> localpoint, Vector3D<Real_t> localdir,
0053 Real_t step)
0054 {
0055 auto const &surfdata = vgbrep::SurfData<Real_t>::Instance();
0056
0057 auto const &shell = surfdata.fShells[lv_index];
0058
0059 FramedSurface<Real_t, TransformationMP<Real_t>> *framed_surface;
0060 bool exiting{false};
0061
0062
0063
0064 if (index >= shell.fNExitingSurfaces)
0065 {
0066 int entering_index = index - shell.fNExitingSurfaces;
0067 framed_surface = &(surfdata.fLocalSurf[shell.fEnteringSurfaces[entering_index]]);
0068
0069
0070 auto const &pvol_trans = surfdata.fPVolTrans[shell.fEnteringSurfacesPvolTrans[entering_index]];
0071
0072
0073 localpoint = pvol_trans.Transform(localpoint);
0074 localdir = pvol_trans.TransformDirection(localdir);
0075
0076
0077 lv_index = shell.fEnteringSurfacesLvolIds[entering_index];
0078
0079 } else {
0080 exiting = true;
0081 auto exiting_index = shell.fExitingSurfaces[index];
0082 framed_surface = &(surfdata.fLocalSurf[shell.fSurfaces[exiting_index]]);
0083 }
0084
0085
0086
0087
0088 Real_t intersect_distance{0};
0089 bool surfhit{false};
0090 Real_t safety;
0091 intersect_distance =
0092 DistanceToLocalFS(localpoint, localdir, lv_index, surfdata, *framed_surface, exiting, surfhit, safety);
0093 if (surfhit &&
0094 (intersect_distance > -vecgeom::kToleranceStrict<Real_t> || Abs(safety) < vecgeom::kToleranceStrict<Real_t>)) {
0095 return intersect_distance;
0096 } else {
0097 return vecgeom::InfinityLength<Real_t>();
0098 }
0099 }
0100
0101 VECCORE_ATT_HOST_DEVICE
0102 static int GetLogicalId(int lv_index, int surfindex, bool &isBoolean)
0103 {
0104 auto const &surfdata = vgbrep::SurfData<Real_t>::Instance();
0105 auto const &shell = surfdata.fShells[lv_index];
0106 if (surfindex >= shell.fNExitingSurfaces) {
0107 auto entering_index = surfindex - shell.fNExitingSurfaces;
0108 lv_index = shell.fEnteringSurfacesLvolIds[entering_index];
0109 isBoolean = surfdata.fLocalSurf[shell.fEnteringSurfaces[entering_index]].fLogicId > 0;
0110 return lv_index;
0111 }
0112 isBoolean = surfdata.fLocalSurf[shell.fSurfaces[shell.fExitingSurfaces[surfindex]]].fLogicId > 0;
0113 return lv_index;
0114 }
0115
0116 VECCORE_ATT_HOST_DEVICE
0117 static bool IsNegated(int lv_index, int surfindex)
0118 {
0119 auto const &surfdata = vgbrep::SurfData<Real_t>::Instance();
0120 auto const &shell = surfdata.fShells[lv_index];
0121 if (surfindex >= shell.fNExitingSurfaces)
0122 return (surfdata.fLocalSurf[shell.fEnteringSurfaces[surfindex - shell.fNExitingSurfaces]].fLogicId < 0);
0123 else
0124 return (surfdata.fLocalSurf[shell.fSurfaces[shell.fExitingSurfaces[surfindex]]].fLogicId < 0);
0125 }
0126
0127
0128
0129
0130
0131
0132
0133
0134 VECCORE_ATT_HOST_DEVICE
0135 static Real_t CandidateSafetyToIn(int lv_index, int index, Vector3D<Real_t> localpoint,
0136 Real_t limit = vecgeom::InfinityLength<Real_t>())
0137 {
0138 auto const &surfdata = vgbrep::SurfData<Real_t>::Instance();
0139
0140 auto const &shell = surfdata.fShells[lv_index];
0141
0142 Vector3D<Real_t> surface_point;
0143 Vector3D<Real_t> surface_dir;
0144 FramedSurface<Real_t, TransformationMP<Real_t>> *framed_surface;
0145 bool exiting{false};
0146
0147
0148
0149 if (index >= shell.fNExitingSurfaces)
0150 {
0151 int entering_index = index - shell.fNExitingSurfaces;
0152 framed_surface = &(surfdata.fLocalSurf[shell.fEnteringSurfaces[entering_index]]);
0153
0154 lv_index = shell.fEnteringSurfacesLvolIds[entering_index];
0155
0156
0157 auto const &pvol_trans = surfdata.fPVolTrans[shell.fEnteringSurfacesPvolTrans[entering_index]];
0158
0159 auto const &surf_trans = framed_surface->fTrans;
0160 auto volume_trans = surf_trans * pvol_trans;
0161
0162
0163
0164 surface_point = pvol_trans.Transform(localpoint);
0165 surface_point = surf_trans.Transform(surface_point);
0166
0167 } else {
0168 exiting = true;
0169 auto exiting_index = shell.fExitingSurfaces[index];
0170 framed_surface = &(surfdata.fLocalSurf[shell.fSurfaces[exiting_index]]);
0171
0172 TransformationMP<Real_t> &local_trans = framed_surface->fTrans;
0173
0174 surface_point = local_trans.Transform(localpoint);
0175 }
0176
0177
0178 UnplacedSurface<Real_t> &unplaced_surface = framed_surface->fSurface;
0179
0180
0181
0182 Vector3D<Real_t> onsurf_crt;
0183 Real_t safety_surf{0}, safety_frame{0};
0184 bool valid_safety{true};
0185 bool can_compute{false};
0186
0187 bool flipped = framed_surface->fLogicId < 0;
0188 can_compute = unplaced_surface.Safety(surface_point, exiting ^ flipped, surfdata, safety_surf, onsurf_crt);
0189
0190 if (!can_compute || safety_surf >= limit) return safety_surf;
0191
0192
0193 safety_frame = safety_surf;
0194
0195
0196 if (!framed_surface->fNeverCheck)
0197 safety_frame = framed_surface->LocalSafetyFrame(onsurf_crt, safety_surf, surfdata, valid_safety);
0198
0199 if (valid_safety) return safety_frame;
0200 return limit;
0201 }
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211 VECCORE_ATT_HOST_DEVICE
0212 static VECGEOM_FORCE_INLINE bool SkipItem(int lv_index, int index, long const global_id)
0213 {
0214
0215 return false;
0216 }
0217
0218 template <typename BVH_t>
0219 VECCORE_ATT_HOST_DEVICE static long TestBVHCheckDaughterIntersections(BVH_t &bvh, Vector3D<Real_t> &localpoint,
0220 Vector3D<Real_t> &localdir, double &bvhstep)
0221 {
0222 long hitcandidate_index = -1;
0223 long last_exited_id = -1;
0224 bvh.template CheckDaughterIntersections<BVHSurfNavigator>(localpoint, localdir, bvhstep, last_exited_id,
0225 hitcandidate_index);
0226 return hitcandidate_index;
0227 }
0228
0229 template <typename BVH_t>
0230 VECCORE_ATT_HOST_DEVICE static double TestBVHComputeSafety(BVH_t &bvh, Vector3D<Real_t> &localpoint, Real_t safety)
0231 {
0232 return bvh.template ComputeSafety<BVHSurfNavigator>(localpoint, safety);
0233 }
0234
0235 VECCORE_ATT_HOST_DEVICE
0236 static Precision ComputeSafety(Vector3D<Precision> const &point_i, vecgeom::NavigationState const &in_state,
0237 Precision limit = vecgeom::InfinityLength<Precision>())
0238 {
0239 auto in_navind = in_state.GetNavIndex();
0240 if (in_navind == 0) return vecgeom::InfinityLength<Precision>();
0241
0242
0243 auto const &surfdata = SurfData<Real_t>::Instance();
0244 vecgeom::Vector3D<Real_t> point(point_i);
0245
0246
0247 auto lv_index = in_state.GetLogicalId();
0248 auto const &shell = surfdata.fShells[lv_index];
0249
0250
0251 auto &bvh = surfdata.fBVH[shell.fBVH];
0252
0253 vecgeom::Transformation3D lv_trans;
0254 in_state.TopMatrix(lv_trans);
0255 auto localpoint = lv_trans.Transform(point);
0256
0257 auto safety = bvh.template ComputeSafety<BVHSurfNavigator<Real_t>>(localpoint, limit);
0258
0259 safety = vecgeom::MakeMinusTolerantRel<float>(safety);
0260 return static_cast<Real_t>(safety);
0261 }
0262
0263
0264
0265
0266
0267
0268 VECCORE_ATT_HOST_DEVICE
0269 static uint ItemId(int lv_index, int index)
0270 {
0271 auto const &surfdata = vgbrep::SurfData<Real_t>::Instance();
0272
0273 auto const &shell = surfdata.fShells[lv_index];
0274 return shell.fDaughterPvolIds[index];
0275 }
0276
0277
0278
0279
0280
0281
0282
0283 VECCORE_ATT_HOST_DEVICE
0284 static bool CandidateContains(int lv_index, int index, Vector3D<Real_t> const &localpoint,
0285 vecgeom::NavigationState &path)
0286 {
0287
0288 auto const &surfdata = SurfData<Real_t>::Instance();
0289
0290 auto const &shell = surfdata.fShells[lv_index];
0291
0292 Vector3D<Real_t> daughterlocalpoint;
0293 auto const &trans = surfdata.fPVolTrans[shell.fDaughterPvolTrans[index]];
0294 trans.Transform(localpoint, daughterlocalpoint);
0295
0296
0297 path.PushDaughter(index);
0298
0299
0300 auto inside = vgbrep::protonav::LogicInsideLocal(daughterlocalpoint, path.GetLogicalId(), surfdata);
0301
0302
0303 path.Pop();
0304
0305 return inside;
0306 };
0307
0308 VECCORE_ATT_HOST_DEVICE
0309 static int LocatePointIn(int pvol_id, Vector3D<Precision> const &point_i, vecgeom::NavigationState &path, bool top,
0310 int *exclude = nullptr)
0311 {
0312 using NavigationState = vecgeom::NavigationState;
0313 vecgeom::Vector3D<Real_t> point(point_i);
0314
0315
0316 auto const &surfdata = SurfData<Real_t>::Instance();
0317
0318 if (top) {
0319 VECGEOM_ASSERT(pvol_id >= 0);
0320 auto ivol = NavigationState::ToPlacedId(pvol_id).fVolume.fId;
0321 auto inside = vgbrep::protonav::LogicInsideLocal(point, ivol, surfdata);
0322 if (!inside) return -1;
0323 }
0324
0325 path.Push(pvol_id);
0326 Vector3D<Real_t> currentpoint(point);
0327 Vector3D<Real_t> daughterlocalpoint;
0328 int exclude_id = -1;
0329 int daughter_id = -1;
0330
0331
0332 auto shell = surfdata.fShells[path.GetLogicalId()];
0333
0334
0335 while (shell.fNEnteringSurfaces > 0) {
0336
0337 auto &bvh = surfdata.fBVHSolids[shell.fBVH];
0338
0339 exclude_id = -1;
0340 if (exclude != nullptr) {
0341 exclude_id = *exclude;
0342 }
0343 daughter_id = -1;
0344
0345
0346 if (!bvh.template LevelLocate<BVHSurfNavigator<Real_t>>(exclude_id, currentpoint, daughter_id, path)) break;
0347
0348 path.Push(daughter_id);
0349
0350
0351
0352
0353
0354 vecgeom::Transformation3DMP<Real_t> trans;
0355 path.TopMatrix(trans);
0356 trans.Transform(point, daughterlocalpoint);
0357
0358
0359 currentpoint = daughterlocalpoint;
0360
0361
0362 shell = surfdata.fShells[path.GetLogicalId()];
0363
0364
0365
0366 if (exclude != nullptr) {
0367 *exclude = -1;
0368 }
0369 }
0370
0371 return path.TopId();
0372 }
0373
0374
0375
0376
0377
0378
0379
0380
0381
0382
0383
0384 template <typename Real_i>
0385 VECCORE_ATT_HOST_DEVICE static Real_i ComputeStepAndNextSurface(vecgeom::Vector3D<Real_i> const &point_i,
0386 vecgeom::Vector3D<Real_i> const &direction_i,
0387 vecgeom::NavigationState const &in_state,
0388 vecgeom::NavigationState &out_state,
0389 long &hitsurf_index,
0390 Real_i stepmax = vecgeom::InfinityLength<Real_i>())
0391 {
0392 out_state = in_state;
0393 auto in_navind = in_state.GetNavIndex();
0394
0395 if (in_navind == 0) return vecgeom::InfinityLength<Real_i>();
0396 auto const &surfdata = SurfData<Real_t>::Instance();
0397
0398 auto ivol = in_state.GetLogicalId();
0399 auto &bvh = surfdata.fBVH[surfdata.fShells[ivol].fBVH];
0400
0401
0402
0403 vecgeom::Vector3D<Real_t> point(point_i);
0404 vecgeom::Vector3D<Real_t> direction(direction_i);
0405 vecgeom::Transformation3DMP<Real_t> lv_trans;
0406 in_state.TopMatrix(lv_trans);
0407 auto localpoint = lv_trans.Transform(point);
0408 auto localdir = lv_trans.TransformDirection(direction);
0409
0410
0411
0412
0413
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423
0424 auto bvhstep = stepmax;
0425
0426 bvh.template CheckDaughterIntersections<BVHSurfNavigator>(localpoint, localdir, bvhstep, -1, hitsurf_index);
0427
0428 if (hitsurf_index < 0) {
0429
0430 out_state.SetBoundaryState(false);
0431 return stepmax;
0432 }
0433
0434
0435 out_state.SetBoundaryState(true);
0436 out_state.SetLastExited();
0437
0438
0439 return bvhstep;
0440 }
0441
0442
0443
0444
0445
0446
0447
0448
0449 template <typename Real_i>
0450 VECCORE_ATT_HOST_DEVICE static void RelocateToNextVolume(vecgeom::Vector3D<Real_i> const &point_i,
0451 vecgeom::Vector3D<Real_i> const &direction_i, Real_i step,
0452 long hitsurf_index, vecgeom::NavigationState &out_state,
0453 CrossedSurface &hit_FS)
0454 {
0455 auto const &surfdata = SurfData<Real_t>::Instance();
0456 auto const in_state = out_state;
0457
0458 Real_t bvhstep_RT = Real_t(step);
0459 vecgeom::Vector3D<Real_t> point(point_i);
0460 vecgeom::Vector3D<Real_t> direction(direction_i);
0461 vecgeom::Transformation3DMP<Real_t> scene_trans;
0462 in_state.SceneMatrix(scene_trans);
0463 auto local_scene = scene_trans.Transform(point);
0464 auto localdir_scene = scene_trans.TransformDirection(direction);
0465
0466 auto const ¤tShell = surfdata.fShells[in_state.GetLogicalId()];
0467 Vector3D<Real_t> CS_local, CS_localdir, onsurf_crt;
0468 if (hitsurf_index < currentShell.fNExitingSurfaces) {
0469
0470 auto exiting_index = currentShell.fExitingSurfaces[hitsurf_index];
0471 FSlocator hit_FS_tmp;
0472 surfdata.SceneToTouchableLocator(in_state, exiting_index, hit_FS_tmp);
0473 FSlocator out_frame;
0474 hit_FS_tmp.state = in_state;
0475
0476 auto const &surf = surfdata.fCommonSurfaces[hit_FS_tmp.GetCSindex()];
0477 auto const &CS_trans = surf.fTrans;
0478 CS_local = CS_trans.Transform(local_scene);
0479 CS_localdir = CS_trans.TransformDirection(localdir_scene);
0480 onsurf_crt = CS_local + bvhstep_RT * CS_localdir;
0481 ExitCS(hit_FS_tmp, true, point, direction, bvhstep_RT, onsurf_crt, hit_FS.hit_surf, out_frame);
0482 hit_FS.exit_surf = hit_FS.hit_surf;
0483 out_state = out_frame.state;
0484
0485 } else {
0486
0487 auto entering_index = hitsurf_index - currentShell.fNExitingSurfaces;
0488 auto local_surface_id = currentShell.fEnteringSurfaces[entering_index];
0489 auto const &framed_surface = surfdata.fLocalSurf[local_surface_id];
0490 auto pvol_id = currentShell.fEnteringSurfacesPvol[entering_index];
0491
0492 auto pvol_navstate(in_state);
0493
0494
0495 pvol_navstate.Push(pvol_id);
0496
0497 surfdata.SceneToTouchableLocator(pvol_navstate, framed_surface.fSurfIndex, hit_FS.hit_surf);
0498 hit_FS.hit_surf.state = in_state;
0499 int traversal = surfdata.GetFramedSurface(hit_FS.hit_surf).fTraversal;
0500
0501 auto const &surf = surfdata.fCommonSurfaces[hit_FS.hit_surf.GetCSindex()];
0502 auto const &CS_trans = surf.fTrans;
0503
0504 unsigned short scene_id = 0, newscene_id = 0;
0505 bool is_scene = in_state.GetSceneId(scene_id, newscene_id);
0506
0507 if (!is_scene) {
0508 CS_local = CS_trans.Transform(local_scene);
0509 CS_localdir = CS_trans.TransformDirection(localdir_scene);
0510 } else {
0511 vecgeom::Transformation3DMP<Real_t> lv_trans;
0512
0513 in_state.TopInSceneMatrix(lv_trans);
0514 auto localpoint = lv_trans.Transform(local_scene);
0515 auto localdir = lv_trans.TransformDirection(localdir_scene);
0516 CS_local = CS_trans.Transform(localpoint);
0517 CS_localdir = CS_trans.TransformDirection(localdir);
0518 }
0519 onsurf_crt = CS_local + bvhstep_RT * CS_localdir;
0520
0521
0522 FSlocator out_frame;
0523 EnterCS(hit_FS.hit_surf, point, direction, bvhstep_RT, onsurf_crt, out_frame, traversal);
0524 out_state = out_frame.state;
0525 }
0526
0527
0528 if (out_state.GetSceneLevel() > 0 && out_state.GetNavIndex() == 0) out_state.PopScene();
0529 out_state.SetBoundaryState(true);
0530 }
0531
0532
0533
0534
0535
0536
0537
0538
0539
0540
0541
0542 template <typename Real_i>
0543 VECCORE_ATT_HOST_DEVICE static Real_i ComputeStepAndHit(vecgeom::Vector3D<Real_i> const &point_i,
0544 vecgeom::Vector3D<Real_i> const &direction_i,
0545 vecgeom::NavigationState const &in_state,
0546 vecgeom::NavigationState &out_state, CrossedSurface &hit_FS,
0547 Real_i stepmax = vecgeom::InfinityLength<Real_i>())
0548 {
0549 long hitsurf_index = -1;
0550 auto bvhstep = ComputeStepAndNextSurface(point_i, direction_i, in_state, out_state, hitsurf_index, stepmax);
0551
0552 if (hitsurf_index < 0) {
0553 if (in_state.GetNavIndex() > 0 && stepmax == vecgeom::InfinityLength<Real_i>())
0554 hit_FS.Set(0, -1, 0);
0555
0556
0557 return stepmax;
0558 }
0559 RelocateToNextVolume(point_i, direction_i, bvhstep, hitsurf_index, out_state, hit_FS);
0560 return bvhstep;
0561 }
0562 };
0563
0564 }
0565 }
0566
0567 #endif