BOPTestAPI.jl · BOPTestAPI.jl (original) (raw)

Quickstart

Installation

BOPTestAPI is available from the Julia general registry. Thus, you can add it like

import Pkg; Pkg.add("BOPTestAPI")

Self-contained example

See further below for some explanations.

using BOPTestAPI
using DataFrames
using Plots

dt = 900.0 # time step in seconds
testcase = "bestest_hydronic"

plant = BOPTestPlant("http://api.boptest.net", testcase, dt = dt)

# Get available measurement points
mpts = measurement_points(plant)
Maximum Unit Description Name Minimum
missing ppm CO2 concentration in the zone reaCO2RooAir_y missing
missing W Pump electrical power reaPPum_y missing
missing W Heating thermal power reaQHea_y missing

(Output truncated)

N = 100

# Get forecast data as well (for plotting later)
fc = getforecasts(plant, N * dt, dt)

# Run N time steps of baseline control
res = []
for t = 1:N
    u = Dict() # here you would put your own controller
    y = advance!(plant, u)
    push!(res, y)
end
stop!(plant)

dfres = DataFrame(res)
reaPPum_y reaQHea_y reaTRoo_y weaSta_reaWeaCeiHei_y
12.25 2829.15 292.21 22000.0
12.25 5373.54 293.04 22000.0
12.25 5577.8 294.56 22000.0
12.25 0.0 295.25 22000.0
12.25 0.0 294.37 22000.0

(Output truncated in both columns and rows)

And that's it! You successfully simulated a building HVAC system in the cloud using BOPTEST-Service. The following code will just make some plots of the results.

# Create single df with all data
df = leftjoin(dfres, fc, on = :time => :time)

pl1 = plot(
    df.time ./ 3600,
    Matrix(df[!, ["reaTRoo_y", "LowerSetp[1]"]]);
    xlabel = "t [h]",
    ylabel = "T [K]",
    labels = ["actual" "target"],
)
pl2 = plot(
    df.time ./ 3600,
    df.reaQHea_y ./ 1000;
    xlabel = "t [h]",
    ylabel = "Qdot [kW]",
    labels = "Heating"
)
plot(pl1, pl2; layout = (2, 1))

Example block output

Usage

(See also the README on Github)

The general idea is that the BOPTEST services are abstracted away as a BOPTestPlant, which only stores metadata about the plant such as the endpoints to use.

The package then defines common functions to operate on the plant, which are translated to REST API calls and the required data formattings.

Initialization

Use the BOPTestPlant or CachedBOPTestPlant constructor:

dt = 900.0 # time step in seconds

testcase = "bestest_hydronic"
plant = BOPTestPlant("http://localhost", testcase, dt = dt)

n_forecast = 24
plant_with_cache = CachedBOPTestPlant("http://api.boptest.net", testcase, n_forecast, dt = dt)

# For old BOPTEST < v0.7, use the deprecated initboptest! function
old_plant = initboptest!("http://127.0.0.1:5000", dt = dt)

The initialization functions also query and store the available signals (as DataFrame), since they are constant for a testcase. The signals are available as

Interaction with the plant

The package then defines common functions to operate on the plant, namely

Querying data

The time series functions return a DataFrame with the time series. By default, a conversion to Float64 is attempted (else the datatypes would be Any). You can use the keyword argument convert_f64=false to disable conversion.

# Query forecast data for 24 hours, with 1/dt sampling frequency
# The column "Name" contains all available forecast signal names
fc_pts = forecast_points(plant)
fc = getforecasts(plant, 24*3600, dt, fc_pts.Name)

# For a CachedBOPTestPlant, the forecasts are part of the local cache
# So the following won't result in a REST API call
fc2 = forecasts(plant_with_cache)

Advancing

The advance! function requires the control inputs u as a Dict. Allowed control inputs are test case specific, but can be queried as property input_points.

ipts = input_points(plant)

# Alternative: Create a simple Dict directly
# This will by default overwrite all baseline values with the lowest allowed value
u = controlinputs(plant)

# Simulate 100 steps open-loop
res_ol = [advance!(plant, u) for _ = 1:100]
df_ol = DataFrame(res_ol)

# KPI
kpi = getkpi(plant)

Stop

Stop a test case when no longer needed:

stop!(plant)

API

Types

BOPTestAPI.BOPTestPlant — Type

BOPTestPlant(boptest_url, testcase[; dt, init_vals, scenario])

Initialize a testcase in BOPTEST service.

Arguments

Keyword arguments

source

BOPTestAPI.CachedBOPTestPlant — Type

CachedBOPTestPlant(plant, N[, Nmax])
CachedBOPTestPlant(boptest_url, testcase, N[, Nmax; dt, init_vals, scenario])

Create a plant with a local cache.

In addition to the properties and methods of the normal BOPTestPlant, this type also stores submitted inputs, received measurements, and the current forecast. These values are updated when calling advance!.

Arguments

or (to initialize a new testcase)

Optional arguments

