def disconnect_powerline(self, line_id, previous_action=None):
        """
        Utilities to disconnect a powerline more easily.

        Parameters
        ----------
        line_id: ``int``
            The powerline to be disconnected.

        previous_action

        Returns
        -------

        """
        if previous_action is None:
            res = self.actionClass()
        else:
            if not isinstance(previous_action, self.actionClass):
                raise AmbiguousAction(
                    "The action to update using `ActionSpace` is of type \"{}\" "
                    "which is not the type of action handled by this helper "
                    "(\"{}\")".format(type(previous_action), self.actionClass))
            res = previous_action
        if line_id > self.n_line:
            raise AmbiguousAction(
                "You asked to disconnect powerline of id {} but this id does not exist. The "
                "grid counts only {} powerline".format(line_id, self.n_line))
        res.update({"set_line_status": [(line_id, -1)]})
        return res
    def _extract_dict_action(self,
                             name_element,
                             extremity=None,
                             substation=None,
                             type_element=None,
                             action=None):
        to_subid = None
        to_sub_pos = None
        to_name = None

        if type_element == "line":
            to_subid, to_sub_pos, to_name = self._extract_database_powerline(
                extremity)
        elif type_element[:3] == "gen" or type_element[:4] == "prod":
            to_subid = self.gen_to_subid
            to_sub_pos = self.gen_to_sub_pos
            to_name = self.name_gen
        elif type_element == "load":
            to_subid = self.load_to_subid
            to_sub_pos = self.load_to_sub_pos
            to_name = self.name_load
        elif type_element is None:
            # i have to look through all the objects to find it
            if name_element in self.name_load:
                to_subid = self.load_to_subid
                to_sub_pos = self.load_to_sub_pos
                to_name = self.name_load
            elif name_element in self.name_gen:
                to_subid = self.gen_to_subid
                to_sub_pos = self.gen_to_sub_pos
                to_name = self.name_gen
            elif name_element in self.name_line:
                to_subid, to_sub_pos, to_name = self._extract_database_powerline(
                    extremity)
            else:
                AmbiguousAction(
                    "Element \"{}\" not found in the powergrid".format(
                        name_element))
        else:
            raise AmbiguousAction(
                "unknown type_element specifier \"{}\". type_element should be \"line\" or \"load\" "
                "or \"gen\"".format(extremity))

        my_id = None
        for i, nm in enumerate(to_name):
            if nm == name_element:
                my_id = i
                break
        if my_id is None:
            raise AmbiguousAction(
                "Element \"{}\" not found in the powergrid".format(
                    name_element))
        my_sub_id = to_subid[my_id]

        dict_ = action.effect_on(substation_id=my_sub_id)
        return dict_, to_sub_pos, my_id, my_sub_id
    def disconnect_powerline(self,
                             line_id=None,
                             line_name=None,
                             previous_action=None):
        """
        Utilities to disconnect a powerline more easily.

        Parameters
        ----------
        line_id: ``int``
            The powerline to be disconnected.

        line_name: ``str``
            Name of the powerline. Note that either line_id or line_name should be provided. If both are provided, it is
            an error, if none are provided it is an error.

        previous_action

        Returns
        -------
        res: :class:`BaseAction`
            The action that will disconnect the powerline.

        """
        if line_id is None and line_name is None:
            raise AmbiguousAction(
                "You need to provide either the \"line_id\" or the \"line_name\" of the powerline "
                "you want to disconnect")
        if line_id is not None and line_name is not None:
            raise AmbiguousAction(
                "You need to provide only of the \"line_id\" or the \"line_name\" of the powerline "
                "you want to disconnect")

        if line_id is None:
            line_id = np.where(self.name_line == line_name)[0]
            if not len(line_id):
                raise AmbiguousAction(
                    "Line with name \"{}\" is not on the grid. The powerlines names are:\n{}"
                    "".format(line_name, self.name_line))
        if previous_action is None:
            res = self.actionClass()
        else:
            if not isinstance(previous_action, self.actionClass):
                raise AmbiguousAction(
                    "The action to update using `ActionSpace` is of type \"{}\" "
                    "which is not the type of action handled by this helper "
                    "(\"{}\")".format(type(previous_action), self.actionClass))
            res = previous_action
        if line_id > self.n_line:
            raise AmbiguousAction(
                "You asked to disconnect powerline of id {} but this id does not exist. The "
                "grid counts only {} powerline".format(line_id, self.n_line))
        res.update({"set_line_status": [(line_id, -1)]})
        return res
    def reconnect_powerline(self,
                            line_id,
                            bus_or,
                            bus_ex,
                            previous_action=None):
        """
        Utilities to reconnect a powerline more easily.

        Note that in case "bus_or" or "bus_ex" are not the current bus to which the powerline is connected, they
        will be affected by this action.

        Parameters
        ----------
        line_id: ``int``
            The powerline to be disconnected.

        bus_or: ``int``
            On which bus to reconnect the powerline at its origin end

        bus_ex: ``int``
            On which bus to reconnect the powerline at its extremity end
        previous_action

        Returns
        -------

        """
        if previous_action is None:
            res = self.actionClass()
        else:
            if not isinstance(previous_action, self.actionClass):
                raise AmbiguousAction(
                    "The action to update using `ActionSpace` is of type \"{}\" "
                    "which is not the type of action handled by this helper "
                    "(\"{}\")".format(type(previous_action), self.actionClass))
            res = previous_action
        if line_id > self.n_line:
            raise AmbiguousAction(
                "You asked to disconnect powerline of id {} but this id does not exist. The "
                "grid counts only {} powerline".format(line_id, self.n_line))
        res.update({
            "set_line_status": [(line_id, 1)],
            "set_bus": {
                "lines_or_id": [(line_id, bus_or)],
                "lines_ex_id": [(line_id, bus_ex)]
            }
        })
        return res
