urbanopt-cli 0.10.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (712) hide show
  1. checksums.yaml +4 -4
  2. data/.github/release.yml +24 -0
  3. data/.github/workflows/nightly_ci_build.yml +39 -29
  4. data/.gitignore +1 -0
  5. data/CHANGELOG.md +17 -0
  6. data/CMakeLists.txt +7 -7
  7. data/FindOpenStudioSDK.cmake +8 -8
  8. data/LICENSE.md +8 -35
  9. data/README.md +25 -10
  10. data/example_files/Gemfile +9 -9
  11. data/example_files/example_project_combined.json +6 -2
  12. data/example_files/example_project_with_ghe.json +859 -0
  13. data/example_files/mappers/Baseline.rb +39 -415
  14. data/example_files/mappers/ChilledWaterStorage.rb +1 -1
  15. data/example_files/mappers/CreateBar.rb +1 -1
  16. data/example_files/mappers/EvCharging.rb +1 -1
  17. data/example_files/mappers/FlexibleHotWater.rb +1 -1
  18. data/example_files/mappers/Floorspace.rb +1 -1
  19. data/example_files/mappers/HighEfficiency.rb +1 -1
  20. data/example_files/mappers/HighEfficiencyCreateBar.rb +1 -1
  21. data/example_files/mappers/HighEfficiencyFloorspace.rb +1 -1
  22. data/example_files/mappers/PeakHoursMelsShedding.rb +1 -1
  23. data/example_files/mappers/PeakHoursThermostatAdjust.rb +1 -1
  24. data/example_files/mappers/ThermalStorage.rb +1 -1
  25. data/example_files/mappers/base_workflow.osw +11 -4
  26. data/example_files/mappers/residential/template/util.rb +138 -0
  27. data/example_files/mappers/residential/util.rb +276 -0
  28. data/example_files/measures/BuildResidentialModel/measure.rb +118 -230
  29. data/example_files/measures/BuildResidentialModel/measure.xml +344 -233
  30. data/example_files/measures/BuildResidentialModel/resources/geometry.rb +7 -2
  31. data/example_files/measures/BuildResidentialModel/resources/unit_conversions.rb +5 -0
  32. data/example_files/measures/BuildResidentialModel/resources/util.rb +5 -0
  33. data/example_files/measures/BuildResidentialModel/tests/test_build_residential_model.rb +344 -0
  34. data/example_files/measures/BuildResidentialModel/tests/xml_building/17/feature1.xml +2112 -0
  35. data/example_files/measures/BuildResidentialModel/tests/xml_building/17/feature2.xml +2112 -0
  36. data/example_files/osm_building/7.osm +0 -2
  37. data/example_files/osm_building/8.osm +0 -2
  38. data/example_files/osm_building/9.osm +0 -2
  39. data/example_files/python_deps/dependencies.json +4 -3
  40. data/example_files/resources/hpxml-measures/.gitattributes +3 -0
  41. data/example_files/resources/hpxml-measures/.github/pull_request_template.md +2 -2
  42. data/example_files/resources/hpxml-measures/.github/workflows/add_to_project.yml +17 -0
  43. data/example_files/resources/hpxml-measures/.github/workflows/config.yml +37 -8
  44. data/example_files/resources/hpxml-measures/.gitignore +1 -0
  45. data/example_files/resources/hpxml-measures/.readthedocs.yml +6 -2
  46. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/README.md +5596 -0
  47. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/README.md.erb +41 -0
  48. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/measure.rb +1324 -1035
  49. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/measure.xml +325 -236
  50. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/resources/geometry.rb +119 -152
  51. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/{build_residential_hpxml_test.rb → test_build_residential_hpxml.rb} +225 -107
  52. data/example_files/resources/hpxml-measures/BuildResidentialScheduleFile/README.md +96 -0
  53. data/example_files/resources/hpxml-measures/BuildResidentialScheduleFile/README.md.erb +41 -0
  54. data/example_files/resources/hpxml-measures/BuildResidentialScheduleFile/measure.rb +73 -31
  55. data/example_files/resources/hpxml-measures/BuildResidentialScheduleFile/measure.xml +60 -40
  56. data/example_files/resources/hpxml-measures/BuildResidentialScheduleFile/resources/README.md +48 -23
  57. data/example_files/resources/hpxml-measures/BuildResidentialScheduleFile/resources/constants.rb +5 -0
  58. data/example_files/resources/hpxml-measures/BuildResidentialScheduleFile/resources/schedules.rb +6 -12
  59. data/example_files/resources/hpxml-measures/BuildResidentialScheduleFile/tests/{build_residential_schedule_file_test.rb → test_build_residential_schedule_file.rb} +162 -35
  60. data/example_files/resources/hpxml-measures/Changelog.md +57 -1
  61. data/example_files/resources/hpxml-measures/Gemfile +1 -1
  62. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/README.md +83 -0
  63. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/README.md.erb +41 -0
  64. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/measure.rb +1081 -878
  65. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/measure.xml +258 -204
  66. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/airflow.rb +205 -178
  67. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/battery.rb +43 -18
  68. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/constants.rb +37 -112
  69. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/constructions.rb +34 -73
  70. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/data/Xing_okstate_0664D_13659_Table_A-3.csv +4165 -0
  71. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/data/unavailable_periods.csv +2 -2
  72. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/energyplus.rb +5 -1
  73. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/generator.rb +13 -7
  74. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/geometry.rb +95 -42
  75. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/hotwater_appliances.rb +132 -108
  76. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/hpxml.rb +1695 -1267
  77. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/hpxml_defaults.rb +668 -589
  78. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/hpxml_schema/HPXML.xsd +304 -553
  79. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/hpxml_schematron/EPvalidator.xml +197 -112
  80. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/hvac.rb +1140 -1745
  81. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/hvac_sizing.rb +412 -325
  82. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/lighting.rb +56 -48
  83. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/location.rb +49 -38
  84. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/materials.rb +5 -0
  85. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/meta_measure.rb +17 -1
  86. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/minitest_helper.rb +5 -0
  87. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/misc_loads.rb +94 -78
  88. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/output.rb +60 -2
  89. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/psychrometrics.rb +6 -1
  90. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/pv.rb +11 -5
  91. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/schedule_files/occupancy-non-stochastic.csv +1 -1
  92. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/schedule_files/occupancy-stochastic-30-mins.csv +52561 -0
  93. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/schedule_files/occupancy-stochastic_2.csv +8761 -0
  94. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/schedule_files/occupancy-stochastic_3.csv +8761 -0
  95. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/schedule_files/occupancy-stochastic_4.csv +8761 -0
  96. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/schedule_files/occupancy-stochastic_5.csv +8761 -0
  97. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/schedule_files/occupancy-stochastic_6.csv +8761 -0
  98. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/schedules.rb +129 -137
  99. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/simcontrols.rb +12 -21
  100. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/unit_conversions.rb +5 -0
  101. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/util.rb +7 -2
  102. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/utility_bills.rb +6 -1
  103. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/version.rb +7 -2
  104. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/waterheater.rb +179 -144
  105. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/weather.rb +129 -71
  106. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/xmlhelper.rb +5 -0
  107. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/xmlvalidator.rb +23 -6
  108. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_airflow.rb +129 -118
  109. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_battery.rb +25 -20
  110. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_defaults.rb +2282 -2239
  111. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_enclosure.rb +395 -204
  112. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_generator.rb +12 -7
  113. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_hotwater_appliance.rb +56 -51
  114. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_hvac.rb +369 -230
  115. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_hvac_sizing.rb +371 -191
  116. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_lighting.rb +27 -20
  117. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_location.rb +55 -5
  118. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_miscloads.rb +35 -30
  119. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_pv.rb +13 -8
  120. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_schedules.rb +107 -93
  121. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_simcontrols.rb +11 -6
  122. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_validation.rb +757 -573
  123. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_water_heater.rb +77 -72
  124. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_weather.rb +36 -6
  125. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/util.rb +5 -0
  126. data/example_files/resources/hpxml-measures/README.md +2 -0
  127. data/example_files/resources/hpxml-measures/Rakefile +10 -3
  128. data/example_files/resources/hpxml-measures/ReportSimulationOutput/README.md +787 -0
  129. data/example_files/resources/hpxml-measures/ReportSimulationOutput/README.md.erb +41 -0
  130. data/example_files/resources/hpxml-measures/ReportSimulationOutput/measure.rb +730 -418
  131. data/example_files/resources/hpxml-measures/ReportSimulationOutput/measure.xml +1215 -9
  132. data/example_files/resources/hpxml-measures/ReportSimulationOutput/tests/{output_report_test.rb → test_report_sim_output.rb} +130 -299
  133. data/example_files/resources/hpxml-measures/ReportUtilityBills/README.md +87 -0
  134. data/example_files/resources/hpxml-measures/ReportUtilityBills/README.md.erb +41 -0
  135. data/example_files/resources/hpxml-measures/ReportUtilityBills/measure.rb +261 -89
  136. data/example_files/resources/hpxml-measures/ReportUtilityBills/measure.xml +179 -94
  137. data/example_files/resources/hpxml-measures/ReportUtilityBills/resources/simple_rates/Average_retail_price_of_electricity.csv +68 -68
  138. data/example_files/resources/hpxml-measures/ReportUtilityBills/resources/simple_rates/NG_PRI_SUM_A_EPG0_PRS_DMCF_A.csv +3 -2
  139. data/example_files/resources/hpxml-measures/ReportUtilityBills/resources/simple_rates/PET_PRI_WFR_A_EPD2F_PRS_DPGAL_W.csv +713 -685
  140. data/example_files/resources/hpxml-measures/ReportUtilityBills/resources/simple_rates/PET_PRI_WFR_A_EPLLPA_PRS_DPGAL_W.csv +716 -688
  141. data/example_files/resources/hpxml-measures/ReportUtilityBills/resources/simple_rates/README.md +5 -2
  142. data/example_files/resources/hpxml-measures/ReportUtilityBills/resources/util.rb +18 -9
  143. data/example_files/resources/hpxml-measures/ReportUtilityBills/tests/test_report_utility_bills.rb +1308 -0
  144. data/example_files/resources/hpxml-measures/docs/requirements.txt +5 -0
  145. data/example_files/resources/hpxml-measures/docs/source/conf.py +1 -2
  146. data/example_files/resources/hpxml-measures/docs/source/intro.rst +3 -20
  147. data/example_files/resources/hpxml-measures/docs/source/usage_instructions.rst +1 -1
  148. data/example_files/resources/hpxml-measures/docs/source/workflow_inputs.rst +917 -564
  149. data/example_files/resources/hpxml-measures/docs/source/workflow_outputs.rst +79 -42
  150. data/example_files/resources/hpxml-measures/tasks.rb +2305 -2055
  151. data/example_files/resources/hpxml-measures/workflow/hpxml_inputs.json +270 -587
  152. data/example_files/resources/hpxml-measures/workflow/real_homes/house001.xml +559 -557
  153. data/example_files/resources/hpxml-measures/workflow/real_homes/house002.xml +522 -520
  154. data/example_files/resources/hpxml-measures/workflow/real_homes/house003.xml +534 -532
  155. data/example_files/resources/hpxml-measures/workflow/real_homes/house004.xml +547 -545
  156. data/example_files/resources/hpxml-measures/workflow/real_homes/house005.xml +546 -544
  157. data/example_files/resources/hpxml-measures/workflow/real_homes/house006.xml +603 -623
  158. data/example_files/resources/hpxml-measures/workflow/real_homes/house007.xml +613 -633
  159. data/example_files/resources/hpxml-measures/workflow/real_homes/house008.xml +699 -721
  160. data/example_files/resources/hpxml-measures/workflow/real_homes/house009.xml +662 -661
  161. data/example_files/resources/hpxml-measures/workflow/real_homes/house010.xml +657 -677
  162. data/example_files/resources/hpxml-measures/workflow/real_homes/house011.xml +470 -467
  163. data/example_files/resources/hpxml-measures/workflow/real_homes/house012.xml +441 -438
  164. data/example_files/resources/hpxml-measures/workflow/real_homes/house013.xml +468 -465
  165. data/example_files/resources/hpxml-measures/workflow/real_homes/house014.xml +469 -466
  166. data/example_files/resources/hpxml-measures/workflow/real_homes/house015.xml +468 -465
  167. data/example_files/resources/hpxml-measures/workflow/real_homes/house016.xml +717 -714
  168. data/example_files/resources/hpxml-measures/workflow/real_homes/house017.xml +647 -645
  169. data/example_files/resources/hpxml-measures/workflow/real_homes/house018.xml +569 -566
  170. data/example_files/resources/hpxml-measures/workflow/real_homes/house019.xml +602 -599
  171. data/example_files/resources/hpxml-measures/workflow/real_homes/house020.xml +630 -627
  172. data/example_files/resources/hpxml-measures/workflow/real_homes/house021.xml +776 -774
  173. data/example_files/resources/hpxml-measures/workflow/real_homes/house022.xml +670 -667
  174. data/example_files/resources/hpxml-measures/workflow/real_homes/house023.xml +632 -629
  175. data/example_files/resources/hpxml-measures/workflow/real_homes/house024.xml +731 -729
  176. data/example_files/resources/hpxml-measures/workflow/real_homes/house025.xml +672 -669
  177. data/example_files/resources/hpxml-measures/workflow/real_homes/house026.xml +667 -644
  178. data/example_files/resources/hpxml-measures/workflow/real_homes/house027.xml +646 -644
  179. data/example_files/resources/hpxml-measures/workflow/real_homes/house028.xml +690 -688
  180. data/example_files/resources/hpxml-measures/workflow/real_homes/house029.xml +701 -699
  181. data/example_files/resources/hpxml-measures/workflow/real_homes/house030.xml +637 -615
  182. data/example_files/resources/hpxml-measures/workflow/real_homes/house031.xml +690 -688
  183. data/example_files/resources/hpxml-measures/workflow/real_homes/house032.xml +557 -554
  184. data/example_files/resources/hpxml-measures/workflow/real_homes/house033.xml +534 -531
  185. data/example_files/resources/hpxml-measures/workflow/real_homes/house034.xml +636 -635
  186. data/example_files/resources/hpxml-measures/workflow/real_homes/house035.xml +616 -613
  187. data/example_files/resources/hpxml-measures/workflow/real_homes/house036.xml +601 -598
  188. data/example_files/resources/hpxml-measures/workflow/real_homes/house037.xml +581 -578
  189. data/example_files/resources/hpxml-measures/workflow/real_homes/house038.xml +624 -622
  190. data/example_files/resources/hpxml-measures/workflow/real_homes/house039.xml +584 -582
  191. data/example_files/resources/hpxml-measures/workflow/real_homes/house040.xml +631 -629
  192. data/example_files/resources/hpxml-measures/workflow/real_homes/house041.xml +922 -921
  193. data/example_files/resources/hpxml-measures/workflow/real_homes/house042.xml +855 -853
  194. data/example_files/resources/hpxml-measures/workflow/real_homes/house043.xml +739 -737
  195. data/example_files/resources/hpxml-measures/workflow/real_homes/house044.xml +798 -796
  196. data/example_files/resources/hpxml-measures/workflow/real_homes/house045.xml +696 -694
  197. data/example_files/resources/hpxml-measures/workflow/real_homes/house046.xml +487 -483
  198. data/example_files/resources/hpxml-measures/workflow/real_homes/house047.xml +443 -440
  199. data/example_files/resources/hpxml-measures/workflow/real_homes/house048.xml +688 -686
  200. data/example_files/resources/hpxml-measures/workflow/real_homes/house049.xml +722 -720
  201. data/example_files/resources/hpxml-measures/workflow/real_homes/house050.xml +619 -617
  202. data/example_files/resources/hpxml-measures/workflow/run_simulation.rb +13 -20
  203. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-coal.xml +9 -9
  204. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-dehumidifier-ief-portable.xml +11 -12
  205. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-dehumidifier-ief-whole-home.xml +11 -12
  206. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-dehumidifier-multiple.xml +12 -13
  207. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-dehumidifier.xml +11 -12
  208. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-gas.xml +9 -9
  209. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-modified.xml +9 -9
  210. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-none.xml +4 -4
  211. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-oil.xml +9 -9
  212. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-propane.xml +9 -9
  213. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-wood.xml +9 -9
  214. data/example_files/resources/hpxml-measures/workflow/sample_files/base-atticroof-cathedral.xml +11 -11
  215. data/example_files/resources/hpxml-measures/workflow/sample_files/base-atticroof-conditioned.xml +10 -10
  216. data/example_files/resources/hpxml-measures/workflow/sample_files/base-atticroof-flat.xml +9 -9
  217. data/example_files/resources/hpxml-measures/workflow/sample_files/base-atticroof-radiant-barrier.xml +10 -11
  218. data/example_files/resources/hpxml-measures/workflow/sample_files/base-atticroof-unvented-insulated-roof.xml +9 -9
  219. data/example_files/resources/hpxml-measures/workflow/sample_files/base-atticroof-vented.xml +8 -8
  220. data/example_files/resources/hpxml-measures/workflow/sample_files/base-battery-scheduled.xml +571 -569
  221. data/example_files/resources/hpxml-measures/workflow/sample_files/base-battery.xml +9 -9
  222. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-adjacent-to-multifamily-buffer-space.xml → base-bldgtype-mf-unit-adjacent-to-multifamily-buffer-space.xml} +5 -5
  223. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-adjacent-to-multiple.xml → base-bldgtype-mf-unit-adjacent-to-multiple.xml} +17 -17
  224. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-adjacent-to-non-freezing-space.xml → base-bldgtype-mf-unit-adjacent-to-non-freezing-space.xml} +5 -5
  225. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-adjacent-to-other-heated-space.xml → base-bldgtype-mf-unit-adjacent-to-other-heated-space.xml} +5 -5
  226. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-adjacent-to-other-housing-unit.xml → base-bldgtype-mf-unit-adjacent-to-other-housing-unit.xml} +5 -5
  227. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-infil-compartmentalization-test.xml → base-bldgtype-mf-unit-infil-compartmentalization-test.xml} +461 -461
  228. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-residents-1.xml → base-bldgtype-mf-unit-residents-1.xml} +453 -453
  229. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-boiler-chiller-baseboard.xml → base-bldgtype-mf-unit-shared-boiler-chiller-baseboard.xml} +11 -11
  230. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-boiler-chiller-fan-coil-ducted.xml → base-bldgtype-mf-unit-shared-boiler-chiller-fan-coil-ducted.xml} +11 -11
  231. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-boiler-chiller-fan-coil.xml → base-bldgtype-mf-unit-shared-boiler-chiller-fan-coil.xml} +11 -11
  232. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-boiler-chiller-water-loop-heat-pump.xml → base-bldgtype-mf-unit-shared-boiler-chiller-water-loop-heat-pump.xml} +11 -11
  233. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-boiler-cooling-tower-water-loop-heat-pump.xml → base-bldgtype-mf-unit-shared-boiler-cooling-tower-water-loop-heat-pump.xml} +11 -11
  234. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-boiler-only-baseboard.xml → base-bldgtype-mf-unit-shared-boiler-only-baseboard.xml} +11 -11
  235. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-boiler-only-fan-coil-ducted.xml → base-bldgtype-mf-unit-shared-boiler-only-fan-coil-ducted.xml} +11 -11
  236. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-boiler-only-fan-coil-eae.xml → base-bldgtype-mf-unit-shared-boiler-only-fan-coil-eae.xml} +11 -11
  237. data/example_files/resources/hpxml-measures/workflow/sample_files/base-bldgtype-mf-unit-shared-boiler-only-fan-coil-fireplace-elec.xml +433 -0
  238. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-boiler-only-fan-coil.xml → base-bldgtype-mf-unit-shared-boiler-only-fan-coil.xml} +11 -11
  239. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-boiler-only-water-loop-heat-pump.xml → base-bldgtype-mf-unit-shared-boiler-only-water-loop-heat-pump.xml} +11 -11
  240. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-chiller-only-baseboard.xml → base-bldgtype-mf-unit-shared-chiller-only-baseboard.xml} +11 -11
  241. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-chiller-only-fan-coil-ducted.xml → base-bldgtype-mf-unit-shared-chiller-only-fan-coil-ducted.xml} +11 -11
  242. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-chiller-only-fan-coil.xml → base-bldgtype-mf-unit-shared-chiller-only-fan-coil.xml} +11 -11
  243. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-chiller-only-water-loop-heat-pump.xml → base-bldgtype-mf-unit-shared-chiller-only-water-loop-heat-pump.xml} +11 -11
  244. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-cooling-tower-only-water-loop-heat-pump.xml → base-bldgtype-mf-unit-shared-cooling-tower-only-water-loop-heat-pump.xml} +11 -11
  245. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-generator.xml → base-bldgtype-mf-unit-shared-generator.xml} +13 -13
  246. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-ground-loop-ground-to-air-heat-pump.xml → base-bldgtype-mf-unit-shared-ground-loop-ground-to-air-heat-pump.xml} +13 -13
  247. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-laundry-room-multiple-water-heaters.xml → base-bldgtype-mf-unit-shared-laundry-room-multiple-water-heaters.xml} +480 -480
  248. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-laundry-room.xml → base-bldgtype-mf-unit-shared-laundry-room.xml} +10 -10
  249. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-mechvent-multiple.xml → base-bldgtype-mf-unit-shared-mechvent-multiple.xml} +15 -15
  250. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-mechvent-preconditioning.xml → base-bldgtype-mf-unit-shared-mechvent-preconditioning.xml} +13 -13
  251. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-mechvent.xml → base-bldgtype-mf-unit-shared-mechvent.xml} +13 -13
  252. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-pv.xml → base-bldgtype-mf-unit-shared-pv.xml} +13 -13
  253. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-water-heater-recirc.xml → base-bldgtype-mf-unit-shared-water-heater-recirc.xml} +13 -13
  254. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-water-heater.xml → base-bldgtype-mf-unit-shared-water-heater.xml} +13 -13
  255. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily.xml → base-bldgtype-mf-unit.xml} +13 -13
  256. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-attached-2stories.xml → base-bldgtype-sfa-unit-2stories.xml} +610 -610
  257. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-attached-atticroof-cathedral.xml → base-bldgtype-sfa-unit-atticroof-cathedral.xml} +558 -558
  258. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-attached-infil-compartmentalization-test.xml → base-bldgtype-sfa-unit-infil-compartmentalization-test.xml} +610 -610
  259. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-attached.xml → base-bldgtype-sfa-unit.xml} +610 -610
  260. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-combi-tankless-outside.xml +8 -8
  261. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-combi-tankless.xml +9 -9
  262. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-desuperheater-2-speed.xml +9 -9
  263. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-desuperheater-gshp.xml +9 -9
  264. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-desuperheater-hpwh.xml +9 -9
  265. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-desuperheater-tankless.xml +9 -9
  266. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-desuperheater-var-speed.xml +9 -9
  267. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-desuperheater.xml +9 -9
  268. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-dwhr.xml +9 -9
  269. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-indirect-detailed-setpoints.xml +507 -505
  270. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-indirect-dse.xml +9 -9
  271. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-indirect-outside.xml +8 -8
  272. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-indirect-standbyloss.xml +9 -9
  273. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-indirect-with-solar-fraction.xml +9 -9
  274. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-indirect.xml +9 -9
  275. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-jacket-electric.xml +9 -9
  276. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-jacket-gas.xml +9 -9
  277. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-jacket-hpwh.xml +9 -9
  278. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-jacket-indirect.xml +9 -9
  279. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-low-flow-fixtures.xml +12 -10
  280. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-multiple.xml +14 -14
  281. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-none.xml +5 -5
  282. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-recirc-demand.xml +9 -9
  283. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-recirc-manual.xml +9 -9
  284. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-recirc-nocontrol.xml +9 -9
  285. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-recirc-temperature.xml +9 -9
  286. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-recirc-timer.xml +9 -9
  287. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-solar-direct-evacuated-tube.xml +9 -9
  288. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-solar-direct-flat-plate.xml +9 -9
  289. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-solar-direct-ics.xml +9 -9
  290. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-solar-fraction.xml +9 -9
  291. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-solar-indirect-flat-plate.xml +9 -9
  292. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-solar-thermosyphon-flat-plate.xml +9 -9
  293. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-coal.xml +9 -9
  294. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-detailed-setpoints.xml +12 -10
  295. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-elec-uef.xml +9 -9
  296. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-gas-outside.xml +8 -8
  297. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-gas-uef-fhr.xml +9 -9
  298. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-gas-uef.xml +9 -9
  299. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-gas.xml +9 -9
  300. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-heat-pump-detailed-schedules.xml +13 -11
  301. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-heat-pump-operating-mode-heat-pump-only.xml +9 -9
  302. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-heat-pump-outside.xml +8 -8
  303. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-heat-pump-uef.xml +9 -9
  304. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-heat-pump-with-solar-fraction.xml +9 -9
  305. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-heat-pump-with-solar.xml +9 -9
  306. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-heat-pump.xml +9 -9
  307. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-model-type-stratified-detailed-occupancy-stochastic.xml +12 -10
  308. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-model-type-stratified.xml +9 -9
  309. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-oil.xml +9 -9
  310. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-wood.xml +9 -9
  311. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tankless-detailed-setpoints.xml +12 -10
  312. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tankless-electric-outside.xml +8 -8
  313. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tankless-electric-uef.xml +9 -9
  314. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tankless-electric.xml +9 -9
  315. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tankless-gas-uef.xml +9 -9
  316. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tankless-gas-with-solar-fraction.xml +9 -9
  317. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tankless-gas-with-solar.xml +9 -9
  318. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tankless-gas.xml +9 -9
  319. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tankless-propane.xml +9 -9
  320. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-2stories-garage.xml +13 -14
  321. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-2stories.xml +11 -11
  322. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-beds-1.xml +9 -9
  323. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-beds-2.xml +9 -9
  324. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-beds-4.xml +9 -9
  325. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-beds-5.xml +9 -9
  326. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-ceilingtypes.xml +576 -576
  327. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-floortypes.xml +519 -519
  328. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-garage.xml +4 -5
  329. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-infil-ach-house-pressure.xml +9 -9
  330. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-infil-cfm-house-pressure.xml +9 -9
  331. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-infil-cfm50.xml +9 -9
  332. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-infil-ela.xml +548 -548
  333. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-infil-flue.xml +9 -9
  334. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-infil-natural-ach.xml +9 -9
  335. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-infil-natural-cfm.xml +551 -551
  336. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-orientations.xml +9 -9
  337. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-overhangs.xml +9 -9
  338. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-rooftypes.xml +9 -9
  339. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-skylights-physical-properties.xml +9 -9
  340. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-skylights-shading.xml +9 -9
  341. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-skylights-storms.xml +9 -9
  342. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-skylights.xml +9 -9
  343. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-split-level.xml +10 -11
  344. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-thermal-mass.xml +9 -9
  345. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-walltypes.xml +19 -19
  346. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-windows-natural-ventilation-availability.xml +555 -553
  347. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-windows-none.xml +9 -9
  348. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-windows-physical-properties.xml +9 -9
  349. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-windows-shading-seasons.xml +560 -558
  350. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-windows-shading.xml +9 -9
  351. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-windows-storms.xml +9 -9
  352. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-ambient.xml +10 -10
  353. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-basement-garage.xml +10 -11
  354. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-belly-wing-no-skirt.xml +496 -0
  355. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-belly-wing-skirt.xml +496 -0
  356. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-complex.xml +18 -18
  357. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-schedules-simple-power-outage-natvent-unavailable.xml → base-foundation-conditioned-basement-slab-insulation-full.xml} +552 -564
  358. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-conditioned-basement-slab-insulation.xml +9 -9
  359. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-conditioned-basement-wall-insulation.xml +555 -555
  360. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-conditioned-crawlspace.xml +8 -8
  361. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-multiple.xml +5 -5
  362. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-slab.xml +10 -11
  363. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-unconditioned-basement-above-grade.xml +4 -4
  364. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-unconditioned-basement-assembly-r.xml +4 -4
  365. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-unconditioned-basement-wall-insulation.xml +4 -4
  366. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-unconditioned-basement.xml +4 -4
  367. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-unvented-crawlspace.xml +9 -9
  368. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-vented-crawlspace-above-grade.xml +558 -0
  369. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-vented-crawlspace.xml +9 -9
  370. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-walkout-basement.xml +15 -15
  371. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-air-to-air-heat-pump-1-speed-cooling-only.xml +9 -9
  372. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-air-to-air-heat-pump-1-speed-heating-capacity-17f.xml +552 -552
  373. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-air-to-air-heat-pump-1-speed-heating-only.xml +9 -9
  374. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-air-to-air-heat-pump-1-speed-lockout-temperatures.xml +562 -562
  375. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-air-to-air-heat-pump-1-speed-seer2-hspf2.xml +557 -557
  376. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-air-to-air-heat-pump-1-speed.xml +9 -9
  377. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-air-to-air-heat-pump-2-speed.xml +9 -9
  378. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-air-to-air-heat-pump-var-speed-backup-boiler-hvac-seasons.xml +586 -586
  379. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-air-to-air-heat-pump-var-speed-backup-boiler-switchover-temperature.xml +9 -9
  380. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-air-to-air-heat-pump-var-speed-backup-boiler.xml +9 -9
  381. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-air-to-air-heat-pump-var-speed-backup-furnace.xml +9 -9
  382. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-hvac-autosize-air-to-air-heat-pump-var-speed-sizing-methodology-acca.xml → base-hvac-air-to-air-heat-pump-var-speed-detailed-performance-other-temperatures.xml} +89 -13
  383. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-hvac-autosize-air-to-air-heat-pump-var-speed-sizing-methodology-hers.xml → base-hvac-air-to-air-heat-pump-var-speed-detailed-performance.xml} +107 -13
  384. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-air-to-air-heat-pump-var-speed.xml +9 -9
  385. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-sizing-controls.xml +567 -565
  386. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize.xml +9 -9
  387. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-boiler-coal-only.xml +9 -9
  388. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-boiler-elec-only.xml +9 -9
  389. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-boiler-gas-central-ac-1-speed.xml +9 -9
  390. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-boiler-gas-only-pilot.xml +512 -512
  391. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-boiler-gas-only.xml +9 -9
  392. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-boiler-oil-only.xml +9 -9
  393. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-boiler-propane-only.xml +9 -9
  394. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-boiler-wood-only.xml +9 -9
  395. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-central-ac-only-1-speed-seer2.xml +536 -536
  396. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-central-ac-only-1-speed.xml +9 -9
  397. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-central-ac-only-2-speed.xml +9 -9
  398. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-hvac-autosize-central-ac-only-var-speed.xml → base-hvac-central-ac-only-var-speed-detailed-performance.xml} +49 -10
  399. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-central-ac-only-var-speed.xml +9 -9
  400. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-central-ac-plus-air-to-air-heat-pump-heating.xml +9 -9
  401. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-dse.xml +9 -9
  402. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-dual-fuel-air-to-air-heat-pump-1-speed-lockout-temperatures.xml +559 -559
  403. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-dual-fuel-air-to-air-heat-pump-1-speed.xml +9 -9
  404. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-dual-fuel-air-to-air-heat-pump-2-speed.xml +9 -9
  405. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-dual-fuel-air-to-air-heat-pump-var-speed.xml +9 -9
  406. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-dual-fuel-mini-split-heat-pump-ducted.xml +9 -9
  407. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-ducts-area-fractions.xml +11 -12
  408. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-ducts-area-multipliers.xml +558 -558
  409. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-ducts-buried.xml +554 -554
  410. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-hvac-autosize-furnace-gas-room-ac.xml → base-hvac-ducts-defaults.xml} +28 -14
  411. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-ducts-effective-rvalue.xml +552 -552
  412. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-ducts-leakage-cfm50.xml +9 -9
  413. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-ducts-leakage-percent.xml +9 -9
  414. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-elec-resistance-only.xml +9 -9
  415. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-evap-cooler-furnace-gas.xml +9 -9
  416. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-evap-cooler-only-ducted.xml +9 -9
  417. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-evap-cooler-only.xml +9 -9
  418. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-fireplace-wood-only.xml +9 -9
  419. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-floor-furnace-propane-only.xml +15 -10
  420. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-coal-only.xml +9 -9
  421. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-elec-central-ac-1-speed.xml +9 -9
  422. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-elec-only.xml +9 -9
  423. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-gas-central-ac-2-speed.xml +9 -9
  424. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-gas-central-ac-var-speed.xml +9 -9
  425. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-gas-only-detailed-setpoints.xml +12 -10
  426. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-gas-only-pilot.xml +541 -541
  427. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-gas-only.xml +9 -9
  428. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-gas-room-ac.xml +9 -9
  429. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-oil-only.xml +9 -9
  430. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-propane-only.xml +9 -9
  431. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-wood-only.xml +9 -9
  432. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-x3-dse.xml +9 -9
  433. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-ground-to-air-heat-pump-cooling-only.xml +9 -9
  434. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-ground-to-air-heat-pump-heating-only.xml +9 -9
  435. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-ground-to-air-heat-pump.xml +9 -9
  436. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-install-quality-air-to-air-heat-pump-1-speed.xml +9 -9
  437. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-install-quality-air-to-air-heat-pump-2-speed.xml +9 -9
  438. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-hvac-air-to-air-heat-pump-1-speed-autosized-backup.xml → base-hvac-install-quality-air-to-air-heat-pump-var-speed-detailed-performance.xml} +650 -556
  439. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-install-quality-air-to-air-heat-pump-var-speed.xml +9 -9
  440. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-install-quality-furnace-gas-central-ac-1-speed.xml +9 -9
  441. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-install-quality-furnace-gas-central-ac-2-speed.xml +9 -9
  442. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-install-quality-furnace-gas-central-ac-var-speed.xml +9 -9
  443. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-install-quality-furnace-gas-only.xml +9 -9
  444. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-install-quality-ground-to-air-heat-pump.xml +9 -9
  445. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-install-quality-mini-split-air-conditioner-only-ducted.xml +9 -9
  446. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-install-quality-mini-split-heat-pump-ducted.xml +9 -9
  447. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-mini-split-air-conditioner-only-ducted.xml +9 -9
  448. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-hvac-autosize-mini-split-air-conditioner-only-ducted.xml → base-hvac-mini-split-air-conditioner-only-ductless-detailed-performance.xml} +50 -49
  449. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-mini-split-air-conditioner-only-ductless.xml +9 -9
  450. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-mini-split-heat-pump-ducted-cooling-only.xml +9 -9
  451. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-hvac-autosize-mini-split-heat-pump-ducted-sizing-methodology-maxload.xml → base-hvac-mini-split-heat-pump-ducted-detailed-performance.xml} +109 -14
  452. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-mini-split-heat-pump-ducted-heating-only.xml +9 -9
  453. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-mini-split-heat-pump-ducted.xml +9 -9
  454. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-mini-split-heat-pump-ductless-backup-baseboard.xml +524 -524
  455. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-hvac-autosize-dual-fuel-mini-split-heat-pump-ducted-backup-hardsized.xml → base-hvac-mini-split-heat-pump-ductless-backup-furnace-ducts-defaults.xml} +560 -552
  456. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-mini-split-heat-pump-ductless-backup-furnace.xml +563 -563
  457. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-mini-split-heat-pump-ductless-backup-stove.xml +9 -9
  458. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-hvac-autosize-dual-fuel-mini-split-heat-pump-ducted.xml → base-hvac-mini-split-heat-pump-ductless-detailed-performance.xml} +108 -60
  459. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-mini-split-heat-pump-ductless-heating-capacity-17f.xml +505 -505
  460. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-mini-split-heat-pump-ductless.xml +9 -9
  461. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-multiple.xml +9 -9
  462. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-none.xml +10 -11
  463. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-ptac-with-heating-electricity.xml +9 -9
  464. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-ptac-with-heating-natural-gas.xml +504 -504
  465. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-ptac.xml +9 -9
  466. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-pthp-heating-capacity-17f.xml +512 -512
  467. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-pthp.xml +9 -9
  468. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-room-ac-only-33percent.xml +9 -9
  469. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-room-ac-only-ceer.xml +9 -9
  470. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-room-ac-only-detailed-setpoints.xml +12 -10
  471. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-room-ac-only.xml +9 -9
  472. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-room-ac-with-heating.xml +504 -504
  473. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-room-ac-with-reverse-cycle.xml +517 -517
  474. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-seasons.xml +9 -9
  475. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-setpoints-daily-schedules.xml +9 -9
  476. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-setpoints-daily-setbacks.xml +9 -9
  477. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-setpoints.xml +9 -9
  478. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-hvac-fixed-heater-gas-only.xml → base-hvac-space-heater-gas-only.xml} +10 -10
  479. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-stove-oil-only.xml +9 -9
  480. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-stove-wood-pellets-only.xml +9 -9
  481. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-undersized.xml +9 -9
  482. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-wall-furnace-elec-only.xml +9 -9
  483. data/example_files/resources/hpxml-measures/workflow/sample_files/base-lighting-ceiling-fans.xml +9 -9
  484. data/example_files/resources/hpxml-measures/workflow/sample_files/base-lighting-holiday.xml +9 -9
  485. data/example_files/resources/hpxml-measures/workflow/sample_files/base-lighting-kwh-per-year.xml +531 -528
  486. data/example_files/resources/hpxml-measures/workflow/sample_files/base-lighting-mixed.xml +536 -536
  487. data/example_files/resources/hpxml-measures/workflow/sample_files/base-lighting-none-ceiling-fans.xml +515 -515
  488. data/example_files/resources/hpxml-measures/workflow/sample_files/base-lighting-none.xml +9 -9
  489. data/example_files/resources/hpxml-measures/workflow/sample_files/base-location-AMY-2012.xml +9 -9
  490. data/example_files/resources/hpxml-measures/workflow/sample_files/base-location-baltimore-md.xml +9 -9
  491. data/example_files/resources/hpxml-measures/workflow/sample_files/base-location-capetown-zaf.xml +9 -9
  492. data/example_files/resources/hpxml-measures/workflow/sample_files/base-location-dallas-tx.xml +10 -11
  493. data/example_files/resources/hpxml-measures/workflow/sample_files/base-location-duluth-mn.xml +4 -4
  494. data/example_files/resources/hpxml-measures/workflow/sample_files/base-location-helena-mt.xml +9 -9
  495. data/example_files/resources/hpxml-measures/workflow/sample_files/base-location-honolulu-hi.xml +10 -11
  496. data/example_files/resources/hpxml-measures/workflow/sample_files/base-location-miami-fl.xml +10 -11
  497. data/example_files/resources/hpxml-measures/workflow/sample_files/base-location-phoenix-az.xml +10 -11
  498. data/example_files/resources/hpxml-measures/workflow/sample_files/base-location-portland-or.xml +9 -9
  499. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-balanced.xml +9 -9
  500. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-bath-kitchen-fans.xml +9 -9
  501. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-cfis-airflow-fraction-zero.xml +9 -9
  502. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-cfis-dse.xml +9 -9
  503. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-cfis-evap-cooler-only-ducted.xml +9 -9
  504. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-cfis-supplemental-fan-exhaust.xml +576 -576
  505. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-cfis-supplemental-fan-supply.xml +576 -576
  506. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-cfis.xml +9 -9
  507. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-erv-atre-asre.xml +9 -9
  508. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-erv.xml +9 -9
  509. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-exhaust-rated-flow-rate.xml +9 -9
  510. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-exhaust.xml +9 -9
  511. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-hrv-asre.xml +9 -9
  512. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-hrv.xml +9 -9
  513. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-multiple.xml +9 -9
  514. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-supply.xml +9 -9
  515. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-whole-house-fan.xml +9 -9
  516. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-additional-properties.xml +21 -19
  517. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-bills-pv-detailed-only.xml +605 -605
  518. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-bills-pv-mixed.xml +587 -587
  519. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-bills-pv.xml +9 -9
  520. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-bills.xml +9 -9
  521. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-defaults.xml +3 -3
  522. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-emissions.xml +9 -9
  523. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-generators-battery-scheduled.xml +587 -585
  524. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-generators-battery.xml +584 -584
  525. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-generators.xml +9 -9
  526. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-ground-conductivity.xml +555 -555
  527. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-loads-large-uncommon.xml +26 -26
  528. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-loads-large-uncommon2.xml +26 -26
  529. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-loads-none.xml +9 -9
  530. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-neighbor-shading-bldgtype-multifamily.xml +508 -508
  531. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-neighbor-shading.xml +9 -9
  532. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-shielding-of-home.xml +9 -9
  533. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-schedules-simple-power-outage-natvent-available.xml → base-misc-unit-multiplier.xml} +553 -564
  534. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-usage-multiplier.xml +26 -26
  535. data/example_files/resources/hpxml-measures/workflow/sample_files/base-multiple-mf-units.xml +2755 -0
  536. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-multiple-buildings.xml → base-multiple-sfd-buildings.xml} +31 -22
  537. data/example_files/resources/hpxml-measures/workflow/sample_files/base-pv-battery-ah.xml +9 -9
  538. data/example_files/resources/hpxml-measures/workflow/sample_files/base-pv-battery-garage.xml +4 -5
  539. data/example_files/resources/hpxml-measures/workflow/sample_files/base-pv-battery-round-trip-efficiency.xml +597 -597
  540. data/example_files/resources/hpxml-measures/workflow/sample_files/base-pv-battery-scheduled.xml +599 -597
  541. data/example_files/resources/hpxml-measures/workflow/sample_files/base-pv-battery.xml +9 -9
  542. data/example_files/resources/hpxml-measures/workflow/sample_files/base-pv-generators-battery-scheduled.xml +615 -613
  543. data/example_files/resources/hpxml-measures/workflow/sample_files/base-pv-generators-battery.xml +612 -612
  544. data/example_files/resources/hpxml-measures/workflow/sample_files/base-pv-generators.xml +596 -596
  545. data/example_files/resources/hpxml-measures/workflow/sample_files/base-pv.xml +9 -9
  546. data/example_files/resources/hpxml-measures/workflow/sample_files/base-residents-0-runperiod-1-month.xml +559 -559
  547. data/example_files/resources/hpxml-measures/workflow/sample_files/base-residents-0.xml +555 -555
  548. data/example_files/resources/hpxml-measures/workflow/sample_files/base-residents-1-misc-loads-large-uncommon.xml +616 -616
  549. data/example_files/resources/hpxml-measures/workflow/sample_files/base-residents-1-misc-loads-large-uncommon2.xml +616 -616
  550. data/example_files/resources/hpxml-measures/workflow/sample_files/base-residents-1.xml +547 -547
  551. data/example_files/resources/hpxml-measures/workflow/sample_files/base-residents-5.xml +515 -515
  552. data/example_files/resources/hpxml-measures/workflow/sample_files/base-schedules-detailed-all-10-mins.xml +14 -12
  553. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-hvac-crankcase-heater-40w.xml → base-schedules-detailed-mixed-timesteps-power-outage.xml} +565 -555
  554. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-schedules-detailed-occupancy-stochastic-vacancy-year-round.xml → base-schedules-detailed-mixed-timesteps.xml} +554 -563
  555. data/example_files/resources/hpxml-measures/workflow/sample_files/base-schedules-detailed-occupancy-stochastic-10-mins.xml +12 -10
  556. data/example_files/resources/hpxml-measures/workflow/sample_files/base-schedules-detailed-occupancy-stochastic-power-outage.xml +566 -564
  557. data/example_files/resources/hpxml-measures/workflow/sample_files/base-schedules-detailed-occupancy-stochastic-vacancy.xml +12 -10
  558. data/example_files/resources/hpxml-measures/workflow/sample_files/base-schedules-detailed-occupancy-stochastic.xml +12 -10
  559. data/example_files/resources/hpxml-measures/workflow/sample_files/base-schedules-detailed-setpoints-daily-schedules.xml +12 -10
  560. data/example_files/resources/hpxml-measures/workflow/sample_files/base-schedules-detailed-setpoints-daily-setbacks.xml +12 -10
  561. data/example_files/resources/hpxml-measures/workflow/sample_files/base-schedules-detailed-setpoints.xml +12 -10
  562. data/example_files/resources/hpxml-measures/workflow/sample_files/base-schedules-simple-power-outage.xml +619 -619
  563. data/example_files/resources/hpxml-measures/workflow/sample_files/base-schedules-simple-vacancy.xml +618 -618
  564. data/example_files/resources/hpxml-measures/workflow/sample_files/base-schedules-simple.xml +9 -9
  565. data/example_files/resources/hpxml-measures/workflow/sample_files/base-simcontrol-calendar-year-custom.xml +9 -9
  566. data/example_files/resources/hpxml-measures/workflow/sample_files/base-simcontrol-daylight-saving-custom.xml +9 -9
  567. data/example_files/resources/hpxml-measures/workflow/sample_files/base-simcontrol-daylight-saving-disabled.xml +9 -9
  568. data/example_files/resources/hpxml-measures/workflow/sample_files/base-simcontrol-runperiod-1-month.xml +9 -9
  569. data/example_files/resources/hpxml-measures/workflow/sample_files/base-simcontrol-temperature-capacitance-multiplier.xml +553 -553
  570. data/example_files/resources/hpxml-measures/workflow/sample_files/base-simcontrol-timestep-10-mins-occupancy-stochastic-10-mins.xml +12 -10
  571. data/example_files/resources/hpxml-measures/workflow/sample_files/base-simcontrol-timestep-10-mins-occupancy-stochastic-60-mins.xml +12 -10
  572. data/example_files/resources/hpxml-measures/workflow/sample_files/base-simcontrol-timestep-10-mins.xml +9 -9
  573. data/example_files/resources/hpxml-measures/workflow/sample_files/base-simcontrol-timestep-30-mins.xml +552 -552
  574. data/example_files/resources/hpxml-measures/workflow/sample_files/base.xml +9 -9
  575. data/example_files/resources/hpxml-measures/workflow/template-build-and-run-hpxml-with-stochastic-occupancy.osw +2 -0
  576. data/example_files/resources/hpxml-measures/workflow/template-run-hpxml-with-stochastic-occupancy-subset.osw +2 -0
  577. data/example_files/resources/hpxml-measures/workflow/template-run-hpxml-with-stochastic-occupancy.osw +2 -0
  578. data/example_files/resources/hpxml-measures/workflow/template-run-hpxml.osw +4 -1
  579. data/example_files/resources/hpxml-measures/workflow/tests/ACCA_Examples/Long_Residence.xml +385 -385
  580. data/example_files/resources/hpxml-measures/workflow/tests/ACCA_Examples/Vatilo_Residence.xml +378 -380
  581. data/example_files/resources/hpxml-measures/workflow/tests/ACCA_Examples/Victor_Residence.xml +369 -369
  582. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L100AC.xml +7 -7
  583. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L100AL.xml +7 -7
  584. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L110AC.xml +7 -7
  585. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L110AL.xml +7 -7
  586. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L120AC.xml +7 -7
  587. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L120AL.xml +7 -7
  588. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L130AC.xml +7 -7
  589. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L130AL.xml +7 -7
  590. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L140AC.xml +7 -7
  591. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L140AL.xml +7 -7
  592. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L150AC.xml +7 -7
  593. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L150AL.xml +7 -7
  594. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L155AC.xml +7 -7
  595. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L155AL.xml +7 -7
  596. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L160AC.xml +7 -7
  597. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L160AL.xml +7 -7
  598. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L170AC.xml +7 -7
  599. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L170AL.xml +7 -7
  600. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L200AC.xml +7 -7
  601. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L200AL.xml +7 -7
  602. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L202AC.xml +7 -7
  603. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L202AL.xml +7 -7
  604. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L302XC.xml +7 -8
  605. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L304XC.xml +7 -8
  606. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L322XC.xml +6 -6
  607. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L324XC.xml +6 -6
  608. data/example_files/resources/hpxml-measures/workflow/tests/base_results/results_sizing.csv +363 -0
  609. data/example_files/resources/hpxml-measures/workflow/tests/base_results/results_workflow_simulations1.csv +281 -0
  610. data/example_files/resources/hpxml-measures/workflow/tests/base_results/results_workflow_simulations1_bills.csv +281 -0
  611. data/example_files/resources/hpxml-measures/workflow/tests/base_results/results_workflow_simulations2.csv +141 -0
  612. data/example_files/resources/hpxml-measures/workflow/tests/base_results/results_workflow_simulations2_bills.csv +141 -0
  613. data/example_files/resources/hpxml-measures/workflow/tests/compare.py +12 -6
  614. data/example_files/resources/hpxml-measures/workflow/tests/util.rb +1141 -0
  615. data/example_files/weather/USA_CO_Denver.Intl.AP.725650_TMY3.ddy +536 -0
  616. data/example_files/weather/USA_CO_Denver.Intl.AP.725650_TMY3.epw +8768 -0
  617. data/example_files/weather/USA_CO_Denver.Intl.AP.725650_TMY3.stat +554 -0
  618. data/example_files/weather/USA_FL_MacDill.AFB.747880_TMY3.ddy +536 -0
  619. data/example_files/weather/USA_FL_MacDill.AFB.747880_TMY3.epw +8768 -0
  620. data/example_files/weather/USA_FL_MacDill.AFB.747880_TMY3.stat +553 -0
  621. data/example_files/weather/USA_GA_Atlanta-Hartsfield-Jackson.Intl.AP.722190_TMY3-cache.csv +35 -0
  622. data/example_files/weather/USA_GA_Atlanta-Hartsfield-Jackson.Intl.AP.722190_TMY3.ddy +536 -0
  623. data/example_files/weather/USA_GA_Atlanta-Hartsfield-Jackson.Intl.AP.722190_TMY3.epw +8768 -0
  624. data/example_files/weather/USA_GA_Atlanta-Hartsfield-Jackson.Intl.AP.722190_TMY3.stat +553 -0
  625. data/example_files/weather/USA_NY_Buffalo-Greater.Buffalo.Intl.AP.725280_TMY3-cache.csv +35 -0
  626. data/example_files/xml_building/17/README.md +4 -2
  627. data/example_files/xml_building/17/feature.xml +2112 -0
  628. data/lib/uo_cli/version.rb +1 -1
  629. data/lib/uo_cli.rb +110 -17
  630. data/uo_cli.gemspec +6 -8
  631. metadata +130 -177
  632. data/Jenkinsfile +0 -10
  633. data/example_files/base_workflow_res.osw +0 -276
  634. data/example_files/resources/hpxml-measures/ReportUtilityBills/tests/utility_bills_test.rb +0 -1226
  635. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-oil-location-miami-fl.xml +0 -551
  636. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-propane-location-portland-or.xml +0 -551
  637. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-air-to-air-heat-pump-1-speed-cooling-only.xml +0 -544
  638. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-air-to-air-heat-pump-1-speed-heating-only.xml +0 -550
  639. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-air-to-air-heat-pump-1-speed-sizing-methodology-acca.xml +0 -552
  640. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-air-to-air-heat-pump-1-speed-sizing-methodology-hers.xml +0 -552
  641. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-air-to-air-heat-pump-1-speed-sizing-methodology-maxload-miami-fl.xml +0 -552
  642. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-air-to-air-heat-pump-1-speed-sizing-methodology-maxload.xml +0 -552
  643. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-air-to-air-heat-pump-2-speed-sizing-methodology-acca.xml +0 -552
  644. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-air-to-air-heat-pump-2-speed-sizing-methodology-hers.xml +0 -552
  645. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-air-to-air-heat-pump-2-speed-sizing-methodology-maxload.xml +0 -552
  646. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-air-to-air-heat-pump-var-speed-backup-boiler.xml +0 -569
  647. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-air-to-air-heat-pump-var-speed-backup-furnace.xml +0 -599
  648. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-air-to-air-heat-pump-var-speed-sizing-methodology-maxload.xml +0 -552
  649. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-boiler-elec-only.xml +0 -506
  650. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-boiler-gas-central-ac-1-speed.xml +0 -560
  651. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-boiler-gas-only.xml +0 -507
  652. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-central-ac-only-1-speed.xml +0 -536
  653. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-central-ac-only-2-speed.xml +0 -536
  654. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-central-ac-plus-air-to-air-heat-pump-heating.xml +0 -565
  655. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-dual-fuel-air-to-air-heat-pump-1-speed-sizing-methodology-acca.xml +0 -553
  656. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-dual-fuel-air-to-air-heat-pump-1-speed-sizing-methodology-hers.xml +0 -553
  657. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-dual-fuel-air-to-air-heat-pump-1-speed-sizing-methodology-maxload.xml +0 -553
  658. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-elec-resistance-only.xml +0 -497
  659. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-evap-cooler-furnace-gas.xml +0 -544
  660. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-floor-furnace-propane-only.xml +0 -500
  661. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-furnace-elec-only.xml +0 -536
  662. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-furnace-gas-central-ac-2-speed.xml +0 -551
  663. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-furnace-gas-central-ac-var-speed.xml +0 -551
  664. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-furnace-gas-only.xml +0 -536
  665. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-ground-to-air-heat-pump-cooling-only.xml +0 -546
  666. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-ground-to-air-heat-pump-heating-only.xml +0 -552
  667. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-ground-to-air-heat-pump-sizing-methodology-acca.xml +0 -554
  668. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-ground-to-air-heat-pump-sizing-methodology-hers.xml +0 -554
  669. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-ground-to-air-heat-pump-sizing-methodology-maxload.xml +0 -554
  670. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-mini-split-heat-pump-ducted-cooling-only.xml +0 -543
  671. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-mini-split-heat-pump-ducted-heating-only.xml +0 -549
  672. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-mini-split-heat-pump-ducted-sizing-methodology-acca.xml +0 -551
  673. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-mini-split-heat-pump-ducted-sizing-methodology-hers.xml +0 -551
  674. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-mini-split-heat-pump-ductless-backup-baseboard.xml +0 -519
  675. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-mini-split-heat-pump-ductless-backup-stove.xml +0 -522
  676. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-ptac-with-heating.xml +0 -503
  677. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-ptac.xml +0 -496
  678. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-pthp-sizing-methodology-acca.xml +0 -518
  679. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-pthp-sizing-methodology-hers.xml +0 -518
  680. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-pthp-sizing-methodology-maxload.xml +0 -518
  681. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-room-ac-only.xml +0 -496
  682. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-room-ac-with-heating.xml +0 -503
  683. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-room-ac-with-reverse-cycle-sizing-methodology-acca.xml +0 -518
  684. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-room-ac-with-reverse-cycle-sizing-methodology-hers.xml +0 -518
  685. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-room-ac-with-reverse-cycle-sizing-methodology-maxload.xml +0 -518
  686. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-stove-oil-only.xml +0 -500
  687. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-wall-furnace-elec-only.xml +0 -500
  688. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-floor-furnace-propane-only-pilot-light.xml +0 -506
  689. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-portable-heater-gas-only.xml +0 -501
  690. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-undersized-allow-increased-fixed-capacities.xml +0 -556
  691. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-bills-none.xml +0 -548
  692. data/example_files/resources/hpxml-measures/workflow/sample_files/base-schedules-simple-vacancy-year-round.xml +0 -619
  693. data/example_files/resources/hpxml-measures/workflow/tests/base_results/results.csv +0 -475
  694. data/example_files/resources/hpxml-measures/workflow/tests/base_results/results_bills.csv +0 -475
  695. data/example_files/resources/hpxml-measures/workflow/tests/hpxml_translator_test.rb +0 -1313
  696. data/example_files/resources/measure-info.json +0 -26
  697. data/example_files/resources/meta_measure.rb +0 -301
  698. data/example_files/xml_building/17/unit 1.xml +0 -580
  699. data/example_files/xml_building/17/unit 2.xml +0 -553
  700. data/example_files/xml_building/17/unit 3.xml +0 -553
  701. data/example_files/xml_building/17/unit 4.xml +0 -580
  702. /data/example_files/{residential → mappers/residential/template/iecc}/clothes_dryer.tsv +0 -0
  703. /data/example_files/{residential → mappers/residential/template/iecc}/clothes_washer.tsv +0 -0
  704. /data/example_files/{residential → mappers/residential/template/iecc}/cooling_system.tsv +0 -0
  705. /data/example_files/{residential → mappers/residential/template/iecc}/dishwasher.tsv +0 -0
  706. /data/example_files/{residential → mappers/residential/template/iecc}/enclosure.tsv +0 -0
  707. /data/example_files/{residential → mappers/residential/template/iecc}/heat_pump.tsv +0 -0
  708. /data/example_files/{residential → mappers/residential/template/iecc}/heating_system.tsv +0 -0
  709. /data/example_files/{residential → mappers/residential/template/iecc}/mechanical_ventilation.tsv +0 -0
  710. /data/example_files/{residential → mappers/residential/template/iecc}/refrigerator.tsv +0 -0
  711. /data/example_files/{residential → mappers/residential/template/iecc}/water_heater.tsv +0 -0
  712. /data/example_files/resources/hpxml-measures/ReportUtilityBills/tests/{JacksonElectricMemberCorp-ResidentialSeniorCitizenLowIncomeAssistance.json → Detailed Rate.json} +0 -0
