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