Skip to content

Commit ce6e513

Browse files
committed
Merge branch 'project/411_LoMa_14aOptimization_with_virtual_generators' into features/#618-create-interface-to-import-all-LoMa-data-for-14a-optimization
2 parents 02f4561 + 2170ce2 commit ce6e513

5 files changed

Lines changed: 1201 additions & 5 deletions

File tree

edisgo/edisgo.py

Lines changed: 141 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,12 @@
3535
from edisgo.io.ding0_import import import_ding0_grid
3636
from edisgo.io.electromobility_import import (
3737
distribute_charging_demand,
38+
distribute_charging_demand_14a, #engine
3839
import_electromobility_from_dir,
3940
import_electromobility_from_oedb,
41+
import_electromobility_from_oedb_14a,
4042
integrate_charging_parks,
43+
integrate_charging_parks_14a,
4144
)
4245
from edisgo.io.heat_pump_import import oedb as import_heat_pumps_oedb
4346
from edisgo.io.storage_import import home_batteries_oedb
@@ -53,7 +56,7 @@
5356
from edisgo.opf.results.opf_result_class import OPFResults
5457
from edisgo.tools import plots, tools
5558
from edisgo.tools.config import Config
56-
from edisgo.tools.geo import find_nearest_bus
59+
from edisgo.tools.geo import find_nearest_bus, find_nearest_bus_14a
5760
from edisgo.tools.spatial_complexity_reduction import spatial_complexity_reduction
5861
from edisgo.tools.tools import determine_grid_integration_voltage_level
5962

@@ -1804,6 +1807,91 @@ def integrate_component_based_on_geolocation(
18041807
)
18051808

18061809
return comp_name
1810+
1811+
def integrate_component_based_on_geolocation_14a(
1812+
self,
1813+
comp_type,
1814+
geolocation,
1815+
voltage_level=None,
1816+
add_ts=True,
1817+
ts_active_power=None,
1818+
ts_reactive_power=None,
1819+
**kwargs,
1820+
):
1821+
"""
1822+
14a variant of integrate_component_based_on_geolocation.
1823+
1824+
Uses explicit _14a helper functions where custom behavior was introduced,
1825+
while leaving the original integrate_component_based_on_geolocation
1826+
unchanged for standard users.
1827+
"""
1828+
supported_voltage_levels = {4, 5, 6, 7}
1829+
p_nom = kwargs.get("p_nom", None)
1830+
p_set = kwargs.get("p_set", None)
1831+
1832+
p = p_nom if p_set is None else p_set
1833+
kwargs["p"] = p
1834+
1835+
if voltage_level not in supported_voltage_levels:
1836+
if p is None:
1837+
raise ValueError(
1838+
"Neither appropriate voltage level nor nominal power were supplied."
1839+
)
1840+
voltage_level = determine_grid_integration_voltage_level(self, p)
1841+
1842+
# convert geolocation to shapely Point if needed
1843+
if type(geolocation) is not Point:
1844+
geolocation = Point(geolocation)
1845+
1846+
kwargs["geom"] = geolocation
1847+
kwargs["voltage_level"] = voltage_level
1848+
1849+
# -------------------------
1850+
# Connect in MV
1851+
# -------------------------
1852+
if voltage_level in [4, 5]:
1853+
comp_name = self.topology.connect_to_mv_14a(self, kwargs, comp_type)
1854+
1855+
# -------------------------
1856+
# Connect in LV
1857+
# -------------------------
1858+
else:
1859+
lv_buses = self.topology.buses_df.drop(self.topology.mv_grid.buses_df.index)
1860+
lv_buses_dropna = lv_buses.dropna(axis=0, subset=["x", "y"])
1861+
1862+
# fallback path for non-georeferenced LV grids
1863+
if len(lv_buses_dropna) < len(lv_buses):
1864+
if kwargs.get("mvlv_subst_id", None) is None:
1865+
substations = self.topology.buses_df.loc[
1866+
self.topology.transformers_df.bus1.unique()
1867+
]
1868+
nearest_substation, _ = find_nearest_bus_14a(geolocation, substations)
1869+
kwargs["mvlv_subst_id"] = int(nearest_substation.split("_")[-2])
1870+
1871+
comp_name = self.topology.connect_to_lv_14a(self, kwargs, comp_type)
1872+
1873+
else:
1874+
max_distance_from_target_bus = kwargs.pop(
1875+
"max_distance_from_target_bus", 0.3 #CHANGED #14a
1876+
)
1877+
comp_name = self.topology.connect_to_lv_based_on_geolocation_14a(
1878+
self, kwargs, comp_type, max_distance_from_target_bus
1879+
)
1880+
1881+
if add_ts:
1882+
if comp_type == "generator":
1883+
self.set_time_series_manual(
1884+
generators_p=pd.DataFrame({comp_name: ts_active_power}),
1885+
generators_q=pd.DataFrame({comp_name: ts_reactive_power}),
1886+
)
1887+
else:
1888+
self.set_time_series_manual(
1889+
loads_p=pd.DataFrame({comp_name: ts_active_power}),
1890+
loads_q=pd.DataFrame({comp_name: ts_reactive_power}),
1891+
)
1892+
1893+
return comp_name
1894+
18071895

18081896
def remove_component(self, comp_type, comp_name, drop_ts=True):
18091897
"""
@@ -2111,6 +2199,58 @@ def import_electromobility(
21112199

21122200
integrate_charging_parks(self)
21132201

2202+
def import_electromobility_14a(
2203+
self,
2204+
data_source: str = "oedb",
2205+
scenario: str = None,
2206+
import_electromobility_data_kwds=None,
2207+
allocate_charging_demand_kwds=None,
2208+
):
2209+
"""
2210+
14a variant of import_electromobility.
2211+
2212+
This method uses the specific 14a EV integration path.
2213+
"""
2214+
if data_source != "oedb":
2215+
raise ValueError(
2216+
"Invalid input for parameter 'data_source'. Currently only 'oedb' is supported."
2217+
)
2218+
2219+
valid_scenarios = {"eGon2035", "eGon100RE"}
2220+
if scenario not in valid_scenarios:
2221+
raise ValueError(
2222+
f"Invalid scenario '{scenario}'. Possible options are {sorted(valid_scenarios)}."
2223+
)
2224+
2225+
if self.engine is None:
2226+
raise ValueError(
2227+
"No database engine available. Please set 'self.engine' before calling "
2228+
"import_electromobility_14a()."
2229+
)
2230+
2231+
if import_electromobility_data_kwds is None:
2232+
import_electromobility_data_kwds = {}
2233+
2234+
if "shapefile_path" not in import_electromobility_data_kwds:
2235+
raise ValueError(
2236+
"For import_electromobility_14a with data_source='oedb', "
2237+
"'shapefile_path' must be provided in import_electromobility_data_kwds."
2238+
)
2239+
2240+
if allocate_charging_demand_kwds is None:
2241+
allocate_charging_demand_kwds = {}
2242+
2243+
import_electromobility_from_oedb_14a(
2244+
self,
2245+
scenario=scenario,
2246+
engine=self.engine,
2247+
**import_electromobility_data_kwds,
2248+
)
2249+
2250+
distribute_charging_demand_14a(self, **allocate_charging_demand_kwds)
2251+
2252+
integrate_charging_parks_14a(self)
2253+
21142254
def apply_charging_strategy(self, strategy="dumb", **kwargs):
21152255
"""
21162256
Applies charging strategy to set EV charging time series at charging parks.

0 commit comments

Comments
 (0)