Skip to content

Commit 2902239

Browse files
authored
(v3.7.3) - Weather variability config logging in CSVLogger wrapper (#466)
* Modeling: Delete OU configuration in episode folder, save episode OU parameters as attribute * CSVLogger: Save OU parameters in CSV for each episode * Tests fixed * Documentation: Update Sinergym output graph image and documentation section * Update Sinergym version from 3.7.2 to 3.7.3
1 parent bc874d3 commit 2902239

File tree

8 files changed

+56
-24
lines changed

8 files changed

+56
-24
lines changed
2.15 KB
Loading

docs/source/pages/output.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ The contents of this root output directory include the results of the simulation
4646

4747
- ``progress.csv``. This file contains information about general simulation results. Each row contains episode information registering relevant data such as mean power consumption, rewards or comfort penalties. This file is only available when the environment has been wrapped with a ``LoggerWrapper`` and ``CSVLogger`` (see :ref:`Logger Wrappers` for more information). The structure of this file is defined by the ``LoggerWrapper`` class.
4848

49+
- ``weather_variability_config.json``. This file contains the configuration of the weather variability for each episode. It is only created when the environment has been wrapped with ``LoggerWrapper`` and ``CSVLogger``. It is very useful when you are using ranges in weather variability paramters (more information in :ref:`Weather variability`)
50+
4951
- ``data_available.txt``. It is generated when the *EnergyPlus* API initializes all callbacks and handlers for the simulation. In this file, you can find all the available components of the building model, such as actuators, schedulers, meters, variables, internal variables, etc.
5052

5153
- ``mean.txt`` and ``var.txt``. These files contain the mean and variation values for calibration of normalization in observation space if wrapper ``NormalizeObservation`` is used (see :ref:`NormalizeObservation`).

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
package-mode = true
77
name = "sinergym"
88

9-
version = "3.7.2"
9+
version = "3.7.3"
1010
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"
1111
license = "MIT"
1212

sinergym/config/modeling.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ def __init__(
103103
# Weather data (epw.weather object)
104104
self.weather_data = Weather()
105105
self.weather_data.read(self._weather_path)
106+
# Weather variability if exists
107+
self.weather_variability_config = None
106108

107109
# ----------------------------- Other attributes ----------------------------- #
108110

@@ -340,29 +342,23 @@ def apply_weather_variability(
340342

341343
# Check if there are ranges specified in params and get a random
342344
# value
343-
variability_config = {
345+
self.weather_variability_config = {
344346
weather_var: tuple(
345347
np.random.uniform(param[0], param[1]) if isinstance(param, tuple) else param
346348
for param in params
347349
)
348350
for weather_var, params in weather_variability.items()
349351
}
350352

351-
# Write variability_config to a JSON file for episode
352-
config_path = f"{
353-
self.episode_path}/weather_variability_config.json"
354-
with open(config_path, 'w') as f:
355-
json.dump(variability_config, f)
356-
357353
# Apply Ornstein-Uhlenbeck process to weather data
358354
weather_data_mod.dataframe = ornstein_uhlenbeck_process(
359355
data=self.weather_data.dataframe,
360-
variability_config=variability_config)
356+
variability_config=self.weather_variability_config)
361357

362358
self.logger.info(
363359
'Weather noise applied in columns: {}'.format(
364360
list(
365-
variability_config.keys())))
361+
self.weather_variability_config.keys())))
366362

367363
# Modify filename to reflect noise addition
368364
filename = f"{filename.split('.epw')[0]}_OU_Noise.epw"