@@ -1,3 +1,8 @@
1
+ # *********************************************************************************
2
+ # URBANopt (tm), Copyright (c) Alliance for Sustainable Energy, LLC.
3
+ # See also https://github.com/urbanopt/urbanopt-cli/blob/develop/LICENSE.md
4
+ # *********************************************************************************
5
+
1
6
  # frozen_string_literal: true
2
7
 
3
8
  # Require all gems up front; this is much faster than multiple resource
@@ -63,7 +68,7 @@ class HPXMLtoOpenStudio < OpenStudio::Measure::ModelMeasure
63
68
 
64
69
  arg = OpenStudio::Measure::OSArgument.makeStringArgument('building_id', false)
65
70
  arg.setDisplayName('BuildingID')
66
- arg.setDescription('The ID of the HPXML Building. Only required if there are multiple Building elements in the HPXML file.')
71
+ arg.setDescription("The ID of the HPXML Building. Only required if there are multiple Building elements in the HPXML file. Use 'ALL' to run all the HPXML Buildings (dwelling units) of a multifamily building in a single model.")
67
72
  args << arg
68
73
 
69
74
  return args
@@ -89,6 +94,7 @@ class HPXMLtoOpenStudio < OpenStudio::Measure::ModelMeasure
89
94
  debug = runner.getBoolArgumentValue('debug', user_arguments)
90
95
  skip_validation = runner.getBoolArgumentValue('skip_validation', user_arguments)
91
96
  building_id = runner.getOptionalStringArgumentValue('building_id', user_arguments)
97
+ building_id = building_id.is_initialized ? building_id.get : nil
92
98
 
93
99
  unless (Pathname.new hpxml_path).absolute?
94
100
  hpxml_path = File.expand_path(hpxml_path)
@@ -101,12 +107,6 @@ class HPXMLtoOpenStudio < OpenStudio::Measure::ModelMeasure
101
107
  output_dir = File.expand_path(output_dir)
102
108
  end
103
109
 
104
- if building_id.is_initialized
105
- building_id = building_id.get
106
- else
107
- building_id = nil
108
- end
109
-
110
110
  begin
