22. Wrappers example

In this notebook, we’ll explore the wrappers defined by Sinergym and how to use them. You can also create your own wrappers by inheriting from gym.Wrapper or its variants.

[1]:
import gymnasium as gym
import numpy as np
import sinergym
from sinergym.utils.wrappers import *

22.1. Multi-Objective Wrapper

MO-Gymnasium is an open-source Python library for developing and comparing multi-objective reinforcement learning algorithms. These environments return a reward vector instead of a scalar value, one for each objective.

To be as general as possible, it could be beneficial for Sinergym to also provide that reward vector. This way, Sinergym would be compatible with both multi-objective algorithms and algorithms that work with a traditional reward value.

We can transform the returned reward into a vector using the following wrapper:

[2]:
env=gym.make('Eplus-5zone-hot-discrete-v1')
env=MultiObjectiveReward(env,reward_terms=['energy_term','comfort_term'])
#==============================================================================================#
[ENVIRONMENT] (INFO) : Creating Gymnasium environment... [5zone-hot-discrete-v1]
#==============================================================================================#
[MODELING] (INFO) : Experiment working directory created [/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res1]
[MODELING] (INFO) : Model Config is correct.
[MODELING] (INFO) : Updated building model with whole Output:Variable available names
[MODELING] (INFO) : Updated building model with whole Output:Meter available names
[MODELING] (INFO) : runperiod established: {'start_day': 1, 'start_month': 1, 'start_year': 1991, 'end_day': 31, 'end_month': 12, 'end_year': 1991, 'start_weekday': 0, 'n_steps_per_hour': 4}
[MODELING] (INFO) : Episode length (seconds): 31536000.0
[MODELING] (INFO) : timestep size (seconds): 900.0
[MODELING] (INFO) : timesteps per episode: 35041
[REWARD] (INFO) : Reward function initialized.
[ENVIRONMENT] (INFO) : Environment 5zone-hot-discrete-v1 created successfully.
[WRAPPER DiscretizeEnv] (INFO) : New Discrete Space and mapping: Discrete(10)
[WRAPPER DiscretizeEnv] (INFO) : Make sure that the action space is compatible and contained in the original environment.
[WRAPPER DiscretizeEnv] (INFO) : Wrapper initialized
[WRAPPER MultiObjectiveReward] (INFO) : wrapper initialized.

Ensure that reward_terms are available in the info dict returned in the environment’s step method. Otherwise, an execution error will occur. By default, Sinergym environments return all reward terms specified in the used reward class in the info dict, so if the objective exists in the reward term, you shouldn’t encounter any problems.

[3]:
env.reset()
action = env.action_space.sample()
obs, reward, terminated, truncated, info = env.step(action)
env.close()
print(reward)
#----------------------------------------------------------------------------------------------#
[ENVIRONMENT] (INFO) : Starting a new episode... [5zone-hot-discrete-v1] [Episode 1]
#----------------------------------------------------------------------------------------------#
[MODELING] (INFO) : Episode directory created [/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res1/Eplus-env-sub_run1]
[MODELING] (INFO) : Weather file USA_AZ_Davis-Monthan.AFB.722745_TMY3.epw used.
[MODELING] (INFO) : Adapting weather to building model. [USA_AZ_Davis-Monthan.AFB.722745_TMY3.epw]
[ENVIRONMENT] (INFO) : Saving episode output path... [/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res1/Eplus-env-sub_run1/output]
[SIMULATOR] (INFO) : Running EnergyPlus with args: ['-w', '/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res1/Eplus-env-sub_run1/USA_AZ_Davis-Monthan.AFB.722745_TMY3.epw', '-d', '/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res1/Eplus-env-sub_run1/output', '/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res1/Eplus-env-sub_run1/5ZoneAutoDXVAV.epJSON']
[ENVIRONMENT] (INFO) : Episode 1 started.
[SIMULATOR] (INFO) : handlers initialized.
[SIMULATOR] (INFO) : handlers are ready.
[SIMULATOR] (INFO) : System is ready.
Progress: |***------------------------------------------------------------------------------------------------| 3%
/usr/local/lib/python3.12/dist-packages/gymnasium/spaces/box.py:240: UserWarning: WARN: Casting input x to numpy array.
  gym.logger.warn("Casting input x to numpy array.")
Progress: |***************************************************************************************************| 99%
[ENVIRONMENT] (INFO) : Environment closed. [5zone-hot-discrete-v1]
[-0.00589738497079933, -0.09533249490526607]

22.2. Previous Observations Wrappers

This Wrapper will add the previous timestep’s observation values to the current environment observation. You can select the variables you want to track its previous observation values. The observation space will be updated with the new dimension.

[4]:
env=gym.make('Eplus-5zone-hot-discrete-v1')
env = PreviousObservationWrapper(env, previous_variables=[
        'htg_setpoint',
        'clg_setpoint',
        'air_temperature'])
#==============================================================================================#
[ENVIRONMENT] (INFO) : Creating Gymnasium environment... [5zone-hot-discrete-v1]
#==============================================================================================#
[MODELING] (INFO) : Experiment working directory created [/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res1]
[MODELING] (INFO) : Model Config is correct.
[MODELING] (INFO) : Updated building model with whole Output:Variable available names
[MODELING] (INFO) : Updated building model with whole Output:Meter available names
[MODELING] (INFO) : runperiod established: {'start_day': 1, 'start_month': 1, 'start_year': 1991, 'end_day': 31, 'end_month': 12, 'end_year': 1991, 'start_weekday': 0, 'n_steps_per_hour': 4}
[MODELING] (INFO) : Episode length (seconds): 31536000.0
[MODELING] (INFO) : timestep size (seconds): 900.0
[MODELING] (INFO) : timesteps per episode: 35041
[REWARD] (INFO) : Reward function initialized.
[ENVIRONMENT] (INFO) : Environment 5zone-hot-discrete-v1 created successfully.
[WRAPPER DiscretizeEnv] (INFO) : New Discrete Space and mapping: Discrete(10)
[WRAPPER DiscretizeEnv] (INFO) : Make sure that the action space is compatible and contained in the original environment.
[WRAPPER DiscretizeEnv] (INFO) : Wrapper initialized
[WRAPPER PreviousObservationWrapper] (INFO) : Wrapper initialized.

You can see that the observation values have been updated:

[5]:
env.reset()
obs,_,_,_,_=env.step(env.action_space.sample())
obs_dict=dict(zip(env.get_wrapper_attr('observation_variables'),obs))
env.close()
print('NEW OBSERVATION: ',obs_dict)
#----------------------------------------------------------------------------------------------#
[ENVIRONMENT] (INFO) : Starting a new episode... [5zone-hot-discrete-v1] [Episode 1]
#----------------------------------------------------------------------------------------------#
[MODELING] (INFO) : Episode directory created [/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res1/Eplus-env-sub_run1]
[MODELING] (INFO) : Weather file USA_AZ_Davis-Monthan.AFB.722745_TMY3.epw used.
[MODELING] (INFO) : Adapting weather to building model. [USA_AZ_Davis-Monthan.AFB.722745_TMY3.epw]
[ENVIRONMENT] (INFO) : Saving episode output path... [/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res1/Eplus-env-sub_run1/output]
[SIMULATOR] (INFO) : Running EnergyPlus with args: ['-w', '/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res1/Eplus-env-sub_run1/USA_AZ_Davis-Monthan.AFB.722745_TMY3.epw', '-d', '/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res1/Eplus-env-sub_run1/output', '/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res1/Eplus-env-sub_run1/5ZoneAutoDXVAV.epJSON']
[ENVIRONMENT] (INFO) : Episode 1 started.
[SIMULATOR] (INFO) : handlers initialized.
[SIMULATOR] (INFO) : handlers are ready.
[SIMULATOR] (INFO) : System is ready.
Progress: |****-----------------------------------------------------------------------------------------------| 4%
/usr/local/lib/python3.12/dist-packages/gymnasium/spaces/box.py:240: UserWarning: WARN: Casting input x to numpy array.
  gym.logger.warn("Casting input x to numpy array.")
