diff --git a/Detectors/Base/src/GeometryManager.cxx b/Detectors/Base/src/GeometryManager.cxx index 225f21d8239a1..1e77c76697d23 100644 --- a/Detectors/Base/src/GeometryManager.cxx +++ b/Detectors/Base/src/GeometryManager.cxx @@ -32,6 +32,7 @@ #ifdef O2_WITH_VECGEOM #include "TGeo2VecGeom/RootGeoManager.h" +#include #include #include #include @@ -40,7 +41,11 @@ #include #include #include +#if VECGEOM_VERSION >= 0x020000 +#include +#else #include +#endif #include #include #include @@ -557,6 +562,14 @@ void GeometryManager::loadGeometry(std::string_view simPrefix, bool applyMisalig namespace { +/// Volumes with very few daughters are cheaper to brute-force than to accelerate. Defined once +/// because two places must agree on it: where the navigators and locators are attached below, +/// and where vecGeomMaterialBudget() decides how to take a step. +bool usesBvhAcceleration(vecgeom::LogicalVolume const* vol) +{ + return vol->GetDaughtersp()->size() > 2; +} + /// Converts the currently loaded TGeo geometry to VecGeom and sets up navigators, once per /// process, the first time the VecGeom backend is requested. Not part of loadGeometry(), /// which every job calls regardless of whether it ever uses the VecGeom backend. @@ -578,16 +591,35 @@ void ensureVecGeomWorldBuilt() vecgeom::BVHManager::Init(); // For each logical volume, set both a navigator (used for ComputeStep) and a matched - // level locator (used for point relocation after a boundary crossing via GlobalLocator); - // volumes with very few daughters are cheaper to brute-force than to accelerate. + // level locator (used for point relocation after a boundary crossing via GlobalLocator). for (auto& lvol : vecgeom::GeoManager::Instance().GetLogicalVolumesMap()) { auto* vol = lvol.second; - if (vol->GetDaughtersp()->size() <= 2) { + if (!usesBvhAcceleration(vol)) { vol->SetNavigator(vecgeom::NewSimpleNavigator<>::Instance()); vol->SetLevelLocator(vecgeom::SimpleLevelLocator::GetInstance()); } else { +#if VECGEOM_VERSION >= 0x020000 + // VecGeom 2 turned BVHNavigator into a plain class with static entry points instead of a + // VNavigator singleton, so there is nothing to attach: vecGeomMaterialBudget() calls it + // directly. + // + // The locator changes too, and not by choice. BVHLevelLocator does not compile in 2.1.0 or + // 2.1.1 -- the header is byte-identical in both -- because its four LevelLocate() calls + // have no match among the single templated BVH::LevelLocate(int exclude_item_id, ...) that + // v2 ships. It survived two releases because nothing in VecGeom includes that header + // except itself, so upstream CI never compiles it; O2 appears to be its only consumer. + // + // SimpleABBoxLevelLocator is the accelerated stand-in, using the ABBoxes built just above. + // Three of the four methods could be rebuilt on the templated API (the idiom is in + // BVHNavigator itself: bvh->LevelInside(exclude_id, point, id, dlp)), but + // the direction-aware LevelLocateExclVol has no v2 counterpart at all, so this stays a + // fallback rather than a reimplementation. Revert to BVHLevelLocator once upstream fixes + // or removes it, and measure: whether ABBox location costs anything real here is unknown. + vol->SetLevelLocator(vecgeom::SimpleABBoxLevelLocator::GetInstance()); +#else vol->SetNavigator(vecgeom::BVHNavigator<>::Instance()); vol->SetLevelLocator(vecgeom::BVHLevelLocator::GetInstance()); +#endif } } }); @@ -614,9 +646,24 @@ o2::base::MatBudget GeometryManager::vecGeomMaterialBudget(float x0, float y0, f dir[i] *= invlen; } + // Only the allocation differs between VecGeom versions; everything below works on pointers in + // both, which also keeps the std::swap() at the end of the loop a pointer swap rather than a + // copy of the state itself. + // + // VecGeom 1 builds NavigationState as NavStatePath, a variable-size object that must be told the + // maximum depth at construction and can only be made through MakeInstance(). VecGeom 2 dropped + // NavStatePath and MakeInstance with it: NavigationState is NavStateIndex or NavStateTuple, both + // fixed-size value types, so a thread_local object is the direct equivalent. +#if VECGEOM_VERSION >= 0x020000 + thread_local static vecgeom::NavigationState newnavstateStorage, currnavstateStorage, startCacheStorage; + thread_local static vecgeom::NavigationState* newnavstate = &newnavstateStorage; + thread_local static vecgeom::NavigationState* currnavstate = &currnavstateStorage; + thread_local static vecgeom::NavigationState* startCache = &startCacheStorage; +#else thread_local static vecgeom::NavigationState* newnavstate = vecgeom::NavigationState::MakeInstance(vecgeom::GeoManager::Instance().getMaxDepth()); thread_local static vecgeom::NavigationState* currnavstate = vecgeom::NavigationState::MakeInstance(vecgeom::GeoManager::Instance().getMaxDepth()); thread_local static vecgeom::NavigationState* startCache = vecgeom::NavigationState::MakeInstance(vecgeom::GeoManager::Instance().getMaxDepth()); +#endif thread_local static bool startCacheValid = false; Vector3D currPoint(x0, y0, z0); @@ -649,9 +696,18 @@ o2::base::MatBudget GeometryManager::vecGeomMaterialBudget(float x0, float y0, f Int_t nzero = 0; while (remainingDist > 1.E-10) { auto* lvol = currnavstate->Top()->GetLogicalVolume(); - accountMaterial(static_cast(lvol->GetMaterialPtr()), budStep); - vecgeom::VNavigator const* navigator = lvol->GetNavigator(); - double step = static_cast(navigator->ComputeStepAndPropagatedState(currPoint, dirr, remainingDist, *currnavstate, *newnavstate)); + // Not LogicalVolume::GetMaterialPtr(): VecGeom 2 dropped the material slot from the logical + // volume. TGeo2VecGeom keeps what its conversion hook returned, indexed by logical volume id, + // and serves it for both VecGeom versions. + accountMaterial(static_cast(tgeo2vecgeom::RootGeoManager::Instance().GetMaterialPtr(lvol)), budStep); +#if VECGEOM_VERSION >= 0x020000 + const double step = + usesBvhAcceleration(lvol) + ? static_cast(vecgeom::BVHNavigator::ComputeStepAndPropagatedState(currPoint, dirr, remainingDist, *currnavstate, *newnavstate)) + : static_cast(lvol->GetNavigator()->ComputeStepAndPropagatedState(currPoint, dirr, remainingDist, *currnavstate, *newnavstate)); +#else + const double step = static_cast(lvol->GetNavigator()->ComputeStepAndPropagatedState(currPoint, dirr, remainingDist, *currnavstate, *newnavstate)); +#endif if (step < 2.E-10) { nzero++; } else {