14#include "TG4RootDetectorConstruction.h"
16#include "G4PhysicalVolumeStore.hh"
17#include "G4VPhysicalVolume.hh"
19#include "TGeoManager.h"
21#include "TGeoVolume.h"
24#include "TGeo2VecGeom/RootGeoManager.h"
25#include <VecGeom/management/GeoManager.h>
26#include <VecGeom/volumes/LogicalVolume.h>
28#include <fairlogger/Logger.h>
32#include <unordered_set>
44void flattenDaughter(TGeoNode*
node,
bool flatten, std::vector<TGeoNode*>&
chain,
45 std::vector<std::vector<TGeoNode*>>& out)
48 auto* assembly =
dynamic_cast<TGeoVolumeAssembly*
>(
node->GetVolume());
49 if (
flatten && assembly !=
nullptr) {
50 for (
int i = 0;
i < assembly->GetNdaughters(); ++
i) {
59std::vector<std::vector<TGeoNode*>> flattenedDaughters(TGeoVolume
const* volume,
bool flatten)
61 std::vector<std::vector<TGeoNode*>> out;
62 std::vector<TGeoNode*>
chain;
63 for (
int i = 0;
i < volume->GetNdaughters(); ++
i) {
70void VecGeomG4Map::registerPair(vecgeom::VPlacedVolume
const* parent, vecgeom::VPlacedVolume
const* pv,
71 std::vector<TGeoNode*>
const&
nodes, TG4RootDetectorConstruction
const& dc)
73 const auto vgId =
static_cast<std::size_t
>(pv->id());
74 if (vgId >= mChainBegin.size()) {
75 mChainBegin.resize(vgId + 1, 0);
76 mChainSize.resize(vgId + 1, 0);
78 if (mChainSize[vgId] != 0) {
81 mChainBegin[vgId] =
static_cast<unsigned>(mChain.size());
83 mChainSize[vgId] =
static_cast<unsigned>(
nodes.size());
85 auto* g4pv = dc.GetG4VPhysicalVolume(
node);
86 if (g4pv ==
nullptr) {
87 LOG(fatal) <<
"TGeo node " <<
node->GetName() <<
" has no Geant4 counterpart; the two conversions "
88 <<
"of the geometry do not agree";
90 mChain.push_back(g4pv);
91 if (
first && parent ==
nullptr) {
98 const auto g4Id =
static_cast<std::size_t
>(g4pv->GetInstanceID());
99 if (g4Id >= mG4ToVG.size()) {
100 mG4ToVG.resize(g4Id + 1,
nullptr);
102 if (mG4ToVG[g4Id] ==
nullptr) {
104 }
else if (mG4ToVG[g4Id] ==
ambiguous()) {
105 mAmbiguous[
static_cast<int>(g4Id)].push_back(pv);
106 }
else if (mG4ToVG[g4Id] != pv) {
109 auto&
list = mAmbiguous[
static_cast<int>(g4Id)];
110 list.push_back(mG4ToVG[g4Id]);
120 auto& rootGeoMgr = tgeo2vecgeom::RootGeoManager::Instance();
121 auto& vgMgr = vecgeom::GeoManager::Instance();
124 const auto reserve = std::max<std::size_t>(vgMgr.GetPlacedVolumesCount(), vecgeom::VPlacedVolume::GetIdCount()) + 1;
125 mChainBegin.assign(reserve, 0);
126 mChainSize.assign(reserve, 0);
127 mChain.reserve(reserve);
128 mG4ToVG.assign(G4PhysicalVolumeStore::GetInstance()->
size() + 1,
nullptr);
130 auto* topNode = gGeoManager->GetTopNode();
131 auto const* topPV = rootGeoMgr.Lookup(topNode);
132 if (topPV ==
nullptr) {
133 LOG(fatal) <<
"The VecGeom geometry has no counterpart for the TGeo top node";
135 registerPair(
nullptr, topPV, {topNode}, dc);
139 std::unordered_set<TGeoVolume const*> seen;
140 std::function<
void(vecgeom::VPlacedVolume
const*, TGeoNode*)> walk =
141 [&](vecgeom::VPlacedVolume
const* pv, TGeoNode*
node) {
142 auto* volume =
node->GetVolume();
143 if (!seen.insert(volume).second) {
146 const auto chains = flattenedDaughters(volume, flattenAssemblies);
147 auto const& vgDaughters = pv->GetLogicalVolume()->GetDaughters();
148 if (vgDaughters.size() != chains.size()) {
149 LOG(fatal) <<
"Volume " << volume->GetName() <<
" has " << chains.size()
150 <<
" daughters after flattening but its VecGeom counterpart has " << vgDaughters.size()
151 <<
"; the flattening reproduced here does not match the converter's";
153 for (std::size_t
i = 0;
i < chains.size(); ++
i) {
154 auto const* daughter = vgDaughters[
i];
158 auto const* recorded = rootGeoMgr.tgeonode(daughter);
160 const bool ok = recorded !=
nullptr &&
162 (recorded->GetVolume() ==
expected->GetVolume() &&
163 TString(recorded->GetName()).BeginsWith(TString(
expected->GetName()) +
"_assemblyinternalcount_")));
166 if (mMispaired <= 5) {
167 LOG(warning) <<
"VecGeom daughter " <<
i <<
" of " << volume->GetName() <<
" is "
168 << (recorded !=
nullptr ? recorded->GetName() :
"unknown") <<
", expected "
172 registerPair(pv, daughter, chains[
i], dc);
173 walk(daughter, chains[
i].back());
176 walk(topPV, topNode);
178 if (mMispaired != 0) {
179 LOG(error) << mMispaired <<
" VecGeom placements were paired with the wrong TGeo node; the "
180 <<
"order the converter places flattened daughters in is not the order assumed here";
182 LOG(info) <<
"VecGeom navigation: paired " << mPairs <<
" placements with " << mChain.size()
183 <<
" Geant4 volumes (flattenAssemblies=" << flattenAssemblies <<
"), " <<
ambiguousCount()
184 <<
" of them shared by more than one placement";
std::unique_ptr< expressions::Node > node
static vecgeom::VPlacedVolume const * ambiguous()
Marks a Geant4 volume that several VecGeom placements reach.
void build(TG4RootDetectorConstruction const &dc, bool flattenAssemblies)
std::size_t ambiguousCount() const
How many Geant4 volumes share more than one VecGeom placement.
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
bool list(IEventListener &reporter, Config const &config)
std::map< std::string, ID > expected
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"