From c4c3e3cd84aec0a098d4bf2004ae794a557f48b0 Mon Sep 17 00:00:00 2001 From: romainsacchi Date: Thu, 17 Aug 2023 14:12:41 +0200 Subject: [PATCH] Fix lead time when consequential Fix inter year in fuels.py Version bump --- docs/consequential.rst | 4 +- premise/__init__.py | 2 +- premise/data/consequential/blacklist.yaml | 56 ++++++++++------------- premise/data/consequential/leadtimes.yaml | 14 ++++++ premise/data/consequential/lifetimes.yaml | 16 ++++++- premise/data_collection.py | 21 ++++++--- premise/electricity.py | 2 + premise/fuels.py | 4 +- premise/marginal_mixes.py | 27 +++++++---- setup.py | 2 +- 10 files changed, 95 insertions(+), 53 deletions(-) diff --git a/docs/consequential.rst b/docs/consequential.rst index 278ee049..fcdf217d 100644 --- a/docs/consequential.rst +++ b/docs/consequential.rst @@ -51,12 +51,14 @@ Range time Integer. Years. To measure the trend around the point where the additional capital will be installed, a range of n years before and after the point -is taken as the time interval. +is taken as the time interval. Note that if set to a value other than 0, +the duration argument must be set to 0. Duration ^^^^^^^^ Integer. Years. Duration over which the change in demand should be measured. +Note that if set to a value other than 0, the range time argument must be set to 0. Foresight ^^^^^^^^^ diff --git a/premise/__init__.py b/premise/__init__.py index 3e2cc16a..afc2a9f7 100644 --- a/premise/__init__.py +++ b/premise/__init__.py @@ -1,5 +1,5 @@ __all__ = ("NewDatabase", "clear_cache", "get_regions_definition") -__version__ = (1, 6, 1) +__version__ = (1, 6, 2) from pathlib import Path diff --git a/premise/data/consequential/blacklist.yaml b/premise/data/consequential/blacklist.yaml index 56d9f9db..1985a1fd 100644 --- a/premise/data/consequential/blacklist.yaml +++ b/premise/data/consequential/blacklist.yaml @@ -5,43 +5,19 @@ # if it is present, the activity is replaced by the activity # specified in the `replacement` field. --- -- name: electricity production, at co-generation power plant/hard coal, oxy, pipeline 200km, storage 1000m +- name: electricity production, at co-generation hard coal-fired power plant, post, pipeline 200km, storage 1000m reference product: electricity, high voltage unit: kilowatt hour -- name: electricity production, at co-generation power plant/hard coal, oxy, pipeline 400km, storage 3000m - reference product: electricity, high voltage - unit: kilowatt hour -- name: electricity production, at co-generation power plant/hard coal, post, pipeline 200km, storage 1000m - reference product: electricity, high voltage - unit: kilowatt hour -- name: electricity production, at co-generation power plant/hard coal, post, pipeline 400km, storage 1000m - reference product: electricity, high voltage - unit: kilowatt hour -- name: electricity production, at co-generation power plant/hard coal, post, pipeline 400km, storage 3000m - reference product: electricity, high voltage - unit: kilowatt hour -- name: electricity production, at co-generation power plant/hard coal, pre, pipeline 200km, storage 1000m - reference product: electricity, high voltage - unit: kilowatt hour -- name: electricity production, at co-generation power plant/hard coal, pre, pipeline 400km, storage 3000m - reference product: electricity, high voltage - unit: kilowatt hour -- name: electricity production, at co-generation power plant/wood, post, pipeline 200km, storage 1000m - reference product: electricity, high voltage - unit: kilowatt hour -- name: electricity production, at co-generation power plant/wood, post, pipeline 400km, storage 3000m - reference product: electricity, high voltage - unit: kilowatt hour -- name: electricity production, at co-generation power plant/natural gas, post, pipeline 200km, storage 1000m - reference product: electricity, high voltage - unit: kilowatt hour -- name: electricity production, at co-generation power plant/natural gas, pre, pipeline 200km, storage 1000m + +- name: electricity production, at co-generation wood-fired power plant, post, pipeline 200km, storage 1000m reference product: electricity, high voltage unit: kilowatt hour -- name: electricity production, at co-generation power plant/oil, post, pipeline 200km, storage 1000m + +- name: electricity production, at co-generation natural gas-fired power plant, post, pipeline 200km, storage 1000m reference product: electricity, high voltage unit: kilowatt hour -- name: electricity production, at co-generation power plant/oil, pre, pipeline 200km, storage 1000m + +- name: electricity production, at co-generation oil-fired power plant, post, pipeline 200km, storage 1000m reference product: electricity, high voltage unit: kilowatt hour @@ -117,6 +93,24 @@ reference product: heat, central or small-scale, other than natural gas location: CH +- name: heat and power co-generation, hard coal + reference product: electricity, high voltage + unit: kilowatt hour + location: DE + replacement: + name: electricity production, hard coal + reference product: electricity, high voltage + location: DE + +- name: heat and power co-generation, oil + reference product: electricity, high voltage + unit: kilowatt hour + location: DE + replacement: + name: electricity production, oil + reference product: electricity, high voltage + location: DE + - name: air separation, cryogenic reference product: nitrogen, liquid unit: kilogram diff --git a/premise/data/consequential/leadtimes.yaml b/premise/data/consequential/leadtimes.yaml index 80ab4665..d0107f0a 100644 --- a/premise/data/consequential/leadtimes.yaml +++ b/premise/data/consequential/leadtimes.yaml @@ -17,20 +17,26 @@ Gas CC: 3 Gas CC CCS: 3 Gas CHP: 3 Gas CHP CCS: 3 +Gas ST: 3 Oil ST: 3 Oil CC CCS: 3 Oil CC: 3 Oil CHP CCS: 3 Oil CHP: 3 +Foil ST: 3 Geothermal: 3 Hydro: 4 Hydrogen: 3 Nuclear: 7 +Nuclear_EPR: 7 +Nuclear_SMR: 7 Solar CSP: 3 +Solar CSP autonomous: 3 Solar PV Centralized: 2 Solar PV Residential: 2 Wind Onshore: 2 Wind Offshore: 3 +Wave: 3 diesel: 3 gasoline: 3 diesel, synthetic, from wood: 3 @@ -65,3 +71,11 @@ hydrogen, biomass, with CCS: 3 hydrogen, coal: 3 hydrogen, nat. gas: 3 hydrogen, nat. gas, with CCS: 3 +hydrogen, coal, with CCS: 3 +hydrogen, solar: 3 +cement, dry feed rotary kiln: 10 +steel - primary: 10 +steel - secondary: 10 +daccs_sorbent: 3 +biomass - residual: 3 +biomass crops - purpose grown: 3 diff --git a/premise/data/consequential/lifetimes.yaml b/premise/data/consequential/lifetimes.yaml index ae80f2f2..2eddf0d0 100644 --- a/premise/data/consequential/lifetimes.yaml +++ b/premise/data/consequential/lifetimes.yaml @@ -17,6 +17,7 @@ Gas CC: 35 Gas CC CCS: 35 Gas CHP: 35 Gas CHP CCS: 35 +Gas ST: 35 Oil ST: 25 Oil CC CCS: 25 Oil CC: 25 @@ -26,11 +27,16 @@ Geothermal: 30 Hydro: 130 Hydrogen: 35 Nuclear: 40 +Nuclear_EPR: 40 +Nuclear_SMR: 40 +Foil ST: 25 Solar CSP: 30 +Solar CSP autonomous: 30 Solar PV Centralized: 30 Solar PV Residential: 30 Wind Onshore: 25 Wind Offshore: 25 +Wave: 25 diesel: 35 gasoline: 35 diesel, synthetic, from wood: 35 @@ -64,4 +70,12 @@ hydrogen, biomass: 35 hydrogen, biomass, with CCS: 35 hydrogen, coal: 35 hydrogen, nat. gas: 35 -hydrogen, nat. gas, with CCS: 35 \ No newline at end of file +hydrogen, nat. gas, with CCS: 35 +hydrogen, coal, with CCS: 35 +hydrogen, solar: 35 +cement, dry feed rotary kiln: 40 +steel - primary: 40 +steel - secondary: 40 +daccs_sorbent: 20 +biomass - residual: 35 +biomass crops - purpose grown: 35 \ No newline at end of file diff --git a/premise/data_collection.py b/premise/data_collection.py index f27ada7c..1466cc68 100644 --- a/premise/data_collection.py +++ b/premise/data_collection.py @@ -411,7 +411,9 @@ def __init__( ) self.electricity_markets = self.__fetch_market_data( - data=data, input_vars=electricity_prod_vars + data=data, + input_vars=electricity_prod_vars, + system_model=self.system_model, ) self.petrol_markets = self.__fetch_market_data( @@ -421,6 +423,7 @@ def __init__( for k, v in fuel_prod_vars.items() if any(x in k for x in ["gasoline", "ethanol", "methanol"]) }, + system_model=self.system_model, ) if self.petrol_markets is not None: # divide the volume of "gasoline" by 2 @@ -442,6 +445,7 @@ def __init__( ] ) }, + system_model=self.system_model, ) if self.diesel_markets is not None: # divide the volume of "gasoline" by 2 @@ -458,6 +462,7 @@ def __init__( for k, v in fuel_prod_vars.items() if any(x in k for x in ["biogas", "methane", "natural gas"]) }, + system_model=self.system_model, ) self.hydrogen_markets = self.__fetch_market_data( @@ -472,17 +477,18 @@ def __init__( ] ) }, + system_model=self.system_model, ) self.cement_markets = self.__fetch_market_data( - data=data, input_vars=cement_prod_vars + data=data, input_vars=cement_prod_vars, system_model="cutoff" ) self.steel_markets = self.__fetch_market_data( - data=data, input_vars=steel_prod_vars + data=data, input_vars=steel_prod_vars, system_model="cutoff" ) - self.dac_markets = self.__fetch_market_data(data=data, input_vars=dac_prod_vars) + self.dac_markets = self.__fetch_market_data(data=data, input_vars=dac_prod_vars, system_model="cutoff") self.biomass_markets = self.__fetch_market_data( - data=data, input_vars=biomass_prod_vars + data=data, input_vars=biomass_prod_vars, system_model="cutoff" ) self.carbon_capture_rate = self.__get_carbon_capture_rate( @@ -496,6 +502,7 @@ def __init__( data=data, input_vars=other_vars, normalize=False, + system_model = "cutoff" ) self.electricity_efficiencies = self.get_iam_efficiencies( @@ -707,7 +714,7 @@ def __get_iam_data( return array def __fetch_market_data( - self, data: xr.DataArray, input_vars: dict, normalize: bool = True + self, data: xr.DataArray, input_vars: dict, system_model: str, normalize: bool = True, ) -> [xr.DataArray, None]: """ This method retrieves the market share for each technology, @@ -742,7 +749,7 @@ def __fetch_market_data( rev_input_vars[v] for v in market_data.variables.values ] - if self.system_model == "consequential": + if system_model == "consequential": market_data = consequential_method( market_data, self.year, self.system_model_args ) diff --git a/premise/electricity.py b/premise/electricity.py index 858408c1..7a04c42c 100644 --- a/premise/electricity.py +++ b/premise/electricity.py @@ -1506,6 +1506,8 @@ def create_biomass_markets(self) -> None: 0, 1, ) + elif self.system_model == "consequential" and biomass_type == "biomass - residual": + share = 0 else: share = 0 diff --git a/premise/fuels.py b/premise/fuels.py index f3ccf3a0..b880473d 100644 --- a/premise/fuels.py +++ b/premise/fuels.py @@ -2195,8 +2195,8 @@ def generate_regional_fuel_market( if ( self.iam_fuel_markets.sel( - region=region, variables=prod_vars, year=self.year - ).sum(dim=["variables"]) + region=region, variables=prod_vars + ).interp(year=self.year).sum(dim=["variables"]) == 0 ): print("No fuel market for", dataset["name"], "in", region) diff --git a/premise/marginal_mixes.py b/premise/marginal_mixes.py index 23fbb50c..3ec06797 100644 --- a/premise/marginal_mixes.py +++ b/premise/marginal_mixes.py @@ -48,7 +48,15 @@ def get_leadtime(list_tech: Tuple) -> np.ndarray: with open(IAM_LEADTIMES, "r", encoding="utf-8") as stream: dict_ = yaml.safe_load(stream) - dict_ = {k: v for k, v in dict_.items() if k in list(list_tech)} + # check that all technologies have a lead-time + if not all([k in dict_.keys() for k in list_tech]): + raise ValueError( + f"Not all technologies have a lead-time. " + f"Missing technologies: {set(list_tech) - set(dict_.keys())}" + ) + dict_ = {k: dict_[k] for k in list(list_tech)} + + return np.array(list(dict_.values()), dtype=float) @@ -203,12 +211,12 @@ def consequential_method(data: xr.DataArray, year: int, args: dict) -> xr.DataAr }, (False, False, False, True): { "start": year, - "end": year + leadtime, + "end": year + fetch_avg_leadtime(leadtime, shares), "start_avg": year, "end_avg": year + fetch_avg_lifetime(lifetime=leadtime, shares=shares), }, (False, False, True, True): { - "start": year - leadtime, + "start": year - fetch_avg_leadtime(leadtime, shares), "end": year, "start_avg": year - fetch_avg_lifetime(lifetime=leadtime, shares=shares), @@ -227,8 +235,8 @@ def consequential_method(data: xr.DataArray, year: int, args: dict) -> xr.DataAr "end_avg": year + range_time, }, (True, False, False, True): { - "start": year + leadtime - range_time, - "end": year + leadtime + range_time, + "start": year + fetch_avg_leadtime(leadtime, shares) - range_time, + "end": year + fetch_avg_leadtime(leadtime, shares) + range_time, "start_avg": year + fetch_avg_leadtime(leadtime, shares) - range_time, "end_avg": year + fetch_avg_leadtime(leadtime, shares) + range_time, }, @@ -251,8 +259,8 @@ def consequential_method(data: xr.DataArray, year: int, args: dict) -> xr.DataAr "end_avg": year + duration, }, (False, True, False, True): { - "start": year + leadtime, - "end": year + leadtime + duration, + "start": year + fetch_avg_leadtime(leadtime, shares), + "end": year + fetch_avg_leadtime(leadtime, shares) + duration, "start_avg": year + fetch_avg_leadtime(leadtime, shares), "end_avg": year + fetch_avg_leadtime(leadtime, shares) + duration, }, @@ -281,8 +289,9 @@ def consequential_method(data: xr.DataArray, year: int, args: dict) -> xr.DataAr except KeyError: print( - "The combination of range_time, duration, foresight, and lead_time " - "is not possible. Please check your input." + f"The combination of range_time, duration, foresight, and lead_time {range_time, duration, foresight, lead_time} " + "is not possible. Please check your input. Specifically, if `range_time` is non-null, `duration` must be null, " + "and vice versa." ) continue diff --git a/setup.py b/setup.py index 56709dd1..61c35efa 100644 --- a/setup.py +++ b/setup.py @@ -32,7 +32,7 @@ def package_files(directory): setup( name="premise", - version="1.6.1", + version="1.6.2", python_requires=">=3.9,<3.11", packages=packages, author="Romain Sacchi , Alois Dirnaichner , Chris Mutel "