Esempio n. 1
0
 def _retrieve_scores(self, path_tmp, episode_name):
     my_path = os.path.join(path_tmp, episode_name, EpisodeData.OTHER_REWARDS)
     with open(my_path, "r", encoding="utf-8") as f:
         dict_rewards = json.load(f)
     arr_ = np.array([dt_float(el[self.KEY_SCORE]) for el in dict_rewards])
     self._save_numpy(os.path.join(path_tmp, episode_name, self.SCORES), arr_)
Esempio n. 2
0
    def init_from_dict(self, dict_):
        """
        Initialize the object given a dictionary. All keys are optional. If a key is not present in the dictionary,
        the default parameters is used.

        Parameters
        ----------
        dict_: ``dict``
            The dictionary representing the parameters to load.

        """
        if "NO_OVERFLOW_DISCONNECTION" in dict_:
            self.NO_OVERFLOW_DISCONNECTION = Parameters._isok_txt(
                dict_["NO_OVERFLOW_DISCONNECTION"])

        if "IGNORE_MIN_UP_DOWN_TIME" in dict_:
            self.IGNORE_MIN_UP_DOWN_TIME = Parameters._isok_txt(
                dict_["IGNORE_MIN_UP_DOWN_TIME"])

        if "ALLOW_DISPATCH_GEN_SWITCH_OFF" in dict_:
            self.ALLOW_DISPATCH_GEN_SWITCH_OFF = Parameters._isok_txt(
                dict_["ALLOW_DISPATCH_GEN_SWITCH_OFF"])

        if "NB_TIMESTEP_POWERFLOW_ALLOWED" in dict_:
            self.NB_TIMESTEP_OVERFLOW_ALLOWED = dt_int(
                dict_["NB_TIMESTEP_POWERFLOW_ALLOWED"])
        if "NB_TIMESTEP_OVERFLOW_ALLOWED" in dict_:
            self.NB_TIMESTEP_OVERFLOW_ALLOWED = dt_int(
                dict_["NB_TIMESTEP_OVERFLOW_ALLOWED"])

        if "NB_TIMESTEP_RECONNECTION" in dict_:
            self.NB_TIMESTEP_RECONNECTION = dt_int(
                dict_["NB_TIMESTEP_RECONNECTION"])

        if "HARD_OVERFLOW_THRESHOLD" in dict_:
            self.HARD_OVERFLOW_THRESHOLD = dt_float(
                dict_["HARD_OVERFLOW_THRESHOLD"])

        if "ENV_DC" in dict_:
            self.ENV_DC = Parameters._isok_txt(dict_["ENV_DC"])

        if "FORECAST_DC" in dict_:
            new_val = Parameters._isok_txt(dict_["FORECAST_DC"])
            if new_val != self.FORECAST_DC:
                warnings.warn(
                    "The FORECAST_DC attributes is deprecated. Please change the parameters of the "
                    "\"forecast\" backend with \"env.change_forecast_parameters(new_param)\" function "
                    "with \"new_param.ENV_DC=...\" ")
            self.FORECAST_DC = new_val

        if "MAX_SUB_CHANGED" in dict_:
            self.MAX_SUB_CHANGED = dt_int(dict_["MAX_SUB_CHANGED"])

        if "MAX_LINE_STATUS_CHANGED" in dict_:
            self.MAX_LINE_STATUS_CHANGED = dt_int(
                dict_["MAX_LINE_STATUS_CHANGED"])

        if "NB_TIMESTEP_TOPOLOGY_REMODIF" in dict_:
            # for backward compatibility (in case of old dataset)
            self.NB_TIMESTEP_COOLDOWN_SUB = dt_int(
                dict_["NB_TIMESTEP_TOPOLOGY_REMODIF"])
        if "NB_TIMESTEP_COOLDOWN_SUB" in dict_:
            self.NB_TIMESTEP_COOLDOWN_SUB = dt_int(
                dict_["NB_TIMESTEP_COOLDOWN_SUB"])

        if "NB_TIMESTEP_LINE_STATUS_REMODIF" in dict_:
            # for backward compatibility (in case of old dataset)
            self.NB_TIMESTEP_COOLDOWN_LINE = dt_int(
                dict_["NB_TIMESTEP_LINE_STATUS_REMODIF"])
        if "NB_TIMESTEP_COOLDOWN_LINE" in dict_:
            self.NB_TIMESTEP_COOLDOWN_LINE = dt_int(
                dict_["NB_TIMESTEP_COOLDOWN_LINE"])

        # storage parameters
        if "INIT_STORAGE_CAPACITY" in dict_:
            self.INIT_STORAGE_CAPACITY = dt_float(
                dict_["INIT_STORAGE_CAPACITY"])
        if "ACTIVATE_STORAGE_LOSS" in dict_:
            self.ACTIVATE_STORAGE_LOSS = Parameters._isok_txt(
                dict_["ACTIVATE_STORAGE_LOSS"])

        # alarm parameters
        if "ALARM_BEST_TIME" in dict_:
            self.ALARM_BEST_TIME = dt_int(dict_["ALARM_BEST_TIME"])
        if "ALARM_WINDOW_SIZE" in dict_:
            self.ALARM_WINDOW_SIZE = dt_int(dict_["ALARM_WINDOW_SIZE"])

        authorized_keys = set(self.__dict__.keys())
        authorized_keys = authorized_keys | {
            'NB_TIMESTEP_POWERFLOW_ALLOWED', 'NB_TIMESTEP_TOPOLOGY_REMODIF',
            "NB_TIMESTEP_LINE_STATUS_REMODIF"
        }
        ignored_keys = dict_.keys() - authorized_keys
        if len(ignored_keys):
            warnings.warn(
                "Parameters: The _parameters \"{}\" used to build the Grid2Op.Parameters "
                "class are not recognized and will be ignored.".format(
                    ignored_keys))
Esempio n. 3
0
    def setUp(self):
        """
        The case file is a representation of the case14 as found in the ieee14 powergrid.
        :return:
        """
        self.tolvect = dt_float(1e-2)
        self.tol_one = dt_float(1e-5)
        self.max_iter = 10
        self.real_reward = dt_float(199.99800)

        self.init_grid_path = os.path.join(PATH_DATA_TEST_PP,
                                           "test_case14.json")
        self.path_chron = PATH_ADN_CHRONICS_FOLDER
        self.parameters_path = None
        self.names_chronics_to_backend = {
            "loads": {
                "2_C-10.61": 'load_1_0',
                "3_C151.15": 'load_2_1',
                "14_C63.6": 'load_13_2',
                "4_C-9.47": 'load_3_3',
                "5_C201.84": 'load_4_4',
                "6_C-6.27": 'load_5_5',
                "9_C130.49": 'load_8_6',
                "10_C228.66": 'load_9_7',
                "11_C-138.89": 'load_10_8',
                "12_C-27.88": 'load_11_9',
                "13_C-13.33": 'load_12_10'
            },
            "lines": {
                '1_2_1': '0_1_0',
                '1_5_2': '0_4_1',
                '9_10_16': '8_9_2',
                '9_14_17': '8_13_3',
                '10_11_18': '9_10_4',
                '12_13_19': '11_12_5',
                '13_14_20': '12_13_6',
                '2_3_3': '1_2_7',
                '2_4_4': '1_3_8',
                '2_5_5': '1_4_9',
                '3_4_6': '2_3_10',
                '4_5_7': '3_4_11',
                '6_11_11': '5_10_12',
                '6_12_12': '5_11_13',
                '6_13_13': '5_12_14',
                '4_7_8': '3_6_15',
                '4_9_9': '3_8_16',
                '5_6_10': '4_5_17',
                '7_8_14': '6_7_18',
                '7_9_15': '6_8_19'
            },
            "prods": {
                "1_G137.1": 'gen_0_4',
                "3_G36.31": "gen_2_1",
                "6_G63.29": "gen_5_2",
                "2_G-56.47": "gen_1_0",
                "8_G40.43": "gen_7_3"
            },
        }
        self.gridStateclass = Multifolder
        self.backendClass = PandaPowerBackend
        self.runner = Runner(
            init_grid_path=self.init_grid_path,
            path_chron=self.path_chron,
            parameters_path=self.parameters_path,
            names_chronics_to_backend=self.names_chronics_to_backend,
            gridStateclass=self.gridStateclass,
            backendClass=self.backendClass,
            rewardClass=L2RPNReward,
            other_rewards={"test": L2RPNReward},
            max_iter=self.max_iter,
            name_env="test_episodedata_env")
Esempio n. 4
0
 def __init__(self, action_space):
     BaseActionBudget.__init__(self, action_space)
     self._zero = dt_float(0.)
