Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separate biofuel supply; add biofuel boiler #419

Merged
merged 4 commits into from
Aug 5, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@

### Added (models)

* **ADD** Specific biofuel energy carrier in the Calliope model, which can be used to generate electricity or to meet heat demand (#417).

* **ADD** Industry module: iron and steel, "default" combined categories. NOT CONNECTED TO THE MAIN WORKFLOW. (Fixes #308, #309, #310, #347, #345 and #346)

* **ADD** Spatial resolution that aligns with the regions defined by the [e-Highway 2050 project](https://cordis.europa.eu/project/id/308908/reporting) (`ehighways`) (#370).

* **ADD** Heat demand (#284, #343, #389, #275) and heat pumps with variable COP to meet that demand (#80, #39).
* **ADD** Heat demand (#284, #343, #389, #275), and heat pumps with variable COP and biofuel boilers to meet that demand (#80, #39).

* **ADD** fully-electrified road transportation (#270, #271, #358). A parameter allows to define the share of uncontrolled (timeseries) vs controlled charging (optimised) by the solver (#338). Data for controlled charging constraints is readily available (#356), but corresponding constraints are not yet implemented (#385).

Expand Down
13 changes: 8 additions & 5 deletions Snakefile
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ rule module_with_location_specific_data:
capacity_factors = config["capacity-factors"]["average"],
max_power_densities = config["parameters"]["maximum-installable-power-density"],
heat_pump_shares = config["parameters"]["heat-pump"]["heat-pump-shares"],
biofuel_efficiency = config["parameters"]["biofuel-efficiency"],
wildcard_constraints:
# Exclude all outputs that have their own `techs_and_locations_template` implementation
group_and_tech = "(?!transmission\/|supply\/biofuel).*"
Expand Down Expand Up @@ -162,10 +163,11 @@ rule model:
"techs/supply/rooftop-solar.yaml",
"techs/supply/wind-offshore.yaml",
"techs/supply/nuclear.yaml",
"techs/conversion/electricity-from-biofuel.yaml"
]
),
heat_supply_timeseries_data = (
"build/models/{resolution}/timeseries/supply/heat-pump-cop.csv",
heat_timeseries_data = (
"build/models/{resolution}/timeseries/conversion/heat-pump-cop.csv",
"build/models/{resolution}/timeseries/supply/historic-electrified-heat.csv",
),
capacityfactor_timeseries_data = expand(
Expand Down Expand Up @@ -198,7 +200,8 @@ rule model:
"techs/demand/heat.yaml",
"techs/demand/electrified-heat.yaml",
"techs/storage/heat.yaml",
"techs/supply/heat-from-electricity.yaml",
"techs/conversion/heat-from-electricity.yaml",
"techs/conversion/heat-from-biofuel.yaml",
"techs/supply/historic-electrified-heat.yaml"
]
)
Expand Down Expand Up @@ -258,10 +261,10 @@ rule test:
electrified_heat_demand = "build/models/{resolution}/timeseries/demand/electrified-heat.csv",
heat_demand = "build/models/{resolution}/timeseries/demand/heat.csv",
historic_electrified_heat = "build/models/{resolution}/timeseries/supply/historic-electrified-heat.csv",
cop = "build/models/{resolution}/timeseries/supply/heat-pump-cop.csv"
cop = "build/models/{resolution}/timeseries/conversion/heat-pump-cop.csv"
params:
config = config,
test_args = ["--pdb"] # add e.g. "--pdb" to enter ipdb on test failure
test_args = [] # add e.g. "--pdb" to enter ipdb on test failure
log: "build/logs/{resolution}/test-report.html"
output: "build/logs/{resolution}/test.success"
conda: "./envs/test.yaml"
Expand Down
33 changes: 26 additions & 7 deletions docs/model/customisation.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ You have the following three options:
With the Calliope model in your hands, you will be able to change any model parameter, any technology specifics, and the model definition to your liking.
This kind of customisation can be useful to get to know the model and its parameters.
To create reliable results, we advise making manual changes only to the model definition (`example-model.yaml`) as this makes it possible to trace those changes later.
A typical customisation here would be to change the solver from `gurobi` to an open-source solver, e.g. `cbc` (see [Calliope's documentation](https://calliope.readthedocs.io/en/v{{ calliope_version }}/user/config_defaults.html#run-configuration)).
A typical customisation here would be to change the solver from `gurobi` to an open-source solver, e.g. `cbc` (see [Calliope's documentation](<https://calliope.readthedocs.io/en/v{{> calliope_version }}/user/config_defaults.html#run-configuration)).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you briefly explain this change?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, that looks like it snuck in for some reason. It certainly doesn't look like it makes any sense to me.

We consider all Euro-Calliope model subcomponents (everything other than the model definition itself) as a toolbox from which you can choose to define your model -- see the [Import customisation option](./customisation.md#importing-modules).

## Importing modules

The `example-model.yaml` definition file in each resolution sub-directory (e.g. `national/example-model.yaml`) specifies a list of other files to bring together to describe the model (under the `import` key).
This list can be changed by the modeller to select a combination of different files (see also [Calliope's documentation](https://calliope.readthedocs.io/en/v{{ calliope_version }}/user/building.html#files-that-define-a-model)).
This list can be changed by the modeller to select a combination of different files (see also [Calliope's documentation](<https://calliope.readthedocs.io/en/v{{> calliope_version }}/user/building.html#files-that-define-a-model)).
These files represent "modules" of the model definition and contain everything necessary for a given technology or technology group to exist.
For instance, `techs/supply/hydro.yaml` defines two technologies (under the `techs` key) which will convert river flows into electricity.
It also places that technology in every relevant modelled location (under the `locations` key), along with any location-specific information that is needed; in this case, the maximum capacity of hydropower in that location.
Expand Down Expand Up @@ -86,6 +86,8 @@ Here, we describe each module in terms of the technologies they contain (`callio

**electric_heater_heat_storage_small**: Storage buffer for direct electric heaters which inherits from the `heat_storage_small` abstract technology group, assuming a domestic (small scale) application.

**biofuel_heat_storage_small**: Storage buffer for biofuel boilers which inherits from the `heat_storage_small` abstract technology group, assuming a domestic (small scale) application.

??? note "storage/hydro.yaml"

=== "Technologies"
Expand All @@ -102,9 +104,27 @@ Here, we describe each module in terms of the technologies they contain (`callio

=== "Technologies"

**biofuel**: Biofuel
**biofuel**: Biofuel supply, limited per model location to a total annual production.

=== "Overrides"

**biofuel_flow_limits**: Distribute annual total production limit evenly across all hours of the year and allow biofuel storage up to 50% of total annual production.

??? note "conversion/heat-from-biofuel.yaml"

=== "Technologies"

**biofuel_boiler**: Biofuel-consuming boiler.

**biofuel_tech_heat_to_demand**: Dummy technology to convert biofuel boiler output to a carrier that can be used to meet heat demand.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a unclear to me. Why is this a dummy technology?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because it doesn't actually represent a "real" technology. It's just a modelling artefact to be able to have storage buffers per heat tech (this will be a non-issue when using calliope v0.7)


??? note "supply/heat-from-electricity.yaml"
??? note "conversion/electricity-from-biofuel.yaml"

=== "Technologies"

**electricity_from_biofuel**: Biofuel-consuming electricity production facility (assuming anaerobic digestion).

??? note "conversion/heat-from-electricity.yaml"

=== "Technologies"

Expand Down Expand Up @@ -221,10 +241,9 @@ Here, we describe each module in terms of the technologies they contain (`callio

**free_transmission**: Local power transmission


## Overrides and scenarios

Calliope [overrides](https://calliope.readthedocs.io/en/v{{ calliope_version }}/user/building.html#scenarios-and-overrides) enable models to be easily manipulated.
Calliope [overrides](<https://calliope.readthedocs.io/en/v{{> calliope_version }}/user/building.html#scenarios-and-overrides) enable models to be easily manipulated.
An override named `freeze-hydro-supply-capacities` can be used for example in this way:

``` bash
Expand All @@ -243,7 +262,7 @@ For instance, `freeze-hydro-supply-capacities` and `freeze-hydro-storage-capacit
You can also define your own overrides to manipulate any model component.
We recommend you add these overrides into the model definition YAML file, to ensure they are easy to trace.

In Calliope, [scenarios](https://calliope.readthedocs.io/en/v{{ calliope_version }}/user/building.html#scenarios-and-overrides) are groups of overrides and/or other scenarios.
In Calliope, [scenarios](<https://calliope.readthedocs.io/en/v{{> calliope_version }}/user/building.html#scenarios-and-overrides) are groups of overrides and/or other scenarios.
In Euro-Calliope, it can be helpful to define scenarios to help group similar overrides together.
For instance, cost overrides from the Danish Energy Agency are defined in various files, since they are loaded in alongside the technologies they affect (the option to override offshore wind costs only exists when you load the `techs/supply/wind-offshore.yaml` module).
You can pre-define scenarios in your model definition file, such as:
Expand Down
1 change: 0 additions & 1 deletion rules/biofuels.smk
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ rule biofuel_tech_module:
),
locations = "build/data/{{resolution}}/biofuel/{scenario}/potential-mwh-per-year.csv".format(scenario=config["parameters"]["jrc-biofuel"]["scenario"])
params:
biofuel_efficiency = config["parameters"]["biofuel-efficiency"],
scaling_factors = config["scaling-factors"],
conda: "../envs/default.yaml"
output: "build/models/{resolution}/techs/supply/biofuel.yaml"
Expand Down
2 changes: 1 addition & 1 deletion rules/heat.smk
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ rule heat_pump_final_timeseries:
conda: "../envs/default.yaml"
wildcard_constraints:
input_dataset = "heat-pump-cop"
output: "build/models/{resolution}/timeseries/supply/{input_dataset}.csv"
output: "build/models/{resolution}/timeseries/conversion/{input_dataset}.csv"
script: "../scripts/heat/heat_pump_final_timeseries.py"


Expand Down
2 changes: 1 addition & 1 deletion scripts/biofuels/allocate.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def biofuel_potential(
index_col=["year", "scenario", "country_code", "feedstock"],
)["value"]
.div(GJ_TO_MWH)
.xs((potential_year, scenario), level=("year", "scenario"))
.xs((cost_year, scenario), level=("year", "scenario"))
)
units = pd.read_csv(path_to_units).set_index("id")
if (len(units.index) == 1) and (
Expand Down
37 changes: 8 additions & 29 deletions scripts/biofuels/template_bio.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,14 @@
import pandas as pd
from eurocalliopelib.template import parametrise_template


def construct_techs_and_locations(
path_to_template,
path_to_output,
path_to_locations,
path_to_biofuel_costs,
biofuel_efficiency,
scaling_factors,
):
with open(path_to_biofuel_costs) as f_biofuel_costs:
biofuel_fuel_cost = float(f_biofuel_costs.readline())
locations = pd.read_csv(path_to_locations, index_col=0)

return parametrise_template(
path_to_template,
path_to_output,
biofuel_fuel_cost=biofuel_fuel_cost,
biofuel_efficiency=biofuel_efficiency,
scaling_factors=scaling_factors,
locations=locations,
)


if __name__ == "__main__":
construct_techs_and_locations(
path_to_template=snakemake.input.template,
path_to_locations=snakemake.input.locations,
path_to_biofuel_costs=snakemake.input.biofuel_cost,
biofuel_efficiency=snakemake.params.biofuel_efficiency,
biofuel_cost = float(pd.read_csv(snakemake.input.biofuel_cost).columns[0])
locations = pd.read_csv(snakemake.input.locations, index_col=0)

parametrise_template(
snakemake.input.template,
snakemake.output[0],
biofuel_cost=biofuel_cost,
scaling_factors=snakemake.params.scaling_factors,
path_to_output=snakemake.output[0],
locations=locations,
)
2 changes: 1 addition & 1 deletion scripts/summarise_potentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def summarise_potentials(

list_of_techs = model.inputs.techs.values
list_of_locs = model.inputs.locs.values
list_of_potentials = list(considered_potentials.keys())
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)))
summary[:] = np.nan
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
techs:
electricity_from_biofuel: # from [@JRC:2014] Table 48 Anaerobic digestion
essentials:
name: Electricity from anaerobically digested biofuel
parent: conversion
carrier_in: biofuel
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to remove the old approach, meaning that it won't be possible anymore to avoid modelling biofuel explicitly. I am fine with as long as it doesn't impact performance much. Do you know?

Copy link
Member Author

@brynpickering brynpickering Jul 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know about memory use, but runtime for building and solving the optimisation problem increases by ~3% (43.8s -> 45.1s) in a test I made (UK+IRL, 1yr @ 2hr resolution, using %timeit magic).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually, ran it again and it was the other way around. So, within margins of error, there is no change 😅

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") }}

locations:
{% for id, location in locations.iterrows() %}
{{ id }}.techs.electricity_from_biofuel:
{% endfor %}
29 changes: 29 additions & 0 deletions templates/models/techs/conversion/heat-from-biofuel.yaml.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{# TODO: weight single-/multi-family technology costs based on regional dwelling ratio - see https://github.com/calliope-project/euro-calliope/issues/406 #}
{# Costs/efficiency 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:
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

locations:
{% for id, location in locations.iterrows() %}
{{ id }}.techs:
biofuel_boiler:
biofuel_tech_heat_to_demand:
{% endfor %}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,6 @@
{# 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. #}

tech_groups:
tech_heat_to_demand:
essentials:
name: Technology-specific heat carriers to generic heat carrier converter
parent: conversion
carrier_out: heat

techs:
heat_pump: # [@DEA:2017] - 7.3 - 7.6 Air to water & 7.7 - 7.10 Ground source - 2050
essentials:
Expand All @@ -17,7 +10,7 @@ techs:
carrier_in: electricity
carrier_out: hp_heat
constraints:
energy_eff: file=supply/heat-pump-cop.csv # NOTE: based on data processing pipeline, not [@DEA:2017].
energy_eff: file=conversion/heat-pump-cop.csv # NOTE: based on data processing pipeline, not [@DEA:2017].
lifetime: 20
costs:
monetary:
Expand Down
7 changes: 7 additions & 0 deletions templates/models/techs/demand/heat.yaml.jinja
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
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:
Expand Down
4 changes: 4 additions & 0 deletions templates/models/techs/storage/heat.yaml.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,14 @@ techs:
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

locations:
{% for id, location in locations.iterrows() %}
{{ id }}:
techs.hp_heat_storage_small:
techs.electric_heater_heat_storage_small:
techs.biofuel_heat_storage_small:
{% endfor %}
39 changes: 25 additions & 14 deletions templates/models/techs/supply/biofuel.yaml.jinja
Original file line number Diff line number Diff line change
@@ -1,23 +1,34 @@
techs:
biofuel: # from [@JRC:2014] Table 48 Anaerobic digestion
biofuel_supply:
essentials:
name: Biofuel
name: Biofuel supply stream
parent: supply_plus
carrier: electricity
carrier: biofuel
constraints:
energy_eff: 1.0 # efficiency modelled within the input resource stream to avoid poor numerical scaling
lifetime: 20
lifetime: 1 # arbritrarily chosen to avoid Calliope errors
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_fuel_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
om_prod: {{ biofuel_cost * scaling_factors.specific_costs }} # {{ (1 / scaling_factors.specific_costs) | unit("EUR/MWh") }}

locations:
{% for id, location in locations.iterrows() %}
{{ id }}.techs:
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
{{ id }}.techs.biofuel_supply:
{% endfor %}

group_constraints:
{% for id, location in locations.iterrows() %}
biofuel_max_prod_{{ id }}:
locs: [{{ id }}]
techs: [biofuel_supply]
carrier_prod_max:
biofuel: {{ location.biofuel_potential_mwh_per_year * scaling_factors.power }} # {{ (1 / scaling_factors.power) | unit("MWh") }}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line may be negative for numerical scaling as it introduces a fairly large number. Previously this was solved by applying the efficiency and assuming a 6 month use period, which reduced the number by ~factor 4.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Differences in ranges:

Before

[2024-07-30 17:51:46] DEBUG    Matrix range     [4e-05, 1e+02]
[2024-07-30 17:51:46] DEBUG    Objective range  [1e+00, 1e+00]
[2024-07-30 17:51:46] DEBUG    Bounds range     [1e-05, 2e+01]
[2024-07-30 17:51:46] DEBUG    RHS range        [8e-10, 2e+02]

After

[2024-07-30 18:04:13] DEBUG    Matrix range     [4e-05, 1e+02]
[2024-07-30 18:04:13] DEBUG    Objective range  [1e+00, 1e+00]
[2024-07-30 18:04:13] DEBUG    Bounds range     [1e-05, 2e+01]
[2024-07-30 18:04:13] DEBUG    RHS range        [8e-10, 1e+03]

So, yes, the RHS range increases by an order of magnitude.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure there is an equivalent way to handle that with biofuel as a separate carrier. I guess you just don't need carrier_prod_max if you have an hourly resource since that resource already effectively sets an annual value once it's all been added up.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, so without the annual limit, it becomes:

[2024-07-30 18:25:14] DEBUG    Matrix range     [4e-05, 1e+02]
[2024-07-30 18:25:14] DEBUG    Objective range  [1e+00, 1e+00]
[2024-07-30 18:25:14] DEBUG    Bounds range     [1e-05, 2e+01]
[2024-07-30 18:25:14] DEBUG    RHS range        [8e-10, 5e+02]

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But that would mean that biofuel must be burned whenever it's becoming available as a resource, right? That wouldn't be ideal either.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, the resource per timestep just gives a quantity available. So long as force_resource isn't set to True it won't be forced to make use of it. It can also choose to make use of it but to store it instead of having it converted to electricity etc.

{% endfor %}

overrides:
biofuel_flow_limits:
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("MW") }}
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 %}
Loading
Loading