Progress: |***************************************************************************************************| 99%
[ENVIRONMENT] (INFO) : Environment closed. [5zone-hot-discrete-v1]
NEW OBSERVATION:  {'month': np.float32(1.0), 'day_of_month': np.float32(1.0), 'hour': np.float32(0.0), 'outdoor_temperature': np.float32(4.8), 'outdoor_humidity': np.float32(61.0), 'wind_speed': np.float32(4.65), 'wind_direction': np.float32(160.0), 'diffuse_solar_radiation': np.float32(0.0), 'direct_solar_radiation': np.float32(0.0), 'htg_setpoint': np.float32(12.8), 'clg_setpoint': np.float32(40.0), 'air_temperature': np.float32(19.809336), 'air_humidity': np.float32(27.848707), 'people_occupant': np.float32(0.0), 'co2_emission': np.float32(0.0), 'HVAC_electricity_demand_rate': np.float32(117.9477), 'total_electricity_HVAC': np.float32(106152.93), 'htg_setpoint_previous': np.float32(12.8), 'clg_setpoint_previous': np.float32(40.0), 'air_temperature_previous': np.float32(19.95039)}

22.3. Datetime Wrapper

This wrapper will replace the day value with the is_weekend flag, and hour and month with sin and cos values. The observation space is also automatically updated.

[6]:
env=gym.make('Eplus-5zone-hot-discrete-v1')
env = DatetimeWrapper(env)
#==============================================================================================#
[ENVIRONMENT] (INFO) : Creating Gymnasium environment... [5zone-hot-discrete-v1]
#==============================================================================================#
[MODELING] (INFO) : Experiment working directory created [/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res1]
[MODELING] (INFO) : Model Config is correct.
[MODELING] (INFO) : Updated building model with whole Output:Variable available names
[MODELING] (INFO) : Updated building model with whole Output:Meter available names
[MODELING] (INFO) : runperiod established: {'start_day': 1, 'start_month': 1, 'start_year': 1991, 'end_day': 31, 'end_month': 12, 'end_year': 1991, 'start_weekday': 0, 'n_steps_per_hour': 4}
[MODELING] (INFO) : Episode length (seconds): 31536000.0
[MODELING] (INFO) : timestep size (seconds): 900.0
[MODELING] (INFO) : timesteps per episode: 35041
[REWARD] (INFO) : Reward function initialized.
[ENVIRONMENT] (INFO) : Environment 5zone-hot-discrete-v1 created successfully.
[WRAPPER DiscretizeEnv] (INFO) : New Discrete Space and mapping: Discrete(10)
[WRAPPER DiscretizeEnv] (INFO) : Make sure that the action space is compatible and contained in the original environment.
[WRAPPER DiscretizeEnv] (INFO) : Wrapper initialized
[WRAPPER DatetimeWrapper] (INFO) : Wrapper initialized.

Specifically, this wrapper removes the observation variables month, day, and hour, and adds month_sin, month_cos, is_weekend, hour_sin, and hour_cos instead:

[7]:
env.reset()
obs,_,_,_,_=env.step(env.action_space.sample())
obs_dict=dict(zip(env.get_wrapper_attr('observation_variables'),obs))
env.close()
print('NEW OBSERVATION: ',obs_dict)
#----------------------------------------------------------------------------------------------#
[ENVIRONMENT] (INFO) : Starting a new episode... [5zone-hot-discrete-v1] [Episode 1]
#----------------------------------------------------------------------------------------------#
[MODELING] (INFO) : Episode directory created [/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res1/Eplus-env-sub_run1]
[MODELING] (INFO) : Weather file USA_AZ_Davis-Monthan.AFB.722745_TMY3.epw used.
[MODELING] (INFO) : Adapting weather to building model. [USA_AZ_Davis-Monthan.AFB.722745_TMY3.epw]
[ENVIRONMENT] (INFO) : Saving episode output path... [/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res1/Eplus-env-sub_run1/output]
[SIMULATOR] (INFO) : Running EnergyPlus with args: ['-w', '/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res1/Eplus-env-sub_run1/USA_AZ_Davis-Monthan.AFB.722745_TMY3.epw', '-d', '/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res1/Eplus-env-sub_run1/output', '/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res1/Eplus-env-sub_run1/5ZoneAutoDXVAV.epJSON']
[ENVIRONMENT] (INFO) : Episode 1 started.
[SIMULATOR] (INFO) : handlers initialized.
[SIMULATOR] (INFO) : handlers are ready.
[SIMULATOR] (INFO) : System is ready.
Progress: |***------------------------------------------------------------------------------------------------| 3%
/usr/local/lib/python3.12/dist-packages/gymnasium/spaces/box.py:240: UserWarning: WARN: Casting input x to numpy array.
  gym.logger.warn("Casting input x to numpy array.")
Progress: |***************************************************************************************************| 99%
[ENVIRONMENT] (INFO) : Environment closed. [5zone-hot-discrete-v1]
NEW OBSERVATION:  {'month_cos': np.float64(1.0), 'month_sin': np.float64(0.0), 'is_weekend': np.float64(0.0), 'hour_cos': np.float64(1.0), 'hour_sin': np.float64(0.0), 'outdoor_temperature': np.float64(4.800000190734863), 'outdoor_humidity': np.float64(61.0), 'wind_speed': np.float64(4.650000095367432), 'wind_direction': np.float64(160.0), 'diffuse_solar_radiation': np.float64(0.0), 'direct_solar_radiation': np.float64(0.0), 'htg_setpoint': np.float64(12.800000190734863), 'clg_setpoint': np.float64(40.0), 'air_temperature': np.float64(19.809335708618164), 'air_humidity': np.float64(27.84870719909668), 'people_occupant': np.float64(0.0), 'co2_emission': np.float64(0.0), 'HVAC_electricity_demand_rate': np.float64(117.94770050048828), 'total_electricity_HVAC': np.float64(106152.9296875)}

22.4. Environment Action Normalization Wrapper

Here’s an example of how to normalize a previous continuous environment action space. If we don’t define the range values, it will default to the range [-1,1]:

[8]:
# We will create a continuous environment
env=gym.make('Eplus-5zone-hot-continuous-v1')
print('ORIGINAL ACTION SPACE: ',env.get_wrapper_attr('action_space'))
# NORMALIZATION
# Apply the normalize action wrapper
env=NormalizeAction(env,normalize_range=(-1.0,1.0))
print('WRAPPED ACTION SPACE: ',env.get_wrapper_attr('action_space'))
env.reset()
for i in range(5):
    action=env.action_space.sample()
    print('Normalized action: ',action)
    _,_,_,_,info=env.step(action)
    print('Action done in simulator: ', info['action'])
