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