Beispiel #5
0
    def __call__(self):
        """
        Compare to the ancestor :func:`BaseAction.__call__` this type of BaseAction doesn't allow to change the injections.
        The only difference is in the returned value *dict_injection* that is always an empty dictionnary.

        Returns
        -------
        dict_injection: :class:`dict`
            This dictionnary is always empty

        set_line_status: :class:`numpy.array`, dtype:int
            This array is :attr:`BaseAction._set_line_status`

        switch_line_status: :class:`numpy.array`, dtype:bool
            This array is :attr:`BaseAction._switch_line_status`, it is never modified

        set_topo_vect: :class:`numpy.array`, dtype:int
            This array is :attr:`BaseAction._set_topo_vect`, it is never modified

        change_bus_vect: :class:`numpy.array`, dtype:bool
            This array is :attr:`BaseAction._change_bus_vect`, it is never modified
        """
        if self._dict_inj:
            raise AmbiguousAction(
                "You asked to modify the injection with an action of class \"TopologyAction\"."
            )
        self._check_for_ambiguity()
        return {}, self._set_line_status, self._switch_line_status, self._set_topo_vect, self._change_bus_vect
    def change_bus(self,
                   name_element,
                   extremity=None,
                   substation=None,
                   type_element=None,
                   previous_action=None):
        """
        Utilities to change the bus of a single element if you give its name. **NB** Changing a bus has the effect to
        assign the object to bus 1 if it was before that connected to bus 2, and to assign it to bus 2 if it was
        connected to bus 1. It should not be mixed up with :func:`ActionSpace.set_bus`.

        If the parameter "*previous_action*" is not ``None``, then the action given to it is updated (in place) and
        returned.

        Parameters
        ----------
        name_element: ``str``
            The name of the element you want to change the bus
        extremity: ``str``
            "or" or "ex" for origin or extremity, ignored if an element is not a powerline.
        substation: ``int``, optional
            Its substation ID, if you know it will increase the performance. Otherwise, the method will search for it.
        type_element: ``int``, optional
            Type of the element to look for. It is here to speed up the computation. One of "line", "gen" or "load"
        previous_action: :class:`Action`, optional
            The (optional) action to update. It should be of the same type as :attr:`ActionSpace.actionClass`

        Returns
        -------
        res: :class:`BaseAction`
            The action with the modification implemented

        Raises
        ------
        :class:`grid2op.Exception.AmbiguousAction`
            If *previous_action* has not the same type as :attr:`ActionSpace.actionClass`.

        """
        if previous_action is None:
            res = self.actionClass()
        else:
            if not isinstance(previous_action, self.actionClass):
                raise AmbiguousAction(
                    "The action to update using `ActionSpace` is of type \"{}\" "
                    "which is not the type of action handled by this helper "
                    "(\"{}\")".format(type(previous_action), self.actionClass))
            res = previous_action

        dict_, to_sub_pos, my_id, my_sub_id = self._extract_dict_action(
            name_element, extremity, substation, type_element, res)
        dict_["change_bus"][to_sub_pos[my_id]] = True
        res.update({
            "change_bus": {
                "substations_id": [(my_sub_id, dict_["change_bus"])]
            }
        })
        # res.update(dict_)
        return res
