diff --git a/INTERFACE.yaml b/INTERFACE.yaml index 20e10bf..069a5af 100644 --- a/INTERFACE.yaml +++ b/INTERFACE.yaml @@ -24,8 +24,9 @@ pathvars: WDPA protected areas database from https://www.protectedplanet.net/ in GeoDB format (choose 'File Geodatabase' when downloading). results: area_potential: - default: "/{shape}/area_potential_{tech}.tif" + default: "/{shape}/{scenario}/area_potential_{tech}.tif" description: "Area potential GeoTIFF raster for the specified technology across all subunits." wildcards: shape: "Name of the shape to be processed, e.g., 'world', 'europe', 'MEX'." tech: "Name of the technology, e.g., 'pv_rooftop' or 'wind_offshore'. Available technologies are defined in the module configuration." + scenario: "Scenario name from the module configuration." diff --git a/config/config.yaml b/config/config.yaml index 947d727..03aba1e 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -8,87 +8,91 @@ split_by: country_id # likely country_id or shape_id # Optional - specify land_cover_types here to override the internal defaults. -techs: - pv_rooftop: - initial_area: settlement_area - continuous_layers: - settlement_share: - min: 0.01 - max: 1 - share: 0.8 - binary_layers: - regions_maritime: 0 - regions_land: 1 - protected: 0 - # Include all land cover types; selection is done by settlement_share - landcover_FARM: 1 - landcover_FOREST: 1 - landcover_URBAN: 1 - landcover_OTHER: 1 - landcover_NOT_SUITABLE: 0 - landcover_WATER: 0 - pv_open_field: - initial_area: pixel_area - continuous_layers: - slope: - min: 0 - max: 3 - settlement_share: - min: 0 - max: 0.01 - binary_layers: - regions_maritime: 0 - regions_land: 1 - protected: 0 - landcover_FARM: 0.1 - landcover_FOREST: 0 - landcover_URBAN: 0 - landcover_OTHER: 0.2 - landcover_NOT_SUITABLE: 0 - landcover_WATER: 0 - wind_onshore: - initial_area: pixel_area - continuous_layers: - slope: - min: 0 - max: 20 - settlement_share: - min: 0 - max: 0.01 - binary_layers: - regions_maritime: 0 - regions_land: 1 - protected: 0 - landcover_FARM: 0.2 - landcover_FOREST: 0.05 - landcover_URBAN: 0 - landcover_OTHER: 0.3 - landcover_NOT_SUITABLE: 0 - landcover_WATER: 0 - wind_offshore: - initial_area: pixel_area - continuous_layers: - bathymetry: - min: -50 - max: 0 - share: 0.8 - binary_layers: - regions_land: 0 - regions_maritime: 1 - protected: 0 - shapes_buffer: - land: 10000 # meters +scenarios: + # Define at least one scenario. Multiple scenarios can be used to study + # the effect of different assumptions on the results. + base: + techs: + pv_rooftop: + initial_area: settlement_area + continuous_layers: + settlement_share: + min: 0.01 + max: 1 + share: 0.8 + binary_layers: + regions_maritime: 0 + regions_land: 1 + protected: 0 + # Include all land cover types; selection is done by settlement_share + landcover_FARM: 1 + landcover_FOREST: 1 + landcover_URBAN: 1 + landcover_OTHER: 1 + landcover_NOT_SUITABLE: 0 + landcover_WATER: 0 + pv_open_field: + initial_area: pixel_area + continuous_layers: + slope: + min: 0 + max: 3 + settlement_share: + min: 0 + max: 0.01 + binary_layers: + regions_maritime: 0 + regions_land: 1 + protected: 0 + landcover_FARM: 0.1 + landcover_FOREST: 0 + landcover_URBAN: 0 + landcover_OTHER: 0.2 + landcover_NOT_SUITABLE: 0 + landcover_WATER: 0 + wind_onshore: + initial_area: pixel_area + continuous_layers: + slope: + min: 0 + max: 20 + settlement_share: + min: 0 + max: 0.01 + binary_layers: + regions_maritime: 0 + regions_land: 1 + protected: 0 + landcover_FARM: 0.2 + landcover_FOREST: 0.05 + landcover_URBAN: 0 + landcover_OTHER: 0.3 + landcover_NOT_SUITABLE: 0 + landcover_WATER: 0 + wind_offshore: + initial_area: pixel_area + continuous_layers: + bathymetry: + min: -50 + max: 0 + share: 0.8 + binary_layers: + regions_land: 0 + regions_maritime: 1 + protected: 0 + shapes_buffer: + land: 10000 # meters -# Optional: override settings for specific subunits (countries, regions, etc.) -# This allows you to set specific parameters that differ from the defaults, -# or apply settings that are not defined in the defaults (defaults = `techs` section). -# The subunit keys should match the subunit IDs used in column selected in `split_by`. -overrides: - PRT: # Inside a subunit, any setting from `techs` can be overridden - wind_offshore: - shapes_buffer: - land: 2000 # meters - NLD: - wind_offshore: - shapes_buffer: - land: 22000 # 22 km = 12 nautical miles + # Optional: override settings for specific subunits (countries, regions, etc.) + # This allows you to set specific parameters that differ from the defaults, + # or apply settings that are not defined in the defaults (defaults = `techs` section). + # The subunit keys should match the subunit IDs used in column selected in `split_by`. + overrides: + PRT: # Inside a subunit, any setting from `techs` can be overridden + wind_offshore: + shapes_buffer: + land: 2000 # meters + NLD: + wind_offshore: + shapes_buffer: + land: 22000 # 22 km = 12 nautical miles diff --git a/tests/integration/Snakefile b/tests/integration/Snakefile index 186b871..819f364 100644 --- a/tests/integration/Snakefile +++ b/tests/integration/Snakefile @@ -60,7 +60,7 @@ module module_area_potentials: shapes="resources/inputs/shapes/{shape}.parquet", wdpa="resources/inputs/wdpa.gdb", # Redirect specific module results (outputs) - area_potential="results/outputs/{shape}/area_potential_{tech}.tif", + area_potential="results/outputs/{shape}/{scenario}/area_potential_{tech}.tif", # Redirect module intermediate files logs="resources/module/logs", resources="resources/module/resources", @@ -80,6 +80,6 @@ rule all: default_target: True input: # The report file requires all area potential output files - "resources/module/results/NLD/area_potential_report.html", + "resources/module/results/NLD/base/area_potential_report.html", message: "Run the module for the Netherlands shapes." diff --git a/tests/integration/test_config.yaml b/tests/integration/test_config.yaml index 3a579f4..74be30d 100644 --- a/tests/integration/test_config.yaml +++ b/tests/integration/test_config.yaml @@ -2,73 +2,75 @@ module_area_potentials: tiny_files: True buffer_crs: "epsg:8857" split_by: country_id - techs: - pv_rooftop: - initial_area: settlement_area - continuous_layers: - settlement_share: - min: 0.01 - max: 1 - share: 0.8 - binary_layers: - regions_maritime: 0 - regions_land: 1 - protected: 0 - # Include all land cover types; selection is done by settlement_share - landcover_FARM: 1 - landcover_FOREST: 1 - landcover_URBAN: 1 - landcover_OTHER: 1 - landcover_NOT_SUITABLE: 0 - landcover_WATER: 0 - pv_open_field: - initial_area: pixel_area - continuous_layers: - slope: - min: 0 - max: 3 - settlement_share: - min: 0 - max: 0.01 - binary_layers: - regions_maritime: 0 - regions_land: 1 - protected: 0 - landcover_FARM: 0.1 - landcover_FOREST: 0 - landcover_URBAN: 0 - landcover_OTHER: 0.2 - landcover_NOT_SUITABLE: 0 - landcover_WATER: 0 - wind_onshore: - initial_area: pixel_area - continuous_layers: - slope: - min: 0 - max: 20 - settlement_share: - min: 0 - max: 0.01 - binary_layers: - regions_maritime: 0 - regions_land: 1 - protected: 0 - landcover_FARM: 0.2 - landcover_FOREST: 0.05 - landcover_URBAN: 0 - landcover_OTHER: 0.3 - landcover_NOT_SUITABLE: 0 - landcover_WATER: 0 - wind_offshore: - initial_area: pixel_area - continuous_layers: - bathymetry: - min: -50 - max: 0 - share: 0.8 - binary_layers: - regions_land: 0 - regions_maritime: 1 - protected: 0 - shapes_buffer: - land: 10000 # meters + scenarios: + base: + techs: + pv_rooftop: + initial_area: settlement_area + continuous_layers: + settlement_share: + min: 0.01 + max: 1 + share: 0.8 + binary_layers: + regions_maritime: 0 + regions_land: 1 + protected: 0 + # Include all land cover types; selection is done by settlement_share + landcover_FARM: 1 + landcover_FOREST: 1 + landcover_URBAN: 1 + landcover_OTHER: 1 + landcover_NOT_SUITABLE: 0 + landcover_WATER: 0 + pv_open_field: + initial_area: pixel_area + continuous_layers: + slope: + min: 0 + max: 3 + settlement_share: + min: 0 + max: 0.01 + binary_layers: + regions_maritime: 0 + regions_land: 1 + protected: 0 + landcover_FARM: 0.1 + landcover_FOREST: 0 + landcover_URBAN: 0 + landcover_OTHER: 0.2 + landcover_NOT_SUITABLE: 0 + landcover_WATER: 0 + wind_onshore: + initial_area: pixel_area + continuous_layers: + slope: + min: 0 + max: 20 + settlement_share: + min: 0 + max: 0.01 + binary_layers: + regions_maritime: 0 + regions_land: 1 + protected: 0 + landcover_FARM: 0.2 + landcover_FOREST: 0.05 + landcover_URBAN: 0 + landcover_OTHER: 0.3 + landcover_NOT_SUITABLE: 0 + landcover_WATER: 0 + wind_offshore: + initial_area: pixel_area + continuous_layers: + bathymetry: + min: -50 + max: 0 + share: 0.8 + binary_layers: + regions_land: 0 + regions_maritime: 1 + protected: 0 + shapes_buffer: + land: 10000 # meters diff --git a/workflow/Snakefile b/workflow/Snakefile index fcc85e9..71281ff 100644 --- a/workflow/Snakefile +++ b/workflow/Snakefile @@ -13,7 +13,7 @@ pathvars: shapes="/user/shapes/{shape}.parquet", wdpa="/user/wdpa.gdb", # Module results - area_potential="/{shape}/area_potential_{tech}.tif", + area_potential="/{shape}/{scenario}/area_potential_{tech}.tif", # Load the example configuration. This will be overridden by users. @@ -36,7 +36,14 @@ workflow.source_path("scripts/_script_utils.py") wildcard_constraints: shape="[a-zA-Z0-9_-]+", subunit="[a-zA-Z0-9_]+", - tech="|".join(config["techs"].keys()), + scenario="|".join(config["scenarios"].keys()), + tech="|".join( + [ + tech + for scenario in config["scenarios"] + for tech in config["scenarios"][scenario]["techs"] + ] + ), # Add all your includes here. diff --git a/workflow/internal/config.schema.yaml b/workflow/internal/config.schema.yaml index 0ff7423..aebe3e5 100644 --- a/workflow/internal/config.schema.yaml +++ b/workflow/internal/config.schema.yaml @@ -1,8 +1,7 @@ $schema: "https://json-schema.org/draft/2020-12/schema" description: "Schema for user-provided configuration files." -type: object -additionalProperties: false -properties: + +$defs: tiny_files: type: boolean description: "If True, use smaller, clipped files for processing. If False, use full global datasets." @@ -52,3 +51,12 @@ properties: type: object additionalProperties: type: object + + scenarios: + type: object + required: + - techs + additionalProperties: false + properties: + techs: + $ref: "#/$defs/techs" diff --git a/workflow/rules/functions.smk b/workflow/rules/functions.smk index 89a7fd0..36795a3 100644 --- a/workflow/rules/functions.smk +++ b/workflow/rules/functions.smk @@ -1,8 +1,12 @@ def get_subunits(wildcards): checkpoint_output = checkpoints.breakup_shape.get(**wildcards).output[0] return expand( - "/{{shape}}/{subunit}/area_potential_{{tech}}.tif", + "/{{shape}}/{{scenario}}/{subunit}/area_potential_{{tech}}.tif", subunit=glob_wildcards( os.path.join(checkpoint_output, "{subunit}.parquet") ).subunit, ) + + +def get_techs(wildcards): + return config["scenarios"][wildcards.scenario]["techs"].keys() diff --git a/workflow/rules/process.smk b/workflow/rules/process.smk index 7e1f7b1..6b30574 100644 --- a/workflow/rules/process.smk +++ b/workflow/rules/process.smk @@ -59,23 +59,26 @@ rule area_potential: shapes=rules.breakup_shape.output, resampled_path=rules.prepare_resampled_inputs.output.resampled_input, output: - area_potential="/{shape}/{subunit}/area_potential_{tech}.tif", + area_potential="/{shape}/{scenario}/{subunit}/area_potential_{tech}.tif", plot=report( - "/{shape}/{subunit}/area_potential_{tech}.png", + "/{shape}/{scenario}/{subunit}/area_potential_{tech}.png", category="area_potential", ), log: - "/{shape}/{subunit}/area_potential_{tech}.log", + "/{shape}/{scenario}/{subunit}/area_potential_{tech}.log", conda: "../envs/module.yaml" params: - config=lambda wildcards: config["techs"][f"{wildcards.tech}"], + config=lambda wildcards: config["scenarios"][f"{wildcards.scenario}"]["techs"][ + f"{wildcards.tech}" + ], subunit_override_config=lambda wildcards: config.get("overrides", {}) + .get(wildcards.scenario, {}) .get(wildcards.subunit, {}) .get(wildcards.tech, {}), buffer_crs=lambda wildcards: config["buffer_crs"], message: - "Compute area potential for the tech {wildcards.tech} and {wildcards.subunit} in {wildcards.shape}." + "Compute area potential for the scenario {wildcards.scenario}, the tech {wildcards.tech} and {wildcards.subunit} in {wildcards.shape}." shell: """ python {input.script:q} "{input.shapes}/{wildcards.subunit}.parquet" {input.resampled_path:q} {params.config:q} {params.buffer_crs:q} {output.area_potential:q} {output.plot:q} --override_config={params.subunit_override_config:q} 2>{log:q} @@ -88,11 +91,11 @@ rule aggregate_area_potential: output: aggregated_area_potential="", log: - "/{shape}/aggregate_area_potential_{tech}.log", + "/{shape}/{scenario}/aggregate_area_potential_{tech}.log", conda: "../envs/module.yaml" message: - "Aggregate area potential for the tech {wildcards.tech} in {wildcards.shape}." + "Aggregate area potential for the scenario {wildcards.scenario} and the tech {wildcards.tech} in {wildcards.shape}." shell: """ gdalwarp --config GDAL_CACHEMAX 3000 -wm 3000 -of GTiff -co COMPRESS=LZW {input} {output.aggregated_area_potential:q} @@ -104,15 +107,15 @@ rule plot_aggregated_area_potential: rules.aggregate_area_potential.output.aggregated_area_potential, output: report( - "/{shape}/area_potential_{tech}.png", + "/{shape}/{scenario}/area_potential_{tech}.png", category="area_potential_plot", ), log: - "/{shape}/plot_aggregated_area_potential_{tech}.log", + "/{shape}/{scenario}/plot_aggregated_area_potential_{tech}.log", conda: "../envs/module.yaml" message: - "Plot aggregated area potential for the tech {wildcards.tech} in {wildcards.shape}." + "Plot aggregated area potential for the scenario {wildcards.scenario} and the tech {wildcards.tech} in {wildcards.shape}." script: "../scripts/tif_to_png.py" @@ -122,24 +125,24 @@ rule area_potential_report: shapes="", area_potentials=expand( workflow.pathvars.apply(""), - tech=config["techs"].keys(), + tech=get_techs, allow_missing=True, ), area_potential_plots=expand( - "/{{shape}}/area_potential_{tech}.png", - tech=config["techs"].keys(), + "/{{shape}}/{{scenario}}/area_potential_{tech}.png", + tech=get_techs, ), output: - csv="/{shape}/area_potential_report.csv", + csv="/{shape}/{scenario}/area_potential_report.csv", html=report( - "/{shape}/area_potential_report.html", + "/{shape}/{scenario}/area_potential_report.html", category="area_potential_report_table", ), log: - "/{shape}/area_potential_report.log", + "/{shape}/{scenario}/area_potential_report.log", conda: "../envs/module.yaml" message: - "Generate an overview report of the area potential for all techs in shapes {wildcards.shape}." + "Generate an overview report of the area potential for scenario {wildcards.scenario} for all techs in shapes {wildcards.shape}." script: "../scripts/report.py"