111
111
  if skip_validation
112
112
  schema_validator = nil
@@ -117,6 +117,7 @@ class HPXMLtoOpenStudio < OpenStudio::Measure::ModelMeasure
117
117
  schematron_path = File.join(File.dirname(__FILE__), 'resources', 'hpxml_schematron', 'EPvalidator.xml')
118
118
  schematron_validator = XMLValidator.get_schematron_validator(schematron_path)
119
119
  end
120
+
120
121
  hpxml = HPXML.new(hpxml_path: hpxml_path, schema_validator: schema_validator, schematron_validator: schematron_validator, building_id: building_id)
121
122
  hpxml.errors.each do |error|
122
123
  runner.registerError(error)
@@ -126,16 +127,91 @@ class HPXMLtoOpenStudio < OpenStudio::Measure::ModelMeasure
126
127
  end
127
128
  return false unless hpxml.errors.empty?
128
129
 
129
- epw_path = Location.get_epw_path(hpxml, hpxml_path)
130
- weather = WeatherProcess.new(epw_path: epw_path, runner: runner)
130
+ eri_version = hpxml.header.eri_calculation_version # Hidden feature
131
+ eri_version = 'latest' if eri_version.nil?
132
+ eri_version = Constants.ERIVersions[-1] if eri_version == 'latest'
133
+
134
+ # Process weather once upfront
135
+ epw_path = Location.get_epw_path(hpxml.buildings[0], hpxml_path)
136
+ weather = WeatherProcess.new(epw_path: epw_path, runner: runner, hpxml: hpxml)
137
+ epw_file = OpenStudio::EpwFile.new(epw_path)
138
+ hpxml.buildings.each_with_index do |hpxml_bldg, i|
139
+ next if i == 0
140
+ next if Location.get_epw_path(hpxml_bldg, hpxml_path) == epw_path
141
+
142
+ fail 'Weather station EPW filepath has different values across dwelling units.'
143
+ end
144
+
145
+ if (building_id == 'ALL') && (hpxml.buildings.size > 1)
146
+ if hpxml.buildings.map { |hpxml_bldg| hpxml_bldg.batteries.size }.sum > 0
147
+ # FUTURE: Figure out how to allow this. If we allow it, update docs and hpxml_translator_test.rb too.
148
+ # Batteries use "TrackFacilityElectricDemandStoreExcessOnSite"; to support modeling of batteries in whole
149
+ # SFA/MF building simulations, we'd need to create custom meters with electricity usage *for each unit*
150
+ # and switch to "TrackMeterDemandStoreExcessOnSite".
151
+ # https://github.com/NREL/OpenStudio-HPXML/issues/1499
152
+ fail 'Modeling batteries for whole SFA/MF buildings is not currently supported.'
153
+ end
154
+ end
155
+
156
+ # Apply HPXML defaults upfront; process schedules & emissions
157
+ hpxml_sch_map = {}
158
+ check_emissions_references(hpxml.header, hpxml_path)
159
+ hpxml.buildings.each_with_index do |hpxml_bldg, i|
160
+ check_schedule_references(hpxml_bldg.header, hpxml_path)
161
+ in_schedules_csv = 'in.schedules.csv'
162
+ in_schedules_csv = "in.schedules#{i + 1}.csv" if i > 0
163
+ schedules_file = SchedulesFile.new(runner: runner,
164
+ schedules_paths: hpxml_bldg.header.schedules_filepaths,
165
+ year: Location.get_sim_calendar_year(hpxml.header.sim_calendar_year, epw_file),
166
+ unavailable_periods: hpxml.header.unavailable_periods,
167
+ output_path: File.join(output_dir, in_schedules_csv))
168
+ HPXMLDefaults.apply(runner, hpxml, hpxml_bldg, eri_version, weather, epw_file: epw_file, schedules_file: schedules_file)
169
+ hpxml_sch_map[hpxml_bldg] = schedules_file
170
+ end
171
+ validate_emissions_files(hpxml.header)
172
+
173
+ # Write updated HPXML object (w/ defaults) to file for inspection
174
+ hpxml_defaults_path = File.join(output_dir, 'in.xml')
175
+ XMLHelper.write_file(hpxml.to_doc, hpxml_defaults_path)
176
+
177
+ # Create OpenStudio model
178
+ hpxml_osm_map = {}
179
+ hpxml.buildings.each_with_index do |hpxml_bldg, i|
180
+ schedules_file = hpxml_sch_map[hpxml_bldg]
181
+ if hpxml.buildings.size > 1
182
+ # Create the model for this single unit
183
+ unit_model = OpenStudio::Model::Model.new
184
+ create_unit_model(hpxml, hpxml_bldg, runner, unit_model, epw_path, epw_file, weather, debug, schedules_file, eri_version, i + 1)
185
+ hpxml_osm_map[hpxml_bldg] = unit_model
186
+ else
187
+ create_unit_model(hpxml, hpxml_bldg, runner, model, epw_path, epw_file, weather, debug, schedules_file, eri_version, i + 1)
188
+ hpxml_osm_map[hpxml_bldg] = model
189
+ end
190
+ end
191
+
192
+ # Merge unit models into final model
193
+ if hpxml.buildings.size > 1
194
+ add_unit_model_to_model(model, hpxml_osm_map)
195
+ end
196
+
197
+ # Output
198
+ add_unmet_hours_output(model, hpxml_osm_map)
199
+ add_loads_output(model, add_component_loads, hpxml_osm_map)
200
+ set_output_files(model)
201
+ add_additional_properties(model, hpxml, hpxml_osm_map, hpxml_path, building_id, epw_file, hpxml_defaults_path)
202
+ # Uncomment to debug EMS
203
+ # add_ems_debug_output(model)
131
204
 
132
205
  if debug
206
+ # Write OSM file to run dir
207
+ osm_output_path = File.join(output_dir, 'in.osm')
208
+ File.write(osm_output_path, model.to_s)
209
+ runner.registerInfo("Wrote file: #{osm_output_path}")
210
+
211
+ # Copy EPW file to run dir
133
212
  epw_output_path = File.join(output_dir, 'in.epw')
134
213
  FileUtils.cp(epw_path, epw_output_path)
135
214
  end
136
-
137
- OSModel.create(hpxml, runner, model, hpxml_path, epw_path, weather, output_dir,
138
- add_component_loads, building_id, debug)
139
215
  rescue Exception => e
140
216
  runner.registerError("#{e.message}\n#{e.backtrace.join("\n")}")
141
217
  return false
@@ -143,19 +219,198 @@ class HPXMLtoOpenStudio < OpenStudio::Measure::ModelMeasure
143
219
 
144
220
  return true
145
221
  end
146
- end
147
222
 
148
- class OSModel
149
- def self.create(hpxml, runner, model, hpxml_path, epw_path, weather, output_dir,
150
- add_component_loads, building_id, debug)
151
- @hpxml = hpxml
152
- @debug = debug
223
+ def add_unit_model_to_model(model, hpxml_osm_map)
224
+ unique_objects = { 'OS:ConvergenceLimits' => 'ConvergenceLimits',
225
+ 'OS:Foundation:Kiva:Settings' => 'FoundationKivaSettings',
226
+ 'OS:OutputControl:Files' => 'OutputControlFiles',
227
+ 'OS:Output:Diagnostics' => 'OutputDiagnostics',
228
+ 'OS:Output:JSON' => 'OutputJSON',
229
+ 'OS:PerformancePrecisionTradeoffs' => 'PerformancePrecisionTradeoffs',
230
+ 'OS:RunPeriod' => 'RunPeriod',
231
+ 'OS:RunPeriodControl:DaylightSavingTime' => 'RunPeriodControlDaylightSavingTime',
232
+ 'OS:ShadowCalculation' => 'ShadowCalculation',
233
+ 'OS:SimulationControl' => 'SimulationControl',
234
+ 'OS:Site' => 'Site',
235
+ 'OS:Site:GroundTemperature:Deep' => 'SiteGroundTemperatureDeep',
236
+ 'OS:Site:GroundTemperature:Shallow' => 'SiteGroundTemperatureShallow',
237
+ 'OS:Site:WaterMainsTemperature' => 'SiteWaterMainsTemperature',
238
+ 'OS:SurfaceConvectionAlgorithm:Inside' => 'InsideSurfaceConvectionAlgorithm',
239
+ 'OS:SurfaceConvectionAlgorithm:Outside' => 'OutsideSurfaceConvectionAlgorithm',
240
+ 'OS:Timestep' => 'Timestep' }
241
+
242
+ # Handle unique objects first: Grab one from the first model we find the
243
+ # object on (may not be the first unit).
244
+ unit_model_objects = []
245
+ unique_handles_to_skip = []
246
+ uuid_regex = /\{(.*?)\}/
247
+ unique_objects.each do |idd_obj, osm_class|
248
+ first_model_object_by_type = nil
249
+ hpxml_osm_map.values.each do |unit_model|
250
+ next if unit_model.getObjectsByType(idd_obj.to_IddObjectType).empty?
251
+
252
+ model_object = unit_model.send("get#{osm_class}")
253
+
254
+ if first_model_object_by_type.nil?
255
+ # Retain object for model
256
+ unit_model_objects << model_object
257
+ first_model_object_by_type = model_object
258
+ if idd_obj == 'OS:Site:WaterMainsTemperature' # Handle referenced child object too
259
+ unit_model_objects << unit_model.getObjectsByName(model_object.temperatureSchedule.get.name.to_s)[0]
260
+ end
261
+ else
262
+ # Throw error if different values between this model_object and first_model_object_by_type
263
+ if model_object.to_s.gsub(uuid_regex, '') != first_model_object_by_type.to_s.gsub(uuid_regex, '')
264
+ fail "Unique object (#{idd_obj}) has different values across dwelling units."
265
+ end
266
+
267
+ if idd_obj == 'OS:Site:WaterMainsTemperature' # Handle referenced child object too
268
+ if model_object.temperatureSchedule.get.to_s.gsub(uuid_regex, '') != first_model_object_by_type.temperatureSchedule.get.to_s.gsub(uuid_regex, '')
269
+ fail "Unique object (#{idd_obj}) has different values across dwelling units."
270
+ end
271
+ end
272
+ end
273
+
274
+ unique_handles_to_skip << model_object.handle.to_s
275
+ if idd_obj == 'OS:Site:WaterMainsTemperature' # Handle referenced child object too
276
+ unique_handles_to_skip << model_object.temperatureSchedule.get.handle.to_s
277
+ end
278
+ end
279
+ end
280
+
281
+ hpxml_osm_map.values.each_with_index do |unit_model, unit_number|
282
+ shift_geometry(unit_model, unit_number)
283
+ prefix_all_unit_model_objects(unit_model, unit_number)
284
+
285
+ # Handle remaining (non-unique) objects now
286
+ unit_model.objects.each do |obj|
287
+ next if unit_number > 0 && obj.to_Building.is_initialized
288
+ next if unique_handles_to_skip.include? obj.handle.to_s
153
289
 
154
- @eri_version = @hpxml.header.eri_calculation_version # Hidden feature
155
- @eri_version = 'latest' if @eri_version.nil?
156
- @eri_version = Constants.ERIVersions[-1] if @eri_version == 'latest'
290
+ unit_model_objects << obj
291
+ end
292
+ end
157
293
 
158
- @apply_ashrae140_assumptions = @hpxml.header.apply_ashrae140_assumptions # Hidden feature
294
+ model.addObjects(unit_model_objects, true)
295
+ end
296
+
297
+ def shift_geometry(unit_model, unit_number)
298
+ # Shift units so they aren't right on top and shade each other
299
+ y_shift = 200.0 * unit_number # meters
300
+
301
+ # shift the unit so it's not right on top of the previous one
302
+ unit_model.getSpaces.sort.each do |space|
303
+ space.setYOrigin(y_shift)
304
+ end
305
+
306
+ # shift shading surfaces
307
+ m = OpenStudio::Matrix.new(4, 4, 0)
308
+ m[0, 0] = 1
309
+ m[1, 1] = 1
310
+ m[2, 2] = 1
311
+ m[3, 3] = 1
312
+ m[1, 3] = y_shift
313
+ t = OpenStudio::Transformation.new(m)
314
+
315
+ unit_model.getShadingSurfaceGroups.each do |shading_surface_group|
316
+ next if shading_surface_group.space.is_initialized # already got shifted
317
+
318
+ shading_surface_group.shadingSurfaces.each do |shading_surface|
319
+ shading_surface.setVertices(t * shading_surface.vertices)
320
+ end
321
+ end
322
+ end
323
+
324
+ def prefix_all_unit_model_objects(unit_model, unit_number)
325
+ # Prefix all objects with name using unit number
326
+ # FUTURE: Create objects with unique names up front so we don't have to do this
327
+
328
+ # EMS objects
329
+ ems_map = {}
330
+
331
+ unit_model.getEnergyManagementSystemSensors.each do |sensor|
332
+ ems_map[sensor.name.to_s] = make_variable_name(sensor.name, unit_number)
333
+ sensor.setKeyName(make_variable_name(sensor.keyName, unit_number)) unless sensor.keyName.empty? || sensor.keyName.downcase == 'environment'
334
+ end
335
+
336
+ unit_model.getEnergyManagementSystemActuators.each do |actuator|
337
+ ems_map[actuator.name.to_s] = make_variable_name(actuator.name, unit_number)
338
+ end
339
+
340
+ unit_model.getEnergyManagementSystemInternalVariables.each do |internal_variable|
341
+ ems_map[internal_variable.name.to_s] = make_variable_name(internal_variable.name, unit_number)
342
+ internal_variable.setInternalDataIndexKeyName(make_variable_name(internal_variable.internalDataIndexKeyName, unit_number)) unless internal_variable.internalDataIndexKeyName.empty?
343
+ end
344
+
345
+ unit_model.getEnergyManagementSystemGlobalVariables.each do |global_variable|
346
+ ems_map[global_variable.name.to_s] = make_variable_name(global_variable.name, unit_number)
347
+ end
348
+
349
+ unit_model.getEnergyManagementSystemOutputVariables.each do |output_variable|
350
+ next if output_variable.emsVariableObject.is_initialized
351
+
352
+ new_ems_variable_name = make_variable_name(output_variable.emsVariableName, unit_number)
353
+ ems_map[output_variable.emsVariableName.to_s] = new_ems_variable_name
354
+ output_variable.setEMSVariableName(new_ems_variable_name)
355
+ end
356
+
357
+ unit_model.getEnergyManagementSystemSubroutines.each do |subroutine|
358
+ ems_map[subroutine.name.to_s] = make_variable_name(subroutine.name, unit_number)
359
+ end
360
+
361
+ # variables in program lines don't get updated automatically
362
+ lhs_characters = [' ', ',', '(', ')', '+', '-', '*', '/', ';']
363
+ rhs_characters = [''] + lhs_characters
364
+ (unit_model.getEnergyManagementSystemPrograms + unit_model.getEnergyManagementSystemSubroutines).each do |program|
365
+ new_lines = []
366
+ program.lines.each do |line|
367
+ ems_map.each do |old_name, new_name|
368
+ next unless line.include?(old_name)
369
+
370
+ # old_name between at least 1 character, with the exception of '' on left and ' ' on right
371
+ lhs_characters.each do |lhs|
372
+ next unless line.include?("#{lhs}#{old_name}")
373
+
374
+ rhs_characters.each do |rhs|
375
+ next unless line.include?("#{lhs}#{old_name}#{rhs}")
376
+ next if lhs == '' && ['', ' '].include?(rhs)
377
+
378
+ line.gsub!("#{lhs}#{old_name}#{rhs}", "#{lhs}#{new_name}#{rhs}")
379
+ end
380
+ end
381
+ end
382
+ new_lines << line
383
+ end
384
+ program.setLines(new_lines)
385
+ end
386
+
387
+ # All model objects
388
+ unit_model.objects.each do |model_object|
389
+ next if model_object.name.nil?
390
+
391
+ if unit_number == 0
392
+ # OpenStudio is unhappy if these schedules are renamed
393
+ next if model_object.name.to_s == unit_model.alwaysOnContinuousSchedule.name.to_s
394
+ next if model_object.name.to_s == unit_model.alwaysOnDiscreteSchedule.name.to_s
395
+ next if model_object.name.to_s == unit_model.alwaysOffDiscreteSchedule.name.to_s
396
+ end
397
+
398
+ model_object.setName(make_variable_name(model_object.name, unit_number))
399
+ end
400
+ end
401
+
402
+ def make_variable_name(obj_name, unit_number)
403
+ return "unit#{unit_number + 1}_#{obj_name}".gsub(' ', '_').gsub('-', '_')
404
+ end
405
+
406
+ def create_unit_model(hpxml, hpxml_bldg, runner, model, epw_path, epw_file, weather, debug, schedules_file, eri_version, unit_num)
407
+ @hpxml_header = hpxml.header
408
+ @hpxml_bldg = hpxml_bldg
409
+ @debug = debug
410
+ @schedules_file = schedules_file
411
+ @eri_version = eri_version
412
+
413
+ @apply_ashrae140_assumptions = @hpxml_header.apply_ashrae140_assumptions # Hidden feature
159
414
  @apply_ashrae140_assumptions = false if @apply_ashrae140_assumptions.nil?
160
415
 
161
416
  # Here we turn off OS error-checking so that any invalid values provided
@@ -167,21 +422,14 @@ class OSModel
167
422
  model.setStrictnessLevel('None'.to_StrictnessLevel)
168
423
 
169
424
  # Init
170
- check_file_references(hpxml_path)
171
- epw_file = Location.apply_weather_file(model, epw_path)
172
- @schedules_file = SchedulesFile.new(runner: runner, model: model,
173
- schedules_paths: @hpxml.header.schedules_filepaths,
174
- year: Location.get_sim_calendar_year(@hpxml.header.sim_calendar_year, epw_file),
175
- unavailable_periods: @hpxml.header.unavailable_periods,
176
- output_path: File.join(output_dir, 'in.schedules.csv'))
177
- set_defaults_and_globals(runner, output_dir, epw_file, weather, @schedules_file)
178
- validate_emissions_files()
179
- Location.apply(model, weather, epw_file, @hpxml)
425
+ OpenStudio::Model::WeatherFile.setWeatherFile(model, epw_file)
426
+ set_defaults_and_globals()
427
+ Location.apply(model, weather, epw_file, @hpxml_header, @hpxml_bldg)
180
428
  add_simulation_params(model)
181
429
 
182
430
  # Conditioned space/zone
183
431
  spaces = {}
184
- create_or_get_space(model, spaces, HPXML::LocationLivingSpace)
432
+ create_or_get_space(model, spaces, HPXML::LocationConditionedSpace)
185
433
  set_foundation_and_walls_top()
186
434
  set_heating_and_cooling_seasons()
187
435
  add_setpoints(runner, model, weather, spaces)
@@ -197,16 +445,16 @@ class OSModel
197
445
  add_skylights(model, spaces)
198
446
  add_conditioned_floor_area(model, spaces)
199
447
  add_thermal_mass(model, spaces)
200
- Geometry.set_zone_volumes(spaces, @hpxml, @apply_ashrae140_assumptions)
201
- Geometry.explode_surfaces(model, @hpxml, @walls_top)
448
+ Geometry.set_zone_volumes(spaces, @hpxml_bldg, @apply_ashrae140_assumptions)
449
+ Geometry.explode_surfaces(model, @hpxml_bldg, @walls_top)
202
450
  add_num_occupants(model, runner, spaces)
203
451
 
204
452
  # HVAC
205
- @hvac_unavailable_periods = Schedule.get_unavailable_periods(runner, SchedulesFile::ColumnHVAC, @hpxml.header.unavailable_periods)
453
+ @hvac_unavailable_periods = Schedule.get_unavailable_periods(runner, SchedulesFile::ColumnHVAC, @hpxml_header.unavailable_periods)
206
454
  airloop_map = {} # Map of HPXML System ID -> AirLoopHVAC (or ZoneHVACFourPipeFanCoil)
207
455
  add_ideal_system(model, spaces, epw_path)
208
- add_cooling_system(model, spaces, airloop_map)
209
- add_heating_system(runner, model, spaces, airloop_map)
456
+ add_cooling_system(model, weather, spaces, airloop_map)
457
+ add_heating_system(runner, model, weather, spaces, airloop_map)
210
458
  add_heat_pump(runner, model, weather, spaces, airloop_map)
211
459
  add_dehumidifiers(runner, model, spaces)
212
460
  add_ceiling_fans(runner, model, weather, spaces)
@@ -219,8 +467,8 @@ class OSModel
219
467
  add_mfls(runner, model, spaces)
220
468
  add_lighting(runner, model, epw_file, spaces)
221
469
 
222
- # Pools & Hot Tubs
223
- add_pools_and_hot_tubs(runner, model, spaces)
470
+ # Pools & Permanent Spas
471
+ add_pools_and_permanent_spas(runner, model, spaces)
224
472
 
225
473
  # Other
226
474
  add_cooling_season(model, weather)
@@ -228,34 +476,13 @@ class OSModel
228
476
  add_photovoltaics(model)
229
477
  add_generators(model)
230
478
  add_batteries(runner, model, spaces)
231
- add_additional_properties(model, hpxml_path, building_id, epw_file)
232
-
233
- # Output
234
- add_unmet_hours_output(model, spaces)
235
- add_loads_output(model, spaces, add_component_loads)
236
- set_output_files(model)
237
- # Uncomment to debug EMS
238
- # add_ems_debug_output(model)
239
-
240
- if debug
241
- osm_output_path = File.join(output_dir, 'in.osm')
242
- File.write(osm_output_path, model.to_s)
243
- runner.registerInfo("Wrote file: #{osm_output_path}")
244
- end
479
+ add_building_unit(model, unit_num)
245
480
  end
246
481
 
247
- private
248
-
249
- def self.check_file_references(hpxml_path)
482
+ def check_emissions_references(hpxml_header, hpxml_path)
250
483
  # Check/update file references
251
- @hpxml.header.schedules_filepaths = @hpxml.header.schedules_filepaths.collect { |sfp|
252
- FilePath.check_path(sfp,
253
- File.dirname(hpxml_path),
254
- 'Schedules')
255
- }
256
-
257
- @hpxml.header.emissions_scenarios.each do |scenario|
258
- if @hpxml.header.emissions_scenarios.select { |s| s.emissions_type == scenario.emissions_type && s.name == scenario.name }.size > 1
484
+ hpxml_header.emissions_scenarios.each do |scenario|
485
+ if hpxml_header.emissions_scenarios.select { |s| s.emissions_type == scenario.emissions_type && s.name == scenario.name }.size > 1
259
486
  fail "Found multiple Emissions Scenarios with the Scenario Name=#{scenario.name} and Emissions Type=#{scenario.emissions_type}."
260
487
  end
261
488
  next if scenario.elec_schedule_filepath.nil?
@@ -266,8 +493,17 @@ class OSModel
266
493
  end
267
494
  end
268
495
 
269
- def self.validate_emissions_files()
270
- @hpxml.header.emissions_scenarios.each do |scenario|
496
+ def check_schedule_references(hpxml_bldg_header, hpxml_path)
497
+ # Check/update file references
498
+ hpxml_bldg_header.schedules_filepaths = hpxml_bldg_header.schedules_filepaths.collect { |sfp|
499
+ FilePath.check_path(sfp,
500
+ File.dirname(hpxml_path),
501
+ 'Schedules')
502
+ }
503
+ end
504
+
505
+ def validate_emissions_files(hpxml_header)
506
+ hpxml_header.emissions_scenarios.each do |scenario|
271
507
  next if scenario.elec_schedule_filepath.nil?
272
508
 
273
509
  data = File.readlines(scenario.elec_schedule_filepath)
@@ -283,76 +519,69 @@ class OSModel
283
519
  end
284
520
  end
285
521
 
286
- def self.set_defaults_and_globals(runner, output_dir, epw_file, weather, schedules_file)
522
+ def set_defaults_and_globals()
287
523
  # Initialize
288
524
  @remaining_heat_load_frac = 1.0
289
525
  @remaining_cool_load_frac = 1.0
290
526
 
291
527
  # Set globals
292
- @cfa = @hpxml.building_construction.conditioned_floor_area
293
- @ncfl = @hpxml.building_construction.number_of_conditioned_floors
294
- @ncfl_ag = @hpxml.building_construction.number_of_conditioned_floors_above_grade
295
- @nbeds = @hpxml.building_construction.number_of_bedrooms
296
- @default_azimuths = HPXMLDefaults.get_default_azimuths(@hpxml)
297
-
298
- # Apply defaults to HPXML object
299
- HPXMLDefaults.apply(runner, @hpxml, @eri_version, weather, epw_file: epw_file, schedules_file: schedules_file)
300
-
301
- # Write updated HPXML object (w/ defaults) to file for inspection
302
- @hpxml_defaults_path = File.join(output_dir, 'in.xml')
303
- XMLHelper.write_file(@hpxml.to_oga, @hpxml_defaults_path)
304
-
305
- # Now that we've written in.xml, ensure that no capacities/airflows
306
- # are zero in order to prevent potential E+ errors.
307
- HVAC.ensure_nonzero_sizing_values(@hpxml)
308
-
309
- # Now that we've written in.xml, make adjustments for modeling purposes.
310
- @frac_windows_operable = @hpxml.fraction_of_windows_operable()
311
- @hpxml.collapse_enclosure_surfaces() # Speeds up simulation
312
- @hpxml.delete_adiabatic_subsurfaces() # EnergyPlus doesn't allow this
528
+ @cfa = @hpxml_bldg.building_construction.conditioned_floor_area
529
+ @ncfl = @hpxml_bldg.building_construction.number_of_conditioned_floors
530
+ @ncfl_ag = @hpxml_bldg.building_construction.number_of_conditioned_floors_above_grade
531
+ @nbeds = @hpxml_bldg.building_construction.number_of_bedrooms
532
+ @default_azimuths = HPXMLDefaults.get_default_azimuths(@hpxml_bldg)
533
+
534
+ # Apply unit multipliers to HVAC systems and water heaters
535
+ HVAC.apply_unit_multiplier(@hpxml_bldg)
536
+ # Ensure that no capacities/airflows are zero in order to prevent potential E+ errors.
537
+ HVAC.ensure_nonzero_sizing_values(@hpxml_bldg)
538
+ # Make adjustments for modeling purposes
539
+ @frac_windows_operable = @hpxml_bldg.fraction_of_windows_operable()
540
+ @hpxml_bldg.collapse_enclosure_surfaces() # Speeds up simulation
541
+ @hpxml_bldg.delete_adiabatic_subsurfaces() # EnergyPlus doesn't allow this
313
542
 
314
543
  # We don't want this to be written to in.xml, because then if you ran the in.xml
315
544
  # file, you would get different results (operational calculation) relative to the
316
545
  # original file (asset calculation).
317
- if @hpxml.building_occupancy.number_of_residents.nil?
318
- @hpxml.building_occupancy.number_of_residents = Geometry.get_occupancy_default_num(@nbeds)
546
+ if @hpxml_bldg.building_occupancy.number_of_residents.nil?
547
+ @hpxml_bldg.building_occupancy.number_of_residents = Geometry.get_occupancy_default_num(@nbeds)
319
548
  end
320
549
 
321
550
  # If zero occupants, ensure end uses of interest are zeroed out
