From 73b1ee3599b3d15435c041fe77a344ccf565596d Mon Sep 17 00:00:00 2001 From: adrienmellot Date: Tue, 9 Apr 2024 16:58:48 +0200 Subject: [PATCH 01/13] Add uncontrolled charging share --- config/default.yaml | 1 + config/schema.yaml | 3 ++ rules/transport.smk | 36 ++++++++++--------- scripts/transport/annual_transport_demand.py | 29 ++++++++++++--- .../techs/demand/electrified-transport.yaml | 4 +-- 5 files changed, 50 insertions(+), 23 deletions(-) diff --git a/config/default.yaml b/config/default.yaml index 56d09b07..905b33ef 100644 --- a/config/default.yaml +++ b/config/default.yaml @@ -162,6 +162,7 @@ parameters: coaches-and-buses: Motor coaches, buses and trolley buses passenger-cars: Passenger cars motorcycles: Powered 2-wheelers + uncontrolled-charging-share: 1 entsoe-tyndp: scenario: National Trends grid: Reference diff --git a/config/schema.yaml b/config/schema.yaml index 97d1badf..3996bac7 100644 --- a/config/schema.yaml +++ b/config/schema.yaml @@ -348,6 +348,9 @@ properties: motorcycles: type: string description: JRC-IDEES name of motorcycles. + uncontrolled-charging-share: + type: number + description: Share of uncontrolled charging. entsoe-tyndp: type: object description: Parameters to define scenario choice for data accessed from the ENTSO-E ten-year network development plan 2020. For more information, see https://2020.entsos-tyndp-scenarios.eu/ diff --git a/rules/transport.smk b/rules/transport.smk index 9156067b..3efffd57 100644 --- a/rules/transport.smk +++ b/rules/transport.smk @@ -1,7 +1,7 @@ """Rules to process transport sector data.""" -rule download_transport_timeseries: +rule download_transport_timeseries: # TODO have correct timeseries data once RAMP has generated the new charging profile and it's been put on Zenodo message: "Get EV data from RAMP" params: url = config["data-sources"]["ev-data"] @@ -35,18 +35,20 @@ rule annual_transport_demand: jrc_road_distance = "build/data/jrc-idees/transport/processed-road-distance.csv", params: fill_missing_values = config["data-pre-processing"]["fill-missing-values"]["jrc-idees"], - efficiency_quantile = config["parameters"]["transport"]["future-vehicle-efficiency-percentile"] + efficiency_quantile = config["parameters"]["transport"]["future-vehicle-efficiency-percentile"], + uncontrolled_charging_share = config["parameters"]["transport"]["uncontrolled-charging-share"], conda: "../envs/default.yaml" output: - distance = "build/data/transport/annual-road-transport-distance-demand.csv", - distance_historic_electrification = "build/data/transport/annual-road-transport-historic-electrification.csv", + road_distance_controlled = "build/data/transport/annual-road-transport-distance-demand-controlled.csv", + road_distance_uncontrolled = "build/data/transport/annual-road-transport-distance-demand-uncontrolled.csv", + road_distance_historically_electrified = "build/data/transport/annual-road-transport-distance-demand-historic-electrification.csv", script: "../scripts/transport/annual_transport_demand.py" rule create_road_transport_timeseries: - message: "Create timeseries for road transport demand" + message: "Create timeseries for road transport demand (uncontrolled charging)" input: - annual_data = "build/data/transport/annual-road-transport-distance-demand.csv", + annual_data = "build/data/transport/annual-road-transport-distance-demand-uncontrolled.csv", timeseries = "data/automatic/ramp-ev-consumption-profiles.csv.gz" params: first_year = config["scope"]["temporal"]["first-year"], @@ -60,14 +62,14 @@ rule create_road_transport_timeseries: wildcard_constraints: vehicle_type = "light-duty-vehicles|heavy-duty-vehicles|coaches-and-buses|passenger-cars|motorcycles" output: - main = "build/data/transport/timeseries/timeseries-{vehicle_type}.csv", + main = "build/data/transport/timeseries/timeseries-uncontrolled-{vehicle_type}.csv", script: "../scripts/transport/road_transport_timeseries.py" use rule create_road_transport_timeseries as create_road_transport_timeseries_historic_electrification with: - message: "Create timeseries for historic electrified road transport demand" + message: "Create timeseries for historic electrified road transport demand (uncontrolled charging)" input: - annual_data = "build/data/transport/annual-road-transport-historic-electrification.csv", + annual_data = "build/data/transport/annual-road-transport-distance-demand-historic-electrification.csv", timeseries = "data/automatic/ramp-ev-consumption-profiles.csv.gz", params: first_year = config["scope"]["temporal"]["first-year"], @@ -78,23 +80,23 @@ use rule create_road_transport_timeseries as create_road_transport_timeseries_hi countries = config["scope"]["spatial"]["countries"], country_neighbour_dict = config["data-pre-processing"]["fill-missing-values"]["ramp"], output: - "build/data/transport/timeseries/timeseries-{vehicle_type}-historic-electrification.csv" + "build/data/transport/timeseries/timeseries-uncontrolled-{vehicle_type}-historic-electrification.csv" rule aggregate_timeseries: # TODO consider merge with other rules, as this is tiny atm message: "Aggregates timeseries for {wildcards.resolution} electrified road transport transport" input: time_series = ( - "build/data/transport/timeseries/timeseries-light-duty-vehicles.csv", - "build/data/transport/timeseries/timeseries-heavy-duty-vehicles.csv", - "build/data/transport/timeseries/timeseries-coaches-and-buses.csv", - "build/data/transport/timeseries/timeseries-passenger-cars.csv", - "build/data/transport/timeseries/timeseries-motorcycles.csv"), + "build/data/transport/timeseries/timeseries-uncontrolled-light-duty-vehicles.csv", + "build/data/transport/timeseries/timeseries-uncontrolled-heavy-duty-vehicles.csv", + "build/data/transport/timeseries/timeseries-uncontrolled-coaches-and-buses.csv", + "build/data/transport/timeseries/timeseries-uncontrolled-passenger-cars.csv", + "build/data/transport/timeseries/timeseries-uncontrolled-motorcycles.csv"), locations = "build/data/regional/units.csv", populations = "build/data/regional/population.csv" conda: "../envs/default.yaml" output: - "build/models/{resolution}/timeseries/demand/electrified-road-transport.csv", + "build/models/{resolution}/timeseries/demand/uncontrolled-electrified-road-transport.csv", script: "../scripts/transport/aggregate_timeseries.py" @@ -108,4 +110,4 @@ use rule aggregate_timeseries as aggregate_timeseries_historic_electrified with: locations = "build/data/regional/units.csv", populations = "build/data/regional/population.csv" output: - "build/models/{resolution}/timeseries/demand/road-transport-historic-electrification.csv" + "build/models/{resolution}/timeseries/demand/uncontrolled-road-transport-historic-electrification.csv" diff --git a/scripts/transport/annual_transport_demand.py b/scripts/transport/annual_transport_demand.py index b95247a9..c3cbaf71 100644 --- a/scripts/transport/annual_transport_demand.py +++ b/scripts/transport/annual_transport_demand.py @@ -229,8 +229,29 @@ def fill_missing_countries_and_years( .xs("electricity") ) - # Create CSV Files for calculated data - total_road_distance.rename("value").to_csv(snakemake.output.distance) - total_historically_electrified_distance.rename("value").to_csv( - snakemake.output.distance_historic_electrification + # Separate uncontrolled and controlled charging demands and create csv files + uncontrolled_share = snakemake.params.uncontrolled_charging_share + + road_distance_controlled = ( + total_road_distance + .rename("value") + .mul(1 - uncontrolled_share) + .to_csv(snakemake.output.road_distance_controlled) + ) + road_distance_uncontrolled = ( + total_road_distance + .rename("value") + .mul(uncontrolled_share) + .sub( + total_historically_electrified_distance + .rename("value") + , fill_value=0 + ) + .to_csv(snakemake.output.road_distance_uncontrolled) + ) + road_distance_historically_electrified = ( # ASSUME historically electrified road consumption is all uncontrolled + total_historically_electrified_distance + .rename("value") + .to_csv(snakemake.output.road_distance_historically_electrified) ) + diff --git a/templates/models/techs/demand/electrified-transport.yaml b/templates/models/techs/demand/electrified-transport.yaml index aeffe7d0..fd779b88 100644 --- a/templates/models/techs/demand/electrified-transport.yaml +++ b/templates/models/techs/demand/electrified-transport.yaml @@ -5,7 +5,7 @@ techs: parent: demand carrier: electricity constraints: - resource: file=demand/electrified-road-transport.csv + resource: file=demand/uncontrolled-electrified-road-transport.csv demand_road_transport_historic_electrified: essentials: @@ -13,7 +13,7 @@ techs: parent: supply carrier: electricity constraints: - resource: file=demand/road-transport-historic-electrification.csv + resource: file=demand/uncontrolled-road-transport-historic-electrification.csv resource_min_use: 1 overrides: From 26d87187a7c1a19a9b9f746d02fdd292d866bdb7 Mon Sep 17 00:00:00 2001 From: adrienmellot Date: Wed, 10 Apr 2024 09:49:03 +0200 Subject: [PATCH 02/13] Convert road distance to energy and scale per resolution --- config/default.yaml | 2 +- rules/transport.smk | 26 ++++- .../road_transport_controlled_charging.py | 105 ++++++++++++++++++ 3 files changed, 128 insertions(+), 5 deletions(-) create mode 100644 scripts/transport/road_transport_controlled_charging.py diff --git a/config/default.yaml b/config/default.yaml index 905b33ef..3be4f9c3 100644 --- a/config/default.yaml +++ b/config/default.yaml @@ -162,7 +162,7 @@ parameters: coaches-and-buses: Motor coaches, buses and trolley buses passenger-cars: Passenger cars motorcycles: Powered 2-wheelers - uncontrolled-charging-share: 1 + uncontrolled-charging-share: 0.5 entsoe-tyndp: scenario: National Trends grid: Reference diff --git a/rules/transport.smk b/rules/transport.smk index 3efffd57..8dd781a9 100644 --- a/rules/transport.smk +++ b/rules/transport.smk @@ -44,8 +44,26 @@ rule annual_transport_demand: road_distance_historically_electrified = "build/data/transport/annual-road-transport-distance-demand-historic-electrification.csv", script: "../scripts/transport/annual_transport_demand.py" +rule create_controlled_road_transport_annual_demand: + message: "Create annual demand for controlled charging at {wildcards.resolution} resolution" + input: + annual_controlled_demand = "build/data/transport/annual-road-transport-distance-demand-controlled.csv", + locations = "build/data/regional/units.csv", + populations = "build/data/regional/population.csv", + params: + first_year = config["scope"]["temporal"]["first-year"], + final_year = config["scope"]["temporal"]["final-year"], + power_scaling_factor = config["scaling-factors"]["power"], + conversion_factors = config["parameters"]["transport"]["road-transport-conversion-factors"], + countries = config["scope"]["spatial"]["countries"], + country_neighbour_dict = config["data-pre-processing"]["fill-missing-values"]["ramp"], + conda: "../envs/default.yaml" + output: + main = "build/data/transport/{resolution}/annual-road-transport-electricity-demand-controlled-charging-{resolution}.csv", + script: "../scripts/transport/road_transport_controlled_charging.py" + -rule create_road_transport_timeseries: +rule create_uncontrolled_road_transport_timeseries: message: "Create timeseries for road transport demand (uncontrolled charging)" input: annual_data = "build/data/transport/annual-road-transport-distance-demand-uncontrolled.csv", @@ -66,7 +84,7 @@ rule create_road_transport_timeseries: script: "../scripts/transport/road_transport_timeseries.py" -use rule create_road_transport_timeseries as create_road_transport_timeseries_historic_electrification with: +use rule create_uncontrolled_road_transport_timeseries as create_unctronolled_road_transport_timeseries_historic_electrification with: message: "Create timeseries for historic electrified road transport demand (uncontrolled charging)" input: annual_data = "build/data/transport/annual-road-transport-distance-demand-historic-electrification.csv", @@ -84,7 +102,7 @@ use rule create_road_transport_timeseries as create_road_transport_timeseries_hi rule aggregate_timeseries: # TODO consider merge with other rules, as this is tiny atm - message: "Aggregates timeseries for {wildcards.resolution} electrified road transport transport" + message: "Aggregates uncontrolled charging timeseries for {wildcards.resolution} electrified road transport transport" input: time_series = ( "build/data/transport/timeseries/timeseries-uncontrolled-light-duty-vehicles.csv", @@ -101,7 +119,7 @@ rule aggregate_timeseries: # TODO consider merge with other rules, as this is ti use rule aggregate_timeseries as aggregate_timeseries_historic_electrified with: - message: "Aggregates timeseries for {wildcards.resolution} historically electrified road transport" + message: "Aggregates uncontrolled charging timeseries for {wildcards.resolution} historically electrified road transport" input: time_series = ( "build/data/transport/timeseries/timeseries-light-duty-vehicles-historic-electrification.csv", diff --git a/scripts/transport/road_transport_controlled_charging.py b/scripts/transport/road_transport_controlled_charging.py new file mode 100644 index 00000000..564cc3bd --- /dev/null +++ b/scripts/transport/road_transport_controlled_charging.py @@ -0,0 +1,105 @@ +import pandas as pd +import pycountry + + +def scale_to_regional_resolution(df, region_country_mapping, populations): + """ + Create regional electricity demand for controlled charging. + ASSUME all road transport is subnationally distributed in proportion to population. + """ + df_population_share = ( + populations.loc[:, "population_sum"] + .reindex(region_country_mapping.keys()) + .groupby(by=region_country_mapping) + .transform(lambda df: df / df.sum()) + ) + + regional_df = ( + pd.DataFrame( + index=df.index, + data={ + id: df[country_code] + for id, country_code in region_country_mapping.items() + }, + ) + .mul(df_population_share) + .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 + + +def scale_to_national_resolution(df): + df.columns.name = None + return df + + +def scale_to_continental_resolution(df): + return df.sum(axis=1).to_frame("EUR") + + +def convert_annual_distance_to_electricity_demand( + path_to_controlled_annual_demand: str, + power_scaling_factor: float, + first_year: int, + final_year: int, + conversion_factors: dict[str, float], + country_codes: list[str], +): + """ + Convert annual distance driven demand to electricity demand for + controlled charging accounting for conversion factors. + """ + df_energy_demand = ( + pd.read_csv(path_to_controlled_annual_demand, index_col=[1, 2]) + .xs(slice(first_year, final_year), level="year", drop_level=False) + .assign(value=lambda x: x["value"] * x["vehicle_type"].map(conversion_factors)) + .groupby(["country_code", "year"]) + .sum() + .loc[country_codes] + .mul(power_scaling_factor) + .squeeze() + .unstack("country_code") + ) + + return df_energy_demand + + +if __name__ == "__main__": + resolution = snakemake.wildcards.resolution + + path_to_controlled_annual_demand = snakemake.input.annual_controlled_demand + power_scaling_factor = snakemake.params.power_scaling_factor + first_year = snakemake.params.first_year + final_year = snakemake.params.final_year + conversion_factors = snakemake.params.conversion_factors + path_to_output = snakemake.output[0] + country_codes = ( + [pycountry.countries.lookup(c).alpha_3 for c in snakemake.params.countries], + ) + region_country_mapping = ( + pd.read_csv(snakemake.input.locations, index_col=0) + .loc[:, "country_code"] + .to_dict() + ) + populations = pd.read_csv(snakemake.input.populations, index_col=0) + + df = convert_annual_distance_to_electricity_demand( + path_to_controlled_annual_demand, + power_scaling_factor, + first_year, + final_year, + conversion_factors, + country_codes, + ) + + if resolution == "continental": + scale_to_continental_resolution(df).to_csv(path_to_output) + elif resolution == "national": + scale_to_national_resolution(df).to_csv(path_to_output) + elif resolution == "regional": + scale_to_regional_resolution( + df, region_country_mapping=region_country_mapping, populations=populations + ).to_csv(path_to_output) + else: + raise ValueError("Input resolution is not recognised") From 92f36d76f0143b73ba45d5542223be32a1c4160f Mon Sep 17 00:00:00 2001 From: adrienmellot Date: Wed, 10 Apr 2024 10:07:26 +0200 Subject: [PATCH 03/13] Edit snakefile template and fix naming --- Snakefile | 4 ++-- rules/transport.smk | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Snakefile b/Snakefile index 4d71cbe2..9eb859d1 100644 --- a/Snakefile +++ b/Snakefile @@ -175,8 +175,8 @@ rule model_template: ), demand_timeseries_data = ( "build/models/{resolution}/timeseries/demand/electricity.csv", - "build/models/{resolution}/timeseries/demand/electrified-road-transport.csv", - "build/models/{resolution}/timeseries/demand/road-transport-historic-electrification.csv", + "build/models/{resolution}/timeseries/demand/uncontrolled-electrified-road-transport.csv", + "build/models/{resolution}/timeseries/demand/uncontrolled-road-transport-historic-electrification.csv", "build/models/{resolution}/timeseries/demand/electrified-heat-demand.csv", "build/models/{resolution}/timeseries/demand/heat-demand-historic-electrification.csv", ), diff --git a/rules/transport.smk b/rules/transport.smk index 8dd781a9..56952746 100644 --- a/rules/transport.smk +++ b/rules/transport.smk @@ -122,9 +122,9 @@ use rule aggregate_timeseries as aggregate_timeseries_historic_electrified with: message: "Aggregates uncontrolled charging timeseries for {wildcards.resolution} historically electrified road transport" input: time_series = ( - "build/data/transport/timeseries/timeseries-light-duty-vehicles-historic-electrification.csv", - "build/data/transport/timeseries/timeseries-coaches-and-buses-historic-electrification.csv", - "build/data/transport/timeseries/timeseries-passenger-cars-historic-electrification.csv"), + "build/data/transport/timeseries/timeseries-uncontrolled-light-duty-vehicles-historic-electrification.csv", + "build/data/transport/timeseries/timeseries-uncontrolled-coaches-and-buses-historic-electrification.csv", + "build/data/transport/timeseries/timeseries-uncontrolled-passenger-cars-historic-electrification.csv"), locations = "build/data/regional/units.csv", populations = "build/data/regional/population.csv" output: From 85fdf5109e2e7ccb1b78ebbda31248ccf7fcd4f5 Mon Sep 17 00:00:00 2001 From: adrienmellot Date: Wed, 10 Apr 2024 11:55:27 +0200 Subject: [PATCH 04/13] Add annual controlled demand to yaml model files --- Snakefile | 3 +- rules/transport.smk | 2 +- .../road_transport_controlled_charging.py | 11 +++--- .../techs/demand/electrified-transport.yaml | 35 +++++++++++++++---- 4 files changed, 37 insertions(+), 14 deletions(-) diff --git a/Snakefile b/Snakefile index 9eb859d1..85370b54 100644 --- a/Snakefile +++ b/Snakefile @@ -32,6 +32,7 @@ wildcard_constraints: ruleorder: area_to_capacity_limits > hydro_capacities > biofuels > nuclear_regional_capacity > dummy_tech_locations_template ruleorder: bio_techs_and_locations_template > techs_and_locations_template +ruleorder: create_controlled_road_transport_annual_demand > dummy_tech_locations_template ALL_CF_TECHNOLOGIES = [ "wind-onshore", "wind-offshore", "open-field-pv", @@ -98,7 +99,7 @@ rule all_tests: rule dummy_tech_locations_template: # needed to provide `techs_and_locations_template` with a locational CSV linked to each technology that has no location-specific data to define. - message: "Create empty {wildcards.resolution} location-specific data file for the {wildcards.tech_group} tech `{wildcards.tech}`." + message: "Create empty {wildcards.resolution} location-specific data file for the {wildcards.tech_group} tech `{wildcards.tech}`." # Not used only if ruleorder is updated at top of file input: rules.locations_template.output.csv output: "build/data/{resolution}/{tech_group}/{tech}.csv" conda: "envs/shell.yaml" diff --git a/rules/transport.smk b/rules/transport.smk index 56952746..d699f655 100644 --- a/rules/transport.smk +++ b/rules/transport.smk @@ -59,7 +59,7 @@ rule create_controlled_road_transport_annual_demand: country_neighbour_dict = config["data-pre-processing"]["fill-missing-values"]["ramp"], conda: "../envs/default.yaml" output: - main = "build/data/transport/{resolution}/annual-road-transport-electricity-demand-controlled-charging-{resolution}.csv", + main = "build/data/{resolution}/demand/electrified-transport.csv", script: "../scripts/transport/road_transport_controlled_charging.py" diff --git a/scripts/transport/road_transport_controlled_charging.py b/scripts/transport/road_transport_controlled_charging.py index 564cc3bd..e3fce832 100644 --- a/scripts/transport/road_transport_controlled_charging.py +++ b/scripts/transport/road_transport_controlled_charging.py @@ -62,7 +62,7 @@ def convert_annual_distance_to_electricity_demand( .unstack("country_code") ) - return df_energy_demand + return -df_energy_demand if __name__ == "__main__": @@ -94,12 +94,13 @@ def convert_annual_distance_to_electricity_demand( ) if resolution == "continental": - scale_to_continental_resolution(df).to_csv(path_to_output) + df = scale_to_continental_resolution(df) elif resolution == "national": - scale_to_national_resolution(df).to_csv(path_to_output) + df = scale_to_national_resolution(df) elif resolution == "regional": - scale_to_regional_resolution( + df = scale_to_regional_resolution( df, region_country_mapping=region_country_mapping, populations=populations - ).to_csv(path_to_output) + ) else: raise ValueError("Input resolution is not recognised") + df.T.to_csv(path_to_output, index_label=['id']) diff --git a/templates/models/techs/demand/electrified-transport.yaml b/templates/models/techs/demand/electrified-transport.yaml index fd779b88..78da9565 100644 --- a/templates/models/techs/demand/electrified-transport.yaml +++ b/templates/models/techs/demand/electrified-transport.yaml @@ -1,29 +1,50 @@ techs: - demand_road_transport_electrified: + demand_road_transport_electrified_uncontrolled: essentials: - name: 'Electrified road transport demand' + 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_historic_electrified: + demand_road_transport_historic_electrified_uncontrolled: essentials: - name: 'Removes historic electrified road transport demand' + name: 'Removes historic electrified road transport demand -- assumed uncontrolled' parent: supply carrier: electricity constraints: resource: file=demand/uncontrolled-road-transport-historic-electrification.csv resource_min_use: 1 + demand_road_transport_electrified_controlled: + essentials: + name: 'Controlled electrified road transport demand' + parent: demand + carrier: electricity + constraints: + force_resource: false + resource: -.inf + overrides: keep-historic-electricity-demand-from-road-transport: {% for id, location in locations.iterrows() %} - {{ id }}.techs.demand_road_transport_historic_electrified.exists: False + {{ id }}.techs.demand_road_transport_historic_electrified_uncontrolled.exists: False {% endfor %} + {% for year in locations.columns %} + {{ year }}_transport_controlled_electrified_demand: + group_constraints: + {% for location in locations.index %} + {{ location }}_annual_controlled_electricity_demand: + locs: [{{ location }}] + techs: [demand_road_transport_electrified_controlled] + carrier_con_equals: + electricity: {{ locations.loc[location, year] }} # {{ (1 / scaling_factors.power) | unit("MWh") }} + {% endfor %} + {% endfor %} + locations: {% for id, location in locations.iterrows() %} - {{ id }}.techs.demand_road_transport_electrified: - {{ id }}.techs.demand_road_transport_historic_electrified: + {{ id }}.techs.demand_road_transport_electrified_uncontrolled: + {{ id }}.techs.demand_road_transport_historic_electrified_uncontrolled: {% endfor %} From 398520a2c643ed6dcce10f1a7e00e9a570ba7593 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 10 Apr 2024 10:01:29 +0000 Subject: [PATCH 05/13] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- scripts/transport/annual_transport_demand.py | 19 ++++++------------- .../road_transport_controlled_charging.py | 2 +- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/scripts/transport/annual_transport_demand.py b/scripts/transport/annual_transport_demand.py index c3cbaf71..8e1a5f5f 100644 --- a/scripts/transport/annual_transport_demand.py +++ b/scripts/transport/annual_transport_demand.py @@ -233,25 +233,18 @@ def fill_missing_countries_and_years( uncontrolled_share = snakemake.params.uncontrolled_charging_share road_distance_controlled = ( - total_road_distance - .rename("value") + total_road_distance.rename("value") .mul(1 - uncontrolled_share) .to_csv(snakemake.output.road_distance_controlled) ) road_distance_uncontrolled = ( - total_road_distance - .rename("value") + total_road_distance.rename("value") .mul(uncontrolled_share) - .sub( - total_historically_electrified_distance - .rename("value") - , fill_value=0 - ) + .sub(total_historically_electrified_distance.rename("value"), fill_value=0) .to_csv(snakemake.output.road_distance_uncontrolled) ) road_distance_historically_electrified = ( # ASSUME historically electrified road consumption is all uncontrolled - total_historically_electrified_distance - .rename("value") - .to_csv(snakemake.output.road_distance_historically_electrified) + total_historically_electrified_distance.rename("value").to_csv( + snakemake.output.road_distance_historically_electrified + ) ) - diff --git a/scripts/transport/road_transport_controlled_charging.py b/scripts/transport/road_transport_controlled_charging.py index e3fce832..ccb9fe91 100644 --- a/scripts/transport/road_transport_controlled_charging.py +++ b/scripts/transport/road_transport_controlled_charging.py @@ -103,4 +103,4 @@ def convert_annual_distance_to_electricity_demand( ) else: raise ValueError("Input resolution is not recognised") - df.T.to_csv(path_to_output, index_label=['id']) + df.T.to_csv(path_to_output, index_label=["id"]) From a40424f2fdbefbb5745b62a1fd5007898b87ee52 Mon Sep 17 00:00:00 2001 From: adrienmellot Date: Wed, 10 Apr 2024 12:05:23 +0200 Subject: [PATCH 06/13] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 795cbca0..aeff7636 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ ### Added (models) * **ADD** fully-electrified heat demand (#284). -* **ADD** fully-electrified road transportation (#270), (#271). +* **ADD** fully-electrified road transportation (#270), (#271). A parameter allows to define the share of uncontrolled (timeseries) vs controlled charging (optimised) by the solver (PR #338). * **ADD** nuclear power plant technology with capacity limits. Capacity limits can be equal to today or be bound by a minimum and maximum capacity to represent an available range in future. In either case, capacities are allocated at a subnational resolution based on linear scaling from current capacity geolocations, using the JRC power plant database (#78). From ae2dc9b098e6186c507e2e75a460dc5752253e69 Mon Sep 17 00:00:00 2001 From: adrienmellot Date: Wed, 10 Apr 2024 14:33:13 +0200 Subject: [PATCH 07/13] Adress comments --- Snakefile | 2 +- config/default.yaml | 2 +- config/schema.yaml | 2 +- rules/transport.smk | 17 ++++++++--------- scripts/transport/annual_transport_demand.py | 3 ++- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Snakefile b/Snakefile index 85370b54..dd68bb52 100644 --- a/Snakefile +++ b/Snakefile @@ -99,7 +99,7 @@ rule all_tests: rule dummy_tech_locations_template: # needed to provide `techs_and_locations_template` with a locational CSV linked to each technology that has no location-specific data to define. - message: "Create empty {wildcards.resolution} location-specific data file for the {wildcards.tech_group} tech `{wildcards.tech}`." # Not used only if ruleorder is updated at top of file + message: "Create empty {wildcards.resolution} location-specific data file for the {wildcards.tech_group} tech `{wildcards.tech}`." # Update ruleorder at the top of the file if you instead want the techs_and_locations_template rule to be used to generate a file input: rules.locations_template.output.csv output: "build/data/{resolution}/{tech_group}/{tech}.csv" conda: "envs/shell.yaml" diff --git a/config/default.yaml b/config/default.yaml index 3be4f9c3..1dc50ca3 100644 --- a/config/default.yaml +++ b/config/default.yaml @@ -162,7 +162,7 @@ parameters: coaches-and-buses: Motor coaches, buses and trolley buses passenger-cars: Passenger cars motorcycles: Powered 2-wheelers - uncontrolled-charging-share: 0.5 + uncontrolled-ev-charging-share: 0.5 entsoe-tyndp: scenario: National Trends grid: Reference diff --git a/config/schema.yaml b/config/schema.yaml index 3996bac7..d8e7c175 100644 --- a/config/schema.yaml +++ b/config/schema.yaml @@ -348,7 +348,7 @@ properties: motorcycles: type: string description: JRC-IDEES name of motorcycles. - uncontrolled-charging-share: + uncontrolled-ev-charging-share: type: number description: Share of uncontrolled charging. entsoe-tyndp: diff --git a/rules/transport.smk b/rules/transport.smk index d699f655..118f375b 100644 --- a/rules/transport.smk +++ b/rules/transport.smk @@ -1,7 +1,8 @@ """Rules to process transport sector data.""" -rule download_transport_timeseries: # TODO have correct timeseries data once RAMP has generated the new charging profile and it's been put on Zenodo +rule download_transport_timeseries: + # TODO have correct timeseries data once RAMP has generated the new charging profile and it's been put on Zenodo message: "Get EV data from RAMP" params: url = config["data-sources"]["ev-data"] @@ -36,7 +37,7 @@ rule annual_transport_demand: params: fill_missing_values = config["data-pre-processing"]["fill-missing-values"]["jrc-idees"], efficiency_quantile = config["parameters"]["transport"]["future-vehicle-efficiency-percentile"], - uncontrolled_charging_share = config["parameters"]["transport"]["uncontrolled-charging-share"], + uncontrolled_charging_share = config["parameters"]["transport"]["uncontrolled-ev-charging-share"], conda: "../envs/default.yaml" output: road_distance_controlled = "build/data/transport/annual-road-transport-distance-demand-controlled.csv", @@ -84,7 +85,7 @@ rule create_uncontrolled_road_transport_timeseries: script: "../scripts/transport/road_transport_timeseries.py" -use rule create_uncontrolled_road_transport_timeseries as create_unctronolled_road_transport_timeseries_historic_electrification with: +use rule create_uncontrolled_road_transport_timeseries as create_uncontrolled_road_transport_timeseries_historic_electrification with: message: "Create timeseries for historic electrified road transport demand (uncontrolled charging)" input: annual_data = "build/data/transport/annual-road-transport-distance-demand-historic-electrification.csv", @@ -104,12 +105,10 @@ use rule create_uncontrolled_road_transport_timeseries as create_unctronolled_ro rule aggregate_timeseries: # TODO consider merge with other rules, as this is tiny atm message: "Aggregates uncontrolled charging timeseries for {wildcards.resolution} electrified road transport transport" input: - time_series = ( - "build/data/transport/timeseries/timeseries-uncontrolled-light-duty-vehicles.csv", - "build/data/transport/timeseries/timeseries-uncontrolled-heavy-duty-vehicles.csv", - "build/data/transport/timeseries/timeseries-uncontrolled-coaches-and-buses.csv", - "build/data/transport/timeseries/timeseries-uncontrolled-passenger-cars.csv", - "build/data/transport/timeseries/timeseries-uncontrolled-motorcycles.csv"), + time_series = [ + f'build/data/transport/timeseries/timeseries-uncontrolled-{vehicle_type}.csv' + for vehicle_type in config["parameters"]["transport"]["road-transport-conversion-factors"].keys() + ], locations = "build/data/regional/units.csv", populations = "build/data/regional/population.csv" conda: "../envs/default.yaml" diff --git a/scripts/transport/annual_transport_demand.py b/scripts/transport/annual_transport_demand.py index 8e1a5f5f..8e1cbb8d 100644 --- a/scripts/transport/annual_transport_demand.py +++ b/scripts/transport/annual_transport_demand.py @@ -243,7 +243,8 @@ def fill_missing_countries_and_years( .sub(total_historically_electrified_distance.rename("value"), fill_value=0) .to_csv(snakemake.output.road_distance_uncontrolled) ) - road_distance_historically_electrified = ( # ASSUME historically electrified road consumption is all uncontrolled + # ASSUME historically electrified road consumption is all uncontrolled + road_distance_historically_electrified = ( total_historically_electrified_distance.rename("value").to_csv( snakemake.output.road_distance_historically_electrified ) From cc30987d97298477ed8726dd3a6c256c2684b657 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 10 Apr 2024 12:33:26 +0000 Subject: [PATCH 08/13] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- rules/transport.smk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rules/transport.smk b/rules/transport.smk index 118f375b..46959af7 100644 --- a/rules/transport.smk +++ b/rules/transport.smk @@ -1,7 +1,7 @@ """Rules to process transport sector data.""" -rule download_transport_timeseries: +rule download_transport_timeseries: # TODO have correct timeseries data once RAMP has generated the new charging profile and it's been put on Zenodo message: "Get EV data from RAMP" params: From 145c2a8993dfac9ea77417cb9b02ec13a0ab8f21 Mon Sep 17 00:00:00 2001 From: adrienmellot Date: Wed, 10 Apr 2024 22:55:02 +0200 Subject: [PATCH 09/13] customisation.md and electrified-transport.yaml update --- docs/model/customisation.md | 8 ++++++-- .../models/techs/demand/electrified-transport.yaml | 10 ++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/docs/model/customisation.md b/docs/model/customisation.md index 7be72396..d19a5fd1 100644 --- a/docs/model/customisation.md +++ b/docs/model/customisation.md @@ -42,9 +42,11 @@ Here, we describe each module in terms of the technologies they contain (`callio === "Technologies" - **demand_road_transport_electrified**: Electrified road transport demand + **demand_road_transport_electrified_uncontrolled**: Share of electrified road transport demand which is uncontrolled. - **demand_road_transport_historic_electrified**: Removes historically electrified road transport demand to avoid double counting + **demand_road_transport_historic_electrified_uncontrolled**: Removes historically electrified road transport demand to avoid double counting. It is assumed uncontrolled. + + **demand_road_transport_electrified_controlled**: Share of electrified road transport demand whose charging is optimised by the solver. === "Overrides" @@ -58,6 +60,8 @@ Here, we describe each module in terms of the technologies they contain (`callio **demand_heat_historic_electrified**: Removes historically electrified heat demand to avoid double counting + **_transport_controlled_electrified_demand: Total electrified road transport demand whose charging is optimised by the solver. + === "Overrides" **keep-historic-electricity-demand-from-heat**: Keep historically electrified heat demand. Historically electrified heat demand is deleted by default, as it is already considered in historic electricity demand and would thus be counted twice. Using this override together with Euro-Calliope's default electricity demand is not advised. diff --git a/templates/models/techs/demand/electrified-transport.yaml b/templates/models/techs/demand/electrified-transport.yaml index 78da9565..4668543a 100644 --- a/templates/models/techs/demand/electrified-transport.yaml +++ b/templates/models/techs/demand/electrified-transport.yaml @@ -14,7 +14,7 @@ techs: carrier: electricity constraints: resource: file=demand/uncontrolled-road-transport-historic-electrification.csv - resource_min_use: 1 + force_resource: False demand_road_transport_electrified_controlled: essentials: @@ -22,7 +22,7 @@ techs: parent: demand carrier: electricity constraints: - force_resource: false + force_resource: False resource: -.inf overrides: @@ -45,6 +45,8 @@ overrides: locations: {% for id, location in locations.iterrows() %} - {{ id }}.techs.demand_road_transport_electrified_uncontrolled: - {{ id }}.techs.demand_road_transport_historic_electrified_uncontrolled: + {{ id }}.techs: + demand_road_transport_electrified_uncontrolled: + demand_road_transport_historic_electrified_uncontrolled: + demand_road_transport_electrified_controlled: {% endfor %} From 58175ea436d479449b4638e38c92734e5fd31b29 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 10 Apr 2024 20:55:11 +0000 Subject: [PATCH 10/13] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- docs/model/customisation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/model/customisation.md b/docs/model/customisation.md index d19a5fd1..0c0ca627 100644 --- a/docs/model/customisation.md +++ b/docs/model/customisation.md @@ -45,7 +45,7 @@ Here, we describe each module in terms of the technologies they contain (`callio **demand_road_transport_electrified_uncontrolled**: Share of electrified road transport demand which is uncontrolled. **demand_road_transport_historic_electrified_uncontrolled**: Removes historically electrified road transport demand to avoid double counting. It is assumed uncontrolled. - + **demand_road_transport_electrified_controlled**: Share of electrified road transport demand whose charging is optimised by the solver. === "Overrides" From 3c84405a1c0eb06ea1c2100d7644db4c4d0575b6 Mon Sep 17 00:00:00 2001 From: adrienmellot Date: Wed, 10 Apr 2024 22:59:51 +0200 Subject: [PATCH 11/13] Update customisation.md --- docs/model/customisation.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/model/customisation.md b/docs/model/customisation.md index d19a5fd1..5ef26f0e 100644 --- a/docs/model/customisation.md +++ b/docs/model/customisation.md @@ -52,6 +52,8 @@ Here, we describe each module in terms of the technologies they contain (`callio **keep-historic-electricity-demand-from-road-transport**: Keep historically electrified road transport demand. Historically electrified road transport demand is deleted by default, as it is already considered in historic electricity demand and would thus be counted twice. Using this override together with Euro-Calliope's default electricity demand is not advised. + **(year)_transport_controlled_electrified_demand: Total electrified road transport demand whose charging is optimised by the solver. + ??? note "demand/electrified-heat.yaml" === "Technologies" @@ -60,7 +62,6 @@ Here, we describe each module in terms of the technologies they contain (`callio **demand_heat_historic_electrified**: Removes historically electrified heat demand to avoid double counting - **_transport_controlled_electrified_demand: Total electrified road transport demand whose charging is optimised by the solver. === "Overrides" From 5569fad1a08e6ed9dcd034b8b04922671337c719 Mon Sep 17 00:00:00 2001 From: adrienmellot Date: Wed, 10 Apr 2024 23:08:12 +0200 Subject: [PATCH 12/13] Update customisation.md --- docs/model/customisation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/model/customisation.md b/docs/model/customisation.md index a363bfab..c8a4243d 100644 --- a/docs/model/customisation.md +++ b/docs/model/customisation.md @@ -52,7 +52,7 @@ Here, we describe each module in terms of the technologies they contain (`callio **keep-historic-electricity-demand-from-road-transport**: Keep historically electrified road transport demand. Historically electrified road transport demand is deleted by default, as it is already considered in historic electricity demand and would thus be counted twice. Using this override together with Euro-Calliope's default electricity demand is not advised. - **(year)_transport_controlled_electrified_demand: Total electrified road transport demand whose charging is optimised by the solver. + **(year)_transport_controlled_electrified_demand**: Total electrified road transport demand whose charging is optimised by the solver. ??? note "demand/electrified-heat.yaml" From 60a3e42fe3288e6f68edb66c332f6c5ebe8358e3 Mon Sep 17 00:00:00 2001 From: Bryn Pickering <17178478+brynpickering@users.noreply.github.com> Date: Thu, 11 Apr 2024 09:31:34 +0200 Subject: [PATCH 13/13] Minor fix to YAML template. --- templates/models/techs/demand/electrified-transport.yaml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/templates/models/techs/demand/electrified-transport.yaml b/templates/models/techs/demand/electrified-transport.yaml index 4668543a..bfba831b 100644 --- a/templates/models/techs/demand/electrified-transport.yaml +++ b/templates/models/techs/demand/electrified-transport.yaml @@ -9,12 +9,12 @@ techs: demand_road_transport_historic_electrified_uncontrolled: essentials: - name: 'Removes historic electrified road transport demand -- assumed uncontrolled' + 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: False + force_resource: true demand_road_transport_electrified_controlled: essentials: @@ -22,13 +22,14 @@ techs: parent: demand carrier: electricity constraints: - force_resource: False + force_resource: false resource: -.inf 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 + {{ id }}.techs.demand_road_transport_historic_electrified_uncontrolled.exists: false {% endfor %} {% for year in locations.columns %}