env.close()
#==============================================================================================#
[ENVIRONMENT] (INFO) : Creating Gymnasium environment... [5zone-hot-continuous-v1]
#==============================================================================================#
[MODELING] (INFO) : Experiment working directory created [/workspaces/sinergym/examples/Eplus-env-5zone-hot-continuous-v1-res1]
[MODELING] (INFO) : Model Config is correct.
[MODELING] (INFO) : Updated building model with whole Output:Variable available names
[MODELING] (INFO) : Updated building model with whole Output:Meter available names
[MODELING] (INFO) : runperiod established: {'start_day': 1, 'start_month': 1, 'start_year': 1991, 'end_day': 31, 'end_month': 12, 'end_year': 1991, 'start_weekday': 0, 'n_steps_per_hour': 4}
[MODELING] (INFO) : Episode length (seconds): 31536000.0
[MODELING] (INFO) : timestep size (seconds): 900.0
[MODELING] (INFO) : timesteps per episode: 35041
[REWARD] (INFO) : Reward function initialized.
[ENVIRONMENT] (INFO) : Environment 5zone-hot-continuous-v1 created successfully.
ORIGINAL ACTION SPACE:  Box([12.   23.25], [23.25 30.  ], (2,), float32)
[WRAPPER NormalizeAction] (INFO) : New normalized action Space: Box(-1.0, 1.0, (2,), float32)
[WRAPPER NormalizeAction] (INFO) : Wrapper initialized
WRAPPED ACTION SPACE:  Box(-1.0, 1.0, (2,), float32)
#----------------------------------------------------------------------------------------------#
[ENVIRONMENT] (INFO) : Starting a new episode... [5zone-hot-continuous-v1] [Episode 1]
#----------------------------------------------------------------------------------------------#
[MODELING] (INFO) : Episode directory created [/workspaces/sinergym/examples/Eplus-env-5zone-hot-continuous-v1-res1/Eplus-env-sub_run1]
[MODELING] (INFO) : Weather file USA_AZ_Davis-Monthan.AFB.722745_TMY3.epw used.
[MODELING] (INFO) : Adapting weather to building model. [USA_AZ_Davis-Monthan.AFB.722745_TMY3.epw]
[ENVIRONMENT] (INFO) : Saving episode output path... [/workspaces/sinergym/examples/Eplus-env-5zone-hot-continuous-v1-res1/Eplus-env-sub_run1/output]
[SIMULATOR] (INFO) : Running EnergyPlus with args: ['-w', '/workspaces/sinergym/examples/Eplus-env-5zone-hot-continuous-v1-res1/Eplus-env-sub_run1/USA_AZ_Davis-Monthan.AFB.722745_TMY3.epw', '-d', '/workspaces/sinergym/examples/Eplus-env-5zone-hot-continuous-v1-res1/Eplus-env-sub_run1/output', '/workspaces/sinergym/examples/Eplus-env-5zone-hot-continuous-v1-res1/Eplus-env-sub_run1/5ZoneAutoDXVAV.epJSON']
[ENVIRONMENT] (INFO) : Episode 1 started.
[SIMULATOR] (INFO) : handlers initialized.
[SIMULATOR] (INFO) : handlers are ready.
[SIMULATOR] (INFO) : System is ready.
Normalized action:  [-0.46666247  0.72446996]
Action done in simulator:  [15.000024 29.070086]
Normalized action:  [-0.79799604 -0.04778594]
Action done in simulator:  [13.136272 26.463722]
Normalized action:  [-0.6806781   0.30527842]
Action done in simulator:  [13.7961855 27.655315 ]
Normalized action:  [0.36448804 0.61559314]
Action done in simulator:  [19.675245 28.702627]
Normalized action:  [ 0.4204188  -0.62286806]
Action done in simulator:  [19.989855 24.52282 ]
Progress: |***************************************************************************************************| 99%
[ENVIRONMENT] (INFO) : Environment closed. [5zone-hot-continuous-v1]

22.5. Environment Discretization Wrapper

Here’s an example of how to discretize a previous continuous environment. We’ll need the new discrete action space and an action mapping function whose output matches the original unwrapped environment action space:

[9]:
# We will create a continuous environment
env=gym.make('Eplus-5zone-hot-continuous-v1')
print('ORIGINAL ACTION SPACE: ',env.get_wrapper_attr('action_space'))
print('IS DISCRETE?: ',env.get_wrapper_attr('is_discrete'))
# DISCRETIZATION
# Defining new discrete space and action mapping function
new_discrete_space = gym.spaces.Discrete(10) # Action values [0,9]
def action_mapping_function(action):
    mapping = {
        0: [15, 30], # These lists matches with original action space
        1: [16, 29],
        2: [17, 28],
        3: [18, 27],
        4: [19, 26],
        5: [20, 25],
        6: [21, 24],
        7: [22, 23],
        8: [22, 22.5],
        9: [21, 22.5]
    }

    return mapping[action]
# Apply the discretize wrapper
env=DiscretizeEnv(env,discrete_space=new_discrete_space,action_mapping=action_mapping_function)
print('WRAPPED ACTION SPACE: ',env.get_wrapper_attr('action_space'))
print('IS DISCRETE?: ',env.get_wrapper_attr('is_discrete'))
env.reset()
for i in range(5):
    action=env.action_space.sample()
    print('ACTION DISCRETE: ',action)
    _,_,_,_,info=env.step(action)
    print('Action done in simulator: ', info['action'])
env.close()


#==============================================================================================#
[ENVIRONMENT] (INFO) : Creating Gymnasium environment... [5zone-hot-continuous-v1]
#==============================================================================================#
[MODELING] (INFO) : Experiment working directory created [/workspaces/sinergym/examples/Eplus-env-5zone-hot-continuous-v1-res1]
[MODELING] (INFO) : Model Config is correct.
[MODELING] (INFO) : Updated building model with whole Output:Variable available names
[MODELING] (INFO) : Updated building model with whole Output:Meter available names
[MODELING] (INFO) : runperiod established: {'start_day': 1, 'start_month': 1, 'start_year': 1991, 'end_day': 31, 'end_month': 12, 'end_year': 1991, 'start_weekday': 0, 'n_steps_per_hour': 4}
[MODELING] (INFO) : Episode length (seconds): 31536000.0
[MODELING] (INFO) : timestep size (seconds): 900.0
[MODELING] (INFO) : timesteps per episode: 35041
[REWARD] (INFO) : Reward function initialized.
[ENVIRONMENT] (INFO) : Environment 5zone-hot-continuous-v1 created successfully.
ORIGINAL ACTION SPACE:  Box([12.   23.25], [23.25 30.  ], (2,), float32)
IS DISCRETE?:  False
[WRAPPER DiscretizeEnv] (INFO) : New Discrete Space and mapping: Discrete(10)
[WRAPPER DiscretizeEnv] (INFO) : Make sure that the action space is compatible and contained in the original environment.
[WRAPPER DiscretizeEnv] (INFO) : Wrapper initialized
WRAPPED ACTION SPACE:  Discrete(10)
IS DISCRETE?:  True
#----------------------------------------------------------------------------------------------#
[ENVIRONMENT] (INFO) : Starting a new episode... [5zone-hot-continuous-v1] [Episode 1]
#----------------------------------------------------------------------------------------------#
[MODELING] (INFO) : Episode directory created [/workspaces/sinergym/examples/Eplus-env-5zone-hot-continuous-v1-res1/Eplus-env-sub_run1]
[MODELING] (INFO) : Weather file USA_AZ_Davis-Monthan.AFB.722745_TMY3.epw used.
[MODELING] (INFO) : Adapting weather to building model. [USA_AZ_Davis-Monthan.AFB.722745_TMY3.epw]
[ENVIRONMENT] (INFO) : Saving episode output path... [/workspaces/sinergym/examples/Eplus-env-5zone-hot-continuous-v1-res1/Eplus-env-sub_run1/output]
[SIMULATOR] (INFO) : Running EnergyPlus with args: ['-w', '/workspaces/sinergym/examples/Eplus-env-5zone-hot-continuous-v1-res1/Eplus-env-sub_run1/USA_AZ_Davis-Monthan.AFB.722745_TMY3.epw', '-d', '/workspaces/sinergym/examples/Eplus-env-5zone-hot-continuous-v1-res1/Eplus-env-sub_run1/output', '/workspaces/sinergym/examples/Eplus-env-5zone-hot-continuous-v1-res1/Eplus-env-sub_run1/5ZoneAutoDXVAV.epJSON']
[ENVIRONMENT] (INFO) : Episode 1 started.
[SIMULATOR] (INFO) : handlers initialized.
[SIMULATOR] (INFO) : handlers are ready.
[SIMULATOR] (INFO) : System is ready.
ACTION DISCRETE:  9
[ENVIRONMENT] (WARNING) : Step: The action [21, 22.5] is not correct for the Action Space Box([12.   23.25], [23.25 30.  ], (2,), float32)
Action done in simulator:  [21, 22.5]
ACTION DISCRETE:  6
Action done in simulator:  [21, 24]
ACTION DISCRETE:  4
Action done in simulator:  [19, 26]
ACTION DISCRETE:  1
Action done in simulator:  [16, 29]
ACTION DISCRETE:  3
Action done in simulator:  [18, 27]
Progress: |***------------------------------------------------------------------------------------------------| 3%
/usr/local/lib/python3.12/dist-packages/gymnasium/spaces/box.py:240: UserWarning: WARN: Casting input x to numpy array.
  gym.logger.warn("Casting input x to numpy array.")
