def test_class_with_provided_instance_raises(self): with self.assertRaises(EnvError): _get_default_aux('param', {}, str, defaultClass=str, defaultinstance="strinstance", isclass=True)
def test_no_default_provided_raises(self): with self.assertRaises(EnvError): _get_default_aux('param', {}, str, defaultinstance=None, defaultClass=None, isclass=False)
def test_class_with_provided_build_kwargs_raises(self): with self.assertRaises(EnvError): _get_default_aux('param', {}, str, defaultClass=str, isclass=True, build_kwargs=['s', 't', 'r'])
def test_default_instance_and_class_raises(self): with self.assertRaises(EnvError): _get_default_aux('param', {}, str, defaultClass=str, defaultinstance="strinstance", isclass=False)
def test_default_instance_with_build_kwargs_raises(self): with self.assertRaises(EnvError): _get_default_aux('param', {}, str, defaultinstance="strinstance", isclass=False, build_kwargs=['s', 't', 'r'])
def test_type_is_instance_raises(self): with self.assertRaises(EnvError): kwargs = {"param": 0} _get_default_aux('param', kwargs, defaultClassApp=int, isclass=True)
def test_type_not_subtype_of_defaultClassApp_raises(self): with self.assertRaises(EnvError): kwargs = {"param": str} _get_default_aux('param', kwargs, defaultClassApp=int, isclass=True)
def test_class_not_instance_of_defaultClassApp_raises(self): with self.assertRaises(EnvError): kwargs = {"param": int} _get_default_aux('param', kwargs, defaultClassApp=str, isclass=False)
def test_give_class_nodefault(self): kwargs = {"param": str} param = _get_default_aux('param', kwargs, defaultClass=str, defaultClassApp=str, msg_error="bad stuff", isclass=True) assert param == str, "This should have returned \"toto\""
def test_give_class_default(self): kwargs = {} param = _get_default_aux('param', kwargs, defaultClass=str, defaultClassApp=str, msg_error="bad stuff", isclass=True) assert param == str, "This should have returned the empty string"
def test_give_instance_nodefault(self): kwargs = {"param": "toto"} param = _get_default_aux('param', kwargs, defaultClass=str, defaultClassApp=str, msg_error="bad stuff", isclass=False) assert param == "toto", "This should have returned \"toto\""
def make_old(name_env="case14_realistic", **kwargs): """ .. warning:: /!\\\\ Internal, do not use unless you know what you are doing /!\\\\ (DEPRECATED) This function is a shortcut to rapidly create some (pre defined) environments within the grid2op Framework. For now, only the environment corresponding to the IEEE "case14" powergrid, with some pre defined chronics is available. Other environments, with different powergrids will be made available in the future. It mimic the ``gym.make`` function. Parameters ---------- name_env: ``str`` Name of the environment to create. param: ``grid2op.Parameters.Parameters``, optional Type of parameters used for the Environment. Parameters defines how the powergrid problem is cast into an markov decision process, and some internal backend: ``grid2op.Backend.Backend``, optional The backend to use for the computation. If provided, it must be an instance of :class:`grid2op.Backend.Backend`. action_class: ``type``, optional Type of BaseAction the BaseAgent will be able to perform. If provided, it must be a subclass of :class:`grid2op.BaseAction.BaseAction` observation_class: ``type``, optional Type of BaseObservation the BaseAgent will receive. If provided, It must be a subclass of :class:`grid2op.BaseAction.BaseObservation` reward_class: ``type``, optional Type of reward signal the BaseAgent will receive. If provided, It must be a subclass of :class:`grid2op.BaseReward.BaseReward` gamerules_class: ``type``, optional Type of "Rules" the BaseAgent need to comply with. Rules are here to model some operational constraints. If provided, It must be a subclass of :class:`grid2op.RulesChecker.BaseRules` grid_path: ``str``, optional The path where the powergrid is located. If provided it must be a string, and point to a valid file present on the hard drive. data_feeding_kwargs: ``dict``, optional Dictionnary that is used to build the `data_feeding` (chronics) objects. chronics_class: ``type``, optional The type of chronics that represents the dynamics of the Environment created. Usually they come from different folders. data_feeding: ``type``, optional The type of chronics handler you want to use. chronics_path: ``str`` Path where to look for the chronics dataset. volagecontroler_class: ``type``, optional The type of :class:`grid2op.VoltageControler.VoltageControler` to use, it defaults to other_rewards: ``dict``, optional Dictionnary with other rewards we might want to look at at during training. It is given as a dictionnary with keys the name of the reward, and the values a class representing the new variables. Returns ------- env: :class:`grid2op.Environment.Environment` The created environment. """ warnings.warn("make_old is deprecated. Please consider using make instead") for el in kwargs: if not el in ALLOWED_KWARGS_MAKE: raise EnvError( "Unknown keyword argument \"{}\" used to create an Environement. " "No Environment will be created. " "Accepted keyword arguments are {}".format( el, sorted(ALLOWED_KWARGS_MAKE))) # first extract parameters that doesn't not depend on the powergrid ## the parameters of the game, thermal limits threshold, simulate cascading failure, powerflow mode etc. (the gamification of the game) msg_error = "The parameters of the environment (keyword \"param\") must be an instance of grid2op.Parameters" param = _get_default_aux('param', kwargs, defaultClass=Parameters, defaultClassApp=Parameters, msg_error=msg_error) ## the backend use, to compute the powerflow msg_error = "The backend of the environment (keyword \"backend\") must be an instance of grid2op.Backend" backend = _get_default_aux("backend", kwargs, defaultClass=PandaPowerBackend, defaultClassApp=Backend, msg_error=msg_error) ## type of observation the agent will receive msg_error = "The type of observation of the environment (keyword \"observation_class\")" msg_error += " must be a subclass of grid2op.BaseObservation" observation_class = _get_default_aux("observation_class", kwargs, defaultClass=CompleteObservation, defaultClassApp=BaseObservation, msg_error=msg_error, isclass=True) ## type of rules of the game (mimic the operationnal constraints) msg_error = "The path where the data is located (keyword \"chronics_path\") should be a string." chronics_path = _get_default_aux("chronics_path", kwargs, defaultClassApp=str, defaultinstance='', msg_error=msg_error) # bulid the default parameters for each case file data_feeding_default_class = ChronicsHandler gamerules_class = AlwaysLegal defaultinstance_chronics_kwargs = {} if name_env.lower() == "case14_fromfile": default_grid_path = CASE_14_FILE if chronics_path == '': chronics_path = CHRONICS_MLUTIEPISODE defaultinstance_chronics_kwargs = { "chronicsClass": Multifolder, "path": chronics_path, "gridvalueClass": GridStateFromFileWithForecasts } default_name_converter = {} default_action_class = TopologyAction default_reward_class = L2RPNReward elif name_env.lower() == "l2rpn_2019": warnings.warn( "You are using the \"l2rpn_2019\" environmnet, which will be remove from this package in " "future versions. Please use \"make_new\" to download the real l2rpn dataset." ) if chronics_path == '': msg_error = "Default chronics (provided in this package) cannot be used with the environment " msg_error += "\"l2rpn_2019\". Please download the training data using either the method described in" \ "Grid2Op/l2rpn_2019/README.md (if you downloaded the github repository) or\n" \ "running the command line script (in a terminal):\n" \ "python -m grid2op.download --name \"l2rpn_2019\" --path_save PATH\WHERE\YOU\WANT\TO\DOWNLOAD" raise EnvError(msg_error) default_grid_path = L2RPN2019_CASEFILE defaultinstance_chronics_kwargs = { "chronicsClass": Multifolder, "path": chronics_path, "gridvalueClass": ReadPypowNetData } default_name_converter = L2RPN2019_DICT_NAMES default_action_class = TopologyAction default_reward_class = L2RPNReward gamerules_class = DefaultRules elif name_env.lower() == "case5_example": if chronics_path == '': chronics_path = EXAMPLE_CHRONICSPATH default_grid_path = EXAMPLE_CASEFILE defaultinstance_chronics_kwargs = { "chronicsClass": Multifolder, "path": chronics_path, "gridvalueClass": GridStateFromFileWithForecasts } default_name_converter = {} default_action_class = TopologyAction default_reward_class = L2RPNReward gamerules_class = DefaultRules elif name_env.lower() == "case14_test": if chronics_path == '': chronics_path = case14_test_CHRONICSPATH warnings.warn( "Your are using a case designed for testing purpose. Consider using the \"case14_redisp\" " "environment instead.") default_grid_path = case14_test_CASEFILE defaultinstance_chronics_kwargs = { "chronicsClass": Multifolder, "path": chronics_path, "gridvalueClass": GridStateFromFileWithForecasts } default_name_converter = {} default_action_class = TopologyAndDispatchAction default_reward_class = RedispReward gamerules_class = DefaultRules elif name_env.lower() == "case14_redisp": if chronics_path == '': chronics_path = case14_redisp_CHRONICSPATH warnings.warn( "Your are using only 2 chronics for this environment. More can be download by running, " "from a command line:\n" "python -m grid2op.download --name \"case14_redisp\" " "--path_save PATH\WHERE\YOU\WANT\TO\DOWNLOAD\DATA") default_grid_path = case14_redisp_CASEFILE defaultinstance_chronics_kwargs = { "chronicsClass": Multifolder, "path": chronics_path, "gridvalueClass": GridStateFromFileWithForecasts } default_name_converter = {} default_action_class = TopologyAndDispatchAction default_reward_class = RedispReward gamerules_class = DefaultRules elif name_env.lower() == "case14_realistic": if chronics_path == '': chronics_path = case14_real_CHRONICSPATH warnings.warn( "Your are using only 2 chronics for this environment. More can be download by running, " "from a command line:\n" "python -m grid2op.download --name \"case14_realistic\" " "--path_save PATH\WHERE\YOU\WANT\TO\DOWNLOAD\DATA") default_grid_path = case14_real_CASEFILE defaultinstance_chronics_kwargs = { "chronicsClass": Multifolder, "path": chronics_path, "gridvalueClass": GridStateFromFileWithForecasts } default_name_converter = {} default_action_class = TopologyAndDispatchAction default_reward_class = RedispReward gamerules_class = DefaultRules elif name_env.lower() == "blank": default_name_converter = {} default_grid_path = "" default_action_class = TopologyAction default_reward_class = L2RPNReward gamerules_class = AlwaysLegal else: raise UnknownEnv( "Unknown Environment named \"{}\". Current known environments are \"case14_fromfile\" " "(default), \"case5_example\", \"case14_redisp\", \"case14_realistic\" " "and \"l2rpn_2019\"".format(name_env)) if "chronicsClass" not in defaultinstance_chronics_kwargs: defaultinstance_chronics_kwargs["chronicsClass"] = ChangeNothing # extract powergrid dependant parameters ## type of rules of the game (mimic the operationnal constraints) msg_error = "The type of rules of the environment (keyword \"gamerules_class\")" msg_error += " must be a subclass of grid2op.BaseRules" gamerules_class = _get_default_aux("gamerules_class", kwargs, defaultClass=gamerules_class, defaultClassApp=BaseRules, msg_error=msg_error, isclass=True) ## type of reward the agent will receive msg_error = "The type of observation of the environment (keyword \"reward_class\")" msg_error += " must be a subclass of grid2op.BaseReward" reward_class = _get_default_aux("reward_class", kwargs, defaultClass=default_reward_class, defaultClassApp=BaseReward, msg_error=msg_error, isclass=True) ## type of action the BaseAgent can perform msg_error = "The type of action of the environment (keyword \"action_class\") must be a subclass of grid2op.BaseAction" action_class = _get_default_aux("action_class", kwargs, defaultClass=default_action_class, defaultClassApp=BaseAction, msg_error=msg_error, isclass=True) ## the powergrid path to use msg_error = "The path where the grid is located (keyword \"grid_path\") should be a string." grid_path = _get_default_aux("grid_path", kwargs, defaultClassApp=str, defaultinstance=default_grid_path, msg_error=msg_error) ## msg_error = "The converter between names (keyword \"names_chronics_to_backend\") should be a dictionnary." names_chronics_to_backend = _get_default_aux( "names_chronics_to_backend", kwargs, defaultClassApp=dict, defaultinstance=default_name_converter, msg_error=msg_error) ## the chronics to use ### the arguments used to build the data, note that the arguments must be compatible with the chronics class msg_error = "The argument to build the data generation process [chronics] (keyword \"data_feeding_kwargs\")" msg_error += " should be a dictionnary." data_feeding_kwargs = _get_default_aux( "data_feeding_kwargs", kwargs, defaultClassApp=dict, defaultinstance=defaultinstance_chronics_kwargs, msg_error=msg_error) for el in defaultinstance_chronics_kwargs: if not el in data_feeding_kwargs: data_feeding_kwargs[el] = defaultinstance_chronics_kwargs[el] ### the chronics generator msg_error = "The argument to build the data generation process [chronics] (keyword \"chronics_class\")" msg_error += " should be a class that inherit grid2op.ChronicsHandler.GridValue." chronics_class_used = _get_default_aux( "chronics_class", kwargs, defaultClassApp=GridValue, defaultClass=data_feeding_kwargs["chronicsClass"], msg_error=msg_error, isclass=True) data_feeding_kwargs["chronicsClass"] = chronics_class_used ### the chronics generator msg_error = "The argument to build the data generation process [chronics] (keyword \"data_feeding\")" msg_error += " should be a class that inherit grid2op.ChronicsHandler.ChronicsHandler." data_feeding = _get_default_aux("data_feeding", kwargs, defaultClassApp=ChronicsHandler, defaultClass=data_feeding_default_class, build_kwargs=data_feeding_kwargs, msg_error=msg_error) ### controler for voltages msg_error = "The argument to build the online controler for chronics (keyword \"volagecontroler_class\")" msg_error += " should be a class that inherit grid2op.VoltageControler.ControlVoltageFromFile." volagecontroler_class = _get_default_aux( "volagecontroler_class", kwargs, defaultClassApp=ControlVoltageFromFile, defaultClass=ControlVoltageFromFile, msg_error=msg_error, isclass=True) ### other rewards msg_error = "The argument to build the online controler for chronics (keyword \"other_rewards\")" msg_error += " should be dictionnary." other_rewards = _get_default_aux("other_rewards", kwargs, defaultClassApp=dict, defaultinstance={}, msg_error=msg_error, isclass=False) # Opponent opponent_action_class = _get_default_aux( "opponent_action_class", kwargs, defaultClassApp=BaseAction, defaultClass=DontAct, msg_error=ERR_MSG_KWARGS["opponent_action_class"], isclass=True) opponent_class = _get_default_aux( "opponent_class", kwargs, defaultClassApp=BaseOpponent, defaultClass=BaseOpponent, msg_error=ERR_MSG_KWARGS["opponent_class"], isclass=True) opponent_init_budget = _get_default_aux( "opponent_init_budget", kwargs, defaultClassApp=float, defaultinstance=0., msg_error=ERR_MSG_KWARGS["opponent_init_budget"], isclass=False) if not os.path.exists(grid_path): raise EnvError( "There is noting at \"{}\" where the powergrid should be located". format(os.path.abspath(grid_path))) env = Environment(init_grid_path=grid_path, chronics_handler=data_feeding, backend=backend, parameters=param, names_chronics_to_backend=names_chronics_to_backend, actionClass=action_class, observationClass=observation_class, rewardClass=reward_class, legalActClass=gamerules_class, voltagecontrolerClass=volagecontroler_class, other_rewards=other_rewards, opponent_action_class=opponent_action_class, opponent_class=opponent_class, opponent_init_budget=opponent_init_budget, name=name_env) # update the thermal limit if any if name_env.lower() == "case14_test": env.set_thermal_limit(case14_test_TH_LIM) env.attach_layout(CASE_14_L2RPN2019_LAYOUT) elif name_env.lower() == "case14_redisp": env.set_thermal_limit(case14_redisp_TH_LIM) env.attach_layout(CASE_14_L2RPN2019_LAYOUT) elif name_env.lower() == "case14_realistic": env.set_thermal_limit(case14_real_TH_LIM) env.attach_layout(CASE_14_L2RPN2019_LAYOUT) elif name_env.lower() == "l2rpn_2019": env.attach_layout(CASE_14_L2RPN2019_LAYOUT) elif name_env.lower() == "case5_example": env.attach_layout(CASE_5_GRAPH_LAYOUT) return env
def test_use_sentinel_arg_raises(self): with self.assertRaises(RuntimeError): _get_default_aux('param', {}, str, _sentinel=True)
def make_from_dataset_path(dataset_path="/", _add_to_name="", **kwargs): """ .. warning:: /!\\\\ Internal, do not use unless you know what you are doing /!\\\\ Prefer using the :func:`grid2op.make` function. This function is a shortcut to rapidly create environments within the grid2op Framework. We don't recommend using directly this function. Prefer using the :func:`make` function. It mimic the ``gym.make`` function. .. _Parameters-make-from-path: Parameters ---------- dataset_path: ``str`` Path to the dataset folder param: ``grid2op.Parameters.Parameters``, optional Type of parameters used for the Environment. Parameters defines how the powergrid problem is cast into an markov decision process, and some internal backend: ``grid2op.Backend.Backend``, optional The backend to use for the computation. If provided, it must be an instance of :class:`grid2op.Backend.Backend`. action_class: ``type``, optional Type of BaseAction the BaseAgent will be able to perform. If provided, it must be a subclass of :class:`grid2op.BaseAction.BaseAction` observation_class: ``type``, optional Type of BaseObservation the BaseAgent will receive. If provided, It must be a subclass of :class:`grid2op.BaseAction.BaseObservation` reward_class: ``type``, optional Type of reward signal the BaseAgent will receive. If provided, It must be a subclass of :class:`grid2op.BaseReward.BaseReward` other_rewards: ``dict``, optional Used to additional information than the "info" returned value after a call to env.step. gamerules_class: ``type``, optional Type of "Rules" the BaseAgent need to comply with. Rules are here to model some operational constraints. If provided, It must be a subclass of :class:`grid2op.RulesChecker.BaseRules` data_feeding_kwargs: ``dict``, optional Dictionnary that is used to build the `data_feeding` (chronics) objects. chronics_class: ``type``, optional The type of chronics that represents the dynamics of the Environment created. Usually they come from different folders. data_feeding: ``type``, optional The type of chronics handler you want to use. volagecontroler_class: ``type``, optional The type of :class:`grid2op.VoltageControler.VoltageControler` to use, it defaults to chronics_path: ``str`` Path where to look for the chronics dataset (optional) grid_path: ``str``, optional The path where the powergrid is located. If provided it must be a string, and point to a valid file present on the hard drive. difficulty: ``str``, optional the difficulty level. If present it starts from "0" the "easiest" but least realistic mode. In the case of the dataset being used in the l2rpn competition, the level used for the competition is "competition" ("hardest" and most realistic mode). If multiple difficulty levels are available, the most realistic one (the "hardest") is the default choice. opponent_action_class: ``type``, optional The action class used for the opponent. The opponent will not be able to use action that are invalid with the given action class provided. It defaults to :class:`grid2op.Action.DontAct` which forbid any type of action possible. opponent_class: ``type``, optional The opponent class to use. The default class is :class:`grid2op.Opponent.BaseOpponent` which is a type of opponents that does nothing. opponent_init_budget: ``float``, optional The initial budget of the opponent. It defaults to 0.0 which means the opponent cannot perform any action if this is not modified. opponent_attack_duration: ``int``, optional The number of time steps an attack from the opponent lasts. opponent_attack_cooldown: ``int``, optional The number of time steps the opponent as to wait for an attack. opponent_budget_per_ts: ``float``, optional The increase of the opponent budget per time step. Each time step the opponent see its budget increase. It defaults to 0.0. opponent_budget_class: ``type``, optional defaults: :class:`grid2op.Opponent.UnlimitedBudget` _add_to_name: Internal, used for test only. Do not attempt to modify under any circumstances. Returns ------- env: :class:`grid2op.Environment.Environment` The created environment with the given properties. """ # Compute and find root folder _check_path(dataset_path, "Dataset root directory") dataset_path_abs = os.path.abspath(dataset_path) # Compute env name from directory name name_env = os.path.split(dataset_path_abs)[1] # Compute and find chronics folder chronics_path = _get_default_aux("chronics_path", kwargs, defaultClassApp=str, defaultinstance='', msg_error=ERR_MSG_KWARGS["chronics_path"]) if chronics_path == "": # if no "chronics_path" argument is provided, look into the "chronics" folder chronics_path_abs = os.path.abspath( os.path.join(dataset_path_abs, NAME_CHRONICS_FOLDER)) else: # otherwise use it chronics_path_abs = os.path.abspath(chronics_path) _check_path(chronics_path_abs, "Dataset chronics folder") # Compute and find backend/grid file grid_path = _get_default_aux("grid_path", kwargs, defaultClassApp=str, defaultinstance="", msg_error=ERR_MSG_KWARGS["grid_path"]) if grid_path == "": grid_path_abs = os.path.abspath( os.path.join(dataset_path_abs, NAME_GRID_FILE)) else: grid_path_abs = os.path.abspath(grid_path) _check_path(grid_path_abs, "Dataset power flow solver configuration") # Compute and find grid layout file grid_layout_path_abs = os.path.abspath( os.path.join(dataset_path_abs, NAME_GRID_LAYOUT_FILE)) _check_path(grid_layout_path_abs, "Dataset grid layout") # Check provided config overrides are valid _check_kwargs(kwargs) # Compute and find config file config_path_abs = os.path.abspath( os.path.join(dataset_path_abs, NAME_CONFIG_FILE)) _check_path(config_path_abs, "Dataset environment configuration") # Read config file try: spec = importlib.util.spec_from_file_location("config.config", config_path_abs) config_module = importlib.util.module_from_spec(spec) spec.loader.exec_module(config_module) config_data = config_module.config except Exception as e: print(e) raise EnvError("Invalid dataset config file: {}".format( config_path_abs)) from None # Get graph layout try: with open(grid_layout_path_abs) as layout_fp: graph_layout = json.load(layout_fp) except Exception as e: raise EnvError("Dataset {} doesn't have a valid graph layout".format( config_path_abs)) # Get thermal limits thermal_limits = None if "thermal_limits" in config_data: thermal_limits = config_data["thermal_limits"] # Get chronics_to_backend name_converter = None if "names_chronics_to_grid" in config_data: name_converter = config_data["names_chronics_to_grid"] if name_converter is None: name_converter = {} names_chronics_to_backend = _get_default_aux( "names_chronics_to_backend", kwargs, defaultClassApp=dict, defaultinstance=name_converter, msg_error=ERR_MSG_KWARGS["names_chronics_to_grid"]) # Get default backend class backend_class_cfg = PandaPowerBackend if "backend_class" in config_data and config_data[ "backend_class"] is not None: backend_class_cfg = config_data["backend_class"] ## Create the backend, to compute the powerflow backend = _get_default_aux("backend", kwargs, defaultClass=backend_class_cfg, defaultClassApp=Backend, msg_error=ERR_MSG_KWARGS["backend"]) # Get default observation class observation_class_cfg = CompleteObservation if "observation_class" in config_data and config_data[ "observation_class"] is not None: observation_class_cfg = config_data["observation_class"] ## Setup the type of observation the agent will receive observation_class = _get_default_aux( "observation_class", kwargs, defaultClass=observation_class_cfg, isclass=True, defaultClassApp=BaseObservation, msg_error=ERR_MSG_KWARGS["observation_class"]) ## Create the parameters of the game, thermal limits threshold, # simulate cascading failure, powerflow mode etc. (the gamification of the game) if "param" in kwargs: param = _get_default_aux('param', kwargs, defaultClass=Parameters, defaultClassApp=Parameters, msg_error=ERR_MSG_KWARGS["param"]) else: # param is not in kwargs param = Parameters() json_path = os.path.join(dataset_path_abs, "difficulty_levels.json") if os.path.exists(json_path): with open(json_path, "r", encoding="utf-8") as f: dict_ = json.load(f) available_parameters = sorted(dict_.keys()) if DIFFICULTY_NAME in kwargs: # player enters a difficulty levels my_difficulty = kwargs[DIFFICULTY_NAME] try: my_difficulty = str(my_difficulty) except: raise EnvError( "Impossible to convert your difficulty into a valid string. Please make sure to " "pass a string (eg \"2\") and not something else (eg. int(2)) as a difficulty" ) if my_difficulty in dict_: param.init_from_dict(dict_[my_difficulty]) else: raise EnvError(ERR_MSG_KWARGS[DIFFICULTY_NAME].format( difficulty=my_difficulty, difficulties=available_parameters)) else: # no difficulty name provided, i need to chose the most suited one if CHALLENGE_NAME in dict_: param.init_from_dict(dict_[CHALLENGE_NAME]) else: # i chose the most difficult one available_parameters_int = {} for el in available_parameters: try: int_ = int(el) available_parameters_int[int_] = el except: pass max_ = np.max(list(available_parameters_int.keys())) keys_ = available_parameters_int[max_] param.init_from_dict(dict_[keys_]) else: json_path = os.path.join(dataset_path_abs, "parameters.json") if os.path.exists(json_path): param.init_from_json(json_path) # Get default rules class rules_class_cfg = DefaultRules if "rules_class" in config_data and config_data["rules_class"] is not None: rules_class_cfg = config_data["rules_class"] ## Create the rules of the game (mimic the operationnal constraints) gamerules_class = _get_default_aux( "gamerules_class", kwargs, defaultClass=rules_class_cfg, defaultClassApp=BaseRules, msg_error=ERR_MSG_KWARGS["gamerules_class"], isclass=True) # Get default reward class reward_class_cfg = L2RPNReward if "reward_class" in config_data and config_data[ "reward_class"] is not None: reward_class_cfg = config_data["reward_class"] ## Setup the reward the agent will receive reward_class = _get_default_aux("reward_class", kwargs, defaultClass=reward_class_cfg, defaultClassApp=BaseReward, msg_error=ERR_MSG_KWARGS["reward_class"], isclass=True) # Get default BaseAction class action_class_cfg = BaseAction if "action_class" in config_data and config_data[ "action_class"] is not None: action_class_cfg = config_data["action_class"] ## Setup the type of action the BaseAgent can perform action_class = _get_default_aux("action_class", kwargs, defaultClass=action_class_cfg, defaultClassApp=BaseAction, msg_error=ERR_MSG_KWARGS["action_class"], isclass=True) # Get default Voltage class voltage_class_cfg = ControlVoltageFromFile if "voltage_class" in config_data and config_data[ "voltage_class"] is not None: voltage_class_cfg = config_data["voltage_class"] ### Create controler for voltages volagecontroler_class = _get_default_aux( "volagecontroler_class", kwargs, defaultClassApp=voltage_class_cfg, defaultClass=ControlVoltageFromFile, msg_error=ERR_MSG_KWARGS["voltagecontroler_class"], isclass=True) # Get default Chronics class chronics_class_cfg = ChangeNothing if "chronics_class" in config_data and config_data[ "chronics_class"] is not None: chronics_class_cfg = config_data["chronics_class"] # Get default Grid class grid_value_class_cfg = GridStateFromFile if "grid_value_class" in config_data and config_data[ "grid_value_class"] is not None: grid_value_class_cfg = config_data["grid_value_class"] ## the chronics to use ### the arguments used to build the data, note that the arguments must be compatible with the chronics class default_chronics_kwargs = { "chronicsClass": chronics_class_cfg, "path": chronics_path_abs, "gridvalueClass": grid_value_class_cfg } data_feeding_kwargs = _get_default_aux( "data_feeding_kwargs", kwargs, defaultClassApp=dict, defaultinstance=default_chronics_kwargs, msg_error=ERR_MSG_KWARGS["data_feeding_kwargs"]) for el in default_chronics_kwargs: if not el in data_feeding_kwargs: data_feeding_kwargs[el] = default_chronics_kwargs[el] ### the chronics generator chronics_class_used = _get_default_aux( "chronics_class", kwargs, defaultClassApp=GridValue, defaultClass=data_feeding_kwargs["chronicsClass"], msg_error=ERR_MSG_KWARGS["chronics_class"], isclass=True) data_feeding_kwargs["chronicsClass"] = chronics_class_used data_feeding = _get_default_aux( "data_feeding", kwargs, defaultClassApp=ChronicsHandler, defaultClass=ChronicsHandler, build_kwargs=data_feeding_kwargs, msg_error=ERR_MSG_KWARGS["chronics_handler"]) ### other rewards other_rewards = _get_default_aux("other_rewards", kwargs, defaultClassApp=dict, defaultinstance={}, msg_error=ERR_MSG_KWARGS["other_rewards"], isclass=False) # Opponent chronics_class_cfg = DontAct if "opponent_action_class" in config_data and config_data[ "opponent_action_class"] is not None: chronics_class_cfg = config_data["opponent_action_class"] opponent_action_class = _get_default_aux( "opponent_action_class", kwargs, defaultClassApp=BaseAction, defaultClass=chronics_class_cfg, msg_error=ERR_MSG_KWARGS["opponent_action_class"], isclass=True) opponent_class_cfg = BaseOpponent if "opponent_class" in config_data and config_data[ "opponent_class"] is not None: opponent_class_cfg = config_data["opponent_class"] opponent_class = _get_default_aux( "opponent_class", kwargs, defaultClassApp=BaseOpponent, defaultClass=opponent_class_cfg, msg_error=ERR_MSG_KWARGS["opponent_class"], isclass=True) opponent_budget_class_cfg = NeverAttackBudget if "opponent_budget_class" in config_data and config_data[ "opponent_budget_class"] is not None: opponent_budget_class_cfg = config_data["opponent_budget_class"] opponent_budget_class = _get_default_aux( "opponent_budget_class", kwargs, defaultClassApp=BaseActionBudget, defaultClass=opponent_budget_class_cfg, msg_error=ERR_MSG_KWARGS["opponent_budget_class"], isclass=True) opponent_init_budget_cfg = 0. if "opponent_init_budget" in config_data and config_data[ "opponent_init_budget"] is not None: opponent_init_budget_cfg = config_data["opponent_init_budget"] opponent_init_budget = _get_default_aux( "opponent_init_budget", kwargs, defaultClassApp=float, defaultinstance=opponent_init_budget_cfg, msg_error=ERR_MSG_KWARGS["opponent_init_budget"], isclass=False) opponent_budget_per_ts_cfg = 0. if "opponent_budget_per_ts" in config_data and config_data[ "opponent_budget_per_ts"] is not None: opponent_budget_per_ts_cfg = config_data["opponent_budget_per_ts"] opponent_budget_per_ts = _get_default_aux( "opponent_budget_per_ts", kwargs, defaultClassApp=float, defaultinstance=opponent_budget_per_ts_cfg, msg_error=ERR_MSG_KWARGS["opponent_budget_per_ts"], isclass=False) opponent_attack_duration_cfg = 0 if "opponent_attack_duration" in config_data and config_data[ "opponent_attack_duration"] is not None: opponent_attack_duration_cfg = config_data["opponent_attack_duration"] opponent_attack_duration = _get_default_aux( "opponent_attack_duration", kwargs, defaultClassApp=int, defaultinstance=opponent_attack_duration_cfg, msg_error=ERR_MSG_KWARGS["opponent_attack_duration"], isclass=False) opponent_attack_cooldown_cfg = 99999 if "opponent_attack_cooldown" in config_data and config_data[ "opponent_attack_cooldown"] is not None: opponent_attack_cooldown_cfg = config_data["opponent_attack_cooldown"] opponent_attack_cooldown = _get_default_aux( "opponent_attack_cooldown", kwargs, defaultClassApp=int, defaultinstance=opponent_attack_cooldown_cfg, msg_error=ERR_MSG_KWARGS["opponent_attack_cooldown"], isclass=False) kwargs_opponent_cfg = {} if "kwargs_opponent" in config_data and config_data[ "kwargs_opponent"] is not None: kwargs_opponent_cfg = config_data["kwargs_opponent"] kwargs_opponent = _get_default_aux( "kwargs_opponent", kwargs, defaultClassApp=dict, defaultinstance=kwargs_opponent_cfg, msg_error=ERR_MSG_KWARGS["kwargs_opponent"], isclass=False) # Finally instanciate env from config & overrides env = Environment( init_grid_path=grid_path_abs, chronics_handler=data_feeding, backend=backend, parameters=param, name=name_env + _add_to_name, names_chronics_to_backend=names_chronics_to_backend, actionClass=action_class, observationClass=observation_class, rewardClass=reward_class, legalActClass=gamerules_class, voltagecontrolerClass=volagecontroler_class, other_rewards=other_rewards, opponent_action_class=opponent_action_class, opponent_class=opponent_class, opponent_init_budget=opponent_init_budget, opponent_attack_duration=opponent_attack_duration, opponent_attack_cooldown=opponent_attack_cooldown, opponent_budget_per_ts=opponent_budget_per_ts, opponent_budget_class=opponent_budget_class, kwargs_opponent=kwargs_opponent, ) # Update the thermal limit if any if thermal_limits is not None: env.set_thermal_limit(thermal_limits) # Set graph layout if not None and not an empty dict if graph_layout is not None and graph_layout: env.attach_layout(graph_layout) return env
def make_from_dataset_path(dataset_path="/", **kwargs): """ This function is a shortcut to rapidly create environments within the grid2op Framework. It mimic the ``gym.make`` function. Parameters ---------- dataset_path: ``str`` Path to the dataset folder param: ``grid2op.Parameters.Parameters``, optional Type of parameters used for the Environment. Parameters defines how the powergrid problem is cast into an markov decision process, and some internal backend: ``grid2op.Backend.Backend``, optional The backend to use for the computation. If provided, it must be an instance of :class:`grid2op.Backend.Backend`. action_class: ``type``, optional Type of BaseAction the BaseAgent will be able to perform. If provided, it must be a subclass of :class:`grid2op.BaseAction.BaseAction` observation_class: ``type``, optional Type of BaseObservation the BaseAgent will receive. If provided, It must be a subclass of :class:`grid2op.BaseAction.BaseObservation` reward_class: ``type``, optional Type of reward signal the BaseAgent will receive. If provided, It must be a subclass of :class:`grid2op.BaseReward.BaseReward` gamerules_class: ``type``, optional Type of "Rules" the BaseAgent need to comply with. Rules are here to model some operational constraints. If provided, It must be a subclass of :class:`grid2op.RulesChecker.BaseRules` data_feeding_kwargs: ``dict``, optional Dictionnary that is used to build the `data_feeding` (chronics) objects. chronics_class: ``type``, optional The type of chronics that represents the dynamics of the Environment created. Usually they come from different folders. data_feeding: ``type``, optional The type of chronics handler you want to use. volagecontroler_class: ``type``, optional The type of :class:`grid2op.VoltageControler.VoltageControler` to use, it defaults to chronics_path: ``str`` Path where to look for the chronics dataset (optional) grid_path: ``str``, optional The path where the powergrid is located. If provided it must be a string, and point to a valid file present on the hard drive. Returns ------- env: :class:`grid2op.Environment.Environment` The created environment. """ # Compute and find root folder _check_path(dataset_path, "Dataset root directory") dataset_path_abs = os.path.abspath(dataset_path) # Compute env name from directory name name_env = os.path.split(dataset_path_abs)[1] # Compute and find chronics folder chronics_path = _get_default_aux("chronics_path", kwargs, defaultClassApp=str, defaultinstance='', msg_error=ERR_MSG_KWARGS["chronics_path"]) if chronics_path == "": # if no "chronics_path" argument is provided, look into the "chronics" folder chronics_path_abs = os.path.abspath( os.path.join(dataset_path_abs, NAME_CHRONICS_FOLDER)) else: # otherwise use it chronics_path_abs = os.path.abspath(chronics_path) _check_path(chronics_path_abs, "Dataset chronics folder") # Compute and find backend/grid file grid_path = _get_default_aux("grid_path", kwargs, defaultClassApp=str, defaultinstance="", msg_error=ERR_MSG_KWARGS["grid_path"]) if grid_path == "": grid_path_abs = os.path.abspath( os.path.join(dataset_path_abs, NAME_GRID_FILE)) else: grid_path_abs = os.path.abspath(grid_path) _check_path(grid_path_abs, "Dataset power flow solver configuration") # Compute and find grid layout file grid_layout_path_abs = os.path.abspath( os.path.join(dataset_path_abs, NAME_GRID_LAYOUT_FILE)) _check_path(grid_layout_path_abs, "Dataset grid layout") # Check provided config overrides are valid _check_kwargs(kwargs) # Compute and find config file config_path_abs = os.path.abspath( os.path.join(dataset_path_abs, NAME_CONFIG_FILE)) _check_path(config_path_abs, "Dataset environment configuration") # Read config file try: spec = importlib.util.spec_from_file_location("config.config", config_path_abs) config_module = importlib.util.module_from_spec(spec) spec.loader.exec_module(config_module) config_data = config_module.config except Exception as e: print(e) raise EnvError("Invalid dataset config file: {}".format( config_path_abs)) from None # Get graph layout try: with open(grid_layout_path_abs) as layout_fp: graph_layout = json.load(layout_fp) except Exception as e: raise EnvError("Dataset {} doesn't have a valid graph layout".format( config_path_abs)) # Get thermal limits thermal_limits = None if "thermal_limits" in config_data: thermal_limits = config_data["thermal_limits"] # Get chronics_to_backend name_converter = None if "names_chronics_to_grid" in config_data: name_converter = config_data["names_chronics_to_grid"] if name_converter is None: name_converter = {} names_chronics_to_backend = _get_default_aux( "names_chronics_to_backend", kwargs, defaultClassApp=dict, defaultinstance=name_converter, msg_error=ERR_MSG_KWARGS["names_chronics_to_grid"]) # Get default backend class backend_class_cfg = PandaPowerBackend if "backend_class" in config_data and config_data[ "backend_class"] is not None: backend_class_cfg = config_data["backend_class"] ## Create the backend, to compute the powerflow backend = _get_default_aux("backend", kwargs, defaultClass=backend_class_cfg, defaultClassApp=Backend, msg_error=ERR_MSG_KWARGS["backend"]) # Get default observation class observation_class_cfg = CompleteObservation if "observation_class" in config_data and config_data[ "observation_class"] is not None: observation_class_cfg = config_data["observation_class"] ## Setup the type of observation the agent will receive observation_class = _get_default_aux( "observation_class", kwargs, defaultClass=observation_class_cfg, isclass=True, defaultClassApp=BaseObservation, msg_error=ERR_MSG_KWARGS["observation_class"]) ## Create the parameters of the game, thermal limits threshold, # simulate cascading failure, powerflow mode etc. (the gamification of the game) param = _get_default_aux('param', kwargs, defaultClass=Parameters, defaultClassApp=Parameters, msg_error=ERR_MSG_KWARGS["param"]) # Get default rules class rules_class_cfg = DefaultRules if "rules_class" in config_data and config_data["rules_class"] is not None: rules_class_cfg = config_data["rules_class"] ## Create the rules of the game (mimic the operationnal constraints) gamerules_class = _get_default_aux( "gamerules_class", kwargs, defaultClass=rules_class_cfg, defaultClassApp=BaseRules, msg_error=ERR_MSG_KWARGS["gamerules_class"], isclass=True) # Get default reward class reward_class_cfg = L2RPNReward if "reward_class" in config_data and config_data[ "reward_class"] is not None: reward_class_cfg = config_data["reward_class"] ## Setup the reward the agent will receive reward_class = _get_default_aux("reward_class", kwargs, defaultClass=reward_class_cfg, defaultClassApp=BaseReward, msg_error=ERR_MSG_KWARGS["reward_class"], isclass=True) # Get default BaseAction class action_class_cfg = BaseAction if "action_class" in config_data and config_data[ "action_class"] is not None: action_class_cfg = config_data["action_class"] ## Setup the type of action the BaseAgent can perform action_class = _get_default_aux("action_class", kwargs, defaultClass=action_class_cfg, defaultClassApp=BaseAction, msg_error=ERR_MSG_KWARGS["action_class"], isclass=True) # Get default Voltage class voltage_class_cfg = ControlVoltageFromFile if "voltage_class" in config_data and config_data[ "voltage_class"] is not None: voltage_class_cfg = config_data["voltage_class"] ### Create controler for voltages volagecontroler_class = _get_default_aux( "volagecontroler_class", kwargs, defaultClassApp=voltage_class_cfg, defaultClass=ControlVoltageFromFile, msg_error=ERR_MSG_KWARGS["voltagecontroler_class"], isclass=True) # Get default Chronics class chronics_class_cfg = ChangeNothing if "chronics_class" in config_data and config_data[ "chronics_class"] is not None: chronics_class_cfg = config_data["chronics_class"] # Get default Grid class grid_value_class_cfg = GridStateFromFile if "grid_value_class" in config_data and config_data[ "grid_value_class"] is not None: grid_value_class_cfg = config_data["grid_value_class"] ## the chronics to use ### the arguments used to build the data, note that the arguments must be compatible with the chronics class default_chronics_kwargs = { "chronicsClass": chronics_class_cfg, "path": chronics_path_abs, "gridvalueClass": grid_value_class_cfg } data_feeding_kwargs = _get_default_aux( "data_feeding_kwargs", kwargs, defaultClassApp=dict, defaultinstance=default_chronics_kwargs, msg_error=ERR_MSG_KWARGS["data_feeding_kwargs"]) for el in default_chronics_kwargs: if not el in data_feeding_kwargs: data_feeding_kwargs[el] = default_chronics_kwargs[el] ### the chronics generator chronics_class_used = _get_default_aux( "chronics_class", kwargs, defaultClassApp=GridValue, defaultClass=data_feeding_kwargs["chronicsClass"], msg_error=ERR_MSG_KWARGS["chronics_class"], isclass=True) data_feeding_kwargs["chronicsClass"] = chronics_class_used data_feeding = _get_default_aux( "data_feeding", kwargs, defaultClassApp=ChronicsHandler, defaultClass=ChronicsHandler, build_kwargs=data_feeding_kwargs, msg_error=ERR_MSG_KWARGS["chronics_handler"]) ### other rewards other_rewards = _get_default_aux("other_rewards", kwargs, defaultClassApp=dict, defaultinstance={}, msg_error=ERR_MSG_KWARGS["other_rewards"], isclass=False) # Opponent # TODO make that in config file of the default environment !!! opponent_action_class = _get_default_aux( "opponent_action_class", kwargs, defaultClassApp=BaseAction, defaultClass=DontAct, msg_error=ERR_MSG_KWARGS["opponent_action_class"], isclass=True) opponent_class = _get_default_aux( "opponent_class", kwargs, defaultClassApp=BaseOpponent, defaultClass=BaseOpponent, msg_error=ERR_MSG_KWARGS["opponent_class"], isclass=True) opponent_init_budget = _get_default_aux( "opponent_init_budget", kwargs, defaultClassApp=float, defaultinstance=0., msg_error=ERR_MSG_KWARGS["opponent_init_budget"], isclass=False) # Finally instanciate env from config & overrides env = Environment(init_grid_path=grid_path_abs, 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, rewardClass=reward_class, legalActClass=gamerules_class, voltagecontrolerClass=volagecontroler_class, other_rewards=other_rewards, opponent_action_class=opponent_action_class, opponent_class=opponent_class, opponent_init_budget=opponent_init_budget) # Update the thermal limit if any if thermal_limits is not None: env.set_thermal_limit(thermal_limits) # Set graph layout if not None and not an empty dict if graph_layout is not None and graph_layout: env.attach_layout(graph_layout) return env