Skip to content

Commit

Permalink
some fixes, need proper tests now
Browse files Browse the repository at this point in the history
  • Loading branch information
BDonnot committed Nov 19, 2024
1 parent bbec434 commit e9d1d5b
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 2 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,17 @@ Native multi agents support:
- [FIXED] issue https://github.com/Grid2op/grid2op/issues/657
- [FIXED] missing an import on the `MaskedEnvironment` class
- [FIXED] a bug when trying to set the load_p, load_q, gen_p, gen_v by names.
- [FIXED] the `obs.get_forecast_env` : in some cases the resulting first
observation (obtained from `for_env.reset()`) did not have the correct
topology.
- [ADDED] possibility to set the "thermal limits" when calling `env.reset(..., options={"thermal limit": xxx})`
- [ADDED] possibility to retrieve some structural information about elements with
with `gridobj.get_line_info(...)`, `gridobj.get_load_info(...)`, `gridobj.get_gen_info(...)`
or , `gridobj.get_storage_info(...)`
- [ADDED] codacy badge on the readme
- [ADDED] a method to check the KCL (`obs.check_kirchoff`) directly from the observation
(previously it was only possible to do it from the backend). This should
be used for testing purpose only
- [IMPROVED] possibility to set the injections values with names
to be consistent with other way to set the actions (*eg* set_bus)
- [IMPROVED] error messages when creating an action which changes the injections
Expand All @@ -122,6 +128,8 @@ Native multi agents support:
- [IMPROVED] the classes inherited from `GreedyAgent` with the added possibility to
do the `obs.simulate` on a different time horizon (kwarg `simulated_time_step`)
- [IMPROVED] some type hints for some agent class
- [IMPROVED] the `backend.update_from_obs` function to work even when observation
does not have shunt information but there are not shunts on the grid.

[1.10.4] - 2024-10-15
-------------------------
Expand Down
2 changes: 1 addition & 1 deletion grid2op/Backend/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -2027,7 +2027,7 @@ def update_from_obs(self,
}

if cls.shunts_data_available and type(obs).shunts_data_available:
if "_shunt_bus" not in type(obs).attr_list_set:
if cls.n_shunt > 0 and "_shunt_bus" not in type(obs).attr_list_set:
raise BackendError(
"Impossible to set the backend to the state given by the observation: shunts data "
"are not present in the observation."
Expand Down
5 changes: 4 additions & 1 deletion grid2op/Environment/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -947,6 +947,10 @@ 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)

if self._init_obs is not None:
self.backend.update_from_obs(self._init_obs)