Esempio n. 5
0
    def __init__(self, detailed_infos_for_cascading_failures=False):
        Backend.__init__(self,
                         detailed_infos_for_cascading_failures=
                         detailed_infos_for_cascading_failures)

        # lazy loading because it crashes...
        from grid2op.Backend import PandaPowerBackend
        from grid2op.Space import GridObjects  # lazy import
        self.__has_storage = hasattr(GridObjects, "n_storage")
        if not self.__has_storage:
            pass
            # warnings.warn("Please upgrade your grid2Op to >= 1.5.0. You are using a backward compatibility "
            #              "feature that will be removed in further lightsim2grid version.")

        self.nb_bus_total = None
        self.initdc = True  # does not really hurt computation time
        self.__nb_powerline = None
        self.__nb_bus_before = None
        self._init_bus_load = None
        self._init_bus_gen = None
        self._init_bus_lor = None
        self._init_bus_lex = None
        self._big_topo_to_obj = None
        self.nb_obj_per_bus = None

        self.next_prod_p = None  # this vector is updated with the action that will modify the environment
        # it is done to keep track of the redispatching

        self.topo_vect = None
        self.shunt_topo_vect = None

        self.init_pp_backend = PandaPowerBackend()

        self.V = None
        self.max_it = 10
        self.tol = 1e-8  # tolerance for the solver

        self.prod_pu_to_kv = None
        self.load_pu_to_kv = None
        self.lines_or_pu_to_kv = None
        self.lines_ex_pu_to_kv = None

        self.p_or = None
        self.q_or = None
        self.v_or = None
        self.a_or = None
        self.p_ex = None
        self.q_ex = None
        self.v_ex = None
        self.a_ex = None

        self.load_p = None
        self.load_q = None
        self.load_v = None

        self.prod_p = None
        self.prod_q = None
        self.prod_v = None

        self.storage_p = None
        self.storage_q = None
        self.storage_v = None

        self.thermal_limit_a = None

        self._iref_slack = None
        self._id_bus_added = None
        self._fact_mult_gen = -1
        self._what_object_where = None
        self._number_true_line = -1
        self._corresp_name_fun = {}
        self._get_vector_inj = {}
        self.dim_topo = -1
        self._init_action_to_set = None
        self._backend_action_class = None
        self.cst_1 = dt_float(1.0)
        self.__me_at_init = None
        self.__init_topo_vect = None

        # available solver in lightsim
        self.available_solvers = []
        self.comp_time = 0.  # computation time of just the powerflow
        self.__current_solver_type = None

        # hack for the storage unit:
        # in grid2op, for simplicity, I suppose that if a storage is alone on a busbar, and
        # that it produces / absorbs nothing, then that's fine
        # this behaviour in lightsim (c++ side) would be detected as a non connex grid and raise
        # a diverging powerflow
        # i "fake" to disconnect storage with these properties
        # TODO hummm we need to clarify that ! pandapower automatically disconnect this stuff  too ! This is super weird
        # TODO and should rather be handled in pandapower backend
        # backend SHOULD not do these kind of stuff
        self._idx_hack_storage = []
Esempio n. 6
0
 def compare_vect(self, pred, true):
     return dt_float(np.max(np.abs(pred - true))) <= self.tolvect
Esempio n. 7
0
 def __init__(self, min_pen_lte=0.0, max_pen_gte=1.0):
     BaseReward.__init__(self)
     self.reward_min = dt_float(0.0)
     self.reward_max = dt_float(1.0)
     self.min_pen_lte = dt_float(min_pen_lte)
     self.max_pen_gte = dt_float(max_pen_gte)
Esempio n. 8
0
    def __init__(self, detailed_infos_for_cascading_failures=False):
        Backend.__init__(self,
                         detailed_infos_for_cascading_failures=
                         detailed_infos_for_cascading_failures)

        # lazy loading becuase otherwise somehow it crashes...
        from grid2op.Backend import PandaPowerBackend

        self.nb_bus_total = None
        self.initdc = True  # does not really hurt computation time
        self.__nb_powerline = None
        self.__nb_bus_before = None
        self._init_bus_load = None
        self._init_bus_gen = None
        self._init_bus_lor = None
        self._init_bus_lex = None
        self._big_topo_to_obj = None
        self.nb_obj_per_bus = None

        self.next_prod_p = None  # this vector is updated with the action that will modify the environment
        # it is done to keep track of the redispatching

        self.topo_vect = None
        self.shunt_topo_vect = None

        self.init_pp_backend = PandaPowerBackend()

        self.V = None
        self.max_it = 10
        self.tol = 1e-8  # tolerance for the solver

        self.prod_pu_to_kv = None
        self.load_pu_to_kv = None
        self.lines_or_pu_to_kv = None
        self.lines_ex_pu_to_kv = None

        self.p_or = None
        self.q_or = None
        self.v_or = None
        self.a_or = None
        self.p_ex = None
        self.q_ex = None
        self.v_ex = None
        self.a_ex = None

        self.load_p = None
        self.load_q = None
        self.load_v = None

        self.prod_p = None
        self.prod_q = None
        self.prod_v = None

        self.thermal_limit_a = None

        self._iref_slack = None
        self._id_bus_added = None
        self._fact_mult_gen = -1
        self._what_object_where = None
        self._number_true_line = -1
        self._corresp_name_fun = {}
        self._get_vector_inj = {}
        self.dim_topo = -1
        self._init_action_to_set = None
        self._backend_action_class = None
        self.cst_1 = dt_float(1.0)
        self.__me_at_init = None
        self.__init_topo_vect = None
Esempio n. 9
0
    def update(self, env, with_forecast=True):
        """
        This use the environement to update properly the BaseObservation.

        Parameters
        ----------
        env: :class:`grid2op.Environment.Environment`
            The environment from which to update this observation.

        """
        # reset the matrices
        self._reset_matrices()
        self.reset()

        # extract the time stamps
        self.year = dt_int(env.time_stamp.year)
        self.month = dt_int(env.time_stamp.month)
        self.day = dt_int(env.time_stamp.day)
        self.hour_of_day = dt_int(env.time_stamp.hour)
        self.minute_of_hour = dt_int(env.time_stamp.minute)
        self.day_of_week = dt_int(env.time_stamp.weekday())

        # get the values related to topology
        self.timestep_overflow = copy.copy(env.timestep_overflow)
        self.line_status = copy.copy(env.backend.get_line_status())
        self.topo_vect = copy.copy(env.backend.get_topo_vect())

        # get the values related to continuous values
        self.prod_p[:], self.prod_q[:], self.prod_v[:] = env.backend.generators_info(
        )
        self.load_p[:], self.load_q[:], self.load_v[:] = env.backend.loads_info(
        )
        self.p_or[:], self.q_or[:], self.v_or[:], self.a_or[:] = env.backend.lines_or_info(
        )
        self.p_ex[:], self.q_ex[:], self.v_ex[:], self.a_ex[:] = env.backend.lines_ex_info(
        )

        # handles forecasts here
        if with_forecast:
            inj_action = {}
            dict_ = {}
            dict_["load_p"] = dt_float(1.0 * self.load_p)
            dict_["load_q"] = dt_float(1.0 * self.load_q)
            dict_["prod_p"] = dt_float(1.0 * self.prod_p)
            dict_["prod_v"] = dt_float(1.0 * self.prod_v)
            inj_action["injection"] = dict_
            # inj_action = self.action_helper(inj_action)
            timestamp = self.get_time_stamp()
            self._forecasted_inj = [(timestamp, inj_action)]
            self._forecasted_inj += env.chronics_handler.forecasts()
            self._forecasted_grid = [None for _ in self._forecasted_inj]

        self.rho = env.backend.get_relative_flow().astype(dt_float)

        # cool down and reconnection time after hard overflow, soft overflow or cascading failure
        self.time_before_cooldown_line[:] = env.times_before_line_status_actionable
        self.time_before_cooldown_sub[:] = env.times_before_topology_actionable
        self.time_next_maintenance[:] = env.time_next_maintenance
        self.duration_next_maintenance[:] = env.duration_next_maintenance

        # redispatching
        self.target_dispatch[:] = env.target_dispatch
        self.actual_dispatch[:] = env.actual_dispatch
Esempio n. 10
0
    def __init__(self, detailed_infos_for_cascading_failures=False):
        Backend.__init__(self,
                         detailed_infos_for_cascading_failures=
                         detailed_infos_for_cascading_failures)
        self.prod_pu_to_kv = None
        self.load_pu_to_kv = None
        self.lines_or_pu_to_kv = None
        self.lines_ex_pu_to_kv = None

        self.p_or = None
        self.q_or = None
        self.v_or = None
        self.a_or = None
        self.p_ex = None
        self.q_ex = None
        self.v_ex = None
        self.a_ex = None

        self.load_p = None
        self.load_q = None
        self.load_v = None

        self.prod_p = None
        self.prod_q = None
        self.prod_v = None
        self.line_status = None

        self._pf_init = "flat"
        self._pf_init = "results"
        self._nb_bus_before = None  # number of active bus at the preceeding step

        self.thermal_limit_a = None

        self._iref_slack = None
        self._id_bus_added = None
        self._fact_mult_gen = -1
        self._what_object_where = None
        self._number_true_line = -1
        self._corresp_name_fun = {}
        self._get_vector_inj = {}
        self.dim_topo = -1
        self._vars_action = BaseAction.attr_list_vect
        self._vars_action_set = BaseAction.attr_list_vect
        self.cst_1 = dt_float(1.0)
        self._topo_vect = None
        self.slack_id = None
        self.comp_time = 0.

        # function to rstore some information
        self.__nb_bus_before = None  # number of substation in the powergrid
        self.__nb_powerline = None  # number of powerline (real powerline, not transformer)
        self._init_bus_load = None
        self._init_bus_gen = None
        self._init_bus_lor = None
        self._init_bus_lex = None
        self._get_vector_inj = None
        self._big_topo_to_obj = None
        self._big_topo_to_backend = None
        self.__pp_backend_initial_state = None  # initial state to facilitate the "reset"

        # Mapping some fun to apply bus updates
        self._type_to_bus_set = [
            self._apply_load_bus, self._apply_gen_bus, self._apply_lor_bus,
            self._apply_trafo_hv, self._apply_lex_bus, self._apply_trafo_lv
        ]
