Skip to content

Commit

Permalink
Merge pull request #663 from BDonnot/bd_dev
Browse files Browse the repository at this point in the history
Various fixes and additions
  • Loading branch information
BDonnot authored Nov 20, 2024
2 parents 2b6a03e + 4ac67de commit 8407f6d
Show file tree
Hide file tree
Showing 12 changed files with 396 additions and 72 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -101,14 +101,22 @@ Native multi agents support:
-----------------------
- [BREAKING] Change for `FromMultiEpisodeData` that disables the caching by default
when creating the data.
- [BREAKING] deprecation of `backend.check_kirchoff` in favor of `backend.check_kirchhoff`
(fix the typo in the name)
- [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 +130,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
20 changes: 16 additions & 4 deletions grid2op/Backend/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -897,9 +897,9 @@ def shunt_info(self) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
If not implemented it returns empty list.
Note that if there are shunt on the powergrid, it is recommended that this method should be implemented before
calling :func:`Backend.check_kirchoff`.
calling :func:`Backend.check_kirchhoff`.
If this method is implemented AND :func:`Backend.check_kirchoff` is called, the method
If this method is implemented AND :func:`Backend.check_kirchhoff` is called, the method
:func:`Backend.sub_from_bus_id` should also be implemented preferably.
Returns
Expand Down Expand Up @@ -1154,11 +1154,23 @@ def storage_deact_for_backward_comaptibility(self) -> None:
pass

def check_kirchoff(self) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
"""
.. versionchanged:: 1.11.0
Deprecated in favor of :attr:`Backend.check_kirchhoff` (no typo in the name this time)
"""
warnings.warn(message="please use backend.check_kirchhoff() instead", category=DeprecationWarning)
return self.check_kirchhoff()

def check_kirchhoff(self) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
"""
INTERNAL
.. warning:: /!\\\\ Internal, do not use unless you know what you are doing /!\\\\
.. versionadded:: 1.11.0
Fix the typo of the :attr:`Backend.check_kirchoff` function
Check that the powergrid respects kirchhoff's law.
This function can be called at any moment (after a powerflow has been run)
to make sure a powergrid is in a consistent state, or to perform
Expand Down Expand Up @@ -1402,7 +1414,7 @@ def check_kirchoff(self) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray
)
else:
warnings.warn(
"Backend.check_kirchoff Impossible to get shunt information. Reactive information might be "
"Backend.check_kirchhoff 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)
Expand Down Expand Up @@ -2027,7 +2039,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
183 changes: 179 additions & 4 deletions grid2op/Observation/baseObservation.py
Original file line number Diff line number Diff line change
Expand Up @@ -2391,7 +2391,7 @@ def get_energy_graph(self) -> networkx.Graph:
Examples
--------
The following code explains how to check that a grid meet the kirchoffs law (conservation of energy)
The following code explains how to check that a grid meet the Kirchhoffs law (conservation of energy)
.. code-block:: python
Expand Down Expand Up @@ -2428,8 +2428,8 @@ def get_energy_graph(self) -> networkx.Graph:
# the current node is the largest, so on the "extremity" side
p_lines += graph.edges[(k1, k2)]["p_ex"]
q_lines += graph.edges[(k1, k2)]["q_ex"]
assert abs(p_line - p_) <= 1e-5, "error for kirchoff's law for graph for P"
assert abs(q_line - q_) <= 1e-5, "error for kirchoff's law for graph for Q"
assert abs(p_line - p_) <= 1e-5, "error for Kirchhoff's law for graph for P"
assert abs(q_line - q_) <= 1e-5, "error for Kirchhoff's law for graph for Q"
"""
cls = type(self)
Expand Down Expand Up @@ -2920,7 +2920,7 @@ def get_elements_graph(self) -> networkx.DiGraph:
Examples
---------
You can use, for example to "check" Kirchoff Current Law (or at least that no energy is created
You can use, for example to "check" Kirchhoff Current Law (or at least that no energy is created
at none of the buses):
.. code-block:: python
Expand Down Expand Up @@ -4845,3 +4845,178 @@ 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 is not None and 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_kirchhoff(self) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
"""
Analogous to "backend.check_kirchhoff" 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]
some_kind_of_inf = 1_000_000_000.
v_bus[:,:,0] = some_kind_of_inf
v_bus[:,:,1] = -1 * some_kind_of_inf

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_power, # cst, eg. gen_p
np.zeros(cls.n_storage), # cst, eg. gen_q
None, # 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.shunt_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_kirchhoff 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]
diff_v_bus[np.abs(diff_v_bus - -2. * some_kind_of_inf) <= 1e-5 ] = 0. # disconnected bus
return p_subs, q_subs, p_bus, q_bus, diff_v_bus

Loading

0 comments on commit 8407f6d

Please sign in to comment.