322
- if (@hpxml.building_occupancy.number_of_residents == 0) && (not @apply_ashrae140_assumptions)
323
- @hpxml.header.unavailable_periods.add(column_name: 'Vacancy',
324
- begin_month: @hpxml.header.sim_begin_month,
325
- begin_day: @hpxml.header.sim_begin_day,
551
+ if (@hpxml_bldg.building_occupancy.number_of_residents == 0) && (not @apply_ashrae140_assumptions)
552
+ @hpxml_header.unavailable_periods.add(column_name: 'Vacancy',
553
+ begin_month: @hpxml_header.sim_begin_month,
554
+ begin_day: @hpxml_header.sim_begin_day,
326
555
  begin_hour: 0,
327
- end_month: @hpxml.header.sim_end_month,
328
- end_day: @hpxml.header.sim_end_day,
556
+ end_month: @hpxml_header.sim_end_month,
557
+ end_day: @hpxml_header.sim_end_day,
329
558
  end_hour: 24,
330
559
  natvent_availability: HPXML::ScheduleUnavailable)
331
560
  end
332
561
  end
333
562
 
334
- def self.add_simulation_params(model)
335
- SimControls.apply(model, @hpxml)
563
+ def add_simulation_params(model)
564
+ SimControls.apply(model, @hpxml_header)
336
565
  end
337
566
 
338
- def self.add_num_occupants(model, runner, spaces)
567
+ def add_num_occupants(model, runner, spaces)
339
568
  # Occupants
340
- num_occ = @hpxml.building_occupancy.number_of_residents
569
+ num_occ = @hpxml_bldg.building_occupancy.number_of_residents
341
570
  return if num_occ <= 0
342
571
 
343
- Geometry.apply_occupants(model, runner, @hpxml, num_occ, spaces[HPXML::LocationLivingSpace],
344
- @schedules_file, @hpxml.header.unavailable_periods)
572
+ Geometry.apply_occupants(model, runner, @hpxml_bldg, num_occ, spaces[HPXML::LocationConditionedSpace],
573
+ @schedules_file, @hpxml_header.unavailable_periods)
345
574
  end
346
575
 
347
- def self.create_or_get_space(model, spaces, location)
576
+ def create_or_get_space(model, spaces, location)
348
577
  if spaces[location].nil?
349
- Geometry.create_space_and_zone(model, spaces, location)
578
+ Geometry.create_space_and_zone(model, spaces, location, @hpxml_bldg.building_construction.number_of_units)
350
579
  end
351
580
  return spaces[location]
352
581
  end
353
582
 
354
- def self.add_roofs(runner, model, spaces)
355
- @hpxml.roofs.each do |roof|
583
+ def add_roofs(runner, model, spaces)
584
+ @hpxml_bldg.roofs.each do |roof|
356
585
  next if roof.net_area < 1.0 # skip modeling net surface area for surfaces comprised entirely of subsurface area
357
586
 
358
587
  if roof.azimuth.nil?
@@ -463,8 +692,8 @@ class OSModel
463
692
  end
464
693
  end
465
694
 
466
- def self.add_walls(runner, model, spaces)
467
- @hpxml.walls.each do |wall|
695
+ def add_walls(runner, model, spaces)
696
+ @hpxml_bldg.walls.each do |wall|
468
697
  next if wall.net_area < 1.0 # skip modeling net surface area for surfaces comprised entirely of subsurface area
469
698
 
470
699
  if wall.azimuth.nil?
@@ -531,8 +760,8 @@ class OSModel
531
760
  end
532
761
  end
533
762
 
534
- def self.add_rim_joists(runner, model, spaces)
535
- @hpxml.rim_joists.each do |rim_joist|
763
+ def add_rim_joists(runner, model, spaces)
764
+ @hpxml_bldg.rim_joists.each do |rim_joist|
536
765
  if rim_joist.azimuth.nil?
537
766
  if rim_joist.is_exterior
538
767
  azimuths = @default_azimuths # Model as four directions for average exterior incident solar
@@ -603,8 +832,8 @@ class OSModel
603
832
  end
604
833
  end
605
834
 
606
- def self.add_floors(runner, model, spaces)
607
- @hpxml.floors.each do |floor|
835
+ def add_floors(runner, model, spaces)
836
+ @hpxml_bldg.floors.each do |floor|
608
837
  area = floor.area
609
838
  width = Math::sqrt(area)
610
839
  length = area / width
@@ -632,6 +861,12 @@ class OSModel
632
861
  surface.setWindExposure('NoWind')
633
862
  elsif floor.is_floor
634
863
  surface.setSunExposure('NoSun')
864
+ if floor.exterior_adjacent_to == HPXML::LocationManufacturedHomeUnderBelly
865
+ foundation = @hpxml_bldg.foundations.find { |x| x.to_location == floor.exterior_adjacent_to }
866
+ if foundation.belly_wing_skirt_present
867
+ surface.setWindExposure('NoWind')
868
+ end
869
+ end
635
870
  end
636
871
 
637
872
  # Apply construction
@@ -660,7 +895,7 @@ class OSModel
660
895
  else
661
896
  outside_film = Material.AirFilmFloorReduced
662
897
  end
663
- if floor.interior_adjacent_to == HPXML::LocationLivingSpace
898
+ if floor.interior_adjacent_to == HPXML::LocationConditionedSpace
664
899
  mat_int_finish_or_covering = Material.CoveringBare
665
900
  end
666
901
  end
@@ -671,116 +906,73 @@ class OSModel
671
906
  end
672
907
  end
673
908
 
674
- def self.add_foundation_walls_slabs(runner, model, weather, spaces)
675
- foundation_types = @hpxml.slabs.map { |s| s.interior_adjacent_to }.uniq
909
+ def add_foundation_walls_slabs(runner, model, weather, spaces)
910
+ foundation_types = @hpxml_bldg.slabs.map { |s| s.interior_adjacent_to }.uniq
676
911
 
677
912
  foundation_types.each do |foundation_type|
678
- # Get attached foundation walls/slabs
679
- fnd_walls = []
913
+ # Get attached slabs/foundation walls
680
914
  slabs = []
681
- @hpxml.foundation_walls.each do |foundation_wall|
682
- next unless foundation_wall.interior_adjacent_to == foundation_type
683
- next if foundation_wall.net_area < 1.0 # skip modeling net surface area for surfaces comprised entirely of subsurface area
684
-
685
- fnd_walls << foundation_wall
686
- end
687
- @hpxml.slabs.each do |slab|
915
+ @hpxml_bldg.slabs.each do |slab|
688
916
  next unless slab.interior_adjacent_to == foundation_type
689
917
 
690
918
  slabs << slab
691
919
  slab.exposed_perimeter = [slab.exposed_perimeter, 1.0].max # minimum value to prevent error if no exposed slab
692
920
  end
693
921
 
694
- # Calculate combinations of slabs/walls for each Kiva instance
695
- kiva_instances = get_kiva_instances(fnd_walls, slabs)
696
-
697
- # Obtain some wall/slab information
698
- fnd_wall_lengths = {}
699
- fnd_walls.each do |foundation_wall|
700
- next unless foundation_wall.is_exterior
701
-
702
- fnd_wall_lengths[foundation_wall] = foundation_wall.area / foundation_wall.height
703
- end
704
- slab_exp_perims = {}
705
- slab_areas = {}
706
922
  slabs.each do |slab|
707
- slab_exp_perims[slab] = slab.exposed_perimeter
708
- slab_areas[slab] = slab.area
709
- end
710
- total_slab_exp_perim = slab_exp_perims.values.sum(0.0)
711
- total_slab_area = slab_areas.values.sum(0.0)
712
- total_fnd_wall_length = fnd_wall_lengths.values.sum(0.0)
923
+ slab_frac = slab.exposed_perimeter / slabs.map { |s| s.exposed_perimeter }.sum
924
+ ext_fnd_walls = slab.connected_foundation_walls.select { |fw| fw.net_area >= 1.0 && fw.is_exterior }
713
925
 
714
- no_wall_slab_exp_perim = {}
715
-
716
- kiva_instances.each do |foundation_wall, slab|
717
- # Apportion referenced walls/slabs for this Kiva instance
718
- slab_frac = slab_exp_perims[slab] / total_slab_exp_perim
719
- if total_fnd_wall_length > 0
720
- fnd_wall_frac = fnd_wall_lengths[foundation_wall] / total_fnd_wall_length
926
+ if ext_fnd_walls.empty?
927
+ # Slab w/o foundation walls
928
+ add_foundation_slab(model, weather, spaces, slab, -1 * slab.depth_below_grade.to_f, slab.exposed_perimeter, nil)
721
929
  else
722
- fnd_wall_frac = 1.0 # Handle slab foundation type
723
- end
724
-
725
- kiva_foundation = nil
726
- if not foundation_wall.nil?
727
- # Add exterior foundation wall surface
728
- kiva_foundation = add_foundation_wall(runner, model, spaces, foundation_wall, slab_frac,
729
- total_fnd_wall_length, total_slab_exp_perim)
730
- end
930
+ # Slab w/ foundation walls
931
+ ext_fnd_walls_length = ext_fnd_walls.map { |fw| fw.area / fw.height }.sum
932
+ remaining_exposed_length = slab.exposed_perimeter
933
+
934
+ # Since we don't know which FoundationWalls are adjacent to which Slabs, we apportion
935
+ # each FoundationWall to each slab.
936
+ ext_fnd_walls.each do |fnd_wall|
937
+ # Both the foundation wall and slab must have same exposed length to prevent Kiva errors.
938
+ # For the foundation wall, we are effectively modeling the net *exposed* area.
939
+ fnd_wall_length = fnd_wall.area / fnd_wall.height
940
+ apportioned_exposed_length = fnd_wall_length / ext_fnd_walls_length * slab.exposed_perimeter # Slab exposed perimeter apportioned to this foundation wall
941
+ apportioned_total_length = fnd_wall_length * slab_frac # Foundation wall length apportioned to this slab
942
+ exposed_length = [apportioned_exposed_length, apportioned_total_length].min
943
+ remaining_exposed_length -= exposed_length
944
+
945
+ kiva_foundation = add_foundation_wall(runner, model, spaces, fnd_wall, exposed_length, fnd_wall_length)
946
+ add_foundation_slab(model, weather, spaces, slab, -1 * fnd_wall.depth_below_grade, exposed_length, kiva_foundation)
947
+ end
731
948
 
732
- # Add single combined foundation slab surface (for similar surfaces)
733
- slab_exp_perim = slab_exp_perims[slab] * fnd_wall_frac
734
- slab_area = slab_areas[slab] * fnd_wall_frac
735
- no_wall_slab_exp_perim[slab] = 0.0 if no_wall_slab_exp_perim[slab].nil?
736
- if (not foundation_wall.nil?) && (slab_exp_perim > fnd_wall_lengths[foundation_wall] * slab_frac)
737
- # Keep track of no-wall slab exposed perimeter
738
- no_wall_slab_exp_perim[slab] += (slab_exp_perim - fnd_wall_lengths[foundation_wall] * slab_frac)
739
-
740
- # Reduce this slab's exposed perimeter so that EnergyPlus does not automatically
741
- # create a second no-wall Kiva instance for each of our Kiva instances.
742
- # Instead, we will later create our own Kiva instance to account for it.
743
- # This reduces the number of Kiva instances we end up with.
744
- exp_perim_frac = (fnd_wall_lengths[foundation_wall] * slab_frac) / slab_exp_perim
745
- slab_exp_perim *= exp_perim_frac
746
- slab_area *= exp_perim_frac
747
- end
748
- if not foundation_wall.nil?
749
- z_origin = -1 * foundation_wall.depth_below_grade # Position based on adjacent foundation walls
750
- else
751
- z_origin = -1 * slab.depth_below_grade
949
+ if remaining_exposed_length > 1 # Skip if a small length (e.g., due to rounding)
950
+ # The slab's exposed perimeter exceeds the sum of attached exterior foundation wall lengths.
951
+ # This may legitimately occur for a walkout basement, where a portion of the slab has no
952
+ # adjacent foundation wall.
953
+ add_foundation_slab(model, weather, spaces, slab, 0, remaining_exposed_length, nil)
954
+ end
752
955
  end
753
- add_foundation_slab(model, weather, spaces, slab, slab_exp_perim,
754
- slab_area, z_origin, kiva_foundation)
755
- end
756
-
757
- # For each slab, create a no-wall Kiva slab instance if needed.
758
- slabs.each do |slab|
759
- next unless no_wall_slab_exp_perim[slab] > 1.0
760
-
761
- z_origin = 0
762
- slab_area = total_slab_area * no_wall_slab_exp_perim[slab] / total_slab_exp_perim
763
- add_foundation_slab(model, weather, spaces, slab, no_wall_slab_exp_perim[slab],
764
- slab_area, z_origin, nil)
765
956
  end
766
957
 
767
958
  # Interzonal foundation wall surfaces
768
959
  # The above-grade portion of these walls are modeled as EnergyPlus surfaces with standard adjacency.
769
960
  # The below-grade portion of these walls (in contact with ground) are not modeled, as Kiva does not
770
961
  # calculate heat flow between two zones through the ground.
771
- fnd_walls.each do |foundation_wall|
772
- next unless foundation_wall.is_interior
962
+ int_fnd_walls = @hpxml_bldg.foundation_walls.select { |fw| fw.is_interior && fw.interior_adjacent_to == foundation_type }
963
+ int_fnd_walls.each do |fnd_wall|
964
+ next unless fnd_wall.is_interior
773
965
 
774
- ag_height = foundation_wall.height - foundation_wall.depth_below_grade
775
- ag_net_area = foundation_wall.net_area * ag_height / foundation_wall.height
966
+ ag_height = fnd_wall.height - fnd_wall.depth_below_grade
967
+ ag_net_area = fnd_wall.net_area * ag_height / fnd_wall.height
776
968
  next if ag_net_area < 1.0
777
969
 
778
970
  length = ag_net_area / ag_height
779
971
  z_origin = -1 * ag_height
780
- if foundation_wall.azimuth.nil?
972
+ if fnd_wall.azimuth.nil?
781
973
  azimuth = @default_azimuths[0] # Arbitrary direction, doesn't receive exterior incident solar
782
974
  else
783
- azimuth = foundation_wall.azimuth
975
+ azimuth = fnd_wall.azimuth
784
976
  end
785
977
 
786
978
  vertices = Geometry.create_wall_vertices(length, ag_height, z_origin, azimuth)
@@ -789,10 +981,10 @@ class OSModel
789
981
  surface.additionalProperties.setFeature('Azimuth', azimuth)
790
982
  surface.additionalProperties.setFeature('Tilt', 90.0)
791
983
  surface.additionalProperties.setFeature('SurfaceType', 'FoundationWall')
792
- surface.setName(foundation_wall.id)
984
+ surface.setName(fnd_wall.id)
793
985
  surface.setSurfaceType('Wall')
794
- set_surface_interior(model, spaces, surface, foundation_wall)
795
- set_surface_exterior(model, spaces, surface, foundation_wall)
986
+ set_surface_interior(model, spaces, surface, fnd_wall)
987
+ set_surface_exterior(model, spaces, surface, fnd_wall)
796
988
  surface.setSunExposure('NoSun')
797
989
  surface.setWindExposure('NoWind')
798
990
 
@@ -801,57 +993,50 @@ class OSModel
801
993
  wall_type = HPXML::WallTypeConcrete
802
994
  inside_film = Material.AirFilmVertical
803
995
  outside_film = Material.AirFilmVertical
804
- assembly_r = foundation_wall.insulation_assembly_r_value
805
- mat_int_finish = Material.InteriorFinishMaterial(foundation_wall.interior_finish_type, foundation_wall.interior_finish_thickness)
996
+ assembly_r = fnd_wall.insulation_assembly_r_value
997
+ mat_int_finish = Material.InteriorFinishMaterial(fnd_wall.interior_finish_type, fnd_wall.interior_finish_thickness)
806
998
  if assembly_r.nil?
807
- concrete_thick_in = foundation_wall.thickness
808
- int_r = foundation_wall.insulation_interior_r_value
809
- ext_r = foundation_wall.insulation_exterior_r_value
999
+ concrete_thick_in = fnd_wall.thickness
1000
+ int_r = fnd_wall.insulation_interior_r_value
1001
+ ext_r = fnd_wall.insulation_exterior_r_value
810
1002
  mat_concrete = Material.Concrete(concrete_thick_in)
811
1003
  mat_int_finish_rvalue = mat_int_finish.nil? ? 0.0 : mat_int_finish.rvalue
812
1004
  assembly_r = int_r + ext_r + mat_concrete.rvalue + mat_int_finish_rvalue + inside_film.rvalue + outside_film.rvalue
813
1005
  end
814
1006
  mat_ext_finish = nil
815
1007
 
816
- Constructions.apply_wall_construction(runner, model, [surface], foundation_wall.id, wall_type, assembly_r,
1008
+ Constructions.apply_wall_construction(runner, model, [surface], fnd_wall.id, wall_type, assembly_r,
817
1009
  mat_int_finish, inside_film, outside_film, mat_ext_finish, nil, nil)
818
1010
  end
819
1011
  end
820
1012
  end
821
1013
 
822
- def self.add_foundation_wall(runner, model, spaces, foundation_wall, slab_frac,
823
- total_fnd_wall_length, total_slab_exp_perim)
824
-
825
- net_area = foundation_wall.net_area * slab_frac
826
- gross_area = foundation_wall.area * slab_frac
1014
+ def add_foundation_wall(runner, model, spaces, foundation_wall, exposed_length, fnd_wall_length)
1015
+ exposed_fraction = exposed_length / fnd_wall_length
1016
+ net_exposed_area = foundation_wall.net_area * exposed_fraction
1017
+ gross_exposed_area = foundation_wall.area * exposed_fraction
827
1018
  height = foundation_wall.height
828
1019
  height_ag = height - foundation_wall.depth_below_grade
829
1020
  z_origin = -1 * foundation_wall.depth_below_grade
830
- length = gross_area / height
831
1021
  if foundation_wall.azimuth.nil?
832
1022
  azimuth = @default_azimuths[0] # Arbitrary; solar incidence in Kiva is applied as an orientation average (to the above grade portion of the wall)
833
1023
  else
834
1024
  azimuth = foundation_wall.azimuth
835
1025
  end
836
1026
 
837
- if total_fnd_wall_length > total_slab_exp_perim
838
- # Calculate exposed section of wall based on slab's total exposed perimeter.
839
- length *= total_slab_exp_perim / total_fnd_wall_length
840
- end
1027
+ return if exposed_length < 0.1 # Avoid Kiva error if exposed wall length is too small
841
1028
 
842
- return if length < 0.1 # Avoid Kiva error if exposed wall length is too small
843
-
844
- if gross_area > net_area
1029
+ if gross_exposed_area > net_exposed_area
845
1030
  # Create a "notch" in the wall to account for the subsurfaces. This ensures that
846
1031
  # we preserve the appropriate wall height, length, and area for Kiva.
847
- subsurface_area = gross_area - net_area
1032
+ subsurface_area = gross_exposed_area - net_exposed_area
848
1033
  else
849
1034
  subsurface_area = 0
850
1035
  end
851
1036
 
852
- vertices = Geometry.create_wall_vertices(length, height, z_origin, azimuth, subsurface_area: subsurface_area)
1037
+ vertices = Geometry.create_wall_vertices(exposed_length, height, z_origin, azimuth, subsurface_area: subsurface_area)
853
1038
  surface = OpenStudio::Model::Surface.new(vertices, model)
854
- surface.additionalProperties.setFeature('Length', length)
1039
+ surface.additionalProperties.setFeature('Length', exposed_length)
855
1040
  surface.additionalProperties.setFeature('Azimuth', azimuth)
856
1041
  surface.additionalProperties.setFeature('Tilt', 90.0)
857
1042
  surface.additionalProperties.setFeature('SurfaceType', 'FoundationWall')
@@ -893,7 +1078,7 @@ class OSModel
893
1078
  int_rigid_r = foundation_wall.insulation_interior_r_value
894
1079
  end
895
1080
 
896
- soil_k_in = UnitConversions.convert(@hpxml.site.ground_conductivity, 'ft', 'in')
1081
+ soil_k_in = UnitConversions.convert(@hpxml_bldg.site.ground_conductivity, 'ft', 'in')
897
1082
 
898
1083
  Constructions.apply_foundation_wall(model, [surface], "#{foundation_wall.id} construction",
899
1084
  ext_rigid_offset, int_rigid_offset, ext_rigid_height, int_rigid_height,
@@ -907,10 +1092,10 @@ class OSModel
907
1092
  return surface.adjacentFoundation.get
908
1093
  end
909
1094
 
910
- def self.add_foundation_slab(model, weather, spaces, slab, slab_exp_perim,
911
- slab_area, z_origin, kiva_foundation)
912
-
913
- slab_tot_perim = slab_exp_perim
1095
+ def add_foundation_slab(model, weather, spaces, slab, z_origin, exposed_length, kiva_foundation)
1096
+ exposed_fraction = exposed_length / slab.exposed_perimeter
1097
+ slab_tot_perim = exposed_length
1098
+ slab_area = slab.area * exposed_fraction
914
1099
  if slab_tot_perim**2 - 16.0 * slab_area <= 0
915
1100
  # Cannot construct rectangle with this perimeter/area. Some of the
916
1101
  # perimeter is presumably not exposed, so bump up perimeter value.
@@ -961,18 +1146,18 @@ class OSModel
961
1146
  mat_carpet = Material.CoveringBare(slab.carpet_fraction,
962
1147
  slab.carpet_r_value)
963
1148
  end
964
- soil_k_in = UnitConversions.convert(@hpxml.site.ground_conductivity, 'ft', 'in')
1149
+ soil_k_in = UnitConversions.convert(@hpxml_bldg.site.ground_conductivity, 'ft', 'in')
965
1150
 
966
1151
  Constructions.apply_foundation_slab(model, surface, "#{slab.id} construction",
967
1152
  slab_under_r, slab_under_width, slab_gap_r, slab_perim_r,
968
1153
  slab_perim_depth, slab_whole_r, slab.thickness,
969
- slab_exp_perim, mat_carpet, soil_k_in, kiva_foundation)
1154
+ exposed_length, mat_carpet, soil_k_in, kiva_foundation)
970
1155
 
971
1156
  kiva_foundation = surface.adjacentFoundation.get
972
1157
 
973
1158
  foundation_walls_insulated = false
974
1159
  foundation_ceiling_insulated = false
975
- @hpxml.foundation_walls.each do |fnd_wall|
1160
+ @hpxml_bldg.foundation_walls.each do |fnd_wall|
976
1161
  next unless fnd_wall.interior_adjacent_to == slab.interior_adjacent_to
977
1162
  next unless fnd_wall.exterior_adjacent_to == HPXML::LocationGround
978
1163
 
@@ -982,8 +1167,8 @@ class OSModel
982
1167
  foundation_walls_insulated = true
983
1168
  end
984
1169
  end
985
- @hpxml.floors.each do |floor|
986
- next unless floor.interior_adjacent_to == HPXML::LocationLivingSpace
1170
+ @hpxml_bldg.floors.each do |floor|
1171
+ next unless floor.interior_adjacent_to == HPXML::LocationConditionedSpace
987
1172
  next unless floor.exterior_adjacent_to == slab.interior_adjacent_to
988
1173
 
989
1174
  if floor.insulation_assembly_r_value > 5
@@ -992,29 +1177,29 @@ class OSModel
992
1177
  end
993
1178
 
994
1179
  Constructions.apply_kiva_initial_temp(kiva_foundation, slab, weather,
995
- spaces[HPXML::LocationLivingSpace].thermalZone.get,
996
- @hpxml.header.sim_begin_month, @hpxml.header.sim_begin_day,
997
- @hpxml.header.sim_calendar_year, @schedules_file,
1180
+ spaces[HPXML::LocationConditionedSpace].thermalZone.get,
1181
+ @hpxml_header.sim_begin_month, @hpxml_header.sim_begin_day,
1182
+ @hpxml_header.sim_calendar_year, @schedules_file,
998
1183
  foundation_walls_insulated, foundation_ceiling_insulated)
999
1184
 
1000
1185
  return kiva_foundation
1001
1186
  end
1002
1187
 
1003
- def self.add_conditioned_floor_area(model, spaces)
1188
+ def add_conditioned_floor_area(model, spaces)
1004
1189
  # Check if we need to add floors between conditioned spaces (e.g., between first
1005
1190
  # and second story or conditioned basement ceiling).
1006
1191
  # This ensures that the E+ reported Conditioned Floor Area is correct.
1007
1192
 
1008
1193
  sum_cfa = 0.0
1009
- @hpxml.floors.each do |floor|
1194
+ @hpxml_bldg.floors.each do |floor|
1010
1195
  next unless floor.is_floor
1011
- next unless [HPXML::LocationLivingSpace, HPXML::LocationBasementConditioned].include?(floor.interior_adjacent_to) ||
1012
- [HPXML::LocationLivingSpace, HPXML::LocationBasementConditioned].include?(floor.exterior_adjacent_to)
1196
+ next unless [HPXML::LocationConditionedSpace, HPXML::LocationBasementConditioned].include?(floor.interior_adjacent_to) ||
1197
+ [HPXML::LocationConditionedSpace, HPXML::LocationBasementConditioned].include?(floor.exterior_adjacent_to)
1013
1198
 
1014
1199
  sum_cfa += floor.area
1015
1200
  end
1016
- @hpxml.slabs.each do |slab|
1017
- next unless [HPXML::LocationLivingSpace, HPXML::LocationBasementConditioned].include? slab.interior_adjacent_to
1201
+ @hpxml_bldg.slabs.each do |slab|
1202
+ next unless [HPXML::LocationConditionedSpace, HPXML::LocationBasementConditioned].include? slab.interior_adjacent_to
1018
1203
 
1019
1204
  sum_cfa += slab.area
1020
1205
  end
@@ -1037,7 +1222,7 @@ class OSModel
1037
1222
  floor_surface.setWindExposure('NoWind')
1038
1223
  floor_surface.setName('inferred conditioned floor')
1039
1224
  floor_surface.setSurfaceType('Floor')
1040
- floor_surface.setSpace(create_or_get_space(model, spaces, HPXML::LocationLivingSpace))
1225
+ floor_surface.setSpace(create_or_get_space(model, spaces, HPXML::LocationConditionedSpace))
1041
1226
  floor_surface.setOutsideBoundaryCondition('Adiabatic')
1042
1227
  floor_surface.additionalProperties.setFeature('SurfaceType', 'InferredFloor')
1043
1228
  floor_surface.additionalProperties.setFeature('Tilt', 0.0)
@@ -1050,7 +1235,7 @@ class OSModel
1050
1235
  ceiling_surface.setWindExposure('NoWind')
1051
1236
  ceiling_surface.setName('inferred conditioned ceiling')
1052
1237
  ceiling_surface.setSurfaceType('RoofCeiling')
1053
- ceiling_surface.setSpace(create_or_get_space(model, spaces, HPXML::LocationLivingSpace))
1238
+ ceiling_surface.setSpace(create_or_get_space(model, spaces, HPXML::LocationConditionedSpace))
1054
1239
  ceiling_surface.setOutsideBoundaryCondition('Adiabatic')
1055
1240
  ceiling_surface.additionalProperties.setFeature('SurfaceType', 'InferredCeiling')
1056
1241
  ceiling_surface.additionalProperties.setFeature('Tilt', 0.0)
@@ -1059,22 +1244,22 @@ class OSModel
1059
1244
  apply_adiabatic_construction(model, [floor_surface, ceiling_surface], 'floor')
1060
1245
  end
1061
1246
 
1062
- def self.add_thermal_mass(model, spaces)
1247
+ def add_thermal_mass(model, spaces)
1063
1248
  if @apply_ashrae140_assumptions
1064
1249
  # 1024 ft2 of interior partition wall mass, no furniture mass
1065
1250
  mat_int_finish = Material.InteriorFinishMaterial(HPXML::InteriorFinishGypsumBoard, 0.5)
1066
1251
  partition_wall_area = 1024.0 * 2 # Exposed partition wall area (both sides)
1067
1252
  Constructions.apply_partition_walls(model, 'PartitionWallConstruction', mat_int_finish, partition_wall_area, spaces)
1068
1253
  else
1069
- mat_int_finish = Material.InteriorFinishMaterial(@hpxml.partition_wall_mass.interior_finish_type, @hpxml.partition_wall_mass.interior_finish_thickness)
1070
- partition_wall_area = @hpxml.partition_wall_mass.area_fraction * @cfa # Exposed partition wall area (both sides)
1254
+ mat_int_finish = Material.InteriorFinishMaterial(@hpxml_bldg.partition_wall_mass.interior_finish_type, @hpxml_bldg.partition_wall_mass.interior_finish_thickness)
1255
+ partition_wall_area = @hpxml_bldg.partition_wall_mass.area_fraction * @cfa # Exposed partition wall area (both sides)
1071
1256
  Constructions.apply_partition_walls(model, 'PartitionWallConstruction', mat_int_finish, partition_wall_area, spaces)
1072
1257
 
1073
- Constructions.apply_furniture(model, @hpxml.furniture_mass, spaces)
1258
+ Constructions.apply_furniture(model, @hpxml_bldg.furniture_mass, spaces)
1074
1259
  end
1075
1260
  end
1076
1261
 
1077
- def self.add_cooling_season(model, weather)
1262
+ def add_cooling_season(model, weather)
1078
1263
  # Create cooling season schedule
1079
1264
  # Applies to natural ventilation and calculation of component loads, not HVAC equipment
1080
1265
  # Uses BAHSP cooling season, not user-specified cooling season (which may be, e.g., year-round)
@@ -1086,22 +1271,20 @@ class OSModel
1086
1271
  @clg_ssn_sensor.setKeyName(clg_season_sch.schedule.name.to_s)
1087
1272
  end
1088
1273
 
1089
- def self.add_windows(model, spaces)
1274
+ def add_windows(model, spaces)
1090
1275
  # We already stored @fraction_of_windows_operable, so lets remove the
1091
1276
  # fraction_operable properties from windows and re-collapse the enclosure
1092
1277
  # so as to prevent potentially modeling multiple identical windows in E+,
1093
1278
  # which can increase simulation runtime.
1094
- @hpxml.windows.each do |window|
1279
+ @hpxml_bldg.windows.each do |window|
1095
1280
  window.fraction_operable = nil
1096
1281
  end
1097
- @hpxml.collapse_enclosure_surfaces()
1282
+ @hpxml_bldg.collapse_enclosure_surfaces()
1098
1283
 
1099
- shading_group = nil
1100
1284
  shading_schedules = {}
1101
- shading_ems = { sensors: {}, program: nil }
1102
1285
 
1103
1286
  surfaces = []
1104
- @hpxml.windows.each_with_index do |window, i|
1287
+ @hpxml_bldg.windows.each do |window|
1105
1288
  window_height = 4.0 # ft, default
1106
1289
 
1107
1290
  overhang_depth = nil
@@ -1142,16 +1325,14 @@ class OSModel
1142
1325
 
1143
1326
  if not overhang_depth.nil?
1144
1327
  overhang = sub_surface.addOverhang(UnitConversions.convert(overhang_depth, 'ft', 'm'), UnitConversions.convert(overhang_distance_to_top, 'ft', 'm'))
1145
- overhang.get.setName("#{sub_surface.name} - #{Constants.ObjectNameOverhangs}")
1328
+ overhang.get.setName("#{sub_surface.name} overhangs")
1146
1329
  end
1147
1330
 
1148
1331
  # Apply construction
1149
1332
  Constructions.apply_window(model, sub_surface, 'WindowConstruction', ufactor, shgc)
1150
1333
 
1151
1334
  # Apply interior/exterior shading (as needed)
1152
- shading_vertices = Geometry.create_wall_vertices(window_length, window_height, z_origin, window.azimuth)
1153
- shading_group = Constructions.apply_window_skylight_shading(model, window, i, shading_vertices, surface, sub_surface, shading_group,
1154
- shading_schedules, shading_ems, Constants.ObjectNameWindowShade, @hpxml)
1335
+ Constructions.apply_window_skylight_shading(model, window, sub_surface, shading_schedules, @hpxml_header, @hpxml_bldg)
1155
1336
  else
1156
1337
  # Window is on an interior surface, which E+ does not allow. Model
1157
1338
  # as a door instead so that we can get the appropriate conduction
@@ -1188,14 +1369,11 @@ class OSModel
1188
1369
  apply_adiabatic_construction(model, surfaces, 'wall')
1189
1370
  end
1190
1371
 
1191
- def self.add_skylights(model, spaces)
1372
+ def add_skylights(model, spaces)
1192
1373
  surfaces = []
1193
-
1194
- shading_group = nil
1195
1374
  shading_schedules = {}
1196
- shading_ems = { sensors: {}, program: nil }
1197
1375
 
1198
- @hpxml.skylights.each_with_index do |skylight, i|
1376
+ @hpxml_bldg.skylights.each do |skylight|
1199
1377
  tilt = skylight.roof.pitch / 12.0
1200
1378
  width = Math::sqrt(skylight.area)
1201
1379
  length = skylight.area / width
@@ -1213,7 +1391,7 @@ class OSModel
1213
1391
  surface.additionalProperties.setFeature('SurfaceType', 'Skylight')
1214
1392
  surface.setName("surface #{skylight.id}")
1215
1393
  surface.setSurfaceType('RoofCeiling')
1216
- surface.setSpace(create_or_get_space(model, spaces, HPXML::LocationLivingSpace)) # Ensures it is included in Manual J sizing
1394
+ surface.setSpace(create_or_get_space(model, spaces, HPXML::LocationConditionedSpace)) # Ensures it is included in Manual J sizing
1217
1395
  surface.setOutsideBoundaryCondition('Outdoors') # cannot be adiabatic because subsurfaces won't be created
1218
1396
  surfaces << surface
1219
1397
 
@@ -1227,17 +1405,15 @@ class OSModel
1227
1405
  Constructions.apply_skylight(model, sub_surface, 'SkylightConstruction', ufactor, shgc)
1228
1406
 
1229
1407
  # Apply interior/exterior shading (as needed)
1230
- shading_vertices = Geometry.create_roof_vertices(length, width, z_origin, skylight.azimuth, tilt)
1231
- shading_group = Constructions.apply_window_skylight_shading(model, skylight, i, shading_vertices, surface, sub_surface, shading_group,
1232
- shading_schedules, shading_ems, Constants.ObjectNameSkylightShade, @hpxml)
1408
+ Constructions.apply_window_skylight_shading(model, skylight, sub_surface, shading_schedules, @hpxml_header, @hpxml_bldg)
1233
1409
  end
1234
1410
 
1235
1411
  apply_adiabatic_construction(model, surfaces, 'roof')
1236
1412
  end
1237
1413
 
1238
- def self.add_doors(model, spaces)
1414
+ def add_doors(model, spaces)
1239
1415
  surfaces = []
1240
- @hpxml.doors.each do |door|
1416
+ @hpxml_bldg.doors.each do |door|
1241
1417
  door_height = 6.67 # ft
1242
1418
  door_length = door.area / door_height
1243
1419
  z_origin = @foundation_top
@@ -1277,7 +1453,7 @@ class OSModel
1277
1453
  apply_adiabatic_construction(model, surfaces, 'wall')
1278
1454
  end
1279
1455
 
1280
- def self.apply_adiabatic_construction(model, surfaces, type)
1456
+ def apply_adiabatic_construction(model, surfaces, type)
1281
1457
  # Arbitrary construction for heat capacitance.
1282
1458
  # Only applies to surfaces where outside boundary conditioned is
1283
1459
  # adiabatic or surface net area is near zero.
@@ -1302,80 +1478,81 @@ class OSModel
1302
1478
  end
1303
1479
  end
1304
1480
 
1305
- def self.add_hot_water_and_appliances(runner, model, weather, spaces)
1481
+ def add_hot_water_and_appliances(runner, model, weather, spaces)
1306
1482
  # Assign spaces
1307
- @hpxml.clothes_washers.each do |clothes_washer|
1483
+ @hpxml_bldg.clothes_washers.each do |clothes_washer|
1308
1484
  clothes_washer.additional_properties.space = get_space_from_location(clothes_washer.location, spaces)
1309
1485
  end
1310
- @hpxml.clothes_dryers.each do |clothes_dryer|
1486
+ @hpxml_bldg.clothes_dryers.each do |clothes_dryer|
1311
1487
  clothes_dryer.additional_properties.space = get_space_from_location(clothes_dryer.location, spaces)
1312
1488
  end
1313
- @hpxml.dishwashers.each do |dishwasher|
1489
+ @hpxml_bldg.dishwashers.each do |dishwasher|
1314
1490
  dishwasher.additional_properties.space = get_space_from_location(dishwasher.location, spaces)
1315
1491
  end
1316
- @hpxml.refrigerators.each do |refrigerator|
1492
+ @hpxml_bldg.refrigerators.each do |refrigerator|
1317
1493
  refrigerator.additional_properties.space = get_space_from_location(refrigerator.location, spaces)
1318
1494
  end
1319
- @hpxml.freezers.each do |freezer|
1495
+ @hpxml_bldg.freezers.each do |freezer|
1320
1496
  freezer.additional_properties.space = get_space_from_location(freezer.location, spaces)
1321
1497
  end
1322
- @hpxml.cooking_ranges.each do |cooking_range|
1498
+ @hpxml_bldg.cooking_ranges.each do |cooking_range|
1323
1499
  cooking_range.additional_properties.space = get_space_from_location(cooking_range.location, spaces)
1324
1500
  end
1325
1501
 
1326
1502
  # Distribution
1327
- if @hpxml.water_heating_systems.size > 0
1328
- hot_water_distribution = @hpxml.hot_water_distributions[0]
1503
+ if @hpxml_bldg.water_heating_systems.size > 0
1504
+ hot_water_distribution = @hpxml_bldg.hot_water_distributions[0]
1329
1505
  end
1330
1506
 
1331
1507
  # Solar thermal system
1332
1508
  solar_thermal_system = nil
1333
- if @hpxml.solar_thermal_systems.size > 0
1334
- solar_thermal_system = @hpxml.solar_thermal_systems[0]
1509
+ if @hpxml_bldg.solar_thermal_systems.size > 0
1510
+ solar_thermal_system = @hpxml_bldg.solar_thermal_systems[0]
1335
1511
  end
1336
1512
 
1337
1513
  # Water Heater
1338
- unavailable_periods = Schedule.get_unavailable_periods(runner, SchedulesFile::ColumnWaterHeater, @hpxml.header.unavailable_periods)
1339
- has_uncond_bsmnt = @hpxml.has_location(HPXML::LocationBasementUnconditioned)
1514
+ unavailable_periods = Schedule.get_unavailable_periods(runner, SchedulesFile::ColumnWaterHeater, @hpxml_header.unavailable_periods)
1515
+ unit_multiplier = @hpxml_bldg.building_construction.number_of_units
1516
+ has_uncond_bsmnt = @hpxml_bldg.has_location(HPXML::LocationBasementUnconditioned)
1340
1517
  plantloop_map = {}
1341
- @hpxml.water_heating_systems.each do |water_heating_system|
1518
+ @hpxml_bldg.water_heating_systems.each do |water_heating_system|
1342
1519
  loc_space, loc_schedule = get_space_or_schedule_from_location(water_heating_system.location, model, spaces)
1343
1520
 
1344
1521
  ec_adj = HotWaterAndAppliances.get_dist_energy_consumption_adjustment(has_uncond_bsmnt, @cfa, @ncfl, water_heating_system, hot_water_distribution)
1345
1522
 
1346
1523
  sys_id = water_heating_system.id
1347
1524
  if water_heating_system.water_heater_type == HPXML::WaterHeaterTypeStorage
1348
- plantloop_map[sys_id] = Waterheater.apply_tank(model, runner, loc_space, loc_schedule, water_heating_system, ec_adj, solar_thermal_system, @eri_version, @schedules_file, unavailable_periods)
1525
+ plantloop_map[sys_id] = Waterheater.apply_tank(model, runner, loc_space, loc_schedule, water_heating_system, ec_adj, solar_thermal_system, @eri_version, @schedules_file, unavailable_periods, unit_multiplier)
1349
1526
  elsif water_heating_system.water_heater_type == HPXML::WaterHeaterTypeTankless
1350
- plantloop_map[sys_id] = Waterheater.apply_tankless(model, runner, loc_space, loc_schedule, water_heating_system, ec_adj, solar_thermal_system, @eri_version, @schedules_file, unavailable_periods)
1527
+ plantloop_map[sys_id] = Waterheater.apply_tankless(model, runner, loc_space, loc_schedule, water_heating_system, ec_adj, solar_thermal_system, @eri_version, @schedules_file, unavailable_periods, unit_multiplier)
1351
1528
  elsif water_heating_system.water_heater_type == HPXML::WaterHeaterTypeHeatPump
1352
- living_zone = spaces[HPXML::LocationLivingSpace].thermalZone.get
1353
- plantloop_map[sys_id] = Waterheater.apply_heatpump(model, runner, loc_space, loc_schedule, weather, water_heating_system, ec_adj, solar_thermal_system, living_zone, @eri_version, @schedules_file, unavailable_periods)
1529
+ conditioned_zone = spaces[HPXML::LocationConditionedSpace].thermalZone.get
1530
+ plantloop_map[sys_id] = Waterheater.apply_heatpump(model, runner, loc_space, loc_schedule, weather, water_heating_system, ec_adj, solar_thermal_system, conditioned_zone, @eri_version, @schedules_file, unavailable_periods, unit_multiplier)
1354
1531
  elsif [HPXML::WaterHeaterTypeCombiStorage, HPXML::WaterHeaterTypeCombiTankless].include? water_heating_system.water_heater_type
1355
- plantloop_map[sys_id] = Waterheater.apply_combi(model, runner, loc_space, loc_schedule, water_heating_system, ec_adj, solar_thermal_system, @eri_version, @schedules_file, unavailable_periods)
1532
+ plantloop_map[sys_id] = Waterheater.apply_combi(model, runner, loc_space, loc_schedule, water_heating_system, ec_adj, solar_thermal_system, @eri_version, @schedules_file, unavailable_periods, unit_multiplier)
1356
1533
  else
1357
1534
  fail "Unhandled water heater (#{water_heating_system.water_heater_type})."
1358
1535
  end
1359
1536
  end
1360
1537
 
1361
1538
  # Hot water fixtures and appliances
1362
- HotWaterAndAppliances.apply(model, runner, @hpxml, weather, spaces, hot_water_distribution,
1539
+ HotWaterAndAppliances.apply(model, runner, @hpxml_header, @hpxml_bldg, weather, spaces, hot_water_distribution,
1363
1540
  solar_thermal_system, @eri_version, @schedules_file, plantloop_map,
1364
- @hpxml.header.unavailable_periods)
1541
+ @hpxml_header.unavailable_periods, @hpxml_bldg.building_construction.number_of_units)
1365
1542
 
1366
1543
  if (not solar_thermal_system.nil?) && (not solar_thermal_system.collector_area.nil?) # Detailed solar water heater
1367
1544
  loc_space, loc_schedule = get_space_or_schedule_from_location(solar_thermal_system.water_heating_system.location, model, spaces)
1368
- Waterheater.apply_solar_thermal(model, loc_space, loc_schedule, solar_thermal_system, plantloop_map)
1545
+ Waterheater.apply_solar_thermal(model, loc_space, loc_schedule, solar_thermal_system, plantloop_map, unit_multiplier)
1369
1546
  end
1370
1547
 
1371
1548
  # Add combi-system EMS program with water use equipment information
1372
- Waterheater.apply_combi_system_EMS(model, @hpxml.water_heating_systems, plantloop_map)
1549
+ Waterheater.apply_combi_system_EMS(model, @hpxml_bldg.water_heating_systems, plantloop_map)
1373
1550
  end
1374
1551
 
1375
- def self.add_cooling_system(model, spaces, airloop_map)
1376
- living_zone = spaces[HPXML::LocationLivingSpace].thermalZone.get
1552
+ def add_cooling_system(model, weather, spaces, airloop_map)
1553
+ conditioned_zone = spaces[HPXML::LocationConditionedSpace].thermalZone.get
1377
1554
 
1378
- HVAC.get_hpxml_hvac_systems(@hpxml).each do |hvac_system|
1555
+ HVAC.get_hpxml_hvac_systems(@hpxml_bldg).each do |hvac_system|
1379
1556
  next if hvac_system[:cooling].nil?
1380
1557
  next unless hvac_system[:cooling].is_a? HPXML::CoolingSystem
1381
1558
 
@@ -1405,22 +1582,23 @@ class OSModel
1405
1582
  HPXML::HVACTypeMiniSplitAirConditioner,
1406
1583
  HPXML::HVACTypePTAC].include? cooling_system.cooling_system_type
1407
1584
 
1408
- airloop_map[sys_id] = HVAC.apply_air_source_hvac_systems(model, cooling_system, heating_system,
1409
- sequential_cool_load_fracs, sequential_heat_load_fracs,
1410
- living_zone, @hvac_unavailable_periods)
1585
+ airloop_map[sys_id] = HVAC.apply_air_source_hvac_systems(model, cooling_system, heating_system, sequential_cool_load_fracs, sequential_heat_load_fracs,
1586
+ weather.data.AnnualMaxDrybulb, weather.data.AnnualMinDrybulb,
1587
+ conditioned_zone, @hvac_unavailable_periods)
1411
1588
 
1412
1589
  elsif [HPXML::HVACTypeEvaporativeCooler].include? cooling_system.cooling_system_type
1413
1590
 
1414
- airloop_map[sys_id] = HVAC.apply_evaporative_cooler(model, cooling_system,
1415
- sequential_cool_load_fracs, living_zone, @hvac_unavailable_periods)
1591
+ airloop_map[sys_id] = HVAC.apply_evaporative_cooler(model, cooling_system, sequential_cool_load_fracs,
1592
+ conditioned_zone, @hvac_unavailable_periods,
1593
+ @hpxml_bldg.building_construction.number_of_units)
1416
1594
  end
1417
1595
  end
1418
1596
  end
1419
1597
 
1420
- def self.add_heating_system(runner, model, spaces, airloop_map)
1421
- living_zone = spaces[HPXML::LocationLivingSpace].thermalZone.get
1598
+ def add_heating_system(runner, model, weather, spaces, airloop_map)
1599
+ conditioned_zone = spaces[HPXML::LocationConditionedSpace].thermalZone.get
1422
1600
 
1423
- HVAC.get_hpxml_hvac_systems(@hpxml).each do |hvac_system|
1601
+ HVAC.get_hpxml_hvac_systems(@hpxml_bldg).each do |hvac_system|
1424
1602
  next if hvac_system[:heating].nil?
1425
1603
  next unless hvac_system[:heating].is_a? HPXML::HeatingSystem
1426
1604
 
@@ -1449,43 +1627,42 @@ class OSModel
1449
1627
  sys_id = heating_system.id
1450
1628
  if [HPXML::HVACTypeFurnace].include? heating_system.heating_system_type
1451
1629
 
1452
- airloop_map[sys_id] = HVAC.apply_air_source_hvac_systems(model, nil, heating_system,
1453
- [0], sequential_heat_load_fracs,
1454
- living_zone, @hvac_unavailable_periods)
1630
+ airloop_map[sys_id] = HVAC.apply_air_source_hvac_systems(model, nil, heating_system, [0], sequential_heat_load_fracs,
1631
+ weather.data.AnnualMaxDrybulb, weather.data.AnnualMinDrybulb,
1632
+ conditioned_zone, @hvac_unavailable_periods)
1455
1633
 
1456
1634
  elsif [HPXML::HVACTypeBoiler].include? heating_system.heating_system_type
1457
1635
 
1458
- airloop_map[sys_id] = HVAC.apply_boiler(model, runner, heating_system,
1459
- sequential_heat_load_fracs, living_zone, @hvac_unavailable_periods)
1636
+ airloop_map[sys_id] = HVAC.apply_boiler(model, runner, heating_system, sequential_heat_load_fracs, conditioned_zone,
1637
+ @hvac_unavailable_periods)
1460
1638
 
1461
1639
  elsif [HPXML::HVACTypeElectricResistance].include? heating_system.heating_system_type
1462
1640
 
1463
1641
  HVAC.apply_electric_baseboard(model, heating_system,
1464
- sequential_heat_load_fracs, living_zone, @hvac_unavailable_periods)
1642
+ sequential_heat_load_fracs, conditioned_zone, @hvac_unavailable_periods)
1465
1643
 