Esempio n. 11
0
    def update(self, env, with_forecast=True):
        # reset the matrices
        self._reset_matrices()
        self.reset()

        # extract the time stamps
        self.year = dt_int(env.time_stamp.year)
        self.month = dt_int(env.time_stamp.month)
        self.day = dt_int(env.time_stamp.day)
        self.hour_of_day = dt_int(env.time_stamp.hour)
        self.minute_of_hour = dt_int(env.time_stamp.minute)
        self.day_of_week = dt_int(env.time_stamp.weekday())

        # get the values related to topology
        self.timestep_overflow[:] = env._timestep_overflow
        self.line_status[:] = env.backend.get_line_status()
        self.topo_vect[:] = env.backend.get_topo_vect()

        # get the values related to continuous values
        self.prod_p[:], self.prod_q[:], self.prod_v[:] = env.backend.generators_info(
        )
        self.load_p[:], self.load_q[:], self.load_v[:] = env.backend.loads_info(
        )
        self.p_or[:], self.q_or[:], self.v_or[:], self.a_or[:] = env.backend.lines_or_info(
        )
        self.p_ex[:], self.q_ex[:], self.v_ex[:], self.a_ex[:] = env.backend.lines_ex_info(
        )

        # handles forecasts here
        if with_forecast:
            inj_action = {}
            dict_ = {}
            dict_["load_p"] = dt_float(1.0 * self.load_p)
            dict_["load_q"] = dt_float(1.0 * self.load_q)
            dict_["prod_p"] = dt_float(1.0 * self.prod_p)
            dict_["prod_v"] = dt_float(1.0 * self.prod_v)
            inj_action["injection"] = dict_
            # inj_action = self.action_helper(inj_action)
            timestamp = self.get_time_stamp()
            self._forecasted_inj = [(timestamp, inj_action)]
            self._forecasted_inj += env.chronics_handler.forecasts()
            self._forecasted_grid = [None for _ in self._forecasted_inj]

        self.rho[:] = env.backend.get_relative_flow().astype(dt_float)

        # cool down and reconnection time after hard overflow, soft overflow or cascading failure
        self.time_before_cooldown_line[:] = env._times_before_line_status_actionable
        self.time_before_cooldown_sub[:] = env._times_before_topology_actionable
        self.time_next_maintenance[:] = env._time_next_maintenance
        self.duration_next_maintenance[:] = env._duration_next_maintenance

        # redispatching
        self.target_dispatch[:] = env._target_dispatch
        self.actual_dispatch[:] = env._actual_dispatch

        # handle shunts (if avaialble)
        if self.shunts_data_available:
            sh_p, sh_q, sh_v, sh_bus = env.backend.shunt_info()
            self._shunt_p[:] = sh_p
            self._shunt_q[:] = sh_q
            self._shunt_v[:] = sh_v
            self._shunt_bus[:] = sh_bus
Esempio n. 12
0
 def __init__(self, alpha_redisph=1.0):
     BaseReward.__init__(self)
     self.reward_min = dt_float(1.0)  # carefull here between min and max...
     self.reward_max = dt_float(300.0 * 70.0)
     self.alpha_redisph = dt_float(alpha_redisph)
Esempio n. 13
0
 def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous):
     if not has_error:
         res = dt_float(env._nb_time_step * self.per_timestep)
     else:
         res = self.reward_min
     return res
Esempio n. 14
0
    def _init_backend(self, init_grid_path, chronics_handler, backend,
                      names_chronics_to_backend, actionClass, observationClass,
                      rewardClass, legalActClass):
        """
        INTERNAL

        .. warning:: /!\\\\ Internal, do not use unless you know what you are doing /!\\\\

        Create a proper and valid environment.
        """

        if not isinstance(rewardClass, type):
            raise Grid2OpException(
                "Parameter \"rewardClass\" used to build the Environment should be a type (a class) "
                "and not an object (an instance of a class). "
                "It is currently \"{}\"".format(type(rewardClass)))
        if not issubclass(rewardClass, BaseReward):
            raise Grid2OpException(
                "Parameter \"rewardClass\" used to build the Environment should derived form "
                "the grid2op.BaseReward class, type provided is \"{}\"".format(
                    type(rewardClass)))
        self._rewardClass = rewardClass
        self._actionClass = actionClass
        self._observationClass = observationClass

        # backend
        self._init_grid_path = os.path.abspath(init_grid_path)

        if not isinstance(backend, Backend):
            raise Grid2OpException(
                "Parameter \"backend\" used to build the Environment should derived form the "
                "grid2op.Backend class, type provided is \"{}\"".format(
                    type(backend)))
        self.backend = backend
        # all the above should be done in this exact order, otherwise some weird behaviour might occur
        # this is due to the class attribute
        self.backend.set_env_name(self.name)
        self.backend.load_grid(
            self._init_grid_path)  # the real powergrid of the environment
        self.backend.load_redispacthing_data(self.get_path_env())
        self.backend.load_storage_data(self.get_path_env())
        self.backend.load_grid_layout(self.get_path_env())
        self.backend.assert_grid_correct()
        self._has_been_initialized(
        )  # really important to include this piece of code! and just here after the
        # backend has loaded everything
        self._line_status = np.ones(shape=self.n_line, dtype=dt_bool)

        if self._thermal_limit_a is None:
            self._thermal_limit_a = self.backend.thermal_limit_a.astype(
                dt_float)
        else:
            self.backend.set_thermal_limit(
                self._thermal_limit_a.astype(dt_float))

        *_, tmp = self.backend.generators_info()

        # rules of the game
        if not isinstance(legalActClass, type):
            raise Grid2OpException(
                "Parameter \"legalActClass\" used to build the Environment should be a type "
                "(a class) and not an object (an instance of a class). "
                "It is currently \"{}\"".format(type(legalActClass)))
        if not issubclass(legalActClass, BaseRules):
            raise Grid2OpException(
                "Parameter \"legalActClass\" used to build the Environment should derived form the "
                "grid2op.BaseRules class, type provided is \"{}\"".format(
                    type(legalActClass)))
        self._game_rules = RulesChecker(legalActClass=legalActClass)
        self._legalActClass = legalActClass

        # action helper
        if not isinstance(actionClass, type):
            raise Grid2OpException(
                "Parameter \"actionClass\" used to build the Environment should be a type (a class) "
                "and not an object (an instance of a class). "
                "It is currently \"{}\"".format(type(legalActClass)))
        if not issubclass(actionClass, BaseAction):
            raise Grid2OpException(
                "Parameter \"actionClass\" used to build the Environment should derived form the "
                "grid2op.BaseAction class, type provided is \"{}\"".format(
                    type(actionClass)))

        if not isinstance(observationClass, type):
            raise Grid2OpException(
                "Parameter \"actionClass\" used to build the Environment should be a type (a class) "
                "and not an object (an instance of a class). "
                "It is currently \"{}\"".format(type(legalActClass)))
        if not issubclass(observationClass, BaseObservation):
            raise Grid2OpException(
                "Parameter \"observationClass\" used to build the Environment should derived form the "
                "grid2op.BaseObservation class, type provided is \"{}\"".
                format(type(observationClass)))

        # action affecting the grid that will be made by the agent
        self._helper_action_class = ActionSpace.init_grid(gridobj=self.backend)
        self._helper_action_player = self._helper_action_class(
            gridobj=self.backend,
            actionClass=actionClass,
            legal_action=self._game_rules.legal_action)

        # action that affect the grid made by the environment.
        self._helper_action_env = self._helper_action_class(
            gridobj=self.backend,
            actionClass=CompleteAction,
            legal_action=self._game_rules.legal_action)
        self._helper_observation_class = ObservationSpace.init_grid(
            gridobj=self.backend)
        self._helper_observation = self._helper_observation_class(
            gridobj=self.backend,
            observationClass=observationClass,
            rewardClass=rewardClass,
            env=self)
        # handles input data
        if not isinstance(chronics_handler, ChronicsHandler):
            raise Grid2OpException(
                "Parameter \"chronics_handler\" used to build the Environment should derived form the "
                "grid2op.ChronicsHandler class, type provided is \"{}\"".
                format(type(chronics_handler)))
        self.chronics_handler = chronics_handler
        self.chronics_handler.initialize(
            self.name_load,
            self.name_gen,
            self.name_line,
            self.name_sub,
            names_chronics_to_backend=names_chronics_to_backend)
        self.names_chronics_to_backend = names_chronics_to_backend

        # test to make sure the backend is consistent with the chronics generator
        self.chronics_handler.check_validity(self.backend)
        self.delta_time_seconds = dt_float(
            self.chronics_handler.time_interval.seconds)
        self._reset_storage(
        )  # this should be called after the  self.delta_time_seconds is set

        # reward function
        self._reward_helper = RewardHelper(self._rewardClass)
        self._reward_helper.initialize(self)
        for k, v in self.other_rewards.items():
            v.initialize(self)

        # controller for voltage
        if not issubclass(self._voltagecontrolerClass, BaseVoltageController):
            raise Grid2OpException(
                "Parameter \"voltagecontrolClass\" should derive from \"ControlVoltageFromFile\"."
            )

        self._voltage_controler = self._voltagecontrolerClass(
            gridobj=self.backend, controler_backend=self.backend)

        # create the opponent
        # At least the 3 following attributes should be set before calling _create_opponent
        self._create_opponent()

        # performs one step to load the environment properly (first action need to be taken at first time step after
        # first injections given)
        self._reset_maintenance()
        self._reset_redispatching()
        do_nothing = self._helper_action_env({})
        *_, fail_to_start, info = self.step(do_nothing)
        if fail_to_start:
            raise Grid2OpException(
                "Impossible to initialize the powergrid, the powerflow diverge at iteration 0. "
                "Available information are: {}".format(info))

        # test the backend returns object of the proper size
        self.backend.assert_grid_correct_after_powerflow()

        # for gym compatibility
        self.action_space = self._helper_action_player  # this should be an action !!!
        self.observation_space = self._helper_observation  # this return an observation.
        self.reward_range = self._reward_helper.range()
        self.viewer = None
        self.viewer_fig = None

        self.metadata = {'render.modes': []}
        self.spec = None

        self.current_reward = self.reward_range[0]
        self.done = False

        # reset everything to be consistent
        self._reset_vectors_and_timings()