Beispiel #7
0
    def _check_dict(self):
        """
        Check that nothing, beside prod_v has been updated with this action.

        Returns
        -------

        """
        if self._dict_inj:
            for el in self._dict_inj:
                if el not in self.attr_list_vect:
                    raise AmbiguousAction("Impossible to modify something different than \"prod_v\" using "
                                          "\"VoltageOnlyAction\" action.")
Beispiel #8
0
    def _check_dict(self):
        """
        .. warning:: /!\\\\ Internal, do not use unless you know what you are doing /!\\\\

        Check that nothing, beside prod_v has been updated with this action.

        Returns
        -------

        """
        if self._dict_inj:
            for el in self._dict_inj:
                if el not in self.attr_list_vect:
                    raise AmbiguousAction(
                        "Impossible to modify something different than \"prod_v\" using "
                        "\"VoltageOnlyAction\" action.")
Beispiel #9
0
    def __call__(self):
        """
         .. warning:: /!\\\\ Internal, do not use unless you know what you are doing /!\\\\

        Compare to the ancestor :func:`BaseAction.__call__` this type of BaseAction doesn't allow internal actions
        The returned tuple is same, but with empty dictionaries for internal actions

        Returns
        -------
        dict_injection: ``dict``
            This dictionary is always empty

        set_line_status: :class:`numpy.ndarray`, dtype:int
            This array is :attr:`BaseAction._set_line_status`

        switch_line_status: :class:`numpy.ndarray`, dtype:bool
            This array is :attr:`BaseAction._switch_line_status`

        set_topo_vect: :class:`numpy.ndarray`, dtype:int
            This array is :attr:`BaseAction._set_topo_vect`

        change_bus_vect: :class:`numpy.ndarray`, dtype:bool
            This array is :attr:`BaseAction._change_bus_vect`

        redispatch: :class:`numpy.ndarray`, dtype:float
            The array is :attr:`BaseAction._redispatch`

        curtail: :class:`numpy.ndarray`, dtype:float
            The array is :attr:`BaseAction._curtail`

        shunts: ``dict``
            Always empty for this class
        """
        if self._dict_inj:
            raise AmbiguousAction("Injections actions are not playable.")

        self._check_for_ambiguity()
        # TODO curtailment
        return {}, \
            self._set_line_status, self._switch_line_status, \
            self._set_topo_vect, self._change_bus_vect,\
            self._redispatch, self._storage_power,\
               {}
Beispiel #10
0
    def to_vect(self):
        """
        See :func:`BaseAction.to_vect` for a detailed description of this method.

        This method has the same behaviour as its base class, except it doesn't require any information about the
        injections to be sent, thus being more efficient from a memory footprint perspective.

        Returns
        -------
        _vectorized: :class:`numpy.array`, dtype:float
            The instance of this action converted to a vector.
        """
        if self.as_vect is None:
            self.as_vect = np.concatenate(
                (self._switch_line_status.flatten().astype(np.float),
                 self._change_bus_vect.flatten().astype(np.float)))

            if self.as_vect.shape[0] != self.size():
                raise AmbiguousAction(
                    "L2RPN2019_Action has not the proper shape.")

        return self.as_vect
Beispiel #11
0
    def __call__(self):
        """
        Compare to the ancestor :func:`BaseAction.__call__` this type of BaseAction doesn't allow internal actions
        The returned tuple is same, but with empty dictionaries for internal actions

        Returns
        -------
        dict_injection: ``dict``
            This dictionary is always empty

        set_line_status: :class:`numpy.ndarray`, dtype:int
            This array is :attr:`BaseAction._set_line_status`

        switch_line_status: :class:`numpy.ndarray`, dtype:bool
            This array is :attr:`BaseAction._switch_line_status`

        set_topo_vect: :class:`numpy.ndarray`, dtype:int
            This array is :attr:`BaseAction._set_topo_vect`

        change_bus_vect: :class:`numpy.ndarray`, dtype:bool
            This array is :attr:`BaseAction._change_bus_vect`

        redispatch: :class:`numpy.ndarray`, dtype:float
            Thie array is :attr:`BaseAction._redispatch`

        shunts: ``dict``
            Always empty for this class
        """
        if self._dict_inj:
            raise AmbiguousAction("Injections actions are not playable.")

        self._check_for_ambiguity()
        return {}, \
            self._set_line_status, self._switch_line_status, \
            self._set_topo_vect, self._change_bus_vect,\
            self._redispatch, {}
