9fa6420183
CI / Sync project version with tag (push) Has been skipped
CI / Type check (ty) (push) Successful in 2m3s
CI / Sync project version with tag (pull_request) Has been skipped
CI / Type check (ty) (pull_request) Successful in 1m19s
CI / Lint (ruff check) (push) Successful in 3m55s
CI / Format (ruff format) (push) Successful in 3m54s
CI / Format (ruff format) (pull_request) Successful in 5m37s
CI / Lint (ruff check) (pull_request) Successful in 5m42s
CI / Tests (push) Successful in 8m42s
CI / Bump version, tag, and update changelog on merge to master (push) Has been skipped
CI / Tests (pull_request) Successful in 5m3s
CI / Bump version, tag, and update changelog on merge to master (pull_request) Has been skipped
Replace the event-level n_sec confusion matrix with two step-resolved secondary-multiplicity comparisons: - sec_count_per_step: overlay histogram of how many secondaries a single step emits, rollout series vs reference. - sec_count_per_step_by_species: heatmap of per-step multiplicity of one species (zero row included) against species, drawn as one panel per rollout plus a reference panel, raw counts on a log color scale. Both are backed by a new sources.secondaries_by_step view, which tags each secondary with its emitting step — (event_id, parent_id, birth position) on the rollout side, the row index on the reference side — so neither plot needs a join against the step frame. Steps that emitted nothing are recovered by subtraction from the chunk's step count, keeping both specs sum-mergeable across condor chunks. The rollout multiplicity is derived from the actual secondary birth rows rather than the n_sec_pred column, which records the predicted count before the per-event max-tracks cap. _render_heatmap gained reference-panel and log-color support; marginal_distance_summary sets neither key and is unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
75 lines
2.9 KiB
Python
75 lines
2.9 KiB
Python
"""The compact, self-describing artifact a compute job produces per plot.
|
|
|
|
Serialized as small JSON (no pickle, no per-event arrays) so it is trivially
|
|
transferable off the batch worker and human-inspectable. ``render.py`` dispatches
|
|
on ``kind`` and needs nothing but this file.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from dataclasses import asdict, dataclass, field
|
|
from pathlib import Path
|
|
|
|
# Reduced.kind values (payload keys a rollout series by name under
|
|
# payload["series"], with the reference — where one exists — kept as one
|
|
# distinguished payload["reference"] entry; see catalog.py's module
|
|
# docstring for the full per-kind payload shape):
|
|
# "overlay_hist" N-rollout-series vs reference density histogram over shared edges
|
|
# "grouped_hist" one panel per group (energy/pdg/material), each an overlay
|
|
# "profile" edep-weighted mean +/- event-RMS vs depth/radius, N series + reference
|
|
# "bar" per-category N-rollout-series vs reference bars (share / counts)
|
|
# "single_hist" rollout-only series (e.g. leakage; reference has none)
|
|
# "router_gating" stacked mean MoE gate weight vs energy, one rollout+reference
|
|
# panel-pair per rollout with an enabled MoE router
|
|
# "router_share" stacked bar of MoE top-1 dispatch share by category, one
|
|
# panel per rollout with an enabled MoE router
|
|
# "router_specialization" max gate weight vs energy (one scalar trend line
|
|
# summarizing "router_gating"), per rollout with an enabled router
|
|
# "heatmap" row x col matrix + colorbar, one panel per rollout (a
|
|
# distance scorecard)
|
|
# "unavailable" plot not applicable to this run (e.g. no MoE checkpoint)
|
|
|
|
|
|
@dataclass
|
|
class Reduced:
|
|
id: str
|
|
family: str
|
|
kind: str
|
|
title: str
|
|
xlabel: str
|
|
payload: dict
|
|
meta: dict = field(default_factory=dict)
|
|
|
|
def save(self, path: str | Path) -> None:
|
|
Path(path).parent.mkdir(parents=True, exist_ok=True)
|
|
Path(path).write_text(json.dumps(asdict(self)))
|
|
|
|
@classmethod
|
|
def load(cls, path: str | Path) -> "Reduced":
|
|
return cls(**json.loads(Path(path).read_text()))
|
|
|
|
|
|
@dataclass
|
|
class Partial:
|
|
"""The raw, not-yet-finalized output of one ``(plot, chunk)`` compute job.
|
|
|
|
``data`` holds whatever shape that plot's ``PlotSpec.compute_partial``
|
|
returns — a raw sum-mergeable count dict, or a raw per-event/per-secondary
|
|
array to be concatenated across chunks — never a finished histogram/profile.
|
|
``PlotSpec.finalize`` is the only thing that knows how to interpret it.
|
|
"""
|
|
|
|
id: str
|
|
family: str
|
|
chunk: int
|
|
data: dict
|
|
|
|
def save(self, path: str | Path) -> None:
|
|
Path(path).parent.mkdir(parents=True, exist_ok=True)
|
|
Path(path).write_text(json.dumps(asdict(self)))
|
|
|
|
@classmethod
|
|
def load(cls, path: str | Path) -> "Partial":
|
|
return cls(**json.loads(Path(path).read_text()))
|