2323#include < cassert>
2424#include < cstddef> // for NULL
2525#include < numeric>
26+ #include < type_traits> // for the NavigationState static_assert below
2627
2728#include " DetectorsBase/GeometryManager.h"
2829#include " DetectorsBase/GeometryManagerParam.h"
3233
3334#ifdef O2_WITH_VECGEOM
3435#include " TGeo2VecGeom/RootGeoManager.h"
36+ #include < VecGeom/base/Version.h>
3537#include < VecGeom/management/GeoManager.h>
3638#include < VecGeom/management/ABBoxManager.h>
3739#include < VecGeom/management/BVHManager.h>
4042#include < VecGeom/navigation/NewSimpleNavigator.h>
4143#include < VecGeom/navigation/BVHNavigator.h>
4244#include < VecGeom/navigation/SimpleLevelLocator.h>
45+ #if VECGEOM_VERSION >= 0x020000
46+ #include < VecGeom/navigation/SimpleABBoxLevelLocator.h>
47+ #else
4348#include < VecGeom/navigation/BVHLevelLocator.h>
49+ #endif
4450#include < VecGeom/navigation/VNavigator.h>
4551#include < VecGeom/volumes/LogicalVolume.h>
4652#include < mutex>
@@ -557,6 +563,14 @@ void GeometryManager::loadGeometry(std::string_view simPrefix, bool applyMisalig
557563
558564namespace
559565{
566+ // / Volumes with very few daughters are cheaper to brute-force than to accelerate. Defined once
567+ // / because two places must agree on it: where the navigators and locators are attached below,
568+ // / and where vecGeomMaterialBudget() decides how to take a step.
569+ bool usesBvhAcceleration (vecgeom::LogicalVolume const * vol)
570+ {
571+ return vol->GetDaughtersp ()->size () > 2 ;
572+ }
573+
560574// / Converts the currently loaded TGeo geometry to VecGeom and sets up navigators, once per
561575// / process, the first time the VecGeom backend is requested. Not part of loadGeometry(),
562576// / which every job calls regardless of whether it ever uses the VecGeom backend.
@@ -578,16 +592,35 @@ void ensureVecGeomWorldBuilt()
578592 vecgeom::BVHManager::Init ();
579593
580594 // 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.
595+ // level locator (used for point relocation after a boundary crossing via GlobalLocator).
583596 for (auto & lvol : vecgeom::GeoManager::Instance ().GetLogicalVolumesMap ()) {
584597 auto * vol = lvol.second ;
585- if (vol-> GetDaughtersp ()-> size () <= 2 ) {
598+ if (! usesBvhAcceleration (vol) ) {
586599 vol->SetNavigator (vecgeom::NewSimpleNavigator<>::Instance ());
587600 vol->SetLevelLocator (vecgeom::SimpleLevelLocator::GetInstance ());
588601 } else {
602+ #if VECGEOM_VERSION >= 0x020000
603+ // VecGeom 2 turned BVHNavigator into a plain class with static entry points instead of a
604+ // VNavigator singleton, so there is nothing to attach: vecGeomMaterialBudget() calls it
605+ // directly.
606+ //
607+ // The locator changes too, and not by choice. BVHLevelLocator does not compile in 2.1.0 or
608+ // 2.1.1 -- the header is byte-identical in both -- because its four LevelLocate() calls
609+ // have no match among the single templated BVH::LevelLocate(int exclude_item_id, ...) that
610+ // v2 ships. It survived two releases because nothing in VecGeom includes that header
611+ // except itself, so upstream CI never compiles it; O2 appears to be its only consumer.
612+ //
613+ // SimpleABBoxLevelLocator is the accelerated stand-in, using the ABBoxes built just above.
614+ // Three of the four methods could be rebuilt on the templated API (the idiom is in
615+ // BVHNavigator itself: bvh->LevelInside<BVHNavigator>(exclude_id, point, id, dlp)), but
616+ // the direction-aware LevelLocateExclVol has no v2 counterpart at all, so this stays a
617+ // fallback rather than a reimplementation. Revert to BVHLevelLocator once upstream fixes
618+ // or removes it, and measure: whether ABBox location costs anything real here is unknown.
619+ vol->SetLevelLocator (vecgeom::SimpleABBoxLevelLocator::GetInstance ());
620+ #else
589621 vol->SetNavigator (vecgeom::BVHNavigator<>::Instance ());
590622 vol->SetLevelLocator (vecgeom::BVHLevelLocator::GetInstance ());
623+ #endif
591624 }
592625 }
593626 });
@@ -614,9 +647,16 @@ o2::base::MatBudget GeometryManager::vecGeomMaterialBudget(float x0, float y0, f
614647 dir[i] *= invlen;
615648 }
616649
617- thread_local static vecgeom::NavigationState* newnavstate = vecgeom::NavigationState::MakeInstance (vecgeom::GeoManager::Instance ().getMaxDepth ());
618- thread_local static vecgeom::NavigationState* currnavstate = vecgeom::NavigationState::MakeInstance (vecgeom::GeoManager::Instance ().getMaxDepth ());
619- thread_local static vecgeom::NavigationState* startCache = vecgeom::NavigationState::MakeInstance (vecgeom::GeoManager::Instance ().getMaxDepth ());
650+ // Held by value rather than through NavigationState::MakeInstance(): VecGeom 2 removed
651+ // MakeInstance, and in VecGeom 1 it only ever did `new NavStateIndex()` with the depth argument
652+ // ignored. By value it is also one fewer per-thread allocation that was never freed.
653+ static_assert (std::is_default_constructible_v<vecgeom::NavigationState>,
654+ " NavigationState must be an index or tuple state. A variable-depth NavStatePath "
655+ " build (VecGeom 1 without VECGEOM_USE_INDEXEDNAVSTATES) needs the depth at "
656+ " construction and is not supported here." );
657+ thread_local static vecgeom::NavigationState newnavstate;
658+ thread_local static vecgeom::NavigationState currnavstate;
659+ thread_local static vecgeom::NavigationState startCache;
620660 thread_local static bool startCacheValid = false ;
621661
622662 Vector3D currPoint (x0, y0, z0);
@@ -627,31 +667,40 @@ o2::base::MatBudget GeometryManager::vecGeomMaterialBudget(float x0, float y0, f
627667 budStep.length = length;
628668
629669 // Locate the starting volume, reusing the path from the previous call when still valid.
630- if (startCacheValid && !startCache-> IsOutside ()) {
631- startCache-> CopyTo (currnavstate);
670+ if (startCacheValid && !startCache. IsOutside ()) {
671+ startCache. CopyTo (& currnavstate);
632672 vecgeom::Transformation3D m;
633- currnavstate-> TopMatrix (m);
634- vecgeom::GlobalLocator::RelocatePointFromPath (m.Transform (currPoint), * currnavstate);
673+ currnavstate. TopMatrix (m);
674+ vecgeom::GlobalLocator::RelocatePointFromPath (m.Transform (currPoint), currnavstate);
635675 } else {
636- currnavstate-> Clear ();
637- vecgeom::GlobalLocator::LocateGlobalPoint (world, currPoint, * currnavstate, true );
676+ currnavstate. Clear ();
677+ vecgeom::GlobalLocator::LocateGlobalPoint (world, currPoint, currnavstate, true );
638678 }
639- if (currnavstate-> IsOutside () || currnavstate-> Top () == nullptr ) {
679+ if (currnavstate. IsOutside () || currnavstate. Top () == nullptr ) {
640680 LOG (error) << " start point out of geometry: " << x0 << ' :' << y0 << ' :' << z0;
641681 startCacheValid = false ;
642682 return o2::base::MatBudget ();
643683 }
644- currnavstate-> CopyTo (startCache);
684+ currnavstate. CopyTo (& startCache);
645685 startCacheValid = true ;
646686
647687 double stepTot = 0 .;
648688 double remainingDist = length;
649689 Int_t nzero = 0 ;
650690 while (remainingDist > 1 .E -10 ) {
651- 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));
691+ auto * lvol = currnavstate.Top ()->GetLogicalVolume ();
692+ // Not LogicalVolume::GetMaterialPtr(): VecGeom 2 dropped the material slot from the logical
693+ // volume. TGeo2VecGeom keeps what its conversion hook returned, indexed by logical volume id,
694+ // and serves it for both VecGeom versions.
695+ accountMaterial (static_cast <TGeoMaterial*>(tgeo2vecgeom::RootGeoManager::Instance ().GetMaterialPtr (lvol)), budStep);
696+ #if VECGEOM_VERSION >= 0x020000
697+ const double step =
698+ usesBvhAcceleration (lvol)
699+ ? static_cast <double >(vecgeom::BVHNavigator::ComputeStepAndPropagatedState (currPoint, dirr, remainingDist, currnavstate, newnavstate))
700+ : static_cast <double >(lvol->GetNavigator ()->ComputeStepAndPropagatedState (currPoint, dirr, remainingDist, currnavstate, newnavstate));
701+ #else
702+ const double step = static_cast <double >(lvol->GetNavigator ()->ComputeStepAndPropagatedState (currPoint, dirr, remainingDist, currnavstate, newnavstate));
703+ #endif
655704 if (step < 2 .E -10 ) {
656705 nzero++;
657706 } else {
0 commit comments