Progress: |***************************************************************************************************| 99%
[ENVIRONMENT] (INFO) : Environment closed. [5zone-hot-continuous-v1]

As seen in the output, the input is an int, but a list with the original action space is created in the simulator.

22.6. Discrete Incremental Wrapper

This wrapper updates an environment for an incremental setpoint action space. It converts the environment into a discrete environment with an action mapping function and action space depending on the step and delta specified. The action is added to the current setpoint values instead of overwriting the latest action. Thus, the action is the current setpoint values with the increase, not the discrete value action that defines the increment/decrement itself.

[10]:
env=gym.make('Eplus-5zone-hot-continuous-v1')
print('ORIGINAL ACTION SPACE: ',env.get_wrapper_attr('action_space'))
env = DiscreteIncrementalWrapper(
        env,initial_values=[21.0,25.0], delta_temp=2, step_temp=0.5)
print('WRAPPED ACTION SPACE: ',env.get_wrapper_attr('action_space'))
print('WRAPPED ACTION MAPPING: ',env.get_wrapper_attr('action_mapping'))
#==============================================================================================#
[ENVIRONMENT] (INFO) : Creating Gymnasium environment... [5zone-hot-continuous-v1]
#==============================================================================================#
[MODELING] (INFO) : Experiment working directory created [/workspaces/sinergym/examples/Eplus-env-5zone-hot-continuous-v1-res1]
[MODELING] (INFO) : Model Config is correct.
[MODELING] (INFO) : Updated building model with whole Output:Variable available names
[MODELING] (INFO) : Updated building model with whole Output:Meter available names
[MODELING] (INFO) : runperiod established: {'start_day': 1, 'start_month': 1, 'start_year': 1991, 'end_day': 31, 'end_month': 12, 'end_year': 1991, 'start_weekday': 0, 'n_steps_per_hour': 4}
[MODELING] (INFO) : Episode length (seconds): 31536000.0
[MODELING] (INFO) : timestep size (seconds): 900.0
[MODELING] (INFO) : timesteps per episode: 35041
[REWARD] (INFO) : Reward function initialized.
[ENVIRONMENT] (INFO) : Environment 5zone-hot-continuous-v1 created successfully.
ORIGINAL ACTION SPACE:  Box([12.   23.25], [23.25 30.  ], (2,), float32)
[WRAPPER DiscreteIncrementalWrapper] (INFO) : New incremental action mapping: 17
[WRAPPER DiscreteIncrementalWrapper] (INFO) : {0: [0.0, 0.0], 1: [np.float64(0.5), 0.0], 2: [np.float64(1.0), 0.0], 3: [np.float64(1.5), 0.0], 4: [np.float64(2.0), 0.0], 5: [np.float64(-0.5), 0.0], 6: [np.float64(-1.0), 0.0], 7: [np.float64(-1.5), 0.0], 8: [np.float64(-2.0), 0.0], 9: [0.0, np.float64(0.5)], 10: [0.0, np.float64(1.0)], 11: [0.0, np.float64(1.5)], 12: [0.0, np.float64(2.0)], 13: [0.0, np.float64(-0.5)], 14: [0.0, np.float64(-1.0)], 15: [0.0, np.float64(-1.5)], 16: [0.0, np.float64(-2.0)]}
[WRAPPER DiscreteIncrementalWrapper] (INFO) : Wrapper initialized
WRAPPED ACTION SPACE:  Discrete(17)
WRAPPED ACTION MAPPING:  <bound method DiscreteIncrementalWrapper.action_mapping of <DiscreteIncrementalWrapper<OrderEnforcing<PassiveEnvChecker<EplusEnv<Eplus-5zone-hot-continuous-v1>>>>>>

The maximum and minimum values for creating the action mapping are read from the environment action space, ensuring that the setpoint increments and decrements do not exceed the agreed limits. The delta and step values are used to determine how the discrete space of these increments and decrements will be constructed. Here’s an example of how it works:

[11]:
env.reset()
print('CURRENT SETPOINTS VALUES: ', env.get_wrapper_attr('current_setpoints'))
for i in range(5):
    action=env.action_space.sample()
    _,_,_,_,info=env.step(action)
    print('Action number ',i,': ',env.get_wrapper_attr('action_mapping')(action))
    print('Setpoints update: ', info['action'])
env.close()
#----------------------------------------------------------------------------------------------#
[ENVIRONMENT] (INFO) : Starting a new episode... [5zone-hot-continuous-v1] [Episode 1]
#----------------------------------------------------------------------------------------------#
[MODELING] (INFO) : Episode directory created [/workspaces/sinergym/examples/Eplus-env-5zone-hot-continuous-v1-res1/Eplus-env-sub_run1]
[MODELING] (INFO) : Weather file USA_AZ_Davis-Monthan.AFB.722745_TMY3.epw used.
[MODELING] (INFO) : Adapting weather to building model. [USA_AZ_Davis-Monthan.AFB.722745_TMY3.epw]
[ENVIRONMENT] (INFO) : Saving episode output path... [/workspaces/sinergym/examples/Eplus-env-5zone-hot-continuous-v1-res1/Eplus-env-sub_run1/output]
[SIMULATOR] (INFO) : Running EnergyPlus with args: ['-w', '/workspaces/sinergym/examples/Eplus-env-5zone-hot-continuous-v1-res1/Eplus-env-sub_run1/USA_AZ_Davis-Monthan.AFB.722745_TMY3.epw', '-d', '/workspaces/sinergym/examples/Eplus-env-5zone-hot-continuous-v1-res1/Eplus-env-sub_run1/output', '/workspaces/sinergym/examples/Eplus-env-5zone-hot-continuous-v1-res1/Eplus-env-sub_run1/5ZoneAutoDXVAV.epJSON']
[ENVIRONMENT] (INFO) : Episode 1 started.
[SIMULATOR] (INFO) : handlers initialized.
[SIMULATOR] (INFO) : handlers are ready.
[SIMULATOR] (INFO) : System is ready.
CURRENT SETPOINTS VALUES:  [21.0, 25.0]
Action number  0 :  [0.0, np.float64(-2.0)]
Setpoints update:  [np.float64(21.0), np.float64(23.25)]
Action number  1 :  [0.0, np.float64(0.5)]
Setpoints update:  [np.float64(21.0), np.float64(23.75)]
Action number  2 :  [0.0, np.float64(-1.0)]
Setpoints update:  [np.float64(21.0), np.float64(23.25)]
Action number  3 :  [0.0, 0.0]
Setpoints update:  [np.float64(21.0), np.float64(23.25)]
Action number  4 :  [0.0, np.float64(1.0)]
Setpoints update:  [np.float64(21.0), np.float64(24.25)]
Progress: |***------------------------------------------------------------------------------------------------| 3%
/usr/local/lib/python3.12/dist-packages/gymnasium/spaces/box.py:240: UserWarning: WARN: Casting input x to numpy array.
  gym.logger.warn("Casting input x to numpy array.")
Progress: |***************************************************************************************************| 99%
[ENVIRONMENT] (INFO) : Environment closed. [5zone-hot-continuous-v1]

22.7. Normalization Wrapper

