knitr::opts_chunk$set(
    collapse = TRUE,
    comment = "#>",
    screenshot.force = FALSE,
    fig.align = "center"
)

# the default output hook
hook_output <- knitr::knit_hooks$get("output")
knitr::knit_hooks$set(output = function(x, options) {
    if (!is.null(n <- options$out.lines)) {
        x <- unlist(strsplit(x, "\n", fixed = TRUE))
        if (length(x) > n) {
            # truncate the output
            x <- c(head(x, n), "....", "")
        } else {
            x <- c(x, "")
        }
        x <- paste(x, collapse = "\n") # paste first n lines together
    }
    hook_output(x, options)
})

options(crayon.enabled = FALSE)
options(data.table.print.class = TRUE)

library(eplusr)
if (!is_avail_eplus("22.2")) install_eplus("22.2")

Motivation

EnergyPlus provides a preprocessor call IDFVersionUpdater to update IDF to the latest version. It is written in Fortran and the program itself evolves along with EnergyPlus. Once a new version of EnergyPlus is published, IDFVersionUpdater will add the support of that version.

The original IDFVersionUpdater program is a GUI program and does not provide command line interface. This makes it hard to update lots of IDF files programmatically. The good news is that IDFVersionUpdater itself is a wrapper to call different standalone transition programs for each single version update. For example, when updating your model from EnergyPlus v8.7 to v8.9, Transition-V8-7-0-to-V8-8-0 will be called, and then Transition-V8-8-0-to-V8-9-0.

Introduce version_updater()

version_updater() is eplusr's version of IDFVersionUpdater. version_updater() itself is not complicated. Compared to IDFVersionUpdater, version_updater() has some improvements:

Unfortunately, even though the transition programs are written in Fortran, it could still take several minutes to complete the update process

path <- "RefBldgLargeOfficeNew2004_Chicago.idf"
read_idf(path)$version()

(t_vu <- system.time(verup <- version_updater(path, "23.1")))

Introduce transition()

Having a clear mental model on how the transition works, the most cumbersome work left is to translate all those actions written in Fortran into R and write tests to make sure that the R implement should be the same as IDFVersionUpdater.

transition() is a pure R implementation of transition programs. It takes similar arguments as version_updater() except it has an additional argument save to control whether to save the resultant Idf objects to IDF files or not.

(t_tr <- system.time(trans <- transition(path, "23.1")))

It is about r round(t_vu["elapsed"]/t_tr["elapsed"], 1) times faster.

Fast is always good. The most important thing is to ensure that transition() can provide reasonable results. Here we compare the results.

setdiff(verup$to_string(format = "sorted"), trans$to_string(format = "sorted"))

As we can see from below, there is only one difference between results from transition() and version_updater():

unlink(verup$path())

How the transition works

During version updates, some classes in the original IDF are removed, some classes are splitted into several classes, some fields are removed and there is no way to extract those information back. For example, from EnergyPlus v8.8 to v8.9, one single object in class GroundHeatExchanger:Vertical will be splitted into 4 different objects in class:

A basic transition on a single class is a combination of different transition actions. Below I will describe most typical ones together with the related transition program source code:

The combinations of those four actions together builds a skeleton of an EnergyPlus transition program, together with some pre-processes and post-processes.

In eplusr, all IDF data are stored as data.tables. So transition means to write a function to perform the similar actions on field values stored in data.tables. trans_action() is designed for this purpose.

For example, the equivalent transition implemented in R for Exterior:FuelEquipment objects demonstrated in the Reset code block would be:

# Insert
dt1 <- trans_action(idf, "OtherEquipment", insert = list(2L, "None"))

# Reset
dt2 <- trans_action(idf, "Exterior:FuelEquipment",
    reset = list(2L, "Gas", "NaturalGas"),
    reset = list(2L, "LPG", "PropaneGas")
)

# Delete
dt3 <- trans_action(idf, "HVACTemplate:System:Unitary", delete = list(40L))

# Offset
dt4 <- trans_action(idf, "Daylighting:Controls",
    offset = list(20L, 4L),
    reset = list(3, "SplitFlux")
)

Having the updated IDF data, we can then easily insert them to the next new version of IDF by simply doing new_idf$load(dt).



hongyuanjia/eplusr documentation built on Feb. 14, 2024, 5:38 a.m.