Skip to content

Commit

Permalink
Features/#988 distribute home batteries within grid districts (#1008)
Browse files Browse the repository at this point in the history
* added home battery allocation onto buildings
* add dataset to pipeline
* added sanity checks
* update dataset version and changelog
* undo hard coding in sanity checks and pv_rooftop

Co-authored-by: Julian.Endres <julian.endres@rl-institut.de>
Co-authored-by: nesnoj <jonathan.amme@rl-institut.de>
  • Loading branch information
3 people committed Nov 25, 2022
1 parent e8b9a8e commit 4a2d016
Show file tree
Hide file tree
Showing 9 changed files with 346 additions and 38 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,8 @@ Added
`PR #978 <https://github.com/openego/eGon-data/pull/978>`_
* Add voltage level for electricity building loads
`#955 <https://github.com/openego/eGon-data/issues/955>`_
* Add desaggregation of pv home batteries onto buildings
`#988 <https://github.com/openego/eGon-data/issues/988>`_

.. _PR #159: https://github.com/openego/eGon-data/pull/159
.. _PR #703: https://github.com/openego/eGon-data/pull/703
Expand Down
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
from glob import glob
from os.path import basename, dirname, join, splitext
import io
import re
import re

from setuptools import find_packages, setup


Expand Down
6 changes: 3 additions & 3 deletions src/egon/data/airflow/dags/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
from egon.data.datasets.scenario_capacities import ScenarioCapacities
from egon.data.datasets.scenario_parameters import ScenarioParameters
from egon.data.datasets.society_prognosis import SocietyPrognosis
from egon.data.datasets.storages import PumpedHydro
from egon.data.datasets.storages import Storages
from egon.data.datasets.storages_etrago import StorageEtrago
from egon.data.datasets.substation import SubstationExtraction
from egon.data.datasets.substation_voronoi import SubstationVoronoi
Expand Down Expand Up @@ -419,7 +419,7 @@
run_pypsaeursec,
foreign_lines,
insert_hydrogen_buses,
create_gas_polygons_egon100RE
create_gas_polygons_egon100RE,
]
)

Expand Down Expand Up @@ -507,7 +507,7 @@
)

# Pumped hydro units
pumped_hydro = PumpedHydro(
pumped_hydro = Storages(
dependencies=[
mastr_data,
mv_grid_districts,
Expand Down
25 changes: 24 additions & 1 deletion src/egon/data/datasets.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1155,7 +1155,9 @@ mobility_hgv:
# share of FCEV trucks
# within the egon project the flat guess is 100%
fcev_share: 1.
scenarios: ["eGon2035", "eGon100RE"]
scenarios:
- "eGon2035"
- "eGon100RE"
carrier: "H2_hgv_load"
energy_value_h2: 39.4 # kWh/kg
hours_per_year: 8760
Expand All @@ -1172,3 +1174,24 @@ mobility_hgv:
# Langfristszenarien
# https://www.langfristszenarien.de/enertile-explorer-wAssets/docs/LFS3_Langbericht_Verkehr_final.pdf#page=17
eGon100RE: 40000000000

home_batteries:
constants:
scenarios:
- "eGon2035"
- "eGon100RE"
# Mean ratio between the storage capacity and the power of the pv rooftop system
cbat_ppv_ratio: 1
rtol: 0.05
max_it: 100
sources:
etrago_storage:
schema: 'grid'
table: 'egon_etrago_storage'
storage:
schema: 'supply'
table: 'egon_storages'
targets:
home_batteries:
schema: 'supply'
table: 'egon_home_batteries'
4 changes: 2 additions & 2 deletions src/egon/data/datasets/power_plants/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
pv_rooftop_to_buildings,
)
import egon.data.config
import egon.data.datasets.power_plants.assign_weather_data as assign_weather_data
import egon.data.datasets.power_plants.assign_weather_data as assign_weather_data # noqa: E501
import egon.data.datasets.power_plants.pv_ground_mounted as pv_ground_mounted
import egon.data.datasets.power_plants.wind_farms as wind_onshore
import egon.data.datasets.power_plants.wind_offshore as wind_offshore
Expand Down Expand Up @@ -796,7 +796,7 @@ def allocate_other_power_plants():

# Select power plants representing carrier 'others' from MaStR files
mastr_sludge = pd.read_csv(cfg["sources"]["mastr_gsgk"]).query(
"""EinheitBetriebsstatus=='InBetrieb'and Energietraeger=='Klaerschlamm'"""
"""EinheitBetriebsstatus=='InBetrieb'and Energietraeger=='Klaerschlamm'""" # noqa: E501
)
mastr_geothermal = pd.read_csv(cfg["sources"]["mastr_gsgk"]).query(
"EinheitBetriebsstatus=='InBetrieb' and Energietraeger=='Geothermie' "
Expand Down
31 changes: 23 additions & 8 deletions src/egon/data/datasets/power_plants/pv_rooftop.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"""The module containing all code dealing with pv rooftop distribution.
"""
from pathlib import Path

from loguru import logger
from numpy import isclose
import geopandas as gpd
Expand All @@ -10,6 +12,7 @@
PV_CAP_PER_SQ_M,
ROOF_FACTOR,
load_building_data,
scenario_data,
)
from egon.data.datasets.scenario_parameters import get_sector_parameters

Expand Down Expand Up @@ -158,10 +161,22 @@ def pv_rooftop_per_mv_grid_and_scenario(scenario, level):
dataset = config.settings()["egon-data"]["--dataset-boundary"]

if dataset == "Schleswig-Holstein":
# since the required data is missing for a SH run, it is implemented
# manually here
total_2035 = 84070
sh_2035 = 2700
sources = config.datasets()["scenario_input"]["sources"]

path = Path(
f"./data_bundle_egon_data/nep2035_version2021/"
f"{sources['eGon2035']['capacities']}"
).resolve()

total_2035 = (
pd.read_excel(
path,
sheet_name="1.Entwurf_NEP2035_V2021",
index_col="Unnamed: 0",
).at["PV (Aufdach)", "Summe"]
* 1000
)
sh_2035 = scenario_data(scenario="eGon2035").capacity.sum()

share = sh_2035 / total_2035

Expand All @@ -187,8 +202,8 @@ def pv_rooftop_per_mv_grid_and_scenario(scenario, level):
}
)

