Skip to content

Commit

Permalink
Merge pull request #610 from BDonnot/master
Browse files Browse the repository at this point in the history
Ready for version 1.10.2
  • Loading branch information
BDonnot authored May 27, 2024
2 parents 0183478 + 2acffe9 commit c9de7aa
Show file tree
Hide file tree
Showing 6 changed files with 177 additions and 27 deletions.
10 changes: 9 additions & 1 deletion CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,17 @@ Change Log
- [???] "asynch" multienv
- [???] properly model interconnecting powerlines

[1.10.2] - 2024-xx-yy
[1.10.2] - 2024-05-27
-------------------------
- [BREAKING] the `runner.run_one_episode` now returns an extra first argument:
`chron_id, chron_name, cum_reward, timestep, max_ts = runner.run_one_episode()` which
is consistant with `runner.run(...)` (previously it returned only
`chron_name, cum_reward, timestep, max_ts = runner.run_one_episode()`)
- [BREAKING] the runner now has no `chronics_handler` attribute (`runner.chronics_handler`
is not defined)
- [BREAKING] now grid2op forces everything to be connected at busbar 1 if
`param.IGNORE_INITIAL_STATE_TIME_SERIE == True` (**NOT** the default) and
no initial state is provided in `env.reset(..., options={"init state": ...})`
- [ADDED] it is now possible to call `change_reward` directly from
an observation (no need to do it from the Observation Space)
- [ADDED] method to change the reward from the observation (observation_space
Expand All @@ -55,6 +58,11 @@ Change Log
- [ADDED] some more type hints in the `GridObject` class
- [ADDED] Possibility to deactive the support of shunts if subclassing `PandaPowerBackend`
(and add some basic tests)
- [ADDED] a parameters (`param.IGNORE_INITIAL_STATE_TIME_SERIE`) which defaults to
`False` that tells the environment whether it should ignore the
initial state of the grid provided in the time series.
By default it is NOT ignored, it is taken into account
(for the environment that supports this feature)
- [FIXED] a small issue that could lead to having
"redispatching_unit_commitment_availble" flag set even if the redispatching
data was not loaded correctly
Expand Down
5 changes: 5 additions & 0 deletions grid2op/Chronics/gridValue.py
Original file line number Diff line number Diff line change
Expand Up @@ -833,6 +833,11 @@ def get_init_action(self, names_chronics_to_backend: Dict[Literal["loads", "prod
For later version, we let the possibility to set, in the "time series folder" (or time series generators)
the possibility to change the initial condition of the grid.
Notes
-----
If the environment parameters :attr:`grid2op.Parameters.Parameters.IGNORE_INITIAL_STATE_TIME_SERIE`
is set to `True` (not its default value) then this is ignored.
Returns
-------
grid2op.Action.playableAction.PlayableAction
Expand Down
13 changes: 12 additions & 1 deletion grid2op/Environment/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -834,11 +834,22 @@ def reset_grid(self,

self._backend_action = self._backend_action_class()
self.nb_time_step = -1 # to have init obs at step 1 (and to prevent 'setting to proper state' "action" to be illegal)
init_action : BaseAction = self.chronics_handler.get_init_action(self._names_chronics_to_backend)
init_action = None
if not self._parameters.IGNORE_INITIAL_STATE_TIME_SERIE:
# load the initial state from the time series (default)
# TODO logger: log that
init_action : BaseAction = self.chronics_handler.get_init_action(self._names_chronics_to_backend)
else:
# do as if everything was connected to busbar 1
# TODO logger: log that
init_action = self._helper_action_env({"set_bus": np.ones(type(self).dim_topo, dtype=dt_int)})
if type(self).shunts_data_available:
init_action += self._helper_action_env({"shunt": {"set_bus": np.ones(type(self).n_shunt, dtype=dt_int)}})
if init_action is None:
# default behaviour for grid2op < 1.10.2
init_action = self._helper_action_env({})
else:
# remove the "change part" of the action
init_action.remove_change()

if init_act_opt is not None:
Expand Down
76 changes: 53 additions & 23 deletions grid2op/Parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,19 @@ class Parameters:
MAX_SIMULATE_PER_EPISODE: ``int``
Maximum number of calls to `obs.simuate(...)` allowed per episode (reset each "env.simulate(...)"). Defaults to -1 meaning "as much as you want".
IGNORE_INITIAL_STATE_TIME_SERIE: ``bool``
If set to True (which is NOT the default), then the initial state of the grid
will always be "everything connected" and "everything connected to busbar 1"
regardless of the information present in the time series (see
:func:`grid2op.Chronics.GridValue.get_init_action`)
.. versionadded:: 1.10.2
.. note::
This flag has no impact if an initial state is set through a call to
`env.reset(options={"init state": ...})` (see doc of :func:`grid2op.Environment.Environment.reset`
for more information)
"""

def __init__(self, parameters_path=None):
Expand Down Expand Up @@ -227,6 +240,8 @@ def __init__(self, parameters_path=None):
else:
warn_msg = "Parameters: the file {} is not found. Continuing with default parameters."
warnings.warn(warn_msg.format(parameters_path))

self.IGNORE_INITIAL_STATE_TIME_SERIE = False

@staticmethod
def _isok_txt(arg):
Expand Down Expand Up @@ -368,6 +383,11 @@ def init_from_dict(self, dict_):
if "MAX_SIMULATE_PER_EPISODE" in dict_:
self.MAX_SIMULATE_PER_EPISODE = dt_int(dict_["MAX_SIMULATE_PER_EPISODE"])

if "IGNORE_INITIAL_STATE_TIME_SERIE" in dict_:
self.IGNORE_INITIAL_STATE_TIME_SERIE = Parameters._isok_txt(
dict_["IGNORE_INITIAL_STATE_TIME_SERIE"]
)

authorized_keys = set(self.__dict__.keys())
authorized_keys = authorized_keys | {
"NB_TIMESTEP_POWERFLOW_ALLOWED",
Expand Down Expand Up @@ -416,6 +436,7 @@ def to_dict(self):
res["ALERT_TIME_WINDOW"] = int(self.ALERT_TIME_WINDOW)
res["MAX_SIMULATE_PER_STEP"] = int(self.MAX_SIMULATE_PER_STEP)
res["MAX_SIMULATE_PER_EPISODE"] = int(self.MAX_SIMULATE_PER_EPISODE)
res["IGNORE_INITIAL_STATE_TIME_SERIE"] = int(self.IGNORE_INITIAL_STATE_TIME_SERIE)
return res

def init_from_json(self, json_path):
Expand Down Expand Up @@ -470,16 +491,18 @@ def check_valid(self):
Raises
-------
An exception if the parameter is not valid
An exception (`RuntimeError`) if the parameter is not valid
"""

try:
if not isinstance(self.NO_OVERFLOW_DISCONNECTION, (bool, dt_bool)):
raise RuntimeError("NO_OVERFLOW_DISCONNECTION should be a boolean")
self.NO_OVERFLOW_DISCONNECTION = dt_bool(self.NO_OVERFLOW_DISCONNECTION)
except Exception as exc_:
raise RuntimeError(
f'Impossible to convert NO_OVERFLOW_DISCONNECTION to bool with error \n:"{exc_}"'
)
) from exc_

try:
self.NB_TIMESTEP_OVERFLOW_ALLOWED = int(
Expand All @@ -491,7 +514,7 @@ def check_valid(self):
except Exception as exc_:
raise RuntimeError(
f'Impossible to convert NB_TIMESTEP_OVERFLOW_ALLOWED to int with error \n:"{exc_}"'
)
) from exc_

if self.NB_TIMESTEP_OVERFLOW_ALLOWED < 0:
raise RuntimeError(
Expand All @@ -505,7 +528,7 @@ def check_valid(self):
except Exception as exc_:
raise RuntimeError(
f'Impossible to convert NB_TIMESTEP_RECONNECTION to int with error \n:"{exc_}"'
)
) from exc_
if self.NB_TIMESTEP_RECONNECTION < 0:
raise RuntimeError("NB_TIMESTEP_RECONNECTION < 0., this should be >= 0.")
try:
Expand All @@ -514,7 +537,7 @@ def check_valid(self):
except Exception as exc_:
raise RuntimeError(
f'Impossible to convert NB_TIMESTEP_COOLDOWN_LINE to int with error \n:"{exc_}"'
)
) from exc_
if self.NB_TIMESTEP_COOLDOWN_LINE < 0:
raise RuntimeError("NB_TIMESTEP_COOLDOWN_LINE < 0., this should be >= 0.")
try:
Expand All @@ -525,7 +548,7 @@ def check_valid(self):
except Exception as exc_:
raise RuntimeError(
f'Impossible to convert NB_TIMESTEP_COOLDOWN_SUB to int with error \n:"{exc_}"'
)
) from exc_
if self.NB_TIMESTEP_COOLDOWN_SUB < 0:
raise RuntimeError("NB_TIMESTEP_COOLDOWN_SUB < 0., this should be >= 0.")
try:
Expand All @@ -536,7 +559,7 @@ def check_valid(self):
except Exception as exc_:
raise RuntimeError(
f'Impossible to convert HARD_OVERFLOW_THRESHOLD to float with error \n:"{exc_}"'
)
) from exc_
if self.HARD_OVERFLOW_THRESHOLD < 1.0:
raise RuntimeError(
"HARD_OVERFLOW_THRESHOLD < 1., this should be >= 1. (use env.set_thermal_limit "
Expand All @@ -551,7 +574,7 @@ def check_valid(self):
except Exception as exc_:
raise RuntimeError(
f'Impossible to convert SOFT_OVERFLOW_THRESHOLD to float with error \n:"{exc_}"'
)
) from exc_
if self.SOFT_OVERFLOW_THRESHOLD < 1.0:
raise RuntimeError(
"SOFT_OVERFLOW_THRESHOLD < 1., this should be >= 1. (use env.set_thermal_limit "
Expand All @@ -570,14 +593,14 @@ def check_valid(self):
except Exception as exc_:
raise RuntimeError(
f'Impossible to convert ENV_DC to bool with error \n:"{exc_}"'
)
) from exc_
try:
self.MAX_SUB_CHANGED = int(self.MAX_SUB_CHANGED) # to raise if numpy array
self.MAX_SUB_CHANGED = dt_int(self.MAX_SUB_CHANGED)
except Exception as exc_:
raise RuntimeError(
f'Impossible to convert MAX_SUB_CHANGED to int with error \n:"{exc_}"'
)
) from exc_
if self.MAX_SUB_CHANGED < 0:
raise RuntimeError(
"MAX_SUB_CHANGED should be >=0 (or -1 if you want to be able to change every "
Expand All @@ -591,7 +614,7 @@ def check_valid(self):
except Exception as exc_:
raise RuntimeError(
f'Impossible to convert MAX_LINE_STATUS_CHANGED to int with error \n:"{exc_}"'
)
) from exc_
if self.MAX_LINE_STATUS_CHANGED < 0:
raise RuntimeError(
"MAX_LINE_STATUS_CHANGED should be >=0 "
Expand All @@ -604,7 +627,7 @@ def check_valid(self):
except Exception as exc_:
raise RuntimeError(
f'Impossible to convert IGNORE_MIN_UP_DOWN_TIME to bool with error \n:"{exc_}"'
)
) from exc_
try:
if not isinstance(self.ALLOW_DISPATCH_GEN_SWITCH_OFF, (bool, dt_bool)):
raise RuntimeError("ALLOW_DISPATCH_GEN_SWITCH_OFF should be a boolean")
Expand All @@ -614,7 +637,7 @@ def check_valid(self):
except Exception as exc_:
raise RuntimeError(
f'Impossible to convert ALLOW_DISPATCH_GEN_SWITCH_OFF to bool with error \n:"{exc_}"'
)
) from exc_
try:
if not isinstance(
self.LIMIT_INFEASIBLE_CURTAILMENT_STORAGE_ACTION, (bool, dt_bool)
Expand All @@ -628,7 +651,7 @@ def check_valid(self):
except Exception as exc_:
raise RuntimeError(
f'Impossible to convert LIMIT_INFEASIBLE_CURTAILMENT_STORAGE_ACTION to bool with error \n:"{exc_}"'
)
) from exc_

