Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
3e0b88f
Catch missing home battery efficiency within function
Feb 5, 2025
ae803f2
only set efficiency for relevant storage units
Feb 6, 2025
1292670
allow to use egon-data configuration files without setting up an ssh …
Feb 6, 2025
6abd429
Detect TOEP Database and Enable Translated Table Names
joda9 Feb 6, 2025
45e43f7
setup workshop jupyter notebook
Feb 11, 2025
427944c
Jupyter notebook LoMa Workshop
Feb 11, 2025
97e46f5
Merge branch 'bug/#450-bug-database-imports-not-working-ssh-tunnel-li…
Feb 11, 2025
b094b47
Merge remote-tracking branch 'origin/bug/#450-bug-database-imports-no…
Feb 11, 2025
6b58f58
bugfix wrong schema name in heat pump import
Feb 11, 2025
e2d80ab
adapt notebook to use hetzner db
Feb 11, 2025
4998b8d
fix wrong variable name
Feb 12, 2025
0029d01
make it possible to setup edisgo instance without connecting to oedb
Feb 12, 2025
1b4057a
only get table and schema mapping from db if loading data from (t)oep
Feb 12, 2025
a323903
adapt whatsnew
Feb 12, 2025
8f126a3
use provided engine in config.py
Feb 12, 2025
3bdb727
Fix missing timeindex in set_time_series_active_power_predefined
Feb 17, 2025
0f06d0f
Merge pull request #458 from openego/feature/#456-feature-set-default…
khelfen Feb 17, 2025
bb1f3b4
Overwrite timeindex if given timeindex differs from existing timeinde…
Feb 17, 2025
bad14a9
Merge pull request #459 from openego/feature/#456-feature-set-default…
khelfen Feb 17, 2025
aa075cc
add logging and correct timeindex variable handling
Feb 17, 2025
f5ed235
Merge pull request #460 from openego/feature/#456-feature-set-default…
khelfen Feb 17, 2025
f4253bf
Refactor test cases for improved readability and consistency
joda9 Feb 18, 2025
fa7ff54
updated tests with new warning text
joda9 Feb 18, 2025
76a93c8
Merge branch 'feature/use_TOEP_token' into bug/#450-bug-database-impo…
Feb 18, 2025
57aa264
Merge pull request #465 from openego/feature/#456-feature-set-default…
khelfen Feb 19, 2025
2400fb4
Merge branch 'feature/446-feature-improve-apply_reference_operation-c…
Feb 19, 2025
70b852e
Merge remote-tracking branch 'origin/bug/#450-bug-database-imports-no…
Feb 19, 2025
2fca51c
Refactor object copying in EDisGo class
Feb 19, 2025
dffa1f7
Merge pull request #468 from openego/bug/#450-bug-database-imports-no…
khelfen Feb 19, 2025
567770d
Jupyter Notebook for LoMa Workshop
Feb 18, 2025
426562c
Jupyter Notebook for LoMa Workshop
Feb 18, 2025
dfcf353
Pre-final Jupyter Notebook for LoMa Workshop Part 2
Feb 25, 2025
3eab631
Workshop date modified
Feb 25, 2025
f32abbc
Small changes
Feb 25, 2025
3da99f9
Workshop notebooks with and w/o solutions for 27th Feb
Feb 26, 2025
76e5e9d
Update Workshop Notebooks
Feb 26, 2025
e136f25
fix: rename default schema from 'dataset' to 'data' in Config class
Nov 3, 2025
2d4a434
comment out loading of switches dataframe in import_ding0_grid functi…
joda9 Nov 3, 2025
3df5d9d
feat: add active_power_p_max_pu method to scale generator time series…
joda9 Nov 3, 2025
c3bdf26
fix: initialize engine in get_weather_cells_intersecting_with_grid_di…
joda9 Nov 3, 2025
157bc3e
Merge branch 'project/411-LoMa' into project/LoMa
joda9 Nov 5, 2025
3e7dbbf
Updated TOEP functionallity
joda9 Nov 5, 2025
4ea9d8b
fix: update engine initialization to use toep egon_engine
Nov 5, 2025
bc669cd
Fix load scaling in predefined_conventional_loads_by_sector (issue #471)
nader-00 Nov 26, 2025
e1387c7
Allow custom Series/dict for line_color and node_color in plot_plotly…
nader-00 Nov 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion doc/whatsnew/v0-3-0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,7 @@ Changes
* Move function to assign feeder to Topology class and add methods to the Grid class to get information on the feeders `#360 <https://github.com/openego/eDisGo/pull/360>`_
* Added a storage operation strategy where the storage is charged when PV feed-in is higher than electricity demand of the household and discharged when electricity demand exceeds PV generation `#386 <https://github.com/openego/eDisGo/pull/386>`_
* Added an estimation of the voltage deviation over a cable when selecting a suitable cable to connect a new component `#411 <https://github.com/openego/eDisGo/pull/411>`_
* Added clipping of heat pump electrical power at its maximum value #428 <https://github.com/openego/eDisGo/pull/428>
* Added clipping of heat pump electrical power at its maximum value `#428 <https://github.com/openego/eDisGo/pull/428>`_
* Loading predefined time series now automatically sets the timeindex to the default year of the database if it is empty. `#457 <https://github.com/openego/eDisGo/pull/457>`_
* Made OEP database call optional in get_database_alias_dictionaries, allowing setup without OEP when using an alternative eGon-data database. `#451 <https://github.com/openego/eDisGo/pull/451>`_
* Fixed database import issues by addressing table naming assumptions and added support for external SSH tunneling in eGon-data configurations. `#451 <https://github.com/openego/eDisGo/pull/451>`_
2 changes: 1 addition & 1 deletion edisgo/config/config_opf_julia_default.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@

[julia_dir]

julia_bin = julia-1.1.0/bin
julia_bin = julia/bin
151 changes: 103 additions & 48 deletions edisgo/edisgo.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
)
from edisgo.io.heat_pump_import import oedb as import_heat_pumps_oedb
from edisgo.io.storage_import import home_batteries_oedb
from edisgo.io.timeseries_import import _timeindex_helper_func
from edisgo.network import timeseries
from edisgo.network.dsm import DSM
from edisgo.network.electromobility import Electromobility
Expand Down Expand Up @@ -71,6 +72,11 @@ class EDisGo:
----------
ding0_grid : :obj:`str`
Path to directory containing csv files of network to be loaded.
engine : :sqlalchemy:`sqlalchemy.Engine<sqlalchemy.engine.Engine>` or None
Database engine for connecting to the `OpenEnergy DataBase OEDB
<https://openenergyplatform.org/dataedit/schemas>`_ or other eGon-data
databases. Defaults to the OEDB engine. Can be set to None if no scenario is to
be loaded.
generator_scenario : None or :obj:`str`, optional
If None, the generator park of the imported grid is kept as is.
Otherwise defines which scenario of future generator park to use
Expand Down Expand Up @@ -158,8 +164,10 @@ class EDisGo:
"""

def __init__(self, **kwargs):
# Set database engine for future scenarios
self.engine: Engine | None = kwargs.pop("engine", egon_engine())
# load configuration
self._config = Config(**kwargs)
self._config = Config(engine=self.engine, **kwargs)

# instantiate topology object and load grid data
self.topology = Topology(config=self.config)
Expand Down Expand Up @@ -418,12 +426,9 @@ def set_time_series_active_power_predefined(
Technology- and weather cell-specific hourly feed-in time series are
obtained from the
`OpenEnergy DataBase
<https://openenergyplatform.org/dataedit/schemas>`_. 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.
<https://openenergyplatform.org/dataedit/schemas>`_ or other eGon-data
databases. See :func:`edisgo.io.timeseries_import.feedin_oedb` for more
information.

* :pandas:`pandas.DataFrame<DataFrame>`

Expand Down Expand Up @@ -536,9 +541,6 @@ def set_time_series_active_power_predefined(

Other Parameters
------------------
engine : :sqlalchemy:`sqlalchemy.Engine<sqlalchemy.engine.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
Expand All @@ -556,15 +558,42 @@ def set_time_series_active_power_predefined(
is indexed using a default year and set for the whole year.

"""
timeindex = kwargs.get("timeindex", None)
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 "
"set a time index as all data in TimeSeries class is indexed by the"
"time index. You can set the time index upon initialisation of "
"the EDisGo object by providing the input parameter 'timeindex' or by "
"using the function EDisGo.set_timeindex()."
"The given timeindex is different from the EDisGo.TimeSeries.timeindex."
" Therefore the EDisGo.TimeSeries.timeindex will be overwritten by the "
"given timeindex."
)