This wrapper is used to transform the observation received from the simulator into values between -1 and 1. It’s based on the dynamic normalization wrapper of Gymnasium. Initially, it may not be precise, and the values may often be out of range, so use this wrapper with caution.

[12]:
#Original env
env=gym.make('Eplus-5zone-hot-discrete-v1')
env = NormalizeObservation(
        env=env)
#==============================================================================================#
[ENVIRONMENT] (INFO) : Creating Gymnasium environment... [5zone-hot-discrete-v1]
#==============================================================================================#
[MODELING] (INFO) : Experiment working directory created [/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res1]
[MODELING] (INFO) : Model Config is correct.
[MODELING] (INFO) : Updated building model with whole Output:Variable available names
[MODELING] (INFO) : Updated building model with whole Output:Meter available names
[MODELING] (INFO) : runperiod established: {'start_day': 1, 'start_month': 1, 'start_year': 1991, 'end_day': 31, 'end_month': 12, 'end_year': 1991, 'start_weekday': 0, 'n_steps_per_hour': 4}
[MODELING] (INFO) : Episode length (seconds): 31536000.0
[MODELING] (INFO) : timestep size (seconds): 900.0
[MODELING] (INFO) : timesteps per episode: 35041
[REWARD] (INFO) : Reward function initialized.
[ENVIRONMENT] (INFO) : Environment 5zone-hot-discrete-v1 created successfully.
[WRAPPER DiscretizeEnv] (INFO) : New Discrete Space and mapping: Discrete(10)
[WRAPPER DiscretizeEnv] (INFO) : Make sure that the action space is compatible and contained in the original environment.
[WRAPPER DiscretizeEnv] (INFO) : Wrapper initialized
[WRAPPER NormalizeObservation] (INFO) : Wrapper initialized.

In the following code, you can see how the specified variables have been correctly normalized:

[13]:
env.reset()
obs,_,_,_,_=env.step(env.action_space.sample())
obs_dict=dict(zip(env.get_wrapper_attr('observation_variables'),obs))
env.close()
print('OBSERVATION WITH NORMALIZATION: ',obs_dict)
#----------------------------------------------------------------------------------------------#
[ENVIRONMENT] (INFO) : Starting a new episode... [5zone-hot-discrete-v1] [Episode 1]
#----------------------------------------------------------------------------------------------#
[MODELING] (INFO) : Episode directory created [/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res1/Eplus-env-sub_run1]
[MODELING] (INFO) : Weather file USA_AZ_Davis-Monthan.AFB.722745_TMY3.epw used.
[MODELING] (INFO) : Adapting weather to building model. [USA_AZ_Davis-Monthan.AFB.722745_TMY3.epw]
[ENVIRONMENT] (INFO) : Saving episode output path... [/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res1/Eplus-env-sub_run1/output]
[SIMULATOR] (INFO) : Running EnergyPlus with args: ['-w', '/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res1/Eplus-env-sub_run1/USA_AZ_Davis-Monthan.AFB.722745_TMY3.epw', '-d', '/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res1/Eplus-env-sub_run1/output', '/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res1/Eplus-env-sub_run1/5ZoneAutoDXVAV.epJSON']
[ENVIRONMENT] (INFO) : Episode 1 started.
[SIMULATOR] (INFO) : handlers initialized.
[SIMULATOR] (INFO) : handlers are ready.
[SIMULATOR] (INFO) : System is ready.
[WRAPPER NormalizeObservation] (INFO) : Saving normalization calibration data... [5zone-hot-discrete-v1]
Progress: |***------------------------------------------------------------------------------------------------| 3%
/usr/local/lib/python3.12/dist-packages/gymnasium/spaces/box.py:240: UserWarning: WARN: Casting input x to numpy array.
  gym.logger.warn("Casting input x to numpy array.")
Progress: |***************************************************************************************************| 99%
[ENVIRONMENT] (INFO) : Environment closed. [5zone-hot-discrete-v1]
[WRAPPER NormalizeObservation] (INFO) : Saving normalization calibration data... [5zone-hot-discrete-v1]
OBSERVATION WITH NORMALIZATION:  {'month': np.float64(0.00499968750430059), 'day_of_month': np.float64(0.00499968750430059), 'hour': np.float64(0.0), 'outdoor_temperature': np.float64(0.9875907976185373), 'outdoor_humidity': np.float64(-0.9745626607331893), 'wind_speed': np.float64(0.9973969815420386), 'wind_direction': np.float64(0.9908525387095581), 'diffuse_solar_radiation': np.float64(0.0), 'direct_solar_radiation': np.float64(0.0), 'htg_setpoint': np.float64(0.007049581561774207), 'clg_setpoint': np.float64(0.0070688585864955075), 'air_temperature': np.float64(-0.44169349819860654), 'air_humidity': np.float64(0.1687716004048815), 'people_occupant': np.float64(0.0), 'co2_emission': np.float64(0.0), 'HVAC_electricity_demand_rate': np.float64(0.007070813620268407), 'total_electricity_HVAC': np.float64(0.0070710678115464875)}

22.8. Logging and storing data with logger wrappers

22.8.1. LoggerWrapper layer

This wrapper uses Sinergym’s logger storage class to capture the interaction flow with the environment (LoggerStorage), accumulating all the information. The class used by the wrapper can be replaced with a different back-end. It can then be combined with various wrappers to output the stored data, such as CSVLogger or WandBLogger. For more information about the Sinergym Logger, visit Logging System Overview, Logger Wrappers and an example about custom loggers.

[3]:
env=gym.make('Eplus-5zone-hot-discrete-v1')
env=LoggerWrapper(env, storage_class=LoggerStorage)
#==============================================================================================#
[ENVIRONMENT] (INFO) : Creating Gymnasium environment... [5zone-hot-discrete-v1]
#==============================================================================================#
[MODELING] (INFO) : Experiment working directory created [/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res1]
[MODELING] (INFO) : Model Config is correct.
[MODELING] (INFO) : Updated building model with whole Output:Variable available names
[MODELING] (INFO) : Updated building model with whole Output:Meter available names
[MODELING] (INFO) : runperiod established: {'start_day': 1, 'start_month': 1, 'start_year': 1991, 'end_day': 31, 'end_month': 12, 'end_year': 1991, 'start_weekday': 0, 'n_steps_per_hour': 4}
[MODELING] (INFO) : Episode length (seconds): 31536000.0
[MODELING] (INFO) : timestep size (seconds): 900.0
[MODELING] (INFO) : timesteps per episode: 35041
[REWARD] (INFO) : Reward function initialized.
[ENVIRONMENT] (INFO) : Environment 5zone-hot-discrete-v1 created successfully.
[WRAPPER DiscretizeEnv] (INFO) : New Discrete Space and mapping: Discrete(10)
[WRAPPER DiscretizeEnv] (INFO) : Make sure that the action space is compatible and contained in the original environment.
[WRAPPER DiscretizeEnv] (INFO) : Wrapper initialized
[WRAPPER LoggerWrapper] (INFO) : Wrapper initialized.

This wrapper enables the use of a LoggerStorage instance within the environment class and automatically captures interaction data while actions are sent by an agent. At each reset, the data from this class is cleared to start the next episode. The idea is to combine it with other output loggers like those listed below:

22.8.2. LoggerCSV layer

[4]:
env=CSVLogger(env)

env.reset()
truncated = terminated = False
current_month = 0
while not (terminated or truncated):
    a = env.action_space.sample()
    _,_,terminated,truncated,_=env.step(a)
