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
15 changes: 14 additions & 1 deletion SWEET_python/city_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -4938,7 +4938,12 @@ def _calculate_diverted_masses(self, scenario: int = 0) -> None:
parameters.divs = divs

def dst_baseline_blank(
self, country: str, population: int, precipitation: float, temperature: float
self,
country: str,
population: int,
precipitation: float,
temperature: float,
population_series: Optional[pd.Series] = None,
) -> None:
"""
Initializes the baseline scenario with given parameters for a blank/custom city.
Expand All @@ -4947,6 +4952,10 @@ def dst_baseline_blank(
country (str): The country name.
population (int): Population of the city.
precipitation (float): Average annual precipitation in mm/year.
population_series (pd.Series): the country's population by year, worked
out once by country_population_trajectory and stored. The city's waste
grows along it instead of along SWEET's own table. Only its shape
counts: the city's waste is set by ``population``.

Returns:
None
Expand Down Expand Up @@ -5121,9 +5130,13 @@ def calculate_component_fractions(
waste_masses_df = waste_fractions_df * waste_mass
# The country's population, year by year. The constants above are one rate for
# every country; they stand only for a country SWEET has no series for.
stored_series = population_series
population_series, growth_rate_historic, growth_rate_future = _country_growth(
iso3, year_of_data_pop, growth_rate_historic, growth_rate_future
)
if stored_series is not None:
# The two rates stay the ones a person reads; the stored series is the growth.
population_series = stored_series
waste_generated_df = WasteGeneratedDF.create(
waste_masses_df,
MODEL_START_YEAR,
Expand Down
11 changes: 11 additions & 0 deletions changelog/2026-10.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,17 @@ or 9% above the default (model-output change).
No other number moves. ([#91](https://github.com/RMI/SWEET_python/pull/91),
[RMI/WasteMAP#888](https://github.com/RMI/WasteMAP/pull/888))

- **A Custom Location can grow along a stored country trajectory.**
`City.dst_baseline_blank` takes `population_series`, as `load_csv_new` does: the
country's population by year from `country_population_trajectory`, stored with
WasteMAP's map build. The Custom Location's waste, and its scenario's, grow along
it instead of along SWEET's own table; the city's tonnage still comes from the
population it is given, and the two growth rates a person reads are still the
country's. Without it nothing changes. Handed the country's own trajectory, a
Custom Location grows as before, to within 5.9e-16 in every country, and the 12
with fallback rates exactly. ([#94](https://github.com/RMI/SWEET_python/pull/94),
[RMI/WasteMAP#890](https://github.com/RMI/WasteMAP/pull/890))

- **Seven more Climate TRACE modelling decisions are marked where SWEET applies them**:
waste before 1970 counted as zero, a site's last intake in the year before it closes,
intake following population, the decay rate from climate, each waste type's methane
Expand Down
61 changes: 61 additions & 0 deletions tests/test_population_trajectory.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,3 +137,64 @@ def test_load_csv_new_grows_a_city_along_the_trajectory_it_is_handed():
worked_out.growth_rate_historic,
worked_out.growth_rate_future,
)


def _custom_location(country, population_series=None):
"""A Custom Location, as WasteMAP's city DST builds one."""
city = City("custom")
city.dst_baseline_blank(country, 100_000, 800.0, 15.0, population_series=population_series)
return city


def test_a_custom_location_grows_along_the_country_trajectory_it_is_handed():
stored, _ = country_population_trajectory("USA")
flat = pd.Series(331_000_000.0, index=YEARS)

worked_out, along_stored, along_flat = (
_custom_location("United States", series).baseline_parameters
for series in (None, stored, flat)
)

waste = lambda p: p.waste_generated_df.sum(axis=1) # noqa: E731
np.testing.assert_allclose(waste(along_stored), waste(worked_out), rtol=1e-14)
np.testing.assert_allclose(
(waste(along_stored) / waste(along_stored).loc[2022]).loc[YEARS],
stored / stored.loc[city_params.CUSTOM_LOCATION_POPULATION_YEAR],
rtol=1e-14,
)
# Only the shape counts: the waste is the caller's population's, in every case.
assert waste(along_flat).loc[2022] == waste(worked_out).loc[2022]
assert waste(along_flat).loc[2050] == pytest.approx(waste(along_flat).loc[2022], rel=1e-12)
assert waste(along_flat).loc[2050] != pytest.approx(waste(worked_out).loc[2050], rel=1e-3)
# The two rates a person reads are still the country's.
assert (along_flat.growth_rate_historic, along_flat.growth_rate_future) == (
worked_out.growth_rate_historic,
worked_out.growth_rate_future,
)


def test_a_custom_location_with_its_fallback_trajectory_is_unchanged():
stored, source = country_population_trajectory("ATA")
assert source == city_params.COUNTRY_FALLBACK_RATES

worked_out = _custom_location("Antarctica").baseline_parameters
along_stored = _custom_location("Antarctica", stored).baseline_parameters

pd.testing.assert_frame_equal(along_stored.waste_generated_df, worked_out.waste_generated_df)
assert (along_stored.growth_rate_historic, along_stored.growth_rate_future) == (
city_params.FALLBACK_GROWTH_RATE_HISTORIC,
city_params.FALLBACK_GROWTH_RATE_FUTURE,
)


def test_a_custom_location_scenario_grows_along_the_trajectory_it_is_handed():
flat = pd.Series(331_000_000.0, index=YEARS)
city = _custom_location("United States", flat)
for landfill in city.baseline_parameters.landfills:
landfill.estimate_emissions()

divs = city_params.DiversionFractions(compost=0.1, anaerobic=0.0, combustion=0.0, recycling=0.1)
city.implement_dst_changes_simple_v1_5(divs, False, False, 0.0, 0.0, 2030, 1, 0.0)
waste = city.scenario_parameters[0].waste_generated_df.df.sum(axis=1)

assert waste.loc[2050] == pytest.approx(waste.loc[2030], rel=1e-12)
Loading