2018-02-10 16:16:20 +00:00
|
|
|
# coding: utf-8
|
2019-08-08 13:02:28 +00:00
|
|
|
"""
|
2019-08-11 20:34:18 +00:00
|
|
|
Retrieves conventional powerplant capacities and locations from `powerplantmatching <https://github.com/FRESNA/powerplantmatching>`_, assigns these to buses and creates a ``.csv`` file.
|
2019-08-11 09:40:47 +00:00
|
|
|
|
|
|
|
Relevant Settings
|
|
|
|
-----------------
|
|
|
|
|
2019-08-11 20:34:18 +00:00
|
|
|
.. code:: yaml
|
|
|
|
|
|
|
|
enable:
|
|
|
|
powerplantmatching:
|
2019-08-11 11:17:36 +00:00
|
|
|
|
2019-08-13 08:03:46 +00:00
|
|
|
.. seealso::
|
|
|
|
Documentation of the configuration file ``config.yaml`` at
|
|
|
|
:ref:`toplevel_cf`
|
|
|
|
|
2019-08-11 09:40:47 +00:00
|
|
|
Inputs
|
|
|
|
------
|
|
|
|
|
2019-08-11 20:34:18 +00:00
|
|
|
- ``networks/base.nc``: confer :ref:`base`.
|
|
|
|
|
2019-08-11 09:40:47 +00:00
|
|
|
Outputs
|
|
|
|
-------
|
|
|
|
|
2019-08-12 17:01:53 +00:00
|
|
|
- ``resource/powerplants.csv``: A list of conventional power plants (i.e. neither wind nor solar) with fields for name, fuel type, technology, country, capacity in MW, duration, commissioning year, retrofit year, latitude, longitude, and dam information as documented in the `powerplantmatching README <https://github.com/FRESNA/powerplantmatching/blob/master/README.md>`_; additionally it includes information on the closest substation/bus in ``networks/base.nc``.
|
|
|
|
|
2019-08-14 13:36:46 +00:00
|
|
|
.. image:: ../img/powerplantmatching.png
|
2019-08-12 17:01:53 +00:00
|
|
|
:scale: 30 %
|
|
|
|
|
|
|
|
**Source:** `powerplantmatching on GitHub <https://github.com/FRESNA/powerplantmatching>`_
|
2019-08-11 20:34:18 +00:00
|
|
|
|
2019-08-11 09:40:47 +00:00
|
|
|
Description
|
|
|
|
-----------
|
|
|
|
|
2019-08-08 13:02:28 +00:00
|
|
|
"""
|
2018-02-10 16:16:20 +00:00
|
|
|
|
|
|
|
import logging
|
2018-11-12 20:40:05 +00:00
|
|
|
import numpy as np
|
2018-02-10 16:16:20 +00:00
|
|
|
import pandas as pd
|
|
|
|
from scipy.spatial import cKDTree as KDTree
|
2018-11-12 20:40:05 +00:00
|
|
|
import pycountry as pyc
|
2018-02-10 16:16:20 +00:00
|
|
|
|
|
|
|
import pypsa
|
|
|
|
import powerplantmatching as ppm
|
|
|
|
|
2018-11-12 20:40:05 +00:00
|
|
|
def country_alpha_2(name):
|
|
|
|
try:
|
|
|
|
cntry = pyc.countries.get(name=name)
|
|
|
|
except KeyError:
|
2019-02-05 16:46:51 +00:00
|
|
|
cntry = None
|
|
|
|
if cntry is None:
|
2018-11-12 20:40:05 +00:00
|
|
|
cntry = pyc.countries.get(official_name=name)
|
|
|
|
return cntry.alpha_2
|
|
|
|
|
2019-08-19 16:04:51 +00:00
|
|
|
def add_custom_carriers(ppl):
|
|
|
|
switch = snakemake.config['electricity']['custom_powerplants']
|
|
|
|
if switch not in ('replace', 'add'):
|
|
|
|
logger.warning('custom_carriers is invalid keyword, try "replace" or "add"]. powerplants remain unchanged.')
|
|
|
|
return ppl
|
|
|
|
dirname = os.path.abspath(os.path.join(os.path.dirname(__file__),".."))
|
|
|
|
add_ppls = pd.read_csv(dirname + "/data/custom_powerplants.csv", index_col=0)
|
|
|
|
if switch == 'replace':
|
|
|
|
countries = add_ppls.Country.unique().tolist()
|
|
|
|
carriers = add_ppls.Fueltype.unique().tolist()
|
|
|
|
logger.info('replacing ' + str(carriers) + ' in ' + str(countries) + '...')
|
|
|
|
ppl.query('Fueltype != @carriers or Country != @countries',inplace=True)
|
|
|
|
logger.info('adding custom carriers...')
|
|
|
|
return ppl.append(add_ppls, sort='False')
|
2019-08-17 14:50:57 +00:00
|
|
|
|
|
|
|
def restrict_buildyear(ppl):
|
|
|
|
year = snakemake.config['electricity']['restrict_buildyear']
|
|
|
|
logger.info('restricting build year of generators to ' + str(year) + '...')
|
2019-08-19 16:04:51 +00:00
|
|
|
ppl.YearCommissioned = ppl.YearCommissioned.fillna(0).astype(int) #in case of bad arrangement
|
|
|
|
ppl.YearCommissioned = ppl.YearCommissioned.astype(int)
|
|
|
|
ppl.query('YearCommissioned <= @year',inplace=True)
|
2019-08-17 14:50:57 +00:00
|
|
|
|
2019-02-05 22:00:35 +00:00
|
|
|
if __name__ == "__main__":
|
|
|
|
if 'snakemake' not in globals():
|
|
|
|
from vresutils.snakemake import MockSnakemake, Dict
|
2018-02-10 16:16:20 +00:00
|
|
|
|
2019-02-05 22:00:35 +00:00
|
|
|
snakemake = MockSnakemake(
|
|
|
|
input=Dict(base_network='networks/base.nc'),
|
|
|
|
output=['resources/powerplants.csv']
|
|
|
|
)
|
2018-02-10 16:16:20 +00:00
|
|
|
|
2019-02-05 22:00:35 +00:00
|
|
|
logging.basicConfig(level=snakemake.config['logging_level'])
|
2018-02-10 16:16:20 +00:00
|
|
|
|
2019-02-05 22:00:35 +00:00
|
|
|
n = pypsa.Network(snakemake.input.base_network)
|
2018-02-10 16:16:20 +00:00
|
|
|
|
2019-10-28 16:12:49 +00:00
|
|
|
ppm.powerplants(from_url=True)
|
|
|
|
|
2019-02-05 22:00:35 +00:00
|
|
|
ppl = (ppm.collection.matched_data()
|
|
|
|
[lambda df : ~df.Fueltype.isin(('Solar', 'Wind'))]
|
|
|
|
.pipe(ppm.cleaning.clean_technology)
|
|
|
|
.assign(Fueltype=lambda df: (
|
|
|
|
df.Fueltype.where(df.Fueltype != 'Natural Gas',
|
|
|
|
df.Technology.replace('Steam Turbine', 'OCGT').fillna('OCGT'))))
|
|
|
|
.pipe(ppm.utils.fill_geoposition))
|
2019-08-19 16:04:51 +00:00
|
|
|
ppl = add_custom_carriers(ppl) # add carriers from own powerplant files
|
|
|
|
restrict_buildyear(ppl)
|
2018-07-10 14:29:11 +00:00
|
|
|
|
2019-02-05 22:00:35 +00:00
|
|
|
# ppl.loc[(ppl.Fueltype == 'Other') & ppl.Technology.str.contains('CCGT'), 'Fueltype'] = 'CCGT'
|
|
|
|
# ppl.loc[(ppl.Fueltype == 'Other') & ppl.Technology.str.contains('Steam Turbine'), 'Fueltype'] = 'CCGT'
|
2018-07-10 14:29:11 +00:00
|
|
|
|
2019-02-05 22:00:35 +00:00
|
|
|
ppl = ppl.loc[ppl.lon.notnull() & ppl.lat.notnull()]
|
2019-10-28 15:15:06 +00:00
|
|
|
ppl = ppl.replace({"Country": {"Macedonia, Republic of": "North Macedonia"}})
|
2018-02-10 16:16:20 +00:00
|
|
|
|
2019-02-05 22:00:35 +00:00
|
|
|
ppl_country = ppl.Country.map(country_alpha_2)
|
|
|
|
countries = n.buses.country.unique()
|
|
|
|
cntries_without_ppl = []
|
2018-11-12 20:40:05 +00:00
|
|
|
|
2019-02-05 22:00:35 +00:00
|
|
|
for cntry in countries:
|
|
|
|
substation_lv_i = n.buses.index[n.buses['substation_lv'] & (n.buses.country == cntry)]
|
|
|
|
ppl_b = ppl_country == cntry
|
|
|
|
if not ppl_b.any():
|
|
|
|
cntries_without_ppl.append(cntry)
|
|
|
|
continue
|
2018-11-12 20:40:05 +00:00
|
|
|
|
2019-02-05 22:00:35 +00:00
|
|
|
kdtree = KDTree(n.buses.loc[substation_lv_i, ['x','y']].values)
|
|
|
|
ppl.loc[ppl_b, 'bus'] = substation_lv_i[kdtree.query(ppl.loc[ppl_b, ['lon','lat']].values)[1]]
|
2018-11-12 20:40:05 +00:00
|
|
|
|
2019-02-05 22:00:35 +00:00
|
|
|
if cntries_without_ppl:
|
|
|
|
logging.warning("No powerplants known in: {}".format(", ".join(cntries_without_ppl)))
|
2018-11-12 20:40:05 +00:00
|
|
|
|
2019-02-05 22:00:35 +00:00
|
|
|
bus_null_b = ppl["bus"].isnull()
|
|
|
|
if bus_null_b.any():
|
|
|
|
logging.warning("Couldn't find close bus for {} powerplants".format(bus_null_b.sum()))
|
2018-02-10 16:16:20 +00:00
|
|
|
|
2019-02-05 22:00:35 +00:00
|
|
|
ppl.to_csv(snakemake.output[0])
|