1466
1644
  elsif [HPXML::HVACTypeStove,
1467
- HPXML::HVACTypePortableHeater,
1468
- HPXML::HVACTypeFixedHeater,
1645
+ HPXML::HVACTypeSpaceHeater,
1469
1646
  HPXML::HVACTypeWallFurnace,
1470
1647
  HPXML::HVACTypeFloorFurnace,
1471
1648
  HPXML::HVACTypeFireplace].include? heating_system.heating_system_type
1472
1649
 
1473
1650
  HVAC.apply_unit_heater(model, heating_system,
1474
- sequential_heat_load_fracs, living_zone, @hvac_unavailable_periods)
1651
+ sequential_heat_load_fracs, conditioned_zone, @hvac_unavailable_periods)
1475
1652
  end
1476
1653
 
1477
1654
  next unless heating_system.is_heat_pump_backup_system
1478
1655
 
1479
1656
  # Store OS object for later use
1480
- equipment_list = model.getZoneHVACEquipmentLists.find { |el| el.thermalZone == living_zone }
1657
+ equipment_list = model.getZoneHVACEquipmentLists.find { |el| el.thermalZone == conditioned_zone }
1481
1658
  @heat_pump_backup_system_object = equipment_list.equipment[-1]
1482
1659
  end
1483
1660
  end
1484
1661
 
1485
- def self.add_heat_pump(runner, model, weather, spaces, airloop_map)
1486
- living_zone = spaces[HPXML::LocationLivingSpace].thermalZone.get
1662
+ def add_heat_pump(runner, model, weather, spaces, airloop_map)
1663
+ conditioned_zone = spaces[HPXML::LocationConditionedSpace].thermalZone.get
1487
1664
 
1488
- HVAC.get_hpxml_hvac_systems(@hpxml).each do |hvac_system|
1665
+ HVAC.get_hpxml_hvac_systems(@hpxml_bldg).each do |hvac_system|
1489
1666
  next if hvac_system[:cooling].nil?
1490
1667
  next unless hvac_system[:cooling].is_a? HPXML::HeatPump
1491
1668
 
@@ -1506,26 +1683,27 @@ class OSModel
1506
1683
 
1507
1684
  airloop_map[sys_id] = HVAC.apply_water_loop_to_air_heat_pump(model, heat_pump,
1508
1685
  sequential_heat_load_fracs, sequential_cool_load_fracs,
1509
- living_zone, @hvac_unavailable_periods)
1686
+ conditioned_zone, @hvac_unavailable_periods)
1510
1687
 
1511
1688
  elsif [HPXML::HVACTypeHeatPumpAirToAir,
1512
1689
  HPXML::HVACTypeHeatPumpMiniSplit,
1513
1690
  HPXML::HVACTypeHeatPumpPTHP,
1514
1691
  HPXML::HVACTypeHeatPumpRoom].include? heat_pump.heat_pump_type
1515
- airloop_map[sys_id] = HVAC.apply_air_source_hvac_systems(model, heat_pump, heat_pump,
1516
- sequential_cool_load_fracs, sequential_heat_load_fracs,
1517
- living_zone, @hvac_unavailable_periods)
1692
+ airloop_map[sys_id] = HVAC.apply_air_source_hvac_systems(model, heat_pump, heat_pump, sequential_cool_load_fracs, sequential_heat_load_fracs,
1693
+ weather.data.AnnualMaxDrybulb, weather.data.AnnualMinDrybulb,
1694
+ conditioned_zone, @hvac_unavailable_periods)
1518
1695
  elsif [HPXML::HVACTypeHeatPumpGroundToAir].include? heat_pump.heat_pump_type
1519
1696
 
1520
1697
  airloop_map[sys_id] = HVAC.apply_ground_to_air_heat_pump(model, runner, weather, heat_pump,
1521
1698
  sequential_heat_load_fracs, sequential_cool_load_fracs,
1522
- living_zone, @hpxml.site.ground_conductivity, @hvac_unavailable_periods)
1699
+ conditioned_zone, @hpxml_bldg.site.ground_conductivity, @hvac_unavailable_periods,
1700
+ @hpxml_bldg.building_construction.number_of_units)
1523
1701
 
1524
1702
  end
1525
1703
 
1526
- next unless not heat_pump.backup_system.nil?
1704
+ next if heat_pump.backup_system.nil?
1527
1705
 
1528
- equipment_list = model.getZoneHVACEquipmentLists.find { |el| el.thermalZone == living_zone }
1706
+ equipment_list = model.getZoneHVACEquipmentLists.find { |el| el.thermalZone == conditioned_zone }
1529
1707
 
1530
1708
  # Set priority to be last (i.e., after the heat pump that it is backup for)
1531
1709
  equipment_list.setHeatingPriority(@heat_pump_backup_system_object, 99)
@@ -1533,14 +1711,13 @@ class OSModel
1533
1711
  end
1534
1712
  end
1535
1713
 
1536
- def self.add_ideal_system(model, spaces, epw_path)
1714
+ def add_ideal_system(model, spaces, epw_path)
1537
1715
  # Adds an ideal air system as needed to meet the load under certain circumstances:
1538
1716
  # 1. the sum of fractions load served is less than 1, or
1539
1717
  # 2. we're using an ideal air system for e.g. ASHRAE 140 loads calculation.
1540
- living_zone = spaces[HPXML::LocationLivingSpace].thermalZone.get
1541
- obj_name = Constants.ObjectNameIdealAirSystem
1718
+ conditioned_zone = spaces[HPXML::LocationConditionedSpace].thermalZone.get
1542
1719
 
1543
- if @apply_ashrae140_assumptions && (@hpxml.total_fraction_heat_load_served + @hpxml.total_fraction_heat_load_served == 0.0)
1720
+ if @apply_ashrae140_assumptions && (@hpxml_bldg.total_fraction_heat_load_served + @hpxml_bldg.total_fraction_heat_load_served == 0.0)
1544
1721
  cooling_load_frac = 1.0
1545
1722
  heating_load_frac = 1.0
1546
1723
  if @apply_ashrae140_assumptions
@@ -1552,56 +1729,57 @@ class OSModel
1552
1729
  fail 'Unexpected weather file for ASHRAE 140 run.'
1553
1730
  end
1554
1731
  end
1555
- HVAC.apply_ideal_air_loads(model, obj_name, [cooling_load_frac], [heating_load_frac],
1556
- living_zone, @hvac_unavailable_periods)
1732
+ HVAC.apply_ideal_air_loads(model, [cooling_load_frac], [heating_load_frac],
1733
+ conditioned_zone, @hvac_unavailable_periods)
1557
1734
  return
1558
1735
  end
1559
1736
 
1560
- if (@hpxml.total_fraction_heat_load_served < 1.0) && (@hpxml.total_fraction_heat_load_served > 0.0)
1561
- sequential_heat_load_fracs = HVAC.calc_sequential_load_fractions(@remaining_heat_load_frac - @hpxml.total_fraction_heat_load_served, @remaining_heat_load_frac, @heating_days)
1562
- @remaining_heat_load_frac -= (1.0 - @hpxml.total_fraction_heat_load_served)
1737
+ if (@hpxml_bldg.total_fraction_heat_load_served < 1.0) && (@hpxml_bldg.total_fraction_heat_load_served > 0.0)
1738
+ sequential_heat_load_fracs = HVAC.calc_sequential_load_fractions(@remaining_heat_load_frac - @hpxml_bldg.total_fraction_heat_load_served, @remaining_heat_load_frac, @heating_days)
1739
+ @remaining_heat_load_frac -= (1.0 - @hpxml_bldg.total_fraction_heat_load_served)
1563
1740
  else
1564
1741
  sequential_heat_load_fracs = [0.0]
1565
1742
  end
1566
1743
 
1567
- if (@hpxml.total_fraction_cool_load_served < 1.0) && (@hpxml.total_fraction_cool_load_served > 0.0)
1568
- sequential_cool_load_fracs = HVAC.calc_sequential_load_fractions(@remaining_cool_load_frac - @hpxml.total_fraction_cool_load_served, @remaining_cool_load_frac, @cooling_days)
1569
- @remaining_cool_load_frac -= (1.0 - @hpxml.total_fraction_cool_load_served)
1744
+ if (@hpxml_bldg.total_fraction_cool_load_served < 1.0) && (@hpxml_bldg.total_fraction_cool_load_served > 0.0)
1745
+ sequential_cool_load_fracs = HVAC.calc_sequential_load_fractions(@remaining_cool_load_frac - @hpxml_bldg.total_fraction_cool_load_served, @remaining_cool_load_frac, @cooling_days)
1746
+ @remaining_cool_load_frac -= (1.0 - @hpxml_bldg.total_fraction_cool_load_served)
1570
1747
  else
1571
1748
  sequential_cool_load_fracs = [0.0]
1572
1749
  end
1573
1750
 
1574
1751
  if (sequential_heat_load_fracs.sum > 0.0) || (sequential_cool_load_fracs.sum > 0.0)
1575
- HVAC.apply_ideal_air_loads(model, obj_name, sequential_cool_load_fracs, sequential_heat_load_fracs,
1576
- living_zone, @hvac_unavailable_periods)
1752
+ HVAC.apply_ideal_air_loads(model, sequential_cool_load_fracs, sequential_heat_load_fracs,
1753
+ conditioned_zone, @hvac_unavailable_periods)
1577
1754
  end
1578
1755
  end
1579
1756
 
1580
- def self.add_setpoints(runner, model, weather, spaces)
1581
- return if @hpxml.hvac_controls.size == 0
1757
+ def add_setpoints(runner, model, weather, spaces)
1758
+ return if @hpxml_bldg.hvac_controls.size == 0
1582
1759
 
1583
- hvac_control = @hpxml.hvac_controls[0]
1584
- living_zone = spaces[HPXML::LocationLivingSpace].thermalZone.get
1585
- has_ceiling_fan = (@hpxml.ceiling_fans.size > 0)
1760
+ hvac_control = @hpxml_bldg.hvac_controls[0]
1761
+ conditioned_zone = spaces[HPXML::LocationConditionedSpace].thermalZone.get
1762
+ has_ceiling_fan = (@hpxml_bldg.ceiling_fans.size > 0)
1586
1763
 
1587
- HVAC.apply_setpoints(model, runner, weather, hvac_control, living_zone, has_ceiling_fan, @heating_days, @cooling_days, @hpxml.header.sim_calendar_year, @schedules_file)
1764
+ HVAC.apply_setpoints(model, runner, weather, hvac_control, conditioned_zone, has_ceiling_fan, @heating_days, @cooling_days, @hpxml_header.sim_calendar_year, @schedules_file)
1588
1765
  end
1589
1766
 
1590
- def self.add_ceiling_fans(runner, model, weather, spaces)
1591
- return if @hpxml.ceiling_fans.size == 0
1767
+ def add_ceiling_fans(runner, model, weather, spaces)
1768
+ return if @hpxml_bldg.ceiling_fans.size == 0
1592
1769
 
1593
- ceiling_fan = @hpxml.ceiling_fans[0]
1594
- HVAC.apply_ceiling_fans(model, runner, weather, ceiling_fan, spaces[HPXML::LocationLivingSpace],
1595
- @schedules_file, @hpxml.header.unavailable_periods)
1770
+ ceiling_fan = @hpxml_bldg.ceiling_fans[0]
1771
+ HVAC.apply_ceiling_fans(model, runner, weather, ceiling_fan, spaces[HPXML::LocationConditionedSpace],
1772
+ @schedules_file, @hpxml_header.unavailable_periods)
1596
1773
  end
1597
1774
 
1598
- def self.add_dehumidifiers(runner, model, spaces)
1599
- return if @hpxml.dehumidifiers.size == 0
1775
+ def add_dehumidifiers(runner, model, spaces)
1776
+ return if @hpxml_bldg.dehumidifiers.size == 0
1600
1777
 
1601
- HVAC.apply_dehumidifiers(runner, model, @hpxml.dehumidifiers, spaces[HPXML::LocationLivingSpace], @hpxml.header.unavailable_periods)
1778
+ HVAC.apply_dehumidifiers(runner, model, @hpxml_bldg.dehumidifiers, spaces[HPXML::LocationConditionedSpace], @hpxml_header.unavailable_periods,
1779
+ @hpxml_bldg.building_construction.number_of_units)
1602
1780
  end
1603
1781
 
1604
- def self.check_distribution_system(hvac_distribution, system_type)
1782
+ def check_distribution_system(hvac_distribution, system_type)
1605
1783
  return if hvac_distribution.nil?
1606
1784
 