env.close()
[WRAPPER CSVLogger] (INFO) : Wrapper initialized.
#----------------------------------------------------------------------------------------------#
[ENVIRONMENT] (INFO) : Starting a new episode... [5zone-hot-discrete-v1] [Episode 1]
#----------------------------------------------------------------------------------------------#
[MODELING] (INFO) : Episode directory created [/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res1/Eplus-env-sub_run1]
[MODELING] (INFO) : Weather file USA_AZ_Davis-Monthan.AFB.722745_TMY3.epw used.
[MODELING] (INFO) : Adapting weather to building model. [USA_AZ_Davis-Monthan.AFB.722745_TMY3.epw]
[ENVIRONMENT] (INFO) : Saving episode output path... [/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res1/Eplus-env-sub_run1/output]
[SIMULATOR] (INFO) : Running EnergyPlus with args: ['-w', '/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res1/Eplus-env-sub_run1/USA_AZ_Davis-Monthan.AFB.722745_TMY3.epw', '-d', '/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res1/Eplus-env-sub_run1/output', '/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res1/Eplus-env-sub_run1/5ZoneAutoDXVAV.epJSON']
[ENVIRONMENT] (INFO) : Episode 1 started.
[SIMULATOR] (INFO) : handlers initialized.
[SIMULATOR] (INFO) : handlers are ready.
[SIMULATOR] (INFO) : System is ready.
Progress: |**-------------------------------------------------------------------------------------------------| 2%
/usr/local/lib/python3.12/dist-packages/gymnasium/spaces/box.py:240: UserWarning: WARN: Casting input x to numpy array.
  gym.logger.warn("Casting input x to numpy array.")
Progress: |***************************************************************************************************| 99%
[WRAPPER CSVLogger] (INFO) : Environment closed, data updated in monitor and progress.csv.
[ENVIRONMENT] (INFO) : Environment closed. [5zone-hot-discrete-v1]

Once the LoggerWrapper is applied, this wrapper can be used to output episode data through Sinergym’s output, along with summary metrics added to CSV files. More details on this structure can be found in OutputFormat. Sinergym will raise an error if this wrapper is used without first enabling LoggerWrapper or a custom logger.

22.8.3. WandBLogger layer

[2]:
# env=WandBLogger(env = Env,
#                 entity = <wandb_account_entity>,
#                 project_name = <wandb_project_name>,
#                 run_name = <run_name>
#                 group = 'Notebook_example',
#                 tags: ['tag1','tag2'],
#                 save_code = False,
#                 dump_frequency = 1000,
#                 artifact_save = True,
#                 artifact_type = 'output',
#                 excluded_info_keys = ['reward',
#                                   'action',
#                                   'timestep',
#                                   'month',
#                                   'day',
#                                   'hour',
#                                   'time_elapsed(hours)',
#                                   'reward_weight',
#                                   'is_raining'],
#                 excluded_episode_summary_keys = ['terminated',
#                                              'truncated']):

# env.reset()
# truncated = terminated = False
# current_month = 0
# while not (terminated or truncated):
#     a = env.action_space.sample()
#     _,_,terminated,truncated,_=env.step(a)
# env.close()

Similar to CSVLogger, this wrapper requires the environment to have been previously encapsulated by a LoggerWrapper or any custom logger. The user must have a pre-existing Weights & Biases account and correctly specify the fields. This wrapper does not override CSVLogger; both can be applied simultaneously without issue.

22.9. Multi Observation Wrapper

This wrapper stacks the observations received in a history queue (the size can be customized).

[15]:
#Original environment
env=gym.make('Eplus-5zone-hot-discrete-v1')
obs, info=env.reset()
print('BEFORE MULTI OBSERVATION: ',obs)

#Multi Observation environment
env=MultiObsWrapper(env, n=5, flatten=True)
obs, info=env.reset()
#==============================================================================================#
[ENVIRONMENT] (INFO) : Creating Gymnasium environment... [5zone-hot-discrete-v1]
#==============================================================================================#
[MODELING] (INFO) : Experiment working directory created [/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res2]
[MODELING] (INFO) : Model Config is correct.
[MODELING] (INFO) : Updated building model with whole Output:Variable available names
[MODELING] (INFO) : Updated building model with whole Output:Meter available names
[MODELING] (INFO) : runperiod established: {'start_day': 1, 'start_month': 1, 'start_year': 1991, 'end_day': 31, 'end_month': 12, 'end_year': 1991, 'start_weekday': 0, 'n_steps_per_hour': 4}
[MODELING] (INFO) : Episode length (seconds): 31536000.0
[MODELING] (INFO) : timestep size (seconds): 900.0
[MODELING] (INFO) : timesteps per episode: 35041
[REWARD] (INFO) : Reward function initialized.
[ENVIRONMENT] (INFO) : Environment 5zone-hot-discrete-v1 created successfully.
[WRAPPER DiscretizeEnv] (INFO) : New Discrete Space and mapping: Discrete(10)
[WRAPPER DiscretizeEnv] (INFO) : Make sure that the action space is compatible and contained in the original environment.
[WRAPPER DiscretizeEnv] (INFO) : Wrapper initialized
#----------------------------------------------------------------------------------------------#
[ENVIRONMENT] (INFO) : Starting a new episode... [5zone-hot-discrete-v1] [Episode 1]
#----------------------------------------------------------------------------------------------#
[MODELING] (INFO) : Episode directory created [/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res2/Eplus-env-sub_run1]
[MODELING] (INFO) : Weather file USA_AZ_Davis-Monthan.AFB.722745_TMY3.epw used.
[MODELING] (INFO) : Adapting weather to building model. [USA_AZ_Davis-Monthan.AFB.722745_TMY3.epw]
[ENVIRONMENT] (INFO) : Saving episode output path... [/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res2/Eplus-env-sub_run1/output]
[SIMULATOR] (INFO) : Running EnergyPlus with args: ['-w', '/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res2/Eplus-env-sub_run1/USA_AZ_Davis-Monthan.AFB.722745_TMY3.epw', '-d', '/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res2/Eplus-env-sub_run1/output', '/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res2/Eplus-env-sub_run1/5ZoneAutoDXVAV.epJSON']
[ENVIRONMENT] (INFO) : Episode 1 started.
[SIMULATOR] (INFO) : handlers initialized.
[SIMULATOR] (INFO) : handlers are ready.
[SIMULATOR] (INFO) : System is ready.
BEFORE MULTI OBSERVATION:  [1.0000000e+00 1.0000000e+00 0.0000000e+00 4.4000001e+00 6.5000000e+01
 3.8750000e+00 1.4500000e+02 0.0000000e+00 0.0000000e+00 1.2800000e+01
 4.0000000e+01 1.9950390e+01 2.7784170e+01 0.0000000e+00 0.0000000e+00
 1.1794770e+02 1.0615293e+05]
