urbanopt-cli 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,8 +1,20 @@
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
  class HVAC
9
+ AirSourceHeatRatedODB = 47.0 # degF, Rated outdoor drybulb for air-source systems, heating
10
+ AirSourceHeatRatedIDB = 70.0 # degF, Rated indoor drybulb for air-source systems, heating
11
+ AirSourceCoolRatedODB = 95.0 # degF, Rated outdoor drybulb for air-source systems, cooling
12
+ AirSourceCoolRatedIWB = 67.0 # degF, Rated indoor wetbulb for air-source systems, cooling
13
+ CrankcaseHeaterTemp = 50.0 # degF
14
+
4
15
  def self.apply_air_source_hvac_systems(model, cooling_system, heating_system,
5
16
  sequential_cool_load_fracs, sequential_heat_load_fracs,
17
+ weather_max_drybulb, weather_min_drybulb,
6
18
  control_zone, hvac_unavailable_periods)
7
19
  is_heatpump = false
8
20
  if not cooling_system.nil?
@@ -45,19 +57,43 @@ class HVAC
45
57
  fail "Unexpected cooling system type: #{cooling_system.cooling_system_type}."
46
58
  end
47
59
  end
48
- clg_ap = cooling_system.additional_properties
49
- num_speeds = clg_ap.num_speeds
50
60
  elsif (heating_system.is_a? HPXML::HeatingSystem) && (heating_system.heating_system_type == HPXML::HVACTypeFurnace)
51
61
  obj_name = Constants.ObjectNameFurnace
52
- num_speeds = 1
53
62
  else
54
63
  fail "Unexpected heating system type: #{heating_system.heating_system_type}, expect central air source hvac systems."
55
64
  end
56
65
 
66
+ # Calculate max rated cfm
67
+ max_rated_fan_cfm = -9999
68
+ if not cooling_system.nil?
69
+ clg_ap = cooling_system.additional_properties
70
+ if not cooling_system.cooling_detailed_performance_data.empty?
71
+ cooling_system.cooling_detailed_performance_data.select { |dp| dp.capacity_description == HPXML::CapacityDescriptionMaximum }.each do |dp|
72
+ rated_fan_cfm = UnitConversions.convert(dp.capacity, 'Btu/hr', 'ton') * clg_ap.cool_rated_cfm_per_ton[-1]
73
+ max_rated_fan_cfm = rated_fan_cfm if rated_fan_cfm > max_rated_fan_cfm
74
+ end
75
+ else
76
+ rated_fan_cfm = UnitConversions.convert(cooling_system.cooling_capacity * clg_ap.cool_capacity_ratios[-1], 'Btu/hr', 'ton') * clg_ap.cool_rated_cfm_per_ton[-1]
77
+ max_rated_fan_cfm = rated_fan_cfm if rated_fan_cfm > max_rated_fan_cfm
78
+ end
79
+ end
80
+ if not heating_system.nil?
81
+ htg_ap = heating_system.additional_properties
82
+ if not heating_system.heating_detailed_performance_data.empty?
83
+ heating_system.heating_detailed_performance_data.select { |dp| dp.capacity_description == HPXML::CapacityDescriptionMaximum }.each do |dp|
84
+ rated_fan_cfm = UnitConversions.convert(dp.capacity, 'Btu/hr', 'ton') * htg_ap.heat_rated_cfm_per_ton[-1]
85
+ max_rated_fan_cfm = rated_fan_cfm if rated_fan_cfm > max_rated_fan_cfm
86
+ end
87
+ elsif is_heatpump
88
+ rated_fan_cfm = UnitConversions.convert(heating_system.heating_capacity * htg_ap.heat_capacity_ratios[-1], 'Btu/hr', 'ton') * htg_ap.heat_rated_cfm_per_ton[-1]
89
+ max_rated_fan_cfm = rated_fan_cfm if rated_fan_cfm > max_rated_fan_cfm
90
+ end
91
+ end
92
+
57
93
  fan_cfms = []
58
94
  if not cooling_system.nil?
59
95
  # Cooling Coil
60
- clg_coil = create_dx_cooling_coil(model, obj_name, cooling_system)
96
+ clg_coil = create_dx_cooling_coil(model, obj_name, cooling_system, max_rated_fan_cfm, weather_max_drybulb)
61
97
 
62
98
  clg_cfm = cooling_system.cooling_airflow_cfm
63
99
  clg_ap.cool_fan_speed_ratios.each do |r|
@@ -70,8 +106,8 @@ class HVAC
70
106
  else
71
107
  htg_coil = OpenStudio::Model::CoilHeatingGas.new(model)
72
108
  htg_coil.setGasBurnerEfficiency(cooling_system.integrated_heating_system_efficiency_percent)
73
- htg_coil.setParasiticElectricLoad(0)
74
- htg_coil.setParasiticGasLoad(0)
109
+ htg_coil.setOnCycleParasiticElectricLoad(0)
110
+ htg_coil.setOffCycleParasiticGasLoad(0)
75
111
  htg_coil.setFuelType(EPlus.fuel_type(cooling_system.integrated_heating_system_fuel))
76
112
  end
77
113
  htg_coil.setNominalCapacity(UnitConversions.convert(cooling_system.integrated_heating_system_capacity, 'Btu/hr', 'W'))
@@ -83,13 +119,12 @@ class HVAC
83
119
  end
84
120
 
85
121
  if not heating_system.nil?
86
- htg_ap = heating_system.additional_properties
87
122
  htg_cfm = heating_system.heating_airflow_cfm
88
123
  if is_heatpump
89
124
  supp_max_temp = htg_ap.supp_max_temp
90
125
 
91
126
  # Heating Coil
92
- htg_coil = create_dx_heating_coil(model, obj_name, heating_system)
127
+ htg_coil = create_dx_heating_coil(model, obj_name, heating_system, max_rated_fan_cfm, weather_min_drybulb)
93
128
 
94
129
  # Supplemental Heating Coil
95
130
  htg_supp_coil = create_supp_heating_coil(model, obj_name, heating_system)
@@ -104,8 +139,8 @@ class HVAC
104
139
  else
105
140
  htg_coil = OpenStudio::Model::CoilHeatingGas.new(model)
106
141
  htg_coil.setGasBurnerEfficiency(heating_system.heating_efficiency_afue)
107
- htg_coil.setParasiticElectricLoad(0)
108
- htg_coil.setParasiticGasLoad(UnitConversions.convert(heating_system.pilot_light_btuh.to_f, 'Btu/hr', 'W'))
142
+ htg_coil.setOnCycleParasiticElectricLoad(0)
143
+ htg_coil.setOffCycleParasiticGasLoad(UnitConversions.convert(heating_system.pilot_light_btuh.to_f, 'Btu/hr', 'W'))
109
144
  htg_coil.setFuelType(EPlus.fuel_type(heating_system.heating_system_fuel))
110
145
  end
111
146
  htg_coil.setNominalCapacity(UnitConversions.convert(heating_system.heating_capacity, 'Btu/hr', 'W'))
@@ -152,10 +187,10 @@ class HVAC
152
187
  air_loop_unitary = create_air_loop_unitary_system(model, obj_name, fan, htg_coil, clg_coil, htg_supp_coil, htg_cfm, clg_cfm, supp_max_temp)
153
188
 
154
189
  # Unitary System Performance
155
- if num_speeds > 1
190
+ if (not clg_ap.nil?) && (clg_ap.cool_fan_speed_ratios.size > 1)
156
191
  perf = OpenStudio::Model::UnitarySystemPerformanceMultispeed.new(model)
157
192
  perf.setSingleModeOperation(false)
158
- for speed in 1..num_speeds
193
+ for speed in 1..clg_ap.cool_fan_speed_ratios.size
159
194
  if is_heatpump
160
195
  f = OpenStudio::Model::SupplyAirflowRatioField.new(htg_ap.heat_fan_speed_ratios[speed - 1], clg_ap.cool_fan_speed_ratios[speed - 1])
161
196
  else
@@ -175,7 +210,7 @@ class HVAC
175
210
  end
176
211
 
177
212
  def self.apply_evaporative_cooler(model, cooling_system, sequential_cool_load_fracs, control_zone,
178
- hvac_unavailable_periods)
213
+ hvac_unavailable_periods, unit_multiplier)
179
214
 
180
215
  obj_name = Constants.ObjectNameEvaporativeCooler
181
216
 
@@ -196,7 +231,7 @@ class HVAC
196
231
  air_loop = create_air_loop(model, obj_name, evap_cooler, control_zone, [0], sequential_cool_load_fracs, clg_cfm, nil, hvac_unavailable_periods)
197
232
 
198
233
  # Fan
199
- fan_watts_per_cfm = [2.79 * clg_cfm**-0.29, 0.6].min # W/cfm; fit of efficacy to air flow from the CEC listed equipment
234
+ fan_watts_per_cfm = [2.79 * (clg_cfm / unit_multiplier)**-0.29, 0.6].min # W/cfm; fit of efficacy to air flow from the CEC listed equipment
200
235
  fan = create_supply_fan(model, obj_name, fan_watts_per_cfm, [clg_cfm])
201
236
  fan.addToNode(air_loop.supplyInletNode)
202
237
  disaggregate_fan_or_pump(model, fan, nil, evap_cooler, nil, cooling_system)
@@ -226,7 +261,14 @@ class HVAC
226
261
 
227
262
  def self.apply_ground_to_air_heat_pump(model, runner, weather, heat_pump,
228
263
  sequential_heat_load_fracs, sequential_cool_load_fracs,
229
- control_zone, ground_conductivity, hvac_unavailable_periods)
264
+ control_zone, ground_conductivity, hvac_unavailable_periods,
265
+ unit_multiplier)
266
+
267
+ if unit_multiplier > 1
268
+ # FUTURE: Figure out how to allow this. If we allow it, update docs and hpxml_translator_test.rb too.
269
+ # https://github.com/NREL/OpenStudio-HPXML/issues/1499
270
+ fail 'NumberofUnits greater than 1 is not supported for ground-to-air heat pumps.'
271
+ end
230
272
 
231
273
  obj_name = Constants.ObjectNameGroundSourceHeatPump
232
274
 
@@ -241,13 +283,17 @@ class HVAC
241
283
  runner.registerWarning("Specified #{hp_ap.fluid_type} fluid type and 0 fraction of glycol, so assuming #{Constants.FluidWater} fluid type.")
242
284
  end
243
285
 
286
+ # Apply unit multiplier
287
+ hp_ap.GSHP_Loop_flow *= unit_multiplier
288
+ hp_ap.GSHP_Bore_Holes = hp_ap.GSHP_Bore_Holes.to_i * unit_multiplier
289
+
244
290
  # Cooling Coil
245
291
  clg_total_cap_curve = create_curve_quad_linear(model, hp_ap.cool_cap_curve_spec[0], obj_name + ' clg total cap curve')
246
292
  clg_sens_cap_curve = create_curve_quint_linear(model, hp_ap.cool_sh_curve_spec[0], obj_name + ' clg sens cap curve')
247
293
  clg_power_curve = create_curve_quad_linear(model, hp_ap.cool_power_curve_spec[0], obj_name + ' clg power curve')
248
294
  clg_coil = OpenStudio::Model::CoilCoolingWaterToAirHeatPumpEquationFit.new(model, clg_total_cap_curve, clg_sens_cap_curve, clg_power_curve)
249
295
  clg_coil.setName(obj_name + ' clg coil')
250
- clg_coil.setRatedCoolingCoefficientofPerformance(1.0 / hp_ap.cool_rated_eirs[0])
296
+ clg_coil.setRatedCoolingCoefficientofPerformance(hp_ap.cool_rated_cops[0])
251
297
  clg_coil.setNominalTimeforCondensateRemovaltoBegin(1000)
252
298
  clg_coil.setRatioofInitialMoistureEvaporationRateandSteadyStateLatentCapacity(1.5)
253
299
  clg_coil.setRatedAirFlowRate(UnitConversions.convert(clg_cfm_rated, 'cfm', 'm^3/s'))
@@ -261,7 +307,7 @@ class HVAC
261
307
  htg_power_curve = create_curve_quad_linear(model, hp_ap.heat_power_curve_spec[0], obj_name + ' htg power curve')
262
308
  htg_coil = OpenStudio::Model::CoilHeatingWaterToAirHeatPumpEquationFit.new(model, htg_cap_curve, htg_power_curve)
263
309
  htg_coil.setName(obj_name + ' htg coil')
264
- htg_coil.setRatedHeatingCoefficientofPerformance(1.0 / hp_ap.heat_rated_eirs[0])
310
+ htg_coil.setRatedHeatingCoefficientofPerformance(hp_ap.heat_rated_cops[0])
265
311
  htg_coil.setRatedAirFlowRate(UnitConversions.convert(htg_cfm_rated, 'cfm', 'm^3/s'))
266
312
  htg_coil.setRatedWaterFlowRate(UnitConversions.convert(hp_ap.GSHP_Loop_flow, 'gal/min', 'm^3/s'))
267
313
  htg_coil.setRatedHeatingCapacity(UnitConversions.convert(heat_pump.heating_capacity, 'Btu/hr', 'W'))
@@ -270,13 +316,20 @@ class HVAC
270
316
  # Supplemental Heating Coil
271
317
  htg_supp_coil = create_supp_heating_coil(model, obj_name, heat_pump)
272
318
 
319
+ # Site Ground Temperature Undisturbed
320
+ xing = OpenStudio::Model::SiteGroundTemperatureUndisturbedXing.new(model)
321
+ xing.setSoilSurfaceTemperatureAmplitude1(UnitConversions.convert(weather.data.DeepGroundSurfTempAmp1, 'deltaf', 'deltac'))
322
+ xing.setSoilSurfaceTemperatureAmplitude2(UnitConversions.convert(weather.data.DeepGroundSurfTempAmp2, 'deltaf', 'deltac'))
323
+ xing.setPhaseShiftofTemperatureAmplitude1(weather.data.DeepGroundPhaseShiftTempAmp1)
324
+ xing.setPhaseShiftofTemperatureAmplitude2(weather.data.DeepGroundPhaseShiftTempAmp2)
325
+
273
326
  # Ground Heat Exchanger
274
- ground_heat_exch_vert = OpenStudio::Model::GroundHeatExchangerVertical.new(model)
327
+ ground_heat_exch_vert = OpenStudio::Model::GroundHeatExchangerVertical.new(model, xing)
275
328
  ground_heat_exch_vert.setName(obj_name + ' exchanger')
276
329
  ground_heat_exch_vert.setBoreHoleRadius(UnitConversions.convert(hp_ap.bore_diameter / 2.0, 'in', 'm'))
277
330
  ground_heat_exch_vert.setGroundThermalConductivity(UnitConversions.convert(ground_conductivity, 'Btu/(hr*ft*R)', 'W/(m*K)'))
278
331
  ground_heat_exch_vert.setGroundThermalHeatCapacity(UnitConversions.convert(ground_conductivity / hp_ap.ground_diffusivity, 'Btu/(ft^3*F)', 'J/(m^3*K)'))
279
- ground_heat_exch_vert.setGroundTemperature(UnitConversions.convert(weather.data.AnnualAvgDrybulb, 'F', 'C'))
332
+ ground_heat_exch_vert.setGroundTemperature(UnitConversions.convert(weather.data.DeepGroundAnnualTemp, 'F', 'C'))
280
333
  ground_heat_exch_vert.setGroutThermalConductivity(UnitConversions.convert(hp_ap.grout_conductivity, 'Btu/(hr*ft*R)', 'W/(m*K)'))
281
334
  ground_heat_exch_vert.setPipeThermalConductivity(UnitConversions.convert(hp_ap.pipe_cond, 'Btu/(hr*ft*R)', 'W/(m*K)'))
282
335
  ground_heat_exch_vert.setPipeOutDiameter(UnitConversions.convert(hp_ap.pipe_od, 'in', 'm'))
@@ -285,12 +338,16 @@ class HVAC
285
338
  ground_heat_exch_vert.setMaximumLengthofSimulation(1)
286
339
  ground_heat_exch_vert.setGFunctionReferenceRatio(0.0005)
287
340
  ground_heat_exch_vert.setDesignFlowRate(UnitConversions.convert(hp_ap.GSHP_Loop_flow, 'gal/min', 'm^3/s'))
288
- ground_heat_exch_vert.setNumberofBoreHoles(hp_ap.GSHP_Bore_Holes.to_i)
341
+ ground_heat_exch_vert.setNumberofBoreHoles(hp_ap.GSHP_Bore_Holes)
289
342
  ground_heat_exch_vert.setBoreHoleLength(UnitConversions.convert(hp_ap.GSHP_Bore_Depth, 'ft', 'm'))
290
343
  ground_heat_exch_vert.removeAllGFunctions
291
344
  for i in 0..(hp_ap.GSHP_G_Functions[0].size - 1)
292
345
  ground_heat_exch_vert.addGFunction(hp_ap.GSHP_G_Functions[0][i], hp_ap.GSHP_G_Functions[1][i])
293
346
  end
347
+ xing = ground_heat_exch_vert.undisturbedGroundTemperatureModel.to_SiteGroundTemperatureUndisturbedXing.get
348
+ xing.setSoilThermalConductivity(ground_heat_exch_vert.groundThermalConductivity.get)
349
+ xing.setSoilSpecificHeat(ground_heat_exch_vert.groundThermalHeatCapacity.get / xing.soilDensity)
350
+ xing.setAverageSoilSurfaceTemperature(ground_heat_exch_vert.groundTemperature.get)
294
351
 
295
352
  # Plant Loop
296
353
  plant_loop = OpenStudio::Model::PlantLoop.new(model)
@@ -379,7 +436,7 @@ class HVAC
379
436
  equip_def.setFractionLatent(0)
380
437
  equip_def.setFractionLost(1)
381
438
  equip.setSchedule(model.alwaysOnDiscreteSchedule)
382
- equip.setEndUseSubcategory(equip_def.name.to_s)
439
+ equip.setEndUseSubcategory(Constants.ObjectNameGSHPSharedPump)
383
440
  equip.additionalProperties.setFeature('HPXML_ID', heat_pump.id) # Used by reporting measure
384
441
  end
385
442
 
@@ -437,8 +494,7 @@ class HVAC
437
494
  return air_loop
438
495
  end
439
496
 
440
- def self.apply_boiler(model, runner, heating_system,
441
- sequential_heat_load_fracs, control_zone, hvac_unavailable_periods)
497
+ def self.apply_boiler(model, runner, heating_system, sequential_heat_load_fracs, control_zone, hvac_unavailable_periods)
442
498
  obj_name = Constants.ObjectNameBoiler
443
499
  is_condensing = false # FUTURE: Expose as input; default based on AFUE
444
500
  oat_reset_enabled = false
@@ -514,16 +570,14 @@ class HVAC
514
570
  boiler.setBoilerFlowMode('LeavingSetpointModulated')
515
571
  boiler.setOptimumPartLoadRatio(1.0)
516
572
  boiler.setWaterOutletUpperTemperatureLimit(99.9)
517
- boiler.setParasiticElectricLoad(0)
573
+ boiler.setOnCycleParasiticElectricLoad(0)
518
574
  boiler.setNominalCapacity(UnitConversions.convert(heating_system.heating_capacity, 'Btu/hr', 'W'))
575
+ boiler.setOffCycleParasiticFuelLoad(UnitConversions.convert(heating_system.pilot_light_btuh.to_f, 'Btu/hr', 'W'))
519
576
  plant_loop.addSupplyBranchForComponent(boiler)
520
577
  boiler.additionalProperties.setFeature('HPXML_ID', heating_system.id) # Used by reporting measure
578
+ boiler.additionalProperties.setFeature('IsHeatPumpBackup', heating_system.is_heat_pump_backup_system) # Used by reporting measure
521
579
  set_pump_power_ems_program(model, pump_w, pump, boiler)
522
580
 
523
- # FIXME: EMS program to model pilot light
524
- # Can be replaced if https://github.com/NREL/EnergyPlus/issues/9875 is ever implemented
525
- set_boiler_pilot_light_ems_program(model, boiler, heating_system)
526
-
527
581
  if is_condensing && oat_reset_enabled
528
582
  setpoint_manager_oar = OpenStudio::Model::SetpointManagerOutdoorAirReset.new(model)
529
583
  setpoint_manager_oar.setName(obj_name + ' outdoor reset')
@@ -657,8 +711,8 @@ class HVAC
657
711
  else
658
712
  htg_coil = OpenStudio::Model::CoilHeatingGas.new(model)
659
713
  htg_coil.setGasBurnerEfficiency(efficiency)
660
- htg_coil.setParasiticElectricLoad(0.0)
661
- htg_coil.setParasiticGasLoad(UnitConversions.convert(heating_system.pilot_light_btuh.to_f, 'Btu/hr', 'W'))
714
+ htg_coil.setOnCycleParasiticElectricLoad(0.0)
715
+ htg_coil.setOffCycleParasiticGasLoad(UnitConversions.convert(heating_system.pilot_light_btuh.to_f, 'Btu/hr', 'W'))
662
716
  htg_coil.setFuelType(EPlus.fuel_type(heating_system.heating_system_fuel))
663
717
  end
664
718
  htg_coil.setNominalCapacity(UnitConversions.convert(heating_system.heating_capacity, 'Btu/hr', 'W'))
@@ -680,9 +734,11 @@ class HVAC
680
734
  set_sequential_load_fractions(model, control_zone, unitary_system, sequential_heat_load_fracs, nil, hvac_unavailable_periods, heating_system)
681
735
  end
682
736
 
683
- def self.apply_ideal_air_loads(model, obj_name, sequential_cool_load_fracs,
737
+ def self.apply_ideal_air_loads(model, sequential_cool_load_fracs,
684
738
  sequential_heat_load_fracs, control_zone, hvac_unavailable_periods)
685
739
 
740
+ obj_name = Constants.ObjectNameIdealAirSystem
741
+
686
742
  # Ideal Air System
687
743
  ideal_air = OpenStudio::Model::ZoneHVACIdealLoadsAirSystem.new(model)
688
744
  ideal_air.setName(obj_name)
@@ -709,13 +765,19 @@ class HVAC
709
765
  set_sequential_load_fractions(model, control_zone, ideal_air, sequential_heat_load_fracs, sequential_cool_load_fracs, hvac_unavailable_periods)
710
766
  end
711
767
 
712
- def self.apply_dehumidifiers(runner, model, dehumidifiers, living_space, unavailable_periods)
768
+ def self.apply_dehumidifiers(runner, model, dehumidifiers, conditioned_space, unavailable_periods, unit_multiplier)
713
769
  dehumidifier_id = dehumidifiers[0].id # Syncs with the ReportSimulationOutput measure, which only looks at first dehumidifier ID
714
770
 
715
771
  if dehumidifiers.map { |d| d.rh_setpoint }.uniq.size > 1
716
772
  fail 'All dehumidifiers must have the same setpoint but multiple setpoints were specified.'
717
773
  end
718
774
 
775
+ if unit_multiplier > 1
776
+ # FUTURE: Figure out how to allow this. If we allow it, update docs and hpxml_translator_test.rb too.
777
+ # https://github.com/NREL/OpenStudio-HPXML/issues/1499
778
+ fail 'NumberofUnits greater than 1 is not supported for dehumidifiers.'
779
+ end
780
+
719
781
  # Dehumidifier coefficients
720
782
  # Generic model coefficients from Winkler, Christensen, and Tomerlin (2011)
721
783
  w_coeff = [-1.162525707, 0.02271469, -0.000113208, 0.021110538, -0.0000693034, 0.000378843]
@@ -733,12 +795,15 @@ class HVAC
733
795
  avg_energy_factor = dehumidifiers.map { |d| d.energy_factor * d.capacity }.sum / total_capacity
734
796
  total_fraction_served = dehumidifiers.map { |d| d.fraction_served }.sum
735
797
 
736
- control_zone = living_space.thermalZone.get
798
+ # Apply unit multiplier
799
+ total_capacity *= unit_multiplier
800
+
801
+ control_zone = conditioned_space.thermalZone.get
737
802
  obj_name = Constants.ObjectNameDehumidifier
738
803
 
739
804
  rh_setpoint = dehumidifiers[0].rh_setpoint * 100.0 # (EnergyPlus uses 60 for 60% RH)
740
805
  relative_humidity_setpoint_sch = OpenStudio::Model::ScheduleConstant.new(model)
741
- relative_humidity_setpoint_sch.setName(Constants.ObjectNameRelativeHumiditySetpoint)
806
+ relative_humidity_setpoint_sch.setName("#{obj_name} rh setpoint")
742
807
  relative_humidity_setpoint_sch.setValue(rh_setpoint)
743
808
 
744
809
  capacity_curve = create_curve_biquadratic(model, w_coeff, 'DXDH-CAP-fT', -100, 100, -100, 100)
@@ -773,11 +838,11 @@ class HVAC
773
838
  zone_hvac.additionalProperties.setFeature('HPXML_ID', dehumidifier_id) # Used by reporting measure
774
839
 
775
840
  if total_fraction_served < 1.0
776
- adjust_dehumidifier_load_EMS(total_fraction_served, zone_hvac, model, living_space)
841
+ adjust_dehumidifier_load_EMS(total_fraction_served, zone_hvac, model, conditioned_space)
777
842
  end
778
843
  end
779
844
 
780
- def self.apply_ceiling_fans(model, runner, weather, ceiling_fan, living_space, schedules_file,
845
+ def self.apply_ceiling_fans(model, runner, weather, ceiling_fan, conditioned_space, schedules_file,
781
846
  unavailable_periods)
782
847
  obj_name = Constants.ObjectNameCeilingFan
783
848
  medium_cfm = 3000.0 # From ANSI 301-2019
@@ -792,7 +857,7 @@ class HVAC
792
857
  if not schedules_file.nil?
793
858
  annual_kwh *= Schedule.CeilingFanMonthlyMultipliers(weather: weather).split(',').map(&:to_f).sum(0.0) / 12.0
794
859
  ceiling_fan_design_level = schedules_file.calc_design_level_from_annual_kwh(col_name: ceiling_fan_col_name, annual_kwh: annual_kwh)
795
- ceiling_fan_sch = schedules_file.create_schedule_file(col_name: ceiling_fan_col_name)
860
+ ceiling_fan_sch = schedules_file.create_schedule_file(model, col_name: ceiling_fan_col_name)
796
861
  end
797
862
  if ceiling_fan_sch.nil?
798
863
  ceiling_fan_unavailable_periods = Schedule.get_unavailable_periods(runner, ceiling_fan_col_name, unavailable_periods)
@@ -813,7 +878,7 @@ class HVAC
813
878
  equip_def.setName(obj_name)
814
879
  equip = OpenStudio::Model::ElectricEquipment.new(equip_def)
815
880
  equip.setName(equip_def.name.to_s)
816
- equip.setSpace(living_space)
881
+ equip.setSpace(conditioned_space)
817
882
  equip_def.setDesignLevel(ceiling_fan_design_level)
818
883
  equip_def.setFractionRadiant(0.558)
819
884
  equip_def.setFractionLatent(0)
@@ -822,14 +887,14 @@ class HVAC
822
887
  equip.setSchedule(ceiling_fan_sch)
823
888
  end
824
889
 
825
- def self.apply_setpoints(model, runner, weather, hvac_control, living_zone, has_ceiling_fan, heating_days, cooling_days, year, schedules_file)
890
+ def self.apply_setpoints(model, runner, weather, hvac_control, conditioned_zone, has_ceiling_fan, heating_days, cooling_days, year, schedules_file)
826
891
  heating_sch = nil
827
892
  cooling_sch = nil
828
893
  if not schedules_file.nil?
829
- heating_sch = schedules_file.create_schedule_file(col_name: SchedulesFile::ColumnHeatingSetpoint)
894
+ heating_sch = schedules_file.create_schedule_file(model, col_name: SchedulesFile::ColumnHeatingSetpoint)
830
895
  end
831
896
  if not schedules_file.nil?
832
- cooling_sch = schedules_file.create_schedule_file(col_name: SchedulesFile::ColumnCoolingSetpoint)
897
+ cooling_sch = schedules_file.create_schedule_file(model, col_name: SchedulesFile::ColumnCoolingSetpoint)
833
898
  end
834
899
 
835
900
  # permit mixing detailed schedules with simple schedules
@@ -851,21 +916,21 @@ class HVAC
851
916
  end
852
917
 
853
918
  if heating_sch.nil?
854
- heating_setpoint = HourlyByDaySchedule.new(model, Constants.ObjectNameHeatingSetpoint, htg_weekday_setpoints, htg_weekend_setpoints, nil, false)
919
+ heating_setpoint = HourlyByDaySchedule.new(model, 'heating setpoint', htg_weekday_setpoints, htg_weekend_setpoints, nil, false)
855
920
  heating_sch = heating_setpoint.schedule
856
921
  end
857
922
 
858
923
  if cooling_sch.nil?
859
- cooling_setpoint = HourlyByDaySchedule.new(model, Constants.ObjectNameCoolingSetpoint, clg_weekday_setpoints, clg_weekend_setpoints, nil, false)
924
+ cooling_setpoint = HourlyByDaySchedule.new(model, 'cooling setpoint', clg_weekday_setpoints, clg_weekend_setpoints, nil, false)
860
925
  cooling_sch = cooling_setpoint.schedule
861
926
  end
862
927
 
863
928
  # Set the setpoint schedules
864
929
  thermostat_setpoint = OpenStudio::Model::ThermostatSetpointDualSetpoint.new(model)
865
- thermostat_setpoint.setName("#{living_zone.name} temperature setpoint")
930
+ thermostat_setpoint.setName("#{conditioned_zone.name} temperature setpoint")
866
931
  thermostat_setpoint.setHeatingSetpointTemperatureSchedule(heating_sch)
867
932
  thermostat_setpoint.setCoolingSetpointTemperatureSchedule(cooling_sch)
868
- living_zone.setThermostatSetpointDualSetpoint(thermostat_setpoint)
933
+ conditioned_zone.setThermostatSetpointDualSetpoint(thermostat_setpoint)
869
934
  end
870
935
 
871
936
  def self.create_setpoint_schedules(runner, heating_days, cooling_days, htg_weekday_setpoints, htg_weekend_setpoints, clg_weekday_setpoints, clg_weekend_setpoints, year)
@@ -1024,189 +1089,357 @@ class HVAC
1024
1089
  return clg_sp, clg_setup_sp, clg_setup_hrs_per_week, clg_setup_start_hr
1025
1090
  end
1026
1091
 
1027
- def self.set_cool_curves_central_air_source(heat_pump, use_eer = false)
1028
- hp_ap = heat_pump.additional_properties
1029
- hp_ap.cool_rated_cfm_per_ton = get_default_cool_cfm_per_ton(hp_ap.num_speeds, use_eer)
1030
- if hp_ap.num_speeds == 1
1031
- # From "Improved Modeling of Residential Air Conditioners and Heat Pumps for Energy Calculations", Cutler at al
1092
+ def self.get_default_heating_capacity_retention(compressor_type, hspf = nil)
1093
+ retention_temp = 5.0
1094
+ if [HPXML::HVACCompressorTypeSingleStage, HPXML::HVACCompressorTypeTwoStage].include? compressor_type
1095
+ retention_fraction = 0.425
1096
+ elsif [HPXML::HVACCompressorTypeVariableSpeed].include? compressor_type
1097
+ # Default maximum capacity maintenance based on NEEP data for all var speed heat pump types, if not provided
1098
+ retention_fraction = (0.0461 * hspf + 0.1594).round(4)
1099
+ end
1100
+ return retention_temp, retention_fraction
1101
+ end
1102
+
1103
+ def self.get_cool_cap_eir_ft_spec(compressor_type)
1104
+ if compressor_type == HPXML::HVACCompressorTypeSingleStage
1105
+ cap_ft_spec = [[3.68637657, -0.098352478, 0.000956357, 0.005838141, -0.0000127, -0.000131702]]
1106
+ eir_ft_spec = [[-3.437356399, 0.136656369, -0.001049231, -0.0079378, 0.000185435, -0.0001441]]
1107
+ elsif compressor_type == HPXML::HVACCompressorTypeTwoStage
1108
+ cap_ft_spec = [[3.998418659, -0.108728222, 0.001056818, 0.007512314, -0.0000139, -0.000164716],
1109
+ [3.466810106, -0.091476056, 0.000901205, 0.004163355, -0.00000919, -0.000110829]]
1110
+ eir_ft_spec = [[-4.282911381, 0.181023691, -0.001357391, -0.026310378, 0.000333282, -0.000197405],
1111
+ [-3.557757517, 0.112737397, -0.000731381, 0.013184877, 0.000132645, -0.000338716]]
1112
+ end
1113
+ return cap_ft_spec, eir_ft_spec
1114
+ end
1115
+
1116
+ def self.get_cool_cap_eir_fflow_spec(compressor_type)
1117
+ if compressor_type == HPXML::HVACCompressorTypeSingleStage
1118
+ # Single stage systems have PSC or constant torque ECM blowers, so the airflow rate is affected by the static pressure losses.
1119
+ cap_fflow_spec = [[0.718664047, 0.41797409, -0.136638137]]
1120
+ eir_fflow_spec = [[1.143487507, -0.13943972, -0.004047787]]
1121
+ elsif compressor_type == HPXML::HVACCompressorTypeTwoStage
1122
+ # Most two stage systems have PSC or constant torque ECM blowers, so the airflow rate is affected by the static pressure losses.
1123
+ cap_fflow_spec = [[0.655239515, 0.511655216, -0.166894731],
1124
+ [0.618281092, 0.569060264, -0.187341356]]
1125
+ eir_fflow_spec = [[1.639108268, -0.998953996, 0.359845728],
1126
+ [1.570774717, -0.914152018, 0.343377302]]
1127
+ elsif compressor_type == HPXML::HVACCompressorTypeVariableSpeed
1128
+ # Variable speed systems have constant flow ECM blowers, so the air handler can always achieve the design airflow rate by sacrificing blower power.
1129
+ # So we assume that there is only one corresponding airflow rate for each compressor speed.
1130
+ eir_fflow_spec = [[1, 0, 0]] * 2
1131
+ cap_fflow_spec = [[1, 0, 0]] * 2
1132
+ end
1133
+ return cap_fflow_spec, eir_fflow_spec
1134
+ end
1135
+
1136
+ def self.get_heat_cap_eir_ft_spec(compressor_type, heating_capacity_retention_temp, heating_capacity_retention_fraction)
1137
+ cap_ft_spec = calc_heat_cap_ft_spec(compressor_type, heating_capacity_retention_temp, heating_capacity_retention_fraction)
1138
+ if compressor_type == HPXML::HVACCompressorTypeSingleStage
1139
+ # From "Improved Modeling of Residential Air Conditioners and Heat Pumps for Energy Calculations", Cutler et al
1032
1140
  # https://www.nrel.gov/docs/fy13osti/56354.pdf
1033
- hp_ap.cool_cap_ft_spec = [[3.68637657, -0.098352478, 0.000956357, 0.005838141, -0.0000127, -0.000131702]]
1034
- hp_ap.cool_eir_ft_spec = [[-3.437356399, 0.136656369, -0.001049231, -0.0079378, 0.000185435, -0.0001441]]
1035
- hp_ap.cool_capacity_ratios = [1.0]
1036
- if not use_eer
1037
- hp_ap.cool_rated_airflow_rate = hp_ap.cool_rated_cfm_per_ton[0]
1038
- hp_ap.cool_fan_speed_ratios = calc_fan_speed_ratios(hp_ap.cool_capacity_ratios, hp_ap.cool_rated_cfm_per_ton, hp_ap.cool_rated_airflow_rate)
1039
- # Single stage systems have PSC or constant torque ECM blowers, so the airflow rate is affected by the static pressure losses.
1040
- cap_fflow_spec, eir_fflow_spec = get_airflow_fault_cooling_coeff()
1041
- hp_ap.cool_cap_fflow_spec = [cap_fflow_spec]
1042
- hp_ap.cool_eir_fflow_spec = [eir_fflow_spec]
1043
- hp_ap.cool_eers = [calc_eer_cooling_1speed(heat_pump.cooling_efficiency_seer, hp_ap.cool_c_d, hp_ap.fan_power_rated, hp_ap.cool_eir_ft_spec)]
1044
- else
1045
- hp_ap.cool_fan_speed_ratios = [1.0]
1046
- hp_ap.cool_cap_fflow_spec = [[1.0, 0.0, 0.0]]
1047
- hp_ap.cool_eir_fflow_spec = [[1.0, 0.0, 0.0]]
1048
- end
1049
- elsif hp_ap.num_speeds == 2
1050
- # From "Improved Modeling of Residential Air Conditioners and Heat Pumps for Energy Calculations", Cutler at al
1141
+ eir_ft_spec = [[0.718398423, 0.003498178, 0.000142202, -0.005724331, 0.00014085, -0.000215321]]
1142
+ elsif compressor_type == HPXML::HVACCompressorTypeTwoStage
1143
+ # From "Improved Modeling of Residential Air Conditioners and Heat Pumps for Energy Calculations", Cutler et al
1051
1144
  # https://www.nrel.gov/docs/fy13osti/56354.pdf
1052
- hp_ap.cool_rated_airflow_rate = hp_ap.cool_rated_cfm_per_ton[-1]
1053
- hp_ap.cool_capacity_ratios = [0.72, 1.0]
1054
- hp_ap.cool_fan_speed_ratios = calc_fan_speed_ratios(hp_ap.cool_capacity_ratios, hp_ap.cool_rated_cfm_per_ton, hp_ap.cool_rated_airflow_rate)
1055
- hp_ap.cool_cap_ft_spec = [[3.998418659, -0.108728222, 0.001056818, 0.007512314, -0.0000139, -0.000164716],
1056
- [3.466810106, -0.091476056, 0.000901205, 0.004163355, -0.00000919, -0.000110829]]
1057
- hp_ap.cool_eir_ft_spec = [[-4.282911381, 0.181023691, -0.001357391, -0.026310378, 0.000333282, -0.000197405],
1058
- [-3.557757517, 0.112737397, -0.000731381, 0.013184877, 0.000132645, -0.000338716]]
1145
+ eir_ft_spec = [[0.36338171, 0.013523725, 0.000258872, -0.009450269, 0.000439519, -0.000653723],
1146
+ [0.981100941, -0.005158493, 0.000243416, -0.005274352, 0.000230742, -0.000336954]]
1147
+ end
1148
+ return cap_ft_spec, eir_ft_spec
1149
+ end
1150
+
1151
+ def self.get_heat_cap_eir_fflow_spec(compressor_type)
1152
+ if compressor_type == HPXML::HVACCompressorTypeSingleStage
1153
+ # Single stage systems have PSC or constant torque ECM blowers, so the airflow rate is affected by the static pressure losses.
1154
+ cap_fflow_spec = [[0.694045465, 0.474207981, -0.168253446]]
1155
+ eir_fflow_spec = [[2.185418751, -1.942827919, 0.757409168]]
1156
+ elsif compressor_type == HPXML::HVACCompressorTypeTwoStage
1059
1157
  # Most two stage systems have PSC or constant torque ECM blowers, so the airflow rate is affected by the static pressure losses.
1060
- hp_ap.cool_cap_fflow_spec = [[0.655239515, 0.511655216, -0.166894731],
1061
- [0.618281092, 0.569060264, -0.187341356]]
1062
- hp_ap.cool_eir_fflow_spec = [[1.639108268, -0.998953996, 0.359845728],
1063
- [1.570774717, -0.914152018, 0.343377302]]
1064
- hp_ap.cool_eers = calc_eers_cooling_2speed(heat_pump.cooling_efficiency_seer, hp_ap.cool_c_d, hp_ap.cool_capacity_ratios, hp_ap.cool_fan_speed_ratios, hp_ap.fan_power_rated, hp_ap.cool_eir_ft_spec, hp_ap.cool_cap_ft_spec)
1065
- elsif hp_ap.num_speeds == 4
1066
- # From Carrier heat pump lab testing
1067
- hp_ap.cool_rated_airflow_rate = hp_ap.cool_rated_cfm_per_ton[-1]
1068
- hp_ap.cool_capacity_ratios = [0.36, 0.51, 0.67, 1.0]
1069
- hp_ap.cool_fan_speed_ratios = calc_fan_speed_ratios(hp_ap.cool_capacity_ratios, hp_ap.cool_rated_cfm_per_ton, hp_ap.cool_rated_airflow_rate)
1070
- hp_ap.cool_cap_coeff_perf_map = [[1.6516044444444447, 0.0698916049382716, -0.0005546296296296296, -0.08870160493827162, 0.0004135802469135802, 0.00029077160493827157],
1071
- [-6.84948049382716, 0.26946, -0.0019413580246913577, -0.03281469135802469, 0.00015694444444444442, 3.32716049382716e-05],
1072
- [-4.53543086419753, 0.15358543209876546, -0.0009345679012345678, 0.002666913580246914, -7.993827160493826e-06, -0.00011617283950617283],
1073
- [-3.500948395061729, 0.11738987654320988, -0.0006580246913580248, 0.007003148148148148, -2.8518518518518517e-05, -0.0001284259259259259],
1074
- [1.8769221728395058, -0.04768641975308643, 0.0006885802469135801, 0.006643395061728395, 1.4209876543209876e-05, -0.00024043209876543206]]
1075
- hp_ap.cool_cap_ft_spec = hp_ap.cool_cap_coeff_perf_map.select { |i| [0, 1, 2, 4].include? hp_ap.cool_cap_coeff_perf_map.index(i) }
1076
- hp_ap.cool_cap_ft_spec_3 = hp_ap.cool_cap_coeff_perf_map.select { |i| [0, 1, 4].include? hp_ap.cool_cap_coeff_perf_map.index(i) }
1077
- hp_ap.cool_eir_coeff_perf_map = [[2.896298765432099, -0.12487654320987657, 0.0012148148148148148, 0.04492037037037037, 8.734567901234567e-05, -0.0006348765432098764],
1078
- [6.428076543209876, -0.20913209876543212, 0.0018521604938271604, 0.024392592592592594, 0.00019691358024691356, -0.0006012345679012346],
1079
- [5.136356049382716, -0.1591530864197531, 0.0014151234567901232, 0.018665555555555557, 0.00020398148148148147, -0.0005407407407407407],
1080
- [1.3823471604938273, -0.02875123456790123, 0.00038302469135802463, 0.006344814814814816, 0.00024836419753086417, -0.00047469135802469134],
1081
- [-1.0411735802469133, 0.055261604938271605, -0.0004404320987654321, 0.0002154938271604939, 0.00017484567901234564, -0.0002017901234567901]]
1082
- hp_ap.cool_eir_ft_spec = hp_ap.cool_eir_coeff_perf_map.select { |i| [0, 1, 2, 4].include? hp_ap.cool_eir_coeff_perf_map.index(i) }
1083
- hp_ap.cool_eir_ft_spec_3 = hp_ap.cool_eir_coeff_perf_map.select { |i| [0, 1, 4].include? hp_ap.cool_eir_coeff_perf_map.index(i) }
1158
+ cap_fflow_spec = [[0.741466907, 0.378645444, -0.119754733],
1159
+ [0.76634609, 0.32840943, -0.094701495]]
1160
+ eir_fflow_spec = [[2.153618211, -1.737190609, 0.584269478],
1161
+ [2.001041353, -1.58869128, 0.587593517]]
1162
+ elsif compressor_type == HPXML::HVACCompressorTypeVariableSpeed
1084
1163
  # Variable speed systems have constant flow ECM blowers, so the air handler can always achieve the design airflow rate by sacrificing blower power.
1085
1164
  # So we assume that there is only one corresponding airflow rate for each compressor speed.
1086
- hp_ap.cool_eir_fflow_spec = [[1, 0, 0]] * 4
1087
- hp_ap.cool_cap_fflow_spec = [[1, 0, 0]] * 4
1088
- hp_ap.cap_ratio_seer_3 = hp_ap.cool_capacity_ratios.select { |i| [0, 1, 3].include? hp_ap.cool_capacity_ratios.index(i) }
1089
- hp_ap.fan_speed_seer_3 = hp_ap.cool_fan_speed_ratios.select { |i| [0, 1, 3].include? hp_ap.cool_fan_speed_ratios.index(i) }
1090
- hp_ap.cool_eers = calc_eers_cooling_4speed(heat_pump.cooling_efficiency_seer, hp_ap.cool_c_d, hp_ap.cap_ratio_seer_3, hp_ap.fan_speed_seer_3, hp_ap.fan_power_rated, hp_ap.cool_eir_ft_spec_3, hp_ap.cool_cap_ft_spec_3)
1165
+ cap_fflow_spec = [[1, 0, 0]] * 3
1166
+ eir_fflow_spec = [[1, 0, 0]] * 3
1091
1167
  end
1168
+ return cap_fflow_spec, eir_fflow_spec
1092
1169
  end
1093
1170
 
1094
- def self.set_heat_curves_central_air_source(heat_pump, use_cop = false)
1095
- hp_ap = heat_pump.additional_properties
1096
- hp_ap.heat_rated_cfm_per_ton = get_default_heat_cfm_per_ton(hp_ap.num_speeds, use_cop)
1097
- if hp_ap.num_speeds == 1
1098
- # From "Improved Modeling of Residential Air Conditioners and Heat Pumps for Energy Calculations", Cutler at al
1099
- # https://www.nrel.gov/docs/fy13osti/56354.pdf
1100
- hp_ap.heat_capacity_ratios = [1.0]
1101
- hp_ap.heat_eir_ft_spec = [[0.718398423, 0.003498178, 0.000142202, -0.005724331, 0.00014085, -0.000215321]]
1102
- cap_fflow_spec, eir_fflow_spec = get_airflow_fault_heating_coeff()
1103
- hp_ap.heat_cap_fflow_spec = [cap_fflow_spec]
1104
- hp_ap.heat_eir_fflow_spec = [eir_fflow_spec]
1105
- hp_ap.heat_cap_ft_spec = calc_heat_cap_ft_spec(heat_pump, heat_pump.additional_properties.num_speeds)
1106
- if not use_cop
1107
- hp_ap.heat_cops = [calc_cop_heating_1speed(heat_pump.heating_efficiency_hspf, hp_ap.heat_c_d, hp_ap.fan_power_rated, hp_ap.heat_eir_ft_spec, hp_ap.heat_cap_ft_spec)]
1108
- hp_ap.heat_rated_airflow_rate = hp_ap.heat_rated_cfm_per_ton[0]
1109
- hp_ap.heat_fan_speed_ratios = calc_fan_speed_ratios(hp_ap.heat_capacity_ratios, hp_ap.heat_rated_cfm_per_ton, hp_ap.heat_rated_airflow_rate)
1171
+ def self.set_cool_curves_central_air_source(runner, cooling_system, use_eer = false)
1172
+ clg_ap = cooling_system.additional_properties
1173
+ clg_ap.cool_rated_cfm_per_ton = get_default_cool_cfm_per_ton(cooling_system.compressor_type, use_eer)
1174
+ clg_ap.cool_capacity_ratios = get_cool_capacity_ratios(cooling_system)
1175
+ set_cool_c_d(cooling_system)
1176
+
1177
+ seer = cooling_system.cooling_efficiency_seer
1178
+ if cooling_system.compressor_type == HPXML::HVACCompressorTypeSingleStage
1179
+ clg_ap.cool_cap_ft_spec, clg_ap.cool_eir_ft_spec = get_cool_cap_eir_ft_spec(cooling_system.compressor_type)
1180
+ if not use_eer
1181
+ clg_ap.cool_rated_airflow_rate = clg_ap.cool_rated_cfm_per_ton[0]
1182
+ clg_ap.cool_fan_speed_ratios = calc_fan_speed_ratios(clg_ap.cool_capacity_ratios, clg_ap.cool_rated_cfm_per_ton, clg_ap.cool_rated_airflow_rate)
1183
+ clg_ap.cool_cap_fflow_spec, clg_ap.cool_eir_fflow_spec = get_cool_cap_eir_fflow_spec(cooling_system.compressor_type)
1184
+ clg_ap.cool_rated_cops = [0.2692 * seer + 0.2706] # Regression based on inverse model
1110
1185
  else
1111
- hp_ap.heat_fan_speed_ratios = [1.0]
1186
+ clg_ap.cool_fan_speed_ratios = [1.0]
1187
+ clg_ap.cool_cap_fflow_spec = [[1.0, 0.0, 0.0]]
1188
+ clg_ap.cool_eir_fflow_spec = [[1.0, 0.0, 0.0]]
1112
1189
  end
1113
- elsif hp_ap.num_speeds == 2
1114
- # From "Improved Modeling of Residential Air Conditioners and Heat Pumps for Energy Calculations", Cutler at al
1115
- # https://www.nrel.gov/docs/fy13osti/56354.pdf
1116
- hp_ap.heat_rated_airflow_rate = hp_ap.heat_rated_cfm_per_ton[-1]
1117
- hp_ap.heat_capacity_ratios = [0.72, 1.0]
1118
- hp_ap.heat_fan_speed_ratios = calc_fan_speed_ratios(hp_ap.heat_capacity_ratios, hp_ap.heat_rated_cfm_per_ton, hp_ap.heat_rated_airflow_rate)
1119
- hp_ap.heat_eir_ft_spec = [[0.36338171, 0.013523725, 0.000258872, -0.009450269, 0.000439519, -0.000653723],
1120
- [0.981100941, -0.005158493, 0.000243416, -0.005274352, 0.000230742, -0.000336954]]
1121
- hp_ap.heat_cap_fflow_spec = [[0.741466907, 0.378645444, -0.119754733],
1122
- [0.76634609, 0.32840943, -0.094701495]]
1123
- hp_ap.heat_eir_fflow_spec = [[2.153618211, -1.737190609, 0.584269478],
1124
- [2.001041353, -1.58869128, 0.587593517]]
1125
- hp_ap.heat_cap_ft_spec = calc_heat_cap_ft_spec(heat_pump, heat_pump.additional_properties.num_speeds)
1126
- hp_ap.heat_cops = calc_cops_heating_2speed(heat_pump.heating_efficiency_hspf, hp_ap.heat_c_d, hp_ap.heat_capacity_ratios, hp_ap.heat_fan_speed_ratios, hp_ap.fan_power_rated, hp_ap.heat_eir_ft_spec, hp_ap.heat_cap_ft_spec)
1127
- elsif hp_ap.num_speeds == 4
1128
- # From manufacturers data
1129
- hp_ap.heat_rated_airflow_rate = hp_ap.heat_rated_cfm_per_ton[-2]
1130
- hp_ap.heat_capacity_ratios = [0.33, 0.56, 1.0, 1.17]
1131
- hp_ap.heat_fan_speed_ratios = calc_fan_speed_ratios(hp_ap.heat_capacity_ratios, hp_ap.heat_rated_cfm_per_ton, hp_ap.heat_rated_airflow_rate)
1132
- hp_ap.heat_eir_ft_spec = [[0.708311527, 0.020732093, 0.000391479, -0.037640031, 0.000979937, -0.001079042],
1133
- [0.025480155, 0.020169585, 0.000121341, -0.004429789, 0.000166472, -0.00036447],
1134
- [0.379003189, 0.014195012, 0.0000821046, -0.008894061, 0.000151519, -0.000210299],
1135
- [0.690404655, 0.00616619, 0.000137643, -0.009350199, 0.000153427, -0.000213258]]
1136
- hp_ap.heat_cap_fflow_spec = [[1, 0, 0]] * 4
1137
- hp_ap.heat_eir_fflow_spec = [[1, 0, 0]] * 4
1138
- hp_ap.heat_cap_ft_spec = calc_heat_cap_ft_spec(heat_pump, heat_pump.additional_properties.num_speeds)
1139
- hp_ap.heat_cops = calc_cops_heating_4speed(heat_pump.heating_efficiency_hspf, hp_ap.heat_c_d, hp_ap.heat_capacity_ratios, hp_ap.heat_fan_speed_ratios, hp_ap.fan_power_rated, hp_ap.heat_eir_ft_spec, hp_ap.heat_cap_ft_spec)
1190
+
1191
+ elsif cooling_system.compressor_type == HPXML::HVACCompressorTypeTwoStage
1192
+ clg_ap.cool_rated_airflow_rate = clg_ap.cool_rated_cfm_per_ton[-1]
1193
+ clg_ap.cool_fan_speed_ratios = calc_fan_speed_ratios(clg_ap.cool_capacity_ratios, clg_ap.cool_rated_cfm_per_ton, clg_ap.cool_rated_airflow_rate)
1194
+ clg_ap.cool_cap_ft_spec, clg_ap.cool_eir_ft_spec = get_cool_cap_eir_ft_spec(cooling_system.compressor_type)
1195
+ clg_ap.cool_cap_fflow_spec, clg_ap.cool_eir_fflow_spec = get_cool_cap_eir_fflow_spec(cooling_system.compressor_type)
1196
+ clg_ap.cool_rated_cops = [0.2773 * seer - 0.0018] # Regression based on inverse model
1197
+ clg_ap.cool_rated_cops << clg_ap.cool_rated_cops[0] * 0.91 # COP ratio based on Dylan's data as seen in BEopt 2.8 options
1198
+
1199
+ elsif cooling_system.compressor_type == HPXML::HVACCompressorTypeVariableSpeed
1200
+ clg_ap.cooling_capacity_retention_temperature = 82.0
1201
+ clg_ap.cooling_capacity_retention_fraction = 1.033 # From NEEP data
1202
+ clg_ap.cool_rated_airflow_rate = clg_ap.cool_rated_cfm_per_ton[-1]
1203
+ clg_ap.cool_fan_speed_ratios = calc_fan_speed_ratios(clg_ap.cool_capacity_ratios, clg_ap.cool_rated_cfm_per_ton, clg_ap.cool_rated_airflow_rate)
1204
+ clg_ap.cool_cap_fflow_spec, clg_ap.cool_eir_fflow_spec = get_cool_cap_eir_fflow_spec(cooling_system.compressor_type)
1140
1205
  end
1206
+
1207
+ set_cool_rated_shrs_gross(runner, cooling_system)
1141
1208
  end
1142
1209
 
1143
- def self.set_cool_curves_mshp(heat_pump, num_speeds)
1144
- hp_ap = heat_pump.additional_properties
1210
+ def self.get_cool_capacity_ratios(hvac_system)
1211
+ # For each speed, ratio of capacity to nominal capacity
1212
+ if hvac_system.compressor_type == HPXML::HVACCompressorTypeSingleStage
1213
+ return [1.0]
1214
+ elsif hvac_system.compressor_type == HPXML::HVACCompressorTypeTwoStage
1215
+ return [0.72, 1.0]
1216
+ elsif hvac_system.compressor_type == HPXML::HVACCompressorTypeVariableSpeed
1217
+ is_ducted = !hvac_system.distribution_system_idref.nil?
1218
+ if is_ducted
1219
+ return [0.394, 1.0]
1220
+ else
1221
+ return [0.255, 1.0]
1222
+ end
1223
+ end
1224
+
1225
+ fail 'Unable to get cooling capacity ratios.'
1226
+ end
1227
+
1228
+ def self.set_heat_curves_central_air_source(heating_system, use_cop = false)
1229
+ htg_ap = heating_system.additional_properties
1230
+ htg_ap.heat_rated_cfm_per_ton = get_default_heat_cfm_per_ton(heating_system.compressor_type, use_cop)
1231
+ heating_capacity_retention_temp, heating_capacity_retention_fraction = get_heating_capacity_retention(heating_system)
1232
+ htg_ap.heat_cap_fflow_spec, htg_ap.heat_eir_fflow_spec = get_heat_cap_eir_fflow_spec(heating_system.compressor_type)
1233
+ htg_ap.heat_capacity_ratios = get_heat_capacity_ratios(heating_system)
1234
+ set_heat_c_d(heating_system)
1235
+
1236
+ hspf = heating_system.heating_efficiency_hspf
1237
+ if heating_system.compressor_type == HPXML::HVACCompressorTypeSingleStage
1238
+ htg_ap.heat_cap_ft_spec, htg_ap.heat_eir_ft_spec = get_heat_cap_eir_ft_spec(heating_system.compressor_type, heating_capacity_retention_temp, heating_capacity_retention_fraction)
1239
+ if not use_cop
1240
+ htg_ap.heat_rated_cops = [0.0353 * hspf**2 + 0.0331 * hspf + 0.9447] # Regression based on inverse model
1241
+ htg_ap.heat_rated_airflow_rate = htg_ap.heat_rated_cfm_per_ton[0]
1242
+ htg_ap.heat_fan_speed_ratios = calc_fan_speed_ratios(htg_ap.heat_capacity_ratios, htg_ap.heat_rated_cfm_per_ton, htg_ap.heat_rated_airflow_rate)
1243
+ else
1244
+ htg_ap.heat_fan_speed_ratios = [1.0]
1245
+ end
1145
1246
 
1146
- # From Daikin mini-split lab testing
1147
- hp_ap.cool_cap_ft_spec = [[0.7531983499655835, 0.003618193903031667, 0.0, 0.006574385031351544, -6.87181191015432e-05, 0.0]] * num_speeds
1148
- hp_ap.cool_eir_ft_spec = [[-0.06376924779982301, -0.0013360593470367282, 1.413060577993827e-05, 0.019433076486584752, -4.91395947154321e-05, -4.909341249475308e-05]] * num_speeds
1149
- hp_ap.cool_cap_fflow_spec = [[1, 0, 0]] * num_speeds
1150
- hp_ap.cool_eir_fflow_spec = [[1, 0, 0]] * num_speeds
1247
+ elsif heating_system.compressor_type == HPXML::HVACCompressorTypeTwoStage
1248
+ htg_ap.heat_cap_ft_spec, htg_ap.heat_eir_ft_spec = get_heat_cap_eir_ft_spec(heating_system.compressor_type, heating_capacity_retention_temp, heating_capacity_retention_fraction)
1249
+ htg_ap.heat_rated_airflow_rate = htg_ap.heat_rated_cfm_per_ton[-1]
1250
+ htg_ap.heat_fan_speed_ratios = calc_fan_speed_ratios(htg_ap.heat_capacity_ratios, htg_ap.heat_rated_cfm_per_ton, htg_ap.heat_rated_airflow_rate)
1251
+ htg_ap.heat_rated_cops = [0.0426 * hspf**2 - 0.0747 * hspf + 1.5374] # Regression based on inverse model
1252
+ htg_ap.heat_rated_cops << htg_ap.heat_rated_cops[0] * 0.87 # COP ratio based on Dylan's data as seen in BEopt 2.8 options
1151
1253
 
1152
- hp_ap.cool_capacity_ratios = [0.4, 0.4889, 0.5778, 0.6667, 0.7556, 0.8444, 0.9333, 1.0222, 1.1111, 1.2]
1153
- hp_ap.cool_rated_cfm_per_ton = get_default_cool_cfm_per_ton(num_speeds)
1154
- hp_ap.cool_rated_airflow_rate = hp_ap.cool_rated_cfm_per_ton[-1] * hp_ap.cool_capacity_ratios[-1]
1155
- hp_ap.cool_fan_speed_ratios = calc_fan_speed_ratios(hp_ap.cool_capacity_ratios, hp_ap.cool_rated_cfm_per_ton, hp_ap.cool_rated_airflow_rate)
1254
+ elsif heating_system.compressor_type == HPXML::HVACCompressorTypeVariableSpeed
1255
+ htg_ap.heat_rated_airflow_rate = htg_ap.heat_rated_cfm_per_ton[-1]
1256
+ htg_ap.heat_capacity_ratios = get_heat_capacity_ratios(heating_system)
1257
+ htg_ap.heat_fan_speed_ratios = calc_fan_speed_ratios(htg_ap.heat_capacity_ratios, htg_ap.heat_rated_cfm_per_ton, htg_ap.heat_rated_airflow_rate)
1258
+ end
1156
1259
  end
1157
1260
 
1158
- def self.set_heat_curves_mshp(heat_pump, num_speeds)
1261
+ def self.set_heat_detailed_performance_data(heat_pump)
1262
+ hp_ap = heat_pump.additional_properties
1263
+ is_ducted = !heat_pump.distribution_system_idref.nil?
1264
+ hspf = heat_pump.heating_efficiency_hspf
1265
+
1266
+ # Default data inputs based on NEEP data
1267
+ detailed_performance_data = heat_pump.heating_detailed_performance_data
1268
+ heating_capacity_retention_temp, heating_capacity_retention_fraction = get_heating_capacity_retention(heat_pump)
1269
+ max_cap_maint_5 = 1.0 - (1.0 - heating_capacity_retention_fraction) * (HVAC::AirSourceHeatRatedODB - 5.0) /
1270
+ (HVAC::AirSourceHeatRatedODB - heating_capacity_retention_temp)
1271
+
1272
+ if is_ducted
1273
+ a, b, c, d, e = 0.4348, 0.008923, 1.090, -0.1861, -0.07564
1274
+ else
1275
+ a, b, c, d, e = 0.1914, -1.822, 1.364, -0.07783, 2.221
1276
+ end
1277
+ max_cop_47 = a * hspf + b * max_cap_maint_5 + c * max_cap_maint_5**2 + d * max_cap_maint_5 * hspf + e
1278
+ max_capacity_47 = heat_pump.heating_capacity * hp_ap.heat_capacity_ratios[-1]
1279
+ min_capacity_47 = max_capacity_47 / hp_ap.heat_capacity_ratios[-1] * hp_ap.heat_capacity_ratios[0]
1280
+ min_cop_47 = is_ducted ? max_cop_47 * (-0.0306 * hspf + 1.5385) : max_cop_47 * (-0.01698 * hspf + 1.5907)
1281
+ max_capacity_5 = max_capacity_47 * max_cap_maint_5
1282
+ max_cop_5 = is_ducted ? max_cop_47 * 0.587 : max_cop_47 * 0.671
1283
+ min_capacity_5 = is_ducted ? min_capacity_47 * 1.106 : min_capacity_47 * 0.611
1284
+ min_cop_5 = is_ducted ? min_cop_47 * 0.502 : min_cop_47 * 0.538
1285
+
1286
+ # performance data at 47F, maximum speed
1287
+ detailed_performance_data.add(capacity: max_capacity_47.round(1),
1288
+ efficiency_cop: max_cop_47.round(4),
1289
+ capacity_description: HPXML::CapacityDescriptionMaximum,
1290
+ outdoor_temperature: 47,
1291
+ isdefaulted: true)
1292
+ # performance data at 47F, minimum speed
1293
+ detailed_performance_data.add(capacity: min_capacity_47.round(1),
1294
+ efficiency_cop: min_cop_47.round(4),
1295
+ capacity_description: HPXML::CapacityDescriptionMinimum,
1296
+ outdoor_temperature: 47,
1297
+ isdefaulted: true)
1298
+ # performance data at 5F, maximum speed
1299
+ detailed_performance_data.add(capacity: max_capacity_5.round(1),
1300
+ efficiency_cop: max_cop_5.round(4),
1301
+ capacity_description: HPXML::CapacityDescriptionMaximum,
1302
+ outdoor_temperature: 5,
1303
+ isdefaulted: true)
1304
+ # performance data at 5F, minimum speed
1305
+ detailed_performance_data.add(capacity: min_capacity_5.round(1),
1306
+ efficiency_cop: min_cop_5.round(4),
1307
+ capacity_description: HPXML::CapacityDescriptionMinimum,
1308
+ outdoor_temperature: 5,
1309
+ isdefaulted: true)
1310
+ end
1311
+
1312
+ def self.set_cool_detailed_performance_data(heat_pump)
1159
1313
  hp_ap = heat_pump.additional_properties
1314
+ is_ducted = !heat_pump.distribution_system_idref.nil?
1315
+ seer = heat_pump.cooling_efficiency_seer
1316
+
1317
+ # Default data inputs based on NEEP data
1318
+ detailed_performance_data = heat_pump.cooling_detailed_performance_data
1319
+ max_cap_maint_82 = 1.0 - (1.0 - hp_ap.cooling_capacity_retention_fraction) * (HVAC::AirSourceCoolRatedODB - 82.0) /
1320
+ (HVAC::AirSourceCoolRatedODB - hp_ap.cooling_capacity_retention_temperature)
1321
+
1322
+ max_cop_95 = is_ducted ? 0.1953 * seer : 0.06635 * seer + 1.8707
1323
+ max_capacity_95 = heat_pump.cooling_capacity * hp_ap.cool_capacity_ratios[-1]
1324
+ min_capacity_95 = max_capacity_95 / hp_ap.cool_capacity_ratios[-1] * hp_ap.cool_capacity_ratios[0]
1325
+ min_cop_95 = is_ducted ? max_cop_95 * 1.231 : max_cop_95 * (0.01377 * seer + 1.13948)
1326
+ max_capacity_82 = max_capacity_95 * max_cap_maint_82
1327
+ max_cop_82 = is_ducted ? (1.297 * max_cop_95) : (1.300 * max_cop_95)
1328
+ min_capacity_82 = min_capacity_95 * 1.099
1329
+ min_cop_82 = is_ducted ? (1.402 * min_cop_95) : (1.333 * min_cop_95)
1330
+
1331
+ # performance data at 95F, maximum speed
1332
+ detailed_performance_data.add(capacity: max_capacity_95.round(1),
1333
+ efficiency_cop: max_cop_95.round(4),
1334
+ capacity_description: HPXML::CapacityDescriptionMaximum,
1335
+ outdoor_temperature: 95,
1336
+ isdefaulted: true)
1337
+ # performance data at 95F, minimum speed
1338
+ detailed_performance_data.add(capacity: min_capacity_95.round(1),
1339
+ efficiency_cop: min_cop_95.round(4),
1340
+ capacity_description: HPXML::CapacityDescriptionMinimum,
1341
+ outdoor_temperature: 95,
1342
+ isdefaulted: true)
1343
+ # performance data at 82F, maximum speed
1344
+ detailed_performance_data.add(capacity: max_capacity_82.round(1),
1345
+ efficiency_cop: max_cop_82.round(4),
1346
+ capacity_description: HPXML::CapacityDescriptionMaximum,
1347
+ outdoor_temperature: 82,
1348
+ isdefaulted: true)
1349
+ # performance data at 82F, minimum speed
1350
+ detailed_performance_data.add(capacity: min_capacity_82.round(1),
1351
+ efficiency_cop: min_cop_82.round(4),
1352
+ capacity_description: HPXML::CapacityDescriptionMinimum,
1353
+ outdoor_temperature: 82,
1354
+ isdefaulted: true)
1355
+ end
1356
+
1357
+ def self.get_heat_capacity_ratios(heat_pump)
1358
+ # For each speed, ratio of capacity to nominal capacity
1359
+ if heat_pump.compressor_type == HPXML::HVACCompressorTypeSingleStage
1360
+ return [1.0]
1361
+ elsif heat_pump.compressor_type == HPXML::HVACCompressorTypeTwoStage
1362
+ return [0.72, 1.0]
1363
+ elsif heat_pump.compressor_type == HPXML::HVACCompressorTypeVariableSpeed
1364
+ is_ducted = !heat_pump.distribution_system_idref.nil?
1365
+ if is_ducted
1366
+ nominal_to_max_ratio = 0.972
1367
+ else
1368
+ nominal_to_max_ratio = 0.812
1369
+ end
1370
+ if is_ducted && heat_pump.heat_pump_type == HPXML::HVACTypeHeatPumpAirToAir
1371
+ # central ducted
1372
+ return [0.358 / nominal_to_max_ratio, 1.0, 1.0 / nominal_to_max_ratio]
1373
+ elsif !is_ducted
1374
+ # wall placement
1375
+ return [0.252 / nominal_to_max_ratio, 1.0, 1.0 / nominal_to_max_ratio]
1376
+ else
1377
+ # ducted minisplit
1378
+ return [0.305 / nominal_to_max_ratio, 1.0, 1.0 / nominal_to_max_ratio]
1379
+ end
1380
+ end
1381
+
1382
+ fail 'Unable to get heating capacity ratios.'
1383
+ end
1160
1384
 
1161
- # From Daikin mini-split lab testing
1162
- hp_ap.heat_eir_ft_spec = [[0.9999941697687026, 0.004684593830254383, 5.901286675833333e-05, -0.0028624467783091973, 1.3041120194135802e-05, -0.00016172918478765433]] * num_speeds
1163
- hp_ap.heat_cap_fflow_spec = [[1, 0, 0]] * num_speeds
1164
- hp_ap.heat_eir_fflow_spec = [[1, 0, 0]] * num_speeds
1385
+ def self.drop_intermediate_speeds(hvac_system)
1386
+ # For variable-speed systems, we only want to model min/max speeds in E+.
1387
+ # Here we drop any intermediate speeds that we may have added for other purposes (e.g. hvac sizing).
1388
+ return unless hvac_system.compressor_type == HPXML::HVACCompressorTypeVariableSpeed
1165
1389
 
1166
- hp_ap.heat_cap_ft_spec = calc_heat_cap_ft_spec(heat_pump, num_speeds)
1390
+ hvac_ap = hvac_system.additional_properties
1167
1391
 
1168
- # fan speed ratios
1169
- hp_ap.heat_capacity_ratios = [0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2]
1170
- hp_ap.heat_rated_cfm_per_ton = get_default_heat_cfm_per_ton(num_speeds)
1171
- hp_ap.heat_rated_airflow_rate = hp_ap.heat_rated_cfm_per_ton[-1] * hp_ap.heat_capacity_ratios[-1]
1172
- hp_ap.heat_fan_speed_ratios = calc_fan_speed_ratios(hp_ap.heat_capacity_ratios, hp_ap.heat_rated_cfm_per_ton, hp_ap.heat_rated_airflow_rate)
1392
+ while hvac_ap.cool_capacity_ratios.size > 2
1393
+ hvac_ap.cool_cap_fflow_spec.delete_at(1)
1394
+ hvac_ap.cool_eir_fflow_spec.delete_at(1)
1395
+ hvac_ap.cool_plf_fplr_spec.delete_at(1)
1396
+ hvac_ap.cool_rated_cfm_per_ton.delete_at(1)
1397
+ hvac_ap.cool_capacity_ratios.delete_at(1)
1398
+ hvac_ap.cool_fan_speed_ratios.delete_at(1)
1399
+ end
1400
+ if hvac_system.is_a? HPXML::HeatPump
1401
+ while hvac_ap.heat_capacity_ratios.size > 2
1402
+ hvac_ap.heat_cap_fflow_spec.delete_at(1)
1403
+ hvac_ap.heat_eir_fflow_spec.delete_at(1)
1404
+ hvac_ap.heat_plf_fplr_spec.delete_at(1)
1405
+ hvac_ap.heat_rated_cfm_per_ton.delete_at(1)
1406
+ hvac_ap.heat_capacity_ratios.delete_at(1)
1407
+ hvac_ap.heat_fan_speed_ratios.delete_at(1)
1408
+ end
1409
+ end
1173
1410
  end
1174
1411
 
1175
- def self.get_default_cool_cfm_per_ton(num_speeds, use_eer = false)
1412
+ def self.get_default_cool_cfm_per_ton(compressor_type, use_eer = false)
1176
1413
  # cfm/ton of rated capacity
1177
- if num_speeds == 1
1414
+ if compressor_type == HPXML::HVACCompressorTypeSingleStage
1178
1415
  if not use_eer
1179
1416
  return [394.2]
1180
1417
  else
1181
1418
  return [312] # medium speed
1182
1419
  end
1183
- elsif num_speeds == 2
1420
+ elsif compressor_type == HPXML::HVACCompressorTypeTwoStage
1184
1421
  return [411.0083, 344.1]
1185
- elsif num_speeds == 4
1186
- return [466.6667, 423.5294, 405.9701, 400.0]
1187
- elsif num_speeds == 10
1188
- return [470.6, 433.1356, 407.1997, 388.2406, 373.6898, 362.2454, 352.9412, 345.2945, 338.8354, 333.3333]
1422
+ elsif compressor_type == HPXML::HVACCompressorTypeVariableSpeed
1423
+ return [400.0, 400.0]
1189
1424
  else
1190
- fail 'number of speeds not supported.'
1425
+ fail 'Compressor type not supported.'
1191
1426
  end
1192
1427
  end
1193
1428
 
1194
- def self.get_default_heat_cfm_per_ton(num_speeds, use_cop_or_htg_sys = false)
1429
+ def self.get_default_heat_cfm_per_ton(compressor_type, use_cop_or_htg_sys = false)
1195
1430
  # cfm/ton of rated capacity
1196
- if num_speeds == 1
1431
+ if compressor_type == HPXML::HVACCompressorTypeSingleStage
1197
1432
  if not use_cop_or_htg_sys
1198
1433
  return [384.1]
1199
1434
  else
1200
1435
  return [350]
1201
1436
  end
1202
- elsif num_speeds == 2
1437
+ elsif compressor_type == HPXML::HVACCompressorTypeTwoStage
1203
1438
  return [391.3333, 352.2]
1204
- elsif num_speeds == 4
1205
- return [566.8091, 402.9357, 296.9, 301.9752]
1206
- elsif num_speeds == 10
1207
- return [666.6667, 555.6000, 488.8800, 444.4667, 412.6857, 388.9000, 370.3556, 355.5600, 343.4182, 333.3333]
1439
+ elsif compressor_type == HPXML::HVACCompressorTypeVariableSpeed
1440
+ return [400.0, 400.0, 400.0]
1208
1441
  else
1209
- fail 'number of speeds not supported.'
1442
+ fail 'Compressor type not supported.'
1210
1443
  end
1211
1444
  end
1212
1445
 
@@ -1222,19 +1455,22 @@ class HVAC
1222
1455
  hp_ap.cool_power_curve_spec = [[-4.42471086639888, 0.658017281046304, 4.37331801294626, 0.174096187531254, -0.0526514790164159]]
1223
1456
  hp_ap.cool_sh_curve_spec = [[4.54172823345154, 14.7653304889134, -18.3541272090485, -0.74401391092935, 0.545560799548833, 0.0182620032235494]]
1224
1457
  hp_ap.cool_rated_shrs_gross = [heat_pump.cooling_shr]
1225
- # FUTURE: Reconcile these fan/pump adjustments with ANSI/RESNET/ICC 301-2019 Section 4.4.5
1226
- fan_adjust_kw = UnitConversions.convert(400.0, 'Btu/hr', 'ton') * UnitConversions.convert(1.0, 'cfm', 'm^3/s') * 1000.0 * 0.35 * 249.0 / 300.0 # Adjustment per ISO 13256-1 Internal pressure drop across heat pump assumed to be 0.5 in. w.g.
1227
- pump_adjust_kw = UnitConversions.convert(3.0, 'Btu/hr', 'ton') * UnitConversions.convert(1.0, 'gal/min', 'm^3/s') * 1000.0 * 6.0 * 2990.0 / 3000.0 # Adjustment per ISO 13256-1 Internal Pressure drop across heat pump coil assumed to be 11ft w.g.
1228
- cool_eir = UnitConversions.convert((1.0 - heat_pump.cooling_efficiency_eer * (fan_adjust_kw + pump_adjust_kw)) / (heat_pump.cooling_efficiency_eer * (1.0 + UnitConversions.convert(fan_adjust_kw, 'Wh', 'Btu'))), 'Wh', 'Btu')
1229
- hp_ap.cool_rated_eirs = [cool_eir]
1230
1458
 
1231
1459
  # E+ equation fit coil coefficients from Tang's thesis:
1232
1460
  # See Appendix B Figure B.3 of https://hvac.okstate.edu/sites/default/files/pubs/theses/MS/27-Tang_Thesis_05.pdf
1233
1461
  # Coefficients generated by catalog data
1234
1462
  hp_ap.heat_cap_curve_spec = [[-5.12650150, -0.93997630, 7.21443206, 0.121065721, 0.051809805]]
1235
1463
  hp_ap.heat_power_curve_spec = [[-7.73235249, 6.43390775, 2.29152262, -0.175598629, 0.005888871]]
1236
- heat_eir = (1.0 - heat_pump.heating_efficiency_cop * (fan_adjust_kw + pump_adjust_kw)) / (heat_pump.heating_efficiency_cop * (1.0 - fan_adjust_kw))
1237
- hp_ap.heat_rated_eirs = [heat_eir]
1464
+
1465
+ # Fan/pump adjustments calculations
1466
+ power_f = heat_pump.fan_watts_per_cfm * 400.0 / UnitConversions.convert(1.0, 'ton', 'Btu/hr') * UnitConversions.convert(1.0, 'W', 'kW') # 400 cfm/ton, result is in kW per Btu/hr of capacity
1467
+ power_p = heat_pump.pump_watts_per_ton / UnitConversions.convert(1.0, 'ton', 'Btu/hr') * UnitConversions.convert(1.0, 'W', 'kW') # result is in kW per Btu/hr of capacity
1468
+
1469
+ cool_eir = (1 - UnitConversions.convert(power_f, 'Wh', 'Btu')) / UnitConversions.convert(heat_pump.cooling_efficiency_eer, 'Btu', 'Wh') - power_f - power_p
1470
+ heat_eir = (1 + UnitConversions.convert(power_f, 'Wh', 'Btu')) / heat_pump.heating_efficiency_cop - power_f - power_p
1471
+
1472
+ hp_ap.cool_rated_cops = [1.0 / cool_eir]
1473
+ hp_ap.heat_rated_cops = [1.0 / heat_eir]
1238
1474
  end
1239
1475
 
1240
1476
  def self.get_default_compressor_type(hvac_type, seer)
@@ -1428,44 +1664,6 @@ class HVAC
1428
1664
  pump_program_calling_manager.addProgram(pump_program)
1429
1665
  end
1430
1666
 
1431
- def self.set_boiler_pilot_light_ems_program(model, boiler, heating_system)
1432
- # Create Equipment object for fuel consumption
1433
- loc_space = model.getSpaces[0] # Arbitrary; not used
1434
- fuel_type = heating_system.heating_system_fuel
1435
- pilot_light_object = HotWaterAndAppliances.add_other_equipment(model, Constants.ObjectNameBoilerPilotLight(boiler.name), loc_space, 0.01, 0, 0, model.alwaysOnDiscreteSchedule, fuel_type)
1436
-
1437
- # Sensor
1438
- boiler_plr_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Boiler Part Load Ratio')
1439
- boiler_plr_sensor.setName("#{boiler.name} plr s")
1440
- boiler_plr_sensor.setKeyName(boiler.name.to_s)
1441
-
1442
- # Actuator
1443
- pilot_light_act = OpenStudio::Model::EnergyManagementSystemActuator.new(pilot_light_object, *EPlus::EMSActuatorOtherEquipmentPower, pilot_light_object.space.get)
1444
- pilot_light_act.setName("#{boiler.name} pilot light act")
1445
-
1446
- # Program
1447
- pilot_light_program = OpenStudio::Model::EnergyManagementSystemProgram.new(model)
1448
- pilot_light_program.setName("#{boiler.name} pilot light program")
1449
- pilot_light_program.addLine("Set #{pilot_light_act.name} = (1.0 - #{boiler_plr_sensor.name}) * #{UnitConversions.convert(heating_system.pilot_light_btuh.to_f, 'Btu/hr', 'W')}")
1450
- pilot_light_program.addLine("Set boiler_pilot_energy = #{pilot_light_act.name} * 3600 * SystemTimeStep")
1451
-
1452
- # Program Calling Manager
1453
- program_calling_manager = OpenStudio::Model::EnergyManagementSystemProgramCallingManager.new(model)
1454
- program_calling_manager.setName("#{boiler.name} pilot light program manager")
1455
- program_calling_manager.setCallingPoint('EndOfSystemTimestepBeforeHVACReporting')
1456
- program_calling_manager.addProgram(pilot_light_program)
1457
-
1458
- # EMS Output Variable for reporting
1459
- pilot_light_output_var = OpenStudio::Model::EnergyManagementSystemOutputVariable.new(model, 'boiler_pilot_energy')
1460
- pilot_light_output_var.setName("#{Constants.ObjectNameBoilerPilotLight(boiler.name)} outvar")
1461
- pilot_light_output_var.setTypeOfDataInVariable('Summed')
1462
- pilot_light_output_var.setUpdateFrequency('SystemTimestep')
1463
- pilot_light_output_var.setEMSProgramOrSubroutineName(pilot_light_program)
1464
- pilot_light_output_var.setUnits('J')
1465
- pilot_light_output_var.additionalProperties.setFeature('FuelType', EPlus.fuel_type(fuel_type)) # Used by reporting measure
1466
- pilot_light_output_var.additionalProperties.setFeature('HPXML_ID', heating_system.id) # Used by reporting measure
1467
- end
1468
-
1469
1667
  def self.disaggregate_fan_or_pump(model, fan_or_pump, htg_object, clg_object, backup_htg_object, hpxml_object)
1470
1668
  # Disaggregate into heating/cooling output energy use.
1471
1669
 
@@ -1548,15 +1746,23 @@ class HVAC
1548
1746
  fan_or_pump_program.addLine("Set #{fan_or_pump_var}_#{mode} = 0")
1549
1747
  end
1550
1748
  sensors.each_with_index do |(mode, sensor), i|
1551
- str_prefix = (i == 0 ? 'If' : 'ElseIf')
1749
+ if i == 0
1750
+ if_else_str = "If #{sensor.name} > 0"
1751
+ elsif i == sensors.size - 1
1752
+ # Use else for last mode to make sure we don't miss any energy use
1753
+ # See https://github.com/NREL/OpenStudio-HPXML/issues/1424
1754
+ if_else_str = 'Else'
1755
+ else
1756
+ if_else_str = "ElseIf #{sensor.name} > 0"
1757
+ end
1552
1758
  if mode == 'primary_htg' && sensors.keys[i + 1] == 'backup_htg'
1553
1759
  # HP with both primary and backup heating
1554
1760
  # If both are operating, apportion energy use
1555
- fan_or_pump_program.addLine("#{str_prefix} (#{sensor.name} > 0) && (#{sensors.values[i + 1].name} > 0)")
1761
+ fan_or_pump_program.addLine("#{if_else_str} && (#{sensors.values[i + 1].name} > 0)")
1556
1762
  fan_or_pump_program.addLine(" Set #{fan_or_pump_var}_#{mode} = #{fan_or_pump_sensor.name} * #{sensor.name} / (#{sensor.name} + #{sensors.values[i + 1].name})")
1557
1763
  fan_or_pump_program.addLine(" Set #{fan_or_pump_var}_#{sensors.keys[i + 1]} = #{fan_or_pump_sensor.name} * #{sensors.values[i + 1].name} / (#{sensor.name} + #{sensors.values[i + 1].name})")
1558
1764
  end
1559
- fan_or_pump_program.addLine("#{str_prefix} #{sensor.name} > 0")
1765
+ fan_or_pump_program.addLine(if_else_str)
1560
1766
  fan_or_pump_program.addLine(" Set #{fan_or_pump_var}_#{mode} = #{fan_or_pump_sensor.name}")
1561
1767
  end
1562
1768
  fan_or_pump_program.addLine('EndIf')
@@ -1571,19 +1777,20 @@ class HVAC
1571
1777
  next if sensor.nil?
1572
1778
 
1573
1779
  fan_or_pump_ems_output_var = OpenStudio::Model::EnergyManagementSystemOutputVariable.new(model, "#{fan_or_pump_var}_#{mode}")
1574
- name = { 'clg' => Constants.ObjectNameFanPumpDisaggregateCool(fan_or_pump.name.to_s),
1575
- 'primary_htg' => Constants.ObjectNameFanPumpDisaggregatePrimaryHeat(fan_or_pump.name.to_s),
1576
- 'backup_htg' => Constants.ObjectNameFanPumpDisaggregateBackupHeat(fan_or_pump.name.to_s) }[mode]
1577
- fan_or_pump_ems_output_var.setName(name)
1780
+ object_type = { 'clg' => Constants.ObjectNameFanPumpDisaggregateCool,
1781
+ 'primary_htg' => Constants.ObjectNameFanPumpDisaggregatePrimaryHeat,
1782
+ 'backup_htg' => Constants.ObjectNameFanPumpDisaggregateBackupHeat }[mode]
1783
+ fan_or_pump_ems_output_var.setName("#{fan_or_pump.name} #{object_type}")
1578
1784
  fan_or_pump_ems_output_var.setTypeOfDataInVariable('Summed')
1579
1785
  fan_or_pump_ems_output_var.setUpdateFrequency('SystemTimestep')
1580
1786
  fan_or_pump_ems_output_var.setEMSProgramOrSubroutineName(fan_or_pump_program)
1581
1787
  fan_or_pump_ems_output_var.setUnits('J')
1582
1788
  fan_or_pump_ems_output_var.additionalProperties.setFeature('HPXML_ID', sys_id) # Used by reporting measure
1789
+ fan_or_pump_ems_output_var.additionalProperties.setFeature('ObjectType', object_type) # Used by reporting measure
1583
1790
  end
1584
1791
  end
1585
1792
 
1586
- def self.adjust_dehumidifier_load_EMS(fraction_served, zone_hvac, model, living_space)
1793
+ def self.adjust_dehumidifier_load_EMS(fraction_served, zone_hvac, model, conditioned_space)
1587
1794
  # adjust hvac load to space when dehumidifier serves less than 100% dehumidification load. (With E+ dehumidifier object, it can only model 100%)
1588
1795
 
1589
1796
  # sensor
@@ -1603,7 +1810,7 @@ class HVAC
1603
1810
  dehumidifier_load_adj_def.setFractionLost(0)
1604
1811
  dehumidifier_load_adj = OpenStudio::Model::OtherEquipment.new(dehumidifier_load_adj_def)
1605
1812
  dehumidifier_load_adj.setName("#{zone_hvac.name} sens htg adj")
1606
- dehumidifier_load_adj.setSpace(living_space)
1813
+ dehumidifier_load_adj.setSpace(conditioned_space)
1607
1814
  dehumidifier_load_adj.setSchedule(model.alwaysOnDiscreteSchedule)
1608
1815
 
1609
1816
  dehumidifier_load_adj_act = OpenStudio::Model::EnergyManagementSystemActuator.new(dehumidifier_load_adj, *EPlus::EMSActuatorOtherEquipmentPower, dehumidifier_load_adj.space.get)
@@ -1640,12 +1847,12 @@ class HVAC
1640
1847
  else
1641
1848
  htg_supp_coil = OpenStudio::Model::CoilHeatingGas.new(model)
1642
1849
  htg_supp_coil.setGasBurnerEfficiency(efficiency)
1643
- htg_supp_coil.setParasiticElectricLoad(0)
1644
- htg_supp_coil.setParasiticGasLoad(0)
1850
+ htg_supp_coil.setOnCycleParasiticElectricLoad(0)
1851
+ htg_supp_coil.setOffCycleParasiticGasLoad(0)
1645
1852
  htg_supp_coil.setFuelType(EPlus.fuel_type(fuel))
1646
1853
  end
1647
1854
  htg_supp_coil.setNominalCapacity(UnitConversions.convert(capacity, 'Btu/hr', 'W'))
1648
- htg_supp_coil.setName(obj_name + ' ' + Constants.ObjectNameBackupHeatingCoil)
1855
+ htg_supp_coil.setName(obj_name + ' backup htg coil')
1649
1856
  htg_supp_coil.additionalProperties.setFeature('HPXML_ID', heat_pump.id) # Used by reporting measure
1650
1857
  htg_supp_coil.additionalProperties.setFeature('IsHeatPumpBackup', true) # Used by reporting measure
1651
1858
 
@@ -1668,13 +1875,18 @@ class HVAC
1668
1875
 
1669
1876
  fan_cfms.sort.each do |fan_cfm|
1670
1877
  fan_ratio = fan_cfm / max_fan_cfm
1671
- power_fraction = fan_ratio**3 # fan power curve
1878
+ power_fraction = calculate_fan_power_from_curve(1.0, fan_ratio)
1672
1879
  fan.addSpeed(fan_ratio.round(5), power_fraction.round(5))
1673
1880
  end
1674
1881
 
1675
1882
  return fan
1676
1883
  end
1677
1884
 
1885
+ def self.calculate_fan_power_from_curve(max_fan_power, fan_ratio)
1886
+ # Cubic relationship fan power curve
1887
+ return max_fan_power * (fan_ratio**3)
1888
+ end
1889
+
1678
1890
  def self.set_fan_power(fan, fan_watts_per_cfm)
1679
1891
  if fan_watts_per_cfm > 0
1680
1892
  fan_eff = 0.75 # Overall Efficiency of the Fan, Motor and Drive
@@ -1699,14 +1911,12 @@ class HVAC
1699
1911
  air_loop_unitary.setSupplyFan(fan)
1700
1912
  air_loop_unitary.setFanPlacement('BlowThrough')
1701
1913
  air_loop_unitary.setSupplyAirFanOperatingModeSchedule(cycle_fan_sch)
1702
- air_loop_unitary.setSupplyAirFlowRateMethodDuringHeatingOperation('SupplyAirFlowRate')
1703
1914
  if htg_coil.nil?
1704
1915
  air_loop_unitary.setSupplyAirFlowRateDuringHeatingOperation(0.0)
1705
1916
  else
1706
1917
  air_loop_unitary.setHeatingCoil(htg_coil)
1707
1918
  air_loop_unitary.setSupplyAirFlowRateDuringHeatingOperation(UnitConversions.convert(htg_cfm, 'cfm', 'm^3/s'))
1708
1919
  end
1709
- air_loop_unitary.setSupplyAirFlowRateMethodDuringCoolingOperation('SupplyAirFlowRate')
1710
1920
  if clg_coil.nil?
1711
1921
  air_loop_unitary.setSupplyAirFlowRateDuringCoolingOperation(0.0)
1712
1922
  else
@@ -1841,38 +2051,22 @@ class HVAC
1841
2051
  end
1842
2052
  end
1843
2053
 
1844
- def self.calc_heat_cap_ft_spec(heat_pump, num_speeds)
1845
- if heat_pump.heat_pump_type == HPXML::HVACTypeHeatPumpMiniSplit
1846
- # Coefficients for the indoor temperature relationship are retained from the generic curve (Daikin lab data).
1847
- iat_slope = -0.005770375
1848
- iat_intercept = 0.403926296
1849
- else
1850
- if num_speeds == 1
1851
- iat_slope = -0.002303414
1852
- iat_intercept = 0.18417308
1853
- elsif num_speeds == 2
1854
- iat_slope = -0.002947013
1855
- iat_intercept = 0.23168251
1856
- elsif num_speeds == 4
1857
- iat_slope = -0.002897048
1858
- iat_intercept = 0.209319129
1859
- end
2054
+ def self.calc_heat_cap_ft_spec(compressor_type, heating_capacity_retention_temp, heating_capacity_retention_fraction)
2055
+ if compressor_type == HPXML::HVACCompressorTypeSingleStage
2056
+ iat_slope = -0.002303414
2057
+ iat_intercept = 0.18417308
2058
+ num_speeds = 1
2059
+ elsif compressor_type == HPXML::HVACCompressorTypeTwoStage
2060
+ iat_slope = -0.002947013
2061
+ iat_intercept = 0.23168251
2062
+ num_speeds = 2
1860
2063
  end
1861
2064
 
1862
2065
  # Biquadratic: capacity multiplier = a + b*IAT + c*IAT^2 + d*OAT + e*OAT^2 + f*IAT*OAT
1863
2066
  # Derive coefficients from user input for capacity retention at outdoor drybulb temperature X [C].
1864
- if not heat_pump.heating_capacity_17F.nil?
1865
- x_A = 17.0
1866
- if heat_pump.heating_capacity > 0
1867
- y_A = heat_pump.heating_capacity_17F / heat_pump.heating_capacity
1868
- else
1869
- y_A = 0.0
1870
- end
1871
- else
1872
- x_A = heat_pump.heating_capacity_retention_temp
1873
- y_A = heat_pump.heating_capacity_retention_fraction
1874
- end
1875
- x_B = 47.0 # 47F is the rating point
2067
+ x_A = heating_capacity_retention_temp
2068
+ y_A = heating_capacity_retention_fraction
2069
+ x_B = HVAC::AirSourceHeatRatedODB
1876
2070
  y_B = 1.0
1877
2071
 
1878
2072
  oat_slope = (y_B - y_A) / (x_B - x_A)
@@ -1881,960 +2075,429 @@ class HVAC
1881
2075
  return [[oat_intercept + iat_intercept, iat_slope, 0, oat_slope, 0, 0]] * num_speeds
1882
2076
  end
1883
2077
 
1884
- def self.calc_eir_from_cop(cop, fan_power_rated)
1885
- return UnitConversions.convert((UnitConversions.convert(1.0, 'Btu', 'Wh') + fan_power_rated * 0.03333) / cop - fan_power_rated * 0.03333, 'Wh', 'Btu')
2078
+ def self.get_heating_capacity_retention(heat_pump)
2079
+ if not heat_pump.heating_capacity_17F.nil?
2080
+ heating_capacity_retention_temp = 17.0
2081
+ heating_capacity_retention_fraction = heat_pump.heating_capacity == 0.0 ? 0.0 : heat_pump.heating_capacity_17F / heat_pump.heating_capacity
2082
+ elsif not heat_pump.heating_capacity_retention_fraction.nil?
2083
+ heating_capacity_retention_temp = heat_pump.heating_capacity_retention_temp
2084
+ heating_capacity_retention_fraction = heat_pump.heating_capacity_retention_fraction
2085
+ else
2086
+ fail 'Missing heating capacity retention or 17F heating capacity.'
2087
+ end
2088
+ return heating_capacity_retention_temp, heating_capacity_retention_fraction
1886
2089
  end
1887
2090
 
1888
- def self.calc_eir_from_eer(eer, fan_power_rated)
1889
- return UnitConversions.convert((1.0 - UnitConversions.convert(fan_power_rated * 0.03333, 'Wh', 'Btu')) / eer - fan_power_rated * 0.03333, 'Wh', 'Btu')
2091
+ def self.calc_fan_speed_ratios(capacity_ratios, rated_cfm_per_tons, rated_airflow_rate)
2092
+ fan_speed_ratios = []
2093
+ capacity_ratios.each_with_index do |capacity_ratio, i|
2094
+ fan_speed_ratios << rated_cfm_per_tons[i] * capacity_ratio / rated_airflow_rate
2095
+ end
2096
+ return fan_speed_ratios
1890
2097
  end
1891
2098
 
1892
- def self.calc_eer_from_eir(eir, fan_power_rated)
1893
- cfm_per_ton = 400.0
1894
- cfm_per_btuh = cfm_per_ton / 12000.0
1895
- return ((1.0 - 3.412 * (fan_power_rated * cfm_per_btuh)) / (eir / 3.412 + (fan_power_rated * cfm_per_btuh)))
2099
+ def self.convert_curve_biquadratic(coeff)
2100
+ # Convert IP curves to SI curves
2101
+ si_coeff = []
2102
+ si_coeff << coeff[0] + 32.0 * (coeff[1] + coeff[3]) + 1024.0 * (coeff[2] + coeff[4] + coeff[5])
2103
+ si_coeff << 9.0 / 5.0 * coeff[1] + 576.0 / 5.0 * coeff[2] + 288.0 / 5.0 * coeff[5]
2104
+ si_coeff << 81.0 / 25.0 * coeff[2]
2105
+ si_coeff << 9.0 / 5.0 * coeff[3] + 576.0 / 5.0 * coeff[4] + 288.0 / 5.0 * coeff[5]
2106
+ si_coeff << 81.0 / 25.0 * coeff[4]
2107
+ si_coeff << 81.0 / 25.0 * coeff[5]
2108
+ return si_coeff
1896
2109
  end
1897
2110
 
1898
- def self.calc_eers_from_eir_2speed(eer_2, fan_power_rated)
1899
- # Returns low and high stage EER A given high stage EER A
2111
+ def self.create_table_lookup(model, name, independent_vars, output_values, output_min = nil, output_max = nil)
2112
+ if (not output_min.nil?) && (output_values.min < output_min)
2113
+ fail "Minimum table lookup output value (#{output_values.min}) is less than #{output_min} for #{name}."
2114
+ end
2115
+ if (not output_max.nil?) && (output_values.max > output_max)
2116
+ fail "Maximum table lookup output value (#{output_values.max}) is greater than #{output_max} for #{name}."
2117
+ end
1900
2118
 
1901
- eir_2_a = calc_eir_from_eer(eer_2, fan_power_rated)
2119
+ table = OpenStudio::Model::TableLookup.new(model)
2120
+ table.setName(name)
2121
+ independent_vars.each do |var|
2122
+ ind_var = OpenStudio::Model::TableIndependentVariable.new(model)
2123
+ ind_var.setName(var[:name])
2124
+ ind_var.setMinimumValue(var[:min])
2125
+ ind_var.setMaximumValue(var[:max])
2126
+ ind_var.setExtrapolationMethod('Constant')
2127
+ ind_var.setValues(var[:values])
2128
+ table.addIndependentVariable(ind_var)
2129
+ end
2130
+ table.setMinimumOutput(output_min) unless output_min.nil?
2131
+ table.setMaximumOutput(output_max) unless output_max.nil?
2132
+ table.setOutputValues(output_values)
2133
+ return table
2134
+ end
1902
2135
 
1903
- eir_1_a = 0.8887 * eir_2_a + 0.0083 # Relationship derived using Dylan's data for two stage heat pumps
2136
+ def self.create_curve_biquadratic_constant(model)
2137
+ curve = OpenStudio::Model::CurveBiquadratic.new(model)
2138
+ curve.setName('ConstantBiquadratic')
2139
+ curve.setCoefficient1Constant(1)
2140
+ curve.setCoefficient2x(0)
2141
+ curve.setCoefficient3xPOW2(0)
2142
+ curve.setCoefficient4y(0)
2143
+ curve.setCoefficient5yPOW2(0)
2144
+ curve.setCoefficient6xTIMESY(0)
2145
+ curve.setMinimumValueofx(-100)
2146
+ curve.setMaximumValueofx(100)
2147
+ curve.setMinimumValueofy(-100)
2148
+ curve.setMaximumValueofy(100)
2149
+ return curve
2150
+ end
1904
2151
 
1905
- return [calc_eer_from_eir(eir_1_a, fan_power_rated), eer_2]
2152
+ def self.create_curve_quadratic_constant(model)
2153
+ curve = OpenStudio::Model::CurveQuadratic.new(model)
2154
+ curve.setName('ConstantQuadratic')
2155
+ curve.setCoefficient1Constant(1)
2156
+ curve.setCoefficient2x(0)
2157
+ curve.setCoefficient3xPOW2(0)
2158
+ curve.setMinimumValueofx(-100)
2159
+ curve.setMaximumValueofx(100)
2160
+ curve.setMinimumCurveOutput(-100)
2161
+ curve.setMaximumCurveOutput(100)
2162
+ return curve
1906
2163
  end
1907
2164
 
1908
- def self.calc_eers_from_eir_4speed(eer_nom, fan_power_rated, calc_type = 'seer')
1909
- # Returns EER A at minimum, intermediate, and nominal speed given EER A (and a fourth speed if calc_type != 'seer')
2165
+ def self.create_curve_biquadratic(model, coeff, name, min_x, max_x, min_y, max_y)
2166
+ curve = OpenStudio::Model::CurveBiquadratic.new(model)
2167
+ curve.setName(name)
2168
+ curve.setCoefficient1Constant(coeff[0])
2169
+ curve.setCoefficient2x(coeff[1])
2170
+ curve.setCoefficient3xPOW2(coeff[2])
2171
+ curve.setCoefficient4y(coeff[3])
2172
+ curve.setCoefficient5yPOW2(coeff[4])
2173
+ curve.setCoefficient6xTIMESY(coeff[5])
2174
+ curve.setMinimumValueofx(min_x)
2175
+ curve.setMaximumValueofx(max_x)
2176
+ curve.setMinimumValueofy(min_y)
2177
+ curve.setMaximumValueofy(max_y)
2178
+ return curve
2179
+ end
1910
2180
 
1911
- eir_nom = calc_eir_from_eer(eer_nom, fan_power_rated)
2181
+ def self.create_curve_bicubic(model, coeff, name, min_x, max_x, min_y, max_y)
2182
+ curve = OpenStudio::Model::CurveBicubic.new(model)
2183
+ curve.setName(name)
2184
+ curve.setCoefficient1Constant(coeff[0])
2185
+ curve.setCoefficient2x(coeff[1])
2186
+ curve.setCoefficient3xPOW2(coeff[2])
2187
+ curve.setCoefficient4y(coeff[3])
2188
+ curve.setCoefficient5yPOW2(coeff[4])
2189
+ curve.setCoefficient6xTIMESY(coeff[5])
2190
+ curve.setCoefficient7xPOW3(coeff[6])
2191
+ curve.setCoefficient8yPOW3(coeff[7])
2192
+ curve.setCoefficient9xPOW2TIMESY(coeff[8])
2193
+ curve.setCoefficient10xTIMESYPOW2(coeff[9])
2194
+ curve.setMinimumValueofx(min_x)
2195
+ curve.setMaximumValueofx(max_x)
2196
+ curve.setMinimumValueofy(min_y)
2197
+ curve.setMaximumValueofy(max_y)
2198
+ return curve
2199
+ end
1912
2200
 
1913
- if calc_type == 'seer'
1914
- indices = [0, 1, 4]
1915
- else
1916
- indices = [0, 1, 2, 4]
2201
+ def self.create_curve_quadratic(model, coeff, name, min_x, max_x, min_y, max_y, is_dimensionless = false)
2202
+ curve = OpenStudio::Model::CurveQuadratic.new(model)
2203
+ curve.setName(name)
2204
+ curve.setCoefficient1Constant(coeff[0])
2205
+ curve.setCoefficient2x(coeff[1])
2206
+ curve.setCoefficient3xPOW2(coeff[2])
2207
+ curve.setMinimumValueofx(min_x)
2208
+ curve.setMaximumValueofx(max_x)
2209
+ if not min_y.nil?
2210
+ curve.setMinimumCurveOutput(min_y)
1917
2211
  end
1918
-
1919
- cop_ratios = [1.07, 1.11, 1.08, 1.05, 1.0] # Gross cop
1920
-
1921
- # Seer calculation is based on performance at three speeds
1922
- cops = [cop_ratios[indices[0]], cop_ratios[indices[1]], cop_ratios[indices[2]]]
1923
-
1924
- if calc_type != 'seer'
1925
- cops << cop_ratios[indices[3]]
2212
+ if not max_y.nil?
2213
+ curve.setMaximumCurveOutput(max_y)
1926
2214
  end
1927
-
1928
- eers = []
1929
- cops.each do |mult|
1930
- eir = eir_nom / mult
1931
- eers << calc_eer_from_eir(eir, fan_power_rated)
2215
+ if is_dimensionless
2216
+ curve.setInputUnitTypeforX('Dimensionless')
2217
+ curve.setOutputUnitType('Dimensionless')
1932
2218
  end
2219
+ return curve
2220
+ end
1933
2221
 
1934
- return eers
2222
+ def self.create_curve_quad_linear(model, coeff, name)
2223
+ curve = OpenStudio::Model::CurveQuadLinear.new(model)
2224
+ curve.setName(name)
2225
+ curve.setCoefficient1Constant(coeff[0])
2226
+ curve.setCoefficient2w(coeff[1])
2227
+ curve.setCoefficient3x(coeff[2])
2228
+ curve.setCoefficient4y(coeff[3])
2229
+ curve.setCoefficient5z(coeff[4])
2230
+ return curve
1935
2231
  end
1936
2232
 
1937
- def self.calc_cop_from_eir(eir, fan_power_rated)
1938
- cfm_per_ton = 400.0
1939
- cfm_per_btuh = cfm_per_ton / 12000.0
1940
- return (1.0 / 3.412 + fan_power_rated * cfm_per_btuh) / (eir / 3.412 + fan_power_rated * cfm_per_btuh)
2233
+ def self.create_curve_quint_linear(model, coeff, name)
2234
+ curve = OpenStudio::Model::CurveQuintLinear.new(model)
2235
+ curve.setName(name)
2236
+ curve.setCoefficient1Constant(coeff[0])
2237
+ curve.setCoefficient2v(coeff[1])
2238
+ curve.setCoefficient3w(coeff[2])
2239
+ curve.setCoefficient4x(coeff[3])
2240
+ curve.setCoefficient5y(coeff[4])
2241
+ curve.setCoefficient6z(coeff[5])
2242
+ return curve
1941
2243
  end
1942
2244
 
1943
- def self.calc_cops_from_eir_2speed(cop_2, fan_power_rated)
1944
- # Returns low and high stage rated cop given high stage cop
2245
+ def self.convert_net_to_gross_capacity_cop(net_cap, fan_power, mode, net_cop = nil)
2246
+ net_cap_watts = UnitConversions.convert(net_cap, 'Btu/hr', 'w')
2247
+ if mode == :clg
2248
+ gross_cap_watts = net_cap_watts + fan_power
2249
+ else
2250
+ gross_cap_watts = net_cap_watts - fan_power
2251
+ end
2252
+ if not net_cop.nil?
2253
+ net_power = net_cap_watts / net_cop
2254
+ gross_power = net_power - fan_power
2255
+ gross_cop = gross_cap_watts / gross_power
2256
+ end
2257
+ gross_cap_btu_hr = UnitConversions.convert(gross_cap_watts, 'w', 'Btu/hr')
2258
+ return gross_cap_btu_hr, gross_cop
2259
+ end
1945
2260
 
1946
- eir_2 = calc_eir_from_cop(cop_2, fan_power_rated)
2261
+ def self.process_neep_detailed_performance(detailed_performance_data, hvac_ap, mode, max_rated_fan_cfm, weather_temp, compressor_lockout_temp = nil)
2262
+ data_array = Array.new(2) { Array.new }
2263
+ detailed_performance_data.sort_by { |dp| dp.outdoor_temperature }.each do |data_point|
2264
+ # Only process min and max capacities at each outdoor drybulb
2265
+ next unless [HPXML::CapacityDescriptionMinimum, HPXML::CapacityDescriptionMaximum].include? data_point.capacity_description
1947
2266
 
1948
- eir_1 = 0.6241 * eir_2 + 0.0681 # Relationship derived using Dylan's data for Carrier two stage heat pumps
2267
+ if data_point.capacity_description == HPXML::CapacityDescriptionMinimum
2268
+ data_array[0] << data_point
2269
+ elsif data_point.capacity_description == HPXML::CapacityDescriptionMaximum
2270
+ data_array[1] << data_point
2271
+ end
2272
+ end
1949
2273
 
1950
- return [calc_cop_from_eir(eir_1, fan_power_rated), cop_2]
2274
+ # convert net to gross, adds more data points for table lookup, etc.
2275
+ if mode == :clg
2276
+ cfm_per_ton = hvac_ap.cool_rated_cfm_per_ton
2277
+ hvac_ap.cooling_performance_data_array = data_array
2278
+ hvac_ap.cool_rated_capacities_gross = []
2279
+ hvac_ap.cool_rated_capacities_net = []
2280
+ hvac_ap.cool_rated_cops = []
2281
+ elsif mode == :htg
2282
+ cfm_per_ton = hvac_ap.heat_rated_cfm_per_ton
2283
+ hvac_ap.heating_performance_data_array = data_array
2284
+ hvac_ap.heat_rated_capacities_gross = []
2285
+ hvac_ap.heat_rated_capacities_net = []
2286
+ hvac_ap.heat_rated_cops = []
2287
+ end
2288
+ # convert net to gross
2289
+ data_array.each_with_index do |data, speed|
2290
+ data.each do |dp|
2291
+ this_cfm = UnitConversions.convert(dp.capacity, 'Btu/hr', 'ton') * cfm_per_ton[speed]
2292
+ fan_ratio = this_cfm / max_rated_fan_cfm
2293
+ fan_power = calculate_fan_power_from_curve(hvac_ap.fan_power_rated * max_rated_fan_cfm, fan_ratio)
2294
+ dp.gross_capacity, dp.gross_efficiency_cop = convert_net_to_gross_capacity_cop(dp.capacity, fan_power, mode, dp.efficiency_cop)
2295
+ end
2296
+ end
2297
+ # convert to table lookup data
2298
+ interpolate_to_odb_table_points(data_array, mode, compressor_lockout_temp, weather_temp)
2299
+ add_data_point_adaptive_step_size(data_array, mode)
2300
+ correct_ft_cap_eir(data_array, mode)
2301
+ end
2302
+
2303
+ def self.interpolate_to_odb_table_points(data_array, mode, compressor_lockout_temp, weather_temp)
2304
+ # Set of data used for table lookup
2305
+ data_array.each do |data|
2306
+ user_odbs = data.map { |dp| dp.outdoor_temperature }
2307
+ # Determine min/max ODB temperatures to cover full range of heat pump operation
2308
+ if mode == :clg
2309
+ outdoor_dry_bulbs = []
2310
+ # Calculate ODB temperature at which COP or capacity is zero
2311
+ high_odb_at_zero_cop = calculate_odb_at_zero_cop_or_capacity(data, mode, user_odbs, :gross_efficiency_cop, true)
2312
+ high_odb_at_zero_capacity = calculate_odb_at_zero_cop_or_capacity(data, mode, user_odbs, :gross_capacity, true)
2313
+ low_odb_at_zero_cop = calculate_odb_at_zero_cop_or_capacity(data, mode, user_odbs, :gross_efficiency_cop, false)
2314
+ low_odb_at_zero_capacity = calculate_odb_at_zero_cop_or_capacity(data, mode, user_odbs, :gross_capacity, false)
2315
+ outdoor_dry_bulbs << [low_odb_at_zero_cop, low_odb_at_zero_capacity, 55.0].max # Min cooling ODB
2316
+ outdoor_dry_bulbs << [high_odb_at_zero_cop, high_odb_at_zero_capacity, weather_temp].min # Max cooling ODB
2317
+ else
2318
+ outdoor_dry_bulbs = []
2319
+ # Calculate ODB temperature at which COP or capacity is zero
2320
+ low_odb_at_zero_cop = calculate_odb_at_zero_cop_or_capacity(data, mode, user_odbs, :gross_efficiency_cop, false)
2321
+ low_odb_at_zero_capacity = calculate_odb_at_zero_cop_or_capacity(data, mode, user_odbs, :gross_capacity, false)
2322
+ high_odb_at_zero_cop = calculate_odb_at_zero_cop_or_capacity(data, mode, user_odbs, :gross_efficiency_cop, true)
2323
+ high_odb_at_zero_capacity = calculate_odb_at_zero_cop_or_capacity(data, mode, user_odbs, :gross_capacity, true)
2324
+ outdoor_dry_bulbs << [low_odb_at_zero_cop, low_odb_at_zero_capacity, compressor_lockout_temp, weather_temp].max # Min heating ODB
2325
+ outdoor_dry_bulbs << [high_odb_at_zero_cop, high_odb_at_zero_capacity, 60.0].min # Max heating ODB
2326
+ end
2327
+ capacity_description = data[0].capacity_description
2328
+ outdoor_dry_bulbs.each do |target_odb|
2329
+ next if user_odbs.include? target_odb
2330
+
2331
+ if mode == :clg
2332
+ new_dp = HPXML::CoolingPerformanceDataPoint.new(nil)
2333
+ else
2334
+ new_dp = HPXML::HeatingPerformanceDataPoint.new(nil)
2335
+ end
2336
+ new_dp.outdoor_temperature = target_odb
2337
+ new_dp.gross_capacity = interpolate_to_odb_table_point(data, capacity_description, target_odb, :gross_capacity)
2338
+ new_dp.gross_efficiency_cop = interpolate_to_odb_table_point(data, capacity_description, target_odb, :gross_efficiency_cop)
2339
+ data << new_dp
2340
+ end
2341
+ end
1951
2342
  end
1952
2343
 
1953
- def self.calc_cops_from_eir_4speed(cop_nom, fan_power_rated, calc_type: 'hspf')
1954
- # Returns rated cop at minimum, intermediate, and nominal speed given rated cop
1955
-
1956
- eir_nom = calc_eir_from_cop(cop_nom, fan_power_rated)
2344
+ def self.calculate_odb_at_zero_cop_or_capacity(data, _mode, user_odbs, property, find_high)
2345
+ if find_high
2346
+ odb_dp1 = data.find { |dp| dp.outdoor_temperature == user_odbs[-1] }
2347
+ odb_dp2 = data.find { |dp| dp.outdoor_temperature == user_odbs[-2] }
2348
+ else
2349
+ odb_dp1 = data.find { |dp| dp.outdoor_temperature == user_odbs[0] }
2350
+ odb_dp2 = data.find { |dp| dp.outdoor_temperature == user_odbs[1] }
2351
+ end
1957
2352
 
1958
- cop_ratios = [1.385171617, 1.183214059, 1.0, 0.95544453] # Updated based on Nordyne 3 ton heat pump
2353
+ slope = (odb_dp1.send(property) - odb_dp2.send(property)) / (odb_dp1.outdoor_temperature - odb_dp2.outdoor_temperature)
1959
2354
 
1960
- # HSPF calculation is based on performance at three speeds
1961
- if calc_type == 'hspf'
1962
- indices = [0, 1, 2]
1963
- elsif calc_type == 'model'
1964
- indices = [0, 1, 2, 3]
2355
+ # Datapoints don't trend toward zero COP?
2356
+ if (find_high && slope >= 0)
2357
+ return 999999.0
2358
+ elsif (!find_high && slope <= 0)
2359
+ return -999999.0
1965
2360
  end
1966
2361
 
1967
- cops_net = []
1968
- indices.each do |i|
1969
- eir = eir_nom / cop_ratios[i]
1970
- cops_net << calc_cop_from_eir(eir, fan_power_rated)
1971
- end
2362
+ intercept = odb_dp2.send(property) - (slope * odb_dp2.outdoor_temperature)
2363
+ target_odb = -intercept / slope
1972
2364
 
1973
- return cops_net
2365
+ # Return a slightly larger (or smaller, for cooling) ODB so things don't blow up
2366
+ delta_odb = 1.0
2367
+ if find_high
2368
+ return target_odb - delta_odb
2369
+ else
2370
+ return target_odb + delta_odb
2371
+ end
1974
2372
  end
1975
2373
 
1976
- def self.calc_eer_cooling_1speed(seer, c_d, fan_power_rated, coeff_eir)
1977
- # Directly calculate cooling coil net EER at condition A (95/80/67) using SEER
2374
+ def self.interpolate_to_odb_table_point(detailed_performance_data, capacity_description, target_odb, property)
2375
+ data = detailed_performance_data.select { |dp| dp.capacity_description == capacity_description }
1978
2376
 
1979
- # 1. Calculate EER_b using SEER and c_d
1980
- eer_b = seer / (1.0 - 0.5 * c_d)
2377
+ target_dp = data.find { |dp| dp.outdoor_temperature == target_odb }
2378
+ if not target_dp.nil?
2379
+ return target_dp.send(property)
2380
+ end
1981
2381
 
1982
- # 2. Calculate EIR_b
1983
- eir_b = calc_eir_from_eer(eer_b, fan_power_rated)
2382
+ # Property can be :capacity, :efficiency_cop, etc.
2383
+ user_odbs = data.map { |dp| dp.outdoor_temperature }.uniq.sort
1984
2384
 
1985
- # 3. Calculate EIR_a using performance curves
1986
- eir_a = eir_b / MathTools.biquadratic(67.0, 82.0, coeff_eir[0])
1987
- eer_a = calc_eer_from_eir(eir_a, fan_power_rated)
2385
+ right_odb = user_odbs.find { |e| e > target_odb }
2386
+ left_odb = user_odbs.reverse.find { |e| e < target_odb }
2387
+ if right_odb.nil?
2388
+ # extrapolation
2389
+ right_odb = user_odbs[-1]
2390
+ left_odb = user_odbs[-2]
2391
+ elsif left_odb.nil?
2392
+ # extrapolation
2393
+ right_odb = user_odbs[1]
2394
+ left_odb = user_odbs[0]
2395
+ end
2396
+ right_dp = data.find { |dp| dp.outdoor_temperature == right_odb }
2397
+ left_dp = data.find { |dp| dp.outdoor_temperature == left_odb }
1988
2398
 
1989
- return eer_a
2399
+ slope = (right_dp.send(property) - left_dp.send(property)) / (right_odb - left_odb)
2400
+ val = (target_odb - left_odb) * slope + left_dp.send(property)
2401
+ return val
1990
2402
  end
1991
2403
 
1992
- def self.calc_eers_cooling_2speed(seer, c_d, capacity_ratios, fanspeed_ratios, fan_power_rated, coeff_eir, coeff_q)
1993
- # Iterate to find rated net EERs given SEER using simple bisection method for two stage heat pumps
1994
-
1995
- # Initial large bracket of EER (A condition) to span possible SEER range
1996
- eer_a = 5.0
1997
- eer_b = 20.0
1998
-
1999
- # Iterate
2000
- iter_max = 100
2001
- tol = 0.0001
2404
+ def self.add_data_point_adaptive_step_size(data_array, mode, tol = 0.1)
2405
+ data_array.each do |data|
2406
+ data_sorted = data.sort_by { |dp| dp.outdoor_temperature }
2407
+ data_sorted.each_with_index do |dp, i|
2408
+ next unless i < (data_sorted.size - 1)
2002
2409
 
2003
- err = 1
2004
- eer_c = (eer_a + eer_b) / 2.0
2005
- for _n in 1..iter_max
2006
- eers = calc_eers_from_eir_2speed(eer_a, fan_power_rated)
2007
- f_a = calc_seer_2speed(eers, c_d, capacity_ratios, fanspeed_ratios, fan_power_rated, coeff_eir, coeff_q) - seer
2008
-
2009
- eers = calc_eers_from_eir_2speed(eer_c, fan_power_rated)
2010
- f_c = calc_seer_2speed(eers, c_d, capacity_ratios, fanspeed_ratios, fan_power_rated, coeff_eir, coeff_q) - seer
2011
-
2012
- if f_c == 0
2013
- return eer_c
2014
- elsif f_a * f_c < 0
2015
- eer_b = eer_c
2016
- else
2017
- eer_a = eer_c
2018
- end
2019
-
2020
- eer_c = (eer_a + eer_b) / 2.0
2021
- err = (eer_b - eer_a) / 2.0
2022
-
2023
- if err <= tol
2024
- break
2025
- end
2026
- end
2027
-
2028
- if err > tol
2029
- fail 'Two-speed cooling eers iteration failed to converge.'
2030
- end
2031
-
2032
- return calc_eers_from_eir_2speed(eer_c, fan_power_rated)
2033
- end
2034
-
2035
- def self.calc_eers_cooling_4speed(seer, c_d, capacity_ratios, fanspeed_ratios, fan_power_rated, coeff_eir, coeff_q)
2036
- # Iterate to find rated net eers given Seer using simple bisection method for two stage and variable speed air conditioners
2037
-
2038
- # Initial large bracket of eer (A condition) to span possible seer range
2039
- eer_a = 5.0
2040
- eer_b = 30.0
2041
-
2042
- # Iterate
2043
- iter_max = 100
2044
- tol = 0.0001
2045
-
2046
- err = 1
2047
- eer_c = (eer_a + eer_b) / 2.0
2048
- for _n in 1..iter_max
2049
- eers = calc_eers_from_eir_4speed(eer_a, fan_power_rated, 'seer')
2050
- f_a = calc_seer_4speed(eers, c_d, capacity_ratios, fanspeed_ratios, fan_power_rated, coeff_eir, coeff_q) - seer
2051
-
2052
- eers = calc_eers_from_eir_4speed(eer_c, fan_power_rated, 'seer')
2053
- f_c = calc_seer_4speed(eers, c_d, capacity_ratios, fanspeed_ratios, fan_power_rated, coeff_eir, coeff_q) - seer
2054
-
2055
- if f_c == 0
2056
- return eer_c
2057
- elsif f_a * f_c < 0
2058
- eer_b = eer_c
2059
- else
2060
- eer_a = eer_c
2061
- end
2062
-
2063
- eer_c = (eer_a + eer_b) / 2.0
2064
- err = (eer_b - eer_a) / 2.0
2065
-
2066
- if err <= tol
2067
- break
2068
- end
2069
- end
2070
-
2071
- if err > tol
2072
- fail 'Variable-speed cooling eers iteration failed to converge.'
2073
- end
2074
-
2075
- return calc_eers_from_eir_4speed(eer_c, fan_power_rated, 'model')
2076
- end
2077
-
2078
- def self.calc_seer_2speed(eers, c_d, capacity_ratios, fanspeed_ratios, fan_power_rated, coeff_eir, coeff_q)
2079
- eir_A2 = calc_eir_from_eer(eers[1], fan_power_rated)
2080
- eir_B2 = eir_A2 * MathTools.biquadratic(67.0, 82.0, coeff_eir[1])
2081
-
2082
- eir_A1 = calc_eir_from_eer(eers[0], fan_power_rated)
2083
- eir_B1 = eir_A1 * MathTools.biquadratic(67.0, 82.0, coeff_eir[0])
2084
- eir_F1 = eir_A1 * MathTools.biquadratic(67.0, 67.0, coeff_eir[0])
2085
-
2086
- q_A2 = 1.0
2087
- q_B2 = q_A2 * MathTools.biquadratic(67.0, 82.0, coeff_q[1])
2088
-
2089
- q_B1 = q_A2 * capacity_ratios[0] * MathTools.biquadratic(67.0, 82.0, coeff_q[0])
2090
- q_F1 = q_A2 * capacity_ratios[0] * MathTools.biquadratic(67.0, 67.0, coeff_q[0])
2091
-
2092
- cfm_Btu_h = 400.0 / 12000.0
2093
-
2094
- q_A2_net = q_A2 - fan_power_rated * 3.412 * cfm_Btu_h
2095
- q_B2_net = q_B2 - fan_power_rated * 3.412 * cfm_Btu_h
2096
- q_B1_net = q_B1 - fan_power_rated * 3.412 * cfm_Btu_h * fanspeed_ratios[0]
2097
- q_F1_net = q_F1 - fan_power_rated * 3.412 * cfm_Btu_h * fanspeed_ratios[0]
2098
-
2099
- p_A2 = (q_A2 * eir_A2) / 3.412 + fan_power_rated * cfm_Btu_h
2100
- p_B2 = (q_B2 * eir_B2) / 3.412 + fan_power_rated * cfm_Btu_h
2101
- p_B1 = (q_B1 * eir_B1) / 3.412 + fan_power_rated * cfm_Btu_h * fanspeed_ratios[0]
2102
- p_F1 = (q_F1 * eir_F1) / 3.412 + fan_power_rated * cfm_Btu_h * fanspeed_ratios[0]
2103
-
2104
- t_bins = [67.0, 72.0, 77.0, 82.0, 87.0, 92.0, 97.0, 102.0]
2105
- frac_hours = [0.214, 0.231, 0.216, 0.161, 0.104, 0.052, 0.018, 0.004]
2106
-
2107
- e_tot = 0.0
2108
- q_tot = 0.0
2109
- (0..7).each do |i|
2110
- bL_i = ((t_bins[i] - 65.0) / (95.0 - 65.0)) * (q_A2_net / 1.1)
2111
- q_low_i = q_F1_net + ((q_B1_net - q_F1_net) / (82.0 - 67.0)) * (t_bins[i] - 67.0)
2112
- e_low_i = p_F1 + ((p_B1 - p_F1) / (82.0 - 67.0)) * (t_bins[i] - 67.0)
2113
- q_high_i = q_B2_net + ((q_A2_net - q_B2_net) / (95.0 - 82.0)) * (t_bins[i] - 82.0)
2114
- e_high_i = p_B2 + ((p_A2 - p_B2) / (95.0 - 82.0)) * (t_bins[i] - 82.0)
2115
- if q_low_i >= bL_i
2116
- pLF_i = 1.0 - c_d * (1.0 - (bL_i / q_low_i))
2117
- q_i = bL_i * frac_hours[i]
2118
- e_i = (((bL_i / q_low_i) * e_low_i) / pLF_i) * frac_hours[i]
2119
- elsif (q_low_i < bL_i) && (bL_i < q_high_i)
2120
- x_i = (q_high_i - bL_i) / (q_high_i - q_low_i)
2121
- q_i = (x_i * q_low_i + (1.0 - x_i) * q_high_i) * frac_hours[i]
2122
- e_i = (x_i * e_low_i + (1.0 - x_i) * e_high_i) * frac_hours[i]
2123
- elsif q_high_i <= bL_i
2124
- q_i = q_high_i * frac_hours[i]
2125
- e_i = e_high_i * frac_hours[i]
2126
- end
2127
-
2128
- e_tot += e_i
2129
- q_tot += q_i
2130
- end
2131
-
2132
- seer = q_tot / e_tot
2133
- return seer
2134
- end
2135
-
2136
- def self.calc_seer_4speed(eers, c_d, capacity_ratios, fanspeed_ratios, fan_power_rated, coeff_eir, coeff_q)
2137
- n_max = 2
2138
- n_int = 1
2139
- n_min = 0
2140
-
2141
- wBin = 67.0
2142
- tout_B = 82.0
2143
- tout_E = 87.0
2144
- tout_F = 67.0
2145
-
2146
- eir_A2 = calc_eir_from_eer(eers[n_max], fan_power_rated)
2147
- eir_B2 = eir_A2 * MathTools.biquadratic(wBin, tout_B, coeff_eir[n_max])
2148
-
2149
- eir_Av = calc_eir_from_eer(eers[n_int], fan_power_rated)
2150
- eir_Ev = eir_Av * MathTools.biquadratic(wBin, tout_E, coeff_eir[n_int])
2151
-
2152
- eir_A1 = calc_eir_from_eer(eers[n_min], fan_power_rated)
2153
- eir_B1 = eir_A1 * MathTools.biquadratic(wBin, tout_B, coeff_eir[n_min])
2154
- eir_F1 = eir_A1 * MathTools.biquadratic(wBin, tout_F, coeff_eir[n_min])
2155
-
2156
- q_A2 = capacity_ratios[n_max]
2157
- q_B2 = q_A2 * MathTools.biquadratic(wBin, tout_B, coeff_q[n_max])
2158
- q_Ev = capacity_ratios[n_int] * MathTools.biquadratic(wBin, tout_E, coeff_q[n_int])
2159
- q_B1 = capacity_ratios[n_min] * MathTools.biquadratic(wBin, tout_B, coeff_q[n_min])
2160
- q_F1 = capacity_ratios[n_min] * MathTools.biquadratic(wBin, tout_F, coeff_q[n_min])
2161
-
2162
- cfm_Btu_h = 400.0 / 12000.0
2163
-
2164
- q_A2_net = q_A2 - fan_power_rated * 3.412 * cfm_Btu_h * fanspeed_ratios[n_max]
2165
- q_B2_net = q_B2 - fan_power_rated * 3.412 * cfm_Btu_h * fanspeed_ratios[n_max]
2166
- q_Ev_net = q_Ev - fan_power_rated * 3.412 * cfm_Btu_h * fanspeed_ratios[n_int]
2167
- q_B1_net = q_B1 - fan_power_rated * 3.412 * cfm_Btu_h * fanspeed_ratios[n_min]
2168
- q_F1_net = q_F1 - fan_power_rated * 3.412 * cfm_Btu_h * fanspeed_ratios[n_min]
2169
-
2170
- p_A2 = (q_A2 * eir_A2) / 3.412 + fan_power_rated * cfm_Btu_h * fanspeed_ratios[n_max]
2171
- p_B2 = (q_B2 * eir_B2) / 3.412 + fan_power_rated * cfm_Btu_h * fanspeed_ratios[n_max]
2172
- p_Ev = (q_Ev * eir_Ev) / 3.412 + fan_power_rated * cfm_Btu_h * fanspeed_ratios[n_int]
2173
- p_B1 = (q_B1 * eir_B1) / 3.412 + fan_power_rated * cfm_Btu_h * fanspeed_ratios[n_min]
2174
- p_F1 = (q_F1 * eir_F1) / 3.412 + fan_power_rated * cfm_Btu_h * fanspeed_ratios[n_min]
2175
-
2176
- q_k1_87 = q_F1_net + (q_B1_net - q_F1_net) / (82.0 - 67.0) * (87.0 - 67.0)
2177
- q_k2_87 = q_B2_net + (q_A2_net - q_B2_net) / (95.0 - 82.0) * (87.0 - 82.0)
2178
- n_Q = (q_Ev_net - q_k1_87) / (q_k2_87 - q_k1_87)
2179
- m_Q = (q_B1_net - q_F1_net) / (82.0 - 67.0) * (1.0 - n_Q) + (q_A2_net - q_B2_net) / (95.0 - 82.0) * n_Q
2180
- p_k1_87 = p_F1 + (p_B1 - p_F1) / (82.0 - 67.0) * (87.0 - 67.0)
2181
- p_k2_87 = p_B2 + (p_A2 - p_B2) / (95.0 - 82.0) * (87.0 - 82.0)
2182
- n_E = (p_Ev - p_k1_87) / (p_k2_87 - p_k1_87)
2183
- m_E = (p_B1 - p_F1) / (82.0 - 67.0) * (1.0 - n_E) + (p_A2 - p_B2) / (95.0 - 82.0) * n_E
2184
-
2185
- c_T_1_1 = q_A2_net / (1.1 * (95.0 - 65.0))
2186
- c_T_1_2 = q_F1_net
2187
- c_T_1_3 = (q_B1_net - q_F1_net) / (82.0 - 67.0)
2188
- t_1 = (c_T_1_2 - 67.0 * c_T_1_3 + 65.0 * c_T_1_1) / (c_T_1_1 - c_T_1_3)
2189
- q_T_1 = q_F1_net + (q_B1_net - q_F1_net) / (82.0 - 67.0) * (t_1 - 67.0)
2190
- p_T_1 = p_F1 + (p_B1 - p_F1) / (82.0 - 67.0) * (t_1 - 67.0)
2191
- eer_T_1 = q_T_1 / p_T_1
2192
-
2193
- t_v = (q_Ev_net - 87.0 * m_Q + 65.0 * c_T_1_1) / (c_T_1_1 - m_Q)
2194
- q_T_v = q_Ev_net + m_Q * (t_v - 87.0)
2195
- p_T_v = p_Ev + m_E * (t_v - 87.0)
2196
- eer_T_v = q_T_v / p_T_v
2197
-
2198
- c_T_2_1 = c_T_1_1
2199
- c_T_2_2 = q_B2_net
2200
- c_T_2_3 = (q_A2_net - q_B2_net) / (95.0 - 82.0)
2201
- t_2 = (c_T_2_2 - 82.0 * c_T_2_3 + 65.0 * c_T_2_1) / (c_T_2_1 - c_T_2_3)
2202
- q_T_2 = q_B2_net + (q_A2_net - q_B2_net) / (95.0 - 82.0) * (t_2 - 82.0)
2203
- p_T_2 = p_B2 + (p_A2 - p_B2) / (95.0 - 82.0) * (t_2 - 82.0)
2204
- eer_T_2 = q_T_2 / p_T_2
2205
-
2206
- d = (t_2**2.0 - t_1**2.0) / (t_v**2.0 - t_1**2.0)
2207
- b = (eer_T_1 - eer_T_2 - d * (eer_T_1 - eer_T_v)) / (t_1 - t_2 - d * (t_1 - t_v))
2208
- c = (eer_T_1 - eer_T_2 - b * (t_1 - t_2)) / (t_1**2.0 - t_2**2.0)
2209
- a = eer_T_2 - b * t_2 - c * t_2**2.0
2210
-
2211
- t_bins = [67.0, 72.0, 77.0, 82.0, 87.0, 92.0, 97.0, 102.0]
2212
- frac_hours = [0.214, 0.231, 0.216, 0.161, 0.104, 0.052, 0.018, 0.004]
2213
-
2214
- e_tot = 0.0
2215
- q_tot = 0.0
2216
- (0..7).each do |i|
2217
- bL = ((t_bins[i] - 65.0) / (95.0 - 65.0)) * (q_A2_net / 1.1)
2218
- q_k1 = q_F1_net + (q_B1_net - q_F1_net) / (82.0 - 67.0) * (t_bins[i] - 67.0)
2219
- p_k1 = p_F1 + (p_B1 - p_F1) / (82.0 - 67.0) * (t_bins[i] - 67)
2220
- q_k2 = q_B2_net + (q_A2_net - q_B2_net) / (95.0 - 82.0) * (t_bins[i] - 82.0)
2221
- p_k2 = p_B2 + (p_A2 - p_B2) / (95.0 - 82.0) * (t_bins[i] - 82.0)
2222
-
2223
- if bL <= q_k1
2224
- x_k1 = bL / q_k1
2225
- q_Tj_N = x_k1 * q_k1 * frac_hours[i]
2226
- e_Tj_N = x_k1 * p_k1 * frac_hours[i] / (1.0 - c_d * (1.0 - x_k1))
2227
- elsif (q_k1 < bL) && (bL <= q_k2)
2228
- q_Tj_N = bL * frac_hours[i]
2229
- eer_T_j = a + b * t_bins[i] + c * t_bins[i]**2.0
2230
- e_Tj_N = q_Tj_N / eer_T_j
2231
- else
2232
- q_Tj_N = frac_hours[i] * q_k2
2233
- e_Tj_N = frac_hours[i] * p_k2
2234
- end
2235
-
2236
- q_tot += q_Tj_N
2237
- e_tot += e_Tj_N
2238
- end
2239
-
2240
- seer = q_tot / e_tot
2241
- return seer
2242
- end
2243
-
2244
- def self.calc_cop_heating_1speed(hspf, c_d, fan_power_rated, coeff_eir, coeff_q)
2245
- # Iterate to find rated net cop given HSPF using simple bisection method
2246
-
2247
- # Initial large bracket to span possible hspf range
2248
- cop_a = 0.1
2249
- cop_b = 10.0
2250
-
2251
- # Iterate
2252
- iter_max = 100
2253
- tol = 0.0001
2254
-
2255
- err = 1
2256
- cop_c = (cop_a + cop_b) / 2.0
2257
- for _n in 1..iter_max
2258
- f_a = calc_hspf_1speed(cop_a, c_d, fan_power_rated, coeff_eir, coeff_q) - hspf
2259
- f_c = calc_hspf_1speed(cop_c, c_d, fan_power_rated, coeff_eir, coeff_q) - hspf
2260
-
2261
- if f_c == 0
2262
- return cop_c
2263
- elsif f_a * f_c < 0
2264
- cop_b = cop_c
2265
- else
2266
- cop_a = cop_c
2267
- end
2268
-
2269
- cop_c = (cop_a + cop_b) / 2.0
2270
- err = (cop_b - cop_a) / 2.0
2271
-
2272
- if err <= tol
2273
- break
2274
- end
2275
- end
2276
-
2277
- if err > tol
2278
- fail 'Single-speed heating cop iteration failed to converge.'
2279
- end
2280
-
2281
- return cop_c
2282
- end
2283
-
2284
- def self.calc_cops_heating_2speed(hspf, c_d, capacity_ratios, fanspeed_ratios, fan_power_rated, coeff_eir, coeff_q)
2285
- # Iterate to find rated net eers given Seer using simple bisection method for two stage air conditioners
2286
-
2287
- # Initial large bracket of cop to span possible hspf range
2288
- cop_a = 1.0
2289
- cop_b = 10.0
2290
-
2291
- # Iterate
2292
- iter_max = 100
2293
- tol = 0.0001
2294
-
2295
- err = 1
2296
- cop_c = (cop_a + cop_b) / 2.0
2297
- for _n in 1..iter_max
2298
- cops = calc_cops_from_eir_2speed(cop_a, fan_power_rated)
2299
- f_a = calc_hspf_2speed(cops, c_d, capacity_ratios, fanspeed_ratios, fan_power_rated, coeff_eir, coeff_q) - hspf
2300
-
2301
- cops = calc_cops_from_eir_2speed(cop_c, fan_power_rated)
2302
- f_c = calc_hspf_2speed(cops, c_d, capacity_ratios, fanspeed_ratios, fan_power_rated, coeff_eir, coeff_q) - hspf
2303
-
2304
- if f_c == 0
2305
- return cop_c
2306
- elsif f_a * f_c < 0
2307
- cop_b = cop_c
2308
- else
2309
- cop_a = cop_c
2310
- end
2311
-
2312
- cop_c = (cop_a + cop_b) / 2.0
2313
- err = (cop_b - cop_a) / 2.0
2314
-
2315
- if err <= tol
2316
- break
2317
- end
2318
- end
2319
-
2320
- if err > tol
2321
- fail 'Two-speed heating cop iteration failed to converge.'
2322
- end
2323
-
2324
- return calc_cops_from_eir_2speed(cop_c, fan_power_rated)
2325
- end
2326
-
2327
- def self.calc_cops_heating_4speed(hspf, c_d, capacity_ratios, fanspeed_ratios, fan_power_rated, coeff_eir, coeff_q)
2328
- # Iterate to find rated net cops given HSPF using simple bisection method for variable speed heat pumps
2329
-
2330
- # Initial large bracket of cop to span possible hspf range
2331
- cop_a = 1.0
2332
- cop_b = 15.0
2333
-
2334
- # Iterate
2335
- iter_max = 100
2336
- tol = 0.0001
2337
-
2338
- err = 1
2339
- cop_c = (cop_a + cop_b) / 2.0
2340
- for _n in 1..iter_max
2341
- cops = calc_cops_from_eir_4speed(cop_a, fan_power_rated, calc_type: 'hspf')
2342
- f_a = calc_hspf_4speed(cops, c_d, capacity_ratios, fanspeed_ratios, fan_power_rated, coeff_eir, coeff_q) - hspf
2343
-
2344
- cops = calc_cops_from_eir_4speed(cop_c, fan_power_rated, calc_type: 'hspf')
2345
- f_c = calc_hspf_4speed(cops, c_d, capacity_ratios, fanspeed_ratios, fan_power_rated, coeff_eir, coeff_q) - hspf
2346
-
2347
- if f_c == 0
2348
- return cop_c
2349
- elsif f_a * f_c < 0
2350
- cop_b = cop_c
2351
- else
2352
- cop_a = cop_c
2353
- end
2354
-
2355
- cop_c = (cop_a + cop_b) / 2.0
2356
- err = (cop_b - cop_a) / 2.0
2357
-
2358
- if err <= tol
2359
- break
2360
- end
2361
- end
2362
-
2363
- if err > tol
2364
- fail 'Variable-speed heating cops iteration failed to converge.'
2365
- end
2366
-
2367
- return calc_cops_from_eir_4speed(cop_c, fan_power_rated, calc_type: 'model')
2368
- end
2369
-
2370
- def self.calc_hspf_1speed(cop_47, c_d, fan_power_rated, coeff_eir, coeff_q)
2371
- eir_47 = calc_eir_from_cop(cop_47, fan_power_rated)
2372
- eir_35 = eir_47 * MathTools.biquadratic(70.0, 35.0, coeff_eir[0])
2373
- eir_17 = eir_47 * MathTools.biquadratic(70.0, 17.0, coeff_eir[0])
2374
-
2375
- q_47 = 1.0
2376
- q_35 = 0.7519
2377
- q_17 = q_47 * MathTools.biquadratic(70.0, 17.0, coeff_q[0])
2378
-
2379
- cfm_Btu_h = 400.0 / 12000.0
2380
-
2381
- q_47_net = q_47 + fan_power_rated * 3.412 * cfm_Btu_h
2382
- q_35_net = q_35 + fan_power_rated * 3.412 * cfm_Btu_h
2383
- q_17_net = q_17 + fan_power_rated * 3.412 * cfm_Btu_h
2384
-
2385
- p_47 = (q_47 * eir_47) / 3.412 + fan_power_rated * cfm_Btu_h
2386
- p_35 = (q_35 * eir_35) / 3.412 + fan_power_rated * cfm_Btu_h
2387
- p_17 = (q_17 * eir_17) / 3.412 + fan_power_rated * cfm_Btu_h
2388
-
2389
- t_bins = [62.0, 57.0, 52.0, 47.0, 42.0, 37.0, 32.0, 27.0, 22.0, 17.0, 12.0, 7.0, 2.0, -3.0, -8.0]
2390
- frac_hours = [0.132, 0.111, 0.103, 0.093, 0.100, 0.109, 0.126, 0.087, 0.055, 0.036, 0.026, 0.013, 0.006, 0.002, 0.001]
2391
-
2392
- designtemp = 5.0
2393
- t_off = 10.0
2394
- t_on = 14.0
2395
- ptot = 0.0
2396
- rHtot = 0.0
2397
- bLtot = 0.0
2398
- dHRmin = q_47
2399
- (0..14).each do |i|
2400
- bL = ((65.0 - t_bins[i]) / (65.0 - designtemp)) * 0.77 * dHRmin
2401
-
2402
- if (t_bins[i] > 17.0) && (t_bins[i] < 45.0)
2403
- q_h = q_17_net + (((q_35_net - q_17_net) * (t_bins[i] - 17.0)) / (35.0 - 17.0))
2404
- p_h = p_17 + (((p_35 - p_17) * (t_bins[i] - 17.0)) / (35.0 - 17.0))
2405
- else
2406
- q_h = q_17_net + (((q_47_net - q_17_net) * (t_bins[i] - 17.0)) / (47.0 - 17.0))
2407
- p_h = p_17 + (((p_47 - p_17) * (t_bins[i] - 17.0)) / (47.0 - 17.0))
2408
- end
2409
-
2410
- x_t = [bL / q_h, 1.0].min
2411
-
2412
- pLF = 1.0 - (c_d * (1.0 - x_t))
2413
- if (t_bins[i] <= t_off) || (q_h / (3.412 * p_h) < 1.0)
2414
- sigma_t = 0.0
2415
- elsif (t_off < t_bins[i]) && (t_bins[i] <= t_on) && (q_h / (p_h * 3.412) >= 1.0)
2416
- sigma_t = 0.5
2417
- elsif (t_bins[i] > t_on) && (q_h / (3.412 * p_h) >= 1.0)
2418
- sigma_t = 1.0
2410
+ cap_diff = data_sorted[i + 1].gross_capacity - dp.gross_capacity
2411
+ odb_diff = data_sorted[i + 1].outdoor_temperature - dp.outdoor_temperature
2412
+ cop_diff = data_sorted[i + 1].gross_efficiency_cop - dp.gross_efficiency_cop
2413
+ if mode == :clg
2414
+ eir_rated = 1 / data_sorted.find { |dp| dp.outdoor_temperature == HVAC::AirSourceCoolRatedODB }.gross_efficiency_cop
2415
+ else
2416
+ eir_rated = 1 / data_sorted.find { |dp| dp.outdoor_temperature == HVAC::AirSourceHeatRatedODB }.gross_efficiency_cop
2417
+ end
2418
+ eir_diff = ((1 / data_sorted[i + 1].gross_efficiency_cop) / eir_rated) - ((1 / dp.gross_efficiency_cop) / eir_rated)
2419
+ n_pt = (eir_diff.abs / tol).ceil() - 1
2420
+ eir_interval = eir_diff / (n_pt + 1)
2421
+ next if n_pt < 1
2422
+
2423
+ for i in 1..n_pt
2424
+ if mode == :clg
2425
+ new_dp = HPXML::CoolingPerformanceDataPoint.new(nil)
2426
+ else
2427
+ new_dp = HPXML::HeatingPerformanceDataPoint.new(nil)
2428
+ end
2429
+ new_eir_normalized = (1 / dp.gross_efficiency_cop) / eir_rated + eir_interval * i
2430
+ new_dp.gross_efficiency_cop = (1 / (new_eir_normalized * eir_rated))
2431
+ new_dp.outdoor_temperature = odb_diff / cop_diff * (new_dp.gross_efficiency_cop - dp.gross_efficiency_cop) + dp.outdoor_temperature
2432
+ new_dp.gross_capacity = cap_diff / odb_diff * (new_dp.outdoor_temperature - dp.outdoor_temperature) + dp.gross_capacity
2433
+ data << new_dp
2434
+ end
2419
2435
  end
2420
-
2421
- p_h_i = (x_t * p_h * sigma_t / pLF) * frac_hours[i]
2422
- rH_i = ((bL - (x_t * q_h * sigma_t)) / 3.412) * frac_hours[i]
2423
- bL_i = bL * frac_hours[i]
2424
- ptot += p_h_i
2425
- rHtot += rH_i
2426
- bLtot += bL_i
2427
2436
  end
2428
-
2429
- hspf = bLtot / (ptot + rHtot)
2430
- return hspf
2431
2437
  end
2432
2438
 
2433
- def self.calc_hspf_2speed(cops, c_d, capacity_ratios, fanspeed_ratios, fan_power_rated, coeff_eir, coeff_q)
2434
- eir_47_H = calc_eir_from_cop(cops[1], fan_power_rated)
2435
- eir_35_H = eir_47_H * MathTools.biquadratic(70.0, 35.0, coeff_eir[1])
2436
- eir_17_H = eir_47_H * MathTools.biquadratic(70.0, 17.0, coeff_eir[1])
2437
-
2438
- eir_47_L = calc_eir_from_cop(cops[0], fan_power_rated)
2439
- eir_62_L = eir_47_L * MathTools.biquadratic(70.0, 62.0, coeff_eir[0])
2440
- eir_35_L = eir_47_L * MathTools.biquadratic(70.0, 35.0, coeff_eir[0])
2441
- eir_17_L = eir_47_L * MathTools.biquadratic(70.0, 17.0, coeff_eir[0])
2442
-
2443
- q_H47 = 1.0
2444
- q_H35 = q_H47 * MathTools.biquadratic(70.0, 35.0, coeff_q[1])
2445
- q_H17 = q_H47 * MathTools.biquadratic(70.0, 17.0, coeff_q[1])
2446
-
2447
- q_L47 = q_H47 * capacity_ratios[0]
2448
- q_L62 = q_L47 * MathTools.biquadratic(70.0, 62.0, coeff_q[0])
2449
- q_L35 = q_L47 * MathTools.biquadratic(70.0, 35.0, coeff_q[0])
2450
- q_L17 = q_L47 * MathTools.biquadratic(70.0, 17.0, coeff_q[0])
2451
-
2452
- cfm_Btu_h = 400.0 / 12000.0
2453
-
2454
- q_H47_net = q_H47 + fan_power_rated * 3.412 * cfm_Btu_h
2455
- q_H35_net = q_H35 + fan_power_rated * 3.412 * cfm_Btu_h
2456
- q_H17_net = q_H17 + fan_power_rated * 3.412 * cfm_Btu_h
2457
- q_L62_net = q_L62 + fan_power_rated * 3.412 * cfm_Btu_h * fanspeed_ratios[0]
2458
- q_L47_net = q_L47 + fan_power_rated * 3.412 * cfm_Btu_h * fanspeed_ratios[0]
2459
- q_L35_net = q_L35 + fan_power_rated * 3.412 * cfm_Btu_h * fanspeed_ratios[0]
2460
- q_L17_net = q_L17 + fan_power_rated * 3.412 * cfm_Btu_h * fanspeed_ratios[0]
2461
-
2462
- p_H47 = (q_H47 * eir_47_H) / 3.412 + fan_power_rated * cfm_Btu_h
2463
- p_H35 = (q_H35 * eir_35_H) / 3.412 + fan_power_rated * cfm_Btu_h
2464
- p_H17 = (q_H17 * eir_17_H) / 3.412 + fan_power_rated * cfm_Btu_h
2465
- p_L62 = (q_L62 * eir_62_L) / 3.412 + fan_power_rated * cfm_Btu_h * fanspeed_ratios[0]
2466
- p_L47 = (q_L47 * eir_47_L) / 3.412 + fan_power_rated * cfm_Btu_h * fanspeed_ratios[0]
2467
- p_L35 = (q_L35 * eir_35_L) / 3.412 + fan_power_rated * cfm_Btu_h * fanspeed_ratios[0]
2468
- p_L17 = (q_L17 * eir_17_L) / 3.412 + fan_power_rated * cfm_Btu_h * fanspeed_ratios[0]
2469
-
2470
- t_bins = [62.0, 57.0, 52.0, 47.0, 42.0, 37.0, 32.0, 27.0, 22.0, 17.0, 12.0, 7.0, 2.0, -3.0, -8.0]
2471
- frac_hours = [0.132, 0.111, 0.103, 0.093, 0.100, 0.109, 0.126, 0.087, 0.055, 0.036, 0.026, 0.013, 0.006, 0.002, 0.001]
2472
-
2473
- designtemp = 5.0
2474
- t_off = 10.0
2475
- t_on = 14.0
2476
- ptot = 0.0
2477
- rHtot = 0.0
2478
- bLtot = 0.0
2479
- dHRmin = q_H47
2480
- (0..14).each do |i|
2481
- bL = ((65.0 - t_bins[i]) / (65.0 - designtemp)) * 0.77 * dHRmin
2482
-
2483
- if (17.0 < t_bins[i]) && (t_bins[i] < 45.0)
2484
- q_h = q_H17_net + (((q_H35_net - q_H17_net) * (t_bins[i] - 17.0)) / (35.0 - 17.0))
2485
- p_h = p_H17 + (((p_H35 - p_H17) * (t_bins[i] - 17.0)) / (35.0 - 17.0))
2486
- else
2487
- q_h = q_H17_net + (((q_H47_net - q_H17_net) * (t_bins[i] - 17.0)) / (47.0 - 17.0))
2488
- p_h = p_H17 + (((p_H47 - p_H17) * (t_bins[i] - 17.0)) / (47.0 - 17.0))
2489
- end
2490
-
2491
- if t_bins[i] >= 40.0
2492
- q_l = q_L47_net + (((q_L62_net - q_L47_net) * (t_bins[i] - 47.0)) / (62.0 - 47.0))
2493
- p_l = p_L47 + (((p_L62 - p_L47) * (t_bins[i] - 47.0)) / (62.0 - 47.0))
2494
- elsif (17.0 <= t_bins[i]) && (t_bins[i] < 40.0)
2495
- q_l = q_L17_net + (((q_L35_net - q_L17_net) * (t_bins[i] - 17.0)) / (35.0 - 17.0))
2496
- p_l = p_L17 + (((p_L35 - p_L17) * (t_bins[i] - 17.0)) / (35.0 - 17.0))
2497
- else
2498
- q_l = q_L17_net + (((q_L47_net - q_L17_net) * (t_bins[i] - 17.0)) / (47.0 - 17.0))
2499
- p_l = p_L17 + (((p_L47 - p_L17) * (t_bins[i] - 17.0)) / (47.0 - 17.0))
2500
- end
2501
-
2502
- x_t_l = [bL / q_l, 1.0].min
2503
- pLF = 1.0 - (c_d * (1.0 - x_t_l))
2504
- if (t_bins[i] <= t_off) || (q_h / (p_h * 3.412) < 1.0)
2505
- sigma_t_h = 0.0
2506
- elsif (t_off < t_bins[i]) && (t_bins[i] <= t_on) && (q_h / (p_h * 3.412) >= 1.0)
2507
- sigma_t_h = 0.5
2508
- elsif (t_bins[i] > t_on) && (q_h / (p_h * 3.412) >= 1.0)
2509
- sigma_t_h = 1.0
2510
- end
2511
-
2512
- if t_bins[i] <= t_off
2513
- sigma_t_l = 0.0
2514
- elsif (t_off < t_bins[i]) && (t_bins[i] <= t_on)
2515
- sigma_t_l = 0.5
2516
- elsif t_bins[i] > t_on
2517
- sigma_t_l = 1.0
2518
- end
2519
-
2520
- if q_l > bL
2521
- p_h_i = (x_t_l * p_l * sigma_t_l / pLF) * frac_hours[i]
2522
- rH_i = (bL * (1.0 - sigma_t_l)) / 3.412 * frac_hours[i]
2523
- elsif (q_l < bL) && (q_h > bL)
2524
- x_t_l = ((q_h - bL) / (q_h - q_l))
2525
- x_t_h = 1.0 - x_t_l
2526
- p_h_i = (x_t_l * p_l + x_t_h * p_h) * sigma_t_l * frac_hours[i]
2527
- rH_i = (bL * (1.0 - sigma_t_l)) / 3.412 * frac_hours[i]
2528
- elsif q_h <= bL
2529
- p_h_i = p_h * sigma_t_h * frac_hours[i]
2530
- rH_i = (bL - (q_h * sigma_t_l)) / 3.412 * frac_hours[i]
2439
+ def self.correct_ft_cap_eir(data_array, mode)
2440
+ # Add sensitivity to indoor conditions
2441
+ # single speed cutler curve coefficients
2442
+ if mode == :clg
2443
+ cap_ft_spec_ss, eir_ft_spec_ss = get_cool_cap_eir_ft_spec(HPXML::HVACCompressorTypeSingleStage)
2444
+ rated_t_i = HVAC::AirSourceCoolRatedIWB
2445
+ indoor_t = [50.0, rated_t_i, 80.0]
2446
+ else
2447
+ # default capacity retention for single speed
2448
+ retention_temp, retention_fraction = get_default_heating_capacity_retention(HPXML::HVACCompressorTypeSingleStage)
2449
+ cap_ft_spec_ss, eir_ft_spec_ss = get_heat_cap_eir_ft_spec(HPXML::HVACCompressorTypeSingleStage, retention_temp, retention_fraction)
2450
+ rated_t_i = HVAC::AirSourceHeatRatedIDB
2451
+ indoor_t = [60.0, rated_t_i, 80.0]
2452
+ end
2453
+ data_array.each do |data|
2454
+ data.each do |dp|
2455
+ if mode == :clg
2456
+ dp.indoor_wetbulb = rated_t_i
2457
+ else
2458
+ dp.indoor_temperature = rated_t_i
2459
+ end
2531
2460
  end
2532
-
2533
- bL_i = bL * frac_hours[i]
2534
- ptot += p_h_i
2535
- rHtot += rH_i
2536
- bLtot += bL_i
2537
2461
  end
2538
-
2539
- hspf = bLtot / (ptot + rHtot)
2540
- return hspf
2541
- end
2542
-
2543
- def self.calc_hspf_4speed(cop_47, c_d, capacity_ratios, fanspeed_ratios, fan_power_rated, coeff_eir, coeff_q)
2544
- n_max = 2
2545
- n_int = 1
2546
- n_min = 0
2547
-
2548
- tin = 70.0
2549
- tout_3 = 17.0
2550
- tout_2 = 35.0
2551
- tout_0 = 62.0
2552
-
2553
- eir_H1_2 = calc_eir_from_cop(cop_47[n_max], fan_power_rated)
2554
- eir_H3_2 = eir_H1_2 * MathTools.biquadratic(tin, tout_3, coeff_eir[n_max])
2555
-
2556
- eir_adjv = calc_eir_from_cop(cop_47[n_int], fan_power_rated)
2557
- eir_H2_v = eir_adjv * MathTools.biquadratic(tin, tout_2, coeff_eir[n_int])
2558
-
2559
- eir_H1_1 = calc_eir_from_cop(cop_47[n_min], fan_power_rated)
2560
- eir_H0_1 = eir_H1_1 * MathTools.biquadratic(tin, tout_0, coeff_eir[n_min])
2561
-
2562
- q_H1_2 = capacity_ratios[n_max]
2563
- q_H3_2 = q_H1_2 * MathTools.biquadratic(tin, tout_3, coeff_q[n_max])
2564
-
2565
- q_H2_v = capacity_ratios[n_int] * MathTools.biquadratic(tin, tout_2, coeff_q[n_int])
2566
-
2567
- q_H1_1 = capacity_ratios[n_min]
2568
- q_H0_1 = q_H1_1 * MathTools.biquadratic(tin, tout_0, coeff_q[n_min])
2569
-
2570
- cfm_Btu_h = 400.0 / 12000.0
2571
-
2572
- q_H1_2_net = q_H1_2 + fan_power_rated * 3.412 * cfm_Btu_h * fanspeed_ratios[n_max]
2573
- q_H3_2_net = q_H3_2 + fan_power_rated * 3.412 * cfm_Btu_h * fanspeed_ratios[n_max]
2574
- q_H2_v_net = q_H2_v + fan_power_rated * 3.412 * cfm_Btu_h * fanspeed_ratios[n_int]
2575
- q_H1_1_net = q_H1_1 + fan_power_rated * 3.412 * cfm_Btu_h * fanspeed_ratios[n_min]
2576
- q_H0_1_net = q_H0_1 + fan_power_rated * 3.412 * cfm_Btu_h * fanspeed_ratios[n_min]
2577
-
2578
- p_H1_2 = q_H1_2 * eir_H1_2 + fan_power_rated * 3.412 * cfm_Btu_h * fanspeed_ratios[n_max]
2579
- p_H3_2 = q_H3_2 * eir_H3_2 + fan_power_rated * 3.412 * cfm_Btu_h * fanspeed_ratios[n_max]
2580
- p_H2_v = q_H2_v * eir_H2_v + fan_power_rated * 3.412 * cfm_Btu_h * fanspeed_ratios[n_int]
2581
- p_H1_1 = q_H1_1 * eir_H1_1 + fan_power_rated * 3.412 * cfm_Btu_h * fanspeed_ratios[n_min]
2582
- p_H0_1 = q_H0_1 * eir_H0_1 + fan_power_rated * 3.412 * cfm_Btu_h * fanspeed_ratios[n_min]
2583
-
2584
- q_H35_2 = 0.9 * (q_H3_2_net + 0.6 * (q_H1_2_net - q_H3_2_net))
2585
- p_H35_2 = 0.985 * (p_H3_2 + 0.6 * (p_H1_2 - p_H3_2))
2586
- q_H35_1 = q_H1_1_net + (q_H0_1_net - q_H1_1_net) / (62.0 - 47.0) * (35.0 - 47.0)
2587
- p_H35_1 = p_H1_1 + (p_H0_1 - p_H1_1) / (62.0 - 47.0) * (35.0 - 47.0)
2588
- n_Q = (q_H2_v_net - q_H35_1) / (q_H35_2 - q_H35_1)
2589
- m_Q = (q_H0_1_net - q_H1_1_net) / (62.0 - 47.0) * (1.0 - n_Q) + n_Q * (q_H35_2 - q_H3_2_net) / (35.0 - 17.0)
2590
- n_E = (p_H2_v - p_H35_1) / (p_H35_2 - p_H35_1)
2591
- m_E = (p_H0_1 - p_H1_1) / (62.0 - 47.0) * (1.0 - n_E) + n_E * (p_H35_2 - p_H3_2) / (35.0 - 17.0)
2592
-
2593
- t_OD = 5.0
2594
- dHR = q_H1_2_net * (65.0 - t_OD) / 60.0
2595
-
2596
- c_T_3_1 = q_H1_1_net
2597
- c_T_3_2 = (q_H0_1_net - q_H1_1_net) / (62.0 - 47.0)
2598
- c_T_3_3 = 0.77 * dHR / (65.0 - t_OD)
2599
- t_3 = (47.0 * c_T_3_2 + 65.0 * c_T_3_3 - c_T_3_1) / (c_T_3_2 + c_T_3_3)
2600
- q_HT3_1 = q_H1_1_net + (q_H0_1_net - q_H1_1_net) / (62.0 - 47.0) * (t_3 - 47.0)
2601
- p_HT3_1 = p_H1_1 + (p_H0_1 - p_H1_1) / (62.0 - 47.0) * (t_3 - 47.0)
2602
- cop_T3_1 = q_HT3_1 / p_HT3_1
2603
-
2604
- c_T_v_1 = q_H2_v_net
2605
- c_T_v_3 = c_T_3_3
2606
- t_v = (35.0 * m_Q + 65 * c_T_v_3 - c_T_v_1) / (m_Q + c_T_v_3)
2607
- q_HTv_v = q_H2_v_net + m_Q * (t_v - 35.0)
2608
- p_HTv_v = p_H2_v + m_E * (t_v - 35.0)
2609
- cop_Tv_v = q_HTv_v / p_HTv_v
2610
-
2611
- c_T_4_1 = q_H3_2_net
2612
- c_T_4_2 = (q_H35_2 - q_H3_2_net) / (35.0 - 17.0)
2613
- c_T_4_3 = c_T_v_3
2614
- t_4 = (17.0 * c_T_4_2 + 65.0 * c_T_4_3 - c_T_4_1) / (c_T_4_2 + c_T_4_3)
2615
- q_HT4_2 = q_H3_2_net + (q_H35_2 - q_H3_2_net) / (35.0 - 17.0) * (t_4 - 17.0)
2616
- p_HT4_2 = p_H3_2 + (p_H35_2 - p_H3_2) / (35.0 - 17.0) * (t_4 - 17.0)
2617
- cop_T4_2 = q_HT4_2 / p_HT4_2
2618
-
2619
- d = (t_3**2.0 - t_4**2.0) / (t_v**2.0 - t_4**2.0)
2620
- b = (cop_T4_2 - cop_T3_1 - d * (cop_T4_2 - cop_Tv_v)) / (t_4 - t_3 - d * (t_4 - t_v))
2621
- c = (cop_T4_2 - cop_T3_1 - b * (t_4 - t_3)) / (t_4**2.0 - t_3**2.0)
2622
- a = cop_T4_2 - b * t_4 - c * t_4**2.0
2623
-
2624
- t_bins = [62.0, 57.0, 52.0, 47.0, 42.0, 37.0, 32.0, 27.0, 22.0, 17.0, 12.0, 7.0, 2.0, -3.0, -8.0]
2625
- frac_hours = [0.132, 0.111, 0.103, 0.093, 0.100, 0.109, 0.126, 0.087, 0.055, 0.036, 0.026, 0.013, 0.006, 0.002, 0.001]
2626
-
2627
- t_off = 10.0
2628
- t_on = t_off + 4
2629
- etot = 0.0
2630
- bLtot = 0.0
2631
- (0..14).each do |i|
2632
- bL = ((65.0 - t_bins[i]) / (65.0 - t_OD)) * 0.77 * dHR
2633
-
2634
- q_1 = q_H1_1_net + (q_H0_1_net - q_H1_1_net) / (62.0 - 47.0) * (t_bins[i] - 47.0)
2635
- p_1 = p_H1_1 + (p_H0_1 - p_H1_1) / (62.0 - 47.0) * (t_bins[i] - 47.0)
2636
-
2637
- if (t_bins[i] <= 17.0) || (t_bins[i] >= 45.0)
2638
- q_2 = q_H3_2_net + (q_H1_2_net - q_H3_2_net) * (t_bins[i] - 17.0) / (47.0 - 17.0)
2639
- p_2 = p_H3_2 + (p_H1_2 - p_H3_2) * (t_bins[i] - 17.0) / (47.0 - 17.0)
2640
- else
2641
- q_2 = q_H3_2_net + (q_H35_2 - q_H3_2_net) * (t_bins[i] - 17.0) / (35.0 - 17.0)
2642
- p_2 = p_H3_2 + (p_H35_2 - p_H3_2) * (t_bins[i] - 17.0) / (35.0 - 17.0)
2643
- end
2644
-
2645
- if t_bins[i] <= t_off
2646
- delta = 0.0
2647
- elsif t_bins[i] >= t_on
2648
- delta = 1.0
2649
- else
2650
- delta = 0.5
2462
+ # table lookup output values
2463
+ data_array.each do |data|
2464
+ # create a new array to temporarily store expanded data points, to concat after the existing data loop
2465
+ array_tmp = Array.new
2466
+ indoor_t.each do |t_i|
2467
+ # introduce indoor conditions other than rated, expand to rated data points
2468
+ next if t_i == rated_t_i
2469
+
2470
+ data_tmp = Array.new
2471
+ data.each do |dp|
2472
+ dp_new = dp.dup
2473
+ data_tmp << dp_new
2474
+ if mode == :clg
2475
+ dp_new.indoor_wetbulb = t_i
2476
+ else
2477
+ dp_new.indoor_temperature = t_i
2478
+ end
2479
+ # capacity FT curve output
2480
+ cap_ft_curve_output = MathTools.biquadratic(t_i, dp_new.outdoor_temperature, cap_ft_spec_ss[0])
2481
+ cap_ft_curve_output_rated = MathTools.biquadratic(rated_t_i, dp_new.outdoor_temperature, cap_ft_spec_ss[0])
2482
+ cap_correction_factor = cap_ft_curve_output / cap_ft_curve_output_rated
2483
+ # corrected capacity hash, with two temperature independent variables
2484
+ dp_new.gross_capacity *= cap_correction_factor
2485
+
2486
+ # eir FT curve output
2487
+ eir_ft_curve_output = MathTools.biquadratic(t_i, dp_new.outdoor_temperature, eir_ft_spec_ss[0])
2488
+ eir_ft_curve_output_rated = MathTools.biquadratic(rated_t_i, dp_new.outdoor_temperature, eir_ft_spec_ss[0])
2489
+ eir_correction_factor = eir_ft_curve_output / eir_ft_curve_output_rated
2490
+ dp_new.gross_efficiency_cop /= eir_correction_factor
2491
+ end
2492
+ array_tmp << data_tmp
2651
2493
  end
2652
-
2653
- if bL <= q_1
2654
- x_1 = bL / q_1
2655
- e_Tj_n = delta * x_1 * p_1 * frac_hours[i] / (1.0 - c_d * (1.0 - x_1))
2656
- elsif (q_1 < bL) && (bL <= q_2)
2657
- cop_T_j = a + b * t_bins[i] + c * t_bins[i]**2.0
2658
- e_Tj_n = delta * frac_hours[i] * bL / cop_T_j + (1.0 - delta) * bL * (frac_hours[i])
2659
- else
2660
- e_Tj_n = delta * frac_hours[i] * p_2 + frac_hours[i] * (bL - delta * q_2)
2494
+ array_tmp.each do |new_data|
2495
+ data.concat(new_data)
2661
2496
  end
2662
-
2663
- bLtot += frac_hours[i] * bL
2664
- etot += e_Tj_n
2665
2497
  end
2666
-
2667
- hspf = bLtot / (etot / 3.412)
2668
- return hspf
2669
2498
  end
2670
2499
 
2671
- def self.calc_fan_speed_ratios(capacity_ratios, rated_cfm_per_tons, rated_airflow_rate)
2672
- fan_speed_ratios = []
2673
- capacity_ratios.each_with_index do |capacity_ratio, i|
2674
- fan_speed_ratios << rated_cfm_per_tons[i] * capacity_ratio / rated_airflow_rate
2675
- end
2676
- return fan_speed_ratios
2677
- end
2678
-
2679
- def self.create_curve_biquadratic_constant(model)
2680
- curve = OpenStudio::Model::CurveBiquadratic.new(model)
2681
- curve.setName('ConstantBiquadratic')
2682
- curve.setCoefficient1Constant(1)
2683
- curve.setCoefficient2x(0)
2684
- curve.setCoefficient3xPOW2(0)
2685
- curve.setCoefficient4y(0)
2686
- curve.setCoefficient5yPOW2(0)
2687
- curve.setCoefficient6xTIMESY(0)
2688
- curve.setMinimumValueofx(-100)
2689
- curve.setMaximumValueofx(100)
2690
- curve.setMinimumValueofy(-100)
2691
- curve.setMaximumValueofy(100)
2692
- return curve
2693
- end
2694
-
2695
- def self.create_curve_quadratic_constant(model)
2696
- curve = OpenStudio::Model::CurveQuadratic.new(model)
2697
- curve.setName('ConstantQuadratic')
2698
- curve.setCoefficient1Constant(1)
2699
- curve.setCoefficient2x(0)
2700
- curve.setCoefficient3xPOW2(0)
2701
- curve.setMinimumValueofx(-100)
2702
- curve.setMaximumValueofx(100)
2703
- curve.setMinimumCurveOutput(-100)
2704
- curve.setMaximumCurveOutput(100)
2705
- return curve
2706
- end
2707
-
2708
- def self.create_curve_cubic_constant(model)
2709
- curve = OpenStudio::Model::CurveCubic.new(model)
2710
- curve.setName('ConstantCubic')
2711
- curve.setCoefficient1Constant(1)
2712
- curve.setCoefficient2x(0)
2713
- curve.setCoefficient3xPOW2(0)
2714
- curve.setCoefficient4xPOW3(0)
2715
- curve.setMinimumValueofx(-100)
2716
- curve.setMaximumValueofx(100)
2717
- return curve
2718
- end
2719
-
2720
- def self.convert_curve_biquadratic(coeff)
2721
- # Convert IP curves to SI curves
2722
- si_coeff = []
2723
- si_coeff << coeff[0] + 32.0 * (coeff[1] + coeff[3]) + 1024.0 * (coeff[2] + coeff[4] + coeff[5])
2724
- si_coeff << 9.0 / 5.0 * coeff[1] + 576.0 / 5.0 * coeff[2] + 288.0 / 5.0 * coeff[5]
2725
- si_coeff << 81.0 / 25.0 * coeff[2]
2726
- si_coeff << 9.0 / 5.0 * coeff[3] + 576.0 / 5.0 * coeff[4] + 288.0 / 5.0 * coeff[5]
2727
- si_coeff << 81.0 / 25.0 * coeff[4]
2728
- si_coeff << 81.0 / 25.0 * coeff[5]
2729
- return si_coeff
2730
- end
2731
-
2732
- def self.create_curve_biquadratic(model, coeff, name, min_x, max_x, min_y, max_y)
2733
- curve = OpenStudio::Model::CurveBiquadratic.new(model)
2734
- curve.setName(name)
2735
- curve.setCoefficient1Constant(coeff[0])
2736
- curve.setCoefficient2x(coeff[1])
2737
- curve.setCoefficient3xPOW2(coeff[2])
2738
- curve.setCoefficient4y(coeff[3])
2739
- curve.setCoefficient5yPOW2(coeff[4])
2740
- curve.setCoefficient6xTIMESY(coeff[5])
2741
- curve.setMinimumValueofx(min_x)
2742
- curve.setMaximumValueofx(max_x)
2743
- curve.setMinimumValueofy(min_y)
2744
- curve.setMaximumValueofy(max_y)
2745
- return curve
2746
- end
2747
-
2748
- def self.create_curve_bicubic(model, coeff, name, min_x, max_x, min_y, max_y)
2749
- curve = OpenStudio::Model::CurveBicubic.new(model)
2750
- curve.setName(name)
2751
- curve.setCoefficient1Constant(coeff[0])
2752
- curve.setCoefficient2x(coeff[1])
2753
- curve.setCoefficient3xPOW2(coeff[2])
2754
- curve.setCoefficient4y(coeff[3])
2755
- curve.setCoefficient5yPOW2(coeff[4])
2756
- curve.setCoefficient6xTIMESY(coeff[5])
2757
- curve.setCoefficient7xPOW3(coeff[6])
2758
- curve.setCoefficient8yPOW3(coeff[7])
2759
- curve.setCoefficient9xPOW2TIMESY(coeff[8])
2760
- curve.setCoefficient10xTIMESYPOW2(coeff[9])
2761
- curve.setMinimumValueofx(min_x)
2762
- curve.setMaximumValueofx(max_x)
2763
- curve.setMinimumValueofy(min_y)
2764
- curve.setMaximumValueofy(max_y)
2765
- return curve
2766
- end
2767
-
2768
- def self.create_curve_quadratic(model, coeff, name, min_x, max_x, min_y, max_y, is_dimensionless = false)
2769
- curve = OpenStudio::Model::CurveQuadratic.new(model)
2770
- curve.setName(name)
2771
- curve.setCoefficient1Constant(coeff[0])
2772
- curve.setCoefficient2x(coeff[1])
2773
- curve.setCoefficient3xPOW2(coeff[2])
2774
- curve.setMinimumValueofx(min_x)
2775
- curve.setMaximumValueofx(max_x)
2776
- if not min_y.nil?
2777
- curve.setMinimumCurveOutput(min_y)
2778
- end
2779
- if not max_y.nil?
2780
- curve.setMaximumCurveOutput(max_y)
2781
- end
2782
- if is_dimensionless
2783
- curve.setInputUnitTypeforX('Dimensionless')
2784
- curve.setOutputUnitType('Dimensionless')
2785
- end
2786
- return curve
2787
- end
2788
-
2789
- def self.create_curve_cubic(model, coeff, name, min_x, max_x, min_y, max_y)
2790
- curve = OpenStudio::Model::CurveCubic.new(model)
2791
- curve.setName(name)
2792
- curve.setCoefficient1Constant(coeff[0])
2793
- curve.setCoefficient2x(coeff[1])
2794
- curve.setCoefficient3xPOW2(coeff[2])
2795
- curve.setCoefficient4xPOW3(coeff[3])
2796
- curve.setMinimumValueofx(min_x)
2797
- curve.setMaximumValueofx(max_x)
2798
- curve.setMinimumCurveOutput(min_y)
2799
- curve.setMaximumCurveOutput(max_y)
2800
- return curve
2801
- end
2802
-
2803
- def self.create_curve_exponent(model, coeff, name, min_x, max_x)
2804
- curve = OpenStudio::Model::CurveExponent.new(model)
2805
- curve.setName(name)
2806
- curve.setCoefficient1Constant(coeff[0])
2807
- curve.setCoefficient2Constant(coeff[1])
2808
- curve.setCoefficient3Constant(coeff[2])
2809
- curve.setMinimumValueofx(min_x)
2810
- curve.setMaximumValueofx(max_x)
2811
- return curve
2812
- end
2813
-
2814
- def self.create_curve_quad_linear(model, coeff, name)
2815
- curve = OpenStudio::Model::CurveQuadLinear.new(model)
2816
- curve.setName(name)
2817
- curve.setCoefficient1Constant(coeff[0])
2818
- curve.setCoefficient2w(coeff[1])
2819
- curve.setCoefficient3x(coeff[2])
2820
- curve.setCoefficient4y(coeff[3])
2821
- curve.setCoefficient5z(coeff[4])
2822
- return curve
2823
- end
2824
-
2825
- def self.create_curve_quint_linear(model, coeff, name)
2826
- curve = OpenStudio::Model::CurveQuintLinear.new(model)
2827
- curve.setName(name)
2828
- curve.setCoefficient1Constant(coeff[0])
2829
- curve.setCoefficient2v(coeff[1])
2830
- curve.setCoefficient3w(coeff[2])
2831
- curve.setCoefficient4x(coeff[3])
2832
- curve.setCoefficient5y(coeff[4])
2833
- curve.setCoefficient6z(coeff[5])
2834
- return curve
2835
- end
2836
-
2837
- def self.create_dx_cooling_coil(model, obj_name, cooling_system)
2500
+ def self.create_dx_cooling_coil(model, obj_name, cooling_system, max_rated_fan_cfm, weather_max_drybulb)
2838
2501
  clg_ap = cooling_system.additional_properties
2839
2502
 
2840
2503
  if cooling_system.is_a? HPXML::CoolingSystem
@@ -2843,23 +2506,51 @@ class HVAC
2843
2506
  clg_type = cooling_system.heat_pump_type
2844
2507
  end
2845
2508
 
2846
- if clg_ap.num_speeds > 1
2847
- constant_biquadratic = create_curve_biquadratic_constant(model)
2509
+ if cooling_system.cooling_detailed_performance_data.empty?
2510
+ max_clg_cfm = UnitConversions.convert(cooling_system.cooling_capacity * clg_ap.cool_capacity_ratios[-1], 'Btu/hr', 'ton') * clg_ap.cool_rated_cfm_per_ton[-1]
2511
+ clg_ap.cool_rated_capacities_gross = []
2512
+ clg_ap.cool_rated_capacities_net = []
2513
+ clg_ap.cool_capacity_ratios.each_with_index do |capacity_ratio, speed|
2514
+ fan_ratio = clg_ap.cool_fan_speed_ratios[speed] * max_clg_cfm / max_rated_fan_cfm
2515
+ fan_power = calculate_fan_power_from_curve(clg_ap.fan_power_rated * max_rated_fan_cfm, fan_ratio)
2516
+ net_capacity = capacity_ratio * cooling_system.cooling_capacity
2517
+ clg_ap.cool_rated_capacities_net << net_capacity
2518
+ gross_capacity = convert_net_to_gross_capacity_cop(net_capacity, fan_power, :clg)[0]
2519
+ clg_ap.cool_rated_capacities_gross << gross_capacity
2520
+ end
2521
+ else
2522
+ process_neep_detailed_performance(cooling_system.cooling_detailed_performance_data, clg_ap, :clg, max_rated_fan_cfm, weather_max_drybulb)
2848
2523
  end
2849
2524
 
2850
2525
  clg_coil = nil
2851
- crankcase_heater_temp = 50 # F
2852
-
2853
- for i in 0..(clg_ap.num_speeds - 1)
2854
- cap_ft_spec_si = convert_curve_biquadratic(clg_ap.cool_cap_ft_spec[i])
2855
- eir_ft_spec_si = convert_curve_biquadratic(clg_ap.cool_eir_ft_spec[i])
2856
- cap_ft_curve = create_curve_biquadratic(model, cap_ft_spec_si, "Cool-CAP-fT#{i + 1}", -100, 100, -100, 100)
2857
- eir_ft_curve = create_curve_biquadratic(model, eir_ft_spec_si, "Cool-EIR-fT#{i + 1}", -100, 100, -100, 100)
2858
- plf_fplr_curve = create_curve_quadratic(model, clg_ap.cool_plf_fplr_spec[i], "Cool-PLF-fPLR#{i + 1}", 0, 1, 0.7, 1)
2526
+ num_speeds = clg_ap.cool_rated_cfm_per_ton.size
2527
+ for i in 0..(num_speeds - 1)
2528
+ if not cooling_system.cooling_detailed_performance_data.empty?
2529
+ speed_performance_data = clg_ap.cooling_performance_data_array[i].sort_by { |dp| [dp.indoor_wetbulb, dp.outdoor_temperature] }
2530
+ var_wb = { name: 'wet_bulb_temp_in', min: -100, max: 100, values: speed_performance_data.map { |dp| UnitConversions.convert(dp.indoor_wetbulb, 'F', 'C') }.uniq }
2531
+ var_db = { name: 'dry_bulb_temp_out', min: -100, max: 100, values: speed_performance_data.map { |dp| UnitConversions.convert(dp.outdoor_temperature, 'F', 'C') }.uniq }
2532
+ cap_ft_independent_vars = [var_wb, var_db]
2533
+ eir_ft_independent_vars = [var_wb, var_db]
2534
+
2535
+ rate_dp = speed_performance_data.find { |dp| (dp.indoor_wetbulb == HVAC::AirSourceCoolRatedIWB) && (dp.outdoor_temperature == HVAC::AirSourceCoolRatedODB) }
2536
+ clg_ap.cool_rated_cops << rate_dp.gross_efficiency_cop
2537
+ clg_ap.cool_rated_capacities_gross << rate_dp.gross_capacity
2538
+ clg_ap.cool_rated_capacities_net << rate_dp.capacity
2539
+ cap_ft_output_values = speed_performance_data.map { |dp| dp.gross_capacity / rate_dp.gross_capacity }
2540
+ eir_ft_output_values = speed_performance_data.map { |dp| (1.0 / dp.gross_efficiency_cop) / (1.0 / rate_dp.gross_efficiency_cop) }
2541
+ cap_ft_curve = create_table_lookup(model, "Cool-CAP-fT#{i + 1}", cap_ft_independent_vars, cap_ft_output_values, 0.0)
2542
+ eir_ft_curve = create_table_lookup(model, "Cool-EIR-fT#{i + 1}", eir_ft_independent_vars, eir_ft_output_values, 0.0)
2543
+ else
2544
+ cap_ft_spec_si = convert_curve_biquadratic(clg_ap.cool_cap_ft_spec[i])
2545
+ eir_ft_spec_si = convert_curve_biquadratic(clg_ap.cool_eir_ft_spec[i])
2546
+ cap_ft_curve = create_curve_biquadratic(model, cap_ft_spec_si, "Cool-CAP-fT#{i + 1}", -100, 100, -100, 100)
2547
+ eir_ft_curve = create_curve_biquadratic(model, eir_ft_spec_si, "Cool-EIR-fT#{i + 1}", -100, 100, -100, 100)
2548
+ end
2859
2549
  cap_fff_curve = create_curve_quadratic(model, clg_ap.cool_cap_fflow_spec[i], "Cool-CAP-fFF#{i + 1}", 0, 2, 0, 2)
2860
2550
  eir_fff_curve = create_curve_quadratic(model, clg_ap.cool_eir_fflow_spec[i], "Cool-EIR-fFF#{i + 1}", 0, 2, 0, 2)
2551
+ plf_fplr_curve = create_curve_quadratic(model, clg_ap.cool_plf_fplr_spec[i], "Cool-PLF-fPLR#{i + 1}", 0, 1, 0.7, 1)
2861
2552
 
2862
- if clg_ap.num_speeds == 1
2553
+ if num_speeds == 1
2863
2554
  clg_coil = OpenStudio::Model::CoilCoolingDXSingleSpeed.new(model, model.alwaysOnDiscreteSchedule, cap_ft_curve, cap_fff_curve, eir_ft_curve, eir_fff_curve, plf_fplr_curve)
2864
2555
  # Coil COP calculation based on system type
2865
2556
  if [HPXML::HVACTypeRoomAirConditioner, HPXML::HVACTypePTAC, HPXML::HVACTypeHeatPumpPTHP, HPXML::HVACTypeHeatPumpRoom].include? clg_type
@@ -2870,16 +2561,16 @@ class HVAC
2870
2561
  end
2871
2562
  clg_coil.setRatedCOP(UnitConversions.convert(ceer, 'Btu/hr', 'W'))
2872
2563
  else
2873
- clg_coil.setRatedCOP(1.0 / clg_ap.cool_rated_eirs[i])
2564
+ clg_coil.setRatedCOP(clg_ap.cool_rated_cops[i])
2874
2565
  end
2875
- clg_coil.setMaximumOutdoorDryBulbTemperatureForCrankcaseHeaterOperation(UnitConversions.convert(crankcase_heater_temp, 'F', 'C')) if cooling_system.crankcase_heater_watts.to_f > 0.0 # From RESNET Publication No. 002-2017
2566
+ clg_coil.setMaximumOutdoorDryBulbTemperatureForCrankcaseHeaterOperation(UnitConversions.convert(CrankcaseHeaterTemp, 'F', 'C')) if cooling_system.crankcase_heater_watts.to_f > 0.0 # From RESNET Publication No. 002-2017
2876
2567
  clg_coil.setRatedSensibleHeatRatio(clg_ap.cool_rated_shrs_gross[i])
2877
2568
  clg_coil.setNominalTimeForCondensateRemovalToBegin(1000.0)
2878
2569
  clg_coil.setRatioOfInitialMoistureEvaporationRateAndSteadyStateLatentCapacity(1.5)
2879
2570
  clg_coil.setMaximumCyclingRate(3.0)
2880
2571
  clg_coil.setLatentCapacityTimeConstant(45.0)
2881
- clg_coil.setRatedTotalCoolingCapacity(UnitConversions.convert(cooling_system.cooling_capacity, 'Btu/hr', 'W'))
2882
- clg_coil.setRatedAirFlowRate(calc_rated_airflow(cooling_system.cooling_capacity, clg_ap.cool_rated_cfm_per_ton[0], 1.0))
2572
+ clg_coil.setRatedTotalCoolingCapacity(UnitConversions.convert(clg_ap.cool_rated_capacities_gross[i], 'Btu/hr', 'W'))
2573
+ clg_coil.setRatedAirFlowRate(calc_rated_airflow(clg_ap.cool_rated_capacities_net[i], clg_ap.cool_rated_cfm_per_ton[0]))
2883
2574
  else
2884
2575
  if clg_coil.nil?
2885
2576
  clg_coil = OpenStudio::Model::CoilCoolingDXMultiSpeed.new(model)
@@ -2887,18 +2578,19 @@ class HVAC
2887
2578
  clg_coil.setApplyLatentDegradationtoSpeedsGreaterthan1(false)
2888
2579
  clg_coil.setFuelType(EPlus::FuelTypeElectricity)
2889
2580
  clg_coil.setAvailabilitySchedule(model.alwaysOnDiscreteSchedule)
2890
- clg_coil.setMaximumOutdoorDryBulbTemperatureforCrankcaseHeaterOperation(UnitConversions.convert(crankcase_heater_temp, 'F', 'C')) if cooling_system.crankcase_heater_watts.to_f > 0.0 # From RESNET Publication No. 002-2017
2581
+ clg_coil.setMaximumOutdoorDryBulbTemperatureforCrankcaseHeaterOperation(UnitConversions.convert(CrankcaseHeaterTemp, 'F', 'C')) if cooling_system.crankcase_heater_watts.to_f > 0.0 # From RESNET Publication No. 002-2017
2582
+ constant_biquadratic = create_curve_biquadratic_constant(model)
2891
2583
  end
2892
2584
  stage = OpenStudio::Model::CoilCoolingDXMultiSpeedStageData.new(model, cap_ft_curve, cap_fff_curve, eir_ft_curve, eir_fff_curve, plf_fplr_curve, constant_biquadratic)
2893
- stage.setGrossRatedCoolingCOP(1.0 / clg_ap.cool_rated_eirs[i])
2585
+ stage.setGrossRatedCoolingCOP(clg_ap.cool_rated_cops[i])
2894
2586
  stage.setGrossRatedSensibleHeatRatio(clg_ap.cool_rated_shrs_gross[i])
2895
2587
  stage.setNominalTimeforCondensateRemovaltoBegin(1000)
2896
2588
  stage.setRatioofInitialMoistureEvaporationRateandSteadyStateLatentCapacity(1.5)
2897
2589
  stage.setRatedWasteHeatFractionofPowerInput(0.2)
2898
2590
  stage.setMaximumCyclingRate(3.0)
2899
2591
  stage.setLatentCapacityTimeConstant(45.0)
2900
- stage.setGrossRatedTotalCoolingCapacity(UnitConversions.convert(cooling_system.cooling_capacity, 'Btu/hr', 'W') * clg_ap.cool_capacity_ratios[i])
2901
- stage.setRatedAirFlowRate(calc_rated_airflow(cooling_system.cooling_capacity, clg_ap.cool_rated_cfm_per_ton[i], clg_ap.cool_capacity_ratios[i]))
2592
+ stage.setGrossRatedTotalCoolingCapacity(UnitConversions.convert(clg_ap.cool_rated_capacities_gross[i], 'Btu/hr', 'W'))
2593
+ stage.setRatedAirFlowRate(calc_rated_airflow(clg_ap.cool_rated_capacities_net[i], clg_ap.cool_rated_cfm_per_ton[i]))
2902
2594
  clg_coil.addStage(stage)
2903
2595
  end
2904
2596
  end
@@ -2911,46 +2603,75 @@ class HVAC
2911
2603
  return clg_coil
2912
2604
  end
2913
2605
 
2914
- def self.create_dx_heating_coil(model, obj_name, heating_system)
2606
+ def self.create_dx_heating_coil(model, obj_name, heating_system, max_rated_fan_cfm, weather_min_drybulb)
2915
2607
  htg_ap = heating_system.additional_properties
2916
2608
 
2917
- if htg_ap.num_speeds > 1
2918
- constant_biquadratic = create_curve_biquadratic_constant(model)
2609
+ if heating_system.heating_detailed_performance_data.empty?
2610
+ max_htg_cfm = UnitConversions.convert(heating_system.heating_capacity * htg_ap.heat_capacity_ratios[-1], 'Btu/hr', 'ton') * htg_ap.heat_rated_cfm_per_ton[-1]
2611
+ htg_ap.heat_rated_capacities_gross = []
2612
+ htg_ap.heat_rated_capacities_net = []
2613
+ htg_ap.heat_capacity_ratios.each_with_index do |capacity_ratio, speed|
2614
+ fan_ratio = htg_ap.heat_fan_speed_ratios[speed] * max_htg_cfm / max_rated_fan_cfm
2615
+ fan_power = calculate_fan_power_from_curve(htg_ap.fan_power_rated * max_rated_fan_cfm, fan_ratio)
2616
+ net_capacity = capacity_ratio * heating_system.heating_capacity
2617
+ htg_ap.heat_rated_capacities_net << net_capacity
2618
+ gross_capacity = convert_net_to_gross_capacity_cop(net_capacity, fan_power, :htg)[0]
2619
+ htg_ap.heat_rated_capacities_gross << gross_capacity
2620
+ end
2621
+ else
2622
+ process_neep_detailed_performance(heating_system.heating_detailed_performance_data, htg_ap, :htg, max_rated_fan_cfm, weather_min_drybulb, htg_ap.hp_min_temp)
2919
2623
  end
2920
2624
 
2921
2625
  htg_coil = nil
2922
- crankcase_heater_temp = 50 # F
2923
-
2924
- for i in 0..(htg_ap.num_speeds - 1)
2925
- cap_ft_spec_si = convert_curve_biquadratic(htg_ap.heat_cap_ft_spec[i])
2926
- eir_ft_spec_si = convert_curve_biquadratic(htg_ap.heat_eir_ft_spec[i])
2927
- cap_ft_curve = create_curve_biquadratic(model, cap_ft_spec_si, "Heat-CAP-fT#{i + 1}", -100, 100, -100, 100)
2928
- eir_ft_curve = create_curve_biquadratic(model, eir_ft_spec_si, "Heat-EIR-fT#{i + 1}", -100, 100, -100, 100)
2929
- plf_fplr_curve = create_curve_quadratic(model, htg_ap.heat_plf_fplr_spec[i], "Heat-PLF-fPLR#{i + 1}", 0, 1, 0.7, 1)
2626
+ num_speeds = htg_ap.heat_rated_cfm_per_ton.size
2627
+ for i in 0..(num_speeds - 1)
2628
+ if not heating_system.heating_detailed_performance_data.empty?
2629
+ speed_performance_data = htg_ap.heating_performance_data_array[i].sort_by { |dp| [dp.indoor_temperature, dp.outdoor_temperature] }
2630
+ var_idb = { name: 'dry_bulb_temp_in', min: -100, max: 100, values: speed_performance_data.map { |dp| UnitConversions.convert(dp.indoor_temperature, 'F', 'C') }.uniq }
2631
+ var_odb = { name: 'dry_bulb_temp_out', min: -100, max: 100, values: speed_performance_data.map { |dp| UnitConversions.convert(dp.outdoor_temperature, 'F', 'C') }.uniq }
2632
+ cap_ft_independent_vars = [var_idb, var_odb]
2633
+ eir_ft_independent_vars = [var_idb, var_odb]
2634
+
2635
+ rate_dp = speed_performance_data.find { |dp| (dp.indoor_temperature == HVAC::AirSourceHeatRatedIDB) && (dp.outdoor_temperature == HVAC::AirSourceHeatRatedODB) }
2636
+ htg_ap.heat_rated_cops << rate_dp.gross_efficiency_cop
2637
+ htg_ap.heat_rated_capacities_net << rate_dp.capacity
2638
+ htg_ap.heat_rated_capacities_gross << rate_dp.gross_capacity
2639
+ cap_ft_output_values = speed_performance_data.map { |dp| dp.gross_capacity / rate_dp.gross_capacity }
2640
+ eir_ft_output_values = speed_performance_data.map { |dp| (1.0 / dp.gross_efficiency_cop) / (1.0 / rate_dp.gross_efficiency_cop) }
2641
+ cap_ft_curve = create_table_lookup(model, "Heat-CAP-fT#{i + 1}", cap_ft_independent_vars, cap_ft_output_values, 0)
2642
+ eir_ft_curve = create_table_lookup(model, "Heat-EIR-fT#{i + 1}", eir_ft_independent_vars, eir_ft_output_values, 0)
2643
+ else
2644
+ cap_ft_spec_si = convert_curve_biquadratic(htg_ap.heat_cap_ft_spec[i])
2645
+ eir_ft_spec_si = convert_curve_biquadratic(htg_ap.heat_eir_ft_spec[i])
2646
+ cap_ft_curve = create_curve_biquadratic(model, cap_ft_spec_si, "Heat-CAP-fT#{i + 1}", -100, 100, -100, 100)
2647
+ eir_ft_curve = create_curve_biquadratic(model, eir_ft_spec_si, "Heat-EIR-fT#{i + 1}", -100, 100, -100, 100)
2648
+ end
2930
2649
  cap_fff_curve = create_curve_quadratic(model, htg_ap.heat_cap_fflow_spec[i], "Heat-CAP-fFF#{i + 1}", 0, 2, 0, 2)
2931
2650
  eir_fff_curve = create_curve_quadratic(model, htg_ap.heat_eir_fflow_spec[i], "Heat-EIR-fFF#{i + 1}", 0, 2, 0, 2)
2651
+ plf_fplr_curve = create_curve_quadratic(model, htg_ap.heat_plf_fplr_spec[i], "Heat-PLF-fPLR#{i + 1}", 0, 1, 0.7, 1)
2932
2652
 
2933
- if htg_ap.num_speeds == 1
2653
+ if num_speeds == 1
2934
2654
  htg_coil = OpenStudio::Model::CoilHeatingDXSingleSpeed.new(model, model.alwaysOnDiscreteSchedule, cap_ft_curve, cap_fff_curve, eir_ft_curve, eir_fff_curve, plf_fplr_curve)
2935
2655
  if heating_system.heating_efficiency_cop.nil?
2936
- htg_coil.setRatedCOP(1.0 / htg_ap.heat_rated_eirs[i])
2656
+ htg_coil.setRatedCOP(htg_ap.heat_rated_cops[i])
2937
2657
  else # PTHP or room heat pump
2938
2658
  htg_coil.setRatedCOP(heating_system.heating_efficiency_cop)
2939
2659
  end
2940
- htg_coil.setRatedTotalHeatingCapacity(UnitConversions.convert(heating_system.heating_capacity, 'Btu/hr', 'W'))
2941
- htg_coil.setRatedAirFlowRate(calc_rated_airflow(heating_system.heating_capacity, htg_ap.heat_rated_cfm_per_ton[0], 1.0))
2660
+ htg_coil.setRatedTotalHeatingCapacity(UnitConversions.convert(htg_ap.heat_rated_capacities_gross[i], 'Btu/hr', 'W'))
2661
+ htg_coil.setRatedAirFlowRate(calc_rated_airflow(htg_ap.heat_rated_capacities_net[i], htg_ap.heat_rated_cfm_per_ton[0]))
2942
2662
  else
2943
2663
  if htg_coil.nil?
2944
2664
  htg_coil = OpenStudio::Model::CoilHeatingDXMultiSpeed.new(model)
2945
2665
  htg_coil.setFuelType(EPlus::FuelTypeElectricity)
2946
2666
  htg_coil.setApplyPartLoadFractiontoSpeedsGreaterthan1(false)
2947
2667
  htg_coil.setAvailabilitySchedule(model.alwaysOnDiscreteSchedule)
2668
+ constant_biquadratic = create_curve_biquadratic_constant(model)
2948
2669
  end
2949
2670
  stage = OpenStudio::Model::CoilHeatingDXMultiSpeedStageData.new(model, cap_ft_curve, cap_fff_curve, eir_ft_curve, eir_fff_curve, plf_fplr_curve, constant_biquadratic)
2950
- stage.setGrossRatedHeatingCOP(1.0 / htg_ap.heat_rated_eirs[i])
2671
+ stage.setGrossRatedHeatingCOP(htg_ap.heat_rated_cops[i])
2951
2672
  stage.setRatedWasteHeatFractionofPowerInput(0.2)
2952
- stage.setGrossRatedHeatingCapacity(UnitConversions.convert(heating_system.heating_capacity, 'Btu/hr', 'W') * htg_ap.heat_capacity_ratios[i])
2953
- stage.setRatedAirFlowRate(calc_rated_airflow(heating_system.heating_capacity, htg_ap.heat_rated_cfm_per_ton[i], htg_ap.heat_capacity_ratios[i]))
2673
+ stage.setGrossRatedHeatingCapacity(UnitConversions.convert(htg_ap.heat_rated_capacities_gross[i], 'Btu/hr', 'W'))
2674
+ stage.setRatedAirFlowRate(calc_rated_airflow(htg_ap.heat_rated_capacities_net[i], htg_ap.heat_rated_cfm_per_ton[i]))
2954
2675
  htg_coil.addStage(stage)
2955
2676
  end
2956
2677
  end
@@ -2965,31 +2686,13 @@ class HVAC
2965
2686
  if heating_system.fraction_heat_load_served == 0
2966
2687
  htg_coil.setResistiveDefrostHeaterCapacity(0)
2967
2688
  end
2968
- htg_coil.setMaximumOutdoorDryBulbTemperatureforCrankcaseHeaterOperation(UnitConversions.convert(crankcase_heater_temp, 'F', 'C')) if heating_system.crankcase_heater_watts.to_f > 0.0 # From RESNET Publication No. 002-2017
2689
+ htg_coil.setMaximumOutdoorDryBulbTemperatureforCrankcaseHeaterOperation(UnitConversions.convert(CrankcaseHeaterTemp, 'F', 'C')) if heating_system.crankcase_heater_watts.to_f > 0.0 # From RESNET Publication No. 002-2017
2969
2690
  htg_coil.setCrankcaseHeaterCapacity(heating_system.crankcase_heater_watts)
2970
2691
  htg_coil.additionalProperties.setFeature('HPXML_ID', heating_system.id) # Used by reporting measure
2971
2692
 
2972
2693
  return htg_coil
2973
2694
  end
2974
2695
 
2975
- def self.set_cool_rated_eirs(cooling_system)
2976
- clg_ap = cooling_system.additional_properties
2977
-
2978
- clg_ap.cool_rated_eirs = []
2979
- for speed in 0..clg_ap.num_speeds - 1
2980
- clg_ap.cool_rated_eirs << calc_eir_from_eer(clg_ap.cool_eers[speed], clg_ap.fan_power_rated)
2981
- end
2982
- end
2983
-
2984
- def self.set_heat_rated_eirs(heating_system)
2985
- htg_ap = heating_system.additional_properties
2986
-
2987
- htg_ap.heat_rated_eirs = []
2988
- for speed in 0..htg_ap.num_speeds - 1
2989
- htg_ap.heat_rated_eirs << calc_eir_from_cop(htg_ap.heat_cops[speed], htg_ap.fan_power_rated)
2990
- end
2991
- end
2992
-
2993
2696
  def self.set_cool_rated_shrs_gross(runner, cooling_system)
2994
2697
  clg_ap = cooling_system.additional_properties
2995
2698
 
@@ -3001,13 +2704,13 @@ class HVAC
3001
2704
  dB_rated = 80.0 # deg-F
3002
2705
  win = 0.01118470 # Humidity ratio corresponding to 80F dry bulb/67F wet bulb (from EnergyPlus)
3003
2706
 
3004
- if clg_ap.num_speeds > 1
3005
- cool_nominal_cfm_per_ton = (clg_ap.cool_rated_airflow_rate - clg_ap.cool_rated_cfm_per_ton[0] * clg_ap.cool_capacity_ratios[0]) / (clg_ap.cool_capacity_ratios[-1] - clg_ap.cool_capacity_ratios[0]) * (1.0 - clg_ap.cool_capacity_ratios[0]) + clg_ap.cool_rated_cfm_per_ton[0] * clg_ap.cool_capacity_ratios[0]
3006
- else
2707
+ if cooling_system.compressor_type == HPXML::HVACCompressorTypeSingleStage
3007
2708
  cool_nominal_cfm_per_ton = clg_ap.cool_rated_cfm_per_ton[0]
2709
+ else
2710
+ cool_nominal_cfm_per_ton = (clg_ap.cool_rated_airflow_rate - clg_ap.cool_rated_cfm_per_ton[0] * clg_ap.cool_capacity_ratios[0]) / (clg_ap.cool_capacity_ratios[-1] - clg_ap.cool_capacity_ratios[0]) * (1.0 - clg_ap.cool_capacity_ratios[0]) + clg_ap.cool_rated_cfm_per_ton[0] * clg_ap.cool_capacity_ratios[0]
3008
2711
  end
3009
2712
 
3010
- p_atm = 14.696 # standard atmospheric pressure (psia)
2713
+ p_atm = UnitConversions.convert(1, 'atm', 'psi')
3011
2714
 
3012
2715
  ao = Psychrometrics.CoilAoFactor(runner, dB_rated, p_atm, UnitConversions.convert(1, 'ton', 'kBtu/hr'), cool_nominal_cfm_per_ton, cooling_system.cooling_shr, win)
3013
2716
 
@@ -3023,47 +2726,50 @@ class HVAC
3023
2726
  return [(1.0 - c_d), c_d, 0.0] # Linear part load model
3024
2727
  end
3025
2728
 
3026
- def self.set_cool_c_d(cooling_system, num_speeds)
2729
+ def self.set_cool_c_d(cooling_system)
3027
2730
  clg_ap = cooling_system.additional_properties
3028
2731
 
3029
2732
  # Degradation coefficient for cooling
3030
2733
  if ((cooling_system.is_a? HPXML::CoolingSystem) && ([HPXML::HVACTypeRoomAirConditioner, HPXML::HVACTypePTAC].include? cooling_system.cooling_system_type)) ||
3031
2734
  ((cooling_system.is_a? HPXML::HeatPump) && ([HPXML::HVACTypeHeatPumpPTHP, HPXML::HVACTypeHeatPumpRoom].include? cooling_system.heat_pump_type))
3032
2735
  clg_ap.cool_c_d = 0.22
3033
- elsif num_speeds == 1
2736
+ elsif cooling_system.compressor_type == HPXML::HVACCompressorTypeSingleStage
3034
2737
  if cooling_system.cooling_efficiency_seer < 13.0
3035
2738
  clg_ap.cool_c_d = 0.20
3036
2739
  else
3037
2740
  clg_ap.cool_c_d = 0.07
3038
2741
  end
3039
- elsif num_speeds == 2
2742
+ elsif cooling_system.compressor_type == HPXML::HVACCompressorTypeTwoStage
3040
2743
  clg_ap.cool_c_d = 0.11
3041
- elsif num_speeds >= 4
2744
+ elsif cooling_system.compressor_type == HPXML::HVACCompressorTypeVariableSpeed
3042
2745
  clg_ap.cool_c_d = 0.25
3043
2746
  end
3044
2747
 
3045
2748
  # PLF curve
2749
+ num_speeds = clg_ap.cool_capacity_ratios.size
3046
2750
  clg_ap.cool_plf_fplr_spec = [calc_plr_coefficients(clg_ap.cool_c_d)] * num_speeds
3047
2751
  end
3048
2752
 
3049
- def self.set_heat_c_d(heating_system, num_speeds)
2753
+ def self.set_heat_c_d(heating_system)
3050
2754
  htg_ap = heating_system.additional_properties
3051
2755
 
3052
2756
  # Degradation coefficient for heating
3053
2757
  if (heating_system.is_a? HPXML::HeatPump) && ([HPXML::HVACTypeHeatPumpPTHP, HPXML::HVACTypeHeatPumpRoom].include? heating_system.heat_pump_type)
3054
2758
  htg_ap.heat_c_d = 0.22
3055
- elsif num_speeds == 1
2759
+ elsif heating_system.compressor_type == HPXML::HVACCompressorTypeSingleStage
3056
2760
  if heating_system.heating_efficiency_hspf < 7.0
3057
2761
  htg_ap.heat_c_d = 0.20
3058
2762
  else
3059
2763
  htg_ap.heat_c_d = 0.11
3060
2764
  end
3061
- elsif num_speeds == 2
2765
+ elsif heating_system.compressor_type == HPXML::HVACCompressorTypeTwoStage
3062
2766
  htg_ap.heat_c_d = 0.11
3063
- elsif num_speeds >= 4
2767
+ elsif heating_system.compressor_type == HPXML::HVACCompressorTypeVariableSpeed
3064
2768
  htg_ap.heat_c_d = 0.25
3065
2769
  end
3066
2770
 
2771
+ # PLF curve
2772
+ num_speeds = htg_ap.heat_capacity_ratios.size
3067
2773
  htg_ap.heat_plf_fplr_spec = [calc_plr_coefficients(htg_ap.heat_c_d)] * num_speeds
3068
2774
  end
3069
2775
 
@@ -3072,10 +2778,13 @@ class HVAC
3072
2778
  return cooling_system.cooling_efficiency_eer / 1.01
3073
2779
  end
3074
2780
 
3075
- def self.set_fan_power_rated(hvac_system)
2781
+ def self.set_fan_power_rated(hvac_system, use_eer_cop)
3076
2782
  hvac_ap = hvac_system.additional_properties
3077
2783
 
3078
- if hvac_system.distribution_system.nil?
2784
+ if use_eer_cop
2785
+ # Fan not separately modeled
2786
+ hvac_ap.fan_power_rated = 0.0
2787
+ elsif hvac_system.distribution_system.nil?
3079
2788
  # Ductless, installed and rated value should be equal
3080
2789
  hvac_ap.fan_power_rated = hvac_system.fan_watts_per_cfm # W/cfm
3081
2790
  else
@@ -3106,258 +2815,17 @@ class HVAC
3106
2815
  return
3107
2816
  end
3108
2817
 
3109
- def self.set_cool_rated_eirs_mshp(cooling_system, num_speeds)
3110
- clg_ap = cooling_system.additional_properties
3111
-
3112
- cops_norm = [1.901, 1.859, 1.746, 1.609, 1.474, 1.353, 1.247, 1.156, 1.079, 1.0]
3113
- fan_powers_norm = [0.604, 0.634, 0.670, 0.711, 0.754, 0.800, 0.848, 0.898, 0.948, 1.0]
3114
-
3115
- cop_max_speed = 3.5 # 3.5 is an initial guess, final value solved for below
3116
-
3117
- fan_powers_rated = []
3118
- eers_rated = []
3119
-
3120
- for i in 0..num_speeds - 1
3121
- fan_powers_rated << clg_ap.fan_power_rated * fan_powers_norm[i]
3122
- eers_rated << UnitConversions.convert(cop_max_speed, 'W', 'Btu/hr') * cops_norm[i]
3123
- end
3124
-
3125
- cop_max_speed_1 = cop_max_speed
3126
- cop_max_speed_2 = cop_max_speed
3127
- error = cooling_system.cooling_efficiency_seer - calc_mshp_seer(eers_rated, clg_ap.cool_c_d, clg_ap.cool_capacity_ratios, clg_ap.cool_rated_cfm_per_ton, fan_powers_rated, clg_ap.cool_eir_ft_spec, clg_ap.cool_cap_ft_spec)
3128
- error1 = error
3129
- error2 = error
3130
-
3131
- itmax = 50 # maximum iterations
3132
- cvg = false
3133
- final_n = nil
3134
-
3135
- for n in 1..itmax + 1
3136
- final_n = n
3137
- for i in 0..num_speeds - 1
3138
- eers_rated[i] = UnitConversions.convert(cop_max_speed, 'W', 'Btu/hr') * cops_norm[i]
3139
- end
3140
-
3141
- error = cooling_system.cooling_efficiency_seer - calc_mshp_seer(eers_rated, clg_ap.cool_c_d, clg_ap.cool_capacity_ratios, clg_ap.cool_rated_cfm_per_ton, fan_powers_rated, clg_ap.cool_eir_ft_spec, clg_ap.cool_cap_ft_spec)
3142
-
3143
- cop_max_speed, cvg, cop_max_speed_1, error1, cop_max_speed_2, error2 = MathTools.Iterate(cop_max_speed, error, cop_max_speed_1, error1, cop_max_speed_2, error2, n, cvg)
3144
-
3145
- if cvg
3146
- break
3147
- end
3148
- end
3149
-
3150
- if (not cvg) || (final_n > itmax)
3151
- cop_max_speed = UnitConversions.convert(0.547 * cooling_system.cooling_efficiency_seer - 0.104, 'Btu/hr', 'W') # Correlation developed from JonW's MatLab scripts. Only used if an eer cannot be found.
3152
- end
3153
-
3154
- clg_ap.cool_rated_eirs = []
3155
-
3156
- for i in 0..num_speeds - 1
3157
- clg_ap.cool_rated_eirs << calc_eir_from_eer(UnitConversions.convert(cop_max_speed, 'W', 'Btu/hr') * cops_norm[i], fan_powers_rated[i])
3158
- end
3159
- end
3160
-
3161
- def self.set_mshp_downselected_speed_indices(heat_pump)
3162
- hp_ap = heat_pump.additional_properties
3163
-
3164
- # Down-select to speed indices
3165
-
3166
- # Cooling
3167
- hp_ap.cool_cap_ft_spec = hp_ap.cool_cap_ft_spec.select.with_index { |_x, i| hp_ap.speed_indices.include? i }
3168
- hp_ap.cool_eir_ft_spec = hp_ap.cool_eir_ft_spec.select.with_index { |_x, i| hp_ap.speed_indices.include? i }
3169
- hp_ap.cool_cap_fflow_spec = hp_ap.cool_cap_fflow_spec.select.with_index { |_x, i| hp_ap.speed_indices.include? i }
3170
- hp_ap.cool_eir_fflow_spec = hp_ap.cool_eir_fflow_spec.select.with_index { |_x, i| hp_ap.speed_indices.include? i }
3171
- hp_ap.cool_plf_fplr_spec = hp_ap.cool_plf_fplr_spec.select.with_index { |_x, i| hp_ap.speed_indices.include? i }
3172
- hp_ap.cool_rated_cfm_per_ton = hp_ap.cool_rated_cfm_per_ton.select.with_index { |_x, i| hp_ap.speed_indices.include? i }
3173
- hp_ap.cool_capacity_ratios = hp_ap.cool_capacity_ratios.select.with_index { |_x, i| hp_ap.speed_indices.include? i }
3174
- hp_ap.cool_rated_shrs_gross = hp_ap.cool_rated_shrs_gross.select.with_index { |_x, i| hp_ap.speed_indices.include? i }
3175
- hp_ap.cool_rated_eirs = hp_ap.cool_rated_eirs.select.with_index { |_x, i| hp_ap.speed_indices.include? i }
3176
- hp_ap.cool_fan_speed_ratios = hp_ap.cool_fan_speed_ratios.select.with_index { |_x, i| hp_ap.speed_indices.include? i }
3177
-
3178
- if heat_pump.is_a? HPXML::HeatPump # Skip for mini-split air conditioner
3179
- # Heating
3180
- hp_ap.heat_eir_ft_spec = hp_ap.heat_eir_ft_spec.select.with_index { |_x, i| hp_ap.speed_indices.include? i }
3181
- hp_ap.heat_cap_fflow_spec = hp_ap.heat_cap_fflow_spec.select.with_index { |_x, i| hp_ap.speed_indices.include? i }
3182
- hp_ap.heat_eir_fflow_spec = hp_ap.heat_eir_fflow_spec.select.with_index { |_x, i| hp_ap.speed_indices.include? i }
3183
- hp_ap.heat_cap_ft_spec = hp_ap.heat_cap_ft_spec.select.with_index { |_x, i| hp_ap.speed_indices.include? i }
3184
- hp_ap.heat_plf_fplr_spec = hp_ap.heat_plf_fplr_spec.select.with_index { |_x, i| hp_ap.speed_indices.include? i }
3185
- hp_ap.heat_rated_cfm_per_ton = hp_ap.heat_rated_cfm_per_ton.select.with_index { |_x, i| hp_ap.speed_indices.include? i }
3186
- hp_ap.heat_capacity_ratios = hp_ap.heat_capacity_ratios.select.with_index { |_x, i| hp_ap.speed_indices.include? i }
3187
- hp_ap.heat_rated_eirs = hp_ap.heat_rated_eirs.select.with_index { |_x, i| hp_ap.speed_indices.include? i }
3188
- hp_ap.heat_fan_speed_ratios = hp_ap.heat_fan_speed_ratios.select.with_index { |_x, i| hp_ap.speed_indices.include? i }
3189
- end
3190
- end
3191
-
3192
- def self.calc_mshp_seer(eer_a, c_d, capacity_ratio, cfm_tons, fan_power_rated, cool_eir_ft_spec, cool_cap_ft_spec)
3193
- n_max = (eer_a.length - 1.0) - 3.0 # Don't use max speed; FIXME: this is different than calc_mshp_hspf?
3194
- n_min = 0
3195
- n_int = (n_min + (n_max - n_min) / 3.0).ceil.to_i
3196
-
3197
- wBin = 67.0
3198
- tout_B = 82.0
3199
- tout_E = 87.0
3200
- tout_F = 67.0
3201
-
3202
- eir_A2 = calc_eir_from_eer(eer_a[n_max], fan_power_rated[n_max])
3203
- eir_B2 = eir_A2 * MathTools.biquadratic(wBin, tout_B, cool_eir_ft_spec[n_max])
3204
-
3205
- eir_Av = calc_eir_from_eer(eer_a[n_int], fan_power_rated[n_int])
3206
- eir_Ev = eir_Av * MathTools.biquadratic(wBin, tout_E, cool_eir_ft_spec[n_int])
3207
-
3208
- eir_A1 = calc_eir_from_eer(eer_a[n_min], fan_power_rated[n_min])
3209
- eir_B1 = eir_A1 * MathTools.biquadratic(wBin, tout_B, cool_eir_ft_spec[n_min])
3210
- eir_F1 = eir_A1 * MathTools.biquadratic(wBin, tout_F, cool_eir_ft_spec[n_min])
3211
-
3212
- q_A2 = capacity_ratio[n_max]
3213
- q_B2 = q_A2 * MathTools.biquadratic(wBin, tout_B, cool_cap_ft_spec[n_max])
3214
- q_Ev = capacity_ratio[n_int] * MathTools.biquadratic(wBin, tout_E, cool_cap_ft_spec[n_int])
3215
- q_B1 = capacity_ratio[n_min] * MathTools.biquadratic(wBin, tout_B, cool_cap_ft_spec[n_min])
3216
- q_F1 = capacity_ratio[n_min] * MathTools.biquadratic(wBin, tout_F, cool_cap_ft_spec[n_min])
3217
-
3218
- q_A2_net = q_A2 - fan_power_rated[n_max] * UnitConversions.convert(1, 'W', 'Btu/hr') * (cfm_tons[n_max] * capacity_ratio[n_max]) / UnitConversions.convert(1, 'ton', 'Btu/hr')
3219
- q_B2_net = q_B2 - fan_power_rated[n_max] * UnitConversions.convert(1, 'W', 'Btu/hr') * (cfm_tons[n_max] * capacity_ratio[n_max]) / UnitConversions.convert(1, 'ton', 'Btu/hr')
3220
- q_Ev_net = q_Ev - fan_power_rated[n_int] * UnitConversions.convert(1, 'W', 'Btu/hr') * (cfm_tons[n_int] * capacity_ratio[n_int]) / UnitConversions.convert(1, 'ton', 'Btu/hr')
3221
- q_B1_net = q_B1 - fan_power_rated[n_min] * UnitConversions.convert(1, 'W', 'Btu/hr') * (cfm_tons[n_min] * capacity_ratio[n_min]) / UnitConversions.convert(1, 'ton', 'Btu/hr')
3222
- q_F1_net = q_F1 - fan_power_rated[n_min] * UnitConversions.convert(1, 'W', 'Btu/hr') * (cfm_tons[n_min] * capacity_ratio[n_min]) / UnitConversions.convert(1, 'ton', 'Btu/hr')
3223
-
3224
- p_A2 = UnitConversions.convert(q_A2 * eir_A2, 'Btu', 'Wh') + fan_power_rated[n_max] * (cfm_tons[n_max] * capacity_ratio[n_max]) / UnitConversions.convert(1, 'ton', 'Btu/hr')
3225
- p_B2 = UnitConversions.convert(q_B2 * eir_B2, 'Btu', 'Wh') + fan_power_rated[n_max] * (cfm_tons[n_max] * capacity_ratio[n_max]) / UnitConversions.convert(1, 'ton', 'Btu/hr')
3226
- p_Ev = UnitConversions.convert(q_Ev * eir_Ev, 'Btu', 'Wh') + fan_power_rated[n_int] * (cfm_tons[n_int] * capacity_ratio[n_int]) / UnitConversions.convert(1, 'ton', 'Btu/hr')
3227
- p_B1 = UnitConversions.convert(q_B1 * eir_B1, 'Btu', 'Wh') + fan_power_rated[n_min] * (cfm_tons[n_min] * capacity_ratio[n_min]) / UnitConversions.convert(1, 'ton', 'Btu/hr')
3228
- p_F1 = UnitConversions.convert(q_F1 * eir_F1, 'Btu', 'Wh') + fan_power_rated[n_min] * (cfm_tons[n_min] * capacity_ratio[n_min]) / UnitConversions.convert(1, 'ton', 'Btu/hr')
3229
-
3230
- q_k1_87 = q_F1_net + (q_B1_net - q_F1_net) / (82.0 - 67.0) * (87 - 67.0)
3231
- q_k2_87 = q_B2_net + (q_A2_net - q_B2_net) / (95.0 - 82.0) * (87.0 - 82.0)
3232
- n_Q = (q_Ev_net - q_k1_87) / (q_k2_87 - q_k1_87)
3233
- m_Q = (q_B1_net - q_F1_net) / (82.0 - 67.0) * (1.0 - n_Q) + (q_A2_net - q_B2_net) / (95.0 - 82.0) * n_Q
3234
- p_k1_87 = p_F1 + (p_B1 - p_F1) / (82.0 - 67.0) * (87.0 - 67.0)
3235
- p_k2_87 = p_B2 + (p_A2 - p_B2) / (95.0 - 82.0) * (87.0 - 82.0)
3236
- n_E = (p_Ev - p_k1_87) / (p_k2_87 - p_k1_87)
3237
- m_E = (p_B1 - p_F1) / (82.0 - 67.0) * (1.0 - n_E) + (p_A2 - p_B2) / (95.0 - 82.0) * n_E
3238
-
3239
- c_T_1_1 = q_A2_net / (1.1 * (95.0 - 65.0))
3240
- c_T_1_2 = q_F1_net
3241
- c_T_1_3 = (q_B1_net - q_F1_net) / (82.0 - 67.0)
3242
- t_1 = (c_T_1_2 - 67.0 * c_T_1_3 + 65.0 * c_T_1_1) / (c_T_1_1 - c_T_1_3)
3243
- q_T_1 = q_F1_net + (q_B1_net - q_F1_net) / (82.0 - 67.0) * (t_1 - 67.0)
3244
- p_T_1 = p_F1 + (p_B1 - p_F1) / (82.0 - 67.0) * (t_1 - 67.0)
3245
- eer_T_1 = q_T_1 / p_T_1
3246
-
3247
- t_v = (q_Ev_net - 87.0 * m_Q + 65.0 * c_T_1_1) / (c_T_1_1 - m_Q)
3248
- q_T_v = q_Ev_net + m_Q * (t_v - 87.0)
3249
- p_T_v = p_Ev + m_E * (t_v - 87.0)
3250
- eer_T_v = q_T_v / p_T_v
3251
-
3252
- c_T_2_1 = c_T_1_1
3253
- c_T_2_2 = q_B2_net
3254
- c_T_2_3 = (q_A2_net - q_B2_net) / (95.0 - 82.0)
3255
- t_2 = (c_T_2_2 - 82.0 * c_T_2_3 + 65.0 * c_T_2_1) / (c_T_2_1 - c_T_2_3)
3256
- q_T_2 = q_B2_net + (q_A2_net - q_B2_net) / (95.0 - 82.0) * (t_2 - 82.0)
3257
- p_T_2 = p_B2 + (p_A2 - p_B2) / (95.0 - 82.0) * (t_2 - 82.0)
3258
- eer_T_2 = q_T_2 / p_T_2
3259
-
3260
- d = (t_2**2 - t_1**2) / (t_v**2 - t_1**2)
3261
- b = (eer_T_1 - eer_T_2 - d * (eer_T_1 - eer_T_v)) / (t_1 - t_2 - d * (t_1 - t_v))
3262
- c = (eer_T_1 - eer_T_2 - b * (t_1 - t_2)) / (t_1**2 - t_2**2)
3263
- a = eer_T_2 - b * t_2 - c * t_2**2
3264
-
3265
- e_tot = 0
3266
- q_tot = 0
3267
- t_bins = [67.0, 72.0, 77.0, 82.0, 87.0, 92.0, 97.0, 102.0]
3268
- frac_hours = [0.214, 0.231, 0.216, 0.161, 0.104, 0.052, 0.018, 0.004]
3269
-
3270
- for i in 0..7
3271
- bL = ((t_bins[i] - 65.0) / (95.0 - 65.0)) * (q_A2_net / 1.1)
3272
- q_k1 = q_F1_net + (q_B1_net - q_F1_net) / (82.0 - 67.0) * (t_bins[i] - 67.0)
3273
- p_k1 = p_F1 + (p_B1 - p_F1) / (82.0 - 67.0) * (t_bins[i] - 67)
3274
- q_k2 = q_B2_net + (q_A2_net - q_B2_net) / (95.0 - 82.0) * (t_bins[i] - 82.0)
3275
- p_k2 = p_B2 + (p_A2 - p_B2) / (95.0 - 82.0) * (t_bins[i] - 82.0)
3276
-
3277
- if bL <= q_k1
3278
- x_k1 = bL / q_k1
3279
- q_Tj_N = x_k1 * q_k1 * frac_hours[i]
3280
- e_Tj_N = x_k1 * p_k1 * frac_hours[i] / (1 - c_d * (1 - x_k1))
3281
- elsif (q_k1 < bL) && (bL <= q_k2)
3282
- q_Tj_N = bL * frac_hours[i]
3283
- eer_T_j = a + b * t_bins[i] + c * t_bins[i]**2
3284
- e_Tj_N = q_Tj_N / eer_T_j
3285
- else
3286
- q_Tj_N = frac_hours[i] * q_k2
3287
- e_Tj_N = frac_hours[i] * p_k2
3288
- end
3289
-
3290
- q_tot += q_Tj_N
3291
- e_tot += e_Tj_N
3292
- end
3293
-
3294
- seer = q_tot / e_tot
3295
- return seer
3296
- end
3297
-
3298
- def self.set_heat_rated_eirs_mshp(heat_pump, num_speeds)
3299
- hp_ap = heat_pump.additional_properties
3300
-
3301
- cops_norm = [1.792, 1.502, 1.308, 1.207, 1.145, 1.105, 1.077, 1.056, 1.041, 1.0]
3302
- fan_powers_norm = [0.577, 0.625, 0.673, 0.720, 0.768, 0.814, 0.861, 0.907, 0.954, 1.0]
3303
-
3304
- cop_max_speed = 3.25 # 3.35 is an initial guess, final value solved for below
3305
-
3306
- fan_powers_rated = []
3307
- cops_rated = []
3308
-
3309
- for i in 0..num_speeds - 1
3310
- fan_powers_rated << hp_ap.fan_power_rated * fan_powers_norm[i]
3311
- cops_rated << cop_max_speed * cops_norm[i]
3312
- end
3313
-
3314
- cop_max_speed_1 = cop_max_speed
3315
- cop_max_speed_2 = cop_max_speed
3316
- error = heat_pump.heating_efficiency_hspf - calc_mshp_hspf(cops_rated, hp_ap.heat_c_d, hp_ap.heat_capacity_ratios, hp_ap.heat_rated_cfm_per_ton, fan_powers_rated, hp_ap.heat_eir_ft_spec, hp_ap.heat_cap_ft_spec)
3317
-
3318
- error1 = error
3319
- error2 = error
3320
-
3321
- itmax = 50 # maximum iterations
3322
- cvg = false
3323
- final_n = nil
3324
-
3325
- for n in 1..itmax
3326
- final_n = n
3327
- for i in 0..num_speeds - 1
3328
- cops_rated[i] = cop_max_speed * cops_norm[i]
3329
- end
3330
-
3331
- error = heat_pump.heating_efficiency_hspf - calc_mshp_hspf(cops_rated, hp_ap.heat_c_d, hp_ap.heat_capacity_ratios, hp_ap.heat_rated_cfm_per_ton, fan_powers_rated, hp_ap.heat_eir_ft_spec, hp_ap.heat_cap_ft_spec)
3332
-
3333
- cop_max_speed, cvg, cop_max_speed_1, error1, cop_max_speed_2, error2 = MathTools.Iterate(cop_max_speed, error, cop_max_speed_1, error1, cop_max_speed_2, error2, n, cvg)
3334
-
3335
- if cvg
3336
- break
3337
- end
3338
- end
3339
-
3340
- if (not cvg) || (final_n > itmax)
3341
- cop_max_speed = UnitConversions.convert(0.4174 * heat_pump.heating_efficiency_hspf - 1.1134, 'Btu/hr', 'W') # Correlation developed from JonW's MatLab scripts. Only used if a cop cannot be found.
3342
- end
3343
-
3344
- hp_ap.heat_rated_eirs = []
3345
- for i in 0..num_speeds - 1
3346
- hp_ap.heat_rated_eirs << calc_eir_from_cop(cop_max_speed * cops_norm[i], fan_powers_rated[i])
3347
- end
3348
- end
3349
-
3350
2818
  def self.set_gshp_assumptions(heat_pump, weather)
3351
2819
  hp_ap = heat_pump.additional_properties
3352
2820
 
3353
- hp_ap.design_chw = [85.0, weather.design.CoolingDrybulb - 15.0, weather.data.AnnualAvgDrybulb + 10.0].max # Temperature of water entering indoor coil,use 85F as lower bound
2821
+ hp_ap.design_chw = [85.0, weather.design.CoolingDrybulb - 15.0, weather.data.DeepGroundAnnualTemp + 10.0].max # Temperature of water entering indoor coil,use 85F as lower bound
3354
2822
  hp_ap.design_delta_t = 10.0
3355
2823
  hp_ap.fluid_type = Constants.FluidPropyleneGlycol
3356
2824
  hp_ap.frac_glycol = 0.3
3357
2825
  if hp_ap.fluid_type == Constants.FluidWater
3358
- hp_ap.design_hw = [45.0, weather.design.HeatingDrybulb + 35.0, weather.data.AnnualAvgDrybulb - 10.0].max # Temperature of fluid entering indoor coil, use 45F as lower bound for water
2826
+ hp_ap.design_hw = [45.0, weather.design.HeatingDrybulb + 35.0, weather.data.DeepGroundAnnualTemp - 10.0].max # Temperature of fluid entering indoor coil, use 45F as lower bound for water
3359
2827
  else
3360
- hp_ap.design_hw = [35.0, weather.design.HeatingDrybulb + 35.0, weather.data.AnnualAvgDrybulb - 10.0].min # Temperature of fluid entering indoor coil, use 35F as upper bound
2828
+ hp_ap.design_hw = [35.0, weather.design.HeatingDrybulb + 35.0, weather.data.DeepGroundAnnualTemp - 10.0].min # Temperature of fluid entering indoor coil, use 35F as upper bound
3361
2829
  end
3362
2830
  hp_ap.ground_diffusivity = 0.0208
3363
2831
  hp_ap.grout_conductivity = 0.4 # Btu/h-ft-R
@@ -3391,134 +2859,6 @@ class HVAC
3391
2859
  hp_ap.shank_spacing = hp_ap.u_tube_spacing + hp_ap.pipe_od # Distance from center of pipe to center of pipe
3392
2860
  end
3393
2861
 
3394
- def self.calc_mshp_hspf(cop_47, c_d, capacity_ratio, cfm_tons, fan_power_rated, heat_eir_ft_spec, heat_cap_ft_spec)
3395
- n_max = (cop_47.length - 1.0) #-3 # Don't use max speed; FIXME: this is different than calc_mshp_seer?
3396
- n_min = 0
3397
- n_int = (n_min + (n_max - n_min) / 3.0).ceil.to_i
3398
-
3399
- tin = 70.0
3400
- tout_3 = 17.0
3401
- tout_2 = 35.0
3402
- tout_0 = 62.0
3403
-
3404
- eir_H1_2 = calc_eir_from_cop(cop_47[n_max], fan_power_rated[n_max])
3405
- eir_H3_2 = eir_H1_2 * MathTools.biquadratic(tin, tout_3, heat_eir_ft_spec[n_max])
3406
-
3407
- eir_adjv = calc_eir_from_cop(cop_47[n_int], fan_power_rated[n_int])
3408
- eir_H2_v = eir_adjv * MathTools.biquadratic(tin, tout_2, heat_eir_ft_spec[n_int])
3409
-
3410
- eir_H1_1 = calc_eir_from_cop(cop_47[n_min], fan_power_rated[n_min])
3411
- eir_H0_1 = eir_H1_1 * MathTools.biquadratic(tin, tout_0, heat_eir_ft_spec[n_min])
3412
-
3413
- q_H1_2 = capacity_ratio[n_max]
3414
- q_H3_2 = q_H1_2 * MathTools.biquadratic(tin, tout_3, heat_cap_ft_spec[n_max])
3415
-
3416
- q_H2_v = capacity_ratio[n_int] * MathTools.biquadratic(tin, tout_2, heat_cap_ft_spec[n_int])
3417
-
3418
- q_H1_1 = capacity_ratio[n_min]
3419
- q_H0_1 = q_H1_1 * MathTools.biquadratic(tin, tout_0, heat_cap_ft_spec[n_min])
3420
-
3421
- q_H1_2_net = q_H1_2 + fan_power_rated[n_max] * UnitConversions.convert(1, 'W', 'Btu/hr') * cfm_tons[n_max] * capacity_ratio[n_max] / UnitConversions.convert(1, 'ton', 'Btu/hr')
3422
- q_H3_2_net = q_H3_2 + fan_power_rated[n_max] * UnitConversions.convert(1, 'W', 'Btu/hr') * cfm_tons[n_max] * capacity_ratio[n_max] / UnitConversions.convert(1, 'ton', 'Btu/hr')
3423
- q_H2_v_net = q_H2_v + fan_power_rated[n_int] * UnitConversions.convert(1, 'W', 'Btu/hr') * cfm_tons[n_int] * capacity_ratio[n_int] / UnitConversions.convert(1, 'ton', 'Btu/hr')
3424
- q_H1_1_net = q_H1_1 + fan_power_rated[n_min] * UnitConversions.convert(1, 'W', 'Btu/hr') * cfm_tons[n_min] * capacity_ratio[n_min] / UnitConversions.convert(1, 'ton', 'Btu/hr')
3425
- q_H0_1_net = q_H0_1 + fan_power_rated[n_min] * UnitConversions.convert(1, 'W', 'Btu/hr') * cfm_tons[n_min] * capacity_ratio[n_min] / UnitConversions.convert(1, 'ton', 'Btu/hr')
3426
-
3427
- p_H1_2 = q_H1_2 * eir_H1_2 + fan_power_rated[n_max] * UnitConversions.convert(1, 'W', 'Btu/hr') * cfm_tons[n_max] * capacity_ratio[n_max] / UnitConversions.convert(1, 'ton', 'Btu/hr')
3428
- p_H3_2 = q_H3_2 * eir_H3_2 + fan_power_rated[n_max] * UnitConversions.convert(1, 'W', 'Btu/hr') * cfm_tons[n_max] * capacity_ratio[n_max] / UnitConversions.convert(1, 'ton', 'Btu/hr')
3429
- p_H2_v = q_H2_v * eir_H2_v + fan_power_rated[n_int] * UnitConversions.convert(1, 'W', 'Btu/hr') * cfm_tons[n_int] * capacity_ratio[n_int] / UnitConversions.convert(1, 'ton', 'Btu/hr')
3430
- p_H1_1 = q_H1_1 * eir_H1_1 + fan_power_rated[n_min] * UnitConversions.convert(1, 'W', 'Btu/hr') * cfm_tons[n_min] * capacity_ratio[n_min] / UnitConversions.convert(1, 'ton', 'Btu/hr')
3431
- p_H0_1 = q_H0_1 * eir_H0_1 + fan_power_rated[n_min] * UnitConversions.convert(1, 'W', 'Btu/hr') * cfm_tons[n_min] * capacity_ratio[n_min] / UnitConversions.convert(1, 'ton', 'Btu/hr')
3432
-
3433
- q_H35_2 = 0.9 * (q_H3_2_net + 0.6 * (q_H1_2_net - q_H3_2_net))
3434
- p_H35_2 = 0.985 * (p_H3_2 + 0.6 * (p_H1_2 - p_H3_2))
3435
- q_H35_1 = q_H1_1_net + (q_H0_1_net - q_H1_1_net) / (62.0 - 47.0) * (35.0 - 47.0)
3436
- p_H35_1 = p_H1_1 + (p_H0_1 - p_H1_1) / (62.0 - 47.0) * (35.0 - 47.0)
3437
- n_Q = (q_H2_v_net - q_H35_1) / (q_H35_2 - q_H35_1)
3438
- m_Q = (q_H0_1_net - q_H1_1_net) / (62.0 - 47.0) * (1 - n_Q) + n_Q * (q_H35_2 - q_H3_2_net) / (35.0 - 17.0)
3439
- n_E = (p_H2_v - p_H35_1) / (p_H35_2 - p_H35_1)
3440
- m_E = (p_H0_1 - p_H1_1) / (62.0 - 47.0) * (1.0 - n_E) + n_E * (p_H35_2 - p_H3_2) / (35.0 - 17.0)
3441
-
3442
- t_OD = 5.0
3443
- dHR = q_H1_2_net * (65.0 - t_OD) / 60.0
3444
-
3445
- c_T_3_1 = q_H1_1_net
3446
- c_T_3_2 = (q_H0_1_net - q_H1_1_net) / (62.0 - 47.0)
3447
- c_T_3_3 = 0.77 * dHR / (65.0 - t_OD)
3448
- t_3 = (47.0 * c_T_3_2 + 65.0 * c_T_3_3 - c_T_3_1) / (c_T_3_2 + c_T_3_3)
3449
- q_HT3_1 = q_H1_1_net + (q_H0_1_net - q_H1_1_net) / (62.0 - 47.0) * (t_3 - 47.0)
3450
- p_HT3_1 = p_H1_1 + (p_H0_1 - p_H1_1) / (62.0 - 47.0) * (t_3 - 47.0)
3451
- cop_T3_1 = q_HT3_1 / p_HT3_1
3452
-
3453
- c_T_v_1 = q_H2_v_net
3454
- c_T_v_3 = c_T_3_3
3455
- t_v = (35.0 * m_Q + 65.0 * c_T_v_3 - c_T_v_1) / (m_Q + c_T_v_3)
3456
- q_HTv_v = q_H2_v_net + m_Q * (t_v - 35.0)
3457
- p_HTv_v = p_H2_v + m_E * (t_v - 35.0)
3458
- cop_Tv_v = q_HTv_v / p_HTv_v
3459
-
3460
- c_T_4_1 = q_H3_2_net
3461
- c_T_4_2 = (q_H35_2 - q_H3_2_net) / (35.0 - 17.0)
3462
- c_T_4_3 = c_T_v_3
3463
- t_4 = (17.0 * c_T_4_2 + 65.0 * c_T_4_3 - c_T_4_1) / (c_T_4_2 + c_T_4_3)
3464
- q_HT4_2 = q_H3_2_net + (q_H35_2 - q_H3_2_net) / (35.0 - 17.0) * (t_4 - 17.0)
3465
- p_HT4_2 = p_H3_2 + (p_H35_2 - p_H3_2) / (35.0 - 17.0) * (t_4 - 17.0)
3466
- cop_T4_2 = q_HT4_2 / p_HT4_2
3467
-
3468
- d = (t_3**2 - t_4**2) / (t_v**2 - t_4**2)
3469
- b = (cop_T4_2 - cop_T3_1 - d * (cop_T4_2 - cop_Tv_v)) / (t_4 - t_3 - d * (t_4 - t_v))
3470
- c = (cop_T4_2 - cop_T3_1 - b * (t_4 - t_3)) / (t_4**2 - t_3**2)
3471
- a = cop_T4_2 - b * t_4 - c * t_4**2
3472
-
3473
- t_bins = [62.0, 57.0, 52.0, 47.0, 42.0, 37.0, 32.0, 27.0, 22.0, 17.0, 12.0, 7.0, 2.0, -3.0, -8.0]
3474
- frac_hours = [0.132, 0.111, 0.103, 0.093, 0.100, 0.109, 0.126, 0.087, 0.055, 0.036, 0.026, 0.013, 0.006, 0.002, 0.001]
3475
-
3476
- # T_off = hp_min_temp
3477
- t_off = 10.0
3478
- t_on = t_off + 4.0
3479
- etot = 0
3480
- bLtot = 0
3481
-
3482
- for i in 0..14
3483
- bL = ((65.0 - t_bins[i]) / (65.0 - t_OD)) * 0.77 * dHR
3484
-
3485
- q_1 = q_H1_1_net + (q_H0_1_net - q_H1_1_net) / (62.0 - 47.0) * (t_bins[i] - 47.0)
3486
- p_1 = p_H1_1 + (p_H0_1 - p_H1_1) / (62.0 - 47.0) * (t_bins[i] - 47.0)
3487
-
3488
- if (t_bins[i] <= 17.0) || (t_bins[i] >= 45.0)
3489
- q_2 = q_H3_2_net + (q_H1_2_net - q_H3_2_net) * (t_bins[i] - 17.0) / (47.0 - 17.0)
3490
- p_2 = p_H3_2 + (p_H1_2 - p_H3_2) * (t_bins[i] - 17.0) / (47.0 - 17.0)
3491
- else
3492
- q_2 = q_H3_2_net + (q_H35_2 - q_H3_2_net) * (t_bins[i] - 17) / (35.0 - 17.0)
3493
- p_2 = p_H3_2 + (p_H35_2 - p_H3_2) * (t_bins[i] - 17.0) / (35.0 - 17.0)
3494
- end
3495
-
3496
- if t_bins[i] <= t_off
3497
- delta = 0
3498
- elsif t_bins[i] >= t_on
3499
- delta = 1.0
3500
- else
3501
- delta = 0.5
3502
- end
3503
-
3504
- if bL <= q_1
3505
- x_1 = bL / q_1
3506
- e_Tj_n = delta * x_1 * p_1 * frac_hours[i] / (1.0 - c_d * (1.0 - x_1))
3507
- elsif (q_1 < bL) && (bL <= q_2)
3508
- cop_T_j = a + b * t_bins[i] + c * t_bins[i]**2
3509
- e_Tj_n = delta * frac_hours[i] * bL / cop_T_j + (1.0 - delta) * bL * (frac_hours[i])
3510
- else
3511
- e_Tj_n = delta * frac_hours[i] * p_2 + frac_hours[i] * (bL - delta * q_2)
3512
- end
3513
-
3514
- bLtot += frac_hours[i] * bL
3515
- etot += e_Tj_n
3516
- end
3517
-
3518
- hspf = bLtot / UnitConversions.convert(etot, 'Btu/hr', 'W')
3519
- return hspf
3520
- end
3521
-
3522
2862
  def self.calc_sequential_load_fractions(load_fraction, remaining_fraction, availability_days)
3523
2863
  # Returns the EnergyPlus sequential load fractions for every day of the year
3524
2864
  if remaining_fraction > 0
@@ -3605,24 +2945,42 @@ class HVAC
3605
2945
  if not heat_pump.backup_heating_switchover_temp.nil?
3606
2946
  hp_ap.hp_min_temp = heat_pump.backup_heating_switchover_temp
3607
2947
  hp_ap.supp_max_temp = heat_pump.backup_heating_switchover_temp
3608
-
3609
- if heat_pump.backup_type == HPXML::HeatPumpBackupTypeIntegrated
3610
- hp_backup_fuel = heat_pump.backup_heating_fuel
3611
- elsif not heat_pump.backup_system.nil?
3612
- hp_backup_fuel = heat_pump.backup_system.heating_system_fuel
3613
- end
3614
- if (hp_backup_fuel == HPXML::FuelTypeElectricity) && (not runner.nil?)
3615
- runner.registerError('Switchover temperature should not be used for a heat pump with electric backup; use compressor lockout temperature instead.')
3616
- end
3617
2948
  else
3618
2949
  hp_ap.hp_min_temp = heat_pump.compressor_lockout_temp
3619
2950
  hp_ap.supp_max_temp = heat_pump.backup_heating_lockout_temp
3620
2951
  end
2952
+
2953
+ # Error-checking
2954
+ # Can't do this in Schematron because temperatures can be defaulted
2955
+ if heat_pump.backup_type == HPXML::HeatPumpBackupTypeIntegrated
2956
+ hp_backup_fuel = heat_pump.backup_heating_fuel
2957
+ elsif not heat_pump.backup_system.nil?
2958
+ hp_backup_fuel = heat_pump.backup_system.heating_system_fuel
2959
+ end
2960
+ if (hp_backup_fuel == HPXML::FuelTypeElectricity) && (not runner.nil?)
2961
+ if (not hp_ap.hp_min_temp.nil?) && (not hp_ap.supp_max_temp.nil?) && ((hp_ap.hp_min_temp - hp_ap.supp_max_temp).abs < 5)
2962
+ if not heat_pump.backup_heating_switchover_temp.nil?
2963
+ runner.registerError('Switchover temperature should only be used for a heat pump with fossil fuel backup; use compressor lockout temperature instead.')
2964
+ else
2965
+ runner.registerError('Similar compressor/backup lockout temperatures should only be used for a heat pump with fossil fuel backup.')
2966
+ end
2967
+ end
2968
+ end
2969
+ end
2970
+
2971
+ def self.get_default_duct_fraction_outside_conditioned_space(ncfl_ag)
2972
+ # Equation based on ASHRAE 152
2973
+ # https://www.energy.gov/eere/buildings/downloads/ashrae-standard-152-spreadsheet
2974
+ f_out = (ncfl_ag <= 1) ? 1.0 : 0.75
2975
+ return f_out
3621
2976
  end
3622
2977
 
3623
2978
  def self.get_default_duct_surface_area(duct_type, ncfl_ag, cfa_served, n_returns)
2979
+ # Equations based on ASHRAE 152
2980
+ # https://www.energy.gov/eere/buildings/downloads/ashrae-standard-152-spreadsheet
2981
+
3624
2982
  # Fraction of primary ducts (ducts outside conditioned space)
3625
- f_out = (ncfl_ag <= 1) ? 1.0 : 0.75
2983
+ f_out = get_default_duct_fraction_outside_conditioned_space(ncfl_ag)
3626
2984
 
3627
2985
  if duct_type == HPXML::DuctTypeSupply
3628
2986
  primary_duct_area = 0.27 * cfa_served * f_out
@@ -3636,7 +2994,7 @@ class HVAC
3636
2994
  return primary_duct_area, secondary_duct_area
3637
2995
  end
3638
2996
 
3639
- def self.get_default_duct_locations(hpxml)
2997
+ def self.get_default_duct_locations(hpxml_bldg)
3640
2998
  primary_duct_location_hierarchy = [HPXML::LocationBasementConditioned,
3641
2999
  HPXML::LocationBasementUnconditioned,
3642
3000
  HPXML::LocationCrawlspaceConditioned,
@@ -3648,12 +3006,12 @@ class HVAC
3648
3006
 
3649
3007
  primary_duct_location = nil
3650
3008
  primary_duct_location_hierarchy.each do |location|
3651
- if hpxml.has_location(location)
3009
+ if hpxml_bldg.has_location(location)
3652
3010
  primary_duct_location = location
3653
3011
  break
3654
3012
  end
3655
3013
  end
3656
- secondary_duct_location = HPXML::LocationLivingSpace
3014
+ secondary_duct_location = HPXML::LocationConditionedSpace
3657
3015
 
3658
3016
  return primary_duct_location, secondary_duct_location
3659
3017
  end
@@ -3682,21 +3040,7 @@ class HVAC
3682
3040
  return qgr_values, p_values, ff_chg_values
3683
3041
  end
3684
3042
 
3685
- def self.get_airflow_fault_cooling_coeff()
3686
- # Cutler curve coefficients for single speed
3687
- cool_cap_fflow_spec = [0.718664047, 0.41797409, -0.136638137]
3688
- cool_eir_fflow_spec = [1.143487507, -0.13943972, -0.004047787]
3689
- return cool_cap_fflow_spec, cool_eir_fflow_spec
3690
- end
3691
-
3692
- def self.get_airflow_fault_heating_coeff()
3693
- # Cutler curve coefficients for single speed
3694
- heat_cap_fflow_spec = [0.694045465, 0.474207981, -0.168253446]
3695
- heat_eir_fflow_spec = [2.185418751, -1.942827919, 0.757409168]
3696
- return heat_cap_fflow_spec, heat_eir_fflow_spec
3697
- end
3698
-
3699
- def self.add_install_quality_calculations(fault_program, tin_sensor, tout_sensor, airflow_rated_defect_ratio, clg_or_htg_coil, model, f_chg, obj_name, mode, defect_ratio)
3043
+ def self.add_install_quality_calculations(fault_program, tin_sensor, tout_sensor, airflow_rated_defect_ratio, clg_or_htg_coil, model, f_chg, obj_name, mode, defect_ratio, hvac_ap)
3700
3044
  if mode == :clg
3701
3045
  if clg_or_htg_coil.is_a? OpenStudio::Model::CoilCoolingDXSingleSpeed
3702
3046
  num_speeds = 1
@@ -3704,8 +3048,13 @@ class HVAC
3704
3048
  eir_pow_fff_curves = [clg_or_htg_coil.energyInputRatioFunctionOfFlowFractionCurve.to_CurveQuadratic.get]
3705
3049
  elsif clg_or_htg_coil.is_a? OpenStudio::Model::CoilCoolingDXMultiSpeed
3706
3050
  num_speeds = clg_or_htg_coil.stages.size
3707
- cap_fff_curves = clg_or_htg_coil.stages.map { |stage| stage.totalCoolingCapacityFunctionofFlowFractionCurve.to_CurveQuadratic.get }
3708
- eir_pow_fff_curves = clg_or_htg_coil.stages.map { |stage| stage.energyInputRatioFunctionofFlowFractionCurve.to_CurveQuadratic.get }
3051
+ if clg_or_htg_coil.stages[0].totalCoolingCapacityFunctionofFlowFractionCurve.to_CurveQuadratic.is_initialized
3052
+ cap_fff_curves = clg_or_htg_coil.stages.map { |stage| stage.totalCoolingCapacityFunctionofFlowFractionCurve.to_CurveQuadratic.get }
3053
+ eir_pow_fff_curves = clg_or_htg_coil.stages.map { |stage| stage.energyInputRatioFunctionofFlowFractionCurve.to_CurveQuadratic.get }
3054
+ else
3055
+ cap_fff_curves = clg_or_htg_coil.stages.map { |stage| stage.totalCoolingCapacityFunctionofFlowFractionCurve.to_TableLookup.get }
3056
+ eir_pow_fff_curves = clg_or_htg_coil.stages.map { |stage| stage.energyInputRatioFunctionofFlowFractionCurve.to_TableLookup.get }
3057
+ end
3709
3058
  elsif clg_or_htg_coil.is_a? OpenStudio::Model::CoilCoolingWaterToAirHeatPumpEquationFit
3710
3059
  num_speeds = 1
3711
3060
  cap_fff_curves = [clg_or_htg_coil.totalCoolingCapacityCurve.to_CurveQuadLinear.get] # quadlinear curve, only forth term is for airflow
@@ -3730,8 +3079,13 @@ class HVAC
3730
3079
  eir_pow_fff_curves = [clg_or_htg_coil.energyInputRatioFunctionofFlowFractionCurve.to_CurveQuadratic.get]
3731
3080
  elsif clg_or_htg_coil.is_a? OpenStudio::Model::CoilHeatingDXMultiSpeed
3732
3081
  num_speeds = clg_or_htg_coil.stages.size
3733
- cap_fff_curves = clg_or_htg_coil.stages.map { |stage| stage.heatingCapacityFunctionofFlowFractionCurve.to_CurveQuadratic.get }
3734
- eir_pow_fff_curves = clg_or_htg_coil.stages.map { |stage| stage.energyInputRatioFunctionofFlowFractionCurve.to_CurveQuadratic.get }
3082
+ if clg_or_htg_coil.stages[0].heatingCapacityFunctionofFlowFractionCurve.to_CurveQuadratic.is_initialized
3083
+ cap_fff_curves = clg_or_htg_coil.stages.map { |stage| stage.heatingCapacityFunctionofFlowFractionCurve.to_CurveQuadratic.get }
3084
+ eir_pow_fff_curves = clg_or_htg_coil.stages.map { |stage| stage.energyInputRatioFunctionofFlowFractionCurve.to_CurveQuadratic.get }
3085
+ else
3086
+ cap_fff_curves = clg_or_htg_coil.stages.map { |stage| stage.heatingCapacityFunctionofFlowFractionCurve.to_TableLookup.get }
3087
+ eir_pow_fff_curves = clg_or_htg_coil.stages.map { |stage| stage.energyInputRatioFunctionofFlowFractionCurve.to_TableLookup.get }
3088
+ end
3735
3089
  elsif clg_or_htg_coil.is_a? OpenStudio::Model::CoilHeatingWaterToAirHeatPumpEquationFit
3736
3090
  num_speeds = 1
3737
3091
  cap_fff_curves = [clg_or_htg_coil.heatingCapacityCurve.to_CurveQuadLinear.get] # quadlinear curve, only forth term is for airflow
@@ -3753,20 +3107,20 @@ class HVAC
3753
3107
 
3754
3108
  # Apply Cutler curve airflow coefficients to later equations
3755
3109
  if mode == :clg
3756
- cap_fflow_spec, eir_fflow_spec = get_airflow_fault_cooling_coeff()
3110
+ cap_fflow_spec, eir_fflow_spec = get_cool_cap_eir_fflow_spec(HPXML::HVACCompressorTypeSingleStage)
3757
3111
  qgr_values, p_values, ff_chg_values = get_charge_fault_cooling_coeff(f_chg)
3758
3112
  suffix = 'clg'
3759
3113
  elsif mode == :htg
3760
- cap_fflow_spec, eir_fflow_spec = get_airflow_fault_heating_coeff()
3114
+ cap_fflow_spec, eir_fflow_spec = get_heat_cap_eir_fflow_spec(HPXML::HVACCompressorTypeSingleStage)
3761
3115
  qgr_values, p_values, ff_chg_values = get_charge_fault_heating_coeff(f_chg)
3762
3116
  suffix = 'htg'
3763
3117
  end
3764
- fault_program.addLine("Set a1_AF_Qgr_#{suffix} = #{cap_fflow_spec[0]}")
3765
- fault_program.addLine("Set a2_AF_Qgr_#{suffix} = #{cap_fflow_spec[1]}")
3766
- fault_program.addLine("Set a3_AF_Qgr_#{suffix} = #{cap_fflow_spec[2]}")
3767
- fault_program.addLine("Set a1_AF_EIR_#{suffix} = #{eir_fflow_spec[0]}")
3768
- fault_program.addLine("Set a2_AF_EIR_#{suffix} = #{eir_fflow_spec[1]}")
3769
- fault_program.addLine("Set a3_AF_EIR_#{suffix} = #{eir_fflow_spec[2]}")
3118
+ fault_program.addLine("Set a1_AF_Qgr_#{suffix} = #{cap_fflow_spec[0][0]}")
3119
+ fault_program.addLine("Set a2_AF_Qgr_#{suffix} = #{cap_fflow_spec[0][1]}")
3120
+ fault_program.addLine("Set a3_AF_Qgr_#{suffix} = #{cap_fflow_spec[0][2]}")
3121
+ fault_program.addLine("Set a1_AF_EIR_#{suffix} = #{eir_fflow_spec[0][0]}")
3122
+ fault_program.addLine("Set a2_AF_EIR_#{suffix} = #{eir_fflow_spec[0][1]}")
3123
+ fault_program.addLine("Set a3_AF_EIR_#{suffix} = #{eir_fflow_spec[0][2]}")
3770
3124
 
3771
3125
  # charge fault coefficients
3772
3126
  fault_program.addLine("Set a1_CH_Qgr_#{suffix} = #{qgr_values[0]}")
@@ -3821,12 +3175,14 @@ class HVAC
3821
3175
  fault_program.addLine("Set EIR_IQ_adj_#{suffix} = EIR_Cutler_Curve_After_#{suffix} / EIR_Cutler_Curve_Pre_#{suffix}")
3822
3176
  # NOTE: heat pump (cooling) curves don't exhibit expected trends at extreme faults;
3823
3177
  if (not clg_or_htg_coil.is_a? OpenStudio::Model::CoilCoolingWaterToAirHeatPumpEquationFit) && (not clg_or_htg_coil.is_a? OpenStudio::Model::CoilHeatingWaterToAirHeatPumpEquationFit)
3824
- fault_program.addLine("Set CAP_c1_#{suffix} = #{cap_fff_curve.coefficient1Constant}")
3825
- fault_program.addLine("Set CAP_c2_#{suffix} = #{cap_fff_curve.coefficient2x}")
3826
- fault_program.addLine("Set CAP_c3_#{suffix} = #{cap_fff_curve.coefficient3xPOW2}")
3827
- fault_program.addLine("Set EIR_c1_#{suffix} = #{eir_pow_fff_curve.coefficient1Constant}")
3828
- fault_program.addLine("Set EIR_c2_#{suffix} = #{eir_pow_fff_curve.coefficient2x}")
3829
- fault_program.addLine("Set EIR_c3_#{suffix} = #{eir_pow_fff_curve.coefficient3xPOW2}")
3178
+ cap_fff_specs_coeff = (mode == :clg) ? hvac_ap.cool_cap_fflow_spec[speed] : hvac_ap.heat_cap_fflow_spec[speed]
3179
+ eir_fff_specs_coeff = (mode == :clg) ? hvac_ap.cool_eir_fflow_spec[speed] : hvac_ap.heat_eir_fflow_spec[speed]
3180
+ fault_program.addLine("Set CAP_c1_#{suffix} = #{cap_fff_specs_coeff[0]}")
3181
+ fault_program.addLine("Set CAP_c2_#{suffix} = #{cap_fff_specs_coeff[1]}")
3182
+ fault_program.addLine("Set CAP_c3_#{suffix} = #{cap_fff_specs_coeff[2]}")
3183
+ fault_program.addLine("Set EIR_c1_#{suffix} = #{eir_fff_specs_coeff[0]}")
3184
+ fault_program.addLine("Set EIR_c2_#{suffix} = #{eir_fff_specs_coeff[1]}")
3185
+ fault_program.addLine("Set EIR_c3_#{suffix} = #{eir_fff_specs_coeff[2]}")
3830
3186
  fault_program.addLine("Set cap_curve_v_pre_#{suffix} = (CAP_c1_#{suffix}) + ((CAP_c2_#{suffix})*FF_AF_nodef_#{suffix}) + ((CAP_c3_#{suffix})*FF_AF_nodef_#{suffix}*FF_AF_nodef_#{suffix})")
3831
3187
  fault_program.addLine("Set eir_curve_v_pre_#{suffix} = (EIR_c1_#{suffix}) + ((EIR_c2_#{suffix})*FF_AF_nodef_#{suffix}) + ((EIR_c3_#{suffix})*FF_AF_nodef_#{suffix}*FF_AF_nodef_#{suffix})")
3832
3188
  fault_program.addLine("Set #{cap_fff_act.name} = cap_curve_v_pre_#{suffix} * CAP_IQ_adj_#{suffix}")
@@ -3860,9 +3216,11 @@ class HVAC
3860
3216
  if not cooling_system.nil?
3861
3217
  charge_defect_ratio = cooling_system.charge_defect_ratio
3862
3218
  cool_airflow_defect_ratio = cooling_system.airflow_defect_ratio
3219
+ clg_ap = cooling_system.additional_properties
3863
3220
  end
3864
3221
  if not heating_system.nil?
3865
3222
  heat_airflow_defect_ratio = heating_system.airflow_defect_ratio
3223
+ htg_ap = heating_system.additional_properties
3866
3224
  end
3867
3225
  return if (charge_defect_ratio.to_f.abs < 0.001) && (cool_airflow_defect_ratio.to_f.abs < 0.001) && (heat_airflow_defect_ratio.to_f.abs < 0.001)
3868
3226
 
@@ -3907,11 +3265,11 @@ class HVAC
3907
3265
  fault_program.addLine("Set F_CH = #{f_chg.round(3)}")
3908
3266
 
3909
3267
  if not cool_airflow_rated_defect_ratio.empty?
3910
- add_install_quality_calculations(fault_program, tin_sensor, tout_sensor, cool_airflow_rated_defect_ratio, clg_coil, model, f_chg, obj_name, :clg, cool_airflow_defect_ratio)
3268
+ add_install_quality_calculations(fault_program, tin_sensor, tout_sensor, cool_airflow_rated_defect_ratio, clg_coil, model, f_chg, obj_name, :clg, cool_airflow_defect_ratio, clg_ap)
3911
3269
  end
3912
3270
 
3913
3271
  if not heat_airflow_rated_defect_ratio.empty?
3914
- add_install_quality_calculations(fault_program, tin_sensor, tout_sensor, heat_airflow_rated_defect_ratio, htg_coil, model, f_chg, obj_name, :htg, heat_airflow_defect_ratio)
3272
+ add_install_quality_calculations(fault_program, tin_sensor, tout_sensor, heat_airflow_rated_defect_ratio, htg_coil, model, f_chg, obj_name, :htg, heat_airflow_defect_ratio, htg_ap)
3915
3273
  end
3916
3274
  program_calling_manager = OpenStudio::Model::EnergyManagementSystemProgramCallingManager.new(model)
3917
3275
  program_calling_manager.setName("#{obj_name} program manager")
@@ -3923,13 +3281,13 @@ class HVAC
3923
3281
  return 30.0 # W/ton, per ANSI/RESNET/ICC 301-2019 Section 4.4.5 (closed loop)
3924
3282
  end
3925
3283
 
3926
- def self.apply_shared_systems(hpxml)
3927
- applied_clg = apply_shared_cooling_systems(hpxml)
3928
- applied_htg = apply_shared_heating_systems(hpxml)
3284
+ def self.apply_shared_systems(hpxml_bldg)
3285
+ applied_clg = apply_shared_cooling_systems(hpxml_bldg)
3286
+ applied_htg = apply_shared_heating_systems(hpxml_bldg)
3929
3287
  return unless (applied_clg || applied_htg)
3930
3288
 
3931
3289
  # Remove WLHP if not serving heating nor cooling
3932
- hpxml.heat_pumps.each do |hp|
3290
+ hpxml_bldg.heat_pumps.each do |hp|
3933
3291
  next unless hp.heat_pump_type == HPXML::HVACTypeHeatPumpWaterLoopToAir
3934
3292
  next if hp.fraction_heat_load_served > 0
3935
3293
  next if hp.fraction_cool_load_served > 0
@@ -3938,9 +3296,9 @@ class HVAC
3938
3296
  end
3939
3297
 
3940
3298
  # Remove any orphaned HVAC distributions
3941
- hpxml.hvac_distributions.each do |hvac_distribution|
3299
+ hpxml_bldg.hvac_distributions.each do |hvac_distribution|
3942
3300
  hvac_systems = []
3943
- hpxml.hvac_systems.each do |hvac_system|
3301
+ hpxml_bldg.hvac_systems.each do |hvac_system|
3944
3302
  next if hvac_system.distribution_system_idref.nil?
3945
3303
  next unless hvac_system.distribution_system_idref == hvac_distribution.id
3946
3304
 
@@ -3952,9 +3310,9 @@ class HVAC
3952
3310
  end
3953
3311
  end
3954
3312
 
3955
- def self.apply_shared_cooling_systems(hpxml)
3313
+ def self.apply_shared_cooling_systems(hpxml_bldg)
3956
3314
  applied = false
3957
- hpxml.cooling_systems.each do |cooling_system|
3315
+ hpxml_bldg.cooling_systems.each do |cooling_system|
3958
3316
  next unless cooling_system.is_shared_system
3959
3317
 
3960
3318
  applied = true
@@ -3973,7 +3331,7 @@ class HVAC
3973
3331
  chiller_input = UnitConversions.convert(cooling_system.cooling_efficiency_kw_per_ton * UnitConversions.convert(cap, 'Btu/hr', 'ton'), 'kW', 'W')
3974
3332
  if distribution_type == HPXML::HVACDistributionTypeHydronic
3975
3333
  if distribution_system.hydronic_type == HPXML::HydronicTypeWaterLoop
3976
- wlhp = hpxml.heat_pumps.find { |hp| hp.heat_pump_type == HPXML::HVACTypeHeatPumpWaterLoopToAir }
3334
+ wlhp = hpxml_bldg.heat_pumps.find { |hp| hp.heat_pump_type == HPXML::HVACTypeHeatPumpWaterLoopToAir }
3977
3335
  aux_dweq = wlhp.cooling_capacity / wlhp.cooling_efficiency_eer
3978
3336
  else
3979
3337
  aux_dweq = 0.0
@@ -3991,7 +3349,7 @@ class HVAC
3991
3349
  # Cooling tower w/ water loop heat pump
3992
3350
  if distribution_type == HPXML::HVACDistributionTypeHydronic
3993
3351
  if distribution_system.hydronic_type == HPXML::HydronicTypeWaterLoop
3994
- wlhp = hpxml.heat_pumps.find { |hp| hp.heat_pump_type == HPXML::HVACTypeHeatPumpWaterLoopToAir }
3352
+ wlhp = hpxml_bldg.heat_pumps.find { |hp| hp.heat_pump_type == HPXML::HVACTypeHeatPumpWaterLoopToAir }
3995
3353
  wlhp_cap = wlhp.cooling_capacity
3996
3354
  wlhp_input = wlhp_cap / wlhp.cooling_efficiency_eer
3997
3355
  end
@@ -4026,45 +3384,45 @@ class HVAC
4026
3384
  wlhp.fraction_heat_load_served = 0.0
4027
3385
  else
4028
3386
  # Assign DSE=1
4029
- hpxml.hvac_distributions.add(id: "#{cooling_system.id}AirDistributionSystem",
4030
- distribution_system_type: HPXML::HVACDistributionTypeDSE,
4031
- annual_cooling_dse: 1.0,
4032
- annual_heating_dse: 1.0)
4033
- cooling_system.distribution_system_idref = hpxml.hvac_distributions[-1].id
3387
+ hpxml_bldg.hvac_distributions.add(id: "#{cooling_system.id}AirDistributionSystem",
3388
+ distribution_system_type: HPXML::HVACDistributionTypeDSE,
3389
+ annual_cooling_dse: 1.0,
3390
+ annual_heating_dse: 1.0)
3391
+ cooling_system.distribution_system_idref = hpxml_bldg.hvac_distributions[-1].id
4034
3392
  end
4035
3393
  elsif (distribution_type == HPXML::HVACDistributionTypeAir) && (distribution_system.air_type == HPXML::AirTypeFanCoil)
4036
3394
  # Convert "fan coil" air distribution system to "regular velocity"
4037
3395
  if distribution_system.hvac_systems.size > 1
4038
3396
  # Has attached heating system, so create a copy specifically for the cooling system
4039
- hpxml.hvac_distributions.add(id: "#{distribution_system.id}_#{cooling_system.id}",
4040
- distribution_system_type: distribution_system.distribution_system_type,
4041
- air_type: distribution_system.air_type,
4042
- number_of_return_registers: distribution_system.number_of_return_registers,
4043
- conditioned_floor_area_served: distribution_system.conditioned_floor_area_served)
3397
+ hpxml_bldg.hvac_distributions.add(id: "#{distribution_system.id}_#{cooling_system.id}",
3398
+ distribution_system_type: distribution_system.distribution_system_type,
3399
+ air_type: distribution_system.air_type,
3400
+ number_of_return_registers: distribution_system.number_of_return_registers,
3401
+ conditioned_floor_area_served: distribution_system.conditioned_floor_area_served)
4044
3402
  distribution_system.duct_leakage_measurements.each do |lm|
4045
- hpxml.hvac_distributions[-1].duct_leakage_measurements << lm.dup
3403
+ hpxml_bldg.hvac_distributions[-1].duct_leakage_measurements << lm.dup
4046
3404
  end
4047
3405
  distribution_system.ducts.each do |d|
4048
- hpxml.hvac_distributions[-1].ducts << d.dup
3406
+ hpxml_bldg.hvac_distributions[-1].ducts << d.dup
4049
3407
  end
4050
- cooling_system.distribution_system_idref = hpxml.hvac_distributions[-1].id
3408
+ cooling_system.distribution_system_idref = hpxml_bldg.hvac_distributions[-1].id
4051
3409
  end
4052
- hpxml.hvac_distributions[-1].air_type = HPXML::AirTypeRegularVelocity
4053
- if hpxml.hvac_distributions[-1].duct_leakage_measurements.select { |lm| (lm.duct_type == HPXML::DuctTypeSupply) && (lm.duct_leakage_total_or_to_outside == HPXML::DuctLeakageToOutside) }.size == 0
3410
+ hpxml_bldg.hvac_distributions[-1].air_type = HPXML::AirTypeRegularVelocity
3411
+ if hpxml_bldg.hvac_distributions[-1].duct_leakage_measurements.select { |lm| (lm.duct_type == HPXML::DuctTypeSupply) && (lm.duct_leakage_total_or_to_outside == HPXML::DuctLeakageToOutside) }.size == 0
4054
3412
  # Assign zero supply leakage
4055
- hpxml.hvac_distributions[-1].duct_leakage_measurements.add(duct_type: HPXML::DuctTypeSupply,
4056
- duct_leakage_units: HPXML::UnitsCFM25,
4057
- duct_leakage_value: 0,
4058
- duct_leakage_total_or_to_outside: HPXML::DuctLeakageToOutside)
3413
+ hpxml_bldg.hvac_distributions[-1].duct_leakage_measurements.add(duct_type: HPXML::DuctTypeSupply,
3414
+ duct_leakage_units: HPXML::UnitsCFM25,
3415
+ duct_leakage_value: 0,
3416
+ duct_leakage_total_or_to_outside: HPXML::DuctLeakageToOutside)
4059
3417
  end
4060
- if hpxml.hvac_distributions[-1].duct_leakage_measurements.select { |lm| (lm.duct_type == HPXML::DuctTypeReturn) && (lm.duct_leakage_total_or_to_outside == HPXML::DuctLeakageToOutside) }.size == 0
3418
+ if hpxml_bldg.hvac_distributions[-1].duct_leakage_measurements.select { |lm| (lm.duct_type == HPXML::DuctTypeReturn) && (lm.duct_leakage_total_or_to_outside == HPXML::DuctLeakageToOutside) }.size == 0
4061
3419
  # Assign zero return leakage
4062
- hpxml.hvac_distributions[-1].duct_leakage_measurements.add(duct_type: HPXML::DuctTypeReturn,
4063
- duct_leakage_units: HPXML::UnitsCFM25,
4064
- duct_leakage_value: 0,
4065
- duct_leakage_total_or_to_outside: HPXML::DuctLeakageToOutside)
3420
+ hpxml_bldg.hvac_distributions[-1].duct_leakage_measurements.add(duct_type: HPXML::DuctTypeReturn,
3421
+ duct_leakage_units: HPXML::UnitsCFM25,
3422
+ duct_leakage_value: 0,
3423
+ duct_leakage_total_or_to_outside: HPXML::DuctLeakageToOutside)
4066
3424
  end
4067
- hpxml.hvac_distributions[-1].ducts.each do |d|
3425
+ hpxml_bldg.hvac_distributions[-1].ducts.each do |d|
4068
3426
  d.id = "#{d.id}_#{cooling_system.id}"
4069
3427
  end
4070
3428
  end
@@ -4073,9 +3431,9 @@ class HVAC
4073
3431
  return applied
4074
3432
  end
4075
3433
 
4076
- def self.apply_shared_heating_systems(hpxml)
3434
+ def self.apply_shared_heating_systems(hpxml_bldg)
4077
3435
  applied = false
4078
- hpxml.heating_systems.each do |heating_system|
3436
+ hpxml_bldg.heating_systems.each do |heating_system|
4079
3437
  next unless heating_system.is_shared_system
4080
3438
 
4081
3439
  applied = true
@@ -4092,7 +3450,7 @@ class HVAC
4092
3450
 
4093
3451
  # Heat pump
4094
3452
  # If this approach is ever removed, also remove code in HVACSizing.apply_hvac_loads()
4095
- wlhp = hpxml.heat_pumps.find { |hp| hp.heat_pump_type == HPXML::HVACTypeHeatPumpWaterLoopToAir }
3453
+ wlhp = hpxml_bldg.heat_pumps.find { |hp| hp.heat_pump_type == HPXML::HVACTypeHeatPumpWaterLoopToAir }
4096
3454
  wlhp.fraction_heat_load_served = fraction_heat_load_served * (1.0 / wlhp.heating_efficiency_cop)
4097
3455
  wlhp.fraction_cool_load_served = 0.0
4098
3456
 
@@ -4106,31 +3464,13 @@ class HVAC
4106
3464
  return applied
4107
3465
  end
4108
3466
 
4109
- def self.set_num_speeds(hvac_system)
4110
- hvac_ap = hvac_system.additional_properties
4111
-
4112
- if hvac_system.is_a?(HPXML::CoolingSystem) && ([HPXML::HVACTypeRoomAirConditioner, HPXML::HVACTypePTAC].include? hvac_system.cooling_system_type)
4113
- hvac_ap.num_speeds = 1
4114
- elsif (hvac_system.is_a?(HPXML::CoolingSystem) && (hvac_system.cooling_system_type == HPXML::HVACTypeMiniSplitAirConditioner)) ||
4115
- (hvac_system.is_a?(HPXML::HeatPump) && (hvac_system.heat_pump_type == HPXML::HVACTypeHeatPumpMiniSplit))
4116
- hvac_ap.speed_indices = [1, 3, 5, 9] # Speeds we model
4117
- hvac_ap.num_speeds = hvac_ap.speed_indices.size
4118
- elsif hvac_system.compressor_type == HPXML::HVACCompressorTypeSingleStage
4119
- hvac_ap.num_speeds = 1
4120
- elsif hvac_system.compressor_type == HPXML::HVACCompressorTypeTwoStage
4121
- hvac_ap.num_speeds = 2
4122
- elsif hvac_system.compressor_type == HPXML::HVACCompressorTypeVariableSpeed
4123
- hvac_ap.num_speeds = 4
4124
- end
4125
- end
4126
-
4127
- def self.calc_rated_airflow(capacity, rated_cfm_per_ton, capacity_ratio)
4128
- return UnitConversions.convert(capacity, 'Btu/hr', 'ton') * UnitConversions.convert(rated_cfm_per_ton, 'cfm', 'm^3/s') * capacity_ratio
3467
+ def self.calc_rated_airflow(capacity, rated_cfm_per_ton)
3468
+ return UnitConversions.convert(capacity, 'Btu/hr', 'ton') * UnitConversions.convert(rated_cfm_per_ton, 'cfm', 'm^3/s')
4129
3469
  end
4130
3470
 
4131
- def self.is_attached_heating_and_cooling_systems(hpxml, heating_system, cooling_system)
3471
+ def self.is_attached_heating_and_cooling_systems(hpxml_bldg, heating_system, cooling_system)
4132
3472
  # Now only allows furnace+AC
4133
- if not ((hpxml.heating_systems.include? heating_system) && (hpxml.cooling_systems.include? cooling_system))
3473
+ if not ((hpxml_bldg.heating_systems.include? heating_system) && (hpxml_bldg.cooling_systems.include? cooling_system))
4134
3474
  return false
4135
3475
  end
4136
3476
  if not (heating_system.heating_system_type == HPXML::HVACTypeFurnace && cooling_system.cooling_system_type == HPXML::HVACTypeCentralAirConditioner)
@@ -4140,23 +3480,23 @@ class HVAC
4140
3480
  return true
4141
3481
  end
4142
3482
 
4143
- def self.get_hpxml_hvac_systems(hpxml)
3483
+ def self.get_hpxml_hvac_systems(hpxml_bldg)
4144
3484
  # Returns a list of heating/cooling systems, incorporating whether
4145
3485
  # multiple systems are connected to the same distribution system
4146
3486
  # (e.g., a furnace + central air conditioner w/ the same ducts).
4147
3487
  hvac_systems = []
4148
3488
 
4149
- hpxml.cooling_systems.each do |cooling_system|
3489
+ hpxml_bldg.cooling_systems.each do |cooling_system|
4150
3490
  heating_system = nil
4151
- if is_attached_heating_and_cooling_systems(hpxml, cooling_system.attached_heating_system, cooling_system)
3491
+ if is_attached_heating_and_cooling_systems(hpxml_bldg, cooling_system.attached_heating_system, cooling_system)
4152
3492
  heating_system = cooling_system.attached_heating_system
4153
3493
  end
4154
3494
  hvac_systems << { cooling: cooling_system,
4155
3495
  heating: heating_system }
4156
3496
  end
4157
3497
 
4158
- hpxml.heating_systems.each do |heating_system|
4159
- if is_attached_heating_and_cooling_systems(hpxml, heating_system, heating_system.attached_cooling_system)
3498
+ hpxml_bldg.heating_systems.each do |heating_system|
3499
+ if is_attached_heating_and_cooling_systems(hpxml_bldg, heating_system, heating_system.attached_cooling_system)
4160
3500
  next # Already processed with cooling
4161
3501
  end
4162
3502
 
@@ -4167,7 +3507,7 @@ class HVAC
4167
3507
  # Heat pump with backup system must be sorted last so that the last two
4168
3508
  # HVAC systems in the EnergyPlus EquipmentList are 1) the heat pump and
4169
3509
  # 2) the heat pump backup system.
4170
- hpxml.heat_pumps.sort_by { |hp| hp.backup_system_idref.to_s }.each do |heat_pump|
3510
+ hpxml_bldg.heat_pumps.sort_by { |hp| hp.backup_system_idref.to_s }.each do |heat_pump|
4171
3511
  hvac_systems << { cooling: heat_pump,
4172
3512
  heating: heat_pump }
4173
3513
  end
@@ -4175,30 +3515,85 @@ class HVAC
4175
3515
  return hvac_systems
4176
3516
  end
4177
3517
 
4178
- def self.ensure_nonzero_sizing_values(hpxml)
3518
+ def self.ensure_nonzero_sizing_values(hpxml_bldg)
4179
3519
  min_capacity = 1.0 # Btuh
4180
3520
  min_airflow = 3.0 # cfm; E+ min airflow is 0.001 m3/s
4181
- hpxml.heating_systems.each do |htg_sys|
3521
+ hpxml_bldg.heating_systems.each do |htg_sys|
4182
3522
  htg_sys.heating_capacity = [htg_sys.heating_capacity, min_capacity].max
4183
- if not htg_sys.heating_airflow_cfm.nil?
4184
- htg_sys.heating_airflow_cfm = [htg_sys.heating_airflow_cfm, min_airflow].max
4185
- end
3523
+ htg_sys.heating_airflow_cfm = [htg_sys.heating_airflow_cfm, min_airflow].max unless htg_sys.heating_airflow_cfm.nil?
4186
3524
  end
4187
- hpxml.cooling_systems.each do |clg_sys|
3525
+ hpxml_bldg.cooling_systems.each do |clg_sys|
4188
3526
  clg_sys.cooling_capacity = [clg_sys.cooling_capacity, min_capacity].max
4189
3527
  clg_sys.cooling_airflow_cfm = [clg_sys.cooling_airflow_cfm, min_airflow].max
3528
+ next unless not clg_sys.cooling_detailed_performance_data.empty?
3529
+
3530
+ clg_sys.cooling_detailed_performance_data.each do |dp|
3531
+ speed = dp.capacity_description == HPXML::CapacityDescriptionMinimum ? 1 : 2
3532
+ dp.capacity = [dp.capacity, min_capacity * speed].max
3533
+ end
4190
3534
  end
4191
- hpxml.heat_pumps.each do |hp_sys|
3535
+ hpxml_bldg.heat_pumps.each do |hp_sys|
4192
3536
  hp_sys.cooling_capacity = [hp_sys.cooling_capacity, min_capacity].max
4193
3537
  hp_sys.cooling_airflow_cfm = [hp_sys.cooling_airflow_cfm, min_airflow].max
4194
3538
  hp_sys.additional_properties.cooling_capacity_sensible = [hp_sys.additional_properties.cooling_capacity_sensible, min_capacity].max
4195
3539
  hp_sys.heating_capacity = [hp_sys.heating_capacity, min_capacity].max
4196
3540
  hp_sys.heating_airflow_cfm = [hp_sys.heating_airflow_cfm, min_airflow].max
4197
- if not hp_sys.heating_capacity_17F.nil?
4198
- hp_sys.heating_capacity_17F = [hp_sys.heating_capacity_17F, min_capacity].max
3541
+ hp_sys.heating_capacity_17F = [hp_sys.heating_capacity_17F, min_capacity].max unless hp_sys.heating_capacity_17F.nil?
3542
+ hp_sys.backup_heating_capacity = [hp_sys.backup_heating_capacity, min_capacity].max unless hp_sys.backup_heating_capacity.nil?
3543
+ if not hp_sys.heating_detailed_performance_data.empty?
3544
+ hp_sys.heating_detailed_performance_data.each do |dp|
3545
+ speed = dp.capacity_description == HPXML::CapacityDescriptionMinimum ? 1 : 2
3546
+ dp.capacity = [dp.capacity, min_capacity * speed].max
3547
+ end
3548
+ end
3549
+ next unless not hp_sys.cooling_detailed_performance_data.empty?
3550
+
3551
+ hp_sys.cooling_detailed_performance_data.each do |dp|
3552
+ speed = dp.capacity_description == HPXML::CapacityDescriptionMinimum ? 1 : 2
3553
+ dp.capacity = [dp.capacity, min_capacity * speed].max
3554
+ end
3555
+ end
3556
+ end
3557
+
3558
+ def self.apply_unit_multiplier(hpxml_bldg)
3559
+ # Apply unit multiplier (E+ thermal zone multiplier); E+ sends the
3560
+ # multiplied thermal zone load to the HVAC system, so the HVAC system
3561
+ # needs to be sized to meet the entire multiplied zone load.
3562
+ unit_multiplier = hpxml_bldg.building_construction.number_of_units
3563
+ hpxml_bldg.heating_systems.each do |htg_sys|
3564
+ htg_sys.heating_capacity *= unit_multiplier
3565
+ htg_sys.heating_airflow_cfm *= unit_multiplier unless htg_sys.heating_airflow_cfm.nil?
3566
+ htg_sys.pilot_light_btuh *= unit_multiplier unless htg_sys.pilot_light_btuh.nil?
3567
+ htg_sys.electric_auxiliary_energy *= unit_multiplier unless htg_sys.electric_auxiliary_energy.nil?
3568
+ htg_sys.fan_watts *= unit_multiplier unless htg_sys.fan_watts.nil?
3569
+ htg_sys.heating_detailed_performance_data.each do |dp|
3570
+ dp.capacity *= unit_multiplier unless dp.capacity.nil?
3571
+ end
3572
+ end
3573
+ hpxml_bldg.cooling_systems.each do |clg_sys|
3574
+ clg_sys.cooling_capacity *= unit_multiplier
3575
+ clg_sys.cooling_airflow_cfm *= unit_multiplier
3576
+ clg_sys.crankcase_heater_watts *= unit_multiplier unless clg_sys.crankcase_heater_watts.nil?
3577
+ clg_sys.integrated_heating_system_capacity *= unit_multiplier unless clg_sys.integrated_heating_system_capacity.nil?
3578
+ clg_sys.integrated_heating_system_airflow_cfm *= unit_multiplier unless clg_sys.integrated_heating_system_airflow_cfm.nil?
3579
+ clg_sys.cooling_detailed_performance_data.each do |dp|
3580
+ dp.capacity *= unit_multiplier unless dp.capacity.nil?
3581
+ end
3582
+ end
3583
+ hpxml_bldg.heat_pumps.each do |hp_sys|
3584
+ hp_sys.cooling_capacity *= unit_multiplier
3585
+ hp_sys.cooling_airflow_cfm *= unit_multiplier
3586
+ hp_sys.additional_properties.cooling_capacity_sensible *= unit_multiplier
3587
+ hp_sys.heating_capacity *= unit_multiplier
3588
+ hp_sys.heating_airflow_cfm *= unit_multiplier
3589
+ hp_sys.heating_capacity_17F *= unit_multiplier unless hp_sys.heating_capacity_17F.nil?
3590
+ hp_sys.backup_heating_capacity *= unit_multiplier unless hp_sys.backup_heating_capacity.nil?
3591
+ hp_sys.crankcase_heater_watts *= unit_multiplier unless hp_sys.crankcase_heater_watts.nil?
3592
+ hp_sys.heating_detailed_performance_data.each do |dp|
3593
+ dp.capacity *= unit_multiplier unless dp.capacity.nil?
4199
3594
  end
4200
- if not hp_sys.backup_heating_capacity.nil?
4201
- hp_sys.backup_heating_capacity = [hp_sys.backup_heating_capacity, min_capacity].max
3595
+ hp_sys.cooling_detailed_performance_data.each do |dp|
3596
+ dp.capacity *= unit_multiplier unless dp.capacity.nil?
4202
3597
  end
4203
3598
  end
4204
3599
  end
@@ -4237,7 +3632,7 @@ class HVAC
4237
3632
  # and space-constrained) that we don't handle here.
4238
3633
  if is_ducted # Ducted split system
4239
3634
  return hspf2 / 0.85
4240
- else # Ducted split system
3635
+ else # Ductless system
4241
3636
  return hspf2 / 0.90
4242
3637
  end
4243
3638
  end