20. Rule Controller example
First we import all the used libraries, remember to always import sinergym
even if it says is not used, because that is needed to define the environments
[1]:
from typing import List, Any, Sequence
from sinergym.utils.common import get_season_comfort_range
from datetime import datetime
import gymnasium as gym
import numpy as np
import sinergym
Now we can define the environment we want to use, in our case we are using the Eplus demo.
[2]:
env = gym.make('Eplus-demo-v1')
[2023-02-09 11:25:10,224] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf ExternalInterface object if it is not present...
[2023-02-09 11:25:10,225] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf Site:Location and SizingPeriod:DesignDay(s) to weather and ddy file...
[2023-02-09 11:25:10,227] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Updating idf OutPut:Variable and variables XML tree model for BVCTB connection.
[2023-02-09 11:25:10,228] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up extra configuration in building model if exists...
[2023-02-09 11:25:10,228] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Setting up action definition in building model if exists...
For the Rule-base controller have a look at the already defined controllers, there is one for each building, since the demo is based on the 5Zone building we are extending that controller and defining the action function we desire, feel free to play with the function to define your own action.
[3]:
from sinergym.utils.controllers import RBC5Zone
class MyRuleBasedController(RBC5Zone):
def act(self, observation: List[Any]) -> Sequence[Any]:
"""Select action based on outdoor air drybulb temperature and daytime.
Args:
observation (List[Any]): Perceived observation.
Returns:
Sequence[Any]: Action chosen.
"""
obs_dict = dict(zip(self.variables['observation'], observation))
out_temp = obs_dict['Site Outdoor Air Drybulb Temperature(Environment)']
day = int(obs_dict['day'])
month = int(obs_dict['month'])
hour = int(obs_dict['hour'])
year = int(obs_dict['year'])
summer_start_date = datetime(year, 6, 1)
summer_final_date = datetime(year, 9, 30)
current_dt = datetime(year, month, day)
# Get season comfort range
if current_dt >= summer_start_date and current_dt <= summer_final_date:
season_comfort_range = self.setpoints_summer
else:
season_comfort_range = self.setpoints_summer
season_comfort_range = get_season_comfort_range(1991,month, day)
# Update setpoints
in_temp = obs_dict['Zone Air Temperature(SPACE1-1)']
current_heat_setpoint = obs_dict[
'Zone Thermostat Heating Setpoint Temperature(SPACE1-1)']
current_cool_setpoint = obs_dict[
'Zone Thermostat Cooling Setpoint Temperature(SPACE1-1)']
new_heat_setpoint = current_heat_setpoint
new_cool_setpoint = current_cool_setpoint
if in_temp < season_comfort_range[0]:
new_heat_setpoint = current_heat_setpoint + 1
new_cool_setpoint = current_cool_setpoint + 1
elif in_temp > season_comfort_range[1]:
new_cool_setpoint = current_cool_setpoint - 1
new_heat_setpoint = current_heat_setpoint - 1
action = (new_heat_setpoint, new_cool_setpoint)
if current_dt.weekday() > 5 or hour in range(22, 6):
#weekend or night
action = (18.33, 23.33)
return action
Now that we have our controller ready we can use it:
[4]:
# create rule-based controller
agent = MyRuleBasedController(env)
for i in range(1):
obs, info = env.reset()
rewards = []
terminated = False
current_month = 0
while not terminated:
action = agent.act(obs)
obs, reward, terminated, truncated, info = env.step(action)
rewards.append(reward)
if info['month'] != current_month: # display results every month
current_month = info['month']
print('Reward: ', sum(rewards), info)
print(
'Episode ',
i,
'Mean reward: ',
np.mean(rewards),
'Cumulative reward: ',
sum(rewards))
[2023-02-09 11:25:14,756] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:Creating new EnergyPlus simulation episode...
[2023-02-09 11:25:14,764] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus working directory is in /workspaces/sinergym/examples/Eplus-env-demo-v1-res1/Eplus-env-sub_run1
Reward: -0.9027267231826451 {'timestep': 1, 'time_elapsed': 900, 'year': 1991, 'month': 1, 'day': 1, 'hour': 0, 'action': [21.0, 25.0], 'total_power': 18054.5344636529, 'total_power_no_units': -1.8054534463652903, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [20.99998833869494]}
Reward: -1764.4480209727506 {'timestep': 2976, 'time_elapsed': 2678400, 'year': 1991, 'month': 2, 'day': 1, 'hour': 0, 'action': [20.33, 25.33], 'total_power': 18190.11301727289, 'total_power_no_units': -1.8190113017272893, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [20.32998609178986]}
Reward: -3319.0240158271495 {'timestep': 5664, 'time_elapsed': 5097600, 'year': 1991, 'month': 3, 'day': 1, 'hour': 0, 'action': [20.33, 25.33], 'total_power': 6499.498986238363, 'total_power_no_units': -0.6499498986238363, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [20.32985628557421]}
Reward: -4331.530660717744 {'timestep': 8640, 'time_elapsed': 7776000, 'year': 1991, 'month': 4, 'day': 1, 'hour': 0, 'action': [18.33, 23.33], 'total_power': 152.4868953414246, 'total_power_no_units': -0.01524868953414246, 'comfort_penalty': -1.2698020216335806, 'abs_comfort': 1.2698020216335806, 'temperatures': [18.73019797836642]}
Reward: -5030.34341168003 {'timestep': 11520, 'time_elapsed': 10368000, 'year': 1991, 'month': 5, 'day': 1, 'hour': 0, 'action': [20.33, 25.33], 'total_power': 2756.596244185509, 'total_power_no_units': -0.2756596244185509, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [20.33021642625628]}
Reward: -5624.205479307242 {'timestep': 14496, 'time_elapsed': 13046400, 'year': 1991, 'month': 6, 'day': 1, 'hour': 0, 'action': [20.33, 25.33], 'total_power': 871.8985175509725, 'total_power_no_units': -0.08718985175509726, 'comfort_penalty': -2.6700868290835906, 'abs_comfort': 2.6700868290835906, 'temperatures': [20.32991317091641]}
Reward: -7188.94373222068 {'timestep': 17376, 'time_elapsed': 15638400, 'year': 1991, 'month': 7, 'day': 1, 'hour': 0, 'action': [18.33, 23.33], 'total_power': 175.7796758221068, 'total_power_no_units': -0.017577967582210682, 'comfort_penalty': -2.710258038781241, 'abs_comfort': 2.710258038781241, 'temperatures': [20.28974196121876]}
Reward: -9056.39052356895 {'timestep': 20352, 'time_elapsed': 18316800, 'year': 1991, 'month': 8, 'day': 1, 'hour': 0, 'action': [23.33, 28.33], 'total_power': 20410.91452531903, 'total_power_no_units': -2.041091452531903, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [23.33010209424337]}
Reward: -10854.090922968613 {'timestep': 23328, 'time_elapsed': 20995200, 'year': 1991, 'month': 9, 'day': 1, 'hour': 0, 'action': [23.33, 28.33], 'total_power': 3438.778066876331, 'total_power_no_units': -0.3438778066876331, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [23.32982109298299]}
Reward: -12308.980146004908 {'timestep': 26208, 'time_elapsed': 23587200, 'year': 1991, 'month': 10, 'day': 1, 'hour': 0, 'action': [23.33, 28.33], 'total_power': 6368.219126588838, 'total_power_no_units': -0.6368219126588838, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [23.33031589389634]}
Reward: -12900.560641948945 {'timestep': 29184, 'time_elapsed': 26265600, 'year': 1991, 'month': 11, 'day': 1, 'hour': 0, 'action': [20.33, 25.33], 'total_power': 2705.336525778672, 'total_power_no_units': -0.2705336525778672, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [20.33017846907974]}
Reward: -13780.798440045137 {'timestep': 32064, 'time_elapsed': 28857600, 'year': 1991, 'month': 12, 'day': 1, 'hour': 0, 'action': [20.33, 25.33], 'total_power': 5352.233991403948, 'total_power_no_units': -0.5352233991403947, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [20.32992237675168]}
Reward: -15499.608669456482 {'timestep': 35040, 'time_elapsed': 31536000, 'year': 1992, 'month': 1, 'day': 1, 'hour': 0, 'action': [20.33, 25.33], 'total_power': 19332.86497279549, 'total_power_no_units': -1.9332864972795492, 'comfort_penalty': -0.0, 'abs_comfort': 0.0, 'temperatures': [20.33000068783789]}
Episode 0 Mean reward: -0.4423404300643832 Cumulative reward: -15499.608669456482
Always remember to close the environment:
[5]:
env.close()
[2023-02-09 11:25:25,999] EPLUS_ENV_demo-v1_MainThread_ROOT INFO:EnergyPlus simulation closed successfully.
Note
For more information about our defines controllers and how create a new one, please, visit our Controller Documentation