15 Detailed output

15.1 Prerequisites

In this chapter we will focus on how to set and get EnergyPlus simulation outputs using the eplusr package. We will illustrate the manipulation of simulation data using tidyverse, and use ggplot2 to visualize the simulation data

We will be working with the IDF and EPW file that pertains to the U.S. Department of Energy (DOE) Commercial Reference Building and Chicago’s TMY3 respectively.

path_idf <- here("data", "idf", "RefBldgMediumOfficeNew2004_Chicago.idf")
model <- read_idf(path_idf)

path_epw <- here("data", "epw", "USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.epw")
epw <- read_epw(path_epw)

15.2 Variable dictionary reports

The variable dictionary reports are one of the most important outputs when working with EnergyPlus simulations. These reports inform EnergyPlus users the outputs that are available for a specific EnergyPlus simulation. Knowing the outputs that are available in your model would allow users to identify and subsequently specify relevant outputs for further analysis. Two data dictionary reports are produced and they are the meter data dictionary (.mdd) file and the report data dictionary (.rdd) file. The .mdd file lists the names of the output meters while the .rdd file lists the names of the output variables that are available for the simulation. However, you must first run the simulation before the available variables and meters can be known. By setting weather = NULL, a design day simulation will be run, allowing us to obtain the .rdd and .mdd file without running an annual simulation that can be time consuming for complex models.

job <- model$run(weather = NULL, dir = tempdir())
## ExpandObjects Started.
## No expanded file generated.
## ExpandObjects Finished. Time:     0.053
## EnergyPlus Starting
## EnergyPlus, Version 9.4.0-998c4b761e, YMD=2023.03.09 00:28
## Could not find platform independent libraries <prefix>
## Could not find platform dependent libraries <exec_prefix>
## Consider setting $PYTHONHOME to <prefix>[:<exec_prefix>]
## 
## Initializing Response Factors
## Calculating CTFs for "STEEL FRAME NON-RES EXT WALL"
## Calculating CTFs for "IEAD NON-RES ROOF"
## Calculating CTFs for "EXT-SLAB"
## Calculating CTFs for "INT-WALLS"
## Calculating CTFs for "INT-FLOOR-TOPSIDE"
....

You can then retrieve the list of available variables and meters with the function read_rdd() and the read_mdd() function respectively. Both functions return a five column data.table.

mdd <- job$read_mdd()
mdd
## ══ EnergyPlus Meter Data Dictionary File ═══════════════════════════════════════
##   * EnergyPlus version: 9.4.0 (998c4b761e)
##   * Simulation started: 2023-03-09 00:28:00
## 
## ── Details ─────────────────────────────────────────────────────────────────────
##      index reported_time_step report_type
##   1:     1               Zone       Meter
##   2:     2               Zone       Meter
##   3:     3               Zone       Meter
##   4:     4               Zone       Meter
....
rdd <- job$read_rdd()
rdd
## ══ EnergyPlus Report Data Dictionary File ══════════════════════════════════════
##   * EnergyPlus version: 9.4.0 (998c4b761e)
##   * Simulation started: 2023-03-09 00:28:00
## 
## ── Details ─────────────────────────────────────────────────────────────────────
##      index reported_time_step report_type
##   1:     1               Zone     Average
##   2:     2               Zone     Average
##   3:     3               Zone     Average
##   4:     4               Zone     Average
....

To specify an output variable of interest, you can add the name of the variable and the corresponding reporting frequency to the Output:Variable object. To avoid a long list of redundant and unnecessary output variables, you should first remove all of them.

model$Output_Variable <- NULL
model$Output_Meter <- NULL

You can then use the $add() method to add your variable output of interest. The first argument to the $add() method is a list of EnergyPlus object definitions where each list is named with a valid class name. In this case, the relevant EnergyPlus objects for defining output meters (.mdd) and variables (.rdd) are the Output:Meter and the Output:Variable objects respectively.

