Merge pull request #1105 from PyPSA/document-heat-rules
Document heating rules
This commit is contained in:
commit
0ead0dc6a4
@ -6,11 +6,40 @@
|
|||||||
Build coefficient of performance (COP) time series for air- or ground-sourced
|
Build coefficient of performance (COP) time series for air- or ground-sourced
|
||||||
heat pumps.
|
heat pumps.
|
||||||
|
|
||||||
The COP is a function of the temperature difference between source and
|
The COP is approximated as a quatratic function of the temperature difference between source and
|
||||||
sink.
|
sink, based on Staffell et al. 2012.
|
||||||
|
|
||||||
The quadratic regression used is based on Staffell et al. (2012)
|
This rule is executed in ``build_sector.smk``.
|
||||||
https://doi.org/10.1039/C2EE22653G.
|
|
||||||
|
Relevant Settings
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
.. code:: yaml
|
||||||
|
heat_pump_sink_T:
|
||||||
|
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
-------
|
||||||
|
- ``resources/<run_name>/temp_soil_total_elec_s<simpl>_<clusters>.nc``: Soil temperature (total) time series.
|
||||||
|
- ``resources/<run_name>/temp_soil_rural_elec_s<simpl>_<clusters>.nc``: Soil temperature (rural) time series.
|
||||||
|
- ``resources/<run_name>/temp_soil_urban_elec_s<simpl>_<clusters>.nc``: Soil temperature (urban) time series.
|
||||||
|
- ``resources/<run_name>/temp_air_total_elec_s<simpl>_<clusters>.nc``: Ambient air temperature (total) time series.
|
||||||
|
- ``resources/<run_name>/temp_air_rural_elec_s<simpl>_<clusters>.nc``: Ambient air temperature (rural) time series.
|
||||||
|
- ``resources/<run_name>/temp_air_urban_elec_s<simpl>_<clusters>.nc``: Ambient air temperature (urban) time series.
|
||||||
|
|
||||||
|
Outputs:
|
||||||
|
--------
|
||||||
|
- ``resources/cop_soil_total_elec_s<simpl>_<clusters>.nc``: COP (ground-sourced) time series (total).
|
||||||
|
- ``resources/cop_soil_rural_elec_s<simpl>_<clusters>.nc``: COP (ground-sourced) time series (rural).
|
||||||
|
- ``resources/cop_soil_urban_elec_s<simpl>_<clusters>.nc``: COP (ground-sourced) time series (urban).
|
||||||
|
- ``resources/cop_air_total_elec_s<simpl>_<clusters>.nc``: COP (air-sourced) time series (total).
|
||||||
|
- ``resources/cop_air_rural_elec_s<simpl>_<clusters>.nc``: COP (air-sourced) time series (rural).
|
||||||
|
- ``resources/cop_air_urban_elec_s<simpl>_<clusters>.nc``: COP (air-sourced) time series (urban).
|
||||||
|
|
||||||
|
|
||||||
|
References
|
||||||
|
----------
|
||||||
|
[1] Staffell et al., Energy & Environmental Science 11 (2012): A review of domestic heat pumps, https://doi.org/10.1039/C2EE22653G.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import xarray as xr
|
import xarray as xr
|
||||||
|
@ -3,7 +3,45 @@
|
|||||||
#
|
#
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
"""
|
"""
|
||||||
Build heat demand time series using heating degree day (HDD) approximation.
|
This rule builds heat demand time series using heating degree day (HDD)
|
||||||
|
approximation.
|
||||||
|
|
||||||
|
Snapshots are resampled to daily time resolution and ``Atlite.convert.heat_demand`` is used to convert ambient temperature from the default weather cutout to heat demand time series for the respective cutout.
|
||||||
|
|
||||||
|
Heat demand is distributed by population to clustered onshore regions.
|
||||||
|
|
||||||
|
The rule is executed in ``build_sector.smk``.
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
`Atlite.Cutout.heat_demand <https://atlite.readthedocs.io/en/master/ref_api.html#module-atlite.convert>`_
|
||||||
|
|
||||||
|
Relevant Settings
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
.. code:: yaml
|
||||||
|
|
||||||
|
snapshots:
|
||||||
|
drop_leap_day:
|
||||||
|
|
||||||
|
Inputs
|
||||||
|
------
|
||||||
|
|
||||||
|
- ``resources/<run_name>/pop_layout_<scope>.nc``: Population layout (spatial population distribution).
|
||||||
|
- ``resources/<run_name>/regions_onshore_elec_s<simpl>_<clusters>.geojson``: Onshore region shapes.
|
||||||
|
- ``cutout``: Weather data cutout, as specified in config
|
||||||
|
|
||||||
|
Outputs
|
||||||
|
-------
|
||||||
|
|
||||||
|
- ``resources/daily_heat_demand_<scope>_elec_s<simpl>_<clusters>.nc``:
|
||||||
|
|
||||||
|
Relevant settings
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
.. code:: yaml
|
||||||
|
|
||||||
|
atlite:
|
||||||
|
default_cutout``:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import atlite
|
import atlite
|
||||||
|
@ -4,6 +4,29 @@
|
|||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
"""
|
"""
|
||||||
Build district heat shares at each node, depending on investment year.
|
Build district heat shares at each node, depending on investment year.
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
-------
|
||||||
|
- `resources/<run_name>/pop_layout.csv`: Population layout for each node: Total, urban and rural population.
|
||||||
|
- `resources/<run_name>/district_heat_share.csv`: Historical district heat share at each country. Output of `scripts/build_energy_totals.py`.
|
||||||
|
|
||||||
|
Outputs:
|
||||||
|
--------
|
||||||
|
- `resources/<run_name>/district_heat_share.csv`: District heat share at each node, potential for each investment year.
|
||||||
|
|
||||||
|
Relevant settings:
|
||||||
|
------------------
|
||||||
|
.. code:: yaml
|
||||||
|
sector:
|
||||||
|
district_heating:
|
||||||
|
energy:
|
||||||
|
energy_totals_year:
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
------
|
||||||
|
- The district heat share is calculated as the share of urban population at each node, multiplied by the share of district heating in the respective country.
|
||||||
|
- The `sector.district_heating.potential` setting defines the max. district heating share.
|
||||||
|
- The max. share of district heating is increased by a progress factor, depending on the investment year (See `sector.district_heating.progress` setting).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
@ -3,12 +3,45 @@
|
|||||||
#
|
#
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
"""
|
"""
|
||||||
Build total energy demands per country using JRC IDEES, eurostat, and EEA data.
|
Build total energy demands and carbon emissions per country using JRC IDEES,
|
||||||
|
eurostat, and EEA data.
|
||||||
|
|
||||||
|
- Country-specific data is read in :func:`build_eurostat`, :func:`build_idees` and `build_swiss`.
|
||||||
|
- :func:`build_energy_totals` then combines energy data from Eurostat, Swiss, and IDEES data and :func:`rescale_idees_from_eurostat` rescales IDEES data to match Eurostat data.
|
||||||
|
- :func:`build_district_heat_share` calculates the share of district heating for each country from IDEES data.
|
||||||
|
- Historical CO2 emissions are calculated in :func:`build_eea_co2` and :func:`build_eurostat_co2` and combined in :func:`build_co2_totals`.
|
||||||
|
|
||||||
|
Relevant Settings
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
.. code:: yaml
|
||||||
|
countries:
|
||||||
|
energy:
|
||||||
|
|
||||||
|
Inputs
|
||||||
|
------
|
||||||
|
|
||||||
|
- `resources/<run_name>/nuts3_shapes.gejson`: NUTS3 shapes.
|
||||||
|
- `data/bundle/eea_UNFCCC_v23.csv`: CO2 emissions data from EEA.
|
||||||
|
- `data/switzerland-new_format-all_years.csv`: Swiss energy data.
|
||||||
|
- `data/gr-e-11.03.02.01.01-cc.csv`: Swiss transport data
|
||||||
|
- `data/bundle/jrc-idees`: JRC IDEES data.
|
||||||
|
- `data/district_heat_share.csv`: District heating shares.
|
||||||
|
- `data/eurostat/Balances-April2023`: Eurostat energy balances.
|
||||||
|
- `data/eurostat/eurostat-household_energy_balances-february_2024.csv`: Eurostat household energy balances.
|
||||||
|
|
||||||
|
Outputs
|
||||||
|
-------
|
||||||
|
- `resources/<run_name>/energy_totals.csv`: Energy totals per country, sector and year.
|
||||||
|
- `resources/<run_name>/co2_totals.csv`: CO2 emissions per country, sector and year.
|
||||||
|
- `resources/<run_name>/transport_data.csv`: Transport data per country and year.
|
||||||
|
- `resources/<run_name>/district_heat_share.csv`: District heating share per by country and year.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import multiprocessing as mp
|
import multiprocessing as mp
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
from typing import List
|
||||||
|
|
||||||
import country_converter as coco
|
import country_converter as coco
|
||||||
import geopandas as gpd
|
import geopandas as gpd
|
||||||
@ -22,16 +55,54 @@ logger = logging.getLogger(__name__)
|
|||||||
idx = pd.IndexSlice
|
idx = pd.IndexSlice
|
||||||
|
|
||||||
|
|
||||||
def cartesian(s1, s2):
|
def cartesian(s1: pd.Series, s2: pd.Series) -> pd.DataFrame:
|
||||||
"""
|
"""
|
||||||
Cartesian product of two pd.Series.
|
Compute the Cartesian product of two pandas Series.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
s1: pd.Series
|
||||||
|
The first pandas Series
|
||||||
|
s2: pd.Series:
|
||||||
|
The second pandas Series.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
----------
|
||||||
|
pd.DataFrame
|
||||||
|
A DataFrame representing the Cartesian product of s1 and s2.
|
||||||
|
|
||||||
|
Examples
|
||||||
|
--------
|
||||||
|
>>> s1 = pd.Series([1, 2, 3], index=["a", "b", "c"])
|
||||||
|
>>> s2 = pd.Series([4, 5, 6], index=["d", "e", "f"])
|
||||||
|
>>> cartesian(s1, s2)
|
||||||
|
d e f
|
||||||
|
a 4 5 6
|
||||||
|
b 8 10 12
|
||||||
|
c 12 15 18
|
||||||
"""
|
"""
|
||||||
return pd.DataFrame(np.outer(s1, s2), index=s1.index, columns=s2.index)
|
return pd.DataFrame(np.outer(s1, s2), index=s1.index, columns=s2.index)
|
||||||
|
|
||||||
|
|
||||||
def reverse(dictionary):
|
def reverse(dictionary: dict) -> dict:
|
||||||
"""
|
"""
|
||||||
Reverses a keys and values of a dictionary.
|
Reverses the keys and values of a dictionary.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
dictionary : dict
|
||||||
|
The dictionary to be reversed.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
dict
|
||||||
|
A new dictionary with the keys and values reversed.
|
||||||
|
|
||||||
|
Examples
|
||||||
|
--------
|
||||||
|
>>> d = {"a": 1, "b": 2, "c": 3}
|
||||||
|
>>> reverse(d)
|
||||||
|
{1: 'a', 2: 'b', 3: 'c'}
|
||||||
"""
|
"""
|
||||||
return {v: k for k, v in dictionary.items()}
|
return {v: k for k, v in dictionary.items()}
|
||||||
|
|
||||||
@ -68,7 +139,28 @@ to_ipcc = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def eurostat_per_country(input_eurostat, country):
|
def eurostat_per_country(input_eurostat: str, country: str) -> pd.DataFrame:
|
||||||
|
"""
|
||||||
|
Read energy balance data for a specific country from Eurostat.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
input_eurostat : str
|
||||||
|
Path to the directory containing Eurostat data files.
|
||||||
|
country : str
|
||||||
|
Country code for the specific country.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
pd.DataFrame
|
||||||
|
Concatenated energy balance data for the specified country.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
- The function reads `<input_eurostat>/<country>.-Energy-balance-sheets-April-2023-edition.xlsb`
|
||||||
|
- It removes the "Cover" sheet from the data and concatenates all the remaining sheets into a single DataFrame.
|
||||||
|
"""
|
||||||
|
|
||||||
filename = (
|
filename = (
|
||||||
f"{input_eurostat}/{country}-Energy-balance-sheets-April-2023-edition.xlsb"
|
f"{input_eurostat}/{country}-Energy-balance-sheets-April-2023-edition.xlsb"
|
||||||
)
|
)
|
||||||
@ -83,10 +175,38 @@ def eurostat_per_country(input_eurostat, country):
|
|||||||
return pd.concat(sheet)
|
return pd.concat(sheet)
|
||||||
|
|
||||||
|
|
||||||
def build_eurostat(input_eurostat, countries, nprocesses=1, disable_progressbar=False):
|
def build_eurostat(
|
||||||
|
input_eurostat: str,
|
||||||
|
countries: List[str],
|
||||||
|
nprocesses: int = 1,
|
||||||
|
disable_progressbar: bool = False,
|
||||||
|
) -> pd.DataFrame:
|
||||||
"""
|
"""
|
||||||
Return multi-index for all countries' energy data in TWh/a.
|
Return multi-index for all countries' energy data in TWh/a.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
-----------
|
||||||
|
input_eurostat : str
|
||||||
|
Path to the Eurostat database.
|
||||||
|
countries : List[str]
|
||||||
|
List of countries for which energy data is to be retrieved.
|
||||||
|
nprocesses : int, optional
|
||||||
|
Number of processes to use for parallel execution, by default 1.
|
||||||
|
disable_progressbar : bool, optional
|
||||||
|
Whether to disable the progress bar, by default False.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
--------
|
||||||
|
pd.DataFrame
|
||||||
|
Multi-index DataFrame containing energy data for all countries in TWh/a.
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
------
|
||||||
|
- The function first renames the countries in the input list using the `idees_rename` mapping and removes "CH".
|
||||||
|
- It then reads country-wise data using :func:`eurostat_per_country` into a single DataFrame.
|
||||||
|
- The data is reordered, converted to TWh/a, and missing values are filled.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
countries = {idees_rename.get(country, country) for country in countries} - {"CH"}
|
countries = {idees_rename.get(country, country) for country in countries} - {"CH"}
|
||||||
|
|
||||||
func = partial(eurostat_per_country, input_eurostat)
|
func = partial(eurostat_per_country, input_eurostat)
|
||||||
@ -152,9 +272,20 @@ def build_eurostat(input_eurostat, countries, nprocesses=1, disable_progressbar=
|
|||||||
return df
|
return df
|
||||||
|
|
||||||
|
|
||||||
def build_swiss():
|
def build_swiss() -> pd.DataFrame:
|
||||||
"""
|
"""
|
||||||
Return a pd.DataFrame of Swiss energy data in TWh/a.
|
Return a pd.DataFrame of Swiss energy data in TWh/a.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
--------
|
||||||
|
pd.DataFrame
|
||||||
|
Swiss energy data in TWh/a.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
- Reads Swiss energy data from `data/switzerland-new_format-all_years.csv`.
|
||||||
|
- Reshapes and renames data.
|
||||||
|
- Converts energy units from PJ/a to TWh/a.
|
||||||
"""
|
"""
|
||||||
fn = snakemake.input.swiss
|
fn = snakemake.input.swiss
|
||||||
|
|
||||||
@ -174,7 +305,29 @@ def build_swiss():
|
|||||||
return df
|
return df
|
||||||
|
|
||||||
|
|
||||||
def idees_per_country(ct, base_dir):
|
def idees_per_country(ct: str, base_dir: str) -> pd.DataFrame:
|
||||||
|
"""
|
||||||
|
Calculate energy totals per country using JRC-IDEES data.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
ct : str
|
||||||
|
The country code.
|
||||||
|
base_dir : str
|
||||||
|
The base directory where the JRC-IDEES data files are located.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
pd.DataFrame
|
||||||
|
A DataFrame containing the energy totals per country. Columns are energy uses.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
- Retrieves JRC-IDEES data for the specified country from `base_dir` for residential, tertiary, and transport sectors.
|
||||||
|
- Calculates energy totals for each sector, stores them in a dictionary and returns them as data frame.
|
||||||
|
- Assertions ensure indices of JRC-IDEES data are as expected.
|
||||||
|
"""
|
||||||
|
|
||||||
ct_idees = idees_rename.get(ct, ct)
|
ct_idees = idees_rename.get(ct, ct)
|
||||||
fn_residential = f"{base_dir}/JRC-IDEES-2015_Residential_{ct_idees}.xlsx"
|
fn_residential = f"{base_dir}/JRC-IDEES-2015_Residential_{ct_idees}.xlsx"
|
||||||
fn_tertiary = f"{base_dir}/JRC-IDEES-2015_Tertiary_{ct_idees}.xlsx"
|
fn_tertiary = f"{base_dir}/JRC-IDEES-2015_Tertiary_{ct_idees}.xlsx"
|
||||||
@ -372,7 +525,27 @@ def idees_per_country(ct, base_dir):
|
|||||||
return pd.DataFrame(ct_totals)
|
return pd.DataFrame(ct_totals)
|
||||||
|
|
||||||
|
|
||||||
def build_idees(countries):
|
def build_idees(countries: List[str]) -> pd.DataFrame:
|
||||||
|
"""
|
||||||
|
Build energy totals from IDEES database for the given list of countries
|
||||||
|
using :func:`idees_per_country`.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
countries : List[str]
|
||||||
|
List of country names for which energy totals need to be built.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
pd.DataFrame
|
||||||
|
Energy totals for the given countries.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
- Retrieves energy totals per country and year using :func:`idees_per_country`.
|
||||||
|
- Returns a DataFrame with columns: country, year, and energy totals for different categories.
|
||||||
|
"""
|
||||||
|
|
||||||
nprocesses = snakemake.threads
|
nprocesses = snakemake.threads
|
||||||
disable_progress = snakemake.config["run"].get("disable_progressbar", False)
|
disable_progress = snakemake.config["run"].get("disable_progressbar", False)
|
||||||
|
|
||||||
@ -403,7 +576,42 @@ def build_idees(countries):
|
|||||||
return totals
|
return totals
|
||||||
|
|
||||||
|
|
||||||
def build_energy_totals(countries, eurostat, swiss, idees):
|
def build_energy_totals(
|
||||||
|
countries: List[str],
|
||||||
|
eurostat: pd.DataFrame,
|
||||||
|
swiss: pd.DataFrame,
|
||||||
|
idees: pd.DataFrame,
|
||||||
|
) -> pd.DataFrame:
|
||||||
|
"""
|
||||||
|
Combine energy totals for the specified countries from Eurostat, Swiss, and
|
||||||
|
IDEES data.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
countries : List[str]
|
||||||
|
List of country codes for which energy totals are to be calculated.
|
||||||
|
eurostat : pd.DataFrame
|
||||||
|
Eurostat energy balances dataframe.
|
||||||
|
swiss : pd.DataFrame
|
||||||
|
Swiss energy data dataframe.
|
||||||
|
idees : pd.DataFrame
|
||||||
|
IDEES energy data dataframe.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
pd.DataFrame
|
||||||
|
Energy totals dataframe for the given countries.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
- Missing values are filled based on Eurostat energy balances and average values in EU28.
|
||||||
|
- The function also performs specific calculations for Norway and splits road, rail, and aviation traffic for non-IDEES data.
|
||||||
|
|
||||||
|
References
|
||||||
|
----------
|
||||||
|
- `Norway heating data <http://www.ssb.no/en/energi-og-industri/statistikker/husenergi/hvert-3-aar/2014-07-14>`_
|
||||||
|
"""
|
||||||
|
|
||||||
eurostat_fuels = {"electricity": "Electricity", "total": "Total all products"}
|
eurostat_fuels = {"electricity": "Electricity", "total": "Total all products"}
|
||||||
eurostat_countries = eurostat.index.levels[0]
|
eurostat_countries = eurostat.index.levels[0]
|
||||||
eurostat_years = eurostat.index.levels[1]
|
eurostat_years = eurostat.index.levels[1]
|
||||||
@ -591,7 +799,30 @@ def build_energy_totals(countries, eurostat, swiss, idees):
|
|||||||
return df
|
return df
|
||||||
|
|
||||||
|
|
||||||
def build_district_heat_share(countries, idees):
|
def build_district_heat_share(countries: List[str], idees: pd.DataFrame) -> pd.Series:
|
||||||
|
"""
|
||||||
|
Calculate the share of district heating for each country.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
countries : List[str]
|
||||||
|
List of country codes for which to calculate district heating share.
|
||||||
|
idees : pd.DataFrame
|
||||||
|
IDEES energy data dataframe.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
pd.Series
|
||||||
|
Series with the district heating share for each country.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
- The function calculates the district heating share as the sum of residential and services derived heat, divided by the sum of residential and services thermal uses.
|
||||||
|
- The district heating share is then reindexed to match the provided list of countries.
|
||||||
|
- Missing district heating shares are filled from `data/district_heat_share.csv`.
|
||||||
|
- The function makes a conservative assumption and takes the minimum district heating share from both the IDEES data and `data/district_heat_share.csv`.
|
||||||
|
"""
|
||||||
|
|
||||||
# district heating share
|
# district heating share
|
||||||
district_heat = idees[["derived heat residential", "derived heat services"]].sum(
|
district_heat = idees[["derived heat residential", "derived heat services"]].sum(
|
||||||
axis=1
|
axis=1
|
||||||
@ -625,9 +856,37 @@ def build_district_heat_share(countries, idees):
|
|||||||
return district_heat_share
|
return district_heat_share
|
||||||
|
|
||||||
|
|
||||||
def build_eea_co2(input_co2, year=1990, emissions_scope="CO2"):
|
def build_eea_co2(
|
||||||
# https://www.eea.europa.eu/data-and-maps/data/national-emissions-reported-to-the-unfccc-and-to-the-eu-greenhouse-gas-monitoring-mechanism-16
|
input_co2: str, year: int = 1990, emissions_scope: str = "CO2"
|
||||||
# downloaded 201228 (modified by EEA last on 201221)
|
) -> pd.DataFrame:
|
||||||
|
"""
|
||||||
|
Calculate CO2 emissions for a given year based on EEA data in Mt.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
input_co2 : str
|
||||||
|
Path to the input CSV file with CO2 data.
|
||||||
|
year : int, optional
|
||||||
|
Year for which to calculate emissions, by default 1990.
|
||||||
|
emissions_scope : str, optional
|
||||||
|
Scope of the emissions to consider, by default "CO2".
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
pd.DataFrame
|
||||||
|
DataFrame with CO2 emissions for the given year.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
- The function reads the `input_co2` data and for a specific `year` and `emission scope`
|
||||||
|
- It calculates "industrial non-elec" and "agriculture" emissions from that data
|
||||||
|
- It drops unneeded columns and converts the emissions to Mt.
|
||||||
|
|
||||||
|
References
|
||||||
|
---------
|
||||||
|
- `EEA CO2 data <https://www.eea.europa.eu/data-and-maps/data/national-emissions-reported-to-the-unfccc-and-to-the-eu-greenhouse-gas-monitoring-mechanism-16>`_ (downloaded 201228, modified by EEA last on 201221)
|
||||||
|
"""
|
||||||
|
|
||||||
df = pd.read_csv(input_co2, encoding="latin-1", low_memory=False)
|
df = pd.read_csv(input_co2, encoding="latin-1", low_memory=False)
|
||||||
|
|
||||||
df.replace(dict(Year="1985-1987"), 1986, inplace=True)
|
df.replace(dict(Year="1985-1987"), 1986, inplace=True)
|
||||||
@ -673,11 +932,43 @@ def build_eea_co2(input_co2, year=1990, emissions_scope="CO2"):
|
|||||||
]
|
]
|
||||||
emissions.drop(columns=to_drop, inplace=True)
|
emissions.drop(columns=to_drop, inplace=True)
|
||||||
|
|
||||||
# convert from Gg to Mt
|
# convert from Gt to Mt
|
||||||
return emissions / 1e3
|
return emissions / 1e3
|
||||||
|
|
||||||
|
|
||||||
def build_eurostat_co2(eurostat, year=1990):
|
def build_eurostat_co2(eurostat: pd.DataFrame, year: int = 1990) -> pd.Series:
|
||||||
|
"""
|
||||||
|
Calculate CO2 emissions for a given year based on Eurostat fuel consumption
|
||||||
|
data and fuel-specific emissions.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
eurostat : pd.DataFrame
|
||||||
|
DataFrame with Eurostat data.
|
||||||
|
year : int, optional
|
||||||
|
Year for which to calculate emissions, by default 1990.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
pd.Series
|
||||||
|
Series with CO2 emissions for the given year.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
- The function hard-sets fuel-specific emissions:
|
||||||
|
- solid fuels: 0.36 tCO2_equi/MW_th (approximates coal)
|
||||||
|
- oil: 0.285 tCO2_equi/MW_th (average of distillate and residue)
|
||||||
|
- natural gas: 0.2 tCO2_equi/MW_th
|
||||||
|
- It then multiplies the Eurostat fuel consumption data for `year` by the specific emissions and sums the result.
|
||||||
|
|
||||||
|
References
|
||||||
|
----------
|
||||||
|
- Oil values from `EIA <https://www.eia.gov/tools/faqs/faq.cfm?id=74&t=11>`_
|
||||||
|
- Distillate oil (No. 2) 0.276
|
||||||
|
- Residual oil (No. 6) 0.298
|
||||||
|
- `EIA Electricity Annual <https://www.eia.gov/electricity/annual/html/epa_a_03.html>`_
|
||||||
|
"""
|
||||||
|
|
||||||
eurostat_year = eurostat.xs(year, level="year")
|
eurostat_year = eurostat.xs(year, level="year")
|
||||||
|
|
||||||
specific_emissions = pd.Series(index=eurostat.columns, dtype=float)
|
specific_emissions = pd.Series(index=eurostat.columns, dtype=float)
|
||||||
@ -687,15 +978,34 @@ def build_eurostat_co2(eurostat, year=1990):
|
|||||||
specific_emissions["Oil (total)"] = 0.285 # Average of distillate and residue
|
specific_emissions["Oil (total)"] = 0.285 # Average of distillate and residue
|
||||||
specific_emissions["Gas"] = 0.2 # For natural gas
|
specific_emissions["Gas"] = 0.2 # For natural gas
|
||||||
|
|
||||||
# oil values from https://www.eia.gov/tools/faqs/faq.cfm?id=74&t=11
|
|
||||||
# Distillate oil (No. 2) 0.276
|
|
||||||
# Residual oil (No. 6) 0.298
|
|
||||||
# https://www.eia.gov/electricity/annual/html/epa_a_03.html
|
|
||||||
|
|
||||||
return eurostat_year.multiply(specific_emissions).sum(axis=1)
|
return eurostat_year.multiply(specific_emissions).sum(axis=1)
|
||||||
|
|
||||||
|
|
||||||
def build_co2_totals(countries, eea_co2, eurostat_co2):
|
def build_co2_totals(
|
||||||
|
countries: List[str], eea_co2: pd.DataFrame, eurostat_co2: pd.DataFrame
|
||||||
|
) -> pd.DataFrame:
|
||||||
|
"""
|
||||||
|
Combine CO2 emissions data from EEA and Eurostat for a list of countries.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
countries : List[str]
|
||||||
|
List of country codes for which CO2 totals need to be built.
|
||||||
|
eea_co2 : pd.DataFrame
|
||||||
|
DataFrame with EEA CO2 emissions data.
|
||||||
|
eurostat_co2 : pd.DataFrame
|
||||||
|
DataFrame with Eurostat CO2 emissions data.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
pd.DataFrame
|
||||||
|
Combined CO2 emissions data for the given countries.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
- The function combines the CO2 emissions from EEA and Eurostat into a single DataFrame for the given countries.
|
||||||
|
"""
|
||||||
|
|
||||||
co2 = eea_co2.reindex(countries)
|
co2 = eea_co2.reindex(countries)
|
||||||
|
|
||||||
for ct in pd.Index(countries).intersection(["BA", "RS", "AL", "ME", "MK"]):
|
for ct in pd.Index(countries).intersection(["BA", "RS", "AL", "ME", "MK"]):
|
||||||
@ -722,9 +1032,38 @@ def build_co2_totals(countries, eea_co2, eurostat_co2):
|
|||||||
return co2
|
return co2
|
||||||
|
|
||||||
|
|
||||||
def build_transport_data(countries, population, idees):
|
def build_transport_data(
|
||||||
# first collect number of cars
|
countries: List[str], population: pd.DataFrame, idees: pd.DataFrame
|
||||||
|
) -> pd.DataFrame:
|
||||||
|
"""
|
||||||
|
Build transport data for a set of countries based on IDEES data.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
countries : List[str]
|
||||||
|
List of country codes.
|
||||||
|
population : pd.DataFrame
|
||||||
|
DataFrame with population data.
|
||||||
|
idees : pd.DataFrame
|
||||||
|
DataFrame with IDEES data.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
pd.DataFrame
|
||||||
|
DataFrame with transport data.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
- The function first collects the number of passenger cars.
|
||||||
|
- For Switzerland, it reads the data from `data/gr-e-11.03.02.01.01-cc.csv`.
|
||||||
|
- It fills missing data on the number of cars and fuel efficiency with average data.
|
||||||
|
|
||||||
|
References
|
||||||
|
----------
|
||||||
|
- Swiss transport data: `BFS <https://www.bfs.admin.ch/bfs/en/home/statistics/mobility-transport/transport-infrastructure-vehicles/vehicles/road-vehicles-stock-level-motorisation.html>`_
|
||||||
|
"""
|
||||||
|
|
||||||
|
# first collect number of cars
|
||||||
transport_data = pd.DataFrame(idees["passenger cars"])
|
transport_data = pd.DataFrame(idees["passenger cars"])
|
||||||
|
|
||||||
countries_without_ch = set(countries) - {"CH"}
|
countries_without_ch = set(countries) - {"CH"}
|
||||||
@ -735,7 +1074,6 @@ def build_transport_data(countries, population, idees):
|
|||||||
|
|
||||||
transport_data = transport_data.reindex(index=new_index)
|
transport_data = transport_data.reindex(index=new_index)
|
||||||
|
|
||||||
# https://www.bfs.admin.ch/bfs/en/home/statistics/mobility-transport/transport-infrastructure-vehicles/vehicles/road-vehicles-stock-level-motorisation.html
|
|
||||||
if "CH" in countries:
|
if "CH" in countries:
|
||||||
fn = snakemake.input.swiss_transport
|
fn = snakemake.input.swiss_transport
|
||||||
swiss_cars = pd.read_csv(fn, index_col=0).loc[2000:2015, ["passenger cars"]]
|
swiss_cars = pd.read_csv(fn, index_col=0).loc[2000:2015, ["passenger cars"]]
|
||||||
@ -782,16 +1120,38 @@ def build_transport_data(countries, population, idees):
|
|||||||
|
|
||||||
|
|
||||||
def rescale_idees_from_eurostat(
|
def rescale_idees_from_eurostat(
|
||||||
idees_countries,
|
idees_countries: List[str], energy: pd.DataFrame, eurostat: pd.DataFrame
|
||||||
energy,
|
) -> pd.DataFrame:
|
||||||
eurostat,
|
|
||||||
):
|
|
||||||
"""
|
"""
|
||||||
Takes JRC IDEES data from 2015 and rescales it by the ratio of the eurostat
|
Takes JRC IDEES data from 2015 and rescales it by the ratio of the Eurostat
|
||||||
data and the 2015 eurostat data.
|
data and the 2015 Eurostat data.
|
||||||
|
Missing data: ['passenger car efficiency', 'passenger cars']
|
||||||
|
|
||||||
missing data: ['passenger car efficiency', 'passenger cars']
|
Parameters
|
||||||
|
----------
|
||||||
|
idees_countries : List[str]
|
||||||
|
List of IDEES country codes.
|
||||||
|
energy : pd.DataFrame
|
||||||
|
DataFrame with JRC IDEES data.
|
||||||
|
eurostat : pd.DataFrame
|
||||||
|
DataFrame with Eurostat data.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
pd.DataFrame
|
||||||
|
DataFrame with rescaled IDEES data.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
- The function first reads in the Eurostat data for 2015 and calculates the ratio of that data with other Eurostat data.
|
||||||
|
- This ratio is mapped to the IDEES data.
|
||||||
|
|
||||||
|
References
|
||||||
|
----------
|
||||||
|
- JRC IDEES data: `JRC IDEES <https://ec.europa.eu/jrc/en/publication/eur-scientific-and-technical-research-reports/jrc-idees>`_
|
||||||
|
- Eurostat data: `Eurostat <https://ec.europa.eu/eurostat/data/database>`_
|
||||||
"""
|
"""
|
||||||
|
|
||||||
main_cols = ["Total all products", "Electricity"]
|
main_cols = ["Total all products", "Electricity"]
|
||||||
# read in the eurostat data for 2015
|
# read in the eurostat data for 2015
|
||||||
eurostat_2015 = eurostat.xs(2015, level="year")[main_cols]
|
eurostat_2015 = eurostat.xs(2015, level="year")[main_cols]
|
||||||
@ -959,10 +1319,25 @@ def rescale_idees_from_eurostat(
|
|||||||
return energy
|
return energy
|
||||||
|
|
||||||
|
|
||||||
def update_residential_from_eurostat(energy):
|
def update_residential_from_eurostat(energy: pd.DataFrame) -> pd.DataFrame:
|
||||||
"""
|
"""
|
||||||
Updates energy balances for residential from disaggregated data from
|
Updates energy balances for residential from disaggregated data from
|
||||||
Eurostat.
|
Eurostat by mutating input data DataFrame.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
energy : pd.DataFrame
|
||||||
|
DataFrame with energy data.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
pd.DataFrame
|
||||||
|
DataFrame with updated energy balances.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
- The function first reads in the Eurostat data for households and maps the energy types to the corresponding Eurostat codes.
|
||||||
|
- For each energy type, it selects the corresponding data, converts units, and drops unnecessary data.
|
||||||
"""
|
"""
|
||||||
eurostat_households = pd.read_csv(snakemake.input.eurostat_households)
|
eurostat_households = pd.read_csv(snakemake.input.eurostat_households)
|
||||||
|
|
||||||
|
@ -5,6 +5,38 @@
|
|||||||
"""
|
"""
|
||||||
Builds table of existing heat generation capacities for initial planning
|
Builds table of existing heat generation capacities for initial planning
|
||||||
horizon.
|
horizon.
|
||||||
|
|
||||||
|
Existing heat generation capacities are distributed to nodes based on population.
|
||||||
|
Within the nodes, the capacities are distributed to sectors (residential and services) based on sectoral consumption and urban/rural based population distribution.
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
-------
|
||||||
|
- Existing heating generators: `data/existing_heating_raw.csv` per country
|
||||||
|
- Population layout: `resources/{run_name}/pop_layout_s<simpl>_<clusters>.csv`. Output of `scripts/build_clustered_population_layout.py`
|
||||||
|
- Population layout with energy demands: `resources/<run_name>/pop_weighted_energy_totals_s<simpl>_<clusters>.csv`
|
||||||
|
- District heating share: `resources/<run_name>/district_heat_share_elec_s<simpl>_<clusters>_<planning_horizons>.csv`
|
||||||
|
|
||||||
|
Outputs:
|
||||||
|
--------
|
||||||
|
- Existing heat generation capacities distributed to nodes: `resources/{run_name}/existing_heating_distribution_elec_s{simpl}_{clusters}_{planning_horizons}.csv`
|
||||||
|
|
||||||
|
Relevant settings:
|
||||||
|
------------------
|
||||||
|
.. code:: yaml
|
||||||
|
scenario:
|
||||||
|
planning_horizons
|
||||||
|
sector:
|
||||||
|
existing_capacities:
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
------
|
||||||
|
- Data for Albania, Montenegro and Macedonia is not included in input database and assumed 0.
|
||||||
|
- Coal and oil boilers are assimilated to oil boilers.
|
||||||
|
- All ground-source heat pumps are assumed in rural areas and all air-source heat pumps are assumed to be in urban areas.
|
||||||
|
|
||||||
|
References:
|
||||||
|
-----------
|
||||||
|
- "Mapping and analyses of the current and future (2020 - 2030) heating/cooling fuel deployment (fossil/renewables)" (https://energy.ec.europa.eu/publications/mapping-and-analyses-current-and-future-2020-2030-heatingcooling-fuel-deployment-fossilrenewables-1_en)
|
||||||
"""
|
"""
|
||||||
import country_converter as coco
|
import country_converter as coco
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
@ -4,6 +4,17 @@
|
|||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
"""
|
"""
|
||||||
Approximate heat demand for all weather years.
|
Approximate heat demand for all weather years.
|
||||||
|
|
||||||
|
:func:`approximate_heat_demand` approximates annual heat demand based on energy totals and heating degree days (HDD) using a regression of heat demand on HDDs.
|
||||||
|
|
||||||
|
Inputs
|
||||||
|
------
|
||||||
|
- `resources/<run_name>/energy_totals.csv`: Energy consumption by sector (columns), country and year. Output of :func:`scripts.build_energy_totals.py`.
|
||||||
|
- `data/era5-annual-HDD-per-country.csv`: Number of heating degree days by year (columns) and country (index).
|
||||||
|
|
||||||
|
Outputs
|
||||||
|
-------
|
||||||
|
- `resources/<run_name>/heat_totals.csv`: Approximated annual heat demand for each country.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from itertools import product
|
from itertools import product
|
||||||
@ -14,7 +25,30 @@ from numpy.polynomial import Polynomial
|
|||||||
idx = pd.IndexSlice
|
idx = pd.IndexSlice
|
||||||
|
|
||||||
|
|
||||||
def approximate_heat_demand(energy_totals, hdd):
|
def approximate_heat_demand(energy_totals: pd.DataFrame, hdd: pd.DataFrame):
|
||||||
|
"""
|
||||||
|
Approximate heat demand for a set of countries based on energy totals and
|
||||||
|
heating degree days (HDD). A polynomial regression of heat demand on HDDs
|
||||||
|
is performed on the data from 2007 to 2021. Then, for 2022 and 2023, the
|
||||||
|
heat demand is estimated from known HDDs based on the regression.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
energy_totals : pd.DataFrame
|
||||||
|
DataFrame with energy consumption by sector (columns), country and year. Output of :func:`scripts.build_energy_totals.py`.
|
||||||
|
hdd : pd.DataFrame
|
||||||
|
DataFrame with number of heating degree days by year (columns) and country (index).
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
pd.DataFrame
|
||||||
|
DataFrame with approximated heat demand for each country.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
- Missing data is filled forward for GB in 2020 and backward for CH from 2007 to 2009.
|
||||||
|
- If only one year of heating data is available for a country, a point (0, 0) is added to make the polynomial fit work.
|
||||||
|
"""
|
||||||
|
|
||||||
countries = hdd.columns.intersection(energy_totals.index.levels[0])
|
countries = hdd.columns.intersection(energy_totals.index.levels[0])
|
||||||
|
|
||||||
|
@ -3,7 +3,31 @@
|
|||||||
#
|
#
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
"""
|
"""
|
||||||
Build hourly heat demand time series from daily ones.
|
Build hourly heat demand time series from daily heat demand.
|
||||||
|
|
||||||
|
Water and space heating demand profiles are generated using intraday profiles from BDEW. Different profiles are used for the residential and services sectors as well as weekdays and weekend.
|
||||||
|
|
||||||
|
The daily heat demand is multiplied by the intraday profile to obtain the hourly heat demand time series. The rule is executed in ``build_sector.smk``.
|
||||||
|
|
||||||
|
|
||||||
|
Relevant Settings
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
.. code:: yaml
|
||||||
|
|
||||||
|
snapshots:
|
||||||
|
drop_leap_day:
|
||||||
|
|
||||||
|
Inputs
|
||||||
|
------
|
||||||
|
|
||||||
|
- ``data/heat_load_profile_BDEW.csv``: Intraday heat profile for water and space heating demand for the residential and services sectors for weekends and weekdays.
|
||||||
|
- ``resources/daily_heat_demand_<scope>_elec_s<simpl>_<clusters>.nc``: Daily heat demand per cluster.
|
||||||
|
|
||||||
|
Outputs
|
||||||
|
-------
|
||||||
|
|
||||||
|
- ``resources/hourly_heat_demand_<scope>_elec_s<simpl>_<clusters>.nc``:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from itertools import product
|
from itertools import product
|
||||||
|
@ -3,7 +3,36 @@
|
|||||||
#
|
#
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
"""
|
"""
|
||||||
Build solar thermal collector time series.
|
Build solar thermal collector profile time series.
|
||||||
|
|
||||||
|
Uses ``atlite.Cutout.solar_thermal` to compute heat generation for clustered onshore regions from population layout and weather data cutout.
|
||||||
|
The rule is executed in ``build_sector.smk``.
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
`Atlite.Cutout.solar_thermal <https://atlite.readthedocs.io/en/master/ref_api.html#module-atlite.convert>`_
|
||||||
|
|
||||||
|
Relevant Settings
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
.. code:: yaml
|
||||||
|
|
||||||
|
snapshots:
|
||||||
|
drop_leap_day:
|
||||||
|
solar_thermal:
|
||||||
|
atlite:
|
||||||
|
default_cutout:
|
||||||
|
|
||||||
|
Inputs
|
||||||
|
------
|
||||||
|
|
||||||
|
- ``resources/<run_name/pop_layout_<scope>.nc``:
|
||||||
|
- ``resources/<run_name/regions_onshore_elec_s<simpl>_<clusters>.geojson``:
|
||||||
|
- ``cutout``: Weather data cutout, as specified in config
|
||||||
|
|
||||||
|
Outputs
|
||||||
|
-------
|
||||||
|
|
||||||
|
- ``resources/solar_thermal_<scope>_elec_s<simpl>_<clusters>.nc``:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import atlite
|
import atlite
|
||||||
|
@ -4,6 +4,36 @@
|
|||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
"""
|
"""
|
||||||
Build time series for air and soil temperatures per clustered model region.
|
Build time series for air and soil temperatures per clustered model region.
|
||||||
|
|
||||||
|
Uses ``atlite.Cutout.temperature`` and ``atlite.Cutout.soil_temperature compute temperature ambient air and soil temperature for the respective cutout. The rule is executed in ``build_sector.smk``.
|
||||||
|
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
`Atlite.Cutout.temperature <https://atlite.readthedocs.io/en/master/ref_api.html#module-atlite.convert>`_
|
||||||
|
`Atlite.Cutout.soil_temperature <https://atlite.readthedocs.io/en/master/ref_api.html#module-atlite.convert>`_
|
||||||
|
|
||||||
|
Relevant Settings
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
.. code:: yaml
|
||||||
|
|
||||||
|
snapshots:
|
||||||
|
drop_leap_day:
|
||||||
|
atlite:
|
||||||
|
default_cutout:
|
||||||
|
|
||||||
|
Inputs
|
||||||
|
------
|
||||||
|
|
||||||
|
- ``resources/<run_name>/pop_layout_<scope>.nc``:
|
||||||
|
- ``resources/<run_name>/regions_onshore_elec_s<simpl>_<clusters>.geojson``:
|
||||||
|
- ``cutout``: Weather data cutout, as specified in config
|
||||||
|
|
||||||
|
Outputs
|
||||||
|
-------
|
||||||
|
|
||||||
|
- ``resources/temp_soil_<scope>_elec_s<simpl>_<clusters>.nc``:
|
||||||
|
- ``resources/temp_air_<scope>_elec_s<simpl>_<clusters>.nc`
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import atlite
|
import atlite
|
||||||
|
Loading…
Reference in New Issue
Block a user