sinergym/utils/wrappers.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1478,6 +1478,9 @@ def __init__(
14781478
self.progress_file_path = self.get_wrapper_attr(
14791479
'workspace_path') + '/progress.csv'
14801480

1481+
self.weather_variability_config_path = self.get_wrapper_attr(
1482+
'workspace_path') + '/weather_variability_config.csv'
1483+
14811484
self.logger.info('Wrapper initialized.')
14821485

14831486
def reset(self,
@@ -1602,6 +1605,31 @@ def dump_log_files(self) -> None:
16021605
writer.writerow(list(episode_summary.keys()))
16031606
writer.writerow(list(episode_summary.values()))
16041607

1608+
# Update weather_variability_config if exists
1609+
modeling = self.get_wrapper_attr('model')
1610+
config_path = self.get_wrapper_attr(
1611+
'weather_variability_config_path')
1612+
1613+
if modeling.weather_variability_config is not None:
1614+
with open(config_path, 'a+') as f:
1615+
writer = csv.writer(f)
1616+
1617+
# If first episode, write header
1618+
if self.get_wrapper_attr('episode') == 1:
1619+
header = ['episode_num'] + [
1620+
f"{var_name}_{var_param}"
1621+
for var_name in list(modeling.weather_variability_config.keys())
1622+
for var_param in ['sigma', 'mu', 'tau']
1623+
]
1624+
writer.writerow(header)
1625+
1626+
# Write OU params for each weather variable
1627+
var_values = list()
1628+
var_values = [
1629+
self.get_wrapper_attr('episode')] + [
1630+
value for params in modeling.weather_variability_config.values() for value in params]
1631+
writer.writerow(var_values)
1632+
16051633

16061634
# ---------------------------------------------------------------------------- #
16071635

sinergym/version.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3.7.2
1+
3.7.3

tests/test_modeling.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -200,23 +200,13 @@ def test_apply_weather_variability(model_5zone):
200200
original_filename = model_5zone._weather_path.split('/')[-1]
201201
path_filename = path_result.split('/')[-1]
202202
assert original_filename == path_filename
203-
# It shouldn't generate variability config
204-
# It should generate a json file
205-
assert not os.path.exists(
206-
model_5zone.episode_path +
207-
'/weather_variability_config.json')
208-
209203
# Check with a variation
210204
weather_variability = {
211205
'Dry Bulb Temperature': (1.0, 0.0, 24.0),
212206
'Wind Speed': (3.0, 0.0, 35.0)
213207
}
214208
path_result = model_5zone.apply_weather_variability(
215209
weather_variability=weather_variability)
216-
# It should generate weather variability config file
217-
assert os.path.exists(
218-
model_5zone.episode_path +
219-
'/weather_variability_config.json')
220210
filename = model_5zone._weather_path.split('/')[-1]
221211
filename = filename.split('.epw')[0]
222212
filename += '_OU_Noise.epw'

tests/test_wrapper.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -850,9 +850,14 @@ def test_custom_loggers(env_demo, custom_logger_wrapper):
850850
assert logger.interactions == 0
851851

852852

853-
def test_CSVlogger_wrapper(env_demo):
854-
855-
env = CSVLogger(env=LoggerWrapper(env=NormalizeObservation(env=env_demo)))
853+
@pytest.mark.parametrize('env_name',
854+
[('env_demo'),
855+
('env_5zone_stochastic')
856+
])
857+
def test_CSVlogger_wrapper(env_name, request):
858+
env = request.getfixturevalue(env_name)
859+
860+
env = CSVLogger(env=LoggerWrapper(env=NormalizeObservation(env=env)))
856861
# Check progress CSV path
857862
assert env.get_wrapper_attr('progress_file_path') == env.get_wrapper_attr(
858863
'workspace_path') + '/progress.csv'
@@ -862,6 +867,8 @@ def test_CSVlogger_wrapper(env_demo):
862867

863868
# Assert logger files are not created
864869
assert not os.path.isfile(env.get_wrapper_attr('progress_file_path'))
870+
assert not os.path.isfile(env.get_wrapper_attr(
871+
'weather_variability_config_path'))
865872
assert not os.path.isdir(env.get_wrapper_attr('episode_path') + '/monitor')
866873

867874
# simulating short episode
@@ -881,6 +888,15 @@ def test_CSVlogger_wrapper(env_demo):
881888
reader = csv.reader(csvfile, delimiter=',')
882889
# Header row and episode summary
883890
assert len(list(reader)) == 2
891+
if env_name == 'env_demo':
892+
# File not exists
893+
assert not os.path.isfile(env.get_wrapper_attr(
894+
'weather_variability_config_path'))
895+
else:
896+
with open(env.get_wrapper_attr('weather_variability_config_path'), mode='r', newline='') as csvfile:
897+
reader = csv.reader(csvfile, delimiter=',')
898+
# Header row and episode config
899+
assert len(list(reader)) == 2
884900
# Check csv in monitor is created correctly (only check with observations)
885901
with open(episode_path + '/monitor/observations.csv', mode='r', newline='') as csvfile:
886902
reader = csv.reader(csvfile, delimiter=',')

0 commit comments

Comments
 (0)