Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-10-16 08:49:32

0001 """Versioned material files and the explicit legacy compatibility bindings."""
0002 
0003 import json
0004 import shutil
0005 import subprocess
0006 from pathlib import Path
0007 
0008 import pytest
0009 import acts
0010 
0011 acts_json = pytest.importorskip("acts.json")
0012 TrackingGeometryMaterialJsonConverter = acts_json.TrackingGeometryMaterialJsonConverter
0013 MaterialMapDecorator = acts_json.MaterialMapDecorator
0014 
0015 FIXTURES = Path(__file__).resolve().parents[3] / "docs/examples"
0016 
0017 
0018 def test_material_document(tmp_path):
0019     converter = TrackingGeometryMaterialJsonConverter()
0020     material = converter.fromFile(FIXTURES / "material-map-v1/minimal.json")
0021     material.description = "Python round trip"
0022     options = TrackingGeometryMaterialJsonConverter.Options()
0023     options.materialFractionBits = 16
0024     for suffix in (".json", ".cbor"):
0025         path = tmp_path / ("material" + suffix)
0026         converter.toFile(material, path, options)
0027         assert converter.fromFile(path).description == "Python round trip"
0028         assert isinstance(acts.IMaterialDecorator.fromFile(path), MaterialMapDecorator)
0029     encoded = json.loads((tmp_path / "material.json").read_text())
0030     assert encoded["header"]["version"] == 1
0031     assert encoded["header"]["description"] == "Python round trip"
0032 
0033 
0034 def test_legacy_material_error():
0035     path = FIXTURES / "material_map_example.json"
0036     with pytest.raises(
0037         ValueError, match="Legacy material format.*ActsMaterialMapMigrate"
0038     ):
0039         TrackingGeometryMaterialJsonConverter().fromFile(path)
0040 
0041 
0042 @pytest.fixture
0043 def material_migrator():
0044     executable = shutil.which("ActsMaterialMapMigrate")
0045     if executable is None:
0046         candidate = (
0047             Path(acts.__file__).absolute().parents[2] / "bin/ActsMaterialMapMigrate"
0048         )
0049         if not candidate.is_file():
0050             pytest.skip("ActsMaterialMapMigrate is not built")
0051         executable = str(candidate)
0052 
0053     return executable
0054 
0055 
0056 def test_material_map_migration(tmp_path, material_migrator):
0057     executable = material_migrator
0058 
0059     def run(*args):
0060         return subprocess.run(
0061             [executable, *map(str, args)], capture_output=True, text=True
0062         )
0063 
0064     original = FIXTURES / "material_map_example.json"
0065     output = tmp_path / "new.json"
0066     rejected = run(original, output)
0067     assert rejected.returncode != 0
0068     assert "surface material only" in rejected.stderr
0069     assert not output.exists()
0070     legacy = json.loads(original.read_text())
0071     legacy["Volumes"]["entries"] = []
0072     legacy["KeyedSurfaces"] = [
0073         {
0074             "key": "migration-test",
0075             "geometry_id": 0,
0076             "material": legacy["Surfaces"]["entries"][0]["value"]["material"],
0077         }
0078     ]
0079     source = tmp_path / "legacy.json"
0080     source.write_text(json.dumps(legacy))
0081     migrated = run(source, output)
0082     assert migrated.returncode == 0, migrated.stderr
0083     material = TrackingGeometryMaterialJsonConverter().fromFile(output)
0084     assert "migration-test" in material.keyedSurfaces
0085     assert len(material.surfaceMaterials) == len(legacy["Surfaces"]["entries"])
0086     quantized = tmp_path / "quantized.json"
0087     result = run(
0088         source,
0089         quantized,
0090         "--material-fraction-bits",
0091         16,
0092         "--indentation",
0093         0,
0094         "--compression-level",
0095         19,
0096     )
0097     assert result.returncode == 0, result.stderr
0098     TrackingGeometryMaterialJsonConverter().fromFile(quantized)
0099     for args in [
0100         (output, tmp_path / "invalid.json"),
0101         (source, source),
0102         (source, output, "--material-fraction-bits", "24"),
0103         (source, output, "--indentation"),
0104     ]:
0105         assert run(*args).returncode != 0
0106 
0107 
0108 def test_root_material_map_migration(tmp_path, material_migrator):
0109     import numpy as np
0110     import uproot
0111 
0112     source = tmp_path / "material.root"
0113     output = tmp_path / "material.json"
0114     geometry_id = (1 << 56) | (256 << 8)
0115     data = {
0116         "hGeoId": np.array([geometry_id], dtype=np.int64),
0117         **{
0118             name: np.array([value], dtype=np.float32)
0119             for name, value in {
0120                 "t": 0.25,
0121                 "x0": 93.7,
0122                 "l0": 465.2,
0123                 "A": 28.0855,
0124                 "Z": 14.0,
0125                 "rho": 0.00233,
0126             }.items()
0127         },
0128     }
0129     with uproot.recreate(source) as root:
0130         tree = root.mktree(
0131             "HomogeneousMaterial", {name: values.dtype for name, values in data.items()}
0132         )
0133         tree.extend(data)
0134 
0135     def run(path, target):
0136         return subprocess.run(
0137             [material_migrator, str(path), str(target)], capture_output=True, text=True
0138         )
0139 
0140     result = run(source, output)
0141     if "ROOT input is unavailable" in result.stderr:
0142         assert result.returncode != 0
0143         assert "ACTS_BUILD_PLUGIN_ROOT=ON" in result.stderr
0144         assert not output.exists()
0145         return
0146     assert result.returncode == 0, result.stderr
0147     converter = TrackingGeometryMaterialJsonConverter()
0148     assert len(converter.fromFile(output).surfaceMaterials) == 1
0149     document = json.loads(output.read_text())
0150     entry = document["surfaces"][0]
0151     assert entry["target"]["geometry_id"] == {"volume": 1, "sensitive": 256}
0152     assert entry["material"]["slab"]["thickness"] == pytest.approx(0.25)
0153     assert entry["material"]["slab"]["material"]["radiation_length"] == pytest.approx(
0154         93.7
0155     )
0156     cbor = tmp_path / "material.cbor"
0157     assert run(source, cbor).returncode == 0
0158     assert len(converter.fromFile(cbor).surfaceMaterials) == 1
0159 
0160     with uproot.update(source) as root:
0161         root.mkdir("VolumeMaterial_vol1")
0162     rejected = run(source, tmp_path / "volume.json")
0163     assert rejected.returncode != 0
0164     assert "surface material only" in rejected.stderr
0165     assert not (tmp_path / "volume.json").exists()
0166 
0167     empty = tmp_path / "empty.root"
0168     with uproot.recreate(empty):
0169         pass
0170     rejected = run(empty, tmp_path / "empty.json")
0171     assert rejected.returncode != 0
0172     assert "No material maps" in rejected.stderr