Nothing
# CLASS_DEL_COMMON {{{
CLASS_DEL_COMMON <- c(
"PROGRAMCONTROL",
"SKY RADIANCE DISTRIBUTION",
"AIRFLOW MODEL",
"GENERATOR:FC:BATTERY DATA",
"AIRFLOWNETWORK:MULTIZONE:SITEWINDCONDITIONS",
"WATER HEATER:SIMPLE"
)
# }}}
#' Perform version transition of EnergyPlus model
#'
#' `transition()` takes an [Idf] object or a path of IDF file and a target
#' version, performs version transitions and returns an [Idf] object of
#' specified version.
#'
#' @param idf An [Idf] object or a path of IDF file.
#' @param ver A valid EnergyPlus IDD version, e.g. `"9"`, `"8.8"`, or `"8.8.0"`.
#' @param save If `TRUE`, the models will be saved into specified directory.
#' Default: `FALSE`.
#' @param dir Only applicable when `save` is `TRUE`. The directory to save the
#' new IDF files. If the directory does not exist, it will be created before
#' save. If `NULL`, the directory of input [Idf] object or IDF file will be
#' used. Default: `NULL`.
#' @param keep_all If `TRUE`, a list will be return which contains all
#' [Idf] objects of intermediate versions. The list will be named using first
#' two number of that version, e.g. `8.1`, `8.2`. If `FALSE`, only the [Idf]
#' object of the version specified by `ver` will be returned. Default: `FALSE`.
#' @return An [Idf] object if `keep_all` is `FALSE` or a list of [Idf] objects
#' if `keep_all` is `TRUE`.
#' @seealso See [version_updater()] which directly call EnergyPlus preprocessor
#' `IDFVersionUpdater` to perform the version transitions.
#' @author Hongyuan Jia
#' @examples
#' \dontrun{
#' if (any(avail_eplus()) > "7.2") {
#' # create an empty IDF
#' idf <- empty_idf("7.2")
#'
#' # convert it from v7.2 to the latest EnergyPlus installed
#' transition(idf, max(avail_eplus()))
#'
#' # convert it from v7.2 to the latest EnergyPlus installed and keep all
#' # intermediate versions
#' transition(idf, max(avail_eplus()), keep_all = TRUE)
#'
#' # convert it from v7.2 to the latest EnergyPlus installed and keep all
#' # intermediate versions and save all them
#' idf$save(tempfile(fileext = ".idf"))
#' transition(idf, max(avail_eplus()), keep_all = TRUE,
#' save = TRUE, dir = tempdir()
#' )
#' }
#' }
#' @export
# transition {{{
#' @importFrom checkmate assert_vector
# TODO: how to give the names of saved files
transition <- function(idf, ver, keep_all = FALSE, save = FALSE, dir = NULL) {
if (!is_idf(idf)) idf <- read_idf(idf)
if (length(ver) != 1L || is.na(ver <- convert_to_idd_ver(ver))) {
abort("'ver' must be a valid EnergyPlus IDD version")
}
ver <- ver[, 1:2]
if (idf$version() < "7.2") {
abort(paste0("Input IDF has version ", surround(idf$version()), ". ",
"Currently only EnergyPlus v7.2 and above are suppored."
))
}
# only compare Major and Mversioninor version, skip patch version
if (idf$version()[, 1L:2L] == ver) {
verbose_info("IDF is already at latest version ", ver, ". No transition is needed.")
if (keep_all) {
res <- list(idf)
setattr(res, "names", as.character(idf$version()[, 1L:2L]))
return(res)
} else {
return(idf)
}
# cannot go reverse
} else if (idf$version()[, 1L:2L] > ver) {
abort("Only version updating is supported. Downgrading is not supported.")
}
# stop if unsaved
if (idf$is_unsaved()) {
abort("Idf has been modified since read or last saved. Please save Idf using '$save()' before transition.")
}
# clone original input
idf <- idf$clone(TRUE)
# perform transition
res <- trans_apply(idf, ver, keep_all)
# directly return if no saving is required
if (!save) return(res)
# check if original file exists
if (is.null(idf$path())) {
abort("The Idf object is not created from local file. Please save Idf using '$save()' before transition.", "idf_not_local")
}
if (is.null(dir)) {
dir <- dirname(idf$path())
} else if (!dir.exists(dir)) {
dir.create(dir, recursive = TRUE)
}
save_new <- function(idf, dir, path) {
nm <- paste0(tools::file_path_sans_ext(basename(path)), "V", idf$version()[, 1L], idf$version()[, 2L], "0.idf")
idf$save(file.path(dir, nm), overwrite = TRUE)
}
if (!keep_all) {
save_new(res, dir, path = idf$path())
} else {
lapply(res, save_new, dir = dir, path = idf$path())
}
res
}
# }}}
# trans_apply {{{
trans_apply <- function(idf, ver, keep_all) {
# get all versions needed to handle
vers <- trans_upper_versions(idf, ver)
# get corresponding transition function names
funs <- trans_fun_names(vers)
# apply transition functions
if (!keep_all) {
for (i in seq_along(funs)) {
verbose_info(
" From Ver: ", vers[i], "\n",
"Toward Ver: ", vers[i + 1L]
)
idf <- without_checking(trans_funs[[funs[i]]](idf))
verbose_info("[", vers[i], " --> ", vers[i + 1L], "] SUCCEEDED.\n")
}
idf
} else {
res <- vector("list", length(funs) + 1L)
res[[1L]] <- idf
for (i in seq_along(res)) {
if (i == length(res)) break
verbose_info(
" From Ver: ", vers[i], "\n",
"Toward Ver: ", vers[i + 1L]
)
res[[i + 1L]] <- without_checking(trans_funs[[funs[[i]]]](res[[i]]))
verbose_info("[", vers[i], " --> ", vers[i + 1L], "] SUCCEEDED.\n")
}
nms <- paste0(stri_sub(funs, 6L, 6L), ".", stri_sub(funs, 7L, 7L))
setattr(res, "names", c(as.character(idf$version()[, 1L:2L]), nms))
res
}
}
# }}}
trans_funs <- new.env(parent = emptyenv())
# trans_720_800 {{{
#' @importFrom checkmate assert_true
trans_funs$f720t800 <- function(idf) {
assert_true(idf$version()[, 1:2] == "7.2")
target_cls <- c(
"ShadowCalculation", # 1
"Coil:Heating:DX:MultiSpeed", # 2
"EnergyManagementSystem:OutputVariable", # 3
"EnergyManagementSystem:MeteredOutputVariable", # 4
"Branch", # 5
"PlantEquipmentList", # 6
"CondenserEquipmentList", # 7
"HeatExchanger:WatersideEconomizer", # 8
"HeatExchanger:Hydronic", # 9
"HeatExchanger:Plate", # 10
"BuildingSurface:Detailed", # 11
"Wall:Detailed", # 12
"RoofCeiling:Detailed", # 13
"Floor:Detailed", # 14
"FenestrationSurface:Detailed", # 15
"Shading:Site:Detailed", # 16
"Shading:Building:Detailed", # 17
"Shading:Zone:Detailed", # 18
"AirflowNetwork:Distribution:Component:ConstantVolumeFan", # 19
"ZoneHVAC:HighTemperatureRadiant", # 20
"AirConditioner:VariableRefrigerantFlow", # 21
"ZoneHVAC:WaterToAirHeatPump", # 22
"AirLoopHVAC:UnitaryHeatPump:WaterToAir", # 23
"Boiler:HotWater", # 24
"Chiller:Electric", # 25
"Chiller:ConstantCOP", # 26
"Chiller:EngineDriven", # 27
"Chiller:CombustionTurbine", # 28
"Chiller:Electric:EIR", # 29
"Chiller:Electric:ReformulatedEIR", # 30
"Chiller:Absorption", # 31
"Chiller:Absorption:Indirect" # 32
)
new_idf <- trans_preprocess(idf, "8.0", target_cls)
# 1: ShadowCalculation {{{
dt1 <- trans_action(idf, "ShadowCalculation", insert = list(1L, "AverageOverDaysInFrequency"))
# }}}
# 2: Coil:Heating:DX:MultiSpeed {{{
dt2 <- trans_action(idf, class = "Coil:Heating:DX:MultiSpeed",
insert = list(6L),
insert = list(17L),
insert = list(22L),
insert = list(33L),
insert = list(44L),
insert = list(55L)
)
# }}}
# 3: EnergyManagementSystem:OutputVariable {{{
dt3 <- trans_action(idf, "EnergyManagementSystem:OutputVariable", add = list(6L))
if (nrow(dt3)) {
# add unit if applicable
units <- dt3[J(1L), on = "index"][, c("value", "unit") := {
as.data.table(stri_match_first_regex(value, "^(.+)\\s+\\[(.*)\\]$"))[, 2:3]
}][!is.na(value)]
# update key value
dt3[units, on = c("id", "index"), value := i.value]
# update unit
set(units, NULL, "index", 6L)
dt3[units, on = c("id", "index"), value := i.unit]
}
# }}}
# 4: EnergyManagementSystem:MeteredOutputVariable {{{
dt4 <- trans_action(idf, "EnergyManagementSystem:MeteredOutputVariable", add = list(9L))
if (nrow(dt4)) {
# add unit if applicable
units <- dt4[J(1L), on = "index"][, c("value", "unit") := {
as.data.table(stri_match_first_regex(value, "^(.+)\\s+\\[(.*)\\]$"))[, 2:3]
}][!is.na(value)]
# update key value
dt4[units, on = c("id", "index"), value := i.value]
# update unit
set(units, NULL, "index", 9L)
dt4[units, on = c("id", "index"), value := i.unit]
}
# }}}
# 5: Branch {{{
dt5 <- trans_action(idf, "Branch")
if (nrow(dt5)) {
dt5[(index - 4L) %% 5L == 0L & stri_trans_tolower(value) %in% paste0("heatexchanger:", c("watersideeconomizer", "hydronic", "plate")),
value := "HeatExchanger:FluidToFluid"]
}
# }}}
# 6: PlantEquipmentList {{{
dt6 <- trans_action(idf, "PlantEquipmentList")
if (nrow(dt6)) {
dt6[(index - 2L) %% 2L == 0L & stri_trans_tolower(value) %in% paste0("heatexchanger:", c("watersideeconomizer", "hydronic", "plate")),
value := "HeatExchanger:FluidToFluid"]
}
# }}}
# 7: CondenserEquipmentList {{{
dt7 <- trans_action(idf, "CondenserEquipmentList")
if (nrow(dt7)) {
dt7[(index - 2L) %% 2L == 0L & stri_trans_tolower(value) %in% paste0("heatexchanger:", c("watersideeconomizer", "hydronic", "plate")),
value := "HeatExchanger:FluidToFluid"]
}
# }}}
# 8: HeatExchanger:WatersideEconomizer {{{
dt8 <- trans_action(idf, c("HeatExchanger:FluidToFluid" = "HeatExchanger:WatersideEconomizer"), all = TRUE,
offset = list(
c(3L, 6L, 7L, 9L, 4L, 5L, 8L, 2L),
c(2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L)
),
reset = list(9L, "PlateFrame", "CrossFlowBothUnMixed"),
insert = list(11L, "CoolingDifferentialOnOff"),
insert = list(12L),
add = list(14L, "FreeCooling")
)
# }}}
# 9: HeatExchanger:Hydronic {{{
dt9 <- trans_action(idf, c("HeatExchanger:FluidToFluid" = "HeatExchanger:Hydronic"), all = TRUE,
delete = list(18L),
offset = list(
c(5L, 6L, 13L, 7L, 8L, 14L, 11L, 12L, 17L, 15L, 9L),
c(3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 15L, 16L, 17L)
),
reset = list(2L, NA_character_),
reset = list(9L, "UFactorTimesAreaEffectiveness", "CrossFlowBothUnMixed"),
add = list(11L, "CoolingSetpointOnOffWithComponentOverride"),
add = list(12L),
add = list(13L, "0.0"),
add = list(14L, "FreeCooling")
)
if (nrow(dt9)) {
dt9[, value := {value[12L] <- value[7L]; value}, by = "id"]
# create corresponding SetpointManager:Schedule objects
dt9_spm <- trans_action(idf, c("SetpointManager:Scheduled" = "HeatExchanger:Hydronic"), min_fields = 8L)[
J(c(1L, 2L, 4L, 8L)), on = "index"]
dt9_spm[J(1L), on = "index", value := {
if (any(!is.na(value))) {
value[!is.na(value)] <- paste0(value[!is.na(value)], " Setpoint Manager")
}
value
}]
dt9_spm[J(2L), on = "index", value := "Temperature"]
dt9_spm[, index := seq_len(.N), by = "id"]
new_idf$load(dt9_spm, .unique = FALSE, .default = FALSE)
}
# }}}
# 10: HeatExchanger:Plate {{{
dt10 <- trans_action(idf, c("HeatExchanger:FluidToFluid" = "HeatExchanger:Plate"), all = TRUE,
offset = list(
c(4L, 5L, 10L, 11L, 8L, 9L),
c(3L, 4L, 5L, 8L, 9L, 10L)
),
reset = list(2L, NA_character_),
reset = list(9L, "UFactorTimesAreaEffectiveness", "CrossFlowBothUnMixed"),
add = list(11L, "UncontrolledOn"),
add = list(12L:13L),
add = list(14L, "LoopToLoop"),
add = list(15L:17L)
)
# }}}
# standardize_vertices {{{
standardize_vertices <- function(idf, class, start) {
dt <- trans_action(idf, class)
if (nrow(dt)) dt[index >= start & is.na(value), value := "0.0"]
dt
}
# }}}
# 11: BuildingSurface:Detailed {{{
dt11 <- standardize_vertices(idf, "BuildingSurface:Detailed", 11L)
# }}}
# 12: Wall:Detailed {{{
dt12 <- standardize_vertices(idf, "Wall:Detailed", 10L)
# }}}
# 13: RoofCeiling:Detailed {{{
dt13 <- standardize_vertices(idf, "RoofCeiling:Detailed", 10L)
# }}}
# 14: Floor:Detailed {{{
dt14 <- standardize_vertices(idf, "Floor:Detailed", 10L)
# }}}
# 15: FenestrationSurface:Detailed {{{
dt15 <- standardize_vertices(idf, "FenestrationSurface:Detailed", 11L)
# }}}
# 16: Shading:Site:Detailed {{{
dt16 <- standardize_vertices(idf, "Shading:Site:Detailed", 4L)
# }}}
# 17: Shading:Building:Detailed {{{
dt17 <- standardize_vertices(idf, "Shading:Building:Detailed", 4L)
# }}}
# 18: Shading:Zone:Detailed {{{
dt18 <- standardize_vertices(idf, "Shading:Zone:Detailed", 5L)
# }}}
# 19: AirflowNetwork:Distribution:Component:ConstantVolumeFan {{{
dt19 <- trans_action(idf, c("AirflowNetwork:Distribution:Component:Fan" = "AirflowNetwork:Distribution:Component:ConstantVolumeFan"))
# }}}
# 20: ZoneHVAC:HighTemperatureRadiant {{{
dt20 <- trans_action(idf, "ZoneHVAC:HighTemperatureRadiant",
reset = list(5L, "electric", "Electricity"),
reset = list(5L, "gas", "NaturalGas")
)
# }}}
# 21: AirConditioner:VariableRefrigerantFlow {{{
dt21 <- trans_action(idf, "AirConditioner:VariableRefrigerantFlow",
reset = list(67L, "electric", "Electricity")
)
# }}}
# warning_reset {{{
warning_reset <- function(idf, class, index = NULL, old = NULL, new = NULL) {
if (is.null(index)) return(trans_action(idf, class))
dt <- trans_action(idf, class, reset = list(index, old, new))
if (nrow(dt)) {
warn(paste0("Default values for some fields in class ", surround(class),
" have been changed from v7.2 to v8.0. ",
"Results may be different than previous. ",
"See InputOutputReference document for details."
),
"trans_720_800"
)
}
dt
}
# }}}
# 22: ZoneHVAC:WaterToAirHeatPump {{{
dt22 <- warning_reset(idf, "ZoneHVAC:WaterToAirHeatPump")
# }}}
# 23: AirLoopHVAC:UnitaryHeatPump:WaterToAir {{{
dt23 <- warning_reset(idf, "AirLoopHVAC:UnitaryHeatPump:WaterToAir")
# }}}
# 24: Boiler:HotWater {{{
dt24 <- warning_reset(idf, "Boiler:HotWater", 15L, "VariableFlow", "LeavingSetpointModulated")
# }}}
# 25: Chiller:Electric {{{
dt25 <- warning_reset(idf, "Chiller:Electric", 27L, "VariableFlow", "LeavingSetpointModulated")
# }}}
# 26: Chiller:ConstantCOP {{{
dt26 <- warning_reset(idf, "Chiller:ConstantCOP", 11L, "VariableFlow", "LeavingSetpointModulated")
# }}}
# 27: Chiller:EngineDriven {{{
dt27 <- warning_reset(idf, "Chiller:EngineDriven", 41L, "VariableFlow", "LeavingSetpointModulated")
# }}}
# 28: Chiller:CombustionTurbine {{{
dt28 <- warning_reset(idf, "Chiller:CombustionTurbine", 54L, "VariableFlow", "LeavingSetpointModulated")
# }}}
# 29: Chiller:Electric:EIR {{{
dt29 <- warning_reset(idf, "Chiller:Electric:EIR", 23L, "VariableFlow", "LeavingSetpointModulated")
# }}}
# 30: Chiller:Electric:ReformulatedEIR {{{
dt30 <- warning_reset(idf, "Chiller:Electric:ReformulatedEIR", 21L, "VariableFlow", "LeavingSetpointModulated")
# }}}
# 31: Chiller:Absorption {{{
dt31 <- warning_reset(idf, "Chiller:Absorption", 23L, "VariableFlow", "LeavingSetpointModulated")
# }}}
# 32: Chiller:Absorption:Indirect {{{
dt32 <- warning_reset(idf, "Chiller:Absorption:Indirect", 16L, "VariableFlow", "LeavingSetpointModulated")
# }}}
trans_process(new_idf, idf, rbindlist(mget(paste0("dt", 1:32))))
trans_postprocess(new_idf, idf$version(), new_idf$version())
}
# }}}
# trans_800_810 {{{
#' @importFrom checkmate assert_true
trans_funs$f800t810 <- function(idf) {
assert_true(idf$version()[, 1:2] == "8.0")
target_cls <- c(
"People", # 1
"CoolingTower:SingleSpeed", # 2
"CoolingTower:TwoSpeed", # 3
"EvaporativeFluidCooler:SingleSpeed", # 4
"EvaporativeFluidCooler:TwoSpeed", # 5
"FluidCooler:TwoSpeed", # 6
"HeatPump:WaterToWater:EquationFit:Heating", # 7
"HeatPump:WaterToWater:EquationFit:Cooling", # 8
"HeatPump:WaterToWater:ParameterEstimation:Heating", # 9
"HeatPump:WaterToWater:ParameterEstimation:Cooling", # 10
"HVACTemplate:Zone:PTAC", # 11
"HVACTemplate:Zone:PTHP", # 12
"HVACTemplate:Zone:WaterToAirHeatPump", # 13
"HVACTemplate:System:Unitary", # 14
"HVACTemplate:System:UnitaryHeatPump:AirToAir" # 15
)
new_idf <- trans_preprocess(idf, "8.1", target_cls)
# 1: People {{{
dt1 <- trans_action(idf, "People",
insert = list(16L, "ClothingInsulationSchedule"),
insert = list(17L)
)
# }}}
# 2: CoolingTower:SingleSpeed {{{
dt2 <- trans_action(idf, class = "CoolingTower:SingleSpeed", min_fields = 12L,
reset = list(8L, "autosize", "Autocalculate"),
insert = list(9L),
reset = list(10L, "autosize", "Autocalculate"),
insert = list(11L),
insert = list(13L),
insert = list(16L)
)
# }}}
# 3: CoolingTower:TwoSpeed {{{
dt3 <- trans_action(idf, "CoolingTower:TwoSpeed", min_fields = 16L,
reset = list(8L, "autosize", "Autocalculate"),
insert = list(9L),
reset = list(10L, "autosize", "Autocalculate"),
insert = list(11L),
insert = list(13L),
reset = list(14L, "autosize", "Autocalculate"),
insert = list(15L),
reset = list(16L, "autosize", "Autocalculate"),
insert = list(17L),
insert = list(19L),
insert = list(22L),
insert = list(24L)
)
# }}}
# 4: EvaporativeFluidCooler:SingleSpeed {{{
dt4 <- trans_action(idf, "EvaporativeFluidCooler:SingleSpeed", min_fields = 9L,
insert = list(9L)
)
# }}}
# 5: EvaporativeFluidCooler:TwoSpeed {{{
dt5 <- trans_action(idf, "EvaporativeFluidCooler:TwoSpeed", min_fields = 17L,
reset = list(6L, "autosize", "Autocalculate"),
insert = list(7L),
reset = list(8L, "autosize", "Autocalculate"),
insert = list(9L),
insert = list(13L),
insert = list(16L),
reset = list(18L, "autosize", "Autocalculate"),
insert = list(19L),
insert = list(23L)
)
# }}}
# 6: FluidCooler:TwoSpeed {{{
dt6 <- trans_action(idf, "FluidCooler:TwoSpeed", min_fields = 16L,
reset = list(6L, "autosize", "Autocalculate"),
insert = list(7L),
insert = list(10L),
reset = list(17L, "autosize", "Autocalculate"),
insert = list(18L),
reset = list(19L, "autosize", "Autocalculate"),
insert = list(20L)
)
# }}}
# 7: HeatPump:WaterToWater:EquationFit:Heating {{{
dt7 <- trans_action(idf, "HeatPump:WaterToWater:EquationFit:Heating", min_fields = 19L,
delete = list(20L)
)
# }}}
# 8: HeatPump:WaterToWater:EquationFit:Cooling {{{
dt8 <- trans_action(idf, "HeatPump:WaterToWater:EquationFit:Cooling", min_fields = 19L,
delete = list(20L)
)
# }}}
# 9: HeatPump:WaterToWater:ParameterEstimation:Heating {{{
dt9 <- trans_action(idf, "HeatPump:WaterToWater:ParameterEstimation:Heating", min_fields = 20L,
delete = list(23L)
)
# }}}
# 10: HeatPump:WaterToWater:ParameterEstimation:Cooling {{{
dt10 <- trans_action(idf, "HeatPump:WaterToWater:ParameterEstimation:Cooling", min_fields = 20L,
delete = list(23L)
)
# }}}
# Add `Any Number` ScheduleTypeLimits {{{
if (any(idf$is_valid_class(c(
"HVACTemplate:Zone:PTAC", "HVACTemplate:Zone:PTHP",
"HVACTemplate:Zone:WaterToAirHeatPump", "HVACTemplate:System:Unitary",
"HVACTemplate:System:UnitaryHeatPump:AirToAir"
)))) {
# check if there are any `Any Number` ScheduleTypeLimits objects
if (idf$is_valid_class("ScheduleTypeLimits")) {
nm_schtype <- idf$object_name(class = "ScheduleTypeLimits", simplify = TRUE)
if (!any(stri_trans_tolower(nm_schtype) == "any number")) {
new_idf$add(ScheduleTypeLimits = list("Any Number"))
}
} else {
new_idf$add(ScheduleTypeLimits = list("Any Number"))
}
}
# }}}
# update_hvactemplate_fan {{{
update_hvactemplate_fan <- function(new_idf, idf, class, min_fields) {
dt <- trans_action(idf, class = class, min_fields = min_fields)
if (!nrow(dt)) return(dt)
dt[, value := {
if (!is.na(value[min_fields])) {
if (stri_trans_tolower(value[min_fields]) == "cycling") {
sch <- "CyclingFanSchedule"
len <- 100L - nchar(paste0(class[[1L]], sch)) - 1L
nm <- stri_sub(value[1L], to = len)
if (is.na(nm)) nm <- ""
value[min_fields] <- paste0(class[[1L]], nm, sch)
new_idf$add(`Schedule:Constant` = list(value[[min_fields]], "Any Number", 0))
} else if (stri_trans_tolower(value[min_fields]) == "continuous") {
sch <- "ContinuousFanSchedule"
len <- 100L - nchar(paste0(class[[1L]], sch)) - 1L
nm <- stri_sub(value[1L], to = len)
if (is.na(nm)) nm <- ""
value[min_fields] <- paste0(class[[1L]], nm, sch)
new_idf$add(`Schedule:Constant` = list(value[[min_fields]], "Any Number", 1))
}
}
value
}, by = "id"]
dt
}
# }}}
# 11: HVACTemplate:Zone:PTAC {{{
dt11 <- update_hvactemplate_fan(new_idf, idf, "HVACTemplate:Zone:PTAC", min_fields = 13L)
# }}}
# 12: HVACTemplate:Zone:PTHP {{{
dt12 <- update_hvactemplate_fan(new_idf, idf, "HVACTemplate:Zone:PTHP", min_fields = 13L)
# }}}
# 13: HVACTemplate:Zone:WaterToAirHeatPump {{{
dt13 <- update_hvactemplate_fan(new_idf, idf, "HVACTemplate:Zone:WaterToAirHeatPump", min_fields = 13L)
# }}}
# 14: HVACTemplate:System:Unitary {{{
dt14 <- update_hvactemplate_fan(new_idf, idf, "HVACTemplate:System:Unitary", min_fields = 5L)
# }}}
# 15: HVACTemplate:System:UnitaryHeatPump:AirToAir {{{
dt15 <- update_hvactemplate_fan(new_idf, idf, "HVACTemplate:System:UnitaryHeatPump:AirToAir", min_fields = 7L)
# }}}
trans_process(new_idf, idf, rbindlist(mget(paste0("dt", 1:15))))
trans_postprocess(new_idf, idf$version(), new_idf$version())
}
# }}}
# trans_810_820 {{{
#' @importFrom checkmate assert_true
trans_funs$f810t820 <- function(idf) {
assert_true(idf$version()[, 1:2] == "8.1")
target_cls <- c(
"ZoneHVAC:UnitVentilator", # 1
"ZoneHVAC:UnitHeater", # 2
"PlantLoop", # 3
"CondenserLoop", # 4
"HVACTemplate:Plant:ChilledWaterLoop", # 5
"HVACTemplate:Plant:HotWaterLoop", # 6
"HVACTemplate:Plant:MixedWaterLoop", # 7
"Sizing:System", # 8
"ZoneHVAC:Baseboard:RadiantConvective:Water", # 9
"ZoneHVAC:HighTemperatureRadiant", # 10
"ZoneHVAC:Baseboard:RadiantConvective:Steam", # 11
"ZoneHVAC:Baseboard:RadiantConvective:Electric", # 12
"ZoneHVAC:Baseboard:Convective:Water", # 13
"ZoneHVAC:Baseboard:Convective:Electric", # 14
"ZoneHVAC:LowTemperatureRadiant:VariableFlow", # 15
"ZoneHVAC:LowTemperatureRadiant:Electric" # 16
)
new_idf <- trans_preprocess(idf, "8.2", target_cls)
# 1: ZoneHVAC:UnitVentilator {{{
dt1 <- trans_action(idf, "ZoneHVAC:UnitVentilator", min_fields = 16L,
insert = list(17L)
)
# }}}
# 2: ZoneHVAC:UnitHeater {{{
dt2 <- trans_action(idf, class = "ZoneHVAC:UnitHeater", all = TRUE, add = list(15L))
if (nrow(dt2)) {
dt2[, by = "id", value := {
fantype <- value[[8L]]
fantype[stri_trans_tolower(fantype) == "onoff"] <- "No"
fantype[stri_trans_tolower(fantype) == "continuous"] <- "Yes"
if (any(!fantype %in% c("No", "Yes"))) {
warn(paste0("Invalid 'Fan Control Type' value for object [ID:", id, "] ",
"in class 'ZoneHVAC:UnitHeater' in original v8.1 IDF. ",
"Expected 'OnOff' or 'Continuous'. Assuming 'OnOff'..."),
"trans_810_820"
)
fantype[!fantype %in% c("No", "Yes")] <- "No"
}
c(value[c(1:7, 9:10)], value[15], fantype, value[11:14])
}]
}
# }}}
# 3: PlantLoop {{{
dt3 <- trans_action(idf, "PlantLoop", min_fields = 19L,
reset = list(19L, "Sequential", "SequentialLoad"),
reset = list(19L, "Uniform", "UniformLoad")
)
# }}}
# 4: CondenserLoop {{{
dt4 <- trans_action(idf, "CondenserLoop", min_fields = 19L,
reset = list(19L, "Sequential", "SequentialLoad"),
reset = list(19L, "Uniform", "UniformLoad")
)
# }}}
# 5: HVACTemplate:Plant:ChilledWaterLoop {{{
dt5 <- trans_action(idf, "HVACTemplate:Plant:ChilledWaterLoop", min_fields = 33L,
reset = list(32L, "Sequential", "SequentialLoad"),
reset = list(32L, "Uniform", "UniformLoad"),
reset = list(33L, "Sequential", "SequentialLoad"),
reset = list(33L, "Uniform", "UniformLoad")
)
# }}}
# 6: HVACTemplate:Plant:HotWaterLoop {{{
dt6 <- trans_action(idf, "HVACTemplate:Plant:HotWaterLoop", min_fields = 21L,
reset = list(21L, "Sequential", "SequentialLoad"),
reset = list(21L, "Uniform", "UniformLoad")
)
# }}}
# 7: HVACTemplate:Plant:MixedWaterLoop {{{
dt7 <- trans_action(idf, "HVACTemplate:Plant:MixedWaterLoop", min_fields = 17L,
reset = list(17L, "Sequential", "SequentialLoad"),
reset = list(17L, "Uniform", "UniformLoad")
)
# }}}
# 8: Sizing:System {{{
dt8 <- trans_action(idf, "Sizing:System", min_fields = 21L,
insert = list(18:20),
insert = list(23:26)
)
# }}}
# 9: ZoneHVAC:Baseboard:RadiantConvective:Water {{{
dt9 <- trans_action(idf, "ZoneHVAC:Baseboard:RadiantConvective:Water", min_fields = 8L,
insert = list(7L, "HeatingDesignCapacity"),
insert = list(9:10)
)
# }}}
# 10: ZoneHVAC:HighTemperatureRadiant {{{
dt10 <- trans_action(idf, "ZoneHVAC:HighTemperatureRadiant", min_fields = 4L,
insert = list(4L, "HeatingDesignCapacity"),
insert = list(6:7)
)
# }}}
# 11: ZoneHVAC:Baseboard:RadiantConvective:Steam {{{
dt11 <- trans_action(idf, "ZoneHVAC:Baseboard:RadiantConvective:Steam", min_fields = 4L,
insert = list(5L, "HeatingDesignCapacity"),
insert = list(6L, "Autosize"),
insert = list(7:8)
)
# }}}
# 12: ZoneHVAC:Baseboard:RadiantConvective:Electric {{{
dt12 <- trans_action(idf, "ZoneHVAC:Baseboard:RadiantConvective:Electric", min_fields = 3L,
insert = list(3L, "HeatingDesignCapacity"),
insert = list(5:6)
)
# }}}
# 13: ZoneHVAC:Baseboard:Convective:Water {{{
dt13 <- trans_action(idf, "ZoneHVAC:Baseboard:Convective:Water", min_fields = 4L,
insert = list(5L, "HeatingDesignCapacity"),
insert = list(6L, "Autosize"),
insert = list(7:8)
)
# }}}
# 14: ZoneHVAC:Baseboard:Convective:Electric {{{
dt14 <- trans_action(idf, "ZoneHVAC:Baseboard:Convective:Electric", min_fields = 4L,
insert = list(3L, "HeatingDesignCapacity"),
insert = list(5:6)
)
# }}}
# 15: ZoneHVAC:LowTemperatureRadiant:VariableFlow {{{
dt15 <- trans_action(idf, "ZoneHVAC:LowTemperatureRadiant:VariableFlow", min_fields = 12L,
insert = list(8L, "HeatingDesignCapacity"),
insert = list(9L, "Autosize"),
insert = list(10:11),
insert = list(17L, "CoolingDesignCapacity"),
insert = list(18L, "Autosize"),
insert = list(19:20)
)
# }}}
# 16: ZoneHVAC:LowTemperatureRadiant:Electric {{{
dt16 <- trans_action(idf, "ZoneHVAC:LowTemperatureRadiant:Electric", min_fields = 5L,
insert = list(5L, "HeatingDesignCapacity"),
insert = list(7:8)
)
# }}}
trans_process(new_idf, idf, rbindlist(mget(paste0("dt", 1:16))))
trans_postprocess(new_idf, idf$version(), new_idf$version())
}
# }}}
# trans_820_830 {{{
#' @importFrom checkmate assert_true
trans_funs$f820t830 <- function(idf) {
assert_true(idf$version()[, 1:2] == "8.2")
target_cls <- c(
"Chiller:Electric:ReformulatedEIR", # 1
"Site:GroundDomain", # 2
"GroundHeatExchanger:Vertical", # 3
"EvaporativeCooler:Indirect:ResearchSpecial", # 4
"EvaporativeCooler:Direct:ResearchSpecial" # 5
)
new_idf <- trans_preprocess(idf, "8.3", target_cls)
# 1: Chiller:Electric:ReformulatedEIR {{{
dt1 <- trans_action(idf, "Chiller:Electric:ReformulatedEIR", min_fields = 10L,
insert = list(10L, "LeavingCondenserWaterTemperature")
)
# }}}
# 2: Site:GroundDomain {{{
dt2 <- trans_action(idf, class = c("Site:GroundDomain:Slab" = "Site:GroundDomain"))
# }}}
# 3: GroundHeatExchanger:Vertical {{{
dt3 <- trans_action(idf, "GroundHeatExchanger:Vertical", offset = list(11L, 4L))
if (nrow(dt3)) dt3[index > 10L, index := index - 1L]
# }}}
# 4: EvaporativeCooler:Indirect:ResearchSpecial {{{
dt4 <- trans_action(idf, "EvaporativeCooler:Indirect:ResearchSpecial", all = TRUE,
reset = list(4L, NA_character_),
insert = list(5L:6L),
insert = list(8L:9L),
insert = list(11L, "1.0"),
insert = list(12L, "Autosize"),
reset = list(17L, "Autosize"),
insert = list(20L)
)
if (nrow(dt4)) {
dt4[J(c(13L:14L)), on = "index", value := {
val <- suppressWarnings(as.double(value))
value[1L] <- sprintf("%.5f", val[[2L]] / val[[1L]])
value[2L] <- NA_character_
value
}, by = "id"]
}
# }}}
# 5: EvaporativeCooler:Direct:ResearchSpecial {{{
dt5 <- trans_action(idf, "EvaporativeCooler:Direct:ResearchSpecial",
insert = list(4L),
insert = list(6L:7L)
)
# }}}
trans_process(new_idf, idf, rbindlist(mget(paste0("dt", 1:5))))
trans_postprocess(new_idf, idf$version(), new_idf$version())
}
# }}}
# trans_830_840 {{{
#' @importFrom checkmate assert_true
trans_funs$f830t840 <- function(idf) {
assert_true(idf$version()[, 1:2] == "8.3")
target_cls <- c(
"Coil:WaterHeating:AirToWaterHeatPump", # 1
"WaterHeater:Stratified", # 2
"WaterHeater:HeatPump", # 3
"Branch", # 4
"ZoneHVAC:EquipmentList", # 5
"PlantEquipmentList", # 6
"EvaporativeCooler:Direct:ResearchSpecial", # 7
"Controller:MechanicalVentilation", # 8
"Site:GroundDomain:Slab", # 9
"Site:GroundDomain:Basement", # 10
"PipingSystem:Underground:Domain", # 11
"Pipe:Underground", # 12
"GroundHeatExchanger:HorizontalTrench", # 13
"GroundHeatExchanger:Slinky", # 14
"HVACTemplate:Plant:ChilledWaterLoop", # 15
"HVACTemplate:Plant:HotWaterLoop", # 16
"HVACTemplate:Plant:MixedWaterLoop", # 17
"ZoneAirMassFlowConservation" # 18
)
new_idf <- trans_preprocess(idf, "8.4", target_cls)
# 1: Coil:WaterHeating:AirToWaterHeatPump {{{
dt1 <- trans_action(idf, class = c("Coil:WaterHeating:AirToWaterHeatPump:Pumped" = "Coil:WaterHeating:AirToWaterHeatPump"))
# }}}
# 2: WaterHeater:Stratified {{{
dt2 <- trans_action(idf, "WaterHeater:Stratified", all = TRUE, insert = list(64L:65L))
# }}}
# 3: WaterHeater:HeatPump {{{
dt3 <- trans_action(idf, all = TRUE,
class = c("WaterHeater:HeatPump:PumpedCondenser" = "WaterHeater:HeatPump"),
reset = list(21L, "Coil:WaterHeating:AirToWaterHeatPump", "Coil:WaterHeating:AirToWaterHeatPump:Pumped"),
insert = list(24L),
add = list(37L:39L)
)
if (nrow(dt3)) {
dt3[, value := {
if (is.na(value[17L])) {
heater_num <- 0L
} else if (stri_trans_tolower(value[17L]) == "waterheater:stratified") {
heater_num <- 0L
} else if (stri_trans_tolower(value[36L]) == "heater1") {
heater_num <- 1L
} else if (stri_trans_tolower(value[36L]) == "heater2") {
heater_num <- 2L
} else {
heater_num <- 0L
}
value[36L] <- NA_character_
if (heater_num > 0L) {
tank <- with_silent(idf$object(.BY$id)$ref_to_object(18L)[[1L]])
if (length(tank)) {
if (stri_trans_tolower(tank$class_name()) == "waterheater:stratified") {
if (heater_num == 1L) {
value[37L] <- as.character(tank$Heater_1_Height)
} else {
value[37L] <- as.character(tank$Heater_2_Height)
}
}
}
}
value
}, by = "id"]
}
# }}}
# 4: Branch {{{
dt4 <- trans_action(idf, "Branch")
if (nrow(dt4)) {
dt4[(index - 4L) %% 5L == 0L & stri_trans_tolower(value) == "waterheater:heatpump",
value := "WaterHeater:HeatPump:PumpedCondenser"
]
}
# }}}
# 5: ZoneHVAC:EquipmentList {{{
dt5 <- trans_action(idf, "ZoneHVAC:EquipmentList")
if (nrow(dt5)) {
dt5[(index - 2L) %% 4L == 0L & stri_trans_tolower(value) == "waterheater:heatpump",
value := "WaterHeater:HeatPump:PumpedCondenser"
]
}
# }}}
# 6: PlantEquipmentList {{{
dt6 <- trans_action(idf, "PlantEquipmentList")
if (nrow(dt6)) {
dt6[(index - 2L) %% 2L == 0L & stri_trans_tolower(value) == "waterheater:heatpump",
value := "WaterHeater:HeatPump:PumpedCondenser"
]
}
# }}}
# 7: EvaporativeCooler:Direct:ResearchSpecial {{{
dt7 <- trans_action(idf, "EvaporativeCooler:Direct:ResearchSpecial", min_fields = 5L,
insert = list(5L, "Autosize")
)
# }}}
# 8: Controller:MechanicalVentilation {{{
dt8 <- trans_action(idf, "Controller:MechanicalVentilation",
reset = list(4L, "ProportionalControl", "ProportionalControlBasedonOccupancySchedule")
)
# }}}
ka_num <- 0L
# 9: Site:GroundDomain:Slab {{{
dt9 <- trans_action(idf, "Site:GroundDomain:Slab", all = TRUE)
if (nrow(dt9)) {
dt9_2 <- dt9[J(c(1L, 5L:7L, 10L:12L)), on = "index"]
set(dt9_2, NULL, "index", rowidv(dt9_2, "id"))
set(dt9_2, NULL, "class", "Site:GroundTemperature:Undisturbed:KusudaAchenbach")
dt9_2[J(1L), on = "index", value := paste("KATemp", seq.int(.N) + ka_num)]
dt9_1 <- dt9[!J(12L), on = "index"][
J(10L), on = "index", value := "Site:GroundTemperature:Undisturbed:KusudaAchenbach"][
J(11L), on = "index", value := paste("KATemp", seq.int(.N) + ka_num)]
set(dt9_1, NULL, "index", rowidv(dt9_1, "id"))
dt9 <- rbindlist(list(dt9_1, dt9_2))
ka_num <- ka_num + length(unique(dt9_1$id))
}
# }}}
# 10: Site:GroundDomain:Basement {{{
dt10 <- trans_action(idf, "Site:GroundDomain:Basement", all = TRUE)
if (nrow(dt10)) {
dt10_2 <- dt10[J(c(1L, 5L:7L, 10L:12L)), on = "index"]
set(dt10_2, NULL, "index", rowidv(dt10_2, "id"))
set(dt10_2, NULL, "class", "Site:GroundTemperature:Undisturbed:KusudaAchenbach")
dt10_2[J(1L), on = "index", value := paste("KATemp", seq.int(.N) + ka_num)]
dt10_1 <- dt10[!J(12L), on = "index"][
J(10L), on = "index", value := "Site:GroundTemperature:Undisturbed:KusudaAchenbach"][
J(11L), on = "index", value := paste("KATemp", seq.int(.N) + ka_num)]
set(dt10_1, NULL, "index", rowidv(dt10_1, "id"))
dt10 <- rbindlist(list(dt10_1, dt10_2))
ka_num <- ka_num + length(unique(dt10_1$id))
}
# }}}
# 11: PipingSystem:Underground:Domain {{{
dt11 <- trans_action(idf, "PipingSystem:Underground:Domain", all = TRUE)
if (nrow(dt11)) {
dt11_2 <- dt11[J(c(1L, 14L:16L, 19L:21L)), on = "index"]
set(dt11_2, NULL, "index", rowidv(dt11_2, "id"))
set(dt11_2, NULL, "class", "Site:GroundTemperature:Undisturbed:KusudaAchenbach")
dt11_2[J(1L), on = "index", value := paste("KATemp", seq.int(.N) + ka_num)]
dt11_1 <- dt11[!J(21L), on = "index"][
J(19L), on = "index", value := "Site:GroundTemperature:Undisturbed:KusudaAchenbach"][
J(20L), on = "index", value := paste("KATemp", seq.int(.N) + ka_num)]
set(dt11_1, NULL, "index", rowidv(dt11_1, "id"))
dt11 <- rbindlist(list(dt11_1, dt11_2))
ka_num <- ka_num + length(unique(dt11_1$id))
}
# }}}
# 12: Pipe:Underground {{{
dt12 <- trans_action(idf, "Pipe:Underground", all = TRUE)
if (nrow(dt12)) {
dt12_2 <- dt12[J(c(1L:3L, 8L:11L)), on = "index"]
set(dt12_2, NULL, "index", rowidv(dt12_2, "id"))
set(dt12_2, NULL, "class", "Site:GroundTemperature:Undisturbed:KusudaAchenbach")
dt12_2[J(1L), on = "index", value := paste("KATemp", seq.int(.N) + ka_num)]
dt12_2[J(c(2L:4L)), on = "index", value := {
# get material properties
mat <- with_silent(idf$object(.BY$id)$ref_to_object(8L, "Material")[[1L]])
if (length(mat)) {
value <- mat$value(simplify = TRUE)[2L:4L]
}
value
}, by = "id"]
dt12_1 <- dt12[!J(11L), on = "index"][
J(9L), on = "index", value := "Site:GroundTemperature:Undisturbed:KusudaAchenbach"][
J(10L), on = "index", value := paste("KATemp", seq.int(.N) + ka_num)]
set(dt12_1, NULL, "index", rowidv(dt12_1, "id"))
dt12 <- rbindlist(list(dt12_1, dt12_2))
ka_num <- ka_num + length(unique(dt12_1$id))
}
# }}}
# 13: GroundHeatExchanger:HorizontalTrench {{{
dt13 <- trans_action(idf, "GroundHeatExchanger:HorizontalTrench", all = TRUE)
if (nrow(dt13)) {
dt13_2 <- dt13[J(c(1L, 11L:13L, 19L:21L)), on = "index"]
set(dt13_2, NULL, "index", rowidv(dt13_2, "id"))
set(dt13_2, NULL, "class", "Site:GroundTemperature:Undisturbed:KusudaAchenbach")
dt13_2[J(1L), on = "index", value := paste("KATemp", seq.int(.N) + ka_num)]
dt13_1 <- dt13[!J(21L), on = "index"][
J(19L), on = "index", value := "Site:GroundTemperature:Undisturbed:KusudaAchenbach"][
J(20L), on = "index", value := paste("KATemp", seq.int(.N) + ka_num)]
set(dt13_1, NULL, "index", rowidv(dt13_1, "id"))
dt13 <- rbindlist(list(dt13_1, dt13_2))
ka_num <- ka_num + length(unique(dt13_1$id))
}
# }}}
# 14: GroundHeatExchanger:Slinky {{{
dt14 <- trans_action(idf, "GroundHeatExchanger:Slinky", all = TRUE)
if (nrow(dt14)) {
dt14_2 <- dt14[J(c(1L, 5L:7L, 20L:22L)), on = "index"]
set(dt14_2, NULL, "index", rowidv(dt14_2, "id"))
set(dt14_2, NULL, "class", "Site:GroundTemperature:Undisturbed:KusudaAchenbach")
dt14_2[J(1L), on = "index", value := paste("KATemp", seq.int(.N) + ka_num)]
dt14_1 <- dt14[!J(22L), on = "index"][
J(20L), on = "index", value := "Site:GroundTemperature:Undisturbed:KusudaAchenbach"][
J(21L), on = "index", value := paste("KATemp", seq.int(.N) + ka_num)]
set(dt14_1, NULL, "index", rowidv(dt14_1, "id"))
dt14 <- rbindlist(list(dt14_1, dt14_2))
ka_num <- ka_num + length(unique(dt14_1$id))
}
# }}}
# 15: HVACTemplate:Plant:ChilledWaterLoop {{{
dt15 <- trans_action(idf, "HVACTemplate:Plant:ChilledWaterLoop",
reset = list(32L, "Sequential", "SequentialLoad"),
reset = list(32L, "Uniform", "UniformLoad"),
reset = list(33L, "Sequential", "SequentialLoad"),
reset = list(33L, "Uniform", "UniformLoad")
)
# }}}
# 16: HVACTemplate:Plant:HotWaterLoop {{{
dt16 <- trans_action(idf, "HVACTemplate:Plant:HotWaterLoop",
reset = list(21L, "Sequential", "SequentialLoad"),
reset = list(21L, "Uniform", "UniformLoad")
)
# }}}
# 17: HVACTemplate:Plant:MixedWaterLoop {{{
dt17 <- trans_action(idf, "HVACTemplate:Plant:MixedWaterLoop",
reset = list(17L, "Sequential", "SequentialLoad"),
reset = list(17L, "Uniform", "UniformLoad")
)
# }}}
# 18: ZoneAirMassFlowConservation {{{
dt18 <- trans_action(idf, "ZoneAirMassFlowConservation",
add = list(3L, "MixingSourceZonesOnly")
)
if (nrow(dt18)) {
dt18[, value := {
if (stri_trans_tolower(value[1L]) != "yes") {
value[2L] <- "None"
}
value
}, by = "id"]
}
# }}}
trans_process(new_idf, idf, rbindlist(mget(paste0("dt", 1:18))))
trans_postprocess(new_idf, idf$version(), new_idf$version())
}
# }}}
# trans_840_850 {{{
#' @importFrom checkmate assert_true
trans_funs$f840t850 <- function(idf) {
assert_true(idf$version()[, 1:2] == "8.4")
target_cls <- c(
"EnergyManagementSystem:Actuator" # 1
)
new_idf <- trans_preprocess(idf, "8.5", target_cls)
# 1: EnergyManagementSystem:Actuator {{{
dt <- trans_action(idf, "EnergyManagementSystem:Actuator",
reset = list(4L, "outdoor air dryblub temperature", "Outdoor Air Drybulb Temperature"),
reset = list(4L, "outdoor air wetblub temperature", "Outdoor Air Wetbulb Temperature")
)
# }}}
trans_process(new_idf, idf, dt)
trans_postprocess(new_idf, idf$version(), new_idf$version())
}
# }}}
# trans_850_860 {{{
#' @importFrom checkmate assert_true
trans_funs$f850t860 <- function(idf) {
assert_true(idf$version()[, 1:2] == "8.5")
target_cls <- c(
"Exterior:FuelEquipment", # 1
"HVACTemplate:System:UnitarySystem", # 2
"HVACTemplate:System:Unitary", # 3
"ChillerHeater:Absorption:DirectFired", # 4
"SetpointManager:SingleZone:Humidity:Minimum", # 5
"SetpointManager:SingleZone:Humidity:Maximum", # 6
"AirTerminal:SingleDuct:VAV:Reheat", # 7
"Branch", # 8
"AirTerminal:SingleDuct:InletSideMixer", # 9
"AirTerminal:SingleDuct:SupplySideMixer", # 10
"ZoneHVAC:AirDistributionUnit", # 11
"OtherEquipment", # 12
"Coil:Heating:Gas", # 13
"Daylighting:Controls", # 14
"Daylighting:DELight:ReferencePoint", # 15
"Daylighting:DELight:Controls", # 16
"MaterialProperty:MoisturePenetrationDepth:Settings", # 17
"EnergyManagementSystem:Actuator" # 18
)
# SPECIAL
# replace all "Coil:Heating:Gas" with "Coil:Heating:Fuel"
get_priv_env(idf)$idf_env()$value[
stri_detect_fixed(value_chr, "coil:heating:gas", case_insensitive = TRUE),
value_chr := "Coil:Heating:Fuel"
]
new_idf <- trans_preprocess(idf, "8.6", target_cls)
# 1: Exterior:FuelEquipment {{{
dt1 <- trans_action(idf, "Exterior:FuelEquipment",
reset = list(2L, "Gas", "NaturalGas"),
reset = list(2L, "LPG", "PropaneGas")
)
# }}}
# 2: HVACTemplate:System:UnitarySystem {{{
dt2 <- trans_action(idf, "HVACTemplate:System:UnitarySystem", all = TRUE, delete = list(57))
if (nrow(dt2)) dt2[, index := seq_len(.N), by = "id"]
# }}}
# 3: HVACTemplate:System:Unitary {{{
dt3 <- trans_action(idf, "HVACTemplate:System:Unitary", all = TRUE, delete = list(40L))
if (nrow(dt3)) dt3[, index := seq_len(.N), by = "id"]
# }}}
# 4: ChillerHeater:Absorption:DirectFired {{{
dt4 <- trans_action(idf, "ChillerHeater:Absorption:DirectFired", delete = list(33L))
if (nrow(dt4)) dt4[, index := seq_len(.N), by = "id"]
# }}}
# 5: SetpointManager:SingleZone:Humidity:Minimum {{{
dt5 <- trans_action(idf, "SetpointManager:SingleZone:Humidity:Minimum", delete = list(2:3))
if (nrow(dt5)) dt5[, index := seq_len(.N), by = "id"]
# }}}
# 6: SetpointManager:SingleZone:Humidity:Maximum {{{
dt6 <- trans_action(idf, "SetpointManager:SingleZone:Humidity:Maximum", delete = list(2:3))
if (nrow(dt2)) dt6[, index := seq_len(.N), by = "id"]
# }}}
# 7: AirTerminal:SingleDuct:VAV:Reheat {{{
dt7 <- trans_action(idf, "AirTerminal:SingleDuct:VAV:Reheat", all = TRUE)
if (nrow(dt7)) {
dt7[, value := {
if (!anyNA(value[16L:18L]) & stri_trans_tolower(value[16]) == "reverse") {
value[16] <- "ReverseWithLimits"
}
value
}, by = "id"]
}
# }}}
# 8: Branch {{{
dt8 <- trans_action(idf, "Branch", delete = list(2), delete = list(8, step = 5))
if (nrow(dt8)) dt8[, index := seq_len(.N), by = "id"]
# }}}
# 9: AirTerminal:SingleDuct:InletSideMixer {{{
dt9 <- trans_action(idf, all = TRUE,
class = c("AirTerminal:SingleDuct:Mixer" = "AirTerminal:SingleDuct:InletSideMixer"),
add = list(7L, "InletSide")
)
# }}}
# 10: AirTerminal:SingleDuct:SupplySideMixer {{{
dt10 <- trans_action(idf, all = TRUE,
class = c("AirTerminal:SingleDuct:Mixer" = "AirTerminal:SingleDuct:SupplySideMixer"),
add = list(7L, "SupplySide")
)
# }}}
# 11: ZoneHVAC:AirDistributionUnit {{{
dt11 <- trans_action(idf, "ZoneHVAC:AirDistributionUnit", all = TRUE,
reset = list(3L, "AirTerminal:SingleDuct:InletSideMixer", "AirTerminal:SingleDuct:InletSideMixer"),
reset = list(3L, "AirTerminal:SingleDuct:SupplySideMixer", "AirTerminal:SingleDuct:InletSideMixer")
)
# }}}
# 12: OtherEquipment {{{
dt12 <- trans_action(idf, "OtherEquipment", insert = list(2L, "None"))
# }}}
# 13: Coil:Heating:Gas {{{
dt13 <- trans_action(idf, min_fields = 2L,
class = c("Coil:Heating:Fuel" = "Coil:Heating:Gas"),
insert = list(3L, "NaturalGas"))
# }}}
# 14: Daylighting:Controls {{{
dt14_1 <- trans_action(idf, "Daylighting:Controls", all = TRUE,
offset = list(
c(20L, 16:19, 13L, 14:15, 9L, 11L, 10L, 12L),
c(4L, 6:9, 5L, 11:12, 15L, 16L, 18L, 19L)
),
add = list(c(10L, 13L, 14L, 17L)),
reset = list(3L, "SplitFlux"),
reset = list(8L, "0", NA_character_),
reset = list(13L, NA_character_)
)
if (!nrow(dt14_1)) {
dt14_2 <- data.table()
dt14_3 <- data.table()
} else {
dt14_1[, value := {
nm <- if (is.na(value[1L])) "" else value[1L]
value[10L] <- paste0(nm, "_DaylRefPt1")
value[14L] <- paste0(nm, "_DaylRefPt1")
if (value[2L] == "2") {
value[17L] <- paste0(nm, "_DaylRefPt2")
} else {
value[17L:19L] <- NA_character_
}
value[2L] <- value[1L]
value[1L] <- paste0(nm, "_DaylCtrl")
value
}, by = "id"]
# remove #2 ref point if applicable
obj_id <- dt14_1[J(17L:19L), on = "index", list(all(is.na(value))), by = "id"][V1 == TRUE, id]
if (length(obj_id)) {
dt14_1 <- dt14_1[!data.table::CJ(id = obj_id, index = 17L:19L), on = c("id", "index")]
}
dt14_1[J(5L), on = "index", value := {
if (is.na(value)) {
"Continuous"
} else if (value == "1") {
"Continuous"
} else if (value == "2") {
"Stepped"
} else if (value == "3") {
"ContinuousOff"
} else {
"Continuous"
}
}, by = "id"]
# add reference points
dt14_2 <- trans_action(idf, all = TRUE,
class = c("Daylighting:ReferencePoint" = "Daylighting:Controls")
)
dt14_3 <- dt14_2[J(c(1L, 2L, 6L:8L)), on = "index"]
dt14_2 <- dt14_2[index <= 5L]
dt14_2[, value := {
value[2L] <- value[1L]
value[1L] <- if (is.na(value[1L])) "_DaylRefPt1" else paste0(value[1L], "_DaylRefPt1")
value
}, by = "id"]
obj_id <- dt14_3[J(2L, "2"), on = c("index", "value"), id, nomatch = 0L]
if (!length(obj_id)) {
dt14_3 <- data.table()
} else {
dt14_3 <- dt14_3[J(obj_id), on = "id"][
J(c(6L:8L)), on = "index", index := c(3L:5L), by = "id"
][, value := {
value[2L] <- value[1L]
value[1L] <- if (is.na(value[1L])) "_DaylRefPt2" else paste0(value[1L], "_DaylRefPt2")
value
}, by = "id"]
# in order to distinguish from first ref point's id
dt14_3[, id := -id]
}
}
dt14 <- rbindlist(list(dt14_1, dt14_2, dt14_3))
# }}}
# 15: Daylighting:DELight:ReferencePoint {{{
dt15 <- trans_action(idf, all = TRUE,
class = c("Daylighting:ReferencePoint" = "Daylighting:DELight:ReferencePoint")
)
if (nrow(dt15)) {
dt15 <- dt15[index <= 5L]
nm_zone <- vcapply(unique(dt15$id),
function(id) {
zone <- with_silent(idf$object(id)$ref_to_object(2L, class = "Zone", depth = NULL)[[1L]])
if (!length(zone)) NA_character_ else zone$value(2)[[1L]]
}
)
dt15[J(2L), on = "index", value := nm_zone]
}
# }}}
# 16: Daylighting:DElight:Controls {{{
dt16 <- trans_action(idf, all = TRUE,
class = c("Daylighting:Controls" = "Daylighting:DELight:Controls"),
insert = list(3L, "DElight"),
insert = list(4L, NA_character_),
add = list(11L:13L, c("0", NA_character_, NA_character_))
)
if (nrow(dt16)) {
dt16_1 <- dt16[index <= 13L][, value := {
if (is.na(value[5L])) {
value[5L] <- "Continuous"
} else if (value[5L] == "1") {
value[5L] <- "Continuous"
} else if (value[5L] == "2") {
value[5L] <- "Stepped"
} else if (value[5L] == "3") {
value[5L] <- "ContinuousOff"
} else {
value[5L] <- "Continuous"
}
val <- value[8L]
if (!is.na(value[8L]) && value[8L] == "0") value[8L] <- NA_character_
value[13L] <- value[10L]
value[10L] <- NA_character_
value
}, by = "id"]
# extract reference point name, zone name, and illuminance setpoint
dt16_2 <- lapply(unique(dt16_1$id),
function(id) {
refp <- with_silent(idf$object(id)$ref_by_object(1L, class = "Daylighting:DELight:ReferencePoint"))
if (!length(refp)) {
data.table()
} else {
dt <- rbindlist(lapply(refp, function(x) x$to_table(all = TRUE)))[index %in% c(1L, 6L, 7L)]
# update object id
set(dt, NULL, "id", id)
set(dt, NULL, "class", "Daylighting:Controls")
set(dt, NULL, "index", seq.int(nrow(dt)) + 13L)
}
}
)
dt16 <- rbindlist(c(list(dt16_1), dt16_2))
setorderv(dt16, c("id", "index"))
}
# }}}
# 17: MaterialProperty:MoisturePenetrationDepth:Settings {{{
dt17 <- trans_action(idf, all = TRUE,
class = "MaterialProperty:MoisturePenetrationDepth:Settings",
add = list(7L:10L, "0")
)
if (nrow(dt17)) {
# cal_mu_empd {{{
# reference: CalculateMuEMPD() in UtilityRoutines.f90 under Transition
cal_mu_empd <- function(a, b, c, d, d_empd, density) {
TEMP <- 24
RH <- 0.45
P_ambient <- 101325
Seconds <- 24L * 60L * 60L
slope_MC <- a * b * RH ** (b - 1) + c * d * RH ** (d - 1)
PV_sat <- psat_fn_tdb(TEMP) * 1000
diffusivity_EMPD <- d_empd ** 2 * 3.1415926535 * slope_MC * density / (Seconds * PV_sat)
diffusivity_air <- 2.0e-7 * (TEMP + 273.15) ** 0.81 / P_ambient
diffusivity_air / diffusivity_EMPD
}
# }}}
# psat_fn_tdb {{{
# reference: GetSatVapPressFromDryBulb() in UtilityRoutines.f90 under Transition
psat_fn_tdb <- function(tdb) {
tk <- tdb + 273.15
C1 <- -5674.5359
C2 <- 6.3925247
C3 <- -0.009677843
C4 <- 0.00000062215701
C5 <- 2.0747825E-09
C6 <- -9.484024E-13
C7 <- 4.1635019
C8 <- -5800.2206
C9 <- 1.3914993
C10 <- -0.048640239
C11 <- 0.000041764768
C12 <- -0.000000014452093
C13 <- 6.5459673
psat <- rep(NA_real_, length(tdb))
psat[tdb <= 0] <- exp(C1/tk + C2 + C3*tk + C4*tk**2 + C5*tk**3 + C6*tk**4 + C7*log(tk)) / 1000
psat[tdb > 0] <- exp(C8/tk + C9 + C10*tk + C11*tk**2 + C12*tk**3 + C13*log(tk)) / 1000
psat
}
# }}}
dt17 <- dt17[, by = "id",
value := {
value[7L] <- value[2L]
# get material density
mat <- with_silent(idf$object(.BY$id)$ref_to_object(1L, "Material")[[1L]])
if (length(mat)) {
den <- mat$Density
} else {
warn(paste0(
"Material match issue:\n",
"Did not find a matched material component for name '",
value[[1L]], "' referenced in class ",
"'MaterialProperty:MoisturePenetrationDepth:Settings'."
),
"tran_850_860"
)
den <- NA_real_
}
# calculate
coeffs <- suppressWarnings(as.double(value[3L:6L]))
d_empd <- suppressWarnings(as.double(value[2L]))
mu <- cal_mu_empd(coeffs[1L], coeffs[2L], coeffs[3L], coeffs[4L], d_empd, den)
if (is.na(mu)) {
value[2L] <- paste0("Could not find Material Match for ",
if (is.na(value[1L])) "" else value[1L]
)
} else {
value[2L] <- sprintf("%.7f", mu)
}
value
}
]
}
# }}}
# 18: EnergyManagementSystem:Actuator {{{
dt18 <- trans_action(idf, "EnergyManagementSystem:Actuator",
reset = list(4L, "outdoor air dryblub temperature", "Outdoor Air Drybulb Temperature"),
reset = list(4L, "outdoor air wetblub temperature", "Outdoor Air Wetbulb Temperature")
)
# }}}
# 19: Output:Variable (DIRECTLY UPDATE) {{{
# For Output:Variable that reference a specific Daylighting:Controls object
# need update to the new reference point name
if (new_idf$is_valid_class("Output:Variable")) {
dt19 <- new_idf$to_table(class = "Output:Variable", wide = TRUE)
set(dt19, NULL, "key_value", stri_trans_tolower(stri_trim_both(dt19$`Key Value`)))
set(dt19, NULL, "variable_name", stri_trans_tolower(stri_trim_both(dt19$`Variable Name`)))
dt19_1 <- dt19[key_value != "*" & stri_sub(variable_name, to = 27L) == "daylighting reference point"]
if (nrow(dt19_1)) {
# DELight Reference Point
if (nrow(dt15)) {
refpt <- dt15[index == 1L, list(id, key_value = stri_trans_tolower(stri_trim_both(value)))]
dt19_1[!refpt, on = "key_value", list(id, class, index = 1L, value = paste0(stri_trim_both(`Key Value`), "_DaylCtrl"))]
} else {
dt19_1 <- dt19_1[, list(id, class = class, index = 1L, value = paste0(stri_trim_both(`Key Value`), "_DaylCtrl"))]
}
set(dt19_1, NULL, c("key_value", "variable_name"), NULL)
dt19_1 <- dt_to_load(dt19_1)
} else {
dt19_1 <- data.table()
}
dt19_2 <- dt19[key_value != "*" & variable_name == "daylighting lighting power multiplier"]
if (nrow(dt19_2)) {
# DELight Reference Point
if (nrow(dt15)) {
refpt <- dcast.data.table(dt15[J(c(1:2)), on = "index"], id + class ~ field, value.var = "value")
# add control name
refpt[, `:=`(ctrlname = idf$object(id[[1L]])$value(2L)[[1L]]), by = "id"]
dt19_2 <- dt19_2[refpt, on = c("key_value" = "DElight Name"), list(id, class, index = 1L, value = ctrlname), nomatch = 0L]
} else {
dt19_2 <- dt19_2[, list(id, class = class, index = 1L, value = paste0(stri_trim_both(`Key Value`), "_DaylCtrl"))]
}
} else {
dt19_2 <- data.table()
}
dt19 <- rbindlist(list(dt19_1, dt19_2), fill = TRUE)
if (nrow(dt19)) new_idf$update(dt19, .default = FALSE)
}
# }}}
trans_process(new_idf, idf, rbindlist(mget(paste0("dt", 1:18))))
trans_postprocess(new_idf, idf$version(), new_idf$version())
}
# }}}
# trans_860_870 {{{
#' @importFrom checkmate assert_true
trans_funs$f860t870 <- function(idf) {
assert_true(idf$version()[, 1:2] == "8.6")
target_cls <- c(
"Coil:Cooling:DX:MultiSpeed", # 1
"Coil:Heating:DX:MultiSpeed", # 2
"CoolingTower:SingleSpeed", # 3
"CoolingTower:TwoSpeed", # 4
"CoolingTower:VariableSpeed:Merkel", # 5
"AirflowNetwork:SimulationControl", # 6
"ZoneCapacitanceMultiplier:ResearchSpecial", # 7
"WaterHeater:HeatPump:WrappedCondenser", # 8
"AirflowNetwork:Distribution:Component:Duct" # 9
)
new_idf <- trans_preprocess(idf, "8.7", target_cls)
# 1: Coil:Cooling:DX:MultiSpeed {{{
dt1 <- trans_action(idf, "Coil:Cooling:DX:MultiSpeed",
reset = list(16, NA_character_, "NaturalGas"),
reset = list(16, "PropaneGas", "Propane")
)
# }}}
# 2: Coil:Heating:DX:MultiSpeed {{{
dt2 <- trans_action(idf, "Coil:Heating:DX:MultiSpeed",
reset = list(16, NA_character_, "NaturalGas"),
reset = list(16, "PropaneGas", "Propane")
)
# }}}
# 3: CoolingTower:SingleSpeed {{{
dt3 <- trans_action(idf, "CoolingTower:SingleSpeed", insert = list(17:20))
# }}}
# 4: CoolingTower:TwoSpeed {{{
dt4 <- trans_action(idf, "CoolingTower:TwoSpeed", insert = list(25:28))
# }}}
# 5: CoolingTower:VariableSpeed:Merkel {{{
dt5 <- trans_action(idf, "CoolingTower:VariableSpeed:Merkel", insert = list(25:28))
# }}}
# 6: AirflowNetwork:SimulationControl {{{
dt6 <- trans_action(idf, "AirflowNetwork:SimulationControl", delete = list(4L))
if (nrow(dt6)) dt6[, index := seq_len(.N), by = "id"]
# }}}
# 7: ZoneCapacitanceMultiplier:ResearchSpecial {{{
dt7 <- trans_action(idf, "ZoneCapacitanceMultiplier:ResearchSpecial",
insert = list(1:2, c("Multiplier", NA_character_))
)
# }}}
# 8: WaterHeater:HeatPump:WrappedCondenser {{{
dt8 <- trans_action(idf, "WaterHeater:HeatPump:WrappedCondenser",
reset = list(35, "MutuallyExlcusive", "MutuallyExclusive"))
# }}}
# 9: AirflowNetwork:Distribution:Component:Duct {{{
dt9 <- trans_action(idf, "AirflowNetwork:Distribution:Component:Duct", all = TRUE,
add = list(9:10)
)
if (nrow(dt9)) {
dt9[index >= 7L, value := {
AFNDuctFracRcond <- 0.815384615
AFNDuctFracRout <- 0.153846154
AFNDuctFracRin <- 0.030769231
val <- suppressWarnings(as.double(value))
# 7
value[1L] <- sprintf("%.6f", val[1L] / AFNDuctFracRcond)
# 9
value[3L] <- sprintf("%.6f", val[1L] / AFNDuctFracRout)
# 10
value[4L] <- sprintf("%.6f", val[1L] / AFNDuctFracRin)
value
}, by = "id"]
}
# }}}
trans_process(new_idf, idf, rbindlist(mget(paste0("dt", 1:9))))
trans_postprocess(new_idf, idf$version(), new_idf$version())
}
# }}}
# trans_870_880 {{{
#' @importFrom checkmate assert_true
trans_funs$f870t880 <- function(idf) {
assert_true(idf$version()[, 1:2] == "8.7")
target_cls <- c(
"Output:Surfaces:List", # 1
"Table:TwoIndependentVariables", # 2
# Only used to check corresponding perimeter object
#"BuildingSurface:Detailed", # 3
# Only used to check corresponding perimeter object
#"Floor:Detailed", # 4
"SurfaceProperty:ExposedFoundationPerimeter", # 5
"Foundation:Kiva:Settings", # 6
"UnitarySystemPerformance:Multispeed", # 7
"Coil:Cooling:DX:SingleSpeed", # 8
"Coil:Cooling:DX:TwoSpeed", # 9
"Coil:Cooling:DX:MultiSpeed", # 10
"Coil:Cooling:DX:VariableSpeed", # 11
"Coil:Cooling:DX:TwoStageWithHumidityControlMode", # 12
"ZoneHVAC:PackagedTerminalHeatPump", # 13
"ZoneHVAC:IdealLoadsAirSystem", # 14
"ZoneControl:ContaminantController", # 15
"AvailabilityManager:NightCycle" # 16
)
new_idf <- trans_preprocess(idf, "8.8", target_cls)
# 1: Output:Surfaces:List {{{
dt1 <- trans_action(idf, "Output:Surfaces:List",
reset = list(1, "DecayCurvesfromZoneComponentLoads", "DecayCurvesFromComponentLoadsSummary")
)
# }}}
# 2: Table:TwoIndependentVariables {{{
dt2 <- trans_action(idf, "Table:TwoIndependentVariables", insert = list(14))
# }}}
# 3: BuildingSurface:Detailed {{{
dt3 <- trans_action(idf, "BuildingSurface:Detailed", min_fields = 5L)
if (nrow(dt3)) {
targets <- dt3[index == 5L, !is.na(value) & tolower(value) == "foundation"] &
dt3[index == 2L, !is.na(value) & tolower(value) == "floor"]
obj_id <- dt3[index == 1L, id][targets]
if (!length(obj_id)) {
dt3 <- data.table()
} else {
# check if surface has a corresponding perimeter object
# if not, give a warning and add one
dt3 <- rbindlist(lapply(obj_id,
function(i) {
perim <- with_silent(idf$object(i)$ref_by_object(1L, class = "SurfaceProperty:ExposedFoundationPerimeter")[[1L]])
if (length(perim)) return(data.table())
dt <- dt3[J(i), on = "id"]
n <- ceiling((nrow(dt) - 10L) / 3L)
dt <- dt[index <= 4L + n]
set(dt, NULL, "class", "SurfaceProperty:ExposedFoundationPerimeter")
dt[J(2L), on = "index", value := "BySegment"]
dt[J(c(3L, 4L)), on = "index", value := NA_character_]
dt[index > 4L, value := "Yes"]
warn(paste0(
"Foundation floors now require a ",
"'SurfaceProperty:ExposedFoundationPerimeter' ",
"object. One was added with each segment of the ",
"floor surface exposed (", surround(idf$object(i)$name()), "). ",
"Please check your inputs to make sure this ",
"reflects your foundation."
),
"trans_870_880"
)
dt
}
))
}
}
# }}}
# 4: Floor:Detailed {{{
dt4 <- trans_action(idf, "Floor:Detailed", min_fields = 4L)
if (nrow(dt4)) {
targets <- dt4[index == 4L, !is.na(value) & tolower(value) == "foundation"]
obj_id <- dt4[index == 1L, id][targets]
if (!length(obj_id)) {
dt4 <- data.table()
} else {
# check if surface has a corresponding perimeter object
# if not, give a warning and add one
dt4 <- rbindlist(lapply(obj_id,
function(i) {
perim <- with_silent(idf$object(i)$ref_by_object(1L, class = "SurfaceProperty:ExposedFoundationPerimeter")[[1L]])
if (length(perim)) return(data.table())
dt <- dt4[J(i), on = "id"]
n <- ceiling((nrow(dt) - 9L) / 3L)
dt <- dt[index <= 4L + n]
set(dt, NULL, "class", "SurfaceProperty:ExposedFoundationPerimeter")
dt[J(2L), on = "index", value := "BySegment"]
dt[J(c(3L, 4L)), on = "index", value := NA_character_]
dt[index > 4L, value := "Yes"]
warn(paste0(
"Foundation floors now require a ",
"'SurfaceProperty:ExposedFoundationPerimeter' ",
"object. One was added with each segment of the ",
"floor surface exposed (", surround(idf$object(i)$name()), "). ",
"Please check your inputs to make sure this ",
"reflects your foundation."
),
"trans_870_880"
)
dt
}
))
}
}
# }}}
# 5: SurfaceProperty:ExposedFoundationPerimeter {{{
dt5 <- trans_action(idf, "SurfaceProperty:ExposedFoundationPerimeter",
insert = list(2L, "BySegment")
)
# }}}
# 6: Foundation:Kiva:Settings {{{
dt6 <- trans_action(idf, "Foundation:Kiva:Settings",
reset = list(8L, "autocalculate", "autoselect")
)
# }}}
# 7: UnitarySystemPerformance:Multispeed {{{
dt7 <- trans_action(idf, "UnitarySystemPerformance:Multispeed", insert = list(5))
# }}}
# 8: Coil:Cooling:DX:SingleSpeed {{{
dt8 <- trans_action(idf, "Coil:Cooling:DX:SingleSpeed", insert = list(15))
# }}}
# 9: Coil:Cooling:DX:TwoSpeed {{{
dt9 <- trans_action(idf, "Coil:Cooling:DX:TwoSpeed", insert = list(23))
# }}}
# 10: Coil:Cooling:DX:MultiSpeed {{{
dt10 <- trans_action(idf, "Coil:Cooling:DX:MultiSpeed", insert = list(7))
# }}}
# 11: Coil:Cooling:DX:VariableSpeed {{{
dt11 <- trans_action(idf, "Coil:Cooling:DX:VariableSpeed", insert = list(16))
# }}}
# 12: Coil:Cooling:DX:TwoStageWithHumidityControlMode {{{
dt12 <- trans_action(idf, "Coil:Cooling:DX:TwoStageWithHumidityControlMode", insert = list(19))
# }}}
# 13: ZoneHVAC:PackagedTerminalHeatPump {{{
dt13 <- trans_action(idf, "ZoneHVAC:PackagedTerminalHeatPump", delete = list(18))
if (nrow(dt13)) dt13[, index := seq_len(.N), by = "id"]
# }}}
# 14: ZoneHVAC:IdealLoadsAirSystem {{{
dt14 <- trans_action(idf, "ZoneHVAC:IdealLoadsAirSystem", insert = list(5))
# }}}
# 15: ZoneControl:ContaminantController{{{
dt15 <- trans_action(idf, "ZoneControl:ContaminantController", insert = list(6))
# }}}
# 16: AvailabilityManager:NightCycle {{{
dt16 <- trans_action(idf, "AvailabilityManager:NightCycle", insert = list(6, "FixedRunTime"))
# }}}
trans_process(new_idf, idf, rbindlist(mget(paste0("dt", 1:16))))
trans_postprocess(new_idf, idf$version(), new_idf$version())
}
# }}}
# trans_880_890 {{{
#' @importFrom checkmate assert_true
trans_funs$f880t890 <- function(idf) {
assert_true(idf$version()[, 1:2] == "8.8")
target_cls <- c(
"ZoneHVAC:EquipmentList", # 1
"GroundHeatExchanger:Vertical", # 2
"Branch", # 3
"CondenserEquipmentList", # 4
"ElectricEquipment:ITE:AirCooled", # 5
"Schedule:Day:Interval", # 6
"Schedule:Day:List", # 7
"Schedule:Compact" # 8
)
new_idf <- trans_preprocess(idf, "8.9", target_cls)
# 1: ZoneHVAC:EquipmentList {{{
dt1 <- trans_action(idf, "ZoneHVAC:EquipmentList", insert = list(2, "SequentialLoad"))
# }}}
# 2: GroundHeatExchanger:Vertical {{{
# GroundHeatExchanger:System {{{
dt2_1 <- trans_action(idf, min_fields = 9,
class = c("GroundHeatExchanger:System" = "GroundHeatExchanger:Vertical"),
# this will remove #9
offset = list(8:9, 7:8),
reset = list(5L, "Site:GroundTemperature:Undisturbed:KusudaAchenbach"),
add = list(9L)
)
if (nrow(dt2_1)) {
dt2_1 <- dt2_1[index <= 9L]
dt2_1[, value := {
name <- if (is.na(value[1L])) "" else value[1L]
value[6L] <- paste(name, "Ground Temps")
value[9L] <- paste(name, "Response Factors")
value
}, by = "id"]
}
# }}}
# GroundHeatExchanger:Vertical:Properties {{{
dt2_2 <- trans_action(idf, min_fields = 15L,
class = c("GroundHeatExchanger:Vertical:Properties" = "GroundHeatExchanger:Vertical"),
offset = list(c(6L, 7L, 11L, 12L, 13L, 15L, 14L),
c(3L, 4L, 5L, 7L, 9L, 10L, 11L)
),
reset = list(2L, "1"),
add = list(6L, "3.90e+6"),
reset = list(8L, "1.77e+6")
)
if (nrow(dt2_2)) {
dt2_2 <- dt2_2[index <= 11L]
dt2_2[J(1L), on = "index", value := {
paste(if (is.na(value)) "" else value, "Properties")
}, by = "id"]
dt2_2[J(4L), on = "index", value := as.character(as.double(value) * 2)]
}
# }}}
# Site:GroundTemperature:Undisturbed:KusudaAchenbach {{{
dt2_3 <- trans_action(idf, min_fields = 10L,
class = c("Site:GroundTemperature:Undisturbed:KusudaAchenbach" = "GroundHeatExchanger:Vertical"),
offset = list(c(8L, 9L, 10L),
c(2L, 4L, 5L)
),
reset = list(3L, "920"),
reset = list(6L, "3.2"),
reset = list(7L, "8")
)
if (nrow(dt2_3)) {
dt2_3 <- dt2_3[index <= 7L]
dt2_3[J(1L), on = "index", value := {
value[!is.na(value)] <- paste(value[!is.na(value)], "Ground Temps")
value
}]
dt2_3[J(4L), on = "index", value := {
val <- suppressWarnings(as.double(value))
val[is.na(val)] <- 0.0
val <- val / 920
sprintf("%.5f", val)
}, by = "id"]
}
# }}}
# GroundHeatExchanger:ResponseFactors {{{
dt2_4 <- trans_action(idf, min_fields = 17L,
class = c("GroundHeatExchanger:ResponseFactors" = "GroundHeatExchanger:Vertical"),
offset = list(c(5L, 17L),
c(3L, 4L)
),
delete = list(c(6:18))
)
if (nrow(dt2_4)) {
dt2_4[index >= 19L, index := index - 14L]
dt2_4[J(c(1L, 2L)), on = "index", value := {
nm <- if (is.na(value[1L])) "" else value[1L]
value[1L] <- paste(nm, "Response Factors")
value[2L] <- paste(nm, "Properties")
value
}, by = "id"]
}
# }}}
dt2 <- rbindlist(list(dt2_1, dt2_2, dt2_3, dt2_4))
# }}}
# 3: Branch {{{
dt3 <- trans_action(idf, "Branch")
if (nrow(dt3)) {
dt3[(index - 2L) %% 4L == 1, value := gsub("GroundHeatExchanger:Vertical", "GroundHeatExchanger:System", value, ignore.case = TRUE)]
}
# }}}
# 4: CondenserEquipmentList {{{
dt4 <- trans_action(idf, "CondenserEquipmentList")
if (nrow(dt4)) {
dt4[(index - 2L) %% 2L == 0L, value := gsub("GroundHeatExchanger:Vertical",
"GroundHeatExchanger:System", value, ignore.case = TRUE)
]
}
# }}}
# 5: ElectricEquipment:ITE:AirCooled {{{
dt5 <- trans_action(idf, "ElectricEquipment:ITE:AirCooled", insert = list(3L, "FlowFromSystem"))
# }}}
# 6: Schedule:Day:Interval {{{
dt6 <- trans_action(idf, "Schedule:Day:Interval", reset = list(3L, "yes", "Average"))
# }}}
# 7: Schedule:Day:List {{{
dt7 <- trans_action(idf, "Schedule:Day:List", reset = list(3L, "yes", "Average"))
# }}}
# 8: Schedule:Compact {{{
dt8 <- trans_action(idf, "Schedule:Compact")
if (nrow(dt8)) {
dt8[index >= 3L & grepl("interpolate.+yes", value, ignore.case = TRUE), value := "Interpolate:Average"]
}
# }}}
trans_process(new_idf, idf, rbindlist(mget(paste0("dt", 1:8))))
trans_postprocess(new_idf, idf$version(), new_idf$version())
}
# }}}
# trans_890_900 {{{
#' @importFrom checkmate assert_true
trans_funs$f890t900 <- function(idf) {
assert_true(idf$version()[, 1:2] == "8.9")
target_cls <- c(
"AirflowNetwork:Distribution:Component:OutdoorAirFlow", # 1
"AirflowNetwork:Distribution:Component:ReliefAirFlow", # 2
"Boiler:HotWater", # 3
"FenestrationSurface:Detailed", # 4
"GlazedDoor", # 5
"RunPeriod:CustomRange", # 6
"RunPeriod", # 7
"Table:OneIndependentVariable", # 8
"WindowMaterial:ComplexShade", # 9
"Window", # 10
"WindowProperty:ShadingControl" # 11
)
new_idf <- trans_preprocess(idf, "9.0", target_cls)
# 1: AirflowNetwork:Distribution:Component:OutdoorAirFlow {{{
dt1 <- trans_action(idf,
class = "AirflowNetwork:Distribution:Component:OutdoorAirFlow",
insert = list(2,
tryCatch(idf$object_name("OutdoorAir:Mixer", simplify = TRUE)[[1L]],
eplusr_error_invalid_class_name = function(e) NA_character_
)
)
)
if (nrow(dt1) && idf$object_num("OutdoorAir:Mixer") > 1L) {
warn("Multiple 'OutdoorAir:Mixer' object found.", "trans_890_900")
}
# }}}
# 2: AirflowNetwork:Distribution:Component:ReliefAirFlow {{{
dt2 <- trans_action(idf, "AirflowNetwork:Distribution:Component:ReliefAirFlow",
insert = list(2,
tryCatch(idf$object_name("OutdoorAir:Mixer", simplify = TRUE)[[1L]],
eplusr_error_invalid_class_name = function(e) NA_character_
)
)
)
if (nrow(dt2) && idf$object_num("OutdoorAir:Mixer") > 1L) {
warn("Multiple 'OutdoorAir:Mixer' object found.", "trans_890_900")
}
# }}}
# 3: Boiler:HotWater {{{
dt3 <- trans_action(idf, "Boiler:HotWater", delete = list(7L))
if (nrow(dt3)) dt3[, index := seq_len(.N), by = "id"]
# }}}
# 4: FenestrationSurface:Detailed {{{
dt4 <- trans_action(idf, "FenestrationSurface:Detailed", delete = list(7L))
if (nrow(dt4)) dt4[, index := seq_len(.N), by = "id"]
# }}}
# 5: GlazedDoor {{{
dt5 <- trans_action(idf, "GlazedDoor", delete = list(4L))
if (nrow(dt5)) dt5[, index := seq_len(.N), by = "id"]
# }}}
# 6: RunPeriod:CustomRange {{{
dt6 <- trans_action(idf, c("RunPeriod" = "RunPeriod:CustomRange"))
if (nrow(dt6)) {
dt6[index == 8L, value := {
if (any(usewthrfile <- tolower(value) == "useweatherfile")) {
warn(paste0(
"For 'RunPeriod:CustomRange' ", surround(name[[1L]]), " [ID:", id[[1L]], "]:\n",
"Option 'UseWeatherFile' for 'Start Day of Week' has been removed, ",
"start week day is set by the input start date."
),
"trans_890_900"
)
value[usewthrfile] <- NA_character_
}
value
}]
}
# }}}
# 7: RunPeriod {{{
dt7 <- trans_action(idf, "RunPeriod", all = TRUE,
insert = list(c(`Begin Year` = 4L)),
insert = list(c(`End Year` = 7L))
)
# calculate start year and do some checkings
if (nrow(dt7)) {
dt7[, value :=
{
start_year <- value[14L + 2L]
num_rep <- value[12L + 2L]
if (!is.na(start_year)) {
if (!checkmate::test_count(as.numeric(start_year))) {
abort(paste0(
"For 'RunPeriod' ", surround(name[[1L]]), " [ID:", id[[1L]], "]:\n",
"Invalid 'Start Year' value (", surround(start_year), ") found."
))
}
# if start year is set in the old run period, use it
value[4L] <- start_year
}
start_year <- as.integer(start_year)
# convert num of repeats to integer
if (!is.na(num_rep)) {
if (!checkmate::test_count(as.numeric(num_rep))) {
abort(paste0(
"For 'RunPeriod' ", surround(name[[1L]]), " [ID:", id[[1L]], "]:\n",
"Invalid 'Number of Times Runperiod to be Repeated' value (",
surround(num_rep), ") found."
))
}
if (!is.na(value[8L]) && tolower(value[8L]) == "useweatherfile") {
warn(paste0(
"For 'RunPeriod' ", surround(name[[1L]]), " [ID:", id[[1L]], "]:\n",
"Option 'UseWeatherFile' for 'Start Day of Week' has been removed, ",
"start week day is set by the input start date."
),
"trans_890_900"
)
value[8L] <- NA_character_
}
num_rep <- as.integer(num_rep)
} else {
num_rep <- 0L
if (!is.na(value[8L]) && tolower(value[8L]) == "useweatherfile") {
warn(paste0(
"For 'RunPeriod' ", surround(name[[1L]]), " [ID:", id[[1L]], "]:\n",
"Option 'UseWeatherFile' for 'Start Day of Week' has been removed, ",
"start week day is set by the input start date."
),
"trans_890_900"
)
value[8L] <- NA_character_
}
}
if (num_rep > 1L) {
# for case when start year is given
if (!is.na(start_year)) {
if (!is.na(value[8L]) && tolower(value[8L]) == "useweatherfile") {
warn(paste0(
"For 'RunPeriod' ", surround(name[[1L]]), " [ID:", id[[1L]], "]:\n",
"Option 'UseWeatherFile' for 'Start Day of Week' has been removed, ",
"start week day is set by the input start date."
),
"trans_890_900"
)
value[8L] <- NA_character_
}
# if start year is not set but repeat times larger than 1
# need to calculate start year
} else {
# in case of leap year
start_date <- lubridate::make_date(year = 2016L, month = value[2L], day = value[3L])
# validate start month and day
if (is.na(start_date)) {
abort(paste0(
"For 'RunPeriod' ", surround(name[[1L]]), " [ID:", id[[1L]], "]:\n",
"Invalid 'Start Month' (", surround(value[2]), ") or ",
"'Start Day of Month' (", surround(value[3]), ") found."
))
}
# validate day of week
if (is.na(value[8L])) {
# Sunday
weekday <- 1L
} else if (tolower(value[8L]) == "useweatherfile") {
warn(paste0(
"For 'RunPeriod' ", surround(name[[1L]]), " [ID:", id[[1L]], "]:\n",
"Option 'UseWeatherFile' for 'Start Day of Week' has been removed, ",
"start week day is set by the input start date."
),
"trans_890_900"
)
value[8L] <- NA_character_
# Sunday
weekday <- 0L
} else {
weekday <- get_epw_wday(value[8L], monday_start = FALSE)
if (is.na(weekday)) {
warn(paste0(
"For 'RunPeriod' ", surround(name[[1L]]), " [ID:", id[[1L]], "]:\n",
"Invalid 'Start Day of Week' (", surround(value[8L]), ") found. ",
"Assuming 'Sunday'."
),
"trans_890_900"
)
}
}
# NOTE: just to make sure the year calculation results are
# the same as VersionUpdater
YEARS <- c(2013, 2014, 2015, 2010, 2011, 2017, 2007, 2013, 2014, 2015, 2010, 2011, 2017)
LYEARS <- c(2008, 1992, 2004, 2016, 2000, 2012, 1996, 2008, 1992, 2004, 2016, 2000, 2012)
if (lubridate::month(start_date) == 2 && lubridate::mday(start_date) == 29) {
leap <- TRUE
} else {
leap <- FALSE
lubridate::year(start_date) <- 2017L
}
ord <- lubridate::yday(start_date)
rem <- ord %% 7L
# start year
if (leap) {
start_year <- LYEARS[weekday - rem + 6]
} else {
start_year <- YEARS[weekday - rem + 6]
}
value[4L] <- as.character(start_year)
}
# end year
end_year <- start_year + num_rep
value[7L] <- as.character(end_year)
end_month <- assert_integerish(as.numeric(value[5L]), len = 1L, lower = 1L, upper = 12L, any.missing = FALSE, coerce = TRUE, .var.name = "End Month")
end_day <- assert_integerish(as.numeric(value[6L]), len = 1L, lower = 1L, upper = 31L, any.missing = FALSE, coerce = TRUE, .var.name = "End Day of Month")
# check if leap day of end date is specified in an non-leap year
if ((!leap_year(end_year)) && end_month == 2L && end_day == 29L) {
warn(paste0(
"For 'RunPeriod' ", surround(name[[1L]]), " [ID:", id[[1L]], "]:\n",
"With 'Number of Times Runperiod to be Repeated' being ", num_rep,
"the end year will be ", end_year, ", which is not a leap year. ",
"The end date will be reset to Feb 28th."
), "trans_890_900")
value[6L] <- "28"
}
# validate end month and day
end_date <- lubridate::make_date(year = end_year, month = end_month, day = end_day)
# validate start month and day
if (is.na(end_date)) {
abort(paste0(
"For 'RunPeriod' ", surround(name[[1L]]), " [ID:", id[[1L]], "]:\n",
"Invalid 'End Month' (", surround(value[2]), ") or ",
"'End Day of Month' (", surround(value[3]), ") found."
))
}
}
value
},
by = "id"
]
dt7 <- dt7[!J(c(15L:16L)), on = "index"][J(14L), on = "index", value := NA_character_]
}
# }}}
# 8: Table:OneIndependentVariable {{{
dt8 <- trans_action(idf, "Table:OneIndependentVariable", reset = list(2L, "exponent", NA_character_))
# }}}
# 9: WindowMaterial:ComplexShade {{{
dt9 <- trans_action(idf, "WindowMaterial:ComplexShade",
reset = list(2L, "venetian", "VenetianHorizontal")
)
# }}}
# 10: Window {{{
dt10 <- trans_action(idf, "Window", delete = list(4L))
if (nrow(dt10)) dt10[, index := seq_len(.N), by = "id"]
# }}}
# 11: WindowProperty:ShadingControl {{{
if (!idf$is_valid_class("WindowProperty:ShadingControl")) {
dt11 <- data.table()
} else {
# get all old shading control objects
shadctrl <- idf$objects_in_class("WindowProperty:ShadingControl")
# get zone that is being controled {{{
fene_daylight_zone <- lapply(shadctrl,
function(ctrl) {
# get all fenestrations that uses this control
fene <- with_silent(ctrl$ref_by_object("Name",
class = c("FenestrationSurface:Detailed", "Window", "GlazedDoor")
))
if (!length(fene)) {
data.table(id_ctrl = ctrl$id(), name_ctrl = ctrl$name(),
id_fene = NA_integer_, name_fene = NA_character_,
id_zone = NA_integer_, name_zone = NA_character_,
id_daylgt = NA_integer_, name_daylgt = NA_character_
)
} else {
# use low-level API to speed up
fene <- data.table(id_fene = viapply(fene, function(f) f$id()), name_fene = names(fene))
surf <- get_idf_value(
get_priv_env(idf)$idd_env(),
get_priv_env(idf)$idf_env(),
object = fene$id_fene, field = rep("Building Surface Name", nrow(fene)),
align = TRUE
)
# combine
fene[surf, on = c("id_fene" = "object_id"), `:=`(id_surf = i.value_id, name_surf = i.value_chr)]
# get zone name this fenestration belongs to
zone <- get_idf_relation(
get_priv_env(idf)$idd_env(),
get_priv_env(idf)$idf_env(),
value_id = unique(fene$id_surf), name = TRUE,
direction = "ref_to", keep_all = TRUE, depth = 1
)
# get surface name
surf <- zone[dep == 0L, list(id_surf = src_object_id, name_surf = value_chr)]
# get zone name
zone <- zone[J(1L, "Zone"), on = c("dep", "src_class_name")][
surf, on = c("object_id" = "id_surf"), list(id_zone = src_object_id, name_zone = value_chr)]
# combine
set(fene, NULL, c("id_zone", "name_zone"), zone)
# get daylighting control for each zone
daylgt <- get_idf_relation(
get_priv_env(idf)$idd_env(),
get_priv_env(idf)$idf_env(),
object_id = unique(zone$id_zone), name = TRUE,
direction = "ref_by", keep_all = TRUE
)[class_name == "Daylighting:Controls",
list(id_zone = src_object_id, id_daylgt = object_id)]
# get daylighting control name
if (!nrow(daylgt)) {
set(daylgt, NULL, "name_daylgt", character())
} else {
daylgt[get_priv_env(idf)$idf_env()$object, on = c("id_daylgt" = "object_id"),
name_daylgt := i.object_name
]
}
# combine
fene[daylgt, on = "id_zone", `:=`(id_daylgt = i.id_daylgt, name_daylgt = i.name_daylgt)]
# add control id and name
set(fene, NULL, c("id_ctrl", "name_ctrl"), list(ctrl$id(), ctrl$name()))
# clean
set(fene, NULL, c("id_surf", "name_surf"), NULL)
}
}
)
# }}}
fene_daylight_zone <- rbindlist(fene_daylight_zone, use.names = TRUE)[,
list(rleid = .GRP, name_fene = list(name_fene)),
by = c("id_ctrl", "id_zone", "name_ctrl", "name_zone", "name_daylgt")
]
dt11 <- trans_action(idf, all = TRUE,
class = c("WindowShadingControl" = "WindowProperty:ShadingControl"),
insert = list(c(`Zone Name` = 2L, `Shading Control Sequence Number` = 3L)),
add = list(c(`Daylighting Control Object Name` = 15L,
`Multiple Surface Control Type` = 16L
))
)
# duplicate
dt11 <- rbindlist(lapply(seq.int(nrow(fene_daylight_zone)), function(i) {
set(copy(dt11), NULL, "rleid", i)
}))
# update name with zone name suffix
set(fene_daylight_zone, NULL, "index", 1L)
dt11[fene_daylight_zone, on = c("rleid", "id" = "id_ctrl", "index"), value := {
found <- !is.na(value) & !is.na(i.name_zone)
value[found] <- paste0(value[found], "-", i.name_zone[found])
value
}]
# update zone name
set(fene_daylight_zone, NULL, "index", 2L)
dt11[fene_daylight_zone, on = c("rleid", "id" = "id_ctrl", "index"), value := i.name_zone]
# assign new object ID
fene_daylight_zone[, id_ctrl := new_id(get_priv_env(idf)$idf_env()$object, "object_id", .N)]
# update dt
dt11[fene_daylight_zone, on = "rleid", id := i.id_ctrl]
# if unused, remove and throw a warning
if (nrow(empty <- dt11[J(2L, NA_character_), on = c("index", "value"), nomatch = 0L])) {
warn(paste0(
"WindowProperty:ShadingControl = ",
collapse(unique(empty[, {ifelse(is.na(name), "", (name))}])),
" was not used by any surfaces, so it has been deleted.",
collpase = "\n"
), "trans_890_900")
dt11 <- dt11[!empty, on = c("id", "name")]
fene_daylight_zone <- fene_daylight_zone[!empty, on = c("id_ctrl" = "id", "name_ctrl" = "name")]
}
if (!nrow(dt11)) {
dt11 <- data.table()
} else {
# update control sequence
set(fene_daylight_zone, NULL, "index", 3L)
fene_daylight_zone[, ctrl_seq := seq_along(.N), by = "id_zone"]
dt11[fene_daylight_zone, on = c("rleid", "id" = "id_ctrl", "index"), value := as.character(ctrl_seq)]
# update multiple surface control type name
dt11[, value := {
if (!is.na(value[[4L]]) & tolower(value[[4L]]) == "switchableglazing" &&
!is.na(value[[6L]]) & tolower(value[[6L]]) == "meetdaylightilluminancesetpoint"
) {
value[[16]] <- "Group"
} else {
value[[16]] <- "Sequential"
}
value
}, by = "id"]
# update daylighting control name
set(fene_daylight_zone, NULL, "index", 15L)
dt11[fene_daylight_zone, on = c("rleid", "id" = "id_ctrl", "index"), value := i.name_daylgt]
# add fenestration surface names
fene_fld <- fene_daylight_zone[, list(
name = NA_character_,
class = "WindowShadingControl",
index = seq_along(unlist(name_fene)) + 16L,
field = NA_character_,
value = unlist(name_fene)
), by = "rleid"]
fene_fld[dt11, on = "rleid", id := i.id]
dt11 <- rbindlist(list(dt11, fene_fld), use.names = TRUE)
setorderv(dt11, c("id", "index"))
set(dt11, NULL, "rleid", NULL)
}
}
# }}}
trans_process(new_idf, idf, rbindlist(mget(paste0("dt", 1:11))))
trans_postprocess(new_idf, idf$version(), new_idf$version())
}
# }}}
# trans_900_910 {{{
#' @importFrom checkmate assert_true
trans_funs$f900t910 <- function(idf) {
assert_true(idf$version()[, 1:2] == "9.0")
target_cls <- c(
"HybridModel:Zone", # 1
"ZoneHVAC:EquipmentList" # 2
)
new_idf <- trans_preprocess(idf, "9.1", target_cls)
# 1: HybridModel:Zone {{{
dt1 <- trans_action(idf, "HybridModel:Zone", all = 9L,
# Old [6:9] --> New [17:20]
offset = list(6:9, 17:20),
# Old NA --> New [7:16]
add = list(7:16),
# Old [5] --> New [6]
offset = list(5L, 6L),
# Old NA --> New [5]
add = list(5L, "No")
)
# }}}
# 2: ZoneHVAC:EquipmentList {{{
dt2 <- trans_action(idf, "ZoneHVAC:EquipmentList", min_fields = 6L,
# Old NA --> New [7:8] with step 4
insert = list(7:8, NA, 4L)
)
# }}}
trans_process(new_idf, idf, rbindlist(mget(paste0("dt", 1:2))))
trans_postprocess(new_idf, idf$version(), new_idf$version())
}
# }}}
# trans_910_920 {{{
#' @importFrom checkmate assert_true
trans_funs$f910t920 <- function(idf) {
assert_true(idf$version()[, 1:2] == "9.1")
target_cls <- c(
"Foundation:Kiva", # 1
"RunPeriod", # 2
"Schedule:File", # 3
"Table:OneIndependentVariable", # 4
"Table:TwoIndependentVariables", # 5
"Table:MultiVariableLookup", # 6
"ThermalStorage:Ice:Detailed", # 7
"ZoneHVAC:EquipmentList" # 8
)
new_idf <- trans_preprocess(idf, "9.2", target_cls)
# 1: Foundation:Kiva {{{
dt1 <- trans_action(idf, "Foundation:Kiva", insert = list(2L))
# }}}
# 2: RunPeriod {{{
dt2 <- trans_action(idf, "RunPeriod")
if (nrow(dt2)) {
dt2[J(1L), on = "index", value := {
# get exiting run period number
existing <- stri_match_first_regex(stri_trans_tolower(value), "^runperiod (\\d+)$")[, 2L]
existing <- as.integer(existing)
# get number of run period without names
n <- sum(is.na(value))
# valid index left
valid <- setdiff(seq.int(.N), existing)
if (n >= length(valid)) {
new <- c(valid, seq(max(valid) + 1L, length.out = n - length(valid)))
} else {
new <- valid[seq.int(n)]
}
value[is.na(value)] <- paste("RUNPERIOD", new)
value
}]
}
# }}}
# 3: Schedule:File {{{
dt3 <- trans_action(idf, "Schedule:File", reset = list(7, "fixed", "SPACE"))
# }}}
id_max <- 0L
# init_var_dt {{{
init_var_dt <- function(dt, i_expr = NULL, min_max, type) {
dt <- if (is.null(i_expr)) copy(dt) else dt[eval(i_expr)]
# calculate fields should be added
to_add <- setdiff(c(min_max, type), c(4L:5L, 7L))
# only add fields with index no more than 10
if (length(to_add)) to_add <- to_add[to_add <= 10L]
trans_action_dt(dt,
offset = list(min_max, 4L:5L),
offset = list(type, 7L),
add = list(to_add, NA_character_),
reset = list(6L, NA_character_),
reset = list(8L:10L, NA_character_)
)
}
# }}}
# init_var_type {{{
init_var_type <- function(dt, index_cond = 3L) {
set(dt, NULL, "value_lower", stri_trans_tolower(dt$value))
id_const <- dt[index == index_cond & value_lower == "linearinterpolationoftable", id]
id_linear <- dt[index == index_cond & value_lower == "lagrangeinterpolationlinearextrapolation", id]
set(dt, NULL, "value_lower", NULL)
dt[J(id_const), on = "id", value := {
value[2] <- "Linear"
value[3] <- "Constant"
value
}, by = "id"]
dt[J(id_linear), on = "id", value := {
value[2] <- "Cubic"
value[3] <- "Linear"
value
}, by = "id"]
dt[!J(c(id_const, id_linear)), on = "id", value := {
value[2] <- "Cubic"
value[3] <- "Constant"
value
}, by = "id"]
dt[J(1L, NA_character_), on = c("index", "value"), value := ""]
dt[, index := seq.int(.N), by = "id"]
}
# }}}
# init_list_dt {{{
init_list_dt <- function(dt, num) {
if (is.integer(num)) {
dt <- dt[J(rep(1L, num + 1L)), on = "index"]
} else if (is.data.frame(num)) {
dt <- dt[num, on = c("id", "index")]
dt[dt[J(1L), on = "index"], on = "id", value := i.value]
}
dt[, index := seq.int(.N), by = "id"]
set(dt, NULL, "class", "Table:IndependentVariableList")
dt[is.na(value), value := ""]
dt[J(1L), on = "index", value := paste0(value, "_IndependentVariableList")]
dt[index > 1L, value := paste0(value, "_IndependentVariable", seq.int(.N)), by = "id"]
setorderv(dt, "id")
dt
}
# }}}
# init_lookup_dt {{{
init_lookup_dt <- function(dt, i_expr = NULL, ref = 10L, min_max = 6L:7L, type = 9L, del = NULL) {
dt <- if (is.null(i_expr)) copy(dt) else dt[eval(i_expr)]
dt[, class := "Table:Lookup"]
dt[J(1L, NA_character_), on = c("index", "value"), value := ""]
dt[J(c(1L:2L)), on = "index", value := {
value[2L] <- paste0(value[1L], "_IndependentVariableList")
value
}, by = "id"]
# calculate fields should be added
to_add <- setdiff(c(ref, min_max, type), c(4L:7L))
# only add fields with index no more than 10
if (length(to_add)) to_add <- to_add[to_add <= 10L]
dt <- trans_action_dt(dt,
offset = list(ref, 4L),
offset = list(min_max, 5L:6L),
offset = list(type, 7L),
add = list(to_add),
reset = list(8L:10L, NA_character_)
)
if (!is.null(del)) dt <- dt[!J(del), on = "index"]
dt[J(c(3L, 4L)), on = "index", value := {
value[[1L]] <- if (is.na(value[[2L]])) NA_character_ else "DivisorOnly"
value
}, by = "id"]
dt[, index := seq.int(.N), by = "id"]
dt
}
# }}}
# warn_removed_as_comment {{{
warn_removed_as_comment <- function(idf, class) {
warn(paste0("Class '", class, "' has been removed in EnergyPlus v9.2. ",
"Objects in that class will be listed as comments in the new output file."
), "trans_910_920")
# separate by objects
cmt <- idf$to_string(class = class, header = FALSE, format = "new_top")
sep <- which(stri_isempty(cmt))
cmt <- apply2(c(1L, sep[-length(sep)] + 1L), sep - 1L,
function(start, end) cmt[start:end]
)
# assign to object table
ids <- idf$object_id(class = class, simplify = TRUE)
get_priv_env(idf)$idf_env()$object[J(ids), on = "object_id", comment := list(cmt)]
}
# }}}
# warn_table_convert {{{
warn_table_convert <- function(dt, class, idx, ascending = NULL) {
dt_file <- dt[index == idx & !is.na(value)]
if (!nrow(dt_file)) return(dt)
# rename column for formatting object info
setnames(dt_file, c("id", "name", "class"), c("object_id", "object_name", "class_name"))
obj <- get_object_info(dt_file, c("name", "id"), numbered = TRUE)
# get file path
files <- dt_file$value
warn(paste0("Objects in Class '", class, "' references external ",
"file. External files must be converted to the new format and saved ",
"to CSV with a name suffix '-New':\n",
paste0(obj, ": ", surround(files))
), "trans_910_920")
# convert
if (is.null(ascending)) {
tables <- lapply(files, trans_table_convert)
} else {
assert_same_len(files, ascending)
tables <- apply2(files, ascending, trans_table_convert)
}
# save
files <- paste0(tools::file_path_sans_ext(basename(files)), "-New.csv")
apply2(tables, files, function(x, file) fwrite(x, file))
# update field value
dt[index == idx & !is.na(value), value := normalizePath(files)]
dt
}
# }}}
# assert_integer {{{
assert_integer <- function(dt, idx = NULL, col = "value", name) {
if (!is.null(idx)) dt <- dt[J(idx), on = "index"]
set(dt, NULL, col, suppressWarnings(as.integer(dt[[col]])))
if (!anyNA(dt[[col]])) return(dt)
abort(paste0("Failed to get ", name, "objects below:\n", obj_info(dt)))
}
# }}}
# obj_info {{{
obj_info <- function(dt, numbered = TRUE, collapse = "\n") {
setnames(dt, c("id", "name", "class"), c("object_id", "object_name", "class_name"))
get_object_info(dt, c("name", "id"), numbered = numbered, collapse = collapse)
}
# }}}
# 4: Table:OneIndependentVariable {{{
dt4 <- trans_action(idf, min_fields = 10L, c("Table:IndependentVariable" = "Table:OneIndependentVariable"))
if (nrow(dt4)) {
warn_removed_as_comment(idf, "Table:OneIndependentVariable")
# independent variable
dt4_1 <- init_var_dt(dt4,
quote(index <= 10L | (index > 10L & (index - 11) %% 2 == 0)),
min_max = 4L:5L, type = 8L
)
dt4_1 <- init_var_type(dt4_1, 3L)
dt4_1[J(1L), on = "index", value := paste0(value, "_IndependentVariable1")]
# variable list
dt4_2 <- init_list_dt(dt4, 1L)
dt4_2[, id := -.GRP + id_max, by = "id"]
id_max <- min(dt4_2$id)
# lookup
dt4_3 <- init_lookup_dt(dt4,
quote(index <= 10L | (index > 10L & (index - 12) %% 2 == 0)),
ref = 10L, min_max = 6L:7L, type = 9L
)
dt4_3[, id := -.GRP + id_max, by = "id"]
id_max <- min(dt4_3$id)
dt4 <- rbindlist(list(dt4_1, dt4_2, dt4_3))
}
# }}}
# 5: Table:TwoIndependentVariables {{{
dt5 <- trans_action(idf, min_fields = 14L, align = FALSE,
c("Table:IndependentVariable" = "Table:TwoIndependentVariables")
)
if (nrow(dt5)) {
warn_removed_as_comment(idf, "Table:TwoIndependentVariables")
dt5 <- warn_table_convert(dt5, "Table:TwoIndependentVariables", 14L)
val <- dt5[index > 14, by = "id", {
val <- matrix(suppressWarnings(as.numeric(value)), ncol = 3L, byrow = TRUE)
val <- setnames(as.data.table(val), c("x", "y", "out"))
setorderv(val, c("x", "y"))
list(x = list(unique(val$x)), y = list(unique(val$y)), out = list(val$out)
)
}]
# independent variable
## X
dt5_11 <- init_var_dt(dt5, quote(index <= 10L), min_max = 4L:5L, type = 10L)
dt5_11 <- init_var_type(dt5_11, 3L)
dt5_11[J(1L), on = "index", value := paste0(value, "_IndependentVariable1")]
dt5_11 <- rbindlist(fill = TRUE, list(
dt5_11,
val[, by = "id", list(class = "Table:IndependentVariable",
index = 10L + seq_along((x[[1L]])), value = as.character(x[[1L]]))]
))
## Y
dt5_12 <- init_var_dt(dt5, quote(index <= 11L), min_max = 6L:7L, type = 11L)
dt5_12 <- init_var_type(dt5_12, 3L)
dt5_12[J(1L), on = "index", value := paste0(value, "_IndependentVariable2")]
dt5_12 <- rbindlist(fill = TRUE, list(
dt5_12,
val[, by = "id", list(class = "Table:IndependentVariable",
index = 10L + seq_along((y[[1L]])), value = as.character(y[[1L]]))]
))
dt5_12[, id := -.GRP + id_max, by = "id"]
id_max <- min(dt5_12$id)
## merge
dt5_1 <- rbindlist(list(dt5_11, dt5_12))
# variable list
dt5_2 <- init_list_dt(dt5, 2L)
dt5_2[, id := -.GRP + id_max, by = "id"]
id_max <- min(dt5_2$id)
# lookup
dt5_3 <- init_lookup_dt(dt5, quote(index <= 13L), ref = 13L, min_max = 8L:9L, type = 12L, del = 11L)
dt5_3 <- rbindlist(fill = TRUE, list(
dt5_3,
val[, by = "id", list(class = "Table:Lookup",
index = 10L + seq_along((out[[1L]])), value = as.character(out[[1L]]))]
))
dt5_3[, id := -.GRP + id_max, by = "id"]
id_max <- min(dt5_3$id)
dt5 <- rbindlist(list(dt5_1, dt5_2, dt5_3))
setorderv(dt5, c("id", "index"))
}
# }}}
# 6: Table:MultiVariableLookup {{{
dt6 <- trans_action(idf, min_fields = 31L, align = FALSE,
c("Table:IndependentVariable" = "Table:MultiVariableLookup")
)
if (nrow(dt6)) {
warn_removed_as_comment(idf, "Table:MultiVariableLookup")
# get sort order
asc <- dt6[J(c(7L, 8L)), on = "index",
list(asc = list(is.na(value) | stri_trans_tolower(value) == c("ascending", "ascending"))),
by = "id"]$asc
# convert external file if possible
dt6 <- warn_table_convert(dt6, "Table:MultiVariableLookup", 6L, asc)
# independent variable {{{
# get independent variable number
num_vars <- dt6[J(31L), on = "index"]
set(num_vars, NULL, "value", suppressWarnings(as.integer(num_vars$value)))
if (anyNA(num_vars$value)) {
abort(paste0("Failed to get number of independent variables for 'Table:MultiVariableLookup' objects ",
"objects below:\n", obj_info(num_vars[is.na(value)])
))
}
# get indices for different fields
meta <- num_vars[, {
idx <- seq.int(value)
list(idx_var = idx,
min = as.integer(10L + 2 * (idx - 1L)),
max = as.integer(11L + 2 * (idx - 1L)),
type = 23L + idx,
number = 31L + idx
)
}, by = "id"]
# get value number
meta[dt6, on = c("id", "number" = "index"), val_number := suppressWarnings(as.integer(i.value))]
if (anyNA(meta$val_number)) {
invld <- meta[is.na(val_number), list(id, idx_var)]
invld <- num_vars[invld, on = "id"]
obj <- obj_info(invld, collapse = NULL)
mes <- paste0(obj, " for independent variable #", invld$idx_var)
abort(paste0("Failed to get value number of independent variables for 'Table:MultiVariableLookup' objects below:\n", mes))
}
meta[, cum := cumsum(data.table::shift(val_number, fill = 0L)), by = "id"]
meta[, c("start", "end") := {
start <- number + max(idx_var) - idx_var + 1L + cum
list(start = start, end = start + val_number - 1L)
}, by = "id"]
# assign id
meta[, object_id := id]
meta[idx_var > 1L, object_id := -.I + id_max]
id_max <- min(meta$object_id)
# reusable fields
dt6_1 <- init_var_type(dt6[index <= 10L], 2L)
meta_1 <- data.table::CJ(
object_id = meta$object_id, index = c(1L:3L, 6L, 8L:10L))[
meta[, list(id, object_id)], on = "object_id"]
dt6_11 <- dt6_1[meta_1, on = c("id", "index")][
index %in% 8L:10L, value := NA_character_]
dt6_11[J(1L), on = "index", value := paste0(value, "_IndependentVariable", seq.int(.N)), by = "id"]
# melt
meta_2 <- melt.data.table(meta, id.vars = c("id", "idx_var", "object_id"),
measure.vars = c("min", "max", "type"), value.name = "index"
)
meta_2[J("min"), on = "variable", field_index := 4L]
meta_2[J("max"), on = "variable", field_index := 5L]
meta_2[J("type"), on = "variable", field_index := 7L]
dt6_12 <- dt6[meta_2[, list(id, index, object_id, field_index)], on = c("id", "index")]
set(dt6_12, NULL, "index", NULL)
setnames(dt6_12, "field_index", "index")
# variable values
meta_3 <- meta[,
list(id = rep(id, val_number),
index = seq(start, end),
field_index = seq.int(val_number) + 10L
),
by = "object_id"
]
dt6_13 <- dt6[meta_3, on = c("id", "index")]
set(dt6_13, NULL, "index", NULL)
setnames(dt6_13, "field_index", "index")
dt6_1 <- rbindlist(list(dt6_11, dt6_12, dt6_13), use.names = TRUE)
# retain object order
setorderv(dt6_1, c("id", "index"))
dt6_1 <- dt6_1[J(meta$object_id), on = "object_id"]
# update object id
set(dt6_1, NULL, "id", NULL)
setnames(dt6_1, "object_id", "id")
setcolorder(dt6_1, "id")
# }}}
# variable list
dt6_2 <- init_list_dt(dt6,
rbindlist(list(
num_vars[, list(id, index = 1L)],
meta[, list(id, index = idx_var)]
))
)
dt6_2[, id := -.GRP + id_max, by = "id"]
id_max <- min(dt6_2$id)
# lookup object {{{
dt6_31 <- init_lookup_dt(dt6, quote(index <= 30L),
ref = 9L, min_max = 22L:23L, type = 30L
)[index <= 10L]
meta_out <- meta[
, list(# where to start
start = max(end) + 1L,
# variable #3 above should be listed before output data
step = if (.N <= 2L) 0L else .N - 2L,
# number of output data per variable #1
num = if (.N <= 2L) 0L else val_number[[1L]] * val_number[[2L]]
), by = "id"][
dt6[, list(end = max(which(!is.na(value)))), by = "id"], on = "id"]
# get exact field index for each value
meta_out <- meta_out[, list(index = {
# for case when variable number no more than 2
if (step == 0L) {
seq(start, end)
} else {
# for case when variable number more than 2
unlist(lapply(seq(start + step, end, by = step + num), seq, length.out = num))
}
}), by = "id"]
dt6_32 <- dt6[meta_out, on = c("id", "index")]
dt6_32[, index := seq.int(.N) + 10L, by = "id"]
dt6_32[, class := "Table:Lookup"]
# split by independent variables in each object
vars <- split(dt6_13[, list(id, object_id, value = suppressWarnings(as.numeric(value)))],
by = c("id", "object_id"), flatten = FALSE, keep.by = FALSE
)
# reverse the order of independent variables and unlist
vars <- apply2(vars, asc, function(var, ascending) {
var <- lapply(var, unlist, use.names = FALSE)
if (!ascending[1L] && length(var) >= 1L) var[[1L]] <- rev(var[[1L]])
if (!ascending[2L] && length(var) >= 2L) var[[2L]] <- rev(var[[2L]])
var
})
vars <- lapply(vars, rev)
# get combination
cj <- function(...) data.table::CJ(..., sorted = FALSE, unique = FALSE)
vars <- lapply(vars, function(x) do.call(cj, x))
# get output
outs <- split(dt6_32[, list(id, value)], by = "id", keep.by = FALSE)
outs <- lapply(outs, unlist, use.names = FALSE)
# combine value and output
vals <- apply2(vars, outs, function(var, out) set(var, NULL, "value", out))
# change order
vals <- lapply(vals, function(dt) setorderv(dt, rev(setdiff(names(dt), "value"))))
# replace with ordered values
set(dt6_32, NULL, "value", as.character(unlist(lapply(vals, "[[", "value"))))
dt6_3 <- rbindlist(list(dt6_31, dt6_32))
dt6_3[, id := -.GRP + id_max, by = "id"]
# }}}
dt6 <- rbindlist(list(dt6_1, dt6_2, dt6_3))
setorderv(dt6, c("id", "index"))
}
# }}}
# 7: ThermalStorage:Ice:Detailed {{{
dt7 <- trans_action(idf, "ThermalStorage:Ice:Detailed",
reset = list(6L, "quadraticlinear", "FractionDischargedLMTD"),
reset = list(6L, "cubiclinear", "LMTDMassFlow"),
reset = list(8L, "quadraticlinear", "FractionChargedLMTD"),
reset = list(8L, "cubiclinear", "LMTDMassFlow")
)
# }}}
# 8: ZoneHVAC:EquipmentList {{{
dt8 <- trans_action(idf, "ZoneHVAC:EquipmentList")
if (nrow(dt8)) {
clg <- dt8[index > 2L & ((index - 2L) - 5L) %% 6 == 0L & !is.na(value)]
if (!nrow(clg)) {
dt8_1 <- data.table()
} else {
clg[, object_id := -.I + id_max]
clg[is.na(name), name := ""]
dt8_1 <- clg[, list(id, class = "Schedule:Constant", index = 1L:3L,
value = c(
paste0(name, " CoolingFrac", as.integer((index - 3L) / 6L + 1L)),
"ZoneEqList ScheduleTypeLimits",
value
)
), by = "object_id"]
id_max <- min(clg$object_id)
# update value
set(clg, NULL, "value", dt8_1[index == 1L, value])
dt8[clg, on = c("id", "index"), value := i.value]
# clean
set(dt8_1, NULL, "id", NULL)
setnames(dt8_1, "object_id", "id")
}
htg <- dt8[index > 2L & ((index - 2L) - 6L) %% 6 == 0L & !is.na(value)]
if (!nrow(htg)) {
dt8_2 <- data.table()
} else {
htg[, object_id := -.I + id_max]
htg[is.na(name), name := ""]
dt8_2 <- htg[, list(id, class = "Schedule:Constant", index = 1L:3L,
value = c(
paste0(name, " HeatingFrac", as.integer((index - 3L) / 6L + 1L)),
"ZoneEqList ScheduleTypeLimits",
value
)
), by = "object_id"]
id_max <- min(htg$object_id)
# update value
set(htg, NULL, "value", dt8_2[index == 1L, value])
dt8[htg, on = c("id", "index"), value := i.value]
# clean
set(dt8_2, NULL, "id", NULL)
setnames(dt8_2, "object_id", "id")
}
# add a schedule type object for sequential clg/htg fraction
if ((nrow(dt8_1) || nrow(dt8_2)) &&
(
!idf$is_valid_class("ScheduleTypeLimits") ||
!idf$is_valid_name("ZoneEqList ScheduleTypeLimits")
)
) {
new_idf$add(ScheduleTypeLimits = list("ZoneEqList ScheduleTypeLimits", 0.0, 1.0, "Continuous"))
}
dt8 <- rbindlist(list(dt8, dt8_1, dt8_2), fill = TRUE)
}
# }}}
trans_process(new_idf, idf, rbindlist(mget(paste0("dt", 1:8))))
trans_postprocess(new_idf, idf$version(), new_idf$version())
}
# }}}
# trans_920_930 {{{
#' @importFrom checkmate assert_true
trans_funs$f920t930 <- function(idf) {
assert_true(idf$version()[, 1:2] == "9.2")
target_cls <- c(
"AirConditioner:VariableRefrigerantFlow", # 1
"AirTerminal:SingleDuct:Uncontrolled", # 2
"ZoneHVAC:EquipmentList", # 3
"AirLoopHVAC:ZoneSplitter", # 4
"AirLoopHVAC:SupplyPlenum", # 5
"AirLoopHVAC", # 6
"RoomAir:Node:AirflowNetwork:HVACEquipment", # 7
"AirflowNetwork:Distribution:Node", # 8
"AirflowNetwork:Distribution:Linkage", # 9
"Boiler:HotWater", # 10
"Boiler:Steam", # 11
"Chiller:EngineDriven", # 12
"Chiller:CombustionTurbine", # 13
"ChillerHeater:Absorption:DirectFired", # 14
"Coil:Cooling:DX:MultiSpeed", # 15
"Coil:Heating:Fuel", # 16
"Coil:Heating:DX:MultiSpeed", # 17
"EnergyManagementSystem:Program", # 18
"EnergyManagementSystem:Subroutine", # 19
"EnergyManagementSystem:MeteredOutputVariable", # 20
"Exterior:FuelEquipment", # 21
"FuelFactors", # 22
"Generator:CombustionTurbine", # 23
"Generator:InternalCombustionEngine", # 24
"Generator:MicroTurbine", # 25
"GlobalGeometryRules", # 26
"HeatPump:WaterToWater:EIR:Heating", # 27
"HeatPump:WaterToWater:EIR:Cooling", # 28
"HVACTemplate:System:VRF", # 29
"HVACTemplate:Plant:Boiler", # 30
"LifeCycleCost:UsePriceEscalation", # 31
"LifeCycleCost:UseAdjustment", # 32
"OtherEquipment", # 33
"Output:Table:SummaryReports", # 34
"ShadowCalculation", # 35
"WaterHeater:Mixed", # 36
"WaterHeater:Stratified", # 37
"ZoneHVAC:HybridUnitaryHVAC" # 38
)
new_idf <- trans_preprocess(idf, "9.3", target_cls)
# fix_fuel_types {{{
fix_fuel_types <- function(dt, idx) {
if (!nrow(dt)) return(dt)
input <- dt[J(idx), on = "index", nomatch = NULL]
if (!nrow(input)) return(dt)
set(input, NULL, "value", stri_trans_tolower(input$value))
map <- data.table(
old = c(
"electricity",
"electric",
"elec",
"gas",
"naturalgas",
"natural gas",
"propane",
"propanegas",
"lpg",
"propane gas",
"fueloil#1",
"fuel oil #1",
"fuel oil",
"distillate oil",
"distillateoil",
"fueloil#2",
"fuel oil #2",
"residual oil",
"residualoil"
),
new = c(
"Electricity",
"Electricity",
"Electricity",
"NaturalGas",
"NaturalGas",
"NaturalGas",
"Propane",
"Propane",
"Propane",
"Propane",
"FuelOilNo1",
"FuelOilNo1",
"FuelOilNo1",
"FuelOilNo1",
"FuelOilNo1",
"FuelOilNo2",
"FuelOilNo2",
"FuelOilNo2",
"FuelOilNo2"
)
)
input[map, on = c("value" = "old"), value := i.new]
dt[input, on = c("id", "index"), value := i.value]
}
# }}}
# 1: AirConditioner:VariableRefrigerantFlow {{{
dt1 <- trans_action(idf, "AirConditioner:VariableRefrigerantFlow")
dt1 <- fix_fuel_types(dt1, 67L)
# }}}
# 2: AirTerminal:SingleDuct:Uncontrolled {{{
dt2 <- trans_action(idf,
c("AirTerminal:SingleDuct:ConstantVolume:NoReheat" = "AirTerminal:SingleDuct:Uncontrolled"),
insert = list(3L, " ATInlet")
)
if (nrow(dt2)) {
# create a nwe inlet node name using the original zone supply air node
dt2[J(c(3L, 4L)), on = "index", by = "id", value := {
pre <- if (is.na(value[2L])) "" else value[2L]
value[1L] <- paste0(pre, value[1L])
value
}]
# create one air distribution unit for each terminal
dt2_adu <- new_idf$to_table(init = TRUE, all = TRUE,
class = rep("ZoneHVAC:AirDistributionUnit", length(unique(dt2$id)))
)
dt2_adu[J(1L), on = "index", value := {
nm <- dt2[J(1L), on = "index", value]
nm[!is.na(nm)] <- paste(nm[!is.na(nm)], "ADU")
nm
}]
dt2_adu[J(2L), on = "index", value := dt2[J(4L), on = "index", value]]
dt2_adu[J(3L), on = "index", value := "AirTerminal:SingleDuct:ConstantVolume:NoReheat"]
dt2_adu[J(4L), on = "index", value := dt2[J(1L), on = "index", value]]
dt2_adu[J(5:6), on = "index", value := NA_character_]
dt2_adu[J(7L), on = "index", value := dt2[J(8L), on = "index", value]]
# after creating ADU, remove the 7th field, i.e. design specification
# sizing object
dt2 <- dt2[index < 7L]
dt2 <- rbindlist(list(dt2, dt2_adu))
# all outlet nodes
nodes <- dt2[J(4L), on = "index"]
set(nodes, NULL, "value_lower", stri_trans_tolower(nodes$value))
# all nodelists
nodelists <- idf$to_table(class = "NodeList")
set(nodelists, NULL, "value_lower", stri_trans_tolower(nodelists$value))
set(nodelists, NULL, "matched", FALSE)
}
# }}}
# 3: ZoneHVAC:EquipmentList {{{
dt3 <- trans_action(idf, "ZoneHVAC:EquipmentList")
# replace object types and names accordingly
if (nrow(dt2) && nrow(dt3)) {
set(dt3, NULL, "value_lower", stri_trans_tolower(dt3$value))
# calculate extensible group
dt3[, by = "id", extensible_field_index := (index - 2L) %/% 6L * 6L + (index - 2L) %% 6L]
dt3[J(1:2), on = "index", extensible_field_index := 0L]
m <- dt3[J(1L, "airterminal:singleduct:uncontrolled"),
on = c("extensible_field_index", "value_lower"),
list(id, index)]
dt3[m, on = c("id", "index"), value := "ZoneHVAC:AirDistributionUnit"]
dt3[m[, index := index + 1L], on = c("id", "index"), value := {
value[!is.na(value)] <- paste(value[!is.na(value)], "ADU")
value
}]
set(dt3, NULL, c("value_lower", "extensible_field_index"), NULL)
}
# }}}
# replace_node {{{
replace_node <- function(dt, nodes, nodelists = NULL, index_exclude) {
set(dt, NULL, "value_lower", stri_trans_tolower(dt$value))
# check if the node is referenced directly
set(dt, NULL, "matched", FALSE)
dt[nodes, on = "value_lower", matched := TRUE]
# exclude specified fields
dt[J(index_exclude), on = "index", matched := FALSE]
# exclude empty fields
dt[J(NA_character_), on = "value_lower", matched := FALSE]
dt[J(TRUE), on = "matched", value := paste(value, "ATInlet")]
# check if the node is referenced by a node list
if (!is.null(nodelists)) {
# get matched node list id
dt[nodelists[J(1L), on = "index"], on = "value_lower", id_list := i.id]
# exclude specified fields
dt[J(index_exclude), on = "index", id_list := NA_integer_]
# exclude empty fields
dt[J(NA_character_), on = "value_lower", id_list := NA_integer_]
# extract all matched node lists that contain target nodes
nl <- nodelists[J(dt[!is.na(id_list), id_list]), on = "id"][
nodes, on = "value_lower", matched := TRUE]
nl <- nl[J(TRUE), on = "matched", nomatch = NULL]
# tag matched field in the whole nodelist table
nodelists[nl, on = c("id", "index"), matched := TRUE]
# append name suffix
dt[J(unique(nl$id)), on = "id_list", value := paste(value, "ATInlet")]
set(dt, NULL, "id_list", NULL)
}
# clean up columns
set(dt, NULL, c("value_lower", "matched"), NULL)
}
# }}}
# 4: AirLoopHVAC:ZoneSplitter {{{
dt4 <- trans_action(idf, "AirLoopHVAC:ZoneSplitter")
if (nrow(dt2) && nrow(dt4)) dt4 <- replace_node(dt4, nodes, nodelists, 1:2)
# }}}
# 5: AirLoopHVAC:SupplyPlenum {{{
dt5 <- trans_action(idf, "AirLoopHVAC:SupplyPlenum")
if (nrow(dt2) && nrow(dt5)) dt5 <- replace_node(dt5, nodes, nodelists, 1:4)
# }}}
# 6: AirLoopHVAC {{{
dt6 <- trans_action(idf, "AirLoopHVAC")
if (nrow(dt2) && nrow(dt6)) dt6 <- replace_node(dt6, nodes, nodelists, setdiff(1:11, 9L)) # 9
# }}}
# 7: RoomAir:Node:AirflowNetwork:HVACEquipment {{{
dt7 <- trans_action(idf, "RoomAir:Node:AirflowNetwork:HVACEquipment")
# replace object types and names accordingly
if (nrow(dt2) && nrow(dt7)) {
set(dt7, NULL, "value_lower", stri_trans_tolower(dt7$value))
# calculate extensible group
dt7[, by = "id", extensible_field_index := (index - 1L) %/% 4L * 4L + (index - 1L) %% 4L]
dt7[J(1L), on = "index", extensible_field_index := 0L]
m <- dt7[J(1L, "airterminal:singleduct:uncontrolled"),
on = c("extensible_field_index", "value_lower"),
list(id, index)]
dt7[m, on = c("id", "index"), value := "ZoneHVAC:AirDistributionUnit"]
dt7[m[, index := index + 1L], on = c("id", "index"), value := {
value[!is.na(value)] <- paste(value[!is.na(value)], "ADU")
value
}]
set(dt7, NULL, c("value_lower", "extensible_field_index"), NULL)
}
# }}}
# 8: AirflowNetwork:Distribution:Node {{{
dt8 <- trans_action(idf, "AirflowNetwork:Distribution:Node")
if (nrow(dt2) && nrow(dt8)) {
# store original node name
val <- dt8[J(2L), on = "index", nomatch = NULL, value]
# store original data
ori <- copy(dt8)
dt8 <- replace_node(dt8, nodes, NULL, setdiff(1:4, 2L))
# get matched object id
id_m <- dt8[J(2L), on = "index", nomatch = NULL, id[which(value != val)]]
if (length(id_m)) {
dt8 <- dt8[id %in% id_m]
dt8[J(1L), on = "index", value := {
value[is.na(value)] <- ""
paste(value, "ATInlet")
}]
set(dt8, NULL, "id", -dt8$id)
dt8 <- rbindlist(list(ori, dt8))
}
}
# }}}
# 9: AirflowNetwork:Distribution:Linkage {{{
dt9 <- trans_action(idf, "AirflowNetwork:Distribution:Linkage")
if (nrow(dt2) && nrow(dt8) && any(dt8$id < 0)&& nrow(dt9)) {
# store original node name
val <- dt9[J(3L), on = "index", nomatch = NULL, value]
# store original data
ori <- copy(dt9)
# get matched nodes
dt9 <- replace_node(dt9,
# use the original matched node names
nodes = dt8[id %in% dt8[id < 0, -id] & index == 1L,
list(value_lower = stri_trans_tolower(value))],
NULL, setdiff(1:5, 3L)
)
# get matched object id
m <- dt9[J(3L), on = "index", nomatch = NULL, value != val]
if (any(m)) {
# create new linkage
dt9_1 <- dt9[id %in% unique(id)[m]]
# assume component is a duct
rel <- idf$object_relation(unique(dt9_1$id), "ref_to",
class = "AirflowNetwork:Distribution:Component:Duct")$ref_to
# get id of objects that reference ducts
id_m <- unique(rel$object_id)
# update data for linkage
dt9_1[, by = "id", value := {
val <- value
val[1L] <- paste(value[1L], "ATInlet")
val[2L] <- value[3L]
# remove suffix
val[3L] <- stri_sub(value[3L], to = -9L)
# give a warning if the referenced duct is not found
if (.BY$id %in% id_m) {
val[4L] <- paste(val[1L], "Duct")
} else {
warn(sprintf(paste0(
"Linkage component '%s' in '%s'[id:%s] in class 'AirflowNetwork:Distribution:Linkage' ",
"is not an 'AirflowNetwork:Distribution:Component:Duct' object. ",
"No new duct will be added."),
value[4L], name[1L], .BY$id
), "trans_920_930")
}
val
}]
# create a matching new duct for the new linkage
dt9_2 <- idf$to_table(rel$src_object_id)
dt9_2[J(1L), on = "index", value := dt9_1[J(id_m, 4L), on = c("id", "index"), value]]
dt9_2[J(2L), on = "index", value := "0.0001"]
dt9_2[J(6L), on = "index", value := "0.0"]
dt9_2[J(7L), on = "index", value := "0.0000001"]
dt9_2[J(8L), on = "index", value := "0.0000001"]
# update object id
set(dt9_1, NULL, "id", -dt9_1$id)
dt9 <- rbindlist(list(dt9, dt9_1, dt9_2))
}
}
# }}}
# 10: Boiler:HotWater {{{
dt10 <- trans_action(idf, "Boiler:HotWater")
dt10 <- fix_fuel_types(dt10, 2L)
# }}}
# 11: Boiler:Steam {{{
dt11 <- trans_action(idf, "Boiler:Steam")
dt11 <- fix_fuel_types(dt11, 2L)
# }}}
# 12: Chiller:EngineDriven {{{
dt12 <- trans_action(idf, "Chiller:EngineDriven")
dt12 <- fix_fuel_types(dt12, 36L)
# }}}
# 13: Chiller:CombustionTurbine {{{
dt13 <- trans_action(idf, "Chiller:CombustionTurbine")
dt13 <- fix_fuel_types(dt13, 55L)
# }}}
# 14: ChillerHeater:Absorption:DirectFired {{{
dt14 <- trans_action(idf, "ChillerHeater:Absorption:DirectFired")
dt14 <- fix_fuel_types(dt14, 33L)
# }}}
# 15: Coil:Cooling:DX:MultiSpeed {{{
dt15 <- trans_action(idf, "Coil:Cooling:DX:MultiSpeed")
dt15 <- fix_fuel_types(dt15, 17L)
# }}}
# 16: Coil:Heating:Fuel {{{
dt16 <- trans_action(idf, "Coil:Heating:Fuel")
dt16 <- fix_fuel_types(dt16, 3L)
# }}}
# 17: Coil:Heating:DX:MultiSpeed {{{
dt17 <- trans_action(idf, "Coil:Heating:DX:MultiSpeed")
dt17 <- fix_fuel_types(dt17, 16L)
# }}}
# 18: EnergyManagementSystem:Program {{{
dt18 <- trans_action(idf, "EnergyManagementSystem:Program", aling = FALSE)
# change function '@CpAirFnWTdb' to '@CpAirFnW' and remove the 2nd argument
if (nrow(dt18)) {
dt18[index > 1L & stri_detect_fixed(value, "@CpAirFnWTdb", case_insensitive = TRUE), value := {
stri_replace_first_regex(value, "@CpAirFnWTdb\\s+(.+)\\s+.+", "@CpAirFnW $1", case_insensitive = TRUE)
}]
}
# }}}
# 19: EnergyManagementSystem:Subroutine {{{
dt19 <- trans_action(idf, "EnergyManagementSystem:Subroutine")
# change function '@CpAirFnWTdb' to '@CpAirFnW' and remove the 2nd argument
if (nrow(dt19)) {
dt19[index > 1L & stri_detect_fixed(value, "@CpAirFnWTdb", case_insensitive = TRUE), value := {
stri_replace_first_regex(value, "@CpAirFnWTdb\\s+(.+)\\s+.+", "@CpAirFnW $1", case_insensitive = TRUE)
}]
}
# }}}
# 20: EnergyManagementSystem:MeteredOutputVariable {{{
dt20 <- trans_action(idf, "EnergyManagementSystem:MeteredOutputVariable")
dt20 <- fix_fuel_types(dt20, 5L)
# }}}
# 21: Exterior:FuelEquipment {{{
dt21 <- trans_action(idf, "Exterior:FuelEquipment")
dt21 <- fix_fuel_types(dt21, 2L)
# }}}
# 22: FuelFactors {{{
dt22 <- trans_action(idf, "FuelFactors")
dt22 <- fix_fuel_types(dt22, 1L)
# }}}
# 23: Generator:CombustionTurbine {{{
dt23 <- trans_action(idf, "Generator:CombustionTurbine")
dt23 <- fix_fuel_types(dt23, 22L)
# }}}
# 24: Generator:InternalCombustionEngine {{{
dt24 <- trans_action(idf, "Generator:InternalCombustionEngine")
dt24 <- fix_fuel_types(dt24, 20L)
# }}}
# 25: Generator:MicroTurbine {{{
dt25 <- trans_action(idf, "Generator:MicroTurbine")
dt25 <- fix_fuel_types(dt25, 12L)
# }}}
# 26: GlobalGeometryRules {{{
dt26 <- trans_action(idf, "GlobalGeometryRules",
reset = list(1L, "ULC", "UpperLeftCorner"),
reset = list(1L, "LLC", "LowerLeftCorner"),
reset = list(1L, "LRC", "LowerRightCorner"),
reset = list(1L, "URC", "UpperRightCorner"),
reset = list(2L, "CCW", "Counterclockwise"),
reset = list(2L, "CW", "Clockwise"),
reset = list(3L, c("WCS", "WorldCoordinateSystem", "Absolute"), "World"),
reset = list(3L, c("Local", "Rel"), "Relative"),
reset = list(4L, c("WCS", "WorldCoordinateSystem", "Absolute"), "World"),
reset = list(4L, c("Local", "Rel"), "Relative"),
reset = list(5L, c("WCS", "WorldCoordinateSystem", "Absolute"), "World"),
reset = list(5L, c("Local", "Rel"), "Relative")
)
# }}}
# 27: HeatPump:WaterToWater:EIR:Heating {{{
dt27 <- trans_action(idf,
c("HeatPump:PlantLoop:EIR:Heating" = "HeatPump:WaterToWater:EIR:Heating"),
insert = list(4L)
)
# }}}
# 28: HeatPump:WaterToWater:EIR:Cooling {{{
dt28 <- trans_action(idf,
c("HeatPump:PlantLoop:EIR:Cooling" = "HeatPump:WaterToWater:EIR:Cooling"),
insert = list(4L)
)
# }}}
# 29: HVACTemplate:System:VRF {{{
dt29 <- trans_action(idf, "HVACTemplate:System:VRF")
dt29 <- fix_fuel_types(dt29, 37L)
# }}}
# 30: HVACTemplate:Plant:Boiler {{{
dt30 <- trans_action(idf, "HVACTemplate:Plant:Boiler")
dt30 <- fix_fuel_types(dt30, 5L)
# }}}
# 31: LifeCycleCost:UsePriceEscalation {{{
dt31 <- trans_action(idf, "LifeCycleCost:UsePriceEscalation")
dt31 <- fix_fuel_types(dt31, 2L)
# }}}
# 32: LifeCycleCost:UseAdjustment {{{
dt32 <- trans_action(idf, "LifeCycleCost:UseAdjustment")
dt32 <- fix_fuel_types(dt32, 2L)
# }}}
# 33: OtherEquipment {{{
dt33 <- trans_action(idf, "OtherEquipment")
dt33 <- fix_fuel_types(dt33, 2L)
# }}}
# 34: Output:Table:SummaryReports {{{
dt34 <- trans_action(idf, "Output:Table:SummaryReports")
if (nrow(dt34)) {
set(dt34, NULL, "value_lower", stri_trans_tolower(dt34$value))
dt34[J(c("abups", "beps")), on = "value_lower", value := "AnnualBuildingUtilityPerformanceSummary"]
dt34[J("ivrs"), on = "value_lower", value := "InputVerificationandResultsSummary"]
dt34[J("css"), on = "value_lower", value := "ComponentSizingSummary"]
dt34[J("shad"), on = "value_lower", value := "SurfaceShadowingSummary"]
dt34[J("eio"), on = "value_lower", value := "InitializationSummary"]
set(dt34, NULL, "value_lower", NULL)
}
# }}}
# 35: ShadowCalculation {{{
dt35 <- trans_action(idf, "ShadowCalculation", all = TRUE, insert = list(7L))
if (nrow(dt35)) {
dt35[, by = "id", value := {
val <- value
value_lower <- stri_trans_tolower(value)
val[1L] <- switch(value_lower[6L],
scheduledshading = "Scheduled",
importedshading = "Imported",
"PolygonClipping"
)
val[2L] <- switch(value_lower[1L],
averageoverdaysinfrequency = "Periodic",
timestepfrequency = "Timestep",
""
)
val[3:5] <- value[2:4]
val[6L] <- ""
val[7L] <- value[5L]
val
}]
}
# }}}
# 36: WaterHeater:Mixed {{{
dt36 <- trans_action(idf, "WaterHeater:Mixed")
dt36 <- fix_fuel_types(dt36, c(11L, 15L, 18L))
# }}}
# 37: WaterHeater:Stratified {{{
dt37 <- trans_action(idf, "WaterHeater:Stratified")
dt37 <- fix_fuel_types(dt37, c(17L, 20L, 24L))
# }}}
# 38: ZoneHVAC:HybridUnitaryHVAC {{{
dt38 <- trans_action(idf, "ZoneHVAC:HybridUnitaryHVAC")
dt38 <- fix_fuel_types(dt37, 18:20)
# }}}
# create new NodeList if necessary {{{
if (nrow(dt2) && any(nodelists$matched)) {
m <- nodelists[J(TRUE), on = "matched"]
nodelists[m, on = c("id", "index"), value := paste(value, "ATInlet")]
nodelists <- nodelists[J(unique(m$id)), on = "id"]
nodelists[J(1L), on = "index", value := paste(value, "ATInlet")]
set(nodelists, NULL, c("matched", "value_lower"), NULL)
dt2 <- rbindlist(list(dt2, nodelists))
}
# }}}
trans_process(new_idf, idf, rbindlist(mget(paste0("dt", 1:38))))
trans_postprocess(new_idf, idf$version(), new_idf$version())
}
# }}}
# trans_930_940 {{{
#' @importFrom checkmate assert_true
trans_funs$f930t940 <- function(idf) {
assert_true(idf$version()[, 1:2] == "9.3")
target_cls <- c(
"Construction:InternalSource", # 1
"EnergyManagementSystem:Actuator", # 2
"Output:DebuggingData", # 3
"Output:Diagnostics", # 4
"PerformancePrecisionTradeoffs", # 5
# only issue warning
# "PythonPlugin:Instance",
"ZoneHVAC:LowTemperatureRadiant:VariableFlow", # 6
"ZoneHVAC:LowTemperatureRadiant:Electric", # 7
"ZoneHVAC:LowTemperatureRadiant:ConstantFlow", # 8
"ZoneHVAC:HybridUnitaryHVAC" # 9
)
new_idf <- trans_preprocess(idf, "9.4", target_cls)
# 1: Construction:InternalSource {{{
dt1 <- trans_action(idf, "Construction:InternalSource", insert = list(6, "0.0"))
# }}}
# 2: EnergyManagementSystem:Actuator {{{
dt2 <- trans_action(idf,
"EnergyManagementSystem:Actuator",
reset = list(4L, "Electric Power Level", "Electricity Rate"),
reset = list(4L, "Gas Power Level", "NaturalGas Rate")
)
# }}}
# 3: Output:DebuggingData {{{
dt3 <- trans_action(idf, "Output:DebuggingData")
if (nrow(dt3)) {
# convert 1 & 0 to Yes and No and warning if non-numeric values found
set(dt3, NULL, "value_num", suppressWarnings(as.numeric(dt3$value)))
set(dt3, NULL, "value", "No")
dt3[is.na(value_num), by = c("id", "index"), c("value", "value_num") := {
warn(sprintf(paste0(
"Field '%s' for object [id:%s] in class 'Output:DebuggingData' ",
"is not a number, defaulting to 'No'."),
field[1L], .BY$id
), "trans_930_940")
list("No", 0.0)
}]
dt3[as.integer(value_num) == 1L, value := "Yes"]
set(dt3, NULL, "value_num", NULL)
}
# }}}
# 4: Output:Diagnostics {{{
dt4 <- trans_action(idf, "Output:Diagnostics")
if (nrow(dt4)) {
if (length(unique(dt4$id)) > 1L) {
# consolidate all into one
warn(paste0(
"'Output:Diagnostics' has become an unique-object class in EnergyPlus v9.4. ",
"All other objects except the first one found will be listed as comments and ",
"their keys will be all consolidated into the first one."
), "trans_930_940")
id_cmt <- unique(dt4$id)[-1L]
id_left <- dt4$id[1L]
cmt <- idf$to_string(id_cmt, header = FALSE, format = "new_bot")
idf$object(id_left)$comment(cmt)
dt4 <- unique(dt4, by = "value")
set(dt4, NULL, "id", id_left)
set(dt4, NULL, "index", seq_len(nrow(dt4)))
}
}
# }}}
# 5: PerformancePrecisionTradeoffs {{{
dt5 <- trans_action(idf, "PerformancePrecisionTradeoffs", reset = list(3L, "Mode05", "Mode06"))
# }}}
# 6: ZoneHVAC:LowTemperatureRadiant:VariableFlow {{{
dt6 <- trans_action(idf, "ZoneHVAC:LowTemperatureRadiant:VariableFlow",
insert = list(5L, "ConvectionOnly"),
insert = list(7L, "0.016"),
insert = list(9L, "0.35"),
insert = list(11L, "HalfFlowPower")
)
# }}}
# 7: ZoneHVAC:LowTemperatureRadiant:Electric {{{
dt7 <- trans_action(idf, "ZoneHVAC:LowTemperatureRadiant:Electric",
insert = list(10L, "HalfFlowPower")
)
# }}}
# 8: ZoneHVAC:LowTemperatureRadiant:ConstantFlow {{{
dt8 <- trans_action(idf, "ZoneHVAC:LowTemperatureRadiant:ConstantFlow",
insert = list(5L, "ConvectionOnly"),
insert = list(7L, "0.016"),
insert = list(9L, "0.35"),
insert = list(11L, "0.8")
)
# }}}
# 9: ZoneHVAC:HybridUnitaryHVAC {{{
dt9 <- trans_action(idf, "ZoneHVAC:HybridUnitaryHVAC",
insert = list(15L, "Yes"),
insert = list(16L),
insert = list(17L),
delete = list(19L)
)
if (nrow(dt9)) dt9[, by = "id", index := seq_len(.N)]
# }}}
# Warning for PythonPlugin:Instance {{{
if (idf$is_valid_class("PythonPlugin:Instance")) {
warn(paste0("Objects in class 'PythonPlugin:Instance' found. ",
"Note that the API has been changed from v9.3 and v9.4. ",
"Please check the docs and update with new state argument."
), "trans_930_940")
}
# }}}
trans_process(new_idf, idf, rbindlist(mget(paste0("dt", 1:9))))
trans_postprocess(new_idf, idf$version(), new_idf$version())
}
# }}}
# trans_940_950 {{{
#' @importFrom checkmate assert_true
trans_funs$f940t950 <- function(idf) {
assert_true(idf$version()[, 1:2] == "9.4")
target_cls <- c(
"Construction:AirBoundary", # 1
"Coil:Cooling:WaterToAirHeatPump:EquationFit", # 2
"Coil:Heating:WaterToAirHeatPump:EquationFit", # 3
"Construction:InternalSource", # 4
"HeatPump:WaterToWater:EquationFit:Cooling", # 5
"HeatPump:WaterToWater:EquationFit:Heating", # 6
"ZoneAirMassFlowConservation", # 7
"ZoneHVAC:LowTemperatureRadiant:VariableFlow", # 8
"ZoneHVAC:LowTemperatureRadiant:ConstantFlow", # 9
"ZoneHVAC:Baseboard:RadiantConvective:Water", # 10
"ZoneHVAC:Baseboard:RadiantConvective:Steam" # 11
)
new_idf <- trans_preprocess(idf, "9.5", target_cls)
NUM_ADDED <- 0L
# 1: Construction:AirBoundary {{{
dt1 <- trans_action(idf, "Construction:AirBoundary", min_fields = 6)
if (nrow(dt1)) {
dt1[index == 2L & stri_trans_tolower(value) %chin% "interiorwindow", {
warn(sprintf(paste0(
"Option 'InteriorWindow' for field 'Solar and Daylighting Method' ",
"in class 'Construction:AirBoundary' is no loger valid in Energyplus v9.5. ",
"All air boundaries will be modelled using the 'GroupedZones' method. Object(s) below were affected:\n%s"),
paste(sprintf(" #%s| Object '%s' [ID: %i]", lpad(seq_along(index), "0"), name, id), collapse = "\n")
), "trans_940_950")
}]
dt1[index == 3L & stri_trans_tolower(value) %chin% "irtsurface", {
warn(sprintf(paste0(
"Option 'IRTSurface' for field 'Radiant Exchange Method' ",
"in class 'Construction:AirBoundary' is no loger valid in Energyplus v9.5. ",
"All air boundaries will be modelled using the 'GroupedZones' method. Object(s) below were affected:\n%s"),
paste(sprintf(" #%s| Object '%s' [ID: %i]", lpad(seq_along(index), "0"), name, id), collapse = "\n")
), "trans_940_950")
}]
dt1 <- dt1[!index %in% c(2L, 3L)]
dt1[, index := seq_len(.N), by = "id"]
}
# }}}
split_curves <- function(dt, pos, name) {
if (!nrow(dt)) return(dt)
num_objs <- length(unique(dt$id))
num <- viapply(pos, length)
rng <- range(unlist(pos, use.names = FALSE))
# fields that are retained
dt_remain <- dt[index < rng[1L] | index > rng[2L]]
# update field index
dt_remain[index > rng[2L], index := seq(rng[1L] + length(pos), length.out = .N), by = "id"]
# curve fields
dt_name <- dt[J(viapply(pos, "[[", 1L, use.names = FALSE)), on = "index"]
set(dt_name, NULL, "value", paste(rep(name, each = num_objs), rep(seq.int(num_objs), length(pos))))
set(dt_name, NULL, "index", rep(seq(min(pos[[1L]]), length.out = length(pos)), each = num_objs))
# curve objects
ind_curve <- unlist(lapply(pos, function(x) c(1L, x)), use.names = FALSE)
dt_curve <- dt[J(ind_curve), on = "index"]
dt_curve[J(1L), on = "index", value := dt_name$value]
# update curve object IDs
set(dt_curve, NULL, "id", rep(NUM_ADDED - seq.int(num_objs * length(pos)), rep(num + 1L, num_objs)))
# update curve object classes
set(dt_curve, NULL, "class", rep(rep(names(pos), num + 1L), num_objs))
# update curve object indices
set(dt_curve, NULL, "index", rep(unlist(lapply(num + 1L, seq.int), use.names = FALSE), num_objs))
# create min max table
dt_rng <- dt_curve[, by = "id", {
class <- class[1L]
num <- data.table::fcase(
class[1L] == "Curve:QuadLinear", 8L,
class[1L] == "Curve:QuintLinear", 10L
)
index <- seq.int(num)
value <- rep(c("-100", "100"), num / 2L)
list(name = NA_character_, class, index, field = NA_character_, value)
}]
dt_curve <- rbindlist(list(dt_curve, dt_rng))
dt_curve[, by = "id", index := seq.int(.N)]
# update num of new objects added
NUM_ADDED <<- min(dt_curve$id)
rbindlist(list(dt_remain, dt_name, dt_curve))
}
# 2: Coil:Cooling:WaterToAirHeatPump:EquationFit {{{
dt2 <- trans_action(idf, "Coil:Cooling:WaterToAirHeatPump:EquationFit", all = TRUE)
dt2 <- split_curves(dt2,
list("Curve:QuadLinear" = 11:15, "Curve:QuintLinear" = 16:21, "Curve:QuadLinear" = 22:26),
c("WAHPCoolCapCurveTot", "WAHPCoolCapCurveSens", "WAHPCoolPowCurve")
)
# }}}
# 3: Coil:Heating:WaterToAirHeatPump:EquationFit {{{
dt3 <- trans_action(idf, "Coil:Heating:WaterToAirHeatPump:EquationFit", all = TRUE)
dt3 <- split_curves(dt3,
list("Curve:QuadLinear" = 10:14, "Curve:QuadLinear" = 15:19),
c("WAHPHeatCapCurve", "WAHPHeatPowCurve")
)
# }}}
# 4: Construction:InternalSource {{{
dt4 <- trans_action(idf,
c("ConstructionProperty:InternalHeatSource" = "Construction:InternalSource"),
insert = list(1)
)
if (nrow(dt4)) {
dt4[J(1L), on = "index", value := paste(name, "Heat Source")]
# new construction
dt41 <- dt4[index == 2L | index >= 8L]
set(dt41, NULL, "class", "Construction")
dt41[, index := seq.int(.N), by = "id"]
set(dt41, NULL, "id", -rleid(dt41$id) + NUM_ADDED)
NUM_ADDED <- min(dt41$id)
dt4 <- rbindlist(list(dt4[index <= 7L], dt41))
}
# }}}
# 5: HeatPump:WaterToWater:EquationFit:Cooling {{{
dt5 <- trans_action(idf, "HeatPump:WaterToWater:EquationFit:Cooling", all = TRUE)
dt5 <- split_curves(dt5,
list("Curve:QuadLinear" = 10:14, "Curve:QuadLinear" = 15:19),
c("WWHPCoolCapCurve", "WWHPCoolPowCurve")
)
# }}}
# 6: HeatPump:WaterToWater:EquationFit:Heating {{{
dt6 <- trans_action(idf, "HeatPump:WaterToWater:EquationFit:Heating", all = TRUE)
dt6 <- split_curves(dt6,
list("Curve:QuadLinear" = 10:14, "Curve:QuadLinear" = 15:19),
c("WWHPHeatCapCurve", "WWHPHeatPowCurve")
)
# }}}
# 7: ZoneAirMassFlowConservation {{{
dt7 <- trans_action(idf, "ZoneAirMassFlowConservation",
reset = list(1L, "Yes", "AdjustMixingOnly"),
reset = list(1L, "No", "None")
)
# }}}
split_radiant <- function(dt, remain, new, remain_since = NULL) {
if (!nrow(dt)) return(dt)
dt1 <- dt[J(c(remain)), on = "index", nomatch = NULL]
if (!is.null(remain_since)) {
dt1 <- rbindlist(list(dt1, dt[index >= remain_since]))
}
dt2 <- dt[J(c(new)), on = "index", nomatch = NULL]
# construct design name
dt1[, index := seq.int(.N), by = "id"]
dt1[J(2L), on = "index", value := paste(value, "Design Object")]
# construct design object
set(dt2, NULL, "class", paste0(dt2$class, ":Design"))
dt2[, index := seq.int(.N), by = "id"]
dt2[J(1L), on = "index", value := paste(value, "Design Object")]
dt2[, by = "id", id := NUM_ADDED - .GRP]
NUM_ADDED <<- min(dt2$id)
dt <- rbindlist(list(dt1, dt2))
}
# 8: ZoneHVAC:LowTemperatureRadiant:VariableFlow {{{
dt8 <- trans_action(idf, "ZoneHVAC:LowTemperatureRadiant:VariableFlow")
dt8 <- split_radiant(dt8,
c(1L, 1L, 2:4, 8, 13L, 16:18, 22L, 25:27, 32:33),
c(1L, 5:7, 9:12, 14:15, 19:24, 28:31, 34L)
)
# }}}
# 9: ZoneHVAC:LowTemperatureRadiant:ConstantFlow {{{
dt9 <- trans_action(idf, "ZoneHVAC:LowTemperatureRadiant:ConstantFlow")
dt9 <- split_radiant(dt9,
c(1L, 1L, 2:4, 8, 12:15, 18:29, 32:33),
c(1L, 5:7, 9:11, 16:17, 30:31)
)
# }}}
# 10: ZoneHVAC:Baseboard:RadiantConvective:Water {{{
dt10 <- trans_action(idf, "ZoneHVAC:Baseboard:RadiantConvective:Water")
dt10 <- split_radiant(dt10,
c(1L, 1L, 2:6, 8, 11),
c(1L, 7L, 9:10, 12:14),
15L
)
# }}}
# 11: ZoneHVAC:Baseboard:RadiantConvective:Steam {{{
dt11 <- trans_action(idf, "ZoneHVAC:Baseboard:RadiantConvective:Steam")
dt11 <- split_radiant(dt11,
c(1L, 1L, 2:4, 6L, 9:10),
c(1L, 5L, 7:8, 11:13),
14L
)
# }}}
trans_process(new_idf, idf, rbindlist(mget(paste0("dt", 1:11))))
trans_postprocess(new_idf, idf$version(), new_idf$version())
}
# }}}
# trans_950_960 {{{
trans_funs$f950t960 <- function(idf) {
assert_true(idf$version()[, 1:2] == "9.5")
target_cls <- c(
"AirflowNetwork:MultiZone:ReferenceCrackConditions", # 1
"AirLoopHVAC:OutdoorAirSystem", # 2
"BuildingSurface:Detailed", # 3
"Ceiling:Adiabatic", # 4
"Ceiling:Interzone", # 5
"Controller:MechanicalVentilation", # 6
"Floor:Detailed", # 7
"Floor:GroundContact", # 8
"Floor:Adiabatic", # 9
"Floor:Interzone", # 10
"GroundHeatExchanger:System", # 11
"InternalMass", # 12
"RoofCeiling:Detailed", # 13
"Sizing:System", # 14
"Roof", # 15
"PerformancePrecisionTradeoffs", # 16
"Wall:Detailed", # 17
"Wall:Exterior", # 18
"Wall:Adiabatic", # 19
"Wall:Underground", # 20
"Wall:Interzone" # 21
)
new_idf <- trans_preprocess(idf, "9.6", target_cls)
# 1: AirflowNetwork:MultiZone:ReferenceCrackConditions {{{
dt1 <- trans_action(idf, "AirflowNetwork:MultiZone:ReferenceCrackConditions",
reset = list(2, NA_character_, "20.0")
)
# }}}
# 2: AirLoopHVAC:OutdoorAirSystem {{{
dt2 <- trans_action(idf, "AirLoopHVAC:OutdoorAirSystem", delete = list(4L))
# }}}
# 3:BuildingSurface:Detailed {{{
dt3 <- trans_action(idf, "BuildingSurface:Detailed", insert = list(5L))
# }}}
# 4: Construction:InternalSource {{{
dt4 <- trans_action(idf, "Ceiling:Adiabatic", insert = list(4L))
# }}}
# 5: Ceiling:Interzone {{{
dt5 <- trans_action(idf, "Ceiling:Interzone", insert = list(4L))
# }}}
# 6: Controller:MechanicalVentilation {{{
dt6 <- trans_action(idf, "Controller:MechanicalVentilation",
reset = list(4L, "VentilationRateProcedure", "Standard62.1VentilationRateProcedure")
)
# }}}
# 7: Floor:Detailed {{{
dt7 <- trans_action(idf, "Floor:Detailed", insert = list(4L))
# }}}
# 8: Floor:GroundContact {{{
dt8 <- trans_action(idf, "Floor:GroundContact", insert = list(4L))
# }}}
# 9: Floor:Adiabatic {{{
dt9 <- trans_action(idf, "Floor:Adiabatic", insert = list(4L))
# }}}
# 10: Floor:Interzone {{{
dt10 <- trans_action(idf, "Floor:Interzone", insert = list(4L))
# }}}
# 11: GroundHeatExchanger:System {{{
dt11 <- trans_action(idf, "GroundHeatExchanger:System", insert = list(10L))
if (nrow(dt11)) {
id_target <- dt11[index == 9L & is.na(value), id]
if (length(id_target)) {
dt11[J(id_target, 10L), on = c("id", "index"), value := "UHFCalc"]
}
}
# }}}
# 12: InternalMass {{{
dt12 <- trans_action(idf, "InternalMass", insert = list(4L))
# }}}
# 13: RoofCeiling:Detailed {{{
dt13 <- trans_action(idf, "RoofCeiling:Detailed", insert = list(4L))
# }}}
# 14: Sizing:System {{{
dt14 <- trans_action(idf, "Sizing:System",
reset = list(27L, "VentilationRateProcedure", "Standard62.1VentilationRateProcedure")
)
# }}}
# 15: Roof {{{
dt15 <- trans_action(idf, "Roof", insert = list(4L))
# }}}
# 16: PerformancePrecisionTradeoffs {{{
dt16 <- trans_action(idf, "PerformancePrecisionTradeoffs",
reset = list(3L, "Mode07", "Mode08"),
reset = list(3L, "Mode06", "Mode07")
)
# }}}
# 17: Wall:Detailed {{{
dt17 <- trans_action(idf, "Wall:Detailed", insert = list(4L))
# }}}
# 18: Wall:Exterior {{{
dt18 <- trans_action(idf, "Wall:Exterior", insert = list(4L))
# }}}
# 19: Wall:Adiabatic {{{
dt19 <- trans_action(idf, "Wall:Adiabatic", insert = list(4L))
# }}}
# 20: Wall:Underground {{{
dt20 <- trans_action(idf, "Wall:Underground", insert = list(4L))
# }}}
# 21: Wall:Interzone {{{
dt21 <- trans_action(idf, "Wall:Interzone", insert = list(4L))
# }}}
trans_process(new_idf, idf, rbindlist(mget(paste0("dt", 1:21))))
trans_postprocess(new_idf, idf$version(), new_idf$version())
}
# }}}
# trans_960_2210 {{{
trans_funs$f960t2210 <- function(idf) {
assert_true(idf$version()[, 1:2] == "9.6")
target_cls <- c(
"PythonPlugin:SearchPaths" # 1
)
new_idf <- trans_preprocess(idf, "22.1", target_cls)
# 1: PythonPlugin:SearchPaths {{{
dt1 <- trans_action(idf, "PythonPlugin:SearchPaths",
insert = list(4, "Yes")
)
# }}}
trans_process(new_idf, idf, dt1)
trans_postprocess(new_idf, idf$version(), new_idf$version())
}
# }}}
# trans_2210_2220 {{{
trans_funs$f2210t2220 <- function(idf) {
assert_true(idf$version()[, 1:2] == "22.1")
target_cls <- c(
"Coil:Cooling:DX:CurveFit:Speed", # 1
"Coil:Cooling:DX:SingleSpeed", # 2
"Coil:Cooling:DX:MultiSpeed", # 3
"Coil:Heating:DX:SingleSpeed", # 4
"Coil:Heating:DX:MultiSpeed", # 5
"FuelFactors", # 6
"Space", # 7
"Coil:Cooling:WaterToAirHeatPump:EquationFit", # 8
"Coil:Heating:WaterToAirHeatPump:EquationFit" # 9
)
new_idf <- trans_preprocess(idf, "22.2", target_cls)
# 1: Coil:Cooling:DX:CurveFit:Speed {{{
dt1 <- trans_action(idf, "Coil:Cooling:DX:CurveFit:Speed", insert = list(9L))
# }}}
# 2: Coil:Cooling:DX:SingleSpeed {{{
dt2 <- trans_action(idf, "Coil:Cooling:DX:SingleSpeed", insert = list(8L))
# }}}
# 3: Coil:Cooling:DX:MultiSpeed {{{
dt3 <- trans_action(idf, "Coil:Cooling:DX:MultiSpeed",
insert = list(24L),
insert = list(44L),
insert = list(64L),
insert = list(84L)
)
# }}}
# 4: Coil:Heating:DX:SingleSpeed {{{
dt4 <- trans_action(idf, "Coil:Heating:DX:SingleSpeed", insert = list(6L))
# }}}
# 5: Coil:Heating:DX:MultiSpeed {{{
dt5 <- trans_action(idf, "Coil:Heating:DX:MultiSpeed",
insert = list(23L),
insert = list(35L),
insert = list(47L),
insert = list(59L)
)
# }}}
# 6: FuelFactors {{{
dt6 <- trans_action(idf, "FuelFactors", delete = list(2:3))
if (nrow(dt6)) dt6[, index := seq_len(.N), by = "id"]
# }}}
# 7: Space {{{
dt7 <- trans_action(idf, "Space",
insert = list(3, "autocalculate"),
insert = list(4, "autocalculate")
)
# }}}
warn_temp <- function(class, dt) {
warn(paste0(
"When transitioning to EnergyPlus v22.2.0, rated temperature ",
"from ISO 13256-1:1988 for water loop application are used ",
"for objects below in class '", class, "'. ",
"Make sure that they align with your application.\n",
get_object_info(dt, c("name", "id"), collapse = "\n")
),
"trans_2210_2220"
)
}
# 8: Coil:Cooling:WaterToAirHeatPump:EquationFit {{{
dt8 <- trans_action(idf, "Coil:Cooling:WaterToAirHeatPump:EquationFit",
insert = list(11, "30.0"),
insert = list(12, "27.0"),
insert = list(13, "19.0")
)
if (nrow(dt8)) {
dt <- unique(dt8[, .SD, .SDcols = c("id", "name", "class")])
setnames(dt, c("id", "name", "class"), c("object_id", "object_name", "class_name"))
warn_temp("Coil:Cooling:WaterToAirHeatPump:EquationFit", dt)
}
# }}}
# 9: Coil:Heating:WaterToAirHeatPump:EquationFit {{{
dt9 <- trans_action(idf, "Coil:Heating:WaterToAirHeatPump:EquationFit",
insert = list(10, "20.0"),
insert = list(11, "20.0"),
insert = list(12, "1.0")
)
if (nrow(dt9)) {
dt <- unique(dt9[, .SD, .SDcols = c("id", "name", "class")])
setnames(dt, c("id", "name", "class"), c("object_id", "object_name", "class_name"))
warn_temp("Coil:Heating:WaterToAirHeatPump:EquationFit", dt)
}
# }}}
trans_process(new_idf, idf, rbindlist(mget(paste0("dt", 1:9))))
trans_postprocess(new_idf, idf$version(), new_idf$version())
}
# }}}
# trans_2220_2310 {{{
trans_funs$f2220t2310 <- function(idf) {
assert_true(idf$version()[, 1:2] == "22.2")
new_idf <- trans_preprocess(idf, "23.1")
trans_process(new_idf, idf, data.table())
trans_postprocess(new_idf, idf$version(), new_idf$version())
}
# }}}
# trans_preprocess {{{
# 1. delete objects in deprecated class
# 2. delete all old objects
# 3. update IDD data
# 4. update version
# 5. assign new uuid
trans_preprocess <- function(idf, version, class = NULL) {
# clone old IDF
new_idf <- idf$clone(deep = TRUE)
# get new IDD
new_idd <- use_idd(version, "auto")
# delete deprecated classes
class_del <- setdiff(use_idd(idf$version())$class_name(), new_idd$class_name())
# get all classes to be deleted
class <- unique(c(CLASS_DEL_COMMON, class_del, class))
# del all related class
class <- class[idf$is_valid_class(class)]
if (length(class)) {
with_silent(new_idf$del(new_idf$object_id(class, simplify = TRUE), .force = TRUE))
}
priv <- get_priv_env(new_idf)
# use old class name in object and value table
add_joined_cols(priv$idd_env()$class, priv$idf_env()$object, "class_id", "class_name")
add_joined_cols(priv$idf_env()$object, priv$idf_env()$value, "object_id", "class_name")
# add field index in value table
set(priv$idf_env()$value, NULL, "field_index", rowidv(priv$idf_env()$value, "object_id"))
# store old idd table for comparison on min fields requirements
old_class <- priv$idd_env()$class
# update IDD
priv$m_idd <- new_idd
# update class id in object table
add_joined_cols(priv$idd_env()$class, priv$idf_env()$object, "class_name", "class_id")
# add class names in field table
add_joined_cols(priv$idd_env()$class, priv$idd_env()$field, "class_id", "class_name")
# update field id in value table
set(priv$idf_env()$value, NULL, "field_id",
priv$idd_env()$field[priv$idf_env()$value, on = c("class_name", "field_index"), "field_id"]
)
# check if there are newly added extensible groups
if (anyNA(priv$idf_env()$value$field_id)) {
# get id of object that has new extensible fields
id_obj <- priv$idf_env()$value[is.na(field_id), unique(object_id)]
# get field number per object
dt_obj <- priv$idf_env()$value[J(id_obj), on = "object_id", list(field_num = .N), by = c("class_name", "object_id")]
# merge with class table
dt_cls <- priv$idd_env()$class[dt_obj, on = "class_name"]
# calculate num of group to add
dt_cls[, `:=`(num = as.integer((field_num - num_fields) / num_extensible))]
# add extensible groups
add_idd_extensible_group(priv$idd_env(), dt_cls)
# update field id in value table
set(priv$idf_env()$value, NULL, "field_id",
priv$idd_env()$field[priv$idf_env()$value, on = c("class_name", "field_index"), "field_id"]
)
}
# should remove class_name and field_index column before calling append_dt
set(priv$idf_env()$value, NULL, c("class_name", "field_index"), NULL)
# if min-fields increased, should add new fields
priv$idf_env()$object[old_class, on = "class_name", old_min_fields := i.min_fields]
priv$idf_env()$object[priv$idd_env()$class, on = "class_name", min_fields := i.min_fields]
# get objects in classes whose min-fields requirements increased
obj <- priv$idf_env()$object[min_fields > old_min_fields]
if (nrow(obj)) {
# get current field num
obj[, field_num := priv$idf_env()$value[J(obj$object_id), on = "object_id", .N, by = "object_id"]$N]
# check if there is a need to insert new fields
if (nrow(obj <- obj[field_num < min_fields])) {
obj <- obj[, list(
field_index = seq(field_num + 1L, min_fields, 1L),
class_id = class_id[[1L]]
), by = "object_id"]
add_rleid(obj)
val <- get_idd_field(priv$idd_env(), obj$class_id, obj$field_index,
property = c("units", "ip_units", "default_chr", "default_num",
"required_field", "src_enum", "type_enum"
)
)
# assign default values
val <- assign_idf_value_default(priv$idd_env(), priv$idf_env(), val)
# assign old object id
val[obj, on = "rleid", object_id := i.object_id]
# assign new value id
set(val, NULL, "value_id", new_id(priv$idf_env()$value, "value_id", nrow(val)))
# merge data
idd_env <- priv$idd_env()
idf_env <- priv$idf_env()
idf_env$value <- append_dt(idf_env$value, val, "value_id")
# add necessary columns used for getting references
add_field_property(idd_env, idf_env$value, "src_enum")
add_joined_cols(idf_env$object, idf_env$value, "object_id", "class_id")
add_class_name(idd_env, idf_env$value)
ref <- get_value_reference_map(idd_env, idf_env$value, idf_env$value)
set(idf_env$value, NULL, c("src_enum", "class_id", "class_name"), NULL)
idf_env$reference <- ref
}
}
set(priv$idf_env()$object, NULL, c("class_name", "old_min_fields", "min_fields"), NULL)
set(priv$idd_env()$field, NULL, c("class_name"), NULL)
# update version
priv$m_version <- priv$m_idd$version()
priv$idf_env()$value[field_id == 1L, `:=`(
value_chr = as.character(priv$m_version[, 1:2]),
value_num = NA_real_
)]
# remove path
priv$m_path <- NULL
# reset log
priv$m_log$unsaved <- TRUE
priv$m_log$uuid <- unique_id()
priv$m_log$job <- NULL
new_idf
}
# }}}
# trans_process {{{
trans_process <- function(new_idf, old_idf, dt) {
if (!nrow(dt)) return(new_idf)
# remove redundant empty fields
dt[get_priv_env(new_idf)$idd_env()$class, on = c("class" = "class_name"),
`:=`(class_id = i.class_id, min_fields = i.min_fields, num_extensible = i.num_extensible)
]
dt[get_priv_env(new_idf)$idd_env()$field, on = c("class_id", index = "field_index"),
`:=`(extensible_group = i.extensible_group, required_field = i.required_field)
]
# check if there are newly added extensible groups
# if detected, set extensible_group to a random number
# since extensible_group is only used to detect if current field is
# extensible, it will be enough to assign newly-added extensible fields with
# a non-zero integer
dt[J(NA_integer_), on = "extensible_group", `:=`(required_field = FALSE, extensible_group = -1L)]
# add fake value id
dt[, value_id := .I]
setnames(dt, c("id", "index", "value"), c("object_id", "field_index", "value_chr"))
dt <- remove_empty_fields(get_priv_env(new_idf)$idd_env(), get_priv_env(new_idf)$idf_env(), dt)
setnames(dt, c("object_id", "field_index", "value_chr"), c("id", "index", "value"))
trans_process_load(new_idf, old_idf, dt)
}
# }}}
# trans_postprocess {{{
trans_postprocess <- function(idf, from, to) {
id_del <- NULL
# reset_key {{{
reset_key <- function(dt, field_index = 1L) {
if (!nrow(dt)) return(dt)
dt[J(field_index, NA_character_), on = c("index", "value"), value := "*"]
}
# }}}
# update_var {{{
update_var <- function(dt, mapping, field_index, step = NULL, is_meter = FALSE, idf = NULL) {
if (!nrow(dt)) return(dt)
if (!nrow(mapping)) return(dt)
if (!has_names(dt, "value_lower")) {
set(dt, NULL, "value_lower", stri_trans_tolower(dt$value))
}
new <- NULL # eliminate check warning of no visible binding
# delete deprecatd variable first
id_obj <- dt[mapping[!is.na(old) & is.na(new)], on = c(value_lower = "old"), unique(id)]
id_del <<- c(id_del, id_obj[!is.na(id_obj)])
dt <- dt[!J(id_obj), on = "id"]
# remove delete rules
mapping <- mapping[!is.na(new)]
if (!nrow(dt) || !nrow(mapping)) return(set(dt, NULL, "value_lower", NULL))
# calculate field index
if (!is.null(step)) {
n <- (nrow(dt) - field_index) %/% step
field_index <- as.integer(c(field_index, seq.int(n) * step + field_index))
}
# update variable names
dt[J(field_index), on = "index", value := {
# from v7.2 to v8.0 there are duplicated old vars
# use the first and then handle the other
mapping[J(value_lower), on = "old", mult = "first", {
updated <- new
# if no match, keep the old
updated[is.na(new)] <- value[is.na(new)]
updated
}]
}]
# special case from v7.2 to v8.0 {{{
if (nrow(mapping) && unique(mapping$from) == "7.2") {
has_chiller <- any(idf$is_valid_class(c(
"Chiller:Electric:EIR",
"Chiller:Electric:ReformulatedEIR",
"Chiller:Electric",
"Chiller:Absorption:Indirect",
"Chiller:Absorption",
"Chiller:ConstantCOP",
"Chiller:EngineDriven",
"Chiller:CombustionTurbine"
)))
has_heater <- any(idf$is_valid_class(c(
"ChillerHeater:Absorption:DirectFired",
"ChillerHeater:Absorption:DoubleEffect"
)))
# there are duplicated old vars should add new rows {{{
# remove the first case
if (has_chiller && has_heater) {
dup <- mapping[duplicated(old)]
# update variable names
sec <- dt[J(field_index), on = "index", nomatch = 0L]
if (nrow(sec)) {
sec <- sec[, value := {
# in this case, no matched will return NA
dup[J(value_lower), on = "old", new]
}][!is.na(value)]
# get other fields
sec_1 <- dt[J(sec$id), on = "id"][!J(sec$index), on = "index"]
# combine and change old id to negative
sec <- rbindlist(list(sec, sec_1))[, id := -id]
setorderv(sec, c("id", "index"))
# combine them all
dt <- rbindlist(list(dt, sec))
}
}
# }}}
# handle CondFD Nodal Temperature {{{
if (!is_meter) {
# can still use the old name as value_lower has not been changed
nodal <- dt[J(field_index, "condfd nodal temperature"),
on = c("index", "value_lower"), nomatch = 0L
]
if (nrow(nodal)) {
key <- dt[J(nodal$index - 1L, nodal$id), on = c("index", "id")][,
value_lower := stri_trim_both(value_lower)
][stri_isempty(value_lower), value_lower := NA_character_]
# if key value is "*" or NA
id_wild <- key[is.na(value_lower) | value_lower == "*", id]
# duplicate 10 times
if (length(id_wild)) {
obj_wild <- dt[J(id_wild), on = "id"]
# remove the original
id_del <<- c(id_del, id_wild[!is.na(id_wild)])
dt <- dt[!J(id_wild), on = "id"]
# get the smallest negative id in case processes above
# also assign negative id for distinguishing purpose
id_ne <- if (!nrow(dt)) 0L else min(c(dt$id, 0L))
obj_wild <- rbindlist(lapply(id_ne - (1L:10L),
function(dt, id) set(copy(dt), NULL, "id", id),
dt = obj_wild
))
obj_wild[J("condfd nodal temperature"), on = "value_lower",
value := paste0("CondFD Surface Temperature Node ", rep(1L:10L, each = length(id_wild)))
]
dt <- rbindlist(list(dt, obj_wild))
}
nodal <- nodal[!J(id_wild), on = "id"]
key <- key[!J(id_wild), on = "id"]
# use the key if given
key[, c("key_value", "variable") := as.data.table(stri_match_first_regex(value, "(.*)#(.*)"))[, 1L:2L]]
key <- key[!is.na(key_value)][, key_value := stri_sub(key_value, to = -5L)]
nodal <- nodal[J(key$id), on = "id"]
# update the original input
dt[key, on = c("id", "index"), value := i.key_value]
dt[nodal, on = c("id", "index"), value := i.value]
}
}
# }}}
}
# }}}
set(dt, NULL, "value_lower", NULL)
}
# }}}
# reset_meter_resource {{{
reset_meter_resource <- function(dt, mapping, field_index, step = NULL, exclude = character(), idf) {
if (to != "9.4") return(dt)
if (!nrow(dt)) return(dt)
if (!nrow(mapping)) return(dt)
# calculate field index
if (!is.null(step)) {
n <- (nrow(dt) - field_index) %/% step
field_index <- as.integer(c(field_index, seq.int(n) * step + field_index))
}
meters <- dt[J(field_index), on = "index", nomatch = NULL]
# only consider meters contain ":"
set(meters, NULL, "num", stri_count_fixed(meters$value, ":") + 1L)
meters <- meters[num > 1L]
if (!nrow(meters)) return(dt)
# exclude custom meters if necessary
set(meters, NULL, "value_lower", stri_trans_tolower(meters$value))
meters <- meters[!J(exclude), on = "value_lower"]
if (!nrow(meters)) return(dt)
# split by ":"
set(meters, NULL, "value_lower", stri_split_fixed(meters$value_lower, ":", meters$num))
# since resouce type is never in the middle, only consider the first and
# last components
set(meters, NULL, "value_lower_start", vcapply(meters$value_lower, .subset2, 1L))
set(meters, NULL, "value_lower_end", apply2_chr(meters$value_lower, meters$num, .subset2))
meters[mapping, on = c("value_lower_start" = "old"), c("value", "value_lower_end") := {
list(paste0(i.new, stri_sub(value, stri_length(value_lower_start) + 1L)), NA_character_)
}]
meters[mapping, on = c("value_lower_end" = "old"), "value" := {
paste0(stri_sub(value, to = -stri_length(value_lower_start) - 1L), i.new)
}]
dt[meters, on = c("id", "index"), value := i.value]
}
# }}}
# special case from v9.3 to v9.4 {{{
mtr_custom <- character()
map <- data.table()
if (to == "9.4") {
# extract names of Meter:Custom and Meter:CustomDecrement
cls <- c("Meter:Custom", "Meter:CustomDecrement")
cls <- cls[idf$is_valid_class(cls)]
if (length(cls)) {
mtr_custom <- stri_trans_tolower(unique(idf$object_name(cls, simplify = TRUE)))
}
map <- data.table(
old = c("electric", "gas", "fueloil#1", "fueloil#2"),
new = c("Electricity", "NaturalGas", "FuelOilNo1", "FuelOilNo2")
)
}
# }}}
f <- as.double(as.character(standardize_ver(from)[, 1:2]))
t <- as.double(as.character(standardize_ver(to)[, 1:2]))
rep_vars <- REPORTVAR_RULES[J(f, t), on = c("from", "to")]
if (nrow(rep_vars)) set(rep_vars, NULL, "old", stri_trans_tolower(rep_vars$old))
# 1: Output:Variable {{{
dt1 <- trans_action(idf, "Output:Variable")
dt1 <- reset_key(dt1, 1L)
dt1 <- update_var(dt1, rep_vars, 2L, idf = idf)
# }}}
# 2: Output:Meter:* {{{
dt2 <- rbindlist(lapply(
c("Output:Meter",
"Output:Meter:MeterFileOnly",
"Output:Meter:Cumulative",
"Output:Meter:Cumulative:MeterFileOnly"
),
trans_action, idf = idf
))
dt2 <- update_var(dt2, rep_vars, 1L, is_meter = TRUE, idf = idf)
dt2 <- reset_meter_resource(dt2, map, 1L, exclude = mtr_custom)
# }}}
# 3: Output:Table:TimeBins {{{
dt3 <- trans_action(idf, "Output:Table:TimeBins")
dt3 <- reset_key(dt3, 1L)
dt3 <- update_var(dt3, rep_vars, 2L, idf = idf)
dt3 <- reset_meter_resource(dt3, map, 2L, exclude = mtr_custom)
# }}}
# 4: Output:Table:Monthly {{{
dt4 <- trans_action(idf, "Output:Table:Monthly", min_fields = 4L)
dt4 <- update_var(dt4, rep_vars, 3L, step = 2L, idf = idf)
dt4 <- reset_meter_resource(dt4, map, 3L, step = 2L, exclude = mtr_custom)
# }}}
# 5: Output:Table:Annual {{{
# Output:Table:Annual was first added in EnergyPlus v8.4
dt5 <- data.table()
if (from >= "8.4") {
dt5 <- trans_action(idf, "Output:Table:Annual", min_fields = 6L)
dt5 <- update_var(dt5, rep_vars, 4L, step = 3L, idf = idf)
dt5 <- reset_meter_resource(dt5, map, 4L, step = 3L, exclude = mtr_custom)
}
# }}}
# 6: Meter:Custom {{{
dt6 <- trans_action(idf, "Meter:Custom")
dt6 <- update_var(dt6, rep_vars, 4L, step = 2L, is_meter = TRUE, idf = idf)
dt6 <- reset_meter_resource(dt6, map, 4L, step = 2L, exclude = mtr_custom)
# }}}
# 7: Meter:CustomDecrement {{{
dt7 <- trans_action(idf, "Meter:CustomDecrement")
dt7 <- update_var(dt7, rep_vars, 3L, 2L, is_meter = TRUE, idf = idf)
dt7 <- reset_meter_resource(dt7, map, 3L, step = 2L, exclude = mtr_custom)
# }}}
# 8: ExternalInterface:FunctionalMockupUnitImport:From:Variable & ExternalInterface:FunctionalMockupUnitExport:From:Variable {{{
dt8_1 <- trans_action(idf, "ExternalInterface:FunctionalMockupUnitImport:From:Variable")
dt8_2 <- trans_action(idf, "ExternalInterface:FunctionalMockupUnitExport:From:Variable")
dt8 <- rbindlist(list(dt8_1, dt8_2))
dt8 <- reset_key(dt8, 1L)
dt8 <- update_var(dt8, rep_vars, 2L, idf = idf)
# }}}
# 9: EnergyManagementSystem:Sensor {{{
dt9 <- trans_action(idf, "EnergyManagementSystem:Sensor")
dt9 <- update_var(dt9, rep_vars, 3L, idf = idf)
dt9 <- reset_meter_resource(dt9, map, 3L, exclude = mtr_custom)
# }}}
# 10: DemandManagerAssignmentList {{{
dt10 <- trans_action(idf, "DemandManagerAssignmentList")
dt10 <- update_var(dt10, rep_vars, 2L, is_meter = TRUE, idf = idf)
dt10 <- reset_meter_resource(dt10, map, 2L, exclude = mtr_custom)
# }}}
# 11: UtilityCost:Tariff {{{
dt11 <- trans_action(idf, "UtilityCost:Tariff")
dt11 <- update_var(dt11, rep_vars, 2L, is_meter = TRUE, idf = idf)
dt11 <- reset_meter_resource(dt11, map, 2L, exclude = mtr_custom)
# }}}
# 12: ElectricLoadCenter:Transformer {{{
dt12 <- trans_action(idf, "ElectricLoadCenter:Transformer")
dt12 <- update_var(dt12, rep_vars, 19L, step = 1L, is_meter = TRUE, idf = idf)
dt12 <- reset_meter_resource(dt12, map, 19L, step = 1L, exclude = mtr_custom)
# }}}
# 13: ElectricLoadCenter:Distribution {{{
dt13 <- trans_action(idf, "ElectricLoadCenter:Distribution")
dt13 <- update_var(dt13, rep_vars, c(6L, 12L), is_meter = TRUE, idf = idf)
dt13 <- reset_meter_resource(dt13, map, c(6L, 12L), exclude = mtr_custom)
# }}}
dt <- rbindlist(mget(paste0("dt", 1:13)))
if (!nrow(dt)) return(idf)
if (length(id_del <- unique(c(id_del, dt[id > 0, id])))) {
trans_process_load(idf$clone()$del(id_del), idf, dt, empty = FALSE)
} else {
trans_process_load(idf$clone(), idf, dt, empty = FALSE)
}
}
# }}}
# trans_action {{{
#' @importFrom checkmate assert_true test_names
trans_action <- function(idf, class, min_fields = 1L, all = FALSE, align = TRUE, ...) {
assert_true(idf$is_valid_class(class, all = TRUE))
if (!idf$is_valid_class(class)) return(data.table())
dt <- idf$to_table(class = class, align = align, all = all)
# make sure min fields are returned
if (!all && min_fields > max(dt$index)) {
cur_max <- max(dt$index)
num_obj <- length(unique(dt$id))
miss <- dt[J(rep(1L, min_fields - cur_max)), on = "index", allow.cartesian = TRUE][
, index := seq(cur_max + 1L, min_fields), by = "id"]
set(miss, NULL, c("field", "value"), NA_character_)
dt <- rbindlist(list(dt, miss))
}
setindexv(dt, c("index"))
setindexv(dt, c("id"))
setindexv(dt, c("id", "index"))
if (!is.null(names(class))) set(dt, NULL, "class", names(class))
trans_action_dt(dt, ...)
}
# }}}
# trans_action_dt {{{
trans_action_dt <- function(dt, ...) {
act <- list(...)
if (!length(act)) return(dt)
new <- data.table()
for (i in seq_along(act)) {
action <- names(act)[[i]]
content <- act[[i]]
new1 <- data.table()
if (action == "reset") {
if (length(content) == 2L) {
dt[J(content[[1L]]), on = "index", `:=`(value = content[[2L]])]
} else if (length(content) >= 3L) {
# step
if (length(content) == 4L) {
n_grp <- (nrow(dt) - content[[1L]]) %/% content[[4L]]
content[[1L]] <- content[[1L]] + c(0L, seq_len(n_grp) * content[[4L]])
}
set(dt, NULL, "value_lower", stri_trans_tolower(dt$value))
dt[J(content[[1L]], stri_trans_tolower(content[[2L]])), on = c("index", "value_lower"),
`:=`(value = content[[3L]])
]
set(dt, NULL, "value_lower", NULL)
}
} else if (action == "offset") {
# delete original first
dt <- dt[!J(setdiff(content[[2L]], content[[1L]])), on = "index"]
dt[J(content[[1L]]), on = "index", `:=`(index = content[[2L]]), by = "id"]
} else if (action == "add") {
# if no new value is given, assign NA
if (length(content) == 1L) content[[2L]] <- rep(NA_character_, length(content[[1L]]))
content[[2L]] <- rep(content[[2L]], length.out = length(content[[1L]]))
new1 <- dt[J(rep(1L, length(content[[1L]]))), on = "index", allow.cartesian = TRUE][
, `:=`(index = content[[1L]], field = names2(content[[1L]]), value = content[[2L]]), by = "id"
]
} else if (action == "insert") {
# if no new value is given, assign NA
if (length(content) == 1L) content[[2]] <- rep(NA_character_, length(content[[1L]]))
# if no step value is given, assgin zero
if (length(content) == 2L) content[[3L]] <- 0L
# calculate new index of group rows to insert
num_grp <- dt[index >= content[[1L]][[1L]],
{
if (content[[3L]] == 0L) {
num <- 1L
} else {
num <- .N / content[[3L]] + 1L
assert_count(num, .var.name = "step for row insertion")
}
index <- content[[1L]] + rep((length(content[[1L]]) + content[[3L]]) * (seq_len(num) - 1L), each = length(content[[1L]]))
value <- rep(rep(content[[2L]], length.out = length(content[[1L]])), num)
field <- rep(rep(names2(content[[1L]]), length.out = length(content[[1L]])), num)
list(index = 1L, new_index = as.integer(index),
new_value = value, new_field = field
)
},
by = "id"
]
# extract group of groups
new1 <- dt[num_grp, on = c("id", "index")]
set(new1, NULL, c("index", "value", "field"), NULL)
setnames(new1, c("new_index", "new_field", "new_value"), c("index", "field", "value"))
# update index of field left
dt[index >= content[[1L]][[1L]], index := {
if (content[[3L]] == 0L) {
num <- 1L
} else {
num <- .N / content[[3L]]
}
as.integer(index + length(content[[1L]]) *
rep(seq_len(num), each = if (content[[3L]]) content[[3L]] else 1L)
)
}, by = "id"]
} else if (action == "delete") {
if (length(content) < 2L) {
dt <- dt[!J(content[[1L]]), on = "index"]
} else {
dt <- dt[index < content[[1L]] | (index - content[[1L]]) %% content[[2L]] != 0L]
}
}
new <- rbindlist(list(new, new1), use.names = TRUE)
}
new_dt <- rbindlist(list(dt, new), use.names = TRUE)
setorderv(new_dt, c("id", "index"))
setindexv(new_dt, c("index"))
setindexv(new_dt, c("id"))
setindexv(new_dt, c("id", "index"))
setorderv(new_dt, c("id", "index"))
new_dt
}
# }}}
# trans_upper_versions {{{
trans_upper_versions <- function(idf, ver, patch = FALSE) {
# get all versions needed to handle
all_vers <- standardize_ver(ALL_IDD_VER)
vers <- all_vers[all_vers >= idf$version() & all_vers <= standardize_ver(ver)]
# remove patch version
if (length(vers) && !patch) {
vers <- vers[!duplicated(as.character(vers[, 1:2]))]
}
vers
}
# }}}
# trans_fun_names {{{
trans_fun_names <- function(vers) {
# get corresponding transition function names
vers <- gsub(".", "", as.character(vers), fixed = TRUE)
vers[vers == "901"] <- "900"
vers <- unique(vers)
funs <- paste0("f", vers[-length(vers)], "t", vers[-1L])
# only include transition functions available
funs[funs %in% names(trans_funs)]
}
# }}}
# trans_process_load {{{
trans_process_load <- function(new_idf, old_idf, dt, empty = TRUE) {
if (!nrow(dt)) return(new_idf)
# get object table from old input
old <- get_priv_env(old_idf)$idf_env()$object[J(unique(dt$id)), on = "object_id", nomatch = 0L]
# get object table before inserting new objects
new_before <- get_priv_env(new_idf)$idf_env()$object
# insert new objects
new_idf$load(dt, .unique = FALSE, .default = FALSE, .empty = empty)
if (is.null(unlist(old$comment, use.names = FALSE))) return(new_idf)
# update
input <- dt[, list(rleid = .GRP), by = list(object_id = id, class)]
input[old, on = "object_id", comment := i.comment]
get_priv_env(new_idf)$idf_env()$object[
!new_before, on = "object_id", `:=`(comment = {
if (.N == nrow(input)) {
if (.N == 1L) {
list(input$comment)
} else {
input$comment
}
} else {
warn(
paste0("Failed to preserve comments of objects involved during transition ",
"from ", old_idf$version()[, 1:2], " to ", new_idf$version()[, 1:2], ". ",
"Comments of objects below will be removed:\n",
get_object_info(.SD, c("name", "id"), collapse = "\n")
),
paste0("warning_trans_",
gsub(".", "", as.character(old_idf$version()), fixed = TRUE), "_",
gsub(".", "", as.character(new_idf$version()), fixed = TRUE))
)
list(comment)
}
})]
new_idf
}
# }}}
# trans_table_convert {{{
trans_table_convert <- function(path, ascending = c(TRUE, TRUE)) {
vars <- fread(path, nrows = 1, header = FALSE)
val_vars <- lapply(seq.int(vars$V1), function(row) unlist(fread(path, nrows = 1, skip = row)))
# reorder if necessary
if (any(!ascending) && vars$V1 >= 2L) {
val_vars <- apply2(val_vars, ascending, function(val, asc) if (!asc) rev(val) else val)
}
# check consistency between value number specified and found
num_vals <- viapply(val_vars, length)
if (any(mismatch <- (num_vals != unlist(vars[, -"V1"])))) {
invld <- unlist(vars[, .SD, .SDcols = setdiff(names(vars), "V1")[mismatch]])
abort(paste0("Number of independent variable values found mismatches with description in header:\n",
" #", which(mismatch), "| ", invld, " specified in header but ",
num_vals[mismatch], " values found"
))
}
# get cross joined table
dt_vars <- do.call(data.table::CJ, rev(val_vars))
# change column order
setcolorder(dt_vars, rev(names(dt_vars)))
# rename columns
setnames(dt_vars, paste0("var", seq.int(ncol(dt_vars))))
# read tabular data and change it to one row matrix
table <- matrix(t(as.matrix(fread(path, skip = 1 + num_vals, header = FALSE))), nrow = 1L)
# add value column
dt_vars[, value := as.vector(table)]
# change row order
setorderv(dt_vars, setdiff(names(dt_vars), "value"))
}
# }}}
#' Run IDFVersionUpdater to Update Model Versions
#'
#' `version_updater()` is a wrapper of IDFVersionUpdater preprocessor
#' distributed with EnergyPlus. It takes a path of IDF file or an [Idf] object,
#' a target version to update to and a directory to save the new models.
#'
#' An attribute named `errors` is attached which is a list of
#' [ErrFiles][read_err()] that contain all error messages from transition error
#' (.VCpErr) files.
#'
#' @inheritParams transition
#' @param dir The directory to save the new IDF files. If the directory does not
#' exist, it will be created before save. If `NULL`, the directory of input
#' [Idf] object or IDF file will be used. Default: `NULL`.
#' @return An [Idf] object if `keep_all` is `FALSE` or a list of [Idf] objects
#' if `keep_all` is `TRUE`. An attribute named `errors` is attached which
#' contains all error messages from transition error (.VCpErr) files.
#' @author Hongyuan Jia
#' @examples
#' \dontrun{
#' if (any(avail_eplus()) > "7.2") {
#' # create an empty IDF
#' idf <- empty_idf("7.2")
#' idf$save(tempfile(fileext = ".idf"))
#'
#' # convert it from v7.2 to the latest EnergyPlus installed
#' updated <- version_updater(idf, max(avail_eplus()))
#'
#' # convert it from v7.2 to the latest EnergyPlus installed and keep all
#' # intermediate versions
#' updated <- version_updater(idf, max(avail_eplus()), keep_all = TRUE)
#'
#' # see transition error messages
#' attr(updated, "errors")
#' }
#' }
#' @export
# version_updater {{{
version_updater <- function(idf, ver, dir = NULL, keep_all = FALSE) {
# parse file
if (!is_idf(idf)) idf <- read_idf(idf)
if (length(ver) != 1L || is.na(ver <- convert_to_idd_ver(ver))) {
abort("'ver' must be a valid EnergyPlus IDD version")
}
# save the model to the output dir if necessary
if (is.null(idf$path()) || !utils::file_test("-f", idf$path())) {
abort(paste0("The Idf object is not created from local file or local file has ",
"been deleted from disk. Please save Idf using '$save()' before transition."
), "idf_not_local")
}
# stop if unsaved
if (idf$is_unsaved()) {
abort("Idf has been modified since read or last saved. Please save Idf using '$save()' before transition.")
}
if (is.null(dir)) {
dir <- dirname(idf$path())
} else if (!dir.exists(dir)) {
dir.create(dir, recursive = TRUE)
}
# skip if input is already at the specified version
if (idf$version()[, 1:2] == ver[, 1:2]) {
verbose_info("IDF is already at latest version ", ver, ". No transition needed.")
if (keep_all) {
res <- list(idf)
setattr(res, "names", as.character(idf$version()[, 1L:2L]))
return(res)
} else {
return(idf)
}
}
newer_ep <- avail_eplus()[avail_eplus()[, 1:2] >= ver[, 1:2]]
if (!length(newer_ep)) {
abort(paste0("EnergyPlus v", ver, " or newer are not installed."))
}
# save the original file with trailing version number
original <- paste0(tools::file_path_sans_ext(basename(idf$path())), "V", idf$version()[, 1L], idf$version()[, 2L], "0.idf")
# clone original
idf <- idf$clone(TRUE)
idf$save(file.path(dir, original), overwrite = TRUE)
# get upper versions toward target version
vers <- trans_upper_versions(idf, ver)
# get transition executable names
exe <- if (is_windows()) ".exe" else NULL
from <- vers[-length(vers)]
to <- vers[-1L]
trans_exe <- paste0("Transition-",
"V", from[, 1L], "-", from[, 2L], "-0", "-to-",
"V", to[, 1L], "-", to[, 2L], "-0", exe
)
# results
models <- vector("list", 1L + length(to))
names(models) <- as.character(c(idf$version()[, 1:2], to[, 1:2]))
# paths
paths <- character(1L + length(to))
names(paths) <- names(models)
# errors
errors <- vector("list", 1L + length(to))
names(errors) <- names(models)
# avoid to use IDFVersionUpdater v9.0 as there are fatal errors
if (length(newer_ep[newer_ep[, 1:2] != "9.0"])) newer_ep <- newer_ep[newer_ep[, 1:2] != "9.0"]
# NOTE: From EnergyPlus v23.1, the supported oldest version for transition
# is v9.0. Should check if transitions below v9.0 are needed. If so, check
# if there is an installed EnergyPlus version lower than v23.1 and use
# transition executable from there when applicable.
#
# get the version updater from the latest version
path_updater <- file.path(eplus_config(max(newer_ep))$dir, "PreProcess/IDFVersionUpdater")
path_updater <- rep(path_updater, length(trans_exe))
# check if there are available EnergyPlus < v23.1
if (any(vers < "9.0") && max(newer_ep) >= "23.1" &&
any(is_lower_ep <- avail_eplus() > max(vers[vers < "9.0"]) & avail_eplus() < "23.1")) {
lower_ep <- avail_eplus()[is_lower_ep]
# avoid to use IDFVersionUpdater v9.0 as there are fatal errors
if (length(lower_ep[lower_ep[, 1:2] != "9.0"])) lower_ep <- lower_ep[lower_ep[, 1:2] != "9.0"]
path_updater[to <= "9.0"] <- file.path(
eplus_config(max(lower_ep))$dir, "PreProcess/IDFVersionUpdater"
)
}
names(path_updater) <- as.character(to)
while (idf$version()[, 1:2] != max(to)[, 1:2]) {
# restore paths
paths[names(paths) == as.character(idf$version()[, 1:2])] <- idf$path()
# restore models
models[names(models) == as.character(idf$version()[, 1:2])] <- list(idf)
current_exe <- trans_exe[from[, 1:2] == idf$version()[, 1:2]]
toward <- to[from[, 1:2] == idf$version()[, 1:2]]
updater <- path_updater[names(path_updater) == as.character(toward)]
verbose_info("IDFVersionUpdater: ", normalizePath(updater, mustWork = FALSE))
verbose_info(
"Input file: ", idf$path(), "\n",
" From Ver: ", idf$version(), "\n",
"Toward Ver: ", toward
)
trans_path <- file.path(updater, current_exe)
if (!file.exists(trans_path)) {
abort(paste0("Transition executable ", surround(trans_path), " does not exist."))
}
job <- tryCatch(processx::run(trans_path, idf$path(), wd = updater),
error = function(e) {
if (grepl("System command error", conditionMessage(e))) {
abort(paste0("Failed to update file ", idf$path(), " from V", idf$version(), " to V", toward, ":\n", conditionMessage(e)))
} else {
stop(e)
}
}
)
if (job$status != 0L) {
abort(paste0("Failed to update file ", idf$path(), " from V", idf$version(), " to V", toward, "."))
}
verbose_info("[", idf$version(), " --> ", toward, "] SUCCEEDED.\n")
# delete the new IDF file with old name since there is another new IDF file
# with ".idfold" extenstion
unlink(idf$path(), force = TRUE)
# read error file
path_err <- paste0(tools::file_path_sans_ext(idf$path()), ".VCpErr")
# in case VersionUpdater crashed
if (!file.exists(path_err)) {
err <- data.table()
} else {
err <- read_err(path_err)
# remove VCpErr file generated
unlink(path_err, force = TRUE)
}
# rename the old file
file.rename(paste0(tools::file_path_sans_ext(idf$path()), ".idfold"), idf$path())
# name of the new file
path_new <- paste0(tools::file_path_sans_ext(idf$path()), ".idfnew")
# replace the old Idf object
idf <- read_idf(path_new)
# resave using eplusr
new_name <- paste0(stri_sub(tools::file_path_sans_ext(path_new), to = -4L), toward[, 1L], toward[, 2L], "0.idf")
idf$save(new_name, overwrite = TRUE)
# rename the orignal new file
unlink(path_new, force = TRUE)
# remove log file generated
unlink(file.path(path_updater, c("fort.6", "Energy+.ini", "Transition.audit")), force = TRUE)
# restore paths
paths[names(paths) == as.character(idf$version()[, 1:2])] <- idf$path()
# restore models
models[names(models) == as.character(idf$version()[, 1:2])] <- list(idf)
# restore errors
errors[names(errors) == as.character(idf$version()[, 1:2])] <- list(err)
}
if (!keep_all) {
unlink(paths[-length(paths)], force = TRUE)
models <- models[[length(models)]]
}
attr(models, "errors") <- errors
models
}
# }}}
# vim: set fdm=marker:
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.