Skip to content

Moving waste to a city's existing gas capture changes its emissions - #75

Open
HughRunyan wants to merge 3 commits into
mainfrom
move-to-existing-gas-capture-takes-effect
Open

HughRunyan wants to merge 3 commits into
mainfrom
move-to-existing-gas-capture-takes-effect

Conversation

@HughRunyan

@HughRunyan HughRunyan commented Oct 8, 2026 •

Copy link
Copy Markdown
Collaborator

Bug

The City DST's "% of waste diverted to existing landfill with gas capture" slider (move_gas, existing_gas_pct in City.implement_dst_changes_simple_v1_5) did nothing. At every setting it returned the no-change scenario exactly.

Environment: SWEET_python main at d5c592e, the generic branch of implement_dst_changes_simple_v1_5 (if not scenario_parameters.sites_method:). WasteMAP /v1/city_emissions/implement_dst_simple_v1_5, with the June 2026 cities table (cities_for_map_0626.csv) and load_city replicated offline.

Reproduction: load Lahore (34.4% of disposal to landfills with gas capture). Run the scenario twice with its own diversions and implement_year=2026: once with move_gas=0, once with move_gas=1, existing_gas_pct=0.9.

Expected: moving waste from the landfill without capture to the one with it lowers emissions after 2026.

Actual: both give 92,872 t CH₄ in 2040. The scenario's split_fractions came out as 0.9 / 1.714 / 0, and the landfills kept 0.344 / 0.656 / 0. Mexico City (2.3%) gave 0.9 / 38.48 / 0, also with no change. The same no-op held for all 7 cities in the June table where the slider is live (0 < share < 99%): Mexico City, Lahore, Santiago, Amman, Tegucigalpa, Cebu City, Tunis.

Root cause

  1. The new split never reached the landfills. LandfillWasteMassDF.create reads each landfill's fraction_of_waste. Only the if new_gas_pct > 0: block copied split_fractions there. WasteMAP's frontend offers this slider only to a city that already captures gas, and disables "new landfill with gas capture" for exactly those cities (useChartData.ts), so the two never ran together.
  2. The arithmetic scaled the wrong way. It set the capture share to existing_gas_pct, then multiplied the shares without capture by existing / original, scaling them up. With no capture to start from, it zeroed them. Combined with new_gas_pct, the inflated split failed its sum check, and that check built CustomError with one argument, so it raised TypeError (an API 500).

