From 2333b59b14352ec9ac15243a2c825a179ba4c6fd Mon Sep 17 00:00:00 2001 From: Bryn Pickering <17178478+brynpickering@users.noreply.github.com> Date: Sat, 24 Aug 2024 13:40:22 +0100 Subject: [PATCH 1/2] v0.6 -> v0.7.0.dev3 templates --- .editorconfig | 3 + Snakefile | 6 +- envs/test.yaml | 31 +-- lib/eurocalliopelib/template.py | 8 +- scripts/demand/load.py | 8 +- scripts/heat/heat_demand_final_timeseries.py | 6 +- scripts/heat/heat_pump_final_timeseries.py | 2 +- scripts/heat/population_per_gridbox.py | 2 +- scripts/heat/rescale.py | 2 +- scripts/hydro/capacityfactors_hydro.py | 3 +- scripts/shapes/template_locations.py | 2 +- scripts/summarise_potentials.py | 12 +- scripts/template_model.py | 12 +- scripts/transport/aggregate_timeseries.py | 4 +- .../road_transport_controlled_charging.py | 2 +- .../road_transport_controlled_constraints.py | 4 +- .../transport/road_transport_timeseries.py | 3 - scripts/wind-and-solar/capacityfactors.py | 6 +- .../capacityfactors_offshore.py | 4 +- scripts/wind-and-solar/shared_coast.py | 2 +- templates/environment.yaml | 25 +-- templates/models/additional-math.yaml | 69 ++++++ templates/models/example-model.yaml.jinja | 27 +-- templates/models/interest-rate.yaml | 29 +-- templates/models/locations.yaml.jinja | 10 +- .../electricity-from-biofuel.yaml.jinja | 41 ++-- .../conversion/heat-from-biofuel.yaml.jinja | 44 ++-- .../heat-from-electricity.yaml.jinja | 92 ++++---- .../conversion/heat-from-methane.yaml.jinja | 44 ++-- .../hydrogen-from-electricity.yaml.jinja | 42 ++-- .../synfuels-from-biofuel.yaml.jinja | 188 ++++++++++------- .../synfuels-from-hydrogen.yaml.jinja | 198 ++++++++++-------- .../techs/demand/electricity.yaml.jinja | 28 ++- .../techs/demand/electrified-heat.yaml.jinja | 27 ++- .../demand/electrified-transport.yaml.jinja | 169 +++++++-------- templates/models/techs/demand/heat.yaml.jinja | 35 ++-- .../techs/storage/electricity.yaml.jinja | 102 +++++---- .../models/techs/storage/heat.yaml.jinja | 70 ++++--- .../models/techs/storage/hydro.yaml.jinja | 83 ++++---- .../models/techs/supply/biofuel.yaml.jinja | 30 +-- .../supply/electrified-biofuel.yaml.jinja | 51 +++-- .../historic-electrified-heat.yaml.jinja | 29 +-- .../models/techs/supply/hydro.yaml.jinja | 179 +++++++++------- .../techs/supply/load-shedding.yaml.jinja | 27 ++- .../models/techs/supply/nuclear.yaml.jinja | 59 +++--- ...en-field-solar-and-wind-onshore.yaml.jinja | 174 +++++++++------ .../techs/supply/rooftop-solar.yaml.jinja | 163 ++++++++------ .../techs/supply/wind-offshore.yaml.jinja | 77 ++++--- .../electricity-transmission.yaml.jinja | 60 +++--- tests/model/test_model.py | 35 ++-- tests/model/test_runner.py | 21 +- .../timeseries/demand/test_heat_demand.py | 4 +- tests/resources/test.yaml | 36 ++-- 53 files changed, 1362 insertions(+), 1028 deletions(-) create mode 100644 templates/models/additional-math.yaml diff --git a/.editorconfig b/.editorconfig index 2b81fe66..bbe9762d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -10,5 +10,8 @@ insert_final_newline = true charset = utf-8 end_of_line = lf +[*.{yaml,yml,yaml.jinja}] +indent_size = 2 + [LICENSE] insert_final_newline = false diff --git a/Snakefile b/Snakefile index 1d2caaca..c2bb3550 100644 --- a/Snakefile +++ b/Snakefile @@ -125,7 +125,7 @@ rule module_without_specific_data: template = model_template_dir + "{template}", output: "build/models/{resolution}/{template}" wildcard_constraints: - template = "interest-rate.yaml" + template = "interest-rate.yaml|additional-math.yaml" conda: "envs/shell.yaml" shell: "cp {input.template} {output}" @@ -165,6 +165,10 @@ rule model: "techs/supply/nuclear.yaml", ] ), + math_files = expand( + "build/models/{{resolution}}/{file}", + file=["additional-math.yaml"] + ), heat_timeseries_data = ( "build/models/{resolution}/timeseries/conversion/heat-pump-cop.csv", "build/models/{resolution}/timeseries/supply/historic-electrified-heat.csv", diff --git a/envs/test.yaml b/envs/test.yaml index 2955f667..5a4d3188 100644 --- a/envs/test.yaml +++ b/envs/test.yaml @@ -1,18 +1,19 @@ name: test channels: - - conda-forge - - gurobi + - conda-forge + - conda-forge/label/calliope_dev + - gurobi dependencies: - - python=3.9 - - ipdb=0.13.13 - - numpy=1.23 - - pandas=1.5 - - xarray=2022.3 - - gurobi=9.5.1 - - pytest=7.3.1 - - pytest-html=3.2.0 - - calliope=0.6.10 - - pyomo=6.4.1 - - netCDF4=1.6.2 - - hdf5=1.12.2 - - libnetcdf=4.8.1 + - python=3.12 + - ipdb=0.13.13 + - numpy=1.26.4 + - pandas=2.1.4 + - xarray=2024.2.0 + - gurobi=11.0.3 + - pytest=8.2.2 + - pytest-html=3.2.0 + - calliope=0.7.0 + - pyomo=6.7.1 + - netCDF4=1.6.5 + - hdf5=1.14.2 + - libnetcdf=4.9.2 diff --git a/lib/eurocalliopelib/template.py b/lib/eurocalliopelib/template.py index e07283bf..0fc6826e 100644 --- a/lib/eurocalliopelib/template.py +++ b/lib/eurocalliopelib/template.py @@ -33,10 +33,14 @@ def _update_kwargs(**kwargs): kwargs["scaling_factors"]["specific_costs"] = ( kwargs["scaling_factors"]["monetary"] / kwargs["scaling_factors"]["power"] ) - for config_key in ["locations", "links"]: # we cannot allow keys with "." in them + for config_key in [ + "locations", + "nodes", + "links", + ]: # we cannot allow keys with "." in them if config_key in kwargs: kwargs[config_key] = kwargs[config_key].rename( - index=lambda x: x.replace(".", "-") + index=lambda x: x.replace(".", "_") ) return kwargs diff --git a/scripts/demand/load.py b/scripts/demand/load.py index f1b6d593..3287d905 100644 --- a/scripts/demand/load.py +++ b/scripts/demand/load.py @@ -57,10 +57,10 @@ def load( axis=1, ) assert math.isclose( - load_ts.sum().sum() * (-1) / scaling_factor, + load_ts.sum().sum() / scaling_factor, national_load.reindex(columns=units.country_code.unique()).sum().sum(), ) - load_ts.tz_convert(None).to_csv(path_to_result) + load_ts.tz_convert(None).rename_axis(index="timesteps").to_csv(path_to_result) def split_national_load(national_load, units): @@ -86,18 +86,16 @@ def unit_time_series( unit_industrial_ts = ( national_industrial_load.loc[:, country_code].copy() * multiplier - * (-1) * scaling_factor ) multiplier = unit.fraction_of_national_residential_load unit_residential_ts = ( national_residential_load.loc[:, country_code].copy() * multiplier - * (-1) * scaling_factor ) unit_ts = unit_industrial_ts + unit_residential_ts - unit_ts.name = unit_name.replace(".", "-") + unit_ts.name = unit_name.replace(".", "_") return unit_ts diff --git a/scripts/heat/heat_demand_final_timeseries.py b/scripts/heat/heat_demand_final_timeseries.py index d613e3c6..b65c50b0 100644 --- a/scripts/heat/heat_demand_final_timeseries.py +++ b/scripts/heat/heat_demand_final_timeseries.py @@ -119,11 +119,7 @@ def electrify_heat_demand_profiles( scaled_profiles, cop, snakemake.params.electrification_shares ) - # Demands are stored as negative values for Calliope to ingest - if snakemake.wildcards.tech_group == "demand": - scaled_profiles *= -1 - final_df = ( scaled_profiles.sum("end_use").astype("float32").to_series().unstack("id") ) - final_df.to_csv(snakemake.output[0]) + final_df.rename_axis(index="timesteps").to_csv(snakemake.output[0]) diff --git a/scripts/heat/heat_pump_final_timeseries.py b/scripts/heat/heat_pump_final_timeseries.py index 8a31bd5f..fb1b3204 100644 --- a/scripts/heat/heat_pump_final_timeseries.py +++ b/scripts/heat/heat_pump_final_timeseries.py @@ -54,4 +54,4 @@ def _end_use_weighted_ave( timeseries_data_group_end_use = group_end_uses(timeseries_data, annual_demand_ds) final_df = timeseries_data_group_end_use.astype("float32").to_series().unstack("id") - final_df.to_csv(snakemake.output[0]) + final_df.rename_axis(index="timesteps").to_csv(snakemake.output[0]) diff --git a/scripts/heat/population_per_gridbox.py b/scripts/heat/population_per_gridbox.py index af2f6b24..29e9c9af 100644 --- a/scripts/heat/population_per_gridbox.py +++ b/scripts/heat/population_per_gridbox.py @@ -31,7 +31,7 @@ def population_on_weather_grid( # Locations are shapefiles at the resolution of interest # (e.g. countries for resolution `national`) locations = gpd.read_file(path_to_locations) - locations["id"] = locations["id"].str.replace(".", "-", regex=False) + locations["id"] = locations["id"].str.replace(".", "_", regex=False) gridbox_points = gpd.GeoDataFrame( geometry=gpd.points_from_xy( diff --git a/scripts/heat/rescale.py b/scripts/heat/rescale.py index e6aab837..36f15414 100644 --- a/scripts/heat/rescale.py +++ b/scripts/heat/rescale.py @@ -37,7 +37,7 @@ def national_to_regional_resolution( }, ) .mul(df_population_share) - .rename(columns=lambda col_name: col_name.replace(".", "-")) + .rename(columns=lambda col_name: col_name.replace(".", "_")) ) pd.testing.assert_series_equal(regional_df.sum(axis=1), annual_demand.sum(axis=1)) diff --git a/scripts/hydro/capacityfactors_hydro.py b/scripts/hydro/capacityfactors_hydro.py index fd6b5d85..2d114925 100644 --- a/scripts/hydro/capacityfactors_hydro.py +++ b/scripts/hydro/capacityfactors_hydro.py @@ -51,7 +51,8 @@ def time_series(plants, locations, capacities): .pivot(index="time", columns="index_right", values="inflow_MWh") .reindex(columns=locations.index, fill_value=0) .div(capacities) - .rename(columns=lambda col: col.replace(".", "-")) + .rename(columns=lambda col: col.replace(".", "_")) + .rename_axis(index="timesteps") ) diff --git a/scripts/shapes/template_locations.py b/scripts/shapes/template_locations.py index cea4284e..55938904 100644 --- a/scripts/shapes/template_locations.py +++ b/scripts/shapes/template_locations.py @@ -19,7 +19,7 @@ def construct_locations( ).loc[:, ["name", "centroid"]] locations = locations.assign( - id=locations.index.str.replace(".", "-", regex=False) + id=locations.index.str.replace(".", "_", regex=False) ).set_index("id") parametrise_template( diff --git a/scripts/summarise_potentials.py b/scripts/summarise_potentials.py index e5b15608..a051e146 100644 --- a/scripts/summarise_potentials.py +++ b/scripts/summarise_potentials.py @@ -41,7 +41,7 @@ def summarise_potentials( model = calliope.Model(path_to_model) list_of_techs = model.inputs.techs.values - list_of_locs = model.inputs.locs.values + list_of_locs = model.inputs.nodes.values list_of_potentials = list(set(considered_potentials).intersection(model.inputs)) summary = np.empty((len(list_of_techs), len(list_of_potentials), len(list_of_locs))) @@ -51,25 +51,25 @@ def summarise_potentials( summary = xr.DataArray( summary, - dims=("techs", "potentials", "locs"), + dims=("techs", "potentials", "nodes"), coords={ "techs": list_of_techs, "potentials": list_of_potentials, - "locs": list_of_locs, + "nodes": list_of_locs, "unit": (["potentials"], units), }, ) for potential in list_of_potentials: - aux = model.get_formatted_array(potential) + aux = model._model_data[potential] summary.coords["unit"].loc[dict(potentials=potential)] = considered_potentials[ potential ]["unit"] for tech in list_of_techs: for loc in list_of_locs: try: - summary.loc[dict(techs=tech, locs=loc, potentials=potential)] = ( - aux.loc[dict(techs=tech, locs=loc)] + summary.loc[dict(techs=tech, nodes=loc, potentials=potential)] = ( + aux.loc[dict(techs=tech, nodes=loc)] / considered_potentials[potential]["sf"] ) except KeyError: diff --git a/scripts/template_model.py b/scripts/template_model.py index c5f3e738..1b91e966 100644 --- a/scripts/template_model.py +++ b/scripts/template_model.py @@ -5,13 +5,22 @@ from eurocalliopelib.template import parametrise_template -def construct_model(path_to_template, path_to_output, modules, resolution, year): +def construct_model( + path_to_template, + path_to_output, + modules, + resolution, + math_files, + year, +): input_files = sorted([update_path(file, resolution) for file in modules]) + math_files = [update_path(file, resolution) for file in math_files] return parametrise_template( path_to_template, path_to_output, input_files=input_files, + math_files=math_files, resolution=resolution, year=year, ) @@ -27,6 +36,7 @@ def update_path(path_string, resolution): construct_model( path_to_template=snakemake.input.template, modules=snakemake.input.modules, + math_files=snakemake.input.math_files, resolution=snakemake.wildcards.resolution, year=snakemake.params.year, path_to_output=snakemake.output[0], diff --git a/scripts/transport/aggregate_timeseries.py b/scripts/transport/aggregate_timeseries.py index 627b56ba..db045362 100644 --- a/scripts/transport/aggregate_timeseries.py +++ b/scripts/transport/aggregate_timeseries.py @@ -53,7 +53,7 @@ def create_regional_timeseries( }, ) .mul(df_population_share) - .rename(columns=lambda col_name: col_name.replace(".", "-")) + .rename(columns=lambda col_name: col_name.replace(".", "_")) ) pd.testing.assert_series_equal(df_regional.sum(axis=1), df_national.sum(axis=1)) @@ -79,4 +79,4 @@ def create_regional_timeseries( else: raise ValueError("Input resolution not recognised.") - ts.to_csv(path_to_output) + ts.rename_axis(index="timesteps").to_csv(path_to_output) diff --git a/scripts/transport/road_transport_controlled_charging.py b/scripts/transport/road_transport_controlled_charging.py index e91a847a..b70ff8e7 100644 --- a/scripts/transport/road_transport_controlled_charging.py +++ b/scripts/transport/road_transport_controlled_charging.py @@ -23,7 +23,7 @@ def scale_to_regional_resolution(df, region_country_mapping, populations): }, ) .mul(df_population_share) - .rename(columns=lambda col_name: col_name.replace(".", "-")) + .rename(columns=lambda col_name: col_name.replace(".", "_")) ) pd.testing.assert_series_equal(regional_df.sum(axis=1), df.sum(axis=1)) return regional_df diff --git a/scripts/transport/road_transport_controlled_constraints.py b/scripts/transport/road_transport_controlled_constraints.py index 5761eff1..53f96ed9 100644 --- a/scripts/transport/road_transport_controlled_constraints.py +++ b/scripts/transport/road_transport_controlled_constraints.py @@ -13,7 +13,7 @@ def scale_to_resolution_and_create_file( df = scale_national_to_regional(df, region_country_mapping, populations) else: raise ValueError(f"Resolution {resolution} is not supported") - df.tz_localize(None).rename_axis("utc-timestamp").to_csv(output_path) + df.tz_localize(None).rename_axis("timesteps").to_csv(output_path) def scale_national_to_regional(df, region_country_mapping, populations): @@ -33,7 +33,7 @@ def scale_national_to_regional(df, region_country_mapping, populations): }, ) .mul(df_population_share) - .rename(columns=lambda col_name: col_name.replace(".", "-")) + .rename(columns=lambda col_name: col_name.replace(".", "_")) ) pd.testing.assert_series_equal(regional_df.sum(axis=1), df.sum(axis=1)) return regional_df diff --git a/scripts/transport/road_transport_timeseries.py b/scripts/transport/road_transport_timeseries.py index dd11c5d2..c5c508a4 100644 --- a/scripts/transport/road_transport_timeseries.py +++ b/scripts/transport/road_transport_timeseries.py @@ -54,9 +54,6 @@ def create_road_transport_demand_timeseries( df_timeseries = ( df_timeseries.mul(conversion_factor) .mul(power_scaling_factor) - .mul( - 1 if historic else -1 - ) # historic demand is actually a supply to avoid double counting .loc[:, country_codes] .tz_localize(None) .rename_axis("utc-timestamp") diff --git a/scripts/wind-and-solar/capacityfactors.py b/scripts/wind-and-solar/capacityfactors.py index 290b22f6..ab5268bb 100644 --- a/scripts/wind-and-solar/capacityfactors.py +++ b/scripts/wind-and-solar/capacityfactors.py @@ -23,7 +23,7 @@ def capacityfactors( locations = ( gpd.read_file(path_to_locations).set_index("id").to_crs(EPSG3035).geometry ) - locations.index = locations.index.map(lambda x: x.replace(".", "-")) + locations.index = locations.index.map(lambda x: x.replace(".", "_")) ts = xr.open_dataset(path_to_timeseries) ts = ts.sel(time=slice(first_year, final_year)) # xarray will silently miss the fact that data doesn't exist with slice @@ -56,7 +56,9 @@ def capacityfactors( spatiotemporal=ts, gridcell_overlap_threshold=gridcell_overlap_threshold, ) - capacityfactors.where(capacityfactors >= cf_threshold, 0).to_csv(path_to_result) + capacityfactors.where(capacityfactors >= cf_threshold, 0).rename_axis( + index="timesteps" + ).to_csv(path_to_result) if __name__ == "__main__": diff --git a/scripts/wind-and-solar/capacityfactors_offshore.py b/scripts/wind-and-solar/capacityfactors_offshore.py index 870f5f02..d557ccba 100644 --- a/scripts/wind-and-solar/capacityfactors_offshore.py +++ b/scripts/wind-and-solar/capacityfactors_offshore.py @@ -54,7 +54,9 @@ def capacityfactors( capacityfactors = _allocate_to_onshore_locations( capacityfactors_per_eez, shared_coast ) - capacityfactors.where(capacityfactors >= cf_threshold, 0).to_csv(path_to_result) + capacityfactors.where(capacityfactors >= cf_threshold, 0).rename_axis( + index="timesteps" + ).to_csv(path_to_result) def _allocate_to_onshore_locations(capacityfactors_per_eez, shared_coast): diff --git a/scripts/wind-and-solar/shared_coast.py b/scripts/wind-and-solar/shared_coast.py index 7a091005..1e827258 100644 --- a/scripts/wind-and-solar/shared_coast.py +++ b/scripts/wind-and-solar/shared_coast.py @@ -90,7 +90,7 @@ def allocate_eezs( # Clean up id and MRGID data share.index = share.index.set_levels( levels=( - share.index.levels[0].map(lambda x: x.replace(".", "-")), + share.index.levels[0].map(lambda x: x.replace(".", "_")), share.index.levels[1].astype(int), ), level=[0, 1], diff --git a/templates/environment.yaml b/templates/environment.yaml index c184cf01..7b08b8fb 100644 --- a/templates/environment.yaml +++ b/templates/environment.yaml @@ -1,15 +1,16 @@ name: euro-calliope channels: - - conda-forge - - gurobi + - conda-forge + - conda-forge/label/calliope_dev + - gurobi dependencies: - - python=3.9 - - numpy=1.23 - - pandas=1.5 - - xarray=2022.3 - - netCDF4=1.6.2 - - hdf5=1.12.2 - - libnetcdf=4.8.1 - - gurobi=9.5.1 - - calliope=0.6.10 - - pyomo=6.4.1 + - python=3.12 + - numpy=1.26.4 + - pandas=2.1.4 + - xarray=2024.2.0 + - netCDF4=1.6.5 + - hdf5=1.14.2 + - libnetcdf=4.9.2 + - gurobi=11.0.3 + - calliope=0.7.0 + - pyomo=6.7.1 diff --git a/templates/models/additional-math.yaml b/templates/models/additional-math.yaml new file mode 100644 index 00000000..b25ae850 --- /dev/null +++ b/templates/models/additional-math.yaml @@ -0,0 +1,69 @@ +constraints: + set_total_flow_in: + foreach: [nodes, techs, carriers] + where: flow_in_total + equations: + - expression: sum(flow_in, over=timesteps) == flow_in_total + + set_flow_cap_max_time_varying: + description: > + Limit flow out in each hour according to a time varying fractional limit + that is multiplied by the technology flow cap. This represents, for + instance, the impact of outdoor temperature on the maximum output of a + technology relative to its rated max output. + foreach: [nodes, techs, carriers, timesteps] + where: flow_cap_max_time_varying + equations: + - expression: flow_out <= flow_cap_max_time_varying * flow_cap * flow_out_parasitic_eff + + min_monthly_flow_in: + foreach: [nodes, techs, carriers, monthsteps] + where: flow_in_per_month_min + active: false # FIXME: Need a way to map between timesteps and monthsteps + equations: + - expression: sum(flow_in, over=monthsteps) >= flow_in_per_month_min + + max_monthly_flow_in: + foreach: [nodes, techs, carriers, monthsteps] + where: flow_in_per_month_max + active: false # FIXME: Need a way to map between timesteps and monthsteps + equations: + - expression: sum(flow_in, over=monthsteps) <= flow_in_per_month_max + + set_co2_consumption: + foreach: [nodes, techs, timesteps] + where: co2_consumption + equations: + - expression: flow_in[carriers=co2] == (sum(flow_in, over=carriers) - flow_in[carriers=co2]) * co2_consumption + + balance_conversion: + description: >- + Fix the relationship between a `conversion` technology's outflow and consumption. + foreach: [nodes, techs, timesteps] + where: base_tech=conversion AND NOT include_storage=true + equations: + - where: not co2_consumption + expression: sum(flow_out_inc_eff, over=carriers) == sum(flow_in_inc_eff, over=carriers) + - where: co2_consumption + expression: sum(flow_out_inc_eff, over=carriers) == sum(flow_in_inc_eff, over=carriers) - flow_in_inc_eff[carriers=co2] + + set_flow_out_share: + foreach: [nodes, techs, carriers, timesteps] + where: flow_out_share + equations: + - expression: flow_out == sum(flow_out, over=carriers) * flow_out_share + + set_flow_in_share: + foreach: [nodes, techs, carriers, timesteps] + where: flow_in_share + equations: + - where: not co2_consumption + expression: flow_in == sum(flow_in, over=carriers) * flow_in_share + - where: co2_consumption + expression: flow_in == (sum(flow_in, over=carriers) - flow_in[carriers=co2]) * flow_in_share + + link_storage_techs: + foreach: [nodes, techs, carriers, timesteps] + where: lookup_linked_storage_tech + equations: + - expression: flow_in <= select_from_lookup_arrays(flow_out, techs=lookup_linked_storage_tech) diff --git a/templates/models/example-model.yaml.jinja b/templates/models/example-model.yaml.jinja index 0581cfd2..e1afdf9f 100644 --- a/templates/models/example-model.yaml.jinja +++ b/templates/models/example-model.yaml.jinja @@ -1,17 +1,18 @@ import: - {% for file in input_files %} - - {{ file }} - {% endfor %} -model: + {% for file in input_files %} + - {{ file }} + {% endfor %} +config: + init: name: 'Example model' - calliope_version: 0.6.10 - timeseries_data_path: ./timeseries - subset_time: ['{{ year }}-01-01', '{{ year }}-01-01'] -run: + calliope_version: "0.7" + time_subset: ['{{ year }}-01-01', '{{ year }}-01-01'] + add_math: + {% for file in math_files %} + - {{ file }} + {% endfor %} + build: + mode: plan + solve: solver: gurobi solver_io: python - mode: plan - objective_options: { - 'cost_class': {'monetary': 1}, - 'sense': 'minimize' - } diff --git a/templates/models/interest-rate.yaml b/templates/models/interest-rate.yaml index b409e574..362113f8 100644 --- a/templates/models/interest-rate.yaml +++ b/templates/models/interest-rate.yaml @@ -1,25 +1,6 @@ tech_groups: - conversion: - costs: - monetary: - interest_rate: 0.073 # average wind onshore WACC OECD from [@Steffen:2019] - conversion_plus: - costs: - monetary: - interest_rate: 0.073 # average wind onshore WACC OECD from [@Steffen:2019] - storage: - costs: - monetary: - interest_rate: 0.073 # average wind onshore WACC OECD from [@Steffen:2019] - supply: - costs: - monetary: - interest_rate: 0.073 # average wind onshore WACC OECD from [@Steffen:2019] - supply_plus: - costs: - monetary: - interest_rate: 0.073 # average wind onshore WACC OECD from [@Steffen:2019] - transmission: - costs: - monetary: - interest_rate: 0.073 # average wind onshore WACC OECD from [@Steffen:2019] + interest_rate: + cost_interest_rate: + data: 0.073 # average wind onshore WACC OECD from [@Steffen:2019] + index: monetary + dims: costs diff --git a/templates/models/locations.yaml.jinja b/templates/models/locations.yaml.jinja index 87243061..db95e046 100644 --- a/templates/models/locations.yaml.jinja +++ b/templates/models/locations.yaml.jinja @@ -1,4 +1,6 @@ -locations: - {% for id, location in locations.iterrows() %} - {{ id }}.coordinates: {lat: {{ location.centroid.y }}, lon: {{ location.centroid.x }}} # {{ location["name"] }} - {% endfor %} +nodes: + {% for id, location in locations.iterrows() %} + {{ id }}: # {{ location["name"] }} + latitude: {{ location.centroid.y }} + longitude: {{ location.centroid.x }} + {% endfor %} diff --git a/templates/models/techs/conversion/electricity-from-biofuel.yaml.jinja b/templates/models/techs/conversion/electricity-from-biofuel.yaml.jinja index 37f0c5a7..92fb53b3 100644 --- a/templates/models/techs/conversion/electricity-from-biofuel.yaml.jinja +++ b/templates/models/techs/conversion/electricity-from-biofuel.yaml.jinja @@ -1,19 +1,26 @@ techs: - electricity_from_biofuel: # from [@JRC:2014] Table 48 Anaerobic digestion - essentials: - name: Electricity from anaerobically digested biofuel - parent: conversion - carrier_in: biofuel - carrier_out: electricity - constraints: - energy_eff: {{ biofuel_efficiency }} - lifetime: 20 - costs.monetary: - energy_cap: {{2300000 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} - om_annual: {{2300000 * 0.041 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} 4.1% of CAPEX - om_prod: {{ 3.1 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MWh") }} + electricity_from_biofuel: # from [@JRC:2014] Table 48 Anaerobic digestion + name: Electricity from anaerobically digested biofuel + inherit: interest_rate + base_tech: conversion + carrier_in: biofuel + carrier_out: electricity + flow_out_eff: {{ biofuel_efficiency }} + lifetime: 20 + cost_flow_cap: + data: {{2300000 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} + index: [[monetary, electricity]] + dims: [costs, carriers] + cost_om_annual: + data: {{2300000 * 0.041 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} 4.1% of CAPEX + index: [[monetary, electricity]] + dims: [costs, carriers] + cost_flow_out: + data: {{ 3.1 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MWh") }} + index: monetary + dims: costs -locations: - {% for id, location in locations.iterrows() %} - {{ id }}.techs.electricity_from_biofuel: - {% endfor %} +nodes: + {% for id, location in locations.iterrows() %} + {{ id }}.techs.electricity_from_biofuel: + {% endfor %} diff --git a/templates/models/techs/conversion/heat-from-biofuel.yaml.jinja b/templates/models/techs/conversion/heat-from-biofuel.yaml.jinja index 9b4370a3..f0cd2034 100644 --- a/templates/models/techs/conversion/heat-from-biofuel.yaml.jinja +++ b/templates/models/techs/conversion/heat-from-biofuel.yaml.jinja @@ -3,27 +3,25 @@ {# Costs are given by DEA per technology "unit" (1000EUR/unit), so are converted to a cost per capacity (1000EUR/kW_heating) by dividing by the capacity of one unit, as given in the same data table. #} techs: - biofuel_boiler: # [@DEA:2017] - Biomass boiler, automatic stoking , wood pellets or wood chips - 2050 - # Costs and efficiency are an average of data for existing single-family, new single-family, existing multi-family, and new multi-family homes. - essentials: - name: Biofuel boiler - parent: conversion - carrier_in: biofuel - carrier_out: biofuel_heat - constraints: - energy_eff: {{ mean([0.88, 0.85, 0.90, 0.90]) }} - lifetime: 20 - costs: - monetary: - energy_cap: {{ mean([5.9 / 10, 5.9 / 8, 76 / 400, 45 / 160]) * 1e6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_heat") }} - om_annual: {{ mean([0.42 / 10, 0.42 / 10, 1.343 / 400, 0.889 / 160]) * 1e6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_heat/year") }} - biofuel_tech_heat_to_demand: - essentials.parent: tech_heat_to_demand - essentials.carrier_in: biofuel_heat + biofuel_boiler: # [@DEA:2017] - Biomass boiler, automatic stoking , wood pellets or wood chips - 2050 + # Costs and efficiency are an average of data for existing single-family, new single-family, existing multi-family, and new multi-family homes. + name: Biofuel boiler + inherit: interest_rate + base_tech: conversion + carrier_in: biofuel + carrier_out: heat + flow_out_eff: {{ mean([0.88, 0.85, 0.90, 0.90]) }} + lifetime: 20 + cost_flow_cap: + data: {{ mean([5.9 / 10, 5.9 / 8, 76 / 400, 45 / 160]) * 1e6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_heat") }} + index: [[monetary, heat]] + dims: [costs, carriers] + cost_om_annual: + data: {{ mean([0.42 / 10, 0.42 / 10, 1.343 / 400, 0.889 / 160]) * 1e6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_heat/year") }} + index: [[monetary, heat]] + dims: [costs, carriers] -locations: - {% for id, location in locations.iterrows() %} - {{ id }}.techs: - biofuel_boiler: - biofuel_tech_heat_to_demand: - {% endfor %} +nodes: + {% for id, location in locations.iterrows() %} + {{ id }}.techs.biofuel_boiler: + {% endfor %} diff --git a/templates/models/techs/conversion/heat-from-electricity.yaml.jinja b/templates/models/techs/conversion/heat-from-electricity.yaml.jinja index 4184f90e..23d9d1f6 100644 --- a/templates/models/techs/conversion/heat-from-electricity.yaml.jinja +++ b/templates/models/techs/conversion/heat-from-electricity.yaml.jinja @@ -3,48 +3,54 @@ {# Costs are given by DEA per technology "unit" (1000EUR/unit), so are converted to a cost per capacity (1000EUR/kW_heating) by dividing by the capacity of one unit, as given in the same data table. #} techs: - heat_pump: # [@DEA:2017] - 7.3 - 7.6 Air to water & 7.7 - 7.10 Ground source - 2050 - essentials: - name: Heat pump - parent: conversion - carrier_in: electricity - carrier_out: hp_heat - constraints: - energy_eff: file=conversion/heat-pump-cop.csv # NOTE: based on data processing pipeline, not [@DEA:2017]. - lifetime: 20 - costs: - monetary: - # Costs are an average of data for existing single-family, new single-family, existing multi-family, and new multi-family homes | weighted average between air- and ground-source heat pumps according to an assumed relative share of installed capacity. - energy_cap: {{ (mean([7.6 / 10, 5 / 4, 114 / 400, 57 / 160]) * heat_pump_shares.ashp + mean([12 / 10, 9 / 4, 202 / 400, 72 / 160]) * heat_pump_shares.gshp) * 1e6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_heat") }} - om_annual: {{ (mean([0.222 / 10, 0.222 / 4, 0.761 / 400, 0.761 / 160]) * heat_pump_shares.ashp + mean([0.222 / 10, 0.222 / 4, 0.761 / 400, 0.761 / 160]) * heat_pump_shares.gshp) * 1e6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_heat/year") }} - heat_pump_tech_heat_to_demand: - essentials.parent: tech_heat_to_demand - essentials.carrier_in: hp_heat + heat_pump: # [@DEA:2017] - 7.3 - 7.6 Air to water & 7.7 - 7.10 Ground source - 2050 + name: Heat pump + inherit: interest_rate + base_tech: conversion + carrier_in: electricity + carrier_out: heat + lifetime: 20 - electric_heater: # [@DEA:2017] - 16 Electric heating - 2050 - essentials: - name: Electrical heater - parent: conversion - carrier_in: electricity - carrier_out: electric_heater_heat - constraints: - energy_eff: 1 - lifetime: 30 - costs: - monetary: - # Costs are an average of data for new single-family and new multi-family homes - energy_cap: {{ mean([2.5 / 3, 89 / 160]) * 1e6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_heat") }} - om_annual: {{ mean([0.021 / 3, 0.042 / 160]) * 1e6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_heat/year") }} - electric_heater_tech_heat_to_demand: - essentials.parent: tech_heat_to_demand - essentials.carrier_in: electric_heater_heat + # Costs are an average of data for existing single-family, new single-family, existing multi-family, and new multi-family homes | weighted average between air- and ground-source heat pumps according to an assumed relative share of installed capacity. + cost_flow_cap: + data: {{ (mean([7.6 / 10, 5 / 4, 114 / 400, 57 / 160]) * heat_pump_shares.ashp + mean([12 / 10, 9 / 4, 202 / 400, 72 / 160]) * heat_pump_shares.gshp) * 1e6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_heat") }} + index: [[monetary, heat]] + dims: [costs, carriers] + cost_om_annual: + data: {{ (mean([0.222 / 10, 0.222 / 4, 0.761 / 400, 0.761 / 160]) * heat_pump_shares.ashp + mean([0.222 / 10, 0.222 / 4, 0.761 / 400, 0.761 / 160]) * heat_pump_shares.gshp) * 1e6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_heat/year") }} + index: [[monetary, heat]] + dims: [costs, carriers] -locations: - {% for id, location in locations.iterrows() %} - {{ id }}: - techs: - heat_pump: - heat_pump_tech_heat_to_demand: - electric_heater: - electric_heater_tech_heat_to_demand: - {% endfor %} + electric_heater: # [@DEA:2017] - 16 Electric heating - 2050 + name: Electrical heater + inherit: interest_rate + base_tech: conversion + carrier_in: electricity + carrier_out: heat + flow_out_eff: 1 + lifetime: 30 + # Costs are an average of data for new single-family and new multi-family homes + cost_flow_cap: + data: {{ mean([2.5 / 3, 89 / 160]) * 1e6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_heat") }} + index: [[monetary, heat]] + dims: [costs, carriers] + cost_om_annual: + data: {{ mean([0.021 / 3, 0.042 / 160]) * 1e6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_heat/year") }} + index: [[monetary, heat]] + dims: [costs, carriers] + +data_sources: + heat_pump_eff: + source: timeseries/conversion/heat-pump-cop.csv + rows: timesteps + columns: nodes + add_dimensions: + techs: heat_pump + parameters: flow_out_eff + +nodes: + {% for id, location in locations.iterrows() %} + {{ id }}.techs: + heat_pump: + electric_heater: + {% endfor %} diff --git a/templates/models/techs/conversion/heat-from-methane.yaml.jinja b/templates/models/techs/conversion/heat-from-methane.yaml.jinja index f9d33fa5..41726886 100644 --- a/templates/models/techs/conversion/heat-from-methane.yaml.jinja +++ b/templates/models/techs/conversion/heat-from-methane.yaml.jinja @@ -2,27 +2,25 @@ {# Costs being averaged are given in the order they appear in the spreadsheet (which is the same order as in the inline comments). #} {# Costs are given by DEA per technology "unit" (1000EUR/unit), so are converted to a cost per capacity (1000EUR/kW_heating) by dividing by the capacity of one unit, as given in the same data table. #} techs: - methane_boiler: # [@DEA:2017] - 202 Natural gas boiler - 2050 - essentials: - name: Natural gas / methane boiler - parent: conversion - carrier_in: methane - carrier_out: methane_heat - constraints: - energy_eff: 0.99 - lifetime: 20 - costs: - monetary: - # Costs are an average of data for existing single-family, new single-family, existing multi-family, and new multi-family homes. - energy_cap: {{ mean([2.7 / 10, 2.7 / 10, 21.1 / 400, 15.1 / 160]) * 1e6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_heat") }} - om_annual: {{ mean([0.168 / 10, 0.168 / 10, 0.561/ 400, 0.374 / 160]) * 1e6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_heat/year") }} - methane_tech_heat_to_demand: - essentials.parent: tech_heat_to_demand - essentials.carrier_in: methane_heat + methane_boiler: # [@DEA:2017] - 202 Natural gas boiler - 2050 + name: Natural gas / methane boiler + inherit: interest_rate + base_tech: conversion + carrier_in: methane + carrier_out: heat + flow_out_eff: 0.99 + lifetime: 20 + # Costs are an average of data for existing single-family, new single-family, existing multi-family, and new multi-family homes. + cost_flow_cap: + data: {{ mean([2.7 / 10, 2.7 / 10, 21.1 / 400, 15.1 / 160]) * 1e6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_heat") }} + index: [[monetary, heat]] + dims: [costs, carriers] + cost_om_annual: + data: {{ mean([0.168 / 10, 0.168 / 10, 0.561/ 400, 0.374 / 160]) * 1e6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_heat/year") }} + index: [[monetary, heat]] + dims: [costs, carriers] -locations: - {% for id, location in locations.iterrows() %} - {{ id }}.techs: - methane_boiler: - methane_tech_heat_to_demand: - {% endfor %} +nodes: + {% for id, location in locations.iterrows() %} + {{ id }}.techs.methane_boiler: + {% endfor %} diff --git a/templates/models/techs/conversion/hydrogen-from-electricity.yaml.jinja b/templates/models/techs/conversion/hydrogen-from-electricity.yaml.jinja index 13e95643..140c6021 100644 --- a/templates/models/techs/conversion/hydrogen-from-electricity.yaml.jinja +++ b/templates/models/techs/conversion/hydrogen-from-electricity.yaml.jinja @@ -1,23 +1,25 @@ {# Costs are given by DEA per technology "unit" (1000EUR/unit), so are converted to a cost per capacity (1000EUR/kW_H2) by dividing by the capacity of one unit, as given in the same data table. #} techs: - # ASSUME: Electrolyser can run intermittently - # Technology constraints and costs are averages over different electrolyser types: SOEC, PEM, and Alkaline - electrolysis: # [@DEA:2020b] - 86-88 Electrolysers - 2050 - essentials: - name: Hydrogen by electrolysis - parent: conversion - carrier_in: electricity - carrier_out: hydrogen - constraints: - energy_eff: {{ mean([0.79, 0.67, 0.692])}} - lifetime: {{ mean([30, 15, 25])}} - costs: - monetary: - energy_cap: {{ mean([0.4 / 0.79, 0.4 / 0.67, 0.5 / 0.692]) * 1e6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_H2") }} | - om_annual: {{ mean([12 / 0.79, 20 / 0.67, 25 / 0.692]) * 1e3 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_H2/year") }} + # ASSUME: Electrolyser can run intermittently + # Technology constraints and costs are averages over different electrolyser types: SOEC, PEM, and Alkaline + electrolysis: # [@DEA:2020b] - 86-88 Electrolysers - 2050 + name: Hydrogen by electrolysis + inherit: interest_rate + base_tech: conversion + carrier_in: electricity + carrier_out: hydrogen + flow_out_eff: {{ mean([0.79, 0.67, 0.692])}} + lifetime: {{ mean([30, 15, 25])}} + cost_flow_cap: + data: {{ mean([0.4 / 0.79, 0.4 / 0.67, 0.5 / 0.692]) * 1e6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_H2") }} | + index: [[monetary, hydrogen]] + dims: [costs, carriers] + cost_om_annual: + data: {{ mean([12 / 0.79, 20 / 0.67, 25 / 0.692]) * 1e3 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_H2/year") }} + index: [[monetary, hydrogen]] + dims: [costs, carriers] -locations: - {% for id, location in locations.iterrows() %} - {{ id }}.techs: - electrolysis: - {% endfor %} +nodes: + {% for id, location in locations.iterrows() %} + {{ id }}.techs.electrolysis: + {% endfor %} diff --git a/templates/models/techs/conversion/synfuels-from-biofuel.yaml.jinja b/templates/models/techs/conversion/synfuels-from-biofuel.yaml.jinja index 4d583e09..504f1982 100644 --- a/templates/models/techs/conversion/synfuels-from-biofuel.yaml.jinja +++ b/templates/models/techs/conversion/synfuels-from-biofuel.yaml.jinja @@ -1,84 +1,114 @@ techs: - biofuel_to_liquids: # [@DEA:2020b] - 85 Gasif. Ent. Flow FT, liq fu - 2050 - # ASSUME: Naptha production can be diverted to kerosene and diesel production, in equal measure. - essentials: - name: Biofuel to liquid fuels converter - parent: conversion_plus - carrier_in: biofuel - carrier_out: kerosene - primary_carrier_out: diesel - carrier_out_2: diesel - carrier_out_3: electricity - constraints: - carrier_ratios: - carrier_out.kerosene: {{ 0.017 + 0.163 / 2 }} # MWh_kerosene/MWh_in (includes 50% of Naptha production) - carrier_out_2.diesel: {{ 0.118 + 0.163 / 2 }} # MWh_diesel/MWh_in (includes 50% of Naptha production) - carrier_out_3.electricity: 0.02 # MWhe/MWh_in - lifetime: 25 - costs: - monetary: - {# TODO: sense check energy_cap vs om_annual costs #} - # EUR/MW(h)_diesel(/year) calculated from source data as: EYR/MW(h)_liquids(/year) / MW(h)_diesel/MW(h)_in * MW(h)_liquids/MW(h)_in - energy_cap: {{ 3.46e6 / (0.118 + 0.163 / 2) * (0.017 + 0.163 + 0.118) * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_diesel") }} - om_annual: {{ 104e3 / (0.118 + 0.163 / 2) * (0.017 + 0.163 + 0.118) * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_diesel/year") }} - om_prod: {{ 1.063 / (0.118 + 0.163 / 2) * (0.017 + 0.163 + 0.118) * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_diesel") }} + biofuel_to_liquids: # [@DEA:2020b] - 85 Gasif. Ent. Flow FT, liq fu - 2050 + # ASSUME: Naptha production can be diverted to kerosene and diesel production, in equal measure. + name: Biofuel to liquid fuels converter + inherit: interest_rate + base_tech: conversion + carrier_in: biofuel + carrier_out: [kerosene, diesel, electricity] + flow_out_eff: {{ 0.017 + 0.163 / 2 + 0.118 + 0.163 / 2 + 0.02 }} # MWh_out/MWh_in + flow_out_share: + data: + - {{ (0.017 + 0.163 / 2) / (0.017 + 0.163 + 0.118 + 0.02) }} # MWh_kerosene/MWh_out (includes 50% of Naptha production) + - {{ (0.118 + 0.163 / 2) / (0.017 + 0.163 + 0.118 + 0.02) }} # MWh_diesel/MWh_out (includes 50% of Naptha production) + - {{ 0.02 / (0.017 + 0.163 + 0.118 + 0.02) }} # MWhe/MWh_out + index: + - kerosene + - diesel + - electricity + dims: carriers + lifetime: 25 - # ASSUME: ignore electricity input, as it is 1% of the input energy requirements. - # ASSUME: all vehicle fuel is diesel. - biofuel_to_diesel: # [@DEA:2020b] - 101 Catalytic Hydropyrolysis 2 - 2050 - essentials: - name: Biofuel to vehicle fuel converter - parent: conversion - carrier_in: biofuel - carrier_out: diesel - constraints: - energy_eff: 0.6 # {{ 1 | unit("MWh_diesel/MWh_biofuel") }} - lifetime: 20 - costs: - monetary: - energy_cap: {{ 0.93 * 1e6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_diesel") }} - om_annual: {{ 0.027 * 1e6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_diesel/year") }} - {# TODO: triple check this: the number seems too high... #} - om_prod: {{ 1.31 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MWh_diesel") }} + {# TODO: sense check energy_cap vs om_annual costs #} + # EUR/MW(h)_diesel(/year) calculated from source data as: EYR/MW(h)_liquids(/year) / MW(h)_diesel/MW(h)_in * MW(h)_liquids/MW(h)_in + cost_flow_cap: + data: {{ 3.46e6 / (0.118 + 0.163 / 2) * (0.017 + 0.163 + 0.118) * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_diesel") }} + index: [[monetary, diesel]] + dims: [costs, carriers] + cost_om_annual: + data: {{ 104e3 / (0.118 + 0.163 / 2) * (0.017 + 0.163 + 0.118) * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_diesel/year") }} + index: [[monetary, diesel]] + dims: [costs, carriers] + cost_flow_out: + data: {{ 1.063 / (0.118 + 0.163 / 2) * (0.017 + 0.163 + 0.118) * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_diesel") }} + index: [[monetary, diesel]] + dims: [costs, carriers] - # ASSUME: ignore waste low grade heat output (which could be used for district heating) - # ASSUME: ignore electricity output, as it can cause numerical trouble. - biofuel_to_methanol: # [@DEA:2020b] - 97 Methanol from biomass gasif. - 2050 - essentials: - name: Biofuel to Methanol converter - parent: conversion - carrier_in: biofuel - carrier_out: methanol - constraints: - energy_eff: 0.65 # MWh_methanol/MWh_bio - lifetime: 20 - costs: - monetary: - energy_cap: {{ 1.46e6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_methanol") }} - om_annual: {{ 0.039e6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_methanol/year") }} - om_prod: {{ 13.6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MWh_methanol") }} + # ASSUME: ignore electricity input, as it is 1% of the input energy requirements. + # ASSUME: all vehicle fuel is diesel. + biofuel_to_diesel: # [@DEA:2020b] - 101 Catalytic Hydropyrolysis 2 - 2050 + name: Biofuel to vehicle fuel converter + inherit: interest_rate + base_tech: conversion + carrier_in: biofuel + carrier_out: diesel + flow_out_eff: 0.6 # {{ 1 | unit("MWh_diesel/MWh_biofuel") }} + lifetime: 20 + cost_flow_cap: + data: {{ 0.93 * 1e6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_diesel") }} + index: [[monetary, diesel]] + dims: [costs, carriers] + cost_om_annual: + data: {{ 0.027 * 1e6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_diesel/year") }} + index: [[monetary, diesel]] + dims: [costs, carriers] + {# TODO: triple check this: the number seems too high... #} + cost_flow_out: + data: {{ 1.31 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MWh_diesel") }} + index: [[monetary, diesel]] + dims: [costs, carriers] - # ASSUME: ignore waste low grade heat (which could be used for district heating) - biofuel_to_methane: # [@DEA:2020b] - 84 Biomass to SNG gassifier - 2050 - essentials: - name: Biofuel to Methane converter - parent: conversion - carrier_in: biofuel - carrier_out: methane - constraints: - energy_eff: 0.7 - lifetime: 20 - costs: - monetary: # source gives in terms of carrier_in, so these are scaled by the methane production efficiency - energy_cap: {{ 1.5e6 / 0.7 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_methane") }} - om_annual: {{ 24.1e3 / 0.7 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_methane/year") }} - om_prod: {{ 1.6 / 0.7 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MWh_methane") }} + # ASSUME: ignore waste low grade heat output (which could be used for district heating) + # ASSUME: ignore electricity output, as it can cause numerical trouble. + biofuel_to_methanol: # [@DEA:2020b] - 97 Methanol from biomass gasif. - 2050 + name: Biofuel to Methanol converter + inherit: interest_rate + base_tech: conversion + carrier_in: biofuel + carrier_out: methanol + flow_out_eff: 0.65 # MWh_methanol/MWh_bio + lifetime: 20 + cost_flow_cap: + data: {{ 1.46e6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_methanol") }} + index: [[monetary, methanol]] + dims: [costs, carriers] + cost_om_annual: + data: {{ 0.039e6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_methanol/year") }} + index: [[monetary, methanol]] + dims: [costs, carriers] + cost_flow_out: + data: {{ 13.6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MWh_methanol") }} + index: [[monetary, methanol]] + dims: [costs, carriers] -locations: - {% for id, location in locations.iterrows() %} - {{ id }}.techs: - biofuel_to_liquids: - biofuel_to_diesel: - biofuel_to_methanol: - biofuel_to_methane: - {% endfor %} + # ASSUME: ignore waste low grade heat (which could be used for district heating) + biofuel_to_methane: # [@DEA:2020b] - 84 Biomass to SNG gassifier - 2050 + name: Biofuel to Methane converter + inherit: interest_rate + base_tech: conversion + carrier_in: biofuel + carrier_out: methane + flow_out_eff: 0.7 + lifetime: 20 + # source gives in terms of carrier_in, so these are scaled by the methane production efficiency + cost_flow_cap: + data: {{ 1.5e6 / 0.7 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_methane") }} + index: [[monetary, methane]] + dims: [costs, carriers] + cost_om_annual: + data: {{ 24.1e3 / 0.7 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_methane/year") }} + index: [[monetary, methane]] + dims: [costs, carriers] + cost_flow_out: + data: {{ 1.6 / 0.7 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MWh_methane") }} + index: [[monetary, methane]] + dims: [costs, carriers] + +nodes: + {% for id, location in locations.iterrows() %} + {{ id }}.techs: + biofuel_to_liquids: + biofuel_to_diesel: + biofuel_to_methanol: + biofuel_to_methane: + {% endfor %} diff --git a/templates/models/techs/conversion/synfuels-from-hydrogen.yaml.jinja b/templates/models/techs/conversion/synfuels-from-hydrogen.yaml.jinja index d7026bbd..d3b53e76 100644 --- a/templates/models/techs/conversion/synfuels-from-hydrogen.yaml.jinja +++ b/templates/models/techs/conversion/synfuels-from-hydrogen.yaml.jinja @@ -1,91 +1,117 @@ techs: - # ASSUME: ignore waste low grade heat output (which could be used for district heating) - hydrogen_to_liquids: # [@DEA:2020b] - renewable fuels - 102 Hydrogen to Jet - 2050 - essentials: - name: Hydrogen to liquid fuels converter - parent: conversion_plus - carrier_in: hydrogen - primary_carrier_in: hydrogen - carrier_in_2: electricity - carrier_in_3: co2 - carrier_out: kerosene - carrier_out_2: diesel - primary_carrier_out: kerosene - constraints: - carrier_ratios: - carrier_in.hydrogen: 0.995 # MWh_H2/MWh_in - carrier_in_2.electricity: 0.005 # MWhe/MWh_in - carrier_in_3.co2: {{ 3.3 * 0.75 / 11.9 * scaling_factors.co2 / scaling_factors.power}} # {{ (1 / (scaling_factors.co2 / scaling_factors.power)) | unit("tCO2/(MWhe + MWhH2)") }} | Calculated from source using `tCO2/t_fuels * MWh_fuels/MWh_in / MWh_fuels/t_fuels` - carrier_out.kerosene: {{ 0.75 * 0.6 }} # MWh_kerosene/MWh_in @ 60% liquids content - carrier_out_2.diesel: {{ 0.75 * 0.4 }} # MWh_diesel/MWh_in @ 40% liquids content (combining diesel oil and light oil production) - lifetime: 25 - costs: - monetary: - {# TODO: sense check energy_cap vs om_annual costs #} - energy_cap: {{ 0.9e6 / 0.6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_kerosene") }} | Calculated from source using `MEur/MW_liquids / MW_kerosene/MW_liquids` - om_annual: {{ 7.4 * 8000 / 0.6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_kerosene/year") }} | Calculated from source using `Eur/MWh_liquids * 8000h_operation/year / MW_kerosene/MW_liquids` - om_prod: {{ 2.1 / 0.6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MWh_kerosene") }} | Calculated from source using `Eur/MWh_liquids / MWh_kerosene/MWh_liquids` + # ASSUME: ignore waste low grade heat output (which could be used for district heating) + hydrogen_to_liquids: # [@DEA:2020b] - renewable fuels - 102 Hydrogen to Jet - 2050 + name: Hydrogen to liquid fuels converter + inherit: interest_rate + base_tech: conversion + carrier_in: [hydrogen, electricity, co2] # TODO: custom math to link these carrier flows + carrier_out: [kerosene, diesel] # TODO: custom math to link these carrier flows + co2_consumption: {{ 3.3 * 0.75 / 11.9 * scaling_factors.co2 / scaling_factors.power}} # {{ (1 / (scaling_factors.co2 / scaling_factors.power)) | unit("tCO2/(MWhe + MWhH2)") }} | Calculated from source using `tCO2/t_fuels * MWh_fuels/MWh_in / MWh_fuels/t_fuels` + flow_out_eff: 0.75 + flow_in_share: + data: + - 0.995 # MWh_H2/MWh_in + - 0.005 # MWhe/MWh_in + index: + - hydrogen + - electricity + dims: carriers + flow_out_share: + data: + - 0.6 # MWh_kerosene/MWh_out @ 60% liquids content + - 0.4 # MWh_diesel/MWh_out @ 40% liquids content (combining diesel oil and light oil production) + index: + - kerosene + - diesel + dims: carriers + lifetime: 25 + {# TODO: sense check energy_cap vs om_annual costs #} + cost_flow_cap: + data: {{ 0.9e6 / 0.6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_kerosene") }} | Calculated from source using `MEur/MW_liquids / MW_kerosene/MW_liquids` + index: [[kerosene, monetary]] + dims: [carriers, costs] + cost_om_annual: + data: {{ 7.4 * 8000 / 0.6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_kerosene/year") }} | Calculated from source using `Eur/MWh_liquids * 8000h_operation/year / MW_kerosene/MW_liquids` + index: [[kerosene, monetary]] + dims: [carriers, costs] + cost_flow_out: + data: {{ 2.1 / 0.6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MWh_kerosene") }} | Calculated from source using `Eur/MWh_liquids / MWh_kerosene/MWh_liquids` + index: [[kerosene, monetary]] + dims: [carriers, costs] - # ASSUME: Can run intermittently - hydrogen_to_methanol: # [@DEA:2020b] - renewable fuels - 98 Methanol from power - 2050 - essentials: - name: Hydrogen to Methanol converter - parent: conversion_plus - carrier_in: hydrogen - primary_carrier_in: hydrogen - carrier_in_2: co2 - carrier_out: methanol - constraints: - energy_eff: {{ 1 / (0.192 * 33.3 / 5.583) }} # MWhMethanol/MWhH2 | Calculated from source using `1 / (tH2/tMethanol * MWhH2/tH2 / MWhMethanol/tMethanol)` - carrier_ratios: - carrier_in_2.co2: {{ 1.37 / 0.192 / 33.3 * scaling_factors.co2 / scaling_factors.power }} # {{ (1 / (scaling_factors.co2 / scaling_factors.power)) | unit("tCO2/MWH2") }} | Calculated from source using `tCO2/tMethanol / tH2/tMethanol / MWhH2/tH2` - lifetime: 20 - costs: - monetary: - energy_cap: {{ 1.5e6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_methanol") }} - om_annual: {{ 0.053e6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_methanol/year") }} - om_prod: {{ 6.27 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MWh_methanol") }} + # ASSUME: Can run intermittently + hydrogen_to_methanol: # [@DEA:2020b] - renewable fuels - 98 Methanol from power - 2050 + name: Hydrogen to Methanol converter + inherit: interest_rate + base_tech: conversion + carrier_in: [hydrogen, co2] # TODO: custom math to link these carrier flows + carrier_out: methanol + flow_out_eff: {{ 1 / (0.192 * 33.3 / 5.583) }} # MWhMethanol/MWhH2 | Calculated from source using `1 / (tH2/tMethanol * MWhH2/tH2 / MWhMethanol/tMethanol)` + co2_consumption: {{ 1.37 / 0.192 / 33.3 * scaling_factors.co2 / scaling_factors.power }} # {{ (1 / (scaling_factors.co2 / scaling_factors.power)) | unit("tCO2/MWH2") }} | Calculated from source using `tCO2/tMethanol / tH2/tMethanol / MWhH2/tH2` + lifetime: 20 + cost_flow_cap: + data: {{ 1.5e6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_methanol") }} + index: [[methanol, monetary]] + dims: [carriers, costs] + cost_om_annual: + data: {{ 0.053e6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_methanol/year") }} + index: [[methanol, monetary]] + dims: [carriers, costs] + cost_flow_out: + data: {{ 6.27 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MWh_methanol") }} + index: [[methanol, monetary]] + dims: [carriers, costs] - hydrogen_to_methane: # [@Boehm:2020] - 2050 - essentials: - name: Hydrogen to Methane converter - parent: conversion_plus - carrier_in: hydrogen - primary_carrier_in: hydrogen - carrier_in_2: co2 - carrier_out: methane - constraints: - energy_eff: 0.826 # MW_methane/MW_H2 - carrier_ratios: - carrier_in_2.co2: {{ 0.196 / 1.21 * scaling_factors.co2 / scaling_factors.power }} # {{ (1 / (scaling_factors.co2 / scaling_factors.power)) | unit("tCO2/MW_in") }} | calculated from source using `tCO2/MW_methane / MW_H2/MW_methane` - lifetime: 20 - costs: - monetary: - interest_rate: 0.04 - energy_cap: {{ 0.3e6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_methane") }} |average of catalytic and biological processes - om_annual: {{ 0.0344e6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_methane/year") }} - om_annual_investment_fraction: 0.05 # 5% of annual CAPEX + hydrogen_to_methane: # [@Boehm:2020] - 2050 + name: Hydrogen to Methane converter + base_tech: conversion + carrier_in: [hydrogen, co2] + carrier_out: methane + flow_out_eff: 0.826 # MW_methane/MW_H2 + co2_consumption: {{ 0.196 / 1.21 * scaling_factors.co2 / scaling_factors.power }} # {{ (1 / (scaling_factors.co2 / scaling_factors.power)) | unit("tCO2/MW_in") }} | calculated from source using `tCO2/MW_methane / MW_H2/MW_methane` + lifetime: 20 + cost_interest_rate: + data: 0.04 + index: monetary + dims: costs + cost_flow_cap: + data: {{ 0.3e6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_methane") }} |average of catalytic and biological processes + index: [[methane, monetary]] + dims: [carriers, costs] + cost_om_annual: + data: {{ 0.0344e6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW_methane/year") }} + index: [[methane, monetary]] + dims: [carriers, costs] + cost_om_annual_investment_fraction: + data: 0.05 # 5% of annual CAPEX + index: monetary + dims: costs - dac: # [@Fasihi:2019] - Low T - 2050 - essentials: - name: Direct air CO2 capture - parent: conversion - carrier_in: electricity - carrier_out: co2 - constraints: - energy_eff: {{ 5 * scaling_factors.co2 / scaling_factors.power }} # {{ (1 / (scaling_factors.co2 / scaling_factors.power)) | unit("tCO2/MWh") }} - lifetime: 30 - costs: - monetary: - interest_rate: 0.07 - energy_cap: {{ 1.592e6 * scaling_factors.monetary / scaling_factors.co2 }} # {{ (1 / (scaling_factors.monetary / scaling_factors.co2)) | unit("EUR2015/tCO2") }}, 199 Eur/tCO2/y -> 199 Eur/0.125kgCO2/h (8000 operational hours) -> 1592Eur/kgCO2 -> 1.592x10^6 Eur/tCO2 - om_annual_investment_fraction: 0.04 # 3.7% of annual CAPEX + dac: # [@Fasihi:2019] - Low T - 2050 + name: Direct air CO2 capture + base_tech: conversion + carrier_in: electricity + carrier_out: co2 + flow_out_eff: {{ 5 * scaling_factors.co2 / scaling_factors.power }} # {{ (1 / (scaling_factors.co2 / scaling_factors.power)) | unit("tCO2/MWh") }} + lifetime: 30 + cost_interest_rate: + data: 0.07 + index: monetary + dims: costs + cost_flow_cap: + data: {{ 1.592e6 * scaling_factors.monetary / scaling_factors.co2 }} # {{ (1 / (scaling_factors.monetary / scaling_factors.co2)) | unit("EUR2015/tCO2") }}, 199 Eur/tCO2/y -> 199 Eur/0.125kgCO2/h (8000 operational hours) -> 1592Eur/kgCO2 -> 1.592x10^6 Eur/tCO2 + index: [[monetary, co2]] + dims: [costs, carriers] + cost_om_annual_investment_fraction: + data: 0.04 # 3.7% of annual CAPEX + index: monetary + dims: costs -locations: - {% for id, location in locations.iterrows() %} - {{ id }}.techs: - hydrogen_to_liquids: - hydrogen_to_methanol: - hydrogen_to_methane: - dac: - {% endfor %} +nodes: + {% for id, location in locations.iterrows() %} + {{ id }}.techs: + hydrogen_to_liquids: + hydrogen_to_methanol: + hydrogen_to_methane: + dac: + {% endfor %} diff --git a/templates/models/techs/demand/electricity.yaml.jinja b/templates/models/techs/demand/electricity.yaml.jinja index f526454a..9df278f5 100644 --- a/templates/models/techs/demand/electricity.yaml.jinja +++ b/templates/models/techs/demand/electricity.yaml.jinja @@ -1,13 +1,19 @@ techs: - demand_elec: - essentials: - name: 'Electricity demand' - parent: demand - carrier: electricity - constraints: - resource: file=demand/electricity.csv + demand_elec: + name: 'Electricity demand' + base_tech: demand + carrier_in: electricity -locations: - {% for id, location in locations.iterrows() %} - {{ id }}.techs.demand_elec: - {% endfor %} +data_sources: + demand_electricity: + source: timeseries/demand/electricity.csv + rows: timesteps + columns: nodes + add_dimensions: + techs: demand_elec + parameters: sink_use_equals + +nodes: + {% for id, location in locations.iterrows() %} + {{ id }}.techs.demand_elec: + {% endfor %} diff --git a/templates/models/techs/demand/electrified-heat.yaml.jinja b/templates/models/techs/demand/electrified-heat.yaml.jinja index 027845c1..09d11f15 100644 --- a/templates/models/techs/demand/electrified-heat.yaml.jinja +++ b/templates/models/techs/demand/electrified-heat.yaml.jinja @@ -1,13 +1,18 @@ techs: - demand_heat_electrified: - essentials: - name: Electrified heat demand - parent: demand - carrier: electricity - constraints: - resource: file=demand/electrified-heat.csv + demand_heat_electrified: + name: Electrified heat demand + base_tech: demand + carrier_in: electricity -locations: - {% for id, location in locations.iterrows() %} - {{ id }}.techs.demand_heat_electrified: - {% endfor %} +data_sources: + demand_electrified_heat: + source: timeseries/demand/electrified-heat.csv + rows: timesteps + columns: nodes + add_dimensions: + techs: demand_heat_electrified + parameters: sink_use_equals +nodes: + {% for id, location in locations.iterrows() %} + {{ id }}.techs.demand_heat_electrified: + {% endfor %} diff --git a/templates/models/techs/demand/electrified-transport.yaml.jinja b/templates/models/techs/demand/electrified-transport.yaml.jinja index 59d74107..eeefc6a7 100644 --- a/templates/models/techs/demand/electrified-transport.yaml.jinja +++ b/templates/models/techs/demand/electrified-transport.yaml.jinja @@ -1,95 +1,100 @@ techs: - demand_road_transport_electrified_uncontrolled: - essentials: - name: 'Uncontrolled electrified road transport demand -- follows a timeseries' - parent: demand - carrier: electricity - constraints: - resource: file=demand/uncontrolled-electrified-road-transport.csv + demand_road_transport_electrified_uncontrolled: + name: 'Uncontrolled electrified road transport demand -- follows a timeseries' + base_tech: demand + carrier_in: electricity - demand_road_transport_historic_electrified_uncontrolled: - essentials: - name: 'Removes historic electrified road transport demand from ENTSOE-derived historical electricity demand profile -- assumed uncontrolled' - parent: supply - carrier: electricity - constraints: - resource: file=demand/uncontrolled-road-transport-historic-electrification.csv - force_resource: true + demand_road_transport_historic_electrified_uncontrolled: + name: 'Removes historic electrified road transport demand from ENTSOE-derived historical electricity demand profile -- assumed uncontrolled' + base_tech: supply + carrier_out: electricity - demand_road_transport_electrified_controlled: - essentials: - name: 'Controlled electrified road transport demand' - parent: demand - carrier: electricity - constraints: - force_resource: false - resource: -.inf + demand_road_transport_electrified_controlled: + name: 'Controlled electrified road transport demand' + base_tech: demand + carrier_in: electricity - road_transport_controlled_dummy: - exists: false - essentials: - name: 'Dummy tech for controlled road transport demand -- required for max potential charging and demand shape' - parent: conversion - carrier_in: electricity - carrier_out: electricity - constraints: - energy_eff: 1 - energy_cap_max_time_varying: file=demand/plugin-profiles-ev.csv -overrides: - keep-historic-electricity-demand-from-road-transport: - {# TODO: possibly remove this override as there may be no use-cases for it. #} - {% for id, location in locations.iterrows() %} - {{ id }}.techs.demand_road_transport_historic_electrified_uncontrolled.exists: false - {% endfor %} +data_sources: + demand_uncontrolled_electrified_road_transport: + source: timeseries/demand/uncontrolled-electrified-road-transport.csv + rows: timesteps + columns: nodes + add_dimensions: + techs: demand_road_transport_electrified_uncontrolled + parameters: sink_use_equals - {% for year in locations.columns %} - {% if "demand" in year %} - {{ year }}_transport_controlled_electrified: - group_constraints: - {% for location in locations.index %} - {{ location }}_annual_controlled_electricity: - locs: [{{ location }}] - techs: [demand_road_transport_electrified_controlled] - carrier_con_equals: - electricity: {{ locations.loc[location, year] }} # {{ (1 / scaling_factors.power) | unit("MWh") }} + demand_uncontrolled_road_transport_historic_electrification: + source: timeseries/demand/uncontrolled-road-transport-historic-electrification.csv + rows: timesteps + columns: nodes + add_dimensions: + techs: demand_road_transport_historic_electrified_uncontrolled + parameters: source_use_equals + +overrides: + keep_historic_electricity_demand_from_road_transport: + {# TODO: possibly remove this override as there may be no use-cases for it. #} + {% for id, location in locations.iterrows() %} + nodes.{{ id }}.techs.demand_road_transport_historic_electrified_uncontrolled.active: false {% endfor %} - {% endif %} + + {% for year in locations.columns %} + {% if "demand" in year %} + {{ year }}_transport_controlled_electrified: + nodes: + {% for id in locations.index %} + {{ id }}.techs.demand_road_transport_electrified_controlled: + flow_in_total: {{ locations.loc[id, year] }} # {{ (1 / scaling_factors.power) | unit("MWh") }} {% endfor %} + {% endif %} + {% endfor %} - monthly_transport_demand_range: - techs: - demand_road_transport_electrified_controlled: - constraints: - demand_shape_per_month_min_time_varying: file=demand/demand-shape-min-ev.csv - demand_shape_per_month_max_time_varying: file=demand/demand-shape-max-ev.csv + monthly_transport_demand_range: + data_sources: + demand_shape_min_ev: + source: timeseries/demand/demand-shape-min-ev.csv + rows: monthsteps + columns: nodes + add_dimensions: + techs: demand_road_transport_electrified_controlled + parameters: flow_in_per_month_min + demand_shape_max_ev: + source: timeseries/demand/demand-shape-max-ev.csv + rows: monthsteps + columns: nodes + add_dimensions: + techs: demand_road_transport_electrified_controlled + parameters: flow_in_per_month_max - monthly_transport_demand_equality: - techs: - demand_road_transport_electrified_controlled: - constraints: - demand_shape_per_month_equals_time_varying: file=demand/demand-shape-equals-ev.csv - {% for year in locations.columns %} - {% if "charging" in year %} - {{ year }}_max_ev_potential: - techs: - road_transport_controlled_dummy.exists: true - locations: - {% for location in locations.index %} - {{ location }}: - techs: - road_transport_controlled_dummy: - constraints: - energy_cap_max: {{ locations.loc[location, year] }} # {{ (1 / scaling_factors.transport) | unit("Mio km") }} - {% endfor %} - {% endif %} + {% for year in locations.columns %} + {% if "charging" in year %} + {{ year }}_max_ev_potential: + demand_plugin_profiles_ev: + source: timeseries/demand/plugin-profiles-ev.csv + rows: timesteps + columns: nodes + add_dimensions: + techs: road_transport_controlled_dummy + parameters: energy_cap_max_varying + techs: + road_transport_controlled_dummy: + name: 'Dummy tech for controlled road transport demand -- required for max potential charging and demand shape' + base_tech: conversion + carrier_in: electricity + carrier_out: electricity + nodes: + {% for id in locations.index %} + {{ id }}.techs.road_transport_controlled_dummy.flow_cap_max: {{ locations.loc[id, year] }} # {{ (1 / scaling_factors.transport) | unit("Mio km") }} {% endfor %} + {% endif %} + {% endfor %} -locations: - {% for id, location in locations.iterrows() %} - {{ id }}.techs: - demand_road_transport_electrified_uncontrolled: - demand_road_transport_historic_electrified_uncontrolled: - demand_road_transport_electrified_controlled: - {% endfor %} +nodes: + {% for id, location in locations.iterrows() %} + {{ id }}.techs: + demand_road_transport_electrified_uncontrolled: + demand_road_transport_historic_electrified_uncontrolled: + demand_road_transport_electrified_controlled: + {% endfor %} diff --git a/templates/models/techs/demand/heat.yaml.jinja b/templates/models/techs/demand/heat.yaml.jinja index 164690fa..d9bf159f 100644 --- a/templates/models/techs/demand/heat.yaml.jinja +++ b/templates/models/techs/demand/heat.yaml.jinja @@ -1,20 +1,19 @@ -tech_groups: - tech_heat_to_demand: - essentials: - name: Technology-specific heat carriers to generic heat carrier converter - parent: conversion - carrier_out: heat - techs: - demand_heat: - essentials: - name: Heat demand - parent: demand - carrier: heat - constraints: - resource: file=demand/heat.csv + demand_heat: + name: Heat demand + base_tech: demand + carrier_in: heat + +data_sources: + demand_heat: + source: timeseries/demand/heat.csv + rows: timesteps + columns: nodes + add_dimensions: + techs: demand_heat + parameters: sink_use_equals -locations: - {% for id, location in locations.iterrows() %} - {{ id }}.techs.demand_heat: - {% endfor %} +nodes: + {% for id, location in locations.iterrows() %} + {{ id }}.techs.demand_heat: + {% endfor %} diff --git a/templates/models/techs/storage/electricity.yaml.jinja b/templates/models/techs/storage/electricity.yaml.jinja index 5a984169..be2a8521 100644 --- a/templates/models/techs/storage/electricity.yaml.jinja +++ b/templates/models/techs/storage/electricity.yaml.jinja @@ -1,48 +1,66 @@ techs: - battery: # from [@schmidt:2019] Table S4 - essentials: - name: 'Battery storage' - parent: storage - carrier: electricity - constraints: - energy_cap_max: inf - storage_cap_max: inf - energy_eff: 0.9273 # 0.86 round trip efficiency - storage_loss: 0 # No loss over time assumed - lifetime: 10 - costs.monetary: - storage_cap: {{ 723130 * 0.14 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MWh") }}, 802 $2015 - energy_cap: {{ 611324 * 0.14 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW") }}, 678 $2015 - om_annual: {{ 9016 * 0.14 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW/year") }}, 10 $2015 - om_prod: {{ 2.7 * 0.14 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MWh") }}, 3 $2015 + battery: # from [@schmidt:2019] Table S4 + name: 'Battery storage' + inherit: interest_rate + base_tech: storage + carrier_in: electricity + carrier_out: electricity + # 0.86 round trip efficiency + flow_in_eff: 0.9273 + flow_out_eff: 0.9273 + storage_loss: 0 # No loss over time assumed + lifetime: 10 + cost_storage_cap: + data: {{ 723130 * 0.14 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MWh") }}, 802 $2015 + index: monetary + dims: costs + cost_flow_cap: + data: {{ 611324 * 0.14 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW") }}, 678 $2015 + index: monetary + dims: costs + cost_om_annual: + data: {{ 9016 * 0.14 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW/year") }}, 10 $2015 + index: monetary + dims: costs + cost_flow_out: + data: {{ 2.7 * 0.14 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MWh") }}, 3 $2015 + index: monetary + dims: costs - hydrogen: # from [@schmidt:2019] Table S4 - essentials: - name: Hydrogen power storage - parent: storage - carrier: electricity - constraints: - energy_cap_max: inf - storage_cap_max: inf - energy_eff: 0.6325 # 0.40 round-trip - lifetime: 15 - costs.monetary: - storage_cap: {{ 27951 * 0.33 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MWh") }}, 31 $2015 - energy_cap: {{ 4884287 * 0.33 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW") }}, 5417 $2015 - om_annual: {{ 41476 * 0.33 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW/year") }}, 46 $2015 - om_prod: 0 + hydrogen: # from [@schmidt:2019] Table S4 + name: Hydrogen power storage + inherit: interest_rate + base_tech: storage + carrier_in: electricity + carrier_out: electricity + # 0.40 round-trip + flow_in_eff: 0.6325 + flow_out_eff: 0.6325 + lifetime: 15 + cost_storage_cap: + data: {{ 27951 * 0.33 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MWh") }}, 31 $2015 + index: monetary + dims: costs + cost_flow_cap: + data: {{ 4884287 * 0.33 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW") }}, 5417 $2015 + index: monetary + dims: costs + cost_om_annual: + data: {{ 41476 * 0.33 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW/year") }}, 46 $2015 + index: monetary + dims: costs overrides: - exclusive-energy-to-power-ratios: - # Ensures exclusive energy to power ratios of battery (≤4h) and hydrogen (≥4h) storage. - techs: - battery.constraints.energy_cap_per_storage_cap_min: 0.25 # ≤ 4h full-power discharge - hydrogen.constraints.energy_cap_per_storage_cap_max: 0.25 # ≥ 4h full-power discharge + exclusive_energy_to_power_ratios: + # Ensures exclusive energy to power ratios of battery (≤4h) and hydrogen (≥4h) storage. + techs: + battery.flow_cap_per_storage_cap_min: 0.25 # ≤ 4h full-power discharge + hydrogen.flow_cap_per_storage_cap_max: 0.25 # ≥ 4h full-power discharge -locations: - {% for id, location in locations.iterrows() %} - {{ id }}.techs: - battery: - hydrogen: - {% endfor %} +nodes: + {% for id, location in locations.iterrows() %} + {{ id }}.techs: + battery: + hydrogen: + {% endfor %} diff --git a/templates/models/techs/storage/heat.yaml.jinja b/templates/models/techs/storage/heat.yaml.jinja index 51aea3de..b15dea7d 100644 --- a/templates/models/techs/storage/heat.yaml.jinja +++ b/templates/models/techs/storage/heat.yaml.jinja @@ -1,36 +1,42 @@ tech_groups: - heat_storage_small: # [@DEA:2019] - energy storage - 142 small scale hot water tank - 2050 - essentials: - name: Small hot water tank - parent: storage - constraints: - energy_cap_per_storage_cap_max: 6.67 # 20kW/3kWh - storage_loss: 0.021 # fraction / hour - lifetime: 30 - costs: - monetary: - # Source also gives om_prod and purchase costs, but the former is in terms of storage cap - storage_cap: {{ 0.41e6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MWh_heat") }} + heat_storage_small: # [@DEA:2019] - energy storage - 142 small scale hot water tank - 2050 + base_tech: storage + carrier_in: heat + carrier_out: heat + inherit: interest_rate + flow_cap_per_storage_cap_max: 6.67 # 20kW/3kWh + storage_loss: 0.021 # fraction / hour + lifetime: 30 + # Source also gives om_prod and purchase costs, but the former is in terms of storage cap + cost_storage_cap: + data: {{ 0.41e6 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MWh_heat") }} + index: monetary + dims: costs techs: - hp_heat_storage_small: - essentials.parent: heat_storage_small - essentials.carrier: hp_heat - electric_heater_heat_storage_small: - essentials.parent: heat_storage_small - essentials.carrier: electric_heater_heat - biofuel_heat_storage_small: - essentials.parent: heat_storage_small - essentials.carrier: biofuel_heat - methane_heat_storage_small: - essentials.parent: heat_storage_small - essentials.carrier: methane_heat + methane_boiler_storage: + name: Small hot water tank linked to methane boilers + inherit: heat_storage_small + biofuel_boiler_storage: + name: Small hot water tank linked to biofuel boilers + inherit: heat_storage_small + heat_pump_storage: + name: Small hot water tank linked to heat pumps + inherit: heat_storage_small + electric_heater_storage: + name: Small hot water tank linked to electric heaters + inherit: heat_storage_small -locations: - {% for id, location in locations.iterrows() %} - {{ id }}.techs: - hp_heat_storage_small: - electric_heater_heat_storage_small: - biofuel_heat_storage_small: - methane_heat_storage_small: - {% endfor %} +parameters: + lookup_linked_storage_tech: + data: [methane_boiler, biofuel_boiler, heat_pump, electric_heater] + index: [methane_boiler_storage, biofuel_boiler_storage, heat_pump_storage, electric_heater_storage] + dims: techs +nodes: + {% for id, location in locations.iterrows() %} + {{ id }}.techs: + methane_boiler_storage: + biofuel_boiler_storage: + heat_pump_storage: + electric_heater_storage: + {% endfor %} diff --git a/templates/models/techs/storage/hydro.yaml.jinja b/templates/models/techs/storage/hydro.yaml.jinja index e308c6b9..47ae2386 100644 --- a/templates/models/techs/storage/hydro.yaml.jinja +++ b/templates/models/techs/storage/hydro.yaml.jinja @@ -1,41 +1,50 @@ techs: - pumped_hydro: # from [@schmidt:2019] Table S4 - essentials: - name: 'Pumped hydro power storage' - parent: storage - carrier: electricity - constraints: - energy_cap_max: inf - storage_cap_max: inf - energy_eff: 0.8832 # 0.78 round-trip - lifetime: 55 - costs.monetary: - storage_cap: {{ 72133 * 1.02 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MWh") }}, 80 $2015 - energy_cap: {{ 1017973 * 1.02 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW") }}, 1129 $2015 - om_annual: {{ 7213 * 1.02 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW/year") }}, 8 $2015 - om_prod: {{ 1 * 1.02 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MWh") }}, 1 $2015, rounded to 1€ for numeric range + pumped_hydro: # from [@schmidt:2019] Table S4 + name: 'Pumped hydro power storage' + inherit: interest_rate + base_tech: storage + carrier_in: electricity + carrier_out: electricity + # 0.78 round-trip efficiency + flow_out_eff: 0.8832 + flow_in_eff: 0.8832 + lifetime: 55 + cost_storage_cap: + data: {{ 72133 * 1.02 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MWh") }}, 80 $2015 + index: monetary + dims: costs + cost_flow_cap: + data: {{ 1017973 * 1.02 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW") }}, 1129 $2015 + index: monetary + dims: costs + cost_om_annual: + data: {{ 7213 * 1.02 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW/year") }}, 8 $2015 + index: monetary + dims: costs + cost_flow_out: + data: {{ 1 * 1.02 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MWh") }}, 1 $2015, rounded to 1€ for numeric range + index: monetary + dims: costs overrides: - no-hydro-storage-fixed-cost: - # Only assign costs to O&M and variable costs - techs.pumped_hydro.costs.monetary: - storage_cap: 0 - energy_cap: 0 - freeze-hydro-storage-capacities: - locations: - {% for id, location in locations.iterrows() %} - {{ id }}.techs: - pumped_hydro: - constraints: - energy_cap_equals: {{ location.installed_capacity_hphs_MW * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MW") }} - storage_cap_equals: {{ location.storage_capacity_hphs_MWh * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MWh") }} - {% endfor %} + no_hydro_storage_fixed_cost: + # Only assign costs to O&M and variable costs + techs.pumped_hydro: + cost_storage_cap.data: 0 + cost_flow_cap.data: 0 + freeze_hydro_storage_capacities: + nodes: + {% for id, location in locations.iterrows() %} + {{ id }}.techs: + pumped_hydro: + flow_cap_min: {{ location.installed_capacity_hphs_MW * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MW") }} + storage_cap_min: {{ location.storage_capacity_hphs_MWh * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MWh") }} + {% endfor %} -locations: - {% for id, location in locations.iterrows() %} - {{ id }}.techs: - pumped_hydro: - constraints: - energy_cap_max: {{ location.installed_capacity_hphs_MW * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MW") }} - storage_cap_max: {{ location.storage_capacity_hphs_MWh * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MWh") }} - {% endfor %} +nodes: + {% for id, location in locations.iterrows() %} + {{ id }}.techs: + pumped_hydro: + flow_cap_max: {{ location.installed_capacity_hphs_MW * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MW") }} + storage_cap_max: {{ location.storage_capacity_hphs_MWh * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MWh") }} + {% endfor %} diff --git a/templates/models/techs/supply/biofuel.yaml.jinja b/templates/models/techs/supply/biofuel.yaml.jinja index 8a8e353b..179d076e 100644 --- a/templates/models/techs/supply/biofuel.yaml.jinja +++ b/templates/models/techs/supply/biofuel.yaml.jinja @@ -1,16 +1,18 @@ techs: - biofuel_supply: - essentials: - name: Biofuel supply stream - parent: supply_plus - carrier: biofuel - costs.monetary: - om_prod: {{ biofuel_cost * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR/MWh") }} + biofuel_supply: + name: Biofuel supply stream + base_tech: supply + carrier_out: biofuel + include_storage: true + cost_flow_out: + data: {{ biofuel_cost * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR/MWh") }} + index: monetary + dims: costs -locations: - {% for id, location in locations.iterrows() %} - {{ id }}.techs.biofuel_supply: - constraints: - resource: {{ location.biofuel_potential_mwh_per_year / 8760 * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MWh") }} - storage_cap_equals: {{ location.biofuel_potential_mwh_per_year / 2 * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MWh") }} (0.5x annual yield) # ASSUME < 1 for numerical range - {% endfor %} +nodes: + {% for id, location in locations.iterrows() %} + {{ id }}.techs.biofuel_supply: + source_use_max: {{ location.biofuel_potential_mwh_per_year / 8760 * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MWh") }} + storage_cap_min: {{ location.biofuel_potential_mwh_per_year / 2 * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MWh") }} (0.5x annual yield) # ASSUME < 1 for numerical range + storage_cap_max: {{ location.biofuel_potential_mwh_per_year / 2 * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MWh") }} (0.5x annual yield) # ASSUME < 1 for numerical range + {% endfor %} diff --git a/templates/models/techs/supply/electrified-biofuel.yaml.jinja b/templates/models/techs/supply/electrified-biofuel.yaml.jinja index 7ebd3b4c..b31c40aa 100644 --- a/templates/models/techs/supply/electrified-biofuel.yaml.jinja +++ b/templates/models/techs/supply/electrified-biofuel.yaml.jinja @@ -1,23 +1,32 @@ techs: - electrified_biofuel: # from [@JRC:2014] Table 48 Anaerobic digestion - essentials: - name: Biofuel-derived electricity - parent: supply_plus - carrier: electricity - constraints: - energy_eff: 1.0 # efficiency modelled within the input resource stream to avoid poor numerical scaling - lifetime: 20 - costs.monetary: - energy_cap: {{2300000 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} - om_annual: {{2300000 * 0.041 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} 4.1% of CAPEX - om_con: {{ (biofuel_cost / biofuel_efficiency + 3.1) * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} - om_prod: 0 # 3.1 (EUR2013/MWh) added to om_con because value is very small and causing poor numerical range + electrified_biofuel: # from [@JRC:2014] Table 48 Anaerobic digestion + name: Biofuel-derived electricity + base_tech: supply + carrier_out: electricity + lifetime: 20 + include_storage: true + cost_flow_cap: + data: {{2300000 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} + index: monetary + dims: costs + cost_om_annual: + data: {{2300000 * 0.041 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} 4.1% of CAPEX + index: monetary + dims: costs + cost_flow_in: + data: {{ (biofuel_cost / biofuel_efficiency + 3.1) * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} + index: monetary + dims: costs + cost_flow_out: + data: 0 # 3.1 (EUR2013/MWh) added to om_con because value is very small and causing poor numerical range + index: monetary + dims: costs -locations: - {% for id, location in locations.iterrows() %} - {{ id }}.techs: - electrified_biofuel: - constraints: - resource: {{ location.biofuel_potential_mwh_per_year * biofuel_efficiency / 8760 * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MW") }} - storage_cap_equals: {{ location.biofuel_potential_mwh_per_year * biofuel_efficiency / 2 * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MWh") }} (0.5x annual yield) # ASSUME < 1 for numerical range - {% endfor %} +nodes: + {% for id, location in locations.iterrows() %} + {{ id }}.techs: + electrified_biofuel: + source_use_max: {{ location.biofuel_potential_mwh_per_year * biofuel_efficiency / 8760 * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MW") }} + storage_cap_min: {{ location.biofuel_potential_mwh_per_year * biofuel_efficiency / 2 * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MWh") }} (0.5x annual yield) # ASSUME < 1 for numerical range + storage_cap_max: {{ location.biofuel_potential_mwh_per_year * biofuel_efficiency / 2 * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MWh") }} (0.5x annual yield) # ASSUME < 1 for numerical range + {% endfor %} diff --git a/templates/models/techs/supply/historic-electrified-heat.yaml.jinja b/templates/models/techs/supply/historic-electrified-heat.yaml.jinja index 915b4fa4..5817f29f 100644 --- a/templates/models/techs/supply/historic-electrified-heat.yaml.jinja +++ b/templates/models/techs/supply/historic-electrified-heat.yaml.jinja @@ -1,14 +1,19 @@ techs: - historic_electrified_heat: - essentials: - name: Removes historic electrified heat demand from the electricity demand profile - parent: supply - carrier: electricity - constraints: - resource: file=supply/historic-electrified-heat.csv - force_resource: true + historic_electrified_heat: + name: Removes historic electrified heat demand from the electricity demand profile + base_tech: supply + carrier_out: electricity -locations: - {% for id, location in locations.iterrows() %} - {{ id }}.techs.historic_electrified_heat: - {% endfor %} +data_sources: + historic_electrified_heat: + source: timeseries/supply/historic-electrified-heat.csv + rows: timesteps + columns: nodes + add_dimensions: + techs: historic_electrified_heat + parameters: source_use_equals + +nodes: + {% for id, location in locations.iterrows() %} + {{ id }}.techs.historic_electrified_heat: + {% endfor %} diff --git a/templates/models/techs/supply/hydro.yaml.jinja b/templates/models/techs/supply/hydro.yaml.jinja index 76850c64..4544f407 100644 --- a/templates/models/techs/supply/hydro.yaml.jinja +++ b/templates/models/techs/supply/hydro.yaml.jinja @@ -1,77 +1,116 @@ techs: - hydro_run_of_river: # from [@JRC:2014] Table 14 - essentials: - name: Run of river hydro electricity - parent: supply - carrier: electricity - constraints: - resource: file=supply/capacityfactors-hydro-run-of-river.csv - resource_unit: energy_per_cap - lifetime: 60 - costs.monetary: - energy_cap: {{5620000 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} - om_annual: {{5620000 * 0.03 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} 3% of CAPEX - om_prod: {{5 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} - hydro_reservoir: # from [@JRC:2014] Table 12 - essentials: - name: Hydro electricity with a reservoir. - parent: supply_plus - carrier: electricity - constraints: - resource: file=supply/capacityfactors-hydro-reservoir.csv - resource_unit: energy_per_cap - lifetime: 60 - costs.monetary: - energy_cap: {{3370000 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} - om_annual: {{3370000 * 0.03 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} 3% of CAPEX - om_prod: {{5 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} + hydro_run_of_river: # from [@JRC:2014] Table 14 + name: Run of river hydro electricity + inherit: interest_rate + base_tech: supply + carrier_out: electricity + source_unit: per_cap + lifetime: 60 + cost_flow_cap: + data: {{5620000 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} + index: monetary + dims: costs + cost_om_annual: + data: {{5620000 * 0.03 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} 3% of CAPEX + index: monetary + dims: costs + cost_flow_out: + data: {{5 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} + index: monetary + dims: costs + hydro_reservoir: # from [@JRC:2014] Table 12 + name: Hydro electricity with a reservoir. + inherit: interest_rate + base_tech: supply + carrier_out: electricity + source_unit: per_cap + include_storage: true + lifetime: 60 + cost_flow_cap: + data: {{3370000 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} + index: monetary + dims: costs + cost_om_annual: + data: {{3370000 * 0.03 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} 3% of CAPEX + index: monetary + dims: costs + cost_flow_out: + data: {{5 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} + index: monetary + dims: costs -overrides: - no-hydro-supply-fixed-cost: - # Only assign costs to O&M and variable costs - techs.hydro_run_of_river.costs.monetary: - energy_cap: 0 - om_con: 0 - techs.hydro_reservoir.costs.monetary: - energy_cap: 0 - storage_cap: 0 - om_con: 0 +data_sources: + capacityfactors_hydro_run_of_river: + source: timeseries/supply/capacityfactors-hydro-run-of-river.csv + rows: timesteps + columns: nodes + add_dimensions: + techs: hydro_run_of_river + parameters: source_use_max + capacityfactors_hydro_reservoir: + source: timeseries/supply/capacityfactors-hydro-reservoir.csv + rows: timesteps + columns: nodes + add_dimensions: + techs: hydro_reservoir + parameters: source_use_max - schroeder-hydro-cost: # from [@schroeder:2013] - techs.hydro_run_of_river: - constraints.lifetime: 60 - costs.monetary: - energy_cap: {{ 3000000 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2010/MW") }} Table 33 - om_annual: {{ (60000 - 1 * 8760 * capacity_factors.ror) * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2010/MW") }} Table 34 - om_prod: {{ 1 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2010/MW") }} stolen from om_annual for technical reasons - techs.hydro_reservoir: - constraints.lifetime: 60 - costs.monetary: - energy_cap: {{ 2000000 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2010/MW") }} Table 33 - om_annual: {{ (20000 - 1 * 8760 * capacity_factors.ror) * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2010/MW") }} Table 34 - om_prod: {{ 1 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2010/MW") }} stolen from om_annual for technical reasons +overrides: + no_hydro_supply_fixed_cost: + # Only assign costs to O&M and variable costs + techs.hydro_run_of_river: + cost_flow_cap.data: 0 + techs.hydro_reservoir: + cost_flow_cap.data: 0 - freeze-hydro-supply-capacities: - locations: - {% for id, location in locations.iterrows() %} - {{ id }}.techs: # {{ location["name"] }} - hydro_run_of_river: - constraints: - energy_cap_equals: {{ location.installed_capacity_hror_MW * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MW") }} - hydro_reservoir: - constraints: - energy_cap_equals: {{ location.installed_capacity_hdam_MW * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MW") }} - storage_cap_equals: {{ location.storage_capacity_hdam_MWh * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MWh") }} - {% endfor %} + schroeder_hydro_cost: # from [@schroeder:2013] + techs: + hydro_run_of_river: + lifetime: 60 + cost_flow_cap: + data: {{ 3000000 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2010/MW") }} Table 33 + index: monetary + dims: costs + cost_om_annual: + data: {{ (60000 - 1 * 8760 * capacity_factors.ror) * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2010/MW") }} Table 34 + index: monetary + dims: costs + cost_flow_out: + data: {{ 1 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2010/MW") }} stolen from om_annual for technical reasons + index: monetary + dims: costs + hydro_reservoir: + lifetime: 60 + cost_flow_cap: + data: {{ 2000000 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2010/MW") }} Table 33 + index: monetary + dims: costs + cost_om_annual: + data: {{ (20000 - 1 * 8760 * capacity_factors.ror) * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2010/MW") }} Table 34 + index: monetary + dims: costs + cost_flow_out: + data: {{ 1 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2010/MW") }} stolen from om_annual for technical reasons + index: monetary + dims: costs -locations: - {% for id, location in locations.iterrows() %} - {{ id }}.techs: + freeze_hydro_supply_capacities: + nodes: + {% for id, location in locations.iterrows() %} + {{ id }}.techs: # {{ location["name"] }} hydro_run_of_river: - constraints: - energy_cap_max: {{ location.installed_capacity_hror_MW * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MW") }} + flow_cap_min: {{ location.installed_capacity_hror_MW * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MW") }} hydro_reservoir: - constraints: - energy_cap_max: {{ location.installed_capacity_hdam_MW * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MW") }} - storage_cap_max: {{ location.storage_capacity_hdam_MWh * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MWh") }} - {% endfor %} + flow_cap_min: {{ location.installed_capacity_hdam_MW * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MW") }} + storage_cap_min: {{ location.storage_capacity_hdam_MWh * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MWh") }} + {% endfor %} + +nodes: + {% for id, location in locations.iterrows() %} + {{ id }}.techs: + hydro_run_of_river: + flow_cap_max: {{ location.installed_capacity_hror_MW * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MW") }} + hydro_reservoir: + flow_cap_max: {{ location.installed_capacity_hdam_MW * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MW") }} + storage_cap_max: {{ location.storage_capacity_hdam_MWh * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MWh") }} + {% endfor %} diff --git a/templates/models/techs/supply/load-shedding.yaml.jinja b/templates/models/techs/supply/load-shedding.yaml.jinja index 9e18193a..746bab74 100644 --- a/templates/models/techs/supply/load-shedding.yaml.jinja +++ b/templates/models/techs/supply/load-shedding.yaml.jinja @@ -1,17 +1,16 @@ techs: - load_shedding: - essentials: - name: Load shedding as last resort - parent: supply - carrier: electricity - constraints: - energy_cap_max: inf - costs.monetary: - om_prod: {{ 8000 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR/MWh") }} + load_shedding: + name: Load shedding as last resort + base_tech: supply + carrier_out: electricity + cost_flow_out: + data: {{ 8000 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR/MWh") }} + index: monetary + dims: costs overrides: - load-shedding: - locations: - {% for id, location in locations.iterrows() %} - {{ id }}.techs.load_shedding: - {% endfor %} + load_shedding: + nodes: + {% for id, location in locations.iterrows() %} + {{ id }}.techs.load_shedding: + {% endfor %} diff --git a/templates/models/techs/supply/nuclear.yaml.jinja b/templates/models/techs/supply/nuclear.yaml.jinja index c2f0ea53..fb37bdbe 100644 --- a/templates/models/techs/supply/nuclear.yaml.jinja +++ b/templates/models/techs/supply/nuclear.yaml.jinja @@ -4,29 +4,38 @@ # but tends towards being more optimistic in some areas (longer technology lifetime, higher average capacity factor, lower O&M costs) # and less optimistic in others (higher investment and annual O&M cost range) techs: - nuclear: - essentials: - name: Nuclear power - carrier: electricity - parent: supply - constraints: - energy_eff: 0.4 - lifetime: 50 # average of 40 [Wealer:2019] and 60 [IEA:2020] - energy_cap_min_use: 0.8 # average of 0.75 [Wealer:2019] and 0.85 [IEA:2020] - costs: - monetary: - energy_cap: {{ 3672000 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW") }} - om_annual: {{ 76116 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW/year") }} - om_prod: {{ 10 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MWh") }} | ASSUME: fuel costs given by [IEA:2020,Barkatullah:2017] are per MWh electricity produced, not MWh available energy in the input fuel. + nuclear: + name: Nuclear power + inherit: interest_rate + carrier_out: electricity + base_tech: supply + flow_out_eff: 0.4 + lifetime: 50 # average of 40 [Wealer:2019] and 60 [IEA:2020] + flow_out_min_relative: 0.8 # average of 0.75 [Wealer:2019] and 0.85 [IEA:2020] + cost_flow_cap: + data: {{ 3672000 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW") }} + index: monetary + dims: costs + cost_om_annual: + data: {{ 76116 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW/year") }} + index: monetary + dims: costs + cost_flow_out: + data: {{ 10 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MWh") }} | ASSUME: fuel costs given by [IEA:2020,Barkatullah:2017] are per MWh electricity produced, not MWh available energy in the input fuel. + index: monetary + dims: costs -locations: - {% for id, location in locations.iterrows() %} - {{ id }}.techs: - nuclear: - constraints: - {% for sense in ["min", "max", "equals"] %} - {% if "installed_capacity_nuclear_" + sense + "_MW" in location %} - energy_cap_{{ sense }}: {{ location["installed_capacity_nuclear_" + sense + "_MW"] * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MW") }} - {% endif %} - {% endfor %} - {% endfor %} +nodes: + {% for id, location in locations.iterrows() %} + {{ id }}.techs.nuclear: + {% for sense in ["min", "max", "equals"] %} + {% if "installed_capacity_nuclear_" + sense + "_MW" in location %} + {% if sense == "equals" %} + flow_cap_min: {{ location["installed_capacity_nuclear_" + sense + "_MW"] * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MW") }} + flow_cap_max: {{ location["installed_capacity_nuclear_" + sense + "_MW"] * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MW") }} + {% else %} + flow_cap_{{ sense }}: {{ location["installed_capacity_nuclear_" + sense + "_MW"] * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MW") }} + {% endif %} + {% endif %} + {% endfor %} + {% endfor %} diff --git a/templates/models/techs/supply/open-field-solar-and-wind-onshore.yaml.jinja b/templates/models/techs/supply/open-field-solar-and-wind-onshore.yaml.jinja index 89d32e6d..756765d4 100644 --- a/templates/models/techs/supply/open-field-solar-and-wind-onshore.yaml.jinja +++ b/templates/models/techs/supply/open-field-solar-and-wind-onshore.yaml.jinja @@ -1,75 +1,113 @@ tech_groups: - wind_onshore: # from [@JRC:2014] Table 4 - essentials: - name: Onshore wind - carrier: electricity - parent: supply - constraints: - resource: file=supply/capacityfactors-wind-onshore.csv - resource_unit: energy_per_cap - lifetime: 25 - costs.monetary: - energy_cap: {{ 1100000 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} - om_annual: {{ (1100000 * 0.017 - 1 * 8760 * capacity_factors.onshore) * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} 1.7% of CAPEX - om_prod: {{1 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} stolen from om_annual for technical reasons + wind_onshore: # from [@JRC:2014] Table 4 + name: Onshore wind + inherit: interest_rate + carrier_out: electricity + base_tech: supply + source_unit: per_cap + lifetime: 25 + cost_flow_cap: + data: {{ 1100000 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} + index: monetary + dims: costs + cost_om_annual: + data: {{ (1100000 * 0.017 - 1 * 8760 * capacity_factors.onshore) * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} 1.7% of CAPEX + index: monetary + dims: costs + cost_flow_out: + data: {{1 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} stolen from om_annual for technical reasons + index: monetary + dims: costs techs: - open_field_pv: # from [@JRC:2014] Table 7 - essentials: - name: Open field PV - carrier: electricity - parent: supply - constraints: - # open_field_pv and wind_onshore_competing are the only technologies with area footprints - # as they are the only technologies competing on the same land. - resource_area_per_energy_cap: {{ (1 / max_power_densities["pv-on-flat-areas"]) * scaling_factors.area / scaling_factors.power }} # {{ (scaling_factors.power / scaling_factors.area) | unit("km^2/MW") }} from [@Gagnon:2016][@Klauser:2016][@Wirth:2017] - resource_area_max: inf # see https://github.com/calliope-project/calliope/pull/160 - resource: file=supply/capacityfactors-open-field-pv.csv - resource_unit: energy_per_cap - lifetime: 25 - costs.monetary: - energy_cap: {{ 520000 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} - om_annual: {{ (520000 * 0.017 - 1 * 8760 * capacity_factors.pv) * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} 1.7% of CAPEX - om_prod: {{1 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} stolen from om_annual for technical reasons - wind_onshore_monopoly: - essentials: - name: Onshore wind without land competition - parent: wind_onshore - wind_onshore_competing: - essentials: - name: Onshore wind competing with open field PV on land - parent: wind_onshore - constraints: - # open_field_pv and wind_onshore_competing are the only technologies with area footprints - # as they are the only technologies competing on the same land. - resource_area_per_energy_cap: {{ (1 / max_power_densities["onshore-wind"]) * scaling_factors.area / scaling_factors.power }} # {{ (scaling_factors.power / scaling_factors.area) | unit("km^2/MW") }} from [@EuropeanEnvironmentAgency:2009] - resource_area_max: inf # see https://github.com/calliope-project/calliope/pull/160 + open_field_pv: # from [@JRC:2014] Table 7 + inherit: interest_rate + name: Open field PV + carrier_out: electricity + base_tech: supply + # open_field_pv and wind_onshore_competing are the only technologies with area footprints + # as they are the only technologies competing on the same land. + area_use_per_flow_cap: {{ (1 / max_power_densities["pv-on-flat-areas"]) * scaling_factors.area / scaling_factors.power }} # {{ (scaling_factors.power / scaling_factors.area) | unit("km^2/MW") }} from [@Gagnon:2016][@Klauser:2016][@Wirth:2017] + source_unit: per_cap + lifetime: 25 + cost_flow_cap: + data: {{ 520000 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} + index: monetary + dims: costs + cost_om_annual: + data: {{ (520000 * 0.017 - 1 * 8760 * capacity_factors.pv) * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} 1.7% of CAPEX + index: monetary + dims: costs + cost_flow_out: + data: {{1 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} stolen from om_annual for technical reasons + index: monetary + dims: costs + wind_onshore_monopoly: + name: Onshore wind without land competition + inherit: wind_onshore + wind_onshore_competing: + name: Onshore wind competing with open field PV on land + inherit: wind_onshore + # open_field_pv and wind_onshore_competing are the only technologies with area footprints + # as they are the only technologies competing on the same land. + area_use_per_flow_cap: {{ (1 / max_power_densities["onshore-wind"]) * scaling_factors.area / scaling_factors.power }} # {{ (scaling_factors.power / scaling_factors.area) | unit("km^2/MW") }} from [@EuropeanEnvironmentAgency:2009] + +data_sources: + capacityfactors_wind_onshore: + source: timeseries/supply/capacityfactors-wind-onshore.csv + rows: timesteps + columns: nodes + add_dimensions: + techs: [wind_onshore_monopoly, wind_onshore_competing] + parameters: source_use_max + capacityfactors_open_field_pv: + source: timeseries/supply/capacityfactors-open-field-pv.csv + rows: timesteps + columns: nodes + add_dimensions: + techs: open_field_pv + parameters: source_use_max overrides: - dea-renewable-cost-pv-open-field: # from [@DEA:2020a] - techs.open_field_pv: # Sheet 22 - Photovoltaics Large (last updated 2016) - constraints.lifetime: 40 # inverter lifetime is shorter but the replacement cost is included in O&M - costs.monetary: - energy_cap: {{ 241000 * 1.25 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW") }} with DC/AC sizing factor - om_annual: {{ (5000 * 1.25 - 1 * 8760 * capacity_factors.pv) * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW/year") }} with DC/AC sizing factor - om_prod: {{ 1 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW") }} stolen from om_annual for technical reasons + dea_renewable_cost_pv_open_field: # from [@DEA:2020a] + techs.open_field_pv: # Sheet 22 - Photovoltaics Large (last updated 2016) + lifetime: 40 # inverter lifetime is shorter but the replacement cost is included in O&M + cost_flow_cap: + data: {{ 241000 * 1.25 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW") }} with DC/AC sizing factor + index: monetary + dims: costs + cost_om_annual: + data: {{ (5000 * 1.25 - 1 * 8760 * capacity_factors.pv) * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW/year") }} with DC/AC sizing factor + index: monetary + dims: costs + cost_flow_out: + data: {{ 1 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW") }} stolen from om_annual for technical reasons + index: monetary + dims: costs - dea-renewable-cost-wind-onshore: # from [@DEA:2020a] - tech_groups.wind_onshore: # Sheet 20 Onshore Turbines (last updated 2019) - constraints.lifetime: 30 - costs.monetary: - energy_cap: {{ 963000 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW") }} - om_annual: {{ (11340 - 1 * 8760 * capacity_factors.onshore) * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW/year") }} - om_prod: {{ 1 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW") }} stolen from om_annual for technical reasons + dea_renewable_cost_wind_onshore: # from [@DEA:2020a] + tech_groups.wind_onshore: # Sheet 20 Onshore Turbines (last updated 2019) + lifetime: 30 + cost_flow_cap: + data: {{ 963000 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW") }} + index: monetary + dims: costs + cost_om_annual: + data: {{ (11340 - 1 * 8760 * capacity_factors.onshore) * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW/year") }} + index: monetary + dims: costs + cost_flow_out: + data: {{ 1 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW") }} stolen from om_annual for technical reasons + index: monetary + dims: costs -locations: - {% for id, location in locations.iterrows() %} - {{ id }}: - available_area: {{ location.eligibility_onshore_wind_and_pv_km2 * scaling_factors.area }} # {{ (1 / scaling_factors.area) | unit("km2") }} usable by onshore wind or open field pv - techs: - open_field_pv: - wind_onshore_competing: - wind_onshore_monopoly: - constraints: - energy_cap_max: {{ location.eligibility_onshore_wind_monopoly_mw * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MW") }} - {% endfor %} +nodes: + {% for id, location in locations.iterrows() %} + {{ id }}: + available_area: {{ location.eligibility_onshore_wind_and_pv_km2 * scaling_factors.area }} # {{ (1 / scaling_factors.area) | unit("km2") }} usable by onshore wind or open field pv + techs: + open_field_pv: + wind_onshore_competing: + wind_onshore_monopoly: + flow_cap_max: {{ location.eligibility_onshore_wind_monopoly_mw * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MW") }} + {% endfor %} diff --git a/templates/models/techs/supply/rooftop-solar.yaml.jinja b/templates/models/techs/supply/rooftop-solar.yaml.jinja index 8dc12964..21b227fd 100644 --- a/templates/models/techs/supply/rooftop-solar.yaml.jinja +++ b/templates/models/techs/supply/rooftop-solar.yaml.jinja @@ -1,78 +1,105 @@ tech_groups: pv_on_roof: # from [@JRC:2014] Table 9 - essentials: - name: Roof mounted PV - carrier: electricity - parent: supply - constraints.lifetime: 25 - costs.monetary: - energy_cap: {{ 880000 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} - om_annual: {{ (880000 * 0.02 - 1 * 8760 * capacity_factors.pv) * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} 2% of CAPEX - om_prod: {{1 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} stolen from om_annual for technical reasons + name: Roof mounted PV + inherit: interest_rate + carrier_out: electricity + base_tech: supply + source_unit: per_cap + lifetime: 25 + cost_flow_cap: + data: {{ 880000 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} + index: monetary + dims: costs + cost_om_annual: + data: {{ (880000 * 0.02 - 1 * 8760 * capacity_factors.pv) * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} 2% of CAPEX + index: monetary + dims: costs + cost_flow_out: + data: {{1 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} stolen from om_annual for technical reasons + index: monetary + dims: costs + techs: roof_mounted_pv: - essentials: - name: Roof mounted PV - parent: pv_on_roof - constraints: - resource: file=supply/capacityfactors-rooftop-pv.csv - resource_unit: energy_per_cap + inherit: pv_on_roof + +data_sources: + capacityfactors_rooftop_pv: + source: timeseries/supply/capacityfactors-rooftop-pv.csv + rows: timesteps + columns: nodes + add_dimensions: + techs: roof_mounted_pv + parameters: source_use_max overrides: - dea-renewable-cost-pv-roof-mounted: # from [@DEA:2020a] - tech_groups.pv_on_roof: # Sheet 22 - Photovoltaics Small (last updated 2016) - constraints.lifetime: 40 # inverter lifetime is shorter but the replacement cost is included in O&M - costs.monetary: - energy_cap: {{ 587500 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW") }} - om_annual: {{ (9135 - 1 * 8760 * capacity_factors.pv) * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW") }} - om_prod: {{1 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW") }} stolen from om_annual for technical reasons + dea_renewable_cost_pv_roof_mounted: # from [@DEA:2020a] + tech_groups.pv_on_roof: # Sheet 22 - Photovoltaics Small (last updated 2016) + lifetime: 40 # inverter lifetime is shorter but the replacement cost is included in O&M + cost_flow_cap: + data: {{ 587500 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW") }} + index: monetary + dims: costs + cost_om_annual: + data: {{ (9135 - 1 * 8760 * capacity_factors.pv) * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW") }} + index: monetary + dims: costs + cost_flow_out: + data: {{1 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW") }} stolen from om_annual for technical reasons + index: monetary + dims: costs - directional-rooftop-pv: - techs: - roof_mounted_pv: - exists: False - roof_mounted_pv_s_flat: - essentials: - name: Roof mounted PV south-facing and flat - parent: pv_on_roof - constraints: - resource: file=supply/capacityfactors-rooftop-pv-s-flat.csv - resource_unit: energy_per_cap - roof_mounted_pv_n: - essentials: - name: Roof mounted PV north-facing - parent: pv_on_roof - constraints: - resource: file=supply/capacityfactors-rooftop-pv-n.csv - resource_unit: energy_per_cap - roof_mounted_pv_e_w: - essentials: - name: Roof mounted PV east-facing and west-facing - parent: pv_on_roof - constraints: - resource: file=supply/capacityfactors-rooftop-pv-e-w.csv - resource_unit: energy_per_cap + directional_rooftop_pv: + techs: + roof_mounted_pv_s_flat: + name: Roof mounted PV south-facing and flat + inherit: pv_on_roof + roof_mounted_pv_n: + name: Roof mounted PV north-facing + inherit: pv_on_roof + roof_mounted_pv_e_w: + name: Roof mounted PV east-facing and west-facing + inherit: pv_on_roof + data_sources: + capacityfactors_rooftop_pv_s_flat: + source: timeseries/supply/capacityfactors-rooftop-pv-s-flat.csv + rows: timesteps + columns: nodes + add_dimensions: + techs: roof_mounted_pv_s_flat + parameters: source_use_max + capacityfactors_rooftop_pv_n: + source: timeseries/supply/capacityfactors-rooftop-pv-n.csv + rows: timesteps + columns: nodes + add_dimensions: + techs: roof_mounted_pv_n + parameters: source_use_max + capacityfactors_rooftop_pv_e_w: + source: timeseries/supply/capacityfactors-rooftop-pv-e-w.csv + rows: timesteps + columns: nodes + add_dimensions: + techs: roof_mounted_pv_e_w + parameters: source_use_max - locations: - {% for id, location in locations.iterrows() %} - {{ id }}.techs: - roof_mounted_pv_s_flat: - constraints: - energy_cap_max: {{ location.eligibility_rooftop_pv_s_flat_mw * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MW") }} - roof_mounted_pv_n: - constraints: - energy_cap_max: {{ location.eligibility_rooftop_pv_n_mw * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MW") }} - roof_mounted_pv_e_w: - constraints: - energy_cap_max: {{ location.eligibility_rooftop_pv_e_w_mw * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MW") }} - {% endfor %} + nodes: + {% for id, location in locations.iterrows() %} + {{ id }}.techs: + roof_mounted_pv.active: False + roof_mounted_pv_s_flat: + flow_cap_max: {{ location.eligibility_rooftop_pv_s_flat_mw * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MW") }} + roof_mounted_pv_n: + flow_cap_max: {{ location.eligibility_rooftop_pv_n_mw * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MW") }} + roof_mounted_pv_e_w: + flow_cap_max: {{ location.eligibility_rooftop_pv_e_w_mw * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MW") }} + {% endfor %} -locations: - {% for id, location in locations.iterrows() %} - {{ id }}: - techs: - roof_mounted_pv: - constraints: - energy_cap_max: {{ location.eligibility_rooftop_pv_mw * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MW") }} - {% endfor %} +nodes: + {% for id, location in locations.iterrows() %} + {{ id }}: + techs: + roof_mounted_pv: + flow_cap_max: {{ location.eligibility_rooftop_pv_mw * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MW") }} + {% endfor %} diff --git a/templates/models/techs/supply/wind-offshore.yaml.jinja b/templates/models/techs/supply/wind-offshore.yaml.jinja index bd2e2560..59010cb9 100644 --- a/templates/models/techs/supply/wind-offshore.yaml.jinja +++ b/templates/models/techs/supply/wind-offshore.yaml.jinja @@ -1,32 +1,53 @@ techs: - wind_offshore: # from [@JRC:2014] Table 5 - essentials: - name: Offshore wind - carrier: electricity - parent: supply - constraints: - resource: file=supply/capacityfactors-wind-offshore.csv - resource_unit: energy_per_cap - lifetime: 30 - costs.monetary: - energy_cap: {{ 2280000 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} - om_annual: {{ (2280000 * 0.023 - 1 * 8760 * capacity_factors.offshore) * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} 2.3% of CAPEX - om_prod: {{1 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} stolen from om_annual for technical reasons + wind_offshore: # from [@JRC:2014] Table 5 + name: Offshore wind + inherit: interest_rate + carrier_out: electricity + base_tech: supply + source_unit: per_cap + lifetime: 30 + cost_flow_cap: + data: {{ 2280000 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} + index: monetary + dims: costs + cost_om_annual: + data: {{ (2280000 * 0.023 - 1 * 8760 * capacity_factors.offshore) * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} 2.3% of CAPEX + index: monetary + dims: costs + cost_flow_out: + data: {{1 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} stolen from om_annual for technical reasons + index: monetary + dims: costs overrides: - dea-renewable-cost-wind-offshore: # from [@DEA:2020a] - techs.wind_offshore: # Sheet 21 Offshore Turbines (last updated 2019) - constraints.lifetime: 30 - costs.monetary: - energy_cap: {{ 1777000 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW") }} - om_annual: {{ (32448 - 1 * 8760 * capacity_factors.offshore) * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW/year") }} - om_prod: {{ 1 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW") }} stolen from om_annual for technical reasons + dea_renewable_cost_wind_offshore: # from [@DEA:2020a] + techs.wind_offshore: # Sheet 21 Offshore Turbines (last updated 2019) + lifetime: 30 + cost_flow_cap: + data: {{ 1777000 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW") }} + index: monetary + dims: costs + cost_om_annual: + data: {{ (32448 - 1 * 8760 * capacity_factors.offshore) * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW/year") }} + index: monetary + dims: costs + cost_flow_out: + data: {{ 1 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW") }} stolen from om_annual for technical reasons + index: monetary + dims: costs -locations: - {% for id, location in locations.iterrows() %} - {{ id }}: - techs: - wind_offshore: - constraints: - energy_cap_max: {{ location.eligibility_offshore_wind_mw * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MW") }} - {% endfor %} +data_sources: + capacityfactors_wind_offshore: + source: timeseries/supply/capacityfactors-wind-offshore.csv + rows: timesteps + columns: nodes + add_dimensions: + techs: wind_offshore + parameters: source_use_max +nodes: + {% for id, location in locations.iterrows() %} + {{ id }}: + techs: + wind_offshore: + flow_cap_max: {{ location.eligibility_offshore_wind_mw * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MW") }} + {% endfor %} diff --git a/templates/models/techs/transmission/electricity-transmission.yaml.jinja b/templates/models/techs/transmission/electricity-transmission.yaml.jinja index dd4f2579..a7d728a7 100644 --- a/templates/models/techs/transmission/electricity-transmission.yaml.jinja +++ b/templates/models/techs/transmission/electricity-transmission.yaml.jinja @@ -1,34 +1,36 @@ -techs: - free_transmission: - essentials: - name: 'Local power transmission' - parent: transmission - carrier: electricity - constraints: - energy_cap_max: inf - energy_eff: 1.0 - costs.monetary.om_prod: 0 - ac_transmission: - essentials: - name: "High voltage AC transmission line" - parent: transmission - carrier: electricity - constraints: - energy_eff_per_distance: 0.99999995 # (1/m) - lifetime: 60 - costs.monetary: # from [@JRC:2014], Table 39 - energy_cap_per_distance: {{ 0.9 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW/m") }} - om_annual_investment_fraction: 0.015 +tech_groups: + free_transmission: + name: 'Local power transmission' + inherit: interest_rate + base_tech: transmission + carrier_in: electricity + carrier_out: electricity + ac_transmission: + name: "High voltage AC transmission line" + inherit: free_transmission + flow_out_eff: 0.99999995 # (1/m) + lifetime: 60 + # costs from [@JRC:2014], Table 39 + cost_flow_cap_per_distance: + data: {{ 0.9 * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW/m") }} + index: monetary + dims: costs + cost_om_annual_investment_fraction: + data: 0.015 + index: monetary + dims: costs {% if link_comment is defined %} {{ link_comment }} {% endif %} -links: - {% for link in links.index %} - {{ link[0] }},{{ link[1] }}: - techs.ac_transmission: - {% if energy_cap_limit is defined %} - constraints.energy_cap_{{ energy_cap_limit }}: {{ links.loc[link] * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MW") }} - {% endif %} - {% endfor %} +techs: + {% for link in links.index %} + link_{{ link[0] }}_{{ link[1] }}: + inherit: ac_transmission + from: {{ link[0] }} + to: {{ link[1] }} + {% if energy_cap_limit is defined %} + flow_cap_{{ energy_cap_limit }}: {{ links.loc[link] * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MW") }} + {% endif %} + {% endfor %} diff --git a/tests/model/test_model.py b/tests/model/test_model.py index c2b9ae20..c0949c77 100644 --- a/tests/model/test_model.py +++ b/tests/model/test_model.py @@ -22,17 +22,13 @@ ]) HEAT_TECHS = set([ "biofuel_boiler", - "biofuel_tech_heat_to_demand", "heat_pump", - "heat_pump_tech_heat_to_demand", "electric_heater", - "electric_heater_tech_heat_to_demand", - "hp_heat_storage_small", - "electric_heater_heat_storage_small", - "biofuel_heat_storage_small", - "methane_heat_storage_small", + "heat_pump_storage", + "electric_heater_storage", + "biofuel_boiler_storage", + "methane_boiler_storage", "methane_boiler", - "methane_tech_heat_to_demand", ]) BIOFUEL_TECHS = set([ "biofuel_supply", @@ -52,8 +48,9 @@ ]) # Only includes scenarios with non-default technology sets TECHNOLOGIES = { - "connected_all_neighbours": DEFAULT_TECHNOLOGIES | set(["ac_transmission"]), - "connected_entsoe_tyndp": DEFAULT_TECHNOLOGIES | set(["ac_transmission"]), + # TODO: work out way to check for transmission techs + "connected_all_neighbours": DEFAULT_TECHNOLOGIES, + "connected_entsoe_tyndp": DEFAULT_TECHNOLOGIES, "directional-pv": (DEFAULT_TECHNOLOGIES | DIRECTIONAL_PV) - set(["roof_mounted_pv"]), "shed-load": DEFAULT_TECHNOLOGIES | set(["load_shedding"]), @@ -90,21 +87,19 @@ def test_example_model_runs(optimised_example_model): assert optimised_example_model.results.termination_condition == "optimal" -def test_technologies_are_available(energy_cap, location, technologies): +def test_technologies_are_available(flow_cap, location, technologies): for technology in technologies: - if "transmission" in technology: - assert pd.notna( - energy_cap.where(energy_cap.techs.str.find(technology) > -1) - .sum(min_count=1) - .item() - ) + if "link_" in technology: + assert pd.notna(flow_cap.sel(techs=technology).sum(min_count=1).item()) elif technology in OPTIONAL_LOCATIONAL_TECHNOLOGIES: # don't check the capacity values at each location, # since we can't be certain that the technology exists at any specific location - assert technology in energy_cap.techs + assert technology in flow_cap.techs else: - assert (technology in energy_cap.techs) and pd.notna( - energy_cap.sel(locs=location, techs=technology).item() + assert (technology in flow_cap.techs) and pd.notna( + flow_cap.sel(nodes=location, techs=technology) + .sum("carriers", min_count=1) + .item() ) diff --git a/tests/model/test_runner.py b/tests/model/test_runner.py index 880e6487..44687f61 100644 --- a/tests/model/test_runner.py +++ b/tests/model/test_runner.py @@ -51,7 +51,7 @@ def scaling_factors(self, config): @pytest.fixture(scope="session") def override_dict(self): - return {"model.subset_time": subset_time, "overrides": override_dict} + return {"config.init.time_subset": subset_time, "overrides": override_dict} @pytest.fixture(scope="session", params=list(scenarios.keys())) def scenario(self, request): @@ -61,21 +61,19 @@ def scenario(self, request): def model(self, scenario, override_dict): return calliope.Model( snakemake.input.example_model, - scenario=",".join(scenarios[scenario]), + scenario=",".join(scenarios[scenario]) if scenarios[scenario] else None, override_dict=override_dict, ) @pytest.fixture(scope="session") def optimised_model(self, model): - model.run() + model.build() + model.solve() return model @pytest.fixture(scope="session") - def energy_cap(self, optimised_model, scaling_factors): - return ( - optimised_model.get_formatted_array("energy_cap") - / scaling_factors["power"] - ) + def flow_cap(self, optimised_model, scaling_factors): + return optimised_model.results.flow_cap / scaling_factors["power"] @pytest.fixture( scope="module", @@ -89,9 +87,12 @@ def optimised_example_model(self, override_dict): model = calliope.Model( snakemake.input.example_model, override_dict=override_dict, - scenario=",".join(scenarios["default"]), + scenario=",".join(scenarios["default"]) + if scenarios["default"] + else None, ) - model.run() + model.build() + model.solve() return model @pytest.fixture( diff --git a/tests/model/timeseries/demand/test_heat_demand.py b/tests/model/timeseries/demand/test_heat_demand.py index d4cde1db..27ac6582 100644 --- a/tests/model/timeseries/demand/test_heat_demand.py +++ b/tests/model/timeseries/demand/test_heat_demand.py @@ -4,7 +4,7 @@ @pytest.mark.parametrize("demand", ["heat_demand", "electrified_heat_demand"]) def test_heat_demand_sign(request, demand): demand_df = request.getfixturevalue(demand) - assert (demand_df.stack() <= 0).all(), "Found positive heat demand." + assert (demand_df.stack() >= 0).all(), "Found positive heat demand." @pytest.mark.parametrize("demand", ["heat_demand", "electrified_heat_demand"]) @@ -24,5 +24,5 @@ def test_electrified_heat_vs_heat_demand( ): """Expecting heat demand to always be the same as or _higher_ than electrified heat demand, due to heating techs having a COP >= 1.""" assert ( - heat_demand[location].abs() >= electrified_heat_demand[location].abs() + heat_demand[location] >= electrified_heat_demand[location] ).all(), "Found higher electrified heat demand than final heat demand." diff --git a/tests/resources/test.yaml b/tests/resources/test.yaml index 96c80f6a..5bce6f07 100644 --- a/tests/resources/test.yaml +++ b/tests/resources/test.yaml @@ -2,22 +2,22 @@ test-model: scenarios: continental: default: [] - directional-pv: ["directional-rooftop-pv"] - e-to-p-ratios: ["exclusive-energy-to-power-ratios"] - frozen-hydro: ["freeze-hydro-supply-capacities", "freeze-hydro-storage-capacities", "no-hydro-supply-fixed-cost", "no-hydro-storage-fixed-cost"] - alternative-cost: ["dea-renewable-cost-pv-open-field", "dea-renewable-cost-wind-onshore", "dea-renewable-cost-wind-offshore", "dea-renewable-cost-pv-roof-mounted", "schroeder-hydro-cost"] - shed-load: ["load-shedding"] - keep-historic-transport: ["keep-historic-electricity-demand-from-road-transport"] + directional-pv: ["directional_rooftop_pv"] + e-to-p-ratios: ["exclusive_energy_to_power_ratios"] + frozen-hydro: ["freeze_hydro_supply_capacities", "freeze_hydro_storage_capacities", "no_hydro_supply_fixed_cost", "no_hydro_storage_fixed_cost"] + alternative-cost: ["dea_renewable_cost_pv_open_field", "dea_renewable_cost_wind_onshore", "dea_renewable_cost_wind_offshore", "dea_renewable_cost_pv_roof_mounted", "schroeder_hydro_cost"] + shed-load: ["load_shedding"] + keep-historic-transport: ["keep_historic_electricity_demand_from_road_transport"] national: default: [] connected_neighbours: ["connect_all_neighbours"] connected_entsoe_tyndp: ["connect_entsoe_tyndp"] - directional-pv: ["directional-rooftop-pv"] - e-to-p-ratios: ["exclusive-energy-to-power-ratios"] - frozen-hydro: ["freeze-hydro-supply-capacities", "freeze-hydro-storage-capacities", "no-hydro-supply-fixed-cost", "no-hydro-storage-fixed-cost"] - alternative-cost: ["dea-renewable-cost-pv-open-field", "dea-renewable-cost-wind-onshore", "dea-renewable-cost-wind-offshore", "dea-renewable-cost-pv-roof-mounted", "schroeder-hydro-cost"] - shed-load: ["load-shedding"] - keep-historic-transport: ["keep-historic-electricity-demand-from-road-transport"] + directional-pv: ["directional_rooftop_pv"] + e-to-p-ratios: ["exclusive_energy_to_power_ratios"] + frozen-hydro: ["freeze_hydro_supply_capacities", "freeze_hydro_storage_capacities", "no_hydro_supply_fixed_cost", "no_hydro_storage_fixed_cost"] + alternative-cost: ["dea_renewable_cost_pv_open_field", "dea_renewable_cost_wind_onshore", "dea_renewable_cost_wind_offshore", "dea_renewable_cost_pv_roof_mounted", "schroeder_hydro_cost"] + shed-load: ["load_shedding"] + keep-historic-transport: ["keep_historic_electricity_demand_from_road_transport"] heat: ["heat_carrier"] electrified-heat: ["electrified_heat"] biofuel: ["biofuel_carrier"] @@ -26,12 +26,12 @@ test-model: regional: default: ["connect_all_neighbours", "run_barrier_no_crossover"] - all-overrides: ["connect_all_neighbours", "directional-rooftop-pv", "exclusive-energy-to-power-ratios", - "dea-renewable-cost-pv-open-field", "dea-renewable-cost-wind-onshore", "dea-renewable-cost-wind-offshore", "dea-renewable-cost-pv-roof-mounted", "schroeder-hydro-cost", "freeze-hydro-supply-capacities", "freeze-hydro-storage-capacities", "load-shedding", "heat_carrier", "biofuel_carrier", "synfuel_carriers"] + all-overrides: ["connect_all_neighbours", "directional_rooftop_pv", "exclusive_energy_to_power_ratios", + "dea_renewable_cost_pv_open_field", "dea_renewable_cost_wind_onshore", "dea_renewable_cost_wind_offshore", "dea_renewable_cost_pv_roof_mounted", "schroeder_hydro_cost", "freeze_hydro_supply_capacities", "freeze_hydro_storage_capacities", "load_shedding", "heat_carrier", "biofuel_carrier", "synfuel_carriers"] ehighways: default: ["connect_all_neighbours", "run_barrier_no_crossover"] - all-overrides: ["connect_all_neighbours", "directional-rooftop-pv", "exclusive-energy-to-power-ratios", - "dea-renewable-cost-pv-open-field", "dea-renewable-cost-wind-onshore", "dea-renewable-cost-wind-offshore", "dea-renewable-cost-pv-roof-mounted", "schroeder-hydro-cost", "freeze-hydro-supply-capacities", "freeze-hydro-storage-capacities", "load-shedding", "heat_carrier", "biofuel_carrier", "synfuel_carriers"] + all-overrides: ["connect_all_neighbours", "directional_rooftop_pv", "exclusive_energy_to_power_ratios", + "dea_renewable_cost_pv_open_field", "dea_renewable_cost_wind_onshore", "dea_renewable_cost_wind_offshore", "dea_renewable_cost_pv_roof_mounted", "schroeder_hydro_cost", "freeze_hydro_supply_capacities", "freeze_hydro_storage_capacities", "load_shedding", "heat_carrier", "biofuel_carrier", "synfuel_carriers"] overrides: continental: {} national: @@ -92,7 +92,7 @@ test-model: - "build/models/regional/techs/conversion/hydrogen-from-electricity.yaml" run_barrier_no_crossover: - run.solver_options: {Method: 2, Crossover: 0} + config.solve.solver_options: {Method: 2, Crossover: 0} ehighways: connect_all_neighbours: import: @@ -119,7 +119,7 @@ test-model: - "build/models/ehighways/techs/conversion/hydrogen-from-electricity.yaml" run_barrier_no_crossover: - run.solver_options: {Method: 2, Crossover: 0} + config.solve.solver_options: {Method: 2, Crossover: 0} subset_time: continental: ['2016-01-01', '2016-01-02'] national: ['2016-01-01', '2016-01-01'] From 5089a4fadd89dbdeb1b7af4e7350f73c3df8b6d8 Mon Sep 17 00:00:00 2001 From: Bryn Pickering <17178478+brynpickering@users.noreply.github.com> Date: Tue, 17 Sep 2024 18:19:43 +0100 Subject: [PATCH 2/2] Update to v0.7.0dev4 --- envs/test.yaml | 4 +- templates/environment.yaml | 4 +- templates/models/interest-rate.yaml | 2 +- .../electricity-from-biofuel.yaml.jinja | 2 +- .../conversion/heat-from-biofuel.yaml.jinja | 2 +- .../heat-from-electricity.yaml.jinja | 6 +- .../conversion/heat-from-methane.yaml.jinja | 2 +- .../hydrogen-from-electricity.yaml.jinja | 2 +- .../synfuels-from-biofuel.yaml.jinja | 8 +-- .../synfuels-from-hydrogen.yaml.jinja | 4 +- .../techs/demand/electricity.yaml.jinja | 2 +- .../techs/demand/electrified-heat.yaml.jinja | 2 +- .../demand/electrified-transport.yaml.jinja | 10 +-- templates/models/techs/demand/heat.yaml.jinja | 2 +- .../techs/storage/electricity.yaml.jinja | 4 +- .../models/techs/storage/heat.yaml.jinja | 13 ++-- .../models/techs/storage/hydro.yaml.jinja | 2 +- .../historic-electrified-heat.yaml.jinja | 2 +- .../models/techs/supply/hydro.yaml.jinja | 8 +-- .../models/techs/supply/nuclear.yaml.jinja | 2 +- ...en-field-solar-and-wind-onshore.yaml.jinja | 16 ++--- .../techs/supply/rooftop-solar.yaml.jinja | 72 +++++++++---------- .../techs/supply/wind-offshore.yaml.jinja | 4 +- .../electricity-transmission.yaml.jinja | 8 +-- tests/lib/test_parametrise_template.py | 6 +- 25 files changed, 95 insertions(+), 94 deletions(-) diff --git a/envs/test.yaml b/envs/test.yaml index 5a4d3188..07d620e5 100644 --- a/envs/test.yaml +++ b/envs/test.yaml @@ -1,7 +1,7 @@ name: test channels: - - conda-forge - conda-forge/label/calliope_dev + - conda-forge - gurobi dependencies: - python=3.12 @@ -12,7 +12,7 @@ dependencies: - gurobi=11.0.3 - pytest=8.2.2 - pytest-html=3.2.0 - - calliope=0.7.0 + - calliope=0.7.0dev4 - pyomo=6.7.1 - netCDF4=1.6.5 - hdf5=1.14.2 diff --git a/templates/environment.yaml b/templates/environment.yaml index 7b08b8fb..80aead0d 100644 --- a/templates/environment.yaml +++ b/templates/environment.yaml @@ -1,7 +1,7 @@ name: euro-calliope channels: - - conda-forge - conda-forge/label/calliope_dev + - conda-forge - gurobi dependencies: - python=3.12 @@ -12,5 +12,5 @@ dependencies: - hdf5=1.14.2 - libnetcdf=4.9.2 - gurobi=11.0.3 - - calliope=0.7.0 + - calliope=0.7.0dev4 - pyomo=6.7.1 diff --git a/templates/models/interest-rate.yaml b/templates/models/interest-rate.yaml index 362113f8..50ef5714 100644 --- a/templates/models/interest-rate.yaml +++ b/templates/models/interest-rate.yaml @@ -1,4 +1,4 @@ -tech_groups: +templates: interest_rate: cost_interest_rate: data: 0.073 # average wind onshore WACC OECD from [@Steffen:2019] diff --git a/templates/models/techs/conversion/electricity-from-biofuel.yaml.jinja b/templates/models/techs/conversion/electricity-from-biofuel.yaml.jinja index 92fb53b3..5c5797aa 100644 --- a/templates/models/techs/conversion/electricity-from-biofuel.yaml.jinja +++ b/templates/models/techs/conversion/electricity-from-biofuel.yaml.jinja @@ -1,7 +1,7 @@ techs: electricity_from_biofuel: # from [@JRC:2014] Table 48 Anaerobic digestion name: Electricity from anaerobically digested biofuel - inherit: interest_rate + template: interest_rate base_tech: conversion carrier_in: biofuel carrier_out: electricity diff --git a/templates/models/techs/conversion/heat-from-biofuel.yaml.jinja b/templates/models/techs/conversion/heat-from-biofuel.yaml.jinja index f0cd2034..77c51364 100644 --- a/templates/models/techs/conversion/heat-from-biofuel.yaml.jinja +++ b/templates/models/techs/conversion/heat-from-biofuel.yaml.jinja @@ -6,7 +6,7 @@ techs: biofuel_boiler: # [@DEA:2017] - Biomass boiler, automatic stoking , wood pellets or wood chips - 2050 # Costs and efficiency are an average of data for existing single-family, new single-family, existing multi-family, and new multi-family homes. name: Biofuel boiler - inherit: interest_rate + template: interest_rate base_tech: conversion carrier_in: biofuel carrier_out: heat diff --git a/templates/models/techs/conversion/heat-from-electricity.yaml.jinja b/templates/models/techs/conversion/heat-from-electricity.yaml.jinja index 23d9d1f6..7847f6a2 100644 --- a/templates/models/techs/conversion/heat-from-electricity.yaml.jinja +++ b/templates/models/techs/conversion/heat-from-electricity.yaml.jinja @@ -5,7 +5,7 @@ techs: heat_pump: # [@DEA:2017] - 7.3 - 7.6 Air to water & 7.7 - 7.10 Ground source - 2050 name: Heat pump - inherit: interest_rate + template: interest_rate base_tech: conversion carrier_in: electricity carrier_out: heat @@ -23,7 +23,7 @@ techs: electric_heater: # [@DEA:2017] - 16 Electric heating - 2050 name: Electrical heater - inherit: interest_rate + template: interest_rate base_tech: conversion carrier_in: electricity carrier_out: heat @@ -44,7 +44,7 @@ data_sources: source: timeseries/conversion/heat-pump-cop.csv rows: timesteps columns: nodes - add_dimensions: + add_dims: techs: heat_pump parameters: flow_out_eff diff --git a/templates/models/techs/conversion/heat-from-methane.yaml.jinja b/templates/models/techs/conversion/heat-from-methane.yaml.jinja index 41726886..319d45bc 100644 --- a/templates/models/techs/conversion/heat-from-methane.yaml.jinja +++ b/templates/models/techs/conversion/heat-from-methane.yaml.jinja @@ -4,7 +4,7 @@ techs: methane_boiler: # [@DEA:2017] - 202 Natural gas boiler - 2050 name: Natural gas / methane boiler - inherit: interest_rate + template: interest_rate base_tech: conversion carrier_in: methane carrier_out: heat diff --git a/templates/models/techs/conversion/hydrogen-from-electricity.yaml.jinja b/templates/models/techs/conversion/hydrogen-from-electricity.yaml.jinja index 140c6021..730f26af 100644 --- a/templates/models/techs/conversion/hydrogen-from-electricity.yaml.jinja +++ b/templates/models/techs/conversion/hydrogen-from-electricity.yaml.jinja @@ -4,7 +4,7 @@ techs: # Technology constraints and costs are averages over different electrolyser types: SOEC, PEM, and Alkaline electrolysis: # [@DEA:2020b] - 86-88 Electrolysers - 2050 name: Hydrogen by electrolysis - inherit: interest_rate + template: interest_rate base_tech: conversion carrier_in: electricity carrier_out: hydrogen diff --git a/templates/models/techs/conversion/synfuels-from-biofuel.yaml.jinja b/templates/models/techs/conversion/synfuels-from-biofuel.yaml.jinja index 504f1982..20b40e82 100644 --- a/templates/models/techs/conversion/synfuels-from-biofuel.yaml.jinja +++ b/templates/models/techs/conversion/synfuels-from-biofuel.yaml.jinja @@ -2,7 +2,7 @@ techs: biofuel_to_liquids: # [@DEA:2020b] - 85 Gasif. Ent. Flow FT, liq fu - 2050 # ASSUME: Naptha production can be diverted to kerosene and diesel production, in equal measure. name: Biofuel to liquid fuels converter - inherit: interest_rate + template: interest_rate base_tech: conversion carrier_in: biofuel carrier_out: [kerosene, diesel, electricity] @@ -38,7 +38,7 @@ techs: # ASSUME: all vehicle fuel is diesel. biofuel_to_diesel: # [@DEA:2020b] - 101 Catalytic Hydropyrolysis 2 - 2050 name: Biofuel to vehicle fuel converter - inherit: interest_rate + template: interest_rate base_tech: conversion carrier_in: biofuel carrier_out: diesel @@ -62,7 +62,7 @@ techs: # ASSUME: ignore electricity output, as it can cause numerical trouble. biofuel_to_methanol: # [@DEA:2020b] - 97 Methanol from biomass gasif. - 2050 name: Biofuel to Methanol converter - inherit: interest_rate + template: interest_rate base_tech: conversion carrier_in: biofuel carrier_out: methanol @@ -84,7 +84,7 @@ techs: # ASSUME: ignore waste low grade heat (which could be used for district heating) biofuel_to_methane: # [@DEA:2020b] - 84 Biomass to SNG gassifier - 2050 name: Biofuel to Methane converter - inherit: interest_rate + template: interest_rate base_tech: conversion carrier_in: biofuel carrier_out: methane diff --git a/templates/models/techs/conversion/synfuels-from-hydrogen.yaml.jinja b/templates/models/techs/conversion/synfuels-from-hydrogen.yaml.jinja index d3b53e76..b084cecb 100644 --- a/templates/models/techs/conversion/synfuels-from-hydrogen.yaml.jinja +++ b/templates/models/techs/conversion/synfuels-from-hydrogen.yaml.jinja @@ -2,7 +2,7 @@ techs: # ASSUME: ignore waste low grade heat output (which could be used for district heating) hydrogen_to_liquids: # [@DEA:2020b] - renewable fuels - 102 Hydrogen to Jet - 2050 name: Hydrogen to liquid fuels converter - inherit: interest_rate + template: interest_rate base_tech: conversion carrier_in: [hydrogen, electricity, co2] # TODO: custom math to link these carrier flows carrier_out: [kerosene, diesel] # TODO: custom math to link these carrier flows @@ -42,7 +42,7 @@ techs: # ASSUME: Can run intermittently hydrogen_to_methanol: # [@DEA:2020b] - renewable fuels - 98 Methanol from power - 2050 name: Hydrogen to Methanol converter - inherit: interest_rate + template: interest_rate base_tech: conversion carrier_in: [hydrogen, co2] # TODO: custom math to link these carrier flows carrier_out: methanol diff --git a/templates/models/techs/demand/electricity.yaml.jinja b/templates/models/techs/demand/electricity.yaml.jinja index 9df278f5..1a224263 100644 --- a/templates/models/techs/demand/electricity.yaml.jinja +++ b/templates/models/techs/demand/electricity.yaml.jinja @@ -9,7 +9,7 @@ data_sources: source: timeseries/demand/electricity.csv rows: timesteps columns: nodes - add_dimensions: + add_dims: techs: demand_elec parameters: sink_use_equals diff --git a/templates/models/techs/demand/electrified-heat.yaml.jinja b/templates/models/techs/demand/electrified-heat.yaml.jinja index 09d11f15..1cd1e1a0 100644 --- a/templates/models/techs/demand/electrified-heat.yaml.jinja +++ b/templates/models/techs/demand/electrified-heat.yaml.jinja @@ -9,7 +9,7 @@ data_sources: source: timeseries/demand/electrified-heat.csv rows: timesteps columns: nodes - add_dimensions: + add_dims: techs: demand_heat_electrified parameters: sink_use_equals nodes: diff --git a/templates/models/techs/demand/electrified-transport.yaml.jinja b/templates/models/techs/demand/electrified-transport.yaml.jinja index eeefc6a7..ebe78488 100644 --- a/templates/models/techs/demand/electrified-transport.yaml.jinja +++ b/templates/models/techs/demand/electrified-transport.yaml.jinja @@ -20,7 +20,7 @@ data_sources: source: timeseries/demand/uncontrolled-electrified-road-transport.csv rows: timesteps columns: nodes - add_dimensions: + add_dims: techs: demand_road_transport_electrified_uncontrolled parameters: sink_use_equals @@ -28,7 +28,7 @@ data_sources: source: timeseries/demand/uncontrolled-road-transport-historic-electrification.csv rows: timesteps columns: nodes - add_dimensions: + add_dims: techs: demand_road_transport_historic_electrified_uncontrolled parameters: source_use_equals @@ -56,14 +56,14 @@ overrides: source: timeseries/demand/demand-shape-min-ev.csv rows: monthsteps columns: nodes - add_dimensions: + add_dims: techs: demand_road_transport_electrified_controlled parameters: flow_in_per_month_min demand_shape_max_ev: source: timeseries/demand/demand-shape-max-ev.csv rows: monthsteps columns: nodes - add_dimensions: + add_dims: techs: demand_road_transport_electrified_controlled parameters: flow_in_per_month_max @@ -75,7 +75,7 @@ overrides: source: timeseries/demand/plugin-profiles-ev.csv rows: timesteps columns: nodes - add_dimensions: + add_dims: techs: road_transport_controlled_dummy parameters: energy_cap_max_varying techs: diff --git a/templates/models/techs/demand/heat.yaml.jinja b/templates/models/techs/demand/heat.yaml.jinja index d9bf159f..09098c92 100644 --- a/templates/models/techs/demand/heat.yaml.jinja +++ b/templates/models/techs/demand/heat.yaml.jinja @@ -9,7 +9,7 @@ data_sources: source: timeseries/demand/heat.csv rows: timesteps columns: nodes - add_dimensions: + add_dims: techs: demand_heat parameters: sink_use_equals diff --git a/templates/models/techs/storage/electricity.yaml.jinja b/templates/models/techs/storage/electricity.yaml.jinja index be2a8521..343cdb47 100644 --- a/templates/models/techs/storage/electricity.yaml.jinja +++ b/templates/models/techs/storage/electricity.yaml.jinja @@ -1,7 +1,7 @@ techs: battery: # from [@schmidt:2019] Table S4 name: 'Battery storage' - inherit: interest_rate + template: interest_rate base_tech: storage carrier_in: electricity carrier_out: electricity @@ -29,7 +29,7 @@ techs: hydrogen: # from [@schmidt:2019] Table S4 name: Hydrogen power storage - inherit: interest_rate + template: interest_rate base_tech: storage carrier_in: electricity carrier_out: electricity diff --git a/templates/models/techs/storage/heat.yaml.jinja b/templates/models/techs/storage/heat.yaml.jinja index b15dea7d..98136c72 100644 --- a/templates/models/techs/storage/heat.yaml.jinja +++ b/templates/models/techs/storage/heat.yaml.jinja @@ -1,9 +1,9 @@ -tech_groups: +templates: heat_storage_small: # [@DEA:2019] - energy storage - 142 small scale hot water tank - 2050 base_tech: storage carrier_in: heat carrier_out: heat - inherit: interest_rate + template: interest_rate flow_cap_per_storage_cap_max: 6.67 # 20kW/3kWh storage_loss: 0.021 # fraction / hour lifetime: 30 @@ -16,22 +16,23 @@ tech_groups: techs: methane_boiler_storage: name: Small hot water tank linked to methane boilers - inherit: heat_storage_small + template: heat_storage_small biofuel_boiler_storage: name: Small hot water tank linked to biofuel boilers - inherit: heat_storage_small + template: heat_storage_small heat_pump_storage: name: Small hot water tank linked to heat pumps - inherit: heat_storage_small + template: heat_storage_small electric_heater_storage: name: Small hot water tank linked to electric heaters - inherit: heat_storage_small + template: heat_storage_small parameters: lookup_linked_storage_tech: data: [methane_boiler, biofuel_boiler, heat_pump, electric_heater] index: [methane_boiler_storage, biofuel_boiler_storage, heat_pump_storage, electric_heater_storage] dims: techs + nodes: {% for id, location in locations.iterrows() %} {{ id }}.techs: diff --git a/templates/models/techs/storage/hydro.yaml.jinja b/templates/models/techs/storage/hydro.yaml.jinja index 47ae2386..c7ab2cd4 100644 --- a/templates/models/techs/storage/hydro.yaml.jinja +++ b/templates/models/techs/storage/hydro.yaml.jinja @@ -1,7 +1,7 @@ techs: pumped_hydro: # from [@schmidt:2019] Table S4 name: 'Pumped hydro power storage' - inherit: interest_rate + template: interest_rate base_tech: storage carrier_in: electricity carrier_out: electricity diff --git a/templates/models/techs/supply/historic-electrified-heat.yaml.jinja b/templates/models/techs/supply/historic-electrified-heat.yaml.jinja index 5817f29f..59708a49 100644 --- a/templates/models/techs/supply/historic-electrified-heat.yaml.jinja +++ b/templates/models/techs/supply/historic-electrified-heat.yaml.jinja @@ -9,7 +9,7 @@ data_sources: source: timeseries/supply/historic-electrified-heat.csv rows: timesteps columns: nodes - add_dimensions: + add_dims: techs: historic_electrified_heat parameters: source_use_equals diff --git a/templates/models/techs/supply/hydro.yaml.jinja b/templates/models/techs/supply/hydro.yaml.jinja index 4544f407..64a54b10 100644 --- a/templates/models/techs/supply/hydro.yaml.jinja +++ b/templates/models/techs/supply/hydro.yaml.jinja @@ -1,7 +1,7 @@ techs: hydro_run_of_river: # from [@JRC:2014] Table 14 name: Run of river hydro electricity - inherit: interest_rate + template: interest_rate base_tech: supply carrier_out: electricity source_unit: per_cap @@ -20,7 +20,7 @@ techs: dims: costs hydro_reservoir: # from [@JRC:2014] Table 12 name: Hydro electricity with a reservoir. - inherit: interest_rate + template: interest_rate base_tech: supply carrier_out: electricity source_unit: per_cap @@ -44,14 +44,14 @@ data_sources: source: timeseries/supply/capacityfactors-hydro-run-of-river.csv rows: timesteps columns: nodes - add_dimensions: + add_dims: techs: hydro_run_of_river parameters: source_use_max capacityfactors_hydro_reservoir: source: timeseries/supply/capacityfactors-hydro-reservoir.csv rows: timesteps columns: nodes - add_dimensions: + add_dims: techs: hydro_reservoir parameters: source_use_max diff --git a/templates/models/techs/supply/nuclear.yaml.jinja b/templates/models/techs/supply/nuclear.yaml.jinja index fb37bdbe..dd45b5ba 100644 --- a/templates/models/techs/supply/nuclear.yaml.jinja +++ b/templates/models/techs/supply/nuclear.yaml.jinja @@ -6,7 +6,7 @@ techs: nuclear: name: Nuclear power - inherit: interest_rate + template: interest_rate carrier_out: electricity base_tech: supply flow_out_eff: 0.4 diff --git a/templates/models/techs/supply/open-field-solar-and-wind-onshore.yaml.jinja b/templates/models/techs/supply/open-field-solar-and-wind-onshore.yaml.jinja index 756765d4..5854c34c 100644 --- a/templates/models/techs/supply/open-field-solar-and-wind-onshore.yaml.jinja +++ b/templates/models/techs/supply/open-field-solar-and-wind-onshore.yaml.jinja @@ -1,7 +1,7 @@ -tech_groups: +templates: wind_onshore: # from [@JRC:2014] Table 4 name: Onshore wind - inherit: interest_rate + template: interest_rate carrier_out: electricity base_tech: supply source_unit: per_cap @@ -21,7 +21,7 @@ tech_groups: techs: open_field_pv: # from [@JRC:2014] Table 7 - inherit: interest_rate + template: interest_rate name: Open field PV carrier_out: electricity base_tech: supply @@ -44,10 +44,10 @@ techs: dims: costs wind_onshore_monopoly: name: Onshore wind without land competition - inherit: wind_onshore + template: wind_onshore wind_onshore_competing: name: Onshore wind competing with open field PV on land - inherit: wind_onshore + template: wind_onshore # open_field_pv and wind_onshore_competing are the only technologies with area footprints # as they are the only technologies competing on the same land. area_use_per_flow_cap: {{ (1 / max_power_densities["onshore-wind"]) * scaling_factors.area / scaling_factors.power }} # {{ (scaling_factors.power / scaling_factors.area) | unit("km^2/MW") }} from [@EuropeanEnvironmentAgency:2009] @@ -57,14 +57,14 @@ data_sources: source: timeseries/supply/capacityfactors-wind-onshore.csv rows: timesteps columns: nodes - add_dimensions: + add_dims: techs: [wind_onshore_monopoly, wind_onshore_competing] parameters: source_use_max capacityfactors_open_field_pv: source: timeseries/supply/capacityfactors-open-field-pv.csv rows: timesteps columns: nodes - add_dimensions: + add_dims: techs: open_field_pv parameters: source_use_max @@ -86,7 +86,7 @@ overrides: dims: costs dea_renewable_cost_wind_onshore: # from [@DEA:2020a] - tech_groups.wind_onshore: # Sheet 20 Onshore Turbines (last updated 2019) + templates.wind_onshore: # Sheet 20 Onshore Turbines (last updated 2019) lifetime: 30 cost_flow_cap: data: {{ 963000 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW") }} diff --git a/templates/models/techs/supply/rooftop-solar.yaml.jinja b/templates/models/techs/supply/rooftop-solar.yaml.jinja index 21b227fd..6816c7b9 100644 --- a/templates/models/techs/supply/rooftop-solar.yaml.jinja +++ b/templates/models/techs/supply/rooftop-solar.yaml.jinja @@ -1,41 +1,41 @@ -tech_groups: - pv_on_roof: # from [@JRC:2014] Table 9 - name: Roof mounted PV - inherit: interest_rate - carrier_out: electricity - base_tech: supply - source_unit: per_cap - lifetime: 25 - cost_flow_cap: - data: {{ 880000 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} - index: monetary - dims: costs - cost_om_annual: - data: {{ (880000 * 0.02 - 1 * 8760 * capacity_factors.pv) * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} 2% of CAPEX - index: monetary - dims: costs - cost_flow_out: - data: {{1 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} stolen from om_annual for technical reasons - index: monetary - dims: costs +templates: + pv_on_roof: # from [@JRC:2014] Table 9 + name: Roof mounted PV + template: interest_rate + carrier_out: electricity + base_tech: supply + source_unit: per_cap + lifetime: 25 + cost_flow_cap: + data: {{ 880000 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} + index: monetary + dims: costs + cost_om_annual: + data: {{ (880000 * 0.02 - 1 * 8760 * capacity_factors.pv) * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} 2% of CAPEX + index: monetary + dims: costs + cost_flow_out: + data: {{1 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2013/MW") }} stolen from om_annual for technical reasons + index: monetary + dims: costs techs: - roof_mounted_pv: - inherit: pv_on_roof + roof_mounted_pv: + template: pv_on_roof data_sources: - capacityfactors_rooftop_pv: - source: timeseries/supply/capacityfactors-rooftop-pv.csv - rows: timesteps - columns: nodes - add_dimensions: - techs: roof_mounted_pv - parameters: source_use_max + capacityfactors_rooftop_pv: + source: timeseries/supply/capacityfactors-rooftop-pv.csv + rows: timesteps + columns: nodes + add_dims: + techs: roof_mounted_pv + parameters: source_use_max overrides: dea_renewable_cost_pv_roof_mounted: # from [@DEA:2020a] - tech_groups.pv_on_roof: # Sheet 22 - Photovoltaics Small (last updated 2016) + templates.pv_on_roof: # Sheet 22 - Photovoltaics Small (last updated 2016) lifetime: 40 # inverter lifetime is shorter but the replacement cost is included in O&M cost_flow_cap: data: {{ 587500 * scaling_factors.specific_costs}} # {{ (1 / scaling_factors.specific_costs) | unit("EUR2015/MW") }} @@ -54,33 +54,33 @@ overrides: techs: roof_mounted_pv_s_flat: name: Roof mounted PV south-facing and flat - inherit: pv_on_roof + template: pv_on_roof roof_mounted_pv_n: name: Roof mounted PV north-facing - inherit: pv_on_roof + template: pv_on_roof roof_mounted_pv_e_w: name: Roof mounted PV east-facing and west-facing - inherit: pv_on_roof + template: pv_on_roof data_sources: capacityfactors_rooftop_pv_s_flat: source: timeseries/supply/capacityfactors-rooftop-pv-s-flat.csv rows: timesteps columns: nodes - add_dimensions: + add_dims: techs: roof_mounted_pv_s_flat parameters: source_use_max capacityfactors_rooftop_pv_n: source: timeseries/supply/capacityfactors-rooftop-pv-n.csv rows: timesteps columns: nodes - add_dimensions: + add_dims: techs: roof_mounted_pv_n parameters: source_use_max capacityfactors_rooftop_pv_e_w: source: timeseries/supply/capacityfactors-rooftop-pv-e-w.csv rows: timesteps columns: nodes - add_dimensions: + add_dims: techs: roof_mounted_pv_e_w parameters: source_use_max diff --git a/templates/models/techs/supply/wind-offshore.yaml.jinja b/templates/models/techs/supply/wind-offshore.yaml.jinja index 59010cb9..6e79c861 100644 --- a/templates/models/techs/supply/wind-offshore.yaml.jinja +++ b/templates/models/techs/supply/wind-offshore.yaml.jinja @@ -1,7 +1,7 @@ techs: wind_offshore: # from [@JRC:2014] Table 5 name: Offshore wind - inherit: interest_rate + template: interest_rate carrier_out: electricity base_tech: supply source_unit: per_cap @@ -41,7 +41,7 @@ data_sources: source: timeseries/supply/capacityfactors-wind-offshore.csv rows: timesteps columns: nodes - add_dimensions: + add_dims: techs: wind_offshore parameters: source_use_max nodes: diff --git a/templates/models/techs/transmission/electricity-transmission.yaml.jinja b/templates/models/techs/transmission/electricity-transmission.yaml.jinja index a7d728a7..af9d2834 100644 --- a/templates/models/techs/transmission/electricity-transmission.yaml.jinja +++ b/templates/models/techs/transmission/electricity-transmission.yaml.jinja @@ -1,13 +1,13 @@ -tech_groups: +templates: free_transmission: name: 'Local power transmission' - inherit: interest_rate + template: interest_rate base_tech: transmission carrier_in: electricity carrier_out: electricity ac_transmission: name: "High voltage AC transmission line" - inherit: free_transmission + template: free_transmission flow_out_eff: 0.99999995 # (1/m) lifetime: 60 # costs from [@JRC:2014], Table 39 @@ -27,7 +27,7 @@ tech_groups: techs: {% for link in links.index %} link_{{ link[0] }}_{{ link[1] }}: - inherit: ac_transmission + template: ac_transmission from: {{ link[0] }} to: {{ link[1] }} {% if energy_cap_limit is defined %} diff --git a/tests/lib/test_parametrise_template.py b/tests/lib/test_parametrise_template.py index ab7ead7e..608b06c0 100644 --- a/tests/lib/test_parametrise_template.py +++ b/tests/lib/test_parametrise_template.py @@ -43,12 +43,12 @@ TEMPLATE_LOCATIONS_IN_PARAMS = """ foo: - bar: {{ locations.loc['A-B', 'foo'] }} + bar: {{ locations.loc['A_B', 'foo'] }} """ TEMPLATE_LINKS_IN_PARAMS = """ foo: - bar: {{ links.loc['A-B,C-D', 'foo'] }} + bar: {{ links.loc['A_B,C_D', 'foo'] }} """ TEMPLATE_LOCATIONS_LINKS_IN_PARAMS_EXPECTED = """ @@ -69,7 +69,7 @@ """ TEMPLATE_LOCATIONS_ITERATE_EXPECTED = """ foo: - A-B: 1.0 + A_B: 1.0 """