Esempio n. 15
0
 def setUp(self):
     self.init_grid_path = os.path.join(PATH_DATA_TEST_PP,
                                        "test_case14.json")
     self.path_chron = PATH_ADN_CHRONICS_FOLDER
     self.parameters_path = None
     self.max_iter = 10
     # self.real_reward = dt_float(199.99800)
     self.real_reward = dt_float(179.99818)
     self.all_real_rewards = [
         19.999783, 19.999786, 19.999784, 19.999794, 19.9998, 19.999804,
         19.999804, 19.999817, 19.999823, 0.
     ]
     self.names_chronics_to_backend = {
         "loads": {
             "2_C-10.61": 'load_1_0',
             "3_C151.15": 'load_2_1',
             "14_C63.6": 'load_13_2',
             "4_C-9.47": 'load_3_3',
             "5_C201.84": 'load_4_4',
             "6_C-6.27": 'load_5_5',
             "9_C130.49": 'load_8_6',
             "10_C228.66": 'load_9_7',
             "11_C-138.89": 'load_10_8',
             "12_C-27.88": 'load_11_9',
             "13_C-13.33": 'load_12_10'
         },
         "lines": {
             '1_2_1': '0_1_0',
             '1_5_2': '0_4_1',
             '9_10_16': '8_9_2',
             '9_14_17': '8_13_3',
             '10_11_18': '9_10_4',
             '12_13_19': '11_12_5',
             '13_14_20': '12_13_6',
             '2_3_3': '1_2_7',
             '2_4_4': '1_3_8',
             '2_5_5': '1_4_9',
             '3_4_6': '2_3_10',
             '4_5_7': '3_4_11',
             '6_11_11': '5_10_12',
             '6_12_12': '5_11_13',
             '6_13_13': '5_12_14',
             '4_7_8': '3_6_15',
             '4_9_9': '3_8_16',
             '5_6_10': '4_5_17',
             '7_8_14': '6_7_18',
             '7_9_15': '6_8_19'
         },
         "prods": {
             "1_G137.1": 'gen_0_4',
             "3_G36.31": "gen_2_1",
             "6_G63.29": "gen_5_2",
             "2_G-56.47": "gen_1_0",
             "8_G40.43": "gen_7_3"
         },
     }
     self.gridStateclass = Multifolder
     self.backendClass = PandaPowerBackend
     with warnings.catch_warnings():
         warnings.filterwarnings(
             "ignore")  # silence the warning about missing layout
         self.runner = Runner(
             init_grid_path=self.init_grid_path,
             path_chron=self.path_chron,
             parameters_path=self.parameters_path,
             names_chronics_to_backend=self.names_chronics_to_backend,
             gridStateclass=self.gridStateclass,
             backendClass=self.backendClass,
             rewardClass=L2RPNReward,
             max_iter=self.max_iter,
             name_env="test_runner_env")
Esempio n. 16
0
 def __init__(self, methodName='runTest'):
     unittest.TestCase.__init__(self, methodName=methodName)
     self.tolvect = dt_float(1e-2)
     self.tol_one = dt_float(1e-5)
Esempio n. 17
0
 def __init__(self):
     super().__init__()
     self.reward_min = dt_float(-1.0)
     self.reward_max = dt_float(1.0)
Esempio n. 18
0
 def __init__(self):
     BaseReward.__init__(self)
     self.reward_min = dt_float(0.0)
     self.reward_max = dt_float(1.0)
     self.penalty_max_at_n_lines = dt_float(2.0)
Esempio n. 19
0
    def setUp(self):
        # powergrid
        self.backend = PandaPowerBackend()
        self.path_matpower = PATH_DATA_TEST_PP
        self.case_file = "test_case14.json"

        # chronics
        self.path_chron = os.path.join(PATH_CHRONICS, "chronics")
        self.chronics_handler = ChronicsHandler(
            chronicsClass=GridStateFromFile, path=self.path_chron)

        self.tolvect = dt_float(1e-2)
        self.tol_one = dt_float(1e-5)
        self.id_chron_to_back_load = np.array(
            [0, 1, 10, 2, 3, 4, 5, 6, 7, 8, 9])

        # force the verbose backend
        self.backend.detailed_infos_for_cascading_failures = True

        self.names_chronics_to_backend = {
            "loads": {
                "2_C-10.61": 'load_1_0',
                "3_C151.15": 'load_2_1',
                "14_C63.6": 'load_13_2',
                "4_C-9.47": 'load_3_3',
                "5_C201.84": 'load_4_4',
                "6_C-6.27": 'load_5_5',
                "9_C130.49": 'load_8_6',
                "10_C228.66": 'load_9_7',
                "11_C-138.89": 'load_10_8',
                "12_C-27.88": 'load_11_9',
                "13_C-13.33": 'load_12_10'
            },
            "lines": {
                '1_2_1': '0_1_0',
                '1_5_2': '0_4_1',
                '9_10_16': '8_9_2',
                '9_14_17': '8_13_3',
                '10_11_18': '9_10_4',
                '12_13_19': '11_12_5',
                '13_14_20': '12_13_6',
                '2_3_3': '1_2_7',
                '2_4_4': '1_3_8',
                '2_5_5': '1_4_9',
                '3_4_6': '2_3_10',
                '4_5_7': '3_4_11',
                '6_11_11': '5_10_12',
                '6_12_12': '5_11_13',
                '6_13_13': '5_12_14',
                '4_7_8': '3_6_15',
                '4_9_9': '3_8_16',
                '5_6_10': '4_5_17',
                '7_8_14': '6_7_18',
                '7_9_15': '6_8_19'
            },
            "prods": {
                "1_G137.1": 'gen_0_4',
                "3_G36.31": "gen_2_1",
                "6_G63.29": "gen_5_2",
                "2_G-56.47": "gen_1_0",
                "8_G40.43": "gen_7_3"
            },
        }

        # _parameters for the environment
        self.env_params = Parameters()

        self.env = Environment(
            init_grid_path=os.path.join(self.path_matpower, self.case_file),
            backend=self.backend,
            chronics_handler=self.chronics_handler,
            parameters=self.env_params,
            names_chronics_to_backend=self.names_chronics_to_backend,
            name="test_env_env1")
Esempio n. 20
0
 def initialize(self, env):
     self.reward_min = dt_float(0.0)
     self.reward_max = dt_float(env.backend.n_line)
