Skip to content

A Custom Location buries or dumps its waste in every country - #74

Open
HughRunyan wants to merge 2 commits into
mainfrom
custom-location-disposes-of-waste-in-every-country
Open

HughRunyan wants to merge 2 commits into
mainfrom
custom-location-disposes-of-waste-in-every-country

Conversation

@HughRunyan

@HughRunyan HughRunyan commented Oct 8, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

In 31 countries, a WasteMAP Custom Location city modelled no landfill methane at all. City.dst_baseline_blank gave those countries a disposal split of (0, 0, 0), so every landfill took 0% of the waste. Custom Location now gets the split the cities table already gives a city with no landfill data.

Affected (ISO3): ATF BGD BRN BTN BWA CAN CHE DEU IDN IND IOT IRN KHM LAO LKA LSO MDV MMR MOZ MYS NAM NPL PAK PHL SHN SWZ THA TLS VNM ZAF ZWE

Environment

  • SWEET_python main @ d5c592e, Python 3.12 (CI) / 3.13 (local)
  • Component: City.dst_baseline_blank, which WasteMAP calls for any city not in the cities table (the frontend's "Custom Location") from /v1/city_emissions/city_baseline_parameters_v1_5 and /v1/city_emissions/implement_dst_simple_v1_5
  • Seen on prod: api.wastemap.earth, 2026-08-21 build, checked 2026-10-08

Reproduction

python -c "from SWEET_python.city_params import City; c = City('x'); c.dst_baseline_blank('Pakistan', 2_000_000, 500.0, 25.0); print(c.baseline_parameters.split_fractions, c.baseline_parameters.total_emissions.loc[2040, 'total'])"

At the API (a read-only GET):

curl -sG https://api.wastemap.earth/v1/city_emissions/city_baseline_parameters_v1_5 --data-urlencode "city_name=Custom Location" --data-urlencode country=Pakistan --data-urlencode population=2000000 --data-urlencode precipitation=500 --data-urlencode temperature=25

Expected vs actual

2040 total emissions, t CH4/yr, for 2M people, 500 mm, 25 °C:

Country Prod today main (actual) This branch (expected) Split on this branch
Pakistan 0.0 0.0 21,156 all dumpsite
Philippines 0.0 0.0 10,513 all dumpsite
India 0.0 0.0 5,284 all dumpsite
Indonesia 0.0 0.0 31,277 all dumpsite
South Africa 0.0 0.0 33,478 all dumpsite
Germany 34 26 (compost only) 29,521 all landfill
Canada 45 40 (compost only) 74,846 all landfill
Switzerland 43 36 (compost only) 17,263 all landfill
Mexico (control) 29,897 28,745 28,745 (unchanged) all landfill

Prod runs an older build (before #71's population growth), which is why its Mexico figure differs from main.

Root cause

It is not a region-label mismatch. Every other regional table (msw_per_capita_defaults, waste_fraction_defaults, fraction_incinerated, fraction_composted, fraction_unspecified) uses exactly the labels in region_lookup_iso3. The two disposal tables have no extra or misspelled keys. Two data gaps meet a lookup that hides them:

  1. Southern Asia, South-Eastern Asia and Southern Africa have no row in fraction_open_dumped / fraction_landfilled. The other tables carry them as 0.0 # np.nan. That is the same gap wp-264 fixed central asia default for afghanistan #18 (WP-264) filled for Central Asia and Rest of Oceania. None of the 28 countries here has a country row; Singapore and Madagascar, which do, were unaffected.
  2. Canada's, Germany's and Switzerland's country rows are all zeros. Canada's waste sits in "unspecified" (0.88).

dst_baseline_blank read both tables with .get(iso3, .get(region, 0)). The normalization step skipped a zero total, so the waste the city didn't divert left the model. Its except KeyError fallback was unreachable, because .get never raises. The code has been like this since the initial commit.

City.load_andre_params, which builds the cities table, handles both gaps. It checks with in and falls back to all landfill in landfill_default_regions, all dumpsite elsewhere, and it hard-codes CAN/CHE/DEU to all landfill. So a Custom Location in Pakistan disagreed with an equivalent mapped city in Pakistan.

Fix

  • New defaults_2019.disposal_split_for(iso3, region), next to the tables it reads (as waste_composition_for is). It uses the country's row if it sends waste anywhere, else the region's. A place with neither is all landfill in landfill_default_regions and all dumpsite elsewhere. CAN/CHE/DEU fall through to their regions' rows, which are landfill-only. That reproduces load_andre_params's hard-coded override without a second copy of the list.
  • dst_baseline_blank calls it. The dead try/except and the now-redundant normalization are removed.
  • load_andre_params is deliberately untouched. It publishes landfill_split_defaults as the cities table's "Defaults Used: Landfill Fractions" column, and switching it to the helper would flip that flag for CAN/CHE/DEU. Adding the three regions to the data tables, as wp-264 fixed central asia default for afghanistan #18 did, would flip it for every city in them. Either is a published-output change, so this PR leaves the table alone, and a parity test keeps the two paths from drifting.

Blast radius

I ran Custom Location for all 250 ISO3 codes in region_lookup_iso3 on main and on this branch:

  • Exactly the 31 change.
  • The other 218 are bit-identical: same split, and DataFrame.equals on the emissions frame.
  • Kosovo (XKX) raises Country 'XKX' not found on both, because pycountry has no Kosovo. That is a separate issue.

No other SWEET path reads these tables. In WasteMAP, the endpoint's no_landfills_present (dumpsite == 1.0) becomes true for the 28 dump-only countries. The City DST then disables "Add gas capture" for them, as it does for any city with only dumpsites.

Tests (tests/test_custom_location_disposal_split.py, ~3 s)

On main, all 38 tests on the reported behaviour fail. The all-countries helper check also fails, trivially, because the helper doesn't exist there. On this branch they all pass.

Test What it checks On main
test_a_custom_location_models_methane_from_the_waste_it_disposes_of All 31: landfill shares sum to 1 and landfill methane in 2040 > 0. It asserts landfill methane, not the total, because Germany's total was already 26 t from compost. 31/31 fail
test_a_country_in_a_region_with_no_row_dumps_its_waste PAK/PHL/ZAF are all dumpsite 3/3 fail
test_a_country_whose_row_is_all_zeros_landfills_its_waste CAN/CHE/DEU are all landfill 3/3 fail
test_a_custom_location_starts_from_the_cities_tables_split Parity with load_andre_params on a no-data row, one country per (region × which row decides): 39 cases 6 fail (BGD, BRN, ATF, CAN, CHE, DEU); 33 pass
test_every_country_has_a_disposal_split The helper gives a valid split for all 250 codes fails (helper doesn't exist)

The 33 parity cases that pass on both are the evidence that nothing else moves. The full suite has 349 passed (272 before).

Known limitations (in the changelog)

  • The three regions fall back to all dumpsite. That is the same placeholder wp-264 fixed central asia default for afghanistan #18 used for Central Asia, and the one the cities table already uses. It is coarse for countries that landfill most of their waste, South Africa among them. A real regional default is a methodology change for the cities table too, so it wants its own ticket. @rosewangrmi raised the same question on wp-264 fixed central asia default for afghanistan #18.
  • Germany and Switzerland now landfill everything they don't compost or burn. Their "unspecified" share holds recycling, which Custom Location doesn't default. Japan, Austria, the Netherlands and Sweden were already treated this way. Before this change the residual simply vanished, which only looked realistic.
  • Sri Lanka gives the highest figure of the 31: 122,745 t. Its msw_per_capita_country default is 1.86 t/yr, which is 5.1 kg/person/day. Fourteen countries there are above 3 kg/person/day. That is a separate data issue.

Acceptance criteria

  • A Custom Location in each of the 31 countries sends all its disposed waste to a landfill or dumpsite and models landfill methane.
  • The split matches what the cities table gives a city with no landfill data in that country.
  • Every other country's Custom Location output is unchanged.
  • The cities table (load_andre_params) is unchanged.
  • Changelog entry, labelled bug + model-output-change.

Definition of Done

  • Acceptance criteria met
  • Tests & checks pass (CI)
  • Docs updated (changelog/2026-10.md)
  • Reviewed & merged. Merge this before RMI/WasteMAP#853 (endpoint test + backend changelog): WasteMAP's CI installs the same-named branch until then and SWEET main after, and prod picks the fix up from main on its next API deploy.

🤖 Generated with Claude Code

City.dst_baseline_blank looked a country's disposal split up with
.get(iso3, .get(region, 0)). Southern Asia, South-Eastern Asia and
Southern Africa have no row in fraction_open_dumped / fraction_landfilled
(no label mismatch: the other regional tables carry them as 0.0 # np.nan),
and Canada's, Germany's and Switzerland's country rows are all zeros, so
31 countries got a (0, 0, 0) split. Every landfill took 0% of the waste
and the city modelled no landfill methane; the except-KeyError fallback
never ran because .get never raises.

defaults_2019.disposal_split_for gives the split load_andre_params gives
a cities-table row with no landfill data: the country's row if it sends
waste anywhere, else the region's, else all landfill in
landfill_default_regions and all dumpsite elsewhere. load_andre_params is
unchanged, so the cities table doesn't move; the other 218 countries'
Custom Location output is bit-identical.

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 labels Oct 8, 2026
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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant