From 5a8df7af8c0829e77f5b269f20446edba7a296dc Mon Sep 17 00:00:00 2001 From: joda9 Date: Tue, 2 Dec 2025 17:29:47 +0100 Subject: [PATCH] Refactor database engine usage in import functions - Removed the `engine` parameter from various functions in the `oedb` imports for generators, heat pumps, storage, and timeseries. - Updated internal function calls to use `edisgo_object.engine` instead of passing the engine as a parameter. - Adjusted related tests to reflect these changes, ensuring that the `engine` parameter is no longer required. - Improved code consistency and readability by centralizing the engine access through the `EDisGo` object. --- CHANGELOG_ENGINE.md | 183 ++++++++++++++++++++++++ doc/usage_details.rst | 7 + edisgo/edisgo.py | 60 ++++---- edisgo/io/dsm_import.py | 16 +-- edisgo/io/electromobility_import.py | 29 ++-- edisgo/io/generators_import.py | 16 +-- edisgo/io/heat_pump_import.py | 38 +++-- edisgo/io/storage_import.py | 9 +- edisgo/io/timeseries_import.py | 62 ++++---- edisgo/network/heat.py | 16 +-- edisgo/network/timeseries.py | 11 +- edisgo/tools/tools.py | 5 + tests/conftest.py | 2 +- tests/io/test_dsm_import.py | 10 +- tests/io/test_electromobility_import.py | 4 +- tests/io/test_generators_import.py | 4 +- tests/io/test_heat_pump_import.py | 7 +- tests/io/test_storage_import.py | 8 +- tests/io/test_timeseries_import.py | 3 +- tests/network/test_heat.py | 7 - tests/network/test_timeseries.py | 2 +- tests/test_edisgo.py | 5 +- 22 files changed, 321 insertions(+), 183 deletions(-) create mode 100644 CHANGELOG_ENGINE.md diff --git a/CHANGELOG_ENGINE.md b/CHANGELOG_ENGINE.md new file mode 100644 index 000000000..82e31eaad --- /dev/null +++ b/CHANGELOG_ENGINE.md @@ -0,0 +1,183 @@ +# Engine-Handling Änderungen + +## Zusammenfassung + +Das Engine-Handling in eDisGo wurde grundlegend umstrukturiert, um eine einheitlichere und logischere Nutzung zu ermöglichen. + +## Hauptänderungen + +### 1. Zentrales Engine-Objekt in EDisGo-Klasse + +Die `EDisGo`-Klasse verfügt nun über ein zentrales `engine`-Attribut, das standardmäßig die TOEP (The Open Energy Platform) Engine enthält: + +```python +# Neu in edisgo/edisgo.py +class EDisGo: + def __init__(self, **kwargs): + # Engine wird beim Initialisieren gesetzt (TOEP by default) + self._engine = kwargs.get("engine", None) + if self._engine is None: + self._engine = egon_engine() + # ... + + @property + def engine(self): + """Database engine für OEDB-Zugriff.""" + return self._engine + + @engine.setter + def engine(self, engine): + self._engine = engine +``` + +### 2. Entfernte Engine-Parameter + +Die folgenden Methoden benötigen **keinen** `engine` Parameter mehr: + +**edisgo/edisgo.py:** +- `set_time_series_active_power_predefined()` +- `import_generators()` +- `import_electromobility()` +- `import_heat_pumps()` +- `import_dsm()` +- `import_home_batteries()` + +**edisgo/network/heat.py:** +- `HeatPump.set_cop()` +- `HeatPump.set_heat_demand()` + +**edisgo/network/timeseries.py:** +- `TimeSeries.predefined_fluctuating_generators_by_technology()` + +### 3. Verwendung von self.engine + +Alle oben genannten Methoden verwenden jetzt intern `self.engine` bzw. `edisgo_object.engine`: + +```python +# Vorher +def import_generators(self, generator_scenario, **kwargs): + engine = kwargs["engine"] if "engine" in kwargs else egon_engine() + generators_import.oedb( + edisgo_object=self, + engine=engine, + scenario=generator_scenario, + ) + +# Nachher +def import_generators(self, generator_scenario, **kwargs): + generators_import.oedb( + edisgo_object=self, + engine=self.engine, + scenario=generator_scenario, + ) +``` + +### 4. IO-Module bleiben unverändert + +Die Funktionen in `edisgo/io/*.py` behalten ihre `engine` Parameter, da sie Utility-Funktionen sind, die von verschiedenen Stellen aufgerufen werden können. Sie werden nun mit `edisgo_object.engine` von den aufrufenden Funktionen versorgt. + +## Verwendung + +### Standard-Verwendung (TOEP) + +```python +from edisgo import EDisGo + +# Engine wird automatisch als TOEP initialisiert +edisgo = EDisGo(ding0_grid="path/to/grid") + +# Alle Funktionen verwenden automatisch self.engine +edisgo.import_generators(generator_scenario="eGon2035") +edisgo.import_heat_pumps(scenario="eGon2035") +edisgo.import_electromobility(data_source="oedb", scenario="eGon2035") +edisgo.import_dsm(scenario="eGon2035") +edisgo.import_home_batteries(scenario="eGon2035") + +# Auf Engine zugreifen +print(edisgo.engine) +``` + +### Verwendung mit Custom Engine + +```python +from edisgo import EDisGo +from sqlalchemy import create_engine + +# Option 1: Engine beim Initialisieren übergeben +custom_engine = create_engine("postgresql://user:password@host:port/database") +edisgo = EDisGo(ding0_grid="path/to/grid", engine=custom_engine) + +# Option 2: Engine nachträglich setzen +edisgo = EDisGo(ding0_grid="path/to/grid") +edisgo.engine = create_engine("postgresql://user:password@host:port/database") + +# Alle Funktionen verwenden die custom engine +edisgo.import_generators(generator_scenario="eGon2035") +``` + +## Vorteile + +✅ **Einheitlich**: Engine wird nur einmal beim Erstellen des EDisGo-Objekts definiert +✅ **Logischer**: Kein wiederholtes Übergeben der Engine in jeder Funktion +✅ **Weniger fehleranfällig**: Keine Gefahr, verschiedene Engines in verschiedenen Funktionsaufrufen zu verwenden +✅ **Abwärtskompatibel**: Beim Initialisieren kann weiterhin eine custom Engine übergeben werden +✅ **Standard TOEP**: Die TOEP-Engine wird standardmäßig verwendet + +## Breaking Changes + +⚠️ **WICHTIG**: Die folgenden Funktionen akzeptieren **keinen** `engine` Parameter mehr: + +```python +# FALSCH - funktioniert nicht mehr: +edisgo.import_generators(generator_scenario="eGon2035", engine=my_engine) + +# RICHTIG - engine wird von edisgo.engine genommen: +edisgo.engine = my_engine # optional, falls nicht TOEP +edisgo.import_generators(generator_scenario="eGon2035") +``` + +## Migration Guide + +### Alt (vor den Änderungen): + +```python +from edisgo import EDisGo +from edisgo.io.db import engine as egon_engine + +# Engine muss überall übergeben werden +my_engine = egon_engine() +edisgo = EDisGo(ding0_grid="path/to/grid") + +edisgo.set_time_series_active_power_predefined( + fluctuating_generators_ts="oedb", + engine=my_engine +) +edisgo.import_generators(generator_scenario="eGon2035", engine=my_engine) +edisgo.import_heat_pumps(scenario="eGon2035", engine=my_engine) +``` + +### Neu (nach den Änderungen): + +```python +from edisgo import EDisGo + +# Engine wird automatisch initialisiert (TOEP) +edisgo = EDisGo(ding0_grid="path/to/grid") + +# Kein engine Parameter mehr nötig +edisgo.set_time_series_active_power_predefined( + fluctuating_generators_ts="oedb" +) +edisgo.import_generators(generator_scenario="eGon2035") +edisgo.import_heat_pumps(scenario="eGon2035") + +# Optional: Custom Engine verwenden +# edisgo.engine = my_custom_engine +``` + +## Geänderte Dateien + +- `edisgo/edisgo.py` +- `edisgo/network/heat.py` +- `edisgo/network/timeseries.py` +- `doc/usage_details.rst` diff --git a/doc/usage_details.rst b/doc/usage_details.rst index 48e9bb95b..b7d7a2a35 100644 --- a/doc/usage_details.rst +++ b/doc/usage_details.rst @@ -32,6 +32,10 @@ Results data holding results e.g. from the power flow analysis and grid expansion is stored in the :class:`~.network.results.Results` class. Configuration data from the config files (see :ref:`default_configs`) is stored in the :class:`~.tools.config.Config` class. +The database engine for accessing the OpenEnergy DataBase (OEDB) is stored as +:attr:`~.edisgo.EDisGo.engine`. By default, this is the TOEP (The Open Energy Platform) +engine, but can be customized by providing an `engine` parameter when initializing +the :class:`~.EDisGo` object. All these can be accessed through the :class:`~.EDisGo` object. In the following code examples `edisgo` constitues an :class:`~.EDisGo` object. @@ -56,6 +60,9 @@ code examples `edisgo` constitues an :class:`~.EDisGo` object. # Access configuration data container object edisgo.config + # Access database engine (TOEP by default) + edisgo.engine + Grid data is stored in :pandas:`pandas.DataFrames` in the :class:`~.network.topology.Topology` object. There are extra data frames for all diff --git a/edisgo/edisgo.py b/edisgo/edisgo.py index eaa1111ef..f3e1189a5 100755 --- a/edisgo/edisgo.py +++ b/edisgo/edisgo.py @@ -161,6 +161,11 @@ def __init__(self, **kwargs): # load configuration self._config = Config(**kwargs) + # instantiate database engine (TOEP by default) + self._engine = kwargs.get("engine", None) + if self._engine is None: + self._engine = egon_engine() + # instantiate topology object and load grid data self.topology = Topology(config=self.config) self.import_ding0_grid( @@ -229,6 +234,25 @@ def config(self): def config(self, kwargs): self._config = Config(**kwargs) + @property + def engine(self): + """ + Database engine for accessing the OEDB (OpenEnergy Database). + + By default, this is the TOEP (The Open Energy Platform) engine. + + Returns + ------- + :sqlalchemy:`sqlalchemy.Engine` + Database engine. + + """ + return self._engine + + @engine.setter + def engine(self, engine): + self._engine = engine + def import_ding0_grid(self, path, legacy_ding0_grids=True): """ Import ding0 topology data from csv files in the format as @@ -536,9 +560,6 @@ def set_time_series_active_power_predefined( Other Parameters ------------------ - engine : :sqlalchemy:`sqlalchemy.Engine` - Database engine. This parameter is only required in case - `conventional_loads_ts` or `fluctuating_generators_ts` is 'oedb'. scenario : str Scenario for which to retrieve demand data. Possible options are 'eGon2035' and 'eGon100RE'. This parameter is only required in case @@ -556,7 +577,6 @@ def set_time_series_active_power_predefined( is indexed using a default year and set for the whole year. """ - engine = kwargs["engine"] if "engine" in kwargs else egon_engine() if self.timeseries.timeindex.empty: logger.warning( "When setting time series using predefined profiles it is better to " @@ -570,7 +590,6 @@ def set_time_series_active_power_predefined( self, fluctuating_generators_ts, fluctuating_generators_names, - engine=engine, timeindex=kwargs.get("timeindex", None), ) if dispatchable_generators_ts is not None: @@ -585,7 +604,6 @@ def set_time_series_active_power_predefined( loads_ts_df = timeseries_import.electricity_demand_oedb( edisgo_obj=self, scenario=kwargs.get("scenario"), - engine=engine, timeindex=kwargs.get("timeindex", None), load_names=conventional_loads_names, ) @@ -972,14 +990,11 @@ def import_generators(self, generator_scenario=None, **kwargs): Other Parameters ---------------- kwargs : - In case you are using new ding0 grids, where the LV is geo-referenced, a - database engine needs to be provided through keyword argument `engine`. In case you are using old ding0 grids, where the LV is not geo-referenced, you can check :func:`edisgo.io.generators_import.oedb_legacy` for possible keyword arguments. """ - engine = kwargs["engine"] if "engine" in kwargs else egon_engine() if self.legacy_grids is True: generators_import.oedb_legacy( edisgo_object=self, generator_scenario=generator_scenario, **kwargs @@ -987,7 +1002,6 @@ def import_generators(self, generator_scenario=None, **kwargs): else: generators_import.oedb( edisgo_object=self, - engine=engine, scenario=generator_scenario, ) @@ -1923,7 +1937,6 @@ def import_electromobility( self, data_source: str, scenario: str = None, - engine: Engine = None, charging_processes_dir: PurePath | str = None, potential_charging_points_dir: PurePath | str = None, import_electromobility_data_kwds=None, @@ -1967,8 +1980,7 @@ def import_electromobility( Electromobility data is obtained from the `OpenEnergy DataBase `_. - This option requires that the parameters `scenario` and `engine` are - provided. + This option requires that the parameter `scenario` is provided. * "directory" @@ -1978,9 +1990,6 @@ def import_electromobility( scenario : str Scenario for which to retrieve electromobility data in case `data_source` is set to "oedb". Possible options are "eGon2035" and "eGon100RE". - engine : :sqlalchemy:`sqlalchemy.Engine` - Database engine. Needs to be provided in case `data_source` is set to - "oedb". charging_processes_dir : str or pathlib.PurePath Directory holding data on charging processes (standing times, charging demand, etc. per vehicle), including metadata, from SimBEV. @@ -2042,7 +2051,6 @@ def import_electromobility( import_electromobility_from_oedb( self, scenario=scenario, - engine=engine, **import_electromobility_data_kwds, ) elif data_source == "directory": @@ -2135,7 +2143,7 @@ def apply_charging_strategy(self, strategy="dumb", **kwargs): """ charging_strategy(self, strategy=strategy, **kwargs) - def import_heat_pumps(self, scenario, engine, timeindex=None, import_types=None): + def import_heat_pumps(self, scenario, timeindex=None, import_types=None): """ Gets heat pump data for specified scenario from oedb and integrates the heat pumps into the grid. @@ -2193,8 +2201,6 @@ def import_heat_pumps(self, scenario, engine, timeindex=None, import_types=None) scenario : str Scenario for which to retrieve heat pump data. Possible options are 'eGon2035' and 'eGon100RE'. - engine : :sqlalchemy:`sqlalchemy.Engine` - Database engine. timeindex : :pandas:`pandas.DatetimeIndex` or None Specifies time steps for which to set COP and heat demand data. Leap years can currently not be handled. In case the given @@ -2235,7 +2241,6 @@ def import_heat_pumps(self, scenario, engine, timeindex=None, import_types=None) year = tools.get_year_based_on_scenario(scenario) return self.import_heat_pumps( scenario, - engine, timeindex=pd.date_range(f"1/1/{year}", periods=8760, freq="H"), import_types=import_types, ) @@ -2243,7 +2248,6 @@ def import_heat_pumps(self, scenario, engine, timeindex=None, import_types=None) integrated_heat_pumps = import_heat_pumps_oedb( edisgo_object=self, scenario=scenario, - engine=engine, import_types=import_types, ) if len(integrated_heat_pumps) > 0: @@ -2251,7 +2255,6 @@ def import_heat_pumps(self, scenario, engine, timeindex=None, import_types=None) self, "oedb", heat_pump_names=integrated_heat_pumps, - engine=engine, scenario=scenario, timeindex=timeindex, ) @@ -2259,7 +2262,6 @@ def import_heat_pumps(self, scenario, engine, timeindex=None, import_types=None) self, "oedb", heat_pump_names=integrated_heat_pumps, - engine=engine, timeindex=timeindex, ) @@ -2307,7 +2309,7 @@ def apply_heat_pump_operating_strategy( """ hp_operating_strategy(self, strategy=strategy, heat_pump_names=heat_pump_names) - def import_dsm(self, scenario: str, engine: Engine, timeindex=None): + def import_dsm(self, scenario: str, timeindex=None): """ Gets industrial and CTS DSM profiles from the `OpenEnergy DataBase `_. @@ -2326,8 +2328,6 @@ def import_dsm(self, scenario: str, engine: Engine, timeindex=None): scenario : str Scenario for which to retrieve DSM data. Possible options are 'eGon2035' and 'eGon100RE'. - engine : :sqlalchemy:`sqlalchemy.Engine` - Database engine. timeindex : :pandas:`pandas.DatetimeIndex` or None Specifies time steps for which to get data. Leap years can currently not be handled. In case the given timeindex contains a leap year, the data will be @@ -2340,7 +2340,7 @@ def import_dsm(self, scenario: str, engine: Engine, timeindex=None): """ dsm_profiles = dsm_import.oedb( - edisgo_obj=self, scenario=scenario, engine=engine, timeindex=timeindex + edisgo_obj=self, scenario=scenario, timeindex=timeindex ) self.dsm.p_min = dsm_profiles["p_min"] self.dsm.p_max = dsm_profiles["p_max"] @@ -2350,7 +2350,6 @@ def import_dsm(self, scenario: str, engine: Engine, timeindex=None): def import_home_batteries( self, scenario: str, - engine: Engine, ): """ Gets home battery data for specified scenario and integrates the batteries into @@ -2378,14 +2377,11 @@ def import_home_batteries( scenario : str Scenario for which to retrieve home battery data. Possible options are 'eGon2035' and 'eGon100RE'. - engine : :sqlalchemy:`sqlalchemy.Engine` - Database engine. """ home_batteries_oedb( edisgo_obj=self, scenario=scenario, - engine=engine, ) def plot_mv_grid_topology(self, technologies=False, **kwargs): diff --git a/edisgo/io/dsm_import.py b/edisgo/io/dsm_import.py index fb0637036..38a6130a1 100644 --- a/edisgo/io/dsm_import.py +++ b/edisgo/io/dsm_import.py @@ -23,7 +23,6 @@ def oedb( edisgo_obj: EDisGo, scenario: str, - engine: Engine, timeindex=None, ): """ @@ -39,8 +38,6 @@ def oedb( scenario : str Scenario for which to retrieve DSM data. Possible options are 'eGon2035' and 'eGon100RE'. - engine : :sqlalchemy:`sqlalchemy.Engine` - Database engine. timeindex : :pandas:`pandas.DatetimeIndex` or None Specifies time steps for which to return data. Leap years can currently not be handled. In case the given timeindex contains a leap year, the data will @@ -62,13 +59,13 @@ def oedb( """ # get CTS and industrial DSM profiles - dsm_cts = get_profile_cts(edisgo_obj, scenario, engine) + dsm_cts = get_profile_cts(edisgo_obj, scenario) ind_loads = edisgo_obj.topology.loads_df[ (edisgo_obj.topology.loads_df.type == "conventional_load") & (edisgo_obj.topology.loads_df.sector == "industrial") ] dsm_ind = get_profiles_per_industrial_load( - ind_loads.building_id.unique(), scenario, engine + ind_loads.building_id.unique(), scenario, edisgo_obj.engine ) # rename industrial DSM profiles, join with CTS profiles and set time index @@ -202,7 +199,6 @@ def get_profiles_per_industrial_load( def get_profile_cts( edisgo_obj: EDisGo, scenario: str, - engine: Engine, ): """ Gets CTS DSM profiles for all CTS loads in the MV grid. @@ -213,8 +209,6 @@ def get_profile_cts( scenario : str Scenario for which to retrieve DSM data. Possible options are 'eGon2035' and 'eGon100RE'. - engine : :sqlalchemy:`sqlalchemy.Engine` - Database engine. Returns -------- @@ -237,13 +231,13 @@ def get_profile_cts( """ config = Config() (egon_etrago_electricity_cts_dsm_timeseries,) = config.import_tables_from_oep( - engine, ["egon_etrago_electricity_cts_dsm_timeseries"], "demand" + edisgo_obj.engine, ["egon_etrago_electricity_cts_dsm_timeseries"], "demand" ) # get data dsm_dict = {} - with session_scope_egon_data(engine) as session: + with session_scope_egon_data(edisgo_obj.engine) as session: query = session.query( egon_etrago_electricity_cts_dsm_timeseries.bus.label("site_id"), egon_etrago_electricity_cts_dsm_timeseries.p_min, @@ -254,7 +248,7 @@ def get_profile_cts( egon_etrago_electricity_cts_dsm_timeseries.scn_name == scenario, egon_etrago_electricity_cts_dsm_timeseries.bus == edisgo_obj.topology.id, ) - df = pd.read_sql(sql=query.statement, con=engine) + df = pd.read_sql(sql=query.statement, con=edisgo_obj.engine) # add time step column df["time_step"] = len(df) * [np.arange(0, 8760)] # un-nest time series data and pivot so that time_step becomes index and diff --git a/edisgo/io/electromobility_import.py b/edisgo/io/electromobility_import.py index 83dc68af4..c82585cb7 100644 --- a/edisgo/io/electromobility_import.py +++ b/edisgo/io/electromobility_import.py @@ -1149,7 +1149,6 @@ def integrate_charging_parks(edisgo_obj): def import_electromobility_from_oedb( edisgo_obj: EDisGo, scenario: str, - engine: Engine, **kwargs, ): """ @@ -1164,8 +1163,6 @@ def import_electromobility_from_oedb( scenario : str Scenario for which to retrieve electromobility data. Possible options are 'eGon2035' and 'eGon100RE'. - engine : :sqlalchemy:`sqlalchemy.Engine` - Database engine. Other Parameters ---------------- @@ -1177,13 +1174,13 @@ def import_electromobility_from_oedb( """ edisgo_obj.electromobility.charging_processes_df = charging_processes_from_oedb( - edisgo_obj=edisgo_obj, engine=engine, scenario=scenario, **kwargs + edisgo_obj=edisgo_obj, scenario=scenario, **kwargs ) edisgo_obj.electromobility.simbev_config_df = simbev_config_from_oedb( - scenario=scenario, engine=engine + scenario=scenario, engine=edisgo_obj.engine ) potential_charging_parks_gdf = potential_charging_parks_from_oedb( - edisgo_obj=edisgo_obj, engine=engine, **kwargs + edisgo_obj=edisgo_obj, **kwargs ) edisgo_obj.electromobility.potential_charging_parks_gdf = ( assure_minimum_potential_charging_parks( @@ -1234,7 +1231,6 @@ def simbev_config_from_oedb( def potential_charging_parks_from_oedb( edisgo_obj: EDisGo, - engine: Engine, ): """ Gets :attr:`~.network.electromobility.Electromobility.potential_charging_parks_gdf` @@ -1243,8 +1239,6 @@ def potential_charging_parks_from_oedb( Parameters ---------- edisgo_obj : :class:`~.EDisGo` - engine : :sqlalchemy:`sqlalchemy.Engine` - Database engine. Returns -------- @@ -1256,12 +1250,12 @@ def potential_charging_parks_from_oedb( """ config = Config() (egon_emob_charging_infrastructure,) = config.import_tables_from_oep( - engine, ["egon_emob_charging_infrastructure"], "grid" + edisgo_obj.engine, ["egon_emob_charging_infrastructure"], "grid" ) crs = edisgo_obj.topology.grid_district["srid"] - with session_scope_egon_data(engine) as session: + with session_scope_egon_data(edisgo_obj.engine) as session: srid = get_srid_of_db_table(session, egon_emob_charging_infrastructure.geometry) query = session.query( @@ -1283,7 +1277,7 @@ def potential_charging_parks_from_oedb( def charging_processes_from_oedb( - edisgo_obj: EDisGo, engine: Engine, scenario: str, **kwargs + edisgo_obj: EDisGo, scenario: str, **kwargs ): """ Gets :attr:`~.network.electromobility.Electromobility.charging_processes_df` data @@ -1292,7 +1286,6 @@ def charging_processes_from_oedb( Parameters ---------- edisgo_obj : :class:`~.EDisGo` - engine : :sqlalchemy:`sqlalchemy.Engine` Database engine. scenario : str Scenario for which to retrieve data. Possible options are 'eGon2035' and @@ -1314,22 +1307,22 @@ def charging_processes_from_oedb( """ config = Config() egon_ev_mv_grid_district, egon_ev_trip = config.import_tables_from_oep( - engine, ["egon_ev_mv_grid_district", "egon_ev_trip"], "demand" + edisgo_obj.engine, ["egon_ev_mv_grid_district", "egon_ev_trip"], "demand" ) # get EV pool in grid scenario_variation = {"eGon2035": "NEP C 2035", "eGon100RE": "Reference 2050"} - with session_scope_egon_data(engine) as session: + with session_scope_egon_data(edisgo_obj.engine) as session: query = session.query(egon_ev_mv_grid_district.egon_ev_pool_ev_id).filter( egon_ev_mv_grid_district.scenario == scenario, egon_ev_mv_grid_district.scenario_variation == scenario_variation[scenario], egon_ev_mv_grid_district.bus_id == edisgo_obj.topology.id, ) - pool = Counter(pd.read_sql(sql=query.statement, con=engine).egon_ev_pool_ev_id) + pool = Counter(pd.read_sql(sql=query.statement, con=edisgo_obj.engine).egon_ev_pool_ev_id) # get charging processes for each EV ID - with session_scope_egon_data(engine) as session: + with session_scope_egon_data(edisgo_obj.engine) as session: query = session.query( egon_ev_trip.egon_ev_pool_ev_id.label("car_id"), egon_ev_trip.use_case, @@ -1347,7 +1340,7 @@ def charging_processes_from_oedb( ) if kwargs.get("mode_parking_times", "frugal") == "frugal": query = query.filter(egon_ev_trip.charging_demand > 0) - ev_trips_df = pd.read_sql(sql=query.statement, con=engine) + ev_trips_df = pd.read_sql(sql=query.statement, con=edisgo_obj.engine) # duplicate EVs that were chosen more than once from EV pool df_list = [] diff --git a/edisgo/io/generators_import.py b/edisgo/io/generators_import.py index cd4868c70..6c269c002 100755 --- a/edisgo/io/generators_import.py +++ b/edisgo/io/generators_import.py @@ -765,7 +765,6 @@ def scale_generators(gen_type, total_capacity): def oedb( edisgo_object: EDisGo, scenario: str, - engine: Engine, max_capacity=20, ): """ @@ -810,11 +809,10 @@ def oedb( Parameters ---------- edisgo_object : :class:`~.EDisGo` + The eDisGo API object. scenario : str Scenario for which to retrieve generator data. Possible options are "eGon2035" and "eGon100RE". - engine : :sqlalchemy:`sqlalchemy.Engine` - Database engine. max_capacity : float Maximum capacity in MW of power plants to retrieve from database. In general, the generators that are retrieved from the database are selected based on the @@ -834,7 +832,7 @@ def oedb( """ def _get_egon_power_plants(): - with session_scope_egon_data(engine) as session: + with session_scope_egon_data(edisgo_object.engine) as session: srid_table = get_srid_of_db_table(session, egon_power_plants.geom) query = ( session.query( @@ -854,7 +852,7 @@ def _get_egon_power_plants(): .order_by(egon_power_plants.id) ) power_plants_gdf = gpd.read_postgis( - sql=query.statement, con=engine, crs=f"EPSG:{srid_table}" + sql=query.statement, con=edisgo_object.engine, crs=f"EPSG:{srid_table}" ).to_crs(srid_edisgo) # rename wind_onshore to wind power_plants_gdf["type"] = power_plants_gdf["type"].str.replace("_onshore", "") @@ -885,7 +883,7 @@ def _get_egon_pv_rooftop(): # mapped to the MV grid they lie within and sometimes to the MV grid the zensus # cell is mapped to building_ids = edisgo_object.topology.loads_df.building_id.unique() - with session_scope_egon_data(engine) as session: + with session_scope_egon_data(edisgo_object.engine) as session: query = ( session.query( egon_power_plants_pv_roof_building.index.label("generator_id"), @@ -902,7 +900,7 @@ def _get_egon_pv_rooftop(): ) .order_by(egon_power_plants_pv_roof_building.index) ) - pv_roof_df = pd.read_sql(sql=query.statement, con=engine) + pv_roof_df = pd.read_sql(sql=query.statement, con=edisgo_object.engine) # add type and subtype pv_roof_df = pv_roof_df.assign( type="solar", @@ -911,7 +909,7 @@ def _get_egon_pv_rooftop(): return pv_roof_df def _get_egon_chp_plants(): - with session_scope_egon_data(engine) as session: + with session_scope_egon_data(edisgo_object.engine) as session: srid_table = get_srid_of_db_table(session, egon_chp_plants.geom) query = ( session.query( @@ -943,7 +941,7 @@ def _get_egon_chp_plants(): egon_power_plants, egon_power_plants_pv_roof_building, ) = config.import_tables_from_oep( - engine, + edisgo_object.engine, ["egon_chp_plants", "egon_power_plants", "egon_power_plants_pv_roof_building"], "supply", ) diff --git a/edisgo/io/heat_pump_import.py b/edisgo/io/heat_pump_import.py index f57622911..09742198e 100644 --- a/edisgo/io/heat_pump_import.py +++ b/edisgo/io/heat_pump_import.py @@ -20,7 +20,7 @@ logger = logging.getLogger(__name__) -def oedb(edisgo_object, scenario, engine, import_types=None): +def oedb(edisgo_object, scenario, import_types=None): """ Gets heat pumps for specified scenario from oedb and integrates them into the grid. @@ -32,8 +32,6 @@ def oedb(edisgo_object, scenario, engine, import_types=None): scenario : str Scenario for which to retrieve heat pump data. Possible options are "eGon2035" and "eGon100RE". - engine : :sqlalchemy:`sqlalchemy.Engine` - Database engine. import_types : list(str) or None Specifies which technologies to import. Possible options are "individual_heat_pumps", "central_heat_pumps" and "central_resistive_heaters". @@ -88,7 +86,7 @@ def _get_individual_heat_pumps(): ) ) - df = pd.read_sql(query.statement, engine, index_col=None) + df = pd.read_sql(query.statement, edisgo_object.engine, index_col=None) # drop duplicated building IDs that exist because # egon_map_zensus_mvgd_buildings can contain several entries per building, @@ -148,7 +146,7 @@ def _get_central_heat_pump_or_resistive_heaters( egon_etrago_link.p_nom <= edisgo_object.config["grid_connection"]["upper_limit_voltage_level_4"], ) - df = pd.read_sql(query.statement, engine, index_col=None) + df = pd.read_sql(query.statement, edisgo_object.engine, index_col=None) if not df.empty: # Query for egon_etrago_bus srid_etrago_bus = db.get_srid_of_db_table(session, egon_etrago_bus.geom) @@ -163,7 +161,7 @@ def _get_central_heat_pump_or_resistive_heaters( ) gdf_etrago_bus = gpd.read_postgis( query_etrago_bus.statement, - engine, + edisgo_object.engine, index_col=None, crs=f"EPSG:{srid_etrago_bus}", ).to_crs(mv_grid_geom_srid) @@ -175,7 +173,7 @@ def _get_central_heat_pump_or_resistive_heaters( ) gdf_weather_cells = gpd.read_postgis( query_weather_cells.statement, - engine, + edisgo_object.engine, index_col=None, crs=f"EPSG:{edisgo_object.topology.grid_district['srid']}", ).to_crs(mv_grid_geom_srid) @@ -194,7 +192,7 @@ def _get_central_heat_pump_or_resistive_heaters( gdf_district_heating_areas = gpd.read_postgis( query_district_heating_areas.statement, - engine, + edisgo_object.engine, geom_col="geom_polygon", index_col=None, crs=f"EPSG:{srid}", @@ -242,7 +240,7 @@ def _get_central_heat_pump_or_resistive_heaters( ) df_geom_chp = gpd.read_postgis( query.statement, - engine, + edisgo_object.engine, index_col=None, crs=f"EPSG:{srid_dh_supply}", ).to_crs(mv_grid_geom_srid) @@ -307,14 +305,14 @@ def _get_individual_heat_pump_capacity(): egon_district_heating_areas, egon_hp_capacity_buildings, ) = config.import_tables_from_oep( - engine, ["egon_district_heating_areas", "egon_hp_capacity_buildings"], "demand" + edisgo_object.engine, ["egon_district_heating_areas", "egon_hp_capacity_buildings"], "demand" ) ( egon_district_heating, egon_era5_weather_cells, egon_individual_heating, ) = config.import_tables_from_oep( - engine, + edisgo_object.engine, ["egon_district_heating", "egon_era5_weather_cells", "egon_individual_heating"], "supply", ) @@ -322,12 +320,12 @@ def _get_individual_heat_pump_capacity(): egon_map_zensus_mvgd_buildings, egon_map_zensus_weather_cell, ) = config.import_tables_from_oep( - engine, + edisgo_object.engine, ["egon_map_zensus_mvgd_buildings", "egon_map_zensus_weather_cell"], "boundaries", ) egon_etrago_bus, egon_etrago_link = config.import_tables_from_oep( - engine, ["egon_etrago_bus", "egon_etrago_link"], "supply" + edisgo_object.engine, ["egon_etrago_bus", "egon_etrago_link"], "supply" ) building_ids = edisgo_object.topology.loads_df.building_id.unique() @@ -342,7 +340,7 @@ def _get_individual_heat_pump_capacity(): # get individual and district heating heat pumps, as well as resistive heaters # in district heating - with db.session_scope_egon_data(engine) as session: + with db.session_scope_egon_data(edisgo_object.engine) as session: if "individual_heat_pumps" in import_types: hp_individual = _get_individual_heat_pumps() else: @@ -363,7 +361,7 @@ def _get_individual_heat_pump_capacity(): resistive_heaters_central = pd.DataFrame(columns=["p_set"]) # sanity check - with db.session_scope_egon_data(engine) as session: + with db.session_scope_egon_data(edisgo_object.engine) as session: hp_individual_cap = _get_individual_heat_pump_capacity() if not np.isclose(hp_individual_cap, hp_individual.p_set.sum(), atol=1e-3): logger.warning( @@ -624,7 +622,7 @@ def _grid_integration( return integrated_hps -def efficiency_resistive_heaters_oedb(scenario, engine): +def efficiency_resistive_heaters_oedb(scenario, edisgo_object): """ Get efficiency of resistive heaters from the `OpenEnergy DataBase `_. @@ -634,8 +632,8 @@ def efficiency_resistive_heaters_oedb(scenario, engine): scenario : str Scenario for which to retrieve efficiency data. Possible options are "eGon2035" and "eGon100RE". - engine : :sqlalchemy:`sqlalchemy.Engine` - Database engine. + edisgo_object : :class:`~.EDisGo` + The eDisGo API object. Returns ------- @@ -650,11 +648,11 @@ def efficiency_resistive_heaters_oedb(scenario, engine): """ config = Config() (egon_scenario_parameters,) = config.import_tables_from_oep( - engine, ["egon_scenario_parameters"], "scenario" + edisgo_object.engine, ["egon_scenario_parameters"], "scenario" ) # get cop from database - with db.session_scope_egon_data(engine) as session: + with db.session_scope_egon_data(edisgo_object.engine) as session: query = session.query( egon_scenario_parameters.heat_parameters, ).filter(egon_scenario_parameters.name == scenario) diff --git a/edisgo/io/storage_import.py b/edisgo/io/storage_import.py index 2ba1716cf..6064b4a6d 100644 --- a/edisgo/io/storage_import.py +++ b/edisgo/io/storage_import.py @@ -25,7 +25,6 @@ def home_batteries_oedb( edisgo_obj: EDisGo, scenario: str, - engine: Engine, ): """ Gets home battery data from oedb and integrates them into the grid. @@ -38,8 +37,6 @@ def home_batteries_oedb( scenario : str Scenario for which to retrieve home battery data. Possible options are "eGon2035" and "eGon100RE". - engine : :sqlalchemy:`sqlalchemy.Engine` - Database engine. Returns -------- @@ -51,10 +48,10 @@ def home_batteries_oedb( """ config = Config() (egon_home_batteries,) = config.import_tables_from_oep( - engine, ["egon_home_batteries"], "supply" + edisgo_obj.engine, ["egon_home_batteries"], "supply" ) - with session_scope_egon_data(engine) as session: + with session_scope_egon_data(edisgo_obj.engine) as session: query = ( session.query( egon_home_batteries.building_id, @@ -71,7 +68,7 @@ def home_batteries_oedb( ) .order_by(egon_home_batteries.index) ) - batteries_df = pd.read_sql(sql=query.statement, con=engine, index_col=None) + batteries_df = pd.read_sql(sql=query.statement, con=edisgo_obj.engine, index_col=None) return _home_batteries_grid_integration(edisgo_obj, batteries_df) diff --git a/edisgo/io/timeseries_import.py b/edisgo/io/timeseries_import.py index 914ac13fc..6e93558e9 100644 --- a/edisgo/io/timeseries_import.py +++ b/edisgo/io/timeseries_import.py @@ -153,7 +153,6 @@ def _retrieve_timeseries_from_oedb(session): def feedin_oedb( edisgo_object, - engine: Engine, timeindex=None, ): """ @@ -162,9 +161,8 @@ def feedin_oedb( Parameters ---------- - edisgo_obj : :class:`~.EDisGo` - engine : :sqlalchemy:`sqlalchemy.Engine` - Database engine. + edisgo_object : :class:`~.EDisGo` + The eDisGo API object. timeindex : :pandas:`pandas.DatetimeIndex` or None Specifies time steps for which to return feed-in data. Leap years can currently not be handled. In case the given timeindex contains a leap year, the data will @@ -184,15 +182,15 @@ def feedin_oedb( """ # get weather cell IDs in grid weather_cell_ids = tools.get_weather_cells_intersecting_with_grid_district( - edisgo_object, engine=engine + edisgo_object ) config = Config() (egon_era5_renewable_feedin,) = config.import_tables_from_oep( - engine, ["egon_era5_renewable_feedin"], "supply" + edisgo_object.engine, ["egon_era5_renewable_feedin"], "supply" ) - with session_scope_egon_data(engine) as session: + with session_scope_egon_data(edisgo_object.engine) as session: query = ( session.query( egon_era5_renewable_feedin.w_id.label("weather_cell_id"), @@ -207,7 +205,7 @@ def feedin_oedb( egon_era5_renewable_feedin.w_id, egon_era5_renewable_feedin.carrier ) ) - feedin_df = pd.read_sql(sql=query.statement, con=engine) + feedin_df = pd.read_sql(sql=query.statement, con=edisgo_object.engine) # rename pv to solar and wind_onshore to wind feedin_df.carrier = feedin_df.carrier.str.replace("pv", "solar").str.replace( @@ -322,7 +320,7 @@ def load_time_series_demandlib(edisgo_obj, timeindex=None): return elec_demand.loc[timeindex] -def cop_oedb(edisgo_object, engine, weather_cell_ids, timeindex=None): +def cop_oedb(edisgo_object, weather_cell_ids, timeindex=None): """ Get COP (coefficient of performance) time series data from the `OpenEnergy DataBase `_. @@ -330,8 +328,7 @@ def cop_oedb(edisgo_object, engine, weather_cell_ids, timeindex=None): Parameters ---------- edisgo_object : :class:`~.EDisGo` - engine : :sqlalchemy:`sqlalchemy.Engine` - Database engine. + The eDisGo API object. weather_cell_ids : list(int) or list(float) List (or array) of weather cell IDs to obtain COP data for. timeindex : :pandas:`pandas.DatetimeIndex` or None @@ -358,11 +355,11 @@ def cop_oedb(edisgo_object, engine, weather_cell_ids, timeindex=None): config = Config() (egon_era5_renewable_feedin,) = config.import_tables_from_oep( - engine, ["egon_era5_renewable_feedin"], "supply" + edisgo_object.engine, ["egon_era5_renewable_feedin"], "supply" ) # get cop from database - with session_scope_egon_data(engine) as session: + with session_scope_egon_data(edisgo_object.engine) as session: query = ( session.query( egon_era5_renewable_feedin.w_id, @@ -372,7 +369,7 @@ def cop_oedb(edisgo_object, engine, weather_cell_ids, timeindex=None): .filter(egon_era5_renewable_feedin.w_id.in_(weather_cell_ids)) ) - cop = pd.read_sql(query.statement, engine, index_col="w_id") + cop = pd.read_sql(query.statement, edisgo_object.engine, index_col="w_id") # convert dataframe to have weather cell ID as column name and time index cop = pd.DataFrame( @@ -382,7 +379,7 @@ def cop_oedb(edisgo_object, engine, weather_cell_ids, timeindex=None): return cop.loc[timeindex, :] -def heat_demand_oedb(edisgo_obj, scenario, engine, timeindex=None): +def heat_demand_oedb(edisgo_obj, scenario, timeindex=None): """ Get heat demand profiles for heat pumps from the `OpenEnergy DataBase `_. @@ -397,11 +394,10 @@ def heat_demand_oedb(edisgo_obj, scenario, engine, timeindex=None): Parameters ---------- edisgo_obj : :class:`~.EDisGo` + The eDisGo API object. scenario : str Scenario for which to retrieve demand data. Possible options are 'eGon2035' and 'eGon100RE'. - engine : :sqlalchemy:`sqlalchemy.Engine` - Database engine. timeindex : :pandas:`pandas.DatetimeIndex` or None Specifies time steps for which to return data. Leap years can currently not be handled. In case the given timeindex contains a leap year, the data will @@ -447,10 +443,10 @@ def heat_demand_oedb(edisgo_obj, scenario, engine, timeindex=None): building_ids = pth_ind_df.building_id.dropna().unique() if len(building_ids) > 0: residential_profiles_df = get_residential_heat_profiles_per_building( - building_ids, scenario, engine + building_ids, scenario, edisgo_obj.engine ) cts_profiles_df = get_cts_profiles_per_building( - edisgo_obj, scenario, "heat", engine + edisgo_obj, scenario, "heat" ) # drop CTS profiles for buildings without a heat pump buildings_no_hp = [_ for _ in cts_profiles_df.columns if _ not in building_ids] @@ -484,7 +480,7 @@ def heat_demand_oedb(edisgo_obj, scenario, engine, timeindex=None): dh_ids = [] if len(dh_ids) > 0: dh_profile_df = get_district_heating_heat_demand_profiles( - dh_ids, scenario, engine + dh_ids, scenario, edisgo_obj.engine ) # set column names to be heat pump names instead of district heating IDs dh_profile_df = pd.DataFrame( @@ -502,7 +498,7 @@ def heat_demand_oedb(edisgo_obj, scenario, engine, timeindex=None): def electricity_demand_oedb( - edisgo_obj, scenario, engine, timeindex=None, load_names=None + edisgo_obj, scenario, timeindex=None, load_names=None ): """ Get electricity demand profiles for all conventional loads from the @@ -518,11 +514,10 @@ def electricity_demand_oedb( Parameters ---------- edisgo_obj : :class:`~.EDisGo` + The eDisGo API object. scenario : str Scenario for which to retrieve demand data. Possible options are 'eGon2035' and 'eGon100RE'. - engine : :sqlalchemy:`sqlalchemy.Engine` - Database engine. timeindex : :pandas:`pandas.DatetimeIndex` or None Specifies time steps for which to return data. Leap years can currently not be handled. In case the given timeindex contains a leap year, the data will @@ -573,7 +568,7 @@ def electricity_demand_oedb( res_building_ids = residential_loads.building_id.dropna().unique() if len(res_building_ids) > 0: residential_profiles_df = get_residential_electricity_profiles_per_building( - res_building_ids, scenario, engine + res_building_ids, scenario, edisgo_obj.engine ) rename_series = ( residential_loads.loc[:, ["building_id"]] @@ -592,7 +587,7 @@ def electricity_demand_oedb( cts_building_ids = cts_loads.building_id.dropna().unique() if len(cts_building_ids) > 0: cts_profiles_df = get_cts_profiles_per_building( - edisgo_obj, scenario, "electricity", engine + edisgo_obj, scenario, "electricity" ) drop_buildings = [ _ for _ in cts_profiles_df.columns if _ not in cts_building_ids @@ -616,7 +611,7 @@ def electricity_demand_oedb( ind_building_ids = ind_loads.building_id.dropna().unique() if len(ind_building_ids) > 0: ind_profiles_df = get_industrial_electricity_profiles_per_site( - ind_building_ids, scenario, engine + ind_building_ids, scenario, edisgo_obj.engine ) # set column names to be load names instead of building IDs rename_series = ( @@ -962,7 +957,7 @@ def get_district_heating_heat_demand_profiles(district_heating_ids, scenario, en return df.astype("float") -def get_cts_profiles_per_building(edisgo_obj, scenario, sector, engine): +def get_cts_profiles_per_building(edisgo_obj, scenario, sector): """ Gets CTS heat demand profiles per CTS building for all CTS buildings in MV grid. @@ -979,13 +974,12 @@ def get_cts_profiles_per_building(edisgo_obj, scenario, sector, engine): Parameters ---------- edisgo_obj : :class:`~.EDisGo` + The eDisGo API object. scenario : str Scenario for which to retrieve demand data. Possible options are 'eGon2035' and 'eGon100RE'. sector : str - Demand sector for which profile is calculated: "electricity" or "heat" - engine : :sqlalchemy:`sqlalchemy.Engine` - Database engine. + Demand sector for which profile is calculated: "electricity" or "heat". Returns ------- @@ -997,7 +991,7 @@ def get_cts_profiles_per_building(edisgo_obj, scenario, sector, engine): """ config = Config() (egon_map_zensus_mvgd_buildings,) = config.import_tables_from_oep( - engine, ["egon_map_zensus_mvgd_buildings"], "boundaries" + edisgo_obj.engine, ["egon_map_zensus_mvgd_buildings"], "boundaries" ) # get MV grid IDs of CTS loads @@ -1006,20 +1000,20 @@ def get_cts_profiles_per_building(edisgo_obj, scenario, sector, engine): & (edisgo_obj.topology.loads_df.sector == "cts") ] cts_building_ids = cts_loads.building_id.dropna().unique() - with session_scope_egon_data(engine) as session: + with session_scope_egon_data(edisgo_obj.engine) as session: query = session.query( egon_map_zensus_mvgd_buildings.building_id, egon_map_zensus_mvgd_buildings.bus_id, ).filter( egon_map_zensus_mvgd_buildings.building_id.in_(cts_building_ids), ) - df = pd.read_sql(query.statement, engine, index_col="building_id") + df = pd.read_sql(query.statement, edisgo_obj.engine, index_col="building_id") # iterate over grid IDs profiles_df = pd.DataFrame() for bus_id in df.bus_id.unique(): profiles_grid_df = get_cts_profiles_per_grid( - bus_id=bus_id, scenario=scenario, sector=sector, engine=engine + bus_id=bus_id, scenario=scenario, sector=sector, engine=edisgo_obj.engine ) profiles_df = pd.concat([profiles_df, profiles_grid_df], axis=1) diff --git a/edisgo/network/heat.py b/edisgo/network/heat.py index 47356ec4c..22c4ba47d 100644 --- a/edisgo/network/heat.py +++ b/edisgo/network/heat.py @@ -166,8 +166,7 @@ def set_cop(self, edisgo_object, ts_cop, **kwargs): information, a random existing weather cell is used to fill missing information. - This option requires that the parameter `engine` is provided as keyword - argument. For further settings, the parameters `timeindex` and + For further settings, the parameters `timeindex` and `heat_pump_names` can also be provided as keyword arguments. * :pandas:`pandas.DataFrame` @@ -177,8 +176,6 @@ def set_cop(self, edisgo_object, ts_cop, **kwargs): Other Parameters ------------------ - engine : :sqlalchemy:`sqlalchemy.Engine` - Database engine. This parameter is required in case `ts_cop` is 'oedb'. heat_pump_names : list(str) or None Defines for which heat pumps to set COP time series in case `ts_cop` is 'oedb'. If None, all heat pumps in @@ -246,7 +243,6 @@ def set_cop(self, edisgo_object, ts_cop, **kwargs): # get COP per weather cell ts_cop_per_weather_cell = timeseries_import.cop_oedb( edisgo_object=edisgo_object, - engine=kwargs.get("engine", None), weather_cell_ids=weather_cells, timeindex=kwargs.get("timeindex", None), ) @@ -275,7 +271,7 @@ def set_cop(self, edisgo_object, ts_cop, **kwargs): # get efficiencies of resistive heaters eta_dict = heat_pump_import.efficiency_resistive_heaters_oedb( scenario="eGon2035", # currently only possible scenario - engine=kwargs.get("engine", None), + edisgo_object=edisgo_object, ) # determine timeindex to use if not cop_df.empty: @@ -341,8 +337,8 @@ def set_heat_demand(self, edisgo_object, ts_heat_demand, **kwargs): information). Time series are only obtained for heat pumps that are already integrated into the grid. - This option requires that the parameters `engine` and `scenario` are - provided as keyword arguments. For further settings, the parameters + This parameter requires that the parameter `scenario` is + provided as keyword argument. For further settings, the parameters `timeindex` and `heat_pump_names` can also be provided as keyword arguments. @@ -358,9 +354,6 @@ def set_heat_demand(self, edisgo_object, ts_heat_demand, **kwargs): Scenario for which to retrieve heat demand data. This parameter is required in case `ts_heat_demand` is 'oedb'. Possible options are 'eGon2035' and 'eGon100RE'. - engine : :sqlalchemy:`sqlalchemy.Engine` - Database engine. This parameter is required in case `ts_heat_demand` is - 'oedb'. heat_pump_names : list(str) or None Defines for which heat pumps to get heat demand time series for in case `ts_heat_demand` is 'oedb'. If None, all heat pumps in @@ -392,7 +385,6 @@ def set_heat_demand(self, edisgo_object, ts_heat_demand, **kwargs): heat_demand_df = timeseries_import.heat_demand_oedb( edisgo_object, scenario=kwargs.get("scenario", ""), - engine=kwargs.get("engine", None), timeindex=kwargs.get("timeindex", None), ) heat_pump_names_select = [ diff --git a/edisgo/network/timeseries.py b/edisgo/network/timeseries.py index 6cf4a7b47..a783082bb 100644 --- a/edisgo/network/timeseries.py +++ b/edisgo/network/timeseries.py @@ -1183,7 +1183,6 @@ def predefined_fluctuating_generators_by_technology( ts_generators, generator_names=None, timeindex=None, - engine=None, ): """ Set active power feed-in time series for fluctuating generators by technology. @@ -1207,9 +1206,7 @@ def predefined_fluctuating_generators_by_technology( `_. See :func:`edisgo.io.timeseries_import.feedin_oedb` for more information. - This option requires that the parameter `engine` is provided in case - new ding0 grids with geo-referenced LV grids are used. For further - settings, the parameter `timeindex` can also be provided. + For further settings, the parameter `timeindex` can also be provided. * :pandas:`pandas.DataFrame` @@ -1244,10 +1241,6 @@ def predefined_fluctuating_generators_by_technology( Specifies time steps for which to set feed-in time series. This parameter is only used in case `ts_generators` is 'oedb'. See parameter `timeindex` in :func:`edisgo.io.timeseries_import.feedin_oedb` for more information. - engine : :sqlalchemy:`sqlalchemy.Engine` - Database engine. This parameter is only required in case - `ts_generators` is 'oedb' and new ding0 grids with geo-referenced LV grids - are used. """ # in case time series from oedb are used, retrieve oedb time series @@ -1258,7 +1251,7 @@ def predefined_fluctuating_generators_by_technology( ) else: ts_generators = timeseries_import.feedin_oedb( - edisgo_object, engine=engine, timeindex=timeindex + edisgo_object, timeindex=timeindex ) elif not isinstance(ts_generators, pd.DataFrame): raise ValueError( diff --git a/edisgo/tools/tools.py b/edisgo/tools/tools.py index 66353c55d..49a8d0ba7 100644 --- a/edisgo/tools/tools.py +++ b/edisgo/tools/tools.py @@ -722,6 +722,7 @@ def get_weather_cells_intersecting_with_grid_district( edisgo_obj : :class:`~.EDisGo` engine : :sqlalchemy:`sqlalchemy.Engine` Database engine. Only needed when using new egon_data data. + Deprecated - will be removed in a future version. Use edisgo_obj.engine instead. Returns ------- @@ -729,6 +730,10 @@ def get_weather_cells_intersecting_with_grid_district( Set with weather cell IDs. """ + # Use engine from edisgo_obj if not provided (for backwards compatibility) + if engine is None: + engine = edisgo_obj.engine + # Download geometries of weather cells sql_geom = sql_grid_geom(edisgo_obj) srid = edisgo_obj.topology.grid_district["srid"] diff --git a/tests/conftest.py b/tests/conftest.py index 93327ea66..a757886af 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -33,7 +33,7 @@ def pytest_configure(config): "/home/jonas/.ssh/egon-data.configuration.yaml", ) - pytest.engine = engine() + pytest.engine = engine(path=pytest.egon_data_config_yml, ssh=True) config.addinivalue_line("markers", "slow: mark test as slow to run") config.addinivalue_line("markers", "local: mark test as local to run") diff --git a/tests/io/test_dsm_import.py b/tests/io/test_dsm_import.py index d2f595e6d..5770c4560 100644 --- a/tests/io/test_dsm_import.py +++ b/tests/io/test_dsm_import.py @@ -8,10 +8,10 @@ class TestDSMImport: def test_oedb(self): # test without industrial load edisgo_object = EDisGo( - ding0_grid=pytest.ding0_test_network_3_path, legacy_ding0_grids=False + ding0_grid=pytest.ding0_test_network_3_path, legacy_ding0_grids=False, engine=pytest.engine ) dsm_profiles = dsm_import.oedb( - edisgo_object, scenario="eGon2035", engine=pytest.engine + edisgo_object, scenario="eGon2035" ) for dsm_profile in ["e_max", "e_min", "p_max", "p_min"]: assert dsm_profiles[dsm_profile].shape == (8760, 87) @@ -29,7 +29,7 @@ def test_oedb(self): edisgo_object.topology.loads_df.at[dsm_load, "building_id"] = 1 dsm_profiles = dsm_import.oedb( - edisgo_object, scenario="eGon2035", engine=pytest.engine + edisgo_object, scenario="eGon2035" ) for dsm_profile in ["e_max", "e_min", "p_max", "p_min"]: assert dsm_profiles[dsm_profile].shape == (8760, 87) @@ -58,10 +58,10 @@ def test_get_profiles_per_industrial_load(self): def test_get_profile_cts(self): edisgo = EDisGo( - ding0_grid=pytest.ding0_test_network_3_path, legacy_ding0_grids=False + ding0_grid=pytest.ding0_test_network_3_path, legacy_ding0_grids=False, engine=pytest.engine ) dsm_profiles = dsm_import.get_profile_cts( - edisgo_obj=edisgo, scenario="eGon2035", engine=pytest.engine + edisgo_obj=edisgo, scenario="eGon2035" ) for dsm_profile in ["e_max", "e_min", "p_max", "p_min"]: assert dsm_profiles[dsm_profile].shape == (8760, 85) diff --git a/tests/io/test_electromobility_import.py b/tests/io/test_electromobility_import.py index f4c67eb38..d21618751 100644 --- a/tests/io/test_electromobility_import.py +++ b/tests/io/test_electromobility_import.py @@ -205,7 +205,7 @@ def test_potential_charging_parks_from_oedb(self): ding0_grid=pytest.ding0_test_network_3_path, legacy_ding0_grids=False ) potential_parks_df = electromobility_import.potential_charging_parks_from_oedb( - edisgo_obj=edisgo_obj, engine=pytest.engine + edisgo_obj=edisgo_obj ) assert len(potential_parks_df) == 1083 # check for random charging points if they are within MV grid district @@ -218,7 +218,7 @@ def test_charging_processes_from_oedb(self): ding0_grid=pytest.ding0_test_network_3_path, legacy_ding0_grids=False ) charging_processes_df = electromobility_import.charging_processes_from_oedb( - edisgo_obj=edisgo_obj, engine=pytest.engine, scenario="eGon2035" + edisgo_obj=edisgo_obj, scenario="eGon2035" ) assert len(charging_processes_df.car_id.unique()) == 1604 assert len(charging_processes_df) == 324117 diff --git a/tests/io/test_generators_import.py b/tests/io/test_generators_import.py index 781e27c49..0de78079a 100644 --- a/tests/io/test_generators_import.py +++ b/tests/io/test_generators_import.py @@ -21,7 +21,7 @@ class TestGeneratorsImport: @pytest.yield_fixture(autouse=True) def setup_class(self): - self.edisgo = EDisGo(ding0_grid=pytest.ding0_test_network_path) + self.edisgo = EDisGo(ding0_grid=pytest.ding0_test_network_path, engine=pytest.engine) self.edisgo.set_time_series_worst_case_analysis() def test_update_grids(self): @@ -714,5 +714,5 @@ def test_oedb(self): edisgo = EDisGo( ding0_grid=pytest.ding0_test_network_3_path, legacy_ding0_grids=False ) - edisgo.import_generators(generator_scenario="eGon2035", engine=pytest.engine) + edisgo.import_generators(generator_scenario="eGon2035") assert len(edisgo.topology.generators_df) == 677 diff --git a/tests/io/test_heat_pump_import.py b/tests/io/test_heat_pump_import.py index 68fb6d059..90bad2cac 100644 --- a/tests/io/test_heat_pump_import.py +++ b/tests/io/test_heat_pump_import.py @@ -15,7 +15,7 @@ class TestHeatPumpImport: @pytest.fixture(autouse=True) def setup_class(self): self.edisgo = EDisGo( - ding0_grid=pytest.ding0_test_network_3_path, legacy_ding0_grids=False + ding0_grid=pytest.ding0_test_network_3_path, legacy_ding0_grids=False, engine=pytest.engine ) def setup_heat_pump_data_individual_heating(self): @@ -60,7 +60,7 @@ def setup_resistive_heater_data_dh(self): def test_oedb(self, caplog): with caplog.at_level(logging.DEBUG): heat_pump_import.oedb( - self.edisgo, scenario="eGon2035", engine=pytest.engine + self.edisgo, scenario="eGon2035" ) loads_df = self.edisgo.topology.loads_df hp_df = loads_df[loads_df.type == "heat_pump"] @@ -87,7 +87,6 @@ def test_oedb(self, caplog): heat_pump_import.oedb( self.edisgo, scenario="eGon2035", - engine=pytest.engine, import_types=["central_heat_pumps"], ) loads_df = self.edisgo.topology.loads_df @@ -197,7 +196,7 @@ def test__grid_integration(self, caplog): def test_efficiency_resistive_heaters_oedb(self): eta_dict = heat_pump_import.efficiency_resistive_heaters_oedb( - scenario="eGon2035", engine=pytest.engine + scenario="eGon2035", edisgo_object=self.edisgo ) assert eta_dict["central_resistive_heater"] == 0.99 assert eta_dict["rural_resistive_heater"] == 0.9 diff --git a/tests/io/test_storage_import.py b/tests/io/test_storage_import.py index 941cdc62e..d1c66dac1 100644 --- a/tests/io/test_storage_import.py +++ b/tests/io/test_storage_import.py @@ -12,7 +12,7 @@ class TestStorageImport: @pytest.fixture(autouse=True) def setup_class(self): self.edisgo = EDisGo( - ding0_grid=pytest.ding0_test_network_3_path, legacy_ding0_grids=False + ding0_grid=pytest.ding0_test_network_3_path, legacy_ding0_grids=False, engine=pytest.engine ) def setup_home_batteries_data(self): @@ -30,7 +30,7 @@ def test_oedb(self, caplog): # test without new PV rooftop plants with caplog.at_level(logging.DEBUG): integrated_storages = storage_import.home_batteries_oedb( - self.edisgo, scenario="eGon2035", engine=pytest.engine + self.edisgo, scenario="eGon2035" ) storage_df = self.edisgo.topology.storage_units_df assert len(integrated_storages) == 666 @@ -48,11 +48,11 @@ def test_oedb(self, caplog): ding0_grid=pytest.ding0_test_network_3_path, legacy_ding0_grids=False ) self.edisgo.import_generators( - generator_scenario="eGon2035", engine=pytest.engine + generator_scenario="eGon2035" ) with caplog.at_level(logging.DEBUG): integrated_storages = storage_import.home_batteries_oedb( - self.edisgo, scenario="eGon2035", engine=pytest.engine + self.edisgo, scenario="eGon2035" ) storage_df = self.edisgo.topology.storage_units_df assert len(integrated_storages) == 666 diff --git a/tests/io/test_timeseries_import.py b/tests/io/test_timeseries_import.py index ca0cef72a..9a182bdae 100644 --- a/tests/io/test_timeseries_import.py +++ b/tests/io/test_timeseries_import.py @@ -80,7 +80,6 @@ def test_feedin_oedb(self): edisgo_object.set_timeindex(timeindex) feedin_df = timeseries_import.feedin_oedb( edisgo_object, - engine=pytest.engine, ) assert feedin_df.shape == (6, 4) assert_index_equal(feedin_df.index, timeindex) @@ -105,7 +104,7 @@ def test_load_time_series_demandlib(self): def test_cop_oedb(self): edisgo = EDisGo(ding0_grid=pytest.ding0_test_network_path) cop_df = timeseries_import.cop_oedb( - edisgo_object=edisgo, engine=pytest.engine, weather_cell_ids=[11051, 11052] + edisgo_object=edisgo, weather_cell_ids=[11051, 11052] ) assert cop_df.shape == (8760, 2) assert (cop_df > 1.0).all().all() diff --git a/tests/network/test_heat.py b/tests/network/test_heat.py index 6ed384bef..5f6285ffc 100644 --- a/tests/network/test_heat.py +++ b/tests/network/test_heat.py @@ -114,7 +114,6 @@ def test_set_cop_oedb(self, caplog): edisgo_object.heat_pump.set_cop( edisgo_object, "oedb", - engine=pytest.engine, heat_pump_names=edisgo_object.topology.loads_df.index[0:4], ) @@ -125,7 +124,6 @@ def test_set_cop_oedb(self, caplog): edisgo_object.heat_pump.set_cop( edisgo_object, "oedb", - engine=pytest.engine, heat_pump_names=edisgo_object.topology.loads_df.index[0:4], ) @@ -133,7 +131,6 @@ def test_set_cop_oedb(self, caplog): edisgo_object.heat_pump.set_cop( edisgo_object, "oedb", - engine=pytest.engine, heat_pump_names=[], ) assert edisgo_object.heat_pump.cop_df.empty @@ -151,7 +148,6 @@ def test_set_cop_oedb(self, caplog): edisgo_object.heat_pump.set_cop( edisgo_object, "oedb", - engine=pytest.engine, heat_pump_names=heat_pump_names, ) assert "There are heat pumps with no weather cell ID." in caplog.text @@ -222,7 +218,6 @@ def test_set_heat_demand_oedb(self): edisgo_object.heat_pump.set_heat_demand( edisgo_object, "oedb", - engine=pytest.engine, scenario="eGon2035", ) assert edisgo_object.heat_pump.heat_demand_df.shape == (8760, 5) @@ -237,7 +232,6 @@ def test_set_heat_demand_oedb(self): edisgo_object.heat_pump.set_heat_demand( edisgo_object, "oedb", - engine=pytest.engine, scenario="eGon2035", heat_pump_names=["HP_442081", "HP_dummy"], ) @@ -248,7 +242,6 @@ def test_set_heat_demand_oedb(self): edisgo_object.heat_pump.set_heat_demand( edisgo_object, "oedb", - engine=pytest.engine, scenario="eGon2035", heat_pump_names=[], ) diff --git a/tests/network/test_timeseries.py b/tests/network/test_timeseries.py index 76807a7f6..3b6ff38ec 100644 --- a/tests/network/test_timeseries.py +++ b/tests/network/test_timeseries.py @@ -1412,7 +1412,7 @@ def test_predefined_fluctuating_generators_by_technology_oedb(self): # ############# oedb, all generators (default) edisgo_object.timeseries.predefined_fluctuating_generators_by_technology( - edisgo_object, "oedb", engine=pytest.engine + edisgo_object, "oedb" ) # check shape diff --git a/tests/test_edisgo.py b/tests/test_edisgo.py index bbdbddfb5..acd262f97 100755 --- a/tests/test_edisgo.py +++ b/tests/test_edisgo.py @@ -267,7 +267,6 @@ def test_set_time_series_active_power_predefined_oedb(self): conventional_loads_ts="oedb", fluctuating_generators_ts="oedb", scenario="eGon2035", - engine=pytest.engine, timeindex=pd.date_range("1/1/2011 12:00", periods=2, freq="H"), conventional_loads_names=[ "Load_mvgd_33535_lvgd_1164210000_244_residential" @@ -1305,7 +1304,7 @@ def test_import_electromobility_oedb(self): # test with default parameters self.edisgo.import_electromobility( - data_source="oedb", scenario="eGon2035", engine=pytest.engine + data_source="oedb", scenario="eGon2035" ) assert len(self.edisgo.electromobility.charging_processes_df) == 324117 @@ -1361,13 +1360,11 @@ def test_import_heat_pumps(self): with pytest.raises(ValueError): edisgo_object.import_heat_pumps( scenario="eGon", - engine=pytest.engine, ) # ################# test with leap year ############# edisgo_object.import_heat_pumps( scenario="eGon2035", - engine=pytest.engine, timeindex=pd.date_range("1/1/2020", periods=2, freq="H"), import_types=["individual_heat_pumps", "central_heat_pumps"], )