diff --git a/docs/application-flow.rst b/docs/application-flow.rst index f25c24645..883b7c5a4 100644 --- a/docs/application-flow.rst +++ b/docs/application-flow.rst @@ -414,7 +414,7 @@ This deeper level of the process is where most of the input options of MUSE are Investment ~~~~~~~~~~ -In the investment step is where new capacity is added to the different assets managed by the agents. This investment might be needed to cover an increase in demand (between now and forecast) or to match decommissioned assets, typically to do both. +In the investment step is where new capacity is added to the different assets managed by the agents. This investment might be needed to cover an increase in demand (between now and the investment year) or to match decommissioned assets, typically to do both. The following graph summarises the process. @@ -455,8 +455,8 @@ The following graph summarises the process. First the demand is distributed among the available agents as requested by the ``demand_share`` argument of each ``subsector`` in the ``settings.toml`` file. This distribution can be done based on any attribute or property of the agents, as included in the ``Agents.csv`` file. Demand can also be shared across multiple agents, depending on the "quantity" attribute (defined in ``Agents.csv``). The two built-in options in MUSE are: -- `standard_demand` (default): The demand is split only amongst *new* agents (indeed there will be an error if a *retro* agent is found for this subsector). *New* agents get a share of the increase in demand for the forecast years well as the demand that occurs from decommissioned assets. -- `new_and_retro`: The input demand is split amongst both *new* and *retro* agents. *New* agents get a share of the increase in demand for the forecast year, whereas *retrofit* agents are assigned a share of the demand that occurs from decommissioned assets. +- `standard_demand` (default): The demand is split only amongst *new* agents (indeed there will be an error if a *retro* agent is found for this subsector). *New* agents get a share of the increase in demand over the investment period as well as the demand that occurs from decommissioned assets. +- `new_and_retro`: The input demand is split amongst both *new* and *retro* agents. *New* agents get a share of the increase in demand for the investment period, whereas *retrofit* agents are assigned a share of the demand that occurs from decommissioned assets. Then, each agent select the technologies it can invest in based on what is needed and the **search rules** defined for it in the ``Agents.csv`` file. The possible search rules are described in :py:mod:`muse.filters`. These determine the search rules for each replacement technology. diff --git a/docs/inputs/toml.rst b/docs/inputs/toml.rst index a72d29c09..72d60f090 100644 --- a/docs/inputs/toml.rst +++ b/docs/inputs/toml.rst @@ -455,11 +455,11 @@ Sectors contain a number of subsections: - :py:func:`~muse.demand_share.standard_demand` (default): The input demand is split amongst *new* agents. *New* agents get a share of the increase in demand - for the forecast years, as well as the demand that occurs from decommissioned + over the investment period, as well as the demand that occurs from decommissioned assets. - :py:func:`~muse.demand_share.new_and_retro`: The input demand is split amongst both *new* and *retrofit* agents. *New* agents get a share of the increase in - demand for the forecast year, whereas *retrofit* agents are assigned a share + demand over the investment period, whereas *retrofit* agents are assigned a share of the demand that occurs from decommissioned assets. *constraints* @@ -577,7 +577,6 @@ function of macro-economic data, i.e. population and gdp. macrodrivers_path = '{path}/technodata/Macrodrivers.csv' regression_path = '{path}/technodata/regressionparameters.csv' timeslices_levels = {'day': ['all-day']} - forecast = [0, 5] The following attributes are accepted: diff --git a/docs/tutorial-code/add-agent/1-single-objective/settings.toml b/docs/tutorial-code/add-agent/1-single-objective/settings.toml index f1324fdd7..54fa58505 100644 --- a/docs/tutorial-code/add-agent/1-single-objective/settings.toml +++ b/docs/tutorial-code/add-agent/1-single-objective/settings.toml @@ -51,7 +51,6 @@ constraints = [ "demand_limiting_capacity" ] demand_share = "standard_demand" # Optional, default to standard_demand -forecast = 5 # Optional, defaults to 5 [sectors.power] type = 'default' diff --git a/docs/tutorial-code/add-agent/2-multiple-objective/settings.toml b/docs/tutorial-code/add-agent/2-multiple-objective/settings.toml index f1324fdd7..54fa58505 100644 --- a/docs/tutorial-code/add-agent/2-multiple-objective/settings.toml +++ b/docs/tutorial-code/add-agent/2-multiple-objective/settings.toml @@ -51,7 +51,6 @@ constraints = [ "demand_limiting_capacity" ] demand_share = "standard_demand" # Optional, default to standard_demand -forecast = 5 # Optional, defaults to 5 [sectors.power] type = 'default' diff --git a/docs/tutorial-code/add-correlation-demand/1-correlation/settings.toml b/docs/tutorial-code/add-correlation-demand/1-correlation/settings.toml index cc21586fa..ab6609bda 100644 --- a/docs/tutorial-code/add-correlation-demand/1-correlation/settings.toml +++ b/docs/tutorial-code/add-correlation-demand/1-correlation/settings.toml @@ -51,7 +51,6 @@ constraints = [ "demand_limiting_capacity" ] demand_share = "standard_demand" # Optional, default to standard_demand -forecast = 5 # Optional, defaults to 5 [sectors.power] type = 'default' diff --git a/docs/tutorial-code/add-new-technology/1-introduction/settings.toml b/docs/tutorial-code/add-new-technology/1-introduction/settings.toml index 5350c198b..b4fd25519 100644 --- a/docs/tutorial-code/add-new-technology/1-introduction/settings.toml +++ b/docs/tutorial-code/add-new-technology/1-introduction/settings.toml @@ -51,7 +51,6 @@ constraints = [ "demand_limiting_capacity" ] demand_share = "standard_demand" # Optional, default to standard_demand -forecast = 5 # Optional, defaults to 5 [sectors.power] type = 'default' diff --git a/docs/tutorial-code/add-new-technology/2-scenario/settings.toml b/docs/tutorial-code/add-new-technology/2-scenario/settings.toml index 5350c198b..b4fd25519 100644 --- a/docs/tutorial-code/add-new-technology/2-scenario/settings.toml +++ b/docs/tutorial-code/add-new-technology/2-scenario/settings.toml @@ -51,7 +51,6 @@ constraints = [ "demand_limiting_capacity" ] demand_share = "standard_demand" # Optional, default to standard_demand -forecast = 5 # Optional, defaults to 5 [sectors.power] type = 'default' diff --git a/docs/tutorial-code/add-region/1-new-region/settings.toml b/docs/tutorial-code/add-region/1-new-region/settings.toml index edcf9888a..02e69b641 100644 --- a/docs/tutorial-code/add-region/1-new-region/settings.toml +++ b/docs/tutorial-code/add-region/1-new-region/settings.toml @@ -51,7 +51,6 @@ constraints = [ "demand_limiting_capacity" ] demand_share = "standard_demand" # Optional, default to standard_demand -forecast = 5 # Optional, defaults to 5 [sectors.power] type = 'default' diff --git a/docs/tutorial-code/add-service-demand/1-exogenous-demand/settings.toml b/docs/tutorial-code/add-service-demand/1-exogenous-demand/settings.toml index f1324fdd7..54fa58505 100644 --- a/docs/tutorial-code/add-service-demand/1-exogenous-demand/settings.toml +++ b/docs/tutorial-code/add-service-demand/1-exogenous-demand/settings.toml @@ -51,7 +51,6 @@ constraints = [ "demand_limiting_capacity" ] demand_share = "standard_demand" # Optional, default to standard_demand -forecast = 5 # Optional, defaults to 5 [sectors.power] type = 'default' diff --git a/docs/tutorial-code/carbon-budget/1-carbon-budget/settings.toml b/docs/tutorial-code/carbon-budget/1-carbon-budget/settings.toml index 0ea705c9d..14c898b90 100644 --- a/docs/tutorial-code/carbon-budget/1-carbon-budget/settings.toml +++ b/docs/tutorial-code/carbon-budget/1-carbon-budget/settings.toml @@ -64,7 +64,6 @@ constraints = [ "demand_limiting_capacity" ] demand_share = "standard_demand" # Optional, default to standard_demand -forecast = 5 # Optional, defaults to 5 [sectors.power] type = 'default' diff --git a/docs/tutorial-code/min-max-timeslice-constraints/1-min-constraint/settings.toml b/docs/tutorial-code/min-max-timeslice-constraints/1-min-constraint/settings.toml index ba89aa072..f87bc8366 100644 --- a/docs/tutorial-code/min-max-timeslice-constraints/1-min-constraint/settings.toml +++ b/docs/tutorial-code/min-max-timeslice-constraints/1-min-constraint/settings.toml @@ -51,7 +51,6 @@ constraints = [ "demand_limiting_capacity" ] demand_share = "standard_demand" # Optional, default to standard_demand -forecast = 5 # Optional, defaults to 5 [sectors.power] type = 'default' diff --git a/docs/tutorial-code/min-max-timeslice-constraints/2-max-constraint/settings.toml b/docs/tutorial-code/min-max-timeslice-constraints/2-max-constraint/settings.toml index ba89aa072..f87bc8366 100644 --- a/docs/tutorial-code/min-max-timeslice-constraints/2-max-constraint/settings.toml +++ b/docs/tutorial-code/min-max-timeslice-constraints/2-max-constraint/settings.toml @@ -51,7 +51,6 @@ constraints = [ "demand_limiting_capacity" ] demand_share = "standard_demand" # Optional, default to standard_demand -forecast = 5 # Optional, defaults to 5 [sectors.power] type = 'default' diff --git a/docs/tutorial-code/modify-timing-data/1-modify-timeslices/settings.toml b/docs/tutorial-code/modify-timing-data/1-modify-timeslices/settings.toml index a0618f0e4..ffcde735c 100644 --- a/docs/tutorial-code/modify-timing-data/1-modify-timeslices/settings.toml +++ b/docs/tutorial-code/modify-timing-data/1-modify-timeslices/settings.toml @@ -51,7 +51,6 @@ constraints = [ "demand_limiting_capacity" ] demand_share = "standard_demand" # Optional, default to standard_demand -forecast = 5 # Optional, defaults to 5 [sectors.power] type = 'default' diff --git a/docs/tutorial-code/modify-timing-data/2-modify-time-framework/settings.toml b/docs/tutorial-code/modify-timing-data/2-modify-time-framework/settings.toml index 0c426b50d..71bbc5523 100644 --- a/docs/tutorial-code/modify-timing-data/2-modify-time-framework/settings.toml +++ b/docs/tutorial-code/modify-timing-data/2-modify-time-framework/settings.toml @@ -51,7 +51,6 @@ constraints = [ "demand_limiting_capacity" ] demand_share = "standard_demand" # Optional, default to standard_demand -forecast = 2 # Optional, defaults to 5 [sectors.power] type = 'default' @@ -66,7 +65,6 @@ agents = '{path}/technodata/Agents.csv' existing_capacity = '{path}/technodata/power/ExistingCapacity.csv' lpsolver = "scipy" demand_share = "standard_demand" -forecast = 2 [sectors.gas] type = 'default' @@ -81,7 +79,6 @@ agents = '{path}/technodata/Agents.csv' existing_capacity = '{path}/technodata/gas/ExistingCapacity.csv' lpsolver = "scipy" demand_share = "standard_demand" -forecast = 2 [sectors.residential_presets] type = 'presets' diff --git a/docs/tutorial-code/modify-timing-data/generate_models.py b/docs/tutorial-code/modify-timing-data/generate_models.py index 5da0d313d..172735c9b 100644 --- a/docs/tutorial-code/modify-timing-data/generate_models.py +++ b/docs/tutorial-code/modify-timing-data/generate_models.py @@ -6,7 +6,7 @@ from tomlkit import dumps, parse from muse import examples -from muse.wizard import add_timeslice, get_sectors, modify_toml +from muse.wizard import add_timeslice, modify_toml parent_path = Path(__file__).parent @@ -80,11 +80,6 @@ def generate_model_2(): settings_file = model_path / "settings.toml" time_framework = [2020, 2022, 2024, 2026, 2028, 2030, 2032, 2034, 2036, 2038, 2040] modify_toml(settings_file, lambda x: x.update({"time_framework": time_framework})) - for sector in get_sectors(model_path): - modify_toml( - settings_file, - lambda x: x["sectors"][sector]["subsectors"]["all"].update({"forecast": 2}), - ) if __name__ == "__main__": diff --git a/docs/tutorial-code/new-decision-metric/settings.toml b/docs/tutorial-code/new-decision-metric/settings.toml index 38031f5c6..05c316389 100644 --- a/docs/tutorial-code/new-decision-metric/settings.toml +++ b/docs/tutorial-code/new-decision-metric/settings.toml @@ -49,7 +49,6 @@ constraints = [ "search_space" ] demand_share = "standard_demand" # Optional, default to standard_demand -forecast = 5 # Optional, defaults to 5 [sectors.power] type = 'default' diff --git a/docs/user-guide/modify-timing-data.ipynb b/docs/user-guide/modify-timing-data.ipynb index 100bfdeff..6c619a10e 100644 --- a/docs/user-guide/modify-timing-data.ipynb +++ b/docs/user-guide/modify-timing-data.ipynb @@ -149,21 +149,6 @@ "```" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We also have to modity the `forecast` value for each sector. For example, for the power sector the `sectors.power.subsectors.all` section should now look as follows:\n", - "\n", - "```toml\n", - "[sectors.power.subsectors.all]\n", - "agents = '{path}/technodata/Agents.csv'\n", - "existing_capacity = '{path}/technodata/power/ExistingCapacity.csv'\n", - "lpsolver = \"scipy\"\n", - "forecast = 2\n", - "```" - ] - }, { "cell_type": "markdown", "metadata": {}, diff --git a/src/muse/agents/agent.py b/src/muse/agents/agent.py index d02f074e3..eddc6600e 100644 --- a/src/muse/agents/agent.py +++ b/src/muse/agents/agent.py @@ -113,7 +113,6 @@ def __init__( decision: Callable | None = None, year: int = 2010, maturity_threshold: float = 0, - forecast: int = 5, housekeeping: Callable | None = None, merge_transform: Callable | None = None, demand_threshold: float | None = None, @@ -137,7 +136,6 @@ def __init__( year: year the agent is created / current year maturity_threshold: threshold when filtering replacement technologies with respect to market share - forecast: Number of years the agent will forecast housekeeping: transform applied to the assets at the start of iteration. Defaults to doing nothing. merge_transform: transform merging current and newly invested assets @@ -170,9 +168,6 @@ def __init__( """ Current year. Incremented by one every time next is called.""" self.year = year - """Number of years to look into the future for forecating purposed.""" - self.forecast = forecast - """Search rule(s) determining potential replacement technologies. This is a string referring to a filter, or a sequence of strings @@ -234,11 +229,6 @@ def __init__( """Threshold below which assets are not added.""" self.asset_threshold = asset_threshold - @property - def forecast_year(self): - """Year to consider when forecasting.""" - return self.year + self.forecast - def asset_housekeeping(self): """Reduces memory footprint of assets. diff --git a/src/muse/carbon_budget.py b/src/muse/carbon_budget.py index a0d578a5a..313353581 100644 --- a/src/muse/carbon_budget.py +++ b/src/muse/carbon_budget.py @@ -334,7 +334,7 @@ def bisection( # Create cache for emissions at different price points emissions_cache = EmissionsCache(market, equilibrium, commodities) - # Carbon price and emissions threshold in the forecast year + # Carbon price and emissions threshold in the investment year future = market.year[-1] target = carbon_budget.sel(year=future).values.item() price = market.prices.sel(year=future, commodity=commodities).mean().values.item() diff --git a/src/muse/data/example/default/settings.toml b/src/muse/data/example/default/settings.toml index f1324fdd7..54fa58505 100644 --- a/src/muse/data/example/default/settings.toml +++ b/src/muse/data/example/default/settings.toml @@ -51,7 +51,6 @@ constraints = [ "demand_limiting_capacity" ] demand_share = "standard_demand" # Optional, default to standard_demand -forecast = 5 # Optional, defaults to 5 [sectors.power] type = 'default' diff --git a/src/muse/data/example/default_retro/settings.toml b/src/muse/data/example/default_retro/settings.toml index 3790378e4..23eb00a41 100644 --- a/src/muse/data/example/default_retro/settings.toml +++ b/src/muse/data/example/default_retro/settings.toml @@ -51,7 +51,6 @@ constraints = [ "demand_limiting_capacity" ] demand_share = "new_and_retro" # Optional, default to standard_demand -forecast = 5 # Optional, defaults to 5 [[sectors.residential.interactions]] net = 'new_to_retro' diff --git a/src/muse/data/example/default_timeslice/settings.toml b/src/muse/data/example/default_timeslice/settings.toml index ba89aa072..f87bc8366 100644 --- a/src/muse/data/example/default_timeslice/settings.toml +++ b/src/muse/data/example/default_timeslice/settings.toml @@ -51,7 +51,6 @@ constraints = [ "demand_limiting_capacity" ] demand_share = "standard_demand" # Optional, default to standard_demand -forecast = 5 # Optional, defaults to 5 [sectors.power] type = 'default' diff --git a/src/muse/data/example/minimum_service/settings.toml b/src/muse/data/example/minimum_service/settings.toml index eec949de7..0f0cc7183 100644 --- a/src/muse/data/example/minimum_service/settings.toml +++ b/src/muse/data/example/minimum_service/settings.toml @@ -56,7 +56,6 @@ constraints = [ "demand_limiting_capacity" ] demand_share = "standard_demand" # Optional, default to standard_demand -forecast = 5 # Optional, defaults to 5 [sectors.industry_presets] type = 'presets' diff --git a/src/muse/data/example/trade/settings.toml b/src/muse/data/example/trade/settings.toml index 17a00af59..a812ea926 100644 --- a/src/muse/data/example/trade/settings.toml +++ b/src/muse/data/example/trade/settings.toml @@ -58,7 +58,6 @@ constraints = [ "demand_limiting_capacity" ] demand_share = "new_and_retro" -forecast = 5 asset_threshold = 1e-4 [[sectors.residential.interactions]] @@ -90,7 +89,6 @@ constraints = [ "demand_limiting_capacity" ] demand_share = "unmet_forecasted_demand" -forecast = 5 asset_threshold = 1e-4 [sectors.gas] @@ -118,7 +116,6 @@ constraints = [ "demand_limiting_capacity" ] demand_share = "unmet_forecasted_demand" -forecast = 5 asset_threshold = 1e-4 [timeslices] diff --git a/src/muse/readers/toml.py b/src/muse/readers/toml.py index 2c237fd06..2f88e892f 100644 --- a/src/muse/readers/toml.py +++ b/src/muse/readers/toml.py @@ -737,7 +737,7 @@ def read_technodata( technologies[name] = data # make sure technologies includes the requisite years - maxyear = getattr(settings, "forecast", 5) + max(time_framework) + maxyear = max(time_framework) if technologies.year.max() < maxyear: msg = "Forward-filling technodata to fit simulation timeframe" getLogger(__name__).info(msg) diff --git a/src/muse/sectors/preset_sector.py b/src/muse/sectors/preset_sector.py index 03bf20080..361105b81 100644 --- a/src/muse/sectors/preset_sector.py +++ b/src/muse/sectors/preset_sector.py @@ -143,29 +143,9 @@ def next(self, mca_market: Dataset) -> Dataset: consumption = self._interpolate(presets.consumption, mca_market.year) costs = self._interpolate(presets.costs, mca_market.year) - result = Dataset({"supply": supply, "consumption": consumption}) - result["costs"] = drop_timeslice(costs) + result = Dataset({"supply": supply, "consumption": consumption, "costs": costs}) assert isinstance(result, Dataset) return result def _interpolate(self, data: DataArray, years: DataArray) -> DataArray: - """Chooses interpolation depending on whether forecast is available.""" - if "forecast" in data.dims: - baseyear = int(years.min()) - forecasted = (years - baseyear).values - result = ( - data.interp( - year=baseyear, - method=self.interpolation_mode, - kwargs={"fill_value": "extrapolate"}, - ) - .interp( - forecast=forecasted, - method=self.interpolation_mode, - kwargs={"fill_value": "extrapolate"}, - ) - .drop_vars(("year", "forecast")) - ) - result["year"] = "forecast", years.values - return result.set_index(forecast="year").rename(forecast="year") return data.interp(year=years, method=self.interpolation_mode).ffill("year") diff --git a/src/muse/sectors/sector.py b/src/muse/sectors/sector.py index e7e4dee6d..00d2532a1 100644 --- a/src/muse/sectors/sector.py +++ b/src/muse/sectors/sector.py @@ -169,15 +169,6 @@ def __init__( """Full supply, consumption and costs data for the most recent year.""" self.output_data: xr.Dataset - @property - def forecast(self): - """Maximum forecast horizon across agents. - - It cannot be lower than 1 year. - """ - forecasts = [getattr(agent, "forecast") for agent in self.agents] - return max(1, max(forecasts)) - def next( self, mca_market: xr.Dataset, diff --git a/src/muse/sectors/subsector.py b/src/muse/sectors/subsector.py index 8e552a0a3..266e54a77 100644 --- a/src/muse/sectors/subsector.py +++ b/src/muse/sectors/subsector.py @@ -24,7 +24,6 @@ def __init__( constraints: Callable | None = None, investment: Callable | None = None, name: str = "subsector", - forecast: int = 5, expand_market_prices: bool = False, timeslice_level: str | None = None, ): @@ -37,7 +36,6 @@ def __init__( self.demand_share = demand_share or ds.factory() self.constraints = constraints or cs.factory() self.investment = investment or iv.factory() - self.forecast = forecast self.name = name self.expand_market_prices = expand_market_prices self.timeslice_level = timeslice_level @@ -133,6 +131,14 @@ def factory( ) getLogger(__name__).warning(msg) + # Raise warning if deprecated forecast parameter is used (PR #645) + if hasattr(settings, "forecast"): + msg = ( + "The 'forecast' parameter has been deprecated. " + "Please remove from your settings file." + ) + getLogger(__name__).warning(msg) + agents = agents_factory( settings.agents, settings.existing_capacity, @@ -142,7 +148,6 @@ def factory( asset_threshold=getattr(settings, "asset_threshold", 1e-12), # only used by self-investing agents investment=getattr(settings, "lpsolver", "scipy"), - forecast=getattr(settings, "forecast", 5), constraints=getattr(settings, "constraints", ()), timeslice_level=timeslice_level, ) @@ -181,7 +186,6 @@ def factory( constraints = cs.factory(getattr(settings, "constraints", None)) # only used by non-self-investing agents investment = iv.factory(getattr(settings, "lpsolver", "scipy")) - forecast = getattr(settings, "forecast", 5) expand_market_prices = getattr(settings, "expand_market_prices", None) if expand_market_prices is None: @@ -195,7 +199,6 @@ def factory( demand_share=demand_share, constraints=constraints, investment=investment, - forecast=forecast, name=name, expand_market_prices=expand_market_prices, timeslice_level=timeslice_level,