Skip to content

Commit 60e8cae

Browse files
sawenzelclaudealibuild
authored
o2-sim: VecGeom navigation mode for Geant4 (#15865)
* Set up the VecGeom BVH navigator and safety estimators for every volume This lets GeometryManager set up VecGeom for Geant4 navigation as well as for the material budget. - buildVecGeomGeometry() converts once and takes the assembly flattening as a parameter; the material budget keeps flattening. - With a VecGeom that has BVHNavigatorV, volumes with more than two daughters get the BVH navigator and level locator, and every volume gets an explicit safety estimator. - Without it the VecGeom v2 setup is unchanged. https://gitlab.cern.ch/VecGeom/VecGeom/-/merge_requests/1547 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Add a VecGeom navigation mode to the Geant4 engine This adds G4.navmode=kVecGeom, in which Geant4 answers every navigation query from VecGeom. - The geometry, materials and touchables stay the ones g4root builds from TGeo. - VecGeomG4Map pairs each VecGeom placement with the chain of g4root volumes it stands for, so volume ids, copy numbers and CurrentVolOffID are unchanged. - VecGeomG4Navigator relocates at the boundary locate, with the volume just left blocked for the next step and the point pushed across the face by a small depth, as G4VecGeomNav's TG4VecGeomNavigator does. - G4.vecgeomCheckRays, vecgeomCheckLocation and vecgeomCheckVolumes compare VecGeom with TGeo before transport. - It is built only when TGeo2VecGeom and a VecGeom with BVHNavigatorV are found. https://gitlab.cern.ch/VecGeom/g4vecgeomnav/-/merge_requests/25 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Add a lighter VecGeom navigator that adopts the propagated state This adds G4.vecgeomNavigator=kPropagated, a second VecGeom navigator kept for comparison. - It adopts the state VecGeom propagated during the step instead of relocating at the boundary. - It returns zero safety for the step after a crossing and nudges stuck steps forward. - The default navigator becomes G4.vecgeomNavigator=kRelocating. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Block the exited volume only as Geant4 does This fixes tracks entering the volume they just left without seeing its boundary. - Both VecGeom navigators kept the volume just left blocked for every following step, whatever the direction. - A track turned back into it at the exit point, as by multiple scattering, crossed it unseen in the mother. - In the hollow RB24 copper tubes this let shower electrons pass the wall and gave about 10 % more FDD-A hits. - The volume is now blocked only in the first step after the exit, and only while the direction points away from it, as in G4NormalNavigation. This follows the same fix in G4VecGeomNav. https://gitlab.cern.ch/swenzel/g4vecgeomnav/-/tree/fix/block-and-reflection Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Please consider the following formatting changes --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: ALICE Action Bot <alibuild@cern.ch>
1 parent 48ac643 commit 60e8cae

17 files changed

Lines changed: 2064 additions & 10 deletions

‎Common/SimConfig/include/SimConfig/G4Params.h‎

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,15 @@ enum class EG4Physics {
3636
// enumerating possible geometry navigation modes
3737
// (understanding that geometry description is always done with TGeo)
3838
enum class EG4Nav {
39-
kTGeo = 0, /* navigate with TGeo */
40-
kG4 = 1 /* navigate with G4 native geometry */
39+
kTGeo = 0, /* navigate with TGeo */
40+
kG4 = 1, /* navigate with G4 native geometry */
41+
kVecGeom = 2 /* navigate with VecGeom, on the G4 geometry built from TGeo */
42+
};
43+
44+
// the Geant4 navigator used with navmode kVecGeom
45+
enum class EVecGeomNav {
46+
kRelocating = 0, /* relocates at the boundary locate, blocking the volume just left (default) */
47+
kPropagated = 1 /* adopts the state VecGeom propagated during the step; less work per crossing */
4148
};
4249

4350
// parameters to influence the G4 engine
@@ -49,6 +56,22 @@ struct G4Params : public o2::conf::ConfigurableParamHelper<G4Params> {
4956

5057
EG4Nav navmode = EG4Nav::kTGeo; // geometry navigation mode (default TGeo)
5158

59+
// Settings for navmode == kVecGeom; ignored otherwise.
60+
// which of the two VecGeom navigators
61+
EVecGeomNav vecgeomNavigator = EVecGeomNav::kRelocating;
62+
double vecgeomPushDepth = 1.e-9; // cm; how far past a face, measured across it, a boundary
63+
// point is pushed before it is located
64+
bool vecgeomZeroSafety = false; // answer zero to every safety query; conservative, but it
65+
// shortens steps and so changes the random history
66+
bool vecgeomFlattenAssemblies = true; // dissolve TGeo assemblies into their content when converting
67+
// to VecGeom; the Geant4 touchable keeps the assembly levels
68+
int vecgeomCheckRays = 0; // if > 0, step this many rays out of the interaction point with
69+
// TGeo and VecGeom and report the volumes they enter differently
70+
int vecgeomCheckLocation = 0; // if > 0, locate this many random points with both and report
71+
// the volumes they disagree on
72+
std::string vecgeomCheckVolumes = ""; // comma-separated volumes to cross-check by sampling inside
73+
// their placements
74+
5275
std::string fluenceWeightFile = ""; // file containing the scoring weights (pdg, ekin, weight)
5376
std::string const& getPhysicsConfigString() const;
5477

‎Detectors/Base/include/DetectorsBase/GeometryManager.h‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,12 @@ class GeometryManager : public TObject
135135
/// Mean material budget between two points, using the VecGeom backend. On first call,
136136
/// lazily converts the currently loaded TGeo geometry to VecGeom (once per process).
137137
static o2::base::MatBudget vecGeomMaterialBudget(float x0, float y0, float z0, float x1, float y1, float z1);
138+
/// Converts the currently loaded TGeo geometry to VecGeom and assigns a navigator, a level
139+
/// locator and a safety estimator to every logical volume. Does the work once per process; later
140+
/// calls, whatever they ask for, return the geometry already built, so a caller that needs a
141+
/// particular assembly treatment must come first. \param flattenAssemblies dissolves TGeo
142+
/// assemblies into their content.
143+
static void buildVecGeomGeometry(bool flattenAssemblies);
138144
#else
139145
static constexpr bool isVecGeomAvailable() { return false; }
140146
#endif

‎Detectors/Base/src/GeometryManager.cxx‎

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,14 @@
4949
#include <VecGeom/navigation/VNavigator.h>
5050
#include <VecGeom/volumes/LogicalVolume.h>
5151
#include <mutex>
52+
// The BVH navigator of the VNavigator family, which Geant4 navigation needs on every volume.
53+
#if __has_include(<VecGeom/navigation/BVHNavigatorV.h>)
54+
#define O2_VECGEOM_HAS_BVH_VNAVIGATOR
55+
#include <VecGeom/navigation/BVHNavigatorV.h>
56+
#include <VecGeom/navigation/BVHLevelLocator.h>
57+
#include <VecGeom/navigation/BVHSafetyEstimator.h>
58+
#include <VecGeom/navigation/SimpleSafetyEstimator.h>
59+
#endif
5260
#endif
5361

5462
using namespace o2::detectors;
@@ -574,15 +582,22 @@ bool usesBvhAcceleration(vecgeom::LogicalVolume const* vol)
574582
/// process, the first time the VecGeom backend is requested. Not part of loadGeometry(),
575583
/// which every job calls regardless of whether it ever uses the VecGeom backend.
576584
void ensureVecGeomWorldBuilt()
585+
{
586+
GeometryManager::buildVecGeomGeometry(true);
587+
}
588+
} // namespace
589+
590+
void GeometryManager::buildVecGeomGeometry(bool flattenAssemblies)
577591
{
578592
static std::once_flag onceFlag;
579-
std::call_once(onceFlag, []() {
593+
std::call_once(onceFlag, [flattenAssemblies]() {
580594
if (!gGeoManager) {
581595
LOG(fatal) << "Cannot build VecGeom geometry: no TGeo geometry loaded (call GeometryManager::loadGeometry() first)";
582596
}
583597
// Translate geometry and material pointers, then build acceleration structures.
584598
tgeo2vecgeom::RootGeoManager::Instance().SetMaterialConversionHook([](TGeoMaterial const* m) { return (void*)m; });
585-
tgeo2vecgeom::RootGeoManager::Instance().SetFlattenAssemblies(true);
599+
LOG(info) << "VecGeom conversion: flattenAssemblies=" << flattenAssemblies;
600+
tgeo2vecgeom::RootGeoManager::Instance().SetFlattenAssemblies(flattenAssemblies);
586601
tgeo2vecgeom::RootGeoManager::Instance().LoadRootGeometry();
587602

588603
// Acceleration structures must be built before the navigators/locators reference them.
@@ -593,15 +608,28 @@ void ensureVecGeomWorldBuilt()
593608
// Builds a BVH per logical volume.
594609
vecgeom::BVHManager::Init();
595610

596-
// For each logical volume, set both a navigator (used for ComputeStep) and a matched
597-
// level locator (used for point relocation after a boundary crossing via GlobalLocator).
611+
// For each logical volume, set a navigator (used for ComputeStep), a matched level locator
612+
// (used for point relocation after a boundary crossing via GlobalLocator) and, where the
613+
// VNavigator family is complete, the safety estimator LogicalVolume::GetSafetyEstimator()
614+
// hands out, which is separate from the one a navigator uses internally.
598615
for (auto& lvol : vecgeom::GeoManager::Instance().GetLogicalVolumesMap()) {
599616
auto* vol = lvol.second;
600617
if (!usesBvhAcceleration(vol)) {
601618
vol->SetNavigator(vecgeom::NewSimpleNavigator<>::Instance());
619+
#ifdef O2_VECGEOM_HAS_BVH_VNAVIGATOR
620+
vol->SetLevelLocator(vol->ContainsAssembly() ? vecgeom::SimpleAssemblyLevelLocator::GetInstance()
621+
: vecgeom::SimpleLevelLocator::GetInstance());
622+
vol->SetSafetyEstimator(vecgeom::SimpleSafetyEstimator::Instance());
623+
#else
602624
vol->SetLevelLocator(vecgeom::SimpleLevelLocator::GetInstance());
625+
#endif
603626
} else {
604-
#if VECGEOM_VERSION >= 0x020000
627+
#if defined(O2_VECGEOM_HAS_BVH_VNAVIGATOR)
628+
vol->SetNavigator(vecgeom::BVHNavigatorV<>::Instance());
629+
vol->SetLevelLocator(vol->ContainsAssembly() ? vecgeom::BVHAssemblyAwareLevelLocator::GetInstance()
630+
: vecgeom::BVHLevelLocator::GetInstance());
631+
vol->SetSafetyEstimator(vecgeom::BVHSafetyEstimator::Instance());
632+
#elif VECGEOM_VERSION >= 0x020000
605633
// VecGeom 2 turned BVHNavigator into a plain class with static entry points instead of a
606634
// VNavigator singleton, so there is nothing to attach: vecGeomMaterialBudget() calls it
607635
// directly.
@@ -627,7 +655,6 @@ void ensureVecGeomWorldBuilt()
627655
}
628656
});
629657
}
630-
} // namespace
631658

632659
//_____________________________________________________________________________________
633660
o2::base::MatBudget GeometryManager::vecGeomMaterialBudget(float x0, float y0, float z0, float x1, float y1, float z1)

‎Detectors/gconfig/CMakeLists.txt‎

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,40 @@ o2_add_library(G3Setup
1414
PUBLIC_LINK_LIBRARIES MC::Geant3 FairRoot::Base O2::SimulationDataFormat O2::Generators O2::SimSetup
1515
)
1616

17+
# Optional VecGeom navigation for Geant4 (G4.navmode=kVecGeom). It needs TGeo2VecGeom and a VecGeom
18+
# with the BVH navigator of the VNavigator family (BVHNavigatorV). Linked PRIVATE: VecGeom types
19+
# never appear in G4Setup's public headers.
20+
find_package(TGeo2VecGeom CONFIG QUIET)
21+
set(G4SETUP_WITH_VECGEOM OFF)
22+
if(TGeo2VecGeom_FOUND)
23+
find_path(O2_VECGEOM_BVHNAVIGATORV_INCLUDE VecGeom/navigation/BVHNavigatorV.h
24+
HINTS ${VecGeom_INCLUDE_DIRS} ${VecGeom_DIR}/../../../include $ENV{VECGEOM_ROOT}/include)
25+
if(O2_VECGEOM_BVHNAVIGATORV_INCLUDE)
26+
set(G4SETUP_WITH_VECGEOM ON)
27+
endif()
28+
endif()
29+
30+
set(G4SETUP_SOURCES src/G4Config.cxx src/G4RunConfiguration.cxx src/G4LocalFieldConstruction.cxx
31+
src/VecGeomNavigation.cxx)
32+
if(G4SETUP_WITH_VECGEOM)
33+
list(APPEND G4SETUP_SOURCES src/VecGeomG4Map.cxx src/VecGeomChecks.cxx src/VecGeomG4NavigatorBase.cxx
34+
src/VecGeomG4Navigator.cxx
35+
src/VecGeomG4PropagatingNavigator.cxx)
36+
endif()
37+
1738
o2_add_library(G4Setup
18-
SOURCES src/G4Config.cxx src/G4RunConfiguration.cxx src/G4LocalFieldConstruction.cxx
19-
PUBLIC_LINK_LIBRARIES MC::Geant4VMC MC::Geant4 FairRoot::Base O2::SimulationDataFormat O2::Generators O2::SimSetup O2::FastSim
39+
TARGETVARNAME targetG4Setup
40+
SOURCES ${G4SETUP_SOURCES}
41+
PUBLIC_LINK_LIBRARIES MC::Geant4VMC MC::Geant4 FairRoot::Base O2::SimulationDataFormat O2::Generators O2::SimSetup O2::FastSim O2::DetectorsBase
2042
)
2143

44+
if(G4SETUP_WITH_VECGEOM)
45+
target_compile_definitions(${targetG4Setup} PRIVATE O2_WITH_VECGEOM)
46+
target_link_libraries(${targetG4Setup} PRIVATE TGeo2VecGeom::TGeo2VecGeom)
47+
else()
48+
message(STATUS "G4.navmode=kVecGeom not built: it needs TGeo2VecGeom and a VecGeom with BVHNavigatorV")
49+
endif()
50+
2251
o2_add_library(FLUKASetup
2352
SOURCES src/FlukaConfig.cxx
2453
PUBLIC_LINK_LIBRARIES FairRoot::Base O2::SimulationDataFormat O2::Generators O2::SimSetup

‎Detectors/gconfig/g4Config.C‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ R__LOAD_LIBRARY(libgeant4vmc)
6666
#include "G4VScoringMesh.hh"
6767
#include <unistd.h>
6868
#include "SimSetup/G4RunConfiguration.h"
69+
#include "SimSetup/VecGeomNavigation.h"
6970
#endif
7071
#include "commonConfig.C"
7172

@@ -115,6 +116,10 @@ void Config()
115116
geomNavStr = "geomRoot";
116117
} else if (g4Params.navmode == o2::conf::EG4Nav::kG4) {
117118
geomNavStr = "geomVMC+RootToGeant4";
119+
} else if (g4Params.navmode == o2::conf::EG4Nav::kVecGeom) {
120+
// The geometry, its materials and the touchable stay the ones g4root builds from TGeo;
121+
// only the navigator is swapped, once the engine below has built that hierarchy.
122+
geomNavStr = "geomRoot";
118123
} else {
119124
LOG(fatal) << "Unsupported geometry navigation mode";
120125
}
@@ -137,6 +142,10 @@ void Config()
137142
TGeant4* geant4 = new TGeant4("TGeant4", "The Geant4 Monte Carlo", runConfiguration);
138143
std::cout << "Geant4 has been created." << std::endl;
139144

145+
if (g4Params.navmode == o2::conf::EG4Nav::kVecGeom) {
146+
o2::simsetup::installVecGeomNavigator();
147+
}
148+
140149
// setup the stack
141150
stackSetup(geant4, FairRunSim::Instance());
142151

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2+
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3+
// All rights not expressly granted are reserved.
4+
//
5+
// This software is distributed under the terms of the GNU General Public
6+
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7+
//
8+
// In applying this license CERN does not waive the privileges and immunities
9+
// granted to it by virtue of its status as an Intergovernmental Organization
10+
// or submit itself to any jurisdiction.
11+
12+
#ifndef O2_SIMSETUP_VECGEOMNAVIGATION_H_
13+
#define O2_SIMSETUP_VECGEOMNAVIGATION_H_
14+
15+
namespace o2::simsetup
16+
{
17+
18+
/// Whether this build of O2 has the VecGeom navigation backend, i.e. whether TGeo2VecGeom and a
19+
/// VecGeom with BVHNavigatorV were found when O2 was configured.
20+
bool isVecGeomNavigationAvailable();
21+
22+
/// Replaces Geant4's tracking navigator by one that answers every navigation query from
23+
/// VecGeom. The Geant4 geometry, its materials and the touchable the scoring code reads stay
24+
/// the ones g4root built from TGeo, so only navigation changes.
25+
///
26+
/// Call after the TGeant4 engine has been constructed: the Geant4 hierarchy this needs to map
27+
/// onto is built while TG4RunManager configures itself. Aborts if the backend is missing.
28+
void installVecGeomNavigator();
29+
30+
} // namespace o2::simsetup
31+
32+
#endif

0 commit comments

Comments
 (0)