Skip to content

Commit 0013aa9

Browse files
committed
Changes following review in upstream repository
Signed-off-by: Giovanni Ferrari <giovanni.ferrari@soft.it>
1 parent f1e92ee commit 0013aa9

5 files changed

Lines changed: 289 additions & 281 deletions

File tree

‎grid2op/Environment/EnvInterface.py‎

Lines changed: 0 additions & 272 deletions
Original file line numberDiff line numberDiff line change
@@ -24,278 +24,6 @@ def reset(self,
2424
*,
2525
seed: Union[int, None] = None,
2626
options: RESET_OPTIONS_TYPING = None) -> BaseObservation:
27-
"""
28-
Reset the environment to a clean state.
29-
It will reload the next chronics if any. And reset the grid to a clean state.
30-
31-
This triggers a full reloading of both the chronics (if they are stored as files) and of the powergrid,
32-
to ensure the episode is fully over.
33-
34-
This method should be called only at the end of an episode.
35-
36-
Parameters
37-
----------
38-
seed: int
39-
The seed to used (new in version 1.9.8), see examples for more details. Ignored if not set (meaning no seeds will
40-
be used, experiments might not be reproducible)
41-
42-
options: dict
43-
Some options to "customize" the reset call. For example (see detailed example bellow) :
44-
45-
- "time serie id" (grid2op >= 1.9.8) to use a given time serie from the input data
46-
- "init state" that allows you to apply a given "action" when generating the
47-
initial observation (grid2op >= 1.10.2)
48-
- "init ts" (grid2op >= 1.10.3) to specify to which "steps" of the time series
49-
the episode will start
50-
- "max step" (grid2op >= 1.10.3) : maximum number of steps allowed for the episode
51-
- "thermal limit" (grid2op >= 1.11.0): which thermal limit to use for this episode
52-
(and the next ones, until they are changed)
53-
- "init datetime": which time stamp is used in the first observation of the episode.
54-
55-
See examples for more information about this. Ignored if
56-
not set.
57-
58-
Examples
59-
--------
60-
The standard "gym loop" can be done with the following code:
61-
62-
.. code-block:: python
63-
64-
import grid2op
65-
66-
# create the environment
67-
env_name = "l2rpn_case14_sandbox"
68-
env = grid2op.make(env_name)
69-
70-
# start a new episode
71-
obs = env.reset()
72-
done = False
73-
reward = env.reward_range[0]
74-
while not done:
75-
action = agent.act(obs, reward, done)
76-
obs, reward, done, info = env.step(action)
77-
78-
.. versionadded:: 1.9.8
79-
It is now possible to set the seed and the time series you want to use at the new
80-
episode by calling `env.reset(seed=..., options={"time serie id": ...})`
81-
82-
Before version 1.9.8, if you wanted to use a fixed seed, you would need to (see
83-
doc of :func:`grid2op.Environment.BaseEnv.seed` ):
84-
85-
.. code-block:: python
86-
87-
seed = ...
88-
env.seed(seed)
89-
obs = env.reset()
90-
...
91-
92-
Starting from version 1.9.8 you can do this in one call:
93-
94-
.. code-block:: python
95-
96-
seed = ...
97-
obs = env.reset(seed=seed)
98-
99-
For the "time series id" it is the same concept. Before you would need to do (see
100-
doc of :func:`Environment.set_id` for more information ):
101-
102-
.. code-block:: python
103-
104-
time_serie_id = ...
105-
env.set_id(time_serie_id)
106-
obs = env.reset()
107-
...
108-
109-
And now (from version 1.9.8) you can more simply do:
110-
111-
.. code-block:: python
112-
113-
time_serie_id = ...
114-
obs = env.reset(options={"time serie id": time_serie_id})
115-
...
116-
117-
.. versionadded:: 1.10.2
118-
119-
Another feature has been added in version 1.10.2, which is the possibility to set the
120-
grid to a given "topological" state at the first observation (before this version,
121-
you could only retrieve an observation with everything connected together).
122-
123-
In grid2op 1.10.2, you can do that by using the keys `"init state"` in the "options" kwargs of
124-
the reset function. The value associated to this key should be dictionnary that can be
125-
converted to a non ambiguous grid2op action using an "action space".
126-
127-
.. note::
128-
The "action space" used here is not the action space of the agent. It's an "action
129-
space" that uses a :func:`grid2op.Action.Action.BaseAction` class meaning you can do any
130-
type of action, on shunts, on topology, on line status etc. even if the agent is not
131-
allowed to.
132-
133-
Likewise, nothing check if this action is legal or not.
134-
135-
You can use it like this:
136-
137-
.. code-block:: python
138-
139-
# to start an episode with a line disconnected, you can do:
140-
init_state_dict = {"set_line_status": [(0, -1)]}
141-
obs = env.reset(options={"init state": init_state_dict})
142-
obs.line_status[0] is False
143-
144-
# to start an episode with a different topolovy
145-
init_state_dict = {"set_bus": {"lines_or_id": [(0, 2)], "lines_ex_id": [(3, 2)]}}
146-
obs = env.reset(options={"init state": init_state_dict})
147-
148-
.. note::
149-
Since grid2op version 1.10.2, there is also the possibility to set the "initial state"
150-
of the grid directly in the time series. The priority is always given to the
151-
argument passed in the "options" value.
152-
153-
Concretely if, in the "time series" (formelly called "chronics") provides an action would change
154-
the topology of substation 1 and 2 (for example) and you provide an action that disable the
155-
line 6, then the initial state will see substation 1 and 2 changed (as in the time series)
156-
and line 6 disconnected.
157-
158-
Another example in this case: if the action you provide would change topology of substation 2 and 4
159-
then the initial state (after `env.reset`) will give:
160-
161-
- substation 1 as in the time serie
162-
- substation 2 as in "options"
163-
- substation 4 as in "options"
164-
165-
.. note::
166-
Concerning the previously described behaviour, if you want to ignore the data in the
167-
time series, you can add : `"method": "ignore"` in the dictionary describing the action.
168-
In this case the action in the time series will be totally ignored and the initial
169-
state will be fully set by the action passed in the "options" dict.
170-
171-
An example is:
172-
173-
.. code-block:: python
174-
175-
init_state_dict = {"set_line_status": [(0, -1)], "method": "force"}
176-
obs = env.reset(options={"init state": init_state_dict})
177-
obs.line_status[0] is False
178-
179-
.. versionadded:: 1.10.3
180-
181-
Another feature has been added in version 1.10.3, the possibility to skip the
182-
some steps of the time series and starts at some given steps.
183-
184-
The time series often always start at a given day of the week (*eg* Monday)
185-
and at a given time (*eg* midnight). But for some reason you notice that your
186-
agent performs poorly on other day of the week or time of the day. This might be
187-
because it has seen much more data from Monday at midnight that from any other
188-
day and hour of the day.
189-
190-
To alleviate this issue, you can now easily reset an episode and ask grid2op
191-
to start this episode after xxx steps have "passed".
192-
193-
Concretely, you can do it with:
194-
195-
.. code-block:: python
196-
197-
import grid2op
198-
env_name = "l2rpn_case14_sandbox"
199-
env = grid2op.make(env_name)
200-
201-
obs = env.reset(options={"init ts": 1})
202-
203-
Doing that your agent will start its episode not at midnight (which
204-
is the case for this environment), but at 00:05
205-
206-
If you do:
207-
208-
.. code-block:: python
209-
210-
obs = env.reset(options={"init ts": 12})
211-
212-
In this case, you start the episode at 01:00 and not at midnight (you
213-
start at what would have been the 12th steps)
214-
215-
If you want to start the "next day", you can do:
216-
217-
.. code-block:: python
218-
219-
obs = env.reset(options={"init ts": 288})
220-
221-
etc.
222-
223-
.. note::
224-
On this feature, if a powerline is on soft overflow (meaning its flow is above
225-
the limit but below the :attr:`grid2op.Parameters.Parameters.HARD_OVERFLOW_THRESHOLD` * `the limit`)
226-
then it is still connected (of course) and the counter
227-
:attr:`grid2op.Observation.BaseObservation.timestep_overflow` is at 0.
228-
229-
If a powerline is on "hard overflow" (meaning its flow would be above
230-
:attr:`grid2op.Parameters.Parameters.HARD_OVERFLOW_THRESHOLD` * `the limit`), then, as it is
231-
the case for a "normal" (without options) reset, this line is disconnected, but can be reconnected
232-
directly (:attr:`grid2op.Observation.BaseObservation.time_before_cooldown_line` == 0)
233-
234-
.. seealso::
235-
The function :func:`Environment.fast_forward_chronics` for an alternative usage (that will be
236-
deprecated at some point)
237-
238-
Yet another feature has been added in grid2op version 1.10.3 in this `env.reset` function. It is
239-
the capacity to limit the duration of an episode.
240-
241-
.. code-block:: python
242-
243-
import grid2op
244-
env_name = "l2rpn_case14_sandbox"
245-
env = grid2op.make(env_name)
246-
247-
obs = env.reset(options={"max step": 288})
248-
249-
This will limit the duration to 288 steps (1 day), meaning your agent
250-
will have successfully managed the entire episode if it manages to keep
251-
the grid in a safe state for a whole day (depending on the environment you are
252-
using the default duration is either one week - roughly 2016 steps or 4 weeks)
253-
254-
.. note::
255-
This option only affect the current episode. It will have no impact on the
256-
next episode (after reset)
257-
258-
For example:
259-
260-
.. code-block:: python
261-
262-
obs = env.reset()
263-
obs.max_step == 8064 # default for this environment
264-
265-
obs = env.reset(options={"max step": 288})
266-
obs.max_step == 288 # specified by the option
267-
268-
obs = env.reset()
269-
obs.max_step == 8064 # retrieve the default behaviour
270-
271-
.. seealso::
272-
The function :func:`Environment.set_max_iter` for an alternative usage with the different
273-
that `set_max_iter` is permenanent: it impacts all the future episodes and not only
274-
the next one.
275-
276-
If you want your environment to start at a given time stamp you can do:
277-
278-
.. code-block:: python
279-
280-
import grid2op
281-
env_name = "l2rpn_case14_sandbox"
282-
283-
env = grid2op.make(env_name)
284-
obs = env.reset(options={"init datetime": "2024-12-06 00:00"})
285-
obs.year == 2024
286-
obs.month == 12
287-
obs.day == 6
288-
289-
.. seealso::
290-
If you specify "init datetime" then the observation resulting to the
291-
`env.reset` call will have this datetime. If you specify also `"skip ts"`
292-
option the behaviour does not change: the first observation will
293-
have the date time attributes you specified.
294-
295-
In other words, the "init datetime" refers to the initial observation of the
296-
episode and NOT the initial time present in the time series.
297-
298-
"""
29927
pass
30028

