45 auto* world = vecgeom::GeoManager::Instance().GetWorld();
46 auto const*
box =
dynamic_cast<TGeoBBox const*
>(gGeoManager->GetTopVolume()->GetShape());
47 if (world ==
nullptr ||
box ==
nullptr) {
48 LOG(warning) <<
"Cannot cross-check the VecGeom location: no world";
52 vecgeom::NavigationState
state;
53 std::map<std::string, std::size_t> byVolume;
56 const double x =
box->GetOrigin()[0] +
box->GetDX() * (2. * rnd.Rndm() - 1.);
57 const double y =
box->GetOrigin()[1] +
box->GetDY() * (2. * rnd.Rndm() - 1.);
58 const double z =
box->GetOrigin()[2] +
box->GetDZ() * (2. * rnd.Rndm() - 1.);
59 auto*
node = gGeoManager->FindNode(
x,
y,
z);
60 const std::string tgeoName = (
node !=
nullptr) ?
node->GetVolume()->GetName() :
"<outside>";
62 vecgeom::GlobalLocator::LocateGlobalPoint(world,
V3(
x,
y,
z),
state,
true);
64 const std::string vgName = (
top !=
nullptr) ?
top->GetLogicalVolume()->GetName() :
"<outside>";
65 if (tgeoName != vgName) {
67 ++byVolume[tgeoName +
" -> " + vgName];
70 LOG(info) <<
"VecGeom location cross-check: " << bad <<
" of " <<
samples <<
" points land in a "
71 <<
"different volume than TGeo puts them in";
72 std::vector<std::pair<std::size_t, std::string>> worst;
73 for (
auto const& e : byVolume) {
74 worst.emplace_back(e.second, e.first);
76 std::sort(worst.rbegin(), worst.rend());
77 for (std::size_t
i = 0;
i < worst.size() &&
i < 15; ++
i) {
78 LOG(info) <<
" " << worst[
i].first <<
" " << worst[
i].second;
85 auto* world = vecgeom::GeoManager::Instance().GetWorld();
86 auto* vol = gGeoManager->GetVolume(
name);
87 if (world ==
nullptr || vol ==
nullptr) {
88 LOG(warning) <<
"Cannot cross-check volume " <<
name <<
": not in the geometry";
91 auto const*
box =
dynamic_cast<TGeoBBox const*
>(vol->GetShape());
93 LOG(warning) <<
"Cannot cross-check volume " <<
name <<
": its shape has no bounding box";
96 LOG(info) <<
"VecGeom sizes: " << vecgeom::GeoManager::Instance().GetRegisteredVolumesCount()
97 <<
" logical, " << vecgeom::GeoManager::Instance().GetPlacedVolumesCount() <<
" placed, "
98 << vecgeom::VPlacedVolume::GetIdCount() <<
" ids handed out";
101 if (
auto* lv = vecgeom::GeoManager::Instance().FindLogicalVolume(
name)) {
102 LOG(info) <<
" " <<
name <<
": TGeo " << vol->GetNdaughters() <<
" daughters, VecGeom "
103 << lv->GetDaughters().size();
106 TIter nextVol(gGeoManager->GetListOfVolumes());
107 TGeoVolume* mother =
nullptr;
108 while ((mother =
static_cast<TGeoVolume*
>(nextVol())) !=
nullptr) {
110 for (
int i = 0;
i < mother->GetNdaughters(); ++
i) {
111 if (mother->GetNode(
i)->GetVolume() == vol) {
119 auto* mlv = vecgeom::GeoManager::Instance().FindLogicalVolume(mother->GetName());
120 LOG(info) <<
" mother " << mother->GetName() <<
": TGeo " << mother->GetNdaughters()
121 <<
" daughters, VecGeom " << (mlv !=
nullptr ? (
long)mlv->GetDaughters().size() : -1)
122 << (mother->GetFinder() !=
nullptr ?
" (divided)" :
"");
127 vecgeom::NavigationState
state;
128 std::map<std::string, std::size_t> byResult;
129 std::size_t placements = 0, tested = 0, bad = 0, badTransform = 0;
130 double worstTransform = 0.;
131 TGeoIterator it(gGeoManager->GetTopVolume());
132 TGeoNode*
node =
nullptr;
133 while ((
node = it.Next()) !=
nullptr && placements < maxPlacements) {
134 if (
node->GetVolume() != vol) {
138 TGeoHMatrix matrix = *it.GetCurrentMatrix();
139 for (std::size_t k = 0; k < perPlacement; ++k) {
140 double local[3] = {
box->GetOrigin()[0] +
box->GetDX() * (2. * rnd.Rndm() - 1.),
141 box->GetOrigin()[1] +
box->GetDY() * (2. * rnd.Rndm() - 1.),
142 box->GetOrigin()[2] +
box->GetDZ() * (2. * rnd.Rndm() - 1.)};
143 if (!vol->GetShape()->Contains(local)) {
147 matrix.LocalToMaster(local, global);
149 auto* found = gGeoManager->FindNode(global[0], global[1], global[2]);
150 const std::string tgeoName = (found !=
nullptr) ? found->GetVolume()->GetName() :
"<outside>";
152 vecgeom::GlobalLocator::LocateGlobalPoint(world,
V3(global[0], global[1], global[2]),
state,
true);
154 const std::string vgName = (
top !=
nullptr) ?
top->GetLogicalVolume()->GetName() :
"<outside>";
155 if (tgeoName != vgName) {
157 ++byResult[tgeoName +
" -> " + vgName];
163 vecgeom::Transformation3D trans;
164 state.TopMatrix(trans);
165 const auto vgLocal = trans.Transform(
V3(global[0], global[1], global[2]));
166 const double d = std::sqrt((vgLocal[0] - local[0]) * (vgLocal[0] - local[0]) +
167 (vgLocal[1] - local[1]) * (vgLocal[1] - local[1]) +
168 (vgLocal[2] - local[2]) * (vgLocal[2] - local[2]));
169 worstTransform = std::max(worstTransform, d);
175 LOG(info) <<
"VecGeom volume cross-check " <<
name <<
": worst local-point deviation "
176 << worstTransform <<
" cm, " << badTransform <<
" points above 1e-6 cm";
177 LOG(info) <<
"VecGeom volume cross-check " <<
name <<
": " << placements <<
" placements, " << tested
178 <<
" points, " << bad <<
" located differently than TGeo";
179 for (
auto const& e : byResult) {
180 LOG(info) <<
" " << e.second <<
" " << e.first;
187 auto* world = vecgeom::GeoManager::Instance().GetWorld();
188 if (world ==
nullptr) {
192 std::map<std::string, std::size_t> tgeoSeen, vgSeen;
193 constexpr std::size_t kMaxSteps = 20000;
195 for (std::size_t
r = 0;
r < rays; ++
r) {
196 const double cost = 2. * rnd.Rndm() - 1.;
197 const double sint = std::sqrt(1. - cost * cost);
198 const double phi = 2. * M_PI * rnd.Rndm();
199 const double dir[3] = {sint * std::cos(phi), sint * std::sin(phi), cost};
201 gGeoManager->InitTrack(0., 0., 0., dir[0], dir[1], dir[2]);
202 for (std::size_t k = 0; k < kMaxSteps && !gGeoManager->IsOutside(); ++k) {
203 ++tgeoSeen[gGeoManager->GetCurrentVolume()->GetName()];
204 gGeoManager->FindNextBoundaryAndStep();
207 vecgeom::NavigationState cur, next;
209 const V3 vdir(dir[0], dir[1], dir[2]);
210 vecgeom::GlobalLocator::LocateGlobalPoint(world,
pos, cur,
true);
211 for (std::size_t k = 0; k < kMaxSteps && cur.Top() !=
nullptr; ++k) {
212 ++vgSeen[cur.Top()->GetLogicalVolume()->GetName()];
214 auto const* nav = cur.Top()->GetLogicalVolume()->GetNavigator();
215 const double step = nav->ComputeStepAndSafetyAndPropagatedState(
pos, vdir, vecgeom::kInfLength, cur, next,
217 if (!(step < vecgeom::kInfLength)) {
227 std::vector<std::string> neverVG, neverTGeo;
228 std::vector<std::pair<long, std::string>> diff;
229 for (
auto const& e : tgeoSeen) {
230 const std::size_t vg = vgSeen.count(e.first) ? vgSeen[e.first] : 0;
232 neverVG.push_back(e.first);
234 const long d =
static_cast<long>(e.second) -
static_cast<long>(vg);
236 diff.emplace_back(std::labs(d), e.first);
239 for (
auto const& e : vgSeen) {
240 if (tgeoSeen.count(e.first) == 0) {
241 neverTGeo.push_back(e.first);
244 std::sort(diff.rbegin(), diff.rend());
245 LOG(info) <<
"VecGeom ray cross-check over " << rays <<
" rays: " << tgeoSeen.size() <<
" volumes seen by TGeo, "
246 << vgSeen.size() <<
" by VecGeom, " << diff.size() <<
" entered a different number of times";
247 LOG(info) <<
" never entered by VecGeom (" << neverVG.size() <<
"):";
248 for (std::size_t
i = 0;
i < neverVG.size() &&
i < 60; ++
i) {
249 LOG(info) <<
" " << neverVG[
i] <<
" (TGeo " << tgeoSeen[neverVG[
i]] <<
")";
251 LOG(info) <<
" never entered by TGeo (" << neverTGeo.size() <<
"):";
252 for (std::size_t
i = 0;
i < neverTGeo.size() &&
i < 30; ++
i) {
253 LOG(info) <<
" " << neverTGeo[
i] <<
" (VecGeom " << vgSeen[neverTGeo[
i]] <<
")";