Ejemplo n.º 1
0
    def __init__(self, detailed_infos_for_cascading_failures=False):
        """
        Initialize an instance of Backend. This does nothing per se. Only the call to :func:`Backend.load_grid`
        should guarantee the backend is properly configured.

        :param detailed_infos_for_cascading_failures: Whether to be detailed (but slow) when computing cascading failures
        :type detailed_infos_for_cascading_failures: :class:`bool`

        """
        # lazy loading
        from grid2op.Action import CompleteAction
        from grid2op.Action._BackendAction import _BackendAction

        GridObjects.__init__(self)

        # the following parameter is used to control the amount of verbosity when computing a cascading failure
        # if it's set to true, it returns all intermediate _grid states. This can slow down the computation!
        self.detailed_infos_for_cascading_failures = detailed_infos_for_cascading_failures

        # the power _grid manipulated. One powergrid per backend.
        self._grid = None

        # thermal limit setting, in ampere, at the same "side" of the powerline than self.get_line_overflow
        self.thermal_limit_a = None

        # action to set me
        self.my_bk_act_class = _BackendAction
        self._complete_action_class = CompleteAction

        # for the shunt (only if supported)
        self._sh_vnkv = None  # for each shunt gives the nominal value at the bus at which it is connected
Ejemplo n.º 2
0
    def __init__(self):
        GridObjects.__init__(self)
        # last connected registered
        self.last_topo_registered = ValueStore(self.dim_topo, dtype=dt_int)

        # topo at time t
        self.current_topo = ValueStore(self.dim_topo, dtype=dt_int)

        # injection at time t
        self.prod_p = ValueStore(self.n_gen, dtype=dt_float)
        self.prod_v = ValueStore(self.n_gen, dtype=dt_float)
        self.load_p = ValueStore(self.n_load, dtype=dt_float)
        self.load_q = ValueStore(self.n_load, dtype=dt_float)

        self.activated_bus = np.full((self.n_sub, 2),
                                     dtype=dt_bool,
                                     fill_value=False)
        self.big_topo_to_subid = np.repeat(list(range(self.n_sub)),
                                           repeats=self.sub_info)

        # shunts
        if self.shunts_data_available:
            self.shunt_p = ValueStore(self.n_shunt, dtype=dt_float)
            self.shunt_q = ValueStore(self.n_shunt, dtype=dt_float)
            self.shunt_bus = ValueStore(self.n_shunt, dtype=dt_int)
Ejemplo n.º 3
0
    def __init__(self, envs):
        GridObjects.__init__(self)
        self.envs = envs
        for env in envs:
            if not isinstance(env, Environment):
                raise MultiEnvException(
                    "You provided environment of type \"{}\" which is not supported."
                    "Please only provide a grid2op.Environment.Environment class."
                    "".format(type(env)))

        self.nb_env = len(envs)
        max_int = np.iinfo(dt_int).max
        self._remotes, self._work_remotes = zip(
            *[Pipe() for _ in range(self.nb_env)])

        env_params = [
            envs[e].get_kwargs(with_backend=False) for e in range(self.nb_env)
        ]
        self._ps = [
            RemoteEnv(env_params=env_,
                      remote=work_remote,
                      parent_remote=remote,
                      name="{}_subprocess_{}".format(envs[i].name, i),
                      seed=envs[i].space_prng.randint(max_int))
            for i, (work_remote, remote, env_) in enumerate(
                zip(self._work_remotes, self._remotes, env_params))
        ]

        for p in self._ps:
            p.daemon = True  # if the main process crashes, we should not cause things to hang
            p.start()
        for remote in self._work_remotes:
            remote.close()

        self._waiting = True
Ejemplo n.º 4
0
    def __init__(self, nb_env, env):
        GridObjects.__init__(self)
        self.imported_env = env
        self.nb_env = nb_env

        self._remotes, self._work_remotes = zip(
            *[Pipe() for _ in range(self.nb_env)])

        env_params = [env.get_kwargs() for _ in range(self.nb_env)]
        for el in env_params:
            el["backendClass"] = type(env.backend)
        self._ps = [
            RemoteEnv(env_params=env_,
                      remote=work_remote,
                      parent_remote=remote,
                      name="env: {}".format(i),
                      seed=np.random.randint(np.iinfo(dt_int).max))
            for i, (work_remote, remote, env_) in enumerate(
                zip(self._work_remotes, self._remotes, env_params))
        ]

        for p in self._ps:
            p.daemon = True  # if the main process crashes, we should not cause things to hang
            p.start()
        for remote in self._work_remotes:
            remote.close()

        self._waiting = True