Esempio n. 21
0
    def init_from_dict(self, dict_):
        """
        Initialize the object given a dictionary. All keys are optional. If a key is not present in the dictionary,
        the default parameters is used.

        Parameters
        ----------
        dict_: ``dict``
            The dictionary representing the parameters to load.

        """
        if "NO_OVERFLOW_DISCONNECTION" in dict_:
            self.NO_OVERFLOW_DISCONNECTION = Parameters._isok_txt(
                dict_["NO_OVERFLOW_DISCONNECTION"])

        if "IGNORE_MIN_UP_DOWN_TIME" in dict_:
            self.IGNORE_MIN_UP_DOWN_TIME = Parameters._isok_txt(
                dict_["IGNORE_MIN_UP_DOWN_TIME"])

        if "ALLOW_DISPATCH_GEN_SWITCH_OFF" in dict_:
            self.ALLOW_DISPATCH_GEN_SWITCH_OFF = Parameters._isok_txt(
                dict_["ALLOW_DISPATCH_GEN_SWITCH_OFF"])

        if "NB_TIMESTEP_POWERFLOW_ALLOWED" in dict_:
            self.NB_TIMESTEP_OVERFLOW_ALLOWED = dt_int(
                dict_["NB_TIMESTEP_POWERFLOW_ALLOWED"])
        if "NB_TIMESTEP_OVERFLOW_ALLOWED" in dict_:
            self.NB_TIMESTEP_OVERFLOW_ALLOWED = dt_int(
                dict_["NB_TIMESTEP_OVERFLOW_ALLOWED"])

        if "NB_TIMESTEP_RECONNECTION" in dict_:
            self.NB_TIMESTEP_RECONNECTION = dt_int(
                dict_["NB_TIMESTEP_RECONNECTION"])

        if "HARD_OVERFLOW_THRESHOLD" in dict_:
            self.HARD_OVERFLOW_THRESHOLD = dt_float(
                dict_["HARD_OVERFLOW_THRESHOLD"])

        if "ENV_DC" in dict_:
            self.ENV_DC = Parameters._isok_txt(dict_["ENV_DC"])

        if "FORECAST_DC" in dict_:
            self.FORECAST_DC = Parameters._isok_txt(dict_["FORECAST_DC"])

        if "MAX_SUB_CHANGED" in dict_:
            self.MAX_SUB_CHANGED = dt_int(dict_["MAX_SUB_CHANGED"])

        if "MAX_LINE_STATUS_CHANGED" in dict_:
            self.MAX_LINE_STATUS_CHANGED = dt_int(
                dict_["MAX_LINE_STATUS_CHANGED"])

        if "NB_TIMESTEP_TOPOLOGY_REMODIF" in dict_:
            # for backward compatibility (in case of old dataset)
            self.NB_TIMESTEP_COOLDOWN_SUB = dt_int(
                dict_["NB_TIMESTEP_TOPOLOGY_REMODIF"])
        if "NB_TIMESTEP_COOLDOWN_SUB" in dict_:
            self.NB_TIMESTEP_COOLDOWN_SUB = dt_int(
                dict_["NB_TIMESTEP_COOLDOWN_SUB"])

        if "NB_TIMESTEP_LINE_STATUS_REMODIF" in dict_:
            # for backward compatibility (in case of old dataset)
            self.NB_TIMESTEP_COOLDOWN_LINE = dt_int(
                dict_["NB_TIMESTEP_LINE_STATUS_REMODIF"])
        if "NB_TIMESTEP_COOLDOWN_LINE" in dict_:
            self.NB_TIMESTEP_COOLDOWN_LINE = dt_int(
                dict_["NB_TIMESTEP_COOLDOWN_LINE"])

        authorized_keys = set(self.__dict__.keys())
        authorized_keys = authorized_keys | {
            'NB_TIMESTEP_POWERFLOW_ALLOWED', 'NB_TIMESTEP_TOPOLOGY_REMODIF',
            "NB_TIMESTEP_LINE_STATUS_REMODIF"
        }
        ignored_keys = dict_.keys() - authorized_keys
        if len(ignored_keys):
            warnings.warn(
                "Parameters: The _parameters \"{}\" used to build the Grid2Op.Parameters "
                "class are not recognized and will be ignored.".format(
                    ignored_keys))
Esempio n. 22
0
 def __init__(self, max_lines=5):
     BaseReward.__init__(self)
     self.reward_min = dt_float(0.0)
     self.reward_max = dt_float(1.0)
     self.max_overflowed = dt_float(max_lines)
