Skip to content

Commit 4eaa150

Browse files
committed
Changelog for #63
1 parent 53f49a2 commit 4eaa150

2 files changed

Lines changed: 36 additions & 2 deletions

File tree

‎changelog/2026-09.md‎

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
# SWEET_python Changelog — September 2026
22

3-
**Highlights:** The annual model was charging a flare's inefficiency twice — a
3+
**Highlights:** Model output frames now come out with their waste-type columns
4+
in one fixed order instead of a per-process one — a `set` fed the ordering, and
5+
Python randomizes set iteration per process, so the same code on the same inputs
6+
diffed dirty against itself. No output-value change. Earlier in the month: the
7+
annual model was charging a flare's inefficiency twice — a
48
hardcoded 2% slip stacked on top of a `flaring` destruction efficiency that
59
already accounted for it — which also made the annual engine disagree with the
610
monthly one by ~3.7% on identical inputs. A site with gas capture now emits
@@ -10,6 +14,28 @@ where an out-of-range value used to produce negative emissions silently.
1014

1115
## Fixed
1216

17+
- **Model output column order no longer depends on `PYTHONHASHSEED`.**
18+
`City.components` and the values of `City.div_components` were plain `set`s.
19+
A set is the right shape for eligibility — that is a membership question — but
20+
they are also what the engines iterate to build DataFrame columns, and a `set`
21+
of `str` iterates in hash order, which Python randomizes per process (PEP 456).
22+
The same code on the same inputs therefore produced a different column order in
23+
every process: 356 of 749 dumped model outputs changed order between two seeds.
24+
`WASTE_TYPES` in `constants.py` is now the single definition of the order — the
25+
field order of `WasteFractions`/`WasteMasses`, so the frames built from a
26+
pydantic `model_dump()` and the frames built from an eligibility set finally
27+
agree — and `WasteTypeSet` is a `frozenset` that iterates in it, which makes all
28+
35 `list(...)` conversions and 45 iterations deterministic without touching a
29+
call site (including the Climate TRACE pipeline's, which reach into the same
30+
attributes). `advanced_dst_city` moves off its lone alphabetical `sorted()` onto
31+
the same order. **No output-value change:** 749 outputs / 297,806 numbers dumped
32+
at full precision are byte-identical across three hash seeds, and column-aligned
33+
against the previous code every per-waste-type number is unchanged. The only
34+
cells that move are 307 in the derived `total` column at one seed, each by
35+
exactly 1 ULP — `total` is a sum *across* the columns and floating-point
36+
addition is not associative, so its last bit used to follow the hash seed too.
37+
([#63](https://github.com/RMI/SWEET_python/pull/63))
38+
1339
- **The annual model charged flare inefficiency twice, and disagreed with the
1440
monthly model.** `ch4_capture` is already `generation × capture_efficiency ×
1541
flaring`, so the gas a flare fails to destroy is emitted through the
@@ -41,6 +67,14 @@ where an out-of-range value used to produce negative emissions silently.
4167

4268
## Known limitations
4369

70+
- **`DivsDF.sum()` still orders its columns alphabetically.** It builds them with
71+
`Index.union`, which sorts, so that frame and the `waste_mass_df` derived from
72+
it use a different order from the rest of the model. Deterministic, so it was
73+
never part of the hash-seed problem, and it affects nothing downstream because
74+
every consumer of `waste_mass_df` slices it by name — but it is a second order,
75+
pinned by a test until it can be unified.
76+
([#63](https://github.com/RMI/SWEET_python/pull/63))
77+
4478
- **Collected gas that is vented is still oxidised as if it left through the
4579
cover.** It left through a stack. At `capture 0.6`, `oxidation 0.22` and
4680
`flaring 0`, the model gives `0.78 × generation` where the physical answer is

‎changelog/README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ The project does not publish semantic version tags, so releases are tracked by
1515

1616
Newest first:
1717

18-
- [2026-09](2026-09.md) — Annual model no longer charges a flare's inefficiency twice (a hardcoded 2% slip stacked on the `flaring` destruction efficiency), so it agrees with the monthly model again and a site with gas capture emits ~3.5% less (model-output change); `gas_capture_efficiency` bounded to [0, 1], where an out-of-range value used to produce negative emissions silently; one methane density constant instead of two 9.1% apart
18+
- [2026-09](2026-09.md) — Model output frames get one fixed waste-type column order instead of a per-process one (a `set` fed the ordering, and Python randomizes set iteration per process), with no output-value change; annual model no longer charges a flare's inefficiency twice (a hardcoded 2% slip stacked on the `flaring` destruction efficiency), so it agrees with the monthly model again and a site with gas capture emits ~3.5% less (model-output change); `gas_capture_efficiency` bounded to [0, 1], where an out-of-range value used to produce negative emissions silently; one methane density constant instead of two 9.1% apart
1919
- [2026-08](2026-08.md) — Single-site adst gains optional `depth` (deep-dump MCF bump) and `k_override` (caller-supplied decomposition rate) inputs, restoring the last two site-DST levers; `/sdst` flaring efficiency reaches the model again after a variable-name bug silently forced flare destruction to 0.98; annual model applies cover oxidation by emission year not deposit year, fixing biocover having no effect on closed landfills (WasteMAP #719); `City.sdst_v1_5` custom-site path holds the scenario equal to the baseline before the implementation year even when composition changes (was back-dating the new composition onto pre-implementation deposits) (model-output change); MCF consolidated into a new `SWEET_python.mcf` module and both dump types moved to the IPCC uncategorised-SWDS 0.6 (open dumps up from 0.4, controlled dumps down from 0.7), with a supplied depth now selecting the deep/shallow category (model-output change)
2020
- [2026-07](2026-07.md) — All ten waste types eligible for combustion (metal/glass/other added); methane-only model treats combustion as landfill diversion (model-output change)
2121
- [2026-06](2026-06.md) — New single-site and city-level ADST modeling modules, min-cost max-flow rewrite of the city DST diversion allocator, physical-k fix for cold/dry sites, no more spurious negative food-waste mass

0 commit comments

Comments
 (0)