Ejemplo n.º 5
0
    def __init__(
            self,
            envs_dir,
            _add_to_name="",  # internal, for test only, do not use !
            **kwargs):
        GridObjects.__init__(self)
        RandomObject.__init__(self)

        self.current_env = None
        self.env_index = None
        self.mix_envs = []

        # Special case handling for backend
        backendClass = None
        if "backend" in kwargs:
            backendClass = type(kwargs["backend"])
            del kwargs["backend"]

        # Inline import to prevent cyclical import
        from grid2op.MakeEnv.Make import make

        try:
            for env_dir in sorted(os.listdir(envs_dir)):
                env_path = os.path.join(envs_dir, env_dir)
                if not os.path.isdir(env_path):
                    continue
                # Special case for backend
                if backendClass is not None:
                    env = make(env_path,
                               backend=backendClass(),
                               _add_to_name=_add_to_name,
                               **kwargs)
                else:
                    env = make(env_path, **kwargs)

                self.mix_envs.append(env)
        except Exception as e:
            err_msg = "MultiMix environment creation failed: {}".format(e)
            raise EnvError(err_msg)

        if len(self.mix_envs) == 0:
            err_msg = "MultiMix envs_dir did not contain any valid env"
            raise EnvError(err_msg)

        self.env_index = 0
        self.current_env = self.mix_envs[self.env_index]
        # Make sure GridObject class attributes are set from first env
        # Should be fine since the grid is the same for all envs
        multi_env_name = os.path.basename(
            os.path.abspath(envs_dir)) + _add_to_name
        save_env_name = self.current_env.env_name
        self.current_env.env_name = multi_env_name
        self.__class__ = self.init_grid(self.current_env)
        self.current_env.env_name = save_env_name
Ejemplo n.º 6
0
    def __init__(self, detailed_infos_for_cascading_failures=False):
        """
        Initialize an instance of Backend. This does nothing per se. Only the call to :func:`Backend.load_grid`
        should guarantee the backend is properly configured.

        :param detailed_infos_for_cascading_failures: Whether to be detailed (but slow) when computing cascading failures
        :type detailed_infos_for_cascading_failures: :class:`bool`

        """
        GridObjects.__init__(self)

        # the following parameter is used to control the amount of verbosity when computing a cascading failure
        # if it's set to true, it returns all intermediate _grid states. This can slow down the computation!
        self.detailed_infos_for_cascading_failures = detailed_infos_for_cascading_failures

        # the power _grid manipulated. One powergrid per backend.
        self._grid = None

        # thermal limit setting, in ampere, at the same "side" of the powerline than self.get_line_overflow
        self.thermal_limit_a = None
