Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue155 v070 #156

Open
wants to merge 51 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
f300f54
Adapt README.
javiarrobas Jun 22, 2022
59a7624
Remove container port in url
javiarrobas Jun 22, 2022
933143e
Add testcase as an argument to the environment and include functionality
javiarrobas Jun 22, 2022
5b28916
Add new testcase argument to example in the README
javiarrobas Jun 22, 2022
0aab474
Use testid in baseline examples.
javiarrobas Jun 22, 2022
d60b52d
use testid in test_and_plot.py.
javiarrobas Jun 22, 2022
4cf6435
Add testid and testcase argument to examples in train_RL.py.
javiarrobas Jun 22, 2022
dea4288
Change commit for BOPTEST-Service.
javiarrobas Jun 22, 2022
a5b4196
Add testcase argument in test_boptestGymEnv.py.
javiarrobas Jun 22, 2022
03584f8
Correct indentation.
javiarrobas Jun 22, 2022
68fbe47
Stop test cases to prevent overwhelming the server.
javiarrobas Jun 23, 2022
e01e98a
Do not use SetUp() since that was overloading the server and duplicating
javiarrobas Jun 23, 2022
f0126ca
Merge commit '187c9a76eefb27cee8285b5cca123aa8f396345f' into boptest-…
javiarrobas Jul 21, 2022
80e43ac
Merge branch 'master' into boptest-gym-service
javiarrobas Sep 1, 2022
04d0f3e
Merge branch 'master' into boptest-gym-service
javiarrobas Sep 2, 2022
3aec496
Merge commit '75e3d5bfb4712e607e5832b147bd74c0fb32e5e7' into issue111…
javiarrobas Sep 3, 2022
de44cd2
Merge pull request #112 from ibpsa/issue111_updateServiceToBoptestV030
javiarrobas Sep 3, 2022
25ff9c4
Solve request for testid not using payload argument
javiarrobas Oct 25, 2022
5a79530
Resolve typo.
javiarrobas Oct 25, 2022
1c5a729
Merge commit '80266f4588a9c28137d67b51a7888d0ca3868f01' into boptest-…
javiarrobas Jun 30, 2023
f1ca5d0
Add missing testid when requesting default step.
javiarrobas Jun 30, 2023
8092d31
Merge branch 'issue118_boptestV400' into boptest-gym-service
javiarrobas Jun 30, 2023
3b02170
Rename CCAI_Summer_School_2022 directory.
javiarrobas Jul 6, 2023
b9620b6
Merge remote-tracking branch 'origin/master' into boptest-gym-service.
javiarrobas Jul 6, 2023
cb11ead
Merge branch 'issue120_tutorialUpdateForV040' into boptest-gym-service
javiarrobas Jul 7, 2023
d2e4123
Merge branch 'issue120_tutorialUpdateForV040' into boptest-gym-service
javiarrobas Jul 7, 2023
cd5daf7
Add missing testid when getting forecast.
javiarrobas Jul 7, 2023
3ddd984
Merge remote-tracking branch 'origin/master' into boptest-gym-service
javiarrobas Jul 13, 2023
875c00d
Merge branch 'issue120_tutorialUpdateForV040' into boptest-gym-service
javiarrobas Jul 13, 2023
3e61855
Merge branch 'issue120_tutorialUpdateForV040' into boptest-gym-service
javiarrobas Jul 14, 2023
6b30aca
Merge branch 'master' into boptest-gym-service
javiarrobas Jul 17, 2023
c5d10de
Merge branch 'master' into boptest-gym-service
javiarrobas Jul 17, 2023
e1ee18e
Merge commit 'd74faa225ead274333607d93709b41bbee1001d3' into boptest-…
javiarrobas Sep 4, 2023
afcc0d6
Merge branch 'issue135_v050' into boptest-gym-service
javiarrobas Nov 10, 2023
5d79c2c
Merge commit '7f5b64fa7a2e8b3fafee6c969b15214af666a3a1' into boptest-…
javiarrobas Nov 10, 2023
59900da
Merge commit 'b51c56ea23fa0051f092765e236f8faa5d5b1000' into boptest-…
javiarrobas Nov 11, 2023
56327e3
Merge branch 'issue141_v060' into boptest-gym-service
javiarrobas May 10, 2024
9d809e9
Merge branch 'multi_dimensional_action' into boptest-gym-service
javiarrobas Oct 3, 2024
52e489e
Merge branch 'multi_dimensional_action' into boptest-gym-service
javiarrobas Oct 3, 2024
910f7e1
Merge branch 'multi_dimensional_action' into boptest-gym-service
javiarrobas Oct 3, 2024
709d5a1
Merge branch 'multi_dimensional_action' into boptest-gym-service
javiarrobas Oct 3, 2024
6eefb08
Change port number from 5000 to 80.
javiarrobas Oct 4, 2024
3423670
Change BOPTEST version.
javiarrobas Dec 27, 2024
09330ef
Update command to run BOPTEST.
javiarrobas Dec 27, 2024
1ad30af
Be more accurate in comment.
javiarrobas Dec 27, 2024
7fb8900
Change maintainer email.
javiarrobas Dec 27, 2024
bc30b1a
Merge branch 'boptest-gym-service-refactor' into issue155_v070
javiarrobas Dec 27, 2024
d140f1f
Remove outdated version from docstring.
javiarrobas Dec 27, 2024
d38e5ef
Read environment as local variable instead of class attribute.
javiarrobas Dec 27, 2024
a2f7125
Do not pull boptest base image from registry.
javiarrobas Dec 27, 2024
6dbe0e6
Run boptest app in detached mode.
javiarrobas Dec 27, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .github/workflows/github-actions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ jobs:
uses: actions/checkout@v3
- name: Pull boptestgym image from registry
run: make pull-boptestgym
- name: Pull boptest_base image from registry
run: make pull-boptestbase
- name: Install Docker Compose
run: |
sudo apt-get update
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# BOPTEST-Gym
# BOPTEST-Gym-service

