Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
9e45c42
fix: update material map validation script to Acts v46.8.1
wdconinc Aug 23, 2026
7fab55c
fix: update runMaterialRecording call for Acts v46.8.1 API
wdconinc Sep 1, 2026
c225cad
fix: update material validation and mapping scripts for Acts v46.8.1 API
wdconinc Sep 1, 2026
d02529b
fix: handle --help flag in run_material_map_validation.sh
wdconinc Sep 1, 2026
e9202ac
fix: ignore plots
wdconinc Sep 1, 2026
5334cd3
fix: indentation
wdconinc Sep 1, 2026
d5eff65
Fix Acts v46.8.1 API compatibility and CBOR removal
wdconinc Sep 1, 2026
fc44171
fix: re-enable material mapping plots
wdconinc Sep 1, 2026
6e0df2a
fix: typo
wdconinc Sep 1, 2026
c6d44a6
fix: add quotes to allow shell variable expansion
wdconinc Sep 1, 2026
9bdf328
Fix geometry JSON schema compatibility for Acts v46.8.1 visualization
wdconinc Sep 1, 2026
237f2a5
fix: upload cbor and json material maps
wdconinc Sep 2, 2026
aa7a6b0
fix: restore cbor support; use upstream patches
wdconinc Sep 2, 2026
fc3e46b
fix: warn if no material map loaded
wdconinc Sep 2, 2026
1482964
fix: ignore *.diff and *.cbor
wdconinc Sep 2, 2026
fa353cc
fix: upload any cbor, json and root files
wdconinc Sep 2, 2026
c304a34
fix: ok, save a bit less to the artifact (was 26 GB)
wdconinc Sep 2, 2026
6760662
fix: upload only material_map-map.*
wdconinc Sep 3, 2026
3ad3398
Change material validation to use matMapFile
wdconinc Sep 3, 2026
8639f6f
Refactor material map parameter interface to use --matFileBase and --…
wdconinc Sep 3, 2026
7101fbd
Add --prefix and --suffix command-line arguments to run_material_map_…
wdconinc Sep 3, 2026
6354cf5
fix: rm patch that is now gotten from url
wdconinc Sep 3, 2026
f793e8f
Support prefix/suffix in geometry generation and configuration files
wdconinc Sep 4, 2026
ae2079f
Fix: pass --inputRootFile argument to material_mapping_epic.py
wdconinc Sep 4, 2026
07c0be6
ci: add material map validation plots to GitHub Pages (#1167)
wdconinc Sep 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 70 additions & 2 deletions .github/workflows/linux-eic-shell.yml
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,7 @@ jobs:
with:
name: material_map
path: |
scripts/material_map/*.json
scripts/material_map/material-map.cbor
scripts/material_map/material-map_map.*
scripts/material_map/plots/
scripts/material_map/Surfaces/
scripts/material_map/Validation/
Expand Down Expand Up @@ -837,6 +836,7 @@ jobs:
needs:
- list-open-prs
- merge-npsim-capybara
- validate-material-map
strategy:
matrix: ${{ fromJSON(needs.list-open-prs.outputs.json) }}
fail-fast: false
Expand All @@ -859,6 +859,35 @@ jobs:
with:
name: capybara-report
path: publishing_docs/pr/${{ matrix.pr }}/capybara/
- name: Download material_map artifact (other PRs)
id: download_material_map
uses: dawidd6/action-download-artifact@v21
if: github.event.pull_request.number != matrix.pr
with:
commit: ${{ matrix.head_sha }}
path: publishing_docs/pr/${{ matrix.pr }}/material-map/
name: material_map
workflow: ".github/workflows/linux-eic-shell.yml"
workflow_conclusion: "completed"
if_no_artifact_found: ignore
- name: Download material_map artifact (this PR)
uses: actions/download-artifact@v8
if: github.event.pull_request.number == matrix.pr
with:
name: material_map
path: publishing_docs/pr/${{ matrix.pr }}/material-map/
- name: Generate material-map validation index
if: github.event.pull_request.number == matrix.pr || steps.download_material_map.outputs.found_artifact == 'true'
run: |
VALDIR="publishing_docs/pr/${{ matrix.pr }}/material-map/Validation"
if [ -d "$VALDIR" ]; then
echo '<html><body><h1>Material map validation plots</h1><ul>' > "$VALDIR/index.html"
find "$VALDIR" -name '*.pdf' | sort | while read f; do
rel="${f#$VALDIR/}"
echo "<li><a href=\"$rel\">$rel</a></li>"
done >> "$VALDIR/index.html"
echo '</ul></body></html>' >> "$VALDIR/index.html"
fi
- uses: actions/upload-artifact@v7
with:
name: github-pages-staging-pr-${{ matrix.pr }}
Expand All @@ -869,6 +898,7 @@ jobs:
runs-on: ubuntu-latest
needs:
- merge-npsim-capybara
- validate-material-map
steps:
# Note:
# - If we run this on a non-main branch, we download from main with action-download-artifact.
Expand All @@ -890,12 +920,46 @@ jobs:
with:
name: capybara-report
path: publishing_docs/capybara/
- name: Download material_map artifact (in PR)
id: download_material_map
uses: dawidd6/action-download-artifact@v21
if: github.ref_name != 'main'
with:
branch: main
path: publishing_docs/material-map/
name: material_map
workflow: ".github/workflows/linux-eic-shell.yml"
workflow_conclusion: "completed"
if_no_artifact_found: ignore
- name: Download material_map artifact (on main)
uses: actions/download-artifact@v8
if: github.ref_name == 'main'
with:
name: material_map
path: publishing_docs/material-map/
- name: Populate capybara summary (on main)
if: github.ref_name == 'main' || steps.download_capybara.outputs.found_artifact == 'true'
run: |
echo "### Capybara summary for main" >> publishing_docs/capybara/index.md
find publishing_docs/capybara/ -mindepth 1 -maxdepth 1 -type d -printf \
"- [%f](https://eic.github.io/epic/capybara/%f/index.html)\n" | sort >> publishing_docs/capybara/index.md
- name: Generate material-map validation index
if: github.ref_name == 'main' || steps.download_material_map.outputs.found_artifact == 'true'
run: |
VALDIR="publishing_docs/material-map/Validation"
if [ -d "$VALDIR" ]; then
echo '<html><body><h1>Material map validation plots</h1><ul>' > "$VALDIR/index.html"
find "$VALDIR" -name '*.pdf' | sort | while read f; do
rel="${f#$VALDIR/}"
echo "<li><a href=\"$rel\">$rel</a></li>"
done >> "$VALDIR/index.html"
echo '</ul></body></html>' >> "$VALDIR/index.html"
fi
- name: Populate material-map summary (on main)
if: github.ref_name == 'main' || steps.download_material_map.outputs.found_artifact == 'true'
run: |
echo "### Material map validation for main" >> publishing_docs/material-map/index.md
echo "- [Validation plots](https://eic.github.io/epic/material-map/Validation/index.html)" >> publishing_docs/material-map/index.md
- name: Create capybara step summary (this PR)
if: github.ref_name == 'main'
run: |
Expand Down Expand Up @@ -958,6 +1022,10 @@ jobs:
[ -d _site/pr/${{ github.event.pull_request.number }}/capybara/ ] && \
find _site/pr/${{ github.event.pull_request.number }}/capybara/ -mindepth 1 -maxdepth 1 -type d -printf \
"- [%f](https://eic.github.io/epic/pr/${{ github.event.pull_request.number }}/capybara/%f/index.html)\n" | sort >> capybara_${{ github.event.pull_request.number }}.md || true
if [ -d _site/pr/${{ github.event.pull_request.number }}/material-map/Validation/ ]; then
echo "### Material map validation" >> capybara_${{ github.event.pull_request.number }}.md
echo "- [Validation plots](https://eic.github.io/epic/pr/${{ github.event.pull_request.number }}/material-map/Validation/index.html)" >> capybara_${{ github.event.pull_request.number }}.md
fi
echo "<sup><sub>Last updated $(TZ=America/New_York date -Iminutes) ${{github.event.pull_request.head.sha}}</sub></sup>" >> capybara_${{ github.event.pull_request.number }}.md
- name: Create capybara step summary
if: ${{ github.event_name == 'pull_request' }}
Expand Down
3 changes: 3 additions & 0 deletions scripts/material_map/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@ Examples/
Surfaces/
Validation/
calibrations/
plots/
*.diff
*.cbor
*.json
19 changes: 11 additions & 8 deletions scripts/material_map/epic.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,23 @@

def getDetector(
xmlFile,
jsonFile="",
matFile="",
logLevel=acts.logging.WARNING,
):
customLogLevel = acts.examples.defaultLogging(logLevel=logLevel)
logger = acts.getDefaultLogger("epic.getDetector", logLevel)

matDeco = None
if len(jsonFile)>0:
file = Path(jsonFile)
logger.info("Adding material from %s", file.absolute())
matDeco = acts.IMaterialDecorator.fromFile(
file,
level=customLogLevel(maxLevel=acts.logging.WARNING),
)
if len(matFile) > 0:
file = Path(matFile)
if file.exists():
logger.info("Adding material from %s", file.absolute())
matDeco = acts.IMaterialDecorator.fromFile(
file,
level=customLogLevel(maxLevel=acts.logging.WARNING),
)
else:
logger.warning("Material map %s not found.", matFile)

dd4hepConfig = acts.examples.dd4hep.DD4hepDetector.Config(
xmlFileNames=[xmlFile],
Expand Down
38 changes: 30 additions & 8 deletions scripts/material_map/geometry_epic.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,39 @@
),
help="Input xml file containing ePIC geometry",
)
p.add_argument(
"-o",
"--outputName",
type=str,
default="geometry-map",
help="output name for the geometry JSON file (without .json extension)",
)
args = p.parse_args()

detector = epic.getDetector(args.xmlFile)
trackingGeometry = detector.trackingGeometry()
decorators = detector.contextDecorators()

runGeometry(
trackingGeometry,
decorators,
outputDir=Path.cwd(),
outputObj=False,
outputCsv=False,
outputJson=True,
)
import tempfile
import shutil

# Generate geometry to a temporary directory, then rename the output file
tmpdir = Path(tempfile.mkdtemp())
Comment thread
veprbl marked this conversation as resolved.
try:
runGeometry(
trackingGeometry,
decorators,
outputDir=tmpdir,
outputObj=False,
outputCsv=False,
outputSurfacesJson=True,
)
# Move the generated geometry-map.json to the desired output name
src_file = tmpdir / "geometry-map.json"
dst_file = Path.cwd() / f"{args.outputName}.json"
if src_file.exists():
shutil.move(str(src_file), str(dst_file))
else:
raise FileNotFoundError(f"Expected geometry file not found at {src_file}")
finally:
shutil.rmtree(tmpdir)
54 changes: 33 additions & 21 deletions scripts/material_map/material_mapping_epic.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,34 +34,46 @@
help="input json file to define volumes and layers used in material mapping",
)
p.add_argument(
"--matFile",
"--matFileBase",
type=str,
default="material-map.json",
help="output filename for the generated material map, can be json and cbor formats",
default="material-map",
help="base name for the generated material map (without extension)",
)
p.add_argument(
"--matFileFormat",
type=str,
nargs="+",
default=["json", "root"],
help="output format(s) for the material map (json, cbor, root). Default: json, root",
)
p.add_argument(
"--inputRootFile",
type=str,
default="geant4_material_tracks.root",
help="input ROOT file with material tracks (typically from material_recording_epic.py)",
)
args = p.parse_args()

mapName = args.matFile.split('.')[0]
if '.json' in args.matFile:
mapFormat = JsonFormat.Json
elif '.cbor' in args.matFile:
mapFormat = JsonFormat.Cbor
else:
print('ERROR(material_mapping_epic.py): please provide a material map file in .json or .cbor format')
exit()
# Parse material map formats
mapFormats = args.matFileFormat
# Validate formats
valid_formats = {"json", "cbor", "root"}
for fmt in mapFormats:
if fmt not in valid_formats:
print(f'ERROR(material_mapping_epic.py): invalid format "{fmt}". Must be one of: {", ".join(valid_formats)}')
exit(1)

detector = epic.getDetector(
args.xmlFile, args.geoFile)
detector = epic.getDetector(args.xmlFile)
trackingGeometry = detector.trackingGeometry()
decorators = detector.contextDecorators()

materialSurfaces = trackingGeometry.extractMaterialSurfaces()

outputFileBase = os.path.join(os.getcwd(), args.matFileBase)

runMaterialMapping(
trackingGeometry,
decorators,
outputDir=Path.cwd(),
inputDir=Path.cwd(),
readCachedSurfaceInformation=False,
mapVolume=False,
mapName=mapName,
mapFormat=mapFormat,
surfaces=materialSurfaces,
inputFile=Path(args.inputRootFile),
outputFileBase=outputFileBase,
outputMapFormats=mapFormats,
).run()
4 changes: 2 additions & 2 deletions scripts/material_map/material_recording_epic.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@ def main():

runMaterialRecording(
detector=detector,
s=acts.examples.Sequencer(events=args.events, numThreads=1),
tracksPerEvent=args.tracks,
outputDir=os.getcwd(),
etaRange=(args.eta_min, args.eta_max),
s=acts.examples.Sequencer(events=args.events, numThreads=1),
outputFileBase=os.path.join(os.getcwd(), args.outputName.replace(".root", "")),
).run()


Expand Down
39 changes: 28 additions & 11 deletions scripts/material_map/material_validation_epic.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import os
import argparse
from pathlib import Path

import acts
import acts.examples.dd4hep
Expand All @@ -12,6 +13,7 @@
import epic
from material_validation import runMaterialValidation

u = acts.UnitConstants

if "__main__" == __name__:

Expand All @@ -24,16 +26,16 @@
help="input xml file containing ePIC geometry",
)
p.add_argument(
"--matFile",
"--matFileBase",
type=str,
default="material-map.json",
help="input material map file with extension, can be either xx.json or xx.cbor",
default="",
help="base name for the input material map file (without extension). Script will search for .json, .cbor, or .root formats (optional)",
)
p.add_argument(
"--outputName",
type=str,
default="propagation-material.root",
help="customized name of the output rootfile",
default="propagation-material",
help="customized name of the output rootfile (without .root extension)",
)
p.add_argument(
"-n","--nevents",
Expand All @@ -50,14 +52,29 @@

args = p.parse_args()

detector = epic.getDetector(args.xmlFile, args.matFile)
# Resolve material file if base name provided
matFile = ""
if len(args.matFileBase) > 0:
# Search for material map file with any valid extension
valid_extensions = [".json", ".cbor", ".root"]
for ext in valid_extensions:
candidate = Path(args.matFileBase + ext)
if candidate.exists():
matFile = str(candidate)
break

detector = epic.getDetector(args.xmlFile, matFile)
trackingGeometry = detector.trackingGeometry()
decorators = detector.contextDecorators()

field = acts.ConstantBField(acts.Vector3(0, 0, 0))
materialSurfaces = trackingGeometry.extractMaterialSurfaces()

s = Sequencer(events=args.nevents, numThreads=-1)

runMaterialValidation(args.nevents, args.ntracks,
trackingGeometry, decorators, field,
outputDir=os.getcwd(), outputName=args.outputName,
s=Sequencer(events=args.nevents, numThreads=-1)
runMaterialValidation(
surfaces=materialSurfaces,
s=s,
tracksPerEvent=args.ntracks,
outputFileBase=os.path.join(os.getcwd(), args.outputName),
trackingGeometry=trackingGeometry,
).run()
Loading
Loading