Ejemplo n.º 7
0
    def __init__(self, obs_env=None, action_helper=None, seed=None):
        GridObjects.__init__(self)

        self.action_helper = action_helper

        # time stamp information
        self.year = 1970
        self.month = 0
        self.day = 0
        self.hour_of_day = 0
        self.minute_of_hour = 0
        self.day_of_week = 0

        # for non deterministic observation that would not use default np.random module
        self.seed = None

        # handles the forecasts here
        self._forecasted_grid_act = {}
        self._forecasted_inj = []

        self.timestep_overflow = np.zeros(shape=(self.n_line, ), dtype=dt_int)

        # 0. (line is disconnected) / 1. (line is connected)
        self.line_status = np.ones(shape=self.n_line, dtype=dt_bool)

        # topological vector
        self.topo_vect = np.full(shape=self.dim_topo,
                                 dtype=dt_int,
                                 fill_value=0)

        # generators information
        self.prod_p = np.full(shape=self.n_gen,
                              dtype=dt_float,
                              fill_value=np.NaN)
        self.prod_q = np.full(shape=self.n_gen,
                              dtype=dt_float,
                              fill_value=np.NaN)
        self.prod_v = np.full(shape=self.n_gen,
                              dtype=dt_float,
                              fill_value=np.NaN)
        # loads information
        self.load_p = np.full(shape=self.n_load,
                              dtype=dt_float,
                              fill_value=np.NaN)
        self.load_q = np.full(shape=self.n_load,
                              dtype=dt_float,
                              fill_value=np.NaN)
        self.load_v = np.full(shape=self.n_load,
                              dtype=dt_float,
                              fill_value=np.NaN)
        # lines origin information
        self.p_or = np.full(shape=self.n_line,
                            dtype=dt_float,
                            fill_value=np.NaN)
        self.q_or = np.full(shape=self.n_line,
                            dtype=dt_float,
                            fill_value=np.NaN)
        self.v_or = np.full(shape=self.n_line,
                            dtype=dt_float,
                            fill_value=np.NaN)
        self.a_or = np.full(shape=self.n_line,
                            dtype=dt_float,
                            fill_value=np.NaN)
        # lines extremity information
        self.p_ex = np.full(shape=self.n_line,
                            dtype=dt_float,
                            fill_value=np.NaN)
        self.q_ex = np.full(shape=self.n_line,
                            dtype=dt_float,
                            fill_value=np.NaN)
        self.v_ex = np.full(shape=self.n_line,
                            dtype=dt_float,
                            fill_value=np.NaN)
        self.a_ex = np.full(shape=self.n_line,
                            dtype=dt_float,
                            fill_value=np.NaN)
        # lines relative flows
        self.rho = np.full(shape=self.n_line,
                           dtype=dt_float,
                           fill_value=np.NaN)

        # cool down and reconnection time after hard overflow, soft overflow or cascading failure
        self.time_before_cooldown_line = np.full(shape=self.n_line,
                                                 dtype=dt_int,
                                                 fill_value=-1)
        self.time_before_cooldown_sub = np.full(shape=self.n_sub,
                                                dtype=dt_int,
                                                fill_value=-1)
        self.time_next_maintenance = np.full(shape=self.n_line,
                                             dtype=dt_int,
                                             fill_value=-1)
        self.duration_next_maintenance = np.full(shape=self.n_line,
                                                 dtype=dt_int,
                                                 fill_value=-1)

        # calendar data
        self.year = dt_int(1970)
        self.month = dt_int(0)
        self.day = dt_int(0)
        self.hour_of_day = dt_int(0)
        self.minute_of_hour = dt_int(0)
        self.day_of_week = dt_int(0)

        # forecasts
        self._forecasted_inj = []
        self._forecasted_grid = []
        self._obs_env = obs_env

        # redispatching
        self.target_dispatch = np.full(shape=self.n_gen,
                                       dtype=dt_float,
                                       fill_value=np.NaN)
        self.actual_dispatch = np.full(shape=self.n_gen,
                                       dtype=dt_float,
                                       fill_value=np.NaN)

        # value to assess if two observations are equal
        self._tol_equal = 5e-1

        self.attr_list_vect = None
Ejemplo n.º 8
0
    def __init__(self,
                 parameters,
                 thermal_limit_a=None,
                 epsilon_poly=1e-2,
                 tol_poly=1e-6,
                 other_rewards={}):
        GridObjects.__init__(self)

        # specific to power system
        if not isinstance(parameters, Parameters):
            raise Grid2OpException(
                "Parameter \"parameters\" used to build the Environment should derived form the "
                "grid2op.Parameters class, type provided is \"{}\"".format(
                    type(parameters)))
        self.parameters = parameters

        # some timers
        self._time_apply_act = 0
        self._time_powerflow = 0
        self._time_extract_obs = 0
        self._time_opponent = 0

        # data relative to interpolation
        self._epsilon_poly = epsilon_poly
        self._tol_poly = tol_poly

        # define logger
        self.logger = None

        # and calendar data
        self.time_stamp = None
        self.nb_time_step = 0

        # observation
        self.current_obs = None

        # type of power flow to play
        # if True, then it will not disconnect lines above their thermal limits
        self.no_overflow_disconnection = self.parameters.NO_OVERFLOW_DISCONNECTION
        self.timestep_overflow = None
        self.nb_timestep_overflow_allowed = None

        # store actions "cooldown"
        self.times_before_line_status_actionable = None
        self.max_timestep_line_status_deactivated = self.parameters.NB_TIMESTEP_LINE_STATUS_REMODIF

        self.times_before_topology_actionable = None
        self.max_timestep_topology_deactivated = self.parameters.NB_TIMESTEP_TOPOLOGY_REMODIF

        # for maintenance operation
        self.time_next_maintenance = None
        self.duration_next_maintenance = None

        # hazard (not used outside of this class, information is given in `time_remaining_before_line_reconnection`
        self._hazard_duration = None

        # hard overflow part
        self.hard_overflow_threshold = self.parameters.HARD_OVERFLOW_THRESHOLD
        self.time_remaining_before_line_reconnection = None
        self.env_dc = self.parameters.ENV_DC

        # redispatching data
        self.target_dispatch = None
        self.actual_dispatch = None
        self.gen_uptime = None
        self.gen_downtime = None
        self.gen_activeprod_t = None

        self._thermal_limit_a = thermal_limit_a

        # maintenance / hazards
        self.time_next_maintenance = None
        self.duration_next_maintenance = None
        self.time_remaining_before_reconnection = None

        # store environment modifications
        self._injection = None
        self._maintenance = None
        self._hazards = None
        self.env_modification = None

        # to use the data
        self.done = False
        self.current_reward = None
        self.helper_action_env = None
        self.chronics_handler = None
        self.game_rules = None
        self.helper_action_player = None

        self.rewardClass = None
        self.actionClass = None
        self.observationClass = None
        self.legalActClass = None
        self.helper_observation = None
        self.names_chronics_to_backend = None
        self.reward_helper = None
        self.reward_range = None, None

        # other rewards
        self.other_rewards = {}
        for k, v in other_rewards.items():
            if not issubclass(v, BaseReward):
                raise Grid2OpException(
                    "All keys of \"rewards\" key word argument should be classes that inherit from "
                    "\"grid2op.BaseReward\"")
            self.other_rewards[k] = RewardHelper(v)

        # opponent
        self.opponent_action_class = DontAct  # class of the action of the opponent
        self.opponent_class = BaseOpponent  # class of the opponent
        self.opponent_init_budget = 0

        ## below initialized by _create_env, above: need to be called
        self.opponent_action_space = None  # ActionSpace(gridobj=)
        self.compute_opp_budg = None  # UnlimitedBudget(self.opponent_act_space)
        self.opponent = None  # OpponentSpace()
        self.oppSpace = None

        # voltage
        self.voltage_controler = None

        # backend
        self.init_grid_path = None

        # specific to Basic Env, do not change
        self.backend = None
        self.__is_init = False
Ejemplo n.º 9
0
    def __init__(self,
                 observation_space,
                 substation_layout=None,
                 radius_sub=20.,
                 load_prod_dist=70.,
                 bus_radius=6.):

        if substation_layout is None:
            if observation_space.grid_layout is None:
                # if no layout is provided, and observation_space has no layout, then it fails
                raise PlotError(
                    "Impossible to use plotting abilities without specifying a layout (coordinates) "
                    "of the substations.")

            # if no layout is provided, use the one in the observation_space
            substation_layout = []
            for el in observation_space.name_sub:
                substation_layout.append(observation_space.grid_layout[el])

        if len(substation_layout) != observation_space.n_sub:
            raise PlotError(
                "You provided a layout with {} elements while there are {} substations on the powergrid. "
                "Your layout is invalid".format(len(substation_layout),
                                                observation_space.n_sub))
        GridObjects.__init__(self)
        self.init_grid(observation_space)

        self.observation_space = observation_space
        self._layout = {}
        self._layout["substations"] = self._get_sub_layout(substation_layout)

        self.radius_sub = radius_sub
        self.load_prod_dist = load_prod_dist  # distance between load and generator to the center of the substation
        self.bus_radius = bus_radius

        self.subs_elements = [None for _ in self.observation_space.sub_info]

        # get the element in each substation
        for sub_id in range(self.observation_space.sub_info.shape[0]):
            this_sub = {}
            objs = self.observation_space.get_obj_connect_to(
                substation_id=sub_id)

            for c_id in objs["loads_id"]:
                c_nm = self._get_load_name(sub_id, c_id)
                this_load = {}
                this_load["type"] = "load"
                this_load["sub_pos"] = self.observation_space.load_to_sub_pos[
                    c_id]
                this_sub[c_nm] = this_load

            for g_id in objs["generators_id"]:
                g_nm = self._get_gen_name(sub_id, g_id)
                this_gen = {}
                this_gen["type"] = "gen"
                this_gen["sub_pos"] = self.observation_space.gen_to_sub_pos[
                    g_id]
                this_sub[g_nm] = this_gen

            for lor_id in objs["lines_or_id"]:
                ext_id = self.observation_space.line_ex_to_subid[lor_id]
                l_nm = self._get_line_name(sub_id, ext_id, lor_id)
                this_line = {}
                this_line["type"] = "line"
                this_line[
                    "sub_pos"] = self.observation_space.line_or_to_sub_pos[
                        lor_id]
                this_sub[l_nm] = this_line

            for lex_id in objs["lines_ex_id"]:
                or_id = self.observation_space.line_or_to_subid[lex_id]
                l_nm = self._get_line_name(or_id, sub_id, lex_id)
                this_line = {}
                this_line["type"] = "line"
                this_line[
                    "sub_pos"] = self.observation_space.line_ex_to_sub_pos[
                        lex_id]
                this_sub[l_nm] = this_line
            self.subs_elements[sub_id] = this_sub
        self._compute_layout()
Ejemplo n.º 10
0
    def __init__(self,
                 obs_env=None,
                 action_helper=None,
                 seed=None):
        GridObjects.__init__(self)

        self.action_helper = action_helper

        # time stamp information
        self.year = 1970
        self.month = 0
        self.day = 0
        self.hour_of_day = 0
        self.minute_of_hour = 0
        self.day_of_week = 0

        # for non deterministic observation that would not use default np.random module
        self.seed = None

        # handles the forecasts here
        self._forecasted_grid_act = {}
        self._forecasted_inj = []
        self._obs_env = obs_env

        self.timestep_overflow = np.zeros(shape=(self.n_line,), dtype=dt_int)

        # 0. (line is disconnected) / 1. (line is connected)
        self.line_status = np.ones(shape=self.n_line, dtype=dt_bool)

        # topological vector
        self.topo_vect = np.zeros(shape=self.dim_topo, dtype=dt_int)

        # generators information
        self.prod_p = np.full(shape=self.n_gen, dtype=dt_float, fill_value=np.NaN)
        self.prod_q = 1.0 * self.prod_p
        self.prod_v = 1.0 * self.prod_p
        # loads information
        self.load_p = np.full(shape=self.n_load, dtype=dt_float, fill_value=np.NaN)
        self.load_q = 1.0 * self.load_p
        self.load_v = 1.0 * self.load_p
        # lines origin information
        self.p_or = np.full(shape=self.n_line, dtype=dt_float, fill_value=np.NaN)
        self.q_or = 1.0 * self.p_or
        self.v_or = 1.0 * self.p_or
        self.a_or = 1.0 * self.p_or
        # lines extremity information
        self.p_ex = 1.0 * self.p_or
        self.q_ex = 1.0 * self.p_or
        self.v_ex = 1.0 * self.p_or
        self.a_ex = 1.0 * self.p_or
        # lines relative flows
        self.rho = 1.0 * self.p_or

        # cool down and reconnection time after hard overflow, soft overflow or cascading failure
        self.time_before_cooldown_line = np.full(shape=self.n_line, dtype=dt_int, fill_value=-1)
        self.time_before_cooldown_sub = np.full(shape=self.n_sub, dtype=dt_int, fill_value=-1)
        self.time_next_maintenance = 1 * self.time_before_cooldown_line
        self.duration_next_maintenance = 1 * self.time_before_cooldown_line

        # calendar data
        self.year = dt_int(1970)
        self.month = dt_int(0)
        self.day = dt_int(0)
        self.hour_of_day = dt_int(0)
        self.minute_of_hour = dt_int(0)
        self.day_of_week = dt_int(0)

        # redispatching
        self.target_dispatch = 1.0 * self.prod_p
        self.actual_dispatch = 1.0 * self.prod_p

        # to save some computation time
        self._connectivity_matrix_ = None
        self._bus_connectivity_matrix_ = None
        self._dictionnarized = None

        # for shunt (these are not stored!)
        if self.shunts_data_available:
            self._shunt_p = np.full(shape=self.n_shunt, dtype=dt_float, fill_value=np.NaN)
            self._shunt_q = 1.0 * self._shunt_p
            self._shunt_v = 1.0 * self._shunt_p
            self._shunt_bus = np.full(shape=self.n_shunt, dtype=dt_int, fill_value=1)
Ejemplo n.º 11
0
    def __init__(self, gridobj, obs_env=None, action_helper=None, seed=None):
        GridObjects.__init__(self)
        self.init_grid(gridobj)

        self.action_helper = action_helper

        # time stamp information
        self.year = 1970
        self.month = 0
        self.day = 0
        self.hour_of_day = 0
        self.minute_of_hour = 0
        self.day_of_week = 0

        # for non deterministic observation that would not use default np.random module
        self.seed = None

        # handles the forecasts here
        self._forecasted_grid = []
        self._forecasted_inj = []

        self._obs_env = obs_env

        self.timestep_overflow = None

        # 0. (line is disconnected) / 1. (line is connected)
        self.line_status = None

        # topological vector
        self.topo_vect = None

        # generators information
        self.prod_p = None
        self.prod_q = None
        self.prod_v = None
        # loads information
        self.load_p = None
        self.load_q = None
        self.load_v = None
        # lines origin information
        self.p_or = None
        self.q_or = None
        self.v_or = None
        self.a_or = None
        # lines extremity information
        self.p_ex = None
        self.q_ex = None
        self.v_ex = None
        self.a_ex = None
        # lines relative flows
        self.rho = None

        # cool down and reconnection time after hard overflow, soft overflow or cascading failure
        self.time_before_cooldown_line = None
        self.time_before_cooldown_sub = None
        self.time_before_line_reconnectable = None
        self.time_next_maintenance = None
        self.duration_next_maintenance = None

        # matrices
        self.connectivity_matrix_ = None
        self.bus_connectivity_matrix_ = None
        self.vectorized = None

        # redispatching
        self.target_dispatch = None
        self.actual_dispatch = None

        # value to assess if two observations are equal
        self._tol_equal = 5e-1

        self.attr_list_vect = None
        self.reset()
Ejemplo n.º 12
0
    def __init__(
            self,
            envs_dir,
            experimental_read_from_local_dir=False,
            _add_to_name="",  # internal, for test only, do not use !
            _compat_glop_version=None,  # internal, for test only, do not use !
            _test=False,
            **kwargs):
        GridObjects.__init__(self)
        RandomObject.__init__(self)
        self.current_env = None
        self.env_index = None
        self.mix_envs = []
        self._env_dir = os.path.abspath(envs_dir)

        # Special case handling for backend
        # TODO: with backend.copy() instead !
        backendClass = None
        if "backend" in kwargs:
            backendClass = type(kwargs["backend"])
            del kwargs["backend"]

        # Inline import to prevent cyclical import
        from grid2op.MakeEnv.Make import make

        # TODO reuse same observation_space and action_space in all the envs maybe ?
        try:
            for env_dir in sorted(os.listdir(envs_dir)):
                env_path = os.path.join(envs_dir, env_dir)
                if not os.path.isdir(env_path):
                    continue
                # Special case for backend
                if backendClass is not None:
                    env = make(env_path,
                               backend=backendClass(),
                               _add_to_name=_add_to_name,
                               _compat_glop_version=_compat_glop_version,
                               test=_test,
                               experimental_read_from_local_dir=
                               experimental_read_from_local_dir,
                               **kwargs)
                else:
                    env = make(env_path,
                               _add_to_name=_add_to_name,
                               _compat_glop_version=_compat_glop_version,
                               test=_test,
                               experimental_read_from_local_dir=
                               experimental_read_from_local_dir,
                               **kwargs)
                self.mix_envs.append(env)
        except Exception as exc_:
            err_msg = "MultiMix environment creation failed: {}".format(exc_)
            raise EnvError(err_msg)

        if len(self.mix_envs) == 0:
            err_msg = "MultiMix envs_dir did not contain any valid env"
            raise EnvError(err_msg)

        self.env_index = 0
        self.current_env = self.mix_envs[self.env_index]
        # Make sure GridObject class attributes are set from first env
        # Should be fine since the grid is the same for all envs
        multi_env_name = os.path.basename(
            os.path.abspath(envs_dir)) + _add_to_name
        save_env_name = self.current_env.env_name
        self.current_env.env_name = multi_env_name
        self.__class__ = self.init_grid(self.current_env)
        self.current_env.env_name = save_env_name