Keyword arguments

See the documentation for BOPTestPlant.

source

Accessors

BOPTestAPI.forecast_points — Function

forecast_points(p::AbstractBOPTestPlant)

Return forecast points as DataFrame.

source

BOPTestAPI.input_points — Function

input_points(p::AbstractBOPTestPlant)

Return forecast points as DataFrame.

source

BOPTestAPI.measurement_points — Function

measurement_points(p::AbstractBOPTestPlant)

Return measurement points as DataFrame.

source

BOPTestAPI.forecasts — Function

forecasts(p::CachedBOPTestPlant)
forecasts(p::CachedBOPTestPlant; rows, columns)

Return forecasts from current time step as DataFrame.

Use valid row and column selectors from DataFrames.jl for the keyword arguments.

source

BOPTestAPI.inputs_sent — Function

inputs_sent(p::CachedBOPTestPlant)
inputs_sent(p::CachedBOPTestPlant; rows, columns)

Return past inputs sent to the plant as DataFrame.

Note that this contains values as sent; if out of bounds, the plant might use other values. Use measurements to get a DataFrame with the actually used inputs. In case the default was used for a signal, the entry here will be missing.

The values in the time column give the plant time after the time step is completed, not when it was sent. This matches the time column in DataFrame returned by measurements(plant).

Use valid row and column selectors from DataFrames.jl for the keyword arguments.

source

BOPTestAPI.measurements — Function

measurements(p::CachedBOPTestPlant)
measurements(p::CachedBOPTestPlant; rows, columns)

Return measurements as DataFrame.

Unlike getmeasurements(p, ...), this method uses the local cache. This also means that the time step corresponds to the controller time step. Use valid row and column selectors from DataFrames.jl for the keyword arguments.

source

Interaction

BOPTestAPI.initialize! — Function

initialize!(api_endpoint::AbstractBOPTestEndpoint; init_vals, timeout)
initialize!(plant::AbstractBOPTestPlant; init_vals, timeout)

Arguments

Keyword arguments

(Re-)Initialize the plant and return the payload from the BOPTEST-Service API. Also re-initializes the caches for a CachedBOPTestPlant.

source

BOPTestAPI.initboptest! — Function

initboptest!(boptest_url[; dt, init_vals, scenario])

Initialize the local BOPTEST server.

Arguments

Keyword arguments

Return a BOPTestPlant instance, or throw an ErrorException on error.

Info: Since v0.7, BOPTEST switched to the BOPTEST-Service API. Use this for a locally deployed BOPTEST < v0.7, or for other BOPTEST-like APIs, e.g. yards (https://gitlab.kuleuven.be/positive-energy-districts/yards/).

source

BOPTestAPI.setscenario! — Function

setscenario!(api_endpoint::AbstractBOPTestEndpoint, d; timeout)
setscenario!(plant::AbstractBOPTestPlant, d; timeout)

Arguments

Keyword arguments

Set the scenario for a BOPTEST plant and return the selected scenario.

source

BOPTestAPI.getforecasts — Function

getforecasts(plant, horizon, interval[, points])

Query forecast from BOPTEST server and return as DataFrame.

Arguments

Keyword Arguments

Available forecast points are available using forecast_points(plant).

source

BOPTestAPI.getmeasurements — Function

getmeasurements(plant, starttime, finaltime[, points])

Query measurements from BOPTEST server and return as DataFrame.

Arguments

Keyword Arguments

To obtain available points, use measurement_points(plant) and input_points(plant), which each return a DataFrame with a column :Name that contains all available signals.

source

BOPTestAPI.getkpi — Function

getkpi(plant::AbstractBOPTestPlant)

Get KPI from BOPTEST server as Dict.

source

BOPTestAPI.getstep — Function

getstep(plant::AbstractBOPTestPlant; timeout = _DEF_TIMEOUT)

Get plant time step as Float64.

source

BOPTestAPI.advance! — Function

advance!(plant::AbstractBOPTestPlant, u::AbstractDict)

Step the plant using control input u.

Returns the payload as Dict{String, Vector}.

source

BOPTestAPI.stop! — Function

stop!(plant::AbstractBOPTestPlant)
stop!([base_url = "http://localhost",] testid::AbstractString)

Stop a BOPTestPlant from running.

This method does nothing for plants run in BOPTEST v0.6.0 and earlier (i.e. not using the BOPTEST-Service API).

source

Utils

BOPTestAPI.controlinputs — Function

controlinputs([f::Function, ]plant::AbstractBOPTestPlant)

Return Dict with control signals for BOPTEST.

This method calls input_points(plant) to gather available inputs, and then creates a Dict with the available inputs as keys and default values defined by function f.

f is a function that is applied to a DataFrame constructed from the input points that have a suffix "_u", i.e. control inputs. The DataFrame normally has columns :Name, :Minimum, :Maximum, :Unit, :Description.

The default for f is df -> df[!, :Minimum], i.e. use the minimum allowed input.

source