Esempio n. 23
0
    def __init__(
        self,
        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,
        observationClass=CompleteObservation,
        rewardClass=FlatReward,
        legalActClass=AlwaysLegal,
        envClass=Environment,
        gridStateclass=GridStateFromFile,
        # type of chronics to use. For example GridStateFromFile if forecasts are not used,
        # or GridStateFromFileWithForecasts otherwise
        backendClass=PandaPowerBackend,
        agentClass=DoNothingAgent,  # class used to build the agent
        agentInstance=None,
        verbose=False,
        gridStateclass_kwargs={},
        voltageControlerClass=ControlVoltageFromFile,
        thermal_limit_a=None,
        max_iter=-1,
        other_rewards={},
        opponent_action_class=DontAct,
        opponent_class=BaseOpponent,
        opponent_init_budget=0.,
        opponent_budget_per_ts=0.,
        opponent_budget_class=NeverAttackBudget,
        opponent_attack_duration=0,
        opponent_attack_cooldown=99999,
        opponent_kwargs={},
        grid_layout=None,
        with_forecast=True,
        attention_budget_cls=LinearAttentionBudget,
        kwargs_attention_budget=None,
        has_attention_budget=False,
        # experimental: whether to read from local dir or generate the classes on the fly:
        _read_from_local_dir=False):
        """
        Initialize the Runner.

        Parameters
        ----------
        init_grid_path: ``str``
            Madantory, used to initialize :attr:`Runner.init_grid_path`.

        path_chron: ``str``
            Madantory where to look for chronics data, used to initialize :attr:`Runner.path_chron`.

        parameters_path: ``str`` or ``dict``, optional
            Used to initialize :attr:`Runner.parameters_path`. If it's a string, this will suppose parameters are
            located at this path, if it's a dictionary, this will use the parameters converted from this dictionary.

        names_chronics_to_backend: ``dict``, optional
            Used to initialize :attr:`Runner.names_chronics_to_backend`.

        actionClass: ``type``, optional
            Used to initialize :attr:`Runner.actionClass`.

        observationClass: ``type``, optional
            Used to initialize :attr:`Runner.observationClass`.

        rewardClass: ``type``, optional
            Used to initialize :attr:`Runner.rewardClass`. Default to :class:`grid2op.ConstantReward` that
            *should not** be used to train or evaluate an agent, but rather as debugging purpose.

        legalActClass: ``type``, optional
            Used to initialize :attr:`Runner.legalActClass`.

        envClass: ``type``, optional
            Used to initialize :attr:`Runner.envClass`.

        gridStateclass: ``type``, optional
            Used to initialize :attr:`Runner.gridStateclass`.

        backendClass: ``type``, optional
            Used to initialize :attr:`Runner.backendClass`.

        agentClass: ``type``, optional
            Used to initialize :attr:`Runner.agentClass`.

        agentInstance: :class:`grid2op.Agent.Agent`
            Used to initialize the agent. Note that either :attr:`agentClass` or :attr:`agentInstance` is used
            at the same time. If both ot them are ``None`` or both of them are "not ``None``" it throw an error.

        verbose: ``bool``, optional
            Used to initialize :attr:`Runner.verbose`.

        thermal_limit_a: ``numpy.ndarray``
            The thermal limit for the environment (if any).

        voltagecontrolerClass: :class:`grid2op.VoltageControler.ControlVoltageFromFile`, optional
            The controler that will change the voltage setpoints of the generators.

        # TODO documentation on the opponent
        # TOOD doc for the attention budget
        """
        self.with_forecast = with_forecast
        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 "
                "(an instance of a class). It is currently \"{}\"".format(
                    type(envClass)))
        if not issubclass(envClass, Environment):
            raise RuntimeError(
                "Impossible to create a runner without an evnrionment derived from grid2op.Environement"
                " class. Please modify \"envClass\" parameter.")
        self.envClass = envClass

        if not isinstance(actionClass, type):
            raise Grid2OpException(
                "Parameter \"actionClass\" used to build the Runner should be a type (a class) and not an object "
                "(an instance of a class). It is currently \"{}\"".format(
                    type(actionClass)))
        if not issubclass(actionClass, BaseAction):
            raise RuntimeError(
                "Impossible to create a runner without an action class derived from grid2op.BaseAction. "
                "Please modify \"actionClass\" parameter.")
        self.actionClass = actionClass

        if not isinstance(observationClass, type):
            raise Grid2OpException(
                "Parameter \"observationClass\" used to build the Runner should be a type (a class) and not an object "
                "(an instance of a class). It is currently \"{}\"".format(
                    type(observationClass)))
        if not issubclass(observationClass, BaseObservation):
            raise RuntimeError(
                "Impossible to create a runner without an observation class derived from "
                "grid2op.BaseObservation. Please modify \"observationClass\" parameter."
            )
        self.observationClass = observationClass
        if not isinstance(rewardClass, type):
            raise Grid2OpException(
                "Parameter \"rewardClass\" used to build the Runner should be a type (a class) and not an object "
                "(an instance of a class). It is currently \"{}\"".format(
                    type(rewardClass)))

        if not issubclass(rewardClass, BaseReward):
            raise RuntimeError(
                "Impossible to create a runner without an observation class derived from "
                "grid2op.BaseReward. Please modify \"rewardClass\" parameter.")
        self.rewardClass = rewardClass

        if not isinstance(gridStateclass, type):
            raise Grid2OpException(
                "Parameter \"gridStateclass\" used to build the Runner should be a type (a class) and not an object "
                "(an instance of a class). It is currently \"{}\"".format(
                    type(gridStateclass)))
        if not issubclass(gridStateclass, GridValue):
            raise RuntimeError(
                "Impossible to create a runner without an chronics class derived from "
                "grid2op.GridValue. Please modify \"gridStateclass\" parameter."
            )
        self.gridStateclass = gridStateclass

        if not isinstance(legalActClass, type):
            raise Grid2OpException(
                "Parameter \"legalActClass\" used to build the Runner should be a type (a class) and not an object "
                "(an instance of a class). It is currently \"{}\"".format(
                    type(legalActClass)))
        if not issubclass(legalActClass, BaseRules):

            raise RuntimeError(
                "Impossible to create a runner without a class defining legal actions derived "
                "from grid2op.BaseRules. Please modify \"legalActClass\" parameter."
            )
        self.legalActClass = legalActClass

        if not isinstance(backendClass, type):
            raise Grid2OpException(
                "Parameter \"legalActClass\" used to build the Runner should be a type (a class) and not an object "
                "(an instance of a class). It is currently \"{}\"".format(
                    type(backendClass)))
        if not issubclass(backendClass, Backend):
            raise RuntimeError(
                "Impossible to create a runner without a backend class derived from grid2op.GridValue. "
                "Please modify \"backendClass\" parameter.")
        self.backendClass = backendClass

        self.__can_copy_agent = True
        if agentClass is not None:
            if agentInstance is not None:
                raise RuntimeError(
                    "Impossible to build the backend. Only one of AgentClass or agentInstance can be "
                    "used (both are not None).")
            if not isinstance(agentClass, type):
                raise Grid2OpException(
                    "Parameter \"agentClass\" used to build the Runner should be a type (a class) and not an object "
                    "(an instance of a class). It is currently \"{}\"".format(
                        type(agentClass)))
            if not issubclass(agentClass, BaseAgent):
                raise RuntimeError(
                    "Impossible to create a runner without an agent class derived from "
                    "grid2op.BaseAgent. "
                    "Please modify \"agentClass\" parameter.")
            self.agentClass = agentClass
            self._useclass = True
            self.agent = None
        elif agentInstance is not None:
            if not isinstance(agentInstance, BaseAgent):
                raise RuntimeError(
                    "Impossible to create a runner without an agent class derived from "
                    "grid2op.BaseAgent. "
                    "Please modify \"agentInstance\" parameter.")
            self.agentClass = None
            self._useclass = False
            self.agent = agentInstance
            # Test if we can copy the agent for parallel runs
            try:
                copy.copy(self.agent)
            except:
                self.__can_copy_agent = False
        else:
            raise RuntimeError(
                "Impossible to build the backend. Either AgentClass or agentInstance must be provided "
                "and both are None.")
        self.agentInstance = agentInstance

        self._read_from_local_dir = _read_from_local_dir

        self.logger = ConsoleLog(
            DoNothingLog.INFO if verbose else DoNothingLog.ERROR)

        # store _parameters
        self.init_grid_path = init_grid_path
        self.names_chronics_to_backend = names_chronics_to_backend

        # game _parameters
        self.parameters_path = parameters_path
        if isinstance(parameters_path, str):
            self.parameters = Parameters(parameters_path)
        elif isinstance(parameters_path, dict):
            self.parameters = Parameters()
            self.parameters.init_from_dict(parameters_path)
        elif parameters_path is None:
            self.parameters = Parameters()
        else:
            raise RuntimeError(
                "Impossible to build the parameters. The argument \"parameters_path\" should either "
                "be a string or a dictionary.")

        # chronics of grid state
        self.path_chron = path_chron
        self.gridStateclass_kwargs = gridStateclass_kwargs
        self.max_iter = max_iter
        if max_iter > 0:
            self.gridStateclass_kwargs["max_iter"] = max_iter
        self.chronics_handler = ChronicsHandler(
            chronicsClass=self.gridStateclass,
            path=self.path_chron,
            **self.gridStateclass_kwargs)

        self.verbose = verbose
        self.thermal_limit_a = thermal_limit_a

        # controler for voltage
        if not issubclass(voltageControlerClass, ControlVoltageFromFile):
            raise Grid2OpException(
                "Parameter \"voltagecontrolClass\" should derive from \"ControlVoltageFromFile\"."
            )
        self.voltageControlerClass = voltageControlerClass
        self._other_rewards = other_rewards

        # for opponent (should be defined here) after the initialization of BaseEnv
        if not issubclass(opponent_action_class, BaseAction):
            raise EnvError(
                "Impossible to make an environment with an opponent action class not "
                "derived from BaseAction")
        try:
            self.opponent_init_budget = dt_float(opponent_init_budget)
        except Exception as e:
            raise EnvError(
                "Impossible to convert \"opponent_init_budget\" to a float with error {}"
                .format(e))
        if self.opponent_init_budget < 0.:
            raise EnvError(
                "If you want to deactive the opponent, please don't set its budget to a negative number."
                "Prefer the use of the DontAct action type (\"opponent_action_class=DontAct\" "
                "and / or set its budget to 0.")
        if not issubclass(opponent_class, BaseOpponent):
            raise EnvError(
                "Impossible to make an opponent with a type that does not inherit from BaseOpponent."
            )
        self.opponent_action_class = opponent_action_class
        self.opponent_class = opponent_class
        self.opponent_init_budget = opponent_init_budget
        self.opponent_budget_per_ts = opponent_budget_per_ts
        self.opponent_budget_class = opponent_budget_class
        self.opponent_attack_duration = opponent_attack_duration
        self.opponent_attack_cooldown = opponent_attack_cooldown
        self.opponent_kwargs = opponent_kwargs
        self.grid_layout = grid_layout

        # attention budget
        self._attention_budget_cls = attention_budget_cls
        self._kwargs_attention_budget = copy.deepcopy(kwargs_attention_budget)
        self._has_attention_budget = has_attention_budget

        # otherwise on windows / macos it sometimes fail in the runner in multi process
        # on linux like OS i prefer to generate all the proper classes accordingly
        if _IS_LINUX:
            pass
            with warnings.catch_warnings():
                warnings.filterwarnings("ignore")
                with self.init_env() as env:
                    bk_class = type(env.backend)
                    pass

        self.__used = False
Esempio n. 24
0
    def load_redispacthing_data(self, path, name='prods_charac.csv'):
        """
        This method will load everything needed for the redispatching and unit commitment problem.


        Parameters
        ----------
        path
        name

        Returns
        -------

        """
        # for redispatching
        fullpath = os.path.join(path, name)
        if not os.path.exists(fullpath):
            self.redispatching_unit_commitment_availble = False
            return
        try:
            df = pd.read_csv(fullpath)
        except Exception as e:
            return

        for el in ["type", "Pmax", "Pmin", "max_ramp_up", "max_ramp_down", "start_cost",
                   "shut_down_cost", "marginal_cost", "min_up_time", "min_down_time"]:
            if el not in df.columns:
                return

        gen_info = {}
        for _, row in df.iterrows():
            gen_info[row["name"]] = {"type": row["type"],
                                     "pmax": row["Pmax"],
                                     "pmin": row["Pmin"],
                                     "max_ramp_up": row["max_ramp_up"],
                                     "max_ramp_down": row["max_ramp_down"],
                                     "start_cost": row["start_cost"],
                                     "shut_down_cost": row["shut_down_cost"],
                                     "marginal_cost": row["marginal_cost"],
                                     "min_up_time": row["min_up_time"],
                                     "min_down_time": row["min_down_time"]
                                     }
        self.redispatching_unit_commitment_availble = True

        self.gen_type = np.full(self.n_gen, fill_value="aaaaaaaaaa")
        self.gen_pmin = np.full(self.n_gen, fill_value=1., dtype=dt_float)
        self.gen_pmax = np.full(self.n_gen, fill_value=1., dtype=dt_float)
        self.gen_redispatchable = np.full(self.n_gen, fill_value=False, dtype=dt_bool)
        self.gen_max_ramp_up = np.full(self.n_gen, fill_value=0., dtype=dt_float)
        self.gen_max_ramp_down = np.full(self.n_gen, fill_value=0., dtype=dt_float)
        self.gen_min_uptime = np.full(self.n_gen, fill_value=-1, dtype=dt_int)
        self.gen_min_downtime = np.full(self.n_gen, fill_value=-1, dtype=dt_int)
        self.gen_cost_per_MW = np.full(self.n_gen, fill_value=1., dtype=dt_float)  # marginal cost
        self.gen_startup_cost = np.full(self.n_gen, fill_value=1., dtype=dt_float)  # start cost
        self.gen_shutdown_cost = np.full(self.n_gen, fill_value=1., dtype=dt_float)  # shutdown cost

        for i, gen_nm in enumerate(self.name_gen):
            tmp_gen = gen_info[gen_nm]
            self.gen_type[i] = str(tmp_gen["type"])
            self.gen_pmin[i] = dt_float(tmp_gen["pmin"])
            self.gen_pmax[i] = dt_float(tmp_gen["pmax"])
            self.gen_redispatchable[i] = dt_bool(tmp_gen["type"] not in ["wind", "solar"])
            tmp = dt_float(tmp_gen["max_ramp_up"])
            if np.isfinite(tmp):
                self.gen_max_ramp_up[i] = tmp
            tmp = dt_float(tmp_gen["max_ramp_down"])
            if np.isfinite(tmp):
                self.gen_max_ramp_down[i] = tmp
            self.gen_min_uptime[i] = dt_int(tmp_gen["min_up_time"])
            self.gen_min_downtime[i] = dt_int(tmp_gen["min_down_time"])
            self.gen_cost_per_MW[i] = dt_float(tmp_gen["marginal_cost"])
            self.gen_startup_cost[i] = dt_float(tmp_gen["start_cost"])
            self.gen_shutdown_cost[i] = dt_float(tmp_gen["shut_down_cost"])