# ensure that no more pv rooftop capacity is allocated to any mv grid district than
# there is rooftop potential
# ensure that no more pv rooftop capacity is allocated to any mv grid
# district than there is rooftop potential
max_cap_per_bus_df = (
valid_buildings_gdf[["max_cap", "bus_id"]].groupby("bus_id").sum()
/ 1000
Expand Down Expand Up @@ -225,8 +240,8 @@ def pv_rooftop_per_mv_grid_and_scenario(scenario, level):

if loss < 0:
logger.debug(
f"{loss:g} MW got redistributed from MV grids with too little rooftop "
f"potential towards other MV grids."
f"{loss:g} MW got redistributed from MV grids with too little "
f"rooftop potential towards other MV grids."
)

# Select feedin timeseries
Expand Down
71 changes: 65 additions & 6 deletions src/egon/data/datasets/sanity_checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
EgonCtsElectricityDemandBuildingShare,
EgonCtsHeatDemandBuildingShare,
)
from egon.data.datasets.emobility.motorized_individual_travel.db_classes import (
from egon.data.datasets.emobility.motorized_individual_travel.db_classes import ( # noqa: E501
EgonEvCountMunicipality,
EgonEvCountMvGridDistrict,
EgonEvCountRegistrationDistrict,
Expand Down Expand Up @@ -49,6 +49,7 @@
scenario_data,
)
from egon.data.datasets.scenario_parameters import get_sector_parameters
from egon.data.datasets.storages.home_batteries import get_cbat_pbat_ratio
import egon.data

TESTMODE_OFF = (
Expand All @@ -60,7 +61,7 @@ class SanityChecks(Dataset):
def __init__(self, dependencies):
super().__init__(
name="SanityChecks",
version="0.0.5",
version="0.0.6",
dependencies=dependencies,
tasks={
etrago_eGon2035_electricity,
Expand All @@ -71,6 +72,7 @@ def __init__(self, dependencies):
cts_heat_demand_share,
sanitycheck_emobility_mit,
sanitycheck_pv_rooftop_buildings,
sanitycheck_home_batteries,
},
)

Expand Down Expand Up @@ -769,10 +771,22 @@ def egon_power_plants_pv_roof_building():
dataset = config.settings()["egon-data"]["--dataset-boundary"]

if dataset == "Schleswig-Holstein":
# since the required data is missing for a SH run, it is implemented
# manually here
total_2035 = 84070
sh_2035 = 2700
sources = config.datasets()["scenario_input"]["sources"]

path = Path(
f"./data_bundle_egon_data/nep2035_version2021/"
f"{sources['eGon2035']['capacities']}"
).resolve()

total_2035 = (
pd.read_excel(
path,
sheet_name="1.Entwurf_NEP2035_V2021",
index_col="Unnamed: 0",
).at["PV (Aufdach)", "Summe"]
* 1000
)
sh_2035 = scenario_data(scenario="eGon2035").capacity.sum()

share = sh_2035 / total_2035

Expand Down Expand Up @@ -1345,3 +1359,48 @@ def check_model_data_lowflex_eGon2035():
check_model_data_lowflex_eGon2035()

print("=====================================================")


def sanitycheck_home_batteries():
# get constants
constants = config.datasets()["home_batteries"]["constants"]
scenarios = constants["scenarios"]
cbat_pbat_ratio = get_cbat_pbat_ratio()

sources = config.datasets()["home_batteries"]["sources"]
targets = config.datasets()["home_batteries"]["targets"]

for scenario in scenarios:
# get home battery capacity per mv grid id
sql = f"""
SELECT el_capacity as p_nom, bus_id FROM
{sources["storage"]["schema"]}
.{sources["storage"]["table"]}
WHERE carrier = 'home_battery'
AND scenario = '{scenario}'
"""

home_batteries_df = db.select_dataframe(sql, index_col="bus_id")

home_batteries_df = home_batteries_df.assign(
capacity=home_batteries_df.p_nom * cbat_pbat_ratio
)

sql = f"""
SELECT * FROM
{targets["home_batteries"]["schema"]}
.{targets["home_batteries"]["table"]}
WHERE scenario = '{scenario}'
"""

home_batteries_buildings_df = db.select_dataframe(
sql, index_col="index"
)

df = (
home_batteries_buildings_df[["bus_id", "p_nom", "capacity"]]
.groupby("bus_id")
.sum()
)

assert (home_batteries_df.round(6) == df.round(6)).all().all()
38 changes: 21 additions & 17 deletions src/egon/data/datasets/storages/__init__.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
"""The central module containing all code dealing with power plant data.
"""
from geoalchemy2 import Geometry
from pathlib import Path

from geoalchemy2 import Geometry
from sqlalchemy import BigInteger, Column, Float, Integer, Sequence, String
from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from egon.data.datasets.storages.pumped_hydro import (
select_mastr_pumped_hydro,
select_nep_pumped_hydro,
match_storage_units,
get_location,
apply_voltage_level_thresholds,
)
from egon.data.datasets.power_plants import assign_voltage_level
import geopandas as gpd
import pandas as pd

from egon.data import db, config
from egon.data import config, db
from egon.data.datasets import Dataset

from egon.data.datasets.power_plants import assign_voltage_level
from egon.data.datasets.storages.home_batteries import (
allocate_home_batteries_to_buildings,
)
from egon.data.datasets.storages.pumped_hydro import (
apply_voltage_level_thresholds,
get_location,
match_storage_units,
select_mastr_pumped_hydro,
select_nep_pumped_hydro,
)

Base = declarative_base()

Expand All @@ -38,17 +41,18 @@ class EgonStorages(Base):
geom = Column(Geometry("POINT", 4326))


class PumpedHydro(Dataset):
class Storages(Dataset):
def __init__(self, dependencies):
super().__init__(
name="Storages",
version="0.0.2",
version="0.0.4",
dependencies=dependencies,
tasks=(
create_tables,
allocate_pumped_hydro_eGon2035,
allocate_pumped_hydro_eGon100RE,
allocate_pv_home_batteries,
allocate_pv_home_batteries_to_grids,
allocate_home_batteries_to_buildings,
),
)

Expand Down Expand Up @@ -292,8 +296,8 @@ def allocate_pumped_hydro_eGon100RE():
else:
raise ValueError(f"'{boundary}' is not a valid dataset boundary.")

# Get allocation of pumped_hydro plants in eGon2035 scenario as the reference
# for the distribution in eGon100RE scenario
# Get allocation of pumped_hydro plants in eGon2035 scenario as the
# reference for the distribution in eGon100RE scenario
allocation = allocate_pumped_hydro_eGon2035(export=False)

scaling_factor = capacity_phes / allocation.el_capacity.sum()
Expand Down Expand Up @@ -412,7 +416,7 @@ def home_batteries_per_scenario(scenario):
session.commit()


def allocate_pv_home_batteries():
def allocate_pv_home_batteries_to_grids():

home_batteries_per_scenario("eGon2035")
home_batteries_per_scenario("eGon100RE")

0 comments on commit 4a2d016

Please sign in to comment.