init_action = None
if not self._parameters.IGNORE_INITIAL_STATE_TIME_SERIE:
# load the initial state from the time series (default)
Expand Down Expand Up @@ -1293,7 +1297,6 @@ def reset(self,
if ambiguous:
raise Grid2OpException("You provided an invalid (ambiguous) action to set the 'init state'") from except_tmp
init_state.remove_change()

super().reset(seed=seed, options=options)

if options is not None and "max step" in options:
Expand Down
171 changes: 171 additions & 0 deletions grid2op/Observation/baseObservation.py
Original file line number Diff line number Diff line change
Expand Up @@ -4845,3 +4845,174 @@ def get_back_to_ref_state(
if self._is_done:
raise Grid2OpException("Cannot use this function in a 'done' state.")
return self.action_helper.get_back_to_ref_state(self, storage_setpoint, precision)

def _aux_kcl(self,
n_el, # cst eg. cls.n_gen
el_to_subid, # cst eg. cls.gen_to_subid
el_bus, # cst eg. gen_bus
el_p, # cst, eg. gen_p
el_q, # cst, eg. gen_q
el_v, # cst, eg. gen_v
p_subs, q_subs,
p_bus, q_bus,
v_bus,
load_conv=True # whether the object is load convention (True) or gen convention (False)
):

# bellow i'm "forced" to do a loop otherwise, numpy do not compute the "+=" the way I want it to.
# for example, if two powerlines are such that line_or_to_subid is equal (eg both connected to substation 0)
# then numpy do not guarantee that `p_subs[self.line_or_to_subid] += p_or` will add the two "corresponding p_or"
# TODO this can be vectorized with matrix product, see example in obs.flow_bus_matrix (BaseObervation.py)
for i in range(n_el):
psubid = el_to_subid[i]
if el_bus[i] == -1:
# el is disconnected
continue

# for substations
if load_conv:
p_subs[psubid] += el_p[i]
q_subs[psubid] += el_q[i]
else:
p_subs[psubid] -= el_p[i]
q_subs[psubid] -= el_q[i]

# for bus
loc_bus = el_bus[i] - 1
if load_conv:
p_bus[psubid, loc_bus] += el_p[i]
q_bus[psubid, loc_bus] += el_q[i]
else:
p_bus[psubid, loc_bus] -= el_p[i]
q_bus[psubid, loc_bus] -= el_q[i]

# compute max and min values
if el_v[i]:
# but only if gen is connected
v_bus[psubid, loc_bus][0] = min(
v_bus[psubid, loc_bus][0],
el_v[i],
)
v_bus[psubid, loc_bus][1] = max(
v_bus[psubid, loc_bus][1],
el_v[i],
)

def check_kirchoff(self) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
"""
Analogous to "backend.check_kirchoff" but from the observation
.. versionadded:: 1.11.0
Returns
-------
p_subs ``numpy.ndarray``
sum of injected active power at each substations (MW)
q_subs ``numpy.ndarray``
sum of injected reactive power at each substations (MVAr)
p_bus ``numpy.ndarray``
sum of injected active power at each buses. It is given in form of a matrix, with number of substations as
row, and number of columns equal to the maximum number of buses for a substation (MW)
q_bus ``numpy.ndarray``
sum of injected reactive power at each buses. It is given in form of a matrix, with number of substations as
row, and number of columns equal to the maximum number of buses for a substation (MVAr)
diff_v_bus: ``numpy.ndarray`` (2d array)
difference between maximum voltage and minimum voltage (computed for each elements)
at each bus. It is an array of two dimension:
- first dimension represents the the substation (between 1 and self.n_sub)
- second element represents the busbar in the substation (0 or 1 usually)
"""
cls = type(self)

# fist check the "substation law" : nothing is created at any substation
p_subs = np.zeros(cls.n_sub, dtype=dt_float)
q_subs = np.zeros(cls.n_sub, dtype=dt_float)

# check for each bus
p_bus = np.zeros((cls.n_sub, cls.n_busbar_per_sub), dtype=dt_float)
q_bus = np.zeros((cls.n_sub, cls.n_busbar_per_sub), dtype=dt_float)
v_bus = (
np.zeros((cls.n_sub, cls.n_busbar_per_sub, 2), dtype=dt_float) - 1.0
) # sub, busbar, [min,max]

self._aux_kcl(
cls.n_line, # cst eg. cls.n_gen
cls.line_or_to_subid, # cst eg. cls.gen_to_subid
self.line_or_bus,
self.p_or, # cst, eg. gen_p
self.q_or, # cst, eg. gen_q
self.v_or, # cst, eg. gen_v
p_subs, q_subs,
p_bus, q_bus,
v_bus,
)
self._aux_kcl(
cls.n_line, # cst eg. cls.n_gen
cls.line_ex_to_subid, # cst eg. cls.gen_to_subid
self.line_ex_bus,
self.p_ex, # cst, eg. gen_p
self.q_ex, # cst, eg. gen_q
self.v_ex, # cst, eg. gen_v
p_subs, q_subs,
p_bus, q_bus,
v_bus,
)
self._aux_kcl(
cls.n_load, # cst eg. cls.n_gen
cls.load_to_subid, # cst eg. cls.gen_to_subid
self.load_bus,
self.load_p, # cst, eg. gen_p
self.load_q, # cst, eg. gen_q
self.load_v, # cst, eg. gen_v
p_subs, q_subs,
p_bus, q_bus,
v_bus,
)
self._aux_kcl(
cls.n_gen, # cst eg. cls.n_gen
cls.gen_to_subid, # cst eg. cls.gen_to_subid
self.gen_bus, # cst eg. self.gen_bus
self.gen_p, # cst, eg. gen_p
self.gen_q, # cst, eg. gen_q
self.gen_v, # cst, eg. gen_v
p_subs, q_subs,
p_bus, q_bus,
v_bus,
load_conv=False
)
if cls.n_storage:
self._aux_kcl(
cls.n_storage, # cst eg. cls.n_gen
cls.storage_to_subid, # cst eg. cls.gen_to_subid
self.storage_bus,
self.storage_p, # cst, eg. gen_p
self.storage_q, # cst, eg. gen_q
self.storage_v, # cst, eg. gen_v
p_subs, q_subs,
p_bus, q_bus,
v_bus,
)

if cls.shunts_data_available:
self._aux_kcl(
cls.n_shunt, # cst eg. cls.n_gen
cls.storage_to_subid, # cst eg. cls.gen_to_subid
self._shunt_bus,
self._shunt_p, # cst, eg. gen_p
self._shunt_q, # cst, eg. gen_q
self._shunt_v, # cst, eg. gen_v
p_subs, q_subs,
p_bus, q_bus,
v_bus,
)
else:
warnings.warn(
"Observation.check_kirchoff Impossible to get shunt information. Reactive information might be "
"incorrect."
)
diff_v_bus = np.zeros((cls.n_sub, cls.n_busbar_per_sub), dtype=dt_float)
diff_v_bus[:, :] = v_bus[:, :, 1] - v_bus[:, :, 0]
return p_subs, q_subs, p_bus, q_bus, diff_v_bus

0 comments on commit e9d1d5b

Please sign in to comment.