set_timeindex = True

elif self.timeseries.timeindex.empty:
logger.warning(
"The EDisGo.TimeSeries.timeindex is empty. By default, this function "
"will set the timeindex to the default year of the provided database "
"connection. To ensure expected behavior, consider setting the "
"timeindex explicitly before running this function using "
"EDisGo.set_timeindex()."
)

set_timeindex = True

if set_timeindex:
if timeindex is None:
timeindex, _ = _timeindex_helper_func(
self, timeindex, allow_leap_year=True
)

logger.warning(f"Setting EDisGo.TimeSeries.timeindex to {timeindex}.")

self.set_timeindex(timeindex)

logger.info(
f"Trying to set predefined timeseries for {self.timeseries.timeindex}"
)

if fluctuating_generators_ts is not None:
self.timeseries.predefined_fluctuating_generators_by_technology(
self,
Expand Down Expand Up @@ -972,9 +1001,7 @@ 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,
If 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.

Expand Down Expand Up @@ -1352,7 +1379,7 @@ def reinforce(

"""
if copy_grid:
edisgo_obj = copy.deepcopy(self)
edisgo_obj = self.copy()
else:
edisgo_obj = self

Expand Down Expand Up @@ -1921,9 +1948,8 @@ def _aggregate_time_series(attribute, groups, naming):

def import_electromobility(
self,
data_source: str,
data_source: str = "oedb",
scenario: str = None,
engine: Engine = None,
charging_processes_dir: PurePath | str = None,
potential_charging_points_dir: PurePath | str = None,
import_electromobility_data_kwds=None,
Expand Down Expand Up @@ -1965,10 +1991,8 @@ def import_electromobility(
* "oedb"

Electromobility data is obtained from the `OpenEnergy DataBase
<https://openenergyplatform.org/dataedit/schemas>`_.

This option requires that the parameters `scenario` and `engine` are
provided.
<https://openenergyplatform.org/dataedit/schemas>`_ or other eGon-data
databases depending on the provided Engine.

* "directory"

Expand All @@ -1978,9 +2002,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<sqlalchemy.engine.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.
Expand Down Expand Up @@ -2042,7 +2063,7 @@ def import_electromobility(
import_electromobility_from_oedb(
self,
scenario=scenario,
engine=engine,
engine=self.engine,
**import_electromobility_data_kwds,
)
elif data_source == "directory":
Expand Down Expand Up @@ -2135,10 +2156,11 @@ 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.
Gets heat pump data for specified scenario from the OEDB or other eGon-data
databases depending on the provided Engine and integrates the heat pumps into
the grid.

Besides heat pump capacity the heat pump's COP and heat demand to be served
are as well retrieved.
Expand Down Expand Up @@ -2193,8 +2215,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<sqlalchemy.engine.Engine>`
Database engine.
timeindex : :pandas:`pandas.DatetimeIndex<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
Expand Down Expand Up @@ -2235,31 +2255,31 @@ 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,
self.engine,
timeindex=pd.date_range(f"1/1/{year}", periods=8760, freq="H"),
import_types=import_types,
)

integrated_heat_pumps = import_heat_pumps_oedb(
edisgo_object=self,
scenario=scenario,
engine=engine,
engine=self.engine,
import_types=import_types,
)
if len(integrated_heat_pumps) > 0:
self.heat_pump.set_heat_demand(
self,
"oedb",
heat_pump_names=integrated_heat_pumps,
engine=engine,
engine=self.engine,
scenario=scenario,
timeindex=timeindex,
)
self.heat_pump.set_cop(
self,
"oedb",
heat_pump_names=integrated_heat_pumps,
engine=engine,
engine=self.engine,
timeindex=timeindex,
)

Expand Down Expand Up @@ -2307,7 +2327,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 <https://openenergyplatform.org/dataedit/schemas>`_.
Expand All @@ -2326,8 +2346,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<sqlalchemy.engine.Engine>`
Database engine.
timeindex : :pandas:`pandas.DatetimeIndex<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
Expand All @@ -2340,7 +2358,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, engine=self.engine, timeindex=timeindex
)
self.dsm.p_min = dsm_profiles["p_min"]
self.dsm.p_max = dsm_profiles["p_max"]
Expand All @@ -2350,7 +2368,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
Expand All @@ -2361,7 +2378,8 @@ def import_home_batteries(
between two scenarios: 'eGon2035' and 'eGon100RE'.

The data is retrieved from the
`open energy platform <https://openenergyplatform.org/>`_.
`open energy platform <https://openenergyplatform.org/>`_ or other eGon-data
databases depending on the given Engine.

The batteries are integrated into the grid (added to
:attr:`~.network.topology.Topology.storage_units_df`) based on their building
Expand All @@ -2378,14 +2396,12 @@ def import_home_batteries(
scenario : str
Scenario for which to retrieve home battery data. Possible options
are 'eGon2035' and 'eGon100RE'.
engine : :sqlalchemy:`sqlalchemy.Engine<sqlalchemy.engine.Engine>`
Database engine.

"""
home_batteries_oedb(
edisgo_obj=self,
scenario=scenario,
engine=engine,
engine=self.engine,
)

def plot_mv_grid_topology(self, technologies=False, **kwargs):
Expand All @@ -2412,6 +2428,7 @@ def plot_mv_grid_topology(self, technologies=False, **kwargs):
xlim=kwargs.get("xlim", None),
ylim=kwargs.get("ylim", None),
title=kwargs.get("title", ""),
**kwargs,
)

def plot_mv_voltages(self, **kwargs):
Expand Down Expand Up @@ -3135,7 +3152,7 @@ def spatial_complexity_reduction(

"""
if copy_edisgo is True:
edisgo_obj = copy.deepcopy(self)
edisgo_obj = self.copy()
else:
edisgo_obj = self
busmap_df, linemap_df = spatial_complexity_reduction(
Expand Down Expand Up @@ -3349,6 +3366,44 @@ def resample_timeseries(
self.heat_pump.resample_timeseries(method=method, freq=freq)
self.overlying_grid.resample(method=method, freq=freq)

def copy(self, deep=True):
"""
Returns a copy of the object, with an option for a deep copy.

The SQLAlchemy engine is excluded from the copying process and restored
afterward.

Parameters
----------
deep : bool
If True, performs a deep copy; otherwise, performs a shallow copy.

Returns
---------
:class:`~.EDisGo`
Copied EDisGo object.

"""
tmp_engine = (
getattr(self, "engine", None)
if isinstance(getattr(self, "engine", None), Engine)
else None
)

if tmp_engine:
logging.info("Temporarily removing the SQLAlchemy engine before copying.")
self.engine = self.config._engine = None

cpy = copy.deepcopy(self) if deep else copy.copy(self)

if tmp_engine:
logging.info("Restoring the SQLAlchemy engine after copying.")
self.engine = self.config._engine = cpy.engine = cpy.config._engine = (
tmp_engine
)

return cpy


def import_edisgo_from_pickle(filename, path=""):
"""
Expand Down
Loading