Skip to content

Commit

Permalink
Merge pull request #68 from BDonnot/master
Browse files Browse the repository at this point in the history
v 0.8.1
  • Loading branch information
BDonnot authored May 6, 2020
2 parents 537b5cc + 5cdd99b commit 31d673c
Show file tree
Hide file tree
Showing 24 changed files with 292 additions and 86 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -197,3 +197,5 @@ getting_started/tf_logs_DDDQN/
getting_started/logs-train/
getting_started/saved_agent_DDDQN_1000/
grid2op/tests.npz
my_runner_output_dir/
test_episode_data.py
9 changes: 9 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ Change Log
- [???] modeled dumps in grid2op (stuff that have a given energy max, and cannot produce more than the available energy)
- [???] fix notebook 5 texts

[0.8.1] - 2020-05-05
----------------------
- [FIXED] `Issue #65 <https://github.com/rte-france/Grid2Op/issues/65>`_: now the length of the Episode Data is properly
computed
- [FIXED] `Issue #66 <https://github.com/rte-france/Grid2Op/issues/66>`_: runner is now compatible with multiprocessing
again
- [FIXED] `Issue #67 <https://github.com/rte-france/Grid2Op/issues/67>`_: L2RPNSandBoxReward is now properly computed
- [FIXED] Serialization / de serialization of Parameters as json is now fixed

[0.8.0] - 2020-05-04
----------------------
- [BREAKING] All previously deprecated features have been removed
Expand Down
2 changes: 2 additions & 0 deletions grid2op/Backend/Backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ class Backend(GridObjects, ABC):
Thermal limit of the powerline in amps for each powerline. Thie thermal limit is relevant on only one
side of the powerline: the same side returned by :func:`Backend.get_line_overflow`
"""
env_name = "unknown"

def __init__(self, detailed_infos_for_cascading_failures=False):
"""
Initialize an instance of Backend. This does nothing per se. Only the call to :func:`Backend.load_grid`
Expand Down
7 changes: 5 additions & 2 deletions grid2op/Download/download.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,11 @@ def download_cli():
print("Argument \"--path_save\" should be a valid path (directory) on your machine.")
sys.exit(1)

main_download(dataset_name, path_data)

try:
main_download(dataset_name, path_data)
except Exception as e:
sys.exit("Aborted")


if __name__ == "__main__":
download_cli()
12 changes: 10 additions & 2 deletions grid2op/Environment/Environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
import numpy as np
import os
import copy
import warnings
import pdb
import collections

from grid2op.dtypes import dt_int, dt_float, dt_bool
from grid2op.Action import ActionSpace, BaseAction, TopologyAction, DontAct, CompleteAction
Expand All @@ -22,7 +22,6 @@
from grid2op.VoltageControler import ControlVoltageFromFile, BaseVoltageController
from grid2op.Environment.BaseEnv import BaseEnv
from grid2op.Opponent import BaseOpponent
from grid2op.Space import GridObjects

# TODO code "start from a given time step" -> link to the "skip" method of GridValue

