Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wp flex changed reinforcement #395

Merged
merged 43 commits into from
Feb 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
5073260
Delete ToDo
birgits Oct 22, 2023
4f6fe13
Fix use same time index
birgits Oct 22, 2023
8c6e57a
Allow selecting most critical time steps from subset of time steps
birgits Oct 22, 2023
475a2f3
Change how reduced_analysis is set
birgits Oct 22, 2023
b7886fc
More changes to change how reduced analysis is set
birgits Oct 22, 2023
43552cf
Change LV reniforcement
birgits Oct 22, 2023
0f15fab
Fix type hinting
birgits Oct 22, 2023
b17d714
Bug fix hand analyze parameters to get_most_critical_time_steps
birgits Oct 22, 2023
b54ebc9
Allow not running an inital analyze when using reduced analysis
birgits Oct 22, 2023
70748ce
Quick bug fix
birgits Oct 23, 2023
708bdb3
Bug fix when analyze mode is lv, station node voltage cannot be checked
birgits Oct 23, 2023
bd5c888
Change back as this wasn't the problem
birgits Oct 23, 2023
c832690
Add return in case no timesteps for reinforcement exist
birgits Oct 23, 2023
44a2203
Bug fix add parameters when function is called
birgits Oct 23, 2023
51b53de
Fix only use reduced analysis when power flow converges
birgits Oct 23, 2023
1bd354b
Add helper function temporarily
birgits Oct 24, 2023
9cc3e67
Bug fix
birgits Oct 24, 2023
e5add23
Merge branch 'dev' into wp_flex_changed_reinforcement
birgits Dec 20, 2023
7b7a7e1
Merge branch 'dev' into wp_flex_changed_reinforcement
birgits Jan 18, 2024
74381c3
Revert "Change LV reniforcement"
birgits Jan 18, 2024
4aff553
Fix test - setup class needs to be rerun
birgits Jan 19, 2024
db325bc
Get rid of redundant code and parameter documentation
birgits Jan 19, 2024
716c636
Allow weighting by costs or without weighting factor
birgits Jan 20, 2024
8d046b3
Fix spelling
birgits Jan 24, 2024
c2e45ad
Bugfix and remove time intervals without grid issues
birgits Jan 24, 2024
edd4ba3
Adapt tests to bugfix and new parameter
birgits Jan 24, 2024
0595d57
Adapt test
birgits Jan 24, 2024
4979e3b
Move approximation of costs to separate functions and add tests
birgits Jan 29, 2024
70b8da5
Add weighting by costs in time steps selection
birgits Jan 30, 2024
cf0c412
Add tests
birgits Jan 30, 2024
139fd7f
Add test
birgits Jan 31, 2024
b6d2f9e
Limit pandas version
birgits Feb 1, 2024
70c3264
Add changes to whatsnew
birgits Feb 1, 2024
85b49f4
Add logging information
birgits Feb 16, 2024
9e0d85d
Add ToDo for how function could be improved
birgits Feb 16, 2024
c272fda
Restrict pandas version
birgits Feb 16, 2024
dfb71ae
Change links that are now redirected
birgits Feb 16, 2024
7ec2ec2
Only conduct reinforcement for previously non-converging time steps i…
birgits Feb 16, 2024
a1ac8c8
Use maximum deviation in feeder rather than weighting all deviations …
birgits Feb 19, 2024
b99abba
Add ToDo
birgits Feb 19, 2024
f04bc2f
Change default for use_troubleshotting_mode as True is not useful in …
birgits Feb 19, 2024
0657cd1
Try fixing failing link check github action
birgits Feb 19, 2024
79b5a31
Ignore stackoverflow links when checking links
birgits Feb 20, 2024
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
7 changes: 6 additions & 1 deletion doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ def setup(sphinx):
"networkx.%s",
),
"sqlalchemy": (
"http://docs.sqlalchemy.org/en/latest/core/connections.html#%s",
"https://docs.sqlalchemy.org/en/latest/core/connections.html#%s",
"sqlalchemy.%s",
),
"numpy": (
Expand All @@ -134,6 +134,11 @@ def setup(sphinx):
"plotly.%s",
),
}
# ignore the following external links when checking the links
# stackoverflow is listed here because for some reason the link check fails for these
# in the github action, even though the link is correct
linkcheck_ignore = [r"https://stackoverflow.com*"]

# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]

Expand Down
4 changes: 2 additions & 2 deletions doc/quickstart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ The steps required to set up HSL are also described in the
Here is a short version for reference:

First, you need to obtain an academic license for HSL Solvers.
Under https://www.hsl.rl.ac.uk/ipopt/ download the sources for Coin-HSL Full (Stable).
Under https://licences.stfc.ac.uk/product/coin-hsl download the sources for Coin-HSL Full (Stable).
You will need to provide an institutional e-mail to gain access.