Beispiel #12
0
    def change_bus(self, name_element, extremity=None, substation=None, type_element=None, previous_action=None):
        """
        Utilities to change the bus of a single element if you give its name. **NB** Changing a bus has the effect to
        assign the object to bus 1 if it was before that connected to bus 2, and to assign it to bus 2 if it was
        connected to bus 1. It should not be mixed up with :func:`ActionSpace.set_bus`.

        If the parameter "*previous_action*" is not ``None``, then the action given to it is updated (in place) and
        returned.

        Parameters
        ----------
        name_element: ``str``
            The name of the element you want to change the bus
        extremity: ``str``
            "or" or "ex" for origin or extremity, ignored if an element is not a powerline.
        substation: ``int``, optional
            Its substation ID, if you know it will increase the performance. Otherwise, the method will search for it.
        type_element: ``str``, optional
            Type of the element to look for. It is here to speed up the computation. One of "line", "gen" or "load"
        previous_action: :class:`Action`, optional
            The (optional) action to update. It should be of the same type as :attr:`ActionSpace.actionClass`

        Notes
        ------
        If you use `previous_action` it will modify the action **in place** which means that
        `previous_action` will be modified by this method.

        Returns
        -------
        res: :class:`BaseAction`
            The action with the modification implemented

        Raises
        ------
        res :class:`grid2op.Exception.AmbiguousAction`
            If *previous_action* has not the same type as :attr:`ActionSpace.actionClass`.

        Examples
        ---------
        You can use it this way:

        .. code-block:: python

            import grid2op
            env = grid2op.make()

            # change bus of element named 'gen_1_0'
            change_gen_0 = env.action_space.change_bus('gen_1_0', type_element="gen")

            # you are not forced to specify the element types
            change_load_1 = env.action_space.change_bus('load_2_1')

            # dealing with powerline, you can affect one of its extremity
            # (handy when you don't know on which substation it is located)
            change_line_8_or = env.action_space.change_bus('5_11_8', extremity="or")

            # and you can combine the action with
            change_line_14_ex = env.action_space.change_bus('12_13_14', extremity="ex")
            change_line_14_ex_load_2 = env.action_space.change_bus("load_3_2",
                                                                   previous_action=change_line_14_ex)
            print(change_line_14_ex_load_2)
            # be careful, "change_line_14_ex" is affected and is in fact equal to
            # "change_line_14_ex_load_2"
            # after the last call!

        """
        if previous_action is None:
            res = self.actionClass()
        else:
            if not isinstance(previous_action, self.actionClass):
                raise AmbiguousAction("The action to update using `ActionSpace` is of type \"{}\" "
                                      "which is not the type of action handled by this helper "
                                      "(\"{}\")".format(type(previous_action), self.actionClass))
            res = previous_action

        dict_, to_sub_pos, my_id, my_sub_id = self._extract_dict_action(name_element, extremity, substation,
                                                                        type_element, res)
        arr_ = dict_["change_bus"]
        me_id_ = to_sub_pos[my_id]
        arr_[me_id_] = True
        res.update({"change_bus": {"substations_id": [(my_sub_id, arr_)]}})
        return res