1607
1785
  hvac_distribution_type_map = { HPXML::HVACTypeFurnace => [HPXML::HVACDistributionTypeAir, HPXML::HVACDistributionTypeDSE],
@@ -1619,9 +1797,9 @@ class OSModel
1619
1797
  end
1620
1798
  end
1621
1799
 
1622
- def self.add_mels(runner, model, spaces)
1800
+ def add_mels(runner, model, spaces)
1623
1801
  # Misc
1624
- @hpxml.plug_loads.each do |plug_load|
1802
+ @hpxml_bldg.plug_loads.each do |plug_load|
1625
1803
  if plug_load.plug_load_type == HPXML::PlugLoadTypeOther
1626
1804
  obj_name = Constants.ObjectNameMiscPlugLoads
1627
1805
  elsif plug_load.plug_load_type == HPXML::PlugLoadTypeTelevision
@@ -1636,14 +1814,14 @@ class OSModel
1636
1814
  next
1637
1815
  end
1638
1816
 
1639
- MiscLoads.apply_plug(model, runner, plug_load, obj_name, spaces[HPXML::LocationLivingSpace], @apply_ashrae140_assumptions,
1640
- @schedules_file, @hpxml.header.unavailable_periods)
1817
+ MiscLoads.apply_plug(model, runner, plug_load, obj_name, spaces[HPXML::LocationConditionedSpace], @apply_ashrae140_assumptions,
1818
+ @schedules_file, @hpxml_header.unavailable_periods)
1641
1819
  end
1642
1820
  end
1643
1821
 
1644
- def self.add_mfls(runner, model, spaces)
1822
+ def add_mfls(runner, model, spaces)
1645
1823
  # Misc
1646
- @hpxml.fuel_loads.each do |fuel_load|
1824
+ @hpxml_bldg.fuel_loads.each do |fuel_load|
1647
1825
  if fuel_load.fuel_load_type == HPXML::FuelLoadTypeGrill
1648
1826
  obj_name = Constants.ObjectNameMiscGrill
1649
1827
  elsif fuel_load.fuel_load_type == HPXML::FuelLoadTypeLighting
@@ -1656,44 +1834,33 @@ class OSModel
1656
1834
  next
1657
1835
  end
1658
1836
 
1659
- MiscLoads.apply_fuel(model, runner, fuel_load, obj_name, spaces[HPXML::LocationLivingSpace],
1660
- @schedules_file, @hpxml.header.unavailable_periods)
1837
+ MiscLoads.apply_fuel(model, runner, fuel_load, obj_name, spaces[HPXML::LocationConditionedSpace],
1838
+ @schedules_file, @hpxml_header.unavailable_periods)
1661
1839
  end
1662
1840
  end
1663
1841
 
1664
- def self.add_lighting(runner, model, epw_file, spaces)
1665
- Lighting.apply(runner, model, epw_file, spaces, @hpxml.lighting_groups, @hpxml.lighting, @eri_version,
1666
- @schedules_file, @cfa, @hpxml.header.unavailable_periods)
1842
+ def add_lighting(runner, model, epw_file, spaces)
1843
+ Lighting.apply(runner, model, epw_file, spaces, @hpxml_bldg.lighting_groups, @hpxml_bldg.lighting, @eri_version,
1844
+ @schedules_file, @cfa, @hpxml_header.unavailable_periods, @hpxml_bldg.building_construction.number_of_units)
1667
1845
  end
1668
1846
 
1669
- def self.add_pools_and_hot_tubs(runner, model, spaces)
1670
- @hpxml.pools.each do |pool|
1671
- next if pool.type == HPXML::TypeNone
1847
+ def add_pools_and_permanent_spas(runner, model, spaces)
1848
+ (@hpxml_bldg.pools + @hpxml_bldg.permanent_spas).each do |pool_or_spa|
1849
+ next if pool_or_spa.type == HPXML::TypeNone
1672
1850
 
1673
- MiscLoads.apply_pool_or_hot_tub_heater(runner, model, pool, Constants.ObjectNameMiscPoolHeater, spaces[HPXML::LocationLivingSpace],
1674
- @schedules_file, @hpxml.header.unavailable_periods)
1675
- next if pool.pump_type == HPXML::TypeNone
1851
+ MiscLoads.apply_pool_or_permanent_spa_heater(runner, model, pool_or_spa, spaces[HPXML::LocationConditionedSpace],
1852
+ @schedules_file, @hpxml_header.unavailable_periods)
1853
+ next if pool_or_spa.pump_type == HPXML::TypeNone
1676
1854
 
1677
- MiscLoads.apply_pool_or_hot_tub_pump(runner, model, pool, Constants.ObjectNameMiscPoolPump, spaces[HPXML::LocationLivingSpace],
1678
- @schedules_file, @hpxml.header.unavailable_periods)
1679
- end
1680
-
1681
- @hpxml.hot_tubs.each do |hot_tub|
1682
- next if hot_tub.type == HPXML::TypeNone
1683
-
1684
- MiscLoads.apply_pool_or_hot_tub_heater(runner, model, hot_tub, Constants.ObjectNameMiscHotTubHeater, spaces[HPXML::LocationLivingSpace],
1685
- @schedules_file, @hpxml.header.unavailable_periods)
1686
- next if hot_tub.pump_type == HPXML::TypeNone
1687
-
1688
- MiscLoads.apply_pool_or_hot_tub_pump(runner, model, hot_tub, Constants.ObjectNameMiscHotTubPump, spaces[HPXML::LocationLivingSpace],
1689
- @schedules_file, @hpxml.header.unavailable_periods)
1855
+ MiscLoads.apply_pool_or_permanent_spa_pump(runner, model, pool_or_spa, spaces[HPXML::LocationConditionedSpace],
1856
+ @schedules_file, @hpxml_header.unavailable_periods)
1690
1857
  end
1691
1858
  end
1692
1859
 
1693
- def self.add_airflow(runner, model, weather, spaces, airloop_map)
1860
+ def add_airflow(runner, model, weather, spaces, airloop_map)
1694
1861
  # Ducts
1695
1862
  duct_systems = {}
1696
- @hpxml.hvac_distributions.each do |hvac_distribution|
1863
+ @hpxml_bldg.hvac_distributions.each do |hvac_distribution|
1697
1864
  next unless hvac_distribution.distribution_system_type == HPXML::HVACDistributionTypeAir
1698
1865
 
1699
1866
  air_ducts = create_ducts(model, hvac_distribution, spaces)
@@ -1721,24 +1888,50 @@ class OSModel
1721
1888
  end
1722
1889
  end
1723
1890
 
1891
+ # Duct leakage to outside warnings?
1892
+ # Need to check here instead of in schematron in case duct locations are defaulted
1893
+ @hpxml_bldg.hvac_distributions.each do |hvac_distribution|
1894
+ next unless hvac_distribution.distribution_system_type == HPXML::HVACDistributionTypeAir
1895
+ next if hvac_distribution.duct_leakage_measurements.empty?
1896
+
1897
+ # Skip if there's a duct outside conditioned space
1898
+ next if hvac_distribution.ducts.select { |d| !HPXML::conditioned_locations_this_unit.include?(d.duct_location) }.size > 0
1899
+
1900
+ # Issue warning if duct leakage to outside above a certain threshold and ducts completely in conditioned space
1901
+ issue_warning = false
1902
+ units = hvac_distribution.duct_leakage_measurements[0].duct_leakage_units
1903
+ lto_measurements = hvac_distribution.duct_leakage_measurements.select { |dlm| dlm.duct_leakage_total_or_to_outside == HPXML::DuctLeakageToOutside }
1904
+ sum_lto = lto_measurements.map { |dlm| dlm.duct_leakage_value }.sum(0.0)
1905
+ if units == HPXML::UnitsCFM25
1906
+ issue_warning = true if sum_lto > 0.04 * @cfa
1907
+ elsif units == HPXML::UnitsCFM50
1908
+ issue_warning = true if sum_lto > 0.06 * @cfa
1909
+ elsif units == HPXML::UnitsPercent
1910
+ issue_warning = true if sum_lto > 0.05
1911
+ end
1912
+ next unless issue_warning
1913
+
1914
+ runner.registerWarning('Ducts are entirely within conditioned space but there is moderate leakage to the outside. Leakage to the outside is typically zero or near-zero in these situations, consider revising leakage values. Leakage will be modeled as heat lost to the ambient environment.')
1915
+ end
1916
+
1724
1917
  # Create HVAC availability sensor
1725
- @hvac_availability_sensor = nil
1918
+ hvac_availability_sensor = nil
1726
1919
  if not @hvac_unavailable_periods.empty?
1727
1920
  avail_sch = ScheduleConstant.new(model, SchedulesFile::ColumnHVAC, 1.0, Constants.ScheduleTypeLimitsFraction, unavailable_periods: @hvac_unavailable_periods)
1728
- avail_sch = avail_sch.schedule
1729
1921
 
1730
- @hvac_availability_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Schedule Value')
1731
- @hvac_availability_sensor.setName('availability s')
1732
- @hvac_availability_sensor.setKeyName(avail_sch.name.to_s)
1922
+ hvac_availability_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Schedule Value')
1923
+ hvac_availability_sensor.setName('hvac availability s')
1924
+ hvac_availability_sensor.setKeyName(avail_sch.schedule.name.to_s)
1925
+ hvac_availability_sensor.additionalProperties.setFeature('ObjectType', Constants.ObjectNameHVACAvailabilitySensor)
1733
1926
  end
1734
1927
 
1735
- Airflow.apply(model, runner, weather, spaces, @hpxml, @cfa, @nbeds,
1928
+ Airflow.apply(model, runner, weather, spaces, @hpxml_header, @hpxml_bldg, @cfa, @nbeds,
1736
1929
  @ncfl_ag, duct_systems, airloop_map, @clg_ssn_sensor, @eri_version,
1737
1930
  @frac_windows_operable, @apply_ashrae140_assumptions, @schedules_file,
1738
- @hpxml.header.unavailable_periods, @hvac_availability_sensor)
1931
+ @hpxml_header.unavailable_periods, hvac_availability_sensor)
1739
1932
  end
1740
1933
 
1741
- def self.create_ducts(model, hvac_distribution, spaces)
1934
+ def create_ducts(model, hvac_distribution, spaces)
1742
1935
  air_ducts = []
1743
1936
 
1744
1937
  # Duct leakage (supply/return => [value, units])
@@ -1817,96 +2010,131 @@ class OSModel
1817
2010
  return air_ducts
1818
2011
  end
1819
2012
 
1820
- def self.add_photovoltaics(model)
1821
- @hpxml.pv_systems.each do |pv_system|
1822
- next if pv_system.inverter.inverter_efficiency == @hpxml.pv_systems[0].inverter.inverter_efficiency
2013
+ def add_photovoltaics(model)
2014
+ @hpxml_bldg.pv_systems.each do |pv_system|
2015
+ next if pv_system.inverter.inverter_efficiency == @hpxml_bldg.pv_systems[0].inverter.inverter_efficiency
1823
2016
 
1824
2017
  fail 'Expected all InverterEfficiency values to be equal.'
1825
2018
  end
1826
- @hpxml.pv_systems.each do |pv_system|
1827
- PV.apply(model, @nbeds, pv_system)
2019
+ @hpxml_bldg.pv_systems.each do |pv_system|
2020
+ PV.apply(model, @nbeds, pv_system, @hpxml_bldg.building_construction.number_of_units)
1828
2021
  end
1829
2022
  end
1830
2023
 
1831
- def self.add_generators(model)
1832
- @hpxml.generators.each do |generator|
1833
- Generator.apply(model, @nbeds, generator)
2024
+ def add_generators(model)
2025
+ @hpxml_bldg.generators.each do |generator|
2026
+ Generator.apply(model, @nbeds, generator, @hpxml_bldg.building_construction.number_of_units)
1834
2027
  end
1835
2028
  end
1836
2029
 
1837
- def self.add_batteries(runner, model, spaces)
1838
- @hpxml.batteries.each do |battery|
2030
+ def add_batteries(runner, model, spaces)
2031
+ @hpxml_bldg.batteries.each do |battery|
1839
2032
  # Assign space
1840
2033
  battery.additional_properties.space = get_space_from_location(battery.location, spaces)
1841
- Battery.apply(runner, model, @hpxml.pv_systems, battery, @schedules_file)
2034
+ Battery.apply(runner, model, @hpxml_bldg.pv_systems, battery, @schedules_file, @hpxml_bldg.building_construction.number_of_units)
1842
2035
  end
1843
2036
  end
1844
2037
 
1845
- def self.add_additional_properties(model, hpxml_path, building_id, epw_file)
2038
+ def add_building_unit(model, unit_num)
2039
+ return if unit_num.nil?
2040
+
2041
+ unit = OpenStudio::Model::BuildingUnit.new(model)
2042
+ unit.additionalProperties.setFeature('unit_num', unit_num)
2043
+ model.getSpaces.each do |s|
2044
+ s.setBuildingUnit(unit)
2045
+ end
2046
+ end
2047
+
2048
+ def add_additional_properties(model, hpxml, hpxml_osm_map, hpxml_path, building_id, epw_file, hpxml_defaults_path)
1846
2049
  # Store some data for use in reporting measure
1847
2050
  additionalProperties = model.getBuilding.additionalProperties
1848
2051
  additionalProperties.setFeature('hpxml_path', hpxml_path)
1849
- additionalProperties.setFeature('hpxml_defaults_path', @hpxml_defaults_path)
2052
+ additionalProperties.setFeature('hpxml_defaults_path', hpxml_defaults_path)
1850
2053
  additionalProperties.setFeature('building_id', building_id.to_s)
1851
- emissions_scenario_names = @hpxml.header.emissions_scenarios.map { |s| s.name }.to_s
1852
- additionalProperties.setFeature('emissions_scenario_names', emissions_scenario_names)
1853
- emissions_scenario_types = @hpxml.header.emissions_scenarios.map { |s| s.emissions_type }.to_s
1854
- additionalProperties.setFeature('emissions_scenario_types', emissions_scenario_types)
1855
- additionalProperties.setFeature('has_heating', @hpxml.total_fraction_heat_load_served > 0)
1856
- additionalProperties.setFeature('has_cooling', @hpxml.total_fraction_cool_load_served > 0)
2054
+ additionalProperties.setFeature('emissions_scenario_names', hpxml.header.emissions_scenarios.map { |s| s.name }.to_s)
2055
+ additionalProperties.setFeature('emissions_scenario_types', hpxml.header.emissions_scenarios.map { |s| s.emissions_type }.to_s)
2056
+ heated_zones, cooled_zones = [], []
2057
+ hpxml_osm_map.each do |hpxml_bldg, unit_model|
2058
+ conditioned_zone_name = unit_model.getThermalZones.find { |z| z.additionalProperties.getFeatureAsString('ObjectType').to_s == HPXML::LocationConditionedSpace }.name.to_s
2059
+
2060
+ heated_zones << conditioned_zone_name if hpxml_bldg.total_fraction_heat_load_served > 0
2061
+ cooled_zones << conditioned_zone_name if hpxml_bldg.total_fraction_cool_load_served > 0
2062
+ end
2063
+ additionalProperties.setFeature('heated_zones', heated_zones.to_s)
2064
+ additionalProperties.setFeature('cooled_zones', cooled_zones.to_s)
1857
2065
  additionalProperties.setFeature('is_southern_hemisphere', epw_file.latitude < 0)
1858
2066
  end
1859
2067
 
1860
- def self.add_unmet_hours_output(model, spaces)
2068
+ def add_unmet_hours_output(model, hpxml_osm_map)
1861
2069
  # We do our own unmet hours calculation via EMS so that we can incorporate,
1862
- # e.g., heating/cooling seasons into the logic.
1863
- hvac_control = @hpxml.hvac_controls[0]
1864
- if not hvac_control.nil?
1865
- sim_year = @hpxml.header.sim_calendar_year
1866
- htg_start_day = Schedule.get_day_num_from_month_day(sim_year, hvac_control.seasons_heating_begin_month, hvac_control.seasons_heating_begin_day)
1867
- htg_end_day = Schedule.get_day_num_from_month_day(sim_year, hvac_control.seasons_heating_end_month, hvac_control.seasons_heating_end_day)
1868
- clg_start_day = Schedule.get_day_num_from_month_day(sim_year, hvac_control.seasons_cooling_begin_month, hvac_control.seasons_cooling_begin_day)
1869
- clg_end_day = Schedule.get_day_num_from_month_day(sim_year, hvac_control.seasons_cooling_end_month, hvac_control.seasons_cooling_end_day)
1870
- end
2070
+ # e.g., heating/cooling seasons into the logic. The calculation layers on top
2071
+ # of the built-in EnergyPlus unmet hours output.
2072
+
2073
+ # Create sensors and gather data
2074
+ htg_sensors, clg_sensors = {}, {}
2075
+ total_heat_load_serveds, total_cool_load_serveds = {}, {}
2076
+ htg_start_days, htg_end_days, clg_start_days, clg_end_days = {}, {}, {}, {}
2077
+ hpxml_osm_map.each_with_index do |(hpxml_bldg, unit_model), unit|
2078
+ conditioned_zone_name = unit_model.getThermalZones.find { |z| z.additionalProperties.getFeatureAsString('ObjectType').to_s == HPXML::LocationConditionedSpace }.name.to_s
2079
+
2080
+ # EMS sensors
2081
+ htg_sensors[unit] = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Zone Heating Setpoint Not Met Time')
2082
+ htg_sensors[unit].setName('zone htg unmet s')
2083
+ htg_sensors[unit].setKeyName(conditioned_zone_name)
1871
2084
 
1872
- living_zone = spaces[HPXML::LocationLivingSpace].thermalZone.get
2085
+ clg_sensors[unit] = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Zone Cooling Setpoint Not Met Time')
2086
+ clg_sensors[unit].setName('zone clg unmet s')
2087
+ clg_sensors[unit].setKeyName(conditioned_zone_name)
1873
2088
 
1874
- # EMS sensors
1875
- htg_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Zone Heating Setpoint Not Met Time')
1876
- htg_sensor.setName('zone htg unmet s')
1877
- htg_sensor.setKeyName(living_zone.name.to_s)
2089
+ total_heat_load_serveds[unit] = hpxml_bldg.total_fraction_heat_load_served
2090
+ total_cool_load_serveds[unit] = hpxml_bldg.total_fraction_cool_load_served
1878
2091
 
1879
- clg_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Zone Cooling Setpoint Not Met Time')
1880
- clg_sensor.setName('zone clg unmet s')
1881
- clg_sensor.setKeyName(living_zone.name.to_s)
2092
+ hvac_control = hpxml_bldg.hvac_controls[0]
2093
+ next unless not hvac_control.nil?
2094
+
2095
+ sim_year = @hpxml_header.sim_calendar_year
2096
+ htg_start_days[unit] = Schedule.get_day_num_from_month_day(sim_year, hvac_control.seasons_heating_begin_month, hvac_control.seasons_heating_begin_day)
2097
+ htg_end_days[unit] = Schedule.get_day_num_from_month_day(sim_year, hvac_control.seasons_heating_end_month, hvac_control.seasons_heating_end_day)
2098
+ clg_start_days[unit] = Schedule.get_day_num_from_month_day(sim_year, hvac_control.seasons_cooling_begin_month, hvac_control.seasons_cooling_begin_day)
2099
+ clg_end_days[unit] = Schedule.get_day_num_from_month_day(sim_year, hvac_control.seasons_cooling_end_month, hvac_control.seasons_cooling_end_day)
2100
+ end
2101
+
2102
+ hvac_availability_sensor = model.getEnergyManagementSystemSensors.find { |s| s.additionalProperties.getFeatureAsString('ObjectType').to_s == Constants.ObjectNameHVACAvailabilitySensor }
1882
2103
 
1883
2104
  # EMS program
1884
2105
  clg_hrs = 'clg_unmet_hours'
1885
2106
  htg_hrs = 'htg_unmet_hours'
1886
2107
  program = OpenStudio::Model::EnergyManagementSystemProgram.new(model)
1887
- program.setName(Constants.ObjectNameUnmetHoursProgram)
2108
+ program.setName('unmet hours program')
2109
+ program.additionalProperties.setFeature('ObjectType', Constants.ObjectNameUnmetHoursProgram)
1888
2110
  program.addLine("Set #{htg_hrs} = 0")
1889
2111
  program.addLine("Set #{clg_hrs} = 0")
1890
- if @hpxml.total_fraction_heat_load_served > 0
1891
- if htg_end_day >= htg_start_day
1892
- line = "If ((DayOfYear >= #{htg_start_day}) && (DayOfYear <= #{htg_end_day}))"
1893
- else
1894
- line = "If ((DayOfYear >= #{htg_start_day}) || (DayOfYear <= #{htg_end_day}))"
2112
+ for unit in 0..hpxml_osm_map.size - 1
2113
+ if total_heat_load_serveds[unit] > 0
2114
+ if htg_end_days[unit] >= htg_start_days[unit]
2115
+ line = "If ((DayOfYear >= #{htg_start_days[unit]}) && (DayOfYear <= #{htg_end_days[unit]}))"
2116
+ else
2117
+ line = "If ((DayOfYear >= #{htg_start_days[unit]}) || (DayOfYear <= #{htg_end_days[unit]}))"
2118
+ end
2119
+ line += " && (#{hvac_availability_sensor.name} == 1)" if not hvac_availability_sensor.nil?
2120
+ program.addLine(line)
2121
+ program.addLine(" If #{htg_sensors[unit].name} > #{htg_hrs}") # Use max hourly value across all units
2122
+ program.addLine(" Set #{htg_hrs} = #{htg_sensors[unit].name}")
2123
+ program.addLine(' EndIf')
2124
+ program.addLine('EndIf')
1895
2125
  end
1896
- line += " && (#{@hvac_availability_sensor.name} == 1)" if not @hvac_availability_sensor.nil?
1897
- program.addLine(line)
1898
- program.addLine(" Set #{htg_hrs} = #{htg_hrs} + #{htg_sensor.name}")
1899
- program.addLine('EndIf')
1900
- end
1901
- if @hpxml.total_fraction_cool_load_served > 0
1902
- if clg_end_day >= clg_start_day
1903
- line = "If ((DayOfYear >= #{clg_start_day}) && (DayOfYear <= #{clg_end_day}))"
2126
+ next unless total_cool_load_serveds[unit] > 0
2127
+
2128
+ if clg_end_days[unit] >= clg_start_days[unit]
2129
+ line = "If ((DayOfYear >= #{clg_start_days[unit]}) && (DayOfYear <= #{clg_end_days[unit]}))"
1904
2130
  else
1905
- line = "If ((DayOfYear >= #{clg_start_day}) || (DayOfYear <= #{clg_end_day}))"
2131
+ line = "If ((DayOfYear >= #{clg_start_days[unit]}) || (DayOfYear <= #{clg_end_days[unit]}))"
1906
2132
  end
1907
- line += " && (#{@hvac_availability_sensor.name} == 1)" if not @hvac_availability_sensor.nil?
2133
+ line += " && (#{hvac_availability_sensor.name} == 1)" if not hvac_availability_sensor.nil?
1908
2134
  program.addLine(line)
1909
- program.addLine(" Set #{clg_hrs} = #{clg_hrs} + #{clg_sensor.name}")
2135
+ program.addLine(" If #{clg_sensors[unit].name} > #{clg_hrs}") # Use max hourly value across all units
2136
+ program.addLine(" Set #{clg_hrs} = #{clg_sensors[unit].name}")
2137
+ program.addLine(' EndIf')
1910
2138
  program.addLine('EndIf')
1911
2139
  end
1912
2140
 
@@ -1917,68 +2145,88 @@ class OSModel
1917
2145
  program_calling_manager.addProgram(program)
1918
2146
  end
1919
2147
 
1920
- def self.add_loads_output(model, spaces, add_component_loads)
1921
- living_zone = spaces[HPXML::LocationLivingSpace].thermalZone.get
1922
-
1923
- if @apply_ashrae140_assumptions
1924
- total_heat_load_served = 1.0
1925
- total_cool_load_served = 1.0
1926
- else
1927
- total_heat_load_served = @hpxml.total_fraction_heat_load_served
1928
- total_cool_load_served = @hpxml.total_fraction_cool_load_served
1929
- end
1930
-
1931
- liv_load_sensors, intgain_dehumidifier = add_total_loads_output(model, living_zone, total_heat_load_served, total_cool_load_served)
2148
+ def add_loads_output(model, add_component_loads, hpxml_osm_map)
2149
+ loads_data = add_total_loads_output(model, hpxml_osm_map)
1932
2150
  return unless add_component_loads
1933
2151
 
1934
- add_component_loads_output(model, living_zone, liv_load_sensors, intgain_dehumidifier, total_heat_load_served, total_cool_load_served)
2152
+ add_component_loads_output(model, hpxml_osm_map, loads_data)
1935
2153
  end
1936
2154
 
1937
- def self.add_total_loads_output(model, living_zone, total_heat_load_served, total_cool_load_served)
1938
- # Energy transferred in the conditioned space, used for determining heating (winter) vs cooling (summer)
1939
- liv_load_sensors = {}
1940
- liv_load_sensors[:htg] = OpenStudio::Model::EnergyManagementSystemSensor.new(model, "Heating:EnergyTransfer:Zone:#{living_zone.name.to_s.upcase}")
1941
- liv_load_sensors[:htg].setName('htg_load_liv')
1942
- liv_load_sensors[:clg] = OpenStudio::Model::EnergyManagementSystemSensor.new(model, "Cooling:EnergyTransfer:Zone:#{living_zone.name.to_s.upcase}")
1943
- liv_load_sensors[:clg].setName('clg_load_liv')
1944
-
1945
- # Total energy transferred (above plus ducts)
1946
- tot_load_sensors = {}
1947
- tot_load_sensors[:htg] = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Heating:EnergyTransfer')
1948
- tot_load_sensors[:htg].setName('htg_load_tot')
1949
- tot_load_sensors[:clg] = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Cooling:EnergyTransfer')
1950
- tot_load_sensors[:clg].setName('clg_load_tot')
2155
+ def add_total_loads_output(model, hpxml_osm_map)
2156
+ # Create sensors and gather data
2157
+ htg_cond_load_sensors, clg_cond_load_sensors = {}, {}
2158
+ htg_duct_load_sensors, clg_duct_load_sensors = {}, {}
2159
+ total_heat_load_serveds, total_cool_load_serveds = {}, {}
2160
+ dehumidifier_sensors = {}
2161
+
2162
+ hpxml_osm_map.each_with_index do |(hpxml_bldg, unit_model), unit|
2163
+ # Retrieve objects
2164
+ conditioned_zone_name = unit_model.getThermalZones.find { |z| z.additionalProperties.getFeatureAsString('ObjectType').to_s == HPXML::LocationConditionedSpace }.name.to_s
2165
+ duct_zone_names = unit_model.getThermalZones.select { |z| z.isPlenum }.map { |z| z.name.to_s }
2166
+ dehumidifier = unit_model.getZoneHVACDehumidifierDXs
2167
+ dehumidifier_name = dehumidifier[0].name.to_s unless dehumidifier.empty?
2168
+
2169
+ # Fraction heat/cool load served
2170
+ if @hpxml_header.apply_ashrae140_assumptions
2171
+ total_heat_load_serveds[unit] = 1.0
2172
+ total_cool_load_serveds[unit] = 1.0
2173
+ else
2174
+ total_heat_load_serveds[unit] = hpxml_bldg.total_fraction_heat_load_served
2175
+ total_cool_load_serveds[unit] = hpxml_bldg.total_fraction_cool_load_served
2176
+ end
1951
2177
 
1952
- # Need to adjusted E+ EnergyTransfer meters for dehumidifiers
1953
- intgain_dehumidifier = nil
1954
- model.getZoneHVACDehumidifierDXs.each do |e|
1955
- next unless e.thermalZone.get.name.to_s == living_zone.name.to_s
2178
+ # Energy transferred in conditioned zone, used for determining heating (winter) vs cooling (summer)
2179
+ htg_cond_load_sensors[unit] = OpenStudio::Model::EnergyManagementSystemSensor.new(model, "Heating:EnergyTransfer:Zone:#{conditioned_zone_name.upcase}")
2180
+ htg_cond_load_sensors[unit].setName('htg_load_cond')
2181
+ clg_cond_load_sensors[unit] = OpenStudio::Model::EnergyManagementSystemSensor.new(model, "Cooling:EnergyTransfer:Zone:#{conditioned_zone_name.upcase}")
2182
+ clg_cond_load_sensors[unit].setName('clg_load_cond')
1956
2183
 
1957
- { 'Zone Dehumidifier Sensible Heating Energy' => 'ig_dehumidifier' }.each do |var, name|
1958
- intgain_dehumidifier = OpenStudio::Model::EnergyManagementSystemSensor.new(model, var)
1959
- intgain_dehumidifier.setName(name)
1960
- intgain_dehumidifier.setKeyName(e.name.to_s)
2184
+ # Energy transferred in duct zone(s)
2185
+ htg_duct_load_sensors[unit] = []
2186
+ clg_duct_load_sensors[unit] = []
2187
+ duct_zone_names.each do |duct_zone_name|
2188
+ htg_duct_load_sensors[unit] << OpenStudio::Model::EnergyManagementSystemSensor.new(model, "Heating:EnergyTransfer:Zone:#{duct_zone_name.upcase}")
2189
+ htg_duct_load_sensors[unit][-1].setName('htg_load_duct')
2190
+ clg_duct_load_sensors[unit] << OpenStudio::Model::EnergyManagementSystemSensor.new(model, "Cooling:EnergyTransfer:Zone:#{duct_zone_name.upcase}")
2191
+ clg_duct_load_sensors[unit][-1].setName('clg_load_duct')
1961
2192
  end
2193
+
2194
+ # Need to adjusted E+ EnergyTransfer meters for dehumidifier internal gains
2195
+ next if dehumidifier_name.nil?
2196
+
2197
+ dehumidifier_sensors[unit] = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Zone Dehumidifier Sensible Heating Energy')
2198
+ dehumidifier_sensors[unit].setName('ig_dehumidifier')
2199
+ dehumidifier_sensors[unit].setKeyName(dehumidifier_name)
1962
2200
  end
1963
2201
 
1964
2202
  # EMS program
1965
2203
  program = OpenStudio::Model::EnergyManagementSystemProgram.new(model)
1966
- program.setName(Constants.ObjectNameTotalLoadsProgram)
2204
+ program.setName('total loads program')
2205
+ program.additionalProperties.setFeature('ObjectType', Constants.ObjectNameTotalLoadsProgram)
1967
2206
  program.addLine('Set loads_htg_tot = 0')
1968
2207
  program.addLine('Set loads_clg_tot = 0')
1969
- program.addLine("If #{liv_load_sensors[:htg].name} > 0")
1970
- s = " Set loads_htg_tot = (#{tot_load_sensors[:htg].name} - #{tot_load_sensors[:clg].name}) * #{total_heat_load_served}"
1971
- if not intgain_dehumidifier.nil?
1972
- s += " - #{intgain_dehumidifier.name}"
2208
+ for unit in 0..hpxml_osm_map.size - 1
2209
+ program.addLine("If #{htg_cond_load_sensors[unit].name} > 0")
2210
+ program.addLine(" Set loads_htg_tot = loads_htg_tot + (#{htg_cond_load_sensors[unit].name} - #{clg_cond_load_sensors[unit].name}) * #{total_heat_load_serveds[unit]}")
2211
+ for i in 0..htg_duct_load_sensors[unit].size - 1
2212
+ program.addLine(" Set loads_htg_tot = loads_htg_tot + (#{htg_duct_load_sensors[unit][i].name} - #{clg_duct_load_sensors[unit][i].name}) * #{total_heat_load_serveds[unit]}")
2213
+ end
2214
+ if not dehumidifier_sensors[unit].nil?
2215
+ program.addLine(" Set loads_htg_tot = loads_htg_tot - #{dehumidifier_sensors[unit].name}")
2216
+ end
2217
+ program.addLine('EndIf')
1973
2218
  end
1974
- program.addLine(s)
1975
- program.addLine("ElseIf #{liv_load_sensors[:clg].name} > 0")
1976
- s = " Set loads_clg_tot = (#{tot_load_sensors[:clg].name} - #{tot_load_sensors[:htg].name}) * #{total_cool_load_served}"
1977
- if not intgain_dehumidifier.nil?
1978
- s += " + #{intgain_dehumidifier.name}"
2219
+ for unit in 0..hpxml_osm_map.size - 1
2220
+ program.addLine("If #{clg_cond_load_sensors[unit].name} > 0")
2221
+ program.addLine(" Set loads_clg_tot = loads_clg_tot + (#{clg_cond_load_sensors[unit].name} - #{htg_cond_load_sensors[unit].name}) * #{total_cool_load_serveds[unit]}")
2222
+ for i in 0..clg_duct_load_sensors[unit].size - 1
2223
+ program.addLine(" Set loads_clg_tot = loads_clg_tot + (#{clg_duct_load_sensors[unit][i].name} - #{htg_duct_load_sensors[unit][i].name}) * #{total_cool_load_serveds[unit]}")
2224
+ end
2225
+ if not dehumidifier_sensors[unit].nil?
2226
+ program.addLine(" Set loads_clg_tot = loads_clg_tot + #{dehumidifier_sensors[unit].name}")
2227
+ end
2228
+ program.addLine('EndIf')
1979
2229
  end
1980
- program.addLine(s)
1981
- program.addLine('EndIf')
1982
2230
 
1983
2231
  # EMS calling manager
1984
2232
  program_calling_manager = OpenStudio::Model::EnergyManagementSystemProgramCallingManager.new(model)
@@ -1986,27 +2234,11 @@ class OSModel
1986
2234
  program_calling_manager.setCallingPoint('EndOfZoneTimestepAfterZoneReporting')
1987
2235
  program_calling_manager.addProgram(program)
1988
2236
 
1989
- return liv_load_sensors, intgain_dehumidifier
2237
+ return htg_cond_load_sensors, clg_cond_load_sensors, total_heat_load_serveds, total_cool_load_serveds, dehumidifier_sensors
1990
2238
  end
1991
2239
 
1992
- def self.add_component_loads_output(model, living_zone, liv_load_sensors, intgain_dehumidifier, total_heat_load_served, total_cool_load_served)
1993
- # Prevent certain objects (e.g., OtherEquipment) from being counted towards both, e.g., ducts and internal gains
1994
- objects_already_processed = []
1995
-
1996
- # EMS Sensors: Surfaces, SubSurfaces, InternalMass
1997
- surfaces_sensors = { walls: [],
1998
- rim_joists: [],
1999
- foundation_walls: [],
2000
- floors: [],
2001
- slabs: [],
2002
- ceilings: [],
2003
- roofs: [],
2004
- windows_conduction: [],
2005
- windows_solar: [],
2006
- doors: [],
2007
- skylights_conduction: [],
2008
- skylights_solar: [],
2009
- internal_mass: [] }
2240
+ def add_component_loads_output(model, hpxml_osm_map, loads_data)
2241
+ htg_cond_load_sensors, clg_cond_load_sensors, total_heat_load_serveds, total_cool_load_serveds, dehumidifier_sensors = loads_data
2010
2242
 
2011
2243
  # Output diagnostics needed for some output variables used below
2012
2244
  output_diagnostics = model.getOutputDiagnostics
@@ -2014,397 +2246,376 @@ class OSModel
2014
2246
 
2015
2247
  area_tolerance = UnitConversions.convert(1.0, 'ft^2', 'm^2')
2016
2248
 
2017
- model.getSurfaces.sort.each do |s|
2018
- next unless s.space.get.thermalZone.get.name.to_s == living_zone.name.to_s
2249
+ nonsurf_names = ['intgains', 'lighting', 'infil', 'mechvent', 'natvent', 'whf', 'ducts']
2250
+ surf_names = ['walls', 'rim_joists', 'foundation_walls', 'floors', 'slabs', 'ceilings',
2251
+ 'roofs', 'windows_conduction', 'windows_solar', 'doors', 'skylights_conduction',
2252
+ 'skylights_solar', 'internal_mass']
2253
+
2254
+ # EMS program
2255
+ program = OpenStudio::Model::EnergyManagementSystemProgram.new(model)
2256
+ program.setName('component loads program')
2257
+ program.additionalProperties.setFeature('ObjectType', Constants.ObjectNameComponentLoadsProgram)
2019
2258
 
2020
- surface_type = s.additionalProperties.getFeatureAsString('SurfaceType')
2021
- if not surface_type.is_initialized
2022
- fail "Could not identify surface type for surface: '#{s.name}'."
2259
+ # Initialize
2260
+ [:htg, :clg].each do |mode|
2261
+ surf_names.each do |surf_name|
2262
+ program.addLine("Set loads_#{mode}_#{surf_name} = 0")
2263
+ end
2264
+ nonsurf_names.each do |nonsurf_name|
2265
+ program.addLine("Set loads_#{mode}_#{nonsurf_name} = 0")
2023
2266
  end
2267
+ end
2024
2268
 
2025
- surface_type = surface_type.get
2269
+ hpxml_osm_map.values.each_with_index do |unit_model, unit|
2270
+ conditioned_zone = unit_model.getThermalZones.find { |z| z.additionalProperties.getFeatureAsString('ObjectType').to_s == HPXML::LocationConditionedSpace }
2026
2271
 
2027
- s.subSurfaces.each do |ss|
2028
- # Conduction (windows, skylights, doors)
2029
- key = { 'Window' => :windows_conduction,
2030
- 'Door' => :doors,
2031
- 'Skylight' => :skylights_conduction }[surface_type]
2032
- fail "Unexpected subsurface for component loads: '#{ss.name}'." if key.nil?
2272
+ # Prevent certain objects (e.g., OtherEquipment) from being counted towards both, e.g., ducts and internal gains
2273
+ objects_already_processed = []
2033
2274
 
2034
- if (surface_type == 'Window') || (surface_type == 'Skylight')
2035
- vars = { 'Surface Inside Face Convection Heat Gain Energy' => 'ss_conv',
2036
- 'Surface Inside Face Internal Gains Radiation Heat Gain Energy' => 'ss_ig',
2037
- 'Surface Inside Face Net Surface Thermal Radiation Heat Gain Energy' => 'ss_surf' }
2038
- else
2039
- vars = { 'Surface Inside Face Solar Radiation Heat Gain Energy' => 'ss_sol',
2040
- 'Surface Inside Face Lights Radiation Heat Gain Energy' => 'ss_lgt',
2041
- 'Surface Inside Face Convection Heat Gain Energy' => 'ss_conv',
2042
- 'Surface Inside Face Internal Gains Radiation Heat Gain Energy' => 'ss_ig',
2043
- 'Surface Inside Face Net Surface Thermal Radiation Heat Gain Energy' => 'ss_surf' }
2275
+ # EMS Sensors: Surfaces, SubSurfaces, InternalMass
2276
+ surfaces_sensors = {}
2277
+ surf_names.each do |surf_name|
2278
+ surfaces_sensors[surf_name.to_sym] = []
2279
+ end
2280
+
2281
+ unit_model.getSurfaces.sort.each do |s|
2282
+ next unless s.space.get.thermalZone.get.name.to_s == conditioned_zone.name.to_s
2283
+
2284
+ surface_type = s.additionalProperties.getFeatureAsString('SurfaceType')
2285
+ if not surface_type.is_initialized
2286
+ fail "Could not identify surface type for surface: '#{s.name}'."
2044
2287
  end
2045
2288
 
2046
- vars.each do |var, name|
2289
+ surface_type = surface_type.get
2290
+
2291
+ s.subSurfaces.each do |ss|
2292
+ # Conduction (windows, skylights, doors)
2293
+ key = { 'Window' => :windows_conduction,
2294
+ 'Door' => :doors,
2295
+ 'Skylight' => :skylights_conduction }[surface_type]
2296
+ fail "Unexpected subsurface for component loads: '#{ss.name}'." if key.nil?
2297
+
2298
+ if (surface_type == 'Window') || (surface_type == 'Skylight')
2299
+ vars = { 'Surface Inside Face Convection Heat Gain Energy' => 'ss_conv',
2300
+ 'Surface Inside Face Internal Gains Radiation Heat Gain Energy' => 'ss_ig',
2301
+ 'Surface Inside Face Net Surface Thermal Radiation Heat Gain Energy' => 'ss_surf' }
2302
+ else
2303
+ vars = { 'Surface Inside Face Solar Radiation Heat Gain Energy' => 'ss_sol',
2304
+ 'Surface Inside Face Lights Radiation Heat Gain Energy' => 'ss_lgt',
2305
+ 'Surface Inside Face Convection Heat Gain Energy' => 'ss_conv',
2306
+ 'Surface Inside Face Internal Gains Radiation Heat Gain Energy' => 'ss_ig',
2307
+ 'Surface Inside Face Net Surface Thermal Radiation Heat Gain Energy' => 'ss_surf' }
2308
+ end
2309
+
2310
+ vars.each do |var, name|
2311
+ surfaces_sensors[key] << []
2312
+ sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, var)
2313
+ sensor.setName(name)
2314
+ sensor.setKeyName(ss.name.to_s)
2315
+ surfaces_sensors[key][-1] << sensor
2316
+ end
2317
+
2318
+ # Solar (windows, skylights)
2319
+ next unless (surface_type == 'Window') || (surface_type == 'Skylight')
2320
+
2321
+ key = { 'Window' => :windows_solar,
2322
+ 'Skylight' => :skylights_solar }[surface_type]
2323
+ vars = { 'Surface Window Transmitted Solar Radiation Energy' => 'ss_trans_in',
2324
+ 'Surface Window Shortwave from Zone Back Out Window Heat Transfer Rate' => 'ss_back_out',
2325
+ 'Surface Window Total Glazing Layers Absorbed Shortwave Radiation Rate' => 'ss_sw_abs',
2326
+ 'Surface Window Total Glazing Layers Absorbed Solar Radiation Energy' => 'ss_sol_abs',
2327
+ 'Surface Inside Face Initial Transmitted Diffuse Transmitted Out Window Solar Radiation Rate' => 'ss_trans_out' }
2328
+
2047
2329
  surfaces_sensors[key] << []
