diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 75e291eb..4461e8c3 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -10,16 +10,18 @@ RUN if [ "${NODE_VERSION}" != "none" ]; then su vscode -c "umask 0002 && . /usr/ # [Optional] If your pip requirements rarely change, uncomment this section to add them to the image. COPY requirements/dev_requirements.txt requirements/doc_requirements.txt /tmp/pip-tmp/ +RUN pip3 install --upgrade pip RUN pip3 --disable-pip-version-check --no-cache-dir install -r /tmp/pip-tmp/dev_requirements.txt \ -r /tmp/pip-tmp/doc_requirements.txt \ && rm -rf /tmp/pip-tmp -# Install nvidia container runtime -RUN wget -O tmp/nvidia-container-toolkit.deb https://nvidia.github.io/libnvidia-container/stable/debian10/amd64/nvidia-container-toolkit_1.7.0-1_amd64.deb \ +# [Optional] install nvidia container runtime (custom to beobench, this enables gpu-using containers within devcontainer) +ARG NVIDIA_SUPPORT="none" +RUN if [ "${NVIDIA_SUPPORT}" != "none" ]; then wget -O tmp/nvidia-container-toolkit.deb https://nvidia.github.io/libnvidia-container/stable/debian10/amd64/nvidia-container-toolkit_1.7.0-1_amd64.deb \ && wget -O tmp/nvidia-container-tools.deb https://nvidia.github.io/libnvidia-container/stable/debian10/amd64/libnvidia-container-tools_1.7.0-1_amd64.deb \ && wget -O tmp/libnvidia-container.deb https://nvidia.github.io/libnvidia-container/stable/debian10/amd64/libnvidia-container1_1.7.0-1_amd64.deb \ && dpkg --install --recursive tmp \ - && rm tmp/nvidia-container-toolkit.deb + && rm tmp/nvidia-container-toolkit.deb; fi diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 2bd80550..a25e0a81 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,7 +1,7 @@ // For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: // https://github.com/microsoft/vscode-dev-containers/tree/v0.205.2/containers/python-3 { - "name": "beobench dev (python3.10)", + "name": "beobench_devcontainer", "build": { "dockerfile": "Dockerfile", "context": "..", @@ -9,21 +9,23 @@ // Update 'VARIANT' to pick a Python version: 3, 3.10, 3.9, 3.8, 3.7, 3.6 // Append -bullseye or -buster to pin to an OS version. // Use -bullseye variants on local on arm64/Apple Silicon. - "VARIANT": "3.8", + // Note: ray[rllib] is not available on debian 11 (bullseye) + "VARIANT": "3.9-bullseye", // Options - "NODE_VERSION": "none" + "NODE_VERSION": "none", + "NVIDIA_SUPPORT": "none" } }, - "workspaceFolder": "/workspace", + "workspaceFolder": "/beobench", // "workspaceMount": "source=remote-workspace,target=/workspace,type=volume", // ADAPT: the mount must be adapted to cloned repo location - "workspaceMount": "source=/home/rdnfn-docker/main/repos/github/beobench/,target=/workspace/beobench/,type=bind,consistency=cached", + "workspaceMount": "source=${localWorkspaceFolder},target=/beobench,type=bind,consistency=cached", // ADAPT: the mount must be adapted to the gitconfig location on the remote machine - "mounts": [ - "source=/home/rdnfn-docker/.gitconfig,target=/root/.gitconfig,type=bind,consistency=cached", - "source=/home/rdnfn-docker/main/repos/github/beobench_contrib,target=/workspace/beobench_contrib/,type=bind,consistency=cached" - ], - "postCreateCommand": "cd ./beobench && pip install -e .", + //"mounts": [ + // "source=${localEnv:HOME}/.gitconfig,target=/root/.gitconfig,type=bind,consistency=cached", + //], + //"initializeCommand": "export DOCKER_BUILDKIT=0 && export COMPOSE_DOCKER_CLI_BUILD=0", + "postCreateCommand": "pip install -e .", // Set *default* container specific settings.json values on container create. "settings": { "python.defaultInterpreterPath": "/usr/local/bin/python", @@ -52,7 +54,8 @@ "ms-azuretools.vscode-docker", "trond-snekvik.simple-rst", "lextudio.restructuredtext", - "njpwerner.autodocstring" + "njpwerner.autodocstring", + "donjayamanne.githistory", ], // Use 'forwardPorts' to make a list of ports inside the container available locally. // "forwardPorts": [], @@ -65,7 +68,7 @@ "docker-in-docker": "20.10" }, "runArgs": [ - "--shm-size=32gb", - "--gpus=all" + //"--shm-size=32gb", + //"--gpus=all", ] } \ No newline at end of file diff --git a/.devcontainer/remote/.devcontainer/devcontainer.json b/.devcontainer/remote/.devcontainer/devcontainer.json new file mode 100644 index 00000000..f21da5c1 --- /dev/null +++ b/.devcontainer/remote/.devcontainer/devcontainer.json @@ -0,0 +1,74 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: +// https://github.com/microsoft/vscode-dev-containers/tree/v0.205.2/containers/python-3 +{ + "name": "beobench_devcontainer_remote", + "build": { + "dockerfile": "../../Dockerfile", + "context": "../../..", + "args": { + // Update 'VARIANT' to pick a Python version: 3, 3.10, 3.9, 3.8, 3.7, 3.6 + // Append -bullseye or -buster to pin to an OS version. + // Use -bullseye variants on local on arm64/Apple Silicon. + "VARIANT": "3.9", + // Options + "NODE_VERSION": "none", + "NVIDIA_SUPPORT": "True", + } + }, + "workspaceFolder": "/beobench", + // "workspaceMount": "source=remote-workspace,target=/workspace,type=volume", + // ADAPT: the mount must be adapted to cloned repo location + "workspaceMount": "source=/home/rdnfn-docker/main/repos/github/beobench/,target=/beobench/,type=bind,consistency=cached", + // ADAPT: the mount must be adapted to the gitconfig location on the remote machine + "mounts": [ + "source=/home/rdnfn-docker/.gitconfig,target=/root/.gitconfig,type=bind,consistency=cached", + ], + "postCreateCommand": "pip install -e .", + // Set *default* container specific settings.json values on container create. + "settings": { + "python.defaultInterpreterPath": "/usr/local/bin/python", + "python.linting.enabled": true, + "python.linting.pylintEnabled": true, + "python.formatting.autopep8Path": "/usr/local/py-utils/bin/autopep8", + "python.formatting.blackPath": "/usr/local/py-utils/bin/black", + "python.formatting.yapfPath": "/usr/local/py-utils/bin/yapf", + "python.linting.banditPath": "/usr/local/py-utils/bin/bandit", + "python.linting.flake8Path": "/usr/local/py-utils/bin/flake8", + "python.linting.mypyPath": "/usr/local/py-utils/bin/mypy", + "python.linting.pycodestylePath": "/usr/local/py-utils/bin/pycodestyle", + "python.linting.pydocstylePath": "/usr/local/py-utils/bin/pydocstyle", + "python.linting.pylintPath": "/usr/local/py-utils/bin/pylint", + "files.trimTrailingWhitespace": true, + "python.formatting.provider": "black", + "editor.formatOnSave": true, + "editor.rulers": [ + 88 + ] + }, + // Add the IDs of extensions you want installed when the container is created. + "extensions": [ + "ms-python.python", + "ms-python.vscode-pylance", + "ms-azuretools.vscode-docker", + "trond-snekvik.simple-rst", + "lextudio.restructuredtext", + "njpwerner.autodocstring" + ], + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "pip3 install --user -r requirements.txt", + // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. + // "remoteUser": "vscode", + "features": { + "git": "latest", + "docker-in-docker": { + "version": "latest", + "moby": true + } + }, + "runArgs": [ + "--shm-size=32gb", + "--gpus=all", + ] +} \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index ff0c7858..fb0c2da2 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,15 +1,8 @@ -* beobench version: -* Python version: -* Operating System: - -### Description +### Problem Describe what you were trying to get done. Tell us what happened, what went wrong, and what you expected to happen. -### What I Did +### Potential Solution -``` -Paste the command(s) you ran and the output. -If there was a crash, please include the traceback here. -``` +Describe a potential solution to the problem, if you have any. diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..0aea4b24 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "beobench_contrib"] + path = beobench_contrib + url = https://github.com/rdnfn/beobench_contrib.git diff --git a/.readthedocs.yml b/.readthedocs.yml index 40f72ae1..6252d08b 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -24,4 +24,8 @@ python: install: - method: pip path: . - - requirements: requirements/doc_requirements.txt \ No newline at end of file + - requirements: requirements/doc_requirements.txt + +# Ensure the beobench_contrib submodule is included +submodules: + include: all \ No newline at end of file diff --git a/AUTHORS.rst b/AUTHORS.rst index 20669df0..2b9b1eda 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -1,13 +1,4 @@ -======= -Credits -======= - -Development Lead ----------------- - -* rdnfn <-> - -Contributors ------------- - -None yet. Why not be the first? +Code Contributors +----------------- +* Arduin Findeis (https://github.com/rdnfn) +* Scott Jeen (https://github.com/enjeeneer) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 74d680a0..de2da604 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -59,39 +59,28 @@ Get Started! Ready to contribute? Here's how to set up `beobench` for local development. -1. Fork the `beobench` repo on GitHub. -2. Clone your fork locally:: +1. Follow :doc:`this guide ` to fork the repo and setup the development environment. - $ git clone git@github.com:your_name_here/beobench.git +2. Inside the devcontainer just set up, create a branch for local development:: -3. Install your local copy into a virtualenv. Assuming you have virtualenvwrapper installed, this is how you set up your fork for local development:: - - $ mkvirtualenv beobench - $ cd beobench/ - $ python setup.py develop - -4. Create a branch for local development:: - - $ git checkout -b name-of-your-bugfix-or-feature + $ git checkout -b dev/name-of-your-bugfix-or-feature Now you can make your changes locally. -5. When you're done making changes, check that your changes pass flake8 and the +3. When you're done making changes, check that your changes pass flake8 and the tests, including testing other Python versions with tox:: $ flake8 beobench tests - $ python setup.py test or pytest + $ python setup.py test $ tox - To get flake8 and tox, just pip install them into your virtualenv. - -6. Commit your changes and push your branch to GitHub:: +4. Commit your changes and push your branch to GitHub:: $ git add . $ git commit -m "Your detailed description of your changes." $ git push origin name-of-your-bugfix-or-feature -7. Submit a pull request through the GitHub website. +5. Submit a pull request through the GitHub website. Pull Request Guidelines ----------------------- @@ -102,8 +91,9 @@ Before you submit a pull request, check that it meets these guidelines: 2. If the pull request adds functionality, the docs should be updated. Put your new functionality into a function with a docstring, and add the feature to the list in README.rst. -3. The pull request should work for Python 3.5, 3.6, 3.7 and 3.8, and for PyPy. Check - https://travis-ci.com/rdnfn/beobench/pull_requests +.. 3. The pull request should work for Python 3.6, 3.7, 3.8 and 3.9. + +.. Check https://travis-ci.com/rdnfn/beobench/pull_requests and make sure that the tests pass for all supported Python versions. Tips diff --git a/HISTORY.rst b/HISTORY.rst index d41120c8..6819a2d0 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -2,6 +2,18 @@ History ======= +0.4.0 (2022-03-28) +------------------ + +* Make dependencies that are only used inside experiment/gym containers optional (for all dependencies install via ``pip install beobench[extended]``) +* Add two part experiment image build process so that there is shared beobench installation dockerfile +* Add support for yaml config files (!) +* Overhaul of documentation, including new envs page and new theme +* Enable RLlib free experiment containers when not required +* Add beobench_contrib as submodule +* Simplify Pypi readme file +* Remove GPU requirement for devcontainer + 0.3.0 (2022-02-14) ------------------ diff --git a/MANIFEST.in b/MANIFEST.in index b1b593db..95c17ced 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -9,4 +9,6 @@ recursive-include tests * recursive-exclude * __pycache__ recursive-exclude * *.py[co] -recursive-include docs *.rst conf.py Makefile make.bat *.jpg *.png *.gif +recursive-include beobench/experiment/definitions * + +recursive-exclude docs *.rst conf.py Makefile make.bat *.jpg *.png *.gif diff --git a/PYPI_README.rst b/PYPI_README.rst index 14dd34bc..923dd5b0 100644 --- a/PYPI_README.rst +++ b/PYPI_README.rst @@ -1,84 +1,3 @@ -.. image:: https://github.com/rdnfn/beobench/raw/master/docs/_static/beobench_logo.png - :align: center - :width: 300 px - :alt: Beobench - -.. start-in-sphinx-docs - -.. image:: https://img.shields.io/pypi/v/beobench.svg - :target: https://pypi.python.org/pypi/beobench - -.. image:: https://readthedocs.org/projects/beobench/badge/?version=latest - :target: https://beobench.readthedocs.io/en/latest/?version=latest - :alt: Documentation Status - -.. image:: https://img.shields.io/badge/License-MIT-blue.svg - :target: https://opensource.org/licenses/MIT - :alt: License - A toolbox for benchmarking reinforcement learning (RL) algorithms on building energy optimisation (BEO) problems. Beobench tries to make working on RL for BEO easier: it provides simple access to existing libraries defining BEO problems (such as `BOPTEST `_) and provides a large set of pre-configured RL algorithms. Beobench is *not* a gym library itself - instead it leverages the brilliant work done by many existing gym-type projects and makes their work more easily accessible. -Features --------- - -*Some of the features are work in progress* - -Main features - -- *RL algorithm collection:* what's the best RL method for your BEO problem? Building on `Ray RLlib `_, beobench provides a large collection of pre-configured RL algorithm experiments that can be easily applied to your new BEO problem. -- *Problem collection:* beobench provides ready-to-use docker containers for popular BEO gym-type problem libraries. By enforcing a strict OpenAI ``gym.Env`` it makes testing your method on different libraries easy. - -Additional features - -- *Experiment logging:* log experiment results in a reproducible and shareable manner via `Weights and Biases`_. -- *Hyperparameter tuning:* easily tune hyperparameters using the extensive `Ray Tune Search API `_. -- *Simple installation:* beobench can be installed via pip and only requires docker as an additional non-python dependency. -- *Easily extendable:* beobench is designed for the user to add both environments and methods. - -.. _Weights and Biases: https://wandb.ai/ - -.. end-in-sphinx-docs - - -.. start-quickstart - -Quickstart ----------- - -Run your first beobench experiment in three steps: - -1. `Install docker `_ on your machine (if on Linux, check the `additional installation steps `_) -2. Install *beobench* using: - - .. code-block:: console - - pip install beobench - -3. Finally, start your first experiment using: - - .. code-block:: console - - python -m beobench.experiment.scheduler - -Done, you have just started your first experiment... congrats! Check out the `full getting started guide in the documentation `_ for the next steps. - -.. end-quickstart - -Documentation -------------- -https://beobench.readthedocs.io - -License -------- -MIT license - - - -Credits -------- - -This package was originally created with Cookiecutter_ and the `audreyr/cookiecutter-pypackage`_ project template. - -.. _Cookiecutter: https://github.com/audreyr/cookiecutter -.. _`audreyr/cookiecutter-pypackage`: https://github.com/audreyr/cookiecutter-pypackage - +For more information go to the `documentation `_ and the `GitHub code repository `_. \ No newline at end of file diff --git a/README.rst b/README.rst index 2b3620e3..07064230 100644 --- a/README.rst +++ b/README.rst @@ -24,31 +24,19 @@ :target: https://opensource.org/licenses/MIT :alt: License -A toolbox for benchmarking reinforcement learning (RL) algorithms on building energy optimisation (BEO) problems. Beobench tries to make working on RL for BEO easier: it provides simple access to existing libraries defining BEO problems (such as `BOPTEST `_) and provides a large set of pre-configured RL algorithms. Beobench is *not* a gym library itself - instead it leverages the brilliant work done by many existing gym-type projects and makes their work more easily accessible. +A toolkit providing easy and unified access to building control environments for reinforcement learning (RL). Features -------- - -*Some of the features are work in progress* - -Main features - -- *RL algorithm collection:* what's the best RL method for your BEO problem? Building on `Ray RLlib `_, beobench provides a large collection of pre-configured RL algorithm experiments that can be easily applied to your new BEO problem. -- *Problem collection:* beobench provides ready-to-use docker containers for popular BEO gym-type problem libraries. By enforcing a strict OpenAI ``gym.Env`` it makes testing your method on different libraries easy. - -Additional features - -- *Experiment logging:* log experiment results in a reproducible and shareable manner via `Weights and Biases`_. -- *Hyperparameter tuning:* easily tune hyperparameters using the extensive `Ray Tune Search API `_. -- *Simple installation:* beobench can be installed via pip and only requires docker as an additional non-python dependency. -- *Easily extendable:* beobench is designed for the user to add both environments and methods. - -.. _Weights and Biases: https://wandb.ai/ +- **Large collection of building control environments:** Out-of-the-box Beobench provides access to environments from `BOPTEST `_, `Energym `_, and `Sinergym `_. By providing access to all the environments from these frameworks, Beobench is able to provide the (to the best of our knowledge) largest single collection of building control environments (`see environment list here `_). +- **Clean and light-weight installation:** Beobench is installed via pip and only requires Docker as an additional non-python dependency (`see installation guide `_). Other packages require the user to deal with building simulator installations or manage docker images directly. +- **Built-in RL agents:** Beobench allows the user to apply any agent from the `Ray RLlib collection `_ *in addition* to agents provided by the user directly. +- **Easily extendable:** want to use Beobench with an environment not yet included? The support for user-defined Docker contexts makes it easy to use Beobench with any RL environment. .. end-in-sphinx-docs - .. start-quickstart +.. _sec_quickstart: Quickstart ---------- @@ -76,16 +64,71 @@ Documentation ------------- https://beobench.readthedocs.io -License -------- -MIT license +.. _sec_envs: + +Available environments +---------------------- + +.. csv-table:: + :header-rows: 1 + :widths: auto + + Gym,Environment,Type*,Description + *BOPTEST*,``bestest_air``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/home.svg,"`original `_, `beobench `_" + ,``bestest_hydronic``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/home.svg,"`original `_, `beobench `_" + ,``bestest_hydronic_heat_pump``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/home.svg,"`original `_, `beobench `_" + ,``multizone_residential_hydronic``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/home.svg,"`original `_, `beobench `_" + ,``singlezone_commercial_hydronic``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/building-skyscraper.svg,"`original `_, `beobench `_" + *Energym*,``Apartments2Thermal-v0``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/home.svg,"`original `_, `beobench `_" + ,``Apartments2Grid-v0``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/home.svg,"`original `_, `beobench `_" + ,``ApartmentsThermal-v0``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/home.svg,"`original `_, `beobench `_" + ,``ApartmentsGrid-v0``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/home.svg,"`original `_, `beobench `_" + ,``OfficesThermostat-v0``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/building-skyscraper.svg,"`original `_, `beobench `_" + ,``MixedUseFanFCU-v0``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/building-skyscraper.svg,"`original `_, `beobench `_" + ,``SeminarcenterThermostat-v0``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/building-skyscraper.svg,"`original `_, `beobench `_" + ,``SeminarcenterFull-v0``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/building-skyscraper.svg,"`original `_, `beobench `_" + ,``SimpleHouseRad-v0``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/home.svg,"`original `_, `beobench `_" + ,``SimpleHouseRSla-v0``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/home.svg,"`original `_, `beobench `_" + ,``SwissHouseRSlaW2W-v0``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/home.svg,"`original `_, `beobench `_" + ,``SwissHouseRSlaA2W-v0``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/home.svg,"`original `_, `beobench `_" + ,``SwissHouseRSlaTank-v0``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/home.svg,"`original `_, `beobench `_" + ,``SwissHouseRSlaTankDhw-v0``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/home.svg,"`original `_, `beobench `_" + *Sinergym*,``Eplus-demo-v1``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/home.svg,"`original `_, `beobench `_" + ,``Eplus-5Zone-hot-discrete-v1``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/home.svg,"`original `_, `beobench `_" + ,``Eplus-5Zone-mixed-discrete-v1``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/home.svg,"`original `_, `beobench `_" + ,``Eplus-5Zone-cool-discrete-v1``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/home.svg,"`original `_, `beobench `_" + ,``Eplus-5Zone-hot-continuous-v1``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/home.svg,"`original `_, `beobench `_" + ,``Eplus-5Zone-mixed-continuous-v1``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/home.svg,"`original `_, `beobench `_" + ,``Eplus-5Zone-cool-continuous-v1``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/home.svg,"`original `_, `beobench `_" + ,``Eplus-5Zone-hot-discrete-stochastic-v1``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/home.svg,"`original `_, `beobench `_" + ,``Eplus-5Zone-mixed-discrete-stochastic-v1``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/home.svg,"`original `_, `beobench `_" + ,``Eplus-5Zone-cool-discrete-stochastic-v1``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/home.svg,"`original `_, `beobench `_" + ,``Eplus-5Zone-hot-continuous-stochastic-v1``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/home.svg,"`original `_, `beobench `_" + ,``Eplus-5Zone-mixed-continuous-stochastic-v1``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/home.svg,"`original `_, `beobench `_" + ,``Eplus-5Zone-cool-continuous-stochastic-v1``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/home.svg,"`original `_, `beobench `_" + ,``Eplus-datacenter-discrete-v1``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/building-factory.svg,"`original `_, `beobench `_" + ,``Eplus-datacenter-continuous-v1``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/building-factory.svg,"`original `_, `beobench `_" + ,``Eplus-datacenter-discrete-stochastic-v1``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/building-factory.svg,"`original `_, `beobench `_" + ,``Eplus-datacenter-continuous-stochastic-v1``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/building-factory.svg,"`original `_, `beobench `_" + ,``Eplus-IWMullion-discrete-v1``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/building-skyscraper.svg,"`original `_, `beobench `_" + ,``Eplus-IWMullion-continuous-v1``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/building-skyscraper.svg,"`original `_, `beobench `_" + ,``Eplus-IWMullion-discrete-stochastic-v1``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/building-skyscraper.svg,"`original `_, `beobench `_" + ,``Eplus-IWMullion-continuous-stochastic-v1``,.. image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/building-skyscraper.svg,"`original `_, `beobench `_" + +\* Types of environments: + +* residential |home| +* office |office| +* data center |industry| + +.. |office| image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/building-skyscraper.svg +.. |home| image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/home.svg +.. |industry| image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/building-factory.svg -Credits +License ------- +MIT license, see `credits and license page in docs `_ for more detailed information. -This package was originally created with Cookiecutter_ and the `audreyr/cookiecutter-pypackage`_ project template. -.. _Cookiecutter: https://github.com/audreyr/cookiecutter -.. _`audreyr/cookiecutter-pypackage`: https://github.com/audreyr/cookiecutter-pypackage diff --git a/beobench/__init__.py b/beobench/__init__.py index 635554e2..1ac5307a 100644 --- a/beobench/__init__.py +++ b/beobench/__init__.py @@ -2,7 +2,7 @@ __author__ = """rdnfn""" __email__ = "-" -__version__ = "0.3.0" +__version__ = "0.4.0" from beobench.utils import restart from beobench.experiment.scheduler import run diff --git a/beobench/cli.py b/beobench/cli.py index 6d78d146..775b6be9 100644 --- a/beobench/cli.py +++ b/beobench/cli.py @@ -1,6 +1,8 @@ """Command line interface for beobench.""" import click +import ast + import beobench.experiment.scheduler import beobench.utils @@ -11,6 +13,13 @@ def cli(): @cli.command() +@click.option( + "--config", + "-c", + default=None, + help="Json or filepath with yaml that defines beobench experiment configuration.", + type=str, +) @click.option( "--experiment-file", default=None, @@ -80,11 +89,13 @@ def cli(): help="Whether to use cache to build experiment container.", ) @click.option( - "--dev-beobench-location", + "--dev-path", + "-d", default=None, help="For developer use only: location of custom beobench package version.", ) def run( + config: str, experiment_file: str, agent_file: str, method: str, @@ -98,7 +109,7 @@ def run( docker_shm_size: str, no_additional_container: bool, use_no_cache: bool, - dev_beobench_location: str, + dev_path: str, ) -> None: """Run beobench experiment from command line. @@ -110,7 +121,12 @@ def run( # # See https://stackoverflow.com/a/40094408. + # Parse config str to dict if + if config and config[0] == "{": + config = ast.literal_eval(config) + beobench.experiment.scheduler.run( + config=config, experiment_file=experiment_file, agent_file=agent_file, method=method, @@ -124,7 +140,7 @@ def run( docker_shm_size=docker_shm_size, no_additional_container=no_additional_container, use_no_cache=use_no_cache, - _dev_beobench_location=dev_beobench_location, + dev_path=dev_path, ) diff --git a/beobench/data/agents/random_agent.py b/beobench/data/agents/random_agent.py new file mode 100644 index 00000000..f3189259 --- /dev/null +++ b/beobench/data/agents/random_agent.py @@ -0,0 +1,17 @@ +"""Random agent for testing beobench experiment containers""" + +import beobench.experiment.provider + +print("Random agent: creating env.") +env = beobench.experiment.provider.create_env() +print("Random agent: resetting env.") +observation = env.reset() +for _ in range(10): + print("Random agent: taking action.") + action = env.action_space.sample() + print(action) + observation, reward, done, info = env.step(action) + if done: + observation = env.reset() +env.close() +print("Random agent: completed test.") diff --git a/beobench/data/configs/rewex01.yaml b/beobench/data/configs/rewex01.yaml new file mode 100644 index 00000000..6b433602 --- /dev/null +++ b/beobench/data/configs/rewex01.yaml @@ -0,0 +1,43 @@ +# REWEX Experiment 01 +# Run with the command +# beobench run -c beobench/experiment/definitions/rewex01.yaml -d . --use-gpu --docker-shm-size 28gb + +# agent config +agent: + origin: rllib # either path to agent script or name of agent library (rllib) + config: # given to ray.tune.run() as arguments (since rllib set before) + run_or_experiment: PPO + stop: + timesteps_total: 400000 + config: + lr: 0.005 + model: + fcnet_activation: relu + fcnet_hiddens: [256,256,256,256] + post_fcnet_activation: tanh + batch_mode: complete_episodes + gamma: 0.999 + horizon: 1000 + metrics_smoothing_episodes: 5 + framework: torch + log_level: "WARNING" + num_workers: 1 # this is required for energym to work (can fail silently otherwise) + num_gpus: 1 +# environment config +env: + name: Apartments2Thermal-v0 + gym: energym + config: + # Number of simulation days + days: 365 + # Name of energym environment + energym_environment: Apartments2Thermal-v0 + gym_kwargs: + # Maximum number of timesteps in one episode + max_episode_length: 35040 # corresponds to a year of 15 min steps + # User-provided flag to require state and action spaces to be normalized + normalize: true + # Number of real-world minutes between timesteps in building simulation + step_period: 15 + # Weather file to use for the scenario (possible files depend on env chosen) + weather: ESP_CT_Barcelona \ No newline at end of file diff --git a/beobench/data/configs/rewex01_test01.yaml b/beobench/data/configs/rewex01_test01.yaml new file mode 100644 index 00000000..7ac157e3 --- /dev/null +++ b/beobench/data/configs/rewex01_test01.yaml @@ -0,0 +1,25 @@ +# REWEX Experiment 01 +# Run with the command +# beobench run -c beobench/data/configs/rewex01_test01.yaml -d . --use-gpu --docker-shm-size 28gb + +# agent config +agent: + origin: beobench/data/agents/random_agent.py # either path to agent script or name of agent library (rllib) +# environment config +env: + name: Apartments2Thermal-v0 + gym: energym + config: + # Number of simulation days + days: 365 + # Name of energym environment + energym_environment: Apartments2Thermal-v0 + gym_kwargs: + # Maximum number of timesteps in one episode + max_episode_length: 35040 # corresponds to a year of 15 min steps + # User-provided flag to require state and action spaces to be normalized + normalize: true + # Number of real-world minutes between timesteps in building simulation + step_period: 15 + # Weather file to use for the scenario (possible files depend on env chosen) + weather: ESP_CT_Barcelona \ No newline at end of file diff --git a/beobench/experiment/config_parser.py b/beobench/experiment/config_parser.py new file mode 100644 index 00000000..a5abc600 --- /dev/null +++ b/beobench/experiment/config_parser.py @@ -0,0 +1,79 @@ +"""Experiment config parser module""" + +from typing import Union +import pathlib +import yaml + +# To enable compatiblity with Python<=3.6 (e.g. for sinergym dockerfile) +try: + import importlib.resources +except ImportError: + import importlib_resources + import importlib + + importlib.resources = importlib_resources + + +def parse(config: Union[str, pathlib.Path]) -> dict: + """Parse experiment config from yaml file to dict. + + Args: + config (Union[str, pathlib.Path]): path of yaml file + + Returns: + dict: config in dictionary + """ + + # load config dict if path given + if isinstance(config, (str, pathlib.Path)): + # make sure config is a real path + if isinstance(config, str): + config = pathlib.Path(config) + with open(config, "r", encoding="utf-8") as config_file: + config_dict = yaml.safe_load(config_file) + else: + config_dict = config + + return config_dict + + +def create_rllib_config(config: dict) -> dict: + """Create a configuration for ray.tune.run() method. + + Args: + config (dict): beobench config + + Raises: + ValueError: this is raised if the config does not specify an rllib agent. + + Returns: + dict: kwargs for ray.tune.run() method + """ + + # Check if config is with rllib agent + if config["agent"]["origin"] != "rllib": + raise ValueError( + ( + "Configuration does not have rllib agent origin set." + f"Config is set to: {config}" + ) + ) + + rllib_config = config["agent"]["config"] + rllib_config["config"]["env_config"] = config["env"]["config"] + rllib_config["config"]["env"] = config["env"]["name"] + + return rllib_config + + +def get_default() -> dict: + """Get default beobench config + + Returns: + dict: default beobench config dict + """ + + defs_path = importlib.resources.files("beobench.experiment.definitions") + config = parse(defs_path.joinpath("default.yaml")) + + return config diff --git a/beobench/experiment/containers.py b/beobench/experiment/containers.py index 6babe49e..d9d50180 100644 --- a/beobench/experiment/containers.py +++ b/beobench/experiment/containers.py @@ -3,9 +3,21 @@ import subprocess import os +# To enable compatiblity with Python<=3.6 (e.g. for sinergym dockerfile) +try: + import importlib.resources +except ImportError: + import importlib_resources + import importlib + + importlib.resources = importlib_resources + def build_experiment_container( - build_context: str, docker_tag: str = None, use_no_cache: bool = False + build_context: str, + use_no_cache: bool = False, + version="latest", + enable_rllib=False, ) -> None: """Build experiment container from beobench/integrations/boptest/Dockerfile. @@ -17,6 +29,7 @@ def build_experiment_container( use_no_cache (bool, optional): wether to use cache in build. Defaults to False. """ + # Flags are shared between gym image build and gym_and_beobench image build flags = [] if use_no_cache: flags.append("--no-cache") @@ -28,7 +41,7 @@ def build_experiment_container( ] # pylint: disable=invalid-name if build_context in AVAILABLE_INTEGRATIONS: - docker_tag = f"beobench_{build_context}:latest" + image_name = f"beobench_{build_context}" integration_name = build_context build_context = ( f"https://github.com/rdnfn/" @@ -41,18 +54,20 @@ def build_experiment_container( ) ) else: - if docker_tag is None: - # get alphanumeric name from context - context_name = "".join(e for e in build_context if e.isalnum()) - docker_tag = f"beobench_custom_{context_name}:latest" + # get alphanumeric name from context + context_name = "".join(e for e in build_context if e.isalnum()) + image_name = f"beobench_custom_{context_name}" + + base_image_tag = f"{image_name}_base:{version}" - print(f"Building experiment container `{docker_tag}`...") + print(f"Building experiment base image `{base_image_tag}`...") + # Part 1: build base experiment image args = [ "docker", "build", "-t", - docker_tag, + base_image_tag, "-f", "Dockerfile", # change to non-default name *flags, @@ -65,9 +80,47 @@ def build_experiment_container( env=env, # this enables accessing dockerfile in subdir ) - print("Experiment container build finished.") + # Part 2: build complete experiment image + # This includes installation of beobench in experiment image + complete_image_tag = f"{image_name}_complete:{version}" + complete_dockerfile = str( + importlib.resources.files("beobench.experiment.dockerfiles").joinpath( + "Dockerfile.experiment" + ) + ) + + # Which extras to install beobench container + # e.g. using pip install beobench[extras] + if enable_rllib: + beobench_extras = '"extended,rllib"' + else: + beobench_extras = "extended" + # Load dockerfile into pipe + with subprocess.Popen(["cat", complete_dockerfile], stdout=subprocess.PIPE) as proc: + beobench_build_args = [ + "docker", + "build", + "-t", + complete_image_tag, + "-f", + "-", + "--build-arg", + f"GYM_IMAGE={base_image_tag}", + "--build-arg", + f"EXTRAS={beobench_extras}", + *flags, + build_context, + ] + print("Running command: " + " ".join(beobench_build_args)) + subprocess.check_call( + beobench_build_args, + stdin=proc.stdout, + env=env, # this enables accessing dockerfile in subdir + ) + + print("Experiment gym image build finished.") - return docker_tag + return complete_image_tag def create_docker_network(network_name: str) -> None: diff --git a/beobench/experiment/definitions/default.py b/beobench/experiment/definitions/archive/default.py similarity index 96% rename from beobench/experiment/definitions/default.py rename to beobench/experiment/definitions/archive/default.py index 30575885..9d396ff4 100644 --- a/beobench/experiment/definitions/default.py +++ b/beobench/experiment/definitions/archive/default.py @@ -1,6 +1,5 @@ """Default experiment definitions.""" -import ray.tune problem = { "name": "problem_001", @@ -56,7 +55,7 @@ "framework": "torch", "log_level": "WARNING", "num_workers": 8, # 1 for silent mode, can at least be 6 - "seed": ray.tune.randint(0, 10000000), + # "seed": ray.tune.randint(0, 10000000), }, "log_to_file": True, "checkpoint_freq": 10000, diff --git a/beobench/experiment/definitions/envs.py b/beobench/experiment/definitions/archive/envs.py similarity index 100% rename from beobench/experiment/definitions/envs.py rename to beobench/experiment/definitions/archive/envs.py diff --git a/beobench/experiment/definitions/experiment_001_dqn_boptest.py b/beobench/experiment/definitions/archive/experiment_001_dqn_boptest.py similarity index 100% rename from beobench/experiment/definitions/experiment_001_dqn_boptest.py rename to beobench/experiment/definitions/archive/experiment_001_dqn_boptest.py diff --git a/beobench/experiment/definitions/experiment_002_rllib_setup.py b/beobench/experiment/definitions/archive/experiment_002_rllib_setup.py similarity index 100% rename from beobench/experiment/definitions/experiment_002_rllib_setup.py rename to beobench/experiment/definitions/archive/experiment_002_rllib_setup.py diff --git a/beobench/experiment/definitions/experiment_003_sinergym.py b/beobench/experiment/definitions/archive/experiment_003_sinergym.py similarity index 88% rename from beobench/experiment/definitions/experiment_003_sinergym.py rename to beobench/experiment/definitions/archive/experiment_003_sinergym.py index 5da9de21..392c801f 100644 --- a/beobench/experiment/definitions/experiment_003_sinergym.py +++ b/beobench/experiment/definitions/archive/experiment_003_sinergym.py @@ -1,7 +1,7 @@ """An experiment to test sinergym integration.""" -import ray.tune -from beobench.experiment.definitions.default import problem, method, rllib_setup +# import ray.tune +# from beobench.experiment.definitions.default import problem, method, rllib_setup problem = { @@ -34,7 +34,7 @@ "log_level": "WARNING", "num_workers": 8, # 1 for silent mode, can at least be 6 "num_gpus": 1, - "seed": ray.tune.randint(0, 10000000), + # "seed": ray.tune.randint(0, 10000000), }, # "log_to_file": True, "checkpoint_freq": 10000, diff --git a/beobench/experiment/definitions/experiment_004_energym.py b/beobench/experiment/definitions/archive/experiment_004_energym.py similarity index 83% rename from beobench/experiment/definitions/experiment_004_energym.py rename to beobench/experiment/definitions/archive/experiment_004_energym.py index 1bfabcbe..f6b96683 100644 --- a/beobench/experiment/definitions/experiment_004_energym.py +++ b/beobench/experiment/definitions/archive/experiment_004_energym.py @@ -1,13 +1,12 @@ """An experiment to test sinergym integration.""" -import ray.tune -from beobench.experiment.definitions.default import problem, method, rllib_setup +# import ray.tune problem = { "name": "sinergym_test_problem", "description": ("Control problem corresponding to " "created by sinergym env ''."), - "problem_library": "https://github.com/rdnfn/beobench_contrib.git#dev/energym-integration:gyms/energym", + "problem_library": "energym", "rllib_experiment_config": { "config": { "env": "MixedUseFanFCU-v0", @@ -40,7 +39,7 @@ "log_level": "WARNING", "num_workers": 1, # 1 for silent mode, can at least be 6 "num_gpus": 1, - "seed": ray.tune.randint(0, 10000000), + # "seed": ray.tune.randint(0, 10000000), }, # "log_to_file": True, "checkpoint_freq": 10000, diff --git a/beobench/experiment/definitions/methods.py b/beobench/experiment/definitions/archive/methods.py similarity index 100% rename from beobench/experiment/definitions/methods.py rename to beobench/experiment/definitions/archive/methods.py diff --git a/beobench/experiment/definitions/default.yaml b/beobench/experiment/definitions/default.yaml new file mode 100644 index 00000000..6de6a702 --- /dev/null +++ b/beobench/experiment/definitions/default.yaml @@ -0,0 +1,30 @@ +# agent config +agent: + origin: rllib # either path to agent script or name of agent library (rllib) + config: # given to ray.tune.run() as arguments (since rllib set before) + run_or_experiment: PPO + stop: + timesteps_total: 400000 + config: + lr: 0.005 + model: + fcnet_activation: relu + fcnet_hiddens: [256,256,256,256] + post_fcnet_activation: tanh + batch_mode: complete_episodes + gamma: 0.999 + horizon: 1000 + metrics_smoothing_episodes: 5 + framework: torch +# environment config +env: + name: MixedUseFanFCU-v0 + gym: energym + config: + days: 365 + energym_environment: MixedUseFanFCU-v0 + gym_kwargs: + max_episode_length: 35040 + normalize: true + step_period: 15 + weather: GRC_A_Athens diff --git a/beobench/experiment/definitions/example_energym.yaml b/beobench/experiment/definitions/example_energym.yaml new file mode 100644 index 00000000..6de6a702 --- /dev/null +++ b/beobench/experiment/definitions/example_energym.yaml @@ -0,0 +1,30 @@ +# agent config +agent: + origin: rllib # either path to agent script or name of agent library (rllib) + config: # given to ray.tune.run() as arguments (since rllib set before) + run_or_experiment: PPO + stop: + timesteps_total: 400000 + config: + lr: 0.005 + model: + fcnet_activation: relu + fcnet_hiddens: [256,256,256,256] + post_fcnet_activation: tanh + batch_mode: complete_episodes + gamma: 0.999 + horizon: 1000 + metrics_smoothing_episodes: 5 + framework: torch +# environment config +env: + name: MixedUseFanFCU-v0 + gym: energym + config: + days: 365 + energym_environment: MixedUseFanFCU-v0 + gym_kwargs: + max_episode_length: 35040 + normalize: true + step_period: 15 + weather: GRC_A_Athens diff --git a/beobench/experiment/definitions/example_sinergym.yaml b/beobench/experiment/definitions/example_sinergym.yaml new file mode 100644 index 00000000..2a68a5ba --- /dev/null +++ b/beobench/experiment/definitions/example_sinergym.yaml @@ -0,0 +1,25 @@ +# agent config +agent: + origin: rllib # either path to agent script or name of agent library (rllib) + config: # given to ray.tune.run() as arguments (since rllib set before) + run_or_experiment: PPO + stop: + timesteps_total: 400000 + config: + lr: 0.005 + model: + fcnet_activation: relu + fcnet_hiddens: [256,256,256,256] + post_fcnet_activation: tanh + batch_mode: complete_episodes + gamma: 0.999 + horizon: 1000 + metrics_smoothing_episodes: 5 + framework: torch +# environment config +env: + name: Eplus-5Zone-hot-continuous-v1 + gym: sinergym + config: + name: Eplus-5Zone-hot-continuous-v1 + normalize: True \ No newline at end of file diff --git a/beobench/experiment/definitions/rewex01.yaml b/beobench/experiment/definitions/rewex01.yaml new file mode 100644 index 00000000..6b433602 --- /dev/null +++ b/beobench/experiment/definitions/rewex01.yaml @@ -0,0 +1,43 @@ +# REWEX Experiment 01 +# Run with the command +# beobench run -c beobench/experiment/definitions/rewex01.yaml -d . --use-gpu --docker-shm-size 28gb + +# agent config +agent: + origin: rllib # either path to agent script or name of agent library (rllib) + config: # given to ray.tune.run() as arguments (since rllib set before) + run_or_experiment: PPO + stop: + timesteps_total: 400000 + config: + lr: 0.005 + model: + fcnet_activation: relu + fcnet_hiddens: [256,256,256,256] + post_fcnet_activation: tanh + batch_mode: complete_episodes + gamma: 0.999 + horizon: 1000 + metrics_smoothing_episodes: 5 + framework: torch + log_level: "WARNING" + num_workers: 1 # this is required for energym to work (can fail silently otherwise) + num_gpus: 1 +# environment config +env: + name: Apartments2Thermal-v0 + gym: energym + config: + # Number of simulation days + days: 365 + # Name of energym environment + energym_environment: Apartments2Thermal-v0 + gym_kwargs: + # Maximum number of timesteps in one episode + max_episode_length: 35040 # corresponds to a year of 15 min steps + # User-provided flag to require state and action spaces to be normalized + normalize: true + # Number of real-world minutes between timesteps in building simulation + step_period: 15 + # Weather file to use for the scenario (possible files depend on env chosen) + weather: ESP_CT_Barcelona \ No newline at end of file diff --git a/beobench/experiment/dockerfiles/Dockerfile.experiment b/beobench/experiment/dockerfiles/Dockerfile.experiment new file mode 100644 index 00000000..145373a0 --- /dev/null +++ b/beobench/experiment/dockerfiles/Dockerfile.experiment @@ -0,0 +1,11 @@ +ARG GYM_IMAGE +FROM ${GYM_IMAGE} + +# install beobench +ARG EXTRAS="extended, rllib" +RUN pip3 --disable-pip-version-check --no-cache-dir install "beobench[${EXTRAS}]" + +# add env creator +COPY env_creator.py /opt/beobench/experiment_setup/ +# add env creator to python path +ENV PYTHONPATH "${PYTHONPATH}:/opt/beobench/experiment_setup/" \ No newline at end of file diff --git a/beobench/experiment/dockerfiles/__init__.py b/beobench/experiment/dockerfiles/__init__.py new file mode 100644 index 00000000..731c16b9 --- /dev/null +++ b/beobench/experiment/dockerfiles/__init__.py @@ -0,0 +1 @@ +"""Subpackage with dockerfiles for experiments.""" diff --git a/beobench/experiment/provider.py b/beobench/experiment/provider.py new file mode 100644 index 00000000..1bcb1102 --- /dev/null +++ b/beobench/experiment/provider.py @@ -0,0 +1,36 @@ +""" The experiment provider provides access to environments inside containers.""" + +import beobench.experiment.config_parser + +try: + import env_creator # pylint: disable=import-outside-toplevel,import-error +except ImportError as e: + raise ImportError( + ( + "Cannot import env_creator module. Is Beobench being executed" + "inside beobench experiment container?" + ) + ) from e + +config = beobench.experiment.config_parser.parse("/tmp/beobench/config.yaml") + + +def create_env(env_config: dict = None) -> object: + """Create environment. + + Create environment from Beobench integration currently being used. + This only works INSIDE a beobench experiment container. + + Args: + env_config (dict, optional): env configuration. Defaults to None. + + Returns: + object: environment instance + """ + + # Access env_creator script that is only available inside + # experiment container. + if env_config is None: + env_config = config["env"]["config"] + + return env_creator.create_env(env_config) diff --git a/beobench/experiment/scheduler.py b/beobench/experiment/scheduler.py index 41a436c2..50d28364 100644 --- a/beobench/experiment/scheduler.py +++ b/beobench/experiment/scheduler.py @@ -1,29 +1,33 @@ """Module to schedule experiments.""" +from cgitb import enable import os import uuid import subprocess import pathlib -import importlib.util -import ray.tune -import ray.tune.integration.wandb -import ray.tune.integration.mlflow +import warnings +import yaml +from typing import Union +# RLlib integration is only available with extended extras. +try: + import beobench.integration.rllib +except ImportError: + print("Note: RLlib beobench integration not available.") import beobench.experiment.definitions.utils -import beobench.experiment.definitions.default -import beobench.experiment.definitions.methods -import beobench.experiment.definitions.envs import beobench.experiment.containers +import beobench.experiment.config_parser import beobench.utils def run( + config: Union[str, dict] = None, experiment_file: str = None, agent_file: str = None, method: str = None, env: str = None, - local_dir: str = "./beobench_results/ray_results", + local_dir: str = "./beobench_results", wandb_project: str = "", wandb_entity: str = "", wandb_api_key: str = "", @@ -32,7 +36,7 @@ def run( docker_shm_size: str = "2gb", no_additional_container: bool = False, use_no_cache: bool = False, - _dev_beobench_location: str = None, + dev_path: str = None, ) -> None: """Run experiment. @@ -40,10 +44,12 @@ def run( interface. Args: + config (str or dict, optional): experiment configuration. This can either be + a dictionary or a path to a yaml file. experiment_file (str, optional): File that defines experiment. - Defaults to None. + Defaults to None. DEPRECATED. agent_file (str, optional): File that defines custom agent. This script is - executed inside the gym container. + executed inside the gym container. DEPRECATED, this should be set in config. method (str, optional): RL method to use in experiment. This overwrites any method that is set in experiment file. For example 'PPO'. Defaults to None. env (str, optional): environment to apply method to in experiment. This @@ -65,74 +71,90 @@ def run( is started to run experiments in. use_no_cache (bool, optional): whether to use cache to build experiment container. - _dev_beobench_location (str, optional): github path to beobench package. For + dev_path (str, optional): file or github path to beobench package. For developement purpose only. This will install a custom beobench version inside the experiment container. By default the latest PyPI version is installed. """ + # pylint: disable=unused-argument + # get config dict from config argument + if config: + config = beobench.experiment.config_parser.parse(config) + else: + config = beobench.experiment.config_parser.get_default() # Create a definition of experiment from inputs if experiment_file is not None: - experiment_file = pathlib.Path(experiment_file) + warnings.warn( + "The experiment_file argmunent has been replaced by config", + DeprecationWarning, + ) if agent_file is not None: - agent_file = pathlib.Path(agent_file) - experiment_def = _create_experiment_def(experiment_file, method, env) + warnings.warn( + "The agent_file argmunet has been replaced by config", + DeprecationWarning, + ) + + if config["agent"]["origin"] == "rllib": + agent_file = None + else: + agent_file = pathlib.Path(config["agent"]["origin"]) + + # TODO add parsing of high level API arguments env and agent if no_additional_container: # Execute experiment # (this is usually reached from inside an experiment container) - # Add wandb callback if sufficient information - # TODO: add earlier check to see that also API key available - if wandb_project and wandb_entity: - callbacks = [_create_wandb_callback(wandb_project, wandb_entity)] - elif wandb_project or wandb_entity: - raise ValueError( - "Only one of wandb_project or wandb_entity given, but both required." - ) - elif mlflow_name: - callbacks = [_create_mlflow_callback(mlflow_name)] - else: - callbacks = [] - - # change RLlib setup if GPU used - if use_gpu: - experiment_def["rllib_setup"]["rllib_experiment_config"]["config"][ - "num_gpus" - ] = 1 - # run experiment in ray tune - if not agent_file: - run_in_tune( - problem_def=experiment_def["problem"], - method_def=experiment_def["method"], - rllib_setup=experiment_def["rllib_setup"], - rllib_callbacks=callbacks, + + if config["agent"]["origin"] == "rllib": + beobench.integration.rllib.run_in_tune( + config, + wandb_entity=wandb_entity, + wandb_project=wandb_project, + mlflow_name=mlflow_name, + use_gpu=use_gpu, ) else: # run custom RL agent - args = ["python -m", f"/tmp/beobench/{agent_file.name}"] + args = ["python", f"/tmp/beobench/{agent_file.name}"] subprocess.check_call(args) else: # build and run experiments in docker container - # Ensure local_dir exists, and create otherwise - local_dir_path = pathlib.Path(local_dir) - local_dir_path.mkdir(parents=True, exist_ok=True) - local_dir_abs = str(local_dir_path.absolute()) - - # docker setup + ### part 1: build docker images + enable_rllib = config["agent"]["origin"] == "rllib" image_tag = beobench.experiment.containers.build_experiment_container( - build_context=experiment_def["problem"]["problem_library"], + build_context=config["env"]["gym"], use_no_cache=use_no_cache, + enable_rllib=enable_rllib, ) - # define docker arguments/options/flags + ### part 2: create args and run command in docker container + docker_flags = [] + + # Ensure local_dir exists, and create otherwise + local_dir_path = pathlib.Path(local_dir) + local_dir_path.mkdir(parents=True, exist_ok=True) + ray_path_abs = str((local_dir_path / "ray_results").absolute()) + + # Save config to local dir and add mount flag for config + config_path = local_dir_path / "tmp" / "config.yaml" + config_path.parent.mkdir(parents=True, exist_ok=True) + config_path_abs = config_path.absolute() + with open(config_path, "w", encoding="utf-8") as conf_file: + yaml.dump(config, conf_file) + docker_flags += [ + "-v", + f"{config_path_abs}:/tmp/beobench/config.yaml:ro", + ] + + # define more docker arguments/options/flags unique_id = uuid.uuid4().hex[:6] container_name = f"auto_beobench_experiment_{unique_id}" - docker_flags = [] if experiment_file is not None: exp_file_abs = experiment_file.absolute() exp_file_on_docker = f"/tmp/beobench/{experiment_file.name}" @@ -150,7 +172,7 @@ def run( ] # enable docker-from-docker access only for built-in boptest integration. - if experiment_def["problem"]["problem_library"] == "boptest": + if config["env"]["gym"] == "boptest": # Create docker network (only useful if starting other containers) beobench.experiment.containers.create_docker_network("beobench-net") @@ -173,16 +195,13 @@ def run( # define flags for beobench scheduler call inside experiment container beobench_flags = [] - if experiment_file: - beobench_flags.append(f"--experiment-file={exp_file_on_docker}") + beobench_flags.append(f'--config="{config}"') if wandb_project: beobench_flags.append(f"--wandb-project={wandb_project}") if wandb_entity: beobench_flags.append(f"--wandb-entity={wandb_entity}") if use_gpu: beobench_flags.append("--use-gpu") - if agent_file: - beobench_flags.append(f"--agent-file={agent_file}") beobench_flag_str = " ".join(beobench_flags) # if no wandb API key is given try to get it from env @@ -190,11 +209,27 @@ def run( # this will return "" if env var not set wandb_api_key = os.getenv("WANDB_API_KEY", "") + # dev mode where custom beobench is installed directly from github or local path cmd_list_in_container = [""] - # dev mode where custom beobench is installed directly from git - if _dev_beobench_location is not None: + if dev_path is not None: cmd_list_in_container.append("pip uninstall --yes beobench") - cmd_list_in_container.append(f"pip install {_dev_beobench_location}") + if "https" in dev_path: + cmd_list_in_container.append(f"pip install {dev_path}") + else: + # mount local beobench repo + dev_path = pathlib.Path(dev_path) + dev_abs = dev_path.absolute() + dev_path_on_docker = "/tmp/beobench/beobench" + docker_flags += [ + "-v", + f"{dev_abs}:{dev_path_on_docker}_mount:ro", + ] + cmd_list_in_container.append( + f"cp -r {dev_path_on_docker}_mount {dev_path_on_docker}" + ) + cmd_list_in_container.append( + f"python -m pip install {dev_path_on_docker}" + ) cmd_in_container = " && ".join(cmd_list_in_container) @@ -203,7 +238,7 @@ def run( "run", # mount experiment data dir "-v", - f"{local_dir_abs}:/root/ray_results", + f"{ray_path_abs}:/root/ray_results", # automatically remove container when stopped/exited "--rm", # add more memory @@ -222,180 +257,3 @@ def run( ] print("Executing docker command: ", " ".join(args)) subprocess.check_call(args) - - -def run_in_tune( - problem_def: dict, method_def: dict, rllib_setup: dict, rllib_callbacks: list = None -) -> ray.tune.ExperimentAnalysis: - """Run beobench experiment. - - Additional info: note that RLlib is a submodule of the ray package, i.e. it is - imported as `ray.rllib`. For experiment definitions it uses the `ray.tune` - submodule. Therefore ray tune experiment definition means the same as ray rllib - experiment defintions. To avoid confusion all variable/argument names use rllib - instead of ray tune but strictly speaking these are ray tune experiment - definitions. - - Args: - problem_def (dict): definition of problem. This is an incomplete - ray tune experiment defintion that only defines the problem side. - method_def (dict): definition of method. This is an incomplete - ray tune experiment defintion that only defines the method side. - rllib_setup (dict): rllib setup. This is an incomplete - ray tune experiment defintion that only defines the ray tune/rllib setup - (e.g. number of workers, etc.). - rllib_callbacks (list, optional): callbacks to add to ray.tune.run command. - Defaults to None. - - Returns: - ray.tune.ExperimentAnalysis: analysis object of completed experiment. - """ - if rllib_callbacks is None: - rllib_callbacks = [] - - # combine the three incomplete ray tune experiment - # definitions into a single complete one. - exp_config = beobench.experiment.definitions.utils.get_experiment_config( - problem_def, method_def, rllib_setup - ) - - # register the problem environment with ray tune - # env_creator is a module available in experiment containers - import env_creator # pylint: disable=import-outside-toplevel,import-error - - ray.tune.registry.register_env( - problem_def["rllib_experiment_config"]["config"]["env"], - env_creator.create_env, - ) - - # if run in notebook, change the output reported throughout experiment. - if beobench.utils.check_if_in_notebook(): - reporter = ray.tune.JupyterNotebookReporter(overwrite=True) - else: - reporter = None - - # running the experiment - analysis = ray.tune.run( - progress_reporter=reporter, - callbacks=rllib_callbacks, - **exp_config, - ) - - return analysis - - -def _create_wandb_callback( - wandb_project: str, - wandb_entity: str, -): - """Create an RLlib weights and biases (wandb) callback. - - Args: - wandb_project (str): name of wandb project. - wandb_entity (str): name of wandb entity that owns project. - - Returns: - : a wandb callback - """ - wandb_callback = ray.tune.integration.wandb.WandbLoggerCallback( - project=wandb_project, log_config=True, entity=wandb_entity - ) - return wandb_callback - - -def _create_mlflow_callback( - mlflow_name: str, -): - """Create an RLlib MLflow callback. - - Args: - mlflow_name (str, optional): name of MLflow experiment. - - Returns: - : a wandb callback - """ - mlflow_callback = ray.tune.integration.mlflow.MLflowLoggerCallback( - experiment_name=mlflow_name, tracking_uri="file:/root/ray_results/mlflow" - ) - return mlflow_callback - - -def _create_experiment_def( - experiment_file: pathlib.Path, method: str, env: str -) -> dict: - """Create a Beobench experiment definition. - - Args: - experiment_file (str): path to experiment file. - method (str): name of RL method. - env (str): name of environment. - """ - experiment_def = _load_experiment_file(experiment_file) - - # parsing high level interface options - - # methods - if method: - if method == "ppo": - experiment_def["method"] = beobench.experiment.definitions.methods.PPO - else: - raise ValueError( - ( - f"The supplied method '{method}' does not match any of " - "the pre-configured beobench methods." - ) - ) - - if env: - if env == "boptest_bestest-hydronic-heat-pump-v1": - experiment_def["problem"] = getattr( - beobench.experiment.definitions.envs, - env.replace("-", "_"), - ) - if env == "sinergym_eplus-5zone-hot-continous-v1": - experiment_def["problem"] = getattr( - beobench.experiment.definitions.envs, - env.replace("-", "_"), - ) - if env == "energym_mixed-use-fan-fcu-v0": - experiment_def["problem"] = getattr( - beobench.experiment.definitions.envs, - env.replace("-", "_"), - ) - - return experiment_def - - -def _load_experiment_file(experiment_file: pathlib.Path) -> dict: - """Load a Beobench experiment file. - - Args: - experiment_file (str): path to experiment file. - """ - - # Load experiment definition file - if experiment_file is None: - experiment_file_mod = beobench.experiment.definitions.default - else: - # import experiment definition file as module - spec = importlib.util.spec_from_file_location( - "experiment_definition", - str(experiment_file.absolute()), - ) - experiment_file_mod = importlib.util.module_from_spec(spec) - spec.loader.exec_module(experiment_file_mod) - - experiment_def = dict() - - # Create experiment def dictionary, and set default values if not available - # from experiment_file (module). - for exp_part in ["problem", "method", "rllib_setup"]: - if hasattr(experiment_file_mod, exp_part): - experiment_def[exp_part] = getattr(experiment_file_mod, exp_part) - else: - experiment_def[exp_part] = getattr( - beobench.experiment.definitions.default, - exp_part, - ) - - return experiment_def diff --git a/beobench/integration/__init__.py b/beobench/integration/__init__.py new file mode 100644 index 00000000..296a4adb --- /dev/null +++ b/beobench/integration/__init__.py @@ -0,0 +1 @@ +"""Subpackage with integrations""" diff --git a/beobench/integration/rllib.py b/beobench/integration/rllib.py new file mode 100644 index 00000000..f4cd75e1 --- /dev/null +++ b/beobench/integration/rllib.py @@ -0,0 +1,117 @@ +"""RLlib integration in beobench.""" + +import ray.tune +import ray.tune.integration.wandb +import ray.tune.integration.mlflow + +import beobench.utils +import beobench.experiment.config_parser + + +def run_in_tune( + config: dict, + wandb_project: str = None, + wandb_entity: str = None, + mlflow_name: str = None, + use_gpu: bool = False, +) -> ray.tune.ExperimentAnalysis: + """Run beobench experiment. + + Additional info: note that RLlib is a submodule of the ray package, i.e. it is + imported as `ray.rllib`. For experiment definitions it uses the `ray.tune` + submodule. Therefore ray tune experiment definition means the same as ray rllib + experiment defintions. To avoid confusion all variable/argument names use rllib + instead of ray tune but strictly speaking these are ray tune experiment + definitions. + + Args: + config (dict): beobench config + wandb_project (str, optional): name of wandb project. Defaults to None. + wandb_entity (str, optional): name of wandb entirty. Defaults to None. + mlflow_name (str, optional): name of mlflow experiment. Defaults to None. + use_gpu (bool, optional): whether to use GPU. Defaults to False. + + Raises: + ValueError: raised if only one of wandb project or wandb entity given. + + Returns: + ray.tune.ExperimentAnalysis: analysis object from experiment. + """ + if wandb_project and wandb_entity: + callbacks = [_create_wandb_callback(wandb_project, wandb_entity)] + elif wandb_project or wandb_entity: + raise ValueError( + "Only one of wandb_project or wandb_entity given, but both required." + ) + elif mlflow_name: + callbacks = [_create_mlflow_callback(mlflow_name)] + else: + callbacks = [] + + # combine the three incomplete ray tune experiment + # definitions into a single complete one. + rllib_config = beobench.experiment.config_parser.create_rllib_config(config) + + # change RLlib setup if GPU used + if use_gpu: + rllib_config["config"]["num_gpus"] = 1 + + # register the problem environment with ray tune + # env_creator is a module available in experiment containers + import env_creator # pylint: disable=import-outside-toplevel,import-error + + ray.tune.registry.register_env( + rllib_config["config"]["env"], + env_creator.create_env, + ) + + # if run in notebook, change the output reported throughout experiment. + if beobench.utils.check_if_in_notebook(): + reporter = ray.tune.JupyterNotebookReporter(overwrite=True) + else: + reporter = None + + # running the experiment + analysis = ray.tune.run( + progress_reporter=reporter, + callbacks=callbacks, + **rllib_config, + ) + + return analysis + + +def _create_wandb_callback( + wandb_project: str, + wandb_entity: str, +): + """Create an RLlib weights and biases (wandb) callback. + + Args: + wandb_project (str): name of wandb project. + wandb_entity (str): name of wandb entity that owns project. + + Returns: + : a wandb callback + """ + wandb_callback = ray.tune.integration.wandb.WandbLoggerCallback( + project=wandb_project, log_config=True, entity=wandb_entity + ) + return wandb_callback + + +def _create_mlflow_callback( + mlflow_name: str, +): + """Create an RLlib MLflow callback. + + Args: + mlflow_name (str, optional): name of MLflow experiment. + + Returns: + : a wandb callback + """ + mlflow_callback = ray.tune.integration.mlflow.MLflowLoggerCallback( + experiment_name=mlflow_name, tracking_uri="file:/root/ray_results/mlflow" + ) + return mlflow_callback diff --git a/beobench_contrib b/beobench_contrib new file mode 160000 index 00000000..f2bc0fd0 --- /dev/null +++ b/beobench_contrib @@ -0,0 +1 @@ +Subproject commit f2bc0fd0db9c1c43afe7479952644768355ecf43 diff --git a/docs/_static/custom.css b/docs/_static/custom.css new file mode 100644 index 00000000..83848a78 --- /dev/null +++ b/docs/_static/custom.css @@ -0,0 +1,3 @@ +.container-xl { + max-width: 1000px; +} \ No newline at end of file diff --git a/docs/authors.rst b/docs/authors.rst deleted file mode 100644 index e122f914..00000000 --- a/docs/authors.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../AUTHORS.rst diff --git a/docs/conf.py b/docs/conf.py index c8f82cd7..7a96609a 100755 --- a/docs/conf.py +++ b/docs/conf.py @@ -38,6 +38,7 @@ "sphinx.ext.viewcode", "sphinx.ext.autosummary", "sphinx_tabs.tabs", + "myst_parser", ] # Add any paths that contain templates here, relative to this directory. @@ -90,7 +91,8 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = "alabaster" +# html_theme = "alabaster" +html_theme = "sphinx_book_theme" # Theme options are theme-specific and customize the look and feel of a # theme further. For a list of options available for each theme, see the @@ -162,16 +164,32 @@ ## Custom elements +html_logo = "_static/beobench_logo.png" html_favicon = "_static/beobench_favicon_v2.png" -html_theme_options = { - "logo_name": False, - "logo": "/beobench_logo.png", - "github_repo": "beobench", - "github_user": "rdnfn", - "github_button": True, - "github_count": False, - "github_type": "star", - "fixed_sidebar": True, - # "sidebar_width": "200pt", -} +if html_theme == "alabaster": + html_theme_options = { + "logo_name": False, + "logo": "/beobench_logo.png", + "github_repo": "beobench", + "github_user": "rdnfn", + "github_button": True, + "github_count": False, + "github_type": "star", + "fixed_sidebar": True, + # "sidebar_width": "200pt", + } +elif html_theme == "sphinx_book_theme": + html_theme_options = { + "extra_navbar": "", + "home_page_in_toc": False, + "use_fullscreen_button": False, + "use_download_button": True, + "repository_url": "https://github.com/rdnfn/beobench", + "use_repository_button": True, + "use_issues_button": True, + "logo_only": True, + #'prev_next_buttons_location': None, + } + +html_css_files = ["custom.css"] diff --git a/docs/credits.rst b/docs/credits.rst new file mode 100644 index 00000000..d806e10c --- /dev/null +++ b/docs/credits.rst @@ -0,0 +1,44 @@ +=================== +Credits and license +=================== + +.. include:: ../AUTHORS.rst + +Further acknowledgements +------------------------ + +The initial package structure was created using Cookiecutter_ and the `audreyr/cookiecutter-pypackage`_ project template. + +.. _Cookiecutter: https://github.com/audreyr/cookiecutter +.. _`audreyr/cookiecutter-pypackage`: https://github.com/audreyr/cookiecutter-pypackage + +License +------- + +The code in this repository is published under MIT license (see ``LICENSE`` file). + +Further, the icons used in the environment list in the documentation are licensed under the following MIT license: + +.. code-block:: txt + + MIT License + + Copyright (c) 2020 Paweł Kuna + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. diff --git a/docs/envs.rst b/docs/envs.rst new file mode 100644 index 00000000..e61143f6 --- /dev/null +++ b/docs/envs.rst @@ -0,0 +1,53 @@ +============ +Environments +============ + +Beobench provides easy access to a large number of building control environments for reinforcement learning. Each environment comes from one of the integrated frameworks `BOPTEST `_, `Energym `_ and `Sinergym `_. The list below shows links to all environments available out-of-the-box. Each environment is marked based on whether it represents a residential building (|home|), office (|office|) or data center (|industry|). + +.. include:: envs/envs_list.rst + +---- + +BOPTEST +------- + +.. include:: ../beobench_contrib/gyms/boptest/README.md + :parser: myst_parser.sphinx_ + :start-line: 2 + + +BOPTEST Envs +^^^^^^^^^^^^ + +.. include:: envs/BOPTEST_descriptions.rst + + +---- + +Energym +------- + +.. include:: ../beobench_contrib/gyms/energym/README.md + :parser: myst_parser.sphinx_ + :start-line: 2 + + +Energym Envs +^^^^^^^^^^^^ + +.. include:: envs/Energym_descriptions.rst + +---- + +Sinergym +-------- + +.. include:: ../beobench_contrib/gyms/sinergym/README.md + :parser: myst_parser.sphinx_ + :start-line: 2 + + +Sinergym Envs +^^^^^^^^^^^^^ + +.. include:: envs/Sinergym_descriptions.rst \ No newline at end of file diff --git a/docs/envs/BOPTEST_descriptions.rst b/docs/envs/BOPTEST_descriptions.rst new file mode 100644 index 00000000..d314dc12 --- /dev/null +++ b/docs/envs/BOPTEST_descriptions.rst @@ -0,0 +1,45 @@ + + +.. _env-bestest_air: + +``bestest_air`` +""""""""""""""" + +:Type: residential building (|home|) +:More info: `framework docs `_ + + +.. _env-bestest_hydronic: + +``bestest_hydronic`` +"""""""""""""""""""" + +:Type: residential building (|home|) +:More info: `framework docs `_ + + +.. _env-bestest_hydronic_heat_pump: + +``bestest_hydronic_heat_pump`` +"""""""""""""""""""""""""""""" + +:Type: residential building (|home|) +:More info: `framework docs `_ + + +.. _env-multizone_residential_hydronic: + +``multizone_residential_hydronic`` +"""""""""""""""""""""""""""""""""" + +:Type: residential building (|home|) +:More info: `framework docs `_ + + +.. _env-singlezone_commercial_hydronic: + +``singlezone_commercial_hydronic`` +"""""""""""""""""""""""""""""""""" + +:Type: office building (|office|) +:More info: `framework docs `_ diff --git a/docs/envs/Energym_descriptions.rst b/docs/envs/Energym_descriptions.rst new file mode 100644 index 00000000..0a021e9e --- /dev/null +++ b/docs/envs/Energym_descriptions.rst @@ -0,0 +1,126 @@ + + +.. _env-Apartments2Thermal-v0: + +``Apartments2Thermal-v0`` +""""""""""""""""""""""""" + +:Type: residential building (|home|) +:More info: `framework docs `_ + + +.. _env-Apartments2Grid-v0: + +``Apartments2Grid-v0`` +"""""""""""""""""""""" + +:Type: residential building (|home|) +:More info: `framework docs `_ + + +.. _env-ApartmentsThermal-v0: + +``ApartmentsThermal-v0`` +"""""""""""""""""""""""" + +:Type: residential building (|home|) +:More info: `framework docs `_ + + +.. _env-ApartmentsGrid-v0: + +``ApartmentsGrid-v0`` +""""""""""""""""""""" + +:Type: residential building (|home|) +:More info: `framework docs `_ + + +.. _env-OfficesThermostat-v0: + +``OfficesThermostat-v0`` +"""""""""""""""""""""""" + +:Type: office building (|office|) +:More info: `framework docs `_ + + +.. _env-MixedUseFanFCU-v0: + +``MixedUseFanFCU-v0`` +""""""""""""""""""""" + +:Type: office building (|office|) +:More info: `framework docs `_ + + +.. _env-SeminarcenterThermostat-v0: + +``SeminarcenterThermostat-v0`` +"""""""""""""""""""""""""""""" + +:Type: office building (|office|) +:More info: `framework docs `_ + + +.. _env-SeminarcenterFull-v0: + +``SeminarcenterFull-v0`` +"""""""""""""""""""""""" + +:Type: office building (|office|) +:More info: `framework docs `_ + + +.. _env-SimpleHouseRad-v0: + +``SimpleHouseRad-v0`` +""""""""""""""""""""" + +:Type: residential building (|home|) +:More info: `framework docs `_ + + +.. _env-SimpleHouseRSla-v0: + +``SimpleHouseRSla-v0`` +"""""""""""""""""""""" + +:Type: residential building (|home|) +:More info: `framework docs `_ + + +.. _env-SwissHouseRSlaW2W-v0: + +``SwissHouseRSlaW2W-v0`` +"""""""""""""""""""""""" + +:Type: residential building (|home|) +:More info: `framework docs `_ + + +.. _env-SwissHouseRSlaA2W-v0: + +``SwissHouseRSlaA2W-v0`` +"""""""""""""""""""""""" + +:Type: residential building (|home|) +:More info: `framework docs `_ + + +.. _env-SwissHouseRSlaTank-v0: + +``SwissHouseRSlaTank-v0`` +""""""""""""""""""""""""" + +:Type: residential building (|home|) +:More info: `framework docs `_ + + +.. _env-SwissHouseRSlaTankDhw-v0: + +``SwissHouseRSlaTankDhw-v0`` +"""""""""""""""""""""""""""" + +:Type: residential building (|home|) +:More info: `framework docs `_ diff --git a/docs/envs/Sinergym_descriptions.rst b/docs/envs/Sinergym_descriptions.rst new file mode 100644 index 00000000..3dac008c --- /dev/null +++ b/docs/envs/Sinergym_descriptions.rst @@ -0,0 +1,189 @@ + + +.. _env-Eplus-demo-v1: + +``Eplus-demo-v1`` +""""""""""""""""" + +:Type: residential building (|home|) +:More info: `framework docs `_ + + +.. _env-Eplus-5Zone-hot-discrete-v1: + +``Eplus-5Zone-hot-discrete-v1`` +""""""""""""""""""""""""""""""" + +:Type: residential building (|home|) +:More info: `framework docs `_ + + +.. _env-Eplus-5Zone-mixed-discrete-v1: + +``Eplus-5Zone-mixed-discrete-v1`` +""""""""""""""""""""""""""""""""" + +:Type: residential building (|home|) +:More info: `framework docs `_ + + +.. _env-Eplus-5Zone-cool-discrete-v1: + +``Eplus-5Zone-cool-discrete-v1`` +"""""""""""""""""""""""""""""""" + +:Type: residential building (|home|) +:More info: `framework docs `_ + + +.. _env-Eplus-5Zone-hot-continuous-v1: + +``Eplus-5Zone-hot-continuous-v1`` +""""""""""""""""""""""""""""""""" + +:Type: residential building (|home|) +:More info: `framework docs `_ + + +.. _env-Eplus-5Zone-mixed-continuous-v1: + +``Eplus-5Zone-mixed-continuous-v1`` +""""""""""""""""""""""""""""""""""" + +:Type: residential building (|home|) +:More info: `framework docs `_ + + +.. _env-Eplus-5Zone-cool-continuous-v1: + +``Eplus-5Zone-cool-continuous-v1`` +"""""""""""""""""""""""""""""""""" + +:Type: residential building (|home|) +:More info: `framework docs `_ + + +.. _env-Eplus-5Zone-hot-discrete-stochastic-v1: + +``Eplus-5Zone-hot-discrete-stochastic-v1`` +"""""""""""""""""""""""""""""""""""""""""" + +:Type: residential building (|home|) +:More info: `framework docs `_ + + +.. _env-Eplus-5Zone-mixed-discrete-stochastic-v1: + +``Eplus-5Zone-mixed-discrete-stochastic-v1`` +"""""""""""""""""""""""""""""""""""""""""""" + +:Type: residential building (|home|) +:More info: `framework docs `_ + + +.. _env-Eplus-5Zone-cool-discrete-stochastic-v1: + +``Eplus-5Zone-cool-discrete-stochastic-v1`` +""""""""""""""""""""""""""""""""""""""""""" + +:Type: residential building (|home|) +:More info: `framework docs `_ + + +.. _env-Eplus-5Zone-hot-continuous-stochastic-v1: + +``Eplus-5Zone-hot-continuous-stochastic-v1`` +"""""""""""""""""""""""""""""""""""""""""""" + +:Type: residential building (|home|) +:More info: `framework docs `_ + + +.. _env-Eplus-5Zone-mixed-continuous-stochastic-v1: + +``Eplus-5Zone-mixed-continuous-stochastic-v1`` +"""""""""""""""""""""""""""""""""""""""""""""" + +:Type: residential building (|home|) +:More info: `framework docs `_ + + +.. _env-Eplus-5Zone-cool-continuous-stochastic-v1: + +``Eplus-5Zone-cool-continuous-stochastic-v1`` +""""""""""""""""""""""""""""""""""""""""""""" + +:Type: residential building (|home|) +:More info: `framework docs `_ + + +.. _env-Eplus-datacenter-discrete-v1: + +``Eplus-datacenter-discrete-v1`` +"""""""""""""""""""""""""""""""" + +:Type: data center (|industry|) +:More info: `framework docs `_ + + +.. _env-Eplus-datacenter-continuous-v1: + +``Eplus-datacenter-continuous-v1`` +"""""""""""""""""""""""""""""""""" + +:Type: data center (|industry|) +:More info: `framework docs `_ + + +.. _env-Eplus-datacenter-discrete-stochastic-v1: + +``Eplus-datacenter-discrete-stochastic-v1`` +""""""""""""""""""""""""""""""""""""""""""" + +:Type: data center (|industry|) +:More info: `framework docs `_ + + +.. _env-Eplus-datacenter-continuous-stochastic-v1: + +``Eplus-datacenter-continuous-stochastic-v1`` +""""""""""""""""""""""""""""""""""""""""""""" + +:Type: data center (|industry|) +:More info: `framework docs `_ + + +.. _env-Eplus-IWMullion-discrete-v1: + +``Eplus-IWMullion-discrete-v1`` +""""""""""""""""""""""""""""""" + +:Type: office building (|office|) +:More info: `framework docs `_ + + +.. _env-Eplus-IWMullion-continuous-v1: + +``Eplus-IWMullion-continuous-v1`` +""""""""""""""""""""""""""""""""" + +:Type: office building (|office|) +:More info: `framework docs `_ + + +.. _env-Eplus-IWMullion-discrete-stochastic-v1: + +``Eplus-IWMullion-discrete-stochastic-v1`` +"""""""""""""""""""""""""""""""""""""""""" + +:Type: office building (|office|) +:More info: `framework docs `_ + + +.. _env-Eplus-IWMullion-continuous-stochastic-v1: + +``Eplus-IWMullion-continuous-stochastic-v1`` +"""""""""""""""""""""""""""""""""""""""""""" + +:Type: office building (|office|) +:More info: `framework docs `_ diff --git a/docs/envs/envs_list.rst b/docs/envs/envs_list.rst new file mode 100644 index 00000000..79b48207 --- /dev/null +++ b/docs/envs/envs_list.rst @@ -0,0 +1,54 @@ +:BOPTEST: + - `bestest_air`_ |home| + - `bestest_hydronic`_ |home| + - `bestest_hydronic_heat_pump`_ |home| + - `multizone_residential_hydronic`_ |home| + - `singlezone_commercial_hydronic`_ |office| + +---- + +:Energym: + - `Apartments2Thermal-v0`_ |home| + - `Apartments2Grid-v0`_ |home| + - `ApartmentsThermal-v0`_ |home| + - `ApartmentsGrid-v0`_ |home| + - `OfficesThermostat-v0`_ |office| + - `MixedUseFanFCU-v0`_ |office| + - `SeminarcenterThermostat-v0`_ |office| + - `SeminarcenterFull-v0`_ |office| + - `SimpleHouseRad-v0`_ |home| + - `SimpleHouseRSla-v0`_ |home| + - `SwissHouseRSlaW2W-v0`_ |home| + - `SwissHouseRSlaA2W-v0`_ |home| + - `SwissHouseRSlaTank-v0`_ |home| + - `SwissHouseRSlaTankDhw-v0`_ |home| + +---- + +:Sinergym: + - `Eplus-demo-v1`_ |home| + - `Eplus-5Zone-hot-discrete-v1`_ |home| + - `Eplus-5Zone-mixed-discrete-v1`_ |home| + - `Eplus-5Zone-cool-discrete-v1`_ |home| + - `Eplus-5Zone-hot-continuous-v1`_ |home| + - `Eplus-5Zone-mixed-continuous-v1`_ |home| + - `Eplus-5Zone-cool-continuous-v1`_ |home| + - `Eplus-5Zone-hot-discrete-stochastic-v1`_ |home| + - `Eplus-5Zone-mixed-discrete-stochastic-v1`_ |home| + - `Eplus-5Zone-cool-discrete-stochastic-v1`_ |home| + - `Eplus-5Zone-hot-continuous-stochastic-v1`_ |home| + - `Eplus-5Zone-mixed-continuous-stochastic-v1`_ |home| + - `Eplus-5Zone-cool-continuous-stochastic-v1`_ |home| + - `Eplus-datacenter-discrete-v1`_ |industry| + - `Eplus-datacenter-continuous-v1`_ |industry| + - `Eplus-datacenter-discrete-stochastic-v1`_ |industry| + - `Eplus-datacenter-continuous-stochastic-v1`_ |industry| + - `Eplus-IWMullion-discrete-v1`_ |office| + - `Eplus-IWMullion-continuous-v1`_ |office| + - `Eplus-IWMullion-discrete-stochastic-v1`_ |office| + - `Eplus-IWMullion-continuous-stochastic-v1`_ |office| + + .. |office| image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/building-skyscraper.svg + .. |home| image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/home.svg + .. |industry| image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/building-factory.svg + \ No newline at end of file diff --git a/docs/guides.rst b/docs/guides.rst index c47c9ee6..f097f742 100644 --- a/docs/guides.rst +++ b/docs/guides.rst @@ -1,6 +1,6 @@ -===== +====== Guides -===== +====== Welcome to beobench's usage guides! diff --git a/docs/guides/add_env.rst b/docs/guides/add_env.rst index edb127e5..30cd1951 100644 --- a/docs/guides/add_env.rst +++ b/docs/guides/add_env.rst @@ -14,35 +14,36 @@ Creating build context To add an environment to beobench we need to create a special *docker build context* (for more details `see the official docker build documentation `_). Such a beobench-specific *docker build context* consists at least of the following two files in a folder ``/``: 1. A dockerfile ``Dockerfile`` that defines a docker container that has everything necessary for your environment installed. In addition to any of your packages/modules, the dockerfile must also install `beobench` via pip. -2. A ``env_creator.py`` file that defines a function with the signature ``create_env(env_config: dict = None) -> gym.Env``. This ``create_env()`` function should take an ``env_config`` dictionary (that completely configures your environment) as input and return an instance of your environment with this configuration. If your environment is not yet implementing the commonly used ``gym.Env`` class (`see here `_), you will need to wrap your environment in a class that implements this ``gym.Env`` class within the ``create_env()`` function. +2. An ``env_creator.py`` file that defines a function with the signature ``create_env(env_config: dict = None) -> gym.Env``. This ``create_env()`` function should take an ``env_config`` dictionary (that completely configures your environment) as input and return an instance of your environment with this configuration. If your environment is not yet implementing the commonly used ``gym.Env`` class (`see here `_), you will need to wrap your environment in a class that implements this ``gym.Env`` class within the ``create_env()`` function. The path to the folder with these two files, ``path/to/folder//``, can either be on your local file system or on github. It can also contain additional files that help with the installation process. -**Example**: for an example of such a *docker context folder* see `the official BOPTEST integration folder `_. +**Example**: for an example of such a *docker context folder* see `the official BOPTEST integration folder `_. Defining experiment ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -In order run an experiment on your gym, we need to add the build context to an experiment definition. This can be done by adding/changing the following parameter in your experiment definition file ``example_experiment_def.py`` (see the :doc:`usage` page for how to create a complete experiment definition file): +In order run an experiment on your gym, we need to add the build context to an experiment definition. This can be done by adding/changing the following parameter in your experiment definition file ``example.yaml`` (see :doc:`/guides/intro_experiment` for how to create a complete experiment definition file): -.. code-block:: python +.. code-block:: yaml - problem = { - "problem_library": "path/to/folder//", - ... - } + # ... + env: + gym: "path/to/folder//" + # ... -For example, we could set the ``problem_library`` key to ``"https://github.com/rdnfn/beobench.git#master:beobench/integrations/boptest"``. + +For example, we could set the ``gym`` key to ``"https://github.com/rdnfn/beobench_contrib.git#main:gyms/boptest"``. .. warning:: - Only set ``problem_library`` to experiment build contexts from authors that you trust. This setting can create an arbitrary docker container on your system. + Only set ``gym`` to experiment build contexts from authors that you trust. This setting can create an arbitrary docker container on your system. Running experiment ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -With a complete experiment definition file ``example_experiment_def.py``, we can then use the standard command below to start the experiment: +With a complete experiment definition file ``example.yaml``, we can then use the standard command below to start the experiment: .. include:: ../snippets/run_standard_experiment.rst diff --git a/docs/guides/dev_env.rst b/docs/guides/dev_env.rst index e5ef68cd..b78eafc4 100644 --- a/docs/guides/dev_env.rst +++ b/docs/guides/dev_env.rst @@ -6,39 +6,48 @@ Setting up development environment Requirements ^^^^^^^^^^^^^^^^^^ -Beobench uses `vscode dev containers `_ for its development environment. The installation has the following pre-requisites on the local machine: +Beobench uses `vscode devcontainers `_ for its development environment. A devcontainer allows all developers to work on (almost) identical systems, ensuring that not only python packages but also operating systems are the same. The installation of this development environment has the following pre-requisites: 1. `Docker `_ 2. `Visual Studio Code (vscode) `_ 3. `vscode remote extension pack `_ -Additionally, for remote development, the remote machine must have docker installed. +Standard development +^^^^^^^^^^^^^^^^^^^^ -Local development -^^^^^^^^^^^^^^^^^^ +1. Fork the Beobench repo on GitHub (if you are a maintainer you can skip this step). +2. Clone your fork locally using + .. code-block:: -1. Clone the repo locally to your machine using + git clone --recursive git@github.com:/beobench.git - .. code-block:: + (if you are a maintainer you can clone directly from the main repository) - git clone git@github.com:rdnfn/beobench.git + Note that this requires having your github authentification setup, `see here `_. -2. Open the git repo folder in vscode -3. Inside vscode, open the command palette (shortcut is ``shift`` + ``cmd`` + ``P`` on macos), and use the ``Remote-containers: open folder in container`` command. Select the ``beobench`` repo in the pop-up window (NOT the ``beobench`` folder inside the repo). +3. Open the beobench repo folder in vscode +4. Inside vscode, open the command palette (e.g. on macOS shortcut is ``shift`` + ``cmd`` + ``P``), and use the ``Remote-containers: reopen in container`` command. -This should have opened a new vscode window running in the docker dev container -- once the dev container is ready you're done! (Note: this gets faster after the first docker build) +This should have opened a new vscode window running in the docker dev container --- once the dev container is ready you're done! (Note: this gets faster after the first docker build) Remote development ^^^^^^^^^^^^^^^^^^ -It may be desireable to run your dev container on a remote machine. In order to do this you need to follow the following steps: +.. note:: + Remote development is only useful if you have a separate server available to develop on. The standard development in the previous section will be more useful in most scenarios. + + +It may be desireable to run your devcontainer not directly on your local machine (e.g. laptop) but instead on a remote machine (i.e. server). The local machine then just provides an interface to the remote machine. + +In order to set this up you need to follow these steps: -1. Follow all the instructions for local development above (apart from the final step 3). -2. Clone the repo to your *remote* machine. -3. In the cloned repo on your local machine, in ``.devcontainer/devcontainer.json`` replace the line +1. Follow all the instructions for local development above (apart from the final step 4). +2. Ensure that docker is installed on the remote machine. +3. Clone the repo to your *remote* machine. +4. In the cloned repo on your local machine, in ``.devcontainer/remote/.devcontainer/devcontainer.json`` replace the line .. code-block:: @@ -51,8 +60,8 @@ It may be desireable to run your dev container on a remote machine. In order to "workspaceMount": "source=,target=/workspace,type=bind,consistency=cached" - where ``PATH_TO_CLONED_REPO`` is the path to your repo on the remote machine. + where ``PATH_TO_CLONED_REPO`` is the path to your repo on the remote machine. Similarly, adapt the path in the ``"mounts"`` argument to the location of your ``.gitconfig`` file on the remote machine. -4. Create a docker context on your local machine that connects to docker on your remote machine (`See the instructions here `_). -5. Use the ``Remote-containers: open folder in container`` command and select the ``beobench`` repo in the pop-up window (NOT the ``beobench`` folder inside the repo). +5. Create a docker context on your local machine that connects to docker on your remote machine (`See the instructions here `_). +6. Use the ``Remote-containers: open folder in container`` command and select the ``beobench/.devcontainer/remote`` folder in the pop-up window (beobench here is the main repo folder). diff --git a/docs/guides/intro_experiment.rst b/docs/guides/intro_experiment.rst index 6bfd8bf0..1858b00c 100644 --- a/docs/guides/intro_experiment.rst +++ b/docs/guides/intro_experiment.rst @@ -14,33 +14,15 @@ The diagram below gives an overview of how beobench experiments work. The ``beob Experiment configuration ^^^^^^^^^^^^^^^^^^^^^^^^^ -Beobench defines experiments using three separate dictionaries for problem, method and machine configuration. Each defines the parameters relevant to one of these configurations. Internally, beobench then merges these three dictionaries into a single dictionary that is passed to the ``ray.tune.run()`` function. A beobench configuration file is a ``.py`` file that defines the variables ``problem``, ``method`` and ``rllib_setup``. For example, let the following be the content of a file named ``example_experiment_def.py``: +Beobench experiments are configured either using a *Python dictionary* or an equivalent *yaml file*. For example, the following ``example.yaml`` file configures an experiment that evaluates an RLlib-based *proximal policy optimisation* (PPO) agent on the ``MixedUseFanFCU-v0`` environment of Energym: -.. include:: ../../beobench/experiment/definitions/default.py - :start-line: 2 - :code: python +.. literalinclude:: ../../beobench/experiment/definitions/default.yaml + :language: yaml -Given this configuration file ``example_experiment_def.py``, we can the experiment using the following commands: +Given this configuration file ``example.yaml``, we can run the experiment using the following commands: .. include:: ../snippets/run_standard_experiment.rst - -Hyperparameter Search Spaces -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -So far, we only configured a single experiment. However, we likely want to test multiple experiment configurations. As beobench builds on *Ray RLlib* and *Ray Tune*, we can use the powerful `Ray Tune Search Space API `_. This API allows us to configure pretty much any hyperparameter search space. For example to do grid search on the learning rate, we can replace the following line in the previously shown ``example_experiment_def.py`` - -.. code-block:: python - - "lr": 5e-3, - -with - -.. code-block:: python - - "lr": ray.tune.grid_search([5e-3, 5e-4, 5e-5]), - -Beobench will then run three experiments trying three different values of the learning rate (``lr``). Note that ``import ray.tune`` must also be included in ``example_experiment_def.py``. In addition to simple grid search, it is also possible to use *Ray Tune's* `Random Distribution API `_. This allows us to create probabilistic hyperparameter search spaces, that we can either randomly sample or apply optimisation algorithms to. See the `Ray Tune Search Space API documentation `_ for a more complete description of the functionality. \ No newline at end of file diff --git a/docs/index.rst b/docs/index.rst index 785c075c..aaffebb3 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -14,9 +14,10 @@ Contents self guides/installation guides + envs api contributing - authors + credits history Indices and tables diff --git a/docs/snippets/run_standard_experiment.rst b/docs/snippets/run_standard_experiment.rst index 5ec46ce7..1aed4ff5 100644 --- a/docs/snippets/run_standard_experiment.rst +++ b/docs/snippets/run_standard_experiment.rst @@ -2,10 +2,10 @@ .. code-tab:: console Console - beobench run --experiment-file example_experiment_def.py + beobench run --config example.yaml .. code-tab:: python import beobench - beobench.run(experiment_file = "example_experiment_def.py") \ No newline at end of file + beobench.run(config = "example.yaml") \ No newline at end of file diff --git a/notebooks/utils/nb001_create_envs_table.ipynb b/notebooks/utils/nb001_create_envs_table.ipynb new file mode 100644 index 00000000..0e4eaad0 --- /dev/null +++ b/notebooks/utils/nb001_create_envs_table.ipynb @@ -0,0 +1,165 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "%reload_ext autoreload\n", + "%autoreload 2\n", + "%config IPCompleter.greedy=True\n", + "%config IPCompleter.use_jedi=False" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Load data from google sheet\n", + "sheet_id = \"1QaXBrhDY8tyF9cIBjejDTGMiv5vDUQG0KQ7iVapGQoY\"\n", + "gid = 1987847080\n", + "link = f\"https://docs.google.com/feeds/download/spreadsheets/Export?key={sheet_id}&exportFormat=csv&gid={gid}\"\n", + "envs = pd.read_csv(link)\n", + "\n", + "# Preprocessing\n", + "\n", + "# Add house type icons\n", + "def emojify(row): \n", + " house_type = row[\"House type\"]\n", + " if house_type == \"residential\":\n", + " return \"|home|\"\n", + " elif house_type == \"office\":\n", + " return \"|office|\"\n", + " elif house_type == \"industrial\":\n", + " return \"|industry|\"\n", + " return \"other\"\n", + "\n", + "def new_type(row): \n", + " house_type = row[\"House type\"]\n", + " if house_type == \"residential\":\n", + " return \"residential building\"\n", + " elif house_type == \"office\":\n", + " return \"office building\"\n", + " elif house_type == \"industrial\":\n", + " return \"data center\"\n", + " return \"data center\"\n", + "\n", + "envs['Type'] = envs.apply(lambda row: emojify(row), axis=1)\n", + "envs['new_type'] = envs.apply(lambda row: new_type(row), axis=1)\n", + "\n", + "# Make sure each env has gym\n", + "envs['Gym'] = envs['Gym'].replace('', np.NaN)\n", + "envs['Gym'] = envs['Gym'].fillna(method='ffill',axis=0)\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "# Create main environment list\n", + "\n", + "def create_main_list(filepath=\"../../docs/envs/envs_list.rst\"):\n", + "\n", + " rst_out = \"\"\n", + "\n", + " for i, gym in enumerate(envs['Gym'].unique()):\n", + " gym_envs = envs[envs['Gym']==gym]\n", + "\n", + " rst_out += f\":{gym}:\\n\"\n", + "\n", + " for index, row in gym_envs.iterrows():\n", + " env = row[\"Environment\"]\n", + " symbol = row[\"Type\"]\n", + " rst_out += f\" - `{env}`_ {symbol}\\n\"\n", + "\n", + " # Add hline between gyms\n", + " if i < len(envs['Gym'].unique()) - 1:\n", + " rst_out += \"\\n----\\n\\n\"\n", + "\n", + " # Add image links\n", + " rst_out += \"\"\"\n", + " .. |office| image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/building-skyscraper.svg\n", + " .. |home| image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/home.svg\n", + " .. |industry| image:: https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/building-factory.svg\n", + " \"\"\"\n", + "\n", + " with open(filepath, 'w') as file:\n", + " file.write(rst_out)\n", + "\n", + "\n", + "create_main_list(filepath=\"../../docs/envs/envs_list.rst\")" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "def create_env_descriptions():\n", + " for _, gym in enumerate(envs['Gym'].unique()):\n", + " env_descr_file = f\"../../docs/envs/{gym}_descriptions.rst\"\n", + " rst_out = \"\"\n", + " gym_envs = envs[envs['Gym']==gym]\n", + "\n", + " for _, row in gym_envs.iterrows():\n", + " env = row[\"Environment\"]\n", + " rst_out += f\"\\n\\n.. _env-{env}: \\n\\n\"\n", + " rst_out += f\"``{env}``\\n\"\n", + " rst_out += '\"' * (len(env) + 4) + \"\\n\\n\"\n", + " rst_out += f\":Type: {row['new_type']} ({row['Type']})\\n\"\n", + " rst_out += f\":More info: `framework docs <{row['Original docs']}>`_\\n\"\n", + "\n", + " with open(env_descr_file, 'w') as file:\n", + " file.write(rst_out)\n", + "\n", + "create_env_descriptions()\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "interpreter": { + "hash": "949777d72b0d2535278d3dc13498b2535136f6dfe0678499012e853ee9abcab1" + }, + "kernelspec": { + "display_name": "Python 3.9.7 64-bit", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.7" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/requirements/dev_requirements.txt b/requirements/dev_requirements.txt index 66db0b5b..61976f21 100644 --- a/requirements/dev_requirements.txt +++ b/requirements/dev_requirements.txt @@ -20,10 +20,10 @@ build # PyPA build tool jupyterlab # ML & RL tools -gym -torch -ray[rllib] -wandb +# gym +# torch +# ray[rllib] +# wandb # Convex solver tools (OPTIONAL) # cvxpy \ No newline at end of file diff --git a/requirements/doc_requirements.txt b/requirements/doc_requirements.txt index 0c4cdeeb..a91601fd 100644 --- a/requirements/doc_requirements.txt +++ b/requirements/doc_requirements.txt @@ -1 +1,8 @@ -sphinx-tabs \ No newline at end of file +sphinx-tabs +myst-parser +sphinx-book-theme +docutils>=0.17 + +# Because of the following bug +# https://github.com/readthedocs/readthedocs.org/issues/9038 +Jinja2<3.1 \ No newline at end of file diff --git a/setup.cfg b/setup.cfg index 48467b0f..d798603a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.3.0 +current_version = 0.4.0 commit = True tag = True diff --git a/setup.py b/setup.py index 44d1d342..53fe9b53 100644 --- a/setup.py +++ b/setup.py @@ -10,19 +10,23 @@ with open("HISTORY.rst", encoding="UTF-8") as history_file: history = history_file.read() -version = "0.3.0" +version = "0.4.0" # pylint: disable=invalid-name requirements = [ - "wandb", "docker", - "ray[rllib]", "click", - "torch", - "gym", + "pyyaml", ] +# The extended requirements are only used inside experiment/gym containers +extended_requirements = [] -test_requirements = [] +rllib_requirements = [ + "ray[rllib]", + "torch", + "gym", + "wandb", +] setup( author="rdnfn", @@ -39,6 +43,10 @@ ], description="Beobench is a toolbox for benchmarking reinforcement learning (RL) algorithms on building energy optimisation (BEO) problems.", # pylint: disable=line-too-long install_requires=requirements, + extras_require={ + "extended": extended_requirements, + "rllib": rllib_requirements, + }, license="MIT license", long_description=readme + "\n\n" + history, include_package_data=True, @@ -51,7 +59,6 @@ ], }, test_suite="tests", - tests_require=test_requirements, project_urls={ "Documentation": "https://beobench.readthedocs.io/", "Code": "https://github.com/rdnfn/beobench",