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

# 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("23.1")) install_eplus("23.1")

The Schedule:Compact class

Schedule:Compact class is quite commonly used in EnergyPlus models. Unlike other classes in EnergyPlus, it is quite flexible in value specifications and does not follow the usual definitions for fields. Starting from Field 1, the number of fields and positions are not set, and cannot really be described in the usual Field # manner.

path_idf <- path_eplus_example("23.1", "1ZoneUncontrolled.idf")
idf <- read_idf(path_idf)
idf$definition("Schedule:Compact")

Thus, starting from the 3rd field, all fields in Schedule:Compact class are tagged as "alpha" (string) in IDD.

unique(idf$definition("Schedule:Compact")$field_type()[-(1:2)])

This makes it hard to add, modify, extract and validate schedule values solely based its definitions. For example, an empty Schedule:Compact object is still "valid", even through it does not contain any schedule data.

sch <- idf$add(Schedule_Compact = list("sch"))[[1L]]
sch

sch$validate()

Wrong schedule specifications cannot directly be caught by IdfObject$validate() since all fields are treated as arbitrary strings.

sch$set(..3 = "Through: -1")

sch$validate()

Moreover, every field value should be given as a string, even for schedule values.

sch$set(..3 = "Through: 12/31", ..4 = "For: AllDays", ..5 = "Until: 24:00", ..6 = 1.0)

As a result, the output from $value() and $to_table() method is not very useful.

sch$set(..3 = "Through: 12/31", ..4 = "For: AllDays", ..5 = "Until: 24:00", ..6 = "1.0")

sch$value()

print(sch$to_table())

Introduce the IdfScheduleCompact class

In order to solve this inconvenience, eplusr introduces a new IdfScheduleCompact class which is designed to ease the processing of Schedule:Compact objects. A short description of the core methods is given below.

| Method | Functionality | | :--- | :--- | | $type_limits() | Get or set schedule type limit | | $set() | Modify schedule values using list input | | $update() | Modify schedule values using data.frame input | | $validate() | Check any errors in the schedule | | $is_valid() | Check if no error exists in the schedule | | $extract() | Extract schedule values in a data.table |

Table: Core methods of IdfScheduleCompact class

Note that IdfScheduleCompact class inherits IdfObject class, which means that methods available for an IdfObject object are still available for an IdfScheduleCompact object.

Create an IdfScheduleCompact object

To create an IdfScheduleCompact object from an existing Schedule:Compact object, you can use the schedule_compact() constructor.

schedule_compact(parent = idf, name = "sch")

To directly create a new Schedule:Compact object in the parent Idf, set new to TRUE.

sch <- schedule_compact(idf, "sch1", new = TRUE)
print(sch)

Get type limits

$type_limits() is used to get the type limits of a schedule. It will be used to validate the schedule values to make sure they do not exceed the range specified. $type_limits() gives NULL if no type limits have been set yet.

(sch$type_limits())

To set the type limits, direct give the name of an existing ScheduleTypeLimits object.

idf$object_name("ScheduleTypeLimits")

sch$type_limits("fraction")

Set schedule values using lists

The $set() method provides a flexible interface to modify schedule values using lists:

Please note that currently $set() does not support specifying the Through: fields and Interpolate: fields. All schedules will be applied for all days in a year (.i.e. Through: 12/31). For detailed modifications, please use $update() method which will be described later. For now, neither $set() nor $update() supports interpolation specifications. Interpolate: No is assumed for all input. However, IdfScheduleCompact does support other Interpolate option when parsing and data extraction using $extract().

sch$set(c("weekday", "summerdesignday") := list(
    ..6 = 0.2, "8:00" = 0.5,
    ..12 = 0.95, "13:30" = 0.6, ..14 = 0.8,
    ..18 = 0.95, ..19 = 0.2, ..24 = 0),
    allotherday = list(..24 = 0),
    .check_range = FALSE
)

If schedule type limit is set, you can set .check_range to TRUE to validate schedule values during modification.

sch$set(allday = list(..24 = 2), .check_range = TRUE)

You can also use $validate() and $is_valid() method to check existing schedule values.

sch$validate()

sch$is_valid()

Set schedule values using data.frame

The $update() method takes a data.frame and modify schedule values accordingly. It is designed to work together with $extract() method which will be described later. The input data.frame of $upate() should contain at least 4 columns:

val1 <- data.table::data.table(year_day = "12/31",
    daytype = "weekday, summerdesignday",
    time = c("6:00", "7:00", "8:00", "12:00", "13:30", "14:00", "18:00", "19:00", "24:00"),
    value = c(0.2,    0.5,    0.5,    0.95,    0.6,     0.8,     0.95,    0.2,     0.0)
)
val2 <- data.table::data.table(year_day = "12/31", daytype = "allotherday", time = "24:00", value = 0.0)
val <- data.table::rbindlist(list(val1, val2))
val

sch$update(val, check_range = TRUE)

Extract schedule values into a data.table

Most of the time, we will be dealing with existing schedules instead of creating new ones from scratch. It would be quite handy if we could extract schedule data of given day types and time step. The $extract() is designed for this. It extracts schedule data into a data.table with 5 columns:

print(sch$extract())

By default, grouped day types are concatenated together using ,. The compacted day types, e.g. Weekday and AllOtherDay are kept. If you want to expand all possible day types, set daytype to TRUE or "expand". This becomes handy when you want to specifically extract data of a certain day type.

We can see from the following table that all 12 day types are extracted, with the id column showing their original group.

print(sch$extract(daytype = TRUE))
# OR sch$extract(daytype = "expand")

Compact or expand day types

If you want to compact day types with same schedule values, set daytype to FALSE or "compact". It will try to group weekdays into Weekday, weekends into Weekend, and put all CustomDay1, CustomDay2 and Holiday into AllOtherDay, if possible. This is because, for most of the time, Weekday, Weekend, design days including SummerDesignDay and WinterDesignDay are the most commonly used day types. Please note that if it is not possible to compact those day types, for instance, schedules of Monday and Friday are different, the original day types are kept and no compact day types will be made.

For this specific schedule, we can see from the following table that the original AllOtherDay has been divided into 3, i.e. Weekend, WinterDesignDay and AllOtherDay.

print(sch$extract(daytype = FALSE))
# OR sch$extract(daytype = "compact")

If you want to specify your own grouped day types, you can directly pass a character vector to daytype. All other days except specified ones will be classified into AllOtherDay, if possible.

Let's say we want to compact the weekdays, but keep the weekends separately. We can achieve it by:

print(sch$extract(c("weekday", "saturday", "sunday")))

Compact or expand schedule times

It is convenient to specify schedule values only at times when they change. However, it is useful to get schedule values at a given time step, e.g. 1-hour, especially when we try to visualize the schedule values.

You can achieve this by passing a time step specification to timestep.

print(sch$extract(timestep = "3 hour"))

print(sch$extract(timestep = "1 hour"))

As described above, the time column is a hms vector. It is handy for plotting since hms object is directly supported by the scale system of ggplot2 package.

library(ggplot2)

ggplot(sch$extract(FALSE, "1 hour")) +
    geom_col(aes(time, value, fill = daytype), color = "black") +
    facet_wrap(~daytype)

If your schedule contains multiple time periods that have the same schedule value, you can compact the schedule times and values by setting timestep to "auto".

For this example, time periods 06:00 -- 07:00 and 07:00 -- 08:00 have the same schedule value (0.5). The following table has compact these 2 time periods together into one (06:00 -- 08:00).

print(sch$extract(timestep = "auto"))


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