[WRAPPER MultiObsWrapper] (INFO) : Wrapper initialized.
Progress: |***************************************************************************************************| 99%
#----------------------------------------------------------------------------------------------#
[ENVIRONMENT] (INFO) : Starting a new episode... [5zone-hot-discrete-v1] [Episode 2]
#----------------------------------------------------------------------------------------------#
[MODELING] (INFO) : Episode directory created [/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res2/Eplus-env-sub_run2]
[MODELING] (INFO) : Weather file USA_AZ_Davis-Monthan.AFB.722745_TMY3.epw used.
[MODELING] (INFO) : Adapting weather to building model. [USA_AZ_Davis-Monthan.AFB.722745_TMY3.epw]
[ENVIRONMENT] (INFO) : Saving episode output path... [/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res2/Eplus-env-sub_run2/output]
[SIMULATOR] (INFO) : Running EnergyPlus with args: ['-w', '/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res2/Eplus-env-sub_run2/USA_AZ_Davis-Monthan.AFB.722745_TMY3.epw', '-d', '/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res2/Eplus-env-sub_run2/output', '/workspaces/sinergym/examples/Eplus-env-5zone-hot-discrete-v1-res2/Eplus-env-sub_run2/5ZoneAutoDXVAV.epJSON']
[ENVIRONMENT] (INFO) : Episode 2 started.
[SIMULATOR] (INFO) : handlers are ready.
[SIMULATOR] (INFO) : System is ready.
Progress: |***************************************************************************************************| 99%
[16]:
print('AFTER MULTI OBSERVATION: ',obs)
env.close()
AFTER MULTI OBSERVATION:  [1.0000000e+00 1.0000000e+00 0.0000000e+00 5.1999998e+00 5.7000000e+01
 5.4250002e+00 1.7500000e+02 0.0000000e+00 0.0000000e+00 1.2800000e+01
 4.0000000e+01 1.9671045e+01 2.7883675e+01 0.0000000e+00 0.0000000e+00
 1.1794770e+02 1.0615293e+05 1.0000000e+00 1.0000000e+00 0.0000000e+00
 5.1999998e+00 5.7000000e+01 5.4250002e+00 1.7500000e+02 0.0000000e+00
 0.0000000e+00 1.2800000e+01 4.0000000e+01 1.9671045e+01 2.7883675e+01
 0.0000000e+00 0.0000000e+00 1.1794770e+02 1.0615293e+05 1.0000000e+00
 1.0000000e+00 0.0000000e+00 5.1999998e+00 5.7000000e+01 5.4250002e+00
 1.7500000e+02 0.0000000e+00 0.0000000e+00 1.2800000e+01 4.0000000e+01
 1.9671045e+01 2.7883675e+01 0.0000000e+00 0.0000000e+00 1.1794770e+02
 1.0615293e+05 1.0000000e+00 1.0000000e+00 0.0000000e+00 5.1999998e+00
 5.7000000e+01 5.4250002e+00 1.7500000e+02 0.0000000e+00 0.0000000e+00
 1.2800000e+01 4.0000000e+01 1.9671045e+01 2.7883675e+01 0.0000000e+00
 0.0000000e+00 1.1794770e+02 1.0615293e+05 1.0000000e+00 1.0000000e+00
 0.0000000e+00 5.1999998e+00 5.7000000e+01 5.4250002e+00 1.7500000e+02
 0.0000000e+00 0.0000000e+00 1.2800000e+01 4.0000000e+01 1.9671045e+01
 2.7883675e+01 0.0000000e+00 0.0000000e+00 1.1794770e+02 1.0615293e+05]
[ENVIRONMENT] (INFO) : Environment closed. [5zone-hot-discrete-v1]

22.10. Nesting wrappers

All wrappers available in Sinergym are stackable, organized in layers. However, the order in which these layers are applied can affect the final result, depending on the wrappers being used.

For instance, activating the logger before normalizing differs from doing it in the reverse order. In the first case, the data will be logged without normalization, even though the agent will operate in a normalized environment. In the second case, the logger will capture the normalized values since it encapsulates the normalization applied by the previous layer.

An example of how to nest wrappers is shown below:

[17]:
env = gym.make('Eplus-5zone-hot-continuous-v1')
env = MultiObjectiveReward(
    env=env,
    reward_terms=[
        'energy_term',
        'comfort_term'])
env = PreviousObservationWrapper(env, previous_variables=[
    'htg_setpoint',
    'clg_setpoint',
    'air_temperature'])
env = DatetimeWrapper(env)
env = DiscreteIncrementalWrapper(
    env,initial_values=[21.0,25.0], delta_temp=2, step_temp=0.5)
env = NormalizeObservation(
    env=env)
env = LoggerWrapper(env=env)
env = MultiObsWrapper(env=env, n=5, flatten=True)
#==============================================================================================#
[ENVIRONMENT] (INFO) : Creating Gymnasium environment... [5zone-hot-continuous-v1]
#==============================================================================================#
[MODELING] (INFO) : Experiment working directory created [/workspaces/sinergym/examples/Eplus-env-5zone-hot-continuous-v1-res1]
[MODELING] (INFO) : Model Config is correct.
[MODELING] (INFO) : Updated building model with whole Output:Variable available names
[MODELING] (INFO) : Updated building model with whole Output:Meter available names
[MODELING] (INFO) : runperiod established: {'start_day': 1, 'start_month': 1, 'start_year': 1991, 'end_day': 31, 'end_month': 12, 'end_year': 1991, 'start_weekday': 0, 'n_steps_per_hour': 4}
[MODELING] (INFO) : Episode length (seconds): 31536000.0
[MODELING] (INFO) : timestep size (seconds): 900.0
[MODELING] (INFO) : timesteps per episode: 35041
[REWARD] (INFO) : Reward function initialized.
[ENVIRONMENT] (INFO) : Environment 5zone-hot-continuous-v1 created successfully.
[WRAPPER MultiObjectiveReward] (INFO) : wrapper initialized.
[WRAPPER PreviousObservationWrapper] (INFO) : Wrapper initialized.
[WRAPPER DatetimeWrapper] (INFO) : Wrapper initialized.
[WRAPPER DiscreteIncrementalWrapper] (INFO) : New incremental action mapping: 17
[WRAPPER DiscreteIncrementalWrapper] (INFO) : {0: [0.0, 0.0], 1: [np.float64(0.5), 0.0], 2: [np.float64(1.0), 0.0], 3: [np.float64(1.5), 0.0], 4: [np.float64(2.0), 0.0], 5: [np.float64(-0.5), 0.0], 6: [np.float64(-1.0), 0.0], 7: [np.float64(-1.5), 0.0], 8: [np.float64(-2.0), 0.0], 9: [0.0, np.float64(0.5)], 10: [0.0, np.float64(1.0)], 11: [0.0, np.float64(1.5)], 12: [0.0, np.float64(2.0)], 13: [0.0, np.float64(-0.5)], 14: [0.0, np.float64(-1.0)], 15: [0.0, np.float64(-1.5)], 16: [0.0, np.float64(-2.0)]}
[WRAPPER DiscreteIncrementalWrapper] (INFO) : Wrapper initialized
[WRAPPER NormalizeObservation] (INFO) : Wrapper initialized.
[WRAPPER LoggerWrapper] (INFO) : Wrapper initialized.
[WRAPPER MultiObsWrapper] (INFO) : Wrapper initialized.

Now we simply use the environment with the wrappers, for example:

[18]:
for i in range(1):
    obs, info = env.reset()
    truncated = terminated = False
    current_month = 0
    while not (terminated or truncated):
        a = env.action_space.sample()
        obs, reward, terminated, truncated, info = env.step(a)
        if info['month'] != current_month:  # display results every month
            current_month = info['month']
            print('Reward: ', reward, info)
env.close()
#----------------------------------------------------------------------------------------------#
[ENVIRONMENT] (INFO) : Starting a new episode... [5zone-hot-continuous-v1] [Episode 1]
#----------------------------------------------------------------------------------------------#
[MODELING] (INFO) : Episode directory created [/workspaces/sinergym/examples/Eplus-env-5zone-hot-continuous-v1-res1/Eplus-env-sub_run1]
[MODELING] (INFO) : Weather file USA_AZ_Davis-Monthan.AFB.722745_TMY3.epw used.
[MODELING] (INFO) : Adapting weather to building model. [USA_AZ_Davis-Monthan.AFB.722745_TMY3.epw]
[ENVIRONMENT] (INFO) : Saving episode output path... [/workspaces/sinergym/examples/Eplus-env-5zone-hot-continuous-v1-res1/Eplus-env-sub_run1/output]
[SIMULATOR] (INFO) : Running EnergyPlus with args: ['-w', '/workspaces/sinergym/examples/Eplus-env-5zone-hot-continuous-v1-res1/Eplus-env-sub_run1/USA_AZ_Davis-Monthan.AFB.722745_TMY3.epw', '-d', '/workspaces/sinergym/examples/Eplus-env-5zone-hot-continuous-v1-res1/Eplus-env-sub_run1/output', '/workspaces/sinergym/examples/Eplus-env-5zone-hot-continuous-v1-res1/Eplus-env-sub_run1/5ZoneAutoDXVAV.epJSON']
[ENVIRONMENT] (INFO) : Episode 1 started.
[SIMULATOR] (INFO) : handlers initialized.
[SIMULATOR] (INFO) : handlers are ready.
[SIMULATOR] (INFO) : System is ready.
[WRAPPER NormalizeObservation] (INFO) : Saving normalization calibration data... [5zone-hot-continuous-v1]
Reward:  [-0.00589738497079933, -0.09533249490526607] {'time_elapsed(hours)': 0.5, 'month': 1, 'day': 1, 'hour': 0, 'is_raining': False, 'action': [np.float64(21.0), np.float64(24.5)], 'timestep': 2, 'reward': -0.10122987987606541, 'energy_term': -0.00589738497079933, 'comfort_term': -0.09533249490526607, 'reward_weight': 0.5, 'abs_energy_penalty': -117.9476994159866, 'abs_comfort_penalty': -0.19066498981053215, 'total_power_demand': 117.9476994159866, 'total_temperature_violation': 0.19066498981053215}
Progress: |*--------------------------------------------------------------------------------------------------| 1%
/usr/local/lib/python3.12/dist-packages/gymnasium/spaces/box.py:240: UserWarning: WARN: Casting input x to numpy array.
  gym.logger.warn("Casting input x to numpy array.")