try:
self.INIT_STORAGE_CAPACITY = float(
Expand All @@ -638,16 +661,16 @@ def check_valid(self):
except Exception as exc_:
raise RuntimeError(
f'Impossible to convert INIT_STORAGE_CAPACITY to float with error \n:"{exc_}"'
)
) from exc_

if self.INIT_STORAGE_CAPACITY < 0.0:
raise RuntimeError(
"INIT_STORAGE_CAPACITY < 0., this should be within range [0., 1.]"
)
) from exc_
if self.INIT_STORAGE_CAPACITY > 1.0:
raise RuntimeError(
"INIT_STORAGE_CAPACITY > 1., this should be within range [0., 1.]"
)
) from exc_

try:
if not isinstance(self.ACTIVATE_STORAGE_LOSS, (bool, dt_bool)):
Expand All @@ -656,26 +679,26 @@ def check_valid(self):
except Exception as exc_:
raise RuntimeError(
f'Impossible to convert ACTIVATE_STORAGE_LOSS to bool with error \n:"{exc_}"'
)
) from exc_

try:
self.ALARM_WINDOW_SIZE = dt_int(self.ALARM_WINDOW_SIZE)
except Exception as exc_:
raise RuntimeError(
f'Impossible to convert ALARM_WINDOW_SIZE to int with error \n:"{exc_}"'
)
) from exc_
try:
self.ALARM_BEST_TIME = dt_int(self.ALARM_BEST_TIME)
except Exception as exc_:
raise RuntimeError(
f'Impossible to convert ALARM_BEST_TIME to int with error \n:"{exc_}"'
)
) from exc_
try:
self.ALERT_TIME_WINDOW = dt_int(self.ALERT_TIME_WINDOW)
except Exception as exc_:
raise RuntimeError(
f'Impossible to convert ALERT_TIME_WINDOW to int with error \n:"{exc_}"'
)
) from exc_

