diff --git a/edisgo/flex_opt/reinforce_grid.py b/edisgo/flex_opt/reinforce_grid.py index 7f4fe80d..c6f88b94 100644 --- a/edisgo/flex_opt/reinforce_grid.py +++ b/edisgo/flex_opt/reinforce_grid.py @@ -157,15 +157,6 @@ def reinforce_grid( f"Input {timesteps_pfa} for timesteps_pfa is not valid." ) - if reduced_analysis: - timesteps_pfa = get_most_critical_time_steps( - edisgo, - timesteps=timesteps_pfa, - 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), - ) iteration_step = 1 lv_grid_id = kwargs.get("lv_grid_id", None) scale_timeseries = kwargs.get("scale_timeseries", None) @@ -176,6 +167,19 @@ 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", True), + ) + edisgo.analyze( mode=analyze_mode, timesteps=timesteps_pfa, diff --git a/edisgo/tools/temporal_complexity_reduction.py b/edisgo/tools/temporal_complexity_reduction.py index 048b9301..69bf70af 100644 --- a/edisgo/tools/temporal_complexity_reduction.py +++ b/edisgo/tools/temporal_complexity_reduction.py @@ -396,7 +396,13 @@ def _scored_most_critical_voltage_issues_time_interval( return time_intervals_df -def _troubleshooting_mode(edisgo_obj, timesteps=None): +def _troubleshooting_mode( + edisgo_obj, + mode=None, + timesteps=None, + lv_grid_id=None, + scale_timeseries=None, +): """ Handles non-convergence issues in power flow by iteratively reducing load and feed-in until the power flow converges. @@ -409,16 +415,31 @@ def _troubleshooting_mode(edisgo_obj, timesteps=None): ----------- edisgo_obj : :class:`~.EDisGo` The eDisGo API object + mode : str or None + Allows to toggle between power flow analysis for the whole network or just + the MV or one LV grid. See parameter `mode` in function + :attr:`~.EDisGo.analyze` for more information. timesteps : :pandas:`pandas.DatetimeIndex` or \ :pandas:`pandas.Timestamp` Timesteps specifies from which time steps to select most critical ones. It defaults to None in which case all time steps in :attr:`~.network.timeseries.TimeSeries.timeindex` are used. + lv_grid_id : int or str + ID (e.g. 1) or name (string representation, e.g. "LVGrid_1") of LV grid + to analyze in case mode is 'lv'. Default: None. + scale_timeseries : float or None + See parameter `scale_timeseries` in function :attr:`~.EDisGo.analyze` for more + information. """ try: logger.debug("Running initial power flow for temporal complexity reduction.") - edisgo_obj.analyze(timesteps=timesteps) + edisgo_obj.analyze( + mode=mode, + timesteps=timesteps, + lv_grid_id=lv_grid_id, + scale_timeseries=scale_timeseries, + ) # Exception is used, as non-convergence can also lead to RuntimeError, not only # ValueError except Exception: @@ -429,13 +450,17 @@ def _troubleshooting_mode(edisgo_obj, timesteps=None): "not all time steps converged. Power flow is run again with reduced " "network load." ) - for fraction in np.arange(0.8, 0.0, step=-0.1): + if isinstance(scale_timeseries, float): + iter_start = scale_timeseries - 0.1 + else: + iter_start = 0.8 + for fraction in np.arange(iter_start, 0.0, step=-0.1): try: edisgo_obj.analyze( + mode=mode, timesteps=timesteps, - troubleshooting_mode="iteration", - range_start=fraction, - range_num=1, + lv_grid_id=lv_grid_id, + scale_timeseries=fraction, ) logger.info( f"Power flow fully converged for a reduction factor " @@ -627,7 +652,10 @@ def get_most_critical_time_intervals( def get_most_critical_time_steps( edisgo_obj: EDisGo, + mode=None, timesteps=None, + lv_grid_id=None, + scale_timeseries=None, num_steps_loading=None, num_steps_voltage=None, percentage: float = 1.0, @@ -640,11 +668,21 @@ def get_most_critical_time_steps( ----------- edisgo_obj : :class:`~.EDisGo` The eDisGo API object + mode : str or None + Allows to toggle between power flow analysis for the whole network or just + the MV or one LV grid. See parameter `mode` in function + :attr:`~.EDisGo.analyze` for more information. timesteps : :pandas:`pandas.DatetimeIndex` or \ :pandas:`pandas.Timestamp` Timesteps specifies from which time steps to select most critical ones. It defaults to None in which case all time steps in :attr:`~.network.timeseries.TimeSeries.timeindex` are used. + lv_grid_id : int or str + ID (e.g. 1) or name (string representation, e.g. "LVGrid_1") of LV grid + to analyze in case mode is 'lv'. Default: None. + scale_timeseries : float or None + See parameter `scale_timeseries` in function :attr:`~.EDisGo.analyze` for more + information. num_steps_loading : int The number of most critical overloading events to select. If None, `percentage` is used. Default: None. @@ -675,7 +713,12 @@ def get_most_critical_time_steps( edisgo_obj = _troubleshooting_mode(edisgo_obj, timesteps=timesteps) else: logger.debug("Running initial power flow for temporal complexity reduction.") - edisgo_obj.analyze(timesteps=timesteps) + edisgo_obj.analyze( + mode=mode, + timesteps=timesteps, + lv_grid_id=lv_grid_id, + scale_timeseries=scale_timeseries, + ) # Select most critical steps based on current violations loading_scores = _scored_most_critical_loading(edisgo_obj)