From 7db5a07270898eeed7ac2624d06193db0235ff54 Mon Sep 17 00:00:00 2001
From: Ali Akherati
Date: Tue, 18 Aug 2026 10:45:42 -0700
Subject: [PATCH] docs(studio): SCIENCE-2 and SCIENCE-3 answered; ERA5
confirmed; stages unblocked
Three decisions (Ali, 2026-08-18), closing every science question that gated Phases 1-4:
SCIENCE-2: t = 0 is the moment a volume is defined. Engine exit and wake-vortex breakup
are OUT OF SCOPE -- the model starts from a user-specified parcel and says nothing about
how it came to be. No t0_definition field and no early-regime parameterisation, on the
same reasoning as heating/buoyancy: a wake treatment needs a different model. The caveat
changes character rather than disappearing -- absolute particle numbers are conditional on
the chosen initial concentration -- and CAVEATS.md now states it as a scope boundary.
ASSUMPTION-5 becomes permanent instead of "until SCIENCE-2 resolves".
SCIENCE-3: pure sulfate, by assumption, revisitable. Recorded as ASSUMPTION-8 with the
code location (the backgrounds were already seeded sulfate-only; this converts an implicit
behaviour into a dated decision). The per-dataset dry/ambient basis survives as a
data-description note inside the assumption.
Climatology source: ERA5, confirming BLOCKING-5. Alternatives tracked in #94 -- notably
MLS for H2O, since reanalysis stratospheric water vapour is biased dry.
Follow-through in code: stages 1 and 2 lose their blocked_on labels, and every docstring
and panel hint that described SCIENCE-2 as open now states the answer. The stage-3
sensitivity panel stays, reframed: the sensitivity of the result to a choice the model
does not make for you. Issues #53/#54/#55 retitled ANSWERED.
No schema fields changed; the config hash is untouched.
Co-Authored-By: Claude Opus 5
Claude-Session: https://claude.ai/code/session_01EaDHnPdiacsybr8Tp5WnqR
---
docs/studio/ASSUMPTIONS.md | 35 +++++++++++++++---
docs/studio/CAVEATS.md | 16 +++++----
docs/studio/OPEN_QUESTIONS.md | 68 ++++++++++++++++++-----------------
docs/studio/PROGRESS.md | 29 +++++++++++++++
docs/studio/plan/PHASE_1.md | 7 ++--
studio/modelio/preview.py | 8 ++---
studio/schema/config.py | 6 ++--
studio/schema/enums.py | 9 ++---
studio/schema/layout.py | 14 ++++----
studio/science/__init__.py | 2 +-
studio/science/plume.py | 9 ++---
studio/web/src/panels.tsx | 7 ++--
12 files changed, 136 insertions(+), 74 deletions(-)
diff --git a/docs/studio/ASSUMPTIONS.md b/docs/studio/ASSUMPTIONS.md
index 722f84d..0824bc8 100644
--- a/docs/studio/ASSUMPTIONS.md
+++ b/docs/studio/ASSUMPTIONS.md
@@ -104,15 +104,17 @@ from the existing `runs*/worker_*.log` files and will make the right cap obvious
## ASSUMPTION-5 — Phase 0 defaults follow the golden runs, not the spec's geometry
-**Made:** 2026-08-13 · **Affects:** `studio/schema` defaults, `studio/science/plume_volume.py` ·
-**Tracks:** [SCIENCE-2](OPEN_QUESTIONS.md#science-2--definition-of-t--0--open--blocks-phase-2-caveats-all-results)
+**Made:** 2026-08-13 · **Affects:** `studio/schema` defaults, `studio/science/plume.py` ·
+**Settled 2026-08-18:** SCIENCE-2 is answered — t = 0 is the moment a volume is defined — so this is
+now permanent rather than provisional.
The spec's §4.2 gives a default source cross-section of 10 m × 30 m. The existing 810-run ensemble
uses **10 m × 10 m × 15 km** (`run_ensemble.py:45`, giving V₀ = 1.5e12 cm³) and the D1 flagship run
uses a 30 km track (`run_dilution_d1_clean.py:61`, V₀ = 3e6 m³).
Phase 0 defaults follow the ensemble, because Phase 0's job is to reproduce existing trusted runs.
-The spec's geometry is not implemented as a default until SCIENCE-2 resolves what t = 0 means.
+With SCIENCE-2 answered (t = 0 is when a volume is defined; jet/vortex out of scope), the spec's
+geometry is simply not adopted — there is no pending resolution to wait for.
**Note, and it matters for how this is presented:** V₀ **does not enter the dynamics**. It only sets
the initial SO₂ concentration; the model is intensive and volume-invariant
@@ -120,7 +122,7 @@ the initial SO₂ concentration; the model is intensive and volume-invariant
scaling the initial concentration). The UI must say so rather than implying a geometric dependence
that does not exist.
-**What would settle it.** SCIENCE-2.
+**Settled.** SCIENCE-2 answered 2026-08-18; the defaults are the convention.
---
@@ -164,3 +166,28 @@ error in initial concentration.
`CONVENTION` to `LITERATURE` with that citation. `test_the_speed_default_is_marked_as_a_choice_not_a_measurement` asserts the caveat is present, so it cannot be quietly dropped without the citation
that would justify dropping it.
+## ASSUMPTION-8 — All aerosol is pure sulfate
+
+**Made:** 2026-08-18 (Ali) · **Affects:** every run — background seeding and plume microphysics ·
+**Tracks:** [SCIENCE-3](OPEN_QUESTIONS.md#science-3--aerosol-composition-mixing-state-meteoric-material--answered-2026-08-18--55) (answered)
+
+**What is assumed.** All condensed material, background and plume alike, is sulfate–water. No
+meteoric material, no organics, no external mixtures — with one composition, everything is internally
+mixed by construction.
+
+**Where it lives in code.** The backgrounds are seeded sulfate-only
+(`coupled/tomas_bridge.py::_seed_lognormal`, `Mk[:, SRTSO4]`), and TOMAS carries a single condensed
+composition through condensation and coagulation. This assumption was implicit in the code before it
+was stated; SCIENCE-3's answer converts it into a decision with a date.
+
+**Why.** Simplicity, deliberately: the questions this model is being asked (nucleation vs
+condensation sink, dilution-regime sensitivity) do not require a mixed-composition treatment, and
+adding one would multiply the untestable surface. Marked revisitable — "we might change it later" —
+and this entry is where that change starts.
+
+**What it costs.** Real stratospheric background aerosol carries meteoric and organic material;
+heterogeneous chemistry and optical properties on a pure-sulfate distribution will differ from
+observations in ways this repository does not quantify. Per-dataset caveat that survives: whether
+each background's diameters are **dry or ambient** is implicit in the dataset
+(`AMBIENT_BACKGROUNDS` in `coupled/backgrounds.py`) rather than a declared field.
+
diff --git a/docs/studio/CAVEATS.md b/docs/studio/CAVEATS.md
index 2b9a28d..808d352 100644
--- a/docs/studio/CAVEATS.md
+++ b/docs/studio/CAVEATS.md
@@ -30,15 +30,17 @@ particle-loss process, not a thermodynamic response, and this decision says noth
## Top-level caveats — shown on every results view
-### The definition of t = 0 is unresolved, and it dominates particle number
+### The model starts from a defined volume; how the plume got there is out of scope
-Tracked as [SCIENCE-2](OPEN_QUESTIONS.md#science-2--definition-of-t--0--open--blocks-phase-2-caveats-all-results).
+Decided 2026-08-18 ([SCIENCE-2](OPEN_QUESTIONS.md#science-2--definition-of-t--0--answered-2026-08-18--54),
+answered): **t = 0 is the moment a volume is defined.** The jet and wake-vortex phases — which dilute
+a real plume by orders of magnitude in the first ~10–100 s — are not modelled, the same way heating
+and buoyancy are not (SCIENCE-4): they need a different model.
-The jet and vortex phases dilute a real plume by orders of magnitude within the first ~10–100 s, and
-nucleation is strongly nonlinear in H₂SO₄ concentration. Whether the box starts at the engine exit
-plane or after wake-vortex breakup changes resulting particle number **more than most parameters in
-stages 4–7**. Until `t0_definition` is settled and an early-regime parameterisation is cited, every
-absolute particle-number result carries this uncertainty.
+The consequence for reading results: nucleation is strongly nonlinear in H₂SO₄, so **absolute
+particle numbers are conditional on the chosen initial concentration**. Comparisons within an
+ensemble that shares a V₀ convention are clean; a claim about an actual aircraft plume would need the
+early dilution this model deliberately does not represent.
### Initial plume volume does not affect the dynamics
diff --git a/docs/studio/OPEN_QUESTIONS.md b/docs/studio/OPEN_QUESTIONS.md
index 03c303a..5dfb6f9 100644
--- a/docs/studio/OPEN_QUESTIONS.md
+++ b/docs/studio/OPEN_QUESTIONS.md
@@ -153,45 +153,49 @@ which keeps the ensemble's `day_of_year = 172` as 21 June.
---
-### SCIENCE-2 — Definition of t = 0 · **OPEN** · blocks Phase 2, caveats **all** results · [#54](https://github.com/reflective-org/SANDBOX/issues/54)
+### SCIENCE-2 — Definition of t = 0 · **ANSWERED** (2026-08-18) · [#54](https://github.com/reflective-org/SANDBOX/issues/54)
*Does the box start at the engine exit plane, or after wake-vortex breakup?*
-The most consequential unresolved item in the specification. The jet and vortex phases dilute the
-plume by orders of magnitude within the first ~10–100 s, and nucleation is strongly nonlinear in
-H₂SO₄ concentration, so this choice changes resulting particle number more than most parameters in
-stages 4–7.
-
-Requirements once answered:
-- `t0_definition` is an explicit, **required** schema field.
-- If `ENGINE_EXIT`, the early dilution regime needs a *citable* parameterisation, not the same curve
- used for the later diffusive regime. The existing regimes (`coupled/dilution.py:39`) follow a
- Schumann et al. (1998) volume expansion `V(t)/V₀ = max(1, t^0.8)` for t ≤ 10⁴ s — which is already
- a two-stage form, but is not a jet/vortex treatment.
-- Appears as a top-level caveat in every results view and in `CAVEATS.md`.
-
-**Complication found in the code:** the initial plume volume V₀ **does not enter the dynamics at
-all**. It only sets the initial SO₂ concentration; the model is intensive and volume-invariant
-(`coupled/tests/test_boxvol_invariance.py`; the box-size sweep `run_boxsize.py:43` works purely by
-scaling the initial concentration). So the t=0 question is entirely a question about the *initial
-concentration*, and the UI must not imply a geometric dependence that does not exist.
-
-**Existing geometry is inconsistent with the spec.** The spec proposes a 10 m × 30 m cross-section;
-the 810-run ensemble uses 10 m × 10 m × 15 km (`run_ensemble.py:45`) and the D1 flagship a 30 km
-track (`run_dilution_d1_clean.py:61`). Phase 0 defaults follow the golden runs.
+**Answered (Ali, 2026-08-18): neither. t = 0 is the moment a volume is defined.** The jet and vortex
+phases are **out of scope**: the model starts from a user-specified parcel — a mass in a volume — and
+says nothing about how that parcel came to be. There is no `t0_definition` field, no engine-exit
+option, and no early-regime parameterisation to cite, because the question the spec posed is not one
+this model answers.
+
+What this settles and what it costs:
+
+- **The initial volume is a modelling choice, not a physical claim.** The wizard already says so
+ (stage 2: "V₀ does not enter the dynamics"), and the stage-3 concentration-vs-volume panel is the
+ sensitivity of results to that choice, made visible. That panel stays: it is no longer "the open
+ t = 0 question" but it is exactly the sweep a careful user should look at.
+- **The caveat changes character rather than disappearing.** Results are conditional on the chosen
+ initial concentration; comparisons *within* an ensemble sharing a V₀ convention are clean, and
+ absolute particle numbers still inherit the choice. `CAVEATS.md` states it as a scope boundary now,
+ not an unresolved question.
+- **ASSUMPTION-5 loses its tracker.** The defaults follow the golden runs permanently, not "until
+ SCIENCE-2 resolves"; the spec's 10 m × 30 m cross-section is simply not adopted.
+- Same reasoning as the heating/buoyancy decision (SCIENCE-4): a wake-dynamics treatment needs a
+ different model, and pretending otherwise with a plausible parameterisation is the failure mode
+ this project exists to avoid.
---
-### SCIENCE-3 — Aerosol composition, mixing state, meteoric material · **OPEN** · blocks Phase 4 · [#55](https://github.com/reflective-org/SANDBOX/issues/55)
+### SCIENCE-3 — Aerosol composition, mixing state, meteoric material · **ANSWERED** (2026-08-18) · [#55](https://github.com/reflective-org/SANDBOX/issues/55)
-Required per background distribution: diameter basis (dry vs ambient, and at what water content if
-ambient), composition and mixing state (internal vs external, sulfate mass fraction), and whether
-meteoric material is represented at all.
+**Answered (Ali, 2026-08-18): pure sulfate, by assumption, to keep things simple — revisitable.**
+All aerosol, background and plume alike, is sulfate–water; there is no meteoric material, no organics
+and no mixing-state question, because with one composition everything is internally mixed by
+construction.
-**Partially constrained by the code already:** `coupled/backgrounds.py` defines six named
-lognormal backgrounds, seeded as sulfate-only (`Mk[:, SRTSO4]` in `tomas_bridge._seed_lognormal`),
-and `AMBIENT_BACKGROUNDS` marks which mode sets are specified at ambient vs STP — so the
-dry/ambient distinction exists but is per-dataset and implicit rather than a declared field. Meteoric
-material is **not** represented.
+This converts what the code already did implicitly into a stated assumption: the backgrounds are
+seeded sulfate-only (`Mk[:, SRTSO4]` in `tomas_bridge._seed_lognormal`), and the microphysics
+carries a single condensed composition. Recorded as **ASSUMPTION-8** with the code location, so
+"might change it later" has a single place to start from.
+
+Still per-dataset and worth keeping visible: the **dry vs ambient** diameter basis of each background
+(`AMBIENT_BACKGROUNDS` in `coupled/backgrounds.py`) is implicit in the dataset rather than a declared
+field. That is a data-description question, not a composition question, so it survives this answer —
+folded into the ASSUMPTION-8 record rather than kept as an open science item.
---
diff --git a/docs/studio/PROGRESS.md b/docs/studio/PROGRESS.md
index 1cc4b00..c0a309d 100644
--- a/docs/studio/PROGRESS.md
+++ b/docs/studio/PROGRESS.md
@@ -29,6 +29,35 @@ derivations to resolve rather than fixtures.
---
+### 2026-08-18 — SCIENCE-2 and SCIENCE-3 answered; ERA5 confirmed
+
+Three decisions in one message, closing every science question that gated Phases 1–4 (only
+SCIENCE-4's sedimentation half and SCIENCE-6's ion-pair derivation remain open):
+
+**SCIENCE-2 (t = 0): it is the moment a volume is defined.** Engine exit and wake-vortex breakup are
+out of scope — the model starts from a user-specified parcel and says nothing about how it came to
+be. No `t0_definition` field, no early-regime parameterisation; the same reasoning as
+heating/buoyancy, since a wake treatment needs a different model. The caveat changes character
+rather than disappearing: absolute particle numbers are conditional on the chosen initial
+concentration, and `CAVEATS.md` now says so as a scope boundary. ASSUMPTION-5 (golden-run defaults)
+becomes permanent; stage 2 loses its *blocked on* label; the stage-3 sensitivity panel stays, now
+framed as "your result's sensitivity to a choice the model does not make for you".
+
+**SCIENCE-3 (composition): pure sulfate, by assumption, revisitable.** Recorded as **ASSUMPTION-8**
+with the code location — the backgrounds were already seeded sulfate-only, so this converts what the
+code did implicitly into a decision with a date. No meteoric material, no organics, no mixing-state
+question. The per-dataset dry/ambient diameter basis survives as a data-description point inside the
+assumption record.
+
+**Climatology source: ERA5**, confirming BLOCKING-5's 2026-08-13 answer. Alternatives get their own
+issue (#94) — notably **MLS for H₂O**, since reanalysis stratospheric water vapour is biased dry and
+H₂O is the field the sulfate microphysics is most sensitive to. Task 1.1 proceeds on ERA5.
+
+Follow-through: stages 1 and 2 lose their `blocked_on` labels, and every docstring and panel hint
+that described SCIENCE-2 as open now states the answer. Issues #53/#54/#55 retitled ANSWERED.
+
+---
+
### 2026-08-18 — SCIENCE-1 answered, and the date became a date
**Answered (Ali): zonal-mean, monthly climatology**, selected by the month of the release. So the
diff --git a/docs/studio/plan/PHASE_1.md b/docs/studio/plan/PHASE_1.md
index 576122f..69c99aa 100644
--- a/docs/studio/plan/PHASE_1.md
+++ b/docs/studio/plan/PHASE_1.md
@@ -15,10 +15,10 @@ panels or the comparison view.
| # | Stage | Spec | Fields today | Blocked on |
|---|---|---|---|---|
| 1 | Environment | §5.1 | 8 | SCIENCE-1 **answered** (zonal-mean monthly); the product itself is task 1.1 |
-| 2 | Plume volume and t = 0 | §5.2 | 3 + 1 derived | **SCIENCE-2** — engine exit vs post-vortex breakup changes V₀ by orders of magnitude |
+| 2 | Release and plume volume | §5.2 | 9 + 3 derived | SCIENCE-2 **answered**: t = 0 is when the volume is defined; jet/vortex out of scope |
| 3 | Initial concentration | §5.3 | 1 + 1 derived | — |
| 4 | Dilution | §5.4 | 6 | SCIENCE-5 answered: `background_evolves` fixed False |
-| 5 | Background aerosol | §5.5 | 1 | SCIENCE-3 — composition and mixing state |
+| 5 | Background aerosol | §5.5 | 1 | SCIENCE-3 **answered**: pure sulfate (ASSUMPTION-8) |
| 6 | Emitted and background species | §5.5 | 2 | — |
| 7 | Chemistry, nucleation, numerics | §5.6–5.8 | 19 | — |
| 8 | Review | §8 | — | — |
@@ -34,8 +34,7 @@ All 42 schema fields are placed and rendered; `test_layout.py` fails if a new on
MB, small enough to **commit with a checksum** rather than fetch at run time. Longitude stays an
input for the solar zenith angle but does not select the meteorology, and the convention goes into
the dataset identifier recorded in provenance (ADR-006) so a longitude-resolved product added later
- cannot reinterpret an existing config. Still needs a decision on the **source** (ERA5 vs MERRA-2 vs
- MLS) — note BLOCKING-5's caveat that reanalysis stratospheric water vapour is biased dry, so H₂O
+ cannot reinterpret an existing config. Source decided 2026-08-18: **ERA5** (confirming BLOCKING-5); alternatives tracked in their own issue — note BLOCKING-5's caveat that reanalysis stratospheric water vapour is biased dry, so H₂O
may want a different source from p and T.
- **1.0b Date entry** — *done (2026-08-18).* Month + day of month entered, `day_of_year` derived on a
fixed non-leap calendar. No year, because a monthly climatology is an average over years.
diff --git a/studio/modelio/preview.py b/studio/modelio/preview.py
index e8288fb..7c99bfb 100644
--- a/studio/modelio/preview.py
+++ b/studio/modelio/preview.py
@@ -213,10 +213,10 @@ def bin_grid(config: RunConfig) -> dict[str, Any]:
def concentration_sensitivity(config: RunConfig) -> dict[str, Any]:
"""Initial SO2 mixing ratio against plume volume, with this config marked (stage 3).
- The point of the panel is SCIENCE-2. The t = 0 definition moves V0 by orders of magnitude, and
- on a log-log axis that is a straight line the reader can walk along -- so "we have not decided
- whether t = 0 is engine exit or vortex breakup" becomes a visible range of initial
- concentrations rather than an abstract caveat.
+ The panel is the SCIENCE-2 caveat made visible. t = 0 is the moment the volume is defined
+ (answered 2026-08-18), so V0 is a modelling choice -- and on a log-log axis its consequence is a
+ straight line the reader can walk along: this is the sensitivity of the initial concentration to
+ a choice the model does not make for you.
Pure ``studio.science``: no model import, so this panel costs nothing and needs no JAX.
"""
diff --git a/studio/schema/config.py b/studio/schema/config.py
index 7b14b9f..9e0b955 100644
--- a/studio/schema/config.py
+++ b/studio/schema/config.py
@@ -253,9 +253,9 @@ class Injection(SchemaModel):
below exists only to turn an injected mass into an initial concentration. Presenting it as a
plume shape that the physics responds to would be a lie of layout.
- What t = 0 means -- engine exit plane or post-vortex-breakup -- is SCIENCE-2 (issue #54) and is
- the most consequential open question in the project, because it moves the initial concentration
- by orders of magnitude.
+ What t = 0 means is ANSWERED (SCIENCE-2, 2026-08-18): it is the moment this volume is defined.
+ Jet and wake-vortex dynamics are out of scope -- they need a different model -- so the volume is
+ a modelling choice, and results are conditional on the initial concentration it implies.
"""
so2_mass_kg: float = SciField(
diff --git a/studio/schema/enums.py b/studio/schema/enums.py
index 622e4e0..0450194 100644
--- a/studio/schema/enums.py
+++ b/studio/schema/enums.py
@@ -67,7 +67,8 @@ class BackgroundAerosol(StrEnum):
Wet-vs-dry matters here and is per-dataset rather than declared: ``AER_GEO`` and ``CESM_G6_AMB``
are specified at AMBIENT conditions and skip the STP->ambient factor on seeding, the others are
- at STP. Making that an explicit field is SCIENCE-3 (issue #55).
+ at STP. SCIENCE-3 (issue #55) is answered -- all aerosol is pure sulfate by ASSUMPTION-8 --
+ and the dry/ambient basis stays a per-dataset property recorded there.
"""
#: Marianna's tabulated distribution. The model's default.
@@ -106,9 +107,9 @@ class EmissionInput(StrEnum):
made against.
Note this is about the TRACK, not the wake. ``L = v.t`` describes the line the platform lays
- down; the 10 m x 10 m cross-section is vortex dynamics, so if t = 0 turns out to mean
- post-vortex-breakup (SCIENCE-2, issue #54) the cross-section is not the flight geometry even
- though the length still is.
+ down; the 10 m x 10 m cross-section is wake dynamics and is entered separately. t = 0 is the
+ moment the volume is defined (SCIENCE-2, answered 2026-08-18); how the parcel formed is out of
+ scope.
"""
#: Give the track length; duration follows as L/v and rate as M/t. The paper ensemble's
diff --git a/studio/schema/layout.py b/studio/schema/layout.py
index a93ee6c..ee2bc23 100644
--- a/studio/schema/layout.py
+++ b/studio/schema/layout.py
@@ -82,7 +82,6 @@ class Stage:
blurb="Where and when the plume sits. Everything downstream that depends on ambient "
"conditions is derived from this stage.",
spec_ref="5.1",
- blocked_on=("SCIENCE-1",),
sections=(
Section(
title="Location",
@@ -93,9 +92,9 @@ class Stage:
Section(
title="Ambient state",
fields=("site.temperature_k", "site.pressure_mbar", "site.h2o_ppmv"),
- note="Entered directly today. The spec's tropopause-relative altitude and "
- "dataset-derived p/T need the climatology product, which is blocked on "
- "SCIENCE-1 (sampling convention).",
+ note="Entered directly today. SCIENCE-1 is answered (zonal-mean monthly, ERA5), so "
+ "the climatology-derived p/T arrives with the reduced product (task 1.1); until "
+ "then these are typed.",
),
Section(
title="Date and time",
@@ -118,7 +117,6 @@ class Stage:
blurb="How much is released, over how much track. The emission has ONE degree of freedom: "
"give the rate, the duration or the length, and the other two follow.",
spec_ref="5.2",
- blocked_on=("SCIENCE-2",),
sections=(
Section(
title="Release",
@@ -154,9 +152,9 @@ class Stage:
Section(
title="Cross-section",
fields=("injection.plume_width_m", "injection.plume_height_m"),
- note="Wake dynamics, not flight geometry: if t = 0 means post-vortex-breakup "
- "(SCIENCE-2) the cross-section is not derivable from the track, which is why it is "
- "entered separately.",
+ note="Wake dynamics, not flight geometry, which is why it is entered separately: "
+ "t = 0 is the moment this volume is defined (SCIENCE-2, answered), and how the "
+ "parcel formed is out of scope.",
),
Section(
title="Initial volume",
diff --git a/studio/science/__init__.py b/studio/science/__init__.py
index 4f13ee7..65843ca 100644
--- a/studio/science/__init__.py
+++ b/studio/science/__init__.py
@@ -7,7 +7,7 @@
* **Plume volume and injected mass -> initial concentration** (``plume.py``). Six copies today, and
they disagree: the ensemble uses a 15 km track and the D1 flagship a 30 km one -- a factor of two
- in V0 for the same injected mass. Which is right depends on what t = 0 means (SCIENCE-2, #54).
+ in V0 for the same injected mass. t = 0 is the moment the volume is defined (SCIENCE-2, #54).
* **dN/dlogDp and bin mid-points** (``size_distribution.py``). Four copies, written two ways which
turn out to be algebraically identical -- measured agreement to a few ULP.
* **Air number density** (``air.py``). A deliberate MIRROR of the model's, because this package may
diff --git a/studio/science/plume.py b/studio/science/plume.py
index f7f5c03..ea04cbf 100644
--- a/studio/science/plume.py
+++ b/studio/science/plume.py
@@ -23,7 +23,8 @@
The divergence that matters is the **15 km vs 30 km track**: a factor of two in V0, and therefore a
factor of two in initial concentration for the same injected mass. Which is right depends on what
-t = 0 means, which is SCIENCE-2 (issue #54) and unresolved. Phase 0 follows the 810-run ensemble
+t = 0 means. SCIENCE-2 is answered (2026-08-18): t = 0 is the moment the volume is defined, and
+the jet/vortex phases are out of scope. Phase 0 follows the 810-run ensemble
(ASSUMPTION-5); this module implements the derivation, not the choice of inputs.
**V0 does not enter the dynamics.** The model is intensive and volume-invariant
@@ -158,9 +159,9 @@ def track_length_m(*, speed_m_s: float, duration_s: float) -> float:
"""The along-track length a platform lays down: ``L = v.t``.
This is the TRACK, not the wake. It describes the line the platform flies while emitting; the
- cross-section of the resulting parcel is vortex dynamics and is not derivable from it. If t = 0
- is taken to be post-vortex-breakup (SCIENCE-2, issue #54) the cross-section is not the flight
- geometry -- but the length still is, which is why only the length is derived here.
+ cross-section of the resulting parcel is wake dynamics and is entered separately. t = 0 is the
+ moment the volume is defined (SCIENCE-2, answered 2026-08-18) and how the parcel formed is out
+ of scope -- but the length IS flight geometry, which is why it alone is derived here.
"""
if speed_m_s <= 0.0:
raise ValueError(f"platform speed must be positive, got {speed_m_s} m/s")
diff --git a/studio/web/src/panels.tsx b/studio/web/src/panels.tsx
index 494126f..2d88c63 100644
--- a/studio/web/src/panels.tsx
+++ b/studio/web/src/panels.tsx
@@ -207,8 +207,9 @@ export function ParcelPanel({ config }: PanelProps) {
from it.
- What counts as t = 0 — engine exit or post-vortex breakup — changes this volume by orders
- of magnitude (SCIENCE-2). The next stage shows what that does to the concentration.
+ t = 0 is the moment this volume is defined (SCIENCE-2, answered); how the parcel formed
+ is out of scope. The volume is a modelling choice — the next stage shows what it does to
+ the concentration.
@@ -240,7 +241,7 @@ export function ConcentrationPanel({ config, load }: PanelProps) {
return (