Skip to content

TGDMLParse silently drops elements whose name collides with a material name after 0x pointer-suffix stripping #22831

Description

@olantwin

Check duplicate issues.

  • Checked for duplicates

Description

I think we've hit a bug in TGeoManager::Import of GDML (geom/gdml, TGDMLParse).

When a GDML file contains an <element> and a <material>
whose names are identical after TGDMLParse::NameShort() strips the 0x…
pointer suffix (e.g. element Iron0xaaa and material Iron0xccc), every
<fraction> referencing that element is silently dropped on import: a pure
material referencing it imports as a TGeoMixture with zero elements,
and multi-element mixtures lose that component (remaining weights left
unnormalised). No warning or error is emitted.

This naming pattern is produced routinely by Geant4's G4GDMLParser::Write,
since pure-metal G4Materials are conventionally named after their element
(Iron, Copper, Tungsten, …) and the writer appends pointer suffixes to both.

A simple reproducer below. In the reproducer, renaming only the material (Iron0xcccIronBlock0xccc)
makes everything import correctly (Iron: [FE], Alloy: [FE 0.5, NI 0.5]).
The element form is irrelevant (reproduces with both isotope-composed and
simple <atom> elements).

Expected behaviour: the element reference should resolve to the element regardless
of a like-named material — or at minimum the import should fail loudly
instead of silently producing element-less materials.

Impact: a Geant4-exported detector geometry imported into TGeo lost Fe,
W, Ta, Cu, Si and Pb entirely (element-less materials, mangled alloys).
Downstream consumers deriving physics from material composition (in our
case the GENIE event generator's ROOTGeomAnalyzer target list) silently
produce wrong physics — for SHiP the neutrino target and muon shield became
invisible as interaction targets.

Suspected cause: the per-type name maps in TGDMLParse are keyed by the
NameShort()-stripped string; the fraction-reference resolution in the
material/mixture handling apparently consults a map where the material entry
shadows the element entry (or inserts a null placeholder via the
TGDMAssignmentHelper on first miss).

Reproducer

import ROOT
geo = ROOT.TGeoManager.Import("collide.gdml")
for m in geo.GetListOfMaterials():
    print(m.GetName(), m.GetNelements(),
          [m.GetElement(i).GetName() for i in range(m.GetNelements())])
# Iron  0 []                      <- expected 1 element (FE)
# Alloy 1 ['NI'] (weight 0.5)     <- expected FE 0.5 + NI 0.5

with collide.gdml:

<?xml version="1.0"?>
<gdml xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <define/>
  <materials>
    <element Z="26" formula="FE" name="Iron0xaaa"><atom unit="g/mole" value="55.845"/></element>
    <element Z="28" formula="NI" name="Nickel0xbbb"><atom unit="g/mole" value="58.693"/></element>
    <material name="Iron0xccc" state="solid">   <!-- name collides with the element -->
      <D unit="g/cm3" value="7.87"/><fraction n="1" ref="Iron0xaaa"/>
    </material>
    <material name="Alloy0xddd" state="solid">
      <D unit="g/cm3" value="8.2"/>
      <fraction n="0.5" ref="Iron0xaaa"/><fraction n="0.5" ref="Nickel0xbbb"/>
    </material>
  </materials>
  <solids>
    <box lunit="mm" name="world0x1a" x="1000" y="1000" z="1000"/>
    <box lunit="mm" name="cube0x1b" x="100" y="100" z="100"/>
  </solids>
  <structure>
    <volume name="ironVol0x2a"><materialref ref="Iron0xccc"/><solidref ref="cube0x1b"/></volume>
    <volume name="World0x2c"><materialref ref="Alloy0xddd"/><solidref ref="world0x1a"/>
      <physvol name="ironPV"><volumeref ref="ironVol0x2a"/></physvol></volume>
  </structure>
  <setup name="Default" version="1.0"><world ref="World0x2c"/></setup>
</gdml>

ROOT version

ROOT 6.40.02

Installation method

conda-forge

Operating system

Linux, distribution independent (conda-forge toolchain/env)

Additional context

No response

Metadata

Metadata

Assignees

Type

No type

Fields

No fields configured for issues without a type.

Projects

Status
No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions