Source code for smartgrid.make_env

"""
Functions that can be used to create a "basic" (or standard) environment.
"""


from typing import List

from smartgrid.environment import SmartGrid
from smartgrid.world import World
from smartgrid.agents import DataOpenEIConversion, Agent, comfort
from smartgrid.util import RandomEnergyGenerator
from smartgrid.observation import ObservationManager
from smartgrid.rewards import Reward
from smartgrid.rewards.numeric.differentiated import AdaptabilityThree
from smartgrid.wrappers import SingleRewardAggregator

import os


[docs] def find_profile_data(dataset: str, filename: str) -> str: """ Finds a data file from the data folder. The ``data`` folder can be either: - accessible through a relative path, e.g., because the source code was cloned (``./data/path/to/the/desired/file``). - accessible through imports, e.g., because the package was installed. How to access files in this folder depends on the actual case; this function (hopefully) solves this problem, by checking first whether the files are directly accessible (through relative paths). If they are not, :py:mod:`importlib.resources` is used to get a path to the file through the package. :param dataset: The name of the folder containing the desired file, within the ``data`` folder. For example, ``openei`` to access the OpenEI dataset. This dataset cannot be nested, e.g., ``dataset/subdataset`` or ``dataset.subdataset`` will not work. :param filename: The name of the desired file, within the ``dataset`` folder. :return: A path to the desired file. """ # Equivalent to `./data/dataset/filename`, but OS-agnostic. relative_path = os.path.join('data', dataset, filename) if os.path.isfile(relative_path): # Easy mode: the file is directly accessible through a relative path! return relative_path else: # Hard mode: need to access it through the package (importlib). # Also, importlib returns a context, so we need to get the path # and exit the context when Python terminates. from contextlib import ExitStack import atexit # Depending on the Python version, there are two ways to use importlib. try: # Python 3.9+ from importlib.resources import files, as_file data = files('smartgrid.data').joinpath(dataset, filename) ctx = as_file(data) except ImportError: # Python 3.7 and 3.8 from importlib.resources import path ctx = path(f'smartgrid.data.{dataset}', filename) # Handle the context file_manager = ExitStack() # Close the context when Python terminates atexit.register(file_manager.close) data_file_path = file_manager.enter_context(ctx) # Convert the PosixPath to a simple str for easier usage. return str(data_file_path)
[docs] def make_basic_smartgrid( rewards: List[Reward] = None, max_step: int = 10_000, ) -> SmartGrid: """ Defines a "basic" scenario, a helper method to instantiate a SmartGrid env. This method limits the available parameters, and hence, the possible customization. It is used to simplify the creation of an environment. This basic environment is configured with: * 20 agents with the *Household* profile, 5 agents with the *Office* profile, and 1 agent with the *School* profile. * A :py:class:`smartgrid.util.RandomEnergyGenerator` which provides each time step between 80% and 120% of the agents' total energy need. * The :py:class:`smartgrid.rewards.numeric.differentiated.AdaptabilityThree` reward function, whose definition changes at t=2000 and t=6000 (to force agents to adapt). * The default :py:class:`smartgrid.observation.ObservationManager` to determine observations from the current state of the environment. Users that desire full control over the environment creation, e.g., to experiment with various scenarii, should instead manually create the environment "from scratch", as explained in the documentation. They may take inspiration from this method's content to do so. :param rewards: The list of reward functions to use (see the :py:mod:`smartgrid.rewards` package for a list of available reward functions. Traditionally, most users will want to use a single reward function (*single-objective* reinforcement learning), but this environment supports *multi-objective* reinforcement learning if desired. By default, the :py:class:`.AdaptabilityThree` reward function is used. :param max_step: The maximum number of steps to simulate in the environment. By default, a maximum number of ``10_000`` steps are allowed; however, the environment can still be used after this amount, but it will raise a warning. This is mainly used to control the *interaction loop* automatically through the *terminated* and *truncated* values. :return: An instance of a :py:class:`.SmartGrid` env. This instance must be, as per the PettingZoo framework, ``reset()`` before it can be used. The instance is wrapped in a :py:class:`.RewardAggregator` in order to produce single-objective rewards. To directly access the underlying env, use the :py:attr:`unwrapped` property. """ # 1. Load the data (Agents' Profiles) converter = DataOpenEIConversion() converter.load('Household', find_profile_data('openei', 'profile_residential_annually.npz'), comfort.flexible_comfort_profile) converter.load('Office', find_profile_data('openei', 'profile_office_annually.npz'), comfort.neutral_comfort_profile) converter.load('School', find_profile_data('openei', 'profile_school_annually.npz'), comfort.strict_comfort_profile) # 2. Create Agents agents = [] for i in range(20): agents.append( Agent(f'Household{i+1}', converter.profiles['Household']) ) for i in range(5): agents.append( Agent(f'Office{i+1}', converter.profiles['Office']) ) agents.append( Agent(f'School1', converter.profiles['School']) ) # 3. Create the World generator = RandomEnergyGenerator() world = World(agents, generator) # 4. Choose the reward function(s) to use if rewards is None: rewards = [AdaptabilityThree()] # 5. Create the Env (Smart Grid simulator) simulator = SmartGrid( world, rewards, max_step, ObservationManager() ) # 6. Wrap the Env to receive a single (scalar) reward instead of a dict. simulator = SingleRewardAggregator(simulator) return simulator