Add autoregressive shower rollout driver
Closes the loop from single-step prediction into full showers: - giant/geometry.py + `dwarf build-geometry-oracle`: learn position -> (material, layer_id) from data (KNN/SVM) to supply the conditioning the surrogate does not predict; flag detector escape by NN distance. - giant/rollout.py: breadth-first batched frontier that steps all active tracks, spawns secondaries as new tracks, and terminates on energy cutoff, per-track max steps, escape, or natural end. Energy is deposited locally on every stop except escape (leakage), so showers conserve energy exactly. - `giant rollout` CLI: seed from real events (argmax pre_E), load checkpoint, write a world-frame steps parquet + YAML sidecar. - giant/analysis.py: compute_rollout_observables + plot_rollout_* for single-sided longitudinal/transverse/total-energy shower profiles; analysis/export_rollout_observables.py driver. - scikit-learn added as an optional `geometry` extra (lazy-imported). - Tests: tests/test_geometry.py, tests/test_rollout.py. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
"""Build a position -> (material, layer_id) geometry oracle from steps parquet.
|
||||
|
||||
Backs the `dwarf build-geometry-oracle` subcommand. The oracle is consumed by
|
||||
`giant rollout` to supply the material/layer conditioning at each step, since the
|
||||
surrogate does not predict them.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from giant.data.loader import find_parquet_files
|
||||
from giant.geometry import build_geometry_oracle
|
||||
|
||||
|
||||
def run_build_geometry_oracle(
|
||||
data: Path,
|
||||
out: Path,
|
||||
method: str = "knn",
|
||||
k: int = 1,
|
||||
subsample: int = 500_000,
|
||||
escape_factor: float = 5.0,
|
||||
seed: int = 0,
|
||||
) -> None:
|
||||
files = find_parquet_files(data)
|
||||
print(f"found {len(files)} parquet file(s); sampling up to {subsample:,} points")
|
||||
|
||||
oracle = build_geometry_oracle(
|
||||
files,
|
||||
method=method,
|
||||
k=k,
|
||||
subsample=subsample,
|
||||
escape_factor=escape_factor,
|
||||
seed=seed,
|
||||
)
|
||||
|
||||
print(f"method: {method} reference points: {oracle.metadata['n_reference_points']:,}")
|
||||
print("classes (material, layer_id):")
|
||||
for material, layer_id in oracle.classes:
|
||||
print(f" {material:<12} layer_id={layer_id}")
|
||||
print(
|
||||
f"median NN spacing: {oracle.metadata['median_nn_dist']:.3f} "
|
||||
f"escape_threshold: {oracle.escape_threshold:.3f} "
|
||||
f"(= {escape_factor}x spacing)"
|
||||
)
|
||||
if oracle.escape_threshold <= 0.0:
|
||||
print(
|
||||
"warning: escape_threshold is 0 (reference points are coincident) — "
|
||||
"every rollout query would be flagged as escaped. Pass "
|
||||
"`giant rollout --escape-threshold <mm>` to override, or use data "
|
||||
"with distinct step positions."
|
||||
)
|
||||
|
||||
out.parent.mkdir(parents=True, exist_ok=True)
|
||||
oracle.save(out)
|
||||
print(f"wrote oracle -> {out}")
|
||||
Reference in New Issue
Block a user