Project
Loading...
Searching...
No Matches
VecGeomG4Map.cxx
Go to the documentation of this file.
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#include "VecGeomG4Map.h"
13
14#include "TG4RootDetectorConstruction.h"
15
16#include "G4PhysicalVolumeStore.hh"
17#include "G4VPhysicalVolume.hh"
18
19#include "TGeoManager.h"
20#include "TGeoNode.h"
21#include "TGeoVolume.h"
22#include "TString.h"
23
24#include "TGeo2VecGeom/RootGeoManager.h"
25#include <VecGeom/management/GeoManager.h>
26#include <VecGeom/volumes/LogicalVolume.h>
27
28#include <fairlogger/Logger.h>
29
30#include <algorithm>
31#include <functional>
32#include <unordered_set>
33
34namespace o2::simsetup
35{
36
37namespace
38{
44void flattenDaughter(TGeoNode* node, bool flatten, std::vector<TGeoNode*>& chain,
45 std::vector<std::vector<TGeoNode*>>& out)
46{
47 chain.push_back(node);
48 auto* assembly = dynamic_cast<TGeoVolumeAssembly*>(node->GetVolume());
49 if (flatten && assembly != nullptr) {
50 for (int i = 0; i < assembly->GetNdaughters(); ++i) {
51 flattenDaughter(assembly->GetNode(i), flatten, chain, out);
52 }
53 } else {
54 out.push_back(chain);
55 }
56 chain.pop_back();
57}
58
59std::vector<std::vector<TGeoNode*>> flattenedDaughters(TGeoVolume const* volume, bool flatten)
60{
61 std::vector<std::vector<TGeoNode*>> out;
62 std::vector<TGeoNode*> chain;
63 for (int i = 0; i < volume->GetNdaughters(); ++i) {
64 flattenDaughter(volume->GetNode(i), flatten, chain, out);
65 }
66 return out;
67}
68} // namespace
69
70void VecGeomG4Map::registerPair(vecgeom::VPlacedVolume const* parent, vecgeom::VPlacedVolume const* pv,
71 std::vector<TGeoNode*> const& nodes, TG4RootDetectorConstruction const& dc)
72{
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);
77 }
78 if (mChainSize[vgId] != 0) { // a logical volume placed more than once shares its daughters
79 return;
80 }
81 mChainBegin[vgId] = static_cast<unsigned>(mChain.size());
82 bool first = true;
83 mChainSize[vgId] = static_cast<unsigned>(nodes.size());
84 for (auto* node : nodes) {
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";
89 }
90 mChain.push_back(g4pv);
91 if (first && parent == nullptr) {
92 mWorld = pv;
93 }
94 first = false;
95 if (node != nodes.back()) {
96 continue; // an intermediate assembly level, dissolved on the VecGeom side
97 }
98 const auto g4Id = static_cast<std::size_t>(g4pv->GetInstanceID());
99 if (g4Id >= mG4ToVG.size()) {
100 mG4ToVG.resize(g4Id + 1, nullptr);
101 }
102 if (mG4ToVG[g4Id] == nullptr) {
103 mG4ToVG[g4Id] = pv;
104 } else if (mG4ToVG[g4Id] == ambiguous()) {
105 mAmbiguous[static_cast<int>(g4Id)].push_back(pv);
106 } else if (mG4ToVG[g4Id] != pv) {
107 // Reached through more than one flattened chain: the content of an assembly placed in
108 // more than one place. They are told apart by the chain itself, not by this volume.
109 auto& list = mAmbiguous[static_cast<int>(g4Id)];
110 list.push_back(mG4ToVG[g4Id]);
111 list.push_back(pv);
112 mG4ToVG[g4Id] = ambiguous();
113 }
114 }
115 ++mPairs;
116}
117
118void VecGeomG4Map::build(TG4RootDetectorConstruction const& dc, bool flattenAssemblies)
119{
120 auto& rootGeoMgr = tgeo2vecgeom::RootGeoManager::Instance();
121 auto& vgMgr = vecgeom::GeoManager::Instance();
122 // Ids are handed out by a global counter, so the largest one can exceed the number of
123 // volumes the manager holds; sizing by the count alone reads past the end.
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);
129
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";
134 }
135 registerPair(nullptr, topPV, {topNode}, dc);
136
137 // A TGeoVolume placed twice shares one set of daughter nodes, and so do both conversions of
138 // it, so each volume's daughters are paired up exactly once.
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) {
144 return;
145 }
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";
152 }
153 for (std::size_t i = 0; i < chains.size(); ++i) {
154 auto const* daughter = vgDaughters[i];
155 // The pairing is by position, so check it against what the converter recorded. The
156 // converter names a node it synthesised while flattening after the original one, so
157 // the recorded node must be either that node itself or a flattened copy of it.
158 auto const* recorded = rootGeoMgr.tgeonode(daughter);
159 auto const* expected = chains[i].back();
160 const bool ok = recorded != nullptr &&
161 (recorded == expected ||
162 (recorded->GetVolume() == expected->GetVolume() &&
163 TString(recorded->GetName()).BeginsWith(TString(expected->GetName()) + "_assemblyinternalcount_")));
164 if (!ok) {
165 ++mMispaired;
166 if (mMispaired <= 5) {
167 LOG(warning) << "VecGeom daughter " << i << " of " << volume->GetName() << " is "
168 << (recorded != nullptr ? recorded->GetName() : "unknown") << ", expected "
169 << expected->GetName();
170 }
171 }
172 registerPair(pv, daughter, chains[i], dc);
173 walk(daughter, chains[i].back());
174 }
175 };
176 walk(topPV, topNode);
177
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";
181 }
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";
185}
186
187} // namespace o2::simsetup
std::unique_ptr< expressions::Node > node
int32_t i
GPUChain * chain
static vecgeom::VPlacedVolume const * ambiguous()
Marks a Geant4 volume that several VecGeom placements reach.
void build(TG4RootDetectorConstruction const &dc, bool flattenAssemblies)
std::size_t size() const
std::size_t ambiguousCount() const
How many Geant4 volumes share more than one VecGeom placement.
GLint first
Definition glcorearb.h:399
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"