30129
@abstractmethod

‎grid2op/Environment/EnvRecorder.py‎

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,14 @@
1010
from datetime import datetime
1111
from pathlib import Path
1212
from typing import Tuple, Union, Callable, List
13+
try:
14+
import pyarrow as pa
15+
import pyarrow.parquet
16+
except ImportError:
17+
print("pyarrow is not installed. Please install it to use EnvRecorder.")
18+
import sys
19+
sys.exit(1)
1320

14-
import pyarrow as pa
15-
import pyarrow.parquet
1621

1722
from grid2op.Action import BaseAction
1823
from grid2op.Environment.EnvInterface import EnvInterface
@@ -119,6 +124,8 @@ class EnvRecorder(EnvInterface):
119124
This class serves as a wrapper for a given environment and records its
120125
observations into Parquet files for later analysis. It ensures that environment
121126
data such as observations are properly stored in a structured format.
127+
All the genrated Parquet files are stored in the configured output directory.
128+
This class does not save simulation (obs.simulate) or forecast (obs.get_forecast_env) data.
122129
123130
Attributes
124131
----------
@@ -139,6 +146,7 @@ def __init__(self, env, directory: Path, write_chunk_size: int = 1000):
139146
# env general data
140147
env_data = {
141148
"grid2op_version": GRID2OP_CURRENT_VERSION_STR,
149+
"env_grid2op_version": type(env).glop_version,
142150
"name": env.name,
143151
"path": self._env._init_env_path,
144152
"backend": self._env.backend.__class__.__name__,
@@ -149,11 +157,11 @@ def __init__(self, env, directory: Path, write_chunk_size: int = 1000):
149157
json.dump(env_data, f, indent=4)
150158

151159
# one table for each kind of element
152-
self.write_element_table([env.name_gen, env.gen_type, env.gen_to_subid], ['name', 'type', 'gen_to_subid'], directory, 'gen')
153-
self.write_element_table([env.name_load, env.load_to_subid], ['name', 'load_to_subid'], directory, 'load')
160+
self.write_element_table([env.name_gen, env.gen_type, env.gen_to_subid, env.gen_pos_topo_vect], ['name', 'type', 'gen_to_subid', 'gen_pos_topo_vect'], directory, 'gen')
161+
self.write_element_table([env.name_load, env.load_to_subid, env.load_pos_topo_vect], ['name', 'load_to_subid', 'load_pos_topo_vect'], directory, 'load')
154162
self.write_element_table([env.name_shunt, env.shunt_to_subid], ['name', 'shunt_to_subid'], directory, 'shunt')
155-
self.write_element_table([env.name_storage, env.storage_to_subid], ['name', 'storage_to_subid'], directory, 'storage')
156-
self.write_element_table([env.name_line, env.line_or_to_subid, env.line_ex_to_subid], ['name', 'line_or_to_subid', 'line_ex_to_subid'], directory, 'line')
163+
self.write_element_table([env.name_storage, env.storage_to_subid, env.storage_pos_topo_vect], ['name', 'storage_to_subid', 'storage_pos_topo_vect'], directory, 'storage')
164+
self.write_element_table([env.name_line, env.line_or_to_subid, env.line_ex_to_subid, env.line_or_pos_topo_vect, env.line_ex_pos_topo_vect], ['name', 'line_or_to_subid', 'line_ex_to_subid', 'line_or_pos_topo_vect', 'line_ex_pos_topo_vect'], directory, 'line')
157165

158166
# one table per element attributs.
159167
self._tables = [

‎grid2op/Environment/baseEnv.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@
9191
# WE DO NOT RECOMMEND TO ALTER IT IN ANY WAY
9292
"""
9393

94-
class BaseEnv(EnvInterface, GridObjects, RandomObject, ABC):
94+
class BaseEnv(GridObjects, EnvInterface, RandomObject, ABC):
9595
"""
9696
INTERNAL
9797

0 commit comments

Comments
 (0)