Reward:  [-0.260786748513617, 0.0] {'time_elapsed(hours)': 744.25, 'month': 2, 'day': 1, 'hour': 0, 'is_raining': False, 'action': [np.float64(22.25), np.float64(27.5)], 'timestep': 2977, 'reward': -0.260786748513617, 'energy_term': -0.260786748513617, 'comfort_term': 0.0, 'reward_weight': 0.5, 'abs_energy_penalty': -5215.7349702723395, 'abs_comfort_penalty': 0, 'total_power_demand': 5215.7349702723395, 'total_temperature_violation': 0.0}
Reward:  [-0.00589738497079933, 0.0] {'time_elapsed(hours)': 1416.25, 'month': 3, 'day': 1, 'hour': 0, 'is_raining': False, 'action': [np.float64(20.5), np.float64(27.25)], 'timestep': 5665, 'reward': -0.00589738497079933, 'energy_term': -0.00589738497079933, 'comfort_term': 0.0, 'reward_weight': 0.5, 'abs_energy_penalty': -117.9476994159866, 'abs_comfort_penalty': 0, 'total_power_demand': 117.9476994159866, 'total_temperature_violation': 0.0}
Reward:  [-0.00589738497079933, 0.0] {'time_elapsed(hours)': 2160.25, 'month': 4, 'day': 1, 'hour': 0, 'is_raining': False, 'action': [np.float64(19.0), np.float64(28.25)], 'timestep': 8641, 'reward': -0.00589738497079933, 'energy_term': -0.00589738497079933, 'comfort_term': 0.0, 'reward_weight': 0.5, 'abs_energy_penalty': -117.9476994159866, 'abs_comfort_penalty': 0, 'total_power_demand': 117.9476994159866, 'total_temperature_violation': 0.0}
Reward:  [-0.009860130184571677, 0.0] {'time_elapsed(hours)': 2880.25, 'month': 5, 'day': 1, 'hour': 0, 'is_raining': False, 'action': [np.float64(19.5), np.float64(26.25)], 'timestep': 11521, 'reward': -0.009860130184571677, 'energy_term': -0.009860130184571677, 'comfort_term': 0.0, 'reward_weight': 0.5, 'abs_energy_penalty': -197.20260369143355, 'abs_comfort_penalty': 0, 'total_power_demand': 197.20260369143355, 'total_temperature_violation': 0.0}
Reward:  [-0.04169404624132932, 0.0] {'time_elapsed(hours)': 3624.25, 'month': 6, 'day': 1, 'hour': 0, 'is_raining': False, 'action': [np.float64(19.0), np.float64(26.0)], 'timestep': 14497, 'reward': -0.04169404624132932, 'energy_term': -0.04169404624132932, 'comfort_term': 0.0, 'reward_weight': 0.5, 'abs_energy_penalty': -833.8809248265865, 'abs_comfort_penalty': 0, 'total_power_demand': 833.8809248265865, 'total_temperature_violation': 0.0}
Reward:  [-0.03865736684181221, 0.0] {'time_elapsed(hours)': 4344.25, 'month': 7, 'day': 1, 'hour': 0, 'is_raining': False, 'action': [np.float64(23.25), np.float64(26.5)], 'timestep': 17377, 'reward': -0.03865736684181221, 'energy_term': -0.03865736684181221, 'comfort_term': 0.0, 'reward_weight': 0.5, 'abs_energy_penalty': -773.1473368362441, 'abs_comfort_penalty': 0, 'total_power_demand': 773.1473368362441, 'total_temperature_violation': 0.0}
Reward:  [-0.041642249905664626, -0.09052493785560145] {'time_elapsed(hours)': 5088.25, 'month': 8, 'day': 1, 'hour': 0, 'is_raining': False, 'action': [np.float64(23.25), np.float64(24.75)], 'timestep': 20353, 'reward': -0.13216718776126607, 'energy_term': -0.041642249905664626, 'comfort_term': -0.09052493785560145, 'reward_weight': 0.5, 'abs_energy_penalty': -832.8449981132925, 'abs_comfort_penalty': -0.1810498757112029, 'total_power_demand': 832.8449981132925, 'total_temperature_violation': 0.1810498757112029}
Reward:  [-0.0446008401004661, 0.0] {'time_elapsed(hours)': 5832.25, 'month': 9, 'day': 1, 'hour': 0, 'is_raining': False, 'action': [np.float64(23.25), np.float64(30.0)], 'timestep': 23329, 'reward': -0.0446008401004661, 'energy_term': -0.0446008401004661, 'comfort_term': 0.0, 'reward_weight': 0.5, 'abs_energy_penalty': -892.0168020093221, 'abs_comfort_penalty': 0, 'total_power_demand': 892.0168020093221, 'total_temperature_violation': 0.0}
Reward:  [-0.03296858499533663, 0.0] {'time_elapsed(hours)': 6552.25, 'month': 10, 'day': 1, 'hour': 0, 'is_raining': False, 'action': [np.float64(20.25), np.float64(26.75)], 'timestep': 26209, 'reward': -0.03296858499533663, 'energy_term': -0.03296858499533663, 'comfort_term': 0.0, 'reward_weight': 0.5, 'abs_energy_penalty': -659.3716999067325, 'abs_comfort_penalty': 0, 'total_power_demand': 659.3716999067325, 'total_temperature_violation': 0.0}
Reward:  [-0.12172742321465858, 0.0] {'time_elapsed(hours)': 7296.25, 'month': 11, 'day': 1, 'hour': 0, 'is_raining': False, 'action': [np.float64(22.75), np.float64(30.0)], 'timestep': 29185, 'reward': -0.12172742321465858, 'energy_term': -0.12172742321465858, 'comfort_term': 0.0, 'reward_weight': 0.5, 'abs_energy_penalty': -2434.5484642931715, 'abs_comfort_penalty': 0, 'total_power_demand': 2434.5484642931715, 'total_temperature_violation': 0.0}
Reward:  [-0.00589738497079933, 0.0] {'time_elapsed(hours)': 8016.25, 'month': 12, 'day': 1, 'hour': 0, 'is_raining': False, 'action': [np.float64(12.5), np.float64(25.25)], 'timestep': 32065, 'reward': -0.00589738497079933, 'energy_term': -0.00589738497079933, 'comfort_term': 0.0, 'reward_weight': 0.5, 'abs_energy_penalty': -117.9476994159866, 'abs_comfort_penalty': 0, 'total_power_demand': 117.9476994159866, 'total_temperature_violation': 0.0}
Progress: |***************************************************************************************************| 99%
[ENVIRONMENT] (INFO) : Environment closed. [5zone-hot-continuous-v1]
[WRAPPER NormalizeObservation] (INFO) : Saving normalization calibration data... [5zone-hot-continuous-v1]