Evaluators

This notebook covers how to use the three BESOS Evaluators: - the EnergyPlus Evaluator (EvaluatorEP) - the Generic Evaluator (EvaluatorGeneric) - the Energy Hub Evaluator (EvaluatorEH)

import numpy as np
import pandas as pd

from besos.evaluator import EvaluatorEP, EvaluatorGeneric, EvaluatorEH
from besos import eppy_funcs as ef
from besos import pyehub_funcs as pf
from besos.parameters import FieldSelector, Parameter, PathSelector
from besos.problem import EPProblem, Problem, EHProblem
from besos import sampling

EvaluatorEP

The EnergyPlus evaluator needs a problem with parameters that can modify it, objectives to report, and a building model. A problem (problem = parameters + objectives) can be easily applied to any building model (evaluator = problem + building).

building = ef.get_building()  # load example file if no idf filename is provided

parameters = [
    Parameter(
        FieldSelector(
            object_name="Mass NonRes Wall Insulation",  # define wall insulation thickness as a parameter
            field_name="Thickness",
        )
    )
]  # options: `FieldSelector`, `FilterSelecor`, `GenericSelector`

objectives = [
    "Electricity:Facility",
    "Gas:Facility",
]  # these get made into `MeterReader` or `VariableReader`
problem = EPProblem(parameters, objectives)  # problem = parameters + objectives

evaluator = EvaluatorEP(problem, building)  # evaluator = problem + building
result = evaluator(
    [0.5]
)  # run the evaluator with wall insulation thickness set to 0.5m
values = dict(zip(objectives, result))
for key, value in values.items():
    print(key, " :: ", "{0:.2f}".format(value / 3.6e6), "kWh")
Electricity:Facility  ::  505.20 kWh
Gas:Facility  ::  603.35 kWh

Different version EnergyPlus

EvaluatorEP can set the version of EnergyPlus for running simulation by ‘version’ parameter. See this notebook for detail.

evaluator = EvaluatorEP(problem, building)

EvaluatorGeneric

The generic evaluator takes a function with the correct number of inputs and produces outputs in the format (objectives, constraints) where objectives and constraints are tuples. Since this evaluator only uses it’s parameters to track the number of inputs and outputs (and their names), we can use numbered placeholders that are automatically generated by Problem

def function(values):  # define a dummy fucntion f1(x)=x, f2(x)=x^2
    return ((values[0], values[0] ** 2))


print("Function value at 4 is:", function([4]))

new_problem = Problem(
    1, 2, 0
)  # this denotes a problem which takes 1 input, produces 2 outputs and has no contraints

# These names are used on the headings of DataFrames generated by the problem and evaluators that use it
print(problem.names(), new_problem.names())

evaluator_1 = EvaluatorGeneric(function, problem)
evaluator_2 = EvaluatorGeneric(function, new_problem)
print(evaluator_1([4]))
print(evaluator_2([4]))
Function value at 4 is: (4, 16)
['input', 'Electricity:Facility', 'Gas:Facility'] ['inputs_0', 'outputs_0', 'outputs_1']
(4, 16)
(4, 16)
evaluator_1([4])
(4, 16)

EvaluatorEH

The Energy Hub evaluator needs: + an energy hub model + a problem with parameters that can modify it + objectives that correspond to outputs from the model

Parameters are provided as a list of key list mapping lists for the different variables in the model. Outputs are provided as a list of the keys from the results of the model.

hub = pf.get_hub()  # load the hub model specified in config

parameters = [
    Parameter(PathSelector(['LOADS','Elec'])),
    Parameter(PathSelector(['LOADS','Heat'])),
]  # the parameters are the hourly electricty and heat loads  # the parameters are the hourly electricty and heat loads
objectives = [
    "total_cost",
    "total_carbon",
]  # the objectives are the total_carbon and total_cost variables of the Energy Hub problem
problem = EHProblem(
    parameters, objectives
)  # we make a problem out of the parameters and objectives
evaluatorEH = EvaluatorEH(
    problem, hub
)  # and an Evaluator by combining with the hub model

Input values for overwritting the specified parameters can be given in the form of: + single values + a dictionary time series + a dataframe of single values + a dataframe of time series

default_timeseries = [
    {
        0: 1.0,
        1: 4.0,
        2: 4.0,
        3: 4.0,
        4: 4.0,
        5: 4.0,
        6: 4.0,
        7: 4.0,
        8: 4.0,
        9: 4.0,
        10: 4.0,
    },
    {
        0: 20.0,
        1: 20.0,
        2: 20.0,
        3: 20.0,
        4: 20.0,
        5: 20.0,
        6: 20.0,
        7: 12.0,
        8: 12.0,
        9: 12.0,
        10: 12.0,
    },
]
just_modified_heat = [
    {
        0: 1.0,
        1: 4.0,
        2: 4.0,
        3: 4.0,
        4: 4.0,
        5: 4.0,
        6: 4.0,
        7: 4.0,
        8: 4.0,
        9: 4.0,
        10: 4.0,
    },
    {
        0: 18.0,
        1: 18.0,
        2: 18.0,
        3: 18.0,
        4: 18.0,
        5: 18.0,
        6: 18.0,
        7: 16.0,
        8: 16.0,
        9: 16.0,
        10: 16.0,
    },
]
just_modified_elec = [
    {
        0: 4.0,
        1: 8.0,
        2: 6.0,
        3: 5.0,
        4: 7.0,
        5: 7.0,
        6: 7.0,
        7: 7.0,
        8: 7.0,
        9: 7.0,
        10: 7.0,
    },
    {
        0: 20.0,
        1: 20.0,
        2: 20.0,
        3: 20.0,
        4: 20.0,
        5: 20.0,
        6: 20.0,
        7: 12.0,
        8: 12.0,
        9: 12.0,
        10: 12.0,
    },
]
modified_timeseries = [
    {
        0: 4.0,
        1: 8.0,
        2: 6.0,
        3: 5.0,
        4: 7.0,
        5: 7.0,
        6: 7.0,
        7: 7.0,
        8: 7.0,
        9: 7.0,
        10: 7.0,
    },
    {
        0: 18.0,
        1: 18.0,
        2: 18.0,
        3: 18.0,
        4: 18.0,
        5: 18.0,
        6: 18.0,
        7: 16.0,
        8: 16.0,
        9: 16.0,
        10: 16.0,
    },
]
timeseries_df = pd.DataFrame(
    np.array(
        [
            default_timeseries,
            just_modified_heat,
            just_modified_elec,
            modified_timeseries,
        ]
    ),
    columns=["p1", "p2"],
)

Normally the evaluator can be called directly with the input values, but if using a dataframe as input df_apply must be used.

result = evaluatorEH.df_apply(timeseries_df)
result
HBox(children=(FloatProgress(value=0.0, description='Executing', max=4.0, style=ProgressStyle(description_widt…
total_cost total_carbon
0 1846.19 33.7551
1 1850.01 33.7190
2 1844.18 44.6054
3 1847.10 44.5693