Add total length traveled per event to event observables
sum(step_length) per event_id, alongside the existing total deposited energy, since path length and energy deposit aren't interchangeable once tracks scatter. Adds plot_total_length and a matching notebook cell. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+41
-20
@@ -7,12 +7,12 @@
|
||||
"source": [
|
||||
"# GIANT validation notebook\n",
|
||||
"\n",
|
||||
"Diagnostics for a trained checkpoint's sample quality, run against `giant predict --coord local` output (`pred_*`/`true_*` columns, denormalized but still local-frame/log-scaled — see `giant.analysis`'s module docstring). Four tiers, each building on the last:\n",
|
||||
"Diagnostics for a trained checkpoint's sample quality, run against `giant predict --coord local` output (`pred_*`/`true_*` columns, denormalized but still local-frame/log-scaled \u2014 see `giant.analysis`'s module docstring). Four tiers, each building on the last:\n",
|
||||
"\n",
|
||||
"1. **stratified marginals** — per-dimension real-vs-generated, sliced by pdg/material/energy\n",
|
||||
"2. **joint structure** — correlation matrices, physically-coupled pairwise plots, direction alignment\n",
|
||||
"3. **physical constraints** — unit-norm directions, non-negative step_length/delta_e/edep\n",
|
||||
"4. **event-level (shower) observables** — total energy, longitudinal/transverse profiles, shower-max depth, in world-frame physical units (mm, MeV)\n"
|
||||
"1. **stratified marginals** \u2014 per-dimension real-vs-generated, sliced by pdg/material/energy\n",
|
||||
"2. **joint structure** \u2014 correlation matrices, physically-coupled pairwise plots, direction alignment\n",
|
||||
"3. **physical constraints** \u2014 unit-norm directions, non-negative step_length/delta_e/edep\n",
|
||||
"4. **event-level (shower) observables** \u2014 total energy, longitudinal/transverse profiles, shower-max depth, in world-frame physical units (mm, MeV)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -115,7 +115,7 @@
|
||||
"id": "22c67dc4",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Detailed marginals, correlation & constraints (Tiers 1–3, in-memory sample)\n",
|
||||
"## Detailed marginals, correlation & constraints (Tiers 1\u20133, in-memory sample)\n",
|
||||
"\n",
|
||||
"The richer per-row diagnostics below (overlaid histograms, correlation matrices, pairwise scatter, direction alignment, constraint violations) need `real_raw`/`gen_raw` materialized as numpy arrays, so they run on a `SampleCollection` built from a 50% row sample rather than the lazy, full-file path used above."
|
||||
]
|
||||
@@ -152,7 +152,7 @@
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# sample_frac=0.5 keeps this a manageable in-memory size — fine for these\n",
|
||||
"# sample_frac=0.5 keeps this a manageable in-memory size \u2014 fine for these\n",
|
||||
"# per-row diagnostics, unlike the event-level checks further down, which\n",
|
||||
"# need every row of an event present to sum correctly.\n",
|
||||
"samples = load_predicted_local(FILE, sample_frac=0.5)\n",
|
||||
@@ -228,7 +228,7 @@
|
||||
],
|
||||
"source": [
|
||||
"# Real vs. generated Pearson correlation matrices (+ their difference) over\n",
|
||||
"# the 9 raw target dims — catches a model that decorrelates targets that are\n",
|
||||
"# the 9 raw target dims \u2014 catches a model that decorrelates targets that are\n",
|
||||
"# physically coupled even when every individual marginal looks clean.\n",
|
||||
"_ = plot_correlation_matrices(samples)"
|
||||
]
|
||||
@@ -251,7 +251,7 @@
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Scatter for physically-coupled pairs (step_length/delta_e/edep) — the\n",
|
||||
"# Scatter for physically-coupled pairs (step_length/delta_e/edep) \u2014 the\n",
|
||||
"# joint-structure check correlation matrices alone can't fully capture.\n",
|
||||
"_ = plot_pairwise(samples, n_sample=len(samples.gen_raw))"
|
||||
]
|
||||
@@ -274,7 +274,7 @@
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# cos(angle) between post_dir and travel_dir — coupled through the\n",
|
||||
"# cos(angle) between post_dir and travel_dir \u2014 coupled through the\n",
|
||||
"# scattering physics, so this is another joint-structure check.\n",
|
||||
"_ = plot_direction_alignment(samples)"
|
||||
]
|
||||
@@ -305,7 +305,7 @@
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Unit-norm direction vectors, non-negative step_length/delta_e/edep — the\n",
|
||||
"# Unit-norm direction vectors, non-negative step_length/delta_e/edep \u2014 the\n",
|
||||
"# unconstrained MLP has nothing enforcing these, so any violation here is a\n",
|
||||
"# pure generation artifact rather than a real-data property.\n",
|
||||
"_ = plot_constraint_violations(samples)"
|
||||
@@ -318,11 +318,11 @@
|
||||
"source": [
|
||||
"## Tier 4: event-level (shower) observables\n",
|
||||
"\n",
|
||||
"Everything above is a **step-level** check: one row in, one row out, compared in the local frame (`pre_dir = ẑ`). This section aggregates those same rows **per `event_id`**, reconstructed into world-frame physical units (mm, MeV), to check the shower-level quantities that actually matter physically: total deposited energy, longitudinal/transverse shower profiles, and shower-max depth (see `diffusion-model-tutorial.md` §7.2).\n",
|
||||
"Everything above is a **step-level** check: one row in, one row out, compared in the local frame (`pre_dir = \u1e91`). This section aggregates those same rows **per `event_id`**, reconstructed into world-frame physical units (mm, MeV), to check the shower-level quantities that actually matter physically: total deposited energy, longitudinal/transverse shower profiles, and shower-max depth (see `diffusion-model-tutorial.md` \u00a77.2).\n",
|
||||
"\n",
|
||||
"**Caveat:** this re-aggregates one-step-ahead generations — each row is generated conditioned on the *real* preceding state, then grouped by event — not a full autoregressive shower rollout. It won't surface covariate-shift failures that only appear under true rollout, only how well one-step generation reconstructs aggregate shower structure when fed real conditioning throughout.\n",
|
||||
"**Caveat:** this re-aggregates one-step-ahead generations \u2014 each row is generated conditioned on the *real* preceding state, then grouped by event \u2014 not a full autoregressive shower rollout. It won't surface covariate-shift failures that only appear under true rollout, only how well one-step generation reconstructs aggregate shower structure when fed real conditioning throughout.\n",
|
||||
"\n",
|
||||
"`compute_event_observables_pl` streams the full file directly (two polars passes, no `SampleCollection`) rather than reusing `samples` above — per-event sums would be silently corrupted by `sample_frac`-style row subsampling, since a partially-sampled event no longer sums to the true per-event total."
|
||||
"`compute_event_observables_pl` streams the full file directly (two polars passes, no `SampleCollection`) rather than reusing `samples` above \u2014 per-event sums would be silently corrupted by `sample_frac`-style row subsampling, since a partially-sampled event no longer sums to the true per-event total."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -333,10 +333,11 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from giant.analysis import compute_event_observables_pl\n",
|
||||
"from giant.analysis import plot_total_energy, plot_longitudinal_profile\n",
|
||||
"from giant.analysis import plot_total_energy, plot_total_length\n",
|
||||
"from giant.analysis import plot_longitudinal_profile\n",
|
||||
"from giant.analysis import plot_transverse_profile, plot_shower_max_depth\n",
|
||||
"\n",
|
||||
"# Full file, not `samples` — see the markdown cell above for why.\n",
|
||||
"# Full file, not `samples` \u2014 see the markdown cell above for why.\n",
|
||||
"obs = compute_event_observables_pl(FILE)"
|
||||
]
|
||||
},
|
||||
@@ -347,7 +348,7 @@
|
||||
"source": [
|
||||
"### Total deposited energy per event\n",
|
||||
"\n",
|
||||
"`sum(edep)` grouped by `event_id`, real vs. generated, with the resolution (σ/μ) for each annotated in the legend."
|
||||
"`sum(edep)` grouped by `event_id`, real vs. generated, with the resolution (\u03c3/\u03bc) for each annotated in the legend."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -371,6 +372,26 @@
|
||||
"_ = plot_total_energy(obs)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "8c63c999",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Total length traveled per event\n",
|
||||
"\n",
|
||||
"`sum(step_length)` grouped by `event_id` \u2014 total path length traveled by every track in the shower, real vs. generated (not the same as the depth of any single point, since tracks scatter)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "d6561b73",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"_ = plot_total_length(obs)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "cf3ea615",
|
||||
@@ -378,7 +399,7 @@
|
||||
"source": [
|
||||
"### Longitudinal profile\n",
|
||||
"\n",
|
||||
"Mean deposited energy per event, binned by depth along the shower axis (the `pre_dir` of each event's highest-`pre_E` row), with the event-to-event RMS as error bars — the classic `E_dep(depth)` profile."
|
||||
"Mean deposited energy per event, binned by depth along the shower axis (the `pre_dir` of each event's highest-`pre_E` row), with the event-to-event RMS as error bars \u2014 the classic `E_dep(depth)` profile."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -409,7 +430,7 @@
|
||||
"source": [
|
||||
"### Transverse profile\n",
|
||||
"\n",
|
||||
"Same idea, binned by perpendicular distance from the shower axis instead of depth — a Molière-radius-style lateral containment check."
|
||||
"Same idea, binned by perpendicular distance from the shower axis instead of depth \u2014 a Moli\u00e8re-radius-style lateral containment check."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -440,7 +461,7 @@
|
||||
"source": [
|
||||
"### Shower-maximum depth\n",
|
||||
"\n",
|
||||
"Per event, the depth bin where that event's longitudinal profile peaks — compares the real vs. generated distribution of shower-max depth across events, rather than the pooled profile above."
|
||||
"Per event, the depth bin where that event's longitudinal profile peaks \u2014 compares the real vs. generated distribution of shower-max depth across events, rather than the pooled profile above."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user