output_list <- list(
    Output_Variable = list(
        key_value = "*",
        Variable_Name = "Site Outdoor Air Drybulb Temperature",
        Reporting_Frequency = "Hourly"
    ),
    Output_Variable = list(
        key_value = "*",
        Variable_Name = "Zone Mean Air Temperature",
        Reporting_Frequency = "Hourly"
    ),
    Output_Meter = list(
        key_name = "Cooling:Electricity",
        Reporting_Frequency = "Hourly"
    ),
    Output_Meter = list(
        key_name = "Heating:NaturalGas",
        Reporting_Frequency = "Hourly"
    )
)

model$add(output_list)
## $<NA>
## <IdfObject: 'Output:Variable'> [ID:682]
## Class: <Output:Variable>
## ├─ 1 : "*",                !- Key Value
## │─ 2*: "Site Outdoor Air Drybulb Temperature",  !- Variable Name
## └─ 3 : "Hourly";           !- Reporting Frequency
## 
## $<NA>
## <IdfObject: 'Output:Variable'> [ID:683]
## Class: <Output:Variable>
....

The above code to add meters and variables can become unnecessarily long if you are adding multiple objects of the same class (in the above example, the Output:Meter and Output:Variable class. You can take advantage of data.table’s := operator to assign the object name by reference.

variables <- list(
    key_value = "*",
    Variable_Name = c(
        "Site Outdoor Air Drybulb Temperature",
        "Zone Mean Air Temperature"
    ),
    Reporting_Frequency = "Hourly"
)

model$add(Output_Variable := variables)
## $<NA>
## <IdfObject: 'Output:Variable'> [ID:686]
## Class: <Output:Variable>
## ├─ 1 : "*",                !- Key Value
## │─ 2*: "Site Outdoor Air Drybulb Temperature",  !- Variable Name
## └─ 3 : "Hourly";           !- Reporting Frequency
## 
## $<NA>
## <IdfObject: 'Output:Variable'> [ID:687]
## Class: <Output:Variable>
....

Likewise, you can use the $add() method to add your variable meter of interest.

meters <- list(
    key_name = c(
        "Cooling:Electricity",
        "Heating:NaturalGas"
    ),
    Reporting_Frequency = "Hourly"
)

# add meter outputs to get hourly time-series energy consumption
model$add(Output_Meter := meters)
## $<NA>
## <IdfObject: 'Output:Meter'> [ID:688]
## Class: <Output:Meter>
## ├─ 1*: "Cooling:Electricity",  !- Key Name
## └─ 2 : "Hourly";           !- Reporting Frequency
## 
## $<NA>
## <IdfObject: 'Output:Meter'> [ID:689]
## Class: <Output:Meter>
## ├─ 1*: "Heating:NaturalGas",  !- Key Name
....

Here is a useful function preprocess_idf() that you can use to preprocess your EnergyPlus simulations so that it (1) uses the weather file for the simulation, (2) presents energy consumption outputs in kWh, and (3) remove all existing output meters and variables and add the list of meters and variables provided as arguments to the function.

preprocess_idf <- function(idf, meters, variables) {
    # make sure weather file input is respected
    idf$SimulationControl$Run_Simulation_for_Weather_File_Run_Periods <- "Yes"

    # make sure simulation is not run for sizing periods
    idf$SimulationControl$Run_Simulation_for_Sizing_Periods <- "No"

    # make sure energy consumption is presented in kWh
    if (is.null(idf$OutputControl_Table_Style)) {
        idf$add(OutputControl_Table_Style = list("HTML", "JtoKWH"))
    } else {
        idf$OutputControl_Table_Style$Unit_Conversion <- "JtoKWH"
    }

    # remove all existing meter and variable outputs
    if (!is.null(idf$`Output:Meter`)) {
        idf$Output_Meter <- NULL
    }

    # remove all existing meter and variable outputs
    if (!is.null(idf$`Output:Table:Monthly`)) {
        idf$`Output:Table:Monthly` <- NULL
    }

    if (!is.null(idf$`Output:Variable`)) {
        idf$Output_Variable <- NULL
    }

    # add meter outputs to get hourly time-series energy consumption
    idf$add(Output_Meter := meters)

    # add variable outputs to get hourly zone air temperature
    idf$add(Output_Variable := variables)

    # make sure the modified model is returned
    return(idf)
}

The following code demonstrates the use of the function preprocess_idf().

meters <- list(
    key_name = c(
        "Cooling:Electricity",
        "Heating:NaturalGas",
        "Heating:Electricity",
        "InteriorLights:Electricity",
        "ExteriorLights:Electricity",
        "InteriorEquipment:Electricity",
        "Fans:Electricity",
        "Pumps:Electricity",
        "WaterSystems:NaturalGas"
    ),
    Reporting_Frequency = "Hourly"
)

variables <- list(
    key_value = "*",
    Variable_Name = c(
        "Site Outdoor Air Drybulb Temperature",
        "Site Outdoor Air Relative Humidity"
    ),
    Reporting_Frequency = "Hourly"
)

model <- preprocess_idf(model, meters, variables)

Check if the output variables and meters have been correctly added

model$Output_Variable
## $<NA>
## <IdfObject: 'Output:Variable'> [ID:691]
## Class: <Output:Variable>
## ├─ 1 : "*",                !- Key Value
## │─ 2*: "Site Outdoor Air Drybulb Temperature",  !- Variable Name
## └─ 3 : "Hourly";           !- Reporting Frequency
## 
## $<NA>
## <IdfObject: 'Output:Variable'> [ID:692]
## Class: <Output:Variable>
....
model$Output_Meter
## $<NA>
## <IdfObject: 'Output:Meter'> [ID:682]
## Class: <Output:Meter>
## ├─ 1*: "Cooling:Electricity",  !- Key Name
## └─ 2 : "Hourly";           !- Reporting Frequency
## 
## $<NA>
## <IdfObject: 'Output:Meter'> [ID:683]
## Class: <Output:Meter>
## ├─ 1*: "Heating:NaturalGas",  !- Key Name
....

Before you can explore the outputs, you have to first save the model and run the simulation.

model$save(here("data", "idf", "model_preprocessed.idf"), overwrite = TRUE)
## Replace the existing IDF located at /home/runner/work/r4bes/r4bes/data/idf/model_preprocessed.idf.
job <- model$run(epw, dir = tempdir())
## ExpandObjects Started.
## No expanded file generated.
## ExpandObjects Finished. Time:     0.051
## EnergyPlus Starting
## EnergyPlus, Version 9.4.0-998c4b761e, YMD=2023.03.09 00:28
## Could not find platform independent libraries <prefix>
## Could not find platform dependent libraries <exec_prefix>
## Consider setting $PYTHONHOME to <prefix>[:<exec_prefix>]
## 
## Initializing Response Factors
## Calculating CTFs for "STEEL FRAME NON-RES EXT WALL"
## Calculating CTFs for "IEAD NON-RES ROOF"
## Calculating CTFs for "EXT-SLAB"
## Calculating CTFs for "INT-WALLS"
## Calculating CTFs for "INT-FLOOR-TOPSIDE"
....

You will then be able to extract the output variables and meters that have just been specified.

report <- job$report_data(
        name = c(variables$Variable_Name, meters$key_name),
        environment_name = "annual"
    ) %>%
    select(datetime, name, value) %>%
    pivot_wider(names_from = name, values_from = value)

head(report)
## # A tibble: 6 × 12
##   datetime            `Site Outdoor Air Dryb…` `Site Outdoor …` `InteriorLight…`
##   <dttm>                                 <dbl>            <dbl>            <dbl>
## 1 2017-01-01 01:00:00                    -7.82             72.6         9649498.
## 2 2017-01-01 02:00:00                   -11.9              73           9649498.
## 3 2017-01-01 03:00:00                   -11.4              73           9649498.
## 4 2017-01-01 04:00:00                   -11.1              73           9649498.
## 5 2017-01-01 05:00:00                   -10.8              73           9649498.
## 6 2017-01-01 06:00:00                   -10.6              73           9649498.
## # … with 8 more variables: `InteriorEquipment:Electricity` <dbl>,
....

15.3 mtd file

You can also look at the mtd file to know what report variables are on which meters and vice versa