3232
3333#ifdef O2_WITH_VECGEOM
3434#include " TGeo2VecGeom/RootGeoManager.h"
35+ #include < VecGeom/base/Version.h>
3536#include < VecGeom/management/GeoManager.h>
3637#include < VecGeom/management/ABBoxManager.h>
3738#include < VecGeom/management/BVHManager.h>
4041#include < VecGeom/navigation/NewSimpleNavigator.h>
4142#include < VecGeom/navigation/BVHNavigator.h>
4243#include < VecGeom/navigation/SimpleLevelLocator.h>
44+ #if VECGEOM_VERSION >= 0x020000
45+ #include < VecGeom/navigation/SimpleABBoxLevelLocator.h>
46+ #else
4347#include < VecGeom/navigation/BVHLevelLocator.h>
48+ #endif
4449#include < VecGeom/navigation/VNavigator.h>
4550#include < VecGeom/volumes/LogicalVolume.h>
4651#include < mutex>
@@ -557,6 +562,14 @@ void GeometryManager::loadGeometry(std::string_view simPrefix, bool applyMisalig
557562
558563namespace
559564{
565+ // / Volumes with very few daughters are cheaper to brute-force than to accelerate. Defined once
566+ // / because two places must agree on it: where the navigators and locators are attached below,
567+ // / and where vecGeomMaterialBudget() decides how to take a step.
568+ bool usesBvhAcceleration (vecgeom::LogicalVolume const * vol)
569+ {
570+ return vol->GetDaughtersp ()->size () > 2 ;
571+ }
572+
560573// / Converts the currently loaded TGeo geometry to VecGeom and sets up navigators, once per
561574// / process, the first time the VecGeom backend is requested. Not part of loadGeometry(),
562575// / which every job calls regardless of whether it ever uses the VecGeom backend.
@@ -578,16 +591,35 @@ void ensureVecGeomWorldBuilt()
578591 vecgeom::BVHManager::Init ();
579592
580593 // For each logical volume, set both a navigator (used for ComputeStep) and a matched
581- // level locator (used for point relocation after a boundary crossing via GlobalLocator);
582- // volumes with very few daughters are cheaper to brute-force than to accelerate.
594+ // level locator (used for point relocation after a boundary crossing via GlobalLocator).
583595 for (auto & lvol : vecgeom::GeoManager::Instance ().GetLogicalVolumesMap ()) {
584596 auto * vol = lvol.second ;
585- if (vol-> GetDaughtersp ()-> size () <= 2 ) {
597+ if (! usesBvhAcceleration (vol) ) {
586598 vol->SetNavigator (vecgeom::NewSimpleNavigator<>::Instance ());
587599 vol->SetLevelLocator (vecgeom::SimpleLevelLocator::GetInstance ());
588600 } else {
601+ #if VECGEOM_VERSION >= 0x020000
602+ // VecGeom 2 turned BVHNavigator into a plain class with static entry points instead of a
603+ // VNavigator singleton, so there is nothing to attach: vecGeomMaterialBudget() calls it
604+ // directly.
605+ //
606+ // The locator changes too, and not by choice. BVHLevelLocator does not compile in 2.1.0 or
607+ // 2.1.1 -- the header is byte-identical in both -- because its four LevelLocate() calls
608+ // have no match among the single templated BVH::LevelLocate(int exclude_item_id, ...) that
609+ // v2 ships. It survived two releases because nothing in VecGeom includes that header
610+ // except itself, so upstream CI never compiles it; O2 appears to be its only consumer.
611+ //
612+ // SimpleABBoxLevelLocator is the accelerated stand-in, using the ABBoxes built just above.
613+ // Three of the four methods could be rebuilt on the templated API (the idiom is in
614+ // BVHNavigator itself: bvh->LevelInside<BVHNavigator>(exclude_id, point, id, dlp)), but
615+ // the direction-aware LevelLocateExclVol has no v2 counterpart at all, so this stays a
616+ // fallback rather than a reimplementation. Revert to BVHLevelLocator once upstream fixes
617+ // or removes it, and measure: whether ABBox location costs anything real here is unknown.
618+ vol->SetLevelLocator (vecgeom::SimpleABBoxLevelLocator::GetInstance ());
619+ #else
589620 vol->SetNavigator (vecgeom::BVHNavigator<>::Instance ());
590621 vol->SetLevelLocator (vecgeom::BVHLevelLocator::GetInstance ());
622+ #endif
591623 }
592624 }
593625 });
@@ -614,9 +646,24 @@ o2::base::MatBudget GeometryManager::vecGeomMaterialBudget(float x0, float y0, f
614646 dir[i] *= invlen;
615647 }
616648
649+ // Only the allocation differs between VecGeom versions; everything below works on pointers in
650+ // both, which also keeps the std::swap() at the end of the loop a pointer swap rather than a
651+ // copy of the state itself.
652+ //
653+ // VecGeom 1 builds NavigationState as NavStatePath, a variable-size object that must be told the
654+ // maximum depth at construction and can only be made through MakeInstance(). VecGeom 2 dropped
655+ // NavStatePath and MakeInstance with it: NavigationState is NavStateIndex or NavStateTuple, both
656+ // fixed-size value types, so a thread_local object is the direct equivalent.
657+ #if VECGEOM_VERSION >= 0x020000
658+ thread_local static vecgeom::NavigationState newnavstateStorage, currnavstateStorage, startCacheStorage;
659+ thread_local static vecgeom::NavigationState* newnavstate = &newnavstateStorage;
660+ thread_local static vecgeom::NavigationState* currnavstate = &currnavstateStorage;
661+ thread_local static vecgeom::NavigationState* startCache = &startCacheStorage;
662+ #else
617663 thread_local static vecgeom::NavigationState* newnavstate = vecgeom::NavigationState::MakeInstance (vecgeom::GeoManager::Instance ().getMaxDepth ());
618664 thread_local static vecgeom::NavigationState* currnavstate = vecgeom::NavigationState::MakeInstance (vecgeom::GeoManager::Instance ().getMaxDepth ());
619665 thread_local static vecgeom::NavigationState* startCache = vecgeom::NavigationState::MakeInstance (vecgeom::GeoManager::Instance ().getMaxDepth ());
666+ #endif
620667 thread_local static bool startCacheValid = false ;
621668
622669 Vector3D currPoint (x0, y0, z0);
@@ -649,9 +696,18 @@ o2::base::MatBudget GeometryManager::vecGeomMaterialBudget(float x0, float y0, f
649696 Int_t nzero = 0 ;
650697 while (remainingDist > 1 .E -10 ) {
651698 auto * lvol = currnavstate->Top ()->GetLogicalVolume ();
652- accountMaterial (static_cast <TGeoMaterial*>(lvol->GetMaterialPtr ()), budStep);
653- vecgeom::VNavigator const * navigator = lvol->GetNavigator ();
654- double step = static_cast <double >(navigator->ComputeStepAndPropagatedState (currPoint, dirr, remainingDist, *currnavstate, *newnavstate));
699+ // Not LogicalVolume::GetMaterialPtr(): VecGeom 2 dropped the material slot from the logical
700+ // volume. TGeo2VecGeom keeps what its conversion hook returned, indexed by logical volume id,
701+ // and serves it for both VecGeom versions.
702+ accountMaterial (static_cast <TGeoMaterial*>(tgeo2vecgeom::RootGeoManager::Instance ().GetMaterialPtr (lvol)), budStep);
703+ #if VECGEOM_VERSION >= 0x020000
704+ const double step =
705+ usesBvhAcceleration (lvol)
706+ ? static_cast <double >(vecgeom::BVHNavigator::ComputeStepAndPropagatedState (currPoint, dirr, remainingDist, *currnavstate, *newnavstate))
707+ : static_cast <double >(lvol->GetNavigator ()->ComputeStepAndPropagatedState (currPoint, dirr, remainingDist, *currnavstate, *newnavstate));
708+ #else
709+ const double step = static_cast <double >(lvol->GetNavigator ()->ComputeStepAndPropagatedState (currPoint, dirr, remainingDist, *currnavstate, *newnavstate));
710+ #endif
655711 if (step < 2 .E -10 ) {
656712 nzero++;
657713 } else {
0 commit comments