TGeoNavigator's point location and stepping disagree for geometries using AddNodeOverlap()
(the GEANT3 MANY convention).
A minimal reproducer is in many_only_overlap.C, attached below.
The geometry is deliberately simple:
- Two sibling volumes overlap. One is added with
AddNodeOverlap(), the other is an ONLY
volume.
- The overlapping
MANY volume contains an ONLY daughter covering the overlap region.
FindNode() correctly resolves the overlap and returns the ONLY sibling.
FindNextBoundaryAndStep() instead steps through the overlap as if it were air.
- Removing the daughter makes point location and stepping agree again.
Thus, stepping and FindNode() produce different material sequences for the same geometry.
The likely cause is that FindNextBoundaryAndStep() tracks the overlap state per current node.
When it descends into the ONLY daughter, the overlap state is cleared, so the overlapping
sibling is no longer considered.
This can affect existing ALICE geometries using MANY placements. In one TOF geometry, stepping
missed several cm of aluminium, resulting in a factor-eight discrepancy in the material integral
along one test line.
Expected behaviour is that stepping and FindNode() resolve the same material sequence, with the
ONLY volume taking priority in the MANY overlap region.
Walkthrough
many_only_overlap.C builds a mother air box with A (aluminium) placed MANY and B (lead)
placed ONLY inside it, and scans a line along z twice — once with FindNode(), resetting the
navigator each query, and once with FindNextBoundaryAndStep().
root -l -b -q many_only_overlap.C
Without a daughter in A, the two agree — air, Al, Pb, Al, air:
=== A placed MANY, no daughter ===
point location (FindNode, reset each time):
z [-10.00, -5.00] Air
z [ -5.00, -3.00] Al
z [ -3.00, 3.00] Pb
z [ 3.00, 5.00] Al
z [ 5.00, 10.00] Air
stepping (FindNextBoundaryAndStep):
z [-10.00, -5.00] Air (ovl=0)
z [ -5.00, -3.00] Al (ovl=1)
z [ -3.00, 3.00] Pb (ovl=0)
z [ 3.00, 5.00] Al (ovl=1)
z [ 5.00, 10.00] Air (ovl=0)
With an air daughter D inside A covering the region B occupies, point location still finds
the lead over z = -3..3 while stepping crosses 10 cm of air and never sees it:
=== A placed MANY, with air daughter D covering the overlap ===
point location (FindNode, reset each time):
z [-10.00, -3.00] Air
z [ -3.00, 3.00] Pb
z [ 3.00, 10.00] Air
stepping (FindNextBoundaryAndStep):
z [-10.00, -5.00] Air (ovl=0)
z [ -5.00, 5.00] Air (ovl=0)
z [ 5.00, 10.00] Air (ovl=0)
ovl is TGeoManager::IsCurrentOverlapping() at the start of each step.
Setup
Reproduced on ROOT master, v6-25-02-24334-g9ebb0b723c, self-built on EL9 / x86_64, which
reports ROOT Version: 6.41.01. Also seen on the ALICE fork tag v6-36-10-alice3.
many_only_overlap.C
// Minimal reproducer: does TGeo stepping resolve a declared (MANY) overlap when the
// overlap region lies inside a DAUGHTER of the overlapping node?
// M (air)
// +- A (Al) placed MANY, box 5x5x5
// | +- D (air) box 2x2x5 <- present only in the "with daughter" case
// +- B (Pb) placed ONLY, box 2x2x3, sitting inside A (and inside D when D exists)
#include <cstdio>
static void build(bool withDaughter) {
new TGeoManager("g", "minimal MANY test");
auto* matAir = new TGeoMaterial("Air", 14.61, 7.3, 1.2e-3);
auto* matAl = new TGeoMaterial("Al", 26.98, 13, 2.7);
auto* matPb = new TGeoMaterial("Pb", 207.2, 82, 11.35);
auto* air = new TGeoMedium("air", 1, matAir);
auto* al = new TGeoMedium("al", 2, matAl);
auto* pb = new TGeoMedium("pb", 3, matPb);
TGeoVolume* top = gGeoManager->MakeBox("TOP", air, 50, 50, 50);
gGeoManager->SetTopVolume(top);
TGeoVolume* M = gGeoManager->MakeBox("M", air, 20, 20, 20);
TGeoVolume* A = gGeoManager->MakeBox("A", al, 5, 5, 5);
TGeoVolume* B = gGeoManager->MakeBox("B", pb, 2, 2, 3);
if (withDaughter) {
TGeoVolume* D = gGeoManager->MakeBox("D", air, 2, 2, 5);
A->AddNode(D, 1); // ONLY, fills the region B will overlap
}
top->AddNode(M, 1);
M->AddNodeOverlap(A, 1); // MANY
M->AddNode(B, 1); // ONLY
gGeoManager->CloseGeometry();
}
static void trace(const char* tag) {
double p[3] = {0., 0., -10.}, d[3] = {0., 0., 1.};
printf("%s\n", tag);
printf(" point location (FindNode, reset each time):\n");
TString prev = ""; double z0 = -10;
for (int i = 0; i <= 2000; ++i) {
double z = -10. + i * 0.01;
gGeoManager->CdTop();
TGeoNode* n = gGeoManager->FindNode(0., 0., z);
TString cur = n ? TString(n->GetVolume()->GetMaterial()->GetName()) : TString("OUT");
if (cur != prev) { if (prev != "") printf(" z [%6.2f,%6.2f] %s\n", z0, z, prev.Data()); prev = cur; z0 = z; }
}
printf(" z [%6.2f,%6.2f] %s\n", z0, 10., prev.Data());
printf(" stepping (FindNextBoundaryAndStep):\n");
gGeoManager->InitTrack(p, d);
double travelled = 0.;
for (int i = 0; i < 30 && travelled < 20. && !gGeoManager->IsOutside(); ++i) {
TGeoNode* n = gGeoManager->GetCurrentNode();
const char* mat = n ? n->GetVolume()->GetMaterial()->GetName() : "?";
int ovl = gGeoManager->IsCurrentOverlapping();
gGeoManager->FindNextBoundaryAndStep(20. - travelled);
double st = gGeoManager->GetStep();
if (st <= 0) break;
printf(" z [%6.2f,%6.2f] %-4s (ovl=%d)\n", travelled - 10., travelled + st - 10., mat, ovl);
travelled += st;
}
}
void many_min() {
build(false); trace("=== A placed MANY, no daughter ===");
build(true); trace("=== A placed MANY, with air daughter D covering the overlap ===");
printf("MANY_MIN_DONE\n");
}
TGeoNavigator's point location and stepping disagree for geometries usingAddNodeOverlap()(the GEANT3
MANYconvention).A minimal reproducer is in
many_only_overlap.C, attached below.The geometry is deliberately simple:
AddNodeOverlap(), the other is anONLYvolume.
MANYvolume contains anONLYdaughter covering the overlap region.FindNode()correctly resolves the overlap and returns theONLYsibling.FindNextBoundaryAndStep()instead steps through the overlap as if it were air.Thus, stepping and
FindNode()produce different material sequences for the same geometry.The likely cause is that
FindNextBoundaryAndStep()tracks the overlap state per current node.When it descends into the
ONLYdaughter, the overlap state is cleared, so the overlappingsibling is no longer considered.
This can affect existing ALICE geometries using
MANYplacements. In one TOF geometry, steppingmissed several cm of aluminium, resulting in a factor-eight discrepancy in the material integral
along one test line.
Expected behaviour is that stepping and
FindNode()resolve the same material sequence, with theONLYvolume taking priority in theMANYoverlap region.Walkthrough
many_only_overlap.Cbuilds a mother air box withA(aluminium) placedMANYandB(lead)placed
ONLYinside it, and scans a line along z twice — once withFindNode(), resetting thenavigator each query, and once with
FindNextBoundaryAndStep().Without a daughter in
A, the two agree — air, Al, Pb, Al, air:With an air daughter
DinsideAcovering the regionBoccupies, point location still findsthe lead over z = -3..3 while stepping crosses 10 cm of air and never sees it:
ovlisTGeoManager::IsCurrentOverlapping()at the start of each step.Setup
Reproduced on ROOT master,
v6-25-02-24334-g9ebb0b723c, self-built on EL9 / x86_64, whichreports
ROOT Version: 6.41.01. Also seen on the ALICE fork tagv6-36-10-alice3.many_only_overlap.C