File indexing completed on 2025-01-18 10:13:57
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef VECGEOM_HYBRIDNAVIGATOR
0009 #define VECGEOM_HYBRIDNAVIGATOR
0010
0011 #include "VecGeom/base/Global.h"
0012
0013 #include "VecGeom/volumes/PlacedVolume.h"
0014 #include "VecGeom/base/SOA3D.h"
0015 #include "VecGeom/base/Vector3D.h"
0016 #include "VecGeom/management/GeoManager.h"
0017 #include "VecGeom/navigation/NavigationState.h"
0018 #include "VecGeom/base/Transformation3D.h"
0019 #include "VecGeom/volumes/kernel/BoxImplementation.h"
0020 #include "VecGeom/management/HybridManager2.h"
0021 #include "VecGeom/navigation/VNavigator.h"
0022 #include "VecGeom/navigation/HybridSafetyEstimator.h"
0023 #include "VecGeom/navigation/SimpleABBoxNavigator.h"
0024
0025 #include <vector>
0026 #include <cmath>
0027
0028 namespace vecgeom {
0029 inline namespace VECGEOM_IMPL_NAMESPACE {
0030
0031
0032
0033
0034
0035
0036 template <bool MotherIsConvex = false>
0037 class HybridNavigator : public VNavigatorHelper<HybridNavigator<MotherIsConvex>, MotherIsConvex> {
0038
0039 private:
0040 HybridManager2 &fAccelerationManager;
0041 HybridNavigator()
0042 : VNavigatorHelper<HybridNavigator<MotherIsConvex>, MotherIsConvex>(SimpleABBoxSafetyEstimator::Instance()),
0043 fAccelerationManager(HybridManager2::Instance())
0044 {
0045 }
0046
0047 static VPlacedVolume const *LookupDaughter(LogicalVolume const *lvol, int const daughterIndex)
0048 {
0049 return lvol->GetDaughters()[daughterIndex];
0050 }
0051
0052
0053 template <typename T>
0054 static void insertionsort(T *arr, unsigned int N)
0055 {
0056 for (unsigned short i = 1; i < N; ++i) {
0057 T value = arr[i];
0058 short hole = i;
0059
0060 for (; hole > 0 && value.second < arr[hole - 1].second; --hole)
0061 arr[hole] = arr[hole - 1];
0062
0063 arr[hole] = value;
0064 }
0065 }
0066
0067
0068
0069
0070 size_t GetContainingCandidates_v(HybridManager2::HybridBoxAccelerationStructure const &accstructure,
0071 Vector3D<Precision> const &point, size_t *hitlist) const
0072 {
0073 using Float_v = HybridManager2::Float_v;
0074 using Bool_v = vecCore::Mask<Float_v>;
0075 constexpr auto kVS = vecCore::VectorSize<Float_v>();
0076 size_t count = 0;
0077 int numberOfNodes, size;
0078 auto boxes_v = fAccelerationManager.GetABBoxes_v(accstructure, size, numberOfNodes);
0079 auto const *nodeToDaughters = accstructure.fNodeToDaughters;
0080 for (size_t index = 0, nodeindex = 0; index < size_t(size) * 2; index += 2 * (kVS + 1), nodeindex += kVS) {
0081 Bool_v inside, inside_d;
0082 Vector3D<Float_v> *corners = &boxes_v[index];
0083 ABBoxImplementation::ABBoxContainsKernelGeneric<HybridManager2::Float_v, Precision, Bool_v>(
0084 corners[0], corners[1], point, inside);
0085 if (!vecCore::MaskEmpty(inside)) {
0086
0087 for (size_t i = 0; i < kVS; ++i) {
0088 if (vecCore::MaskLaneAt(inside, i)) {
0089 corners = &boxes_v[index + 2 * (i + 1)];
0090 ABBoxImplementation::ABBoxContainsKernelGeneric<HybridManager2::Float_v, Precision, Bool_v>(
0091 corners[0], corners[1], point, inside_d);
0092 if (!vecCore::MaskEmpty(inside_d)) {
0093
0094 for (size_t j = 0; j < kVS; ++j) {
0095 if (vecCore::MaskLaneAt(inside_d, j)) {
0096 assert(count < VECGEOM_MAXFACETS);
0097 hitlist[count++] = nodeToDaughters[nodeindex + i][j];
0098 }
0099 }
0100 }
0101 }
0102 }
0103 }
0104 }
0105 return count;
0106 }
0107
0108
0109
0110
0111 size_t GetHitCandidates_v(HybridManager2::HybridBoxAccelerationStructure const &accstructure,
0112 Vector3D<Precision> const &point, Vector3D<Precision> const &dir, float maxstep,
0113 HybridManager2::BoxIdDistancePair_t *hitlist) const
0114 {
0115 size_t count = 0;
0116 Vector3D<Precision> invdir(1. / NonZero(dir.x()), 1. / NonZero(dir.y()), 1. / NonZero(dir.z()));
0117 Vector3D<int> sign;
0118 sign[0] = invdir.x() < 0;
0119 sign[1] = invdir.y() < 0;
0120 sign[2] = invdir.z() < 0;
0121 int numberOfNodes, size;
0122 auto boxes_v = fAccelerationManager.GetABBoxes_v(accstructure, size, numberOfNodes);
0123 constexpr auto kVS = vecCore::VectorSize<HybridManager2::Float_v>();
0124 auto const *nodeToDaughters = accstructure.fNodeToDaughters;
0125 for (size_t index = 0, nodeindex = 0; index < size_t(size) * 2; index += 2 * (kVS + 1), nodeindex += kVS) {
0126 HybridManager2::Float_v distance = BoxImplementation::IntersectCachedKernel2<HybridManager2::Float_v, float>(
0127 &boxes_v[index], point, invdir, sign.x(), sign.y(), sign.z(), 0, maxstep);
0128 auto hit = distance < maxstep;
0129 if (!vecCore::MaskEmpty(hit)) {
0130 for (size_t i = 0 ; i < kVS; ++i) {
0131 if (vecCore::MaskLaneAt(hit, i)) {
0132 distance = BoxImplementation::IntersectCachedKernel2<HybridManager2::Float_v, float>(
0133 &boxes_v[index + 2 * (i + 1)], point, invdir, sign.x(), sign.y(), sign.z(), 0, maxstep);
0134 auto hit1 = distance < maxstep;
0135 if (!vecCore::MaskEmpty(hit1)) {
0136 for (size_t j = 0 ; j < kVS; ++j) {
0137 if (vecCore::MaskLaneAt(hit1, j)) {
0138 assert(count < VECGEOM_MAXFACETS);
0139 hitlist[count] = HybridManager2::BoxIdDistancePair_t(nodeToDaughters[nodeindex + i][j],
0140 vecCore::LaneAt(distance, j));
0141 count++;
0142 }
0143 }
0144 }
0145 }
0146 }
0147 }
0148 }
0149 return count;
0150 }
0151
0152 public:
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165 template <typename AccStructure, typename Func>
0166 VECGEOM_FORCE_INLINE
0167 void BVHSortedIntersectionsLooper(AccStructure const &accstructure, Vector3D<Precision> const &localpoint,
0168 Vector3D<Precision> const &localdir, Precision maxstep, Func &&userhook) const
0169 {
0170
0171
0172 using IdDistPair_t = HybridManager2::BoxIdDistancePair_t;
0173 char stackspace[VECGEOM_MAXFACETS * sizeof(IdDistPair_t)];
0174 IdDistPair_t *hitlist = reinterpret_cast<IdDistPair_t *>(&stackspace);
0175
0176
0177
0178 const float maxstep_float = std::min((float)maxstep, InfinityLength<float>());
0179 auto ncandidates = GetHitCandidates_v(accstructure, localpoint, localdir, maxstep_float, hitlist);
0180
0181 insertionsort(hitlist, ncandidates);
0182
0183 for (size_t index = 0; index < ncandidates; ++index) {
0184 auto hitbox = hitlist[index];
0185
0186
0187 auto done = userhook(hitbox);
0188 if (done) break;
0189 }
0190 }
0191
0192 template <typename AccStructure, typename Func>
0193 VECGEOM_FORCE_INLINE
0194 void BVHContainsLooper(AccStructure const &accstructure, Vector3D<Precision> const &localpoint, Func &&userhook) const
0195 {
0196 size_t hitlist[VECGEOM_MAXFACETS];
0197 auto ncandidates = GetContainingCandidates_v(accstructure, localpoint, hitlist);
0198 for (size_t index = 0; index < ncandidates; ++index) {
0199 auto hitbox = hitlist[index];
0200 auto done = userhook(hitbox);
0201 if (done) break;
0202 }
0203 }
0204
0205 VECGEOM_FORCE_INLINE
0206 virtual bool CheckDaughterIntersections(LogicalVolume const *lvol, Vector3D<Precision> const &localpoint,
0207 Vector3D<Precision> const &localdir, NavigationState const *in_state,
0208 NavigationState * , Precision &step,
0209 VPlacedVolume const *&hitcandidate) const override
0210 {
0211 if (lvol->GetDaughtersp()->size() == 0) return false;
0212 auto &accstructure = *fAccelerationManager.GetAccStructure(lvol);
0213
0214 float maxstep = step;
0215 BVHSortedIntersectionsLooper(
0216 accstructure, localpoint, localdir, maxstep, [&](HybridManager2::BoxIdDistancePair_t hitbox) {
0217
0218 if (!(step < hitbox.second)) {
0219 VPlacedVolume const *candidate = LookupDaughter(lvol, hitbox.first);
0220 Precision ddistance = candidate->DistanceToIn(localpoint, localdir, step);
0221 const auto valid = !IsInf(ddistance) && ddistance < step &&
0222 !((ddistance <= 0.) && in_state && in_state->GetLastExited() == candidate);
0223 hitcandidate = valid ? candidate : hitcandidate;
0224 step = valid ? ddistance : step;
0225 return false;
0226 }
0227 return true;
0228 });
0229 return false;
0230 }
0231
0232 VECGEOM_FORCE_INLINE
0233 virtual bool CheckDaughterIntersections(LogicalVolume const *lvol, Vector3D<Precision> const &localpoint,
0234 Vector3D<Precision> const &localdir, VPlacedVolume const *blocked,
0235 Precision &step, VPlacedVolume const *&hitcandidate) const override
0236 {
0237 if (lvol->GetDaughtersp()->size() == 0) return false;
0238 auto &accstructure = *fAccelerationManager.GetAccStructure(lvol);
0239
0240 const float maxstep = step;
0241 BVHSortedIntersectionsLooper(accstructure, localpoint, localdir, maxstep,
0242 [&](HybridManager2::BoxIdDistancePair_t hitbox) {
0243
0244 if (!(step < hitbox.second)) {
0245
0246 Vector3D<Precision> normal;
0247 VPlacedVolume const *candidate = LookupDaughter(lvol, hitbox.first);
0248 if (candidate == blocked) {
0249
0250 candidate->Normal(localpoint, normal);
0251 if (normal.Dot(localdir) >= 0.0) {
0252 std::cerr << "HybridNav2> blocked " << candidate
0253 << " has normal.dir = " << normal.Dot(localdir) << " and distToIn = "
0254 << candidate->DistanceToIn(localpoint, localdir, step) << "\n";
0255 }
0256 }
0257 const Precision ddistance = candidate->DistanceToIn(localpoint, localdir, step);
0258 const auto valid = !IsInf(ddistance) && ddistance < step &&
0259 !((ddistance <= 0.) &&
0260 blocked == candidate);
0261 hitcandidate = valid ? candidate : hitcandidate;
0262 step = valid ? ddistance : step;
0263 #if 0
0264 if ( ddistance<=0 ) {
0265 std::cerr << "HybridNav2> negative distance found for " << candidate->GetName() << "\n";
0266 auto inside = candidate->Inside(localpoint);
0267 static std::string InsideCode[4] = { "N/A", "Inside", "Surface", "Outside" } ;
0268 std::cerr << InsideCode[inside];
0269 const auto transf = candidate->GetTransformation();
0270 const auto unpl = candidate->GetUnplacedVolume();
0271 Vector3D<Precision> normalDg;
0272 const auto testdaughterlocal = transf->Transform(localpoint);
0273 auto valid = unpl->Normal(testdaughterlocal, normalDg);
0274
0275 const auto directiondaughterlocal = transf->TransformDirection(localdir);
0276 const auto dot = normalDg.Dot(directiondaughterlocal);
0277 std::cerr << " normal.dir = " << dot;
0278 if (dot >= 0) {
0279 std::cerr << " exiting " << valid << "\n";
0280 }
0281 else {
0282 std::cerr << " entering " << valid << "\n";
0283 }
0284 }
0285 #endif
0286 return false;
0287 }
0288 return true;
0289 });
0290 return false;
0291 }
0292
0293 static VNavigator *Instance()
0294 {
0295 static HybridNavigator instance;
0296 return &instance;
0297 }
0298
0299 static constexpr const char *gClassNameString = "HybridNavigator";
0300 typedef SimpleABBoxSafetyEstimator SafetyEstimator_t;
0301 };
0302 }
0303 }
0304
0305 #endif