Expand Down Expand Up @@ -115,6 +114,7 @@ def __init__(self,
chronics_handler,
backend,
parameters,
name="unknown",
names_chronics_to_backend=None,
actionClass=TopologyAction,
observationClass=CompleteObservation,
Expand All @@ -135,6 +135,10 @@ def __init__(self,
epsilon_poly=epsilon_poly,
tol_poly=tol_poly,
other_rewards=other_rewards)
if name == "unknown":
warnings.warn("It is NOT recommended to create an environment without \"make\" and EVEN LESS "
"to use an environment without a name")
self.name = name

# the voltage controler
self.voltagecontrolerClass = voltagecontrolerClass
Expand Down Expand Up @@ -203,8 +207,10 @@ def init_backend(self,

self.backend.load_redispacthing_data(os.path.split(self.init_grid_path)[0])
self.backend.load_grid_layout(os.path.split(self.init_grid_path)[0])
self.backend.set_env_name(self.name)

self.backend.assert_grid_correct()

self._has_been_initialized() # really important to include this piece of code!

if self._thermal_limit_a is None:
Expand Down Expand Up @@ -648,6 +654,7 @@ def get_kwargs(self):
res["opponent_action_class"] = self.opponent_action_class
res["opponent_class"] = self.opponent_class
res["opponent_init_budget"] = self.opponent_init_budget
res["name"] = self.name
return res

def get_params_for_runner(self):
Expand Down Expand Up @@ -697,5 +704,6 @@ def get_params_for_runner(self):
res["opponent_class"] = self.opponent_class
res["opponent_init_budget"] = self.opponent_init_budget
res["grid_layout"] = self.grid_layout
res["name_env"] = self.name
# TODO make a test for that
return res
13 changes: 8 additions & 5 deletions grid2op/Episode/EpisodeData.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,14 @@ def __init__(self, actions=None, env_actions=None, observations=None, rewards=No
helper_action_env=None, path_save=None, disc_lines_templ=None,
logger=None, name=str(1), get_dataframes=None, other_rewards=[]):

self.actions = CollectionWrapper(actions, action_space, "actions")
self.observations = CollectionWrapper(observations, observation_space,
self.actions = CollectionWrapper(actions,
action_space,
"actions")
self.observations = CollectionWrapper(observations,
observation_space,
"observations")

self.env_actions = CollectionWrapper(env_actions, helper_action_env,
self.env_actions = CollectionWrapper(env_actions,
helper_action_env,
"env_actions")
self.other_rewards = other_rewards
self.observation_space = observation_space
Expand Down Expand Up @@ -157,7 +160,7 @@ def get_observations(self):
return self.observations.collection

def __len__(self):
return self.meta["chronics_max_timestep"]
return int(self.meta["chronics_max_timestep"])

@classmethod
def from_disk(cls, agent_path, name=str(1)):
Expand Down
1 change: 1 addition & 0 deletions grid2op/MakeEnv/MakeFromPath.py
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ def make_from_dataset_path(dataset_path="/", **kwargs):
chronics_handler=data_feeding,
backend=backend,
parameters=param,
name=name_env,
names_chronics_to_backend=names_chronics_to_backend,
actionClass=action_class,
observationClass=observation_class,
Expand Down
33 changes: 32 additions & 1 deletion grid2op/MakeEnv/MakeOld.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
import warnings
import pkg_resources

from grid2op.Environment import Environment
Expand Down Expand Up @@ -52,6 +53,35 @@
"chronics_class", "volagecontroler_class", "other_rewards",
'opponent_action_class', "opponent_class", "opponent_init_budget"}

ERR_MSG_KWARGS = {
"backend": "The backend of the environment (keyword \"backend\") must be an instance of grid2op.Backend",
"observation_class": "The type of observation of the environment (keyword \"observation_class\")" \
" must be a subclass of grid2op.BaseObservation",
"param": "The parameters of the environment (keyword \"param\") must be an instance of grid2op.Parameters",
"gamerules_class": "The type of rules of the environment (keyword \"gamerules_class\")" \
" must be a subclass of grid2op.BaseRules",
"reward_class": "The type of reward in the environment (keyword \"reward_class\") must be a subclass of grid2op.BaseReward",
"action_class": "The type of action of the environment (keyword \"action_class\") must be a subclass of grid2op.BaseAction",
"data_feeding_kwargs": "The argument to build the data generation process [chronics]" \
" (keyword \"data_feeding_kwargs\") should be a dictionnary.",
"chronics_class": "The argument to build the data generation process [chronics] (keyword \"chronics_class\")" \
" should be a class that inherit grid2op.Chronics.GridValue.",
"chronics_handler": "The argument to build the data generation process [chronics] (keyword \"data_feeding\")" \
" should be a class that inherit grid2op.ChronicsHandler.ChronicsHandler.",
"voltagecontroler_class": "The argument to build the online controler for chronics (keyword \"volagecontroler_class\")" \
" should be a class that inherit grid2op.VoltageControler.ControlVoltageFromFile.",
"names_chronics_to_grid": "The converter between names (keyword \"names_chronics_to_backend\") should be a dictionnary.",
"other_rewards": "The argument to build the online controler for chronics (keyword \"other_rewards\") "
"should be dictionnary.",
"opponent_action_class": "The argument used to build the \"opponent_action_class\" should be a class that "
"inherit from \"BaseAction\"",
"opponent_class": "The argument used to build the \"opponent_class\" should be a class that "
"inherit from \"BaseOpponent\"",
"opponent_init_budget": "The initial budget of the opponent \"opponent_init_budget\" should be a float",
"chronics_path": "The path where the data is located (keyword \"chronics_path\") should be a string.",
"grid_path": "The path where the grid is located (keyword \"grid_path\") should be a string."
}


def make_old(name_env="case14_realistic", **kwargs):
"""
Expand Down Expand Up @@ -375,7 +405,8 @@ def make_old(name_env="case14_realistic", **kwargs):
other_rewards=other_rewards,
opponent_action_class=opponent_action_class,
opponent_class=opponent_class,
opponent_init_budget=opponent_init_budget
opponent_init_budget=opponent_init_budget,
name=name_env
)

# update the thermal limit if any
Expand Down
38 changes: 22 additions & 16 deletions grid2op/Parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import os
import json
import warnings
import re

from grid2op.dtypes import dt_int, dt_float, dt_bool

Expand Down Expand Up @@ -120,15 +119,7 @@ def __init__(self, parameters_path=None):

if parameters_path is not None:
if os.path.isfile(parameters_path):
if re.search(".*\.json$", parameters_path) is not None:
with open(parameters_path) as f:
dict_ = json.load(f)
self._init_from_json(dict_)
else:
warn_msg = "Parameters: the file {} is not a supported file for loading " \
"parameters. Continuing with default _parameters."
warnings.warn(warn_msg.format(parameters_path))

self.init_from_json(parameters_path)
else:
warn_msg = "Parameters: the file {} is not found. Continuing with default parameters."
warnings.warn(warn_msg.format(parameters_path))
Expand Down Expand Up @@ -222,10 +213,28 @@ def to_dict(self):
res["NB_TIMESTEP_LINE_STATUS_REMODIF"] = int(self.NB_TIMESTEP_LINE_STATUS_REMODIF)
return res

def init_from_json(self, json_path):
"""
Set member attributes from a json file
Parameters
----------
json_path: ``str``
The complete (*ie.* path + filename) where the json file is located.
"""
try:
with open(json_path) as f:
dict_ = json.load(f)
self.init_from_dict(dict_)
except:
warn_msg = "Could not load from {}\n" \
"Continuing with default parameters"
warnings.warn(warn_msg.format(json_path))

@staticmethod
def init_from_json(json_path):
def from_json(json_path):
"""
Initializes the _parameters from a json path.
Create instance from a json path.
Parameters
----------
Expand All @@ -238,8 +247,5 @@ def init_from_json(json_path):
The _parameters initialized
"""
with open(json_path) as f:
dict_ = json.load(f)
res = Parameters()
res.init_from_dict(dict_)
res = Parameters(json_path)
return res
3 changes: 2 additions & 1 deletion grid2op/Reward/L2RPNSandBoxScore.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from grid2op.Reward.BaseReward import BaseReward
from grid2op.dtypes import dt_float


class L2RPNSandBoxScore(BaseReward):
"""
This score represent the L2RPN score.
Expand All @@ -32,7 +33,7 @@ def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous):
losses = np.sum(gen_p, dtype=dt_float) - np.sum(load_p, dtype=dt_float)

# compute the marginal cost
p_t = np.max(env.gen_cost_per_MW[env.gen_activeprod_t > 0.], dtype=dt_float)
p_t = np.max(env.gen_cost_per_MW[env.gen_activeprod_t > 0.]).astype(dt_float)

# redispatching amount
c_redispatching = dt_float(2.0) * self.alpha_redisph * np.sum(np.abs(env.actual_dispatch)) * p_t
Expand Down
9 changes: 7 additions & 2 deletions grid2op/Runner/Runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ def __init__(self,
# full path where grid state is located, eg "./data/test_Pandapower/case14.json"
init_grid_path: str,
path_chron, # path where chronics of injections are stored
name_env="unknown",
parameters_path=None,
names_chronics_to_backend=None,
actionClass=TopologyAction,
Expand Down Expand Up @@ -283,6 +284,8 @@ def __init__(self,
"""

self.name_env = name_env

if not isinstance(envClass, type):
raise Grid2OpException(
"Parameter \"envClass\" used to build the Runner should be a type (a class) and not an object "
Expand Down Expand Up @@ -466,7 +469,8 @@ def _new_env(self, chronics_handler, backend, parameters):
other_rewards=self._other_rewards,
opponent_action_class=self.opponent_action_class,
opponent_class=self.opponent_class,
opponent_init_budget=self.opponent_init_budget)
opponent_init_budget=self.opponent_init_budget,
name=self.name_env)

if self.thermal_limit_a is not None:
res.set_thermal_limit(self.thermal_limit_a)
Expand Down Expand Up @@ -601,7 +605,8 @@ def _run_one_episode(env, agent, logger, indx, path_save=None, pbar=False):
helper_action_env=env.helper_action_env,
path_save=path_save,
disc_lines_templ=disc_lines_templ,
logger=logger, name=env.chronics_handler.get_name(),
logger=logger,
name=env.chronics_handler.get_name(),
other_rewards=[])

episode.set_parameters(env)
Expand Down
15 changes: 14 additions & 1 deletion grid2op/Space/GridObjects.py
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,7 @@ class GridObjects:
# __is_init = False

# name of the objects
env_name = "unknown"
name_load = None
name_gen = None
name_line = None
Expand Down Expand Up @@ -1090,10 +1091,14 @@ def attach_layout(self, grid_layout):
"""
GridObjects.grid_layout = grid_layout

@classmethod
def set_env_name(cls, name):
cls.env_name = name

@classmethod
def init_grid(cls, gridobj):
"""
Initialize this :class:`GridObjects` instance with a provided instance.
Initialize this :class:`GridObjects` subclass with a provided class.
It does not perform any check on the validity of the `gridobj` parameters, but it guarantees that if `gridobj`
is a valid grid, then the initialization will lead to a valid grid too.
Expand All @@ -1104,6 +1109,10 @@ def init_grid(cls, gridobj):
The representation of the powergrid
"""
# nothing to do now that the value are class member
name_res = "{}_{}".format(cls.__name__, gridobj.env_name)
if name_res in globals():
return globals()[name_res]

class res(cls):
pass

Expand Down Expand Up @@ -1160,6 +1169,10 @@ class res(cls):
res.n_shunt = gridobj.n_shunt
res.name_shunt = gridobj.name_shunt
res.shunt_to_subid = gridobj.shunt_to_subid

res.__name__ = name_res
res.__qualname__ = "{}_{}".format(cls.__qualname__, gridobj.env_name)
globals()[name_res] = res
return res

def get_obj_connect_to(self, _sentinel=None, substation_id=None):
Expand Down
Loading

0 comments on commit 31d673c

Please sign in to comment.