if self.ALARM_WINDOW_SIZE <= 0:
raise RuntimeError("self.ALARM_WINDOW_SIZE should be a positive integer !")
Expand All @@ -692,7 +715,7 @@ def check_valid(self):
except Exception as exc_:
raise RuntimeError(
f'Impossible to convert MAX_SIMULATE_PER_STEP to int with error \n:"{exc_}"'
)
) from exc_
if self.MAX_SIMULATE_PER_STEP <= -2:
raise RuntimeError(
f"self.MAX_SIMULATE_PER_STEP should be a positive integer or -1, we found {self.MAX_SIMULATE_PER_STEP}"
Expand All @@ -706,8 +729,15 @@ def check_valid(self):
except Exception as exc_:
raise RuntimeError(
f'Impossible to convert MAX_SIMULATE_PER_EPISODE to int with error \n:"{exc_}"'
)
) from exc_
if self.MAX_SIMULATE_PER_EPISODE <= -2:
raise RuntimeError(
f"self.MAX_SIMULATE_PER_EPISODE should be a positive integer or -1, we found {self.MAX_SIMULATE_PER_EPISODE}"
)

try:
self.IGNORE_INITIAL_STATE_TIME_SERIE = dt_bool(self.IGNORE_INITIAL_STATE_TIME_SERIE)
except Exception as exc_:
raise RuntimeError(
f'Impossible to convert IGNORE_INITIAL_STATE_TIME_SERIE to bool with error \n:"{exc_}"'
) from exc_
1 change: 1 addition & 0 deletions grid2op/tests/test_Observation.py
Original file line number Diff line number Diff line change
Expand Up @@ -2975,6 +2975,7 @@ def setUp(self):
"educ_case14_storage", test=True, action_class=PlayableAction,
_add_to_name=type(self).__name__
)
self.env.reset(seed=0, options={"time serie id": 0})
self.obs = self._make_forecast_perfect(self.env)
self.sim_obs = None
self.step_obs = None
Expand Down
Loading

0 comments on commit c9de7aa

Please sign in to comment.