Skip to content

Commit

Permalink
(v3.7.2) - Ornstein-Uhlenbeck parameters range specification feature …
Browse files Browse the repository at this point in the history
…and workflows improvement (#465)

* Fix weather noise configuration in scripts/train_agent.py

* Environment: Env can accept ranges in OU parameters specification for each weather variable, update docstring

* Environment: Added weather variability specification checker

* Modeling: Detect ranges in OU parameters and select a random value before to start OU process

* Modeling: Save the exact OU configuration for each episode

* Documentation: Update copyright to 2025

* Documentation: Added information about ranges in OU parameters (environments section)

* Environment: Fix weather noise checker

* Tests: Fix some tau values in common and wrapper tests

* Test: Check creation of weather noise file configuration in modeling

* Tests: Added asserts for weather noise exceptions

* Add cov.xml to gitignore

* Documentation: Add test coverage section in tests chapter

* Fix docstring

* Update Sinergym version from 3.7.1 to 3.7.2

* Documentation: Add json file weather configuration information

* Workflow improvement: Setup Python before Poetry installation

* Workflow fix: Stop ussing github actions for autopep8 and isort. Instead, using the exact version of the project
  • Loading branch information
AlejandroCN7 authored Jan 20, 2025
1 parent 2f138dc commit 445e3a6
Show file tree
Hide file tree
Showing 16 changed files with 219 additions and 84 deletions.
61 changes: 30 additions & 31 deletions .github/workflows/create_pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on: pull_request
# pwd: /home/runner/work/sinergym/sinergym

jobs:
autopep8-check:
autopep8-isort-check:
runs-on: ubuntu-24.04
steps:

Expand All @@ -16,17 +16,34 @@ jobs:
with:
python-version: ${{ vars.PYTHON_VERSION }}

- name: Install Poetry
uses: snok/install-poetry@v1
with:
version: latest
virtualenvs-create: true
virtualenvs-in-project: true
installer-parallel: true

- name: Install autopep8 and isort
run: poetry install --no-interaction --only format

- name: autopep8 check
id: autopep8
uses: peter-evans/autopep8@v2
with:
args: --exit-code --recursive --diff --aggressive --aggressive .
run: poetry run autopep8 --exit-code --recursive --diff --aggressive --aggressive .
continue-on-error: true

- name: Fail if autopep8 made changes
if: steps.autopep8.outputs.exit-code == 2
run: exit 1
- name: isort check
id: isort
run: poetry run isort --check-only --diff .
continue-on-error: true

- name: Fail if autopep8/isort found diffs
if: steps.autopep8.outcome != 'success' || steps.isort.outcome != 'success'
run: |
echo "Error detected in code formatting (autopep8 and/or isort)."
exit 1
isort-check:
type-check:
runs-on: ubuntu-24.04
steps:

Expand All @@ -38,31 +55,13 @@ jobs:
with:
python-version: ${{ vars.PYTHON_VERSION }}

- name: isort check
id: isort-step
# default configuration use --check-only and --diff instead of --in-place options.
uses: isort/isort-action@master
continue-on-error: false

type-check:
runs-on: ubuntu-24.04
steps:

- name: Checkout code
uses: actions/checkout@v4

- name: Install Poetry
uses: snok/install-poetry@v1
with:
version: latest
virtualenvs-create: true
virtualenvs-in-project: true
installer-parallel: true

- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: ${{ vars.PYTHON_VERSION }}

- name: Install pytype
run: poetry install --no-interaction --only typing
Expand All @@ -77,18 +76,18 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: ${{ vars.PYTHON_VERSION }}

- name: Install Poetry
uses: snok/install-poetry@v1
with:
version: latest
virtualenvs-create: true
virtualenvs-in-project: true
installer-parallel: true

- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: ${{ vars.PYTHON_VERSION }}

- name: Verify documentation update
uses: dorny/paths-filter@v3
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/create_release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: ${{ vars.PYTHON_VERSION }}

- name: Install Poetry
uses: snok/install-poetry@v1
with:
Expand All @@ -75,11 +80,6 @@ jobs:
virtualenvs-in-project: true
installer-parallel: true

- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: ${{ vars.PYTHON_VERSION }}

- name: Build the distribution files
run: poetry build

Expand Down
48 changes: 23 additions & 25 deletions .github/workflows/merge_pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,31 +18,29 @@ jobs:
with:
python-version: ${{ vars.PYTHON_VERSION }}

- name: Apply isort
id: isort-step
# default configuration use --check-only and --diff instead of --in-place options.
uses: isort/isort-action@master
- name: Install Poetry
uses: snok/install-poetry@v1
with:
configuration: --only-modified
version: latest
virtualenvs-create: true
virtualenvs-in-project: true
installer-parallel: true

- name: autopep8 check and fix
id: autopep8
uses: peter-evans/autopep8@v2
with:
args: --exit-code --recursive --in-place --aggressive --aggressive .
- name: Install autopep8 and isort
run: poetry install --no-interaction --only format

- name: Detect changes by isort
uses: tj-actions/verify-changed-files@v18
id: verify-isort-update
with:
files: |
tests/
sinergym/
examples/
*.py
- name: Apply isort
id: isort
run: poetry run isort .
continue-on-error: true

- name: apply autopep8
id: autopep8
run: poetry run autopep8 --exit-code --recursive --in-place --aggressive --aggressive .
continue-on-error: true

- name: Commit format changes
if: steps.autopep8.outputs.exit-code == 2 || steps.verify-isort-update.outputs.files_changed == 'true'
if: steps.autopep8.outcome != 'success' || steps.isort.outcome != 'success'
uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: Automatic format fixes (autopep8 + isort)
Expand All @@ -57,18 +55,18 @@ jobs:
with:
fetch-depth: 0

- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: ${{ vars.PYTHON_VERSION }}

- name: Install Poetry
uses: snok/install-poetry@v1
with:
version: latest
virtualenvs-create: true
virtualenvs-in-project: true
installer-parallel: true

- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: ${{ vars.PYTHON_VERSION }}

- name: Verify documentation update
uses: dorny/paths-filter@v3
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ dist/
.coverage
codecov
coverage.xml
cov.xml

#wandb
wandb/
Expand Down
2 changes: 1 addition & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
# -- Project information -----------------------------------------------------

project = 'Sinergym'
copyright = '2024, J. Jiménez, J. Gómez, M. Molina, A. Manjavacas, A. Campoy'
copyright = '2025, J. Jiménez, J. Gómez, M. Molina, A. Manjavacas, A. Campoy'
author = 'J. Jiménez, J. Gómez, M.l Molina, A. Manjavacas, A. Campoy'


Expand Down
2 changes: 2 additions & 0 deletions docs/source/pages/environments.rst
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ Finally, :math:`\tau` is the time constant (in hours), controlling how quickly t

In climate systems, a large :math:`\tau` could model scenarios where extreme events, such as heatwaves or cold spells, last longer before the system reverts to its average state. The next figure illustrates the effect of different hyperparameters on the Ornstein-Uhlenbeck process noise in a mixed weather.

Starting from version 3.7.2 of Sinergym, these hyperparameters (:math:\sigma, :math:\mu, and :math:\tau) can also be defined as ranges of values rather than fixed constants. To configure this, a tuple of two values (minimum and maximum) is used instead of a single float. For each episode, a random value is sampled from the specified range, enabling more dynamic and varied simulations that better capture the inherent unpredictability of climate systems. A JSON file is saved with the chosen parameters in each episode subfolder.

.. note:: Starting from Sinergym v3.7.1, :math:`\tau` is represented in hours instead of as a percentage of the climate file, making its use more intuitive.

.. image:: /_static/ornstein_noise_v2.png
Expand Down
10 changes: 10 additions & 0 deletions docs/source/pages/tests.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,16 @@ To run tests for a specific module, such as ``test_common.py``, use the followin
$ pytest tests/test_common.py -vv
*************
Test coverage
*************

To check the test coverage, you can use the following command:

.. code:: sh
$ pytest --cov=. tests/ --cov-report xml:cov.xml
***************
Available tests
***************
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
package-mode = true
name = "sinergym"

version = "3.7.1"
version = "3.7.2"
description = "Sinergym provides a Gymnasium-based interface to interact with building simulations. This allows control in simulation time through custom controllers, including reinforcement learning agents"
license = "MIT"

Expand Down
5 changes: 3 additions & 2 deletions scripts/train/train_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ def process_environment_parameters(env_params: dict) -> dict:
env_params['actuators'][actuator_name] = tuple(components)

if env_params.get('weather_variability'):
env_params['weather_variability'] = tuple(
env_params['weather_variability'])
for var_name, var_params in env_params['weather_variability'].items():
env_params['weather_variability'][var_name] = tuple(
var_params)

if env_params.get('reward'):
env_params['reward'] = eval(env_params['reward'])
Expand Down
34 changes: 27 additions & 7 deletions sinergym/config/modeling.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,11 +318,15 @@ def update_weather_path(self) -> None:

def apply_weather_variability(
self,
weather_variability: Optional[Dict[str, Tuple[float, float, float]]] = None) -> str:
weather_variability: Optional[Dict[str, Tuple[
Union[float, Tuple[float, float]],
Union[float, Tuple[float, float]],
Union[float, Tuple[float, float]]
]]] = None) -> str:
"""Modify weather data using Ornstein-Uhlenbeck process according to the variation specified in the weather_variability dictionary.
Args:
weather_variability (Optional[Dict[str, Tuple[float, float, float]]], optional): Dictionary with the variation for each column in the weather data. Defaults to None. The key is the column name and the value is a tuple with the sigma, mean and tau for OU process.
weather_variability (Optional[Dict[str,Tuple[Union[float,Tuple[float,float]],Union[float,Tuple[float,float]],Union[float,Tuple[float,float]]]]]): Dictionary with the variation for each column in the weather data. Defaults to None. The key is the column name and the value is a tuple with the sigma, mean and tau for OU process.
Returns:
str: New EPW file path generated in simulator working path in that episode or current EPW path if variation is not defined.
Expand All @@ -334,18 +338,34 @@ def apply_weather_variability(
# Apply variation to EPW if exists
if weather_variability is not None:

# Check if there are ranges specified in params and get a random
# value
variability_config = {
weather_var: tuple(
np.random.uniform(param[0], param[1]) if isinstance(param, tuple) else param
for param in params
)
for weather_var, params in weather_variability.items()
}

# Write variability_config to a JSON file for episode
config_path = f"{
self.episode_path}/weather_variability_config.json"
with open(config_path, 'w') as f:
json.dump(variability_config, f)

# Apply Ornstein-Uhlenbeck process to weather data
weather_data_mod.dataframe = ornstein_uhlenbeck_process(
data=self.weather_data.dataframe,
variability_config=weather_variability)
variability_config=variability_config)

self.logger.info(
'Weather noise applied in columns: {}'.format(
list(
weather_variability.keys())))
variability_config.keys())))

# Change name filename to specify variation nature in name
filename = filename.split('.epw')[0]
filename += '_OU_Noise.epw'
# Modify filename to reflect noise addition
filename = f"{filename.split('.epw')[0]}_OU_Noise.epw"

episode_weather_path = self.episode_path + '/' + filename
weather_data_mod.write(episode_weather_path)
Expand Down
Loading

0 comments on commit 445e3a6

Please sign in to comment.