Esempio n. 25
0
    def __init__(self, parameters_path=None):
        """
        Build an object representing the _parameters of the game.

        Parameters
        ----------
        parameters_path: ``str``, optional
            Path where to look for parameters.

        """
        # if True, then it will not disconnect lines above their thermal limits
        self.NO_OVERFLOW_DISCONNECTION = False

        # number of timestep before powerline with an overflow is automatically disconnected
        self.NB_TIMESTEP_OVERFLOW_ALLOWED = dt_int(2)

        # number of timestep before a line can be reconnected if it has suffer a forced disconnection
        self.NB_TIMESTEP_RECONNECTION = dt_int(10)

        # number of timestep before a substation topology can be modified again
        self.NB_TIMESTEP_COOLDOWN_LINE = dt_int(0)
        self.NB_TIMESTEP_COOLDOWN_SUB = dt_int(0)

        # threshold above which a powerline is instantly disconnected by protections
        # this is expressed in relative value of the thermal limits
        # for example setting "HARD_OVERFLOW_THRESHOLD = 2" is equivalent, if a powerline has a thermal limit of
        # 243 A, to disconnect it instantly if it has a powerflow higher than 2 * 243 = 486 A
        self.HARD_OVERFLOW_THRESHOLD = dt_float(2.)

        # are the powerflow performed by the environment in DC mode (dc powerflow) or AC (ac powerflow)
        self.ENV_DC = False

        # same as above, but for the forecast states
        self.FORECAST_DC = False  # DEPRECATED use "change_forecast_parameters(new_param)" with "new_param.ENV_DC=..."

        # maximum number of substations that can be change in one action
        self.MAX_SUB_CHANGED = dt_int(1)

        # maximum number of powerline status that can be changed in one action
        self.MAX_LINE_STATUS_CHANGED = dt_int(1)

        # ignore the min_uptime and downtime for the generators: allow them to be connected / disconnected
        # at will
        self.IGNORE_MIN_UP_DOWN_TIME = True

        # allow dispatch on turned off generator (if ``True`` you can actually dispatch a turned on geenrator)
        self.ALLOW_DISPATCH_GEN_SWITCH_OFF = True

        # storage capacity (NOT in pct)
        self.INIT_STORAGE_CAPACITY = 0.5

        # do i take into account the storage loss in the step function
        self.ACTIVATE_STORAGE_LOSS = True

        if parameters_path is not None:
            if os.path.isfile(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))

        self.ALARM_BEST_TIME = 12
        self.ALARM_WINDOW_SIZE = 12
Esempio n. 26
0
 def __init__(self):
     BaseReward.__init__(self)
     self.reward_min = dt_float(0.0)
     self.reward_max = dt_float(1.0)
Esempio n. 27
0
    def check_valid(self):
        """

        check the parameter is valid (ie it checks that all the values are of correct types and within the
        correct range.

        Raises
        -------
        An exception if the parameter is not valid
        """
        try:
            if not isinstance(self.NO_OVERFLOW_DISCONNECTION, (bool, dt_bool)):
                raise RuntimeError(
                    "NO_OVERFLOW_DISCONNECTION should be a boolean")
            self.NO_OVERFLOW_DISCONNECTION = dt_bool(
                self.NO_OVERFLOW_DISCONNECTION)
        except Exception as exc_:
            raise RuntimeError(
                f"Impossible to convert NO_OVERFLOW_DISCONNECTION to bool with error \n:\"{exc_}\""
            )

        try:
            self.NB_TIMESTEP_OVERFLOW_ALLOWED = int(
                self.NB_TIMESTEP_OVERFLOW_ALLOWED)  # to raise if numpy array
            self.NB_TIMESTEP_OVERFLOW_ALLOWED = dt_int(
                self.NB_TIMESTEP_OVERFLOW_ALLOWED)
        except Exception as exc_:
            raise RuntimeError(
                f"Impossible to convert NB_TIMESTEP_OVERFLOW_ALLOWED to int with error \n:\"{exc_}\""
            )

        if self.NB_TIMESTEP_OVERFLOW_ALLOWED < 0:
            raise RuntimeError(
                "NB_TIMESTEP_OVERFLOW_ALLOWED < 0., this should be >= 0.")
        try:
            self.NB_TIMESTEP_RECONNECTION = int(
                self.NB_TIMESTEP_RECONNECTION)  # to raise if numpy array
            self.NB_TIMESTEP_RECONNECTION = dt_int(
                self.NB_TIMESTEP_RECONNECTION)
        except Exception as exc_:
            raise RuntimeError(
                f"Impossible to convert NB_TIMESTEP_RECONNECTION to int with error \n:\"{exc_}\""
            )
        if self.NB_TIMESTEP_RECONNECTION < 0:
            raise RuntimeError(
                "NB_TIMESTEP_RECONNECTION < 0., this should be >= 0.")
        try:
            self.NB_TIMESTEP_COOLDOWN_LINE = int(
                self.NB_TIMESTEP_COOLDOWN_LINE)
            self.NB_TIMESTEP_COOLDOWN_LINE = dt_int(
                self.NB_TIMESTEP_COOLDOWN_LINE)
        except Exception as exc_:
            raise RuntimeError(
                f"Impossible to convert NB_TIMESTEP_COOLDOWN_LINE to int with error \n:\"{exc_}\""
            )
        if self.NB_TIMESTEP_COOLDOWN_LINE < 0:
            raise RuntimeError(
                "NB_TIMESTEP_COOLDOWN_LINE < 0., this should be >= 0.")
        try:
            self.NB_TIMESTEP_COOLDOWN_SUB = int(
                self.NB_TIMESTEP_COOLDOWN_SUB)  # to raise if numpy array
            self.NB_TIMESTEP_COOLDOWN_SUB = dt_int(
                self.NB_TIMESTEP_COOLDOWN_SUB)
        except Exception as exc_:
            raise RuntimeError(
                f"Impossible to convert NB_TIMESTEP_COOLDOWN_SUB to int with error \n:\"{exc_}\""
            )
        if self.NB_TIMESTEP_COOLDOWN_SUB < 0:
            raise RuntimeError(
                "NB_TIMESTEP_COOLDOWN_SUB < 0., this should be >= 0.")
        try:
            self.HARD_OVERFLOW_THRESHOLD = float(
                self.HARD_OVERFLOW_THRESHOLD)  # to raise if numpy array
            self.HARD_OVERFLOW_THRESHOLD = dt_float(
                self.HARD_OVERFLOW_THRESHOLD)
        except Exception as exc_:
            raise RuntimeError(
                f"Impossible to convert HARD_OVERFLOW_THRESHOLD to float with error \n:\"{exc_}\""
            )
        if self.HARD_OVERFLOW_THRESHOLD < 1.:
            raise RuntimeError(
                "HARD_OVERFLOW_THRESHOLD < 1., this should be >= 1. (use env.set_thermal_limit "
                "to modify the thermal limit)")
        try:
            if not isinstance(self.ENV_DC, (bool, dt_bool)):
                raise RuntimeError(
                    "NO_OVERFLOW_DISCONNECTION should be a boolean")
            self.ENV_DC = dt_bool(self.ENV_DC)
        except Exception as exc_:
            raise RuntimeError(
                f"Impossible to convert ENV_DC to bool with error \n:\"{exc_}\""
            )
        try:
            self.MAX_SUB_CHANGED = int(
                self.MAX_SUB_CHANGED)  # to raise if numpy array
            self.MAX_SUB_CHANGED = dt_int(self.MAX_SUB_CHANGED)
        except Exception as exc_:
            raise RuntimeError(
                f"Impossible to convert MAX_SUB_CHANGED to int with error \n:\"{exc_}\""
            )
        if self.MAX_SUB_CHANGED < 0:
            raise RuntimeError(
                "MAX_SUB_CHANGED should be >=0 (or -1 if you want to be able to change every "
                "substation at once)")
        try:
            self.MAX_LINE_STATUS_CHANGED = int(
                self.MAX_LINE_STATUS_CHANGED)  # to raise if numpy array
            self.MAX_LINE_STATUS_CHANGED = dt_int(self.MAX_LINE_STATUS_CHANGED)
        except Exception as exc_:
            raise RuntimeError(
                f"Impossible to convert MAX_LINE_STATUS_CHANGED to int with error \n:\"{exc_}\""
            )
        if self.MAX_LINE_STATUS_CHANGED < 0:
            raise RuntimeError(
                "MAX_LINE_STATUS_CHANGED should be >=0 "
                "(or -1 if you want to be able to change every powerline at once)"
            )
        try:
            if not isinstance(self.IGNORE_MIN_UP_DOWN_TIME, (bool, dt_bool)):
                raise RuntimeError(
                    "IGNORE_MIN_UP_DOWN_TIME should be a boolean")
            self.IGNORE_MIN_UP_DOWN_TIME = dt_bool(
                self.IGNORE_MIN_UP_DOWN_TIME)
        except Exception as exc_:
            raise RuntimeError(
                f"Impossible to convert IGNORE_MIN_UP_DOWN_TIME to bool with error \n:\"{exc_}\""
            )
        try:
            if not isinstance(self.ALLOW_DISPATCH_GEN_SWITCH_OFF,
                              (bool, dt_bool)):
                raise RuntimeError(
                    "ALLOW_DISPATCH_GEN_SWITCH_OFF should be a boolean")
            self.ALLOW_DISPATCH_GEN_SWITCH_OFF = dt_bool(
                self.ALLOW_DISPATCH_GEN_SWITCH_OFF)
        except Exception as exc_:
            raise RuntimeError(
                f"Impossible to convert ALLOW_DISPATCH_GEN_SWITCH_OFF to bool with error \n:\"{exc_}\""
            )

        try:
            self.INIT_STORAGE_CAPACITY = float(
                self.INIT_STORAGE_CAPACITY)  # to raise if numpy array
            self.INIT_STORAGE_CAPACITY = dt_float(self.INIT_STORAGE_CAPACITY)
        except Exception as exc_:
            raise RuntimeError(
                f"Impossible to convert INIT_STORAGE_CAPACITY to float with error \n:\"{exc_}\""
            )

        if self.INIT_STORAGE_CAPACITY < 0.:
            raise RuntimeError(
                "INIT_STORAGE_CAPACITY < 0., this should be within range [0., 1.]"
            )
        if self.INIT_STORAGE_CAPACITY > 1.:
            raise RuntimeError(
                "INIT_STORAGE_CAPACITY > 1., this should be within range [0., 1.]"
            )

        try:
            if not isinstance(self.ACTIVATE_STORAGE_LOSS, (bool, dt_bool)):
                raise RuntimeError("ACTIVATE_STORAGE_LOSS should be a boolean")
            self.ACTIVATE_STORAGE_LOSS = dt_bool(self.ACTIVATE_STORAGE_LOSS)
        except Exception as exc_:
            raise RuntimeError(
                f"Impossible to convert ACTIVATE_STORAGE_LOSS to bool with error \n:\"{exc_}\""
            )

        try:
            self.ALARM_WINDOW_SIZE = dt_int(self.ALARM_WINDOW_SIZE)
        except Exception as exc_:
            raise RuntimeError(
                f"Impossible to convert ALARM_WINDOW_SIZE to int with error \n:\"{exc_}\""
            )
        try:
            self.ALARM_BEST_TIME = dt_int(self.ALARM_BEST_TIME)
        except Exception as exc_:
            raise RuntimeError(
                f"Impossible to convert ALARM_BEST_TIME to int with error \n:\"{exc_}\""
            )

        if self.ALARM_WINDOW_SIZE <= 0:
            raise RuntimeError(
                "self.ALARM_WINDOW_SIZE should be a positive integer !")
        if self.ALARM_BEST_TIME <= 0:
            raise RuntimeError(
                "self.ALARM_BEST_TIME should be a positive integer !")
