-
Notifications
You must be signed in to change notification settings - Fork 18
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
Changes from 2 commits
df9c9f8
2fb31df
7e32a08
0cb6209
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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)). | ||
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. | ||
|
@@ -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" | ||
|
@@ -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. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a unclear to me. Why is this a dummy technology? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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" | ||
|
||
|
@@ -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 | ||
|
@@ -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: | ||
|
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, | ||
) |
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 %} |
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 |
---|---|---|
@@ -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") }} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Differences in ranges: Before
After
So, yes, the RHS range increases by an order of magnitude. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, so without the annual limit, it becomes:
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||
{% 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 %} |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.