BOPTESTS-Gym is the [OpenAI-Gym](https://gym.openai.com/) environment for the [BOPTEST](https://github.com/ibpsa/project1-boptest) framework. This repository accommodates the BOPTEST API to the OpenAI-Gym convention in order to facilitate the implementation, assessment and benchmarking of reinforcement learning (RL) algorithms for their application in building energy management. RL algorithms from the [Stable-Baselines 3](https://github.com/DLR-RM/stable-baselines3) repository are used to exemplify and test this framework.

This is the service version of BOPTEST-Gym, meaning that it has been adapted to use BOPTEST test cases that can be run in a server instead of just locally.

The environment is described in [this paper](https://www.researchgate.net/publication/354386346_An_OpenAI-Gym_environment_for_the_Building_Optimization_Testing_BOPTEST_framework).

## Structure
Expand Down Expand Up @@ -73,7 +75,7 @@ Running BOPTEST locally is substantially faster

1) Create a conda environment from the `environment.yml` file provided (instructions [here](https://docs.conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html#creating-an-environment-from-an-environment-yml-file)).
2) Run a BOPTEST case with the building emulator model to be controlled (instructions [here](https://github.com/ibpsa/project1-boptest/blob/master/README.md)).
3) Check out the `master` branch of this repository and run the example above replacing the url to be `url = 'http://127.0.0.1:5000'` and avoiding the `testcase` argument to the `BoptestGymEnv` class.
3) Check out the `master` branch of this repository and run the example above replacing the url to be `url = 'http://127.0.0.1:80'` and avoiding the `testcase` argument to the `BoptestGymEnv` class.

## Quick-Start (running BOPTEST locally in a vectorized environment)

Expand Down
64 changes: 46 additions & 18 deletions boptestGymEnv.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ class BoptestGymEnv(gym.Env):
metadata = {'render.modes': ['console']}

def __init__(self,
url = 'http://127.0.0.1:5000',
url = 'http://127.0.0.1',
testcase = 'bestest_hydronic_heat_pump',
actions = ['oveHeaPumY_u'],
observations = {'reaTZon_y':(280.,310.)},
reward = ['reward'],
Expand All @@ -56,6 +57,8 @@ def __init__(self,
----------
url: string
Rest API url for communication with the BOPTEST interface
testcase: string
The string identifier of the testcase
actions: list
List of strings indicating the action space. The bounds of
each variable from the action space the are retrieved from
Expand Down Expand Up @@ -134,6 +137,7 @@ def __init__(self,
super(BoptestGymEnv, self).__init__()

self.url = url
self.testcase = testcase
self.actions = actions
self.observations = list(observations.keys())
self.max_episode_length = max_episode_length
Expand All @@ -160,18 +164,26 @@ def __init__(self,
#=============================================================
# Get test information
#=============================================================
# Get testid for the particular testcase
# Check if already started a test case and stop it if so before starting another
try:
requests.put('{0}/stop/{1}'.format(url, self.testid))
except:
pass
# Select and start a new test case
self.testid = requests.post('{0}/testcases/{1}/select'.format(url, testcase)).json()['testid']
# Test case name
self.name = requests.get('{0}/name'.format(url)).json()['payload']
self.name = requests.get('{0}/name/{1}'.format(url, self.testid)).json()['payload']
# Measurements available
self.all_measurement_vars = requests.get('{0}/measurements'.format(url)).json()['payload']
self.all_measurement_vars = requests.get('{0}/measurements/{1}'.format(url, self.testid)).json()['payload']
# Predictive variables available
self.all_predictive_vars = requests.get('{0}/forecast_points'.format(url)).json()['payload']
self.all_predictive_vars = requests.get('{0}/forecast_points/{1}'.format(url, self.testid)).json()['payload']
# Inputs available
self.all_input_vars = requests.get('{0}/inputs'.format(url)).json()['payload']
self.all_input_vars = requests.get('{0}/inputs/{1}'.format(url, self.testid)).json()['payload']
# Default simulation step
self.step_def = requests.get('{0}/step'.format(url)).json()['payload']
self.step_def = requests.get('{0}/step/{1}'.format(url, self.testid)).json()['payload']
# Default scenario
self.scenario_def = requests.get('{0}/scenario'.format(url)).json()['payload']
self.scenario_def = requests.get('{0}/scenario/{1}'.format(url, self.testid)).json()['payload']

#=============================================================
# Define observation space
Expand Down Expand Up @@ -470,15 +482,15 @@ def find_start_time():
self.start_time = find_start_time()

# Initialize the building simulation
res = requests.put('{0}/initialize'.format(self.url),
res = requests.put('{0}/initialize/{1}'.format(self.url,self.testid),
json={'start_time':int(self.start_time),
'warmup_period':int(self.warmup_period)}).json()['payload']

# Set simulation step
requests.put('{0}/step'.format(self.url), json={'step':int(self.step_period)})
requests.put('{0}/step/{1}'.format(self.url,self.testid), json={'step':int(self.step_period)})

# Set BOPTEST scenario
requests.put('{0}/scenario'.format(self.url), json=self.scenario)
requests.put('{0}/scenario/{1}'.format(self.url,self.testid), json=self.scenario)

# Initialize objective integrand
self.objective_integrand = 0.
Expand All @@ -493,6 +505,22 @@ def find_start_time():

return observations, info

def stop(self):
'''
Stop the test case

'''

requests.put('{0}/stop/{1}'.format(self.url, self.testid))

def stop(self):
'''
Stop the test case

'''

requests.put('{0}/stop/{1}'.format(self.url, self.testid))

def step(self, action):
'''
Advance the simulation one time step
Expand Down Expand Up @@ -543,7 +571,7 @@ def step(self, action):
u[act.replace('_u','_activate')] = float(1)

# Advance a BOPTEST simulation
res = requests.post('{0}/advance'.format(self.url), json=u).json()['payload']
res = requests.post('{0}/advance/{1}'.format(self.url,self.testid), json=u).json()['payload']

# Compute reward of this (state-action-state') tuple
reward = self.get_reward()
Expand Down Expand Up @@ -618,7 +646,7 @@ def get_reward(self):
w = 1

# Compute BOPTEST core kpis
kpis = requests.get('{0}/kpi'.format(self.url)).json()['payload']
kpis = requests.get('{0}/kpi/{1}'.format(self.url,self.testid)).json()['payload']

# Calculate objective integrand function at this point
objective_integrand = kpis['cost_tot'] + w*kpis['tdis_tot']
Expand Down Expand Up @@ -716,7 +744,7 @@ def get_observations(self, res):
if self.is_regressive:
regr_index = res['time']-self.step_period*np.arange(1,self.regr_n+1)
for var in self.regressive_vars:
res_var = requests.put('{0}/results'.format(self.url),
res_var = requests.put('{0}/results/{1}'.format(self.url, self.testid),
json={'point_names':[var],
'start_time':int(regr_index[-1]),
'final_time':int(regr_index[0])}).json()['payload']
Expand All @@ -732,7 +760,7 @@ def get_observations(self, res):

# Get predictions if this is a predictive agent.
if self.is_predictive:
predictions = requests.put('{0}/forecast'.format(self.url),
predictions = requests.put('{0}/forecast/{1}'.format(self.url, self.testid),
json={'point_names': self.predictive_vars,
'horizon': int(self.predictive_period),
'interval': int(self.step_period)}).json()['payload']
Expand All @@ -753,7 +781,7 @@ def get_kpis(self):
'''

# Compute BOPTEST core kpis
kpis = requests.get('{0}/kpi'.format(self.url)).json()['payload']
kpis = requests.get('{0}/kpi/{1}'.format(self.url, self.testid)).json()['payload']

return kpis

Expand Down Expand Up @@ -1246,7 +1274,7 @@ def get_reward(self):
'''

# Compute BOPTEST core kpis
kpis = requests.get('{0}/kpi'.format(self.url)).json()['payload']
kpis = requests.get('{0}/kpi/{1}'.format(self.url, self.testid)).json()['payload']

# Calculate objective integrand function at this point
objective_integrand = kpis['cost_tot'] + kpis['tdis_tot']
Expand Down Expand Up @@ -1283,7 +1311,7 @@ def get_reward(self):
w = 0.1

# Compute BOPTEST core kpis
kpis = requests.get('{0}/kpi'.format(self.url)).json()['payload']
kpis = requests.get('{0}/kpi/{1}'.format(self.url, self.testid)).json()['payload']

# Calculate objective integrand function at this point
objective_integrand = kpis['cost_tot'] + w*kpis['tdis_tot']
Expand Down Expand Up @@ -1317,7 +1345,7 @@ def get_reward(self):
w = 10

# Compute BOPTEST core kpis
kpis = requests.get('{0}/kpi'.format(self.url)).json()['payload']
kpis = requests.get('{0}/kpi/{1}'.format(self.url, self.testid)).json()['payload']

# Calculate objective integrand function at this point
objective_integrand = kpis['cost_tot'] + w*kpis['tdis_tot']
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"\n",
"📌 **Note**: This tutorial is prepared for use with BOPTEST v0.6.0.\n",
"and uses a web-based version of BOPTEST (called \"BOPTEST-Service\") as not to require installation of any BOPTEST software on a user's own device. It is also possible to use BOPTEST on a user's own (local) device. \n",
"Both the web-based and local versions have the same functionality, and will produce the same results, with only small changes in the API (changing the BOPTEST-service url to your localhost url, that is, to: `http://127.0.0.1:5000/<request>`). The tutorial is continuously updated to work with the latest BOPTEST versions. See [the release notes](https://github.com/ibpsa/project1-boptest-gym/blob/master/releasenotes.md) for the version history.\n",
"Both the web-based and local versions have the same functionality, and will produce the same results, with only small changes in the API (changing the BOPTEST-service url to your localhost url, that is, to: `http://127.0.0.1:80/<request>`). The tutorial is continuously updated to work with the latest BOPTEST versions. See [the release notes](https://github.com/ibpsa/project1-boptest-gym/blob/master/releasenotes.md) for the version history.\n",
"\n",
"🎥 **Video**: An explanatory video of this tutorial can be seen [here](https://drive.google.com/file/d/1lvCVQef_kctwCagA5QOVj7QljHQ1xKUQ/view?usp=sharing) for the CCAI2022 Summer School on August 18, 2022. The video starts with a one-hour lecture on the application of machine learning in buildings. The part of BOPTEST-Gym follows right after and lasts for 1.5 hours. Please note that the software version used in the video is v0.2.0. The framework and tutorial have been updated since then so you may notice slight differences in the content and interface. However, the main concepts and explanation behind remains the same. \n"
]
Expand Down
11 changes: 7 additions & 4 deletions examples/run_baseline.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from boptestGymEnv import BoptestGymEnv, NormalizedObservationWrapper, NormalizedActionWrapper
from examples.test_and_plot import test_agent

url = 'http://127.0.0.1:5000'
url = 'http://127.0.0.1'

# Seed for random starting times of episodes
random.seed(123456)
Expand Down Expand Up @@ -77,7 +77,7 @@ def get_reward(self):
w = 0.1

# Compute BOPTEST core kpis
kpis = requests.get('{0}/kpi'.format(self.url)).json()['payload']
kpis = requests.get('{0}/kpi/{1}'.format(self.url, self.testid)).json()['payload']

# Calculate objective integrand function at this point
objective_integrand = kpis['cost_tot']*12.*16. + w*kpis['tdis_tot']
Expand Down Expand Up @@ -125,7 +125,7 @@ def get_reward(self):
'''

# Compute BOPTEST core kpis
kpis = requests.get('{0}/kpi'.format(self.url)).json()['payload']
kpis = requests.get('{0}/kpi/{1}'.format(self.url, self.testid)).json()['payload']

# Calculate objective integrand function at this point
objective_integrand = kpis['cost_tot']*12.*16. + kpis['tdis_tot']
Expand Down Expand Up @@ -249,7 +249,10 @@ def run(envClass, wrapper=None, scenario={'electricity_price':'constant'},
episode_length=episode_length_test,
warmup_period=warmup_period_test,
plot=plot)


# stop the test
env.stop()

return observations, actions, rewards

class BaselineModel(object):
Expand Down
5 changes: 4 additions & 1 deletion examples/run_sample.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from examples.test_and_plot import test_agent
import random

url = 'http://127.0.0.1:5000'
url = 'http://127.0.0.1'

# Seed for random starting times of episodes
random.seed(123456)
Expand Down Expand Up @@ -68,6 +68,9 @@ def run(envClass, wrapper=None, plot=False):
episode_length=episode_length_test,
warmup_period=warmup_period_test,
plot=plot)

# stop the test
env.stop()

return observations, actions, rewards

Expand Down
2 changes: 1 addition & 1 deletion examples/run_save_callback.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import random
import os

url = 'http://127.0.0.1:5000'
url = 'http://127.0.0.1'
seed = 123456

# Seed for random starting times of episodes
Expand Down
2 changes: 1 addition & 1 deletion examples/run_variable_episode.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import random
import os

url = 'http://127.0.0.1:5000'
url = 'http://127.0.0.1'
seed = 123456

# Seed for random starting times of episodes
Expand Down
4 changes: 2 additions & 2 deletions examples/test_and_plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def plot_results(env, rewards, points=['reaTZon_y','reaTSetHea_y','reaTSetCoo_y'
# We use env.start_time+1 to ensure that we don't return the last
# point from the initialization period to don't confuse it with
# actions taken by the agent in a previous episode.
res = requests.put('{0}/results'.format(env.url),
res = requests.put('{0}/results/{1}'.format(env.url, env.testid),
json={'point_names':points,
'start_time':env.start_time+1,
'final_time':3.1536e7}).json()['payload']
Expand Down Expand Up @@ -200,4 +200,4 @@ def create_datetime_index(df):

return df



9 changes: 7 additions & 2 deletions examples/train_RL.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import random
import os

url = 'http://127.0.0.1:5000'
url = 'http://127.0.0.1'
seed = 123456

# Seed for random starting times of episodes
Expand Down Expand Up @@ -93,7 +93,7 @@ def get_reward(self):
'''

# Compute BOPTEST core kpis
kpis = requests.get('{0}/kpi'.format(self.url)).json()['payload']
kpis = requests.get('{0}/kpi/{1}'.format(self.url, self.testid)).json()['payload']

# Calculate objective integrand function at this point
objective_integrand = kpis['cost_tot']*12.*16. + 100*kpis['tdis_tot']
Expand All @@ -108,6 +108,7 @@ def get_reward(self):
if case == 'simple':
env = BoptestGymEnvCustomReward(
url = url,
testcase = 'bestest_hydronic_heat_pump',
actions = ['oveHeaPumY_u'],
observations = OrderedDict([('reaTZon_y',(280.,310.))]),
random_start_time = True,
Expand All @@ -120,6 +121,7 @@ def get_reward(self):
elif case == 'A':
env = BoptestGymEnvCustomReward(
url = url,
testcase ='bestest_hydronic_heat_pump',
actions = ['oveHeaPumY_u'],
observations = OrderedDict([('time',(0,604800)),
('reaTZon_y',(280.,310.)),
Expand All @@ -136,6 +138,7 @@ def get_reward(self):
if case == 'B':
env = BoptestGymEnvCustomReward(
url = url,
testcase ='bestest_hydronic_heat_pump',
actions = ['oveHeaPumY_u'],
observations = OrderedDict([('time',(0,604800)),
('reaTZon_y',(280.,310.)),
Expand All @@ -154,6 +157,7 @@ def get_reward(self):
if case == 'C':
env = BoptestGymEnvCustomReward(
url = url,
testcase ='bestest_hydronic_heat_pump',
actions = ['oveHeaPumY_u'],
observations = OrderedDict([('time',(0,604800)),
('reaTZon_y',(280.,310.)),
Expand All @@ -173,6 +177,7 @@ def get_reward(self):
if case == 'D':
env = BoptestGymEnvCustomReward(
url = url,
testcase ='bestest_hydronic_heat_pump',
actions = ['oveHeaPumY_u'],
observations = OrderedDict([('time',(0,604800)),
('reaTZon_y',(280.,310.)),
Expand Down
4 changes: 2 additions & 2 deletions generateDockerComposeYml.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
yaml_target_dir = os.path.dirname(os.path.abspath(__file__))

num_services = 2 # Total Services needed
base_port = 5000 # Start Port number
base_port = 80 # Start Port number


# Function to check if a port is available
Expand Down Expand Up @@ -53,7 +53,7 @@ def is_port_available(port):
"./forecast:${APP_PATH}/forecast/",
"./kpis:${APP_PATH}/kpis/",
],
"ports": [f"127.0.0.1:{port}:5000"],
"ports": [f"127.0.0.1:{port}:80"],
"networks": ["boptest-net"],
"restart": "on-failure" # restart on-failure
}
Expand Down
2 changes: 1 addition & 1 deletion testing/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Start with a base Ubuntu image
FROM --platform=linux/x86_64 ubuntu:20.04
# This is the Focal Fossa ubuntu version
MAINTAINER Javier Arroyo <javier.arroyo@kuleuven.be>
MAINTAINER Javier Arroyo <javier.arroyo@wedoco.io>

# Avoid warnings while installing ubuntu
# debconf: unable to initialize frontend: Dialog
Expand Down
Loading
Loading