File indexing completed on 2026-04-17 08:35:37
0001 #ifndef VECGEOM_SURFACE_NAVIGATOR_H_
0002 #define VECGEOM_SURFACE_NAVIGATOR_H_
0003
0004 #include <VecGeom/management/Logger.h>
0005 #include <VecGeom/surfaces/SurfData.h>
0006 #include <VecGeom/surfaces/Model.h>
0007 #include <VecGeom/surfaces/LogicEvaluator.h>
0008 #include <VecGeom/volumes/VolumeTree.h>
0009 #include <VecGeom/navigation/NavigationState.h>
0010 #include <VecGeom/base/Algorithms.h>
0011
0012 #include <VecGeom/volumes/utilities/VolumeUtilities.h>
0013 #include <VecGeom/base/BVH.h>
0014
0015 #include <iomanip>
0016
0017 namespace vgbrep {
0018 namespace protonav {
0019
0020
0021
0022
0023
0024
0025
0026
0027 template <typename Real_t>
0028 VECCORE_ATT_HOST_DEVICE VECGEOM_FORCE_INLINE bool LogicInsideLocal(vecgeom::Vector3D<Real_t> const &localpoint,
0029 int volId, SurfData<Real_t> const &surfdata,
0030 const int logic_id = vecgeom::kMaximumInt,
0031 const bool is_inside = 0)
0032 {
0033 auto const &logic = surfdata.fShells[volId].fLogic;
0034
0035 auto inside = EvaluateInside(localpoint, volId, logic, surfdata, logic_id, is_inside);
0036 return inside;
0037 }
0038
0039
0040
0041
0042
0043
0044
0045 template <typename Real_t>
0046 VECCORE_ATT_HOST_DEVICE VECGEOM_FORCE_INLINE bool LogicInside(vecgeom::Vector3D<Real_t> const &point,
0047 vecgeom::NavigationState const &in_state,
0048 SurfData<Real_t> const &surfdata,
0049 const int logic_id = vecgeom::kMaximumInt,
0050 const bool is_inside = 0)
0051 {
0052
0053 Vector3D<Real_t> localpoint;
0054 vecgeom::Transformation3DMP<Real_t> trans;
0055 in_state.TopMatrix(trans);
0056 trans.Transform(point, localpoint);
0057 auto volId = in_state.GetLogicalId();
0058 auto inside = LogicInsideLocal(localpoint, volId, surfdata, logic_id, is_inside);
0059 return inside;
0060 }
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072 template <typename Real_t>
0073 VECCORE_ATT_HOST_DEVICE bool IsExitingFrame(
0074 Vector3D<Real_t> const &point, Vector3D<Real_t> const &direction, Real_t distance, Vector3D<Real_t> const &onsurf,
0075 vecgeom::NavigationState const &exited_state,
0076 FramedSurface<Real_t, vecgeom::Transformation2DMP<Real_t>> const &framedsurf, NavIndex_t &last_bool_state,
0077 SurfData<Real_t> const &surfdata)
0078 {
0079 constexpr Real_t kPushDistance = 1000 * vecgeom::kToleranceDist<Real_t>;
0080 bool inframe = framedsurf.fNeverCheck ? true : framedsurf.InsideFrame(onsurf, surfdata);
0081 if (inframe && framedsurf.fLogicId) {
0082 last_bool_state = framedsurf.fState;
0083
0084
0085 auto pushedPoint = std::is_same<Real_t, double>::value
0086 ? point + (distance + kPushDistance) * direction
0087 : point + (distance + vecgeom::kRelTolerance<Real_t>(distance + point.Mag())) * direction;
0088
0089 auto inside = LogicInside(pushedPoint, exited_state, surfdata, framedsurf.fLogicId, false);
0090 if (inside) inframe = false;
0091 }
0092 return inframe;
0093 }
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109 template <typename Real_t>
0110 VECCORE_ATT_HOST_DEVICE bool CheckFramesExiting(FSlocator &crossed_surf, bool frame_hit, Vector3D<Real_t> const &point,
0111 Vector3D<Real_t> const &direction, Real_t distance,
0112 Vector3D<Real_t> const &onsurf, SurfData<Real_t> const &surfdata,
0113 bool &exiting_scene, int &surf_index, int &traversal)
0114 {
0115 constexpr NavIndex_t kInvalidState = NavIndex_t(-1);
0116
0117 traversal = -3;
0118 int isurf = crossed_surf.GetCSindex();
0119 auto const &surf = surfdata.fCommonSurfaces[isurf];
0120 bool left_side = crossed_surf.IsLeftSide();
0121 bool is_scene_surface = surf.IsSceneSurface();
0122 auto const state = crossed_surf.state;
0123 auto in_navind = state.GetNavIndex();
0124 NavIndex_t top_exit_state = NavIndex_t(-1);
0125
0126
0127
0128 auto const &exit_side = left_side ? surf.fLeftSide : surf.fRightSide;
0129
0130 int frameind_start = crossed_surf.frame_id;
0131
0132
0133 bool inframe = frame_hit;
0134 int parent_ind = -1;
0135 bool embedded = true;
0136 bool traversal_set = false;
0137 if (frame_hit) {
0138 traversal = exit_side.GetSurface(frameind_start, surfdata).fTraversal;
0139 traversal_set = true;
0140 }
0141
0142 NavIndex_t last_bool_state = kInvalidState;
0143 auto exited_state = state;
0144
0145 auto onsurf_crt = onsurf;
0146 if (exiting_scene) {
0147
0148 vecgeom::Transformation3DMP<Real_t> scene_trans;
0149 state.SceneMatrix(scene_trans);
0150 auto local_scene = scene_trans.Transform(point + distance * direction);
0151 onsurf_crt = surf.fTrans.Transform(local_scene);
0152 }
0153
0154
0155 auto setTopExited = [&](FramedSurface<Real_t, vecgeom::Transformation2DMP<Real_t>> const &framed_surf, int ind) {
0156 surf_index = framed_surf.fSurfIndex;
0157 parent_ind = framed_surf.fParent;
0158 framed_surf.GetParentState(top_exit_state);
0159 exiting_scene = is_scene_surface && (framed_surf.fState == 0);
0160 embedded = framed_surf.fEmbedded;
0161 crossed_surf.Set(isurf, ind, left_side);
0162 if (!traversal_set) {
0163 traversal = framed_surf.fTraversal;
0164 traversal_set = true;
0165 }
0166 };
0167
0168 for (SideIterator it(exit_side, onsurf_crt, surfdata, 1, frameind_start); !it.Done(); ++it) {
0169 auto ind = it();
0170 auto const &framedsurf = exit_side.GetSurface(ind, surfdata);
0171
0172 if (!exiting_scene && !inframe && framedsurf.fState != in_navind) continue;
0173
0174 if (framedsurf.fState == last_bool_state) continue;
0175
0176 bool inframe_tmp = (ind == frameind_start) && inframe;
0177 if (!inframe_tmp)
0178 inframe_tmp = IsExitingFrame<Real_t>(point, direction, distance, onsurf_crt, exited_state, framedsurf,
0179 last_bool_state, surfdata);
0180 if (inframe_tmp) {
0181
0182 inframe = true;
0183
0184 setTopExited(framedsurf, ind);
0185
0186 if (parent_ind < 0) break;
0187
0188 while (parent_ind > 0) {
0189
0190 it.SetNextIndex(parent_ind);
0191
0192
0193
0194
0195 auto const &parent_framedsurf = exit_side.GetSurface(parent_ind, surfdata);
0196 if (!embedded && !parent_framedsurf.fEmbedding) break;
0197
0198 setTopExited(parent_framedsurf, parent_ind);
0199 if (parent_framedsurf.fState)
0200 exited_state.SetNavIndex(parent_framedsurf.fState);
0201 else
0202 exited_state.PopScene();
0203 }
0204 if (embedded) break;
0205 }
0206 }
0207 if (inframe) {
0208
0209 crossed_surf.state = state;
0210 crossed_surf.state.SetLastExited();
0211
0212
0213 crossed_surf.state.SetNavIndex(top_exit_state);
0214 crossed_surf.state.SetBoundaryState(true);
0215 }
0216 return inframe;
0217 }
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229 template <typename Real_t>
0230 VECCORE_ATT_HOST_DEVICE int FindFrameOnEnteringSide(Side const &side, vecgeom::NavigationState const &in_state,
0231 NavIndex_t in_navind, bool is_scene, bool is_scene_surface,
0232 Vector3D<Real_t> const &onsurf_local,
0233 Vector3D<Real_t> const &pushed_point,
0234 SurfData<Real_t> const &surfdata, int &ihit)
0235 {
0236
0237 bool found = ihit >= 0;
0238 int ifound = ihit;
0239 bool lastinside = false;
0240 int lastbool = -1;
0241
0242 auto getFirstParent = [&](int iframe) {
0243 int ifirst = iframe;
0244 auto refState = side.GetSurface(iframe, surfdata).fState;
0245 for (auto ind = iframe - 1; ind >= 0; --ind) {
0246 if (side.GetSurface(ind, surfdata).fState == refState)
0247 ifirst = ind;
0248 else
0249 return ifirst;
0250 }
0251 return ifirst;
0252 };
0253
0254
0255 auto insideBoolean = [&](FramedSurface<Real_t, vecgeom::Transformation2DMP<Real_t>> const &surf) {
0256 auto checked_state = in_state;
0257 if (surf.fState) {
0258 if (is_scene_surface && checked_state.GetNavIndex() > 0)
0259 checked_state.PushScene(surf.fState);
0260 else
0261 checked_state.SetNavIndex(surf.fState);
0262 }
0263 int ivol = checked_state.GetLogicalId();
0264 if (lastbool == ivol) return lastinside;
0265
0266 lastbool = ivol;
0267 lastinside = LogicInside(pushed_point, checked_state, surfdata, surf.fLogicId, true);
0268 return lastinside;
0269 };
0270
0271
0272 int iparent = ifound;
0273 if (found) iparent = getFirstParent(ifound);
0274 int indstart = (iparent >= 0) ? iparent - 1 : side.fNsurf - 1;
0275 for (SideIterator it(side, onsurf_local, surfdata, -1, indstart); !it.Done(); --it) {
0276 auto ind = it();
0277 auto const &framedsurf = side.GetSurface(ind, surfdata);
0278
0279 if (framedsurf.fNeverCheck) {
0280 ihit = ind;
0281 return ind;
0282 }
0283
0284 if (found && framedsurf.fParent != iparent) continue;
0285
0286 if (!is_scene_surface && framedsurf.fState == in_navind) continue;
0287
0288 if (is_scene && framedsurf.fState == 0) continue;
0289
0290
0291 if (!found && framedsurf.fParent >= 0)
0292 if ((framedsurf.fEmbedded && !(framedsurf.fVirtualParent)) ||
0293 side.GetSurface(framedsurf.fParent, surfdata).fEmbedding)
0294 continue;
0295
0296
0297 auto inframe = framedsurf.InsideFrame(onsurf_local, surfdata);
0298
0299 if (inframe && framedsurf.fLogicId) inframe = insideBoolean(framedsurf);
0300 if (inframe) {
0301 found = true;
0302 ifound = ind;
0303 iparent = getFirstParent(ifound);
0304
0305 if (ihit < 0) ihit = ind;
0306 }
0307 }
0308 return ifound;
0309 }
0310
0311
0312
0313
0314
0315
0316 template <typename Real_t>
0317 VECCORE_ATT_HOST_DEVICE VECGEOM_FORCE_INLINE Real_t LocalLogicSafety(vecgeom::Vector3D<Real_t> const &localpoint,
0318 bool exiting, int lvol_id,
0319 SurfData<Real_t> const &surfdata,
0320 Real_t safe_max)
0321 {
0322 auto const &logic = surfdata.fShells[lvol_id].fLogic;
0323 Real_t safety = EvaluateSafety(localpoint, lvol_id, exiting, logic, surfdata, safe_max);
0324 return safety;
0325 }
0326
0327
0328
0329
0330
0331
0332 template <typename Real_t>
0333 VECCORE_ATT_HOST_DEVICE VECGEOM_FORCE_INLINE Real_t LogicSafety(vecgeom::Vector3D<Real_t> const &point, bool exiting,
0334 vecgeom::NavigationState const &in_state,
0335 SurfData<Real_t> const &surfdata,
0336 Real_t safe_max = vecgeom::InfinityLength<Real_t>())
0337 {
0338
0339 Vector3D<Real_t> localpoint;
0340 vecgeom::Transformation3DMP<Real_t> trans;
0341 in_state.TopMatrix(trans);
0342 trans.Transform(point, localpoint);
0343 auto volId = in_state.GetLogicalId();
0344 auto const &logic = surfdata.fShells[volId].fLogic;
0345 Real_t safety = EvaluateSafety(localpoint, volId, exiting, logic, surfdata, safe_max);
0346 return safety;
0347 }
0348
0349
0350
0351
0352
0353
0354
0355
0356
0357
0358 template <typename Real_i, typename Real_t>
0359 VECCORE_ATT_HOST_DEVICE int LocatePointIn(int iplaced, vecgeom::Vector3D<Real_i> const &point_i,
0360 vecgeom::NavigationState &path, bool top, int exclude = -1)
0361 {
0362 using NavigationState = vecgeom::NavigationState;
0363 auto const &surfdata = SurfData<Real_t>::Instance();
0364 vecgeom::Vector3D<Real_t> point(point_i);
0365
0366 if (top) {
0367 VECGEOM_ASSERT(iplaced >= 0);
0368 auto ivol = NavigationState::ToPlacedId(iplaced).fVolume.fId;
0369 auto inside = LogicInsideLocal(point, ivol, surfdata);
0370 if (!inside) return -1;
0371 }
0372
0373 auto currentvolume = iplaced;
0374 path.Push(currentvolume);
0375
0376 bool godeeper;
0377 do {
0378 godeeper = false;
0379 auto const &lvol = NavigationState::ToPlacedId(currentvolume).fVolume;
0380 for (auto i = 0; i < lvol.fNplaced; ++i) {
0381 auto daughter = lvol.fChildren[i].fId;
0382 if (daughter == exclude) continue;
0383 path.PushDaughter(i);
0384 auto inside = LogicInside(point, path, surfdata);
0385
0386 if (inside) {
0387 currentvolume = daughter;
0388 godeeper = true;
0389 break;
0390 } else {
0391 path.Pop();
0392 }
0393 }
0394
0395
0396 exclude = -1;
0397 } while (godeeper);
0398
0399 return currentvolume;
0400 }
0401
0402
0403
0404
0405
0406
0407 template <typename Real_t>
0408 VECCORE_ATT_HOST_DEVICE bool VolumeHasCommonSurface(vecgeom::NavigationState &path, FSlocator const &crossed_surf)
0409 {
0410
0411
0412 if (path.GetNavIndex() == 0) return false;
0413
0414 if (crossed_surf.GetFSindex() == -1) return false;
0415
0416 auto const &surfdata = SurfData<Real_t>::Instance();
0417 auto const &surf = surfdata.fCommonSurfaces[crossed_surf.GetCSindex()];
0418 auto const &exit_side = crossed_surf.IsLeftSide() ? surf.fLeftSide : surf.fRightSide;
0419
0420 auto state_id = path.GetNavIndex();
0421
0422
0423
0424 if (!surfdata.IsFramedSurfaceEmbedded(crossed_surf) && surfdata.FramedSurfaceParentInd(crossed_surf) >= 0)
0425 return false;
0426
0427
0428
0429
0430
0431
0432
0433
0434
0435 for (int isurf = 0; isurf < exit_side.fNsurf; isurf++) {
0436 if (surfdata.fFramedSurf[exit_side.fSurfaces[isurf]].fState == state_id) return true;
0437 }
0438 return false;
0439 }
0440
0441
0442
0443
0444
0445
0446
0447
0448
0449
0450 template <typename Real_i, typename Real_t>
0451 VECCORE_ATT_HOST_DEVICE int ReLocatePointIn(vecgeom::NavigationState &starting_path,
0452 vecgeom::Vector3D<Real_i> const &point_i,
0453 vecgeom::Vector3D<Real_i> const &direction_i,
0454 vecgeom::NavigationState &path, FSlocator const &crossed_surf,
0455 Real_i distance_i)
0456 {
0457 using PlacedId = vecgeom::PlacedId;
0458 using NavigationState = vecgeom::NavigationState;
0459 using ESolidType = vecgeom::ESolidType;
0460 auto const &surfdata = SurfData<Real_t>::Instance();
0461
0462 vecgeom::Vector3D<Real_t> point(point_i);
0463 vecgeom::Vector3D<Real_t> direction(direction_i);
0464 Real_t distance = static_cast<Real_t>(distance_i);
0465
0466
0467 path = starting_path;
0468 auto currentvolume = starting_path.TopId();
0469 auto placedId = [](int iplaced) -> PlacedId const &{ return NavigationState::ToPlacedId(iplaced); };
0470 auto prev_volume = path.GetLastIdExited();
0471
0472 constexpr Real_t kPushDistance = 1000 * vecgeom::kToleranceDist<Real_t>;
0473 bool is_boolean = false;
0474 bool is_self_entering = false;
0475
0476
0477 bool is_zero_step = distance < 10000 * vecgeom::kToleranceDist<Real_t>;
0478 auto final_point = is_zero_step ? point + kPushDistance * direction : point;
0479
0480 int logic_id_exit = vecgeom::kMaximumInt;
0481
0482
0483 bool godeeper;
0484 bool inside_daughter = false;
0485 if (crossed_surf.GetFSindex() != -1) {
0486 do {
0487 godeeper = false;
0488 for (auto i = 0; i < placedId(currentvolume).fVolume.fNplaced; ++i) {
0489 auto const &daughter = placedId(currentvolume).fVolume.fChildren[i];
0490 is_boolean = daughter.fVolume.fSolidType == ESolidType::boolean;
0491
0492
0493
0494
0495
0496
0497 if (is_boolean) {
0498 final_point = point + kPushDistance * direction;
0499
0500 }
0501 path.PushDaughter(i);
0502 bool inside = LogicInside(final_point, path, surfdata);
0503 final_point = is_zero_step ? point + kPushDistance * direction : point;
0504
0505
0506 if (inside) {
0507 inside_daughter = true;
0508 currentvolume = daughter.fId;
0509 godeeper = true;
0510 break;
0511 } else {
0512 path.Pop();
0513 }
0514 }
0515 } while (godeeper);
0516 }
0517
0518
0519 if (inside_daughter && !path.HasSamePathAsOther(starting_path)) return currentvolume;
0520
0521 if (crossed_surf.GetFSindex() != -1 && crossed_surf.GetCSindex() != 0) {
0522
0523
0524 path = crossed_surf.state;
0525
0526 path.SetNavIndex(surfdata.FramedSurfaceState(crossed_surf));
0527 } else {
0528 path = starting_path;
0529 }
0530
0531
0532
0533
0534
0535
0536
0537
0538
0539
0540
0541 currentvolume = path.TopId();
0542 VECGEOM_VALIDATE(
0543 currentvolume >= 0, << " currentvolume is nullptr in overlap detection! Most likely due to incorrect path!");
0544 is_boolean = placedId(currentvolume).fVolume.fSolidType == ESolidType::boolean;
0545
0546 if (!is_boolean) {
0547
0548 if (path.GetNavIndex() > 1) path.SetLastExited();
0549 prev_volume = path.GetLastIdExited();
0550
0551 if (path.GetNavIndex() > 1) path.Pop();
0552 } else {
0553 prev_volume = starting_path.TopId();
0554 is_self_entering = true;
0555 }
0556
0557 currentvolume = path.TopId();
0558 VECGEOM_VALIDATE(
0559 currentvolume >= 0, << " currentvolume is nullptr in overlap detection! This might due to incorrect path "
0560 "or due to a surface previously being falsely flagged as overlapping!");
0561 is_boolean = placedId(currentvolume).fVolume.fSolidType == ESolidType::boolean;
0562
0563
0564 bool gohigher = false;
0565
0566 bool inside;
0567 do {
0568 gohigher = false;
0569 auto same_cs = VolumeHasCommonSurface<Real_t>(path, crossed_surf);
0570 if (same_cs && !is_boolean) {
0571 inside = false;
0572 } else {
0573
0574
0575 if (placedId(currentvolume).fVolume.fSolidType == ESolidType::boolean) {
0576 final_point = point + kPushDistance * direction;
0577 logic_id_exit = surfdata.FramedSurfaceLogicId(crossed_surf);
0578 }
0579
0580 inside = LogicInside(final_point, path, surfdata, logic_id_exit, false);
0581
0582
0583
0584
0585
0586
0587 if (placedId(currentvolume).fVolume.fSolidType == ESolidType::boolean && !is_self_entering)
0588 inside |= LogicInside(point, path, surfdata, logic_id_exit, false);
0589 final_point = is_zero_step ? point + kPushDistance * direction : point;
0590 logic_id_exit = vecgeom::kMaximumInt;
0591 }
0592
0593 if (inside == false) {
0594 prev_volume = currentvolume;
0595 path.Pop();
0596 currentvolume = path.TopId();
0597 VECGEOM_ASSERT(
0598 currentvolume >= 0 &&
0599 " currentvolume is nullptr in overlap detection! That means some inside call failed or was falsely excluded");
0600 gohigher = true;
0601 }
0602 } while (gohigher);
0603
0604 do {
0605 godeeper = false;
0606 for (auto i = 0; i < placedId(currentvolume).fVolume.fNplaced; ++i) {
0607 auto const &daughter = placedId(currentvolume).fVolume.fChildren[i];
0608 is_boolean = daughter.fVolume.fSolidType == ESolidType::boolean;
0609 if (daughter.fId == prev_volume && !is_boolean) {
0610
0611
0612 prev_volume = -1;
0613 continue;
0614 }
0615 path.PushDaughter(i);
0616 auto same_cs = VolumeHasCommonSurface<Real_t>(path, crossed_surf);
0617 if (same_cs && !is_boolean) {
0618 inside = false;
0619 } else {
0620
0621 if (is_boolean) {
0622 final_point = point + kPushDistance * direction;
0623 if (daughter.fId == prev_volume) {
0624 logic_id_exit = surfdata.FramedSurfaceLogicId(crossed_surf);
0625 }
0626 }
0627
0628 inside = LogicInside(final_point, path, surfdata, logic_id_exit, false);
0629 final_point = is_zero_step ? point + kPushDistance * direction : point;
0630 logic_id_exit = -1;
0631 }
0632 if (inside) {
0633 currentvolume = daughter.fId;
0634 godeeper = true;
0635 break;
0636 } else {
0637 path.Pop();
0638 }
0639 }
0640 } while (godeeper);
0641
0642 return currentvolume;
0643 }
0644
0645
0646
0647
0648
0649
0650
0651
0652
0653 template <typename Real_t>
0654 VECCORE_ATT_HOST_DEVICE bool EnterCS(FSlocator &hit_frame, Vector3D<Real_t> const &point,
0655 Vector3D<Real_t> const &direction, Real_t hit_dist,
0656 Vector3D<Real_t> const &onsurf_local, FSlocator &out_frame, int traversal)
0657 {
0658 constexpr Real_t kPushDistance = 1000 * vecgeom::kTolerance;
0659 auto const &surfdata = SurfData<Real_t>::Instance();
0660 auto const &in_state = hit_frame.state;
0661 unsigned short scene_id = 0, newscene_id = 0;
0662 bool is_scene = in_state.GetSceneId(scene_id, newscene_id);
0663 auto in_navind = in_state.GetNavIndex();
0664 auto pushed_point = std::is_same<Real_t, double>::value
0665 ? point + (hit_dist + kPushDistance) * direction
0666 : point + (hit_dist + vecgeom::kRelTolerance<Real_t>(hit_dist + point.Mag())) * direction;
0667 auto const &surf_crossed = surfdata.GetCommonSurface(hit_frame);
0668 auto const &enter_side = surfdata.GetSide(hit_frame);
0669
0670 bool relocate = hit_frame.GetFSindex() < 0;
0671 int iframe = -1;
0672
0673 #ifndef SURF_DEBUG_TRAVERSALS
0674 if (relocate && traversal > -2) {
0675 iframe = traversal;
0676 } else
0677 #endif
0678 iframe = FindFrameOnEnteringSide(enter_side, in_state, in_navind, is_scene, surf_crossed.IsSceneSurface(),
0679 onsurf_local, pushed_point, surfdata, hit_frame.frame_id);
0680 out_frame.Set(hit_frame.GetCSindex(), iframe, hit_frame.IsLeftSide());
0681 out_frame.state = in_state;
0682 #ifdef SURF_DEBUG_TRAVERSALS
0683 if (relocate) {
0684 if (iframe < 0) {
0685 if (traversal > -1)
0686 printf("Error on CS=%d leftside=%d frame=%d transition=%d -> no hit\n", hit_frame.GetCSindex(),
0687 hit_frame.IsLeftSide(), hit_frame.GetFSindex(), traversal);
0688 VECGEOM_ASSERT(traversal <= -1);
0689 }
0690 if ((traversal == -1 && iframe > -1) || (traversal > -1 && iframe != traversal)) {
0691 printf("Error on CS=%d leftside=%d frame=%d transition=%d -> CS=%d leftside=%d found frame %d\n",
0692 hit_frame.GetCSindex(), !hit_frame.IsLeftSide(), hit_frame.GetFSindex(), traversal, out_frame.GetCSindex(),
0693 out_frame.IsLeftSide(), iframe);
0694 VECGEOM_ASSERT((traversal == -1 && iframe == -1) || (traversal > -1 && iframe == traversal));
0695 }
0696 }
0697 #endif
0698 if (iframe < 0) return false;
0699 while (iframe >= 0) {
0700 auto const &framedsurf = surfdata.GetFramedSurface(out_frame);
0701
0702 out_frame.state.SetLastExited();
0703 out_frame.state.SetBoundaryState(true);
0704 if (is_scene && out_frame.state.GetNavIndex() > 0)
0705
0706 out_frame.state.PushScene(framedsurf.fState);
0707 else
0708
0709 out_frame.state.SetNavIndex(framedsurf.fState);
0710
0711 iframe = -1;
0712
0713 if (framedsurf.fSceneCS > 0) {
0714
0715 out_frame.Set(framedsurf.fSceneCS, vecCore::math::Abs(framedsurf.fSceneCSind) - 1, framedsurf.fSceneCSind > 0);
0716 auto const &portal = surfdata.GetCommonSurface(out_frame);
0717 auto const &portal_side = surfdata.GetSide(out_frame);
0718
0719 if (!portal_side.HasChildren()) return true;
0720
0721 vecgeom::Transformation3DMP<Real_t> scene_trans;
0722
0723
0724 is_scene = out_frame.state.GetSceneId(scene_id, newscene_id);
0725 if (is_scene) {
0726 out_frame.state.TopMatrix(scene_trans);
0727 } else {
0728 out_frame.state.SceneMatrix(scene_trans);
0729 }
0730
0731 auto local_scene = scene_trans.Transform(point + hit_dist * direction);
0732 auto onsurf = portal.fTrans.Transform(local_scene);
0733 iframe = FindFrameOnEnteringSide(portal_side, out_frame.state, out_frame.state.GetNavIndex(), is_scene,
0734 portal.IsSceneSurface(), onsurf, pushed_point, surfdata, out_frame.frame_id);
0735 if (iframe == out_frame.frame_id) return true;
0736
0737 out_frame.frame_id = iframe;
0738 }
0739 }
0740 return true;
0741 }
0742
0743
0744
0745
0746
0747
0748
0749
0750
0751 template <typename Real_t>
0752 VECCORE_ATT_HOST_DEVICE bool ExitCS(FSlocator &hit_frame, bool is_hit, Vector3D<Real_t> const &point,
0753 Vector3D<Real_t> const &direction, Real_t hit_dist,
0754 Vector3D<Real_t> const &onsurf_local, FSlocator &hit_FS, FSlocator &out_frame)
0755 {
0756 auto const &surfdata = SurfData<Real_t>::Instance();
0757 int surf_index = 0;
0758 int traversal = -2;
0759 auto exiting_scene = false;
0760 auto inframe = CheckFramesExiting(hit_frame, is_hit, point, direction, hit_dist, onsurf_local, surfdata,
0761 exiting_scene, surf_index, traversal);
0762 if (!inframe) return false;
0763
0764 auto &out_state = out_frame.state;
0765 hit_FS = hit_frame;
0766 out_state = hit_FS.state;
0767 auto isurfcross = hit_frame.GetCSindex();
0768 auto relocated_left_side = !hit_frame.IsLeftSide();
0769 auto onsurf = onsurf_local;
0770
0771 while (exiting_scene) {
0772 out_state.PopScene();
0773
0774 vecgeom::Transformation3DMP<Real_t> scene_trans;
0775 out_state.SceneMatrix(scene_trans);
0776
0777 surfdata.SceneToTouchableLocator(out_state, surf_index, hit_FS);
0778
0779 hit_FS.state = out_state;
0780 auto local_propagated = scene_trans.Transform(point + hit_dist * direction);
0781 inframe = CheckFramesExiting(hit_FS, true, point, direction, hit_dist, onsurf, surfdata,
0782 exiting_scene, surf_index, traversal);
0783 isurfcross = hit_FS.GetCSindex();
0784 relocated_left_side = !hit_FS.IsLeftSide();
0785 out_state = hit_FS.state;
0786
0787 auto const &surf_crossed = surfdata.GetCommonSurface(hit_FS);
0788 onsurf = surf_crossed.fTrans.Transform(local_propagated);
0789 }
0790
0791 hit_frame.Set(isurfcross, -1, relocated_left_side);
0792
0793 if (surfdata.GetSide(hit_frame).fNsurf == 0) return true;
0794 hit_frame.state = out_state;
0795
0796 EnterCS(hit_frame, point, direction, hit_dist, onsurf, out_frame, traversal);
0797 return true;
0798 }
0799
0800
0801
0802
0803
0804
0805
0806
0807
0808
0809
0810 template <typename Real_t>
0811 VECCORE_ATT_HOST_DEVICE Real_t DistanceToLocalFS(vecgeom::Vector3D<Real_t> const &point_volume,
0812 vecgeom::Vector3D<Real_t> const &direction_volume, int volId,
0813 SurfData<Real_t> const &surfdata,
0814 FramedSurface<Real_t, TransformationMP<Real_t>> const &framedsurf,
0815 bool exiting, bool &surfhit, Real_t &safety)
0816 {
0817 bool two_solutions = false;
0818 constexpr Real_t kPushDistance = 1000 * vecgeom::kToleranceDist<Real_t>;
0819
0820 auto const &trans = framedsurf.fTrans;
0821 Vector3D<Real_t> local = trans.Transform(point_volume);
0822 Vector3D<Real_t> localdir = trans.TransformDirection(direction_volume);
0823
0824 bool flipped_bool = framedsurf.fLogicId < 0;
0825 bool visibility = exiting ^ flipped_bool;
0826
0827 Real_t dist = vecgeom::InfinityLength<Real_t>();
0828 surfhit = framedsurf.fSurface.Intersect(local, localdir, visibility, surfdata, dist, two_solutions, safety);
0829
0830
0831
0832 if (surfhit && Abs(dist) < vecgeom::kTolerance && Abs(localdir[2]) < vecgeom::kToleranceDist<Real_t> && visibility) {
0833 surfhit = false;
0834 dist = vecgeom::InfinityLength<Real_t>();
0835 }
0836 if (!surfhit) return dist;
0837
0838 auto onsurf = local + localdir * dist;
0839 if (!framedsurf.fNeverCheck) surfhit = framedsurf.fFrame.Inside(onsurf, surfdata);
0840 if (!surfhit) return dist;
0841
0842 if (framedsurf.fLogicId) {
0843 onsurf = std::is_same<Real_t, double>::value
0844 ? point_volume + (dist + kPushDistance) * direction_volume
0845 : point_volume + (dist + vecgeom::kRelTolerance<Real_t>(dist + point_volume.Mag())) * direction_volume;
0846
0847 auto inside = LogicInsideLocal(onsurf, volId, surfdata, framedsurf.fLogicId, !exiting);
0848 surfhit = inside ^ exiting;
0849 }
0850
0851 return dist;
0852 }
0853
0854
0855
0856
0857
0858
0859
0860
0861
0862
0863
0864
0865
0866
0867
0868 template <typename Real_t>
0869 VECCORE_ATT_HOST_DEVICE Real_t DistanceToUnplaced(vecgeom::Vector3D<Real_t> const &point,
0870 vecgeom::Vector3D<Real_t> const &direction,
0871 SurfData<Real_t> const &surfdata, int isurf, char sides, bool exiting,
0872 bool &left_side, bool &surfhit, vecgeom::Vector3D<Real_t> &onsurf,
0873 Real_t &dist2, vecgeom::Vector3D<Real_t> &local,
0874 vecgeom::Vector3D<Real_t> &localdir, Real_t &safety)
0875 {
0876 constexpr char kLside = 1;
0877 constexpr char kRside = 2;
0878 auto const &surf = surfdata.fCommonSurfaces[isurf];
0879
0880
0881 auto const &trans = surf.fTrans;
0882 local = trans.Transform(point);
0883 localdir = trans.TransformDirection(direction);
0884
0885
0886 Real_t dist = -vecgeom::InfinityLength<Real_t>();
0887 bool flipped = false;
0888 auto unplaced = surfdata.GetUnplaced(isurf, flipped);
0889
0890 left_side = (sides & kLside) > 0;
0891 bool check_both_sides = left_side && (sides & kRside) > 0;
0892 bool visibility = !exiting ^ left_side ^ flipped;
0893 bool two_solutions = false;
0894 surfhit = unplaced.Intersect(local, localdir, visibility, surfdata, dist, two_solutions, safety);
0895 if ((!surfhit && check_both_sides) || (two_solutions && check_both_sides)) {
0896
0897
0898 left_side = false;
0899 visibility = !exiting ^ flipped;
0900 bool surfhit_right = unplaced.Intersect(local, localdir, visibility, surfdata, dist2, two_solutions, safety);
0901 if (surfhit_right) {
0902 if (surfhit) {
0903
0904
0905
0906 if (dist2 < dist) {
0907 Real_t tmp_dist = dist;
0908 dist = dist2;
0909 dist2 = tmp_dist;
0910 } else {
0911
0912 left_side = true;
0913 }
0914 } else {
0915
0916 dist = dist2;
0917 dist2 = -vecgeom::InfinityLength<Real_t>();
0918 }
0919
0920 surfhit = surfhit_right;
0921 } else {
0922
0923 left_side = true;
0924 }
0925 }
0926 if (surfhit) onsurf = local + dist * localdir;
0927 return dist;
0928 }
0929
0930
0931
0932
0933
0934
0935
0936
0937
0938
0939
0940 template <typename Real_i, typename Real_t>
0941 VECCORE_ATT_HOST_DEVICE Real_t ComputeStepAndHit(vecgeom::Vector3D<Real_t> const &point_i,
0942 vecgeom::Vector3D<Real_t> const &direction_i,
0943 vecgeom::NavigationState const &in_state,
0944 vecgeom::NavigationState &out_state, CrossedSurface &exit_FS,
0945 Real_i stepmax = vecgeom::InfinityLength<Real_t>())
0946 {
0947
0948 auto in_navind = in_state.GetNavIndex();
0949 if (in_navind == 0) return vecgeom::InfinityLength<Real_i>();
0950 auto const &surfdata = SurfData<Real_t>::Instance();
0951
0952
0953 vecgeom::Vector3D<Real_t> point(point_i);
0954 vecgeom::Vector3D<Real_t> direction(direction_i);
0955
0956 Real_i distance = stepmax;
0957 unsigned short scene_id = 0, newscene_id = 0;
0958 bool is_scene = in_state.GetSceneId(scene_id, newscene_id);
0959 auto const &cand = surfdata.GetCandidates(scene_id, in_state.GetId());
0960 auto const &new_cand = is_scene ? surfdata.GetCandidates(newscene_id, 0) : cand;
0961 bool found = false;
0962 FSlocator tmp_hit_FS;
0963
0964 Vector3D<Real_t> onsurf;
0965 out_state = in_state;
0966 out_state.SetBoundaryState(false);
0967 auto skip_surf = exit_FS.hit_surf.GetCSindex();
0968
0969
0970 vecgeom::Transformation3DMP<Real_t> scene_trans;
0971 in_state.SceneMatrix(scene_trans);
0972 Vector3D<Real_t> local_scene = scene_trans.Transform(point);
0973 Vector3D<Real_t> localdir_scene = scene_trans.TransformDirection(direction);
0974 Vector3D<Real_t> local;
0975 Vector3D<Real_t> localdir;
0976
0977
0978 for (auto icand = 0; icand < cand.fNExiting; ++icand) {
0979 int isurf = cand.fCandidates[icand];
0980 char sides = cand.fSides[icand];
0981 if (isurf == 0) continue;
0982 bool left_side, surfhit;
0983 Vector3D<Real_t> onsurf_crt;
0984 Real_t safety;
0985 Real_t dist2 = -vecgeom::InfinityLength<Real_t>();
0986
0987 auto dist = DistanceToUnplaced(local_scene, localdir_scene, surfdata, isurf, sides, true, left_side,
0988 surfhit, onsurf_crt, dist2, local, localdir, safety);
0989 if (!surfhit || (dist < -vecgeom::kToleranceStrict<Real_t> && !(Abs(safety) < vecgeom::kToleranceStrict<Real_t>)) ||
0990 dist >= distance)
0991 continue;
0992
0993
0994 tmp_hit_FS.Set(isurf, cand.fFrameInd[icand], left_side);
0995 tmp_hit_FS.state = in_state;
0996
0997 FSlocator out_frame;
0998 auto inframe =
0999 ExitCS(tmp_hit_FS, false, point, direction, dist, onsurf_crt, exit_FS.hit_surf, out_frame);
1000 exit_FS.exit_surf = exit_FS.hit_surf;
1001
1002 if (!inframe && dist2 < -vecgeom::kToleranceStrict<Real_t>) continue;
1003
1004 if (!inframe && dist2 > -vecgeom::kToleranceStrict<Real_t>) {
1005 tmp_hit_FS.Set(isurf, cand.fFrameInd[icand], !left_side);
1006 onsurf_crt = local + dist2 * localdir;
1007 inframe = ExitCS(tmp_hit_FS, false, point, direction, dist2, onsurf_crt, exit_FS.hit_surf, out_frame);
1008 exit_FS.exit_surf = exit_FS.hit_surf;
1009
1010 if (inframe) dist = dist2;
1011 }
1012 if (!inframe) continue;
1013 found = true;
1014 distance = Real_i(dist);
1015 out_state = out_frame.state;
1016 continue;
1017 }
1018
1019 if (!found && stepmax == vecgeom::InfinityLength<Real_t>()) {
1020
1021 exit_FS.Set(0, -1, 0);
1022
1023
1024
1025 return stepmax;
1026 }
1027
1028
1029 if (is_scene) {
1030
1031 scene_trans.Clear();
1032 in_state.TopMatrix(scene_trans);
1033 local_scene = scene_trans.Transform(point);
1034 localdir_scene = scene_trans.TransformDirection(direction);
1035 }
1036
1037 for (auto icand = new_cand.fNExiting; icand < new_cand.fNcand; ++icand) {
1038 int isurf = vecCore::math::Abs(new_cand[icand]);
1039 bool self_entering = new_cand[icand] < 0;
1040 if (isurf == skip_surf) continue;
1041 char sides = new_cand.fSides[icand];
1042
1043 bool left_side, surfhit;
1044 Vector3D<Real_t> onsurf_crt;
1045 Real_t safety;
1046 Real_t dist2 = -vecgeom::InfinityLength<Real_t>();
1047
1048 auto dist = DistanceToUnplaced(local_scene, localdir_scene, surfdata, isurf, sides, false, left_side,
1049 surfhit, onsurf_crt, dist2, local, localdir, safety);
1050 if (!surfhit || (dist < -vecgeom::kToleranceStrict<Real_t> && !(Abs(safety) < vecgeom::kToleranceStrict<Real_t>)) ||
1051 dist >= distance)
1052 continue;
1053
1054
1055
1056 if (self_entering && vecCore::math::Abs(dist) < vecgeom::kToleranceStrict<Real_t>) continue;
1057
1058 FSlocator out_frame;
1059 auto EnterFrameCheck = [&](auto left_side, auto &onsurf, auto dist) -> int {
1060
1061
1062 tmp_hit_FS.Set(isurf, -1, left_side);
1063 tmp_hit_FS.state = in_state;
1064 EnterCS(tmp_hit_FS, point, direction, dist, onsurf_crt, out_frame, -2);
1065 return tmp_hit_FS.frame_id;
1066 };
1067 auto iframe = EnterFrameCheck(left_side, onsurf_crt, dist);
1068
1069
1070 if (iframe < 0 && dist2 < -vecgeom::kToleranceStrict<Real_t>) continue;
1071
1072
1073 if (iframe < 0 && dist2 > -vecgeom::kToleranceStrict<Real_t> && dist2 < distance) {
1074 onsurf_crt = local + dist2 * localdir;
1075 iframe = EnterFrameCheck(!left_side, onsurf_crt, dist2);
1076 if (iframe >= 0) dist = dist2;
1077 }
1078
1079 if (iframe < 0) continue;
1080
1081 exit_FS.hit_surf = tmp_hit_FS;
1082
1083
1084 distance = Real_i(dist);
1085
1086 out_state = out_frame.state;
1087 }
1088
1089
1090 if (out_state.GetSceneLevel() > 0 && out_state.GetNavIndex() == 0) out_state.PopScene();
1091 return distance;
1092 }
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103 template <typename Real_i, typename Real_t>
1104 VECCORE_ATT_HOST_DEVICE Real_t ComputeSafety(vecgeom::Vector3D<Real_i> const &point_i,
1105 vecgeom::NavigationState const &in_state, int &closest_surf,
1106 Real_i limit = vecgeom::InfinityLength<Real_i>())
1107 {
1108 constexpr char kLside = 0x01;
1109 constexpr char kRside = 0x02;
1110 using vecgeom::NavigationState;
1111 Real_t safety_far = vecgeom::InfinityLength<Real_t>();
1112 bool found{false}, found_far{false};
1113
1114 auto const &surfdata = SurfData<Real_t>::Instance();
1115 vecgeom::Vector3D<Real_t> point(point_i);
1116 closest_surf = 0;
1117 int last_logic_volid = -1;
1118 Real_t safety = vecgeom::InfinityLength<Real_t>();
1119 if (in_state.GetNavIndex() == 0) return safety;
1120 Vector3D<Real_t> onsurf;
1121 unsigned short scene_id = 0, newscene_id = 0;
1122
1123 in_state.GetSceneId(scene_id, newscene_id);
1124 auto const &cand = surfdata.GetCandidates(scene_id, in_state.GetId());
1125
1126
1127 vecgeom::Transformation3DMP<Real_t> scene_trans;
1128 in_state.SceneMatrix(scene_trans);
1129 Vector3D<Real_t> local_scene = scene_trans.Transform(point);
1130
1131
1132 for (auto icand = 0; icand < cand.fNExiting; ++icand) {
1133 bool validSafety = true;
1134 int isurf = cand[icand];
1135 if (isurf == 0) continue;
1136 auto const &surf = surfdata.fCommonSurfaces[isurf];
1137
1138
1139 auto const &trans = surf.fTrans;
1140 Vector3D<Real_t> local = trans.Transform(local_scene);
1141 Vector3D<Real_t> onsurf_crt;
1142 Real_t safety_surf = vecgeom::InfinityLength<Real_t>();
1143 bool flipped = false;
1144 auto unplaced = surfdata.GetUnplaced(isurf, flipped);
1145
1146
1147 char sides = cand.fSides[icand];
1148 bool left_side = (sides & kLside) > 0;
1149 bool right_side = (sides & kRside) > 0;
1150 bool check_both_sides = left_side && right_side;
1151 bool visibility = left_side ^ flipped;
1152
1153
1154
1155
1156
1157
1158 bool can_compute = unplaced.Safety(local, visibility, surfdata, safety_surf, onsurf_crt);
1159 if (!can_compute && check_both_sides) {
1160
1161
1162 left_side = false;
1163 visibility = flipped;
1164 safety_surf = -safety_surf;
1165 can_compute = true;
1166 }
1167
1168 if (!can_compute || safety_surf < -vecgeom::kToleranceDist<Real_t> || safety_surf >= safety) continue;
1169 if (safety_surf > limit) {
1170 found_far = true;
1171 safety_far = vecCore::math::Min(safety_surf, safety_far);
1172 continue;
1173 }
1174
1175
1176
1177
1178
1179
1180 auto const &exit_side = left_side ? surf.fLeftSide : surf.fRightSide;
1181 int frameind = cand.fFrameInd[icand];
1182 auto const &framedsurf = exit_side.GetSurface(frameind, surfdata);
1183
1184
1185
1186 auto safetyFrame = safety_surf;
1187
1188 if (!framedsurf.fNeverCheck) safetyFrame = framedsurf.SafetyFrame(onsurf_crt, safety_surf, surfdata, validSafety);
1189 if (validSafety) {
1190
1191 found = true;
1192 if (safetyFrame < safety) {
1193 closest_surf = isurf;
1194 safety = safetyFrame;
1195 }
1196 }
1197 }
1198
1199
1200 for (auto icand = cand.fNExiting; icand < cand.fNcand; ++icand) {
1201 int isurf = vecCore::math::Abs(cand[icand]);
1202 auto const &surf = surfdata.fCommonSurfaces[isurf];
1203
1204
1205 auto const &trans = surf.fTrans;
1206 Vector3D<Real_t> local = trans.Transform(local_scene);
1207 Vector3D<Real_t> onsurf_crt;
1208 Real_t safety_surf = vecgeom::InfinityLength<Real_t>();
1209 bool flipped = false;
1210 auto unplaced = surfdata.GetUnplaced(isurf, flipped);
1211
1212
1213
1214 char sides = cand.fSides[icand];
1215 bool left_side = (sides & kLside) > 0;
1216 bool right_side = (sides & kRside) > 0;
1217 bool check_both_sides = left_side && right_side;
1218 bool visibility = !left_side ^ flipped;
1219 bool can_compute = unplaced.Safety(local, visibility, surfdata, safety_surf, onsurf_crt);
1220
1221 if (!can_compute && check_both_sides) {
1222
1223
1224 left_side = false;
1225 visibility = !flipped;
1226 safety_surf = -safety_surf;
1227 can_compute = true;
1228
1229 }
1230 if (!can_compute || safety_surf < -vecgeom::kToleranceDist<Real_t> || safety_surf >= safety) continue;
1231 if (safety_surf > limit) {
1232 found_far = true;
1233 safety_far = vecCore::math::Min(safety_surf, safety_far);
1234 continue;
1235 }
1236
1237
1238 auto const &entry_side = left_side ? surf.fLeftSide : surf.fRightSide;
1239 const int num_parents = entry_side.fNumParents;
1240 int iparent = 0;
1241
1242 for (auto ind = entry_side.fNsurf - 1; ind >= 0; --ind) {
1243 bool validSafety = true;
1244 auto const &framedsurf = entry_side.GetSurface(ind, surfdata);
1245 if (framedsurf.fParent >= 0) continue;
1246
1247 if (framedsurf.fLogicId && last_logic_volid == framedsurf.VolumeId()) continue;
1248 iparent++;
1249 auto safetyFrame = safety_surf;
1250 if (!framedsurf.fNeverCheck) safetyFrame = framedsurf.SafetyFrame(onsurf_crt, safety_surf, surfdata, validSafety);
1251 if (validSafety && safetyFrame < safety) {
1252
1253 safety = safetyFrame;
1254 found = true;
1255 closest_surf = isurf;
1256 }
1257 if (iparent == num_parents) break;
1258 }
1259 }
1260 if (!found && found_far) return safety_far;
1261 safety *= found;
1262 return safety;
1263 }
1264
1265 }
1266 }
1267 #endif