Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
35 changes: 31 additions & 4 deletions docs/studio/ASSUMPTIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,23 +104,25 @@ 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
(`coupled/tests/test_boxvol_invariance.py`; the box-size sweep `run_boxsize.py:43` works purely by
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.

---

Expand Down Expand Up @@ -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.

16 changes: 9 additions & 7 deletions docs/studio/CAVEATS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
68 changes: 36 additions & 32 deletions docs/studio/OPEN_QUESTIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

---

Expand Down
29 changes: 29 additions & 0 deletions docs/studio/PROGRESS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 3 additions & 4 deletions docs/studio/plan/PHASE_1.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 | — | — |
Expand All @@ -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.
Expand Down
8 changes: 4 additions & 4 deletions studio/modelio/preview.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
"""
Expand Down
6 changes: 3 additions & 3 deletions studio/schema/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
9 changes: 5 additions & 4 deletions studio/schema/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
Loading
Loading