Beispiel #13
0
    def reconnect_powerline(self, bus_or, bus_ex, line_id=None, line_name=None, previous_action=None):
        """
        Utilities to reconnect a powerline more easily.

        Note that in case "bus_or" or "bus_ex" are not the current bus to which the powerline is connected, they
        will be affected by this action.

        Notes
        ------
        This utility requires you to specify on which bus you want to connect each end
        ("*origin*" or "*extremity*") of the powerline you want to reconnect.

        If you don't want to specify them, you can set them to ``0`` and it will reconnect them
        to the last known buses to which they were connected (this is automatically done by the
        Environment since version `0.8.0`).

        If you use `previous_action` it will modify the action **in place** which means that
        `previous_action` will be modified by this method.

        Parameters
        ----------
        line_id: ``int``
            The powerline to be disconnected.

        bus_or: ``int``
            On which bus to reconnect the powerline at its origin end

        bus_ex: ``int``
            On which bus to reconnect the powerline at its extremity end
        previous_action

        Returns
        -------
        res: :class:`BaseAction`
            The action that will reconnect the powerline.

        Examples
        ---------
        You can use it this way:

        .. code-block:: python

            import grid2op
            env = grid2op.make()

            # and now you can reconnect line 0
            reco_line_0 = env.action_space.reconnect_powerline(line_id=0, bus_or=1, bus_ex=0)

            # or line with name "0_4_1" to bus 1 on its "origin" end and bus 2 on its "extremity" end
            reco_line_1 = env.action_space.reconnect_powerline(line_name="0_4_1", bus_or=1, bus_ex=2)

            # and you can reconnect both line 2 and 3 with:
            reco_line_2 = env.action_space.reconnect_powerline(line_id=2, bus_or=1, bus_ex=2)
            reco_line_2_and_3 = env.action_space.reconnect_powerline(line_id=3,
                                                                    bus_or=0, bus_ex=1,
                                                                    previous_action=reco_line_2)
            print(reco_line_2_and_3)
            # be careful, "reco_line_2" is affected and is in fact equal to "reco_line_2_and_3"
            # after the last call!

        """
        if line_id is None and line_name is None:
            raise AmbiguousAction("You need to provide either the \"line_id\" or the \"line_name\" of the powerline "
                                  "you want to reconnect")
        if line_id is not None and line_name is not None:
            raise AmbiguousAction("You need to provide only of the \"line_id\" or the \"line_name\" of the powerline "
                                  "you want to reconnect")

        if line_id is None:
            line_id = np.where(self.name_line == line_name)[0]

        if previous_action is None:
            res = self.actionClass()
        else:
            if not isinstance(previous_action, self.actionClass):
                raise AmbiguousAction("The action to update using `ActionSpace` is of type \"{}\" "
                                      "which is not the type of action handled by this helper "
                                      "(\"{}\")".format(type(previous_action), self.actionClass))
            res = previous_action
        if line_id > self.n_line:
            raise AmbiguousAction("You asked to disconnect powerline of id {} but this id does not exist. The "
                                  "grid counts only {} powerline".format(line_id, self.n_line))
        res.update({"set_line_status": [(line_id, 1)],
                    "set_bus": {"lines_or_id": [(line_id, bus_or)],
                                "lines_ex_id": [(line_id, bus_ex)]}})
        return res
Beispiel #14
0
    def disconnect_powerline(self, line_id=None, line_name=None, previous_action=None):
        """
        Utilities to disconnect a powerline more easily.

        Parameters
        ----------
        line_id: ``int``
            The powerline to be disconnected.

        line_name: ``str``
            Name of the powerline. Note that either line_id or line_name should be provided. If both are provided, it is
            an error, if none are provided it is an error.

        previous_action: :class:`BaseAction`
            If you want to stack up multiple actions.

        Returns
        -------
        res: :class:`BaseAction`
            The action that will disconnect the powerline.

        Notes
        ------
        If you use `previous_action` it will modify the action **in place** which means that
        `previous_action` will be modified by this method.

        Examples
        ---------
        You can use it this way:

        .. code-block:: python

            import grid2op
            env = grid2op.make()

            # and now you can disconnect line 0
            disco_line_0 = env.action_space.disconnect_powerline(line_id=0)

            # or line with name "0_4_1"
            disco_line_1 = env.action_space.disconnect_powerline(line_name="0_4_1")

            # and you can disconnect both line 2 and 3 with:
            disco_line_2 = env.action_space.disconnect_powerline(line_id=2)
            disco_line_2_and_3 = env.action_space.disconnect_powerline(line_id=3, previous_action=disco_line_2)
            print(disco_line_2_and_3)
            # be careful, "disco_line_2" is affected and is in fact equal to "disco_line_2_and_3"
            # after the last call!

        """
        if line_id is None and line_name is None:
            raise AmbiguousAction("You need to provide either the \"line_id\" or the \"line_name\" of the powerline "
                                  "you want to disconnect")
        if line_id is not None and line_name is not None:
            raise AmbiguousAction("You need to provide only of the \"line_id\" or the \"line_name\" of the powerline "
                                  "you want to disconnect")

        if line_id is None:
            line_id = np.where(self.name_line == line_name)[0]
            if not len(line_id):
                raise AmbiguousAction("Line with name \"{}\" is not on the grid. The powerlines names are:\n{}"
                                      "".format(line_name, self.name_line))
        if previous_action is None:
            res = self.actionClass()
        else:
            if not isinstance(previous_action, self.actionClass):
                raise AmbiguousAction("The action to update using `ActionSpace` is of type \"{}\" "
                                      "which is not the type of action handled by this helper "
                                      "(\"{}\")".format(type(previous_action), self.actionClass))
            res = previous_action
        if line_id > self.n_line:
            raise AmbiguousAction("You asked to disconnect powerline of id {} but this id does not exist. The "
                                  "grid counts only {} powerline".format(line_id, self.n_line))
        res.update({"set_line_status": [(line_id, -1)]})
        return res