File indexing completed on 2026-04-17 08:35:30
0001
0002
0003
0004
0005
0006
0007
0008
0009 #ifndef LOOP_NAVIGATOR_H_
0010 #define LOOP_NAVIGATOR_H_
0011
0012 #include <VecGeom/base/Global.h>
0013 #include <VecGeom/base/Vector3D.h>
0014 #include <VecGeom/navigation/NavigationState.h>
0015 #include <VecGeom/volumes/LogicalVolume.h>
0016
0017 #ifdef VECGEOM_ENABLE_CUDA
0018 #include <VecGeom/backend/cuda/Interface.h>
0019 #endif
0020
0021 namespace vecgeom {
0022
0023 class LoopNavigator {
0024
0025 public:
0026
0027
0028 static constexpr Precision kBoundaryPush = 10 * vecgeom::kTolerance;
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054 VECCORE_ATT_HOST_DEVICE
0055 static Daughter LocatePointIn(Daughter vol, Vector3D<Precision> const &point, vecgeom::NavigationState &path,
0056 bool top, Daughter exclude = nullptr)
0057 {
0058 if (top) {
0059 VECGEOM_ASSERT(vol != nullptr);
0060 auto inside = vol->Inside(point);
0061 if (inside == kOutside) return nullptr;
0062
0063 if (inside == kSurface) path.SetBoundaryState(true);
0064 }
0065
0066 Daughter currentvolume = vol;
0067
0068 Vector3D<Precision> currentpoint(vol->GetTransformation()->Transform<Precision>(point));
0069 path.Push(currentvolume);
0070
0071 bool godeeper;
0072 do {
0073 godeeper = false;
0074 for (auto *daughter : currentvolume->GetDaughters()) {
0075 if (daughter == exclude) {
0076 continue;
0077 }
0078 auto transformedpoint = daughter->GetTransformation()->Transform<Precision>(currentpoint);
0079 auto inside = daughter->GetUnplacedVolume()->Inside(transformedpoint);
0080 if (inside == EnumInside::kOutside) continue;
0081 if (inside == kSurface) path.SetBoundaryState(true);
0082
0083 path.Push(daughter);
0084 currentpoint = transformedpoint;
0085 currentvolume = daughter;
0086 godeeper = true;
0087
0088 break;
0089 }
0090
0091
0092
0093 exclude = nullptr;
0094 } while (godeeper);
0095
0096 return currentvolume;
0097 }
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107 VECCORE_ATT_HOST_DEVICE
0108 static Daughter RelocatePoint(Vector3D<Precision> const &localpoint, vecgeom::NavigationState &path)
0109 {
0110 Daughter currentmother = path.Top();
0111 Daughter skip = nullptr;
0112 Vector3D<Precision> transformed = localpoint;
0113
0114 do {
0115 skip = currentmother;
0116 path.Pop();
0117 transformed = currentmother->GetTransformation()->InverseTransform(transformed);
0118 currentmother = path.Top();
0119 } while (currentmother && (currentmother->IsAssembly() || !currentmother->UnplacedContains(transformed)));
0120
0121
0122
0123 if (currentmother) {
0124 return LocatePointInNavState(transformed, path, false, skip);
0125 }
0126 return currentmother;
0127 }
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142 VECCORE_ATT_HOST_DEVICE
0143 static Daughter LocatePointInNavState(Vector3D<Precision> const &localpoint, vecgeom::NavigationState &path, bool top,
0144 vecgeom::VPlacedVolume const *exclude = nullptr)
0145 {
0146 VECGEOM_ASSERT(path.Top() != nullptr);
0147
0148 auto currentLogical = path.Top()->GetLogicalVolume();
0149 VECGEOM_ASSERT(currentLogical != nullptr);
0150
0151
0152 if (top) {
0153 auto inside = currentLogical->GetUnplacedVolume()->Inside(localpoint);
0154 if (inside == kOutside) return nullptr;
0155
0156 if (inside == kSurface) path.SetBoundaryState(true);
0157 }
0158
0159 Vector3D<Precision> currentpoint(localpoint);
0160
0161 while (currentLogical->GetDaughters().size() > 0) {
0162 bool godeeper = false;
0163
0164
0165 for (auto *daughter : currentLogical->GetDaughters()) {
0166 if (exclude && daughter == exclude) continue;
0167
0168
0169 const auto transformedpoint = daughter->GetTransformation()->Transform<Precision>(currentpoint);
0170 const auto inside = daughter->GetUnplacedVolume()->Inside(transformedpoint);
0171 if (inside == kOutside) continue;
0172 if (inside == kSurface) path.SetBoundaryState(true);
0173
0174 path.Push(daughter);
0175 currentpoint = transformedpoint;
0176 currentLogical = daughter->GetLogicalVolume();
0177 godeeper = true;
0178
0179 break;
0180 }
0181
0182
0183
0184 exclude = nullptr;
0185 if (!godeeper) break;
0186 }
0187
0188 return path.Top();
0189 }
0190
0191 private:
0192
0193
0194
0195
0196 VECCORE_ATT_HOST_DEVICE
0197 static Precision ComputeStepAndHit(Vector3D<Precision> const &localpoint, Vector3D<Precision> const &localdir,
0198 Precision step_limit, vecgeom::NavigationState const &in_state,
0199 vecgeom::NavigationState &out_state, Daughter &hitcandidate)
0200 {
0201 if (step_limit <= 0) {
0202
0203 in_state.CopyTo(&out_state);
0204 out_state.SetBoundaryState(false);
0205 return 0;
0206 }
0207
0208 Precision step = step_limit;
0209 Daughter pvol = in_state.Top();
0210
0211
0212 step = pvol->DistanceToOut(localpoint, localdir, step_limit);
0213
0214 if (step < 0) step = 0;
0215 step = Min(step, step_limit);
0216
0217 for (auto *daughter : pvol->GetDaughters()) {
0218 double ddistance = daughter->DistanceToIn(localpoint, localdir, step);
0219 ddistance = vecCore::math::Max(ddistance, 0.);
0220 const bool valid = ddistance < step;
0221 hitcandidate = valid ? daughter : hitcandidate;
0222 step = valid ? ddistance : step;
0223 }
0224
0225
0226 in_state.CopyTo(&out_state);
0227 if (step == vecgeom::kInfLength && step_limit > 0.) {
0228 out_state.SetBoundaryState(true);
0229 do {
0230 out_state.Pop();
0231 } while (out_state.Top()->IsAssembly());
0232
0233 return vecgeom::kTolerance;
0234 }
0235
0236
0237 if (step >= step_limit) {
0238
0239 out_state.SetBoundaryState(false);
0240 return step_limit;
0241 }
0242
0243
0244 out_state.SetBoundaryState(true);
0245
0246 if (step < 0) {
0247 step = 0;
0248 }
0249
0250 return step;
0251 }
0252
0253 public:
0254
0255 VECCORE_ATT_HOST_DEVICE
0256 static Precision ComputeSafety(Vector3D<Precision> const &globalpoint, vecgeom::NavigationState const &state,
0257 Precision limit = InfinityLength<Precision>())
0258 {
0259 Daughter pvol = state.Top();
0260 if (pvol == nullptr) return kInfLength;
0261 vecgeom::Transformation3D m;
0262 state.TopMatrix(m);
0263 Vector3D<Precision> localpoint = m.Transform(globalpoint);
0264
0265 Precision safety = pvol->SafetyToOut(localpoint);
0266
0267 for (auto *daughter : pvol->GetDaughters()) {
0268 double dsafety = daughter->SafetyToIn(localpoint);
0269 safety = dsafety < safety ? dsafety : safety;
0270 }
0271
0272 return safety;
0273 }
0274
0275
0276
0277
0278
0279 VECCORE_ATT_HOST_DEVICE
0280 static Precision ComputeStepAndPropagatedState(Vector3D<Precision> const &globalpoint,
0281 Vector3D<Precision> const &globaldir, Precision step_limit,
0282 vecgeom::NavigationState const &in_state,
0283 vecgeom::NavigationState &out_state, Precision push = 0)
0284 {
0285 if (in_state.Top() == nullptr) return kInfLength;
0286
0287 if (in_state.IsOnBoundary()) {
0288 push += kBoundaryPush;
0289 }
0290 if (step_limit < push) {
0291
0292
0293 in_state.CopyTo(&out_state);
0294 out_state.SetBoundaryState(false);
0295 return step_limit;
0296 }
0297 step_limit -= push;
0298
0299
0300 Vector3D<Precision> localpoint;
0301 Vector3D<Precision> localdir;
0302
0303 vecgeom::Transformation3D m;
0304 in_state.TopMatrix(m);
0305 localpoint = m.Transform(globalpoint);
0306 localdir = m.TransformDirection(globaldir);
0307
0308 localpoint += push * localdir;
0309
0310 Daughter hitcandidate = nullptr;
0311 Precision step = ComputeStepAndHit(localpoint, localdir, step_limit, in_state, out_state, hitcandidate);
0312 step += push;
0313
0314 if (out_state.IsOnBoundary()) {
0315
0316 localpoint += (step + kBoundaryPush) * localdir;
0317
0318 if (!hitcandidate) {
0319
0320 RelocatePoint(localpoint, out_state);
0321 } else {
0322
0323 localpoint = hitcandidate->GetTransformation()->Transform(localpoint);
0324 LocatePointIn(hitcandidate, localpoint, out_state, false);
0325 }
0326
0327 if (out_state.Top() != nullptr) {
0328 while (out_state.Top()->IsAssembly() || out_state.HasSamePathAsOther(in_state)) {
0329 out_state.Pop();
0330 }
0331 VECGEOM_ASSERT(!out_state.Top()->GetLogicalVolume()->GetUnplacedVolume()->IsAssembly());
0332 }
0333 }
0334
0335 return step;
0336 }
0337
0338
0339
0340
0341
0342
0343
0344
0345 VECCORE_ATT_HOST_DEVICE
0346 static Precision ComputeStepAndNextVolume(Vector3D<Precision> const &globalpoint,
0347 Vector3D<Precision> const &globaldir, Precision step_limit,
0348 vecgeom::NavigationState const &in_state,
0349 vecgeom::NavigationState &out_state, Precision push = 0)
0350 {
0351 if (in_state.Top() == nullptr) return kInfLength;
0352
0353 if (in_state.IsOnBoundary()) {
0354 push += kBoundaryPush;
0355 }
0356 if (step_limit < push) {
0357
0358
0359 in_state.CopyTo(&out_state);
0360 if (step_limit > kTolerance) out_state.SetBoundaryState(false);
0361 return step_limit;
0362 }
0363 step_limit -= push;
0364
0365
0366 Vector3D<Precision> localpoint;
0367 Vector3D<Precision> localdir;
0368
0369 vecgeom::Transformation3D m;
0370 in_state.TopMatrix(m);
0371 localpoint = m.Transform(globalpoint);
0372 localdir = m.TransformDirection(globaldir);
0373
0374 Daughter hitcandidate = nullptr;
0375
0376 Precision step =
0377 ComputeStepAndHit(localpoint + push * localdir, localdir, step_limit, in_state, out_state, hitcandidate);
0378
0379 step += (step > 0.) * push;
0380
0381 if (out_state.IsOnBoundary()) {
0382 if (!hitcandidate) {
0383 Daughter currentmother = out_state.Top();
0384 Vector3D<Precision> transformed = localpoint;
0385
0386 transformed += (step + kBoundaryPush) * localdir;
0387 do {
0388
0389 out_state.SetLastExited();
0390 out_state.Pop();
0391 transformed = currentmother->GetTransformation()->InverseTransform(transformed);
0392 currentmother = out_state.Top();
0393 } while (currentmother &&
0394 (currentmother->IsAssembly() || currentmother->GetUnplacedVolume()->Inside(transformed) != kInside));
0395 } else {
0396 out_state.Push(hitcandidate);
0397 }
0398 }
0399
0400 return step;
0401 }
0402
0403
0404
0405 VECCORE_ATT_HOST_DEVICE
0406 static void RelocateToNextVolume(Vector3D<Precision> const &globalpoint, Vector3D<Precision> const &globaldir,
0407 vecgeom::NavigationState &state)
0408 {
0409
0410 if (state.IsOutside()) return;
0411
0412
0413
0414 Vector3D<Precision> pushed = globalpoint ;
0415
0416
0417 vecgeom::Transformation3D m;
0418 state.TopMatrix(m);
0419 Vector3D<Precision> localpoint = m.Transform(pushed);
0420
0421
0422 LocatePointInNavState(localpoint, state, false, state.GetLastExited());
0423
0424 if (state.Top() != nullptr) {
0425 while (state.Top()->IsAssembly()) {
0426 state.Pop();
0427 }
0428 VECGEOM_ASSERT(!state.Top()->GetLogicalVolume()->GetUnplacedVolume()->IsAssembly());
0429 }
0430 }
0431 };
0432
0433 }
0434
0435 #endif