Esempio n. 28
0
 def __call__(self, action, env, has_error, is_done, is_illegal,
              is_ambiguous):
     return dt_float(0.0)
Esempio n. 29
0
 def __init__(self, per_timestep=1):
     BaseReward.__init__(self)
     self.per_timestep = dt_float(per_timestep)
     self.reward_min = dt_float(0.0)
     self.reward_max = dt_float(per_timestep)
Esempio n. 30
0
    def update(self, env, with_forecast=True):
        # reset the matrices
        self._reset_matrices()
        self.reset()

        # counter
        self.current_step = env.nb_time_step
        self.max_step = env.max_episode_duration()

        # extract the time stamps
        self.year = dt_int(env.time_stamp.year)
        self.month = dt_int(env.time_stamp.month)
        self.day = dt_int(env.time_stamp.day)
        self.hour_of_day = dt_int(env.time_stamp.hour)
        self.minute_of_hour = dt_int(env.time_stamp.minute)
        self.day_of_week = dt_int(env.time_stamp.weekday())

        # get the values related to topology
        self.timestep_overflow[:] = env._timestep_overflow
        self.line_status[:] = env.backend.get_line_status()
        self.topo_vect[:] = env.backend.get_topo_vect()

        # get the values related to continuous values
        self.gen_p[:], self.gen_q[:], self.gen_v[:] = env.backend.generators_info(
        )
        self.load_p[:], self.load_q[:], self.load_v[:] = env.backend.loads_info(
        )
        self.p_or[:], self.q_or[:], self.v_or[:], self.a_or[:] = env.backend.lines_or_info(
        )
        self.p_ex[:], self.q_ex[:], self.v_ex[:], self.a_ex[:] = env.backend.lines_ex_info(
        )

        # storage units
        self.storage_charge[:] = env._storage_current_charge
        self.storage_power_target[:] = env._action_storage
        self.storage_power[:] = env._storage_power

        # handles forecasts here
        if with_forecast:
            inj_action = {}
            dict_ = {}
            dict_["load_p"] = dt_float(1.0 * self.load_p)
            dict_["load_q"] = dt_float(1.0 * self.load_q)
            dict_["prod_p"] = dt_float(1.0 * self.gen_p)
            dict_["prod_v"] = dt_float(1.0 * self.gen_v)
            inj_action["injection"] = dict_
            # inj_action = self.action_helper(inj_action)
            timestamp = self.get_time_stamp()
            self._forecasted_inj = [(timestamp, inj_action)]
            self._forecasted_inj += env.chronics_handler.forecasts()
            self._forecasted_grid = [None for _ in self._forecasted_inj]

        self.rho[:] = env.backend.get_relative_flow().astype(dt_float)

        # cool down and reconnection time after hard overflow, soft overflow or cascading failure
        self.time_before_cooldown_line[:] = env._times_before_line_status_actionable
        self.time_before_cooldown_sub[:] = env._times_before_topology_actionable
        self.time_next_maintenance[:] = env._time_next_maintenance
        self.duration_next_maintenance[:] = env._duration_next_maintenance

        # redispatching
        self.target_dispatch[:] = env._target_dispatch
        self.actual_dispatch[:] = env._actual_dispatch

        # handle shunts (if avaialble)
        if self.shunts_data_available:
            sh_p, sh_q, sh_v, sh_bus = env.backend.shunt_info()
            self._shunt_p[:] = sh_p
            self._shunt_q[:] = sh_q
            self._shunt_v[:] = sh_v
            self._shunt_bus[:] = sh_bus

        self._thermal_limit[:] = env.get_thermal_limit()

        if self.redispatching_unit_commitment_availble:
            self.gen_p_before_curtail[:] = env._gen_before_curtailment
            self.curtailment[:] = (self.gen_p_before_curtail -
                                   self.gen_p) / self.gen_pmax
            self.curtailment[~self.gen_renewable] = 0.
            self.curtailment_limit[:] = env._limit_curtailment
            self.curtailment_limit[self.curtailment_limit >= 1.] = 1.0
        else:
            self.curtailment[:] = 0.
            self.gen_p_before_curtail[:] = self.gen_p
            self.curtailment_limit[:] = 1.0

        if env.backend.can_output_theta:
            self.support_theta = True  # backend supports the computation of theta
            self.theta_or[:], self.theta_ex[:], self.load_theta[:], self.gen_theta[:], self.storage_theta[:] = \
                env.backend.get_theta()

        if self.dim_alarms and env._has_attention_budget:
            self.is_alarm_illegal[:] = env._is_alarm_illegal
            if env._attention_budget.time_last_successful_alarm_raised > 0:
                self.time_since_last_alarm[:] = self.current_step - env._attention_budget.time_last_successful_alarm_raised
            else:
                self.time_since_last_alarm[:] = -1
            self.last_alarm[:] = env._attention_budget.last_successful_alarm_raised
            self.attention_budget[:] = env._attention_budget.current_budget