urbanopt-cli 0.10.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (712) hide show
  1. checksums.yaml +4 -4
  2. data/.github/release.yml +24 -0
  3. data/.github/workflows/nightly_ci_build.yml +39 -29
  4. data/.gitignore +1 -0
  5. data/CHANGELOG.md +17 -0
  6. data/CMakeLists.txt +7 -7
  7. data/FindOpenStudioSDK.cmake +8 -8
  8. data/LICENSE.md +8 -35
  9. data/README.md +25 -10
  10. data/example_files/Gemfile +9 -9
  11. data/example_files/example_project_combined.json +6 -2
  12. data/example_files/example_project_with_ghe.json +859 -0
  13. data/example_files/mappers/Baseline.rb +39 -415
  14. data/example_files/mappers/ChilledWaterStorage.rb +1 -1
  15. data/example_files/mappers/CreateBar.rb +1 -1
  16. data/example_files/mappers/EvCharging.rb +1 -1
  17. data/example_files/mappers/FlexibleHotWater.rb +1 -1
  18. data/example_files/mappers/Floorspace.rb +1 -1
  19. data/example_files/mappers/HighEfficiency.rb +1 -1
  20. data/example_files/mappers/HighEfficiencyCreateBar.rb +1 -1
  21. data/example_files/mappers/HighEfficiencyFloorspace.rb +1 -1
  22. data/example_files/mappers/PeakHoursMelsShedding.rb +1 -1
  23. data/example_files/mappers/PeakHoursThermostatAdjust.rb +1 -1
  24. data/example_files/mappers/ThermalStorage.rb +1 -1
  25. data/example_files/mappers/base_workflow.osw +11 -4
  26. data/example_files/mappers/residential/template/util.rb +138 -0
  27. data/example_files/mappers/residential/util.rb +276 -0
  28. data/example_files/measures/BuildResidentialModel/measure.rb +118 -230
  29. data/example_files/measures/BuildResidentialModel/measure.xml +344 -233
  30. data/example_files/measures/BuildResidentialModel/resources/geometry.rb +7 -2
  31. data/example_files/measures/BuildResidentialModel/resources/unit_conversions.rb +5 -0
  32. data/example_files/measures/BuildResidentialModel/resources/util.rb +5 -0
  33. data/example_files/measures/BuildResidentialModel/tests/test_build_residential_model.rb +344 -0
  34. data/example_files/measures/BuildResidentialModel/tests/xml_building/17/feature1.xml +2112 -0
  35. data/example_files/measures/BuildResidentialModel/tests/xml_building/17/feature2.xml +2112 -0
  36. data/example_files/osm_building/7.osm +0 -2
  37. data/example_files/osm_building/8.osm +0 -2
  38. data/example_files/osm_building/9.osm +0 -2
  39. data/example_files/python_deps/dependencies.json +4 -3
  40. data/example_files/resources/hpxml-measures/.gitattributes +3 -0
  41. data/example_files/resources/hpxml-measures/.github/pull_request_template.md +2 -2
  42. data/example_files/resources/hpxml-measures/.github/workflows/add_to_project.yml +17 -0
  43. data/example_files/resources/hpxml-measures/.github/workflows/config.yml +37 -8
  44. data/example_files/resources/hpxml-measures/.gitignore +1 -0
  45. data/example_files/resources/hpxml-measures/.readthedocs.yml +6 -2
  46. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/README.md +5596 -0
  47. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/README.md.erb +41 -0
  48. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/measure.rb +1324 -1035
  49. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/measure.xml +325 -236
  50. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/resources/geometry.rb +119 -152
  51. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/{build_residential_hpxml_test.rb → test_build_residential_hpxml.rb} +225 -107
  52. data/example_files/resources/hpxml-measures/BuildResidentialScheduleFile/README.md +96 -0
  53. data/example_files/resources/hpxml-measures/BuildResidentialScheduleFile/README.md.erb +41 -0
  54. data/example_files/resources/hpxml-measures/BuildResidentialScheduleFile/measure.rb +73 -31
  55. data/example_files/resources/hpxml-measures/BuildResidentialScheduleFile/measure.xml +60 -40
  56. data/example_files/resources/hpxml-measures/BuildResidentialScheduleFile/resources/README.md +48 -23
  57. data/example_files/resources/hpxml-measures/BuildResidentialScheduleFile/resources/constants.rb +5 -0
  58. data/example_files/resources/hpxml-measures/BuildResidentialScheduleFile/resources/schedules.rb +6 -12
  59. data/example_files/resources/hpxml-measures/BuildResidentialScheduleFile/tests/{build_residential_schedule_file_test.rb → test_build_residential_schedule_file.rb} +162 -35
  60. data/example_files/resources/hpxml-measures/Changelog.md +57 -1
  61. data/example_files/resources/hpxml-measures/Gemfile +1 -1
  62. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/README.md +83 -0
  63. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/README.md.erb +41 -0
  64. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/measure.rb +1081 -878
  65. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/measure.xml +258 -204
  66. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/airflow.rb +205 -178
  67. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/battery.rb +43 -18
  68. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/constants.rb +37 -112
  69. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/constructions.rb +34 -73
  70. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/data/Xing_okstate_0664D_13659_Table_A-3.csv +4165 -0
  71. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/data/unavailable_periods.csv +2 -2
  72. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/energyplus.rb +5 -1
  73. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/generator.rb +13 -7
  74. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/geometry.rb +95 -42
  75. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/hotwater_appliances.rb +132 -108
  76. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/hpxml.rb +1695 -1267
  77. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/hpxml_defaults.rb +668 -589
  78. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/hpxml_schema/HPXML.xsd +304 -553
  79. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/hpxml_schematron/EPvalidator.xml +197 -112
  80. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/hvac.rb +1140 -1745
  81. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/hvac_sizing.rb +412 -325
  82. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/lighting.rb +56 -48
  83. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/location.rb +49 -38
  84. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/materials.rb +5 -0
  85. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/meta_measure.rb +17 -1
  86. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/minitest_helper.rb +5 -0
  87. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/misc_loads.rb +94 -78
  88. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/output.rb +60 -2
  89. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/psychrometrics.rb +6 -1
  90. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/pv.rb +11 -5
  91. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/schedule_files/occupancy-non-stochastic.csv +1 -1
  92. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/schedule_files/occupancy-stochastic-30-mins.csv +52561 -0
  93. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/schedule_files/occupancy-stochastic_2.csv +8761 -0
  94. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/schedule_files/occupancy-stochastic_3.csv +8761 -0
  95. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/schedule_files/occupancy-stochastic_4.csv +8761 -0
  96. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/schedule_files/occupancy-stochastic_5.csv +8761 -0
  97. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/schedule_files/occupancy-stochastic_6.csv +8761 -0
  98. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/schedules.rb +129 -137
  99. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/simcontrols.rb +12 -21
  100. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/unit_conversions.rb +5 -0
  101. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/util.rb +7 -2
  102. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/utility_bills.rb +6 -1
  103. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/version.rb +7 -2
  104. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/waterheater.rb +179 -144
  105. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/weather.rb +129 -71
  106. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/xmlhelper.rb +5 -0
  107. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/xmlvalidator.rb +23 -6
  108. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_airflow.rb +129 -118
  109. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_battery.rb +25 -20
  110. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_defaults.rb +2282 -2239
  111. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_enclosure.rb +395 -204
  112. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_generator.rb +12 -7
  113. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_hotwater_appliance.rb +56 -51
  114. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_hvac.rb +369 -230
  115. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_hvac_sizing.rb +371 -191
  116. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_lighting.rb +27 -20
  117. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_location.rb +55 -5
  118. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_miscloads.rb +35 -30
  119. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_pv.rb +13 -8
  120. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_schedules.rb +107 -93
  121. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_simcontrols.rb +11 -6
  122. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_validation.rb +757 -573
  123. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_water_heater.rb +77 -72
  124. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_weather.rb +36 -6
  125. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/util.rb +5 -0
  126. data/example_files/resources/hpxml-measures/README.md +2 -0
  127. data/example_files/resources/hpxml-measures/Rakefile +10 -3
  128. data/example_files/resources/hpxml-measures/ReportSimulationOutput/README.md +787 -0
  129. data/example_files/resources/hpxml-measures/ReportSimulationOutput/README.md.erb +41 -0
  130. data/example_files/resources/hpxml-measures/ReportSimulationOutput/measure.rb +730 -418
  131. data/example_files/resources/hpxml-measures/ReportSimulationOutput/measure.xml +1215 -9
  132. data/example_files/resources/hpxml-measures/ReportSimulationOutput/tests/{output_report_test.rb → test_report_sim_output.rb} +130 -299
  133. data/example_files/resources/hpxml-measures/ReportUtilityBills/README.md +87 -0
  134. data/example_files/resources/hpxml-measures/ReportUtilityBills/README.md.erb +41 -0
  135. data/example_files/resources/hpxml-measures/ReportUtilityBills/measure.rb +261 -89
  136. data/example_files/resources/hpxml-measures/ReportUtilityBills/measure.xml +179 -94
  137. data/example_files/resources/hpxml-measures/ReportUtilityBills/resources/simple_rates/Average_retail_price_of_electricity.csv +68 -68
  138. data/example_files/resources/hpxml-measures/ReportUtilityBills/resources/simple_rates/NG_PRI_SUM_A_EPG0_PRS_DMCF_A.csv +3 -2
  139. data/example_files/resources/hpxml-measures/ReportUtilityBills/resources/simple_rates/PET_PRI_WFR_A_EPD2F_PRS_DPGAL_W.csv +713 -685
  140. data/example_files/resources/hpxml-measures/ReportUtilityBills/resources/simple_rates/PET_PRI_WFR_A_EPLLPA_PRS_DPGAL_W.csv +716 -688
  141. data/example_files/resources/hpxml-measures/ReportUtilityBills/resources/simple_rates/README.md +5 -2
  142. data/example_files/resources/hpxml-measures/ReportUtilityBills/resources/util.rb +18 -9
  143. data/example_files/resources/hpxml-measures/ReportUtilityBills/tests/test_report_utility_bills.rb +1308 -0
  144. data/example_files/resources/hpxml-measures/docs/requirements.txt +5 -0
  145. data/example_files/resources/hpxml-measures/docs/source/conf.py +1 -2
  146. data/example_files/resources/hpxml-measures/docs/source/intro.rst +3 -20
  147. data/example_files/resources/hpxml-measures/docs/source/usage_instructions.rst +1 -1
  148. data/example_files/resources/hpxml-measures/docs/source/workflow_inputs.rst +917 -564
  149. data/example_files/resources/hpxml-measures/docs/source/workflow_outputs.rst +79 -42
  150. data/example_files/resources/hpxml-measures/tasks.rb +2305 -2055
  151. data/example_files/resources/hpxml-measures/workflow/hpxml_inputs.json +270 -587
  152. data/example_files/resources/hpxml-measures/workflow/real_homes/house001.xml +559 -557
  153. data/example_files/resources/hpxml-measures/workflow/real_homes/house002.xml +522 -520
  154. data/example_files/resources/hpxml-measures/workflow/real_homes/house003.xml +534 -532
  155. data/example_files/resources/hpxml-measures/workflow/real_homes/house004.xml +547 -545
  156. data/example_files/resources/hpxml-measures/workflow/real_homes/house005.xml +546 -544
  157. data/example_files/resources/hpxml-measures/workflow/real_homes/house006.xml +603 -623
  158. data/example_files/resources/hpxml-measures/workflow/real_homes/house007.xml +613 -633
  159. data/example_files/resources/hpxml-measures/workflow/real_homes/house008.xml +699 -721
  160. data/example_files/resources/hpxml-measures/workflow/real_homes/house009.xml +662 -661
  161. data/example_files/resources/hpxml-measures/workflow/real_homes/house010.xml +657 -677
  162. data/example_files/resources/hpxml-measures/workflow/real_homes/house011.xml +470 -467
  163. data/example_files/resources/hpxml-measures/workflow/real_homes/house012.xml +441 -438
  164. data/example_files/resources/hpxml-measures/workflow/real_homes/house013.xml +468 -465
  165. data/example_files/resources/hpxml-measures/workflow/real_homes/house014.xml +469 -466
  166. data/example_files/resources/hpxml-measures/workflow/real_homes/house015.xml +468 -465
  167. data/example_files/resources/hpxml-measures/workflow/real_homes/house016.xml +717 -714
  168. data/example_files/resources/hpxml-measures/workflow/real_homes/house017.xml +647 -645
  169. data/example_files/resources/hpxml-measures/workflow/real_homes/house018.xml +569 -566
  170. data/example_files/resources/hpxml-measures/workflow/real_homes/house019.xml +602 -599
  171. data/example_files/resources/hpxml-measures/workflow/real_homes/house020.xml +630 -627
  172. data/example_files/resources/hpxml-measures/workflow/real_homes/house021.xml +776 -774
  173. data/example_files/resources/hpxml-measures/workflow/real_homes/house022.xml +670 -667
  174. data/example_files/resources/hpxml-measures/workflow/real_homes/house023.xml +632 -629
  175. data/example_files/resources/hpxml-measures/workflow/real_homes/house024.xml +731 -729
  176. data/example_files/resources/hpxml-measures/workflow/real_homes/house025.xml +672 -669
  177. data/example_files/resources/hpxml-measures/workflow/real_homes/house026.xml +667 -644
  178. data/example_files/resources/hpxml-measures/workflow/real_homes/house027.xml +646 -644
  179. data/example_files/resources/hpxml-measures/workflow/real_homes/house028.xml +690 -688
  180. data/example_files/resources/hpxml-measures/workflow/real_homes/house029.xml +701 -699
  181. data/example_files/resources/hpxml-measures/workflow/real_homes/house030.xml +637 -615
  182. data/example_files/resources/hpxml-measures/workflow/real_homes/house031.xml +690 -688
  183. data/example_files/resources/hpxml-measures/workflow/real_homes/house032.xml +557 -554
  184. data/example_files/resources/hpxml-measures/workflow/real_homes/house033.xml +534 -531
  185. data/example_files/resources/hpxml-measures/workflow/real_homes/house034.xml +636 -635
  186. data/example_files/resources/hpxml-measures/workflow/real_homes/house035.xml +616 -613
  187. data/example_files/resources/hpxml-measures/workflow/real_homes/house036.xml +601 -598
  188. data/example_files/resources/hpxml-measures/workflow/real_homes/house037.xml +581 -578
  189. data/example_files/resources/hpxml-measures/workflow/real_homes/house038.xml +624 -622
  190. data/example_files/resources/hpxml-measures/workflow/real_homes/house039.xml +584 -582
  191. data/example_files/resources/hpxml-measures/workflow/real_homes/house040.xml +631 -629
  192. data/example_files/resources/hpxml-measures/workflow/real_homes/house041.xml +922 -921
  193. data/example_files/resources/hpxml-measures/workflow/real_homes/house042.xml +855 -853
  194. data/example_files/resources/hpxml-measures/workflow/real_homes/house043.xml +739 -737
  195. data/example_files/resources/hpxml-measures/workflow/real_homes/house044.xml +798 -796
  196. data/example_files/resources/hpxml-measures/workflow/real_homes/house045.xml +696 -694
  197. data/example_files/resources/hpxml-measures/workflow/real_homes/house046.xml +487 -483
  198. data/example_files/resources/hpxml-measures/workflow/real_homes/house047.xml +443 -440
  199. data/example_files/resources/hpxml-measures/workflow/real_homes/house048.xml +688 -686
  200. data/example_files/resources/hpxml-measures/workflow/real_homes/house049.xml +722 -720
  201. data/example_files/resources/hpxml-measures/workflow/real_homes/house050.xml +619 -617
  202. data/example_files/resources/hpxml-measures/workflow/run_simulation.rb +13 -20
  203. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-coal.xml +9 -9
  204. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-dehumidifier-ief-portable.xml +11 -12
  205. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-dehumidifier-ief-whole-home.xml +11 -12
  206. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-dehumidifier-multiple.xml +12 -13
  207. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-dehumidifier.xml +11 -12
  208. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-gas.xml +9 -9
  209. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-modified.xml +9 -9
  210. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-none.xml +4 -4
  211. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-oil.xml +9 -9
  212. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-propane.xml +9 -9
  213. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-wood.xml +9 -9
  214. data/example_files/resources/hpxml-measures/workflow/sample_files/base-atticroof-cathedral.xml +11 -11
  215. data/example_files/resources/hpxml-measures/workflow/sample_files/base-atticroof-conditioned.xml +10 -10
  216. data/example_files/resources/hpxml-measures/workflow/sample_files/base-atticroof-flat.xml +9 -9
  217. data/example_files/resources/hpxml-measures/workflow/sample_files/base-atticroof-radiant-barrier.xml +10 -11
  218. data/example_files/resources/hpxml-measures/workflow/sample_files/base-atticroof-unvented-insulated-roof.xml +9 -9
  219. data/example_files/resources/hpxml-measures/workflow/sample_files/base-atticroof-vented.xml +8 -8
  220. data/example_files/resources/hpxml-measures/workflow/sample_files/base-battery-scheduled.xml +571 -569
  221. data/example_files/resources/hpxml-measures/workflow/sample_files/base-battery.xml +9 -9
  222. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-adjacent-to-multifamily-buffer-space.xml → base-bldgtype-mf-unit-adjacent-to-multifamily-buffer-space.xml} +5 -5
  223. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-adjacent-to-multiple.xml → base-bldgtype-mf-unit-adjacent-to-multiple.xml} +17 -17
  224. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-adjacent-to-non-freezing-space.xml → base-bldgtype-mf-unit-adjacent-to-non-freezing-space.xml} +5 -5
  225. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-adjacent-to-other-heated-space.xml → base-bldgtype-mf-unit-adjacent-to-other-heated-space.xml} +5 -5
  226. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-adjacent-to-other-housing-unit.xml → base-bldgtype-mf-unit-adjacent-to-other-housing-unit.xml} +5 -5
  227. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-infil-compartmentalization-test.xml → base-bldgtype-mf-unit-infil-compartmentalization-test.xml} +461 -461
  228. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-residents-1.xml → base-bldgtype-mf-unit-residents-1.xml} +453 -453
  229. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-boiler-chiller-baseboard.xml → base-bldgtype-mf-unit-shared-boiler-chiller-baseboard.xml} +11 -11
  230. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-boiler-chiller-fan-coil-ducted.xml → base-bldgtype-mf-unit-shared-boiler-chiller-fan-coil-ducted.xml} +11 -11
  231. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-boiler-chiller-fan-coil.xml → base-bldgtype-mf-unit-shared-boiler-chiller-fan-coil.xml} +11 -11
  232. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-boiler-chiller-water-loop-heat-pump.xml → base-bldgtype-mf-unit-shared-boiler-chiller-water-loop-heat-pump.xml} +11 -11
  233. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-boiler-cooling-tower-water-loop-heat-pump.xml → base-bldgtype-mf-unit-shared-boiler-cooling-tower-water-loop-heat-pump.xml} +11 -11
  234. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-boiler-only-baseboard.xml → base-bldgtype-mf-unit-shared-boiler-only-baseboard.xml} +11 -11
  235. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-boiler-only-fan-coil-ducted.xml → base-bldgtype-mf-unit-shared-boiler-only-fan-coil-ducted.xml} +11 -11
  236. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-boiler-only-fan-coil-eae.xml → base-bldgtype-mf-unit-shared-boiler-only-fan-coil-eae.xml} +11 -11
  237. data/example_files/resources/hpxml-measures/workflow/sample_files/base-bldgtype-mf-unit-shared-boiler-only-fan-coil-fireplace-elec.xml +433 -0
  238. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-boiler-only-fan-coil.xml → base-bldgtype-mf-unit-shared-boiler-only-fan-coil.xml} +11 -11
  239. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-boiler-only-water-loop-heat-pump.xml → base-bldgtype-mf-unit-shared-boiler-only-water-loop-heat-pump.xml} +11 -11
  240. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-chiller-only-baseboard.xml → base-bldgtype-mf-unit-shared-chiller-only-baseboard.xml} +11 -11
  241. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-chiller-only-fan-coil-ducted.xml → base-bldgtype-mf-unit-shared-chiller-only-fan-coil-ducted.xml} +11 -11
  242. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-chiller-only-fan-coil.xml → base-bldgtype-mf-unit-shared-chiller-only-fan-coil.xml} +11 -11
  243. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-chiller-only-water-loop-heat-pump.xml → base-bldgtype-mf-unit-shared-chiller-only-water-loop-heat-pump.xml} +11 -11
  244. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-cooling-tower-only-water-loop-heat-pump.xml → base-bldgtype-mf-unit-shared-cooling-tower-only-water-loop-heat-pump.xml} +11 -11
  245. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-generator.xml → base-bldgtype-mf-unit-shared-generator.xml} +13 -13
  246. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-ground-loop-ground-to-air-heat-pump.xml → base-bldgtype-mf-unit-shared-ground-loop-ground-to-air-heat-pump.xml} +13 -13
  247. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-laundry-room-multiple-water-heaters.xml → base-bldgtype-mf-unit-shared-laundry-room-multiple-water-heaters.xml} +480 -480
  248. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-laundry-room.xml → base-bldgtype-mf-unit-shared-laundry-room.xml} +10 -10
  249. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-mechvent-multiple.xml → base-bldgtype-mf-unit-shared-mechvent-multiple.xml} +15 -15
  250. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-mechvent-preconditioning.xml → base-bldgtype-mf-unit-shared-mechvent-preconditioning.xml} +13 -13
  251. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-mechvent.xml → base-bldgtype-mf-unit-shared-mechvent.xml} +13 -13
  252. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-pv.xml → base-bldgtype-mf-unit-shared-pv.xml} +13 -13
  253. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-water-heater-recirc.xml → base-bldgtype-mf-unit-shared-water-heater-recirc.xml} +13 -13
  254. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily-shared-water-heater.xml → base-bldgtype-mf-unit-shared-water-heater.xml} +13 -13
  255. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-multifamily.xml → base-bldgtype-mf-unit.xml} +13 -13
  256. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-attached-2stories.xml → base-bldgtype-sfa-unit-2stories.xml} +610 -610
  257. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-attached-atticroof-cathedral.xml → base-bldgtype-sfa-unit-atticroof-cathedral.xml} +558 -558
  258. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-attached-infil-compartmentalization-test.xml → base-bldgtype-sfa-unit-infil-compartmentalization-test.xml} +610 -610
  259. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-bldgtype-attached.xml → base-bldgtype-sfa-unit.xml} +610 -610
  260. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-combi-tankless-outside.xml +8 -8
  261. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-combi-tankless.xml +9 -9
  262. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-desuperheater-2-speed.xml +9 -9
  263. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-desuperheater-gshp.xml +9 -9
  264. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-desuperheater-hpwh.xml +9 -9
  265. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-desuperheater-tankless.xml +9 -9
  266. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-desuperheater-var-speed.xml +9 -9
  267. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-desuperheater.xml +9 -9
  268. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-dwhr.xml +9 -9
  269. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-indirect-detailed-setpoints.xml +507 -505
  270. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-indirect-dse.xml +9 -9
  271. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-indirect-outside.xml +8 -8
  272. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-indirect-standbyloss.xml +9 -9
  273. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-indirect-with-solar-fraction.xml +9 -9
  274. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-indirect.xml +9 -9
  275. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-jacket-electric.xml +9 -9
  276. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-jacket-gas.xml +9 -9
  277. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-jacket-hpwh.xml +9 -9
  278. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-jacket-indirect.xml +9 -9
  279. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-low-flow-fixtures.xml +12 -10
  280. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-multiple.xml +14 -14
  281. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-none.xml +5 -5
  282. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-recirc-demand.xml +9 -9
  283. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-recirc-manual.xml +9 -9
  284. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-recirc-nocontrol.xml +9 -9
  285. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-recirc-temperature.xml +9 -9
  286. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-recirc-timer.xml +9 -9
  287. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-solar-direct-evacuated-tube.xml +9 -9
  288. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-solar-direct-flat-plate.xml +9 -9
  289. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-solar-direct-ics.xml +9 -9
  290. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-solar-fraction.xml +9 -9
  291. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-solar-indirect-flat-plate.xml +9 -9
  292. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-solar-thermosyphon-flat-plate.xml +9 -9
  293. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-coal.xml +9 -9
  294. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-detailed-setpoints.xml +12 -10
  295. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-elec-uef.xml +9 -9
  296. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-gas-outside.xml +8 -8
  297. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-gas-uef-fhr.xml +9 -9
  298. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-gas-uef.xml +9 -9
  299. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-gas.xml +9 -9
  300. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-heat-pump-detailed-schedules.xml +13 -11
  301. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-heat-pump-operating-mode-heat-pump-only.xml +9 -9
  302. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-heat-pump-outside.xml +8 -8
  303. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-heat-pump-uef.xml +9 -9
  304. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-heat-pump-with-solar-fraction.xml +9 -9
  305. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-heat-pump-with-solar.xml +9 -9
  306. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-heat-pump.xml +9 -9
  307. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-model-type-stratified-detailed-occupancy-stochastic.xml +12 -10
  308. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-model-type-stratified.xml +9 -9
  309. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-oil.xml +9 -9
  310. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-wood.xml +9 -9
  311. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tankless-detailed-setpoints.xml +12 -10
  312. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tankless-electric-outside.xml +8 -8
  313. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tankless-electric-uef.xml +9 -9
  314. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tankless-electric.xml +9 -9
  315. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tankless-gas-uef.xml +9 -9
  316. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tankless-gas-with-solar-fraction.xml +9 -9
  317. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tankless-gas-with-solar.xml +9 -9
  318. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tankless-gas.xml +9 -9
  319. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tankless-propane.xml +9 -9
  320. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-2stories-garage.xml +13 -14
  321. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-2stories.xml +11 -11
  322. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-beds-1.xml +9 -9
  323. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-beds-2.xml +9 -9
  324. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-beds-4.xml +9 -9
  325. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-beds-5.xml +9 -9
  326. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-ceilingtypes.xml +576 -576
  327. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-floortypes.xml +519 -519
  328. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-garage.xml +4 -5
  329. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-infil-ach-house-pressure.xml +9 -9
  330. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-infil-cfm-house-pressure.xml +9 -9
  331. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-infil-cfm50.xml +9 -9
  332. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-infil-ela.xml +548 -548
  333. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-infil-flue.xml +9 -9
  334. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-infil-natural-ach.xml +9 -9
  335. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-infil-natural-cfm.xml +551 -551
  336. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-orientations.xml +9 -9
  337. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-overhangs.xml +9 -9
  338. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-rooftypes.xml +9 -9
  339. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-skylights-physical-properties.xml +9 -9
  340. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-skylights-shading.xml +9 -9
  341. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-skylights-storms.xml +9 -9
  342. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-skylights.xml +9 -9
  343. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-split-level.xml +10 -11
  344. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-thermal-mass.xml +9 -9
  345. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-walltypes.xml +19 -19
  346. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-windows-natural-ventilation-availability.xml +555 -553
  347. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-windows-none.xml +9 -9
  348. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-windows-physical-properties.xml +9 -9
  349. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-windows-shading-seasons.xml +560 -558
  350. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-windows-shading.xml +9 -9
  351. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-windows-storms.xml +9 -9
  352. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-ambient.xml +10 -10
  353. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-basement-garage.xml +10 -11
  354. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-belly-wing-no-skirt.xml +496 -0
  355. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-belly-wing-skirt.xml +496 -0
  356. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-complex.xml +18 -18
  357. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-schedules-simple-power-outage-natvent-unavailable.xml → base-foundation-conditioned-basement-slab-insulation-full.xml} +552 -564
  358. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-conditioned-basement-slab-insulation.xml +9 -9
  359. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-conditioned-basement-wall-insulation.xml +555 -555
  360. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-conditioned-crawlspace.xml +8 -8
  361. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-multiple.xml +5 -5
  362. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-slab.xml +10 -11
  363. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-unconditioned-basement-above-grade.xml +4 -4
  364. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-unconditioned-basement-assembly-r.xml +4 -4
  365. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-unconditioned-basement-wall-insulation.xml +4 -4
  366. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-unconditioned-basement.xml +4 -4
  367. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-unvented-crawlspace.xml +9 -9
  368. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-vented-crawlspace-above-grade.xml +558 -0
  369. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-vented-crawlspace.xml +9 -9
  370. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-walkout-basement.xml +15 -15
  371. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-air-to-air-heat-pump-1-speed-cooling-only.xml +9 -9
  372. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-air-to-air-heat-pump-1-speed-heating-capacity-17f.xml +552 -552
  373. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-air-to-air-heat-pump-1-speed-heating-only.xml +9 -9
  374. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-air-to-air-heat-pump-1-speed-lockout-temperatures.xml +562 -562
  375. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-air-to-air-heat-pump-1-speed-seer2-hspf2.xml +557 -557
  376. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-air-to-air-heat-pump-1-speed.xml +9 -9
  377. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-air-to-air-heat-pump-2-speed.xml +9 -9
  378. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-air-to-air-heat-pump-var-speed-backup-boiler-hvac-seasons.xml +586 -586
  379. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-air-to-air-heat-pump-var-speed-backup-boiler-switchover-temperature.xml +9 -9
  380. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-air-to-air-heat-pump-var-speed-backup-boiler.xml +9 -9
  381. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-air-to-air-heat-pump-var-speed-backup-furnace.xml +9 -9
  382. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-hvac-autosize-air-to-air-heat-pump-var-speed-sizing-methodology-acca.xml → base-hvac-air-to-air-heat-pump-var-speed-detailed-performance-other-temperatures.xml} +89 -13
  383. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-hvac-autosize-air-to-air-heat-pump-var-speed-sizing-methodology-hers.xml → base-hvac-air-to-air-heat-pump-var-speed-detailed-performance.xml} +107 -13
  384. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-air-to-air-heat-pump-var-speed.xml +9 -9
  385. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-sizing-controls.xml +567 -565
  386. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize.xml +9 -9
  387. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-boiler-coal-only.xml +9 -9
  388. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-boiler-elec-only.xml +9 -9
  389. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-boiler-gas-central-ac-1-speed.xml +9 -9
  390. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-boiler-gas-only-pilot.xml +512 -512
  391. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-boiler-gas-only.xml +9 -9
  392. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-boiler-oil-only.xml +9 -9
  393. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-boiler-propane-only.xml +9 -9
  394. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-boiler-wood-only.xml +9 -9
  395. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-central-ac-only-1-speed-seer2.xml +536 -536
  396. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-central-ac-only-1-speed.xml +9 -9
  397. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-central-ac-only-2-speed.xml +9 -9
  398. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-hvac-autosize-central-ac-only-var-speed.xml → base-hvac-central-ac-only-var-speed-detailed-performance.xml} +49 -10
  399. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-central-ac-only-var-speed.xml +9 -9
  400. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-central-ac-plus-air-to-air-heat-pump-heating.xml +9 -9
  401. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-dse.xml +9 -9
  402. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-dual-fuel-air-to-air-heat-pump-1-speed-lockout-temperatures.xml +559 -559
  403. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-dual-fuel-air-to-air-heat-pump-1-speed.xml +9 -9
  404. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-dual-fuel-air-to-air-heat-pump-2-speed.xml +9 -9
  405. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-dual-fuel-air-to-air-heat-pump-var-speed.xml +9 -9
  406. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-dual-fuel-mini-split-heat-pump-ducted.xml +9 -9
  407. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-ducts-area-fractions.xml +11 -12
  408. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-ducts-area-multipliers.xml +558 -558
  409. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-ducts-buried.xml +554 -554
  410. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-hvac-autosize-furnace-gas-room-ac.xml → base-hvac-ducts-defaults.xml} +28 -14
  411. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-ducts-effective-rvalue.xml +552 -552
  412. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-ducts-leakage-cfm50.xml +9 -9
  413. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-ducts-leakage-percent.xml +9 -9
  414. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-elec-resistance-only.xml +9 -9
  415. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-evap-cooler-furnace-gas.xml +9 -9
  416. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-evap-cooler-only-ducted.xml +9 -9
  417. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-evap-cooler-only.xml +9 -9
  418. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-fireplace-wood-only.xml +9 -9
  419. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-floor-furnace-propane-only.xml +15 -10
  420. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-coal-only.xml +9 -9
  421. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-elec-central-ac-1-speed.xml +9 -9
  422. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-elec-only.xml +9 -9
  423. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-gas-central-ac-2-speed.xml +9 -9
  424. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-gas-central-ac-var-speed.xml +9 -9
  425. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-gas-only-detailed-setpoints.xml +12 -10
  426. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-gas-only-pilot.xml +541 -541
  427. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-gas-only.xml +9 -9
  428. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-gas-room-ac.xml +9 -9
  429. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-oil-only.xml +9 -9
  430. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-propane-only.xml +9 -9
  431. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-wood-only.xml +9 -9
  432. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-x3-dse.xml +9 -9
  433. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-ground-to-air-heat-pump-cooling-only.xml +9 -9
  434. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-ground-to-air-heat-pump-heating-only.xml +9 -9
  435. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-ground-to-air-heat-pump.xml +9 -9
  436. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-install-quality-air-to-air-heat-pump-1-speed.xml +9 -9
  437. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-install-quality-air-to-air-heat-pump-2-speed.xml +9 -9
  438. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-hvac-air-to-air-heat-pump-1-speed-autosized-backup.xml → base-hvac-install-quality-air-to-air-heat-pump-var-speed-detailed-performance.xml} +650 -556
  439. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-install-quality-air-to-air-heat-pump-var-speed.xml +9 -9
  440. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-install-quality-furnace-gas-central-ac-1-speed.xml +9 -9
  441. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-install-quality-furnace-gas-central-ac-2-speed.xml +9 -9
  442. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-install-quality-furnace-gas-central-ac-var-speed.xml +9 -9
  443. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-install-quality-furnace-gas-only.xml +9 -9
  444. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-install-quality-ground-to-air-heat-pump.xml +9 -9
  445. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-install-quality-mini-split-air-conditioner-only-ducted.xml +9 -9
  446. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-install-quality-mini-split-heat-pump-ducted.xml +9 -9
  447. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-mini-split-air-conditioner-only-ducted.xml +9 -9
  448. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-hvac-autosize-mini-split-air-conditioner-only-ducted.xml → base-hvac-mini-split-air-conditioner-only-ductless-detailed-performance.xml} +50 -49
  449. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-mini-split-air-conditioner-only-ductless.xml +9 -9
  450. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-mini-split-heat-pump-ducted-cooling-only.xml +9 -9
  451. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-hvac-autosize-mini-split-heat-pump-ducted-sizing-methodology-maxload.xml → base-hvac-mini-split-heat-pump-ducted-detailed-performance.xml} +109 -14
  452. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-mini-split-heat-pump-ducted-heating-only.xml +9 -9
  453. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-mini-split-heat-pump-ducted.xml +9 -9
  454. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-mini-split-heat-pump-ductless-backup-baseboard.xml +524 -524
  455. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-hvac-autosize-dual-fuel-mini-split-heat-pump-ducted-backup-hardsized.xml → base-hvac-mini-split-heat-pump-ductless-backup-furnace-ducts-defaults.xml} +560 -552
  456. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-mini-split-heat-pump-ductless-backup-furnace.xml +563 -563
  457. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-mini-split-heat-pump-ductless-backup-stove.xml +9 -9
  458. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-hvac-autosize-dual-fuel-mini-split-heat-pump-ducted.xml → base-hvac-mini-split-heat-pump-ductless-detailed-performance.xml} +108 -60
  459. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-mini-split-heat-pump-ductless-heating-capacity-17f.xml +505 -505
  460. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-mini-split-heat-pump-ductless.xml +9 -9
  461. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-multiple.xml +9 -9
  462. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-none.xml +10 -11
  463. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-ptac-with-heating-electricity.xml +9 -9
  464. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-ptac-with-heating-natural-gas.xml +504 -504
  465. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-ptac.xml +9 -9
  466. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-pthp-heating-capacity-17f.xml +512 -512
  467. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-pthp.xml +9 -9
  468. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-room-ac-only-33percent.xml +9 -9
  469. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-room-ac-only-ceer.xml +9 -9
  470. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-room-ac-only-detailed-setpoints.xml +12 -10
  471. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-room-ac-only.xml +9 -9
  472. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-room-ac-with-heating.xml +504 -504
  473. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-room-ac-with-reverse-cycle.xml +517 -517
  474. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-seasons.xml +9 -9
  475. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-setpoints-daily-schedules.xml +9 -9
  476. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-setpoints-daily-setbacks.xml +9 -9
  477. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-setpoints.xml +9 -9
  478. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-hvac-fixed-heater-gas-only.xml → base-hvac-space-heater-gas-only.xml} +10 -10
  479. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-stove-oil-only.xml +9 -9
  480. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-stove-wood-pellets-only.xml +9 -9
  481. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-undersized.xml +9 -9
  482. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-wall-furnace-elec-only.xml +9 -9
  483. data/example_files/resources/hpxml-measures/workflow/sample_files/base-lighting-ceiling-fans.xml +9 -9
  484. data/example_files/resources/hpxml-measures/workflow/sample_files/base-lighting-holiday.xml +9 -9
  485. data/example_files/resources/hpxml-measures/workflow/sample_files/base-lighting-kwh-per-year.xml +531 -528
  486. data/example_files/resources/hpxml-measures/workflow/sample_files/base-lighting-mixed.xml +536 -536
  487. data/example_files/resources/hpxml-measures/workflow/sample_files/base-lighting-none-ceiling-fans.xml +515 -515
  488. data/example_files/resources/hpxml-measures/workflow/sample_files/base-lighting-none.xml +9 -9
  489. data/example_files/resources/hpxml-measures/workflow/sample_files/base-location-AMY-2012.xml +9 -9
  490. data/example_files/resources/hpxml-measures/workflow/sample_files/base-location-baltimore-md.xml +9 -9
  491. data/example_files/resources/hpxml-measures/workflow/sample_files/base-location-capetown-zaf.xml +9 -9
  492. data/example_files/resources/hpxml-measures/workflow/sample_files/base-location-dallas-tx.xml +10 -11
  493. data/example_files/resources/hpxml-measures/workflow/sample_files/base-location-duluth-mn.xml +4 -4
  494. data/example_files/resources/hpxml-measures/workflow/sample_files/base-location-helena-mt.xml +9 -9
  495. data/example_files/resources/hpxml-measures/workflow/sample_files/base-location-honolulu-hi.xml +10 -11
  496. data/example_files/resources/hpxml-measures/workflow/sample_files/base-location-miami-fl.xml +10 -11
  497. data/example_files/resources/hpxml-measures/workflow/sample_files/base-location-phoenix-az.xml +10 -11
  498. data/example_files/resources/hpxml-measures/workflow/sample_files/base-location-portland-or.xml +9 -9
  499. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-balanced.xml +9 -9
  500. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-bath-kitchen-fans.xml +9 -9
  501. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-cfis-airflow-fraction-zero.xml +9 -9
  502. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-cfis-dse.xml +9 -9
  503. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-cfis-evap-cooler-only-ducted.xml +9 -9
  504. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-cfis-supplemental-fan-exhaust.xml +576 -576
  505. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-cfis-supplemental-fan-supply.xml +576 -576
  506. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-cfis.xml +9 -9
  507. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-erv-atre-asre.xml +9 -9
  508. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-erv.xml +9 -9
  509. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-exhaust-rated-flow-rate.xml +9 -9
  510. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-exhaust.xml +9 -9
  511. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-hrv-asre.xml +9 -9
  512. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-hrv.xml +9 -9
  513. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-multiple.xml +9 -9
  514. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-supply.xml +9 -9
  515. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-whole-house-fan.xml +9 -9
  516. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-additional-properties.xml +21 -19
  517. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-bills-pv-detailed-only.xml +605 -605
  518. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-bills-pv-mixed.xml +587 -587
  519. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-bills-pv.xml +9 -9
  520. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-bills.xml +9 -9
  521. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-defaults.xml +3 -3
  522. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-emissions.xml +9 -9
  523. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-generators-battery-scheduled.xml +587 -585
  524. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-generators-battery.xml +584 -584
  525. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-generators.xml +9 -9
  526. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-ground-conductivity.xml +555 -555
  527. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-loads-large-uncommon.xml +26 -26
  528. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-loads-large-uncommon2.xml +26 -26
  529. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-loads-none.xml +9 -9
  530. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-neighbor-shading-bldgtype-multifamily.xml +508 -508
  531. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-neighbor-shading.xml +9 -9
  532. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-shielding-of-home.xml +9 -9
  533. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-schedules-simple-power-outage-natvent-available.xml → base-misc-unit-multiplier.xml} +553 -564
  534. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-usage-multiplier.xml +26 -26
  535. data/example_files/resources/hpxml-measures/workflow/sample_files/base-multiple-mf-units.xml +2755 -0
  536. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-multiple-buildings.xml → base-multiple-sfd-buildings.xml} +31 -22
  537. data/example_files/resources/hpxml-measures/workflow/sample_files/base-pv-battery-ah.xml +9 -9
  538. data/example_files/resources/hpxml-measures/workflow/sample_files/base-pv-battery-garage.xml +4 -5
  539. data/example_files/resources/hpxml-measures/workflow/sample_files/base-pv-battery-round-trip-efficiency.xml +597 -597
  540. data/example_files/resources/hpxml-measures/workflow/sample_files/base-pv-battery-scheduled.xml +599 -597
  541. data/example_files/resources/hpxml-measures/workflow/sample_files/base-pv-battery.xml +9 -9
  542. data/example_files/resources/hpxml-measures/workflow/sample_files/base-pv-generators-battery-scheduled.xml +615 -613
  543. data/example_files/resources/hpxml-measures/workflow/sample_files/base-pv-generators-battery.xml +612 -612
  544. data/example_files/resources/hpxml-measures/workflow/sample_files/base-pv-generators.xml +596 -596
  545. data/example_files/resources/hpxml-measures/workflow/sample_files/base-pv.xml +9 -9
  546. data/example_files/resources/hpxml-measures/workflow/sample_files/base-residents-0-runperiod-1-month.xml +559 -559
  547. data/example_files/resources/hpxml-measures/workflow/sample_files/base-residents-0.xml +555 -555
  548. data/example_files/resources/hpxml-measures/workflow/sample_files/base-residents-1-misc-loads-large-uncommon.xml +616 -616
  549. data/example_files/resources/hpxml-measures/workflow/sample_files/base-residents-1-misc-loads-large-uncommon2.xml +616 -616
  550. data/example_files/resources/hpxml-measures/workflow/sample_files/base-residents-1.xml +547 -547
  551. data/example_files/resources/hpxml-measures/workflow/sample_files/base-residents-5.xml +515 -515
  552. data/example_files/resources/hpxml-measures/workflow/sample_files/base-schedules-detailed-all-10-mins.xml +14 -12
  553. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-hvac-crankcase-heater-40w.xml → base-schedules-detailed-mixed-timesteps-power-outage.xml} +565 -555
  554. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-schedules-detailed-occupancy-stochastic-vacancy-year-round.xml → base-schedules-detailed-mixed-timesteps.xml} +554 -563
  555. data/example_files/resources/hpxml-measures/workflow/sample_files/base-schedules-detailed-occupancy-stochastic-10-mins.xml +12 -10
  556. data/example_files/resources/hpxml-measures/workflow/sample_files/base-schedules-detailed-occupancy-stochastic-power-outage.xml +566 -564
  557. data/example_files/resources/hpxml-measures/workflow/sample_files/base-schedules-detailed-occupancy-stochastic-vacancy.xml +12 -10
  558. data/example_files/resources/hpxml-measures/workflow/sample_files/base-schedules-detailed-occupancy-stochastic.xml +12 -10
  559. data/example_files/resources/hpxml-measures/workflow/sample_files/base-schedules-detailed-setpoints-daily-schedules.xml +12 -10
  560. data/example_files/resources/hpxml-measures/workflow/sample_files/base-schedules-detailed-setpoints-daily-setbacks.xml +12 -10
  561. data/example_files/resources/hpxml-measures/workflow/sample_files/base-schedules-detailed-setpoints.xml +12 -10
  562. data/example_files/resources/hpxml-measures/workflow/sample_files/base-schedules-simple-power-outage.xml +619 -619
  563. data/example_files/resources/hpxml-measures/workflow/sample_files/base-schedules-simple-vacancy.xml +618 -618
  564. data/example_files/resources/hpxml-measures/workflow/sample_files/base-schedules-simple.xml +9 -9
  565. data/example_files/resources/hpxml-measures/workflow/sample_files/base-simcontrol-calendar-year-custom.xml +9 -9
  566. data/example_files/resources/hpxml-measures/workflow/sample_files/base-simcontrol-daylight-saving-custom.xml +9 -9
  567. data/example_files/resources/hpxml-measures/workflow/sample_files/base-simcontrol-daylight-saving-disabled.xml +9 -9
  568. data/example_files/resources/hpxml-measures/workflow/sample_files/base-simcontrol-runperiod-1-month.xml +9 -9
  569. data/example_files/resources/hpxml-measures/workflow/sample_files/base-simcontrol-temperature-capacitance-multiplier.xml +553 -553
  570. data/example_files/resources/hpxml-measures/workflow/sample_files/base-simcontrol-timestep-10-mins-occupancy-stochastic-10-mins.xml +12 -10
  571. data/example_files/resources/hpxml-measures/workflow/sample_files/base-simcontrol-timestep-10-mins-occupancy-stochastic-60-mins.xml +12 -10
  572. data/example_files/resources/hpxml-measures/workflow/sample_files/base-simcontrol-timestep-10-mins.xml +9 -9
  573. data/example_files/resources/hpxml-measures/workflow/sample_files/base-simcontrol-timestep-30-mins.xml +552 -552
  574. data/example_files/resources/hpxml-measures/workflow/sample_files/base.xml +9 -9
  575. data/example_files/resources/hpxml-measures/workflow/template-build-and-run-hpxml-with-stochastic-occupancy.osw +2 -0
  576. data/example_files/resources/hpxml-measures/workflow/template-run-hpxml-with-stochastic-occupancy-subset.osw +2 -0
  577. data/example_files/resources/hpxml-measures/workflow/template-run-hpxml-with-stochastic-occupancy.osw +2 -0
  578. data/example_files/resources/hpxml-measures/workflow/template-run-hpxml.osw +4 -1
  579. data/example_files/resources/hpxml-measures/workflow/tests/ACCA_Examples/Long_Residence.xml +385 -385
  580. data/example_files/resources/hpxml-measures/workflow/tests/ACCA_Examples/Vatilo_Residence.xml +378 -380
  581. data/example_files/resources/hpxml-measures/workflow/tests/ACCA_Examples/Victor_Residence.xml +369 -369
  582. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L100AC.xml +7 -7
  583. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L100AL.xml +7 -7
  584. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L110AC.xml +7 -7
  585. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L110AL.xml +7 -7
  586. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L120AC.xml +7 -7
  587. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L120AL.xml +7 -7
  588. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L130AC.xml +7 -7
  589. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L130AL.xml +7 -7
  590. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L140AC.xml +7 -7
  591. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L140AL.xml +7 -7
  592. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L150AC.xml +7 -7
  593. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L150AL.xml +7 -7
  594. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L155AC.xml +7 -7
  595. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L155AL.xml +7 -7
  596. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L160AC.xml +7 -7
  597. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L160AL.xml +7 -7
  598. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L170AC.xml +7 -7
  599. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L170AL.xml +7 -7
  600. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L200AC.xml +7 -7
  601. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L200AL.xml +7 -7
  602. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L202AC.xml +7 -7
  603. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L202AL.xml +7 -7
  604. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L302XC.xml +7 -8
  605. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L304XC.xml +7 -8
  606. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L322XC.xml +6 -6
  607. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L324XC.xml +6 -6
  608. data/example_files/resources/hpxml-measures/workflow/tests/base_results/results_sizing.csv +363 -0
  609. data/example_files/resources/hpxml-measures/workflow/tests/base_results/results_workflow_simulations1.csv +281 -0
  610. data/example_files/resources/hpxml-measures/workflow/tests/base_results/results_workflow_simulations1_bills.csv +281 -0
  611. data/example_files/resources/hpxml-measures/workflow/tests/base_results/results_workflow_simulations2.csv +141 -0
  612. data/example_files/resources/hpxml-measures/workflow/tests/base_results/results_workflow_simulations2_bills.csv +141 -0
  613. data/example_files/resources/hpxml-measures/workflow/tests/compare.py +12 -6
  614. data/example_files/resources/hpxml-measures/workflow/tests/util.rb +1141 -0
  615. data/example_files/weather/USA_CO_Denver.Intl.AP.725650_TMY3.ddy +536 -0
  616. data/example_files/weather/USA_CO_Denver.Intl.AP.725650_TMY3.epw +8768 -0
  617. data/example_files/weather/USA_CO_Denver.Intl.AP.725650_TMY3.stat +554 -0
  618. data/example_files/weather/USA_FL_MacDill.AFB.747880_TMY3.ddy +536 -0
  619. data/example_files/weather/USA_FL_MacDill.AFB.747880_TMY3.epw +8768 -0
  620. data/example_files/weather/USA_FL_MacDill.AFB.747880_TMY3.stat +553 -0
  621. data/example_files/weather/USA_GA_Atlanta-Hartsfield-Jackson.Intl.AP.722190_TMY3-cache.csv +35 -0
  622. data/example_files/weather/USA_GA_Atlanta-Hartsfield-Jackson.Intl.AP.722190_TMY3.ddy +536 -0
  623. data/example_files/weather/USA_GA_Atlanta-Hartsfield-Jackson.Intl.AP.722190_TMY3.epw +8768 -0
  624. data/example_files/weather/USA_GA_Atlanta-Hartsfield-Jackson.Intl.AP.722190_TMY3.stat +553 -0
  625. data/example_files/weather/USA_NY_Buffalo-Greater.Buffalo.Intl.AP.725280_TMY3-cache.csv +35 -0
  626. data/example_files/xml_building/17/README.md +4 -2
  627. data/example_files/xml_building/17/feature.xml +2112 -0
  628. data/lib/uo_cli/version.rb +1 -1
  629. data/lib/uo_cli.rb +110 -17
  630. data/uo_cli.gemspec +6 -8
  631. metadata +130 -177
  632. data/Jenkinsfile +0 -10
  633. data/example_files/base_workflow_res.osw +0 -276
  634. data/example_files/resources/hpxml-measures/ReportUtilityBills/tests/utility_bills_test.rb +0 -1226
  635. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-oil-location-miami-fl.xml +0 -551
  636. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-propane-location-portland-or.xml +0 -551
  637. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-air-to-air-heat-pump-1-speed-cooling-only.xml +0 -544
  638. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-air-to-air-heat-pump-1-speed-heating-only.xml +0 -550
  639. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-air-to-air-heat-pump-1-speed-sizing-methodology-acca.xml +0 -552
  640. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-air-to-air-heat-pump-1-speed-sizing-methodology-hers.xml +0 -552
  641. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-air-to-air-heat-pump-1-speed-sizing-methodology-maxload-miami-fl.xml +0 -552
  642. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-air-to-air-heat-pump-1-speed-sizing-methodology-maxload.xml +0 -552
  643. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-air-to-air-heat-pump-2-speed-sizing-methodology-acca.xml +0 -552
  644. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-air-to-air-heat-pump-2-speed-sizing-methodology-hers.xml +0 -552
  645. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-air-to-air-heat-pump-2-speed-sizing-methodology-maxload.xml +0 -552
  646. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-air-to-air-heat-pump-var-speed-backup-boiler.xml +0 -569
  647. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-air-to-air-heat-pump-var-speed-backup-furnace.xml +0 -599
  648. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-air-to-air-heat-pump-var-speed-sizing-methodology-maxload.xml +0 -552
  649. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-boiler-elec-only.xml +0 -506
  650. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-boiler-gas-central-ac-1-speed.xml +0 -560
  651. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-boiler-gas-only.xml +0 -507
  652. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-central-ac-only-1-speed.xml +0 -536
  653. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-central-ac-only-2-speed.xml +0 -536
  654. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-central-ac-plus-air-to-air-heat-pump-heating.xml +0 -565
  655. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-dual-fuel-air-to-air-heat-pump-1-speed-sizing-methodology-acca.xml +0 -553
  656. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-dual-fuel-air-to-air-heat-pump-1-speed-sizing-methodology-hers.xml +0 -553
  657. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-dual-fuel-air-to-air-heat-pump-1-speed-sizing-methodology-maxload.xml +0 -553
  658. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-elec-resistance-only.xml +0 -497
  659. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-evap-cooler-furnace-gas.xml +0 -544
  660. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-floor-furnace-propane-only.xml +0 -500
  661. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-furnace-elec-only.xml +0 -536
  662. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-furnace-gas-central-ac-2-speed.xml +0 -551
  663. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-furnace-gas-central-ac-var-speed.xml +0 -551
  664. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-furnace-gas-only.xml +0 -536
  665. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-ground-to-air-heat-pump-cooling-only.xml +0 -546
  666. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-ground-to-air-heat-pump-heating-only.xml +0 -552
  667. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-ground-to-air-heat-pump-sizing-methodology-acca.xml +0 -554
  668. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-ground-to-air-heat-pump-sizing-methodology-hers.xml +0 -554
  669. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-ground-to-air-heat-pump-sizing-methodology-maxload.xml +0 -554
  670. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-mini-split-heat-pump-ducted-cooling-only.xml +0 -543
  671. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-mini-split-heat-pump-ducted-heating-only.xml +0 -549
  672. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-mini-split-heat-pump-ducted-sizing-methodology-acca.xml +0 -551
  673. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-mini-split-heat-pump-ducted-sizing-methodology-hers.xml +0 -551
  674. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-mini-split-heat-pump-ductless-backup-baseboard.xml +0 -519
  675. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-mini-split-heat-pump-ductless-backup-stove.xml +0 -522
  676. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-ptac-with-heating.xml +0 -503
  677. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-ptac.xml +0 -496
  678. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-pthp-sizing-methodology-acca.xml +0 -518
  679. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-pthp-sizing-methodology-hers.xml +0 -518
  680. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-pthp-sizing-methodology-maxload.xml +0 -518
  681. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-room-ac-only.xml +0 -496
  682. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-room-ac-with-heating.xml +0 -503
  683. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-room-ac-with-reverse-cycle-sizing-methodology-acca.xml +0 -518
  684. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-room-ac-with-reverse-cycle-sizing-methodology-hers.xml +0 -518
  685. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-room-ac-with-reverse-cycle-sizing-methodology-maxload.xml +0 -518
  686. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-stove-oil-only.xml +0 -500
  687. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-wall-furnace-elec-only.xml +0 -500
  688. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-floor-furnace-propane-only-pilot-light.xml +0 -506
  689. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-portable-heater-gas-only.xml +0 -501
  690. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-undersized-allow-increased-fixed-capacities.xml +0 -556
  691. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-bills-none.xml +0 -548
  692. data/example_files/resources/hpxml-measures/workflow/sample_files/base-schedules-simple-vacancy-year-round.xml +0 -619
  693. data/example_files/resources/hpxml-measures/workflow/tests/base_results/results.csv +0 -475
  694. data/example_files/resources/hpxml-measures/workflow/tests/base_results/results_bills.csv +0 -475
  695. data/example_files/resources/hpxml-measures/workflow/tests/hpxml_translator_test.rb +0 -1313
  696. data/example_files/resources/measure-info.json +0 -26
  697. data/example_files/resources/meta_measure.rb +0 -301
  698. data/example_files/xml_building/17/unit 1.xml +0 -580
  699. data/example_files/xml_building/17/unit 2.xml +0 -553
  700. data/example_files/xml_building/17/unit 3.xml +0 -553
  701. data/example_files/xml_building/17/unit 4.xml +0 -580
  702. /data/example_files/{residential → mappers/residential/template/iecc}/clothes_dryer.tsv +0 -0
  703. /data/example_files/{residential → mappers/residential/template/iecc}/clothes_washer.tsv +0 -0
  704. /data/example_files/{residential → mappers/residential/template/iecc}/cooling_system.tsv +0 -0
  705. /data/example_files/{residential → mappers/residential/template/iecc}/dishwasher.tsv +0 -0
  706. /data/example_files/{residential → mappers/residential/template/iecc}/enclosure.tsv +0 -0
  707. /data/example_files/{residential → mappers/residential/template/iecc}/heat_pump.tsv +0 -0
  708. /data/example_files/{residential → mappers/residential/template/iecc}/heating_system.tsv +0 -0
  709. /data/example_files/{residential → mappers/residential/template/iecc}/mechanical_ventilation.tsv +0 -0
  710. /data/example_files/{residential → mappers/residential/template/iecc}/refrigerator.tsv +0 -0
  711. /data/example_files/{residential → mappers/residential/template/iecc}/water_heater.tsv +0 -0
  712. /data/example_files/resources/hpxml-measures/ReportUtilityBills/tests/{JacksonElectricMemberCorp-ResidentialSeniorCitizenLowIncomeAssistance.json → Detailed Rate.json} +0 -0
@@ -1,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