class: center, middle, inverse, title-slide # Interfacing EnergyPlus using R ## —— Intro to
eplusr
R package
### Hongyuan Jia ### 2019-05-14 --- name: self class: right, middle <img class="circle" src="https://github.com/hongyuanjia.png" width="150px"/> # Find me at... [
@jiahony](http://twitter.com/jiahony) [
@hongyuanjia](http://github.com/hongyuanjia) [
hongyuan.jia@bears-berkeley.sg](mailto:hongyuan.jia@bears-berkeley.sg) --- name: prerequiste class: middle, inverse # We assume: -- ###
You know R and are comfortable with R programming -- ### <img src="figure/ep-nobg.png" width="6%" style="float:left"/> You know basic EnergyPlus, e.g. how to edit and run a model --- ## Why EnergyPlus? .center[<img src="figure/ep-intro.png" width = "70%" align="center"/>] .footnote[Sources: https://energyplus.net/] --- ## Why EnergyPlus? .center[<img src="figure/op-eco.png" width="70%" align="center" />] .footnote[Sources: https://www.energy.gov/eere/buildings/downloads/openstudio-0] --- ## Why
? .big[.center[.blue[Why not?]]] .center[<img src="figure/r-tiobe.png" width="50%" align="center" />] --- ## Why
? <img src="figure/r4ds-book.png" width="10%" align="right" /> R is great for machine learning, data visualization and analysis, and some areas of scientific computing. <br> <br> <img src="figure/r4ds.svg" width="90%" align="center" /> .footnote[Sources: https://r4ds.had.co.nz/] --- ## Why
? > The goal of reproducible research is to tie specific instructions to data > analysis and experimental data so that scholarship can be recreated, better > understood and verified. .pull-left[ <img src="figure/rmd-book.png" width="50%" align="right" /> ] .pull-right[ <img src="figure/rmd.png" width="70%" align="left" /> ] .footnote[ Sources: https://cran.r-project.org/web/views/ReproducibleResearch.html; https://bookdown.org/yihui/rmarkdown/ ] --- class: inverse middle center ##
Wait! We already have OpenStudio and IDF Editor!! ## Why bother ?? -- ## Because... -- # .blue[Life is hard using OpenStudio and EnergyPlus, sometimes
] --- ##
Sometimes you do not want to learn a new programming language, just for getting familar with OpenStudio Ruby API ... .center[<img src="figure/measure.png" width="70%" align="center" />] --- ##
Sometimes you wish IDF Editor could do better when you rename an object... .center[<img src="figure/idfeditor-rename.png" width="40%" align="center" />] --- ##
Sometimes you failed to recall what magics I did to create all those models... .center[<img src="figure/parametric.png" width="45%" align="center" />] --- ##
Sometimes you accidently moved or deleted that "important" csv file used by your model... .center[<img src="figure/external-file.png" width="90%" align="center" />] --- ##
Sometimes you want **REAL** date and time from EnergyPlus' output... .center[<img src="figure/datetime.png" width="15%" align="center" />] --- ##
Sometimes you wish EnergyPlus could sperate key name and output variable for you... .center[<img src="figure/eplusout.png" width="75%" align="center" />] --- ##
Sometimes you find it is better to show only the data in specific time... .center[<img src="figure/excel-line-graph.png" width="85%" align="center" />] --- ##
Sometmes you don't have enough memory to paste all simulation data into a huge excel file... .center[<img src="figure/excel-no-mem.jpg" width="60%" align="center" />] --- class: inverse middle center .animated.bounce[ <img src="figure/logo.svg" height=280px> ] ## A Toolkit for Using EnergyPlus in R --- ## Features * Read, parse and modify EnergyPlus Input Data File (IDF) * Read, parse and modify EnergyPlus Weather File (EPW) * Query on models, including classes, objects and fields * Directly add, modify, duplicate, insert, and delete objects of IDF * Automatically change referenced fields when modifying objects * Save changed models into standard formats in the same way as IDFEditor distributed along with EnergyPlus * Run your models and collect the simulation output * Conduct parametric energy simulations and collect all results in one go --- ## Install and Load You can install the latest stable release of **eplusr** from CRAN. ```r install.packages("eplusr") ``` **NOTE**: I refactored the implementation of main classes in eplusr `v0.10.0`. If your eplusr version is lower than `v0.10.0`, please update it by simplily reinstall it. After install it, load eplusr by doing: ```r library(eplusr) ``` --- ## Install and Load When loading, eplusr will try to find all EnergyPlus that are installed at the default location. ```r avail_eplus() ``` ``` #> NULL ``` What if your EnergyPlus installed at a custom location? Just add it: ```r use_eplus("your_fancy_path") ``` --- ## Install and Load To check if certain EnergyPlus is located by eplusr: ```r is_avail_eplus(8.8) ``` ``` #> [1] FALSE ``` You can install EnergyPlus using `install_eplus()`. ```r install_eplus(8.8) ``` **Note** that `install_eplus()` requires administrative privileges. You have to run R with administrator (or with sudo if you are on macOS or Linux) to make it work if you are not in interactive mode. You can also download the installer and install it by yourself: ```r download_eplus(8.8, dir = "where_to_save") ``` --- class: inverse middle center # .blue[Idf] Class ### Modify EnergyPlus Model --- ## Imitate your workflow in IDF Editor .center[<img src="figure/idfeditor.png" width="65%" align="center" />] --- ## Read IDF .blue[\[
\] How can I open an IDF file?] ```r (idf <- read_idf("materials/5ZoneWaterLoopHeatPump.idf")) ``` ``` #> IDD v8.8.0 has not been parsed before. #> Try to locate `Energy+.idd` in EnergyPlus v8.8.0 installation folder `/usr/local/EnergyPlus-8-8-0`. ``` ``` #> IDD file found: `/usr/local/EnergyPlus-8-8-0/Energy+.idd`. ``` ``` #> Start parsing... ``` ``` #> Parsing completed. ``` ``` #> ── EnergPlus Input Data File ────────────────────────────────────────────── #> * Path: `/home/travis/build/hongyuanjia/eplusrIntro/materials/5ZoneWa... #> * Version: `8.8.0` #> #> Group: <Simulation Parameters> #> ├─ [001<O>] Class: <Version> #> │─ [001<O>] Class: <SimulationControl> #> │─ [001<O>] Class: <Building> #> │─ [001<O>] Class: <SurfaceConvectionAlgorithm:Inside> #> │─ [001<O>] Class: <SurfaceConvectionAlgorithm:Outside> #> │─ [001<O>] Class: <HeatBalanceAlgorithm> #> └─ [001<O>] Class: <Timestep> .... ``` --- ## Nomenclature .blue[\[
\] What does `Group` and `Class` mean?] .center[<img src="figure/nomenclature.png" width="90%" align="left" />] .center[**`Group`** --> **`Class`** --> **`Object`** --> **`Field`** --> **`Value`** ] --- ## Basic Info .blue[\[
\] Where is my IDF?] ```r idf$path() ``` ``` #> [1] "/home/travis/build/hongyuanjia/eplusrIntro/materials/5ZoneWaterLoopHeatPump.idf" ``` -- .blue[\[
\] Is there any `Location and Climate` related thing in my model?] -- ```r idf$is_valid_group("Location and Climate") ``` ``` #> [1] TRUE ``` -- .blue[\[
\] Is there any `Schedule:Constant` object in my model?] -- ```r idf$is_valid_class("Schedule:Constant") ``` ``` #> [1] FALSE ``` --- ## Basic Info .blue[\[
\] How can I get all names of existing groups and classes in my model?] -- ```r str(idf$group_name()) ``` ``` #> chr [1:24] "Simulation Parameters" "Location and Climate" "Schedules" ... ``` ```r str(idf$class_name()) ``` ``` #> chr [1:75] "Version" "SimulationControl" "Building" ... ``` --- ## Basic Info .blue[\[
\] How can I get all names of existing groups and classes defined by EnergyPlus?] -- ```r str(idf$group_name(all = TRUE)) ``` ``` #> chr [1:58] "Simulation Parameters" "Compliance Objects" ... ``` ```r str(idf$class_name(all = TRUE)) ``` ``` #> chr [1:789] "Version" "SimulationControl" "Building" ... ``` --- ## Basic Info .blue[\[
\] How many construction and zones are there in my model?] -- ```r idf$object_num(c("Construction", "Zone")) ``` ``` #> [1] 7 6 ``` -- .blue[\[
\] Every construction and zone should have a name. Can I get them?] -- ```r idf$object_name(c("Construction", "Zone")) ``` ``` #> $Construction #> [1] "ROOF-1" "WALL-1" "CLNG-1" #> [4] "FLOOR-SLAB-1" "INT-WALL-1" "Dbl Clr 3mm/13mm Air" #> [7] "Sgl Grey 3mm" #> #> $Zone #> [1] "PLENUM-1" "SPACE1-1" "SPACE2-1" "SPACE3-1" "SPACE4-1" "SPACE5-1" ``` --- ## Basic Info .blue[\[
\] I don't think object in class `Version` has a name...] -- ```r idf$object_name("Version") ``` ``` #> $Version #> [1] NA ``` -- .blue[\[
\] If so, how can I distinguish objects that do not have names?] -- ```r idf$object_id(c("Version", "Construction", "Zone")) ``` ``` #> $Version #> [1] 1 #> #> $Construction #> [1] 38 39 40 41 42 50 51 #> #> $Zone #> [1] 52 63 78 90 103 115 ``` --- ## Object Query .blue[\[
\] How can I see if a material is used by other constructions?] -- ```r idf$object_relation("wd01") ``` ``` #> ── Refer to Others ──────────────────────────────────────────────────────── #> Target(s) does not refer to any other field. #> #> ── Referred by Others ───────────────────────────────────────────────────── #> Class: <Material> #> └─ Object [ID:26] <WD01> #> └─ 1: "WD01", !- Name #> ^~~~~~~~~~~~~~~~~~~~~~~~~ #> ├─ Class: <Construction> #> │ └─ Object [ID:38] <ROOF-1> #> │ └─ 5: "WD01"; !- Layer 4 #> │ #> └─ Class: <Construction> #> └─ Object [ID:39] <WALL-1> #> └─ 2: "WD01"; !- Outside Layer .... ``` --- ## Object Query .blue[\[
\] How can I see the contents of an object?] -- ```r idf$object("wall-1") ``` ``` #> <IdfObject: `Construction`> [ID:39] `WALL-1` #> Class: <Construction> #> ├─ 1: "WALL-1", !- Name #> │─ 2: "WD01", !- Outside Layer #> │─ 3: "PW03", !- Layer 2 #> │─ 4: "IN02", !- Layer 3 #> └─ 5: "GP01"; !- Layer 4 ``` --- ## Object Query .blue[\[
\] What if I want to see all objects in class `Material`?] -- ```r idf$Material ``` ``` #> $WD10 #> <IdfObject: `Material`> [ID:22] `WD10` #> Class: <Material> #> ├─ 1: "WD10", !- Name #> │─ 2: "MediumSmooth", !- Roughness #> │─ 3: 0.667, !- Thickness {m} #> │─ 4: 0.115, !- Conductivity {W/m-K} #> │─ 5: 513, !- Density {kg/m3} #> │─ 6: 1381, !- Specific Heat {J/kg-K} #> │─ 7: 0.9, !- Thermal Absorptance #> │─ 8: 0.78, !- Solar Absorptance #> └─ 9: 0.78; !- Visible Absorptance #> #> $RG01 #> <IdfObject: `Material`> [ID:23] `RG01` .... ``` --- ## Object Query .blue[\[
\] What if I want to see both a construction and a material?] -- ```r idf$objects(c("wall-1", "wd01")) ``` ``` #> $`WALL-1` #> <IdfObject: `Construction`> [ID:39] `WALL-1` #> Class: <Construction> #> ├─ 1: "WALL-1", !- Name #> │─ 2: "WD01", !- Outside Layer #> │─ 3: "PW03", !- Layer 2 #> │─ 4: "IN02", !- Layer 3 #> └─ 5: "GP01"; !- Layer 4 #> #> $WD01 #> <IdfObject: `Material`> [ID:26] `WD01` #> Class: <Material> #> ├─ 1: "WD01", !- Name #> │─ 2: "MediumSmooth", !- Roughness #> │─ 3: 0.019099999, !- Thickness {m} .... ``` --- ## Object Query .blue[\[
\] What if I want to see a material and all constructions that use it?] -- ```r idf$objects_in_relation("wd01", "ref_by") ``` ``` #> $WD01 #> <IdfObject: `Material`> [ID:26] `WD01` #> Class: <Material> #> ├─ 1: "WD01", !- Name #> │─ 2: "MediumSmooth", !- Roughness #> │─ 3: 0.019099999, !- Thickness {m} #> │─ 4: 0.115, !- Conductivity {W/m-K} #> │─ 5: 513, !- Density {kg/m3} #> │─ 6: 1381, !- Specific Heat {J/kg-K} #> │─ 7: 0.9, !- Thermal Absorptance #> │─ 8: 0.78, !- Solar Absorptance #> └─ 9: 0.78; !- Visible Absorptance #> #> $`ROOF-1` #> <IdfObject: `Construction`> [ID:38] `ROOF-1` .... ``` --- ## Object Query .blue[\[
\] But those construction may be also used in surfaces. Can I get all objects that has some relations with that material?] -- ```r lapply(idf$objects_in_relation("wd01", "ref_by", recursive = TRUE), function (x) x$class_name()) ``` ``` #> $WD01 #> [1] "Material" #> #> $`ROOF-1` #> [1] "Construction" #> #> $`WALL-1` #> [1] "Construction" #> #> $`TOP-1` #> [1] "BuildingSurface:Detailed" #> #> $`WALL-1PF` #> [1] "BuildingSurface:Detailed" #> .... ``` --- ## Add Objects .blue[\[
\] How can I add new objects?] -- ```r idf$add( RunPeriod = list( name = "Jan", begin_month = 1, begin_day_of_month = 1, end_month = 1, end_day_of_month = 31), Material = list("my_mat", "Rough", 0.2, 1.5, 2000, 800) ) ``` ``` #> $Jan #> <IdfObject: `RunPeriod`> [ID:497] `Jan` #> Class: <RunPeriod> #> ├─ 01: "Jan", !- Name #> │─ 02: 1, !- Begin Month #> │─ 03: 1, !- Begin Day of Month #> │─ 04: 1, !- End Month #> │─ 05: 31, !- End Day of Month #> │─ 06: "UseWeatherFile", !- Day of Week for Start Day #> │─ 07: "Yes", !- Use Weather File Holidays and Special Days .... ``` --- ## Definition .blue[\[
\] But I cannot remember all field names...] -- ```r mat_def <- idf$definition("Material") mat_def ``` ``` #> <IddObject: `Material`> #> ── MEMO ─────────────────────────────────────────────────────────────────── #> "Regular materials described with full set of thermal properties" #> #> ── PROPERTIES ───────────────────────────────────────────────────────────── #> * Group: `Surface Construction Elements` #> * Unique: FALSE #> * Required: FALSE #> * Total fields: 9 #> #> ── FIELDS ───────────────────────────────────────────────────────────────── #> 1*: Name #> 2*: Roughness #> 3*: Thickness #> 4*: Conductivity .... ``` --- ## Definition .blue[\[
\] I don't want to copy from the console...] -- ```r mat_def$field_name() ``` ``` #> [1] "Name" "Roughness" "Thickness" #> [4] "Conductivity" "Density" "Specific Heat" #> [7] "Thermal Absorptance" "Solar Absorptance" "Visible Absorptance" ``` --- ## Definition .blue[\[
\] So I guess there should be other data I can get from `mat_def`...] -- ```r names(mat_def) ``` ``` #> [1] ".__enclos_env__" "print" #> [3] "to_string" "to_table" #> [5] "has_ref_by" "has_ref_to" #> [7] "has_ref" "is_required_field" #> [9] "is_integer_field" "is_real_field" #> [11] "is_numeric_field" "is_autocalculatable_field" #> [13] "is_autosizable_field" "is_valid_field_index" #> [15] "is_valid_field_name" "is_extensible_index" #> [17] "is_valid_field_num" "field_possible" #> [19] "field_reference" "field_relation" .... ``` `IdfObject` is your friend. ```r ?IddObject ``` --- ## Add Objects .blue[\[
\] But that may only be useful for interactive modifcation. How can I add objects programitically?] ```r my_const <- list(Construction = list("my_const", "my_mat")) idf$add(my_const) ``` ``` #> $my_const #> <IdfObject: `Construction`> [ID:499] `my_const` #> Class: <Construction> #> ├─ 1: "my_const", !- Name #> └─ 2: "my_mat"; !- Outside Layer ``` -- ```r idf$object_relation("my_const", "ref_to") ``` ``` #> ── Refer to Others ──────────────────────────────────────────────────────── #> Class: <Construction> #> └─ Object [ID:499] <my_const> #> └─ 2: "my_mat"; !- Outside Layer #> v~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #> └─ Class: <Material> #> └─ Object [ID:498] <my_mat> #> └─ 1: "my_mat"; !- Name #> ``` --- ## Change Existing Objects .blue[\[
\] How can I change existing objects?] ```r idf$set(my_mat = list(name = "new_mat")) ``` ``` #> $new_mat #> <IdfObject: `Material`> [ID:498] `new_mat` #> Class: <Material> #> ├─ 1: "new_mat", !- Name #> │─ 2: "Rough", !- Roughness #> │─ 3: 0.2, !- Thickness {m} #> │─ 4: 1.5, !- Conductivity {W/m-K} #> │─ 5: 2000, !- Density {kg/m3} #> └─ 6: 800; !- Specific Heat {J/kg-K} ``` ```r idf$Construction$my_const ``` ``` #> <IdfObject: `Construction`> [ID:499] `my_const` #> Class: <Construction> #> ├─ 1: "my_const", !- Name #> └─ 2: "new_mat"; !- Outside Layer ``` --- ## Change Existing Objects .blue[\[
\] How can I change an object that does not have a name? Say `SimulationControl`?] ```r idf$SimulationControl$Do_Zone_Sizing_Calculation <- "No" idf$SimulationControl$set(Do_System_Sizing_Calculation = "No") ``` ``` #> <IdfObject: `SimulationControl`> [ID:18] #> Class: <SimulationControl> #> ├─ 1: "No", !- Do Zone Sizing Calculation #> │─ 2: "No", !- Do System Sizing Calculation #> │─ 3: "No", !- Do Plant Sizing Calculation #> │─ 4: "Yes", !- Run Simulation for Sizing Periods #> └─ 5: "No"; !- Run Simulation for Weather File Run Periods ``` --- ## Change Existing Objects .blue[\[
\] What if I forgot to give a name to a material? How can I change field values of that object?] ```r idf$object_id("Material") ``` ``` #> $Material #> [1] 22 23 24 25 26 27 28 29 30 31 498 ``` ```r idf$set(..498 = list(Thickness = 0.3)) ``` ``` #> $new_mat #> <IdfObject: `Material`> [ID:498] `new_mat` #> Class: <Material> #> ├─ 1: "new_mat", !- Name #> │─ 2: "Rough", !- Roughness #> │─ 3: 0.3, !- Thickness {m} #> │─ 4: 1.5, !- Conductivity {W/m-K} #> │─ 5: 2000, !- Density {kg/m3} #> └─ 6: 800; !- Specific Heat {J/kg-K} ``` --- ## Rename Objects .blue[\[
\] `Old_Name = list(Name = "New_Name")` syntax looks wired. What if I just want to rename an object?] ```r idf$rename(mat_renamed = "new_mat") ``` ``` #> $mat_renamed #> <IdfObject: `Material`> [ID:498] `mat_renamed` #> Class: <Material> #> ├─ 1: "mat_renamed", !- Name #> │─ 2: "Rough", !- Roughness #> │─ 3: 0.3, !- Thickness {m} #> │─ 4: 1.5, !- Conductivity {W/m-K} #> │─ 5: 2000, !- Density {kg/m3} #> └─ 6: 800; !- Specific Heat {J/kg-K} ``` ```r idf$Construction$my_const ``` ``` #> <IdfObject: `Construction`> [ID:499] `my_const` #> Class: <Construction> #> ├─ 1: "my_const", !- Name #> └─ 2: "mat_renamed"; !- Outside Layer ``` --- ## Duplicate Objects ```r names(idf$dup(rep("jan", 11))) ``` ``` #> ── Info ─────────────────────────────────────────────────────────────────── #> New names of duplicated objects not given are automatically generated: #> #01| Object ID [500] --> New object name `Jan_1` #> #02| Object ID [501] --> New object name `Jan_2` #> #03| Object ID [502] --> New object name `Jan_3` #> #04| Object ID [503] --> New object name `Jan_4` #> #05| Object ID [504] --> New object name `Jan_5` #> #06| Object ID [505] --> New object name `Jan_6` #> #07| Object ID [506] --> New object name `Jan_7` #> #08| Object ID [507] --> New object name `Jan_8` #> #09| Object ID [508] --> New object name `Jan_9` #> #10| Object ID [509] --> New object name `Jan_10` #> #11| Object ID [510] --> New object name `Jan_11` ``` ``` #> [1] "Jan_1" "Jan_2" "Jan_3" "Jan_4" "Jan_5" "Jan_6" "Jan_7" #> [8] "Jan_8" "Jan_9" "Jan_10" "Jan_11" ``` --- ## BONUS: Paste from IDF Editor (Windows Only) ```r idf$paste() ``` --- ## Load Objects .blue[\[
\] I love copy-- paste...] -- ```r idf$load( "Material, mat-to-load, !- Name rough, !- Roughness 0.1, !- Thickness {m} 1.5, !- Conductivity {W/m-K} 2000, !- Density {kg/m3} 800; !- Specific Heat {J/kg-K} " ) ``` ``` #> $`mat-to-load` #> <IdfObject: `Material`> [ID:511] `mat-to-load` #> Class: <Material> #> ├─ 1: "mat-to-load", !- Name #> │─ 2: "rough", !- Roughness #> │─ 3: 0.1, !- Thickness {m} #> │─ 4: 1.5, !- Conductivity {W/m-K} #> │─ 5: 2000, !- Density {kg/m3} #> └─ 6: 800; !- Specific Heat {J/kg-K} ``` --- ## Load Objects You can use either a single string or a character vector. .pull-left[ ```r idf$load( "Material, mat-to-load, rough, 0.1, 1.5, 2000, 800; " ) ``` ] .pull-right[ ```r idf$load(c( "Material,", "mat-to-load,", "rough,", "0.1,", "1.5,", "2000,", "800;" )) ``` ] --- ## Load Objects .blue[\[
\] You know, R is fameous for `data.frame`...] -- ```r idf$load( data.frame(class = "Material", index = 1:6, value = I(list("mat-in-df", "rough", 0.1, 0.5, 2000, 800)), stringsAsFactors = FALSE ) ) ``` ``` #> $`mat-in-df` #> <IdfObject: `Material`> [ID:512] `mat-in-df` #> Class: <Material> #> ├─ 1: "mat-in-df", !- Name #> │─ 2: "rough", !- Roughness #> │─ 3: 0.1, !- Thickness {m} #> │─ 4: 0.5, !- Conductivity {W/m-K} #> │─ 5: 2000, !- Density {kg/m3} #> └─ 6: 800; !- Specific Heat {J/kg-K} ``` --- ## Data Extraction .blue[\[
\] No one would like to manually create that string or data.frame...] -- ```r idf$to_string("mat_renamed", header = FALSE) ``` ``` #> [1] "!- =========== ALL OBJECTS IN CLASS: MATERIAL ===========" #> [2] "" #> [3] "Material," #> [4] " mat_renamed, !- Name" #> [5] " Rough, !- Roughness" #> [6] " 0.3, !- Thickness {m}" #> [7] " 1.5, !- Conductivity {W/m-K}" #> [8] " 2000, !- Density {kg/m3}" #> [9] " 800; !- Specific Heat {J/kg-K}" #> [10] "" ``` --- ```r idf$to_table("mat_renamed") ``` <table> <thead> <tr> <th style="text-align:right;"> id </th> <th style="text-align:left;"> name </th> <th style="text-align:left;"> class </th> <th style="text-align:right;"> index </th> <th style="text-align:left;"> field </th> <th style="text-align:left;"> value </th> </tr> </thead> <tbody> <tr> <td style="text-align:right;"> 498 </td> <td style="text-align:left;"> mat_renamed </td> <td style="text-align:left;"> Material </td> <td style="text-align:right;"> 1 </td> <td style="text-align:left;"> Name </td> <td style="text-align:left;"> mat_renamed </td> </tr> <tr> <td style="text-align:right;"> 498 </td> <td style="text-align:left;"> mat_renamed </td> <td style="text-align:left;"> Material </td> <td style="text-align:right;"> 2 </td> <td style="text-align:left;"> Roughness </td> <td style="text-align:left;"> Rough </td> </tr> <tr> <td style="text-align:right;"> 498 </td> <td style="text-align:left;"> mat_renamed </td> <td style="text-align:left;"> Material </td> <td style="text-align:right;"> 3 </td> <td style="text-align:left;"> Thickness </td> <td style="text-align:left;"> 0.3 </td> </tr> <tr> <td style="text-align:right;"> 498 </td> <td style="text-align:left;"> mat_renamed </td> <td style="text-align:left;"> Material </td> <td style="text-align:right;"> 4 </td> <td style="text-align:left;"> Conductivity </td> <td style="text-align:left;"> 1.5 </td> </tr> <tr> <td style="text-align:right;"> 498 </td> <td style="text-align:left;"> mat_renamed </td> <td style="text-align:left;"> Material </td> <td style="text-align:right;"> 5 </td> <td style="text-align:left;"> Density </td> <td style="text-align:left;"> 2000 </td> </tr> <tr> <td style="text-align:right;"> 498 </td> <td style="text-align:left;"> mat_renamed </td> <td style="text-align:left;"> Material </td> <td style="text-align:right;"> 6 </td> <td style="text-align:left;"> Specific Heat </td> <td style="text-align:left;"> 800 </td> </tr> </tbody> </table> --- ## Insert Objects .blue[\[
\] What if I want to directly insert objects from another `Idf` or design days from an `.ddy` file?] -- ```r ddy <- read_idf(file.path("materials/USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.ddy"), 8.8) names(idf$insert(ddy$SizingPeriod_DesignDay)) ``` ``` #> [1] "Chicago Ohare Intl Ap Ann Htg 99.6% Condns DB" #> [2] "Chicago Ohare Intl Ap Ann Htg 99% Condns DB" #> [3] "Chicago Ohare Intl Ap Ann Hum_n 99.6% Condns DP=>MCDB" #> [4] "Chicago Ohare Intl Ap Ann Hum_n 99% Condns DP=>MCDB" #> [5] "Chicago Ohare Intl Ap Ann Htg Wind 99.6% Condns WS=>MCDB" #> [6] "Chicago Ohare Intl Ap Ann Htg Wind 99% Condns WS=>MCDB" #> [7] "Chicago Ohare Intl Ap Ann Clg .4% Condns DB=>MWB" #> [8] "Chicago Ohare Intl Ap Ann Clg 1% Condns DB=>MWB" #> [9] "Chicago Ohare Intl Ap Ann Clg 2% Condns DB=>MWB" #> [10] "Chicago Ohare Intl Ap Ann Clg .4% Condns WB=>MDB" #> [11] "Chicago Ohare Intl Ap Ann Clg 1% Condns WB=>MDB" #> [12] "Chicago Ohare Intl Ap Ann Clg 2% Condns WB=>MDB" #> [13] "Chicago Ohare Intl Ap Ann Clg .4% Condns DP=>MDB" #> [14] "Chicago Ohare Intl Ap Ann Clg 1% Condns DP=>MDB" #> [15] "Chicago Ohare Intl Ap Ann Clg 2% Condns DP=>MDB" .... ``` --- ## Delete Objects .blue[\[
\] How can I delete objects?] ```r idf$del("mat-to-load", idf$object_id("SizingPeriod:DesignDay", simplify = TRUE)) ``` --- ## Delete Objects .blue[\[
\] What if I try to delete a material that is used by an construction?] ```r idf$del("mat_renamed") ``` ``` #> Error: Cannot delete object(s) that are referred by others: #> #> Class: <Material> #> └─ Object [ID:498] <mat_renamed> #> └─ 1: "mat_renamed"; !- Name #> ^~~~~~~~~~~~~~~~~~~~~~~~~ #> └─ Class: <Construction> #> └─ Object [ID:499] <my_const> #> └─ 2: "mat_renamed"; !- Outside Layer #> ``` --- ## Delete Objects .blue[\[
\] What if I want to delete the material and all constructions that use it?] ```r idf$del("mat_renamed", .ref_by = TRUE) ``` ``` #> ── Info ─────────────────────────────────────────────────────────────────── #> Deleting object(s) [ID: 498] #> #> Including object(s) [ID:499] that refer to it. #> #> Object relation is shown below: #> ── Referred by Others ───────────────────────────────────────────────────── #> Class: <Material> #> └─ Object [ID:498] <mat_renamed> #> └─ 1: "mat_renamed"; !- Name #> ^~~~~~~~~~~~~~~~~~~~~~~~~ #> └─ Class: <Construction> #> └─ Object [ID:499] <my_const> #> └─ 2: "mat_renamed"; !- Outside Layer #> ``` --- ## Delete Objects .blue[\[
\] What if I want to delete a construction and all materials it uses?] ```r idf$del("my_const", .ref_to = TRUE) ``` --- ## Check for errors .blue[\[
\] How can I check for possible errors in my model just like IDF Editor does?] -- ```r idf$validate() ``` ``` #> ✔ No error found. ``` --- .blue[\[
\] How kinds of checkings are there?] ```r eplusr_option("validate_level") ``` ``` #> [1] "final" ``` ```r str(level_checks(eplusr_option("validate_level"))) ``` ``` #> List of 10 #> $ required_object: logi TRUE #> $ unique_object : logi TRUE #> $ unique_name : logi TRUE #> $ extensible : logi TRUE #> $ required_field : logi TRUE #> $ autofield : logi TRUE #> $ type : logi TRUE #> $ choice : logi TRUE #> $ range : logi TRUE #> $ reference : logi TRUE ``` --- ## Save model .blue[\[
\] I am not quite sure if I made modifcations to the model...] -- ```r idf$is_unsaved() ``` ``` #> [1] TRUE ``` -- ```r idf$save(file.path(tempdir(), "test.idf")) ``` --- name: prerequiste class: middle, inverse ##
No big deal so far... -- ## .blue[
R is a programming language!] --- ## Leverage the power of R .center[<img src="figure/rotate_building.png" width="90%" align="center" />] .footnote[Source: https://bcl.nrel.gov/node/84693] --- ## Demo ```r source("measures/rotate.R") rotate_building(idf, 30) ``` ``` #> <IdfObject: `Building`> [ID:2] `Building` #> Class: <Building> #> ├─ 1: "Building", !- Name #> │─ 2: 60, !- North Axis {deg} #> │─ 3: "City", !- Terrain #> │─ 4: 0.04, !- Loads Convergence Tolerance Value #> │─ 5: 0.4, !- Temperature Convergence Tolerance Value {delt... #> │─ 6: "FullExterior", !- Solar Distribution #> │─ 7: 25, !- Maximum Number of Warmup Days #> └─ 8: 6; !- Minimum Number of Warmup Days ``` --- ## Leverage the power of R .center[<img src="figure/increase-r-value-of-roof.png" width="90%" align="center" />] .footnote[Source: https://bcl.nrel.gov/node/84677] --- ## Demo ```r source("measures/roof_r_value.R") align_roof_r_value(idf, 5) ``` ``` #> ROOF-1 #> 5 ``` --- class: inverse middle center # .blue[EplusJob] Class ### Run and Collect Output --- ## Run and Collect Output .blue[\[
\] Finally! How can I run my simulaion?] ```r idf <- read_idf("materials/5ZoneWaterLoopHeatPump.idf") # make sure objects in `RunPeriod` class take effect idf$SimulationControl$Run_Simulation_for_Weather_File_Run_Periods <- "Yes" # save the model before run idf$save(file.path(tempdir(), "example.idf"), overwrite = TRUE) ``` --- ```r path_epw <- file.path("materials/USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.epw") job <- idf$run(path_epw, dir = tempdir()) ``` ``` #> ── Info ─────────────────────────────────────────────────────────────────── #> Adding object `Output:SQLite` and setting `Option Type` to `SimpleAndTabular` in order to create SQLite output file. #> #> ── Info ─────────────────────────────────────────────────────────────────── #> Replace the existing IDF located at /tmp/Rtmpg5xvmx/example.idf. #> #> ExpandObjects Started. #> No expanded file generated. #> ExpandObjects Finished. Time: 0.058 #> EnergyPlus Starting #> EnergyPlus, Version 8.8.0-7c3bbe4830, YMD=2019.05.15 10:56 #> Processing Data Dictionary #> Processing Input File #> Initializing Simulation #> Reporting Surfaces #> Beginning Primary Simulation #> Initializing New Environment Parameters #> Warming up {1} #> Warming up {2} #> Warming up {3} .... ``` --- ## Run and Collect Output .blue[\[
\] How can I see if there are errors during my simulation?] ```r class(job) ``` ``` #> [1] "EplusJob" "R6" ``` ```r names(job) ``` ``` #> [1] ".__enclos_env__" "print" "tabular_data" #> [4] "report_data" "report_data_dict" "read_table" #> [7] "list_table" "errors" "locate_output" #> [10] "output_dir" "status" "kill" #> [13] "run" "path" "initialize" ``` ```r job ``` ``` #> ── EnergyPlus Simulation Job ────────────────────────────────────────────── #> * Model: `/tmp/Rtmpg5xvmx/example.idf` #> * Weather: `/home/travis/build/hongyuanjia/eplusrIntro/materials/USA_...` #> * EnergyPlus Version: `8.8.0` #> * EnergyPlus Path: `/usr/local/EnergyPlus-8-8-0` #> Simulation started at `2019-05-15 10:56:35` and completed successfully after 3.1 secs. ``` --- ```r job$errors() ``` ``` #> ══ EnergyPlus Error File ══════════════════════════════════════════════════ #> * EnergyPlus version: 8.8.0 (7c3bbe4830) #> * Simulation started: 2019-05-15 10:56:00 #> * Terminated: FALSE #> * Successful: TRUE #> * Warning[W]: 1 #> #> ── During Simulation ────────────────────────────────────────────────────── #> [W 1/1] CalcElectricChillerModel - Chiller:Electric "CENTRAL CHILLER" - Air #> Cooled Condenser Inlet Temperature below 0C. #> ... Outdoor Dry-bulb Condition = -12.60 C. Occurrence info = #> Chicago Ohare Intl Ap IL USA TMY3 WMO#=725300, 01/14 00:00 - 00:15 ``` --- ## Run and Collect Output .blue[\[
\] How can I retrieve my simulation results?] ```r job$report_data() ``` ``` #> case datetime key_value #> 1: example 2019-01-21 01:00:00 Environment #> 2: example 2019-01-21 01:00:00 PLENUM-1 #> 3: example 2019-01-21 01:00:00 PLENUM-1 #> 4: example 2019-01-21 01:00:00 PLENUM-1 #> 5: example 2019-01-21 01:00:00 SPACE1-1 #> --- #> 14828: example 2015-07-08 00:00:00 #> 14829: example 2015-07-08 00:00:00 #> 14830: example 2015-07-08 00:00:00 #> 14831: example 2015-07-08 00:00:00 #> 14832: example 2015-07-08 00:00:00 #> name units value #> 1: Site Outdoor Air Drybulb Temperature C -1.730000e+01 #> 2: Zone Air System Sensible Heating Rate W 0.000000e+00 #> 3: Zone Air System Sensible Cooling Rate W 0.000000e+00 #> 4: Zone Air Temperature C 1.196546e+01 #> 5: Zone Air System Sensible Heating Rate W 3.239758e+03 #> --- #> 14828: Electricity:Facility J 2.312195e+09 #> 14829: Electricity:Building J 4.466700e+08 #> 14830: InteriorLights:Electricity J 2.983500e+08 #> 14831: Electricity:HVAC J 1.772259e+08 #> 14832: Electricity:Plant J 1.688299e+09 ``` --- ## Run and Collect Output .blue[\[
\] What are the advantages of using `$report_data()`?] ```r args(job$report_data) ``` ``` #> function (key_value = NULL, name = NULL, year = NULL, tz = "UTC", #> case = "auto", all = FALSE, period = NULL, month = NULL, #> day = NULL, hour = NULL, minute = NULL, interval = NULL, #> simulation_days = NULL, day_type = NULL, environment_name = NULL) #> NULL ``` --- ## Introducing Tidy Data Tidy data is a standard way of mapping the meaning of a dataset to its structure. A dataset is messy or tidy depending on how rows, columns and tables are matched up with observations, variables and types. In tidy data: * Each variable forms a column. * Each observation forms a row. * Each type of observational unit forms a table. .footnote[Source: https://www.jstatsoft.org/article/view/v059i10] --- ## Introducing Tidy Data .center[<img src="figure/eplusout.png" width="65%" align="center" />] .center[EnergyPlus always gives untidy data] --- .center[<img src="figure/report_data.png" width="10%" align="center" />] ```r first_line <- job$report_data()[1] str(first_line) ``` ``` #> Classes 'data.table' and 'data.frame': 1 obs. of 6 variables: #> $ case : chr "example" #> $ datetime : POSIXct, format: "2019-01-21 01:00:00" #> $ key_value: chr "Environment" #> $ name : chr "Site Outdoor Air Drybulb Temperature" #> $ units : chr "C" #> $ value : num -17.3 #> - attr(*, ".internal.selfref")=<externalptr> ``` `SPACE1-1: Zone Air System Sensible Heating Rate [W](Hourly)`: * .blue[key_value] --> `SPACE1-1` * .blue[name] --> `Zone Air System Sensible Heating Rate` * .blue[units] --> `W` --- .blue[Get all available report variable keys and names] ```r str(job$report_data_dict()) ``` ``` #> Classes 'data.table' and 'data.frame': 166 obs. of 10 variables: #> $ report_data_dictionary_index: int 6 11 12 21 22 41 42 299 300 301 ... #> $ is_meter : int 0 1 1 1 1 1 1 0 0 0 ... #> $ type : chr "Avg" "Sum" "Sum" "Sum" ... #> $ index_group : chr "Zone" "Facility:Electricity" "Facility:Electricity" "Building:Electricity" ... #> $ timestep_type : chr "HVAC System" "HVAC System" "HVAC System" "HVAC System" ... #> $ key_value : chr "Environment" "" "" "" ... #> $ name : chr "Site Outdoor Air Drybulb Temperature" "Electricity:Facility" "Electricity:Facility" "Electricity:Building" ... #> $ reporting_frequency : chr "Hourly" "Monthly" "Run Period" "Monthly" ... #> $ schedule_name : chr NA NA NA NA ... #> $ units : chr "C" "J" "J" "J" ... #> - attr(*, ".internal.selfref")=<externalptr> ``` --- .blue[Get air temperature for all zones] ```r job$report_data(name = "zone air temperature") ``` -- .blue[Get air temperature for zone `SPACE1-1` only] ```r job$report_data("space1-1", "zone air temperature") ``` --- .blue[Directly use `$report_data_dict()` to extract results] ```r dict <- job$report_data_dict() str(job$report_data(dict[is_meter == 1])) ``` ``` #> Classes 'data.table' and 'data.frame': 48 obs. of 6 variables: #> $ case : chr "example" "example" "example" "example" ... #> $ datetime : POSIXct, format: "2019-01-22" "2019-01-22" ... #> $ key_value: chr "" "" "" "" ... #> $ name : chr "Electricity:Facility" "Electricity:Building" "InteriorLights:Electricity" "Electricity:HVAC" ... #> $ units : chr "J" "J" "J" "J" ... #> $ value : num 4.80e+08 1.19e+08 3.24e+07 3.57e+08 1.17e+10 ... #> - attr(*, ".internal.selfref")=<externalptr> ``` --- .blue[Real `DateTime`] ```r str(job$report_data("space1-1", "zone air temperature")$datetime) ``` ``` #> POSIXct[1:96], format: "2019-01-21 01:00:00" "2019-01-21 02:00:00" ... ``` -- .blue[Change the year value of returned date time] ```r job$report_data(year = 2017) ``` -- .blue[Change the time zone of returned date time] ```r lubridate::tz(job$report_data(tz = "Asia/Singapore")$datetime) ``` ``` #> [1] "Asia/Singapore" ``` --- .blue[Make sure start day of week matches!] .pull-left[ ```r idf$RunPeriod[[1]]$value(1:6) ``` ``` #> $Name #> [1] NA #> #> $`Begin Month` #> [1] 1 #> #> $`Begin Day of Month` #> [1] 14 #> #> $`End Month` #> [1] 1 #> #> $`End Day of Month` #> [1] 14 #> #> $`Day of Week for Start Day` #> [1] "Tuesday" ``` ] .pull-right[ ```r idf$RunPeriod[[2]]$value(1:6) ``` ``` #> $Name #> [1] NA #> #> $`Begin Month` #> [1] 7 #> #> $`Begin Day of Month` #> [1] 7 #> #> $`End Month` #> [1] 7 #> #> $`End Day of Month` #> [1] 7 #> #> $`Day of Week for Start Day` #> [1] "Tuesday" ``` ] --- ```r idf$object("clg-setp-sch") ``` ``` #> <IdfObject: `Schedule:Compact`> [ID:134] `CLG-SETP-SCH` #> Class: <Schedule:Compact> #> ├─ 01: "CLG-SETP-SCH", !- Name #> │─ 02: "TEMPERATURE", !- Schedule Type Limits Name #> │─ 03: "Through: 12/31", !- Field 1 #> │─ 04: "For: Weekdays CustomDay1 CustomDay2", !- Field 2 #> │─ 05: "Until: 7:00", !- Field 3 #> │─ 06: "40.00", !- Field 4 #> │─ 07: "Until: 18:00", !- Field 5 #> │─ 08: "23.90", !- Field 6 #> │─ 09: "Until: 24:00", !- Field 7 #> │─ 10: "40.00", !- Field 8 #> │─ 11: "For: Weekends Holidays", !- Field 9 #> │─ 12: "Until: 7:00", !- Field 10 #> │─ 13: "40.00", !- Field 11 #> │─ 14: "Until: 13:00", !- Field 12 #> │─ 15: "23.90", !- Field 13 #> │─ 16: "Until: 24:00", !- Field 14 #> │─ 17: "32.20", !- Field 15 #> │─ 18: "For: SummerDesignDay", !- Field 16 .... ``` --- ```r temp <- job$report_data("space1-1", "zone air temperature", all = TRUE, year = 2018) library(ggplot2) temp %>% ggplot() + geom_line(aes(datetime, value)) + facet_wrap(vars(month, day), labeller = "label_both", scales = "free_x") ``` <img src="figure/unnamed-chunk-65-1.png" width="864" height="50%" style="display: block; margin: auto;" /> --- .blue[Precisely control time period] Get the total cooling rate power of AHU named `Heat Pump Cooling Mode AHU1` at 11 a.m for the first day of all runperiod, tag this simulation as case `example`, and return all possible output columns. ```r job$report_data( key_value = "heat pump cooling mode ahu1", name = "cooling coil total cooling rate", case = "example", all = TRUE, simulation_days = 1, hour = 11, minute = 0) %>% str() ``` ``` #> Classes 'data.table' and 'data.frame': 4 obs. of 21 variables: #> $ case : chr "example" "example" "example" "example" #> $ datetime : POSIXct, format: "2019-01-21 11:00:00" "2014-07-21 11:00:00" ... #> $ month : int 1 7 1 7 #> $ day : int 21 21 14 7 #> $ hour : int 11 11 11 11 #> $ minute : int 0 0 0 0 #> $ dst : int 0 0 0 0 #> $ interval : int 60 60 60 60 #> $ simulation_days : int 1 1 1 1 .... ``` --- .blue[Extract tabular data using `$tabular_data()`] .center[<img src="figure/tabular_data.png" align="center" />] ```r job$tabular_data( report_name = "ComponentSizingSummary", report_for = "entire facility", table_name = "airterminal:singleduct:uncontrolled", column_name = "user-specified maximum air flow rate", row_name = "space5-1 direct air" ) ``` --- ## Other useful data you can retrieve from EnergyPlus SQL output .blue[Get summary data of all materials] ```r str(job$read_table("Materials")) ``` ``` #> Classes 'data.table' and 'data.frame': 23 obs. of 14 variables: #> $ material_index : int 1 2 3 4 5 6 7 8 9 10 ... #> $ name : chr "WD10" "RG01" "BR01" "IN46" ... #> $ material_type : int 0 0 0 0 0 0 0 0 0 0 ... #> $ roughness : int 4 2 1 1 4 4 2 4 4 3 ... #> $ conductivity : num 0.115 1.442 0.162 0.023 0.115 ... #> $ density : num 513 881 1121 24 513 ... #> $ iso_moist_cap : num 0 0 0 0 0 0 0 0 0 0 ... #> $ porosity : num 0 0 0 0 0 0 0 0 0 0 ... #> $ resistance : num 5.8 0.00881 0.05864 3.31304 0.16609 ... #> $ r_only : int 0 0 0 0 0 0 0 0 0 0 ... #> $ spec_heat : num 1381 1674 1464 1590 1381 ... #> $ therm_grad_coef: num 0 0 0 0 0 0 0 0 0 0 ... #> $ thickness : num 0.667 0.0127 0.0095 0.0762 0.0191 ... #> $ vapor_diffus : num 0 0 0 0 0 0 0 0 0 0 ... #> - attr(*, ".internal.selfref")=<externalptr> ``` --- .blue[Get summary data of all constructions] ```r str(job$read_table("Constructions")) ``` ``` #> Classes 'data.table' and 'data.frame': 7 obs. of 14 variables: #> $ construction_index : int 1 2 3 4 5 6 7 #> $ name : chr "ROOF-1" "WALL-1" "CLNG-1" "FLOOR-SLAB-1" ... #> $ total_layers : int 4 4 1 1 3 3 1 #> $ total_solid_layers : int 0 0 0 0 0 2 1 #> $ total_glass_layers : int 0 0 0 0 0 2 1 #> $ inside_absorp_vis : num 0.78 0.75 0.65 0.65 0.75 0 0 #> $ outside_absorp_vis : num 0.65 0.78 0.65 0.65 0.75 0 0 #> $ inside_absorp_solar : num 0.78 0.75 0.65 0.65 0.75 0 0 #> $ outside_absorp_solar : num 0.65 0.78 0.65 0.65 0.75 0 0 #> $ inside_absorp_thermal : num 0.9 0.9 0.65 0.9 0.9 0.84 0.84 #> $ outside_absorp_thermal: num 0.9 0.9 0.65 0.9 0.9 0.84 0.84 #> $ outside_roughness : int 2 4 2 3 4 6 6 #> $ type_is_window : int 0 0 0 0 0 1 1 #> $ uvalue : num 0.282 0.408 1.533 12.894 2.811 ... #> - attr(*, ".internal.selfref")=<externalptr> ``` --- .blue[Get summary data of all surfaces] ```r str(job$read_table("Surfaces")) ``` ``` #> Classes 'data.table' and 'data.frame': 50 obs. of 20 variables: #> $ surface_index : int 1 2 3 4 5 6 7 8 9 10 ... #> $ surface_name : chr "MAIN SOUTH OVERHANG" "Mir-MAIN SOUTH OVERHANG" "SOUTH DOOR OVERHANG" "Mir-SOUTH DOOR OVERHANG" ... #> $ construction_index: int NA NA NA NA 2 2 2 2 3 3 ... #> $ class_name : chr "Shading" "Shading" "Shading" "Shading" ... #> $ area : num 25.7 25.7 6.2 6.2 18.3 ... #> $ gross_area : num 25.7 25.7 6.2 6.2 18.3 ... #> $ perimeter : num 42.2 42.2 10.2 10.2 62.2 ... #> $ azimuth : num 210 30 210 30 210 120 30 300 30 300 ... #> $ height : num 1.3 1.3 2 2 0.6 ... #> $ reveal : num 0 0 0 0 0 0 0 0 0 0 ... #> $ shape : int 3 3 3 3 3 3 3 3 2 2 ... #> $ sides : int 4 4 4 4 4 4 4 4 4 4 ... #> $ tilt : num 180 0 180 0 90 90 90 90 180 180 ... #> $ width : num 19.8 19.8 3.1 3.1 30.5 ... #> $ heat_transfer_surf: int 0 0 0 0 1 1 1 1 1 1 ... #> $ base_surface_index: int NA NA NA NA 5 6 7 8 9 10 ... #> $ zone_index : int NA NA NA NA 1 1 1 1 1 1 ... #> $ ext_bound_cond : int 0 0 0 0 0 0 0 0 22 29 ... #> $ ext_solar : int 1 1 1 1 1 1 1 1 0 0 ... #> $ ext_wind : int 1 1 1 1 1 1 1 1 0 0 ... #> - attr(*, ".internal.selfref")=<externalptr> ``` --- .blue[Get summary data of all zones] ```r str(job$read_table("Zones")) ``` ``` #> Classes 'data.table' and 'data.frame': 6 obs. of 27 variables: #> $ zone_index : int 1 2 3 4 5 6 #> $ zone_name : chr "PLENUM-1" "SPACE1-1" "SPACE2-1" "SPACE3-1" ... #> $ rel_north : num 0 0 0 0 0 0 #> $ origin_x : num 0 0 0 0 0 0 #> $ origin_y : num 0 0 0 0 0 0 #> $ origin_z : num 0 0 0 0 0 0 #> $ centroid_x : num 17.01 14.06 28.88 19.98 5.15 ... #> $ centroid_y : num -1.04 -6.15 -7.88 4.1 5.82 ... #> $ centroid_z : num 2.7 1.2 1.2 1.2 1.2 1.2 #> $ of_type : int 1 1 1 1 1 1 #> $ multiplier : num 1 1 1 1 1 1 #> $ list_multiplier : num 1 1 1 1 1 1 #> $ minimum_x : num 0 0 25.1 7.6 0 ... #> $ maximum_x : num 34 26.4 34 34 9 ... #> $ minimum_y : num -15.25 -15.25 -15.25 -3.35 0 ... #> $ maximum_y : num 13.16 1.35 -2.09 13.16 13.16 ... #> $ minimum_z : num 2.4 0 0 0 0 0 #> $ maximum_z : num 3 2.4 2.4 2.4 2.4 2.4 #> $ ceiling_height : num 0.61 2.44 2.44 2.44 2.44 ... #> $ volume : num 283 239 103 239 103 ... #> $ inside_convection_algo : int 1 1 1 1 1 1 #> $ outside_convection_algo: int 1 1 1 1 1 1 #> $ floor_area : num 463.6 99.2 42.7 96.5 42.7 ... #> $ ext_gross_wall_area : num 54.8 73.2 36.5 73.2 36.5 ... #> $ ext_net_wall_area : num 54.8 51.4 27.4 52.4 27.4 ... #> $ ext_window_area : num 0 21.81 9.12 20.85 9.12 ... #> $ is_part_of_total_area : int 1 1 1 1 1 1 #> - attr(*, ".internal.selfref")=<externalptr> ``` --- .blue[Other resources] ```r job$list_table() ``` ``` #> [1] "ComponentSizes" "ConstructionLayers" #> [3] "Constructions" "DaylightMapHourlyData" #> [5] "DaylightMapHourlyReports" "DaylightMaps" #> [7] "EnvironmentPeriods" "Errors" #> [9] "Materials" "NominalBaseboardHeaters" #> [11] "NominalElectricEquipment" "NominalGasEquipment" #> [13] "NominalHotWaterEquipment" "NominalInfiltration" #> [15] "NominalLighting" "NominalOtherEquipment" #> [17] "NominalPeople" "NominalSteamEquipment" #> [19] "NominalVentilation" "ReportData" #> [21] "ReportDataDictionary" "ReportExtendedData" #> [23] "ReportMeterData" "ReportMeterDataDictionary" #> [25] "ReportMeterExtendedData" "ReportVariableData" #> [27] "ReportVariableDataDictionary" "ReportVariableExtendedData" #> [29] "ReportVariableWithTime" "RoomAirModels" #> [31] "Schedules" "Simulations" #> [33] "StringTypes" "Strings" #> [35] "Surfaces" "SystemSizes" #> [37] "TabularData" "TabularDataWithStrings" #> [39] "Time" "ZoneGroups" #> [41] "ZoneInfoZoneLists" "ZoneLists" #> [43] "ZoneSizes" "Zones" ``` --- class: inverse middle center # .blue[ParametricJob] Class ### Conduct Parametric Simulations --- ## Create a parametric job ```r param <- param_job(idf, "materials/USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.epw") param ``` ``` #> ── EnergPlus Parametric Job ─────────────────────────────────────────────── #> Seed Model: `/tmp/Rtmpg5xvmx/example.idf` #> Weather: `/home/travis/build/hongyuanjia/eplusrIntro/materials/USA_IL_... #> EnergyPlus Version: `8.8.0` #> EnergyPlus Path: `/usr/local/EnergyPlus-8-8-0` #> << No measure has been applied >> ``` --- ## Apply measures .blue[Apply a single measure] ```r rotate <- function (idf, degree) { rotate_building(idf, degree) idf } param$apply_measure(rotate, seq(0, 180, 30), .names = paste0("degree_", seq(0, 180, 30))) ``` ``` #> Measure `rotate` has been applied with 7 new models created: #> 1: degree_0 #> 2: degree_30 #> 3: degree_60 #> 4: degree_90 #> 5: degree_120 #> 6: degree_150 #> 7: degree_180 ``` --- .blue[Apply multiple measures] ```r # get all combinations comb <- cross_df(list(degree = seq(0, 180, 60), r_value = c(3.55, 3.7))) comb$name <- paste("case", comb$degree, comb$r_value, sep = "_") rotate_and_align_r_value <- function (idf, degree, expect_r_value) { rotate_building(idf, degree) align_roof_r_value(idf, expect_r_value) idf } param$apply_measure(rotate_and_align_r_value, comb$degree, comb$r_value, .names = comb$name) ``` ``` #> Measure `rotate_and_align_r_value` has been applied with 8 new models created: #> 1: case_0_3.55 #> 2: case_60_3.55 #> 3: case_120_3.55 #> 4: case_180_3.55 #> 5: case_0_3.7 #> 6: case_60_3.7 #> 7: case_120_3.7 #> 8: case_180_3.7 ``` --- ## Run Parametric Simulations ```r param$run(tempdir()) ``` --- ## Extract Simulation Output ```r param$errors() ``` ``` #> $case_0_3.55 #> ══ EnergyPlus Error File ══════════════════════════════════════════════════ #> * EnergyPlus version: 8.8.0 (7c3bbe4830) #> * Simulation started: 2019-05-15 10:57:00 #> * Terminated: FALSE #> * Successful: TRUE #> * Warning[W]: 1 #> #> ── During Simulation ────────────────────────────────────────────────────── #> [W 1/1] CalcElectricChillerModel - Chiller:Electric "CENTRAL CHILLER" - Air #> Cooled Condenser Inlet Temperature below 0C. #> ... Outdoor Dry-bulb Condition = -12.60 C. Occurrence info = #> Chicago Ohare Intl Ap IL USA TMY3 WMO#=725300, 01/14 00:00 - 00:15 #> #> $case_60_3.55 #> ══ EnergyPlus Error File ══════════════════════════════════════════════════ #> * EnergyPlus version: 8.8.0 (7c3bbe4830) #> * Simulation started: 2019-05-15 10:57:00 .... ``` --- .blue[Does building orientation and roof thermal property influence sensible cooling loads??] ```r cooling_rate <- param$report_data(NULL, name = "Zone Air System Sensible Cooling Rate", month = 7, all = TRUE) # exclude design day data cooling_rate_nodes <- cooling_rate[!grepl("DesignDay", day_type)] # plot cooling_rate_nodes %>% ggplot() + geom_line(aes(datetime, value, group = case, color = case)) + facet_wrap(vars(key_value)) + scale_y_continuous(name = "Air System Sensible Cooling Rate / W") ``` --- <img src="figure/unnamed-chunk-80-1.png" width="864" style="display: block; margin: auto;" /> --- class: inverse middle center # .blue[Epw] Class ### Modify EnergyPlus Weather --- ## Read EPW file ```r epw <- read_epw(path_epw) epw ``` ``` #> ══ EnergyPlus Weather File ════════════════════════════════════════════════ #> [Location ]: Chicago Ohare Intl Ap, IL, USA #> {N 41°58'}, {W 87°55'}, {UTC-06:00} #> [Elevation]: 201m above see level #> [Data Src ]: TMY3 #> [WMO Stat ]: 725300 #> [Leap Year]: FALSE #> [Interval ]: 60 mins #> #> ── Data Periods ─────────────────────────────────────────────────────────── #> Name StartDayOfWeek StartDay EndDay #> 1: Data Sunday 1/ 1 12/31 #> #> ─────────────────────────────────────────────────────────────────────────── ``` --- ## Query and Modify Headers .blue[Get location data] ```r str(epw$location()) ``` ``` #> List of 9 #> $ city : chr "Chicago Ohare Intl Ap" #> $ state_province: chr "IL" #> $ country : chr "USA" #> $ data_source : chr "TMY3" #> $ wmo_number : chr "725300" #> $ latitude : num 42 #> $ longitude : num -87.9 #> $ time_zone : int -6 #> $ elevation : num 201 ``` --- .blue[Modify location data] ```r str(epw$location(city = "my_city", state_province = "my_state", country = "my_country")) ``` ``` #> List of 9 #> $ city : chr "my_city" #> $ state_province: chr "my_state" #> $ country : chr "my_country" #> $ data_source : chr "TMY3" #> $ wmo_number : chr "725300" #> $ latitude : num 42 #> $ longitude : num -87.9 #> $ time_zone : int -6 #> $ elevation : num 201 ``` --- .blue[Get design condition data] ```r str(epw$design_condition()) ``` ``` #> List of 4 #> $ source : chr "Climate Design Data 2009 ASHRAE Handbook" #> $ heating :List of 15 #> ..$ coldest_month : int 1 #> ..$ heating_db_99.6 : num -20 #> ..$ heating_db_99.0 : num -16.6 #> ..$ humidification_dp_99.6 : num -25.7 #> ..$ humidification_hr_99.6 : num 0.4 #> ..$ humidification_mcdb_99.6: num -19.2 #> ..$ humidification_dp_99.0 : num -22.1 #> ..$ humidification_hr_99.0 : num 0.5 #> ..$ humidification_mcdb_99.0: num -15.7 #> ..$ coldest_month_ws_0.4 : num 12.4 #> ..$ coldest_month_mcdb_0.4 : num -3.5 #> ..$ coldest_month_ws_1.0 : num 11.4 .... ``` --- ```r epw$typical_extreme_period() ``` ``` #> index name type #> 1: 1 Summer - Week Nearest Max Temperature For Period extreme #> 2: 2 Summer - Week Nearest Average Temperature For Period typical #> 3: 3 Winter - Week Nearest Min Temperature For Period extreme #> 4: 4 Winter - Week Nearest Average Temperature For Period typical #> 5: 5 Autumn - Week Nearest Average Temperature For Period typical #> 6: 6 Spring - Week Nearest Average Temperature For Period typical #> start_day end_day #> 1: 7/13 7/19 #> 2: 8/24 8/30 #> 3: 1/27 2/ 2 #> 4: 12/22 12/28 #> 5: 10/27 11/ 2 #> 6: 4/26 5/ 2 ``` --- ```r str(epw$ground_temperature()) ``` ``` #> Classes 'data.table' and 'data.frame': 36 obs. of 7 variables: #> $ index : int 1 1 1 1 1 1 1 1 1 1 ... #> $ depth : num 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 ... #> $ month : int 1 2 3 4 5 6 7 8 9 10 ... #> $ soil_conductivity : num NA NA NA NA NA NA NA NA NA NA ... #> $ soil_density : num NA NA NA NA NA NA NA NA NA NA ... #> $ soil_specific_heat: num NA NA NA NA NA NA NA NA NA NA ... #> $ temperature : num -1.89 -3.06 -0.99 2.23 10.68 ... #> - attr(*, ".internal.selfref")=<externalptr> ``` --- .blue[Get leap year flag, daylight saving time and holidays] ```r epw$holiday() ``` ``` #> $leapyear #> [1] FALSE #> #> $dst #> [1] "0 <empty>" "0 <empty>" #> #> $holiday #> Null data.table (0 rows and 0 cols) ``` --- .blue[Add daylight saving time period] ```r epw$holiday(dst = c("3.10", "11.3")) ``` ``` #> $leapyear #> [1] FALSE #> #> $dst #> [1] "Mar 10" "Nov 03" #> #> $holiday #> Null data.table (0 rows and 0 cols) ``` ```r epw$holiday(dst = c("2nd Sunday in March", "1st Sunday in November")) ``` ``` #> $leapyear #> [1] FALSE #> #> $dst #> [1] "2nd Sunday in March" "1st Sunday in November" #> #> $holiday #> Null data.table (0 rows and 0 cols) ``` --- .blue[Add holidays] ```r epw$holiday(holiday = list(name = c("New Year's Day", "Christmas Day"), day = c("1.1", "25 Dec"))) ``` ``` #> $leapyear #> [1] FALSE #> #> $dst #> [1] "2nd Sunday in March" "1st Sunday in November" #> #> $holiday #> name day #> 1: New Year's Day 1/ 1 #> 2: Christmas Day 12/25 ``` --- .blue[Get and modify comments] ```r epw$comment1() ``` ``` #> [1] "Custom/User Format -- WMO#725300; NREL TMY Data Set (2008); Period of Record 1973-2005 (Generally)" ``` ```r epw$comment2() ``` ``` #> [1] " -- Ground temps produced with a standard soil diffusivity of 2.3225760E-03 {m**2/day}" ``` ```r epw$comment1("new comment1") ``` ``` #> [1] "new comment1" ``` ```r epw$comment2("new comment2") ``` ``` #> [1] "new comment2" ``` --- .blue[Get total number of data periods] ```r epw$num_period() ``` ``` #> [1] 1 ``` -- .blue[Get number of observations per hour] ```r epw$interval() ``` ``` #> [1] 1 ``` -- .blue[Get data period] ```r epw$period() ``` ``` #> index name start_day_of_week start_day end_day #> 1: 1 Data 7 1/ 1 12/31 ``` --- ## Weather Data Specifications ```r str(epw$missing_code()) ``` ``` #> List of 29 #> $ dry_bulb_temperature : num 99.9 #> $ dew_point_temperature : num 99.9 #> $ relative_humidity : num 999 #> $ atmospheric_pressure : num 1e+06 #> $ extraterrestrial_horizontal_radiation : num 9999 #> $ extraterrestrial_direct_normal_radiation : num 9999 #> $ horizontal_infrared_radiation_intensity_from_sky: num 9999 #> $ global_horizontal_radiation : num 9999 #> $ direct_normal_radiation : num 1e+06 #> $ diffuse_horizontal_radiation : num 9999 #> $ global_horizontal_illuminance : num 1e+06 #> $ direct_normal_illuminance : num 1e+06 #> $ diffuse_horizontal_illuminance : num 1e+06 #> $ zenith_luminance : num 99990 .... ``` --- ```r str(epw$initial_missing_value()) ``` ``` #> List of 16 #> $ dry_bulb_temperature : num 6 #> $ dew_point_temperature: num 3 #> $ relative_humidity : num 50 #> $ wind_speed : num 2.5 #> $ wind_direction : num 180 #> $ total_sky_cover : int 5 #> $ opaque_sky_cover : int 5 #> $ visibility : num 778 #> $ ceiling : num 77777 #> $ precipitable_water : num 0 #> $ aerosol_optical_depth: num 0 #> $ snow_depth : num 0 #> $ days_since_last_snow : int 88 #> $ albedo : num 0 .... ``` --- ```r epw$range_exist() ``` ``` #> $wind_direction #> [0, 360] #> #> $present_weather_observation #> [0, 9] #> #> $dry_bulb_temperature #> (-Inf, 99.9) #> #> $dew_point_temperature #> (-Inf, 99.9) #> #> $relative_humidity #> [0, 999) #> .... ``` --- ```r epw$range_valid() ``` ``` #> $dry_bulb_temperature #> [-90, 70] #> #> $dew_point_temperature #> [-90, 70] #> #> $relative_humidity #> [0, 110] #> #> $atmospheric_pressure #> (31000, 120000] #> #> $global_horizontal_illuminance #> [0, 999900) #> .... ``` --- ```r epw$fill_action("missing") ``` ``` #> $use_previous #> [1] "dry_bulb_temperature" "atmospheric_pressure" #> [3] "relative_humidity" "dew_point_temperature" #> [5] "wind_speed" "wind_direction" #> [7] "total_sky_cover" "opaque_sky_cover" #> [9] "snow_depth" "liquid_precip_depth" #> #> $use_zero #> [1] "direct_normal_radiation" "diffuse_horizontal_radiation" ``` --- ```r epw$fill_action("out_of_range") ``` ``` #> $do_nothing #> [1] "dry_bulb_temperature" "relative_humidity" "dew_point_temperature" #> [4] "wind_direction" "wind_speed" #> #> $use_zero #> [1] "direct_normal_radiation" "diffuse_horizontal_radiation" #> #> $use_previous #> [1] "atmospheric_pressure" ``` --- ## Get Weather Data ```r str(epw$data(1)) ``` ``` #> Classes 'data.table' and 'data.frame': 8760 obs. of 36 variables: #> $ datetime : POSIXct, format: "2017-01-01 01:00:00" "2017-01-01 02:00:00" ... #> $ year : int 1986 1986 1986 1986 1986 1986 1986 1986 1986 1986 ... #> $ month : int 1 1 1 1 1 1 1 1 1 1 ... #> $ day : int 1 1 1 1 1 1 1 1 1 1 ... #> $ hour : int 1 2 3 4 5 6 7 8 9 10 ... #> $ minute : int 0 0 0 0 0 0 0 0 0 0 ... #> $ datasource : chr "?9?9?9?9E0?9?9?9?9?9?9?9?9?9?9?9?9?9?9*_*9*9*9*9*9" "?9?9?9?9E0?9?9?9?9?9?9?9?9?9?9?9?9?9?9*_*9*9*9*9*9" "?9?9?9?9E0?9?9?9?9?9?9?9?9?9?9?9?9?9?9*_*9*9*9*9*9" "?9?9?9?9E0?9?9?9?9?9?9?9?9?9?9?9?9?9?9*_*9*9*9*9*9" ... #> $ dry_bulb_temperature : num -12.2 -11.7 -11.1 -11.1 -10.6 -10.6 -10.6 -10 -8.9 -6.7 ... #> $ dew_point_temperature : num -16.1 -15.6 -15 -15 -14.4 -14.4 -13.9 -13.3 -13.3 -13.3 ... #> $ relative_humidity : num 73 73 73 73 73 73 77 77 71 60 ... #> $ atmospheric_pressure : num 99500 99600 99500 99500 99500 99500 99500 99500 99500 99500 ... #> $ extraterrestrial_horizontal_radiation : num 0 0 0 0 0 0 0 43 236 410 ... #> $ extraterrestrial_direct_normal_radiation : num 0 0 0 0 0 ... #> $ horizontal_infrared_radiation_intensity_from_sky: num 218 227 230 230 232 232 232 224 207 214 ... .... ``` --- ```r weekdays(epw$data(1)$datetime[[1]]) ``` ``` #> [1] "Sunday" ``` ```r epw$period(1)$start_day_of_week ``` ``` #> [1] 7 ``` --- ## Get Abnormal Weather Data ```r epw$abnormal_data(keep_all = FALSE) ``` ``` #> line datetime year month day hour minute albedo #> 1: 9 1986-01-01 01:00:00 1986 1 1 1 0 999 #> 2: 10 1986-01-01 02:00:00 1986 1 1 2 0 999 #> 3: 11 1986-01-01 03:00:00 1986 1 1 3 0 999 #> 4: 12 1986-01-01 04:00:00 1986 1 1 4 0 999 #> 5: 13 1986-01-01 05:00:00 1986 1 1 5 0 999 #> --- #> 8037: 8764 1981-12-31 20:00:00 1981 12 31 20 0 999 #> 8038: 8765 1981-12-31 21:00:00 1981 12 31 21 0 999 #> 8039: 8766 1981-12-31 22:00:00 1981 12 31 22 0 999 #> 8040: 8767 1981-12-31 23:00:00 1981 12 31 23 0 999 #> 8041: 8768 1981-01-01 00:00:00 1981 12 31 24 0 999 #> liquid_precip_depth liquid_precip_rate #> 1: 999 99 #> 2: 999 99 .... ``` --- ## Get Redundant Weather Data ```r epw$redundant_data() ``` ``` #> ── Info ─────────────────────────────────────────────────────────────────── #> No redundant data found. ``` ``` #> Empty data.table (0 rows and 37 cols): line,datetime,year,month,day,hour... ``` --- ## Modify Weather Data In-Place ```r epw$add_unit() dry_bulb <- epw$data()$dry_bulb_temperature head(dry_bulb) ``` ``` #> Units: [°C] #> [1] -12.2 -11.7 -11.1 -11.1 -10.6 -10.6 ``` ```r units(dry_bulb) <- with(units::ud_units, "kelvin") head(dry_bulb) ``` ``` #> Units: [K] #> [1] 260.95 261.45 262.05 262.05 262.55 262.55 ``` --- ## Modify Weather Data In-Place ```r epw$make_na(missing = TRUE) str(epw$abnormal_data(keep_all = FALSE)) ``` ``` #> Classes 'data.table' and 'data.frame': 8041 obs. of 10 variables: #> $ line : int 9 10 11 12 13 14 15 16 17 18 ... #> $ datetime : POSIXct, format: "1986-01-01 01:00:00" "1986-01-01 02:00:00" ... #> $ year : int 1986 1986 1986 1986 1986 1986 1986 1986 1986 1986 ... #> $ month : int 1 1 1 1 1 1 1 1 1 1 ... #> $ day : int 1 1 1 1 1 1 1 1 1 1 ... #> $ hour : int 1 2 3 4 5 6 7 8 9 10 ... #> $ minute : int 0 0 0 0 0 0 0 0 0 0 ... #> $ albedo : num NA NA NA NA NA NA NA NA NA NA ... #> $ liquid_precip_depth:Object of class units: #> num NA NA NA NA NA NA NA NA NA NA ... #> ..- attr(*, "units")=List of 2 #> .. ..$ numerator : chr "mm" #> .. ..$ denominator: chr #> .. ..- attr(*, "class")= chr "symbolic_units" .... ``` --- ## Set Weather Data ```r epw$add(data, realyear = FALSE, name = NULL, start_day_of_week = NULL, after = 0L, warning = TRUE) epw$set(data, realyear = FALSE, name = NULL, start_day_of_week = NULL, period = 1L, warning = TRUE) epw$delete(period) ``` --- ## Save Weather File ```r epw$save() ``` For more info, see `?Epw` --- ## Note on Using Leap-Year AMY Weather Data in EnergyPlus? See [#32](https://github.com/hongyuanjia/eplusr/issues/32) ```r # version type_runperiod type_epw num_row num_leap # 1: 8.8 tmy nonleap 8760 24 # 2: 9.0 tmy nonleap 8760 24 # 3: 9.1 tmy nonleap 8760 24 # 4: 8.8 amy nonleap 8760 24 # 5: 9.0 amy nonleap 8760 24 # 6: 9.1 amy nonleap 8760 24 # 7: 8.8 tmy leap 8784 48 # 8: 9.0 tmy leap 8784 48 # 9: 9.1 tmy leap 8760 24 # 10: 8.8 amy leap 8784 48 # 11: 9.0 amy leap 8784 48 # 12: 9.1 amy leap 8784 48 ``` --- class: inverse middle center .animated.bounce[ <img src="figure/logo.svg" height=280px> ] ## Summary --- ## Class structure .pull-left[ * `Idd` class --> Model definition * `IddObject` class --> Single class definition * `Idf` class --> Model itself * `IdfObject` class --> Single object * `Epw` class --> Weather file * `EPlusJob` class --> Single simulation * `ParametricJob` class --> Parametric simulations ] .pull-right[ ![](figure/class_structure.png) ] --- ## Future plan * C++ parser for IDD, IDF, and EPW * Integration with Stan (sensitivity analysis, Bayesian Calibration) * HVAC builder based on EnergyPlus example files * Version updater * Eplusr Specific option header? * A Shiny-based GUI? * Friendly schedule generator? --- ## Call for Contributors .center[<img src="figure/issue.png" width="70%" align="center" />] --- class: right, middle # Thanks! <img class="circle" src="https://github.com/hongyuanjia.png" width="150px"/> [
@jiahony](http://twitter.com/jiahony) [
@hongyuanjia](http://github.com/hongyuanjia) [
hongyuan.jia@bears-berkeley.sg](mailto:hongyuan.jia@bears-berkeley.sg)