From 7bd3043f93311c65394d5160040fede9f9d1393a Mon Sep 17 00:00:00 2001 From: Alejandro Campoy Nieves Date: Thu, 25 Aug 2022 12:49:52 +0200 Subject: [PATCH] v2.0.0 - Sinergym documentation (#240) * Updated documentation: introduction with new functionalities and structure * Updated and Added new documentation for environents chaper mainly * Documentation update * Adapted docs source * introduction and installation section update * Adapted new action definition parameter to documentation * Review of documentation (introduction, installation and environments) * Rest of the documentation review and DockerHub URL's fixed * Enhanced basic examples documentation and fixed action definition title indexation * Update notebooks and version to 2.0.0 * Repeated documentation label fixed * Fixed some documentation bugs * isort fix in config.py --- .devcontainer/Dockerfile | 2 +- .devcontainer/Dockerfile_lite | 2 +- README.md | 116 +++-- docs/source/_static/weather_variability.png | Bin 0 -> 160203 bytes docs/source/index.rst | 23 +- docs/source/pages/controllers.rst | 15 +- .../pages/deep-reinforcement-learning.rst | 248 +++++------ docs/source/pages/environments.rst | 327 ++++++++++++-- docs/source/pages/extra-configuration.rst | 61 +-- docs/source/pages/gcloudAPI.rst | 416 +++++++++++++----- docs/source/pages/github-actions.rst | 88 +++- docs/source/pages/installation.rst | 80 ++-- docs/source/pages/introduction.rst | 91 ++-- .../pages/modules/sinergym.utils.common.rst | 3 +- .../modules/sinergym.utils.common.to_idf.rst | 6 + .../modules/sinergym.utils.config.Config.rst | 2 + docs/source/pages/output.rst | 76 +++- docs/source/pages/rewards.rst | 95 +++- docs/source/pages/tests.rst | 79 +++- docs/source/pages/usage-example.rst | 240 +++++++--- docs/source/pages/wrappers.rst | 11 +- examples/MLflow_example.ipynb | 97 ++-- examples/TensorBoard_example.ipynb | 93 ++-- examples/basic_example.ipynb | 49 ++- examples/change_environment.ipynb | 320 +++++++++++--- examples/drl.ipynb | 205 ++++----- examples/personalize_loggerwrapper.ipynb | 61 +-- examples/rule_controller_example.ipynb | 81 ++-- examples/wrappers_examples.ipynb | 289 +++++------- images/weather_variability.png | Bin 0 -> 160203 bytes sinergym/utils/config.py | 3 +- sinergym/version.txt | 2 +- 32 files changed, 2080 insertions(+), 1101 deletions(-) create mode 100644 docs/source/_static/weather_variability.png create mode 100644 docs/source/pages/modules/sinergym.utils.common.to_idf.rst create mode 100644 images/weather_variability.png diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index a398a2fbc0..924a35b76b 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,5 +1,5 @@ # Use the image created with ../Dockerfile and stored in DockerHub -FROM alejandrocn7/sinergym:latest +FROM sailugr/sinergym:latest CMD ["/bin/bash"] \ No newline at end of file diff --git a/.devcontainer/Dockerfile_lite b/.devcontainer/Dockerfile_lite index 54c114dcad..d6e7a4b4f2 100644 --- a/.devcontainer/Dockerfile_lite +++ b/.devcontainer/Dockerfile_lite @@ -1,5 +1,5 @@ # Use the image created with ../Dockerfile and stored in DockerHub -FROM alejandrocn7/sinergym:latest-lite +FROM sailugr/sinergym:latest-lite CMD ["/bin/bash"] \ No newline at end of file diff --git a/README.md b/README.md index 0d54bedfb0..6be4a03535 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,87 @@ -# sinergym +# Sinergym


-**Welcome to sinergym!** +**Welcome to Sinergym!** This is a project based on Zhiang Zhang and Khee Poh Lam [Gym-Eplus](https://github.com/zhangzhizza/Gym-Eplus). The goal of this project is to create an environment following OpenAI Gym interface for wrapping simulation engines for building control using **deep reinforcement learning**. -The main functionalities of Sinergym are the following : - - - **Benchmark environments**. Similarly to Atari or Mujoco environments for RL community, we are designing a set of environments for benchmarking and testing deep RL algorithms. These environments may include different buildings, weathers or action/observation spaces. - - **Develop different experimental settings**. We aim to provide a package that allows to modify experimental settings in an easy manner. For example, several reward functions or observation variables may be defined. - - **Include different simulation engines**. Communication between Python and [EnergyPlus](https://energyplus.net/) is established using [BCVTB](https://simulationresearch.lbl.gov/bcvtb/FrontPage). Since this tool allows for interacting with several simulation engines, more of them (e.g. [OpenModelica](https://openmodelica.org/)) could be included in the backend while maintaining the Gym API. - - **Building Models configuration automatically**: Building models will be - adapted to specification of each simulation. For example, *Designdays* and - *Location* from IDF files will be adapted to weather file specified in - Sinergym simulator backend without any intervention by the user. - - **Extra configuration facilities**: Our team aim to provide extra parameters - in order to amplify the context space for the experiments with this tool. - Sinergym will modify building model automatically based on parameters set. - For example: People occupant, timesteps per simulation hour, observation - and action spaces, etc. - - **Stable Baseline 3 Integration**. Some functionalities like callbacks - have been developed by our team in order to test easily these environments - with deep reinforcement learning algorithms. - - **Google Cloud Integration**. Whether you have a Google Cloud account and you want to - use your infrastructure with Sinergym, we tell you some details about how doing it. - - **Mlflow tracking server**. [Mlflow](https://mlflow.org/) is an open source platform for the machine +The main functionalities of *Sinergym* are the following : + + - **Include different simulation engines**. Communication between + Python and [EnergyPlus](https://energyplus.net/) is established + using [BCVTB](https://simulationresearch.lbl.gov/bcvtb/FrontPage) middleware. + Since this tool allows for interacting with several simulation + engines, more of them (e.g. + [OpenModelica](https://openmodelica.org/)) could be included in + the backend while maintaining the Gym API. + +- **Benchmark environments**. Similarly to *Atari* or *Mujoco* environments + for RL community, we are designing a set of environments for + benchmarking and testing deep RL algorithms. These environments may + include different buildings, weathers, action/observation spaces, function rewards, etc. + +- **Customizable environments**. We aim to provide a + package that allows to modify experimental settings in an easy + manner. The user can create his own environments defining his own + building model, weather, reward, observation/action space and variables, environment name, etc. + The user can also use these pre-configured environments available in *Sinergym* + and change some aspect of it (for example, the weather) in such + a way that he does not have to make an entire definition of the + environment and can start from one pre-designed by us. + Some parameters directly associated with the simulator can be set as **extra configuration** + as well, such as people occupant, time-steps per simulation hour, run-period, etc. + +- **Customizable components**: *Sinergym* is easily scalable by third parties. + Following the structure of the implemented classes, new custom components + can be created for new environments such as function rewards, wrappers, + controllers, etc. + +- **Automatic Building Model adaptation to user changes**: Building models (*IDF*) will be + adapted to specification of each simulation by the user. For example, ``Designdays`` and + ``Location`` components from *IDF* files will be adapted to weather file (*EPW*) specified in + *Sinergym* simulator backend without any intervention by the user (only the environment definition). + *BCVTB middleware* external interface in *IDF* model and *variables.cfg* file is generated when + simulation starts by *Sinergym*, this definition depends on action and observation space and variables defined. + In short, *Sinergym* automates the whole process of model adaptation so that the user + only has to define what he wants for his environment. + +- **Automatic external interface integration for actions**. As far as building model (*IDF*) adaptation + is concerned, it is not enough to set up an external interface and set user-specified + variable names. It is also necessary to make certain adjustments to the building components to be + controlled, so that they use the external variables defined by the user instead of the default + controllers implicitly provided by the building model. To do this, *Sinergym* provides a functionality + that can adapt actuators to the desired building zones by providing a specification by the user. + The building model will be manipulated based on this information automatically. In other words, + if the components to be controlled are directly supported by *Sinergym*, the building model can be modified + accordingly to be controlled, otherwise the user will have to modify the *IDF* file manually. More actuator + types will be directly supported by *Sinergym* in the future. + +- **Stable Baseline 3 Integration**. Some functionalities like callbacks + have been customized by our team in order to test easily these environments + with deep reinforcement learning algorithms. + This tool can be used with any other DRL library that supports the *OpenAI gym* interface as well. + +- **Google Cloud Integration**. Whether you have a Google Cloud account and you want to + use your infrastructure with *Sinergym*, we tell you some details about how doing it. + +- **Mlflow tracking server**. [Mlflow](https://mlflow.org/) is an open source platform for the machine learning lifecycle. This can be used with Google Cloud remote server (if you have Google Cloud account) or using local store. This will help you to manage and store your runs and artifacts generated in an orderly manner. - - **Data Visualization**. Using Sinergym logger or Tensorboard server to visualize training information + +- **Data Visualization**. Using *Sinergym* logger or Tensorboard server to visualize training and evaluation information in real-time. - - Many more! + +- **Notebooks examples**. *Sinergym* develops code in notebook format with the purpose of offering use cases to + the users in order to help them become familiar with the tool. They are constantly updated, along with the updates + and improvements of the tool itself. + +- Many more! _This is a work in progress project. Stay tuned for upcoming releases._ @@ -45,7 +91,7 @@ _This is a work in progress project. Stay tuned for upcoming releases._ ## List of available environments -If you would like to see a complete and updated list of our available environments, please visit [our list](https://ugr-sail.github.io/sinergym/compilation/html/pages/environments.html) in the official Sinergym documentation. +If you would like to see a complete and updated list of our available environments, please visit [our list](https://ugr-sail.github.io/sinergym/compilation/html/pages/environments.html) in the official *Sinergym* documentation. ## Installation @@ -74,7 +120,7 @@ On the other hand, if you don't want any extra library, it's necessary to write $ docker build -t example1/sinergym:latest --build-arg SINERGYM_EXTRAS= . ``` -:pencil: You can install directly our container from `Docker Hub repository `__, all releases of this project are there. +:pencil: You can install directly our container from `Docker Hub repository `__, all releases of this project are there. :pencil: If you use [Visual Studio Code](https://code.visualstudio.com/), by simply opening the root directory and clicking on the pop-up button *Reopen in container*, all the dependencies will be installed automatically and you will be able to run *Sinergym* in an isolated environment. For more information about how to use this functionality, check [VSCode Containers extension documentation](https://code.visualstudio.com/docs/remote/containers). @@ -108,12 +154,12 @@ To install *Sinergym* manually instead of through the container (recommended), f $ conda activate sinergym ``` -- Now, we have a correct python version with required modules to run sinergym. Let's continue with the rest of the programs that are needed outside of Python to run the simulations: +- Now, we have a correct python version with required modules to run *Sinergym*. Let's continue with the rest of the programs that are needed outside of Python to run the simulations: #### 2. Install EnergyPlus 9.5.0 Install EnergyPlus. Currently it has been update compatibility to 9.5.0 and it has -been tested, but code may also work with other versions. Sinergym ensure this support: +been tested, but code may also work with other versions. *Sinergym* ensure this support: | Sinergym Version | EnergyPlus version | | :--------------: | :----------------: | @@ -160,7 +206,7 @@ It's possible to select a subset of these libraries instead of 'extras' tag in w $ pip install -e .[test,doc] ``` -In order to check all our tag list, visit `setup.py `__ in Sinergym root repository. In any case, they are not a requirement of the package. +In order to check all our tag list, visit `setup.py `__ in *Sinergym* root repository. In any case, they are not a requirement of the package. You can also install from `oficial pypi repository `__ with last stable version by default: @@ -170,18 +216,18 @@ You can also install from `oficial pypi repository `__ will do that job (see our documentation for more information). +Anyway, every time *Sinergym* repository is updated, the tests will run automatically in a remote container using the Dockerfile to build it. `Github Action `__ will do that job (see our documentation for more information). ## Usage example -If you used our Dockerfile during installation, you should have the *try_env.py* file in your workspace as soon as you enter in. In case you have installed everything on your local machine directly, place it inside our cloned repository. In any case, we start from the point that you have at your disposal a terminal with the appropriate python version and Sinergym running correctly. +If you used our Dockerfile during installation, you should have the *try_env.py* file in your workspace as soon as you enter in. In case you have installed everything on your local machine directly, place it inside our cloned repository. In any case, we start from the point that you have at your disposal a terminal with the appropriate python version and *Sinergym* running correctly. -Sinergym uses the standard OpenAI gym API. So basic loop should be something like: +*Sinergym* uses the standard OpenAI gym API. So basic loop should be something like: ```python @@ -213,10 +259,10 @@ For more information about this functionality, please, visit our documentation [ ## Citing Sinergym -If you use Sinergym in your work, please cite our [paper](https://dl.acm.org/doi/abs/10.1145/3486611.3488729): +If you use *Sinergym* in your work, please cite our [paper](https://dl.acm.org/doi/abs/10.1145/3486611.3488729): ```bibtex -@inproceedings{jimenez2021sinergym, +@inproceedings{2021sinergym, title={Sinergym: A Building Simulation and Control Framework for Training Reinforcement Learning Agents}, author={Jiménez-Raboso, Javier and Campoy-Nieves, Alejandro and Manjavacas-Lucas, Antonio and Gómez-Romero, Juan and Molina-Solana, Miguel}, year={2021}, diff --git a/docs/source/_static/weather_variability.png b/docs/source/_static/weather_variability.png new file mode 100644 index 0000000000000000000000000000000000000000..6aa019b6731ad82c5c1c22c21a72bb5a801f4414 GIT binary patch literal 160203 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%0Dtf%DrnHPq2z&elL5pLq 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 b8W(eT^!+(PAx)#n`?xGG+M1P{x<&sBYzm*X literal 0 HcmV?d00001 diff --git a/docs/source/index.rst b/docs/source/index.rst index 8ff80051e2..d9eaf1da15 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -7,7 +7,8 @@ Welcome to **sinergym**! Contributing ############ -To any interested in making Sinergym better, there are still some improvements that need to be done. You can check `issues `__ in the repo. +For all those interested in improving Sinergym, there are always improvements to be made. +You can check `issues `__ in the repo. If you want to contribute, please read `CONTRIBUTING.md `__ first. @@ -17,6 +18,26 @@ Examples The examples can be run if you have your computer or container properly configured (see :ref:`Installation` section) from our notebooks hosted in the `examples `__ folder of the official Sinergym repository. +################ +Citing Sinergym +################ + +If you use Sinergym in your work, please cite our `paper `__:: + + @inproceedings{2021sinergym, + title={Sinergym: A Building Simulation and Control Framework for Training Reinforcement Learning Agents}, + author={Jiménez-Raboso, Javier and Campoy-Nieves, Alejandro and Manjavacas-Lucas, Antonio and Gómez-Romero, Juan and Molina-Solana, Miguel}, + year={2021}, + isbn = {9781450391146}, + publisher = {Association for Computing Machinery}, + address = {New York, NY, USA}, + url = {https://doi.org/10.1145/3486611.3488729}, + doi = {10.1145/3486611.3488729}, + booktitle = {Proceedings of the 8th ACM International Conference on Systems for Energy-Efficient Buildings, Cities, and Transportation}, + pages = {319–323}, + numpages = {5}, + } + .. toctree:: :maxdepth: 2 :hidden: diff --git a/docs/source/pages/controllers.rst b/docs/source/pages/controllers.rst index 2a7dd7fdf9..bc824a614a 100644 --- a/docs/source/pages/controllers.rst +++ b/docs/source/pages/controllers.rst @@ -2,13 +2,14 @@ Controllers ############ -Sinergym has a section to implement your own controllers. Currently, we have developed a **random agent** and a **rule-based agent** to 5Zone and Datacenter buildings. -You can find this code in `sinergym/sinergym/utils/controllers.py `__. +*Sinergym* has a section to implement your own **controllers**. Currently, we have developed +a **random agent** and a **rule-based agent** to *5Zone* and *Datacenter* buildings. +You can find this code in +`sinergym/sinergym/utils/controllers.py `__. it is very useful in order to perform benchmarks as a reference point to study DRL algorithms: -.. literalinclude:: ../../../sinergym/utils/controllers.py - :language: python - -The functionality is very simple; given an environment observation, these instances return an action to interact with the environment. You can develop your own -controllers or modify current rules, for example. You can see an example of usage in section :ref:`Using a rule-based controller`. +The functionality is very simple; given an environment observation, these instances return +an action to interact with the environment. You can develop your own +controllers or modify current rules, for example. You can see an example of usage in +section :ref:`Using a rule-based controller`. diff --git a/docs/source/pages/deep-reinforcement-learning.rst b/docs/source/pages/deep-reinforcement-learning.rst index bcdeb485a5..5b00596e8e 100644 --- a/docs/source/pages/deep-reinforcement-learning.rst +++ b/docs/source/pages/deep-reinforcement-learning.rst @@ -2,8 +2,9 @@ Deep Reinforcement Learning Integration ####################################### -Sinergym integrates some facilities in order to use Deep Reinforcement Learning algorithms provided by `Stable Baselines 3 `__. -Current algorithms checked by Sinergym are: +*Sinergym* integrates some facilities in order to use **Deep Reinforcement Learning algorithms** +provided by `Stable Baselines 3 `__. +Current algorithms checked by *Sinergym* are: +--------------------------------------------------------+ | Stable Baselines 3: | @@ -23,176 +24,154 @@ Current algorithms checked by Sinergym are: | TD3 | NO | YES | OffPolicyAlgorithm | +-----------+----------+------------+--------------------+ -``Type`` column has been specified due to its importance about *Stable Baselines callback* functionality. +``Type`` column has been specified due to its importance about +*Stable Baselines callback* functionality. **************** DRL Logger **************** -`Callbacks `__ are a set of functions that will -be called at given stages of the training procedure. You can use callbacks to access internal state of the RL model during training. +`Callbacks `__ +are a set of functions that will be called at given **stages of the training procedure**. +You can use callbacks to access internal state of the RL model **during training**. It allows one to do monitoring, auto saving, model manipulation, progress bars, ... -This structure allows to custom our own logger for DRL executions. Our objective is to **log all information about our custom environment** specifically. -Therefore, `sinergym/sinergym/utils/callbacks.py `__ has been created with this proposal. -Each algorithm has its own differences about how information is extracted which is why its implementation. ``LoggerCallback`` can deal with those subtleties. +This structure allows to custom our own logger for DRL executions. Our objective +is to **log all information about our custom environment** specifically. +Therefore, `sinergym/sinergym/utils/callbacks.py `__ +has been created with this proposal. Each algorithm has its own differences +about how information is extracted which is why its implementation. ``LoggerCallback`` +can deal with those subtleties. -.. literalinclude:: ../../../sinergym/utils/callbacks.py - :language: python - :pyobject: LoggerCallback +.. note:: You can specify if you want Sinergym logger (see :ref:`Logger`) to record + simulation interactions during training at the same time using + ``sinergym_logger`` attribute in constructor. -.. note:: You can specify if you want Sinergym logger (see :ref:`Logger`) to record simulation interactions during training at the same time using ``sinergym_logger`` attribute in constructor. - -This callback derives ``BaseCallback`` from Stable Baselines 3 while ``BaseCallBack`` uses `Tensorboard `__ on the background at the same time. -With Tensorboard, it's possible to visualize all DRL training in real time and compare between different executions. This is an example: +This callback derives ``BaseCallback`` from Stable Baselines 3 while ``BaseCallBack`` +uses `Tensorboard `__ on the +background at the same time. With *Tensorboard*, it's possible to visualize all DRL +training in real time and compare between different executions. This is an example: .. image:: /_static/tensorboard_example.png :width: 800 :alt: Tensorboard example :align: center -There are tables which are in some algorithms and not in others and vice versa. It is important the difference between ``OnPolicyAlgorithms`` and ``OffPolicyAlgorithms``: +There are tables which are in some algorithms and not in others and vice versa. +It is important the difference between ``OnPolicyAlgorithms`` and ``OffPolicyAlgorithms``: + +* **OnPolicyAlgorithms** can be recorded **each timestep**, we can set a ``log_interval`` in + learn process in order to specify the **step frequency log**. -* **OnPolicyAlgorithms** can be recorded each timestep, we can set a ``log_interval`` in learn process in order to specify the step frequency log. -* **OffPolicyAlgorithms** can be recorded each episode. Consequently, ``log_interval`` in learn process is used to specify the episode frequency log and not step frequency. - Some features like actions and observations are set up in each timestep. Thus, Off Policy Algorithms record a mean value of whole episode values instead of values steps by steps (see ``LoggerCallback`` class implementation). +* **OffPolicyAlgorithms** can be recorded **each episode**. Consequently, ``log_interval`` in + learn process is used to specify the **episode frequency log** and not step frequency. + Some features like actions and observations are set up in each timestep. + Thus, Off Policy Algorithms record a **mean value** of whole episode values instead + of values steps by steps (see ``LoggerCallback`` class implementation). ~~~~~~~~~~~~~~~~~~~~~~ Tensorboard structure ~~~~~~~~~~~~~~~~~~~~~~ -The main structure for Sinergym with Tensorboard is: +The main structure for *Sinergym* with *Tensorboard* is: + +* **action**: This section has action values during training. When algorithm + is On Policy, it will appear **action_simulation** too. This is because + algorithms in continuous environments has their own output and clipped + with gym action space. Then, this output is parse to simulation action + space (See :ref:`Observation/action spaces` note box). + +* **episode**: Here is stored all information about entire episodes. + It is equivalent to ``progress.csv`` in *Sinergym logger* + (see *Sinergym* :ref:`Output format` section): + + - *comfort_violation_time(%)*: Percentage of time in episode simulation + in which temperature has been out of bound comfort temperature ranges. + + - *cumulative_comfort_penalty*: Sum of comfort penalties (reward component) + during whole episode. -* **action**: This section has action values during training. When algorithm is On Policy, it will appear **action_simulation** too. This is because algorithms - in continuous environments has their own output and clipped with gym action space. Then, this output is parse to simulation action space (See :ref:`Observation/action spaces`). -* **episode**: Here is stored all information about entire episodes. It is equivalent to progress.csv in Sinergym logger (see Sinergym :ref:`Output format`): - - *comfort_violation_time(%)*: Percentage of time in episode simulation in which temperature has been out of bound comfort temperature ranges. - - *cumulative_comfort_penalty*: Sum of comfort penalties (reward component) during whole episode. - *cumulative_power*: Sum of power consumption during whole episode. - - *cumulative_power_penalty*: Sum of power penalties (reward component) during whole episode. + + - *cumulative_power_penalty*: Sum of power penalties (reward component) + during whole episode. + - *cumulative_reward*: Sum of reward during whole episode. + - *ep_length*: Timesteps executed in each episode. + - *mean_comfort_penalty*: Mean comfort penalty per step in episode. + - *mean_power*: Mean power consumption per step in episode. + - *mean_power_penalty*: Mean power penalty per step in episode. + - *mean_reward*: Mean reward obtained per step in episode. -* **observation**: Here is recorded all observation values during simulation. This values depends on the environment which is being simulated (see :ref:`Output format`). -* **normalized_observation** (optional): This section appear only when environment has been wrapped with normalization (see :ref:`Wrappers`). The model will train with this normalized values and they will be recorded both; original observation and normalized observation. -* **rollout**: Algorithm metrics in Stable Baselines by default. For example, DQN has *exploration_rate* and this value doesn't appear in other algorithms. + +* **observation**: Here is recorded all observation values during simulation. + This values depends on the environment which is being simulated + (see :ref:`Observation/action spaces` section). + +* **normalized_observation** (optional): This section appear only when environment + has been **wrapped with normalization** (see :ref:`Wrappers` section). The model + will train with this normalized values and they will be recorded both; + original observation and normalized observation. + +* **rollout**: Algorithm metrics in **Stable Baselines by default**. For example, + DQN has ``exploration_rate`` and this value doesn't appear in other algorithms. + * **time**: Monitoring time of execution. -* **train**: Record specific neural network information for each algorithm, provided by Stable baselines as well as rollout. -.. note:: Evaluation of models can be recorded too, adding ``EvalLoggerCallback`` to model learn method. +* **train**: Record specific neural network information for each algorithm, + provided by **Stable baselines** as well as rollout. + +.. note:: Evaluation of models can be recorded too, adding ``EvalLoggerCallback`` + to model learn method. ********** How use ********** -You can try your own experiments and benefit from this functionality. `sinergym/examples/DRL_usage.py `__ -is a example code to use it. You can use directly DRL_battery.py directly from your local computer specifying ``--tensorboard`` flag in execution. - -The most important information you must keep in mind when you try your own experiments are: - -* Model is constructed with a algorithm constructor. Each algorithm can use its particular parameters. -* If you wrapper environment with normalization, models will train with those normalized values. -* Callbacks can be concatenated in a ``CallbackList`` instance from Stable Baselines 3. -* Neural network will not train until you execute ``model.learn()`` method. Here is where you - specify train ``timesteps``, ``callbacks`` and ``log_interval`` as we commented in type algorithms (On and Off Policy). -* ``DRL_battery.py`` requires some extra arguments to being executed like ``-env`` and ``-ep``. -* You can execute **Curriculum Learning**, you only have to add ``--model`` field with a valid model path, this script will load the model and execute to train. - -Code example: - -.. code:: python - - import gym - import argparse - import mlflow - - from sinergym.utils.callbacks import LoggerCallback, LoggerEvalCallback - from sinergym.utils.wrappers import NormalizeObservation - - - from stable_baselines3.common.noise import NormalActionNoise, OrnsteinUhlenbeckActionNoise - from stable_baselines3 import A2C, DDPG, DQN, PPO, SAC - from stable_baselines3.common.callbacks import EvalCallback, BaseCallback, CallbackList - from stable_baselines3.common.vec_env import DummyVecEnv - - - parser = argparse.ArgumentParser() - parser.add_argument('--environment', '-env', type=str, default=None) - parser.add_argument('--episodes', '-ep', type=int, default=1) - parser.add_argument('--learning_rate', '-lr', type=float, default=.0007) - parser.add_argument('--n_steps', '-n', type=int, default=5) - parser.add_argument('--gamma', '-g', type=float, default=.99) - parser.add_argument('--gae_lambda', '-gl', type=float, default=1.0) - parser.add_argument('--ent_coef', '-ec', type=float, default=0) - parser.add_argument('--vf_coef', '-v', type=float, default=.5) - parser.add_argument('--max_grad_norm', '-m', type=float, default=.5) - parser.add_argument('--rms_prop_eps', '-rms', type=float, default=1e-05) - args = parser.parse_args() - - # experiment ID - environment = args.environment - n_episodes = args.episodes - name = 'A2C-' + environment + '-' + str(n_episodes) + '-episodes' - - with mlflow.start_run(run_name=name): - - mlflow.log_param('env', environment) - mlflow.log_param('episodes', n_episodes) - - mlflow.log_param('learning_rate', args.learning_rate) - mlflow.log_param('n_steps', args.n_steps) - mlflow.log_param('gamma', args.gamma) - mlflow.log_param('gae_lambda', args.gae_lambda) - mlflow.log_param('ent_coef', args.ent_coef) - mlflow.log_param('vf_coef', args.vf_coef) - mlflow.log_param('max_grad_norm', args.max_grad_norm) - mlflow.log_param('rms_prop_eps', args.rms_prop_eps) - - env = gym.make(environment) - env = NormalizeObservation(env) - - #### TRAINING #### - - # Build model - - model = A2C('MlpPolicy', env, verbose=1, - learning_rate=args.learning_rate, - n_steps=args.n_steps, - gamma=args.gamma, - gae_lambda=args.gae_lambda, - ent_coef=args.ent_coef, - vf_coef=args.vf_coef, - max_grad_norm=args.max_grad_norm, - rms_prop_eps=args.rms_prop_eps, - tensorboard_log='./tensorboard_log/') - - - n_timesteps_episode = env.simulator._eplus_one_epi_len / \ - env.simulator._eplus_run_stepsize - timesteps = n_episodes * n_timesteps_episode - - env = DummyVecEnv([lambda: env]) - - # Callbacks - freq = 2 # evaluate every N episodes - eval_callback = LoggerEvalCallback(env, best_model_save_path='./best_models/' + name + '/', - log_path='./best_models/' + name + '/', eval_freq=n_timesteps_episode * freq, - deterministic=True, render=False, n_eval_episodes=1) - log_callback = LoggerCallback(sinergym_logger=False) - callback = CallbackList([log_callback, eval_callback]) - - # Training - model.learn(total_timesteps=timesteps, callback=callback, log_interval=100) +You can try your own experiments and benefit from this functionality. +`sinergym/scripts/DRL_battery.py `__ +is a example code to use it. You can use ``DRL_battery.py`` directly from +your local computer specifying ``--tensorboard`` flag in execution. + +The most **important information** you must keep in mind when you try +your own experiments are: + +* Model is constructed with a algorithm constructor. + Each algorithm can use its **particular parameters**. + +* If you wrapper environment with normalization, models + will **train** with those **normalized** values. + +* Callbacks can be **concatenated** in a ``CallbackList`` + instance from Stable Baselines 3. + +* Neural network will not train until you execute + ``model.learn()`` method. Here is where you + specify train ``timesteps``, ``callbacks`` and ``log_interval`` + as we commented in type algorithms (On and Off Policy). + +* ``DRL_battery.py`` requires some **extra arguments** to being + executed like ``-env`` and ``-ep``. + +* You can execute **Curriculum Learning**, you only have to + add ``--model`` field with a valid model path, this script + will load the model and execute to train. **************** Mlflow **************** -As you have been able to see in usage examples, it is using `Mlflow `__ in order to tracking experiments and recorded them methodically. It is recommended to use it. -You can start a local server with information stored during the battery of experiments such as initial and ending date of execution, hyperparameters, duration, etc. +Our scripts to run DRL with *Sinergym* environments are using +`Mlflow `__ in order to **tracking experiments** +and recorded them methodically. It is recommended to use it. +You can start a local server with information stored during the +battery of experiments such as initial and ending date of execution, +hyperparameters, duration, etc. + Here is an example: .. image:: /_static/mlflow_example.png @@ -201,6 +180,9 @@ Here is an example: :align: center -.. note:: For information about how use *Tensorboard* and *Mlflow* with a Cloud Computing paradigm, see :ref:`Remote Tensorboard log` and :ref:`Mlflow tracking server set up` +.. note:: For information about how use *Tensorboard* and *Mlflow* with a Cloud + Computing paradigm, see :ref:`Remote Tensorboard log` and + :ref:`Mlflow tracking server set up`. -.. note:: *This is a work in progress project. Compatibility with others algorithms is being planned for the future!* \ No newline at end of file +.. note:: *This is a work in progress project. Direct support with others + algorithms is being planned for the future!* \ No newline at end of file diff --git a/docs/source/pages/environments.rst b/docs/source/pages/environments.rst index 29e5ae5520..c214826d65 100644 --- a/docs/source/pages/environments.rst +++ b/docs/source/pages/environments.rst @@ -6,7 +6,7 @@ Environments Environments List ************************** -The list of available environments is the following: +The **list of available environments** is the following: +----------------------------------------------------+-----------------+---------------------------------------+----------------------------+--------------+-------------------+ | Env. name | Location | IDF file | Weather type (*) | Action space | Simulation period | @@ -118,80 +118,311 @@ classification ()` in order to register them correctly. Sinergym will check for - you that the variable names are correct with respect to the building you are trying to simulate (IDF file). - To do this, it will look at the list found in the `variables `__ folder of the project (**RDD** file). +IDF file +========= -- **observation_space**: Definition of the observation space following the **gym standard**. This space is used to represent all the observations - variables that we have previously defined. Remember that the **year, month, day and hour** are added by Sinergym later, - so space must be reserved for these fields in the definition. If an inconsistency is found, Sinergym will notify you - so that it can be fixed. +The parameter *idf_file* is the path to *IDF* (Intermediate Data Format) +file where *Energyplus* building model is defined. -- **action_variables**: List of the action variables that simulator is going to process like schedule control actuator in the building model. These variables - must be defined in the building model (IDF file) correctly before simulation. You can modify **manually** in the IDF file or using - our **action definition** extra configuration field in which you set what you want to control and Sinergym takes care of modifying - this file for you automatically. For more information about this automatic adaptation in section :ref:`action_definition`. - -- **action_space**: Definition of the action space following the **gym standard**. This definition can be discrete or continuous and must be consistent with - the previously defined action variables (Sinergym will show inconsistency as usual). +*Sinergym* initially provides **"free" buildings**. This means that the *IDF* does not have the external +interface defined and default components, such as the ``timesteps``, the ``runperiod``, the +``location`` or ``DesignDays``. + +Depending on the rest of the parameters that make up the environment, the building model is **updated** +by *Sinergym* automatically, changing those components that are necessary, such as the external interface that we +have mentioned. + +Once the building is configured, it is **copied** to the output folder of that particular experimentation +and used by the simulator of that execution. + +EPW file +========= + +The parameter *weather_file* is the path to *EPW* (EnergyPlus Weather) file where **climate conditions** during +a year is defined. + +Initially, this file will not be copied to the specific output folder of the experiment, since the original +file present in *Sinergym* can be used directly. However, the user can set a year-to-year **variability** in +the climate (see section :ref:`Weather Variability`). In that case, the weather updated with such variability +will be copied and used in the output folder. + +Depending on the climate that is set for the environment, some of building model components need to be **modified** +in such a way that it is **compatible** with that weather. Therefore, *Sinergym* updates the ``DesignDays`` and ``Location`` +fields automatically using the weather data, without the need for user intervention. + +Weather Variability +==================== + +**Weather variability** can be integrated into an environment using *weather_variability* parameter. + +It implements the `Ornstein-Uhlenbeck process `__ +in order to introduce **noise** to the weather data episode to episode. Then, parameter established is a Python tuple of three variables +(*sigma*, *mu* and *tau*) whose values define the nature of that noise. + +.. image:: /_static/weather_variability.png + :scale: 120 % + :alt: Ornstein-Uhlenbeck process noise with different hyperparameters. + :align: center + + +Reward +======= + +The parameter called *reward* is used to define the **reward class** (see section :ref:`Rewards`) +that the environment is going to use to calculate and return reward values each timestep. -.. note:: In order to make environments more generic in DRL solutions. We have updated action space for **continuous problems**. Gym action space is defined always between [-1,1] - and Sinergym **parse** this values to action space defined in environment internally before to send it to EnergyPlus Simulator. The method in charge of parse this values - from [-1,1] to real action space is called ``_setpoints_transform(action)`` in *sinergym/sinergym/envs/eplus_env.py* +Reward Kwargs +============== -- **action_mapping**: It is only necessary to specify it in discrete action spaces. It is a dictionary that links an index to a specific configuration of values for each action variable. +Depending on the reward class that is specified to the environment, it may have **different parameters** +depending on its type. In addition, if a user creates a new custom reward, it can have new parameters as well. -Specification -~~~~~~~~~~~~~~ +Moreover, depending on the building being used (*IDF* file) for the environment, the values of these reward parameters may +need to be different, such as the comfort range or the energy and temperature variables of the simulation that +will be used to calculate the reward. -As we have told, Observation and action spaces are defined **dynamically** in Sinergym Environment constructor. Environment ID's registered in Sinergym use a **default** definition +Then, the parameter called *reward_kwargs* is a Python dictionary where we can **specify all reward class parameters** +that they are needed. For more information about rewards, visit section :ref:`Rewards`. + +Action Repeat +============== + +The parameter called *act_repeat* is the number of timesteps that an **action is repeated** in the simulator, +regardless of the actions it receives during that repetition interval. Default value is 1. + +Maximum Episode Data Stored in Sinergym Output +=============================================== + +*Sinergym* stores all the output of an experiment in a folder organized in sub-folders for each episode +(see section :ref:`Output format` for more information). Depending on the value of the parameter *max_ep_data_store_num*, +the experiment will store the output data of the **last n episodes** set, where **n** is the value of the parameter. + +In any case, if *Sinergym Logger* (See :ref:`Logger` section) is activate, ``progress.csv`` will be present with +the summary data of each episode. + +Observation/action spaces +=========================== + +Structure of observation and action space is defined in Environment constructor directly. +This allows for a **dynamic definition** of these spaces. Let's see the fields required to do it: + +- **observation_variables**: List of observation variables that simulator is going to process like an observation. + These variables names must follow the structure ``()`` in order to register + them correctly. *Sinergym* will check for you that the variable names are correct with respect to + the building you are trying to simulate (*IDF* file). + To do this, it will look at the list found in the + `variables `__ + folder of the project (*RDD* file). + +- **observation_space**: Definition of the observation space following the **OpenAI gym standard**. + This space is used to represent all the observations variables that we have previously + defined. Remember that the **year, month, day and hour** are added by *Sinergym* later, + so space must be reserved for these fields in the definition. If an inconsistency is + found, *Sinergym* will notify you so that it can be fixed easily. + +- **action_variables**: List of the action variables that simulator is going to process + like schedule control actuator in the building model. These variables + must be defined in the building model (*IDF* file) correctly before simulation. You can + modify **manually** in the *IDF* file or using our **action definition** field + in which you set what you want to control and *Sinergym* + takes care of modifying this file for you automatically. For more information about + this automatic adaptation in section :ref:`Action definition`. + +- **action_space**: Definition of the action space following the **OpenAI gym standard**. + This definition can be discrete or continuous and must be consistent with + the previously defined action variables (*Sinergym* will show inconsistency as usual). + +.. note:: In order to make environments more generic in DRL solutions. We have updated + action space for **continuous problems**. Gym action space is defined always + between [-1,1] and Sinergym **parse** this values to action space defined in + environment internally before to send it to EnergyPlus Simulator. + The method in charge of parse this values from [-1,1] to real action space is + called ``_setpoints_transform(action)`` in *sinergym/sinergym/envs/eplus_env.py* + +- **action_mapping**: It is only necessary to specify it in **discrete** action spaces. + It is a dictionary that links an **index** to a specific configuration of values for + each action variable. + +As we have told, observation and action spaces are defined **dynamically** in *Sinergym* +Environment constructor. Environment ID's registered in *Sinergym* use a **default** definition set up in `constants.py `__. -As can be seen in environments observations, the **year, month, day and hour** are included in, but is not configured in default observation variables definition. -This is because they are not variables recognizable by the simulator as such (Energyplus) and Sinergym does the calculations and adds them in the states returned as -output by the environment. This feature is common to all environments available in Sinergym and all supported building designs. In other words, you don't need to -add this variables (**year, month, day and hour**) to observation variables but yes to the observation space. +As can be seen in environments observations, the **year, month, day and hour** are included in, +but is not configured in default observation variables definition. +This is because they are not variables recognizable by the simulator (*Energyplus*) as such +and *Sinergym* does the calculations and adds them in the states returned as +output by the environment. This feature is **common to all environments** available in +*Sinergym* and all supported building designs. In other words, you don't need to +add this variables (**year, month, day and hour**) to observation variables, but yes to +the observation space. -As we told before, all environments ID's registered in Sinergym use its respectively **default action and observation spaces, variables and definition**. -However, you can **change** this values giving you the possibility of playing with different observation/action spaces in discrete and continuous environments in order to study how this affects the resolution of a building problem. +As we told before, all environments ID's registered in *Sinergym* use its respectively +**default action and observation spaces, variables and action definition**. +However, you can **change** this values giving you the possibility of playing with different +observation/action spaces in discrete and continuous environments in order to study how this +affects the resolution of a building problem. -Sinergym has several checkers to ensure that there are no inconsistencies in the alternative specifications made to the default ones. In case the specification offered is wrong, Sinergym will launch messages indicating where the error or inconsistency is located. +*Sinergym* has several **checkers** to ensure that there are no inconsistencies in the alternative +specifications made to the default ones. In case the specification offered is wrong, +*Sinergym* will launch messages indicating where the error or inconsistency is located. -.. note:: `variables.cfg` is a requirement in order to establish a connection between gym environment and Simulator - with a external interface (using BCVTB). Since Sinergym `1.9.0` version, it is created automatically using +.. note:: ``variables.cfg`` is a requirement in order to establish a connection between gym environment and Simulator + with a external interface (using *BCVTB*). Since *Sinergym* ``1.9.0`` version, it is created automatically using action and observation space definition in environment construction. +Environment name +================ + +The parameter *env_name* is used to define the **name of working directory** generation. + +Action definition +================== + +Creating a **new external interface** to control different parts of a building is not a trivial task, +it requires certain changes in the building model (*IDF*), configuration files for the external +interface (``variables.cfg``), etc in order to control it. + +The **changes in the building model** are **complex** due to depending on the building model we will have +available different zones and actuators. + +Thus, there is the possibility to add an **action definition** in environment instead of modify *IDF* +directly about components or actuators changes required to control by external variables specified +in :ref:`Observation/action spaces`. + +For this purpose, we have available *action_definition* parameter in environments. Its value is a +dictionary with the next structure: + +.. code:: python + + action_definition_example={ + :[,, ...], + : ... + } + +The ```` will depend on the specific type of controller that we are +going to create, we have the next support: + +~~~~~~~~~~~~~~~~~~~~~~~~ +Thermostat:DualSetpoint +~~~~~~~~~~~~~~~~~~~~~~~~ + +This controller has the next values in its definition: + +- *name*: DualSetpoint resource name (str). + +- *heating_name*: Heating setpoint name. This name should be an action variable defined + in your environment (str). + +- *cooling_name*: Cooling setpoint name. This name should be an action variable defined + in your environment (str). + +- *heating_initial_value*: Initial value the heating thermostat initialize the simulation with (float). + +- *cooling_initial_value*: Initial value the cooling thermostat initialize the simulation with (float). + +- *zones*: An thermostat can manage several building zones at the same time. Then, you + can specify one or more zones (List(str)). If the zone name specified is not + exist in building, Sinergym will report the error. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +ThermostatSetpoint:SingleHeating +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This controller has the next values in its definition: + +- *name*: SingleHeating Setpoint resource name (str). + +- *heating_name*: Heating setpoint name. This name should be an action variable defined + in your environment (str). + +- *heating_initial_value*: Initial value the heating thermostat initialize the simulation with. + +- *zones*: An thermostat can manage several building zones at the same time. Then, you + can specify one or more zones (List(str)). If the zone name specified is not + exist in building, Sinergym will report the error. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +ThermostatSetpoint:SingleCooling +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This controller has the next values in its definition: + +- *name*: SingleCooling Setpoint resource name (str). + +- *cooling_name*: Cooling setpoint name. This name should be an action variable defined + in your environment (str). + +- *cooling_initial_value*: Initial value the cooling thermostat initialize the simulation with. + +- *zones*: An thermostat can manage several building zones at the same time. Then, you + can specify one or more zones (List(str)). If the zone name specified is not + exist in building, Sinergym will report the error. + +For an example about how to use it, see :ref:`Adding a new action definition`. + +.. note:: If you want to create your own controller type compatibilities, + please see the method ``adapt_idf_to_action_definition`` from + `Config class `__. + +Extra configuration +=================== + +Some parameters directly associated with the simulator can be set as extra configuration +as well, such as ``people occupant``, ``timesteps per simulation hour``, ``runperiod``, etc. + +Like this **extra configuration context** can grow up in the future, this is specified in *config_params* field. +It is a Python Dictionary where this values are specified. For more information about extra configuration +available for *Sinergym* visit section :ref:`Extra Configuration in Sinergym simulations`. + ************************************** Adding new buildings for environments ************************************** -This section is intended to provide information if someone decides to add new buildings for use with Sinergym. The main steps you have to follow are the next: +As we have already mentioned, a user can change the already available environments or even create new environment +definitions including new climates, action and observation spaces, etc. However, perhaps **the most complex thing +to incorporate** into the project are **new building models** (*IDF* files) than the ones we support. + +This section is intended to provide information if someone decides to add new buildings for use with *Sinergym*. +The main steps you have to follow are the next: -1. Add your building (IDF file) to `buildings `__. - As mentioned in section :ref:`Observation/action spaces`, the IDF must be previously adapted to your action space or use our **action definition** (section :ref:`action_definition`) - to be automatically adapted to the action space and variables you have designed for it, as long as we provide support for the specific component you want to control. By default, Sinergym will create - an `ExternalInterface` object in IDF file with an empty action space. Then, all the components will be managed by a default scheduler designed in IDF file. +1. Add your building (*IDF* file) to `buildings `__. + That building model must be "free" as far as external interface is concerned if you plan to use Sinergym's **action + definition** which will modify the model for you before starting the + simulation automatically (see section :ref:`Action definition`). + If you are going to control a component which is not supported by *Sinergym* currently, + you will have to update *IDF* manually before starting + simulation. **Be sure that new IDF model version is compatible with EnergyPlus version**. -2. Add your own EPW file for weather conditions or use ours in environment constructor. Sinergym will adapt `DesignDays` in IDF file using EPW automatically. +2. Add your own *EPW* file for weather conditions or use ours in environment constructor. + *Sinergym* will adapt ``DesignDays`` and ``Location`` in *IDF* file using *EPW* automatically. + It is important to add the *DDY* file too, with the same name than *EPW* in order to + read the ``DesignDay`` correctly. -3. Sinergym will check that observation variables specified are available in the simulation before starting. In order to be able to do these checks, - you need to copy **RDD file** with the same name than IDF file (except extension) to `variables `__. - To obtain this **RDD file** you have to run a simulation with *Energyplus* directly and extract from output folder. - Make sure that **Output:VariableDictionary** object in IDF has the value *Regular* in order to RDD file has the correct formar for Sinergym. +3. *Sinergym* will check that observation variables specified in environments constructor are + available in the simulation before starting. In order to be able to do these checks, + you need to copy **RDD file** with the same name than *IDF* file (except extension) + to `variables `__. + To obtain this **RDD file** you have to run a simulation with *Energyplus* directly + and extract from output folder. + Make sure that **Output:VariableDictionary** object in *IDF* has the value *Regular* + in order to *RDD* file has the correct format for *Sinergym*. -4. Register your own environment ID `here `__ following the same structure than the rest. +4. Register your own environment ID `here `__ + following the same structure than the rest. -5. Now, you can use your own environment ID with `gym.make()` like our documentation examples. +5. Now, you can use your own environment ID with ``gym.make()`` like our documentation examples. diff --git a/docs/source/pages/extra-configuration.rst b/docs/source/pages/extra-configuration.rst index fcd5b8ec97..c56285b93e 100644 --- a/docs/source/pages/extra-configuration.rst +++ b/docs/source/pages/extra-configuration.rst @@ -2,8 +2,10 @@ Extra Configuration in Sinergym simulations ############################################ -Using `Config class `__ in simulator, we have the possibility to set up some details in our simulation. This let us to amplify the context of each experiment and have more parameters to investigate. -To use this functionality easily, you can provide this extra parameters in env constructor in this way: +Using `Config class `__ +in simulator, we have the possibility to set up some **details of context** in our simulation. +This let us to amplify the context of each experiment and have more parameters to investigate. +To use this functionality easily, you can provide this extra parameters in **environment constructor** in this way: .. code:: python @@ -14,7 +16,8 @@ To use this functionality easily, you can provide this extra parameters in env c 'runperiod' : (1,1,1997,12,3,1998)} env = gym.make('Eplus-5Zone-hot-continuous-v1', config_params=extra_params) -Sinergym will modify this simulation model from Python code and save IDF in each episode directory generated in output. For more information, see :ref:`Output format`. +*Sinergym* will modify this simulation model from Python code and save *IDF* in each +episode directory generated in output. For more information, see :ref:`Output format`. The format for apply extra configuration is a **Python dictionary** with extra parameter key name and value. .. note:: *Currently, only code skeleton and some parameters has been designed. Stay tuned for upcoming releases!* @@ -25,48 +28,26 @@ Let's see each implemented parameter for extra configuration separately: timestep_per_hour ****************** -By default, a Sinergym simulation apply 4 timestep per simulation hour. However, you have the possibility to modify this value using **timestep_per_hour** key in `config_params` dictionary and set more/less timesteps in each simulation hour. +By default, a *Sinergym* simulation apply **4** timestep per simulation hour. However, +you have the possibility to modify this value using **timestep_per_hour** key +in `config_params` dictionary and set more/less timesteps in each simulation hour. ****************** runperiod ****************** -By default, a Sinergym simulation episode is one year (from 1/1/1991 to 31/12/1991). You can use this **runperiod** key and, as a result, determine episode length in simulation. -The format value for **runperiod** key is a **tuple** with (*start_day*, *start_month*, *start_year*, *end_day*, *end_month*, *end_year*). +By default, a *Sinergym* simulation episode is one year (*from 1/1/1991 to 31/12/1991*). +You can use this **runperiod** key and, as a result, determine **episode length** in simulation. +The format value for **runperiod** key is a **tuple** with +(*start_day*, *start_month*, *start_year*, *end_day*, *end_month*, *end_year*). -.. warning:: If we include a manual runperiod with this functionality, we should not include any February 29th of a leap year in that range. Otherwise, the simulator will fail, since Energyplus does not take into account leap days and the weather files do not include these days. +.. warning:: If we include a manual runperiod with this functionality, we should not include any + February 29th of a leap year in that range. Otherwise, the simulator will fail, + since *Energyplus* does not take into account leap days and the weather files + do not include these days. -****************** -action_definition -****************** - -Creating a **new external interface** to control different parts of a building is not a trivial task, it requires certain changes in the building model (IDF), -configuration files for the external interface (variables.cfg), etc in order to control it. - -For this purpose, we have available **action_definition** key extra parameter. Its value is a dictionary with the next structure: - -.. code:: python - - extra_params={ - 'action_definition':{ - :[,, ...] - } - } - -The `` will depend on the specific type of controller that we are going to create, we have the next support: - -Thermostat:DualSetpoint -~~~~~~~~~~~~~~~~~~~~~~~~ - -This controller has the next values in its definition: - -- *name*: DualSetpoint resource name (str). -- *heating_name*: Heating setpoint name. This name should be an action variable defined in your environment (str). -- *cooling_name*: Cooling setpoint name. This name should be an action variable defined in your environment (str). -- *zones*: An thermostat can manage several building zones at the same time. Then, you can specify one or more zones (List(str)). If the zone name specified is not exist in building, Sinergym will report the error. - -For an example about how to use it, see :ref:`Adding extra configuration definition`. - -.. note:: Actually, we only support `Thermostat:DualSetpoint` definition, but more components could be managed in the future. Stay tuned for upcoming releases! +.. note:: More components could be managed in the future. Stay tuned for upcoming releases! -.. note:: If you want to create your own extra configuration parameters, please see the method `apply_extra_conf` from `Config class `__. \ No newline at end of file +.. note:: If you want to create your own extra configuration parameters, + please see the method ``apply_extra_conf`` from + `Config class `__. \ No newline at end of file diff --git a/docs/source/pages/gcloudAPI.rst b/docs/source/pages/gcloudAPI.rst index eb8a0bfd19..67b573ecd0 100644 --- a/docs/source/pages/gcloudAPI.rst +++ b/docs/source/pages/gcloudAPI.rst @@ -2,11 +2,19 @@ Sinergym with Google Cloud ########################### -In this project, we have defined some functionality based in gcloud API python in `sinergym/utils/gcloud.py`. Our time aim to configure a Google Cloud account and combine with Sinergym easily. +In this project, we have defined some functionality based in gcloud API +python in ``sinergym/utils/gcloud.py``. Our team aim to configure a Google +Cloud account and combine with *Sinergym* easily. -The main idea is to construct a **virtual machine** (VM) using **Google Cloud Engine** (GCE) in order to execute our **Sinergym container** on it. At the same time, this remote container will update a Google Cloud Bucket with experiments results and mlflow tracking server with artifacts if we configure that experiment with those options. +The main idea is to construct a **virtual machine** (VM) using +**Google Cloud Engine** (GCE) in order to execute our **Sinergym container** +on it. At the same time, this remote container will update a **Google Cloud +Bucket with experiments results** and **mlflow tracking server** with artifacts +if we configure that experiment with those options. -When an instance has finished its job, container **auto-remove** its host instance from Google Cloud Platform if experiments has been configured with this option. +When an instance has finished its job, container **auto-remove** its host +instance from Google Cloud Platform if experiments has been configured +with this option. Let’s see a detailed explanation above. @@ -17,23 +25,32 @@ Preparing Google Cloud 1. First steps (configuration) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Firstly, it is necessary that you have a Google Cloud account set up and SDK configured (auth, invoicing, project ID, etc). If you don't have this, it is recommended to check `their documentation `__. -Secondly, It is important to have installed `Docker `__ in order to be able to manage these containers in Google Cloud. +Firstly, it is necessary that you have a Google Cloud account set up and +SDK configured (auth, invoicing, project ID, etc). If you don't have this, +it is recommended to check `their documentation `__. +Secondly, It is important to have installed +`Docker `__ in order to be able to manage these +containers in Google Cloud. -You can link **gcloud** with **docker** accounts using the next (see `authentication methods `__): +You can link **gcloud** with **docker** accounts using the next +(see `authentication methods `__): .. code:: sh $ gcloud auth configure-docker -If you don't want to have several problems in the future with the image build and Google Cloud functionality in general, we recommend you to **allow permissions for google cloud build** at the beginning (see `this documentation `__). +If you don't want to have several problems in the future with the image +build and Google Cloud functionality in general, we recommend you to +**allow permissions for google cloud build** at the beginning +(see `this documentation `__). .. image:: /_static/service-account-permissions.png :width: 500 :alt: Permissions required for cloud build. :align: center -On the other hand, we are going to enable **Google Cloud services** in *API library*. These are API's which we need currently: +On the other hand, we are going to enable **Google Cloud services** +in *API library*. These are API's which we need currently: - Google Container Registry API. - Artifact Registry API @@ -79,7 +96,9 @@ Or you can use **Google Cloud Platform Console**: :alt: API's required for cloud build. :align: center -If you have installed *Sinergym* and *Sinergym extras*. **Google Cloud SDK must be linked with other python modules** in order to some functionality works in the future (for example, tensorboard). Please, execute the next in your terminal: +If you have installed *Sinergym* and *Sinergym extras*. **Google Cloud SDK must +be linked with other python modules** in order to some functionality works in +the future (for example, *Tensorboard*). Please, execute the next in your terminal: .. code:: sh @@ -88,18 +107,19 @@ If you have installed *Sinergym* and *Sinergym extras*. **Google Cloud SDK must 2. Use our container in Google Cloud Platform ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Our Sinergym container is uploaded in **Container Registry** as a public one currently. You can use it **locally**: +Our *Sinergym* container is uploaded in **Container Registry** as a public one +currently. You can use it **locally**: .. code:: sh - $ docker run -it gcr.io/sinergym/sinergym:latest + $ docker run -it eu.gcr.io/sinergym/sinergym:latest If you want to use it in a **GCE VM**, you can execute the next: .. code:: sh $ gcloud compute instances create-with-container sinergym \ - --container-image gcr.io/sinergym/sinergym \ + --container-image eu.gcr.io/sinergym/sinergym \ --zone europe-west1-b \ --container-privileged \ --container-restart-policy never \ @@ -109,17 +129,23 @@ If you want to use it in a **GCE VM**, you can execute the next: --boot-disk-type pd-ssd \ --machine-type n2-highcpu-8 -We have available containers in Docker Hub too. Please, visit our `repository `__ +We have available containers in Docker Hub too. Please, visit +our `repository `__ -.. note:: It is possible to change parameters in order to set up your own VM with your preferences (see `create-with-container `__). +.. note:: It is possible to change parameters in order to set + up your own VM with your preferences (see + `create-with-container `__). -.. warning:: ``--boot-disk-size`` is really important, by default VM set 10GB and it isn't enough at all for Sinergym container. - This derive in a silence error for Google Cloud Build (and you would need to check logs, which incident is not clear). +.. warning:: ``--boot-disk-size`` is really important, by default + VM set 10GB and it isn't enough at all for *Sinergym* container. + This derive in a silence error for Google Cloud Build + (and you would need to check logs, which incident is not clear). 3. Use your own container ~~~~~~~~~~~~~~~~~~~~~~~~~~ -Suppose you have this repository forked and you want to upload **your own container on Google Cloud** and to use it. You can use **cloudbuild.yaml** +Suppose you have this repository forked and you want to upload **your own +container on Google Cloud** and to use it. You can use **cloudbuild.yaml** with our **Dockerfile** for this purpose: .. literalinclude:: ../../../cloudbuild.yaml @@ -127,20 +153,27 @@ with our **Dockerfile** for this purpose: This file does the next: - 1. Write in **cache** for quick updates (if a older container was uploaded already). + 1. Write in **cache** for quick updates + (if a older container was uploaded already). 2. **Build** image (using cache if it's available) 3. **Push** image built to Container Registry 4. Make container public inner Container Registry. -There is an option section at the end of the file. Do not confuse this part with the virtual machine configuration. -Google Cloud uses a helper VM to build everything mentioned above. At the same time, we are using this YAML file in order to -upgrade our container because of *PROJECT_ID* environment variable is defined by Google Cloud SDK, so its value is your current -project in Google Cloud global configuration. +There is an option section at the end of the file. Do not confuse +this part with the virtual machine configuration. Google Cloud +uses a helper VM to build everything mentioned above. At the same +time, we are using this *YAML* file in order to upgrade our container +because of ``PROJECT_ID`` environment variable is defined by Google +Cloud SDK, so its value is your current project in Google Cloud +global configuration. -.. warning:: In the same way VM needs more memory, Google Cloud Build needs at least 10GB to work correctly. In other case it may fail. +.. warning:: In the same way VM needs more memory, Google Cloud + Build needs at least 10GB to work correctly. In other + case it may fail. -.. warning:: If your local computer doesn't have enough free space it might report the same error (there isn't difference by Google cloud error manager), - so be careful. +.. warning:: If your local computer doesn't have enough free space + it might report the same error (there isn't difference + by Google cloud error manager), so be careful. In order to execute **cloudbuild.yaml**, you have to do the next: @@ -149,12 +182,18 @@ In order to execute **cloudbuild.yaml**, you have to do the next: $ gcloud builds submit --region europe-west1 \ --config ./cloudbuild.yaml . -*--substitutions* can be used in order to configure build parameters if they are needed. +``--substitutions`` can be used in order to configure build +parameters if they are needed. -.. note:: "." in ``--config`` refers to **Dockerfile**, which is necessary to build container image (see `build-config `__). +.. note:: "." in ``--config`` refers to **Dockerfile**, which is + necessary to build container image (see + `build-config `__). -.. note:: In **cloudbuild.yaml** there is a variable named *PROJECT_ID*. However, it is not defined in substitutions. This is because it's a predetermined - variable by Google Cloud. When build begins *"$PROJECT_ID"* is set to current value in gcloud configuration (see `substitutions-variables `__). +.. note:: In **cloudbuild.yaml** there is a variable named *PROJECT_ID*. + However, it is not defined in substitutions. This is because + it's a predetermined variable by Google Cloud. When build begins + *"$PROJECT_ID"* is set to current value in gcloud configuration + (see `substitutions-variables `__). 4. Create your VM or MIG ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -164,7 +203,7 @@ To create a **VM** that uses this container, here there is an example: .. code:: sh $ gcloud compute instances create-with-container sinergym \ - --container-image gcr.io/sinergym/sinergym \ + --container-image eu.gcr.io/sinergym/sinergym \ --zone europe-west1-b \ --container-privileged \ --container-restart-policy never \ @@ -174,17 +213,21 @@ To create a **VM** that uses this container, here there is an example: --boot-disk-type pd-ssd \ --machine-type n2-highcpu-8 -.. note:: ``--container-restart-policy never`` it's really important for a correct functionality. +.. note:: ``--container-restart-policy never`` it's really important for a + correct functionality. -.. warning:: If you decide enter in VM after create it immediately, it is possible container hasn't been created yet. - You can think that is an error, Google cloud should notify this. If this issue happens, you should wait for a several minutes. +.. warning:: If you decide enter in VM after create it immediately, it is + possible container hasn't been created yet. + You can think that is an error, Google cloud should notify this. + If this issue happens, you should wait for a several minutes. -To create a **MIG**, you need to create a machine set up **template** firstly, for example: +To create a **MIG**, you need to create a machine set up **template** +firstly, for example: .. code:: sh $ gcloud compute instance-templates create-with-container sinergym-template \ - --container-image gcr.io/sinergym/sinergym \ + --container-image eu.gcr.io/sinergym/sinergym \ --container-privileged \ --service-account storage-account@sinergym.iam.gserviceaccount.com \ --scopes https://www.googleapis.com/auth/cloud-platform,https://www.googleapis.com/auth/devstorage.full_control \ @@ -196,7 +239,10 @@ To create a **MIG**, you need to create a machine set up **template** firstly, f --boot-disk-type pd-ssd \ --machine-type n2-highcpu-8 -.. note:: ``--service-account``, ``--scopes`` and ``--container-env`` parameters will be explained in :ref:`Containers permission to bucket storage output`. Please, read that documentation before using these parameters, since they require a previous configuration. +.. note:: ``--service-account``, ``--scopes`` and ``--container-env`` parameters + will be explained in :ref:`Containers permission to bucket storage + output`. Please, read that documentation before using these parameters, + since they require a previous configuration. Then, you can create a group-instances as large as you want: @@ -207,18 +253,25 @@ Then, you can create a group-instances as large as you want: --size 3 \ --template sinergym-template -.. warning:: It is possible that quote doesn't let you have more than one VM at the same time. Hence, the rest of VM's probably will be *initializing* always but never ready. If it is your case, we recommend you check your quotes `here `__ +.. warning:: It is possible that quote doesn't let you have more than one + VM at the same time. Hence, the rest of VM's probably will + be *initializing* always but never ready. If it is your case, + we recommend you check your quotes + `here `__ 5. Initiate your VM ~~~~~~~~~~~~~~~~~~~~ -Your virtual machine is ready! To connect you can use ssh (see `gcloud-ssh `__): +Your virtual machine is ready! To connect you can use ssh +(see `gcloud-ssh `__): .. code:: sh $ gcloud compute ssh -Google Cloud use a **Container-Optimized OS** (see `documentation `__) in VM. This SO have docker pre-installed with sinergym container. +Google Cloud use a **Container-Optimized OS** (see +`documentation `__) +in VM. This SO have docker pre-installed with *Sinergym* container. .. image:: /_static/container1.png :width: 800 @@ -237,66 +290,145 @@ To use this container in our machine you only have to do: :alt: GCE VM container usage. :align: center -And now you can execute your own experiments in Google Cloud! For example, you can enter in remote container with *gcloud ssh* and execute *DRL_battery.py* for the experiment you want. +And now you can execute your own experiments in Google Cloud! For example, +you can enter in remote container with *gcloud ssh* and execute +*DRL_battery.py* for the experiment you want. ******************************************** Executing experiments in remote containers ******************************************** -This script, called *DRL_battery.py*, will be allocated in every remote container and it is used to execute experiments and combine it with **Google Cloud Bucket**, **Mlflow Artifacts**, **auto-remove**, etc: +This script, called *DRL_battery.py*, will be allocated in every remote +container and it is used to execute experiments and combine it with +**Google Cloud Bucket**, **Mlflow Artifacts**, **auto-remove**, etc: .. literalinclude:: ../../../scripts/DRL_battery.py :language: python -.. note:: **DRL_battery.py** is able to be used to local experiments into client computer. For example, ``--auto_delete`` parameter will have no effect in experiment. This experiments results could be sent to bucket and mlflow artifacts if it is specified. We will see it. +.. note:: **DRL_battery.py** is able to be used to local experiments + into client computer. For example, ``--auto_delete`` parameter + will have no effect in experiment. This experiments results + could be sent to bucket and mlflow artifacts if it is specified. + We will see it. The list of parameter is pretty large. Let's see it: -- ``--environment`` or ``-env``: Environment name you want to use (see :ref:`Environments`) -- ``--episodes`` or ``-ep``: Number of episodes you want to train agent in simulation (Depending on environment episode length can be different) -- ``--algorithm`` or ``-alg``: Algorithm you want to use to train (Currently, it is available *PPO*, *A2C*, *DQN*, *DDPG* and *SAC*) -- ``--reward`` or ``-rw``: Reward class you want to use for reward function. Currently, possible values are "linear" and "exponential"(see :ref:`Rewards`). -- ``--normalization`` or ``-norm``: Apply normalization wrapper to observations during training. If it isn't specified wrapper will not be applied (see :ref:`Wrappers`). -- ``--multiobs`` or ``-mobs``: Apply Multi-Observation wrapper to observations during training. If it isn't specified wrapper will not be applied (see :ref:`Wrappers`). -- ``--logger`` or ``-log``: Apply Sinergym logger wrapper during training. If it isn't specified wrapper will not be applied (see :ref:`Wrappers` and :ref:`Logger`). -- ``--tensorboard`` or ``-tens``: This parameter will contain a **path-file** or **path-remote-bucket** to allocate tensorboard training logs. If it isn't specified this log will be deactivate (see :ref:`DRL Logger`). -- ``--evaluation`` or ``-eval``: If it is specified, evaluation callback will be activate, else model evaluation will be deactivate during training (see :ref:`Deep Reinforcement Learning Integration`). -- ``--eval_freq`` or ``-evalf``: Only if ``--evaluation`` flag has been written. Episode frequency for evaluation. -- ``--eval_length`` or ``-evall``: Only if ``--evaluation`` flag has been written. Number of episodes for each evaluation. -- ``--log_interval`` or ``-inter``: This parameter is used for ``learn()`` method in each algorithm. It is important specify a correct value. -- ``--seed`` or ``-sd``: Seed for training, random components in process will be able to be recreated. -- ``--remote_store`` or ``-sto``: Determine if sinergym output and tensorboard log (when a local path is specified and not a remote bucket path) will be sent to a common resource (Bucket), else will be allocate in remote container memory only. -- ``--mlflow_store`` or ``-mlflow``: Determine if sinergym output and tensorboard log (when a local path is specified and not a remote bucket path) will be sent to a Mlflow Artifact, else will be allocate in remote container memory only. -- ``--group_name`` or ``-group``: It specify to which MIG the host instance belongs, it is important if --auto-delete is activated. -- ``--auto_delete`` or ``-del``: Whether this parameter is specified, remote instance will be auto removed when its job has finished. +- ``--environment`` or ``-env``: Environment name you want to use + (see :ref:`Environments`). + +- ``--episodes`` or ``-ep``: Number of episodes you want to train + agent in simulation (Depending on environment episode length can + be different). + +- ``--algorithm`` or ``-alg``: Algorithm you want to use to train + (Currently, it is available *PPO*, *A2C*, *DQN*, *DDPG* and *SAC*). + +- ``--reward`` or ``-rw``: Reward class you want to use for reward + function. Currently, possible values are "linear" and "exponential" + (see :ref:`Rewards`). + +- ``--normalization`` or ``-norm``: Apply normalization wrapper to + observations during training. If it isn't specified wrapper will + not be applied (see :ref:`Wrappers`). + +- ``--multiobs`` or ``-mobs``: Apply Multi-Observation wrapper to + observations during training. If it isn't specified wrapper will + not be applied (see :ref:`Wrappers`). + +- ``--logger`` or ``-log``: Apply Sinergym logger wrapper during + training. If it isn't specified wrapper will not be applied + (see :ref:`Wrappers` and :ref:`Logger`). + +- ``--tensorboard`` or ``-tens``: This parameter will contain a + **path-file** or **path-remote-bucket** to allocate tensorboard + training logs. If it isn't specified this log will be deactivate + (see :ref:`DRL Logger`). + +- ``--evaluation`` or ``-eval``: If it is specified, evaluation + callback will be activate, else model evaluation will be deactivate + during training (see :ref:`Deep Reinforcement Learning Integration`). + +- ``--eval_freq`` or ``-evalf``: Only if ``--evaluation`` flag has been + written. Episode frequency for evaluation. + +- ``--eval_length`` or ``-evall``: Only if ``--evaluation`` flag has been + written. Number of episodes for each evaluation. + +- ``--log_interval`` or ``-inter``: This parameter is used for ``learn()`` + method in each algorithm. It is important specify a correct value. + +- ``--seed`` or ``-sd``: Seed for training, random components in process + will be able to be recreated. + +- ``--remote_store`` or ``-sto``: Determine if sinergym output and + tensorboard log (when a local path is specified and not a remote + bucket path) will be sent to a common resource (Bucket), else will + be allocate in remote container memory only. + +- ``--mlflow_store`` or ``-mlflow``: Determine if sinergym output and + tensorboard log (when a local path is specified and not a remote bucket + path) will be sent to a Mlflow Artifact, else will be allocate in remote + container memory only. + +- ``--group_name`` or ``-group``: It specify to which MIG the host instance + belongs, it is important if --auto-delete is activated. + +- ``--auto_delete`` or ``-del``: Whether this parameter is specified, + remote instance will be auto removed when its job has finished. -- **algorithm hyperparameters**: Execute ``python DRL_battery --help`` for more information. +- **algorithm hyperparameters**: Execute ``python DRL_battery --help`` + for more information. -.. warning:: For a correct auto_delete functionality, please, use MIG's instead of individual instances. +.. warning:: For a correct auto_delete functionality, please, use MIG's + instead of individual instances. This script do the next: - 1. Setting an appropriate name for the experiment. Following the next format: ``--episodes-seed()`` - 2. Starting Mlflow track experiment with that name, if mlflow server is not available, it will be used an local path (*./mlruns*) in remote container. + 1. Setting an appropriate name for the experiment. Following the next + format: ``--episodes-seed()`` + + 2. Starting Mlflow track experiment with that name, if mlflow server + is not available, it will be used an local path (*./mlruns*) in + remote container. + 3. Log all MlFlow parameters (including *sinergym.__version__*). + 4. Setting reward function specified in ``--reward`` parameter. + 5. Setting wrappers specified in environment. + 6. Defining model algorithm using hyperparameters. + 7. Calculate training timesteps using number of episodes. + 8. Setting up evaluation callback if it has been specified. + 9. Setting up Tensorboard logger callback if it has been specified. + 10. Training with environment. - 11. If ``--remote_store`` has been specified, saving all outputs in Google Cloud Bucket. If ``--mlflow_store`` has been specified, saving all outputs in Mlflow run artifact. - 12. Auto-delete remote container in Google Cloud Platform when parameter ``--auto_delete`` has been specified. + + 11. If ``--remote_store`` has been specified, saving all outputs in Google + Cloud Bucket. If ``--mlflow_store`` has been specified, saving all + outputs in Mlflow run artifact. + + 12. Auto-delete remote container in Google Cloud Platform when parameter + ``--auto_delete`` has been specified. Containers permission to bucket storage output ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -As you see in sinergym template explained in :ref:`4. Create your VM or MIG`, it is specified ``--scope``, ``--service-account`` and ``--container-env``. This aim to *remote_store* option in *DRL_battery.py* works correctly. -Those parameters provide each container with permissions to write in the bucket and manage Google Cloud Platform (auto instance remove function). -Container environment variables indicate zone, project_id and mlflow tracking server uri need it in :ref:`Mlflow tracking server set up`. +As you see in sinergym template explained in :ref:`4. Create your VM or MIG`, +it is specified ``--scope``, ``--service-account`` and ``--container-env``. +This aim to *remote_store* option in *DRL_battery.py* works correctly. +Those parameters provide each container with permissions to write in the bucket +and manage Google Cloud Platform (auto instance remove function). +Container environment variables indicate zone, project_id and mlflow tracking +server uri need it in :ref:`Mlflow tracking server set up`. -Hence, it is **necessary** to **set up this service account** and give privileges in order to that objective. Then, following `Google authentication documentation `__ we will do the next: +Hence, it is **necessary** to **set up this service account** and give privileges +in order to that objective. Then, following +`Google authentication documentation `__ +we will do the next: .. code:: sh @@ -305,32 +437,62 @@ Hence, it is **necessary** to **set up this service account** and give privilege $ gcloud iam service-accounts keys create PROJECT_PATH/google-storage.json --iam-account=storage-account@PROJECT_ID.iam.gserviceaccount.com $ export GOOGLE_CLOUD_CREDENTIALS= PROJECT_PATH/google-storage.json -In short, we create a new service account called **storage-account**. Then, we dote this account with *roles/owner* permission. The next step is create a file key (json) called **google-storage.json** in our project root (gitignore will ignore this file in remote). -Finally, we export this file in **GOOGLE_CLOUD_CREDENTIALS** in our local computer in order to gcloud SDK knows that it has to use that token to authenticate. +In short, we create a new service account called **storage-account**. +Then, we dote this account with *roles/owner* permission. The next step +is create a file key (json) called **google-storage.json** in our project +root (gitignore will ignore this file in remote). +Finally, we export this file in **GOOGLE_CLOUD_CREDENTIALS** in our local computer +in order to gcloud SDK knows that it has to use that token to authenticate. ********************** Load a trained model ********************** -For this purpose, we have a script called *load_agent.py* which can be used both on a remote machine and locally on our computer, just like *DRL_battery.py*. +For this purpose, we have a script called *load_agent.py* which can be used both +on a remote machine and locally on our computer, just like *DRL_battery.py*. -So, what this script does is to use the path that we pass as a parameter where our model is located. It loads the model and performs the evaluation that we want. +So, what this script does is to use the path that we pass as a parameter where our +model is located. It loads the model and performs the evaluation that we want. The list of parameter is: - ``--environment`` or ``-env``: Environment name you want to use. -- ``--model`` or ``-mod``: Trained model (zip file) you want to use to execute the evaluation. This path can be a local path file into your computer (remote or host) or a Google Cloud Storage resource (bucket like ``gs:///``). -- ``--episodes`` or ``-ep``: Number of episodes you want to evaluate agent in simulation (Depending on environment episode length can be different) -- ``--algorithm`` or ``-alg``: Algorithm which model was trained (Currently, it is available *PPO*, *A2C*, *DQN*, *DDPG* and *SAC*). -- ``--reward`` or ``-rw``: Reward class you want to use for reward function (same reward than training model is recommended). Currently, possible values are "linear" and "exponential". -- ``--normalization`` or ``-norm``: Apply normalization wrapper to observations during evaluation. If it isn't specified wrapper will not be applied. -- ``--logger`` or ``-log``: Apply Sinergym logger wrapper during evaluation. If it isn't specified wrapper will not be applied. -- ``--seed`` or ``-sd``: Seed for evaluation, random components in process will be able to be recreated. -- ``--remote_store`` or ``-sto``: Determine if sinergym output will be sent to a common resource (Bucket), else will be allocate in container or host memory only. -- ``--group_name`` or ``-group``: It specify to which MIG the host instance belongs, it is important if --auto-delete is activated. -- ``--auto_delete`` or ``-del``: Whether this parameter is specified, remote instance will be auto removed when its job has finished. - -This script loads the model. Once the model is loaded, it predicts the actions from the states during the agreed episodes. The information is collected and sent to a cloud storage if it has been specified, otherwise it is stored in local memory. + +- ``--model`` or ``-mod``: Trained model (zip file) you want to use to execute + the evaluation. This path can be a local path file into your computer (remote or host) + or a Google Cloud Storage resource (bucket like ``gs:///``). + +- ``--episodes`` or ``-ep``: Number of episodes you want to evaluate agent in simulation + (Depending on environment episode length can be different). + +- ``--algorithm`` or ``-alg``: Algorithm which model was trained (Currently, it is + available *PPO*, *A2C*, *DQN*, *DDPG* and *SAC*). + +- ``--reward`` or ``-rw``: Reward class you want to use for reward function (same reward + than training model is recommended). Currently, possible values are + "linear" and "exponential". + +- ``--normalization`` or ``-norm``: Apply normalization wrapper to observations during + evaluation. If it isn't specified wrapper will not be applied. + +- ``--logger`` or ``-log``: Apply Sinergym logger wrapper during evaluation. If it isn't + specified wrapper will not be applied. + +- ``--seed`` or ``-sd``: Seed for evaluation, random components in process will be able + to be recreated. + +- ``--remote_store`` or ``-sto``: Determine if sinergym output will be sent to a common resource + (Bucket), else will be allocate in container or host memory only. + +- ``--group_name`` or ``-group``: It specify to which MIG the host instance belongs, it is important + if --auto-delete is activated. + +- ``--auto_delete`` or ``-del``: Whether this parameter is specified, remote instance will be auto + removed when its job has finished. + +This script loads the model. Once the model is loaded, it predicts the actions from the +states during the agreed episodes. The information is collected and sent to a cloud storage +if it has been specified, otherwise it is stored in local memory. *********************** Remote Tensorboard log @@ -338,24 +500,40 @@ Remote Tensorboard log In ``--tensorboard`` parameter we have to specify a **local path** or a **Bucket path**. -If we specify a **local path**, tensorboard logs will be stored in remote containers memory. If you have specified ``--remote_store`` or ``--mlflow_store``, this logs will be sent to those remote storage when experiment finishes. -One of the strengths of Tensorboard is the ability to see the data in real time as the training is running. Thus, it is recommended to define in ``--tensorboard`` the **bucket path** directly in order to send that information -as the training is generating it (see `this issue `__ for more information). In our project we have *gs://experiments-storage/tensorboard_log* but you can have whatever you want. +If we specify a **local path**, tensorboard logs will be stored in remote containers memory. +If you have specified ``--remote_store`` or ``--mlflow_store``, this logs will be sent to +those remote storage when experiment finishes. +One of the strengths of Tensorboard is the ability to see the data in real time as the training +is running. Thus, it is recommended to define in ``--tensorboard`` the **bucket path** directly +in order to send that information +as the training is generating it (see +`this issue `__ +for more information). In our project we have *gs://experiments-storage/tensorboard_log* but you +can have whatever you want. -.. note:: If in ``--tensorboard`` you have specified a gs path, ``--remote_store`` or ``--mlflow_store`` parameters don't store tensorboard logs. +.. note:: If in ``--tensorboard`` you have specified a gs path, ``--remote_store`` + or ``--mlflow_store`` parameters don't store tensorboard logs. -.. warning:: Whether you have written a bucket path, don't write ``/`` at the end (*gs://experiments-storage/tensorboard_log/*), this causes that real-time remote storage doesn't work correctly. +.. warning:: Whether you have written a bucket path, don't write ``/`` at the end + (``gs://experiments-storage/tensorboard_log/``), this causes that real-time + remote storage doesn't work correctly. -.. warning:: In the case that gs URI isn't recognized. Maybe is due to your tensorboard installation hasn't got access your google account. Try `gcloud auth application-default login `__ command. +.. warning:: In the case that gs URI isn't recognized. Maybe is due to your tensorboard + installation hasn't got access your google account. Try + `gcloud auth application-default login `__ command. Visualize remote Tensorboard log in real-time ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ You have two options: + 1. Create a remote server with tensorboard service deployed. - 2. Initiate that service in your local computer, reading from the bucket log, and access to the visualization in *http://localhost:6006* -The second options is enough since we can read from bucket when we need directly and shut down local service when we finish. + 2. Initiate that service in your local computer, reading from the bucket log, + and access to the visualization in *http://localhost:6006* + +The second options is enough since we can read from bucket when we need directly +and shut down local service when we finish. .. code:: sh @@ -366,42 +544,64 @@ The second options is enough since we can read from bucket when we need directly Mlflow tracking server set up ****************************** -Mlflow tracking server can be set up into your google account in order to organize your own experiments (:ref:`Mlflow`). You can separate **back-end** (SQL database) from tracking server. -In this way, you can shut down or delete server instance without loose your experiments run data, since SQL is always up. Let's see how: +Mlflow tracking server can be set up into your google account in order to organize +your own experiments (:ref:`Mlflow`). You can separate **back-end** (SQL database) +from tracking server. +In this way, you can shut down or delete server instance without loose your experiments +run data, since SQL is always up. Let's see how: .. literalinclude:: ../../../mlflowbuild.sh :language: sh -This bash script defines all the process to configure this functionality automatically. (Once you execute it you don't have to use this script anymore). The arguments it needs are: -*PROJECT_ID*, *BUCKET_NAME*, *ZONE* and *DB_ROOT_PASSWORD*. +This bash script defines all the process to configure this functionality automatically. +(Once you execute it you don't have to use this script anymore). The arguments +it needs are: *PROJECT_ID*, *BUCKET_NAME*, *ZONE* and *DB_ROOT_PASSWORD*. This script do the next for you: 1. Creating Service account for mlflow service `[mlflow-tracking-sa]`. + 2. Creating Back-end artifact bucket. + 3. Creating SQL instance with root password specified in argument 4. + 4. Creating mlflow database inner SQL instance. + 5. Creating service account privileges to use Back-end `[roles/cloudsql.editor]` - 6. Generating an automatic script called **start_mlflow_tracking.sh** and sending to ``gs:///scripts/`` + + 6. Generating an automatic script called **start_mlflow_tracking.sh** and sending to + ``gs:///scripts/``. + 7. Deleting local **start_mlflow_tracking.sh** file. - 8. Creating static external IP for `mlflow-tracking-server` - 9. Deploying remote server `[mlflow-tracking-server]` -Step 8 is very important, this allows you to delete server instance and create again when you need it without redefining server IP in sinergym-template for remote container experiments. -Notice that server instance creation use service account for mlflow, with this configuration mlflow can read from SQL server. In :ref:`4. Create your VM or MIG` it is specified MLFLOW_TRACKING_URI container environment variable using that external static IP. + 8. Creating static external IP for ``mlflow-tracking-server``. + + 9. Deploying remote server ``[mlflow-tracking-server]``. + +Step 8 is very important, this allows you to delete server instance and create again when +you need it without redefining server IP in sinergym-template for remote container experiments. +Notice that server instance creation use service account for mlflow, with this configuration +mlflow can read from SQL server. In :ref:`4. Create your VM or MIG` it is specified +MLFLOW_TRACKING_URI container environment variable using that external static IP. -.. warning:: It is important execute this script before create sinergym-template instances in order to annotate `mlflow-server-ip`. +.. warning:: It is important execute this script before create sinergym-template instances in order + to annotate `mlflow-server-ip`. -.. note:: If you want to change any backend configuration, you can change any parameter of the script bellow. +.. note:: If you want to change any backend configuration, you can change any parameter of the + script bellow. -.. note:: Whether you have written ``--mlflow_store``, Sinergym outputs will be sent to mlflow server as artifacts. These artifacts will be stored in the same bucket where is allocated ``gs://`` +.. note:: Whether you have written ``--mlflow_store``, Sinergym outputs will be sent to mlflow server + as artifacts. These artifacts will be stored in the same bucket where is allocated + ``gs://``. ******************** Google Cloud Alerts ******************** -**Google Cloud Platform** include functionality in order to trigger some events and generate alerts in consequence. -Then, a trigger has been created in our gcloud project which aim to advertise when an experiment has finished. +**Google Cloud Platform** include functionality in order to trigger some events and generate +alerts in consequence. Then, a trigger has been created in our gcloud project which aim to +advertise when an experiment has finished. This alert can be captured in several ways (Slack, SMS, Email, etc). -If you want to do the same, please, check Google Cloud Alerts documentation `here `__. +If you want to do the same, please, check Google Cloud Alerts documentation +`here `__. diff --git a/docs/source/pages/github-actions.rst b/docs/source/pages/github-actions.rst index 1ca3a92b8e..924e4de52e 100644 --- a/docs/source/pages/github-actions.rst +++ b/docs/source/pages/github-actions.rst @@ -2,8 +2,10 @@ Github Actions ################ -This project is automatically processed using `Github Action `__ which allows building continuous integration and continuous deployment pipelines -for testing, releasing and deploying software without the use of third-party websites/platforms. +This project is automatically processed using `Github Action `__ +which allows building continuous integration and continuous deployment pipelines +for testing, releasing and deploying software without the use of third-party +websites/platforms. Currently, we have developed the next procedures for this project: @@ -11,22 +13,46 @@ Currently, we have developed the next procedures for this project: Pull Request ************* -- **Python Code format check**: Python code format is checked in every pull request following **Pep8** `standard `__ (Level 2 aggressive) and `isort `__ to sort imports. - If format is incorrect, a bot will comment in pull request advising that issue and notifying it will be correct merging with main. -- **Code type check**: We are using `pytype `__ in Sinergym module. This let dynamic types in Python like it is usual, but controlling input and output types in functions and methods. This workflow ignore `import-error` type using command `pytype -d import-error sinergym/`. - For example, **pytype** cannot include google cloud storage module, so this option specification is necessary. If some type error happens, the workflow show error until user fix it. -- **Documentation Checks**: This action checks whether source documentation has been modified in every pull-request. If source documentation has been updated, it will compile documentation with Sphinx and raise errors if exist. - This workflow checks **vocabulary spelling** too. If you have a mistake and sphinx finds a unknown word, this workflow will return an error. Writing documentation - about this topic is very possible that you want to use a word that is not in default dictionary. In that case, you have to add that word to `docs/source/spelling_wordlist.txt` (please, respect alphabetical order) and Sphinx-spelling will accept words allocated in the list. +- **Python Code format check**: Python code format is checked in every pull + request following **Pep8** `standard `__ + (Level 2 aggressive) and `isort `__ to sort imports. + If format is incorrect, a bot will comment in pull request advising that issue + and notifying it will be correct merging with main. + +- **Code type check**: We are using `pytype `__ in + *Sinergym* module. This let dynamic types in Python like it is usual, but controlling + input and output types in functions and methods. This workflow ignore `import-error` + type using command `pytype -d import-error sinergym/`. + For example, **pytype** cannot include google cloud storage module, so this option + specification is necessary. If some type error happens, the workflow show error until + user fix it. + +- **Documentation Checks**: This action checks whether source documentation has been + modified in every pull-request. If source documentation has been updated, it will + **compile** documentation with *Sphinx* and raise errors if exist. + This workflow checks **vocabulary spelling** too. If you have a mistake and sphinx + finds a unknown word, this workflow will return an error. Writing documentation + about this topic is very possible that you want to use a word that is not in default + dictionary. In that case, you have to add that word to `docs/source/spelling_wordlist.txt` + (please, respect alphabetical order) and Sphinx-spelling will accept words allocated + in the list. .. warning:: Sphinx Warning messages behave like errors for workflow status. .. note:: Sphinx Spelling works on code docstring too. -- **Testing**: There is another action which builds a remote container using *Dockerfile* and executes pytest inner. -- **Repository security**: There is a workflow which compare differences in workflows and tests from source to base. It execute that functionality only in forked repositories in order to prevent malicious software in workflow or ignore tests. Event is *pull_request_target*, this means workflow is checkout from base repository (our main branch) and it cannot be manipulate by third-parties. +- **Testing**: There is another action which builds a remote container using *Dockerfile* + and executes **Pytest** inner. -.. note:: These checks can be skipped in a specific commit writing `[ci skip]` string in commit message. For more information, see issue `#161 `__. +- **Repository security**: There is a workflow which compare differences in workflows + and tests from source to base. It execute that functionality only in forked + repositories in order to **prevent malicious software** in workflow or ignore tests. + Event is *pull_request_target*, this means workflow is checkout from base repository + (our main branch) and it cannot be manipulate by third-parties. + +.. note:: These checks can be skipped in a specific commit writing `[ci skip]` string + in commit message. For more information, see issue + `#161 `__. ************************************ Push main (or merge a pull request) @@ -34,17 +60,41 @@ Push main (or merge a pull request) This workflows will be executed in sequential order: -- **Apply format**: A bot generates a commit in main branch applying format changes when it is necessary (autopep8 2 level aggressive and/or `isort` module). -- **Update Documentation build to GitHub pages**: A bot generates a commit in **main** branch applying new documentation build when it is necessary (spelling check included here too) in a folder called *docs/compilation*. Repository ignore default folder name *build* in order to compile locally to check changes. -- **Update our Docker Hub repository**: This job builds container with all extra requires and it is pushed to our `Docker Hub repository `__ using *latest* tag automatically. It needs format and documentation jobs finish for possible changes. +- **Apply format**: A bot generates a commit in main branch applying + format changes when it is necessary (**autopep8** 2 level aggressive + and/or **isort** module). + +- **Update Documentation build to GitHub pages**: A bot generates a commit + in **main** branch applying new documentation build when it is necessary + (spelling check included here too) in a folder called **docs/compilation**. + Repository ignore default folder name *build* in order to compile locally + to check changes. + +- **Update our Docker Hub repository**: This job builds container with all extra + requires and it is pushed to our + `Docker Hub repository `__ + using *latest* tag automatically. It needs format and documentation jobs finish + for possible changes. ******************************** New release created or modified ******************************** -- When a **release** is *published* or *edited* manually in the repository, there is an action which catches release tag version and uses it to build a container and upload/update on Docker Hub with that tag version. -- At the same time, another job will update the **PyPi** Sinergym repository with its current version tag. +- When a **release** is *published* or *edited* manually in the repository, + there is an action which catches release tag version and uses it to build + a container and upload/update on Docker Hub with that tag version. + +- At the same time, another job will update the **PyPi** *Sinergym* repository + with its current version tag. + +.. note:: See `.github/workflows YML files + `__ + to see code used. -.. note:: See `.github/workflows YML files `__ to see code used. +.. note:: Whether you have a forked repository from *Sinergym*, we recommend you to + **enable Github Action in your project** in order to take advantage of + this functionality in your developments. -.. note:: Whether you have a forked repository from Sinergym, we recommend you to **enable Github Action in your project** in order to take advantage of this functionality in your developments. \ No newline at end of file +.. note:: Currently, the workflows explained above upload two containers. A + container with **all extra packages** and a container with **minimal** + installation. \ No newline at end of file diff --git a/docs/source/pages/installation.rst b/docs/source/pages/installation.rst index 47878a6af6..ba36999749 100644 --- a/docs/source/pages/installation.rst +++ b/docs/source/pages/installation.rst @@ -9,34 +9,44 @@ Docker container We include a **Dockerfile** for installing all dependencies and setting up the image for running *Sinergym*. -By default, Dockerfile will do `pip install -e .[extras]`, if you want to install a different setup, you will have to do in root repository: +By default, *Dockerfile* will do ``pip install -e .[extras]``, if you want +to install a different setup, you will have to do in **root repository**: .. code:: sh $ docker build -t --build-arg SINERGYM_EXTRAS=[] . -For example, if you want a container with only documentation libraries and testing: +For example, if you want a container with only documentation libraries +and testing: .. code:: sh $ docker build -t example1/sinergym:latest --build-arg SINERGYM_EXTRAS=[doc,test] . -On the other hand, if you don't want any extra library, it's necessary to write an empty value like this: +On the other hand, if you don't want any extra library, it's necessary +to write an empty value like this: .. code:: sh $ docker build -t example1/sinergym:latest --build-arg SINERGYM_EXTRAS= . -.. note:: You can install directly our container from `Docker Hub repository `__, all releases of this project are there. +.. note:: You can install directly our container from + `Docker Hub repository `__, + all releases of this project are there. -.. note:: If you use `Visual Studio Code `__, by simply opening the root directory and clicking on the pop-up button *Reopen in container*, all the dependencies will be installed automatically and you will be able to run *Sinergym* in an isolated environment. - For more information about how to use this functionality, check `VSCode Containers extension documentation `__. +.. note:: If you use `Visual Studio Code `__, + by simply opening the root directory and clicking on the pop-up button + *Reopen in container*, all the dependencies will be installed automatically + and you will be able to run *Sinergym* in an isolated environment. + For more information about how to use this functionality, + check `VSCode Containers extension documentation `__. ******************* Manual installation ******************* -To install *Sinergym* manually instead of through the container (recommended), follow these steps: +To install *Sinergym* manually instead of through the container (**recommended**), +follow these steps: 1. Configure Python environment ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -57,7 +67,8 @@ To install *Sinergym* manually instead of through the container (recommended), f $ source env_sinergym/bin/activate $ pip install -e .[extras] -There are other alternatives like **conda environments** (recommended). Conda is very comfortable to use and we have a file to configure it automatically: +There are other alternatives like **conda environments** (*recommended*). +*Conda* is very comfortable to use and we have a file to configure it automatically: .. code:: sh @@ -65,13 +76,15 @@ There are other alternatives like **conda environments** (recommended). Conda is $ conda env create -f python_environment.yml $ conda activate sinergym -Now, we have a correct python version with required modules to run sinergym. Let's continue with the rest of the programs that are needed outside of Python to run the simulations: +Now, we have a correct python version with required modules to run *Sinergym*. +Let's continue with the rest of the programs that are needed outside of Python +to run the simulations: 2. Install EnergyPlus 9.5.0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Install EnergyPlus. Currently it has been update compatibility to 9.5.0 and it has -been tested, but code may also work with other versions. Sinergym ensure this support: +Install *EnergyPlus*. Currently it has been update compatibility to ``9.5.0`` and it has +been tested, but code may also work with other versions. *Sinergym* ensure this support: +------------------+--------------------+ | Sinergym Version | EnergyPlus version | @@ -84,7 +97,7 @@ been tested, but code may also work with other versions. Sinergym ensure this su Other combination may works, but they don't have been tested. Follow the instructions `here `__ and -install it for Linux (only Ubuntu is supported). Choose any location +install it for Linux (only **Ubuntu** is supported by us). Choose any location to install the software. Once installed, a folder called ``Energyplus-9-5-0`` should appear in the selected location. @@ -93,7 +106,7 @@ to install the software. Once installed, a folder called Follow the instructions `here `__ for -installing BCVTB software. Another option is to copy the ``bcvtb`` +installing *BCVTB software*. Another option is to copy the ``bcvtb`` folder from `this repository `__. @@ -101,33 +114,42 @@ repository ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Two environment variables must be set: ``EPLUS_PATH`` and -``BCVTB_PATH``, with the locations where EnergyPlus and BCVTB are +``BCVTB_PATH``, with the locations where *EnergyPlus* and *BCVTB* are installed respectively. *********************** About Sinergym package *********************** -As we have told you in section :ref:`Manual installation`, Python environment can be set up using *python_environment.yml* with *conda*. -However, we can make an installation using the Github repository itself: +As we have told you in section :ref:`Manual installation`, Python environment +can be set up using ``python_environment.yml`` with *conda*. This will install +the virtual environment with Python version required and all packages used +*all-in-one*. +However, we can make an installation using the Github repository in a python +environment directly, like we have shown with *virtualenv*: .. code:: sh + $ source env_sinergym/bin/activate $ cd sinergym $ pip install -e . Extra libraries can be installed by typing ``pip install -e .[extras]``. *extras* include all optional libraries which have been considered in this project such as testing, visualization, Deep Reinforcement Learning, monitoring , etc. -It's possible to select a subset of these libraries instead of 'extras' tag in which we select all optional libraries, for example: +It's possible to select a subset of these libraries instead of 'extras' tag in which +we select all optional libraries, for example: .. code:: sh + $ cd sinergym $ pip install -e .[test,doc] -In order to check all our tag list, visit `setup.py `__ in Sinergym root repository. In any case, they are not a requirement of the package. +In order to check all our tag list, visit `setup.py `__ +in *Sinergym* root repository. In any case, they are not a requirement of the package. -You can also install from `oficial pypi repository `__ with last stable version by default: +You can also install from `oficial pypi repository `__ +with last stable version by default: .. code:: sh @@ -137,18 +159,20 @@ You can also install from `oficial pypi repository `__ will do that job (see our documentation for more information). +Anyway, every time *Sinergym* repository is updated, the tests will run automatically in a remote container +using the Dockerfile to build it. `Github Action `__ will do that job +(see :ref:`Github Actions` section). **************** Cloud Computing **************** -You can run your experiments in the Cloud too. We are using `Google Cloud `__ in order to make it possible. Our team aim to set up -an account in which execute our Sinergym container with **remote storage** and **mlflow tracking**. -For more detail about installation and getting Google Cloud SDK ready to run your experiments, visit our section :ref:`Preparing Google Cloud`. \ No newline at end of file +You can run your experiments in the Cloud too. We are using `Google Cloud `__ +in order to make it possible. Our team aim to set up an account in which execute our *Sinergym* container +with **remote storage** and **mlflow tracking**. +For more detail about installation and getting Google Cloud SDK ready to run your experiments, +visit our section :ref:`Preparing Google Cloud`. \ No newline at end of file diff --git a/docs/source/pages/introduction.rst b/docs/source/pages/introduction.rst index b1ab4cf40a..78b97cb35b 100644 --- a/docs/source/pages/introduction.rst +++ b/docs/source/pages/introduction.rst @@ -1,7 +1,7 @@ .. seealso:: This is a project based on Zhiang Zhang and Khee Poh Lam `Gym-Eplus `__. -The goal of *sinergym* is to create an environment following OpenAI -Gym interface for wrapping simulation engines for building control using +The goal of *sinergym* is to create an environment following *OpenAI +Gym* interface for wrapping simulation engines (*Energyplus*) for building control using **deep reinforcement learning**. .. image:: /_static/operation_diagram.jpg @@ -9,46 +9,79 @@ Gym interface for wrapping simulation engines for building control using :alt: Sinergym diagram :align: center -The main functionalities of *sinergym* are the following: +| + +The main functionalities of *Sinergym* are the following: -- **Benchmark environments**. Similarly to Atari or Mujoco environments - for RL community, we are designing a set of environments for - benchmarking and testing deep RL algorithms. These environments may - include different buildings, weathers or action/observation spaces. -- **Develop different experimental settings**. We aim to provide a - package that allows to modify experimental settings in an easy - manner. For example, several reward functions or observation - variables may be defined. - **Include different simulation engines**. Communication between Python and `EnergyPlus `__ is established - using `BCVTB `__. + using `BCVTB `__ middleware. Since this tool allows for interacting with several simulation engines, more of them (e.g. `OpenModelica `__) could be included in the backend while maintaining the Gym API. -- **Building Models configuration automatically**: Building models will be - adapted to specification of each simulation. For example, *Designdays* and - *Location* from IDF files will be adapted to weather file specified in - Sinergym simulator backend without any intervention by the user. The *variables.cfg* - for external interface with BCVTB is obtained automatically depending on - action and observation space/variables defined. -- **Extra configuration facilities**: Our team aim to provide extra parameters - in order to amplify the context space for the experiments with this tool. - Sinergym will modify building model automatically based on parameters set. - For example: People occupant, timesteps per simulation hour, observation - and action spaces, an action definition in order to modify IDF structure - automatically, etc. + +- **Benchmark environments**. Similarly to *Atari* or *Mujoco* environments + for RL community, we are designing a set of environments for + benchmarking and testing deep RL algorithms. These environments may + include different buildings, weathers, action/observation spaces, function rewards, etc. + +- **Customizable environments**. We aim to provide a + package that allows to modify experimental settings in an easy + manner. The user can create his own environments defining his own + building model, weather, reward, observation/action space and variables, environment name, etc. + The user can also use these pre-configured environments available in *Sinergym* + and change some aspect of it (for example, the weather) in such + a way that he does not have to make an entire definition of the + environment and can start from one pre-designed by us. + Some parameters directly associated with the simulator can be set as **extra configuration** + as well, such as people occupant, time-steps per simulation hour, run-period, etc. + +- **Customizable components**: *Sinergym* is easily scalable by third parties. + Following the structure of the implemented classes, new custom components + can be created for new environments such as function rewards, wrappers, + controllers, etc. + +- **Automatic Building Model adaptation to user changes**: Building models (*IDF*) will be + adapted to specification of each simulation by the user. For example, ``Designdays`` and + ``Location`` components from *IDF* files will be adapted to weather file (*EPW*) specified in + *Sinergym* simulator backend without any intervention by the user (only the environment definition). + *BCVTB middleware* external interface in *IDF* model and *variables.cfg* file is generated when + simulation starts by *Sinergym*, this definition depends on action and observation space and variables defined. + In short, *Sinergym* automates the whole process of model adaptation so that the user + only has to define what he wants for his environment. + +- **Automatic external interface integration for actions**. As far as building model (*IDF*) adaptation + is concerned, it is not enough to set up an external interface and set user-specified + variable names. It is also necessary to make certain adjustments to the building components to be + controlled, so that they use the external variables defined by the user instead of the default + controllers implicitly provided by the building model. To do this, *Sinergym* provides a functionality + that can adapt actuators to the desired building zones by providing a specification by the user. + The building model will be manipulated based on this information automatically. In other words, + if the components to be controlled are directly supported by *Sinergym*, the building model can be modified + accordingly to be controlled, otherwise the user will have to modify the *IDF* file manually. More actuator + types will be directly supported by *Sinergym* in the future. + - **Stable Baseline 3 Integration**. Some functionalities like callbacks - have been developed by our team in order to test easily these environments - with deep reinforcement learning algorithms. + have been customized by our team in order to test easily these environments + with deep reinforcement learning algorithms. + This tool can be used with any other DRL library that supports the *OpenAI gym* interface as well. + - **Google Cloud Integration**. Whether you have a Google Cloud account and you want to - use your infrastructure with Sinergym, we tell you some details about how doing it. + use your infrastructure with *Sinergym*, we tell you some details about how doing it. + - **Mlflow tracking server**. `Mlflow `__ is an open source platform for the machine learning lifecycle. This can be used with Google Cloud remote server (if you have Google Cloud account) or using local store. This will help you to manage and store your runs and artifacts generated in an orderly manner. -- **Data Visualization**. Using Sinergym logger or Tensorboard server to visualize training information + +- **Data Visualization**. Using *Sinergym* logger or Tensorboard server to visualize training and evaluation information in real-time. + +- **Notebooks examples**. *Sinergym* develops code in notebook format with the purpose of offering use cases to + the users in order to help them become familiar with the tool. They are constantly updated, along with the updates + and improvements of the tool itself. + - Many more! -.. note:: *This is a work in progress project. Stay tuned for upcoming releases!* \ No newline at end of file +.. note:: *This is a work in progress project. Stay tuned for upcoming releases!* diff --git a/docs/source/pages/modules/sinergym.utils.common.rst b/docs/source/pages/modules/sinergym.utils.common.rst index 5118ab9345..bc091ea1c4 100644 --- a/docs/source/pages/modules/sinergym.utils.common.rst +++ b/docs/source/pages/modules/sinergym.utils.common.rst @@ -1,4 +1,4 @@ -sinergym.utils.common +sinergym.utils.common ===================== .. automodule:: sinergym.utils.common @@ -23,6 +23,7 @@ sinergym.utils.common parse_variables prepare_batch_from_records ranges_getter + to_idf unwrap_wrapper diff --git a/docs/source/pages/modules/sinergym.utils.common.to_idf.rst b/docs/source/pages/modules/sinergym.utils.common.to_idf.rst new file mode 100644 index 0000000000..3b5af5ed29 --- /dev/null +++ b/docs/source/pages/modules/sinergym.utils.common.to_idf.rst @@ -0,0 +1,6 @@ +sinergym.utils.common.to\_idf +============================= + +.. currentmodule:: sinergym.utils.common + +.. autofunction:: to_idf \ No newline at end of file diff --git a/docs/source/pages/modules/sinergym.utils.config.Config.rst b/docs/source/pages/modules/sinergym.utils.config.Config.rst index 98782dbcf0..42463eb48e 100644 --- a/docs/source/pages/modules/sinergym.utils.config.Config.rst +++ b/docs/source/pages/modules/sinergym.utils.config.Config.rst @@ -16,6 +16,7 @@ .. autosummary:: ~Config.__init__ + ~Config.adapt_idf_to_action_definition ~Config.adapt_idf_to_epw ~Config.adapt_variables_to_cfg_and_idf ~Config.apply_extra_conf @@ -24,6 +25,7 @@ ~Config.save_variables_cfg ~Config.set_episode_working_dir ~Config.set_experiment_working_dir + ~Config.set_external_interface diff --git a/docs/source/pages/output.rst b/docs/source/pages/output.rst index 94b1860d25..e2817af494 100644 --- a/docs/source/pages/output.rst +++ b/docs/source/pages/output.rst @@ -2,7 +2,9 @@ Output format ############### -When a simulation is running, this generates a directory called ``Eplus-env--res``. The content of this directory is the result of the simulation and we have: +When a simulation is running, this generates a directory called +``Eplus-env--res``. The content of +this directory is the result of the simulation and we have: :: @@ -22,37 +24,65 @@ When a simulation is running, this generates a directory called ``Eplus-env-** records the results of each episode in simulation. The number of these directories depends on the number of episodes. +* **Eplus-env-sub_run** records the results of each episode in + simulation. The number of these directories depends on the number of episodes + and *maximum episode data value* + (see :ref:`Maximum Episode Data Stored in Sinergym Output`). + * Within these directories, you have always the same structure: - * A copy of **variables.cfg** and **environment.idf** which are being used during simulation. **Environment.idf** does not have to be the same as the original hosted in the repository. Since the simulation can be modified to suit the specific weather or apply extra user-defined settings when building the gym environment. - * A copy of **Weather.epw** appears only when the weather change for one episode to another (using variability, for example). If weather does not change, original repository *.epw* will be used in each episode. - * A copy of **socket.cfg** and **utilSocket.idf** which are being used in order to establish communication interface with Energyplus during simulation. - * **monitor.csv**: This records all interactions Agent-Environment during the episode timestep by timestep, the format is: *timestep, observation_values, action_values, simulation_time (seconds), reward, done*. This file only exists when environment has been wrapped with **Logger** (see :ref:`Wrappers` for more information). - * **monitor_normalized.csv**: This file is only generated when environment is wrapped with **logger and normalization** (see :ref:`Wrappers`). The structure is the same than **monitor.csv** but ``observation_values`` are normalized. - * **output/**: This directory has **EnergyPlus environment output**. -* **progress.csv**: This file has information about general simulation results. There is a row per episode and it records most important data. Currently, the format is: *episode_num,cumulative_reward,mean_reward,cumulative_power_consumption, - mean_power_consumption,cumulative_comfort_penalty,mean_comfort_penalty, - cumulative_power_penalty,mean_power_penalty,comfort_violation (%),length(timesteps), - time_elapsed(seconds)*. This file only exists when environment has been wrapped with **Logger** (see :ref:`Wrappers` for more information). - -.. note:: For more information about specific EnergyPlus output, visit `EnergyPlus documentation `__. + + * A copy of **variables.cfg** and **environment.idf** which are being used during + simulation. **Environment.idf** does not have to be the same as the original + hosted in the repository. Since the simulation can be modified to suit the + specific weather or apply extra user-defined settings when building the + gym environment. + + * A copy of **Weather.epw** appears only when the weather change for one + episode to another (using variability, for example). If weather does not + change, original repository *.epw* will be used in each episode. + + * A copy of **socket.cfg** and **utilSocket.log** which are being used in + order to establish communication interface with *Energyplus* during simulation. + + * **monitor.csv**: This records all interactions Agent-Environment during + the episode timestep by timestep. This file only exists + when environment has been wrapped with **Logger** (see :ref:`Wrappers` for + more information). + + * **monitor_normalized.csv**: This file is only generated when environment is + wrapped with **logger and normalization** (see :ref:`Wrappers`). The structure + is the same than **monitor.csv** but ``observation_values`` are normalized. + + * **output/**: This directory has **EnergyPlus simulation output**. + If you want to know more about this files, visit + `Energyplus documentation `__. + +* **progress.csv**: This file has information about general simulation results. + There is a **row per episode** and it records most important data such as mean + power consumption or , mean comfort penalty, for example. This file only + exists when environment has been wrapped with + **Logger** (see :ref:`Wrappers` for more information). **************** Logger **************** -The files **monitor.csv**, **monitor_normalized.csv** and **progress.csv** belong to **Sinergym logger** which is a wrapper for the environment (see :ref:`Wrappers`). This logger has the responsibility of recording +The files **monitor.csv**, **monitor_normalized.csv** and **progress.csv** +belong to **Sinergym logger** which is a wrapper for the environment. +This logger has the responsibility of recording all the interactions that are carried out in a simulation, -regardless of the training technique which may be being used or any other external factor. - -Recording is managed by a instance of the class ``CSVLogger`` which is present as a environment attribute and is called in each timestep and in the end of a episode: +regardless of the training technique which may be being used or any other +external factor. -.. literalinclude:: ../../../sinergym/utils/logger.py - :language: python - :pyobject: CSVLogger +Recording is managed by an instance of the class ``CSVLogger`` which is +present as a wrapper attribute and is called in each timestep and +in the end of a episode: -.. note:: Normalized observation methods are only used when environment is wrapped with normalization previously (see :ref:`Wrappers`). +.. note:: Normalized observation methods are only used when environment is + wrapped with normalization previously. -.. note:: Note that you can activate and deactivate logger from environment when you want it, using methods activate and deactivate, so you don't need to unwrap environment. +.. note:: Note that you can activate and deactivate logger from environment + when you want it, using methods activate and deactivate, so + you don't need to unwrap environment. diff --git a/docs/source/pages/rewards.rst b/docs/source/pages/rewards.rst index 76bd5ef2e6..c92f1488f7 100644 --- a/docs/source/pages/rewards.rst +++ b/docs/source/pages/rewards.rst @@ -2,24 +2,68 @@ Rewards ####### -Defining a reward function is one of the most important things in reinforcement learning. Consequently, Sinergym allows you to define your own reward functions or use +Defining a reward function is one of the most important things in reinforcement learning. +Consequently, *Sinergym* allows you to define your own reward functions or use the ones we have already implemented (see code below). -- ``LinearReward`` implements a linear reward function, where both energy consumption and thermal discomfort are normalized and add together with different weights. The - discomfort is calculated as the absolute difference between current temperature and comfort range (so if the temperature is inside that range, the discomfort would be 0). - This is a typically used function where thermal satisfaction of people inside the controlled building has been taken into account. +- ``LinearReward`` implements a **linear reward** function, where both energy consumption and + thermal discomfort are normalized and add together with different weights. + The discomfort is calculated as the absolute difference between current temperature and + comfort range (so if the temperature is inside that range, the discomfort would be 0). + This is a typically used function where thermal satisfaction of people inside the + controlled building has been taken into account. -- ``ExpReward`` is very similar, but in this case the discomfort is calculated using the exponential difference between current temperature and comfort ranges. That means - that the penalty for the discomfort is higher is we are far from the target temperatures. +- ``ExpReward`` is very similar, but in this case the discomfort is calculated + using the **exponential difference** between current temperature and comfort ranges. + That means that the increase penalty for the discomfort is higher if we are far from + the target temperatures. -- ``HourlyLinearReward`` is a slight modification of the linear function, but the weight given to the discomfort depends on the hour of the day. If the current hour of the - simulation is in working hours (by default, from 9 AM to 7 PM) both comfort and energy consumption weights equally, but outside those hours only energy is considered. +- ``HourlyLinearReward`` is a slight modification of the linear function, but + the weight given to the discomfort depends on the **hour of the day**. If the current + hour of the simulation is in working hours (by default, from 9 AM to 7 PM) both + comfort and energy consumption weights equally, but outside those hours only energy + is considered. -These rewards are always negative, meaning that perfect behavior has a cumulative reward of 0. Notice also that there are two temperature comfort ranges defined, one for the -summer period and other for the winter period. The weights of each term in the reward allow to adjust the importance of each aspect when evaluating the environments. +These rewards are **always negative**, meaning that perfect behavior has a cumulative +reward of 0. Notice also that there are two temperature comfort ranges defined, +one for the summer period and other for the winter period. The weights of each +term in the reward allow to adjust the importance of each aspect when evaluating +the environments. -By default, all environments use ``LinearReward`` with default parameters. But you can change this configuration using ``gym.make()`` as follows: +The reward functions have a series of **parameters** in their constructor whose values +may depend on the building we are using or other characteristics. For example, the +internal temperature or energy variables used to calculate penalties may have a +different name in different buildings. + +The main parameters that it is considered in a function reward will be the next: + +- **temperature_variable**: This field can be an *str* (only a unique zone temperature) + or a *list* (with several zone temperatures). + +- **energy_variable**: Name of the observation variable where energy consumption is + reflected. + +- **range_comfort_winter**: Temperature comfort range for cold season. Depends on + environment you are using. + +- **range_comfort_summer**: Temperature comfort range for hot season. Depends on + environment you are using. + +- **energy_weight**: Weight given to the energy term. Defaults to 0.5. Comfort weight + will have 1-*energy_weight*. + +- **lambda_energy**: Constant for removing dimensions from power(1/W). Defaults to 1e-4. + +- **lambda_temperature**: Constant for removing dimensions from temperature(1/C). + Defaults to 1.0. + +.. note:: These parameters are usually common to any reward function. + However, they may have different parameters depending on the + one being used. + +By default, all environments use ``LinearReward`` with default parameters. +But you can change this configuration using ``gym.make()`` as follows: .. code:: python @@ -32,11 +76,24 @@ By default, all environments use ``LinearReward`` with default parameters. But y 'range_comfort_summer': (23.0, 26.0), 'energy_weight': 0.1}) -.. warning:: When specifying a different reward with `gym.make` than the default environment ID, it is very important to set the `reward_kwargs` that are required and therefore do not have a default value. In the rewards we have defined it is required: **temperature_variable(s)**, **energy_variable**, **range_comfort_winter**, **range_comfort_summer**. The rest of them have default values and it is not necessary to specify. - - -It is also pretty simple to define your own classes. For example, imagine you want a reward signal which returns always -1 (however we do not recommend using it for training agents :)). -The only requirement is that the calculation is performed using ``__call__`` method, which returns the reward and a dictionary with extra information. The below code implements this. +.. warning:: When specifying a different reward with `gym.make` than the + default environment ID, it is very important to set the `reward_kwargs` + that are required and therefore do not have a default value. + In the rewards we have defined it is required: + **temperature_variable(s)**, **energy_variable**, + **range_comfort_winter**, **range_comfort_summer**. + The rest of them have default values and it is not necessary to specify. + +*************** +Custom Rewards +*************** + +It is also pretty simple to define your **own classes**. For example, imagine you want +a reward signal which returns always -1 (however we do not recommend using it +for training agents). +The only requirement is that the calculation is performed using ``__call__`` +method, which returns the reward and a dictionary with extra information. +The below code implements this. .. code:: python @@ -52,8 +109,4 @@ The only requirement is that the calculation is performed using ``__call__`` met env = gym.make('Eplus-discrete-stochastic-mixed-v1', reward=CustomReward) -More reward functions will be included in the future, so stay tuned! - - -.. literalinclude:: ../../../sinergym/utils/rewards.py - :language: python +*More reward functions will be included in the future, so stay tuned!* diff --git a/docs/source/pages/tests.rst b/docs/source/pages/tests.rst index ff2d83a48d..882a606071 100644 --- a/docs/source/pages/tests.rst +++ b/docs/source/pages/tests.rst @@ -2,23 +2,30 @@ Tests ############ -This project is automatically supervised using tests developed specifically for it. If you want to check sinergym has been installed successfully, run next command: +This project is **automatically supervised** using tests developed specifically for it. +If you want to check *Sinergym* has been installed successfully, run next command: .. code:: sh $ pytest tests/ -vv -Anyway, every time sinergym repository is updated, the tests will run automatically in a remote container using the Dockerfile to build it. `Github Action `__ will do that job. +Anyway, every time *Sinergym* repository is updated, the tests will run automatically +in a remote container using the Dockerfile to build it. +`Github Action `__ will do that job. -.. note:: See `.github/workflows YML files `__ and :ref:`Github Actions` section for more information. +.. note:: See `.github/workflows YML files `__ + and :ref:`Github Actions` section for more information. -These tests running under `pytest `__ framework which makes it easy to write small tests, yet scales to support complex functional testing for applications and libraries. +These tests running under `pytest `__ +framework which makes it easy to write small tests, yet scales to support +complex functional testing for applications and libraries. **************** Install Pytest **************** -This project has already established this dependency if you have installed *extras* libraries or *test* library specifically. However, to install it independently: +This project has already established this dependency if you have installed *extras* +libraries or *test* library specifically. However, to install it independently: .. code:: sh @@ -36,7 +43,8 @@ In order to run current tests: $ pytest tests/ -vv -This runs all tests within tests/ directory. If you want verbose use `-v` or `-vv` option. To run an unique module tests, for example: +This runs all tests within ``tests/`` directory. If you want verbose use ``-v`` or ``-vv`` +option. To run an unique module tests, for example: .. code:: sh @@ -47,19 +55,54 @@ This runs all tests within tests/ directory. If you want verbose use `-v` or `-v Create new tests **************** -These tests have been created in `sinergym/tests `__ directory, they are organized by different modules: +These tests have been created in +`sinergym/tests `__ +directory, they are organized by different modules: -- **test_common.py**: Tests for `sinergym/sinergym/utils/common.py `__. Here will be all tests that check Sinergym common utils functionalities. -- **test_reward.py**: Tests for `sinergym/sinergym/utils/rewards.py `__. Here will be all tests that check implementation(s) of reward function(s) applicable to sinergym environments. -- **test_wrapper.py**: Tests for `sinergym/sinergym/utils/wrappers.py `__. Here will be all tests that check wrappers to normalize Sinergym default environment observations. -- **test_simulator.py**: Tests for `sinergym/sinergym/simulators/\* `__. Here will be all tests that check low level Sinergym simulator and communication interface. -- **test_config.py**: Tests for `sinergym/sinergym/utils/config.py `__. Here will be all tests that check python building model, weather, directories tree for executions and extra configuration set up in simulator. -- **test_env.py**: Tests for `sinergym/sinergym/envs/\* `__. Here will be all tests that check Sinergym simulation environments based on OpenAI Gym. -- **test_controller.py**: Tests for `sinergym/sinergym/utils/controllers.py `__. Here will be all tests that check agent controller like Rule-Based-Controller for example. -- **test_config.py**: Tests for `sinergym/sinergym/utils/config.py `__. Here will be all tests that check simulator configuration (IDF and EPW Python models and extra configuration functionality). -- **test_stable_baselines.py**: Tests for `Stable Baselines 3 `__. Here will be all tests that check Sinergym simulation environments can be used correctly with Stable Baselines 3 algorithms. +- **test_common.py**: Tests for + `sinergym/sinergym/utils/common.py `__. + Here will be all tests that check *Sinergym* common utils functionalities. +- **test_reward.py**: Tests for + `sinergym/sinergym/utils/rewards.py `__. + Here will be all tests that check implementation(s) of reward function(s) applicable to sinergym environments. -If you want to make new tests, you can append to this modules or create a new one if the conceptual context is different. +- **test_wrapper.py**: Tests for + `sinergym/sinergym/utils/wrappers.py `__. + Here will be all tests that check wrappers to normalize Sinergym default environment observations. -.. note:: For more information about Sinergym tests, visit our `repository README `__. \ No newline at end of file +- **test_simulator.py**: Tests for + `sinergym/sinergym/simulators/\* `__. + Here will be all tests that check low level *Sinergym* simulator and communication interface. + +- **test_config.py**: Tests for + `sinergym/sinergym/utils/config.py `__. + Here will be all tests that check python building model, weather, directories tree for executions and extra + configuration set up in simulator. + +- **test_env.py**: Tests for + `sinergym/sinergym/envs/\* `__. + Here will be all tests that check Sinergym simulation environments based on OpenAI Gym. + +- **test_controller.py**: Tests for + `sinergym/sinergym/utils/controllers.py `__. + Here will be all tests that check agent controller like Rule-Based-Controller for example. + +- **test_config.py**: Tests for + `sinergym/sinergym/utils/config.py `__. + Here will be all tests that check simulator configuration (IDF and EPW Python models and + extra configuration functionality). + +- **test_stable_baselines.py**: Tests for + `Stable Baselines 3 `__. + Here will be all tests that check Sinergym simulation environments + can be used correctly with Stable Baselines 3 algorithms. + If Stable Baselines 3 package is not installed, these tests + will be ignored by *Sinergym*. + + +If you want to **make new tests**, you can append to this modules or +create a new one if the conceptual context is different. + +.. note:: For more information about *Sinergym* tests, visit our + `repository README `__. \ No newline at end of file diff --git a/docs/source/pages/usage-example.rst b/docs/source/pages/usage-example.rst index 802b926617..5c3de60d48 100644 --- a/docs/source/pages/usage-example.rst +++ b/docs/source/pages/usage-example.rst @@ -88,15 +88,9 @@ By default, the ID's of our environments do not include any wrapper, but we can import numpy as np import sinergym - from sinergym.utils.rewards import LinearReward, ExpReward from sinergym.utils.wrappers import LoggerWrapper, NormalizeObservation - env = gym.make('Eplus-5Zone-hot-continuous-v1', reward=ExpReward, reward_kwargs={ - 'temperature_variable': 'Zone Air Temperature (SPACE1-1)', - 'energy_variable': 'Facility Total HVAC Electricity Demand Rate (Whole Building)', - 'range_comfort_winter': (20.0, 23.5), - 'range_comfort_summer': (23.0, 26.0), - 'energy_weight': 0.1}) + env = gym.make('Eplus-5Zone-hot-continuous-v1') env = NormalizeObservation(env) env = LoggerWrapper(env) ... @@ -137,18 +131,9 @@ You can replace the random actions we have used in the previous examples with on import numpy as np import sinergym - from sinergym.utils.rewards import LinearReward, ExpReward - from sinergym.utils.wrappers import LoggerWrapper, NormalizeObservation from sinergym.utils.controllers import RBC5Zone - env = gym.make('Eplus-5Zone-hot-continuous-v1', reward=ExpReward , reward_kwargs={ - 'temperature_variable': 'Zone Air Temperature (SPACE1-1)', - 'energy_variable': 'Facility Total HVAC Electricity Demand Rate (Whole Building)', - 'range_comfort_winter': (20.0, 23.5), - 'range_comfort_summer': (23.0, 26.0), - 'energy_weight': 0.1}) - env = NormalizeObservation(env) - env = LoggerWrapper(env) + env = gym.make('Eplus-5Zone-hot-continuous-v1') agent = RBC5Zone(env) @@ -176,7 +161,7 @@ You can replace the random actions we have used in the previous examples with on .. note:: You can also use our rule-based controller for Datacenter called **RBCDatacenter** if the environment is of that type or a random agent called **RandomController** in every environment. ****************************************************** -Overwriting some default values of the environments. +Overwriting some default values of the environments ****************************************************** In the same way that we can change the default reward function, as we have done in the second example, @@ -192,26 +177,15 @@ the name of the environment or the variability in stochastic environments: import numpy as np import sinergym - from sinergym.utils.rewards import LinearReward, ExpReward - from sinergym.utils.wrappers import LoggerWrapper, NormalizeObservation - from sinergym.utils.controllers import RBCDatacenter + from sinergym.utils.controllers import RBCDatacenter env = gym.make('Eplus-datacenter-cool-continuous-stochastic-v1', - reward=ExpReward, reward_kwargs={ - 'temperature_variable': 'Zone Air Temperature (SPACE1-1)', - 'energy_variable': 'Facility Total HVAC Electricity Demand Rate (Whole Building)', - 'range_comfort_winter': (20.0, 23.5), - 'range_comfort_summer': (23.0, 26.0), - 'energy_weight': 0.1}, weather_file='ESP_Granada.084190_SWEC.epw', weather_variability=(1.0,0.0,0.001), env_name='new_env_name', act_repeat=4, max_ep_data_store_num = 20) - env = NormalizeObservation(env) - env = LoggerWrapper(env) - agent = RBCDatacenter(env) for i in range(1): @@ -235,13 +209,176 @@ the name of the environment or the variability in stochastic environments: sum(rewards)) env.close() +******************************************* +Overwriting observation and action spaces +******************************************* + +By default, the IDs of the predefined environments in *Sinergym* already have a space of actions and observations set. + +However, it can be overwritten by a new definition of them. On the one hand, we will have to define the name of the +**variables**, and on the other hand, the definition of the **spaces** (and an **action mapping** if it is a discrete environment). + +.. code:: python + + import gym + import numpy as np + + import sinergym + + new_observation_variables=[ + 'Site Outdoor Air Drybulb Temperature(Environment)', + 'Site Outdoor Air Relative Humidity(Environment)', + 'Site Wind Speed(Environment)', + 'Zone Thermal Comfort Fanger Model PPD(East Zone PEOPLE)', + 'Zone People Occupant Count(East Zone)', + 'People Air Temperature(East Zone PEOPLE)', + 'Facility Total HVAC Electricity Demand Rate(Whole Building)' + ] + + new_action_variables = [ + 'West-HtgSetP-RL', + 'West-ClgSetP-RL', + 'East-HtgSetP-RL', + 'East-ClgSetP-RL' + ] + + new_observation_space = gym.spaces.Box( + low=-5e6, + high=5e6, + shape=(len(new_observation_variables) + 4,), + dtype=np.float32) + + new_action_mapping = { + 0: (15, 30, 15, 30), + 1: (16, 29, 16, 29), + 2: (17, 28, 17, 28), + 3: (18, 27, 18, 27), + 4: (19, 26, 19, 26), + 5: (20, 25, 20, 25), + 6: (21, 24, 21, 24), + 7: (22, 23, 22, 23), + 8: (22, 22, 22, 22), + 9: (21, 21, 21, 21) + } + + new_action_space = gym.spaces.Discrete(10) + + env = gym.make('Eplus-datacenter-cool-discrete-stochastic-v1', + observation_variables=new_observation_variables, + observation_space=new_observation_space, + action_variables=new_action_variables, + action_mapping=new_action_mapping, + action_space=new_action_space + ) + + + for i in range(1): + obs = env.reset() + rewards = [] + done = False + current_month = 0 + while not done: + a = env.action_space.sample() + obs, reward, done, info = env.step(a) + rewards.append(reward) + if info['month'] != current_month: # display results every month + current_month = info['month'] + print('Reward: ', sum(rewards), info) + print( + 'Episode ', + i, + 'Mean reward: ', + np.mean(rewards), + 'Cumulative reward: ', + sum(rewards)) + env.close() + +In case the definition has some inconsistency, such as the *IDF* has not been +adapted to the new actions, the spaces do not fit with the variables, the +observation variables do not exist, etc. Sinergym will display an error. + +******************************** +Adding a new action definition +******************************** + +As we have explained in the previous example, one of the problems that can arise when +modifying the space of actions and observations is that the *IDF* is not adapted to the +new space of actions established. + +We may even want to modify the effects of actions on the building directly for some kind +of interest without being subject to a change of the action space. For example, we may +want to change the zones assigned to each thermostat or change their value at the start +of the simulation. + +For this purpose, the *Sinergym* **action definition** is available. With a dictionary we can +build a definition of what we want to be controlled in the building and how to control +it using the action space of the environment: + +.. code:: python + + import gym + import numpy as np + + import sinergym + + new_action_definition={ + 'ThermostatSetpoint:DualSetpoint': [{ + 'name': 'West-DualSetP-RL', + 'heating_name': 'West-HtgSetP-RL', + 'cooling_name': 'West-ClgSetP-RL', + 'heating_initial_value':21.0, + 'cooling_initial_value':25.0, + 'zones': ['West Zone'] + }, + { + 'name': 'East-DualSetP-RL', + 'heating_name': 'East-HtgSetP-RL', + 'cooling_name': 'East-ClgSetP-RL', + 'heating_initial_value':21.0, + 'cooling_initial_value':25.0, + 'zones': ['East Zone'] + }] + } + + env = gym.make('Eplus-datacenter-cool-continuous-stochastic-v1', + action_definition=new_action_definition + ) + + for i in range(1): + obs = env.reset() + rewards = [] + done = False + current_month = 0 + while not done: + a = env.action_space.sample() + obs, reward, done, info = env.step(a) + rewards.append(reward) + if info['month'] != current_month: # display results every month + current_month = info['month'] + print('Reward: ', sum(rewards), info) + print( + 'Episode ', + i, + 'Mean reward: ', + np.mean(rewards), + 'Cumulative reward: ', + sum(rewards)) + env.close() + +The name of the heating and cooling should be the name of action variables defined in the environment. +Otherwise, Sinergym will show the inconsistency. + +For more information about the format of the action definition dictionaries, visit the section :ref:`Action definition`. + ************************************** Adding extra configuration definition ************************************** -You can even add a dictionary with extra parameters that modify the IDF you use before it is used in the simulations (or overwrite an existing one). +You can even add a dictionary with extra parameters that modify the IDF you use before it is +used in the simulations (or overwrite an existing one). -This new IDF version, which also adapts to the new weather you put in, is saved in the Sinergym output folder, leaving the original intact: +This new IDF version, which also adapts to the new weather you put in, is saved in the *Sinergym* +output folder, leaving the original intact: .. code:: python @@ -249,56 +386,23 @@ This new IDF version, which also adapts to the new weather you put in, is saved import numpy as np import sinergym - from sinergym.utils.rewards import LinearReward, ExpReward - from sinergym.utils.wrappers import LoggerWrapper, NormalizeObservation - from sinergym.utils.controllers import RBCDatacenter extra_conf={ 'timesteps_per_hour':6, - 'runperiod':(1,1,1991,2,1,1992), - 'action_definition': { - 'ThermostatSetpoint:DualSetpoint': [{ - 'name': 'West-DualSetP-RL', - 'heating_name': 'West-HtgSetP-RL', - 'cooling_name': 'West-ClgSetP-RL', - 'zones': ['West Zone'] - }, - { - 'name': 'East-DualSetP-RL', - 'heating_name': 'East-HtgSetP-RL', - 'cooling_name': 'East-ClgSetP-RL', - 'zones': ['East Zone'] - }] - } + 'runperiod':(1,1,1991,2,1,1992) } env = gym.make('Eplus-datacenter-cool-continuous-stochastic-v1', - reward=ExpReward, reward_kwargs={ - 'temperature_variable': 'Zone Air Temperature (SPACE1-1)', - 'energy_variable': 'Facility Total HVAC Electricity Demand Rate (Whole Building)', - 'range_comfort_winter': (20.0, 23.5), - 'range_comfort_summer': (23.0, 26.0), - 'energy_weight': 0.1}, - weather_file='ESP_Granada.084190_SWEC.epw', - weather_variability=(1.0,0.0,0.001), - env_name='new_env_name', - act_repeat=4, - max_ep_data_store_num = 20, config_params=extra_conf ) - env = NormalizeObservation(env) - env = LoggerWrapper(env) - - agent = RBCDatacenter(env) - for i in range(1): obs = env.reset() rewards = [] done = False current_month = 0 while not done: - a = agent.act(obs) + a = env.action_space.sample() obs, reward, done, info = env.step(a) rewards.append(reward) if info['month'] != current_month: # display results every month @@ -316,3 +420,5 @@ This new IDF version, which also adapts to the new weather you put in, is saved .. note:: For more information on how each of the elements explained here works, please see the appropriate section. .. note:: To see how Sinergym can be combined with DRL algorithms, please visit section :ref:`Deep Reinforcement Learning Integration` of our documentation (specifically the DRL_battery.py script in section :ref:`How use`). + +.. note:: Our team provide several notebooks with more functionality and examples, visit examples section. diff --git a/docs/source/pages/wrappers.rst b/docs/source/pages/wrappers.rst index 8e0a72e0c2..7fc1febb53 100644 --- a/docs/source/pages/wrappers.rst +++ b/docs/source/pages/wrappers.rst @@ -2,13 +2,12 @@ Wrappers ############ -Sinergym has several wrappers in order to add some functionality in the environment that it doesn't have by default. Currently, we have developed a **normalization wrapper**, -**multi-observation wrapper** and **Logger wrapper**. The code can be found in `sinergym/sinergym/utils/wrappers.py `__. +*Sinergym* has several **wrappers** in order to add some functionality in the environment +that it doesn't have by default. Currently, we have developed a **normalization wrapper**, +**multi-observation wrapper** and **Logger wrapper**. The code can be found in +`sinergym/sinergym/utils/wrappers.py `__. You can implement your own wrappers inheriting from *gym.Wrapper* or some of its variants: -.. literalinclude:: ../../../sinergym/utils/wrappers.py - :language: python - An usage of these wrappers could be the next: .. code:: python @@ -46,4 +45,4 @@ An usage of these wrappers could be the next: .. warning:: The order of wrappers if you are going to use several at the same time is really important. The correct order is **Normalization - Logger - MultiObs** and subsets (for example, *Normalization* - *Multiobs* is valid). -.. note:: For more information about Sinergym Logger, visit :ref:`Logger`. \ No newline at end of file +.. note:: For more information about *Sinergym* Logger, visit :ref:`Logger`. \ No newline at end of file diff --git a/examples/MLflow_example.ipynb b/examples/MLflow_example.ipynb index d4c9876766..8ace5af530 100644 --- a/examples/MLflow_example.ipynb +++ b/examples/MLflow_example.ipynb @@ -27,7 +27,16 @@ "name": "#%%\n" } }, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/usr/local/lib/python3.10/dist-packages/gym/spaces/box.py:73: UserWarning: \u001b[33mWARN: Box bound precision lowered by casting to float32\u001b[0m\n", + " logger.warn(\n" + ] + } + ], "source": [ "import mlflow\n", "\n", @@ -97,36 +106,44 @@ "name": "stderr", "output_type": "stream", "text": [ - "[2022-05-16 13:43:49,680] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-16 13:43:49,682] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", - "[2022-05-16 13:43:49,686] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-16 13:43:49,702] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res2/Eplus-env-sub_run1\n", - "[2022-05-16 13:44:07,471] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-16 13:44:07,472] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-16 13:44:07,486] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res2/Eplus-env-sub_run2\n", - "[2022-05-16 13:44:36,436] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-16 13:44:36,437] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-16 13:44:36,451] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res2/Eplus-env-sub_run3\n", - "/usr/local/lib/python3.9/dist-packages/numpy/core/fromnumeric.py:3474: RuntimeWarning: Mean of empty slice.\n", + "[2022-08-24 09:16:23,166] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf ExternalInterface object if it is not present...\n", + "[2022-08-24 09:16:23,167] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", + "[2022-08-24 09:16:23,169] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", + "[2022-08-24 09:16:23,171] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", + "[2022-08-24 09:16:23,179] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:16:23,194] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res3/Eplus-env-sub_run1\n", + "[2022-08-24 09:16:36,239] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", + "[2022-08-24 09:16:36,240] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:16:36,247] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res3/Eplus-env-sub_run2\n", + "[2022-08-24 09:16:56,674] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", + "[2022-08-24 09:16:56,674] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:16:56,682] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res3/Eplus-env-sub_run3\n", + "/usr/local/lib/python3.10/dist-packages/numpy/core/fromnumeric.py:3474: RuntimeWarning: Mean of empty slice.\n", " return _methods._mean(a, axis=axis, dtype=dtype,\n", - "/usr/local/lib/python3.9/dist-packages/numpy/core/_methods.py:189: RuntimeWarning: invalid value encountered in double_scalars\n", + "/usr/local/lib/python3.10/dist-packages/numpy/core/_methods.py:189: RuntimeWarning: invalid value encountered in double_scalars\n", + " ret = ret.dtype.type(ret / rcount)\n", + "/usr/local/lib/python3.10/dist-packages/numpy/core/_methods.py:264: RuntimeWarning: Degrees of freedom <= 0 for slice\n", + " ret = _var(a, axis=axis, dtype=dtype, out=out, ddof=ddof,\n", + "/usr/local/lib/python3.10/dist-packages/numpy/core/_methods.py:222: RuntimeWarning: invalid value encountered in true_divide\n", + " arrmean = um.true_divide(arrmean, div, out=arrmean, casting='unsafe',\n", + "/usr/local/lib/python3.10/dist-packages/numpy/core/_methods.py:256: RuntimeWarning: invalid value encountered in double_scalars\n", " ret = ret.dtype.type(ret / rcount)\n", - "[2022-05-16 13:44:42,769] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-16 13:44:42,770] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-16 13:44:42,782] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res2/Eplus-env-sub_run4\n", - "[2022-05-16 13:45:03,057] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-16 13:45:03,058] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-16 13:45:03,072] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res2/Eplus-env-sub_run5\n", - "[2022-05-16 13:45:24,521] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-16 13:45:24,524] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-16 13:45:24,551] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res2/Eplus-env-sub_run6\n" + "[2022-08-24 09:17:01,669] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", + "[2022-08-24 09:17:01,670] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:17:01,677] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res3/Eplus-env-sub_run4\n", + "[2022-08-24 09:17:15,729] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", + "[2022-08-24 09:17:15,731] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:17:15,744] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res3/Eplus-env-sub_run5\n", + "[2022-08-24 09:17:29,805] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", + "[2022-08-24 09:17:29,807] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:17:29,819] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res3/Eplus-env-sub_run6\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Eval num_timesteps=70080, episode_reward=-18206.05 +/- 0.00\n", + "Eval num_timesteps=70080, episode_reward=-17218.13 +/- 0.00\n", "Episode length: 35040.00 +/- 0.00\n", "New best mean reward!\n" ] @@ -135,28 +152,28 @@ "name": "stderr", "output_type": "stream", "text": [ - "[2022-05-16 13:46:00,519] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-16 13:46:00,519] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-16 13:46:00,532] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res2/Eplus-env-sub_run7\n", - "[2022-05-16 13:46:37,035] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-16 13:46:37,038] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-16 13:46:37,061] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res2/Eplus-env-sub_run8\n", - "[2022-05-16 13:46:43,449] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-16 13:46:43,450] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-16 13:46:43,469] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res2/Eplus-env-sub_run9\n", - "[2022-05-16 13:47:05,531] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-16 13:47:05,531] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-16 13:47:05,544] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res2/Eplus-env-sub_run10\n", - "[2022-05-16 13:47:26,473] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-16 13:47:26,474] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-16 13:47:26,492] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res2/Eplus-env-sub_run11\n" + "[2022-08-24 09:17:57,240] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", + "[2022-08-24 09:17:57,241] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:17:57,248] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res3/Eplus-env-sub_run7\n", + "[2022-08-24 09:18:24,491] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", + "[2022-08-24 09:18:24,492] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:18:24,501] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res3/Eplus-env-sub_run8\n", + "[2022-08-24 09:18:29,701] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", + "[2022-08-24 09:18:29,702] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:18:29,710] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res3/Eplus-env-sub_run9\n", + "[2022-08-24 09:18:43,740] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", + "[2022-08-24 09:18:43,742] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:18:43,760] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res3/Eplus-env-sub_run10\n", + "[2022-08-24 09:18:57,944] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", + "[2022-08-24 09:18:57,946] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:18:57,959] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res3/Eplus-env-sub_run11\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Eval num_timesteps=140160, episode_reward=-19928.33 +/- 0.00\n", + "Eval num_timesteps=140160, episode_reward=-26894.21 +/- 0.00\n", "Episode length: 35040.00 +/- 0.00\n" ] } @@ -231,7 +248,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.11" + "version": "3.10.4" } }, "nbformat": 4, diff --git a/examples/TensorBoard_example.ipynb b/examples/TensorBoard_example.ipynb index 0765f22539..e4d14b79de 100644 --- a/examples/TensorBoard_example.ipynb +++ b/examples/TensorBoard_example.ipynb @@ -23,9 +23,18 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 1, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/usr/local/lib/python3.10/dist-packages/gym/spaces/box.py:73: UserWarning: \u001b[33mWARN: Box bound precision lowered by casting to float32\u001b[0m\n", + " logger.warn(\n" + ] + } + ], "source": [ "import sinergym\n", "from sinergym.utils.callbacks import LoggerEvalCallback, LoggerCallback\n", @@ -48,16 +57,17 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "[2022-05-23 16:41:49,416] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:41:49,418] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:41:49,419] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n" + "[2022-08-24 09:21:36,475] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf ExternalInterface object if it is not present...\n", + "[2022-08-24 09:21:36,477] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", + "[2022-08-24 09:21:36,479] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", + "[2022-08-24 09:21:36,482] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n" ] } ], @@ -82,7 +92,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "metadata": {}, "outputs": [ { @@ -109,7 +119,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -128,22 +138,16 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2022-05-23 16:41:50.179466: W tensorflow/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libcudart.so.11.0'; dlerror: libcudart.so.11.0: cannot open shared object file: No such file or directory\n", - "2022-05-23 16:41:50.179484: I tensorflow/stream_executor/cuda/cudart_stub.cc:29] Ignore above cudart dlerror if you do not have a GPU set up on your machine.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Couldn't import dot_parser, loading of dot files will not be possible.\n" + "2022-08-24 09:21:37.692349: I tensorflow/core/util/util.cc:169] oneDNN custom operations are on. You may see slightly different numerical results due to floating-point round-off errors from different computation orders. To turn them off, set the environment variable `TF_ENABLE_ONEDNN_OPTS=0`.\n", + "2022-08-24 09:21:37.734692: W tensorflow/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libcudart.so.11.0'; dlerror: libcudart.so.11.0: cannot open shared object file: No such file or directory\n", + "2022-08-24 09:21:37.734718: I tensorflow/stream_executor/cuda/cudart_stub.cc:29] Ignore above cudart dlerror if you do not have a GPU set up on your machine.\n" ] } ], @@ -170,32 +174,38 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "[2022-05-23 16:41:51,876] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:41:51,888] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res4/Eplus-env-sub_run1\n", - "[2022-05-23 16:42:11,278] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-23 16:42:11,279] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:42:11,291] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res4/Eplus-env-sub_run2\n", - "[2022-05-23 16:42:42,227] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-23 16:42:42,228] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:42:42,238] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res4/Eplus-env-sub_run3\n", - "[2022-05-23 16:43:19,158] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-23 16:43:19,159] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:43:19,169] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res4/Eplus-env-sub_run4\n", - "[2022-05-23 16:44:01,372] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-23 16:44:01,373] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:44:01,385] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res4/Eplus-env-sub_run5\n", - "/usr/local/lib/python3.9/dist-packages/numpy/core/fromnumeric.py:3474: RuntimeWarning: Mean of empty slice.\n", + "[2022-08-24 09:21:39,780] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:21:39,788] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res6/Eplus-env-sub_run1\n", + "[2022-08-24 09:21:54,888] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", + "[2022-08-24 09:21:54,888] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:21:54,896] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res6/Eplus-env-sub_run2\n", + "[2022-08-24 09:22:19,340] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", + "[2022-08-24 09:22:19,341] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:22:19,348] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res6/Eplus-env-sub_run3\n", + "[2022-08-24 09:22:51,235] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", + "[2022-08-24 09:22:51,238] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:22:51,253] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res6/Eplus-env-sub_run4\n", + "[2022-08-24 09:23:24,742] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", + "[2022-08-24 09:23:24,743] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:23:24,751] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res6/Eplus-env-sub_run5\n", + "/usr/local/lib/python3.10/dist-packages/numpy/core/fromnumeric.py:3474: RuntimeWarning: Mean of empty slice.\n", " return _methods._mean(a, axis=axis, dtype=dtype,\n", - "/usr/local/lib/python3.9/dist-packages/numpy/core/_methods.py:189: RuntimeWarning: invalid value encountered in double_scalars\n", + "/usr/local/lib/python3.10/dist-packages/numpy/core/_methods.py:189: RuntimeWarning: invalid value encountered in double_scalars\n", + " ret = ret.dtype.type(ret / rcount)\n", + "/usr/local/lib/python3.10/dist-packages/numpy/core/_methods.py:264: RuntimeWarning: Degrees of freedom <= 0 for slice\n", + " ret = _var(a, axis=axis, dtype=dtype, out=out, ddof=ddof,\n", + "/usr/local/lib/python3.10/dist-packages/numpy/core/_methods.py:222: RuntimeWarning: invalid value encountered in true_divide\n", + " arrmean = um.true_divide(arrmean, div, out=arrmean, casting='unsafe',\n", + "/usr/local/lib/python3.10/dist-packages/numpy/core/_methods.py:256: RuntimeWarning: invalid value encountered in double_scalars\n", " ret = ret.dtype.type(ret / rcount)\n", - "[2022-05-23 16:44:07,572] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus simulation closed successfully. \n" + "[2022-08-24 09:23:30,387] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus simulation closed successfully. \n" ] } ], @@ -218,7 +228,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3.9.10 64-bit", "language": "python", "name": "python3" }, @@ -232,9 +242,14 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.10" + "version": "3.10.4" + }, + "vscode": { + "interpreter": { + "hash": "767d51c1340bd893661ea55ea3124f6de3c7a262a8b4abca0554b478b1e2ff90" + } } }, "nbformat": 4, "nbformat_minor": 0 -} \ No newline at end of file +} diff --git a/examples/basic_example.ipynb b/examples/basic_example.ipynb index f24bd58711..31e3111505 100644 --- a/examples/basic_example.ipynb +++ b/examples/basic_example.ipynb @@ -38,11 +38,12 @@ "name": "stderr", "output_type": "stream", "text": [ - "/usr/local/lib/python3.9/dist-packages/gym/logger.py:34: UserWarning: \u001b[33mWARN: Box bound precision lowered by casting to float32\u001b[0m\n", - " warnings.warn(colorize(\"%s: %s\" % (\"WARN\", msg % args), \"yellow\"))\n", - "[2022-05-23 16:41:15,262] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:41:15,266] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:41:15,269] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n" + "/usr/local/lib/python3.10/dist-packages/gym/spaces/box.py:73: UserWarning: \u001b[33mWARN: Box bound precision lowered by casting to float32\u001b[0m\n", + " logger.warn(\n", + "[2022-08-24 08:52:56,398] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf ExternalInterface object if it is not present...\n", + "[2022-08-24 08:52:56,399] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", + "[2022-08-24 08:52:56,401] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", + "[2022-08-24 08:52:56,403] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n" ] } ], @@ -84,27 +85,27 @@ "name": "stderr", "output_type": "stream", "text": [ - "[2022-05-23 16:41:15,437] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:41:15,452] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res1/Eplus-env-sub_run1\n" + "[2022-08-24 08:52:56,478] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 08:52:56,492] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res1/Eplus-env-sub_run1\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Reward: -0.6725497890372467 {'timestep': 1, 'time_elapsed': 900, 'year': 1991, 'month': 1, 'day': 1, 'hour': 0, 'total_power': 3133.716390651039, 'total_power_no_units': -0.3133716390651039, 'comfort_penalty': -1.0317279390093894, 'temperatures': [18.96827206099061], 'out_temperature': 1.8, 'action_': [17, 28]}\n", - "Reward: -1846.9621312474262 {'timestep': 2976, 'time_elapsed': 2678400, 'year': 1991, 'month': 2, 'day': 1, 'hour': 0, 'total_power': 5411.063351625962, 'total_power_no_units': -0.5411063351625962, 'comfort_penalty': -1.8909000854544509, 'temperatures': [18.10909991454555], 'out_temperature': -7.0, 'action_': [18, 27]}\n", - "Reward: -3607.264114303269 {'timestep': 5664, 'time_elapsed': 5097600, 'year': 1991, 'month': 3, 'day': 1, 'hour': 0, 'total_power': 4461.216463017275, 'total_power_no_units': -0.4461216463017275, 'comfort_penalty': -0.0, 'temperatures': [20.95766035021237], 'out_temperature': 8.1, 'action_': [21, 21]}\n", - "Reward: -4786.171264451111 {'timestep': 8640, 'time_elapsed': 7776000, 'year': 1991, 'month': 4, 'day': 1, 'hour': 0, 'total_power': 186.5934720667916, 'total_power_no_units': -0.018659347206679163, 'comfort_penalty': -0.0, 'temperatures': [20.67709349698774], 'out_temperature': 7.7, 'action_': [15, 30]}\n", - "Reward: -5611.414269156897 {'timestep': 11520, 'time_elapsed': 10368000, 'year': 1991, 'month': 5, 'day': 1, 'hour': 0, 'total_power': 922.6285285423929, 'total_power_no_units': -0.0922628528542393, 'comfort_penalty': -0.0, 'temperatures': [21.02157118845279], 'out_temperature': 13.0, 'action_': [21, 21]}\n", - "Reward: -6356.324891064242 {'timestep': 14496, 'time_elapsed': 13046400, 'year': 1991, 'month': 6, 'day': 1, 'hour': 0, 'total_power': 1338.345005962429, 'total_power_no_units': -0.1338345005962429, 'comfort_penalty': -2.0096463211117204, 'temperatures': [20.99035367888828], 'out_temperature': 18.4, 'action_': [21, 21]}\n", - "Reward: -9383.627583873596 {'timestep': 17376, 'time_elapsed': 15638400, 'year': 1991, 'month': 7, 'day': 1, 'hour': 0, 'total_power': 395.5098530039662, 'total_power_no_units': -0.03955098530039662, 'comfort_penalty': -1.94742078729465, 'temperatures': [21.05257921270535], 'out_temperature': 17.7, 'action_': [21, 21]}\n", - "Reward: -12767.036699993025 {'timestep': 20352, 'time_elapsed': 18316800, 'year': 1991, 'month': 8, 'day': 1, 'hour': 0, 'total_power': 9254.319513462964, 'total_power_no_units': -0.9254319513462964, 'comfort_penalty': -1.2539429997804383, 'temperatures': [21.74605700021956], 'out_temperature': 20.6, 'action_': [22, 22]}\n", - "Reward: -16085.210572008498 {'timestep': 23328, 'time_elapsed': 20995200, 'year': 1991, 'month': 9, 'day': 1, 'hour': 0, 'total_power': 367.8874637575448, 'total_power_no_units': -0.03678874637575449, 'comfort_penalty': -2.324175301260169, 'temperatures': [20.67582469873983], 'out_temperature': 18.8, 'action_': [19, 26]}\n", - "Reward: -18964.991373602872 {'timestep': 26208, 'time_elapsed': 23587200, 'year': 1991, 'month': 10, 'day': 1, 'hour': 0, 'total_power': 583.799449730454, 'total_power_no_units': -0.0583799449730454, 'comfort_penalty': -0.00723554754091893, 'temperatures': [19.99276445245908], 'out_temperature': 13.3, 'action_': [20, 25]}\n", - "Reward: -19825.964771961888 {'timestep': 29184, 'time_elapsed': 26265600, 'year': 1991, 'month': 11, 'day': 1, 'hour': 0, 'total_power': 186.5934720667916, 'total_power_no_units': -0.018659347206679163, 'comfort_penalty': -0.27634167442781177, 'temperatures': [19.72365832557219], 'out_temperature': 13.0, 'action_': [15, 30]}\n", - "Reward: -20852.888693767633 {'timestep': 32064, 'time_elapsed': 28857600, 'year': 1991, 'month': 12, 'day': 1, 'hour': 0, 'total_power': 712.7997807153837, 'total_power_no_units': -0.07127997807153837, 'comfort_penalty': -0.9134903295960015, 'temperatures': [19.086509670404], 'out_temperature': 5.1, 'action_': [15, 30]}\n", - "Reward: -22604.494577441612 {'timestep': 35040, 'time_elapsed': 31536000, 'year': 1992, 'month': 1, 'day': 1, 'hour': 0, 'total_power': 8077.874829054068, 'total_power_no_units': -0.8077874829054068, 'comfort_penalty': -2.8425197590065814, 'temperatures': [17.15748024099342], 'out_temperature': -12.0, 'action_': [15, 30]}\n" + "Reward: -0.3808358083250144 {'timestep': 1, 'time_elapsed': 900, 'year': 1991, 'month': 1, 'day': 1, 'hour': 0, 'total_power': 7616.716166500288, 'total_power_no_units': -0.7616716166500288, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [20.99998783039325], 'out_temperature': 1.8, 'action_': [21, 21]}\n", + "Reward: -1907.7277939767475 {'timestep': 2976, 'time_elapsed': 2678400, 'year': 1991, 'month': 2, 'day': 1, 'hour': 0, 'total_power': 6074.240017973336, 'total_power_no_units': -0.6074240017973336, 'comfort_penalty': -3.1192635601846987, 'abs_comfort': 3.1192635601846987, 'temperatures': [16.8807364398153], 'out_temperature': -7.0, 'action_': [16, 29]}\n", + "Reward: -3585.4934187414906 {'timestep': 5664, 'time_elapsed': 5097600, 'year': 1991, 'month': 3, 'day': 1, 'hour': 0, 'total_power': 913.1570850309641, 'total_power_no_units': -0.09131570850309642, 'comfort_penalty': -0.7021712738831916, 'abs_comfort': 0.7021712738831916, 'temperatures': [19.29782872611681], 'out_temperature': 8.1, 'action_': [15, 30]}\n", + "Reward: -4752.940264075469 {'timestep': 8640, 'time_elapsed': 7776000, 'year': 1991, 'month': 4, 'day': 1, 'hour': 0, 'total_power': 2550.617218922648, 'total_power_no_units': -0.25506172189226484, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [20.99871397216555], 'out_temperature': 7.7, 'action_': [21, 24]}\n", + "Reward: -5560.830588831498 {'timestep': 11520, 'time_elapsed': 10368000, 'year': 1991, 'month': 5, 'day': 1, 'hour': 0, 'total_power': 1999.124803999265, 'total_power_no_units': -0.1999124803999265, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [20.98506510334393], 'out_temperature': 13.0, 'action_': [21, 21]}\n", + "Reward: -6284.020264489995 {'timestep': 14496, 'time_elapsed': 13046400, 'year': 1991, 'month': 6, 'day': 1, 'hour': 0, 'total_power': 410.8927633115007, 'total_power_no_units': -0.041089276331150074, 'comfort_penalty': -1.7705159780059887, 'abs_comfort': 1.7705159780059887, 'temperatures': [21.22948402199401], 'out_temperature': 18.4, 'action_': [21, 24]}\n", + "Reward: -9322.837829436405 {'timestep': 17376, 'time_elapsed': 15638400, 'year': 1991, 'month': 7, 'day': 1, 'hour': 0, 'total_power': 215.8190765300895, 'total_power_no_units': -0.02158190765300895, 'comfort_penalty': -1.608314422881719, 'abs_comfort': 1.608314422881719, 'temperatures': [21.39168557711828], 'out_temperature': 17.7, 'action_': [18, 27]}\n", + "Reward: -12636.627393394123 {'timestep': 20352, 'time_elapsed': 18316800, 'year': 1991, 'month': 8, 'day': 1, 'hour': 0, 'total_power': 5037.684551333462, 'total_power_no_units': -0.5037684551333462, 'comfort_penalty': -2.854158909419219, 'abs_comfort': 2.854158909419219, 'temperatures': [20.14584109058078], 'out_temperature': 20.6, 'action_': [20, 25]}\n", + "Reward: -15946.738203460833 {'timestep': 23328, 'time_elapsed': 20995200, 'year': 1991, 'month': 9, 'day': 1, 'hour': 0, 'total_power': 367.8874627648617, 'total_power_no_units': -0.03678874627648617, 'comfort_penalty': -2.54812468432662, 'abs_comfort': 2.54812468432662, 'temperatures': [20.45187531567338], 'out_temperature': 18.8, 'action_': [18, 27]}\n", + "Reward: -18806.826419277357 {'timestep': 26208, 'time_elapsed': 23587200, 'year': 1991, 'month': 10, 'day': 1, 'hour': 0, 'total_power': 186.5934720667916, 'total_power_no_units': -0.018659347206679163, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [20.33203794777814], 'out_temperature': 13.3, 'action_': [17, 28]}\n", + "Reward: -19743.85954501463 {'timestep': 29184, 'time_elapsed': 26265600, 'year': 1991, 'month': 11, 'day': 1, 'hour': 0, 'total_power': 186.5934720667916, 'total_power_no_units': -0.018659347206679163, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [20.71761367059368], 'out_temperature': 13.0, 'action_': [16, 29]}\n", + "Reward: -20805.360894738802 {'timestep': 32064, 'time_elapsed': 28857600, 'year': 1991, 'month': 12, 'day': 1, 'hour': 0, 'total_power': 5873.617289712576, 'total_power_no_units': -0.5873617289712576, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [21.42152536802113], 'out_temperature': 5.1, 'action_': [22, 22]}\n", + "Reward: -22566.62456817261 {'timestep': 35040, 'time_elapsed': 31536000, 'year': 1992, 'month': 1, 'day': 1, 'hour': 0, 'total_power': 8311.608954955058, 'total_power_no_units': -0.8311608954955059, 'comfort_penalty': -1.823025839166501, 'abs_comfort': 1.823025839166501, 'temperatures': [18.1769741608335], 'out_temperature': -12.0, 'action_': [18, 27]}\n" ] } ], @@ -149,7 +150,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "[2022-05-23 16:41:26,875] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus simulation closed successfully. \n" + "[2022-08-24 08:53:06,644] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus simulation closed successfully. \n" ] } ], @@ -183,7 +184,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Mean reward: -0.6451054388538969 Cumulative reward: -22604.494577441612\n" + "Mean reward: -0.6440246737491857 Cumulative reward: -22566.62456817261\n" ] } ], @@ -222,9 +223,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.10" + "version": "3.10.4" } }, "nbformat": 4, "nbformat_minor": 0 -} \ No newline at end of file +} diff --git a/examples/change_environment.ipynb b/examples/change_environment.ipynb index 1cff811968..bb1702868c 100644 --- a/examples/change_environment.ipynb +++ b/examples/change_environment.ipynb @@ -23,7 +23,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 1, "metadata": { "collapsed": false, "pycharm": { @@ -36,14 +36,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "[2022-05-23 16:41:29,038] EPLUS_ENV_5Zone-hot-continuous-stochastic-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:41:29,038] EPLUS_ENV_5Zone-hot-continuous-stochastic-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:41:29,041] EPLUS_ENV_5Zone-hot-continuous-stochastic-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:41:29,041] EPLUS_ENV_5Zone-hot-continuous-stochastic-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:41:29,043] EPLUS_ENV_5Zone-hot-continuous-stochastic-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", - "[2022-05-23 16:41:29,043] EPLUS_ENV_5Zone-hot-continuous-stochastic-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", - "/usr/local/lib/python3.9/dist-packages/gym/logger.py:34: UserWarning: \u001b[33mWARN: Box bound precision lowered by casting to float32\u001b[0m\n", - " warnings.warn(colorize(\"%s: %s\" % (\"WARN\", msg % args), \"yellow\"))\n" + "/usr/local/lib/python3.10/dist-packages/gym/spaces/box.py:73: UserWarning: \u001b[33mWARN: Box bound precision lowered by casting to float32\u001b[0m\n", + " logger.warn(\n", + "[2022-08-24 08:55:54,216] EPLUS_ENV_5Zone-hot-continuous-stochastic-v1_MainThread_ROOT INFO:Updating idf ExternalInterface object if it is not present...\n", + "[2022-08-24 08:55:54,217] EPLUS_ENV_5Zone-hot-continuous-stochastic-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", + "[2022-08-24 08:55:54,219] EPLUS_ENV_5Zone-hot-continuous-stochastic-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", + "[2022-08-24 08:55:54,220] EPLUS_ENV_5Zone-hot-continuous-stochastic-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", + "/usr/local/lib/python3.10/dist-packages/gym/spaces/box.py:73: UserWarning: \u001b[33mWARN: Box bound precision lowered by casting to float32\u001b[0m\n", + " logger.warn(\n" ] } ], @@ -59,13 +59,13 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "These environment IDs have a number of components defined, not only the building design (IDF), but also the reward function, the action and observation spaces, the defining variables, etc.\n", + "These environment IDs have a number of components defined, not only the building design (*IDF*), but also the reward function, the action and observation spaces, the defining variables, etc.\n", "\n", "If you want a new environment, you can define it from scratch in our [environment list](https://github.com/ugr-sail/sinergym/blob/main/sinergym/__init__.py) and run it locally.\n", "\n", "Another option (recommended) is to start from one of our environments and change the components you want. You can combine components you want to change obviously.\n", "\n", - "The way to do that is to add in the `gym.make()` those parameters of the constructor of the Sinergym environment we want to change. Let's see what things we can change starting from any environment:" + "The way to do that is to add in the `gym.make()` those parameters of the constructor of the *Sinergym* environment we want to change. Let's see what things we can change starting from any environment:" ] }, { @@ -84,7 +84,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 2, "metadata": { "collapsed": false, "pycharm": { @@ -97,14 +97,12 @@ "name": "stderr", "output_type": "stream", "text": [ - "[2022-05-23 16:41:30,160] EPLUS_ENV_5Zone-hot-continuous-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:41:30,160] EPLUS_ENV_5Zone-hot-continuous-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:41:30,163] EPLUS_ENV_5Zone-hot-continuous-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:41:30,163] EPLUS_ENV_5Zone-hot-continuous-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:41:30,165] EPLUS_ENV_5Zone-hot-continuous-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", - "[2022-05-23 16:41:30,165] EPLUS_ENV_5Zone-hot-continuous-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", - "/usr/local/lib/python3.9/dist-packages/gym/logger.py:34: UserWarning: \u001b[33mWARN: Box bound precision lowered by casting to float32\u001b[0m\n", - " warnings.warn(colorize(\"%s: %s\" % (\"WARN\", msg % args), \"yellow\"))\n" + "[2022-08-24 08:55:55,088] EPLUS_ENV_5Zone-hot-continuous-v1_MainThread_ROOT INFO:Updating idf ExternalInterface object if it is not present...\n", + "[2022-08-24 08:55:55,089] EPLUS_ENV_5Zone-hot-continuous-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", + "[2022-08-24 08:55:55,091] EPLUS_ENV_5Zone-hot-continuous-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", + "[2022-08-24 08:55:55,093] EPLUS_ENV_5Zone-hot-continuous-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", + "/usr/local/lib/python3.10/dist-packages/gym/spaces/box.py:73: UserWarning: \u001b[33mWARN: Box bound precision lowered by casting to float32\u001b[0m\n", + " logger.warn(\n" ] } ], @@ -147,18 +145,19 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "[2022-05-23 16:41:31,228] EPLUS_ENV_new_env_name_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:41:31,231] EPLUS_ENV_new_env_name_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:41:31,234] EPLUS_ENV_new_env_name_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", - "/usr/local/lib/python3.9/dist-packages/gym/logger.py:34: UserWarning: \u001b[33mWARN: Box bound precision lowered by casting to float32\u001b[0m\n", - " warnings.warn(colorize(\"%s: %s\" % (\"WARN\", msg % args), \"yellow\"))\n" + "[2022-08-24 08:55:56,077] EPLUS_ENV_new_env_name_MainThread_ROOT INFO:Updating idf ExternalInterface object if it is not present...\n", + "[2022-08-24 08:55:56,078] EPLUS_ENV_new_env_name_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", + "[2022-08-24 08:55:56,080] EPLUS_ENV_new_env_name_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", + "[2022-08-24 08:55:56,082] EPLUS_ENV_new_env_name_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", + "/usr/local/lib/python3.10/dist-packages/gym/spaces/box.py:73: UserWarning: \u001b[33mWARN: Box bound precision lowered by casting to float32\u001b[0m\n", + " logger.warn(\n" ] } ], @@ -175,53 +174,262 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Adding more configuration definition" + "## Changing observation and action spaces" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "You can even add a dictionary with extra parameters that modify the IDF you use before it is used in the simulations (or overwrite an existing one).\n", + "By default, the IDs of the predefined environments in *Sinergym* already have a space of actions and observations set.\n", "\n", - "This new IDF version, which also adapts to the new weather you put in, is saved in the Sinergym output folder, leaving the original intact:" + "However, it can be overwritten by a new definition of them. On the one hand, we will have to define the name of the \n", + "**variables**, and on the other hand, the definition of the **spaces** (and an **action mapping** if it is a discrete environment)." ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "[2022-05-23 16:41:32,273] EPLUS_ENV_datacenter-cool-continuous-stochastic-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:41:32,276] EPLUS_ENV_datacenter-cool-continuous-stochastic-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:41:32,278] EPLUS_ENV_datacenter-cool-continuous-stochastic-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", - "/usr/local/lib/python3.9/dist-packages/gym/logger.py:34: UserWarning: \u001b[33mWARN: Box bound precision lowered by casting to float32\u001b[0m\n", - " warnings.warn(colorize(\"%s: %s\" % (\"WARN\", msg % args), \"yellow\"))\n" + "[2022-08-24 08:55:56,850] EPLUS_ENV_datacenter-cool-discrete-stochastic-v1_MainThread_ROOT INFO:Updating idf ExternalInterface object if it is not present...\n", + "[2022-08-24 08:55:56,850] EPLUS_ENV_datacenter-cool-discrete-stochastic-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", + "[2022-08-24 08:55:56,852] EPLUS_ENV_datacenter-cool-discrete-stochastic-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", + "[2022-08-24 08:55:56,853] EPLUS_ENV_datacenter-cool-discrete-stochastic-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", + "[2022-08-24 08:55:56,854] EPLUS_ENV_datacenter-cool-discrete-stochastic-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 08:55:56,989] EPLUS_ENV_datacenter-cool-discrete-stochastic-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-datacenter-cool-discrete-stochastic-v1-res1/Eplus-env-sub_run1\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Reward: -0.18562950733969957 {'timestep': 1, 'time_elapsed': 900, 'year': 1991, 'month': 1, 'day': 1, 'hour': 0, 'total_power': 3712.590146793991, 'total_power_no_units': -0.37125901467939915, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [], 'out_temperature': 1.495266997755121, 'action_': [16, 29, 16, 29]}\n", + "Reward: -676.8466963812559 {'timestep': 2976, 'time_elapsed': 2678400, 'year': 1991, 'month': 2, 'day': 1, 'hour': 0, 'total_power': 3962.959903637626, 'total_power_no_units': -0.3962959903637626, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [], 'out_temperature': 6.479715547683856, 'action_': [21, 21, 21, 21]}\n", + "Reward: -1251.9649146249287 {'timestep': 5664, 'time_elapsed': 5097600, 'year': 1991, 'month': 3, 'day': 1, 'hour': 0, 'total_power': 4984.806746157207, 'total_power_no_units': -0.49848067461572076, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [], 'out_temperature': 3.083224933271658, 'action_': [22, 23, 22, 23]}\n", + "Reward: -1856.1854810210355 {'timestep': 8640, 'time_elapsed': 7776000, 'year': 1991, 'month': 4, 'day': 1, 'hour': 0, 'total_power': 2542.049288786898, 'total_power_no_units': -0.25420492887868984, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [], 'out_temperature': 4.548597527242591, 'action_': [15, 30, 15, 30]}\n", + "Reward: -2639.3977262984713 {'timestep': 11520, 'time_elapsed': 10368000, 'year': 1991, 'month': 5, 'day': 1, 'hour': 0, 'total_power': 4389.048609776261, 'total_power_no_units': -0.43890486097762615, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [], 'out_temperature': 9.966961794846867, 'action_': [20, 25, 20, 25]}\n", + "Reward: -3540.0364337521905 {'timestep': 14496, 'time_elapsed': 13046400, 'year': 1991, 'month': 6, 'day': 1, 'hour': 0, 'total_power': 3962.959903637626, 'total_power_no_units': -0.3962959903637626, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [], 'out_temperature': 9.932837191979614, 'action_': [22, 23, 22, 23]}\n", + "Reward: -4966.8910724773705 {'timestep': 17376, 'time_elapsed': 15638400, 'year': 1991, 'month': 7, 'day': 1, 'hour': 0, 'total_power': 3641.533364330611, 'total_power_no_units': -0.36415333643306114, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [], 'out_temperature': 10.73759114382434, 'action_': [16, 29, 16, 29]}\n", + "Reward: -6970.456022185655 {'timestep': 20352, 'time_elapsed': 18316800, 'year': 1991, 'month': 8, 'day': 1, 'hour': 0, 'total_power': 7437.450634930504, 'total_power_no_units': -0.7437450634930505, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [], 'out_temperature': 12.01780444446879, 'action_': [21, 21, 21, 21]}\n", + "Reward: -9176.457187552995 {'timestep': 23328, 'time_elapsed': 20995200, 'year': 1991, 'month': 9, 'day': 1, 'hour': 0, 'total_power': 5205.826494047731, 'total_power_no_units': -0.5205826494047732, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [], 'out_temperature': 11.76682020349629, 'action_': [16, 29, 16, 29]}\n", + "Reward: -10831.128614483414 {'timestep': 26208, 'time_elapsed': 23587200, 'year': 1991, 'month': 10, 'day': 1, 'hour': 0, 'total_power': 3632.325833964732, 'total_power_no_units': -0.3632325833964732, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [], 'out_temperature': 7.408750045244985, 'action_': [16, 29, 16, 29]}\n", + "Reward: -11597.451824735388 {'timestep': 29184, 'time_elapsed': 26265600, 'year': 1991, 'month': 11, 'day': 1, 'hour': 0, 'total_power': 3545.041301484721, 'total_power_no_units': -0.3545041301484721, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [], 'out_temperature': 5.470256190305543, 'action_': [18, 27, 18, 27]}\n", + "Reward: -12205.38913036408 {'timestep': 32064, 'time_elapsed': 28857600, 'year': 1991, 'month': 12, 'day': 1, 'hour': 0, 'total_power': 4171.474946040738, 'total_power_no_units': -0.41714749460407385, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [], 'out_temperature': 4.252032348441579, 'action_': [22, 23, 22, 23]}\n", + "Reward: -12852.455174221925 {'timestep': 35040, 'time_elapsed': 31536000, 'year': 1992, 'month': 1, 'day': 1, 'hour': 0, 'total_power': 5946.285403368743, 'total_power_no_units': -0.5946285403368743, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [], 'out_temperature': -0.01419754187374211, 'action_': [21, 24, 21, 24]}\n", + "Episode 0 Mean reward: -0.36679381204974576 Cumulative reward: -12852.455174221925\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[2022-08-24 08:56:26,964] EPLUS_ENV_datacenter-cool-discrete-stochastic-v1_MainThread_ROOT INFO:EnergyPlus simulation closed successfully. \n" ] } ], + "source": [ + "import gym\n", + "import numpy as np\n", + "\n", + "import sinergym\n", + "\n", + "new_observation_variables=[\n", + " 'Site Outdoor Air Drybulb Temperature(Environment)',\n", + " 'Site Outdoor Air Relative Humidity(Environment)',\n", + " 'Site Wind Speed(Environment)',\n", + " 'Zone Thermal Comfort Fanger Model PPD(East Zone PEOPLE)',\n", + " 'Zone People Occupant Count(East Zone)',\n", + " 'People Air Temperature(East Zone PEOPLE)',\n", + " 'Facility Total HVAC Electricity Demand Rate(Whole Building)'\n", + "]\n", + "\n", + "new_action_variables = [\n", + " 'West-HtgSetP-RL',\n", + " 'West-ClgSetP-RL',\n", + " 'East-HtgSetP-RL',\n", + " 'East-ClgSetP-RL'\n", + "]\n", + "\n", + "new_observation_space = gym.spaces.Box(\n", + " low=-5e6,\n", + " high=5e6,\n", + " shape=(len(new_observation_variables) + 4,),\n", + " dtype=np.float32)\n", + "\n", + "new_action_mapping = {\n", + " 0: (15, 30, 15, 30),\n", + " 1: (16, 29, 16, 29),\n", + " 2: (17, 28, 17, 28),\n", + " 3: (18, 27, 18, 27),\n", + " 4: (19, 26, 19, 26),\n", + " 5: (20, 25, 20, 25),\n", + " 6: (21, 24, 21, 24),\n", + " 7: (22, 23, 22, 23),\n", + " 8: (22, 22, 22, 22),\n", + " 9: (21, 21, 21, 21)\n", + "}\n", + "\n", + "new_action_space = gym.spaces.Discrete(10)\n", + "\n", + "env = gym.make('Eplus-datacenter-cool-discrete-stochastic-v1', \n", + " observation_variables=new_observation_variables,\n", + " observation_space=new_observation_space,\n", + " action_variables=new_action_variables,\n", + " action_mapping=new_action_mapping,\n", + " action_space=new_action_space\n", + " )\n", + "\n", + "\n", + "for i in range(1):\n", + " obs = env.reset()\n", + " rewards = []\n", + " done = False\n", + " current_month = 0\n", + " while not done:\n", + " a = env.action_space.sample()\n", + " obs, reward, done, info = env.step(a)\n", + " rewards.append(reward)\n", + " if info['month'] != current_month: # display results every month\n", + " current_month = info['month']\n", + " print('Reward: ', sum(rewards), info)\n", + " print(\n", + " 'Episode ',\n", + " i,\n", + " 'Mean reward: ',\n", + " np.mean(rewards),\n", + " 'Cumulative reward: ',\n", + " sum(rewards))\n", + "env.close()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In case the definition has some inconsistency, such as the *IDF* has not been \n", + "adapted to the new actions, the spaces do not fit with the variables, the \n", + "observation variables do not exist, etc. Sinergym will display an error." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Updating the action definition of the environment" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As we have explained in the previous example, one of the problems that can arise when \n", + "modifying the space of actions and observations is that the *IDF* is not adapted to the \n", + "new space of actions established.\n", + "\n", + "We may even want to modify the effects of actions on the building directly for some kind \n", + "of interest without being subject to a change of the action space. For example, we may \n", + "want to change the zones assigned to each thermostat or change their value at the start \n", + "of the simulation.\n", + "\n", + "For this purpose, the *Sinergym* **action definition** is available. With a dictionary we can \n", + "build a definition of what we want to be controlled in the building and how to control \n", + "it using the action space of the environment:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import gym\n", + "import numpy as np\n", + "\n", + "new_action_definition={\n", + " 'ThermostatSetpoint:DualSetpoint': [{\n", + " 'name': 'West-DualSetP-RL',\n", + " 'heating_name': 'West-HtgSetP-RL',\n", + " 'cooling_name': 'West-ClgSetP-RL',\n", + " 'heating_initial_value':21.0,\n", + " 'cooling_initial_value':25.0,\n", + " 'zones': ['West Zone']\n", + " },\n", + " {\n", + " 'name': 'East-DualSetP-RL',\n", + " 'heating_name': 'East-HtgSetP-RL',\n", + " 'cooling_name': 'East-ClgSetP-RL',\n", + " 'heating_initial_value':21.0,\n", + " 'cooling_initial_value':25.0,\n", + " 'zones': ['East Zone']\n", + " }]\n", + "}\n", + "\n", + "env = gym.make('Eplus-datacenter-cool-continuous-stochastic-v1', \n", + " action_definition=new_action_definition\n", + " )\n", + "\n", + "for i in range(1):\n", + " obs = env.reset()\n", + " rewards = []\n", + " done = False\n", + " current_month = 0\n", + " while not done:\n", + " a = env.action_space.sample()\n", + " obs, reward, done, info = env.step(a)\n", + " rewards.append(reward)\n", + " if info['month'] != current_month: # display results every month\n", + " current_month = info['month']\n", + " print('Reward: ', sum(rewards), info)\n", + " print(\n", + " 'Episode ',\n", + " i,\n", + " 'Mean reward: ',\n", + " np.mean(rewards),\n", + " 'Cumulative reward: ',\n", + " sum(rewards))\n", + "env.close()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The name of the heating and cooling should be the name of action variables defined in the environment. \n", + "Otherwise, *Sinergym* will show the inconsistency.\n", + "\n", + "For more information about the format of the action definition dictionaries, visit the section called [action definition](https://ugr-sail.github.io/sinergym/compilation/html/pages/environments.html#action-definition)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Adding more extra configuration" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can even add a dictionary with extra parameters that update IDF with some new context concerned with simulation directly.\n", + "\n", + "This new IDF version, which also adapts to the new weather you put in, is saved in the Sinergym output folder, leaving the original intact:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "extra_conf={\n", " 'timesteps_per_hour':6,\n", " 'runperiod':(1,1,1991,2,1,1992),\n", - " 'action_definition': {\n", - " 'ThermostatSetpoint:DualSetpoint': [{\n", - " 'name': 'West-DualSetP-RL',\n", - " 'heating_name': 'West-HtgSetP-RL',\n", - " 'cooling_name': 'West-ClgSetP-RL',\n", - " 'zones': ['West Zone']\n", - " },\n", - " {\n", - " 'name': 'East-DualSetP-RL',\n", - " 'heating_name': 'East-HtgSetP-RL',\n", - " 'cooling_name': 'East-ClgSetP-RL',\n", - " 'zones': ['East Zone']\n", - " }]\n", - " }\n", "}\n", "\n", "env = gym.make('Eplus-datacenter-cool-continuous-stochastic-v1', \n", @@ -238,11 +446,8 @@ } ], "metadata": { - "interpreter": { - "hash": "767d51c1340bd893661ea55ea3124f6de3c7a262a8b4abca0554b478b1e2ff90" - }, "kernelspec": { - "display_name": "Python 3.9.11 64-bit", + "display_name": "Python 3.10.4 64-bit", "language": "python", "name": "python3" }, @@ -256,9 +461,14 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.10" + "version": "3.10.4" + }, + "vscode": { + "interpreter": { + "hash": "e7370f93d1d0cde622a1f8e1c04877d8463912d04d973331ad4851f04de6915a" + } } }, "nbformat": 4, "nbformat_minor": 0 -} \ No newline at end of file +} diff --git a/examples/drl.ipynb b/examples/drl.ipynb index d5c5ad657e..6ed78e8d1d 100644 --- a/examples/drl.ipynb +++ b/examples/drl.ipynb @@ -34,10 +34,8 @@ "name": "stderr", "output_type": "stream", "text": [ - "/usr/local/lib/python3.9/dist-packages/gym/logger.py:34: UserWarning: \u001b[33mWARN: Box bound precision lowered by casting to float32\u001b[0m\n", - " warnings.warn(colorize(\"%s: %s\" % (\"WARN\", msg % args), \"yellow\"))\n", - "/usr/local/lib/python3.9/dist-packages/tqdm/auto.py:22: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", - " from .autonotebook import tqdm as notebook_tqdm\n" + "/usr/local/lib/python3.10/dist-packages/gym/spaces/box.py:73: UserWarning: \u001b[33mWARN: Box bound precision lowered by casting to float32\u001b[0m\n", + " logger.warn(\n" ] } ], @@ -104,9 +102,10 @@ "name": "stderr", "output_type": "stream", "text": [ - "[2022-05-23 16:41:42,528] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:41:42,530] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:41:42,531] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n" + "[2022-08-24 09:07:06,521] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf ExternalInterface object if it is not present...\n", + "[2022-08-24 09:07:06,522] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", + "[2022-08-24 09:07:06,524] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", + "[2022-08-24 09:07:06,526] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n" ] } ], @@ -300,11 +299,11 @@ "name": "stderr", "output_type": "stream", "text": [ - "[2022-05-23 16:41:43,022] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:41:43,033] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res2/Eplus-env-sub_run1\n", - "[2022-05-23 16:41:58,161] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-23 16:41:58,162] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:41:58,172] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res2/Eplus-env-sub_run2\n" + "[2022-08-24 09:07:07,060] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:07:07,069] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res2/Eplus-env-sub_run1\n", + "[2022-08-24 09:07:20,353] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", + "[2022-08-24 09:07:20,354] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:07:20,362] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res2/Eplus-env-sub_run2\n" ] }, { @@ -314,12 +313,12 @@ "-----------------------------------\n", "| rollout/ | |\n", "| ep_len_mean | 3.5e+04 |\n", - "| ep_rew_mean | -2.25e+04 |\n", + "| ep_rew_mean | -2.24e+04 |\n", "| exploration_rate | 0.05 |\n", "| time/ | |\n", "| episodes | 1 |\n", - "| fps | 2230 |\n", - "| time_elapsed | 15 |\n", + "| fps | 2536 |\n", + "| time_elapsed | 13 |\n", "| total_timesteps | 35040 |\n", "-----------------------------------\n" ] @@ -328,63 +327,69 @@ "name": "stderr", "output_type": "stream", "text": [ - "[2022-05-23 16:42:24,200] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-23 16:42:24,201] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:42:24,213] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res2/Eplus-env-sub_run3\n", - "/usr/local/lib/python3.9/dist-packages/numpy/core/fromnumeric.py:3474: RuntimeWarning: Mean of empty slice.\n", + "[2022-08-24 09:07:42,057] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", + "[2022-08-24 09:07:42,058] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:07:42,075] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res2/Eplus-env-sub_run3\n", + "/usr/local/lib/python3.10/dist-packages/numpy/core/fromnumeric.py:3474: RuntimeWarning: Mean of empty slice.\n", " return _methods._mean(a, axis=axis, dtype=dtype,\n", - "/usr/local/lib/python3.9/dist-packages/numpy/core/_methods.py:189: RuntimeWarning: invalid value encountered in double_scalars\n", + "/usr/local/lib/python3.10/dist-packages/numpy/core/_methods.py:189: RuntimeWarning: invalid value encountered in double_scalars\n", " ret = ret.dtype.type(ret / rcount)\n", - "[2022-05-23 16:42:30,689] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-23 16:42:30,690] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:42:30,705] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res2/Eplus-env-sub_run4\n", - "[2022-05-23 16:42:48,619] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-23 16:42:48,620] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:42:48,632] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res2/Eplus-env-sub_run5\n", - "[2022-05-23 16:43:06,271] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-23 16:43:06,271] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:43:06,283] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res2/Eplus-env-sub_run6\n" + "/usr/local/lib/python3.10/dist-packages/numpy/core/_methods.py:264: RuntimeWarning: Degrees of freedom <= 0 for slice\n", + " ret = _var(a, axis=axis, dtype=dtype, out=out, ddof=ddof,\n", + "/usr/local/lib/python3.10/dist-packages/numpy/core/_methods.py:222: RuntimeWarning: invalid value encountered in true_divide\n", + " arrmean = um.true_divide(arrmean, div, out=arrmean, casting='unsafe',\n", + "/usr/local/lib/python3.10/dist-packages/numpy/core/_methods.py:256: RuntimeWarning: invalid value encountered in double_scalars\n", + " ret = ret.dtype.type(ret / rcount)\n", + "[2022-08-24 09:07:46,890] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", + "[2022-08-24 09:07:46,891] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:07:46,899] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res2/Eplus-env-sub_run4\n", + "[2022-08-24 09:08:00,708] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", + "[2022-08-24 09:08:00,711] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:08:00,726] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res2/Eplus-env-sub_run5\n", + "[2022-08-24 09:08:14,972] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", + "[2022-08-24 09:08:14,973] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:08:14,980] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res2/Eplus-env-sub_run6\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Eval num_timesteps=70080, episode_reward=-19088.19 +/- 0.00\n", + "Eval num_timesteps=70080, episode_reward=-17522.75 +/- 0.00\n", "Episode length: 35040.00 +/- 0.00\n", "New best mean reward!\n", - "---------------------------------------\n", - "| eval/ | |\n", - "| comfort_penalty | -2.03e+04 |\n", - "| comfort_violation(%) | 35.6 |\n", - "| mean_ep_length | 3.5e+04 |\n", - "| mean_power_consum... | 1.79e+08 |\n", - "| mean_rewards | -19088.19 |\n", - "| power_penalty | -1.79e+04 |\n", - "| std_rewards | 0.0 |\n", - "| rollout/ | |\n", - "| ep_len_mean | 3.5e+04 |\n", - "| ep_rew_mean | -2.07e+04 |\n", - "| exploration_rate | 0.05 |\n", - "| time/ | |\n", - "| episodes | 2 |\n", - "| fps | 835 |\n", - "| time_elapsed | 83 |\n", - "| total_timesteps | 70080 |\n", - "| train/ | |\n", - "| learning_rate | 0.0001 |\n", - "| loss | 34.7 |\n", - "| n_updates | 5019 |\n", - "---------------------------------------\n" + "-----------------------------------------\n", + "| eval/ | |\n", + "| comfort_penalty | -1.67e+04 |\n", + "| comfort_violation(%) | 35.7 |\n", + "| mean_ep_length | 3.5e+04 |\n", + "| mean_power_consumption | 1.83e+08 |\n", + "| mean_rewards | -17522.75 |\n", + "| power_penalty | -1.83e+04 |\n", + "| std_rewards | 0.0 |\n", + "| rollout/ | |\n", + "| ep_len_mean | 3.5e+04 |\n", + "| ep_rew_mean | -2.06e+04 |\n", + "| exploration_rate | 0.05 |\n", + "| time/ | |\n", + "| episodes | 2 |\n", + "| fps | 1024 |\n", + "| time_elapsed | 68 |\n", + "| total_timesteps | 70080 |\n", + "| train/ | |\n", + "| learning_rate | 0.0001 |\n", + "| loss | 61.9 |\n", + "| n_updates | 5019 |\n", + "-----------------------------------------\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "[2022-05-23 16:43:43,033] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-23 16:43:43,033] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:43:43,045] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res2/Eplus-env-sub_run7\n" + "[2022-08-24 09:08:42,072] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", + "[2022-08-24 09:08:42,073] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:08:42,080] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res2/Eplus-env-sub_run7\n" ] }, { @@ -394,16 +399,16 @@ "-----------------------------------\n", "| rollout/ | |\n", "| ep_len_mean | 3.5e+04 |\n", - "| ep_rew_mean | -1.97e+04 |\n", + "| ep_rew_mean | -1.96e+04 |\n", "| exploration_rate | 0.05 |\n", "| time/ | |\n", "| episodes | 3 |\n", - "| fps | 872 |\n", - "| time_elapsed | 120 |\n", + "| fps | 1100 |\n", + "| time_elapsed | 95 |\n", "| total_timesteps | 105120 |\n", "| train/ | |\n", "| learning_rate | 0.0001 |\n", - "| loss | 14.4 |\n", + "| loss | 15.4 |\n", "| n_updates | 13779 |\n", "-----------------------------------\n" ] @@ -412,55 +417,55 @@ "name": "stderr", "output_type": "stream", "text": [ - "[2022-05-23 16:44:15,042] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-23 16:44:15,043] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:44:15,061] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res2/Eplus-env-sub_run8\n", - "[2022-05-23 16:44:20,389] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-23 16:44:20,390] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:44:20,400] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res2/Eplus-env-sub_run9\n", - "[2022-05-23 16:44:35,500] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-23 16:44:35,502] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:44:35,522] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res2/Eplus-env-sub_run10\n", - "[2022-05-23 16:44:51,322] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-23 16:44:51,323] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:44:51,336] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res2/Eplus-env-sub_run11\n" + "[2022-08-24 09:09:09,600] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", + "[2022-08-24 09:09:09,602] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:09:09,617] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res2/Eplus-env-sub_run8\n", + "[2022-08-24 09:09:14,436] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", + "[2022-08-24 09:09:14,436] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:09:14,444] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res2/Eplus-env-sub_run9\n", + "[2022-08-24 09:09:28,929] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", + "[2022-08-24 09:09:28,929] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:09:28,936] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res2/Eplus-env-sub_run10\n", + "[2022-08-24 09:09:43,141] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", + "[2022-08-24 09:09:43,143] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:09:43,157] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res2/Eplus-env-sub_run11\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Eval num_timesteps=140160, episode_reward=-19104.20 +/- 0.00\n", + "Eval num_timesteps=140160, episode_reward=-21405.96 +/- 0.00\n", "Episode length: 35040.00 +/- 0.00\n", - "----------------------------------------\n", - "| eval/ | |\n", - "| comfort_penalty | -2.15e+04 |\n", - "| comfort_violation(%) | 39.4 |\n", - "| mean_ep_length | 3.5e+04 |\n", - "| mean_power_consum... | 1.67e+08 |\n", - "| mean_rewards | -19104.195 |\n", - "| power_penalty | -1.67e+04 |\n", - "| std_rewards | 0.0 |\n", - "| rollout/ | |\n", - "| ep_len_mean | 3.5e+04 |\n", - "| ep_rew_mean | -1.96e+04 |\n", - "| exploration_rate | 0.05 |\n", - "| time/ | |\n", - "| episodes | 4 |\n", - "| fps | 741 |\n", - "| time_elapsed | 188 |\n", - "| total_timesteps | 140160 |\n", - "| train/ | |\n", - "| learning_rate | 0.0001 |\n", - "| loss | 27.6 |\n", - "| n_updates | 22539 |\n", - "----------------------------------------\n" + "------------------------------------------\n", + "| eval/ | |\n", + "| comfort_penalty | -2.55e+04 |\n", + "| comfort_violation(%) | 40.5 |\n", + "| mean_ep_length | 3.5e+04 |\n", + "| mean_power_consumption | 1.73e+08 |\n", + "| mean_rewards | -21405.959 |\n", + "| power_penalty | -1.73e+04 |\n", + "| std_rewards | 0.0 |\n", + "| rollout/ | |\n", + "| ep_len_mean | 3.5e+04 |\n", + "| ep_rew_mean | -1.94e+04 |\n", + "| exploration_rate | 0.05 |\n", + "| time/ | |\n", + "| episodes | 4 |\n", + "| fps | 895 |\n", + "| time_elapsed | 156 |\n", + "| total_timesteps | 140160 |\n", + "| train/ | |\n", + "| learning_rate | 0.0001 |\n", + "| loss | 28.4 |\n", + "| n_updates | 22539 |\n", + "------------------------------------------\n" ] }, { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 10, @@ -521,7 +526,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "[2022-05-23 16:44:57,008] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus simulation closed successfully. \n" + "[2022-08-24 09:09:48,272] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus simulation closed successfully. \n" ] } ], @@ -549,9 +554,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.10" + "version": "3.10.4" } }, "nbformat": 4, "nbformat_minor": 0 -} \ No newline at end of file +} diff --git a/examples/personalize_loggerwrapper.ipynb b/examples/personalize_loggerwrapper.ipynb index 7b8d264463..6f2a4dbc3b 100644 --- a/examples/personalize_loggerwrapper.ipynb +++ b/examples/personalize_loggerwrapper.ipynb @@ -20,14 +20,23 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 1, "metadata": { "collapsed": true, "pycharm": { "is_executing": true } }, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/usr/local/lib/python3.10/dist-packages/gym/spaces/box.py:73: UserWarning: \u001b[33mWARN: Box bound precision lowered by casting to float32\u001b[0m\n", + " logger.warn(\n" + ] + } + ], "source": [ "import gym\n", "import numpy as np\n", @@ -55,7 +64,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 2, "metadata": { "collapsed": false, "pycharm": { @@ -129,7 +138,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 3, "metadata": { "collapsed": false, "pycharm": { @@ -141,10 +150,10 @@ "name": "stderr", "output_type": "stream", "text": [ - "[2022-06-21 09:33:58,455] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf ExternalInterface object if it is not present...\n", - "[2022-06-21 09:33:58,456] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-06-21 09:33:58,458] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-06-21 09:33:58,460] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n" + "[2022-08-24 09:20:47,476] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf ExternalInterface object if it is not present...\n", + "[2022-08-24 09:20:47,477] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", + "[2022-08-24 09:20:47,479] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", + "[2022-08-24 09:20:47,481] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n" ] } ], @@ -164,7 +173,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 4, "metadata": { "collapsed": false, "pycharm": { @@ -176,35 +185,35 @@ "name": "stderr", "output_type": "stream", "text": [ - "[2022-06-21 09:34:00,784] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-06-21 09:34:00,794] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/Eplus-env-demo-v1-res2/Eplus-env-sub_run1\n" + "[2022-08-24 09:20:47,833] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:20:47,845] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res4/Eplus-env-sub_run1\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Reward: -0.3808358083250144 {'timestep': 1, 'time_elapsed': 900, 'year': 1991, 'month': 1, 'day': 1, 'hour': 0, 'total_power': 7616.716166500288, 'total_power_no_units': -0.7616716166500288, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [20.99998783039325], 'out_temperature': 1.8, 'action_': [21, 21]}\n", - "Reward: -1817.7037351644783 {'timestep': 2976, 'time_elapsed': 2678400, 'year': 1991, 'month': 2, 'day': 1, 'hour': 0, 'total_power': 8278.265126379221, 'total_power_no_units': -0.8278265126379222, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [20.09635860317218], 'out_temperature': -7.0, 'action_': [20, 25]}\n", - "Reward: -3569.893869126496 {'timestep': 5664, 'time_elapsed': 5097600, 'year': 1991, 'month': 3, 'day': 1, 'hour': 0, 'total_power': 833.2920927358493, 'total_power_no_units': -0.08332920927358493, 'comfort_penalty': -0.43408478076705137, 'abs_comfort': 0.43408478076705137, 'temperatures': [19.56591521923295], 'out_temperature': 8.1, 'action_': [16, 29]}\n", - "Reward: -4726.825668121225 {'timestep': 8640, 'time_elapsed': 7776000, 'year': 1991, 'month': 4, 'day': 1, 'hour': 0, 'total_power': 186.5934720667916, 'total_power_no_units': -0.018659347206679163, 'comfort_penalty': -0.435109315811939, 'abs_comfort': 0.435109315811939, 'temperatures': [19.56489068418806], 'out_temperature': 7.7, 'action_': [16, 29]}\n", - "Reward: -5537.597449713271 {'timestep': 11520, 'time_elapsed': 10368000, 'year': 1991, 'month': 5, 'day': 1, 'hour': 0, 'total_power': 186.5934720667916, 'total_power_no_units': -0.018659347206679163, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [20.49458320791672], 'out_temperature': 13.0, 'action_': [16, 29]}\n", - "Reward: -6292.769417325523 {'timestep': 14496, 'time_elapsed': 13046400, 'year': 1991, 'month': 6, 'day': 1, 'hour': 0, 'total_power': 1081.566582699994, 'total_power_no_units': -0.1081566582699994, 'comfort_penalty': -1.0006063738688589, 'abs_comfort': 1.0006063738688589, 'temperatures': [21.99939362613114], 'out_temperature': 18.4, 'action_': [22, 23]}\n", - "Reward: -9282.920861126457 {'timestep': 17376, 'time_elapsed': 15638400, 'year': 1991, 'month': 7, 'day': 1, 'hour': 0, 'total_power': 215.8190761704195, 'total_power_no_units': -0.02158190761704195, 'comfort_penalty': -2.219568577307669, 'abs_comfort': 2.219568577307669, 'temperatures': [20.78043142269233], 'out_temperature': 17.7, 'action_': [19, 26]}\n", - "Reward: -12634.156075131721 {'timestep': 20352, 'time_elapsed': 18316800, 'year': 1991, 'month': 8, 'day': 1, 'hour': 0, 'total_power': 4228.056578307433, 'total_power_no_units': -0.42280565783074325, 'comfort_penalty': -3.7050000356997295, 'abs_comfort': 3.7050000356997295, 'temperatures': [19.29499996430027], 'out_temperature': 20.6, 'action_': [19, 26]}\n", - "Reward: -15998.997030178922 {'timestep': 23328, 'time_elapsed': 20995200, 'year': 1991, 'month': 9, 'day': 1, 'hour': 0, 'total_power': 367.8874627648617, 'total_power_no_units': -0.03678874627648617, 'comfort_penalty': -2.6311272146660514, 'abs_comfort': 2.6311272146660514, 'temperatures': [20.36887278533395], 'out_temperature': 18.8, 'action_': [20, 25]}\n", - "Reward: -18840.99755962802 {'timestep': 26208, 'time_elapsed': 23587200, 'year': 1991, 'month': 10, 'day': 1, 'hour': 0, 'total_power': 186.5934720667916, 'total_power_no_units': -0.018659347206679163, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [20.89715955527449], 'out_temperature': 13.3, 'action_': [20, 25]}\n", - "Reward: -19780.136585783544 {'timestep': 29184, 'time_elapsed': 26265600, 'year': 1991, 'month': 11, 'day': 1, 'hour': 0, 'total_power': 1676.829498258497, 'total_power_no_units': -0.16768294982584972, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [21.00051072214852], 'out_temperature': 13.0, 'action_': [21, 21]}\n", - "Reward: -20847.657706575505 {'timestep': 32064, 'time_elapsed': 28857600, 'year': 1991, 'month': 12, 'day': 1, 'hour': 0, 'total_power': 1300.083757928305, 'total_power_no_units': -0.1300083757928305, 'comfort_penalty': -0.8838907434947707, 'abs_comfort': 0.8838907434947707, 'temperatures': [19.11610925650523], 'out_temperature': 5.1, 'action_': [19, 26]}\n", - "Reward: -22626.148434896502 {'timestep': 35040, 'time_elapsed': 31536000, 'year': 1992, 'month': 1, 'day': 1, 'hour': 0, 'total_power': 8146.94600014605, 'total_power_no_units': -0.814694600014605, 'comfort_penalty': -2.5231669758907707, 'abs_comfort': 2.5231669758907707, 'temperatures': [17.47683302410923], 'out_temperature': -12.0, 'action_': [16, 29]}\n", - "Episode 0 Mean reward: -0.6457234142378936 Cumulative reward: -22626.148434896502\n" + "Reward: -0.2841864127941594 {'timestep': 1, 'time_elapsed': 900, 'year': 1991, 'month': 1, 'day': 1, 'hour': 0, 'total_power': 5683.728255883188, 'total_power_no_units': -0.5683728255883188, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [20.09252236706716], 'out_temperature': 1.8, 'action_': [20, 25]}\n", + "Reward: -1895.1548592605257 {'timestep': 2976, 'time_elapsed': 2678400, 'year': 1991, 'month': 2, 'day': 1, 'hour': 0, 'total_power': 8380.491234768304, 'total_power_no_units': -0.8380491234768305, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [20.21883172787526], 'out_temperature': -7.0, 'action_': [20, 25]}\n", + "Reward: -3633.6399832181337 {'timestep': 5664, 'time_elapsed': 5097600, 'year': 1991, 'month': 3, 'day': 1, 'hour': 0, 'total_power': 978.7532837048899, 'total_power_no_units': -0.097875328370489, 'comfort_penalty': -1.7869800571484404, 'abs_comfort': 1.7869800571484404, 'temperatures': [18.21301994285156], 'out_temperature': 8.1, 'action_': [15, 30]}\n", + "Reward: -4757.122309247712 {'timestep': 8640, 'time_elapsed': 7776000, 'year': 1991, 'month': 4, 'day': 1, 'hour': 0, 'total_power': 186.5934720667916, 'total_power_no_units': -0.018659347206679163, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [20.17697338689386], 'out_temperature': 7.7, 'action_': [18, 27]}\n", + "Reward: -5552.826655404054 {'timestep': 11520, 'time_elapsed': 10368000, 'year': 1991, 'month': 5, 'day': 1, 'hour': 0, 'total_power': 186.5934720667916, 'total_power_no_units': -0.018659347206679163, 'comfort_penalty': -0.72939902519715, 'abs_comfort': 0.72939902519715, 'temperatures': [19.27060097480285], 'out_temperature': 13.0, 'action_': [17, 28]}\n", + "Reward: -6263.697197328473 {'timestep': 14496, 'time_elapsed': 13046400, 'year': 1991, 'month': 6, 'day': 1, 'hour': 0, 'total_power': 386.56918097843, 'total_power_no_units': -0.038656918097843, 'comfort_penalty': -1.7596818210658398, 'abs_comfort': 1.7596818210658398, 'temperatures': [21.24031817893416], 'out_temperature': 18.4, 'action_': [21, 24]}\n", + "Reward: -9272.426890062703 {'timestep': 17376, 'time_elapsed': 15638400, 'year': 1991, 'month': 7, 'day': 1, 'hour': 0, 'total_power': 215.8105427091371, 'total_power_no_units': -0.02158105427091371, 'comfort_penalty': -2.199461395033879, 'abs_comfort': 2.199461395033879, 'temperatures': [20.80053860496612], 'out_temperature': 17.7, 'action_': [17, 28]}\n", + "Reward: -12578.3581208006 {'timestep': 20352, 'time_elapsed': 18316800, 'year': 1991, 'month': 8, 'day': 1, 'hour': 0, 'total_power': 9159.463676532796, 'total_power_no_units': -0.9159463676532796, 'comfort_penalty': -1.2923781219578103, 'abs_comfort': 1.2923781219578103, 'temperatures': [21.70762187804219], 'out_temperature': 20.6, 'action_': [22, 23]}\n", + "Reward: -15903.48380984905 {'timestep': 23328, 'time_elapsed': 20995200, 'year': 1991, 'month': 9, 'day': 1, 'hour': 0, 'total_power': 377.2264848331002, 'total_power_no_units': -0.03772264848331002, 'comfort_penalty': -2.974447422564811, 'abs_comfort': 2.974447422564811, 'temperatures': [20.02555257743519], 'out_temperature': 18.8, 'action_': [20, 25]}\n", + "Reward: -18733.26101206708 {'timestep': 26208, 'time_elapsed': 23587200, 'year': 1991, 'month': 10, 'day': 1, 'hour': 0, 'total_power': 186.5934720667916, 'total_power_no_units': -0.018659347206679163, 'comfort_penalty': -0.27470801492377106, 'abs_comfort': 0.27470801492377106, 'temperatures': [19.72529198507623], 'out_temperature': 13.3, 'action_': [17, 28]}\n", + "Reward: -19665.3048157153 {'timestep': 29184, 'time_elapsed': 26265600, 'year': 1991, 'month': 11, 'day': 1, 'hour': 0, 'total_power': 2998.063053624272, 'total_power_no_units': -0.2998063053624272, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [21.98445623259406], 'out_temperature': 13.0, 'action_': [22, 23]}\n", + "Reward: -20679.519834589526 {'timestep': 32064, 'time_elapsed': 28857600, 'year': 1991, 'month': 12, 'day': 1, 'hour': 0, 'total_power': 6282.049444658835, 'total_power_no_units': -0.6282049444658835, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [20.45374695271586], 'out_temperature': 5.1, 'action_': [22, 22]}\n", + "Reward: -22419.718732977875 {'timestep': 35040, 'time_elapsed': 31536000, 'year': 1992, 'month': 1, 'day': 1, 'hour': 0, 'total_power': 12473.66081362551, 'total_power_no_units': -1.2473660813625511, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [20.43771976775179], 'out_temperature': -12.0, 'action_': [21, 21]}\n", + "Episode 0 Mean reward: -0.639832155621491 Cumulative reward: -22419.718732977875\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "[2022-06-21 09:34:15,548] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus simulation closed successfully. \n" + "[2022-08-24 09:21:00,208] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus simulation closed successfully. \n" ] } ], diff --git a/examples/rule_controller_example.ipynb b/examples/rule_controller_example.ipynb index 54c4498b8f..b774c37775 100644 --- a/examples/rule_controller_example.ipynb +++ b/examples/rule_controller_example.ipynb @@ -20,11 +20,20 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 1, "metadata": { "collapsed": true }, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/usr/local/lib/python3.10/dist-packages/gym/spaces/box.py:73: UserWarning: \u001b[33mWARN: Box bound precision lowered by casting to float32\u001b[0m\n", + " logger.warn(\n" + ] + } + ], "source": [ "from typing import List, Any, Sequence\n", "from sinergym.utils.common import get_season_comfort_range\n", @@ -45,7 +54,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 2, "metadata": { "collapsed": false, "pycharm": { @@ -57,15 +66,10 @@ "name": "stderr", "output_type": "stream", "text": [ - "[2022-05-23 16:43:26,104] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:43:26,104] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:43:26,104] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:43:26,107] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:43:26,107] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:43:26,107] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:43:26,111] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", - "[2022-05-23 16:43:26,111] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", - "[2022-05-23 16:43:26,111] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n" + "[2022-08-24 09:21:11,092] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf ExternalInterface object if it is not present...\n", + "[2022-08-24 09:21:11,093] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", + "[2022-08-24 09:21:11,095] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", + "[2022-08-24 09:21:11,097] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n" ] } ], @@ -84,7 +88,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 3, "metadata": { "collapsed": false, "pycharm": { @@ -166,7 +170,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 4, "metadata": { "collapsed": false, "pycharm": { @@ -178,35 +182,28 @@ "name": "stderr", "output_type": "stream", "text": [ - "[2022-05-23 16:44:48,429] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-23 16:44:48,429] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-23 16:44:48,429] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-23 16:44:48,430] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:44:48,430] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:44:48,430] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:44:48,443] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res10/Eplus-env-sub_run2\n", - "[2022-05-23 16:44:48,443] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res10/Eplus-env-sub_run2\n", - "[2022-05-23 16:44:48,443] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res10/Eplus-env-sub_run2\n" + "[2022-08-24 09:21:11,676] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:21:11,687] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res5/Eplus-env-sub_run1\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Reward: -0.3808358083250143 {'timestep': 1, 'time_elapsed': 900, 'year': 1991, 'month': 1, 'day': 1, 'hour': 0, 'total_power': 7616.716166500285, 'total_power_no_units': -0.7616716166500286, 'comfort_penalty': -0.0, 'temperatures': [20.99998783039325], 'out_temperature': 1.8, 'action_': [21.0, 25.0]}\n", - "Reward: -1394.933741103853 {'timestep': 2976, 'time_elapsed': 2678400, 'year': 1991, 'month': 2, 'day': 1, 'hour': 0, 'total_power': 8783.948537124963, 'total_power_no_units': -0.8783948537124964, 'comfort_penalty': -0.0, 'temperatures': [20.32998668433318], 'out_temperature': -7.0, 'action_': [20.33, 25.33]}\n", - "Reward: -2650.5674622643014 {'timestep': 5664, 'time_elapsed': 5097600, 'year': 1991, 'month': 3, 'day': 1, 'hour': 0, 'total_power': 2828.551434642312, 'total_power_no_units': -0.2828551434642312, 'comfort_penalty': -0.0, 'temperatures': [20.32988764119706], 'out_temperature': 8.1, 'action_': [20.33, 25.33]}\n", - "Reward: -3464.4534634130637 {'timestep': 8640, 'time_elapsed': 7776000, 'year': 1991, 'month': 4, 'day': 1, 'hour': 0, 'total_power': 186.5934720667916, 'total_power_no_units': -0.018659347206679163, 'comfort_penalty': -1.2670384566951505, 'temperatures': [18.73296154330485], 'out_temperature': 7.7, 'action_': [18.33, 23.33]}\n", - "Reward: -4056.362905023052 {'timestep': 11520, 'time_elapsed': 10368000, 'year': 1991, 'month': 5, 'day': 1, 'hour': 0, 'total_power': 1049.348956006732, 'total_power_no_units': -0.10493489560067319, 'comfort_penalty': -0.0, 'temperatures': [20.33021459066708], 'out_temperature': 13.0, 'action_': [20.33, 25.33]}\n", - "Reward: -4575.388821261888 {'timestep': 14496, 'time_elapsed': 13046400, 'year': 1991, 'month': 6, 'day': 1, 'hour': 0, 'total_power': 602.6474404745787, 'total_power_no_units': -0.06026474404745787, 'comfort_penalty': -2.6702171176743406, 'temperatures': [20.32978288232566], 'out_temperature': 18.4, 'action_': [20.33, 25.33]}\n", - "Reward: -5959.068563514961 {'timestep': 17376, 'time_elapsed': 15638400, 'year': 1991, 'month': 7, 'day': 1, 'hour': 0, 'total_power': 215.8105427085715, 'total_power_no_units': -0.02158105427085715, 'comfort_penalty': -2.871010625169369, 'temperatures': [20.12898937483063], 'out_temperature': 17.7, 'action_': [18.33, 23.33]}\n", - "Reward: -7457.679714984278 {'timestep': 20352, 'time_elapsed': 18316800, 'year': 1991, 'month': 8, 'day': 1, 'hour': 0, 'total_power': 9961.587143366478, 'total_power_no_units': -0.9961587143366478, 'comfort_penalty': -0.0, 'temperatures': [23.33021175763765], 'out_temperature': 20.6, 'action_': [23.33, 28.33]}\n", - "Reward: -8981.302898158818 {'timestep': 23328, 'time_elapsed': 20995200, 'year': 1991, 'month': 9, 'day': 1, 'hour': 0, 'total_power': 1814.198506979714, 'total_power_no_units': -0.1814198506979714, 'comfort_penalty': -0.0, 'temperatures': [23.32960549764289], 'out_temperature': 18.8, 'action_': [23.33, 28.33]}\n", - "Reward: -10197.28247814917 {'timestep': 26208, 'time_elapsed': 23587200, 'year': 1991, 'month': 10, 'day': 1, 'hour': 0, 'total_power': 2130.682079753009, 'total_power_no_units': -0.2130682079753009, 'comfort_penalty': -0.0, 'temperatures': [23.33031354561692], 'out_temperature': 13.3, 'action_': [23.33, 28.33]}\n", - "Reward: -10685.569288303852 {'timestep': 29184, 'time_elapsed': 26265600, 'year': 1991, 'month': 11, 'day': 1, 'hour': 0, 'total_power': 944.0904158092015, 'total_power_no_units': -0.09440904158092016, 'comfort_penalty': -0.0, 'temperatures': [20.33017991675662], 'out_temperature': 13.0, 'action_': [20.33, 25.33]}\n", - "Reward: -11374.36750934867 {'timestep': 32064, 'time_elapsed': 28857600, 'year': 1991, 'month': 12, 'day': 1, 'hour': 0, 'total_power': 2788.852968187345, 'total_power_no_units': -0.27888529681873453, 'comfort_penalty': -0.0, 'temperatures': [20.32995260044678], 'out_temperature': 5.1, 'action_': [20.33, 25.33]}\n", - "Reward: -12774.026233137427 {'timestep': 35040, 'time_elapsed': 31536000, 'year': 1992, 'month': 1, 'day': 1, 'hour': 0, 'total_power': 10847.14414165405, 'total_power_no_units': -1.084714414165405, 'comfort_penalty': -0.0, 'temperatures': [20.33000003505644], 'out_temperature': -12.0, 'action_': [20.33, 25.33]}\n", - "Episode 0 Mean reward: -0.36455554318315797 Cumulative reward: -12774.026233137427\n" + "Reward: -0.3808358083250144 {'timestep': 1, 'time_elapsed': 900, 'year': 1991, 'month': 1, 'day': 1, 'hour': 0, 'total_power': 7616.716166500288, 'total_power_no_units': -0.7616716166500288, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [20.99998783039325], 'out_temperature': 1.8, 'action_': [21.0, 25.0]}\n", + "Reward: -1394.9337411038548 {'timestep': 2976, 'time_elapsed': 2678400, 'year': 1991, 'month': 2, 'day': 1, 'hour': 0, 'total_power': 8783.948537124865, 'total_power_no_units': -0.8783948537124865, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [20.32998668433318], 'out_temperature': -7.0, 'action_': [20.33, 25.33]}\n", + "Reward: -2650.5674622643073 {'timestep': 5664, 'time_elapsed': 5097600, 'year': 1991, 'month': 3, 'day': 1, 'hour': 0, 'total_power': 2828.55143464232, 'total_power_no_units': -0.282855143464232, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [20.32988764119707], 'out_temperature': 8.1, 'action_': [20.33, 25.33]}\n", + "Reward: -3464.45346341394 {'timestep': 8640, 'time_elapsed': 7776000, 'year': 1991, 'month': 4, 'day': 1, 'hour': 0, 'total_power': 186.5934720667916, 'total_power_no_units': -0.018659347206679163, 'comfort_penalty': -1.2670384566951398, 'abs_comfort': 1.2670384566951398, 'temperatures': [18.73296154330486], 'out_temperature': 7.7, 'action_': [18.33, 23.33]}\n", + "Reward: -4056.362905025186 {'timestep': 11520, 'time_elapsed': 10368000, 'year': 1991, 'month': 5, 'day': 1, 'hour': 0, 'total_power': 1049.348956006743, 'total_power_no_units': -0.1049348956006743, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [20.33021459066708], 'out_temperature': 13.0, 'action_': [20.33, 25.33]}\n", + "Reward: -4575.388821263204 {'timestep': 14496, 'time_elapsed': 13046400, 'year': 1991, 'month': 6, 'day': 1, 'hour': 0, 'total_power': 602.6474404745892, 'total_power_no_units': -0.06026474404745892, 'comfort_penalty': -2.67021711767433, 'abs_comfort': 2.67021711767433, 'temperatures': [20.32978288232567], 'out_temperature': 18.4, 'action_': [20.33, 25.33]}\n", + "Reward: -5959.068563513181 {'timestep': 17376, 'time_elapsed': 15638400, 'year': 1991, 'month': 7, 'day': 1, 'hour': 0, 'total_power': 215.8105427085715, 'total_power_no_units': -0.02158105427085715, 'comfort_penalty': -2.8710106251693617, 'abs_comfort': 2.8710106251693617, 'temperatures': [20.12898937483064], 'out_temperature': 17.7, 'action_': [18.33, 23.33]}\n", + "Reward: -7457.679714954765 {'timestep': 20352, 'time_elapsed': 18316800, 'year': 1991, 'month': 8, 'day': 1, 'hour': 0, 'total_power': 9961.58714336648, 'total_power_no_units': -0.996158714336648, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [23.33021175763765], 'out_temperature': 20.6, 'action_': [23.33, 28.33]}\n", + "Reward: -8981.302898129286 {'timestep': 23328, 'time_elapsed': 20995200, 'year': 1991, 'month': 9, 'day': 1, 'hour': 0, 'total_power': 1814.198506979717, 'total_power_no_units': -0.1814198506979717, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [23.32960549764289], 'out_temperature': 18.8, 'action_': [23.33, 28.33]}\n", + "Reward: -10197.282478127578 {'timestep': 26208, 'time_elapsed': 23587200, 'year': 1991, 'month': 10, 'day': 1, 'hour': 0, 'total_power': 2130.682079753009, 'total_power_no_units': -0.2130682079753009, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [23.33031354561692], 'out_temperature': 13.3, 'action_': [23.33, 28.33]}\n", + "Reward: -10685.5692882536 {'timestep': 29184, 'time_elapsed': 26265600, 'year': 1991, 'month': 11, 'day': 1, 'hour': 0, 'total_power': 944.0904158092028, 'total_power_no_units': -0.09440904158092028, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [20.33017991675662], 'out_temperature': 13.0, 'action_': [20.33, 25.33]}\n", + "Reward: -11374.367509294058 {'timestep': 32064, 'time_elapsed': 28857600, 'year': 1991, 'month': 12, 'day': 1, 'hour': 0, 'total_power': 2788.852968187356, 'total_power_no_units': -0.27888529681873564, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [20.32995260044678], 'out_temperature': 5.1, 'action_': [20.33, 25.33]}\n", + "Reward: -12774.026233082805 {'timestep': 35040, 'time_elapsed': 31536000, 'year': 1992, 'month': 1, 'day': 1, 'hour': 0, 'total_power': 10847.14414165407, 'total_power_no_units': -1.084714414165407, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [20.33000003505644], 'out_temperature': -12.0, 'action_': [20.33, 25.33]}\n", + "Episode 0 Mean reward: -0.3645555431815984 Cumulative reward: -12774.026233082805\n" ] } ], @@ -247,7 +244,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 5, "metadata": { "collapsed": false, "pycharm": { @@ -259,9 +256,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "[2022-05-23 16:44:59,813] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus simulation closed successfully. \n", - "[2022-05-23 16:44:59,813] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus simulation closed successfully. \n", - "[2022-05-23 16:44:59,813] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus simulation closed successfully. \n" + "[2022-08-24 09:21:20,536] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus simulation closed successfully. \n" ] } ], @@ -296,9 +291,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.10" + "version": "3.10.4" } }, "nbformat": 4, "nbformat_minor": 0 -} \ No newline at end of file +} diff --git a/examples/wrappers_examples.ipynb b/examples/wrappers_examples.ipynb index 6c48d931fe..786b080eb7 100644 --- a/examples/wrappers_examples.ipynb +++ b/examples/wrappers_examples.ipynb @@ -21,14 +21,23 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 1, "metadata": { "collapsed": true, "pycharm": { "is_executing": true } }, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/usr/local/lib/python3.10/dist-packages/gym/spaces/box.py:73: UserWarning: \u001b[33mWARN: Box bound precision lowered by casting to float32\u001b[0m\n", + " logger.warn(\n" + ] + } + ], "source": [ "import gym\n", "import numpy as np\n", @@ -47,7 +56,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 2, "metadata": { "collapsed": false, "pycharm": { @@ -59,31 +68,12 @@ "name": "stderr", "output_type": "stream", "text": [ - "[2022-05-23 16:41:54,693] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:41:54,693] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:41:54,693] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:41:54,693] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:41:54,693] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:41:54,696] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:41:54,696] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:41:54,696] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:41:54,696] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:41:54,696] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:41:54,699] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", - "[2022-05-23 16:41:54,699] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", - "[2022-05-23 16:41:54,699] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", - "[2022-05-23 16:41:54,699] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", - "[2022-05-23 16:41:54,699] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", - "[2022-05-23 16:41:54,702] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:41:54,702] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:41:54,702] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:41:54,702] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:41:54,702] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:41:54,714] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res5/Eplus-env-sub_run1\n", - "[2022-05-23 16:41:54,714] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res5/Eplus-env-sub_run1\n", - "[2022-05-23 16:41:54,714] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res5/Eplus-env-sub_run1\n", - "[2022-05-23 16:41:54,714] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res5/Eplus-env-sub_run1\n", - "[2022-05-23 16:41:54,714] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res5/Eplus-env-sub_run1\n" + "[2022-08-24 09:25:01,984] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf ExternalInterface object if it is not present...\n", + "[2022-08-24 09:25:01,986] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", + "[2022-08-24 09:25:01,990] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", + "[2022-08-24 09:25:01,993] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", + "[2022-08-24 09:25:01,997] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:25:02,013] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res7/Eplus-env-sub_run1\n" ] }, { @@ -100,21 +90,9 @@ "name": "stderr", "output_type": "stream", "text": [ - "[2022-05-23 16:42:00,247] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-23 16:42:00,247] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-23 16:42:00,247] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-23 16:42:00,247] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-23 16:42:00,247] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-23 16:42:00,249] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:42:00,249] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:42:00,249] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:42:00,249] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:42:00,249] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:42:00,261] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res5/Eplus-env-sub_run2\n", - "[2022-05-23 16:42:00,261] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res5/Eplus-env-sub_run2\n", - "[2022-05-23 16:42:00,261] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res5/Eplus-env-sub_run2\n", - "[2022-05-23 16:42:00,261] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res5/Eplus-env-sub_run2\n", - "[2022-05-23 16:42:00,261] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res5/Eplus-env-sub_run2\n" + "[2022-08-24 09:25:07,442] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", + "[2022-08-24 09:25:07,443] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:25:07,451] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res7/Eplus-env-sub_run2\n" ] }, { @@ -149,7 +127,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 3, "metadata": { "collapsed": false, "pycharm": { @@ -161,24 +139,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "[2022-05-23 16:42:01,844] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:42:01,844] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:42:01,844] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:42:01,844] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:42:01,844] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:42:01,844] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:42:01,847] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:42:01,847] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:42:01,847] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:42:01,847] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:42:01,847] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:42:01,847] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:42:01,851] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", - "[2022-05-23 16:42:01,851] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", - "[2022-05-23 16:42:01,851] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", - "[2022-05-23 16:42:01,851] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", - "[2022-05-23 16:42:01,851] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", - "[2022-05-23 16:42:01,851] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n" + "[2022-08-24 09:25:08,780] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf ExternalInterface object if it is not present...\n", + "[2022-08-24 09:25:08,780] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf ExternalInterface object if it is not present...\n", + "[2022-08-24 09:25:08,784] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", + "[2022-08-24 09:25:08,784] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", + "[2022-08-24 09:25:08,788] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", + "[2022-08-24 09:25:08,788] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", + "[2022-08-24 09:25:08,792] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", + "[2022-08-24 09:25:08,792] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n" ] } ], @@ -203,7 +171,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 4, "metadata": { "collapsed": false, "pycharm": { @@ -215,41 +183,24 @@ "name": "stderr", "output_type": "stream", "text": [ - "[2022-05-23 16:42:02,770] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:42:02,770] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:42:02,770] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:42:02,770] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:42:02,770] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:42:02,770] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:42:02,770] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:42:02,773] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:42:02,773] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:42:02,773] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:42:02,773] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:42:02,773] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:42:02,773] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:42:02,773] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:42:02,777] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", - "[2022-05-23 16:42:02,777] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", - "[2022-05-23 16:42:02,777] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", - "[2022-05-23 16:42:02,777] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", - "[2022-05-23 16:42:02,777] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", - "[2022-05-23 16:42:02,777] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", - "[2022-05-23 16:42:02,777] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", - "[2022-05-23 16:42:02,779] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:42:02,779] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:42:02,779] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:42:02,779] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:42:02,779] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:42:02,779] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:42:02,779] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:42:02,792] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res7/Eplus-env-sub_run1\n", - "[2022-05-23 16:42:02,792] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res7/Eplus-env-sub_run1\n", - "[2022-05-23 16:42:02,792] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res7/Eplus-env-sub_run1\n", - "[2022-05-23 16:42:02,792] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res7/Eplus-env-sub_run1\n", - "[2022-05-23 16:42:02,792] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res7/Eplus-env-sub_run1\n", - "[2022-05-23 16:42:02,792] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res7/Eplus-env-sub_run1\n", - "[2022-05-23 16:42:02,792] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res7/Eplus-env-sub_run1\n" + "[2022-08-24 09:25:10,424] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf ExternalInterface object if it is not present...\n", + "[2022-08-24 09:25:10,424] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf ExternalInterface object if it is not present...\n", + "[2022-08-24 09:25:10,424] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf ExternalInterface object if it is not present...\n", + "[2022-08-24 09:25:10,427] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", + "[2022-08-24 09:25:10,427] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", + "[2022-08-24 09:25:10,427] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", + "[2022-08-24 09:25:10,430] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", + "[2022-08-24 09:25:10,430] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", + "[2022-08-24 09:25:10,430] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", + "[2022-08-24 09:25:10,433] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", + "[2022-08-24 09:25:10,433] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", + "[2022-08-24 09:25:10,433] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", + "[2022-08-24 09:25:10,436] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:25:10,436] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:25:10,436] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:25:10,452] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res9/Eplus-env-sub_run1\n", + "[2022-08-24 09:25:10,452] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res9/Eplus-env-sub_run1\n", + "[2022-08-24 09:25:10,452] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res9/Eplus-env-sub_run1\n" ] }, { @@ -266,27 +217,15 @@ "name": "stderr", "output_type": "stream", "text": [ - "[2022-05-23 16:42:08,781] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-23 16:42:08,781] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-23 16:42:08,781] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-23 16:42:08,781] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-23 16:42:08,781] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-23 16:42:08,781] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-23 16:42:08,781] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", - "[2022-05-23 16:42:08,783] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:42:08,783] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:42:08,783] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:42:08,783] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:42:08,783] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:42:08,783] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:42:08,783] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:42:08,798] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res7/Eplus-env-sub_run2\n", - "[2022-05-23 16:42:08,798] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res7/Eplus-env-sub_run2\n", - "[2022-05-23 16:42:08,798] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res7/Eplus-env-sub_run2\n", - "[2022-05-23 16:42:08,798] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res7/Eplus-env-sub_run2\n", - "[2022-05-23 16:42:08,798] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res7/Eplus-env-sub_run2\n", - "[2022-05-23 16:42:08,798] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res7/Eplus-env-sub_run2\n", - "[2022-05-23 16:42:08,798] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res7/Eplus-env-sub_run2\n" + "[2022-08-24 09:25:15,441] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", + "[2022-08-24 09:25:15,441] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", + "[2022-08-24 09:25:15,441] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus episode completed successfully. \n", + "[2022-08-24 09:25:15,442] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:25:15,442] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:25:15,442] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:25:15,451] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res9/Eplus-env-sub_run2\n", + "[2022-08-24 09:25:15,451] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res9/Eplus-env-sub_run2\n", + "[2022-08-24 09:25:15,451] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res9/Eplus-env-sub_run2\n" ] }, { @@ -344,37 +283,29 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "[2022-05-23 16:42:10,602] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:42:10,602] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:42:10,602] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:42:10,602] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:42:10,602] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:42:10,602] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:42:10,602] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:42:10,602] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", - "[2022-05-23 16:42:10,606] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:42:10,606] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:42:10,606] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:42:10,606] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:42:10,606] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:42:10,606] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:42:10,606] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:42:10,606] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", - "[2022-05-23 16:42:10,609] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", - "[2022-05-23 16:42:10,609] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", - "[2022-05-23 16:42:10,609] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", - "[2022-05-23 16:42:10,609] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", - "[2022-05-23 16:42:10,609] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", - "[2022-05-23 16:42:10,609] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", - "[2022-05-23 16:42:10,609] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", - "[2022-05-23 16:42:10,609] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n" + "[2022-08-24 09:25:16,978] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf ExternalInterface object if it is not present...\n", + "[2022-08-24 09:25:16,978] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf ExternalInterface object if it is not present...\n", + "[2022-08-24 09:25:16,978] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf ExternalInterface object if it is not present...\n", + "[2022-08-24 09:25:16,978] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf ExternalInterface object if it is not present...\n", + "[2022-08-24 09:25:16,981] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", + "[2022-08-24 09:25:16,981] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", + "[2022-08-24 09:25:16,981] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", + "[2022-08-24 09:25:16,981] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...\n", + "[2022-08-24 09:25:16,985] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", + "[2022-08-24 09:25:16,985] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", + "[2022-08-24 09:25:16,985] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", + "[2022-08-24 09:25:16,985] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.\n", + "[2022-08-24 09:25:16,990] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", + "[2022-08-24 09:25:16,990] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", + "[2022-08-24 09:25:16,990] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n", + "[2022-08-24 09:25:16,990] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...\n" ] } ], @@ -411,7 +342,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 6, "metadata": { "collapsed": false, "pycharm": { @@ -423,56 +354,44 @@ "name": "stderr", "output_type": "stream", "text": [ - "[2022-05-23 16:42:10,692] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:42:10,692] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:42:10,692] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:42:10,692] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:42:10,692] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:42:10,692] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:42:10,692] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:42:10,692] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", - "[2022-05-23 16:42:10,709] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res8/Eplus-env-sub_run1\n", - "[2022-05-23 16:42:10,709] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res8/Eplus-env-sub_run1\n", - "[2022-05-23 16:42:10,709] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res8/Eplus-env-sub_run1\n", - "[2022-05-23 16:42:10,709] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res8/Eplus-env-sub_run1\n", - "[2022-05-23 16:42:10,709] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res8/Eplus-env-sub_run1\n", - "[2022-05-23 16:42:10,709] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res8/Eplus-env-sub_run1\n", - "[2022-05-23 16:42:10,709] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res8/Eplus-env-sub_run1\n", - "[2022-05-23 16:42:10,709] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res8/Eplus-env-sub_run1\n" + "[2022-08-24 09:25:17,309] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:25:17,309] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:25:17,309] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:25:17,309] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...\n", + "[2022-08-24 09:25:17,326] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res10/Eplus-env-sub_run1\n", + "[2022-08-24 09:25:17,326] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res10/Eplus-env-sub_run1\n", + "[2022-08-24 09:25:17,326] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res10/Eplus-env-sub_run1\n", + "[2022-08-24 09:25:17,326] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res10/Eplus-env-sub_run1\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Reward: -0.3808358083250143 {'timestep': 1, 'time_elapsed': 900, 'year': 1991, 'month': 1, 'day': 1, 'hour': 0, 'total_power': 7616.716166500285, 'total_power_no_units': -0.7616716166500286, 'comfort_penalty': -0.0, 'temperatures': [20.99998783039325], 'out_temperature': 1.8, 'action_': [21, 21]}\n", - "Reward: -1871.2735943472342 {'timestep': 2976, 'time_elapsed': 2678400, 'year': 1991, 'month': 2, 'day': 1, 'hour': 0, 'total_power': 4717.088000520113, 'total_power_no_units': -0.4717088000520114, 'comfort_penalty': -1.7573715796282414, 'temperatures': [18.24262842037176], 'out_temperature': -7.0, 'action_': [17, 28]}\n", - "Reward: -3591.708406946749 {'timestep': 5664, 'time_elapsed': 5097600, 'year': 1991, 'month': 3, 'day': 1, 'hour': 0, 'total_power': 1914.018114977942, 'total_power_no_units': -0.19140181149779423, 'comfort_penalty': -1.0756168928023513, 'temperatures': [18.92438310719765], 'out_temperature': 8.1, 'action_': [19, 26]}\n", - "Reward: -4739.976056551516 {'timestep': 8640, 'time_elapsed': 7776000, 'year': 1991, 'month': 4, 'day': 1, 'hour': 0, 'total_power': 186.5934720667916, 'total_power_no_units': -0.018659347206679163, 'comfort_penalty': -0.41562783370860856, 'temperatures': [19.58437216629139], 'out_temperature': 7.7, 'action_': [17, 28]}\n", - "Reward: -5546.170775112516 {'timestep': 11520, 'time_elapsed': 10368000, 'year': 1991, 'month': 5, 'day': 1, 'hour': 0, 'total_power': 186.5934720667916, 'total_power_no_units': -0.018659347206679163, 'comfort_penalty': -0.6675625711856412, 'temperatures': [19.33243742881436], 'out_temperature': 13.0, 'action_': [16, 29]}\n", - "Reward: -6291.521621999336 {'timestep': 14496, 'time_elapsed': 13046400, 'year': 1991, 'month': 6, 'day': 1, 'hour': 0, 'total_power': 311.2037337978678, 'total_power_no_units': -0.03112037337978678, 'comfort_penalty': -2.76487463809368, 'temperatures': [20.23512536190632], 'out_temperature': 18.4, 'action_': [19, 26]}\n", - "Reward: -9278.775602691854 {'timestep': 17376, 'time_elapsed': 15638400, 'year': 1991, 'month': 7, 'day': 1, 'hour': 0, 'total_power': 215.8105427085715, 'total_power_no_units': -0.02158105427085715, 'comfort_penalty': -2.717878688683829, 'temperatures': [20.28212131131617], 'out_temperature': 17.7, 'action_': [18, 27]}\n", - "Reward: -12603.078345531798 {'timestep': 20352, 'time_elapsed': 18316800, 'year': 1991, 'month': 8, 'day': 1, 'hour': 0, 'total_power': 9710.545171272992, 'total_power_no_units': -0.9710545171272993, 'comfort_penalty': -1.6105363983255216, 'temperatures': [21.38946360167448], 'out_temperature': 20.6, 'action_': [22, 23]}\n", - "Reward: -15898.38172607886 {'timestep': 23328, 'time_elapsed': 20995200, 'year': 1991, 'month': 9, 'day': 1, 'hour': 0, 'total_power': 2724.07911675267, 'total_power_no_units': -0.272407911675267, 'comfort_penalty': -1.0412778161750396, 'temperatures': [21.95872218382496], 'out_temperature': 18.8, 'action_': [22, 22]}\n", - "Reward: -18741.72328624202 {'timestep': 26208, 'time_elapsed': 23587200, 'year': 1991, 'month': 10, 'day': 1, 'hour': 0, 'total_power': 513.7610654329847, 'total_power_no_units': -0.051376106543298466, 'comfort_penalty': -0.0025701501132289195, 'temperatures': [19.99742984988677], 'out_temperature': 13.3, 'action_': [20, 25]}\n", - "Reward: -19653.923057089025 {'timestep': 29184, 'time_elapsed': 26265600, 'year': 1991, 'month': 11, 'day': 1, 'hour': 0, 'total_power': 186.5934720667916, 'total_power_no_units': -0.018659347206679163, 'comfort_penalty': -0.16125875764038966, 'temperatures': [19.83874124235961], 'out_temperature': 13.0, 'action_': [18, 27]}\n", - "Reward: -20670.415163107275 {'timestep': 32064, 'time_elapsed': 28857600, 'year': 1991, 'month': 12, 'day': 1, 'hour': 0, 'total_power': 2374.725317005226, 'total_power_no_units': -0.2374725317005226, 'comfort_penalty': -0.0, 'temperatures': [21.17986449699296], 'out_temperature': 5.1, 'action_': [21, 24]}\n", - "Reward: -22461.581130904375 {'timestep': 35040, 'time_elapsed': 31536000, 'year': 1992, 'month': 1, 'day': 1, 'hour': 0, 'total_power': 7149.075848784849, 'total_power_no_units': -0.7149075848784849, 'comfort_penalty': -1.7503558827192691, 'temperatures': [18.24964411728073], 'out_temperature': -12.0, 'action_': [15, 30]}\n", - "Episode 0 Mean reward: -0.6410268587586611 Cumulative reward: -22461.581130904375\n" + "Reward: -0.6725497890372522 {'timestep': 1, 'time_elapsed': 900, 'year': 1991, 'month': 1, 'day': 1, 'hour': 0, 'total_power': 3133.716390651042, 'total_power_no_units': -0.3133716390651042, 'comfort_penalty': -1.0317279390094, 'abs_comfort': 1.0317279390094, 'temperatures': [18.9682720609906], 'out_temperature': 1.8, 'action_': [18, 27]}\n", + "Reward: -1831.9846868749223 {'timestep': 2976, 'time_elapsed': 2678400, 'year': 1991, 'month': 2, 'day': 1, 'hour': 0, 'total_power': 9625.868884432568, 'total_power_no_units': -0.9625868884432568, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [20.99962719644226], 'out_temperature': -7.0, 'action_': [21, 21]}\n", + "Reward: -3572.1163979019448 {'timestep': 5664, 'time_elapsed': 5097600, 'year': 1991, 'month': 3, 'day': 1, 'hour': 0, 'total_power': 3381.835883111865, 'total_power_no_units': -0.3381835883111865, 'comfort_penalty': -0.04845287512533858, 'abs_comfort': 0.04845287512533858, 'temperatures': [19.95154712487466], 'out_temperature': 8.1, 'action_': [20, 25]}\n", + "Reward: -4744.85182426822 {'timestep': 8640, 'time_elapsed': 7776000, 'year': 1991, 'month': 4, 'day': 1, 'hour': 0, 'total_power': 1059.217058241587, 'total_power_no_units': -0.1059217058241587, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [21.02705837058395], 'out_temperature': 7.7, 'action_': [21, 21]}\n", + "Reward: -5541.648792015279 {'timestep': 11520, 'time_elapsed': 10368000, 'year': 1991, 'month': 5, 'day': 1, 'hour': 0, 'total_power': 186.5934720667916, 'total_power_no_units': -0.018659347206679163, 'comfort_penalty': -0.6904987523763602, 'abs_comfort': 0.6904987523763602, 'temperatures': [19.30950124762364], 'out_temperature': 13.0, 'action_': [19, 26]}\n", + "Reward: -6265.521158571141 {'timestep': 14496, 'time_elapsed': 13046400, 'year': 1991, 'month': 6, 'day': 1, 'hour': 0, 'total_power': 2706.140914592288, 'total_power_no_units': -0.2706140914592288, 'comfort_penalty': -1.0741537654487203, 'abs_comfort': 1.0741537654487203, 'temperatures': [21.92584623455128], 'out_temperature': 18.4, 'action_': [22, 23]}\n", + "Reward: -9267.105328861617 {'timestep': 17376, 'time_elapsed': 15638400, 'year': 1991, 'month': 7, 'day': 1, 'hour': 0, 'total_power': 215.8190761707732, 'total_power_no_units': -0.02158190761707732, 'comfort_penalty': -1.709210011679879, 'abs_comfort': 1.709210011679879, 'temperatures': [21.29078998832012], 'out_temperature': 17.7, 'action_': [16, 29]}\n", + "Reward: -12581.239530466879 {'timestep': 20352, 'time_elapsed': 18316800, 'year': 1991, 'month': 8, 'day': 1, 'hour': 0, 'total_power': 4303.552629721591, 'total_power_no_units': -0.43035526297215915, 'comfort_penalty': -3.137288347910051, 'abs_comfort': 3.137288347910051, 'temperatures': [19.86271165208995], 'out_temperature': 20.6, 'action_': [17, 28]}\n", + "Reward: -15889.752598388217 {'timestep': 23328, 'time_elapsed': 20995200, 'year': 1991, 'month': 9, 'day': 1, 'hour': 0, 'total_power': 2547.043642249929, 'total_power_no_units': -0.2547043642249929, 'comfort_penalty': -1.0062198564813798, 'abs_comfort': 1.0062198564813798, 'temperatures': [21.99378014351862], 'out_temperature': 18.8, 'action_': [22, 23]}\n", + "Reward: -18686.835610714406 {'timestep': 26208, 'time_elapsed': 23587200, 'year': 1991, 'month': 10, 'day': 1, 'hour': 0, 'total_power': 1683.24724933671, 'total_power_no_units': -0.168324724933671, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [20.98601762250864], 'out_temperature': 13.3, 'action_': [21, 24]}\n", + "Reward: -19616.273201273543 {'timestep': 29184, 'time_elapsed': 26265600, 'year': 1991, 'month': 11, 'day': 1, 'hour': 0, 'total_power': 1971.816419607761, 'total_power_no_units': -0.19718164196077612, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [20.98439137803774], 'out_temperature': 13.0, 'action_': [21, 24]}\n", + "Reward: -20664.183622138895 {'timestep': 32064, 'time_elapsed': 28857600, 'year': 1991, 'month': 12, 'day': 1, 'hour': 0, 'total_power': 4794.553408394407, 'total_power_no_units': -0.4794553408394407, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [20.80737243763421], 'out_temperature': 5.1, 'action_': [21, 24]}\n", + "Reward: -22425.618844122902 {'timestep': 35040, 'time_elapsed': 31536000, 'year': 1992, 'month': 1, 'day': 1, 'hour': 0, 'total_power': 12081.03798343912, 'total_power_no_units': -1.208103798343912, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [20.61093146586074], 'out_temperature': -12.0, 'action_': [22, 22]}\n", + "Episode 0 Mean reward: -0.6400005377888734 Cumulative reward: -22425.618844122902\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "[2022-05-23 16:42:33,727] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus simulation closed successfully. \n", - "[2022-05-23 16:42:33,727] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus simulation closed successfully. \n", - "[2022-05-23 16:42:33,727] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus simulation closed successfully. \n", - "[2022-05-23 16:42:33,727] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus simulation closed successfully. \n", - "[2022-05-23 16:42:33,727] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus simulation closed successfully. \n", - "[2022-05-23 16:42:33,727] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus simulation closed successfully. \n", - "[2022-05-23 16:42:33,727] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus simulation closed successfully. \n", - "[2022-05-23 16:42:33,727] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus simulation closed successfully. \n" + "[2022-08-24 09:25:33,119] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus simulation closed successfully. \n", + "[2022-08-24 09:25:33,119] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus simulation closed successfully. \n", + "[2022-08-24 09:25:33,119] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus simulation closed successfully. \n", + "[2022-08-24 09:25:33,119] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus simulation closed successfully. \n" ] } ], @@ -521,9 +440,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.10" + "version": "3.10.4" } }, "nbformat": 4, "nbformat_minor": 0 -} \ No newline at end of file +} diff --git a/images/weather_variability.png b/images/weather_variability.png new file mode 100644 index 0000000000000000000000000000000000000000..6aa019b6731ad82c5c1c22c21a72bb5a801f4414 GIT binary patch literal 160203 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%0Dtf%DrnHPq2z&elL5pLq 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 b8W(eT^!+(PAx)#n`?xGG+M1P{x<&sBYzm*X literal 0 HcmV?d00001 diff --git a/sinergym/utils/config.py b/sinergym/utils/config.py index 9cbfcebf43..062950d659 100644 --- a/sinergym/utils/config.py +++ b/sinergym/utils/config.py @@ -12,8 +12,7 @@ from sinergym.utils.common import (get_delta_seconds, get_record_keys, prepare_batch_from_records, to_idf) -from sinergym.utils.constants import (CWD, PKG_DATA_PATH, - WEEKDAY_ENCODING, YEAR) +from sinergym.utils.constants import CWD, PKG_DATA_PATH, WEEKDAY_ENCODING, YEAR class Config(object): diff --git a/sinergym/version.txt b/sinergym/version.txt index 6ae756c479..227cea2156 100644 --- a/sinergym/version.txt +++ b/sinergym/version.txt @@ -1 +1 @@ -1.9.9 +2.0.0