2048
- sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, var)
2049
- sensor.setName(name)
2050
- sensor.setKeyName(ss.name.to_s)
2051
- surfaces_sensors[key][-1] << sensor
2330
+ vars.each do |var, name|
2331
+ sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, var)
2332
+ sensor.setName(name)
2333
+ sensor.setKeyName(ss.name.to_s)
2334
+ surfaces_sensors[key][-1] << sensor
2335
+ end
2052
2336
  end
2053
2337
 
2054
- # Solar (windows, skylights)
2055
- next unless (surface_type == 'Window') || (surface_type == 'Skylight')
2338
+ next if s.netArea < area_tolerance # Skip parent surfaces (of subsurfaces) that have near zero net area
2056
2339
 
2057
- key = { 'Window' => :windows_solar,
2058
- 'Skylight' => :skylights_solar }[surface_type]
2059
- vars = { 'Surface Window Transmitted Solar Radiation Energy' => 'ss_trans_in',
2060
- 'Surface Window Shortwave from Zone Back Out Window Heat Transfer Rate' => 'ss_back_out',
2061
- 'Surface Window Total Glazing Layers Absorbed Shortwave Radiation Rate' => 'ss_sw_abs',
2062
- 'Surface Window Total Glazing Layers Absorbed Solar Radiation Energy' => 'ss_sol_abs',
2063
- 'Surface Inside Face Initial Transmitted Diffuse Transmitted Out Window Solar Radiation Rate' => 'ss_trans_out' }
2340
+ key = { 'FoundationWall' => :foundation_walls,
2341
+ 'RimJoist' => :rim_joists,
2342
+ 'Wall' => :walls,
2343
+ 'Slab' => :slabs,
2344
+ 'Floor' => :floors,
2345
+ 'Ceiling' => :ceilings,
2346
+ 'Roof' => :roofs,
2347
+ 'InferredCeiling' => :internal_mass,
2348
+ 'InferredFloor' => :internal_mass }[surface_type]
2349
+ fail "Unexpected surface for component loads: '#{s.name}'." if key.nil?
2064
2350
 
2065
2351
  surfaces_sensors[key] << []
2066
- vars.each do |var, name|
2352
+ { 'Surface Inside Face Convection Heat Gain Energy' => 's_conv',
2353
+ 'Surface Inside Face Internal Gains Radiation Heat Gain Energy' => 's_ig',
2354
+ 'Surface Inside Face Solar Radiation Heat Gain Energy' => 's_sol',
2355
+ 'Surface Inside Face Lights Radiation Heat Gain Energy' => 's_lgt',
2356
+ 'Surface Inside Face Net Surface Thermal Radiation Heat Gain Energy' => 's_surf' }.each do |var, name|
2067
2357
  sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, var)
2068
2358
  sensor.setName(name)
2069
- sensor.setKeyName(ss.name.to_s)
2359
+ sensor.setKeyName(s.name.to_s)
2070
2360
  surfaces_sensors[key][-1] << sensor
2071
2361
  end
2072
2362
  end
2073
2363
 
2074
- next if s.netArea < area_tolerance # Skip parent surfaces (of subsurfaces) that have near zero net area
2075
-
2076
- key = { 'FoundationWall' => :foundation_walls,
2077
- 'RimJoist' => :rim_joists,
2078
- 'Wall' => :walls,
2079
- 'Slab' => :slabs,
2080
- 'Floor' => :floors,
2081
- 'Ceiling' => :ceilings,
2082
- 'Roof' => :roofs,
2083
- 'InferredCeiling' => :internal_mass,
2084
- 'InferredFloor' => :internal_mass }[surface_type]
2085
- fail "Unexpected surface for component loads: '#{s.name}'." if key.nil?
2086
-
2087
- surfaces_sensors[key] << []
2088
- { 'Surface Inside Face Convection Heat Gain Energy' => 's_conv',
2089
- 'Surface Inside Face Internal Gains Radiation Heat Gain Energy' => 's_ig',
2090
- 'Surface Inside Face Solar Radiation Heat Gain Energy' => 's_sol',
2091
- 'Surface Inside Face Lights Radiation Heat Gain Energy' => 's_lgt',
2092
- 'Surface Inside Face Net Surface Thermal Radiation Heat Gain Energy' => 's_surf' }.each do |var, name|
2093
- sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, var)
2094
- sensor.setName(name)
2095
- sensor.setKeyName(s.name.to_s)
2096
- surfaces_sensors[key][-1] << sensor
2097
- end
2098
- end
2099
-
2100
- model.getInternalMasss.sort.each do |m|
2101
- next unless m.space.get.thermalZone.get.name.to_s == living_zone.name.to_s
2102
-
2103
- surfaces_sensors[:internal_mass] << []
2104
- { 'Surface Inside Face Convection Heat Gain Energy' => 'im_conv',
2105
- 'Surface Inside Face Internal Gains Radiation Heat Gain Energy' => 'im_ig',
2106
- 'Surface Inside Face Solar Radiation Heat Gain Energy' => 'im_sol',
2107
- 'Surface Inside Face Lights Radiation Heat Gain Energy' => 'im_lgt',
2108
- 'Surface Inside Face Net Surface Thermal Radiation Heat Gain Energy' => 'im_surf' }.each do |var, name|
2109
- sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, var)
2110
- sensor.setName(name)
2111
- sensor.setKeyName(m.name.to_s)
2112
- surfaces_sensors[:internal_mass][-1] << sensor
2113
- end
2114
- end
2115
-
2116
- # EMS Sensors: Infiltration, Mechanical Ventilation, Natural Ventilation, Whole House Fan
2117
- infil_sensors = []
2118
- natvent_sensors = []
2119
- whf_sensors = []
2120
- { Constants.ObjectNameInfiltration => infil_sensors,
2121
- Constants.ObjectNameNaturalVentilation => natvent_sensors,
2122
- Constants.ObjectNameWholeHouseFan => whf_sensors }.each do |prefix, array|
2123
- model.getSpaceInfiltrationDesignFlowRates.sort.each do |i|
2124
- next unless i.name.to_s.start_with? prefix
2125
- next unless i.space.get.thermalZone.get.name.to_s == living_zone.name.to_s
2126
-
2127
- { 'Infiltration Sensible Heat Gain Energy' => prefix.gsub(' ', '_') + '_' + 'gain',
2128
- 'Infiltration Sensible Heat Loss Energy' => prefix.gsub(' ', '_') + '_' + 'loss' }.each do |var, name|
2364
+ unit_model.getInternalMasss.sort.each do |m|
2365
+ next unless m.space.get.thermalZone.get.name.to_s == conditioned_zone.name.to_s
2366
+
2367
+ surfaces_sensors[:internal_mass] << []
2368
+ { 'Surface Inside Face Convection Heat Gain Energy' => 'im_conv',
2369
+ 'Surface Inside Face Internal Gains Radiation Heat Gain Energy' => 'im_ig',
2370
+ 'Surface Inside Face Solar Radiation Heat Gain Energy' => 'im_sol',
2371
+ 'Surface Inside Face Lights Radiation Heat Gain Energy' => 'im_lgt',
2372
+ 'Surface Inside Face Net Surface Thermal Radiation Heat Gain Energy' => 'im_surf' }.each do |var, name|
2373
+ sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, var)
2374
+ sensor.setName(name)
2375
+ sensor.setKeyName(m.name.to_s)
2376
+ surfaces_sensors[:internal_mass][-1] << sensor
2377
+ end
2378
+ end
2379
+
2380
+ # EMS Sensors: Infiltration, Natural Ventilation, Whole House Fan
2381
+ infil_sensors, natvent_sensors, whf_sensors = [], [], []
2382
+ unit_model.getSpaceInfiltrationDesignFlowRates.sort.each do |i|
2383
+ next unless i.space.get.thermalZone.get.name.to_s == conditioned_zone.name.to_s
2384
+
2385
+ object_type = i.additionalProperties.getFeatureAsString('ObjectType').get
2386
+
2387
+ { 'Infiltration Sensible Heat Gain Energy' => 'airflow_gain',
2388
+ 'Infiltration Sensible Heat Loss Energy' => 'airflow_loss' }.each do |var, name|
2129
2389
  airflow_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, var)
2130
2390
  airflow_sensor.setName(name)
2131
2391
  airflow_sensor.setKeyName(i.name.to_s)
2132
- array << airflow_sensor
2392
+ if object_type == Constants.ObjectNameInfiltration
2393
+ infil_sensors << airflow_sensor
2394
+ elsif object_type == Constants.ObjectNameNaturalVentilation
2395
+ natvent_sensors << airflow_sensor
2396
+ elsif object_type == Constants.ObjectNameWholeHouseFan
2397
+ whf_sensors << airflow_sensor
2398
+ end
2133
2399
  end
2134
2400
  end
2135
- end
2136
2401
 
2137
- mechvents_sensors = []
2138
- model.getElectricEquipments.sort.each do |o|
2139
- next unless o.name.to_s.start_with? Constants.ObjectNameMechanicalVentilation
2402
+ # EMS Sensors: Mechanical Ventilation
2403
+ mechvents_sensors = []
2404
+ unit_model.getElectricEquipments.sort.each do |o|
2405
+ next unless o.endUseSubcategory == Constants.ObjectNameMechanicalVentilation
2140
2406
 
2141
- mechvents_sensors << []
2142
- { 'Electric Equipment Convective Heating Energy' => 'mv_conv',
2143
- 'Electric Equipment Radiant Heating Energy' => 'mv_rad' }.each do |var, name|
2144
- mechvent_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, var)
2145
- mechvent_sensor.setName(name)
2146
- mechvent_sensor.setKeyName(o.name.to_s)
2147
- mechvents_sensors[-1] << mechvent_sensor
2148
2407
  objects_already_processed << o
2408
+ { 'Electric Equipment Convective Heating Energy' => 'mv_conv',
2409
+ 'Electric Equipment Radiant Heating Energy' => 'mv_rad' }.each do |var, name|
2410
+ mechvent_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, var)
2411
+ mechvent_sensor.setName(name)
2412
+ mechvent_sensor.setKeyName(o.name.to_s)
2413
+ mechvents_sensors << mechvent_sensor
2414
+ end
2149
2415
  end
2150
- end
2151
- model.getOtherEquipments.sort.each do |o|
2152
- next unless o.name.to_s.start_with? Constants.ObjectNameMechanicalVentilationHouseFan
2416
+ unit_model.getOtherEquipments.sort.each do |o|
2417
+ next unless o.endUseSubcategory == Constants.ObjectNameMechanicalVentilationHouseFan
2153
2418
 
2154
- mechvents_sensors << []
2155
- { 'Other Equipment Convective Heating Energy' => 'mv_conv',
2156
- 'Other Equipment Radiant Heating Energy' => 'mv_rad' }.each do |var, name|
2157
- mechvent_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, var)
2158
- mechvent_sensor.setName(name)
2159
- mechvent_sensor.setKeyName(o.name.to_s)
2160
- mechvents_sensors[-1] << mechvent_sensor
2161
2419
  objects_already_processed << o
2420
+ { 'Other Equipment Convective Heating Energy' => 'mv_conv',
2421
+ 'Other Equipment Radiant Heating Energy' => 'mv_rad' }.each do |var, name|
2422
+ mechvent_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, var)
2423
+ mechvent_sensor.setName(name)
2424
+ mechvent_sensor.setKeyName(o.name.to_s)
2425
+ mechvents_sensors << mechvent_sensor
2426
+ end
2162
2427
  end
2163
- end
2164
2428
 
2165
- # EMS Sensors: Ducts
2166
- ducts_sensors = []
2167
- ducts_mix_gain_sensor = nil
2168
- ducts_mix_loss_sensor = nil
2429
+ # EMS Sensors: Ducts
2430
+ ducts_sensors = []
2431
+ ducts_mix_gain_sensor = nil
2432
+ ducts_mix_loss_sensor = nil
2433
+ conditioned_zone.zoneMixing.each do |zone_mix|
2434
+ object_type = zone_mix.additionalProperties.getFeatureAsString('ObjectType').to_s
2435
+ next unless object_type == Constants.ObjectNameDuctLoad
2169
2436
 
2170
- has_duct_zone_mixing = false
2171
- living_zone.airLoopHVACs.sort.each do |airloop|
2172
- living_zone.zoneMixing.each do |zone_mix|
2173
- next unless zone_mix.name.to_s.start_with? airloop.name.to_s.gsub(' ', '_')
2437
+ ducts_mix_gain_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Zone Mixing Sensible Heat Gain Energy')
2438
+ ducts_mix_gain_sensor.setName('duct_mix_gain')
2439
+ ducts_mix_gain_sensor.setKeyName(conditioned_zone.name.to_s)
2174
2440
 
2175
- has_duct_zone_mixing = true
2441
+ ducts_mix_loss_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Zone Mixing Sensible Heat Loss Energy')
2442
+ ducts_mix_loss_sensor.setName('duct_mix_loss')
2443
+ ducts_mix_loss_sensor.setKeyName(conditioned_zone.name.to_s)
2176
2444
  end
2177
- end
2178
-
2179
- if has_duct_zone_mixing
2180
- ducts_mix_gain_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Zone Mixing Sensible Heat Gain Energy')
2181
- ducts_mix_gain_sensor.setName('duct_mix_gain')
2182
- ducts_mix_gain_sensor.setKeyName(living_zone.name.to_s)
2183
-
2184
- ducts_mix_loss_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Zone Mixing Sensible Heat Loss Energy')
2185
- ducts_mix_loss_sensor.setName('duct_mix_loss')
2186
- ducts_mix_loss_sensor.setKeyName(living_zone.name.to_s)
2187
- end
2188
-
2189
- # Duct losses
2190
- model.getOtherEquipments.sort.each do |o|
2191
- next if objects_already_processed.include? o
2445
+ unit_model.getOtherEquipments.sort.each do |o|
2446
+ next if objects_already_processed.include? o
2447
+ next unless o.endUseSubcategory == Constants.ObjectNameDuctLoad
2192
2448
 
2193
- is_duct_load = o.additionalProperties.getFeatureAsBoolean(Constants.IsDuctLoadForReport)
2194
- next unless is_duct_load.is_initialized
2449
+ objects_already_processed << o
2450
+ { 'Other Equipment Convective Heating Energy' => 'ducts_conv',
2451
+ 'Other Equipment Radiant Heating Energy' => 'ducts_rad' }.each do |var, name|
2452
+ ducts_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, var)
2453
+ ducts_sensor.setName(name)
2454
+ ducts_sensor.setKeyName(o.name.to_s)
2455
+ ducts_sensors << ducts_sensor
2456
+ end
2457
+ end
2195
2458
 
2196
- objects_already_processed << o
2197
- next unless is_duct_load.get
2459
+ # EMS Sensors: Lighting
2460
+ lightings_sensors = []
2461
+ unit_model.getLightss.sort.each do |e|
2462
+ next unless e.space.get.thermalZone.get.name.to_s == conditioned_zone.name.to_s
2198
2463
 
2199
- ducts_sensors << []
2200
- { 'Other Equipment Convective Heating Energy' => 'ducts_conv',
2201
- 'Other Equipment Radiant Heating Energy' => 'ducts_rad' }.each do |var, name|
2202
- ducts_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, var)
2203
- ducts_sensor.setName(name)
2204
- ducts_sensor.setKeyName(o.name.to_s)
2205
- ducts_sensors[-1] << ducts_sensor
2464
+ { 'Lights Convective Heating Energy' => 'ig_lgt_conv',
2465
+ 'Lights Radiant Heating Energy' => 'ig_lgt_rad',
2466
+ 'Lights Visible Radiation Heating Energy' => 'ig_lgt_vis' }.each do |var, name|
2467
+ intgains_lights_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, var)
2468
+ intgains_lights_sensor.setName(name)
2469
+ intgains_lights_sensor.setKeyName(e.name.to_s)
2470
+ lightings_sensors << intgains_lights_sensor
2471
+ end
2206
2472
  end
2207
- end
2208
2473
 
2209
- # EMS Sensors: Lighting
2210
- lightings_sensors = []
2211
- lightings_sensors << []
2212
- model.getLightss.sort.each do |e|
2213
- next unless e.space.get.thermalZone.get.name.to_s == living_zone.name.to_s
2474
+ # EMS Sensors: Internal Gains
2475
+ intgains_sensors = []
2476
+ unit_model.getElectricEquipments.sort.each do |o|
2477
+ next if objects_already_processed.include? o
2478
+ next unless o.space.get.thermalZone.get.name.to_s == conditioned_zone.name.to_s
2214
2479
 
2215
- lightings_sensors << []
2216
- { 'Lights Convective Heating Energy' => 'ig_lgt_conv',
2217
- 'Lights Radiant Heating Energy' => 'ig_lgt_rad',
2218
- 'Lights Visible Radiation Heating Energy' => 'ig_lgt_vis' }.each do |var, name|
2219
- intgains_lights_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, var)
2220
- intgains_lights_sensor.setName(name)
2221
- intgains_lights_sensor.setKeyName(e.name.to_s)
2222
- lightings_sensors[-1] << intgains_lights_sensor
2480
+ { 'Electric Equipment Convective Heating Energy' => 'ig_ee_conv',
2481
+ 'Electric Equipment Radiant Heating Energy' => 'ig_ee_rad' }.each do |var, name|
2482
+ intgains_elec_equip_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, var)
2483
+ intgains_elec_equip_sensor.setName(name)
2484
+ intgains_elec_equip_sensor.setKeyName(o.name.to_s)
2485
+ intgains_sensors << intgains_elec_equip_sensor
2486
+ end
2223
2487
  end
2224
- end
2225
2488
 
2226
- # EMS Sensors: Internal Gains
2227
- intgains_sensors = []
2489
+ unit_model.getOtherEquipments.sort.each do |o|
2490
+ next if objects_already_processed.include? o
2491
+ next unless o.space.get.thermalZone.get.name.to_s == conditioned_zone.name.to_s
2228
2492
 
2229
- model.getElectricEquipments.sort.each do |o|
2230
- next unless o.space.get.thermalZone.get.name.to_s == living_zone.name.to_s
2231
- next if objects_already_processed.include? o
2232
-
2233
- intgains_sensors << []
2234
- { 'Electric Equipment Convective Heating Energy' => 'ig_ee_conv',
2235
- 'Electric Equipment Radiant Heating Energy' => 'ig_ee_rad' }.each do |var, name|
2236
- intgains_elec_equip_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, var)
2237
- intgains_elec_equip_sensor.setName(name)
2238
- intgains_elec_equip_sensor.setKeyName(o.name.to_s)
2239
- intgains_sensors[-1] << intgains_elec_equip_sensor
2493
+ { 'Other Equipment Convective Heating Energy' => 'ig_oe_conv',
2494
+ 'Other Equipment Radiant Heating Energy' => 'ig_oe_rad' }.each do |var, name|
2495
+ intgains_other_equip_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, var)
2496
+ intgains_other_equip_sensor.setName(name)
2497
+ intgains_other_equip_sensor.setKeyName(o.name.to_s)
2498
+ intgains_sensors << intgains_other_equip_sensor
2499
+ end
2240
2500
  end
2241
- end
2242
2501
 
2243
- model.getOtherEquipments.sort.each do |o|
2244
- next unless o.space.get.thermalZone.get.name.to_s == living_zone.name.to_s
2245
- next if objects_already_processed.include? o
2502
+ unit_model.getPeoples.sort.each do |e|
2503
+ next unless e.space.get.thermalZone.get.name.to_s == conditioned_zone.name.to_s
2246
2504
 
2247
- intgains_sensors << []
2248
- { 'Other Equipment Convective Heating Energy' => 'ig_oe_conv',
2249
- 'Other Equipment Radiant Heating Energy' => 'ig_oe_rad' }.each do |var, name|
2250
- intgains_other_equip_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, var)
2251
- intgains_other_equip_sensor.setName(name)
2252
- intgains_other_equip_sensor.setKeyName(o.name.to_s)
2253
- intgains_sensors[-1] << intgains_other_equip_sensor
2505
+ { 'People Convective Heating Energy' => 'ig_ppl_conv',
2506
+ 'People Radiant Heating Energy' => 'ig_ppl_rad' }.each do |var, name|
2507
+ intgains_people = OpenStudio::Model::EnergyManagementSystemSensor.new(model, var)
2508
+ intgains_people.setName(name)
2509
+ intgains_people.setKeyName(e.name.to_s)
2510
+ intgains_sensors << intgains_people
2511
+ end
2254
2512
  end
2255
- end
2256
2513
 
2257
- model.getPeoples.sort.each do |e|
2258
- next unless e.space.get.thermalZone.get.name.to_s == living_zone.name.to_s
2259
-
2260
- intgains_sensors << []
2261
- { 'People Convective Heating Energy' => 'ig_ppl_conv',
2262
- 'People Radiant Heating Energy' => 'ig_ppl_rad' }.each do |var, name|
2263
- intgains_people = OpenStudio::Model::EnergyManagementSystemSensor.new(model, var)
2264
- intgains_people.setName(name)
2265
- intgains_people.setKeyName(e.name.to_s)
2266
- intgains_sensors[-1] << intgains_people
2514
+ if not dehumidifier_sensors[unit].nil?
2515
+ intgains_sensors << dehumidifier_sensors[unit]
2267
2516
  end
2268
- end
2269
2517
 
2270
- if not intgain_dehumidifier.nil?
2271
- intgains_sensors[-1] << intgain_dehumidifier
2272
- end
2518
+ intgains_dhw_sensors = {}
2273
2519
 
2274
- intgains_dhw_sensors = {}
2520
+ (unit_model.getWaterHeaterMixeds + unit_model.getWaterHeaterStratifieds).sort.each do |wh|
2521
+ next unless wh.ambientTemperatureThermalZone.is_initialized
2522
+ next unless wh.ambientTemperatureThermalZone.get.name.to_s == conditioned_zone.name.to_s
2275
2523
 
2276
- (model.getWaterHeaterMixeds + model.getWaterHeaterStratifieds).sort.each do |wh|
2277
- next unless wh.ambientTemperatureThermalZone.is_initialized
2278
- next unless wh.ambientTemperatureThermalZone.get.name.to_s == living_zone.name.to_s
2524
+ dhw_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Water Heater Heat Loss Energy')
2525
+ dhw_sensor.setName('dhw_loss')
2526
+ dhw_sensor.setKeyName(wh.name.to_s)
2279
2527
 
2280
- dhw_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Water Heater Heat Loss Energy')
2281
- dhw_sensor.setName('dhw_loss')
2282
- dhw_sensor.setKeyName(wh.name.to_s)
2528
+ if wh.is_a? OpenStudio::Model::WaterHeaterMixed
2529
+ oncycle_loss = wh.onCycleLossFractiontoThermalZone
2530
+ offcycle_loss = wh.offCycleLossFractiontoThermalZone
2531
+ else
2532
+ oncycle_loss = wh.skinLossFractiontoZone
2533
+ offcycle_loss = wh.offCycleFlueLossFractiontoZone
2534
+ end
2283
2535
 
2284
- if wh.is_a? OpenStudio::Model::WaterHeaterMixed
2285
- oncycle_loss = wh.onCycleLossFractiontoThermalZone
2286
- offcycle_loss = wh.offCycleLossFractiontoThermalZone
2287
- else
2288
- oncycle_loss = wh.skinLossFractiontoZone
2289
- offcycle_loss = wh.offCycleFlueLossFractiontoZone
2536
+ dhw_rtf_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Water Heater Runtime Fraction')
2537
+ dhw_rtf_sensor.setName('dhw_rtf')
2538
+ dhw_rtf_sensor.setKeyName(wh.name.to_s)
2539
+
2540
+ intgains_dhw_sensors[dhw_sensor] = [offcycle_loss, oncycle_loss, dhw_rtf_sensor]
2541
+ end
2542
+
2543
+ # EMS program: Surfaces
2544
+ surfaces_sensors.each do |k, surface_sensors|
2545
+ program.addLine("Set hr_#{k} = 0")
2546
+ surface_sensors.each do |sensors|
2547
+ s = "Set hr_#{k} = hr_#{k}"
2548
+ sensors.each do |sensor|
2549
+ # remove ss_net if switch
2550
+ if sensor.name.to_s.start_with?('ss_net', 'ss_sol_abs', 'ss_trans_in')
2551
+ s += " - #{sensor.name}"
2552
+ elsif sensor.name.to_s.start_with?('ss_sw_abs', 'ss_trans_out', 'ss_back_out')
2553
+ s += " + #{sensor.name} * ZoneTimestep * 3600"
2554
+ else
2555
+ s += " + #{sensor.name}"
2556
+ end
2557
+ end
2558
+ program.addLine(s) if sensors.size > 0
2559
+ end
2290
2560
  end
2291
2561
 
2292
- dhw_rtf_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Water Heater Runtime Fraction')
2293
- dhw_rtf_sensor.setName('dhw_rtf')
2294
- dhw_rtf_sensor.setKeyName(wh.name.to_s)
2562
+ # EMS program: Internal Gains, Lighting, Infiltration, Natural Ventilation, Mechanical Ventilation, Ducts
2563
+ { 'intgains' => intgains_sensors,
2564
+ 'lighting' => lightings_sensors,
2565
+ 'infil' => infil_sensors,
2566
+ 'natvent' => natvent_sensors,
2567
+ 'whf' => whf_sensors,
2568
+ 'mechvent' => mechvents_sensors,
2569
+ 'ducts' => ducts_sensors }.each do |loadtype, sensors|
2570
+ program.addLine("Set hr_#{loadtype} = 0")
2571
+ next if sensors.empty?
2295
2572
 
2296
- intgains_dhw_sensors[dhw_sensor] = [offcycle_loss, oncycle_loss, dhw_rtf_sensor]
2297
- end
2298
-
2299
- nonsurf_names = ['intgains', 'lighting', 'infil', 'mechvent', 'natvent', 'whf', 'ducts']
2300
-
2301
- # EMS program
2302
- program = OpenStudio::Model::EnergyManagementSystemProgram.new(model)
2303
- program.setName(Constants.ObjectNameComponentLoadsProgram)
2304
-
2305
- # EMS program: Surfaces
2306
- surfaces_sensors.each do |k, surface_sensors|
2307
- program.addLine("Set hr_#{k} = 0")
2308
- surface_sensors.each do |sensors|
2309
- s = "Set hr_#{k} = hr_#{k}"
2573
+ s = "Set hr_#{loadtype} = hr_#{loadtype}"
2310
2574
  sensors.each do |sensor|
2311
- # remove ss_net if switch
2312
- if sensor.name.to_s.start_with?('ss_net', 'ss_sol_abs', 'ss_trans_in')
2575
+ if ['intgains', 'lighting', 'mechvent', 'ducts'].include? loadtype
2313
2576
  s += " - #{sensor.name}"
2314
- elsif sensor.name.to_s.start_with?('ss_sw_abs', 'ss_trans_out', 'ss_back_out')
2315
- s += " + #{sensor.name} * ZoneTimestep * 3600"
2316
- else
2577
+ elsif sensor.name.to_s.include? 'gain'
2578
+ s += " - #{sensor.name}"
2579
+ elsif sensor.name.to_s.include? 'loss'
2317
2580
  s += " + #{sensor.name}"
2318
2581
  end
2319
2582
  end
2320
- program.addLine(s) if sensors.size > 0
2321
- end
2322
- end
2323
-
2324
- # EMS program: Lighting
2325
- program.addLine('Set hr_lighting = 0')
2326
- lightings_sensors.each do |lighting_sensors|
2327
- s = 'Set hr_lighting = hr_lighting'
2328
- lighting_sensors.each do |sensor|
2329
- s += " - #{sensor.name}"
2330
- end
2331
- program.addLine(s) if lighting_sensors.size > 0
2332
- end
2333
-
2334
- # EMS program: Internal gains
2335
- program.addLine('Set hr_intgains = 0')
2336
- intgains_sensors.each do |intgain_sensors|
2337
- s = 'Set hr_intgains = hr_intgains'
2338
- intgain_sensors.each do |sensor|
2339
- s += " - #{sensor.name}"
2340
- end
2341
- program.addLine(s) if intgain_sensors.size > 0
2342
- end
2343
- intgains_dhw_sensors.each do |sensor, vals|
2344
- off_loss, on_loss, rtf_sensor = vals
2345
- program.addLine("Set hr_intgains = hr_intgains + #{sensor.name} * (#{off_loss}*(1-#{rtf_sensor.name}) + #{on_loss}*#{rtf_sensor.name})") # Water heater tank losses to zone
2346
- end
2583
+ program.addLine(s)
2584
+ end
2585
+ intgains_dhw_sensors.each do |sensor, vals|
2586
+ off_loss, on_loss, rtf_sensor = vals
2587
+ program.addLine("Set hr_intgains = hr_intgains + #{sensor.name} * (#{off_loss}*(1-#{rtf_sensor.name}) + #{on_loss}*#{rtf_sensor.name})") # Water heater tank losses to zone
2588
+ end
2589
+ if (not ducts_mix_loss_sensor.nil?) && (not ducts_mix_gain_sensor.nil?)
2590
+ program.addLine("Set hr_ducts = hr_ducts + (#{ducts_mix_loss_sensor.name} - #{ducts_mix_gain_sensor.name})")
2591
+ end
2592
+
2593
+ # EMS program: Heating vs Cooling logic
2594
+ program.addLine('Set htg_mode = 0')
2595
+ program.addLine('Set clg_mode = 0')
2596
+ program.addLine("If (#{htg_cond_load_sensors[unit].name} > 0)") # Assign hour to heating if heating load
2597
+ program.addLine(" Set htg_mode = #{total_heat_load_serveds[unit]}")
2598
+ program.addLine("ElseIf (#{clg_cond_load_sensors[unit].name} > 0)") # Assign hour to cooling if cooling load
2599
+ program.addLine(" Set clg_mode = #{total_cool_load_serveds[unit]}")
2600
+ program.addLine("ElseIf (#{@clg_ssn_sensor.name} > 0)") # No load, assign hour to cooling if in cooling season definition (Note: natural ventilation & whole house fan only operate during the cooling season)
2601
+ program.addLine(" Set clg_mode = #{total_cool_load_serveds[unit]}")
2602
+ program.addLine('Else') # No load, assign hour to heating if not in cooling season definition
2603
+ program.addLine(" Set htg_mode = #{total_heat_load_serveds[unit]}")
2604
+ program.addLine('EndIf')
2347
2605
 
2348
- # EMS program: Infiltration, Natural Ventilation, Mechanical Ventilation, Ducts
2349
- { infil_sensors => 'infil',
2350
- natvent_sensors => 'natvent',
2351
- whf_sensors => 'whf' }.each do |sensors, loadtype|
2352
- program.addLine("Set hr_#{loadtype} = 0")
2353
- s = "Set hr_#{loadtype} = hr_#{loadtype}"
2354
- sensors.each do |sensor|
2355
- if sensor.name.to_s.include? 'gain'
2356
- # FIXME: Workaround for https://github.com/NREL/EnergyPlus/issues/9934
2357
- # Remove when the issue is resolved
2358
- if loadtype == 'infil'
2359
- s += " - (#{sensor.name} * 3600)"
2360
- else
2361
- s += " - #{sensor.name}"
2362
- end
2363
- elsif sensor.name.to_s.include? 'loss'
2364
- s += " + #{sensor.name}"
2606
+ unit_multiplier = @hpxml_bldg.building_construction.number_of_units
2607
+ [:htg, :clg].each do |mode|
2608
+ if mode == :htg
2609
+ sign = ''
2610
+ else
2611
+ sign = '-'
2365
2612
  end
2366
- end
2367
- program.addLine(s) if sensors.size > 0
2368
- end
2369
- { mechvents_sensors => 'mechvent',
2370
- ducts_sensors => 'ducts' }.each do |all_sensors, loadtype|
2371
- program.addLine("Set hr_#{loadtype} = 0")
2372
- all_sensors.each do |sensors|
2373
- s = "Set hr_#{loadtype} = hr_#{loadtype}"
2374
- sensors.each do |sensor|
2375
- s += " - #{sensor.name}"
2613
+ surf_names.each do |surf_name|
2614
+ program.addLine("Set loads_#{mode}_#{surf_name} = loads_#{mode}_#{surf_name} + (#{sign}hr_#{surf_name} * #{mode}_mode * #{unit_multiplier})")
2615
+ end
2616
+ nonsurf_names.each do |nonsurf_name|
2617
+ program.addLine("Set loads_#{mode}_#{nonsurf_name} = loads_#{mode}_#{nonsurf_name} + (#{sign}hr_#{nonsurf_name} * #{mode}_mode * #{unit_multiplier})")
2376
2618
  end
2377
- program.addLine(s) if sensors.size > 0
2378
- end
2379
- end
2380
- if (not ducts_mix_loss_sensor.nil?) && (not ducts_mix_gain_sensor.nil?)
2381
- program.addLine("Set hr_ducts = hr_ducts + (#{ducts_mix_loss_sensor.name} - #{ducts_mix_gain_sensor.name})")
2382
- end
2383
-
2384
- # EMS program: Heating vs Cooling logic
2385
- program.addLine('Set htg_mode = 0')
2386
- program.addLine('Set clg_mode = 0')
2387
- program.addLine("If (#{liv_load_sensors[:htg].name} > 0)") # Assign hour to heating if heating load
2388
- program.addLine(" Set htg_mode = #{total_heat_load_served}")
2389
- program.addLine("ElseIf (#{liv_load_sensors[:clg].name} > 0)") # Assign hour to cooling if cooling load
2390
- program.addLine(" Set clg_mode = #{total_cool_load_served}")
2391
- program.addLine("ElseIf (#{@clg_ssn_sensor.name} > 0)") # No load, assign hour to cooling if in cooling season definition (Note: natural ventilation & whole house fan only operate during the cooling season)
2392
- program.addLine(" Set clg_mode = #{total_cool_load_served}")
2393
- program.addLine('Else') # No load, assign hour to heating if not in cooling season definition
2394
- program.addLine(" Set htg_mode = #{total_heat_load_served}")
2395
- program.addLine('EndIf')
2396
-
2397
- [:htg, :clg].each do |mode|
2398
- if mode == :htg
2399
- sign = ''
2400
- else
2401
- sign = '-'
2402
- end
2403
- surfaces_sensors.keys.each do |k|
2404
- program.addLine("Set loads_#{mode}_#{k} = #{sign}hr_#{k} * #{mode}_mode")
2405
- end
2406
- nonsurf_names.each do |nonsurf_name|
2407
- program.addLine("Set loads_#{mode}_#{nonsurf_name} = #{sign}hr_#{nonsurf_name} * #{mode}_mode")
2408
2619
  end
2409
2620
  end
2410
2621
 
@@ -2415,7 +2626,7 @@ class OSModel
2415
2626
  program_calling_manager.addProgram(program)
2416
2627
  end
2417
2628
 
2418
- def self.set_output_files(model)
2629
+ def set_output_files(model)
2419
2630
  oj = model.getOutputJSON
2420
2631
  oj.setOptionType('TimeSeriesAndTabular')
2421
2632
  oj.setOutputJSON(false)
@@ -2423,6 +2634,7 @@ class OSModel
2423
2634
 
2424
2635
  ocf = model.getOutputControlFiles
2425
2636
  ocf.setOutputAUDIT(@debug)
2637
+ ocf.setOutputCSV(@debug)
2426
2638
  ocf.setOutputBND(@debug)
2427
2639
  ocf.setOutputEIO(@debug)
2428
2640
  ocf.setOutputESO(@debug)
@@ -2431,30 +2643,31 @@ class OSModel
2431
2643
  ocf.setOutputMTR(@debug)
2432
2644
  ocf.setOutputRDD(@debug)
2433
2645
  ocf.setOutputSHD(@debug)
2646
+ ocf.setOutputCSV(@debug)
2434
2647
  ocf.setOutputSQLite(@debug)
2435
2648
  ocf.setOutputPerfLog(@debug)
2436
2649
  end
2437
2650
 
2438
- def self.add_ems_debug_output(model)
2651
+ def add_ems_debug_output(model)
2439
2652
  oems = model.getOutputEnergyManagementSystem
2440
2653
  oems.setActuatorAvailabilityDictionaryReporting('Verbose')
2441
2654
  oems.setInternalVariableAvailabilityDictionaryReporting('Verbose')
2442
2655
  oems.setEMSRuntimeLanguageDebugOutputLevel('Verbose')
2443
2656
  end
2444
2657
 
2445
- def self.set_surface_interior(model, spaces, surface, hpxml_surface)
2658
+ def set_surface_interior(model, spaces, surface, hpxml_surface)
2446
2659
  interior_adjacent_to = hpxml_surface.interior_adjacent_to
2447
2660
  if HPXML::conditioned_below_grade_locations.include? interior_adjacent_to
2448
- surface.setSpace(create_or_get_space(model, spaces, HPXML::LocationLivingSpace))
2661
+ surface.setSpace(create_or_get_space(model, spaces, HPXML::LocationConditionedSpace))
2449
2662
  else
2450
2663
  surface.setSpace(create_or_get_space(model, spaces, interior_adjacent_to))
2451
2664
  end
2452
2665
  end
2453
2666
 
2454
- def self.set_surface_exterior(model, spaces, surface, hpxml_surface)
2667
+ def set_surface_exterior(model, spaces, surface, hpxml_surface)
2455
2668
  exterior_adjacent_to = hpxml_surface.exterior_adjacent_to
2456
2669
  is_adiabatic = hpxml_surface.is_adiabatic
2457
- if exterior_adjacent_to == HPXML::LocationOutside
2670
+ if [HPXML::LocationOutside, HPXML::LocationManufacturedHomeUnderBelly].include? exterior_adjacent_to
2458
2671
  surface.setOutsideBoundaryCondition('Outdoors')
2459
2672
  elsif exterior_adjacent_to == HPXML::LocationGround
2460
2673
  surface.setOutsideBoundaryCondition('Foundation')
@@ -2464,7 +2677,7 @@ class OSModel
2464
2677
  HPXML::LocationOtherNonFreezingSpace, HPXML::LocationOtherHousingUnit].include? exterior_adjacent_to
2465
2678
  set_surface_otherside_coefficients(surface, exterior_adjacent_to, model, spaces)
2466
2679
  elsif HPXML::conditioned_below_grade_locations.include? exterior_adjacent_to
2467
- adjacent_surface = surface.createAdjacentSurface(create_or_get_space(model, spaces, HPXML::LocationLivingSpace)).get
2680
+ adjacent_surface = surface.createAdjacentSurface(create_or_get_space(model, spaces, HPXML::LocationConditionedSpace)).get
2468
2681
  adjacent_surface.additionalProperties.setFeature('SurfaceType', surface.additionalProperties.getFeatureAsString('SurfaceType').get)
2469
2682
  else
2470
2683
  adjacent_surface = surface.createAdjacentSurface(create_or_get_space(model, spaces, exterior_adjacent_to)).get
@@ -2472,7 +2685,7 @@ class OSModel
2472
2685
  end
2473
2686
  end
2474
2687
 
2475
- def self.set_surface_otherside_coefficients(surface, exterior_adjacent_to, model, spaces)
2688
+ def set_surface_otherside_coefficients(surface, exterior_adjacent_to, model, spaces)
2476
2689
  otherside_coeffs = nil
2477
2690
  model.getSurfacePropertyOtherSideCoefficientss.each do |c|
2478
2691
  next unless c.name.to_s == exterior_adjacent_to
@@ -2493,7 +2706,7 @@ class OSModel
2493
2706
  surface.setWindExposure('NoWind')
2494
2707
  end
2495
2708
 
2496
- def self.get_space_temperature_schedule(model, location, spaces)
2709
+ def get_space_temperature_schedule(model, location, spaces)
2497
2710
  # Create outside boundary schedules to be actuated by EMS,
2498
2711
  # can be shared by any surface, duct adjacent to / located in those spaces
2499
2712
 
@@ -2506,12 +2719,13 @@ class OSModel
2506
2719
 
2507
2720
  sch = OpenStudio::Model::ScheduleConstant.new(model)
2508
2721
  sch.setName(location)
2722
+ sch.additionalProperties.setFeature('ObjectType', location)
2509
2723
 
2510
2724
  space_values = Geometry.get_temperature_scheduled_space_values(location)
2511
2725
 
2512
2726
  if location == HPXML::LocationOtherHeatedSpace
2513
2727
  # Create a sensor to get dynamic heating setpoint
2514
- htg_sch = spaces[HPXML::LocationLivingSpace].thermalZone.get.thermostatSetpointDualSetpoint.get.heatingSetpointTemperatureSchedule.get
2728
+ htg_sch = spaces[HPXML::LocationConditionedSpace].thermalZone.get.thermostatSetpointDualSetpoint.get.heatingSetpointTemperatureSchedule.get
2515
2729
  sensor_htg_spt = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Schedule Value')
2516
2730
  sensor_htg_spt.setName('htg_spt')
2517
2731
  sensor_htg_spt.setKeyName(htg_sch.name.to_s)
@@ -2527,7 +2741,7 @@ class OSModel
2527
2741
  if space_values[:indoor_weight] > 0
2528
2742
  sensor_ia = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Zone Air Temperature')
2529
2743
  sensor_ia.setName('cond_zone_temp')
2530
- sensor_ia.setKeyName(spaces[HPXML::LocationLivingSpace].thermalZone.get.name.to_s)
2744
+ sensor_ia.setKeyName(spaces[HPXML::LocationConditionedSpace].thermalZone.get.name.to_s)
2531
2745
  end
2532
2746
 
2533
2747
  if space_values[:outdoor_weight] > 0
@@ -2578,7 +2792,7 @@ class OSModel
2578
2792
  # Returns an OS:Space, or temperature OS:Schedule for a MF space, or nil if outside
2579
2793
  # Should be called when the object's energy use is sensitive to ambient temperature
2580
2794
  # (e.g., water heaters and ducts).
2581
- def self.get_space_or_schedule_from_location(location, model, spaces)
2795
+ def get_space_or_schedule_from_location(location, model, spaces)
2582
2796
  return if [HPXML::LocationOtherExterior,
2583
2797
  HPXML::LocationOutside,
2584
2798
  HPXML::LocationRoofDeck].include? location
@@ -2603,7 +2817,7 @@ class OSModel
2603
2817
  # Returns an OS:Space, or nil if a MF space or outside
2604
2818
  # Should be called when the object's energy use is NOT sensitive to ambient temperature
2605
2819
  # (e.g., appliances).
2606
- def self.get_space_from_location(location, spaces)
2820
+ def get_space_from_location(location, spaces)
2607
2821
  return if [HPXML::LocationOutside,
2608
2822
  HPXML::LocationOtherHeatedSpace,
2609
2823
  HPXML::LocationOtherHousingUnit,
@@ -2611,13 +2825,13 @@ class OSModel
2611
2825
  HPXML::LocationOtherNonFreezingSpace].include? location
2612
2826
 
2613
2827
  if HPXML::conditioned_locations.include? location
2614
- location = HPXML::LocationLivingSpace
2828
+ location = HPXML::LocationConditionedSpace
2615
2829
  end
2616
2830
 
2617
2831
  return spaces[location]
2618
2832
  end
2619
2833
 
2620
- def self.set_subsurface_exterior(surface, spaces, model, hpxml_surface)
2834
+ def set_subsurface_exterior(surface, spaces, model, hpxml_surface)
2621
2835
  # Set its parent surface outside boundary condition, which will be also applied to subsurfaces through OS
2622
2836
  # The parent surface is entirely comprised of the subsurface.
2623
2837
 
@@ -2629,36 +2843,25 @@ class OSModel
2629
2843
  end
2630
2844
  end
2631
2845
 
2632
- def self.get_kiva_instances(fnd_walls, slabs)
2633
- # Identify unique Kiva foundations that are required.
2634
- kiva_fnd_walls = []
2635
- fnd_walls.each do |foundation_wall|
2636
- next unless foundation_wall.is_exterior
2637
-
2638
- kiva_fnd_walls << foundation_wall
2639
- end
2640
- if kiva_fnd_walls.empty? # Handle slab foundation type
2641
- kiva_fnd_walls << nil
2642
- end
2643
-
2644
- kiva_slabs = slabs
2645
-
2646
- return kiva_fnd_walls.product(kiva_slabs)
2647
- end
2648
-
2649
- def self.set_foundation_and_walls_top()
2846
+ def set_foundation_and_walls_top()
2650
2847
  @foundation_top = 0
2651
- @hpxml.foundation_walls.each do |foundation_wall|
2848
+ @hpxml_bldg.floors.each do |floor|
2849
+ # Keeping the floor at ground level for ASHRAE 140 tests yields the expected results
2850
+ if floor.is_floor && floor.is_exterior && !@apply_ashrae140_assumptions
2851
+ @foundation_top = 2.0
2852
+ end
2853
+ end
2854
+ @hpxml_bldg.foundation_walls.each do |foundation_wall|
2652
2855
  top = -1 * foundation_wall.depth_below_grade + foundation_wall.height
2653
2856
  @foundation_top = top if top > @foundation_top
2654
2857
  end
2655
- @walls_top = @foundation_top + 8.0 * @ncfl_ag
2858
+ @walls_top = @foundation_top + @hpxml_bldg.building_construction.average_ceiling_height * @ncfl_ag
2656
2859
  end
2657
2860
 
2658
- def self.set_heating_and_cooling_seasons()
2659
- return if @hpxml.hvac_controls.size == 0
2861
+ def set_heating_and_cooling_seasons()
2862
+ return if @hpxml_bldg.hvac_controls.size == 0
2660
2863
 
2661
- hvac_control = @hpxml.hvac_controls[0]
2864
+ hvac_control = @hpxml_bldg.hvac_controls[0]
2662
2865
 
2663
2866
  htg_start_month = hvac_control.seasons_heating_begin_month
2664
2867
  htg_start_day = hvac_control.seasons_heating_begin_day
@@ -2669,8 +2872,8 @@ class OSModel
2669
2872
  clg_end_month = hvac_control.seasons_cooling_end_month
2670
2873
  clg_end_day = hvac_control.seasons_cooling_end_day
2671
2874
 
2672
- @heating_days = Schedule.get_daily_season(@hpxml.header.sim_calendar_year, htg_start_month, htg_start_day, htg_end_month, htg_end_day)
2673
- @cooling_days = Schedule.get_daily_season(@hpxml.header.sim_calendar_year, clg_start_month, clg_start_day, clg_end_month, clg_end_day)
2875
+ @heating_days = Schedule.get_daily_season(@hpxml_header.sim_calendar_year, htg_start_month, htg_start_day, htg_end_month, htg_end_day)
2876
+ @cooling_days = Schedule.get_daily_season(@hpxml_header.sim_calendar_year, clg_start_month, clg_start_day, clg_end_month, clg_end_day)
2674
2877
  end
2675
2878
  end
2676
2879