Unpack the tar.gz:
Expand Down Expand Up @@ -163,7 +163,7 @@ Beyond a running and up-to-date installation of eDisGo you need **grid topology
data**. Currently synthetic grid data generated with the python project
`Ding0 <https://github.com/openego/ding0>`_
is the only supported data source. You can retrieve data from
`Zenodo <https://zenodo.org/record/890479>`_
`Zenodo <https://zenodo.org/records/890479>`_
(make sure you choose latest data) or check out the
`Ding0 documentation <https://dingo.readthedocs.io/en/dev/usage_details.html#ding0-examples>`_
on how to generate grids yourself.
Expand Down
1 change: 1 addition & 0 deletions doc/whatsnew/v0-3-0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Changes
* Added method to aggregate LV grid buses to station bus secondary side `#353 <https://github.com/openego/eDisGo/pull/353>`_
* Adapted codebase to work with pandas 2.0 `#373 <https://github.com/openego/eDisGo/pull/373>`_
* Added option to run reinforcement with reduced number of time steps `#379 <https://github.com/openego/eDisGo/pull/379>`_
(adapted in `#395 <https://github.com/openego/eDisGo/pull/395>`_)
* Added optimization method to determine dispatch of flexibilities that lead to minimal network expansion costs `#376 <https://github.com/openego/eDisGo/pull/376>`_
* Added a new reinforcement method that separate lv grids when the overloading is very high `#380 <https://github.com/openego/eDisGo/pull/380>`_
* 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>`_
Expand Down
2 changes: 1 addition & 1 deletion eDisGo_env.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ channels:
dependencies:
- python >= 3.8, < 3.10
- pip
- pandas >= 1.4
- pandas >= 1.4, < 2.2.0
- conda-forge::fiona
- conda-forge::geopy
- conda-forge::geopandas
Expand Down
2 changes: 1 addition & 1 deletion eDisGo_env_dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ channels:
dependencies:
- python >= 3.8, < 3.10
- pip
- pandas >= 1.4
- pandas >= 1.4, < 2.2.0
- conda-forge::fiona
- conda-forge::geopy
- conda-forge::geopandas
Expand Down
46 changes: 33 additions & 13 deletions edisgo/edisgo.py
Original file line number Diff line number Diff line change
Expand Up @@ -998,7 +998,7 @@ def analyze(
range_num: int = 10,
scale_timeseries: float | None = None,
**kwargs,
) -> tuple[pd.DataFrame, pd.DataFrame]:
) -> tuple[pd.DatetimeIndex, pd.DatetimeIndex]:
"""
Conducts a static, non-linear power flow analysis.

Expand Down Expand Up @@ -1196,6 +1196,7 @@ def _scale_timeseries(pypsa_network_copy, fraction):
def reinforce(
self,
timesteps_pfa: str | pd.DatetimeIndex | pd.Timestamp | None = None,
reduced_analysis: bool = False,
copy_grid: bool = False,
max_while_iterations: int = 20,
split_voltage_band: bool = True,
Expand Down Expand Up @@ -1237,14 +1238,15 @@ def reinforce(
time steps. If your time series already represents the worst-case,
keep the default value of None because finding the worst-case
snapshots takes some time.
* 'reduced_analysis'
Reinforcement is conducted for all time steps at which at least one
branch shows its highest overloading or one bus shows its highest voltage
violation.
* :pandas:`pandas.DatetimeIndex<DatetimeIndex>` or \
:pandas:`pandas.Timestamp<Timestamp>`
Use this option to explicitly choose which time steps to consider.

reduced_analysis : bool
If True, reinforcement is conducted for all time steps at which at least
one branch shows its highest overloading or one bus shows its highest
voltage violation. Time steps to consider are specified through parameter
`timesteps_pfa`. If False, all time steps in parameter `timesteps_pfa`
are used. Default: False.
copy_grid : bool
If True, reinforcement is conducted on a copied grid and discarded.
Default: False.
Expand Down Expand Up @@ -1301,26 +1303,43 @@ def reinforce(
reinforce MV/LV stations for LV worst-cases.
Default: False.
num_steps_loading : int
In case `timesteps_pfa` is set to 'reduced_analysis', this parameter can be
In case `reduced_analysis` is set to True, this parameter can be
used to specify the number of most critical overloading events to consider.
If None, `percentage` is used. Default: None.
num_steps_voltage : int
In case `timesteps_pfa` is set to 'reduced_analysis', this parameter can be
In case `reduced_analysis` is set to True, this parameter can be
used to specify the number of most critical voltage issues to select. If
None, `percentage` is used. Default: None.
percentage : float
In case `timesteps_pfa` is set to 'reduced_analysis', this parameter can be
In case `reduced_analysis` is set to True, this parameter can be
used to specify the percentage of most critical time steps to select. The
default is 1.0, in which case all most critical time steps are selected.
Default: 1.0.
use_troubleshooting_mode : bool
In case `timesteps_pfa` is set to 'reduced_analysis', this parameter can be
used to specify how to handle non-convergence issues in the power flow
analysis. If set to True, non-convergence issues are tried to be
In case `reduced_analysis` is set to True, this parameter can be used to
specify how to handle non-convergence issues when determining the most
critical time steps. If set to True, non-convergence issues are tried to be
circumvented by reducing load and feed-in until the power flow converges.
The most critical time steps are then determined based on the power flow
results with the reduced load and feed-in. If False, an error will be
raised in case time steps do not converge. Default: True.
raised in case time steps do not converge.
Setting this to True doesn't make sense for the grid reinforcement as the
troubleshooting mode is only used when determining the most critical time
steps not when running a power flow analysis to determine grid reinforcement
needs. To handle non-convergence in the grid reinforcement set parameter
`catch_convergence_problems` to True.
Default: False.
run_initial_analyze : bool
In case `reduced_analysis` is set to True, this parameter can be
used to specify whether to run an initial analyze to determine most
critical time steps or to use existing results. If set to False,
`use_troubleshooting_mode` is ignored. Default: True.
weight_by_costs : bool
In case `reduced_analysis` is set to True, this parameter can be used
to specify whether to weight time steps by estimated grid expansion costs.
See parameter `weight_by_costs` in
:func:`~.tools.temporal_complexity_reduction.get_most_critical_time_steps`
for more information. Default: False.

Returns
--------
Expand Down Expand Up @@ -1407,6 +1426,7 @@ def reinforce(

func(
edisgo_obj,
reduced_analysis=reduced_analysis,
max_while_iterations=max_while_iterations,
split_voltage_band=split_voltage_band,
without_generator_import=without_generator_import,
Expand Down
6 changes: 5 additions & 1 deletion edisgo/flex_opt/check_tech_constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -709,7 +709,7 @@ def stations_relative_load(edisgo_obj, grids=None):
except Exception:
pass

return loading / allowed_loading.loc[:, loading.columns]
return loading / allowed_loading.loc[loading.index, loading.columns]


def components_relative_load(edisgo_obj, n_minus_one=False):
Expand Down Expand Up @@ -1190,6 +1190,10 @@ def voltage_deviation_from_allowed_voltage_limits(
v_dev_allowed_upper, v_dev_allowed_lower = allowed_voltage_limits(
edisgo_obj, buses=buses, split_voltage_band=split_voltage_band
)
# the following is needed in case the power flow was only conducted for one LV
# grid - voltage at station node cannot be checked, warning is already raised
# in allowed_voltage_limits()
buses = v_dev_allowed_upper.columns

# get voltages from power flow analysis
v_mag_pu_pfa = edisgo_obj.results.v_res.loc[:, buses]
Expand Down
72 changes: 50 additions & 22 deletions edisgo/flex_opt/reinforce_grid.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
def reinforce_grid(
edisgo: EDisGo,
timesteps_pfa: str | pd.DatetimeIndex | pd.Timestamp | None = None,
reduced_analysis: bool = False,
max_while_iterations: int = 20,
split_voltage_band: bool = True,
mode: str | None = None,
Expand All @@ -47,6 +48,10 @@ def reinforce_grid(
timesteps_pfa specifies for which time steps power flow analysis is
conducted. See parameter `timesteps_pfa` in function :attr:`~.EDisGo.reinforce`
for more information.
reduced_analysis : bool
Specifies, whether to run reinforcement on a subset of time steps that are most
critical. See parameter `reduced_analysis` in function
:attr:`~.EDisGo.reinforce` for more information.
max_while_iterations : int
Maximum number of times each while loop is conducted. Default: 20.
split_voltage_band : bool
Expand Down Expand Up @@ -84,23 +89,34 @@ def reinforce_grid(
reinforce MV/LV stations for LV worst-cases.
Default: False.
num_steps_loading : int
In case `timesteps_pfa` is set to 'reduced_analysis', this parameter can be used
In case `reduced_analysis` is set to True, this parameter can be used
to specify the number of most critical overloading events to consider.
If None, `percentage` is used. Default: None.
num_steps_voltage : int
In case `timesteps_pfa` is set to 'reduced_analysis', this parameter can be used
In case `reduced_analysis` is set to True, this parameter can be used
to specify the number of most critical voltage issues to select. If None,
`percentage` is used. Default: None.
percentage : float
In case `timesteps_pfa` is set to 'reduced_analysis', this parameter can be used
In case `reduced_analysis` is set to True, this parameter can be used
to specify the percentage of most critical time steps to select. The default
is 1.0, in which case all most critical time steps are selected.
Default: 1.0.
use_troubleshooting_mode : bool
In case `timesteps_pfa` is set to 'reduced_analysis', this parameter can be used
In case `reduced_analysis` is set to True, this parameter can be used
to specify how to handle non-convergence issues in the power flow analysis.
See parameter `use_troubleshooting_mode` in function :attr:`~.EDisGo.reinforce`
for more information. Default: True.
for more information. Default: False.
run_initial_analyze : bool
In case `reduced_analysis` is set to True, this parameter can be
used to specify whether to run an initial analyze to determine most
critical time steps or to use existing results. If set to False,
`use_troubleshooting_mode` is ignored. Default: True.
weight_by_costs : bool
In case `reduced_analysis` is set to True, this parameter can be
used to specify whether to weight time steps by estimated grid expansion costs.
See parameter `weight_by_costs` in
:func:`~.tools.temporal_complexity_reduction.get_most_critical_time_steps`
for more information. Default: False.

Returns
-------
Expand Down Expand Up @@ -139,14 +155,6 @@ def reinforce_grid(
snapshots["min_residual_load"],
]
).dropna()
elif isinstance(timesteps_pfa, str) and timesteps_pfa == "reduced_analysis":
timesteps_pfa = get_most_critical_time_steps(
edisgo,
num_steps_loading=kwargs.get("num_steps_loading", None),
num_steps_voltage=kwargs.get("num_steps_voltage", None),
percentage=kwargs.get("percentage", 1.0),
use_troubleshooting_mode=kwargs.get("use_troubleshooting_mode", True),
)
# if timesteps_pfa is not of type datetime or does not contain
# datetimes throw an error
elif not isinstance(timesteps_pfa, datetime.datetime):
Expand All @@ -170,6 +178,24 @@ def reinforce_grid(
else:
analyze_mode = mode

if reduced_analysis:
timesteps_pfa = get_most_critical_time_steps(
edisgo,
mode=analyze_mode,
timesteps=timesteps_pfa,
lv_grid_id=lv_grid_id,
scale_timeseries=scale_timeseries,
num_steps_loading=kwargs.get("num_steps_loading", None),
num_steps_voltage=kwargs.get("num_steps_voltage", None),
percentage=kwargs.get("percentage", 1.0),
use_troubleshooting_mode=kwargs.get("use_troubleshooting_mode", False),
run_initial_analyze=kwargs.get("run_initial_analyze", True),
weight_by_costs=kwargs.get("weight_by_costs", False),
)
if timesteps_pfa is not None and len(timesteps_pfa) == 0:
logger.debug("Zero time steps for grid reinforcement.")
return edisgo.results

edisgo.analyze(
mode=analyze_mode,
timesteps=timesteps_pfa,
Expand Down Expand Up @@ -659,7 +685,7 @@ def catch_convergence_reinforce_grid(
Reinforcement strategy to reinforce grids with non-converging time steps.

First, conducts a grid reinforcement with only converging time steps.
Afterwards, tries to run reinforcement with all time steps that did not converge
Afterward, tries to run reinforcement with all time steps that did not converge
in the beginning. At last, if there are still time steps that do not converge,
the feed-in and load time series are iteratively scaled and the grid reinforced,
starting with a low grid load and scaling-up the time series until the original
Expand Down Expand Up @@ -739,14 +765,16 @@ def reinforce():
selected_timesteps = converging_timesteps
reinforce()

# Run reinforcement for time steps that did not converge after initial reinforcement
if not non_converging_timesteps.empty:
logger.info(
"Run reinforcement for time steps that did not converge after initial "
"reinforcement."
)
selected_timesteps = non_converging_timesteps
converged = reinforce()
# Run reinforcement for time steps that did not converge after initial
# reinforcement (only needs to done, when grid was previously reinforced using
# converged time steps, wherefore it is within that if-statement)
if not non_converging_timesteps.empty:
logger.info(
"Run reinforcement for time steps that did not converge after initial "
"reinforcement."
)
selected_timesteps = non_converging_timesteps
converged = reinforce()

if converged:
return edisgo.results
Expand Down
2 changes: 1 addition & 1 deletion edisgo/io/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ def engine(path: Path | str, ssh: bool = False) -> Engine:

Returns
-------
sqlalchemy.engine.base.Engine
:sqlalchemy:`sqlalchemy.Engine<sqlalchemy.engine.Engine>`
Database engine

"""
Expand Down
Loading
Loading