Fix

  • New _move_to_existing_gas_capture(split_fractions, existing_gas_pct) gives capture existing_gas_pct. The landfill and dumpsite without capture take the rest, 1 − existing_gas_pct, in the proportions they had.
  • The move_gas block applies that split to landfills[0..2].fraction_of_waste. As with every lever, years before the implementation year are still copied from the baseline.
  • A request the lever can't carry out raises INVALID_PARAMETERS (400 at the API) instead of silently returning the no-change scenario:
    • a share outside [0, 1];
    • a share above 0 for a city with no gas capture (the UI doesn't offer the lever there);
    • less than 100% for a city that sends everything to capture (the UI disables the slider for those 41 cities and sends 100%, which leaves the split as it is).
  • The new-landfill sum check builds CustomError("INVALID_PARAMETERS", …).

Model output (model-output-change)

2040 emissions against the no-change scenario, on the June table:

City Share to capture → 0% → 50% → 90% → 100%
Lahore 34.4% +28% −13% −45% −53%
Mexico City 2.3% +1.1% −23% −43% −48%
Cebu City 40% +24% −5.9% −30% −36%
Amman 90% +44% +20% 0% −4.9%
Tegucigalpa 94.7% +76% +36% +3.7% −4.2%
Tunis 95.9% +47% +22% +2.9% −2.0%
Santiago 98.8% +96% +47% +8.5% −1.2%

Before the fix every cell was 0%.

Unchanged, bit for bit: the no-change scenario and every request with move_gas=0 (all other levers), plus all 41 cities at 100% for everything the UI sends.

Visible side effect in WasteMAP: an untouched slider sends the city's share rounded to a whole percent. So Lahore's default scenario now sits 0.35% above its baseline in 2040, Tegucigalpa's 0.25% below, and Santiago, Mexico City and Tunis move less than 0.2%. The diversion sliders already round the same way: Mexico City's untouched scenario was 0.72% below its baseline before this fix.

Fixed separately: "Add gas capture" loses its oxidation settings

In the same generic branch, add_gas sets oxidation to 0.22 for the landfill without capture and 0.1 for the converted dumpsite after the implementation year, and an override at the end of the method reset both to the no-capture defaults. That is fixed in #78 (with RMI/WasteMAP#856), so the Known limitations entry this PR added to changelog/2026-10.md has been dropped (f69fdac).

Tests

tests/test_move_to_existing_gas_capture.py: 16 tests. They build a city from country defaults (dst_baseline_blank) with a 30/50/20 split and run the real implement_dst_changes_simple_v1_5, with no database.

  • 15 of 16 fail on main, each on the defect: no emissions change, the landfills keep the baseline split, Lahore's split comes out 0.9 / 1.714 / 0, TypeError with new_gas_pct, and no error for impossible requests.
  • The one that passes on main is the guard that a city's own share reproduces the no-change scenario.
  • Also pinned: the moved waste is reallocated, not created or lost. From the implementation year each landfill's mass is the no-change mass × new share / old share, and the total landfilled each year is unchanged.
  • Full suite: 288 passed.

The WasteMAP side, RMI/WasteMAP#854 (same branch name, so its CI installs this branch), adds an endpoint test on Lahore's real table row through load_city. Two of its four tests fail against main here. Merge this PR first. WasteMAP CI falls back to SWEET_python main once this branch is gone, so RMI/WasteMAP#854 is green on main only after this lands.

Acceptance criteria

  • move_gas=1 with a share different from the city's own changes emissions from the year after implementation, and never before it.
  • Capture gets exactly existing_gas_pct. The landfill and dumpsite without capture share the rest in their original proportions, and the split sums to 1.
  • Moving waste conserves mass: per-year landfilled totals match the no-change scenario.
  • A city's own share, move_gas=0, and the 41 cities at 100% give the same results as before.
  • Impossible requests return INVALID_PARAMETERS rather than a silent no-op or a 500.
  • Changelog entry (changelog/2026-10.md), cross-linked with WasteMAP's backend changelog.

Definition of done

  • Acceptance criteria met
  • Tests and checks pass (SWEET_python: 288 passed; WasteMAP tests/fast against this branch: 580 passed, 1 skipped)
  • Docs updated (both changelogs)
  • Reviewed and merged (before RMI/WasteMAP#854)

🤖 Generated with Claude Code

The City DST's "move waste to existing gas capture" lever (move_gas and
existing_gas_pct in implement_dst_changes_simple_v1_5) rewrote split_fractions
in the generic branch but never passed the split to the landfills, whose waste
comes from their own fraction_of_waste. Only the new-landfill-with-capture block
did that, and WasteMAP switches that lever off for every city it offers this one
to. So the slider returned the no-change scenario at every setting for all 7
cities in the June 2026 table where it is live.

The arithmetic was wrong too: it multiplied the shares without capture by
existing / original, scaling them up (Lahore's landfill without capture came out
at 171% of its waste) and zeroing them for a city with no capture.

_move_to_existing_gas_capture gives capture existing_gas_pct and the landfill
and dumpsite without capture the rest, in their original proportions, and the
scenario applies that split to the landfills. A request the lever can't carry
out raises INVALID_PARAMETERS. The new-landfill sum check now builds CustomError
with both arguments; it raised TypeError, a 500 at the API.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@HughRunyan HughRunyan added bug Something isn't working model-output-change Changes model OUTPUT values (expected progress, not breaking); results differ from prior runs test Adds or modifies tests labels Oct 8, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
"Add gas capture" losing the oxidation it sets is fixed in #78 (with
RMI/WasteMAP#856), so this changelog no longer lists it as a known limitation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working model-output-change Changes model OUTPUT values (expected progress, not breaking); results differ from prior runs test Adds or modifies tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant