urbanopt-cli 0.5.1 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (907) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -2
  3. data/CHANGELOG.md +43 -1
  4. data/CMakeLists.txt +14 -14
  5. data/FindOpenStudioSDK.cmake +11 -6
  6. data/Gemfile +11 -5
  7. data/LICENSE.md +11 -1
  8. data/Rakefile +16 -6
  9. data/example_files/Gemfile +8 -8
  10. data/example_files/example_project_combined.json +100 -5
  11. data/example_files/example_project_with_streets.json +826 -0
  12. data/example_files/mappers/Baseline.rb +107 -59
  13. data/example_files/mappers/CreateBar.rb +17 -7
  14. data/example_files/mappers/EvCharging.rb +20 -10
  15. data/example_files/mappers/Floorspace.rb +17 -7
  16. data/example_files/mappers/HighEfficiency.rb +20 -8
  17. data/example_files/mappers/HighEfficiencyCreateBar.rb +19 -8
  18. data/example_files/mappers/HighEfficiencyFloorspace.rb +19 -8
  19. data/example_files/mappers/ThermalStorage.rb +16 -6
  20. data/example_files/measures/BuildResidentialModel/measure.rb +249 -134
  21. data/example_files/reopt/base_assumptions.json +2 -2
  22. data/example_files/reopt/multiPV_assumptions.json +4 -3
  23. data/example_files/residential/clothes_dryer.tsv +7 -7
  24. data/example_files/residential/clothes_washer.tsv +1 -1
  25. data/example_files/residential/cooling_system.tsv +42 -22
  26. data/example_files/residential/dishwasher.tsv +1 -1
  27. data/example_files/residential/exhaust.tsv +3 -0
  28. data/example_files/residential/heat_pump.tsv +62 -40
  29. data/example_files/resources/hpxml-measures/.github/pull_request_template.md +2 -1
  30. data/example_files/resources/hpxml-measures/.github/workflows/config.yml +116 -0
  31. data/example_files/resources/hpxml-measures/.gitignore +1 -8
  32. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/measure.rb +746 -1236
  33. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/measure.xml +1550 -1215
  34. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/resources/constants.rb +0 -8
  35. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/resources/geometry.rb +432 -343
  36. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/resources/schedules.rb +134 -91
  37. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/resources/schedules_config.json +388 -0
  38. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/resources/schedules_config.md +43 -0
  39. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/resources/schedules_weekday_state_and_monthly_schedule_shift.csv +613 -0
  40. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/resources/schedules_weekend_state_and_monthly_schedule_shift.csv +613 -0
  41. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-appliances-coal.osw +36 -60
  42. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-appliances-dehumidifier-ief-portable.osw +35 -59
  43. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-appliances-dehumidifier-ief-whole-home.osw +35 -59
  44. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-appliances-dehumidifier.osw +35 -59
  45. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-appliances-gas.osw +36 -60
  46. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-appliances-modified.osw +36 -60
  47. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-appliances-none.osw +41 -65
  48. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-appliances-oil.osw +36 -60
  49. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-appliances-propane.osw +36 -60
  50. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-appliances-wood.osw +36 -60
  51. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-atticroof-flat.osw +36 -60
  52. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-atticroof-radiant-barrier.osw +36 -60
  53. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-atticroof-unvented-insulated-roof.osw +36 -60
  54. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-atticroof-vented.osw +36 -60
  55. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-bldgtype-multifamily-shared-boiler-only-baseboard.osw +341 -0
  56. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-bldgtype-multifamily-shared-boiler-only-fan-coil.osw +341 -0
  57. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-bldgtype-multifamily-shared-mechvent-preconditioning.osw +39 -63
  58. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-bldgtype-multifamily-shared-mechvent.osw +39 -63
  59. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-bldgtype-multifamily-shared-pv.osw +39 -63
  60. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-bldgtype-multifamily-shared-water-heater.osw +39 -63
  61. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-bldgtype-multifamily.osw +39 -63
  62. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-bldgtype-single-family-attached.osw +36 -60
  63. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-combi-tankless-outside.osw +36 -61
  64. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-combi-tankless.osw +36 -61
  65. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-dwhr.osw +36 -60
  66. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-indirect-outside.osw +36 -61
  67. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-indirect-standbyloss.osw +36 -61
  68. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-indirect-with-solar-fraction.osw +36 -61
  69. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-indirect.osw +36 -61
  70. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-jacket-electric.osw +36 -60
  71. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-jacket-gas.osw +36 -60
  72. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-jacket-hpwh.osw +36 -60
  73. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-jacket-indirect.osw +36 -61
  74. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-low-flow-fixtures.osw +36 -60
  75. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-none.osw +37 -61
  76. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-recirc-demand.osw +36 -60
  77. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-recirc-manual.osw +36 -60
  78. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-recirc-nocontrol.osw +36 -60
  79. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-recirc-temperature.osw +36 -60
  80. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-recirc-timer.osw +36 -60
  81. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-solar-direct-evacuated-tube.osw +36 -60
  82. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-solar-direct-flat-plate.osw +36 -60
  83. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-solar-direct-ics.osw +36 -60
  84. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-solar-fraction.osw +36 -60
  85. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-solar-indirect-flat-plate.osw +36 -60
  86. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-solar-thermosyphon-flat-plate.osw +36 -60
  87. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-tank-coal.osw +36 -60
  88. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-tank-elec-uef.osw +36 -60
  89. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-tank-gas-outside.osw +36 -60
  90. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-tank-gas-uef.osw +36 -60
  91. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-tank-gas.osw +36 -60
  92. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-tank-heat-pump-outside.osw +36 -60
  93. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-tank-heat-pump-uef.osw +36 -60
  94. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-tank-heat-pump-with-solar-fraction.osw +36 -60
  95. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-tank-heat-pump-with-solar.osw +36 -60
  96. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-tank-heat-pump.osw +36 -60
  97. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-tank-oil.osw +36 -60
  98. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-tank-wood.osw +36 -60
  99. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-tankless-electric-outside.osw +36 -60
  100. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-tankless-electric-uef.osw +36 -60
  101. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-tankless-electric.osw +36 -60
  102. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-tankless-gas-uef.osw +36 -60
  103. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-tankless-gas-with-solar-fraction.osw +36 -60
  104. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-tankless-gas-with-solar.osw +36 -60
  105. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-tankless-gas.osw +36 -60
  106. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-dhw-tankless-propane.osw +36 -60
  107. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-enclosure-2stories-garage.osw +36 -60
  108. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-enclosure-2stories.osw +36 -60
  109. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-enclosure-beds-1.osw +36 -60
  110. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-enclosure-beds-2.osw +36 -60
  111. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-enclosure-beds-4.osw +36 -60
  112. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-enclosure-beds-5.osw +36 -60
  113. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-enclosure-garage.osw +36 -60
  114. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-enclosure-infil-ach-house-pressure.osw +36 -60
  115. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-enclosure-infil-cfm-house-pressure.osw +36 -60
  116. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-enclosure-infil-cfm50.osw +36 -60
  117. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-enclosure-infil-flue.osw +36 -60
  118. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-enclosure-infil-natural-ach.osw +37 -61
  119. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-enclosure-overhangs.osw +37 -61
  120. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-enclosure-windows-none.osw +36 -60
  121. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-foundation-ambient.osw +36 -60
  122. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-foundation-conditioned-basement-slab-insulation.osw +36 -60
  123. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-foundation-slab.osw +36 -60
  124. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-foundation-unconditioned-basement-assembly-r.osw +35 -59
  125. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-foundation-unconditioned-basement-wall-insulation.osw +35 -59
  126. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-foundation-unconditioned-basement.osw +35 -59
  127. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-foundation-unvented-crawlspace.osw +35 -59
  128. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-foundation-vented-crawlspace.osw +35 -59
  129. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-air-to-air-heat-pump-1-speed-cooling-only.osw +337 -0
  130. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-air-to-air-heat-pump-1-speed-heating-only.osw +337 -0
  131. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-air-to-air-heat-pump-1-speed.osw +36 -61
  132. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-air-to-air-heat-pump-2-speed.osw +36 -60
  133. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-air-to-air-heat-pump-var-speed.osw +36 -60
  134. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-boiler-coal-only.osw +36 -60
  135. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-boiler-elec-only.osw +36 -60
  136. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-boiler-gas-central-ac-1-speed.osw +36 -61
  137. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-boiler-gas-only.osw +36 -61
  138. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-boiler-oil-only.osw +36 -60
  139. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-boiler-propane-only.osw +36 -60
  140. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-boiler-wood-only.osw +36 -60
  141. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-central-ac-only-1-speed.osw +36 -61
  142. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-central-ac-only-2-speed.osw +36 -60
  143. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-central-ac-only-var-speed.osw +36 -60
  144. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-central-ac-plus-air-to-air-heat-pump-heating.osw +36 -62
  145. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-dual-fuel-air-to-air-heat-pump-1-speed-electric.osw +35 -60
  146. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-dual-fuel-air-to-air-heat-pump-1-speed.osw +35 -60
  147. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-dual-fuel-air-to-air-heat-pump-2-speed.osw +35 -59
  148. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-dual-fuel-air-to-air-heat-pump-var-speed.osw +35 -59
  149. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-dual-fuel-mini-split-heat-pump-ducted.osw +36 -61
  150. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-ducts-leakage-percent.osw +36 -60
  151. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-elec-resistance-only.osw +36 -60
  152. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-evap-cooler-furnace-gas.osw +36 -60
  153. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-evap-cooler-only-ducted.osw +37 -61
  154. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-evap-cooler-only.osw +36 -61
  155. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-fireplace-wood-only.osw +36 -61
  156. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-fixed-heater-gas-only.osw +37 -62
  157. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-floor-furnace-propane-only.osw +36 -61
  158. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-furnace-coal-only.osw +337 -0
  159. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-furnace-elec-central-ac-1-speed.osw +36 -60
  160. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-furnace-elec-only.osw +36 -60
  161. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-furnace-gas-central-ac-2-speed.osw +36 -60
  162. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-furnace-gas-central-ac-var-speed.osw +36 -60
  163. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-furnace-gas-only.osw +36 -61
  164. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-furnace-gas-room-ac.osw +36 -60
  165. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-furnace-oil-only.osw +36 -60
  166. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-furnace-propane-only.osw +36 -60
  167. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-furnace-wood-only.osw +36 -60
  168. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-ground-to-air-heat-pump-cooling-only.osw +336 -0
  169. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-ground-to-air-heat-pump-heating-only.osw +336 -0
  170. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-ground-to-air-heat-pump.osw +36 -62
  171. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/{extra-plug-loads-additional-multipliers.osw → base-hvac-install-quality-airflow-defect-furnace-gas-central-ac-1-speed.osw} +41 -63
  172. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-install-quality-all-air-to-air-heat-pump-1-speed.osw +339 -0
  173. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-install-quality-all-air-to-air-heat-pump-2-speed.osw +339 -0
  174. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-install-quality-all-air-to-air-heat-pump-var-speed.osw +339 -0
  175. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-install-quality-all-furnace-gas-central-ac-1-speed.osw +340 -0
  176. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-install-quality-all-furnace-gas-central-ac-2-speed.osw +340 -0
  177. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-install-quality-all-furnace-gas-central-ac-var-speed.osw +340 -0
  178. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-install-quality-all-furnace-gas-only.osw +338 -0
  179. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-install-quality-all-ground-to-air-heat-pump.osw +338 -0
  180. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-install-quality-all-mini-split-air-conditioner-only-ducted.osw +338 -0
  181. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-install-quality-all-mini-split-heat-pump-ducted.osw +339 -0
  182. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-install-quality-charge-defect-furnace-gas-central-ac-1-speed.osw +338 -0
  183. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-install-quality-none-furnace-gas-central-ac-1-speed.osw +340 -0
  184. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-mini-split-air-conditioner-only-ducted.osw +36 -61
  185. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-mini-split-air-conditioner-only-ductless.osw +36 -61
  186. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-mini-split-heat-pump-ducted-cooling-only.osw +36 -61
  187. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-mini-split-heat-pump-ducted-heating-only.osw +36 -61
  188. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-mini-split-heat-pump-ducted.osw +37 -62
  189. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-mini-split-heat-pump-ductless.osw +37 -62
  190. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-none.osw +36 -60
  191. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-portable-heater-gas-only.osw +37 -62
  192. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-programmable-thermostat-detailed.osw +337 -0
  193. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-room-ac-only-33percent.osw +36 -60
  194. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-room-ac-only.osw +36 -60
  195. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-setpoints.osw +36 -60
  196. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-stove-oil-only.osw +36 -61
  197. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-stove-wood-pellets-only.osw +36 -61
  198. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-undersized.osw +36 -60
  199. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-hvac-wall-furnace-elec-only.osw +36 -61
  200. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-lighting-ceiling-fans.osw +36 -60
  201. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-lighting-detailed.osw +36 -60
  202. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-location-AMY-2012.osw +36 -60
  203. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-location-baltimore-md.osw +45 -69
  204. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-location-dallas-tx.osw +36 -60
  205. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-location-duluth-mn.osw +49 -73
  206. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-location-helena-mt.osw +337 -0
  207. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/{base-appliances-dehumidifier-50percent.osw → base-location-honolulu-hi.osw} +39 -63
  208. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-location-miami-fl.osw +36 -60
  209. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-location-phoenix-az.osw +337 -0
  210. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-location-portland-or.osw +337 -0
  211. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-mechvent-balanced.osw +36 -60
  212. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-mechvent-bath-kitchen-fans.osw +44 -70
  213. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-mechvent-cfis-evap-cooler-only-ducted.osw +37 -61
  214. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-mechvent-cfis.osw +36 -60
  215. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-mechvent-erv-atre-asre.osw +36 -60
  216. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-mechvent-erv.osw +36 -60
  217. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-mechvent-exhaust-rated-flow-rate.osw +337 -0
  218. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-mechvent-exhaust.osw +36 -60
  219. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-mechvent-hrv-asre.osw +36 -60
  220. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-mechvent-hrv.osw +36 -60
  221. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-mechvent-supply.osw +36 -60
  222. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-mechvent-whole-house-fan.osw +36 -60
  223. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-misc-defaults.osw +34 -58
  224. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-misc-loads-large-uncommon.osw +34 -58
  225. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-misc-loads-large-uncommon2.osw +34 -58
  226. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-misc-neighbor-shading.osw +36 -60
  227. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-misc-shielding-of-home.osw +337 -0
  228. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-misc-usage-multiplier.osw +35 -59
  229. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-pv.osw +36 -60
  230. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/{extra-vacancy-6-months.osw → base-schedules-stochastic-vacant.osw} +39 -63
  231. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-schedules-stochastic.osw +36 -60
  232. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-schedules-user-specified.osw +36 -60
  233. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-simcontrol-calendar-year-custom.osw +36 -60
  234. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-simcontrol-daylight-saving-custom.osw +36 -60
  235. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-simcontrol-daylight-saving-disabled.osw +36 -60
  236. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-simcontrol-runperiod-1-month.osw +36 -60
  237. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base-simcontrol-timestep-10-mins.osw +36 -60
  238. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/base.osw +36 -60
  239. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/build_residential_hpxml_test.rb +60 -57
  240. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-auto.osw +36 -60
  241. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-double-exterior.osw +341 -0
  242. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-double-loaded-interior.osw +341 -0
  243. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-eaves.osw +341 -0
  244. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-single-exterior-front.osw +341 -0
  245. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-slab-double-loaded-interior.osw +341 -0
  246. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-slab-left-bottom-double-loaded-interior.osw +341 -0
  247. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-slab-left-bottom.osw +341 -0
  248. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-slab-left-middle-double-loaded-interior.osw +341 -0
  249. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-slab-left-middle.osw +341 -0
  250. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-slab-left-top-double-loaded-interior.osw +341 -0
  251. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-slab-left-top.osw +341 -0
  252. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-slab-middle-bottom-double-loaded-interior.osw +341 -0
  253. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-slab-middle-bottom.osw +341 -0
  254. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-slab-middle-middle-double-loaded-interior.osw +341 -0
  255. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-slab-middle-middle.osw +341 -0
  256. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-slab-middle-top-double-loaded-interior.osw +341 -0
  257. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-slab-middle-top.osw +341 -0
  258. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-slab-right-bottom-double-loaded-interior.osw +341 -0
  259. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-slab-right-bottom.osw +341 -0
  260. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-slab-right-middle-double-loaded-interior.osw +341 -0
  261. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-slab-right-middle.osw +341 -0
  262. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-slab-right-top-double-loaded-interior.osw +341 -0
  263. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-slab-right-top.osw +341 -0
  264. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-slab.osw +341 -0
  265. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-unvented-crawlspace-double-loaded-interior.osw +341 -0
  266. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-unvented-crawlspace-left-bottom-double-loaded-interior.osw +341 -0
  267. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-unvented-crawlspace-left-bottom.osw +341 -0
  268. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-unvented-crawlspace-left-middle-double-loaded-interior.osw +341 -0
  269. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-unvented-crawlspace-left-middle.osw +341 -0
  270. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-unvented-crawlspace-left-top-double-loaded-interior.osw +341 -0
  271. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-unvented-crawlspace-left-top.osw +341 -0
  272. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-unvented-crawlspace-middle-bottom-double-loaded-interior.osw +341 -0
  273. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-unvented-crawlspace-middle-bottom.osw +341 -0
  274. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-unvented-crawlspace-middle-middle-double-loaded-interior.osw +341 -0
  275. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-unvented-crawlspace-middle-middle.osw +341 -0
  276. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-unvented-crawlspace-middle-top-double-loaded-interior.osw +341 -0
  277. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-unvented-crawlspace-middle-top.osw +341 -0
  278. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-unvented-crawlspace-right-bottom-double-loaded-interior.osw +341 -0
  279. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-unvented-crawlspace-right-bottom.osw +341 -0
  280. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-unvented-crawlspace-right-middle-double-loaded-interior.osw +341 -0
  281. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-unvented-crawlspace-right-middle.osw +341 -0
  282. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-unvented-crawlspace-right-top-double-loaded-interior.osw +341 -0
  283. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-unvented-crawlspace-right-top.osw +341 -0
  284. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-unvented-crawlspace.osw +341 -0
  285. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-vented-crawlspace-double-loaded-interior.osw +341 -0
  286. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-vented-crawlspace-left-bottom-double-loaded-interior.osw +341 -0
  287. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-vented-crawlspace-left-bottom.osw +341 -0
  288. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-vented-crawlspace-left-middle-double-loaded-interior.osw +341 -0
  289. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-vented-crawlspace-left-middle.osw +341 -0
  290. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-vented-crawlspace-left-top-double-loaded-interior.osw +341 -0
  291. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-vented-crawlspace-left-top.osw +341 -0
  292. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-vented-crawlspace-middle-bottom-double-loaded-interior.osw +341 -0
  293. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-vented-crawlspace-middle-bottom.osw +341 -0
  294. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-vented-crawlspace-middle-middle-double-loaded-interior.osw +341 -0
  295. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-vented-crawlspace-middle-middle.osw +341 -0
  296. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-vented-crawlspace-middle-top-double-loaded-interior.osw +341 -0
  297. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-vented-crawlspace-middle-top.osw +341 -0
  298. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-vented-crawlspace-right-bottom-double-loaded-interior.osw +341 -0
  299. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-vented-crawlspace-right-bottom.osw +341 -0
  300. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-vented-crawlspace-right-middle-double-loaded-interior.osw +341 -0
  301. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-vented-crawlspace-right-middle.osw +341 -0
  302. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-vented-crawlspace-right-top-double-loaded-interior.osw +341 -0
  303. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-vented-crawlspace-right-top.osw +341 -0
  304. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-multifamily-vented-crawlspace.osw +341 -0
  305. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-single-family-attached-atticroof-conditioned-eaves-gable.osw +339 -0
  306. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-single-family-attached-atticroof-conditioned-eaves-hip.osw +339 -0
  307. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-single-family-attached-atticroof-flat.osw +339 -0
  308. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-single-family-attached-double-exterior.osw +339 -0
  309. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-single-family-attached-double-loaded-interior.osw +339 -0
  310. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-single-family-attached-single-exterior-front.osw +339 -0
  311. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-single-family-attached-slab-middle.osw +339 -0
  312. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-single-family-attached-slab-right.osw +339 -0
  313. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-single-family-attached-slab.osw +339 -0
  314. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-single-family-attached-unconditioned-basement-middle.osw +339 -0
  315. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-single-family-attached-unconditioned-basement-right.osw +339 -0
  316. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-single-family-attached-unconditioned-basement.osw +339 -0
  317. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-single-family-attached-unvented-crawlspace-middle.osw +339 -0
  318. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-single-family-attached-unvented-crawlspace-right.osw +339 -0
  319. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-single-family-attached-unvented-crawlspace.osw +339 -0
  320. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-single-family-attached-vented-crawlspace-middle.osw +339 -0
  321. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-single-family-attached-vented-crawlspace-right.osw +339 -0
  322. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-bldgtype-single-family-attached-vented-crawlspace.osw +339 -0
  323. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-dhw-solar-latitude.osw +36 -60
  324. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-enclosure-atticroof-conditioned-eaves-gable.osw +337 -0
  325. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-enclosure-atticroof-conditioned-eaves-hip.osw +337 -0
  326. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-enclosure-garage-atticroof-conditioned.osw +337 -0
  327. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-enclosure-garage-partially-protruded.osw +36 -60
  328. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-enclosure-windows-shading.osw +339 -0
  329. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-gas-hot-tub-heater-with-zero-kwh.osw +337 -0
  330. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-gas-pool-heater-with-zero-kwh.osw +337 -0
  331. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-pv-roofpitch.osw +36 -60
  332. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-schedules-random-seed.osw +36 -60
  333. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-second-heating-system-boiler-to-heat-pump.osw +336 -0
  334. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-second-heating-system-boiler-to-heating-system.osw +337 -0
  335. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-second-heating-system-fireplace-to-heat-pump.osw +337 -0
  336. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/{extra-second-heating-system-fireplace.osw → extra-second-heating-system-fireplace-to-heating-system.osw} +38 -62
  337. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-second-heating-system-portable-heater-to-heat-pump.osw +337 -0
  338. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/{extra-second-heating-system-portable-heater.osw → extra-second-heating-system-portable-heater-to-heating-system.osw} +36 -60
  339. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-second-refrigerator.osw +36 -60
  340. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-zero-clothes-washer-kwh.osw +337 -0
  341. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-zero-dishwasher-kwh.osw +337 -0
  342. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-zero-extra-refrigerator-kwh.osw +337 -0
  343. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-zero-freezer-kwh.osw +337 -0
  344. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-zero-refrigerator-kwh.osw +337 -0
  345. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/invalid_files/conditioned-attic-with-floor-insulation.osw +39 -63
  346. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/invalid_files/conditioned-attic-with-one-floor-above-grade.osw +337 -0
  347. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/invalid_files/conditioned-basement-with-ceiling-insulation.osw +36 -60
  348. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/invalid_files/cooling-system-and-heat-pump.osw +36 -60
  349. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/invalid_files/dhw-indirect-without-boiler.osw +36 -60
  350. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/invalid_files/ducts-location-and-areas-not-same-type.osw +36 -60
  351. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/invalid_files/foundation-wall-insulation-greater-than-height.osw +337 -0
  352. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/invalid_files/heating-system-and-heat-pump.osw +36 -60
  353. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/invalid_files/multifamily-bottom-crawlspace-zero-foundation-height.osw +39 -63
  354. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/invalid_files/multifamily-bottom-slab-non-zero-foundation-height.osw +39 -63
  355. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/invalid_files/multifamily-no-building-orientation.osw +38 -62
  356. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/invalid_files/multipliers-without-fuel-loads.osw +36 -60
  357. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/invalid_files/multipliers-without-other-plug-loads.osw +337 -0
  358. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/invalid_files/{multipliers-without-plug-loads.osw → multipliers-without-tv-plug-loads.osw} +40 -64
  359. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/invalid_files/multipliers-without-vehicle-plug-loads.osw +337 -0
  360. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/invalid_files/multipliers-without-well-pump-plug-loads.osw +337 -0
  361. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/invalid_files/non-electric-heat-pump-water-heater.osw +36 -60
  362. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/invalid_files/non-integer-ceiling-fan-quantity.osw +36 -60
  363. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/invalid_files/non-integer-geometry-num-bathrooms.osw +36 -60
  364. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/invalid_files/second-heating-system-but-no-primary-heating.osw +337 -0
  365. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/invalid_files/second-heating-system-serves-majority-heat.osw +36 -60
  366. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/invalid_files/second-heating-system-serves-total-heat-load.osw +337 -0
  367. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/invalid_files/single-family-attached-ambient.osw +36 -60
  368. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/invalid_files/single-family-attached-no-building-orientation.osw +36 -60
  369. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/invalid_files/single-family-detached-finished-basement-zero-foundation-height.osw +36 -60
  370. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/invalid_files/single-family-detached-slab-non-zero-foundation-height.osw +36 -60
  371. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/invalid_files/single-family-detached-with-shared-system.osw +337 -0
  372. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/invalid_files/slab-non-zero-foundation-height-above-grade.osw +36 -60
  373. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/invalid_files/unconditioned-basement-with-wall-and-ceiling-insulation.osw +36 -60
  374. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/invalid_files/unvented-attic-with-floor-and-roof-insulation.osw +36 -60
  375. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/invalid_files/unvented-crawlspace-with-wall-and-ceiling-insulation.osw +36 -60
  376. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/invalid_files/vented-attic-with-floor-and-roof-insulation.osw +38 -62
  377. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/invalid_files/vented-crawlspace-with-wall-and-ceiling-insulation.osw +36 -60
  378. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/invalid_files/zero-number-of-bedrooms.osw +337 -0
  379. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/schedules/vacant.csv +8761 -0
  380. data/example_files/resources/hpxml-measures/Changelog.md +249 -0
  381. data/example_files/resources/hpxml-measures/Gemfile +3 -4
  382. data/example_files/resources/hpxml-measures/Gemfile.lock +27 -32
  383. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/measure.rb +318 -1283
  384. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/measure.xml +167 -121
  385. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/BaseElements.xsd +7 -97
  386. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/EPvalidator.xml +600 -203
  387. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/HPXMLDataTypes.xsd +21 -28
  388. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/HPXMLvalidator.xml +114 -22
  389. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/airflow.rb +112 -177
  390. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/constants.rb +16 -180
  391. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/constructions.rb +543 -94
  392. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/energyplus.rb +1 -0
  393. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/generator.rb +4 -7
  394. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/geometry.rb +410 -14
  395. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/hotwater_appliances.rb +27 -25
  396. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/hpxml.rb +782 -460
  397. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/hpxml_defaults.rb +455 -107
  398. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/hvac.rb +1466 -1403
  399. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/hvac_sizing.rb +1391 -1467
  400. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/lighting.rb +2 -1
  401. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/location.rb +20 -7
  402. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/meta_measure.rb +85 -13
  403. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/minitest_helper.rb +4 -26
  404. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/misc_loads.rb +14 -33
  405. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/pv.rb +3 -4
  406. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/schedules.rb +43 -7
  407. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/simcontrols.rb +24 -7
  408. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/unit_conversions.rb +2 -0
  409. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/version.rb +2 -2
  410. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/waterheater.rb +4 -4
  411. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/xmlhelper.rb +32 -30
  412. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_airflow.rb +6 -29
  413. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_defaults.rb +523 -635
  414. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_enclosure.rb +151 -0
  415. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_generator.rb +3 -1
  416. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_hotwater_appliance.rb +4 -2
  417. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_hvac.rb +297 -7
  418. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_hvac_sizing.rb +0 -1
  419. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_lighting.rb +3 -1
  420. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_location.rb +3 -1
  421. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_miscloads.rb +3 -1
  422. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_pv.rb +3 -1
  423. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_simcontrols.rb +3 -1
  424. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_validation.rb +26 -3
  425. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_water_heater.rb +3 -1
  426. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/util.rb +26 -0
  427. data/example_files/resources/hpxml-measures/README.md +4 -5
  428. data/example_files/resources/hpxml-measures/Rakefile +1 -2
  429. data/example_files/resources/hpxml-measures/SimulationOutputReport/measure.rb +140 -47
  430. data/example_files/resources/hpxml-measures/SimulationOutputReport/measure.xml +351 -495
  431. data/example_files/resources/hpxml-measures/SimulationOutputReport/tests/output_report_test.rb +260 -189
  432. data/example_files/resources/hpxml-measures/docs/source/conf.py +4 -1
  433. data/example_files/resources/hpxml-measures/docs/source/getting_started.rst +3 -3
  434. data/example_files/resources/hpxml-measures/docs/source/intro.rst +4 -105
  435. data/example_files/resources/hpxml-measures/docs/source/workflow_inputs.rst +538 -396
  436. data/example_files/resources/hpxml-measures/docs/source/workflow_outputs.rst +158 -130
  437. data/example_files/resources/hpxml-measures/tasks.rb +1497 -736
  438. data/example_files/resources/hpxml-measures/weather/USA_AZ_Phoenix-Sky.Harbor.Intl.AP.722780_TMY3-cache.csv +35 -0
  439. data/example_files/resources/hpxml-measures/weather/USA_AZ_Phoenix-Sky.Harbor.Intl.AP.722780_TMY3.epw +8768 -0
  440. data/example_files/resources/hpxml-measures/weather/USA_CO_Denver.Intl.AP.725650_TMY3-cache.csv +10 -10
  441. data/example_files/resources/hpxml-measures/weather/USA_HI_Honolulu.Intl.AP.911820_TMY3-cache.csv +35 -0
  442. data/example_files/resources/hpxml-measures/weather/USA_HI_Honolulu.Intl.AP.911820_TMY3.epw +8768 -0
  443. data/example_files/resources/hpxml-measures/weather/USA_MT_Helena.Rgnl.AP.727720_TMY3-cache.csv +35 -0
  444. data/example_files/resources/hpxml-measures/weather/USA_MT_Helena.Rgnl.AP.727720_TMY3.epw +8768 -0
  445. data/example_files/resources/hpxml-measures/weather/USA_OR_Portland.Intl.AP.726980_TMY3-cache.csv +35 -0
  446. data/example_files/resources/hpxml-measures/weather/USA_OR_Portland.Intl.AP.726980_TMY3.epw +8768 -0
  447. data/example_files/resources/hpxml-measures/workflow/run_simulation.rb +36 -5
  448. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-coal.xml +4 -3
  449. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-dehumidifier-ief-portable.xml +5 -3
  450. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-dehumidifier-ief-whole-home.xml +5 -3
  451. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-dehumidifier-multiple.xml +535 -0
  452. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-dehumidifier.xml +5 -3
  453. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-gas.xml +4 -3
  454. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-modified.xml +4 -3
  455. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-none.xml +4 -2
  456. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-oil.xml +4 -3
  457. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-propane.xml +4 -3
  458. data/example_files/resources/hpxml-measures/workflow/sample_files/base-appliances-wood.xml +4 -3
  459. data/example_files/resources/hpxml-measures/workflow/sample_files/base-atticroof-cathedral.xml +4 -3
  460. data/example_files/resources/hpxml-measures/workflow/sample_files/base-atticroof-conditioned.xml +6 -5
  461. data/example_files/resources/hpxml-measures/workflow/sample_files/base-atticroof-flat.xml +4 -3
  462. data/example_files/resources/hpxml-measures/workflow/sample_files/base-atticroof-radiant-barrier.xml +4 -3
  463. data/example_files/resources/hpxml-measures/workflow/sample_files/base-atticroof-unvented-insulated-roof.xml +4 -3
  464. data/example_files/resources/hpxml-measures/workflow/sample_files/base-atticroof-vented.xml +4 -3
  465. data/example_files/resources/hpxml-measures/workflow/sample_files/base-bldgtype-multifamily-adjacent-to-multifamily-buffer-space.xml +4 -3
  466. data/example_files/resources/hpxml-measures/workflow/sample_files/base-bldgtype-multifamily-adjacent-to-multiple.xml +4 -3
  467. data/example_files/resources/hpxml-measures/workflow/sample_files/base-bldgtype-multifamily-adjacent-to-non-freezing-space.xml +4 -3
  468. data/example_files/resources/hpxml-measures/workflow/sample_files/base-bldgtype-multifamily-adjacent-to-other-heated-space.xml +4 -3
  469. data/example_files/resources/hpxml-measures/workflow/sample_files/base-bldgtype-multifamily-adjacent-to-other-housing-unit.xml +4 -3
  470. data/example_files/resources/hpxml-measures/workflow/sample_files/base-bldgtype-multifamily-shared-boiler-chiller-baseboard.xml +0 -1
  471. data/example_files/resources/hpxml-measures/workflow/sample_files/base-bldgtype-multifamily-shared-boiler-chiller-fan-coil-ducted.xml +4 -4
  472. data/example_files/resources/hpxml-measures/workflow/sample_files/base-bldgtype-multifamily-shared-boiler-chiller-fan-coil.xml +3 -5
  473. data/example_files/resources/hpxml-measures/workflow/sample_files/base-bldgtype-multifamily-shared-boiler-chiller-water-loop-heat-pump.xml +28 -18
  474. data/example_files/resources/hpxml-measures/workflow/sample_files/base-bldgtype-multifamily-shared-boiler-cooling-tower-water-loop-heat-pump.xml +28 -18
  475. data/example_files/resources/hpxml-measures/workflow/sample_files/base-bldgtype-multifamily-shared-boiler-only-baseboard.xml +0 -1
  476. data/example_files/resources/hpxml-measures/workflow/sample_files/base-bldgtype-multifamily-shared-boiler-only-fan-coil-ducted.xml +4 -4
  477. data/example_files/resources/hpxml-measures/workflow/sample_files/base-bldgtype-multifamily-shared-boiler-only-fan-coil-eae.xml +3 -5
  478. data/example_files/resources/hpxml-measures/workflow/sample_files/base-bldgtype-multifamily-shared-boiler-only-fan-coil.xml +3 -5
  479. data/example_files/resources/hpxml-measures/workflow/sample_files/base-bldgtype-multifamily-shared-boiler-only-water-loop-heat-pump.xml +23 -11
  480. data/example_files/resources/hpxml-measures/workflow/sample_files/base-bldgtype-multifamily-shared-chiller-only-baseboard.xml +0 -1
  481. data/example_files/resources/hpxml-measures/workflow/sample_files/base-bldgtype-multifamily-shared-chiller-only-fan-coil-ducted.xml +4 -4
  482. data/example_files/resources/hpxml-measures/workflow/sample_files/base-bldgtype-multifamily-shared-chiller-only-fan-coil.xml +3 -5
  483. data/example_files/resources/hpxml-measures/workflow/sample_files/base-bldgtype-multifamily-shared-chiller-only-water-loop-heat-pump.xml +23 -12
  484. data/example_files/resources/hpxml-measures/workflow/sample_files/base-bldgtype-multifamily-shared-cooling-tower-only-water-loop-heat-pump.xml +23 -12
  485. data/example_files/resources/hpxml-measures/workflow/sample_files/base-bldgtype-multifamily-shared-generator.xml +4 -3
  486. data/example_files/resources/hpxml-measures/workflow/sample_files/base-bldgtype-multifamily-shared-ground-loop-ground-to-air-heat-pump.xml +6 -6
  487. data/example_files/resources/hpxml-measures/workflow/sample_files/base-bldgtype-multifamily-shared-laundry-room.xml +4 -3
  488. data/example_files/resources/hpxml-measures/workflow/sample_files/base-bldgtype-multifamily-shared-mechvent-multiple.xml +8 -5
  489. data/example_files/resources/hpxml-measures/workflow/sample_files/base-bldgtype-multifamily-shared-mechvent-preconditioning.xml +4 -3
  490. data/example_files/resources/hpxml-measures/workflow/sample_files/base-bldgtype-multifamily-shared-mechvent.xml +4 -3
  491. data/example_files/resources/hpxml-measures/workflow/sample_files/base-bldgtype-multifamily-shared-pv.xml +4 -3
  492. data/example_files/resources/hpxml-measures/workflow/sample_files/base-bldgtype-multifamily-shared-water-heater-recirc.xml +4 -3
  493. data/example_files/resources/hpxml-measures/workflow/sample_files/base-bldgtype-multifamily-shared-water-heater.xml +4 -3
  494. data/example_files/resources/hpxml-measures/workflow/sample_files/base-bldgtype-multifamily.xml +4 -3
  495. data/example_files/resources/hpxml-measures/workflow/sample_files/base-bldgtype-single-family-attached.xml +17 -4
  496. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-combi-tankless-outside.xml +1 -2
  497. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-combi-tankless.xml +1 -2
  498. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-desuperheater-2-speed.xml +3 -2
  499. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-desuperheater-gshp.xml +564 -564
  500. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-desuperheater-hpwh.xml +4 -3
  501. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-desuperheater-tankless.xml +3 -5
  502. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-desuperheater-var-speed.xml +3 -2
  503. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-desuperheater.xml +3 -5
  504. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-dwhr.xml +4 -3
  505. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-indirect-dse.xml +1 -2
  506. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-indirect-outside.xml +1 -2
  507. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-indirect-standbyloss.xml +1 -2
  508. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-indirect-with-solar-fraction.xml +1 -2
  509. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-indirect.xml +1 -2
  510. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-jacket-electric.xml +4 -3
  511. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-jacket-gas.xml +4 -3
  512. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-jacket-hpwh.xml +4 -3
  513. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-jacket-indirect.xml +1 -2
  514. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-low-flow-fixtures.xml +4 -3
  515. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-multiple.xml +1 -2
  516. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-none.xml +4 -2
  517. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-recirc-demand.xml +4 -3
  518. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-recirc-manual.xml +4 -3
  519. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-recirc-nocontrol.xml +4 -3
  520. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-recirc-temperature.xml +4 -3
  521. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-recirc-timer.xml +4 -3
  522. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-solar-direct-evacuated-tube.xml +4 -3
  523. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-solar-direct-flat-plate.xml +4 -3
  524. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-solar-direct-ics.xml +4 -3
  525. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-solar-fraction.xml +4 -3
  526. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-solar-indirect-flat-plate.xml +4 -3
  527. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-solar-thermosyphon-flat-plate.xml +4 -3
  528. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-coal.xml +4 -3
  529. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-elec-uef.xml +4 -3
  530. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-gas-outside.xml +4 -3
  531. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-gas-uef.xml +4 -3
  532. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-gas.xml +4 -3
  533. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-heat-pump-outside.xml +4 -3
  534. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-heat-pump-uef.xml +4 -3
  535. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-heat-pump-with-solar-fraction.xml +4 -3
  536. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-heat-pump-with-solar.xml +4 -3
  537. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-heat-pump.xml +4 -3
  538. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-oil.xml +4 -3
  539. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tank-wood.xml +4 -3
  540. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tankless-electric-outside.xml +4 -3
  541. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tankless-electric-uef.xml +4 -3
  542. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tankless-electric.xml +4 -3
  543. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tankless-gas-uef.xml +4 -3
  544. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tankless-gas-with-solar-fraction.xml +4 -3
  545. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tankless-gas-with-solar.xml +4 -3
  546. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tankless-gas.xml +4 -3
  547. data/example_files/resources/hpxml-measures/workflow/sample_files/base-dhw-tankless-propane.xml +4 -3
  548. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-2stories-garage.xml +5 -4
  549. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-2stories.xml +4 -3
  550. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-beds-1.xml +4 -3
  551. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-beds-2.xml +4 -3
  552. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-beds-4.xml +4 -3
  553. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-beds-5.xml +4 -3
  554. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-garage.xml +4 -3
  555. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-infil-ach-house-pressure.xml +4 -3
  556. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-infil-cfm-house-pressure.xml +4 -3
  557. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-infil-cfm50.xml +4 -3
  558. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-infil-flue.xml +4 -3
  559. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-infil-natural-ach.xml +5 -4
  560. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-overhangs.xml +9 -3
  561. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-rooftypes.xml +4 -3
  562. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-skylights-shading.xml +601 -0
  563. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-skylights.xml +6 -5
  564. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-split-level.xml +4 -3
  565. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-split-surfaces.xml +22 -21
  566. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-split-surfaces2.xml +2475 -0
  567. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-walltypes.xml +4 -3
  568. data/example_files/resources/hpxml-measures/workflow/sample_files/base-enclosure-windows-none.xml +4 -3
  569. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-enclosure-windows-interior-shading.xml → base-enclosure-windows-shading.xml} +577 -561
  570. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-ambient.xml +4 -3
  571. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-basement-garage.xml +644 -0
  572. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-complex.xml +4 -3
  573. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-conditioned-basement-slab-insulation.xml +4 -3
  574. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-conditioned-basement-wall-interior-insulation.xml +4 -3
  575. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-multiple.xml +6 -5
  576. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-slab.xml +4 -3
  577. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-unconditioned-basement-above-grade.xml +5 -4
  578. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-unconditioned-basement-assembly-r.xml +5 -4
  579. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-unconditioned-basement-wall-insulation.xml +4 -3
  580. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-unconditioned-basement.xml +5 -4
  581. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-unvented-crawlspace.xml +4 -3
  582. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-vented-crawlspace.xml +4 -3
  583. data/example_files/resources/hpxml-measures/workflow/sample_files/base-foundation-walkout-basement.xml +4 -3
  584. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-air-to-air-heat-pump-1-speed-cooling-only.xml +556 -0
  585. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-air-to-air-heat-pump-1-speed-heating-only.xml +562 -0
  586. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-air-to-air-heat-pump-1-speed.xml +6 -8
  587. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-air-to-air-heat-pump-2-speed.xml +6 -5
  588. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-air-to-air-heat-pump-var-speed.xml +6 -5
  589. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-air-to-air-heat-pump-1-speed-cooling-only.xml +553 -0
  590. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-air-to-air-heat-pump-1-speed-heating-only.xml +558 -0
  591. data/example_files/resources/hpxml-measures/workflow/sample_files/{hvac_autosizing/base-hvac-air-to-air-heat-pump-1-speed-autosize-manual-s-oversize-allowances.xml → base-hvac-autosize-air-to-air-heat-pump-1-speed-manual-s-oversize-allowances.xml} +2 -4
  592. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-air-to-air-heat-pump-1-speed.xml +558 -0
  593. data/example_files/resources/hpxml-measures/workflow/sample_files/{hvac_autosizing/base-hvac-air-to-air-heat-pump-2-speed-autosize-manual-s-oversize-allowances.xml → base-hvac-autosize-air-to-air-heat-pump-2-speed-manual-s-oversize-allowances.xml} +560 -559
  594. data/example_files/resources/hpxml-measures/workflow/sample_files/{hvac_autosizing/base-hvac-air-to-air-heat-pump-2-speed-autosize.xml → base-hvac-autosize-air-to-air-heat-pump-2-speed.xml} +557 -556
  595. data/example_files/resources/hpxml-measures/workflow/sample_files/{hvac_autosizing/base-hvac-air-to-air-heat-pump-var-speed-autosize-manual-s-oversize-allowances.xml → base-hvac-autosize-air-to-air-heat-pump-var-speed-manual-s-oversize-allowances.xml} +560 -559
  596. data/example_files/resources/hpxml-measures/workflow/sample_files/{hvac_autosizing/base-hvac-air-to-air-heat-pump-var-speed-autosize.xml → base-hvac-autosize-air-to-air-heat-pump-var-speed.xml} +557 -556
  597. data/example_files/resources/hpxml-measures/workflow/sample_files/{hvac_autosizing/base-hvac-boiler-elec-only-autosize.xml → base-hvac-autosize-boiler-elec-only.xml} +517 -518
  598. data/example_files/resources/hpxml-measures/workflow/sample_files/{hvac_autosizing/base-hvac-boiler-gas-central-ac-1-speed-autosize.xml → base-hvac-autosize-boiler-gas-central-ac-1-speed.xml} +569 -569
  599. data/example_files/resources/hpxml-measures/workflow/sample_files/{hvac_autosizing/base-hvac-boiler-gas-only-autosize.xml → base-hvac-autosize-boiler-gas-only.xml} +518 -519
  600. data/example_files/resources/hpxml-measures/workflow/sample_files/{hvac_autosizing/base-hvac-central-ac-only-1-speed-autosize.xml → base-hvac-autosize-central-ac-only-1-speed.xml} +2 -4
  601. data/example_files/resources/hpxml-measures/workflow/sample_files/{hvac_autosizing/base-hvac-central-ac-only-2-speed-autosize.xml → base-hvac-autosize-central-ac-only-2-speed.xml} +547 -546
  602. data/example_files/resources/hpxml-measures/workflow/sample_files/{hvac_autosizing/base-hvac-central-ac-only-var-speed-autosize.xml → base-hvac-autosize-central-ac-only-var-speed.xml} +547 -546
  603. data/example_files/resources/hpxml-measures/workflow/sample_files/{hvac_autosizing/base-hvac-central-ac-plus-air-to-air-heat-pump-heating-autosize.xml → base-hvac-autosize-central-ac-plus-air-to-air-heat-pump-heating.xml} +2 -7
  604. data/example_files/resources/hpxml-measures/workflow/sample_files/{hvac_autosizing/base-hvac-dual-fuel-air-to-air-heat-pump-1-speed-autosize.xml → base-hvac-autosize-dual-fuel-air-to-air-heat-pump-1-speed.xml} +2 -4
  605. data/example_files/resources/hpxml-measures/workflow/sample_files/{hvac_autosizing/base-hvac-dual-fuel-mini-split-heat-pump-ducted-autosize.xml → base-hvac-autosize-dual-fuel-mini-split-heat-pump-ducted.xml} +2 -4
  606. data/example_files/resources/hpxml-measures/workflow/sample_files/{hvac_autosizing/base-hvac-elec-resistance-only-autosize.xml → base-hvac-autosize-elec-resistance-only.xml} +508 -509
  607. data/example_files/resources/hpxml-measures/workflow/sample_files/{hvac_autosizing/base-hvac-evap-cooler-furnace-gas-autosize.xml → base-hvac-autosize-evap-cooler-furnace-gas.xml} +553 -552
  608. data/example_files/resources/hpxml-measures/workflow/sample_files/{hvac_autosizing/base-hvac-floor-furnace-propane-only-autosize.xml → base-hvac-autosize-floor-furnace-propane-only.xml} +511 -512
  609. data/example_files/resources/hpxml-measures/workflow/sample_files/{hvac_autosizing/base-hvac-furnace-elec-only-autosize.xml → base-hvac-autosize-furnace-elec-only.xml} +547 -546
  610. data/example_files/resources/hpxml-measures/workflow/sample_files/{hvac_autosizing/base-hvac-furnace-gas-central-ac-2-speed-autosize.xml → base-hvac-autosize-furnace-gas-central-ac-2-speed.xml} +560 -559
  611. data/example_files/resources/hpxml-measures/workflow/sample_files/{hvac_autosizing/base-hvac-furnace-gas-central-ac-var-speed-autosize.xml → base-hvac-autosize-furnace-gas-central-ac-var-speed.xml} +560 -559
  612. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-furnace-gas-only.xml +548 -0
  613. data/example_files/resources/hpxml-measures/workflow/sample_files/{hvac_autosizing/base-hvac-furnace-gas-room-ac-autosize.xml → base-hvac-autosize-furnace-gas-room-ac.xml} +558 -557
  614. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-ground-to-air-heat-pump-cooling-only.xml +555 -0
  615. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-ground-to-air-heat-pump-heating-only.xml +560 -0
  616. data/example_files/resources/hpxml-measures/workflow/sample_files/{hvac_autosizing/base-hvac-ground-to-air-heat-pump-autosize-manual-s-oversize-allowances.xml → base-hvac-autosize-ground-to-air-heat-pump-manual-s-oversize-allowances.xml} +562 -562
  617. data/example_files/resources/hpxml-measures/workflow/sample_files/{hvac_autosizing/base-hvac-ground-to-air-heat-pump-autosize.xml → base-hvac-autosize-ground-to-air-heat-pump.xml} +559 -559
  618. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-mini-split-air-conditioner-only-ducted.xml +547 -0
  619. data/example_files/resources/hpxml-measures/workflow/sample_files/{hvac_autosizing/base-hvac-mini-split-heat-pump-ducted-cooling-only-autosize.xml → base-hvac-autosize-mini-split-heat-pump-ducted-cooling-only.xml} +2 -4
  620. data/example_files/resources/hpxml-measures/workflow/sample_files/{hvac_autosizing/base-hvac-mini-split-heat-pump-ducted-heating-only-autosize.xml → base-hvac-autosize-mini-split-heat-pump-ducted-heating-only.xml} +2 -4
  621. data/example_files/resources/hpxml-measures/workflow/sample_files/{hvac_autosizing/base-hvac-mini-split-heat-pump-ducted-autosize-manual-s-oversize-allowances.xml → base-hvac-autosize-mini-split-heat-pump-ducted-manual-s-oversize-allowances.xml} +2 -4
  622. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-autosize-mini-split-heat-pump-ducted.xml +557 -0
  623. data/example_files/resources/hpxml-measures/workflow/sample_files/{hvac_autosizing/base-hvac-room-ac-only-autosize.xml → base-hvac-autosize-room-ac-only.xml} +507 -508
  624. data/example_files/resources/hpxml-measures/workflow/sample_files/{hvac_autosizing/base-hvac-stove-oil-only-autosize.xml → base-hvac-autosize-stove-oil-only.xml} +511 -512
  625. data/example_files/resources/hpxml-measures/workflow/sample_files/{hvac_autosizing/base-hvac-wall-furnace-elec-only-autosize.xml → base-hvac-autosize-wall-furnace-elec-only.xml} +511 -512
  626. data/example_files/resources/hpxml-measures/workflow/sample_files/{hvac_autosizing/base-autosize.xml → base-hvac-autosize.xml} +560 -559
  627. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-boiler-coal-only.xml +1 -2
  628. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-boiler-elec-only.xml +1 -2
  629. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-boiler-gas-central-ac-1-speed.xml +4 -4
  630. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-boiler-gas-only.xml +1 -2
  631. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-boiler-oil-only.xml +1 -2
  632. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-boiler-propane-only.xml +1 -2
  633. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-boiler-wood-only.xml +1 -2
  634. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-central-ac-only-1-speed.xml +3 -5
  635. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-central-ac-only-2-speed.xml +3 -2
  636. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-central-ac-only-var-speed.xml +3 -2
  637. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-central-ac-plus-air-to-air-heat-pump-heating.xml +7 -12
  638. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-dse.xml +2 -3
  639. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-dual-fuel-air-to-air-heat-pump-1-speed-electric.xml +5 -7
  640. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-dual-fuel-air-to-air-heat-pump-1-speed.xml +5 -7
  641. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-dual-fuel-air-to-air-heat-pump-2-speed.xml +5 -4
  642. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-dual-fuel-air-to-air-heat-pump-var-speed.xml +5 -4
  643. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-dual-fuel-mini-split-heat-pump-ducted.xml +5 -7
  644. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-ducts-leakage-percent.xml +4 -3
  645. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-elec-resistance-only.xml +1 -2
  646. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-evap-cooler-furnace-gas.xml +4 -2
  647. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-evap-cooler-only-ducted.xml +11 -1
  648. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-evap-cooler-only.xml +1 -4
  649. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-fireplace-wood-only.xml +512 -513
  650. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-fixed-heater-gas-only.xml +512 -563
  651. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-floor-furnace-propane-only.xml +512 -513
  652. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-coal-only.xml +548 -547
  653. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-elec-central-ac-1-speed.xml +4 -3
  654. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-elec-only.xml +3 -2
  655. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-gas-central-ac-2-speed.xml +4 -3
  656. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-gas-central-ac-var-speed.xml +4 -3
  657. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-gas-only.xml +548 -550
  658. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-gas-room-ac.xml +4 -3
  659. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-oil-only.xml +3 -2
  660. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-propane-only.xml +3 -2
  661. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-wood-only.xml +3 -2
  662. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-furnace-x3-dse.xml +4 -5
  663. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-ground-to-air-heat-pump-cooling-only.xml +557 -0
  664. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-ground-to-air-heat-pump-heating-only.xml +563 -0
  665. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-ground-to-air-heat-pump.xml +562 -562
  666. data/example_files/resources/hpxml-measures/workflow/sample_files/{invalid_files/slab-zero-exposed-perimeter.xml → base-hvac-install-quality-airflow-defect-furnace-gas-central-ac-1-speed.xml} +568 -561
  667. data/example_files/resources/hpxml-measures/workflow/sample_files/{hvac_autosizing/base-hvac-air-to-air-heat-pump-1-speed-autosize.xml → base-hvac-install-quality-all-air-to-air-heat-pump-1-speed.xml} +566 -559
  668. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-install-quality-all-air-to-air-heat-pump-2-speed.xml +567 -0
  669. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-install-quality-all-air-to-air-heat-pump-var-speed.xml +567 -0
  670. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-misc-shelter-coefficient.xml → base-hvac-install-quality-all-furnace-gas-central-ac-1-speed.xml} +571 -564
  671. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-install-quality-all-furnace-gas-central-ac-2-speed.xml +572 -0
  672. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-install-quality-all-furnace-gas-central-ac-var-speed.xml +572 -0
  673. data/example_files/resources/hpxml-measures/workflow/sample_files/{hvac_autosizing/base-hvac-furnace-gas-only-autosize.xml → base-hvac-install-quality-all-furnace-gas-only.xml} +552 -549
  674. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-install-quality-all-ground-to-air-heat-pump.xml +566 -0
  675. data/example_files/resources/hpxml-measures/workflow/sample_files/{hvac_autosizing/base-hvac-mini-split-air-conditioner-only-ducted-autosize.xml → base-hvac-install-quality-all-mini-split-air-conditioner-only-ducted.xml} +552 -548
  676. data/example_files/resources/hpxml-measures/workflow/sample_files/{hvac_autosizing/base-hvac-mini-split-heat-pump-ducted-autosize.xml → base-hvac-install-quality-all-mini-split-heat-pump-ducted.xml} +565 -558
  677. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-install-quality-blower-efficiency-furnace-gas-central-ac-1-speed.xml +569 -0
  678. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-install-quality-charge-defect-furnace-gas-central-ac-1-speed.xml +566 -0
  679. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-install-quality-none-furnace-gas-central-ac-1-speed.xml +570 -0
  680. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-mini-split-air-conditioner-only-ducted.xml +3 -5
  681. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-mini-split-air-conditioner-only-ductless.xml +1 -5
  682. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-mini-split-heat-pump-ducted-cooling-only.xml +3 -5
  683. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-mini-split-heat-pump-ducted-heating-only.xml +5 -7
  684. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-mini-split-heat-pump-ducted.xml +6 -8
  685. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-mini-split-heat-pump-ductless.xml +3 -7
  686. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-multiple.xml +920 -913
  687. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-none.xml +0 -1
  688. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-portable-heater-gas-only.xml +512 -563
  689. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-programmable-thermostat-detailed.xml +7 -6
  690. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-programmable-thermostat.xml +4 -3
  691. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-room-ac-only-33percent.xml +1 -2
  692. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-room-ac-only.xml +1 -2
  693. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-setpoints.xml +4 -3
  694. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-stove-oil-only.xml +512 -513
  695. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-stove-wood-pellets-only.xml +512 -513
  696. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-undersized-allow-increased-fixed-capacities.xml +4 -3
  697. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-undersized.xml +4 -3
  698. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-wall-furnace-elec-only.xml +512 -513
  699. data/example_files/resources/hpxml-measures/workflow/sample_files/base-lighting-ceiling-fans.xml +4 -3
  700. data/example_files/resources/hpxml-measures/workflow/sample_files/base-lighting-detailed.xml +4 -3
  701. data/example_files/resources/hpxml-measures/workflow/sample_files/base-lighting-none.xml +4 -3
  702. data/example_files/resources/hpxml-measures/workflow/sample_files/base-location-AMY-2012.xml +4 -3
  703. data/example_files/resources/hpxml-measures/workflow/sample_files/base-location-baltimore-md.xml +37 -25
  704. data/example_files/resources/hpxml-measures/workflow/sample_files/base-location-dallas-tx.xml +4 -3
  705. data/example_files/resources/hpxml-measures/workflow/sample_files/base-location-duluth-mn.xml +37 -25
  706. data/example_files/resources/hpxml-measures/workflow/sample_files/base-location-helena-mt.xml +563 -0
  707. data/example_files/resources/hpxml-measures/workflow/sample_files/base-location-honolulu-hi.xml +517 -0
  708. data/example_files/resources/hpxml-measures/workflow/sample_files/base-location-miami-fl.xml +4 -3
  709. data/example_files/resources/hpxml-measures/workflow/sample_files/base-location-phoenix-az.xml +517 -0
  710. data/example_files/resources/hpxml-measures/workflow/sample_files/base-location-portland-or.xml +577 -0
  711. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-balanced.xml +4 -3
  712. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-bath-kitchen-fans.xml +4 -3
  713. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-cfis-dse.xml +2 -3
  714. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-cfis-evap-cooler-only-ducted.xml +11 -1
  715. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-cfis.xml +4 -3
  716. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-erv-atre-asre.xml +4 -3
  717. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-erv.xml +4 -3
  718. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-exhaust-rated-flow-rate.xml +4 -3
  719. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-exhaust.xml +4 -3
  720. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-hrv-asre.xml +4 -3
  721. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-hrv.xml +4 -3
  722. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-multiple.xml +32 -29
  723. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-supply.xml +4 -3
  724. data/example_files/resources/hpxml-measures/workflow/sample_files/base-mechvent-whole-house-fan.xml +4 -3
  725. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-defaults.xml +4 -2
  726. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-generators.xml +5 -4
  727. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-loads-large-uncommon.xml +8 -3
  728. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-loads-large-uncommon2.xml +12 -3
  729. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-loads-none.xml +4 -3
  730. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-neighbor-shading.xml +4 -3
  731. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-shielding-of-home.xml +564 -0
  732. data/example_files/resources/hpxml-measures/workflow/sample_files/base-misc-usage-multiplier.xml +8 -3
  733. data/example_files/resources/hpxml-measures/workflow/sample_files/base-multiple-buildings.xml +1657 -0
  734. data/example_files/resources/hpxml-measures/workflow/sample_files/base-pv.xml +4 -3
  735. data/example_files/resources/hpxml-measures/workflow/sample_files/base-schedules-stochastic-vacant.xml +564 -0
  736. data/example_files/resources/hpxml-measures/workflow/sample_files/base-schedules-stochastic.xml +4 -3
  737. data/example_files/resources/hpxml-measures/workflow/sample_files/base-schedules-user-specified.xml +4 -3
  738. data/example_files/resources/hpxml-measures/workflow/sample_files/base-simcontrol-calendar-year-custom.xml +4 -3
  739. data/example_files/resources/hpxml-measures/workflow/sample_files/base-simcontrol-daylight-saving-custom.xml +4 -3
  740. data/example_files/resources/hpxml-measures/workflow/sample_files/base-simcontrol-daylight-saving-disabled.xml +4 -3
  741. data/example_files/resources/hpxml-measures/workflow/sample_files/base-simcontrol-runperiod-1-month.xml +4 -3
  742. data/example_files/resources/hpxml-measures/workflow/sample_files/base-simcontrol-timestep-10-mins.xml +4 -3
  743. data/example_files/resources/hpxml-measures/workflow/sample_files/base.xml +4 -3
  744. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/boiler-invalid-afue.xml +519 -0
  745. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/cfis-with-hydronic-distribution.xml +1 -2
  746. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/clothes-dryer-location.xml +4 -3
  747. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/clothes-washer-location.xml +4 -3
  748. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/cooking-range-location.xml +4 -3
  749. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-appliances-dehumidifier-50percent.xml → invalid_files/dehumidifier-fraction-served.xml} +534 -523
  750. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/dehumidifier-setpoints.xml +535 -0
  751. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/dhw-frac-load-served.xml +1 -2
  752. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/dhw-invalid-ef-tank.xml +4 -3
  753. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/dhw-invalid-uef-tank-heat-pump.xml +4 -3
  754. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/dishwasher-location.xml +4 -3
  755. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/duct-leakage-cfm25.xml +563 -0
  756. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/duct-leakage-percent.xml +563 -0
  757. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/duct-location-unconditioned-space.xml +4 -3
  758. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/duct-location.xml +4 -3
  759. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/duplicate-id.xml +4 -3
  760. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/enclosure-attic-missing-roof.xml +4 -3
  761. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/enclosure-basement-missing-exterior-foundation-wall.xml +5 -4
  762. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/enclosure-basement-missing-slab.xml +5 -4
  763. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/enclosure-floor-area-exceeds-cfa.xml +7 -6
  764. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/enclosure-floor-area-exceeds-cfa2.xml +448 -0
  765. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/enclosure-garage-missing-exterior-wall.xml +4 -3
  766. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/enclosure-garage-missing-roof-ceiling.xml +4 -3
  767. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/enclosure-garage-missing-slab.xml +4 -3
  768. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/enclosure-living-missing-ceiling-roof.xml +4 -3
  769. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/enclosure-living-missing-exterior-wall.xml +4 -3
  770. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/enclosure-living-missing-floor-slab.xml +14 -60
  771. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/frac-sensible-fuel-load.xml +760 -0
  772. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/frac-sensible-plug-load.xml +759 -0
  773. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/frac-total-fuel-load.xml +761 -0
  774. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/frac-total-plug-load.xml +759 -0
  775. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/furnace-invalid-afue.xml +563 -0
  776. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/generator-number-of-bedrooms-served.xml +460 -0
  777. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/generator-output-greater-than-consumption.xml +579 -0
  778. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/heat-pump-mixed-fixed-and-autosize-capacities.xml +3 -5
  779. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/hvac-distribution-multiple-attached-cooling.xml +920 -913
  780. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/hvac-distribution-multiple-attached-heating.xml +920 -913
  781. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/hvac-distribution-return-duct-leakage-missing.xml +3 -7
  782. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/hvac-dse-multiple-attached-cooling.xml +3 -4
  783. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/hvac-dse-multiple-attached-heating.xml +3 -4
  784. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/hvac-frac-load-served.xml +920 -913
  785. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/hvac-inconsistent-fan-powers.xml +4 -3
  786. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/hvac-invalid-distribution-system-type.xml +4 -3
  787. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/hvac-shared-negative-seer-eq.xml +407 -0
  788. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/invalid-assembly-effective-rvalue.xml +563 -0
  789. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/invalid-datatype-boolean.xml +4 -3
  790. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/invalid-datatype-float.xml +4 -3
  791. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/invalid-datatype-integer.xml +4 -3
  792. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/invalid-daylight-saving.xml +4 -3
  793. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/invalid-distribution-cfa-served.xml +5 -4
  794. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/invalid-epw-filepath.xml +4 -3
  795. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/invalid-facility-type-equipment.xml +4 -3
  796. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/invalid-facility-type-surfaces.xml +4 -3
  797. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/invalid-foundation-wall-properties.xml +574 -0
  798. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/invalid-id.xml +591 -0
  799. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/invalid-id2.xml +591 -0
  800. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/invalid-infiltration-volume.xml +563 -0
  801. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/invalid-input-parameters.xml +4 -3
  802. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/invalid-neighbor-shading-azimuth.xml +4 -3
  803. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/invalid-number-of-bedrooms-served.xml +465 -0
  804. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/invalid-number-of-conditioned-floors.xml +563 -0
  805. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/invalid-number-of-units-served.xml +451 -0
  806. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/invalid-relatedhvac-desuperheater.xml +3 -5
  807. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/invalid-relatedhvac-dhw-indirect.xml +1 -2
  808. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/invalid-runperiod.xml +4 -3
  809. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/invalid-schema-version.xml +4 -3
  810. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/invalid-shared-vent-in-unit-flowrate.xml +473 -0
  811. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/invalid-timestep.xml +4 -3
  812. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/invalid-window-height.xml +9 -3
  813. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/lighting-fractions.xml +4 -3
  814. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/missing-duct-location.xml +916 -909
  815. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/missing-elements.xml +4 -3
  816. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/multifamily-reference-appliance.xml +4 -3
  817. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/multifamily-reference-duct.xml +4 -3
  818. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/multifamily-reference-surface.xml +15 -4
  819. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/multifamily-reference-water-heater.xml +4 -3
  820. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/multiple-buildings-without-building-id.xml +1657 -0
  821. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/multiple-buildings-wrong-building-id.xml +1657 -0
  822. data/example_files/resources/hpxml-measures/workflow/sample_files/{base-hvac-ideal-air.xml → invalid_files/multiple-shared-cooling-systems.xml} +431 -498
  823. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/multiple-shared-heating-systems.xml +434 -0
  824. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/net-area-negative-roof.xml +5 -4
  825. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/net-area-negative-wall.xml +4 -3
  826. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/num-bedrooms-exceeds-limit.xml +4 -3
  827. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/orphaned-hvac-distribution.xml +3 -2
  828. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/refrigerator-location.xml +4 -3
  829. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/refrigerators-multiple-primary.xml +4 -3
  830. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/refrigerators-no-primary.xml +4 -3
  831. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/repeated-relatedhvac-desuperheater.xml +3 -5
  832. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/repeated-relatedhvac-dhw-indirect.xml +1 -2
  833. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/solar-fraction-one.xml +571 -0
  834. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/solar-thermal-system-with-combi-tankless.xml +1 -2
  835. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/solar-thermal-system-with-desuperheater.xml +3 -5
  836. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/solar-thermal-system-with-dhw-indirect.xml +1 -2
  837. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/unattached-cfis.xml +4 -3
  838. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/unattached-door.xml +4 -3
  839. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/unattached-hvac-distribution.xml +4 -3
  840. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/unattached-shared-clothes-washer-water-heater.xml +4 -3
  841. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/unattached-shared-dishwasher-water-heater.xml +4 -3
  842. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/unattached-skylight.xml +6 -5
  843. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/unattached-solar-thermal-system.xml +4 -3
  844. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/unattached-window.xml +4 -3
  845. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/water-heater-location-other.xml +4 -3
  846. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/water-heater-location.xml +4 -3
  847. data/example_files/resources/hpxml-measures/workflow/template.osw +5 -1
  848. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L100AC.xml +0 -3
  849. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L100AL.xml +0 -3
  850. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L110AC.xml +0 -3
  851. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L110AL.xml +0 -3
  852. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L120AC.xml +0 -3
  853. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L120AL.xml +0 -3
  854. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L130AC.xml +0 -3
  855. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L130AL.xml +0 -3
  856. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L140AC.xml +0 -3
  857. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L140AL.xml +0 -3
  858. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L150AC.xml +0 -3
  859. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L150AL.xml +0 -3
  860. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L155AC.xml +0 -3
  861. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L155AL.xml +0 -3
  862. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L160AC.xml +0 -3
  863. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L160AL.xml +0 -3
  864. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L170AC.xml +0 -3
  865. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L170AL.xml +0 -3
  866. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L200AC.xml +0 -3
  867. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L200AL.xml +0 -3
  868. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L202AC.xml +0 -3
  869. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L202AL.xml +0 -3
  870. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L302XC.xml +0 -3
  871. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L304XC.xml +0 -3
  872. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L322XC.xml +0 -3
  873. data/example_files/resources/hpxml-measures/workflow/tests/ASHRAE_Standard_140/L324XC.xml +0 -3
  874. data/example_files/resources/hpxml-measures/workflow/tests/base_results/results.csv +294 -0
  875. data/example_files/resources/hpxml-measures/workflow/tests/base_results/results_ashrae_140.csv +27 -0
  876. data/example_files/resources/hpxml-measures/workflow/tests/base_results/results_hvac_sizing.csv +294 -0
  877. data/example_files/resources/hpxml-measures/workflow/tests/compare.rb +130 -0
  878. data/example_files/resources/hpxml-measures/workflow/tests/hpxml_translator_test.rb +324 -382
  879. data/example_files/{measures/BuildResidentialModel/resources → resources}/measure-info.json +0 -0
  880. data/example_files/{measures/BuildResidentialModel/resources → resources}/meta_measure.rb +53 -44
  881. data/example_files/visualization/input_visualization_feature.html +13 -14
  882. data/example_files/visualization/input_visualization_scenario.html +14 -9
  883. data/lib/uo_cli.rb +293 -60
  884. data/lib/uo_cli/version.rb +17 -7
  885. data/requirements.txt +2 -0
  886. data/scripts/setup-env-gitbash.sh +4 -4
  887. data/scripts/setup-env-unix.sh +4 -4
  888. data/scripts/setup-env.bat +3 -3
  889. data/scripts/setup-env.ps1 +3 -3
  890. data/uo_cli.gemspec +10 -7
  891. metadata +320 -82
  892. data/example_files/measures/ResidentialGeometryCreateMultifamily/measure.rb +0 -1005
  893. data/example_files/measures/ResidentialGeometryCreateMultifamily/measure.xml +0 -326
  894. data/example_files/measures/ResidentialGeometryCreateMultifamily/tests/create_residential_multifamily_geometry_test.rb +0 -477
  895. data/example_files/measures/ResidentialGeometryCreateSingleFamilyAttached/measure.rb +0 -1039
  896. data/example_files/measures/ResidentialGeometryCreateSingleFamilyAttached/measure.xml +0 -393
  897. data/example_files/measures/ResidentialGeometryCreateSingleFamilyAttached/tests/create_residential_single_family_attached_geometry_test.rb +0 -456
  898. data/example_files/measures/ResidentialGeometryCreateSingleFamilyDetached/measure.rb +0 -979
  899. data/example_files/measures/ResidentialGeometryCreateSingleFamilyDetached/measure.xml +0 -388
  900. data/example_files/measures/ResidentialGeometryCreateSingleFamilyDetached/tests/create_residential_single_family_detached_geometry_test.rb +0 -704
  901. data/example_files/resources/hpxml-measures/.circleci/config.yml +0 -20
  902. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/resources/location.rb +0 -24
  903. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/resources/schedules_config.yml +0 -74
  904. data/example_files/resources/hpxml-measures/BuildResidentialHPXML/tests/extra-hvac-programmable-thermostat.osw +0 -369
  905. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_constructions.rb +0 -109
  906. data/example_files/resources/hpxml-measures/workflow/sample_files/base-hvac-multiple2.xml +0 -835
  907. data/example_files/resources/hpxml-measures/workflow/sample_files/invalid_files/heat-pump-mixed-fixed-and-autosize-capacities2.xml +0 -563
@@ -15,6 +15,13 @@ class HVAC
15
15
  obj_name = Constants.ObjectNameCentralAirConditionerAndFurnace
16
16
  end
17
17
 
18
+ if not heating_system.nil?
19
+ htg_ap = heating_system.additional_properties
20
+ end
21
+ if not cooling_system.nil?
22
+ clg_ap = cooling_system.additional_properties
23
+ end
24
+
18
25
  if not heating_system.nil?
19
26
  sequential_heat_load_frac = calc_sequential_load_fraction(heating_system.fraction_heat_load_served, remaining_heat_load_frac)
20
27
  else
@@ -26,33 +33,14 @@ class HVAC
26
33
  sequential_cool_load_frac = 0.0
27
34
  end
28
35
 
36
+ # Cooling Coil
29
37
  if not cooling_system.nil?
30
- if cooling_system.compressor_type == HPXML::HVACCompressorTypeSingleStage
31
- num_speeds = 1
32
- elsif cooling_system.compressor_type == HPXML::HVACCompressorTypeTwoStage
33
- num_speeds = 2
34
- elsif cooling_system.compressor_type == HPXML::HVACCompressorTypeVariableSpeed
35
- num_speeds = 4
36
- end
37
- fan_power_rated = get_fan_power_rated(cooling_system.cooling_efficiency_seer)
38
- crankcase_kw, crankcase_temp = get_crankcase_assumptions(cooling_system.fraction_cool_load_served)
39
-
40
- # Cooling Coil
41
-
42
- cool_c_d = get_cool_c_d(num_speeds, cooling_system.cooling_efficiency_seer)
43
- cool_rated_airflow_rate, cool_fan_speed_ratios, cool_capacity_ratios, cool_shrs, cool_eers, cool_cap_ft_spec, cool_eir_ft_spec, cool_cap_fflow_spec, cool_eir_fflow_spec = get_hp_clg_curves(num_speeds, cooling_system, fan_power_rated, cool_c_d, runner)
44
- cool_cfms_ton_rated = calc_cfms_ton_rated(cool_rated_airflow_rate, cool_fan_speed_ratios, cool_capacity_ratios)
45
- cool_shrs_rated_gross = calc_shrs_rated_gross(num_speeds, cool_shrs, fan_power_rated, cool_cfms_ton_rated)
46
- cool_eirs = calc_cool_eirs(num_speeds, cool_eers, fan_power_rated)
47
- cool_closs_fplr_spec = [calc_plr_coefficients(cool_c_d)] * num_speeds
48
- clg_coil = create_dx_cooling_coil(model, obj_name, (0...num_speeds).to_a, cool_eirs, cool_cap_ft_spec, cool_eir_ft_spec, cool_closs_fplr_spec, cool_cap_fflow_spec, cool_eir_fflow_spec, cool_shrs_rated_gross, cooling_system.cooling_capacity, crankcase_kw, crankcase_temp, fan_power_rated)
38
+ clg_coil = create_dx_cooling_coil(model, obj_name, cooling_system)
49
39
  hvac_map[cooling_system.id] << clg_coil
50
40
  end
51
41
 
42
+ # Heating Coil
52
43
  if not heating_system.nil?
53
-
54
- # Heating Coil
55
-
56
44
  if heating_system.heating_system_fuel == HPXML::FuelTypeElectricity
57
45
  htg_coil = OpenStudio::Model::CoilHeatingElectric.new(model)
58
46
  htg_coil.setEfficiency(heating_system.heating_efficiency_afue)
@@ -63,24 +51,37 @@ class HVAC
63
51
  htg_coil.setParasiticGasLoad(0)
64
52
  htg_coil.setFuelType(EPlus.fuel_type(heating_system.heating_system_fuel))
65
53
  end
54
+ htg_coil.setNominalCapacity(UnitConversions.convert(heating_system.heating_capacity, 'Btu/hr', 'W'))
66
55
  htg_coil.setName(obj_name + ' htg coil')
67
- if not heating_system.heating_capacity.nil?
68
- htg_coil.setNominalCapacity(UnitConversions.convert([heating_system.heating_capacity, Constants.small].max, 'Btu/hr', 'W')) # Used by HVACSizing measure
69
- end
70
56
  hvac_map[heating_system.id] << htg_coil
71
57
  end
72
58
 
73
59
  # Fan
74
-
75
60
  if (not cooling_system.nil?) && (not heating_system.nil?) && (cooling_system.fan_watts_per_cfm.to_f != heating_system.fan_watts_per_cfm.to_f)
76
- fail "Fan powers for heating system '#{heating_system.id}' and cooling system '#{cooling_system.id}' must be the same."
61
+ fail "Fan powers for heating system '#{heating_system.id}' and cooling system '#{cooling_system.id}' are attached to a single distribution system and therefore must be the same."
77
62
  end
63
+
78
64
  if (not cooling_system.nil?) && (not cooling_system.fan_watts_per_cfm.nil?)
79
65
  fan_watts_per_cfm = cooling_system.fan_watts_per_cfm
80
66
  else
81
67
  fan_watts_per_cfm = heating_system.fan_watts_per_cfm
82
68
  end
83
- fan = create_supply_fan(model, obj_name, num_speeds, fan_watts_per_cfm)
69
+ if not cooling_system.nil?
70
+ num_speeds = clg_ap.num_speeds
71
+ else
72
+ num_speeds = 1
73
+ end
74
+ if not heating_system.nil?
75
+ htg_cfm = heating_system.heating_airflow_cfm
76
+ end
77
+ if not cooling_system.nil?
78
+ clg_cfm = cooling_system.cooling_airflow_cfm
79
+ end
80
+ fan_cfm = [htg_cfm.to_f, clg_cfm.to_f].max
81
+ if not cooling_system.nil?
82
+ fan_cfm *= clg_ap.cool_fan_speed_ratios.max
83
+ end
84
+ fan = create_supply_fan(model, obj_name, num_speeds, fan_watts_per_cfm, fan_cfm)
84
85
  if not cooling_system.nil?
85
86
  hvac_map[cooling_system.id] += disaggregate_fan_or_pump(model, fan, nil, clg_coil, nil)
86
87
  end
@@ -89,8 +90,7 @@ class HVAC
89
90
  end
90
91
 
91
92
  # Unitary System
92
-
93
- air_loop_unitary = create_air_loop_unitary_system(model, obj_name, fan, htg_coil, clg_coil, nil)
93
+ air_loop_unitary = create_air_loop_unitary_system(model, obj_name, fan, htg_coil, clg_coil, nil, htg_cfm, clg_cfm)
94
94
  if not cooling_system.nil?
95
95
  hvac_map[cooling_system.id] << air_loop_unitary
96
96
  end
@@ -98,20 +98,19 @@ class HVAC
98
98
  hvac_map[heating_system.id] << air_loop_unitary
99
99
  end
100
100
 
101
+ # Unitary System Performance
101
102
  if (not cooling_system.nil?) && (num_speeds > 1)
102
- # Unitary System Performance
103
103
  perf = OpenStudio::Model::UnitarySystemPerformanceMultispeed.new(model)
104
104
  perf.setSingleModeOperation(false)
105
105
  for speed in 1..num_speeds
106
- f = OpenStudio::Model::SupplyAirflowRatioField.fromCoolingRatio(cool_fan_speed_ratios[speed - 1])
106
+ f = OpenStudio::Model::SupplyAirflowRatioField.fromCoolingRatio(clg_ap.cool_fan_speed_ratios[speed - 1])
107
107
  perf.addSupplyAirflowRatioField(f)
108
108
  end
109
109
  air_loop_unitary.setDesignSpecificationMultispeedObject(perf)
110
110
  end
111
111
 
112
112
  # Air Loop
113
-
114
- air_loop = create_air_loop(model, obj_name, air_loop_unitary, control_zone, sequential_heat_load_frac, sequential_cool_load_frac)
113
+ air_loop = create_air_loop(model, obj_name, air_loop_unitary, control_zone, sequential_heat_load_frac, sequential_cool_load_frac, fan_cfm)
115
114
  if not cooling_system.nil?
116
115
  hvac_map[cooling_system.id] << air_loop
117
116
  end
@@ -119,17 +118,8 @@ class HVAC
119
118
  hvac_map[heating_system.id] << air_loop
120
119
  end
121
120
 
122
- # Store info for HVAC Sizing measure
123
- if not cooling_system.nil?
124
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACCapacityRatioCooling, cool_capacity_ratios.join(','))
125
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACRatedCFMperTonCooling, cool_cfms_ton_rated.join(','))
126
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACFracCoolLoadServed, cooling_system.fraction_cool_load_served)
127
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACCoolType, Constants.ObjectNameCentralAirConditioner)
128
- end
129
- if not heating_system.nil?
130
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACFracHeatLoadServed, heating_system.fraction_heat_load_served)
131
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACHeatType, Constants.ObjectNameFurnace)
132
- end
121
+ # HVAC Installation Quality
122
+ apply_installation_quality(model, heating_system, cooling_system, air_loop_unitary, htg_coil, clg_coil, control_zone)
133
123
  end
134
124
 
135
125
  def self.apply_room_air_conditioner(model, runner, cooling_system,
@@ -140,63 +130,56 @@ class HVAC
140
130
  obj_name = Constants.ObjectNameRoomAirConditioner
141
131
  sequential_cool_load_frac = calc_sequential_load_fraction(cooling_system.fraction_cool_load_served, remaining_cool_load_frac)
142
132
 
133
+ clg_ap = cooling_system.additional_properties
134
+
143
135
  # Performance curves
144
- # From Frigidaire 10.7 eer unit in Winkler et. al. Lab Testing of Window ACs (2013)
145
-
146
- cool_cap_ft_spec = [0.43945980246913574, -0.0008922469135802481, 0.00013984567901234569, 0.0038489259259259253, -5.6327160493827156e-05, 2.041358024691358e-05]
147
- cool_cap_ft_spec_si = convert_curve_biquadratic(cool_cap_ft_spec)
148
- cool_eir_ft_spec = [6.310506172839506, -0.17705185185185185, 0.0014645061728395061, 0.012571604938271608, 0.0001493827160493827, -0.00040308641975308644]
149
- cool_eir_ft_spec_si = convert_curve_biquadratic(cool_eir_ft_spec)
150
- cool_cap_fflow_spec = [0.887, 0.1128, 0]
151
- cool_eir_fflow_spec = [1.763, -0.6081, 0]
152
- cool_plf_fplr = [0.78, 0.22, 0]
153
- cfms_ton_rated = [312] # cfm/ton, medium speed
154
-
155
- roomac_cap_ft_curve = create_curve_biquadratic(model, cool_cap_ft_spec_si, 'RoomAC-Cap-fT', 0, 100, 0, 100)
156
- roomac_cap_fff_curve = create_curve_quadratic(model, cool_cap_fflow_spec, 'RoomAC-Cap-fFF', 0, 2, 0, 2)
157
- roomac_eir_ft_curve = create_curve_biquadratic(model, cool_eir_ft_spec_si, 'RoomAC-eir-fT', 0, 100, 0, 100)
158
- roomcac_eir_fff_curve = create_curve_quadratic(model, cool_eir_fflow_spec, 'RoomAC-eir-fFF', 0, 2, 0, 2)
159
- roomac_plf_fplr_curve = create_curve_quadratic(model, cool_plf_fplr, 'RoomAC-PLF-fPLR', 0, 1, 0, 1)
136
+ cool_cap_ft_spec_si = convert_curve_biquadratic(clg_ap.cool_cap_ft_spec[0])
137
+ cool_eir_ft_spec_si = convert_curve_biquadratic(clg_ap.cool_eir_ft_spec[0])
160
138
 
161
- # Cooling Coil
139
+ roomac_cap_ft_curve = create_curve_biquadratic(model, cool_cap_ft_spec_si, 'Cool-CAP-fT', 0, 100, 0, 100)
140
+ roomac_cap_fff_curve = create_curve_quadratic(model, clg_ap.cool_cap_fflow_spec[0], 'Cool-CAP-fFF', 0, 2, 0, 2)
141
+ roomac_eir_ft_curve = create_curve_biquadratic(model, cool_eir_ft_spec_si, 'Cool-EIR-fT', 0, 100, 0, 100)
142
+ roomcac_eir_fff_curve = create_curve_quadratic(model, clg_ap.cool_eir_fflow_spec[0], 'Cool-EIR-fFF', 0, 2, 0, 2)
143
+ roomac_plf_fplr_curve = create_curve_quadratic(model, clg_ap.cool_plf_fplr_spec[0], 'Cool-PLF-fPLR', 0, 1, 0, 1)
162
144
 
145
+ # Cooling Coil
163
146
  clg_coil = OpenStudio::Model::CoilCoolingDXSingleSpeed.new(model, model.alwaysOnDiscreteSchedule, roomac_cap_ft_curve, roomac_cap_fff_curve, roomac_eir_ft_curve, roomcac_eir_fff_curve, roomac_plf_fplr_curve)
164
147
  clg_coil.setName(obj_name + ' clg coil')
165
- if not cooling_system.cooling_capacity.nil?
166
- clg_coil.setRatedTotalCoolingCapacity(UnitConversions.convert([cooling_system.cooling_capacity, Constants.small].max, 'Btu/hr', 'W')) # Used by HVACSizing measure
167
- end
168
148
  clg_coil.setRatedSensibleHeatRatio(cooling_system.cooling_shr)
169
149
  clg_coil.setRatedCOP(UnitConversions.convert(cooling_system.cooling_efficiency_eer, 'Btu/hr', 'W'))
170
150
  clg_coil.setRatedEvaporatorFanPowerPerVolumeFlowRate(773.3)
171
151
  clg_coil.setEvaporativeCondenserEffectiveness(0.9)
172
152
  clg_coil.setMaximumOutdoorDryBulbTemperatureForCrankcaseHeaterOperation(10)
173
153
  clg_coil.setBasinHeaterSetpointTemperature(2)
154
+ clg_coil.setRatedTotalCoolingCapacity(UnitConversions.convert(cooling_system.cooling_capacity, 'Btu/hr', 'W'))
155
+ clg_coil.setRatedAirFlowRate(calc_rated_airflow(cooling_system.cooling_capacity, clg_ap.cool_rated_cfm_per_ton[0], 1.0))
174
156
  hvac_map[cooling_system.id] << clg_coil
175
157
 
176
158
  # Fan
177
- fan = create_supply_fan(model, obj_name, 1, 0.0) # Fan power included in EER (net COP) above
159
+ clg_cfm = cooling_system.cooling_airflow_cfm
160
+ fan = create_supply_fan(model, obj_name, 1, 0.0, clg_cfm) # Fan power included in EER (net COP) above
178
161
  hvac_map[cooling_system.id] += disaggregate_fan_or_pump(model, fan, nil, clg_coil, nil)
179
162
 
180
163
  # Heating Coil (none)
181
-
182
164
  htg_coil = OpenStudio::Model::CoilHeatingElectric.new(model, model.alwaysOffDiscreteSchedule())
165
+ htg_coil.setNominalCapacity(0.0)
183
166
  htg_coil.setName(obj_name + ' htg coil')
184
167
 
185
168
  # PTAC
186
-
187
169
  ptac = OpenStudio::Model::ZoneHVACPackagedTerminalAirConditioner.new(model, model.alwaysOnDiscreteSchedule, fan, htg_coil, clg_coil)
188
170
  ptac.setName(obj_name)
189
171
  ptac.setSupplyAirFanOperatingModeSchedule(model.alwaysOffDiscreteSchedule)
172
+ ptac.setSupplyAirFlowRateDuringCoolingOperation(UnitConversions.convert(clg_cfm, 'cfm', 'm^3/s'))
173
+ ptac.setSupplyAirFlowRateDuringHeatingOperation(0.00001)
174
+ ptac.setSupplyAirFlowRateWhenNoCoolingorHeatingisNeeded(0.0)
175
+ ptac.setOutdoorAirFlowRateDuringCoolingOperation(0.0)
176
+ ptac.setOutdoorAirFlowRateDuringHeatingOperation(0.0)
177
+ ptac.setOutdoorAirFlowRateWhenNoCoolingorHeatingisNeeded(0.0)
190
178
  ptac.addToThermalZone(control_zone)
191
179
  hvac_map[cooling_system.id] << ptac
192
180
 
193
181
  control_zone.setSequentialCoolingFractionSchedule(ptac, get_sequential_load_schedule(model, sequential_cool_load_frac))
194
182
  control_zone.setSequentialHeatingFractionSchedule(ptac, get_sequential_load_schedule(model, 0))
195
-
196
- # Store info for HVAC Sizing measure
197
- ptac.additionalProperties.setFeature(Constants.SizingInfoHVACRatedCFMperTonCooling, cfms_ton_rated.join(','))
198
- ptac.additionalProperties.setFeature(Constants.SizingInfoHVACFracCoolLoadServed, cooling_system.fraction_cool_load_served)
199
- ptac.additionalProperties.setFeature(Constants.SizingInfoHVACCoolType, Constants.ObjectNameRoomAirConditioner)
200
183
  end
201
184
 
202
185
  def self.apply_evaporative_cooler(model, runner, cooling_system,
@@ -207,21 +190,21 @@ class HVAC
207
190
  obj_name = Constants.ObjectNameEvaporativeCooler
208
191
  sequential_cool_load_frac = calc_sequential_load_fraction(cooling_system.fraction_cool_load_served, remaining_cool_load_frac)
209
192
 
210
- # Evap Cooler
193
+ clg_ap = cooling_system.additional_properties
194
+ clg_cfm = cooling_system.cooling_airflow_cfm
211
195
 
196
+ # Evap Cooler
212
197
  evap_cooler = OpenStudio::Model::EvaporativeCoolerDirectResearchSpecial.new(model, model.alwaysOnDiscreteSchedule)
213
198
  evap_cooler.setName(obj_name)
214
- evap_cooler.setCoolerEffectiveness(0.72) # Assumed effectiveness
199
+ evap_cooler.setCoolerEffectiveness(clg_ap.effectiveness)
215
200
  evap_cooler.setEvaporativeOperationMinimumDrybulbTemperature(0) # relax limitation to open evap cooler for any potential cooling
216
201
  evap_cooler.setEvaporativeOperationMaximumLimitWetbulbTemperature(50) # relax limitation to open evap cooler for any potential cooling
217
202
  evap_cooler.setEvaporativeOperationMaximumLimitDrybulbTemperature(50) # relax limitation to open evap cooler for any potential cooling
203
+ evap_cooler.setPrimaryAirDesignFlowRate(UnitConversions.convert(clg_cfm, 'cfm', 'm^3/s'))
218
204
  hvac_map[cooling_system.id] << evap_cooler
219
205
 
220
206
  # Air Loop
221
-
222
- air_loop = create_air_loop(model, obj_name, evap_cooler, control_zone, 0, sequential_cool_load_frac)
223
- air_loop.additionalProperties.setFeature(Constants.SizingInfoHVACSystemIsDucted, !cooling_system.distribution_system_idref.nil?)
224
- air_loop.additionalProperties.setFeature(Constants.SizingInfoHVACCoolType, Constants.ObjectNameEvaporativeCooler)
207
+ air_loop = create_air_loop(model, obj_name, evap_cooler, control_zone, 0, sequential_cool_load_frac, clg_cfm)
225
208
  hvac_map[cooling_system.id] << air_loop
226
209
 
227
210
  # Fan
@@ -236,7 +219,9 @@ class HVAC
236
219
  fan.setFanPowerCoefficient3(0)
237
220
  fan.setFanPowerCoefficient4(0)
238
221
  fan.setFanPowerCoefficient5(0)
239
- set_fan_power(fan, cooling_system.fan_watts_per_cfm.to_f)
222
+ fan.setMaximumFlowRate(UnitConversions.convert(clg_cfm, 'cfm', 'm^3/s'))
223
+ 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
224
+ set_fan_power(fan, fan_watts_per_cfm)
240
225
  fan.addToNode(air_loop.supplyInletNode)
241
226
  hvac_map[cooling_system.id] += disaggregate_fan_or_pump(model, fan, nil, evap_cooler, nil)
242
227
 
@@ -246,6 +231,7 @@ class HVAC
246
231
  oa_intake_controller.setMinimumLimitType('FixedMinimum')
247
232
  oa_intake_controller.resetEconomizerMinimumLimitDryBulbTemperature
248
233
  oa_intake_controller.setMinimumFractionofOutdoorAirSchedule(model.alwaysOnDiscreteSchedule)
234
+ oa_intake_controller.setMaximumOutdoorAirFlowRate(UnitConversions.convert(clg_cfm, 'cfm', 'm^3/s'))
249
235
 
250
236
  oa_intake = OpenStudio::Model::AirLoopHVACOutdoorAirSystem.new(model, oa_intake_controller)
251
237
  oa_intake.setName("#{air_loop.name} OA System")
@@ -258,10 +244,6 @@ class HVAC
258
244
  evap_stpt_manager.setReferenceTemperatureType('OutdoorAirWetBulb')
259
245
  evap_stpt_manager.setOffsetTemperatureDifference(0.0)
260
246
  evap_stpt_manager.addToNode(air_loop.supplyOutletNode)
261
-
262
- # Store info for HVAC Sizing measure
263
- evap_cooler.additionalProperties.setFeature(Constants.SizingInfoHVACFracCoolLoadServed, cooling_system.fraction_cool_load_served)
264
- evap_cooler.additionalProperties.setFeature(Constants.SizingInfoHVACCoolType, Constants.ObjectNameEvaporativeCooler)
265
247
  end
266
248
 
267
249
  def self.apply_central_air_to_air_heat_pump(model, runner, heat_pump,
@@ -273,156 +255,91 @@ class HVAC
273
255
  obj_name = Constants.ObjectNameAirSourceHeatPump
274
256
  sequential_heat_load_frac = calc_sequential_load_fraction(heat_pump.fraction_heat_load_served, remaining_heat_load_frac)
275
257
  sequential_cool_load_frac = calc_sequential_load_fraction(heat_pump.fraction_cool_load_served, remaining_cool_load_frac)
276
- if heat_pump.compressor_type == HPXML::HVACCompressorTypeSingleStage
277
- num_speeds = 1
278
- elsif heat_pump.compressor_type == HPXML::HVACCompressorTypeTwoStage
279
- num_speeds = 2
280
- elsif heat_pump.compressor_type == HPXML::HVACCompressorTypeVariableSpeed
281
- num_speeds = 4
282
- end
283
- fan_power_rated = get_fan_power_rated(heat_pump.cooling_efficiency_seer)
284
- if heat_pump.fraction_heat_load_served <= 0
285
- crankcase_kw, crankcase_temp = 0, nil
286
- else
287
- crankcase_kw, crankcase_temp = get_crankcase_assumptions(heat_pump.fraction_cool_load_served)
288
- end
289
- hp_min_temp, supp_max_temp = get_heat_pump_temp_assumptions(heat_pump)
290
258
 
291
- # Cooling Coil
259
+ hp_ap = heat_pump.additional_properties
292
260
 
293
- cool_c_d = get_cool_c_d(num_speeds, heat_pump.cooling_efficiency_seer)
294
- cool_rated_airflow_rate, cool_fan_speed_ratios, cool_capacity_ratios, cool_shrs, cool_eers, cool_cap_ft_spec, cool_eir_ft_spec, cool_cap_fflow_spec, cool_eir_fflow_spec = get_hp_clg_curves(num_speeds, heat_pump, fan_power_rated, cool_c_d, runner)
295
- cool_cfms_ton_rated = calc_cfms_ton_rated(cool_rated_airflow_rate, cool_fan_speed_ratios, cool_capacity_ratios)
296
- cool_shrs_rated_gross = calc_shrs_rated_gross(num_speeds, cool_shrs, fan_power_rated, cool_cfms_ton_rated)
297
- cool_eirs = calc_cool_eirs(num_speeds, cool_eers, fan_power_rated)
298
- cool_closs_fplr_spec = [calc_plr_coefficients(cool_c_d)] * num_speeds
299
- clg_coil = create_dx_cooling_coil(model, obj_name, (0...num_speeds).to_a, cool_eirs, cool_cap_ft_spec, cool_eir_ft_spec, cool_closs_fplr_spec, cool_cap_fflow_spec, cool_eir_fflow_spec, cool_shrs_rated_gross, heat_pump.cooling_capacity, 0, nil, fan_power_rated)
261
+ # Cooling Coil
262
+ clg_coil = create_dx_cooling_coil(model, obj_name, heat_pump)
300
263
  hvac_map[heat_pump.id] << clg_coil
301
264
 
302
265
  # Heating Coil
303
-
304
- heat_c_d = get_heat_c_d(num_speeds, heat_pump.heating_efficiency_hspf)
305
- if num_speeds == 1
306
- heat_rated_airflow_rate = 384.1 # cfm/ton
307
- heat_capacity_ratios = [1.0]
308
- heat_fan_speed_ratios = [1.0]
309
- heat_eir_ft_spec = [[0.718398423, 0.003498178, 0.000142202, -0.005724331, 0.00014085, -0.000215321]]
310
- heat_cap_fflow_spec = [[0.694045465, 0.474207981, -0.168253446]]
311
- heat_eir_fflow_spec = [[2.185418751, -1.942827919, 0.757409168]]
312
- if heat_pump.heating_capacity_17F.nil?
313
- heat_cap_ft_spec = [[0.566333415, -0.000744164, -0.0000103, 0.009414634, 0.0000506, -0.00000675]]
314
- else
315
- heat_cap_ft_spec = calc_heat_cap_ft_spec_using_capacity_17F(num_speeds, heat_pump)
316
- end
317
- heat_cops = [calc_cop_heating_1speed(heat_pump.heating_efficiency_hspf, heat_c_d, fan_power_rated, heat_eir_ft_spec, heat_cap_ft_spec)]
318
- elsif num_speeds == 2
319
- heat_rated_airflow_rate = 352.2 # cfm/ton
320
- heat_capacity_ratios = [0.72, 1.0]
321
- heat_fan_speed_ratios = [0.8, 1.0]
322
- heat_eir_ft_spec = [[0.36338171, 0.013523725, 0.000258872, -0.009450269, 0.000439519, -0.000653723],
323
- [0.981100941, -0.005158493, 0.000243416, -0.005274352, 0.000230742, -0.000336954]]
324
- heat_cap_fflow_spec = [[0.741466907, 0.378645444, -0.119754733],
325
- [0.76634609, 0.32840943, -0.094701495]]
326
- heat_eir_fflow_spec = [[2.153618211, -1.737190609, 0.584269478],
327
- [2.001041353, -1.58869128, 0.587593517]]
328
- if heat_pump.heating_capacity_17F.nil?
329
- heat_cap_ft_spec = [[0.335690634, 0.002405123, -0.0000464, 0.013498735, 0.0000499, -0.00000725],
330
- [0.306358843, 0.005376987, -0.0000579, 0.011645092, 0.0000591, -0.0000203]]
331
- else
332
- heat_cap_ft_spec = calc_heat_cap_ft_spec_using_capacity_17F(num_speeds, heat_pump)
333
- end
334
- heat_cops = calc_cops_heating_2speed(heat_pump.heating_efficiency_hspf, heat_c_d, heat_capacity_ratios, heat_fan_speed_ratios, fan_power_rated, heat_eir_ft_spec, heat_cap_ft_spec)
335
- elsif num_speeds == 4
336
- heat_rated_airflow_rate = 296.9 # cfm/ton
337
- heat_capacity_ratios = [0.33, 0.56, 1.0, 1.17]
338
- heat_fan_speed_ratios = [0.63, 0.76, 1.0, 1.19]
339
- heat_eir_ft_spec = [[0.708311527, 0.020732093, 0.000391479, -0.037640031, 0.000979937, -0.001079042],
340
- [0.025480155, 0.020169585, 0.000121341, -0.004429789, 0.000166472, -0.00036447],
341
- [0.379003189, 0.014195012, 0.0000821046, -0.008894061, 0.000151519, -0.000210299],
342
- [0.690404655, 0.00616619, 0.000137643, -0.009350199, 0.000153427, -0.000213258]]
343
- heat_cap_fflow_spec = [[1, 0, 0]] * 4
344
- heat_eir_fflow_spec = [[1, 0, 0]] * 4
345
- if heat_pump.heating_capacity_17F.nil?
346
- heat_cap_ft_spec = [[0.304192655, -0.003972566, 0.0000196432, 0.024471251, -0.000000774126, -0.0000841323],
347
- [0.496381324, -0.00144792, 0.0, 0.016020855, 0.0000203447, -0.0000584118],
348
- [0.697171186, -0.006189599, 0.0000337077, 0.014291981, 0.0000105633, -0.0000387956],
349
- [0.555513805, -0.001337363, -0.00000265117, 0.014328826, 0.0000163849, -0.0000480711]]
350
- else
351
- heat_cap_ft_spec = calc_heat_cap_ft_spec_using_capacity_17F(num_speeds, heat_pump)
352
- end
353
- heat_cops = calc_cops_heating_4speed(runner, heat_pump.heating_efficiency_hspf, heat_c_d, heat_capacity_ratios, heat_fan_speed_ratios, fan_power_rated, heat_eir_ft_spec, heat_cap_ft_spec)
354
- end
355
- heat_cfms_ton_rated = calc_cfms_ton_rated(heat_rated_airflow_rate, heat_fan_speed_ratios, heat_capacity_ratios)
356
- heat_eirs = calc_heat_eirs(num_speeds, heat_cops, fan_power_rated)
357
- heat_closs_fplr_spec = [calc_plr_coefficients(heat_c_d)] * num_speeds
358
- htg_coil = create_dx_heating_coil(model, obj_name, (0...num_speeds).to_a, heat_eirs, heat_cap_ft_spec, heat_eir_ft_spec, heat_closs_fplr_spec, heat_cap_fflow_spec, heat_eir_fflow_spec, heat_pump.heating_capacity, crankcase_kw, crankcase_temp, fan_power_rated, hp_min_temp, heat_pump.fraction_heat_load_served)
266
+ htg_coil = create_dx_heating_coil(model, obj_name, heat_pump)
359
267
  hvac_map[heat_pump.id] << htg_coil
360
268
 
361
269
  # Supplemental Heating Coil
362
-
363
270
  htg_supp_coil = create_supp_heating_coil(model, obj_name, heat_pump)
364
271
  hvac_map[heat_pump.id] << htg_supp_coil
365
272
 
366
273
  # Fan
367
- fan = create_supply_fan(model, obj_name, num_speeds, heat_pump.fan_watts_per_cfm)
274
+ num_speeds = hp_ap.num_speeds
275
+ htg_cfm = heat_pump.heating_airflow_cfm
276
+ clg_cfm = heat_pump.cooling_airflow_cfm
277
+ fan_cfm = hp_ap.cool_fan_speed_ratios.max * [htg_cfm, clg_cfm].max
278
+ fan = create_supply_fan(model, obj_name, num_speeds, heat_pump.fan_watts_per_cfm, fan_cfm)
368
279
  hvac_map[heat_pump.id] += disaggregate_fan_or_pump(model, fan, htg_coil, clg_coil, htg_supp_coil)
369
280
 
370
281
  # Unitary System
371
-
372
- air_loop_unitary = create_air_loop_unitary_system(model, obj_name, fan, htg_coil, clg_coil, htg_supp_coil, supp_max_temp)
282
+ air_loop_unitary = create_air_loop_unitary_system(model, obj_name, fan, htg_coil, clg_coil, htg_supp_coil, htg_cfm, clg_cfm, hp_ap.supp_max_temp)
373
283
  hvac_map[heat_pump.id] << air_loop_unitary
374
284
 
285
+ # Unitary System Performance
375
286
  if num_speeds > 1
376
- # Unitary System Performance
377
287
  perf = OpenStudio::Model::UnitarySystemPerformanceMultispeed.new(model)
378
288
  perf.setSingleModeOperation(false)
379
289
  for speed in 1..num_speeds
380
- f = OpenStudio::Model::SupplyAirflowRatioField.new(heat_fan_speed_ratios[speed - 1], cool_fan_speed_ratios[speed - 1])
290
+ f = OpenStudio::Model::SupplyAirflowRatioField.new(hp_ap.heat_fan_speed_ratios[speed - 1], hp_ap.cool_fan_speed_ratios[speed - 1])
381
291
  perf.addSupplyAirflowRatioField(f)
382
292
  end
383
293
  air_loop_unitary.setDesignSpecificationMultispeedObject(perf)
384
294
  end
385
295
 
386
296
  # Air Loop
387
-
388
- air_loop = create_air_loop(model, obj_name, air_loop_unitary, control_zone, sequential_heat_load_frac, sequential_cool_load_frac)
297
+ air_loop = create_air_loop(model, obj_name, air_loop_unitary, control_zone, sequential_heat_load_frac, sequential_cool_load_frac, fan_cfm)
389
298
  hvac_map[heat_pump.id] << air_loop
390
299
 
391
- # Store info for HVAC Sizing measure
392
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACCapacityRatioHeating, heat_capacity_ratios.join(','))
393
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACCapacityRatioCooling, cool_capacity_ratios.join(','))
394
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACRatedCFMperTonHeating, heat_cfms_ton_rated.join(','))
395
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACRatedCFMperTonCooling, cool_cfms_ton_rated.join(','))
396
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACFracHeatLoadServed, heat_pump.fraction_heat_load_served)
397
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACFracCoolLoadServed, heat_pump.fraction_cool_load_served)
398
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACCoolType, Constants.ObjectNameAirSourceHeatPump)
399
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACHeatType, Constants.ObjectNameAirSourceHeatPump)
300
+ # HVAC Installation Quality
301
+ apply_installation_quality(model, heat_pump, heat_pump, air_loop_unitary, htg_coil, clg_coil, control_zone)
400
302
  end
401
303
 
402
304
  def self.apply_mini_split_air_conditioner(model, runner, cooling_system,
403
305
  remaining_cool_load_frac,
404
306
  control_zone, hvac_map)
405
307
 
406
- # Shoehorn cooling_system object into a corresponding heat_pump object
407
- heat_pump = HPXML::HeatPump.new(cooling_system.hpxml_object)
408
- heat_pump.id = cooling_system.id
409
- heat_pump.heat_pump_type = HPXML::HVACTypeHeatPumpMiniSplit
410
- heat_pump.heat_pump_fuel = cooling_system.cooling_system_fuel
411
- heat_pump.cooling_capacity = cooling_system.cooling_capacity
412
- if !heat_pump.cooling_capacity.nil?
413
- heat_pump.heating_capacity = 0
414
- end
415
- heat_pump.cooling_shr = cooling_system.cooling_shr
416
- heat_pump.fraction_heat_load_served = 0
417
- heat_pump.fraction_cool_load_served = cooling_system.fraction_cool_load_served
418
- heat_pump.cooling_efficiency_seer = cooling_system.cooling_efficiency_seer
419
- heat_pump.heating_efficiency_hspf = 7.7 # Arbitrary; shouldn't affect energy use TODO: Allow nil
420
- heat_pump.distribution_system_idref = cooling_system.distribution_system_idref
421
- heat_pump.fan_watts_per_cfm = cooling_system.fan_watts_per_cfm
422
-
423
- apply_mini_split_heat_pump(model, runner, heat_pump, 0,
424
- remaining_cool_load_frac,
425
- control_zone, hvac_map)
308
+ hvac_map[cooling_system.id] = []
309
+ obj_name = Constants.ObjectNameMiniSplitAirConditioner
310
+ sequential_cool_load_frac = calc_sequential_load_fraction(cooling_system.fraction_cool_load_served, remaining_cool_load_frac)
311
+
312
+ clg_ap = cooling_system.additional_properties
313
+
314
+ # Cooling Coil
315
+ clg_coil = create_dx_cooling_coil(model, obj_name, cooling_system)
316
+ hvac_map[cooling_system.id] << clg_coil
317
+
318
+ # Fan
319
+ num_speeds = clg_ap.num_speeds
320
+ clg_cfm = cooling_system.cooling_airflow_cfm
321
+ fan = create_supply_fan(model, obj_name, num_speeds, cooling_system.fan_watts_per_cfm, clg_cfm)
322
+ hvac_map[cooling_system.id] += disaggregate_fan_or_pump(model, fan, nil, clg_coil, nil)
323
+
324
+ # Unitary System
325
+ air_loop_unitary = create_air_loop_unitary_system(model, obj_name, fan, nil, clg_coil, nil, nil, clg_cfm)
326
+ hvac_map[cooling_system.id] << air_loop_unitary
327
+
328
+ # Unitary System Performance
329
+ perf = OpenStudio::Model::UnitarySystemPerformanceMultispeed.new(model)
330
+ perf.setSingleModeOperation(false)
331
+ for i in 0..(num_speeds - 1)
332
+ f = OpenStudio::Model::SupplyAirflowRatioField.new(1.0, clg_ap.cool_fan_speed_ratios[i])
333
+ perf.addSupplyAirflowRatioField(f)
334
+ end
335
+ air_loop_unitary.setDesignSpecificationMultispeedObject(perf)
336
+
337
+ # Air Loop
338
+ air_loop = create_air_loop(model, obj_name, air_loop_unitary, control_zone, 0, sequential_cool_load_frac, clg_cfm)
339
+ hvac_map[cooling_system.id] << air_loop
340
+
341
+ # HVAC Installation Quality
342
+ apply_installation_quality(model, nil, cooling_system, air_loop_unitary, nil, clg_coil, control_zone)
426
343
  end
427
344
 
428
345
  def self.apply_mini_split_heat_pump(model, runner, heat_pump,
@@ -434,192 +351,48 @@ class HVAC
434
351
  obj_name = Constants.ObjectNameMiniSplitHeatPump
435
352
  sequential_heat_load_frac = calc_sequential_load_fraction(heat_pump.fraction_heat_load_served, remaining_heat_load_frac)
436
353
  sequential_cool_load_frac = calc_sequential_load_fraction(heat_pump.fraction_cool_load_served, remaining_cool_load_frac)
437
- num_speeds = 10
438
- mshp_indices = [1, 3, 5, 9]
439
- hp_min_temp, supp_max_temp = get_heat_pump_temp_assumptions(heat_pump)
440
- pan_heater_power = 0.0 # W, disabled
441
- if not heat_pump.distribution_system.nil?
442
- fan_power_rated = 0.18 # W/cfm, ducted
443
- else
444
- fan_power_rated = heat_pump.fan_watts_per_cfm # ductless, installed and rated value should be equal
445
- end
446
-
447
- # Calculate generic inputs
448
- min_cooling_capacity = 0.4 # frac
449
- max_cooling_capacity = 1.2 # frac
450
- min_cooling_airflow_rate = 200.0
451
- max_cooling_airflow_rate = 425.0
452
- min_heating_capacity = 0.3 # frac
453
- max_heating_capacity = 1.2 # frac
454
- min_heating_airflow_rate = 200.0
455
- max_heating_airflow_rate = 400.0
456
- if heat_pump.heating_capacity.nil?
457
- heating_capacity_offset = 2300.0 # Btu/hr
458
- else
459
- heating_capacity_offset = heat_pump.heating_capacity - heat_pump.cooling_capacity
460
- end
461
- if heat_pump.heating_capacity_17F.nil?
462
- cap_retention_frac = 0.25 # frac
463
- cap_retention_temp = -5.0 # deg-F
464
- else
465
- cap_retention_frac = heat_pump.heating_capacity_17F / heat_pump.heating_capacity
466
- cap_retention_temp = 17.0 # deg-F
467
- end
468
354
 
469
- # Cooling Coil
355
+ hp_ap = heat_pump.additional_properties
470
356
 
471
- cool_cap_ft_spec = [[0.7531983499655835, 0.003618193903031667, 0.0, 0.006574385031351544, -6.87181191015432e-05, 0.0]] * num_speeds
472
- cool_eir_ft_spec = [[-0.06376924779982301, -0.0013360593470367282, 1.413060577993827e-05, 0.019433076486584752, -4.91395947154321e-05, -4.909341249475308e-05]] * num_speeds
473
- cool_cap_fflow_spec = [[1, 0, 0]] * num_speeds
474
- cool_eir_fflow_spec = [[1, 0, 0]] * num_speeds
475
- cool_c_d = get_cool_c_d(num_speeds, heat_pump.cooling_efficiency_seer)
476
- cool_closs_fplr_spec = [calc_plr_coefficients(cool_c_d)] * num_speeds
477
- dB_rated = 80.0 # deg-F
478
- wB_rated = 67.0 # deg-F
479
- cool_cfms_ton_rated, cool_capacity_ratios, cool_shrs_rated_gross = calc_mshp_cfms_ton_cooling(min_cooling_capacity, max_cooling_capacity, min_cooling_airflow_rate, max_cooling_airflow_rate, num_speeds, dB_rated, wB_rated, heat_pump.cooling_shr)
480
- cool_eirs = calc_mshp_cool_eirs(runner, heat_pump.cooling_efficiency_seer, fan_power_rated, cool_c_d, num_speeds, cool_capacity_ratios, cool_cfms_ton_rated, cool_eir_ft_spec, cool_cap_ft_spec)
481
- clg_coil = create_dx_cooling_coil(model, obj_name, mshp_indices, cool_eirs, cool_cap_ft_spec, cool_eir_ft_spec, cool_closs_fplr_spec, cool_cap_fflow_spec, cool_eir_fflow_spec, cool_shrs_rated_gross, heat_pump.cooling_capacity, 0.0, nil, nil)
357
+ # Cooling Coil
358
+ clg_coil = create_dx_cooling_coil(model, obj_name, heat_pump)
482
359
  hvac_map[heat_pump.id] << clg_coil
483
360
 
484
361
  # Heating Coil
485
-
486
- # cop/eir as a function of temperature
487
- # Generic curves (=Daikin from lab data)
488
- heat_eir_ft_spec = [[0.9999941697687026, 0.004684593830254383, 5.901286675833333e-05, -0.0028624467783091973, 1.3041120194135802e-05, -0.00016172918478765433]] * num_speeds
489
- heat_cap_fflow_spec = [[1, 0, 0]] * num_speeds
490
- heat_eir_fflow_spec = [[1, 0, 0]] * num_speeds
491
-
492
- # Derive coefficients from user input for capacity retention at outdoor drybulb temperature X [C].
493
- # Biquadratic: capacity multiplier = a + b*IAT + c*IAT^2 + d*OAT + e*OAT^2 + f*IAT*OAT
494
- x_A = UnitConversions.convert(cap_retention_temp, 'F', 'C')
495
- y_A = cap_retention_frac
496
- x_B = UnitConversions.convert(47.0, 'F', 'C') # 47F is the rating point
497
- y_B = 1.0 # Maximum capacity factor is 1 at the rating point, by definition (this is maximum capacity, not nominal capacity)
498
- oat_slope = (y_B - y_A) / (x_B - x_A)
499
- oat_intercept = y_A - (x_A * oat_slope)
500
-
501
- # Coefficients for the indoor temperature relationship are retained from the generic curve (Daikin lab data).
502
- iat_slope = -0.010386676170938
503
- iat_intercept = 0.219274275
504
- a = oat_intercept + iat_intercept
505
- b = iat_slope
506
- c = 0
507
- d = oat_slope
508
- e = 0
509
- f = 0
510
- heat_cap_ft_spec = [convert_curve_biquadratic([a, b, c, d, e, f], false)] * num_speeds
511
-
512
- heat_c_d = get_heat_c_d(num_speeds, heat_pump.heating_efficiency_hspf)
513
- heat_closs_fplr_spec = [calc_plr_coefficients(heat_c_d)] * num_speeds
514
- heat_cfms_ton_rated, heat_capacity_ratios = calc_mshp_cfms_ton_heating(min_heating_capacity, max_heating_capacity, min_heating_airflow_rate, max_heating_airflow_rate, num_speeds)
515
- heat_eirs = calc_mshp_heat_eirs(runner, heat_pump.heating_efficiency_hspf, fan_power_rated, hp_min_temp, heat_c_d, cool_cfms_ton_rated, num_speeds, heat_capacity_ratios, heat_cfms_ton_rated, heat_eir_ft_spec, heat_cap_ft_spec)
516
- htg_coil = create_dx_heating_coil(model, obj_name, mshp_indices, heat_eirs, heat_cap_ft_spec, heat_eir_ft_spec, heat_closs_fplr_spec, heat_cap_fflow_spec, heat_eir_fflow_spec, heat_pump.heating_capacity, 0.0, nil, nil, hp_min_temp, heat_pump.fraction_heat_load_served)
362
+ htg_coil = create_dx_heating_coil(model, obj_name, heat_pump)
517
363
  hvac_map[heat_pump.id] << htg_coil
518
364
 
519
365
  # Supplemental Heating Coil
520
-
521
366
  htg_supp_coil = create_supp_heating_coil(model, obj_name, heat_pump)
522
367
  hvac_map[heat_pump.id] << htg_supp_coil
523
368
 
524
369
  # Fan
525
- fan = create_supply_fan(model, obj_name, 4, heat_pump.fan_watts_per_cfm)
370
+ num_speeds = hp_ap.num_speeds
371
+ htg_cfm = heat_pump.heating_airflow_cfm
372
+ clg_cfm = heat_pump.cooling_airflow_cfm
373
+ fan_cfm = hp_ap.cool_fan_speed_ratios.max * [htg_cfm, clg_cfm].max
374
+ fan = create_supply_fan(model, obj_name, num_speeds, heat_pump.fan_watts_per_cfm, fan_cfm)
526
375
  hvac_map[heat_pump.id] += disaggregate_fan_or_pump(model, fan, htg_coil, clg_coil, htg_supp_coil)
527
376
 
528
377
  # Unitary System
529
-
530
- air_loop_unitary = create_air_loop_unitary_system(model, obj_name, fan, htg_coil, clg_coil, htg_supp_coil, supp_max_temp)
378
+ air_loop_unitary = create_air_loop_unitary_system(model, obj_name, fan, htg_coil, clg_coil, htg_supp_coil, htg_cfm, clg_cfm, hp_ap.supp_max_temp)
531
379
  hvac_map[heat_pump.id] << air_loop_unitary
532
380
 
381
+ # Unitary System Performance
533
382
  perf = OpenStudio::Model::UnitarySystemPerformanceMultispeed.new(model)
534
383
  perf.setSingleModeOperation(false)
535
- mshp_indices.each do |mshp_index|
536
- ratio_heating = heat_cfms_ton_rated[mshp_index] / heat_cfms_ton_rated[mshp_indices[-1]]
537
- ratio_cooling = cool_cfms_ton_rated[mshp_index] / cool_cfms_ton_rated[mshp_indices[-1]]
538
- f = OpenStudio::Model::SupplyAirflowRatioField.new(ratio_heating, ratio_cooling)
384
+ for i in 0..(num_speeds - 1)
385
+ f = OpenStudio::Model::SupplyAirflowRatioField.new(hp_ap.heat_fan_speed_ratios[i], hp_ap.cool_fan_speed_ratios[i])
539
386
  perf.addSupplyAirflowRatioField(f)
540
387
  end
541
388
  air_loop_unitary.setDesignSpecificationMultispeedObject(perf)
542
389
 
543
390
  # Air Loop
544
-
545
- air_loop = create_air_loop(model, obj_name, air_loop_unitary, control_zone, sequential_heat_load_frac, sequential_cool_load_frac)
391
+ air_loop = create_air_loop(model, obj_name, air_loop_unitary, control_zone, sequential_heat_load_frac, sequential_cool_load_frac, fan_cfm)
546
392
  hvac_map[heat_pump.id] << air_loop
547
393
 
548
- if pan_heater_power > 0
549
-
550
- mshp_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, "Heating Coil #{EPlus::FuelTypeElectricity} Energy")
551
- mshp_sensor.setName("#{obj_name} vrf energy sensor")
552
- mshp_sensor.setKeyName(obj_name + ' coil')
553
-
554
- equip_def = OpenStudio::Model::ElectricEquipmentDefinition.new(model)
555
- equip_def.setName(obj_name + ' pan heater equip')
556
- equip = OpenStudio::Model::ElectricEquipment.new(equip_def)
557
- equip.setName(equip_def.name.to_s)
558
- equip.setSpace(control_zone.spaces[0])
559
- equip_def.setFractionRadiant(0)
560
- equip_def.setFractionLatent(0)
561
- equip_def.setFractionLost(1)
562
- equip.setSchedule(model.alwaysOnDiscreteSchedule)
563
- equip.setEndUseSubcategory(obj_name + ' pan heater')
564
-
565
- pan_heater_actuator = OpenStudio::Model::EnergyManagementSystemActuator.new(equip, *EPlus::EMSActuatorElectricEquipmentPower)
566
- pan_heater_actuator.setName("#{obj_name} pan heater actuator")
567
-
568
- tout_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Zone Outdoor Air Drybulb Temperature')
569
- tout_sensor.setName("#{obj_name} tout sensor")
570
- thermal_zones.each do |thermal_zone|
571
- if Geometry.is_living(thermal_zone)
572
- tout_sensor.setKeyName(thermal_zone.name.to_s)
573
- break
574
- end
575
- end
576
-
577
- program = OpenStudio::Model::EnergyManagementSystemProgram.new(model)
578
- program.setName(obj_name + ' pan heater program')
579
- if not heat_pump.cooling_capacity.nil?
580
- num_outdoor_units = (UnitConversions.convert([heat_pump.cooling_capacity, Constants.small].max, 'Btu/hr', 'ton') / 1.5).ceil # Assume 1.5 tons max per outdoor unit
581
- else
582
- num_outdoor_units = 2
583
- end
584
- pan_heater_power *= num_outdoor_units # W
585
- program.addLine("Set #{pan_heater_actuator.name} = 0")
586
- program.addLine("If #{mshp_sensor.name} > 0")
587
- program.addLine(" If #{tout_sensor.name} <= #{UnitConversions.convert(32.0, 'F', 'C').round(3)}")
588
- program.addLine(" Set #{pan_heater_actuator.name} = #{pan_heater_power}")
589
- program.addLine(' EndIf')
590
- program.addLine('EndIf')
591
-
592
- program_calling_manager = OpenStudio::Model::EnergyManagementSystemProgramCallingManager.new(model)
593
- program_calling_manager.setName(obj_name + ' pan heater program calling manager')
594
- program_calling_manager.setCallingPoint('BeginTimestepBeforePredictor')
595
- program_calling_manager.addProgram(program)
596
-
597
- end
598
-
599
- # Store info for HVAC Sizing measure
600
- heat_capacity_ratios_4 = []
601
- cool_capacity_ratios_4 = []
602
- heat_cfms_ton_rated_4 = []
603
- cool_cfms_ton_rated_4 = []
604
- cool_shrs_rated_gross_4 = []
605
- mshp_indices.each do |mshp_index|
606
- heat_capacity_ratios_4 << heat_capacity_ratios[mshp_index]
607
- cool_capacity_ratios_4 << cool_capacity_ratios[mshp_index]
608
- heat_cfms_ton_rated_4 << heat_cfms_ton_rated[mshp_index]
609
- cool_cfms_ton_rated_4 << cool_cfms_ton_rated[mshp_index]
610
- cool_shrs_rated_gross_4 << cool_shrs_rated_gross[mshp_index]
611
- end
612
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACSystemIsDucted, !heat_pump.distribution_system_idref.nil?)
613
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACCapacityRatioHeating, heat_capacity_ratios_4.join(','))
614
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACCapacityRatioCooling, cool_capacity_ratios_4.join(','))
615
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACRatedCFMperTonHeating, heat_cfms_ton_rated_4.join(','))
616
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACRatedCFMperTonCooling, cool_cfms_ton_rated_4.join(','))
617
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACHeatingCapacityOffset, heating_capacity_offset)
618
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACFracHeatLoadServed, heat_pump.fraction_heat_load_served)
619
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACFracCoolLoadServed, heat_pump.fraction_cool_load_served)
620
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACSHR, cool_shrs_rated_gross_4.join(','))
621
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACCoolType, Constants.ObjectNameMiniSplitHeatPump)
622
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACHeatType, Constants.ObjectNameMiniSplitHeatPump)
394
+ # HVAC Installation Quality
395
+ apply_installation_quality(model, heat_pump, heat_pump, air_loop_unitary, htg_coil, clg_coil, control_zone)
623
396
  end
624
397
 
625
398
  def self.apply_ground_to_air_heat_pump(model, runner, weather, heat_pump,
@@ -630,181 +403,101 @@ class HVAC
630
403
  obj_name = Constants.ObjectNameGroundSourceHeatPump
631
404
  sequential_heat_load_frac = calc_sequential_load_fraction(heat_pump.fraction_heat_load_served, remaining_heat_load_frac)
632
405
  sequential_cool_load_frac = calc_sequential_load_fraction(heat_pump.fraction_cool_load_served, remaining_cool_load_frac)
633
- pipe_cond = 0.23 # Pipe thermal conductivity, default to high density polyethylene
634
- ground_conductivity = 0.6
635
- grout_conductivity = 0.4
636
- bore_config = nil # Autosize
637
- bore_holes = nil # Autosize
638
- bore_depth = nil # Autosize
639
- bore_spacing = 20.0
640
- bore_diameter = 5.0
641
- pipe_size = 0.75
642
- ground_diffusivity = 0.0208
643
- fluid_type = Constants.FluidPropyleneGlycol
644
- frac_glycol = 0.3
645
- design_delta_t = 10.0
646
- chw_design = [85.0, weather.design.CoolingDrybulb - 15.0, weather.data.AnnualAvgDrybulb + 10.0].max # Temperature of water entering indoor coil,use 85F as lower bound
647
- if fluid_type == Constants.FluidWater
648
- hw_design = [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
649
- else
650
- hw_design = [35.0, weather.design.HeatingDrybulb + 35.0, weather.data.AnnualAvgDrybulb - 10.0].min # Temperature of fluid entering indoor coil, use 35F as upper bound
651
- end
652
- # Pipe nominal size conversion to pipe outside diameter and inside diameter,
653
- # only pipe sizes <= 2" are used here with DR11 (dimension ratio),
654
- if pipe_size == 0.75 # 3/4" pipe
655
- pipe_od = 1.050
656
- pipe_id = 0.859
657
- elsif pipe_size == 1.0 # 1" pipe
658
- pipe_od = 1.315
659
- pipe_id = 1.076
660
- elsif pipe_size == 1.25 # 1-1/4" pipe
661
- pipe_od = 1.660
662
- pipe_id = 1.358
663
- end
664
- u_tube_spacing_type = 'b'
665
- # Calculate distance between pipes
666
- if u_tube_spacing_type == 'as'
667
- # Two tubes, spaced 1/8” apart at the center of the borehole
668
- u_tube_spacing = 0.125
669
- elsif u_tube_spacing_type == 'b'
670
- # Two tubes equally spaced between the borehole edges
671
- u_tube_spacing = 0.9661
672
- elsif u_tube_spacing_type == 'c'
673
- # Both tubes placed against outer edge of borehole
674
- u_tube_spacing = bore_diameter - 2 * pipe_od
675
- end
676
- shank_spacing = u_tube_spacing + pipe_od # Distance from center of pipe to center of pipe
677
406
 
678
- if frac_glycol == 0
679
- fluid_type = Constants.FluidWater
680
- runner.registerWarning("Specified #{fluid_type} fluid type and 0 fraction of glycol, so assuming #{Constants.FluidWater} fluid type.")
407
+ hp_ap = heat_pump.additional_properties
408
+ htg_cfm = heat_pump.heating_airflow_cfm
409
+ clg_cfm = heat_pump.cooling_airflow_cfm
410
+
411
+ if hp_ap.frac_glycol == 0
412
+ hp_ap.fluid_type = Constants.FluidWater
413
+ runner.registerWarning("Specified #{hp_ap.fluid_type} fluid type and 0 fraction of glycol, so assuming #{Constants.FluidWater} fluid type.")
681
414
  end
682
415
 
683
416
  # Cooling Coil
684
-
685
- coil_bf = 0.08060000
686
- cool_cap_ft_spec = [0.39039063, 0.01382596, 0.00000000, -0.00445738, 0.00000000, 0.00000000]
687
- cool_SH_ft_spec = [4.27136253, -0.04678521, 0.00000000, -0.00219031, 0.00000000, 0.00000000]
688
- cool_power_ft_spec = [0.01717338, 0.00316077, 0.00000000, 0.01043792, 0.00000000, 0.00000000]
689
- coil_bf_ft_spec = [1.21005458, -0.00664200, 0.00000000, 0.00348246, 0.00000000, 0.00000000]
690
- gshp_cool_cap_fT_coeff = convert_curve_gshp(cool_cap_ft_spec, false)
691
- gshp_cool_power_fT_coeff = convert_curve_gshp(cool_power_ft_spec, false)
692
- gshp_cool_SH_fT_coeff = convert_curve_gshp(cool_SH_ft_spec, false)
693
-
694
- # FUTURE: Reconcile these adjustments with ANSI/RESNET/ICC 301-2019 Section 4.4.5
695
- 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.
696
- 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.
697
- cooling_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')
698
-
699
- clg_coil = OpenStudio::Model::CoilCoolingWaterToAirHeatPumpEquationFit.new(model)
417
+ clg_total_cap_curve = create_curve_quad_linear(model, hp_ap.cool_cap_ft_spec[0], obj_name + ' clg total cap curve')
418
+ clg_sens_cap_curve = create_curve_quint_linear(model, hp_ap.cool_sh_ft_spec[0], obj_name + ' clg sens cap curve')
419
+ clg_power_curve = create_curve_quad_linear(model, hp_ap.cool_power_ft_spec[0], obj_name + ' clg power curve')
420
+ clg_coil = OpenStudio::Model::CoilCoolingWaterToAirHeatPumpEquationFit.new(model, clg_total_cap_curve, clg_sens_cap_curve, clg_power_curve)
700
421
  clg_coil.setName(obj_name + ' clg coil')
701
- if not heat_pump.cooling_capacity.nil?
702
- clg_coil.setRatedTotalCoolingCapacity(UnitConversions.convert([heat_pump.cooling_capacity, Constants.small].max, 'Btu/hr', 'W')) # Used by HVACSizing measure
703
- end
704
- clg_coil.setRatedCoolingCoefficientofPerformance(1.0 / cooling_eir)
705
- clg_coil.setTotalCoolingCapacityCoefficient1(gshp_cool_cap_fT_coeff[0])
706
- clg_coil.setTotalCoolingCapacityCoefficient2(gshp_cool_cap_fT_coeff[1])
707
- clg_coil.setTotalCoolingCapacityCoefficient3(gshp_cool_cap_fT_coeff[2])
708
- clg_coil.setTotalCoolingCapacityCoefficient4(gshp_cool_cap_fT_coeff[3])
709
- clg_coil.setTotalCoolingCapacityCoefficient5(gshp_cool_cap_fT_coeff[4])
710
- clg_coil.setSensibleCoolingCapacityCoefficient1(gshp_cool_SH_fT_coeff[0])
711
- clg_coil.setSensibleCoolingCapacityCoefficient2(0)
712
- clg_coil.setSensibleCoolingCapacityCoefficient3(gshp_cool_SH_fT_coeff[1])
713
- clg_coil.setSensibleCoolingCapacityCoefficient4(gshp_cool_SH_fT_coeff[2])
714
- clg_coil.setSensibleCoolingCapacityCoefficient5(gshp_cool_SH_fT_coeff[3])
715
- clg_coil.setSensibleCoolingCapacityCoefficient6(gshp_cool_SH_fT_coeff[4])
716
- clg_coil.setCoolingPowerConsumptionCoefficient1(gshp_cool_power_fT_coeff[0])
717
- clg_coil.setCoolingPowerConsumptionCoefficient2(gshp_cool_power_fT_coeff[1])
718
- clg_coil.setCoolingPowerConsumptionCoefficient3(gshp_cool_power_fT_coeff[2])
719
- clg_coil.setCoolingPowerConsumptionCoefficient4(gshp_cool_power_fT_coeff[3])
720
- clg_coil.setCoolingPowerConsumptionCoefficient5(gshp_cool_power_fT_coeff[4])
422
+ clg_coil.setRatedCoolingCoefficientofPerformance(1.0 / hp_ap.cool_rated_eirs[0])
721
423
  clg_coil.setNominalTimeforCondensateRemovaltoBegin(1000)
722
424
  clg_coil.setRatioofInitialMoistureEvaporationRateandSteadyStateLatentCapacity(1.5)
425
+ clg_coil.setRatedAirFlowRate(UnitConversions.convert(clg_cfm, 'cfm', 'm^3/s'))
426
+ clg_coil.setRatedWaterFlowRate(UnitConversions.convert(hp_ap.GSHP_Loop_flow, 'gal/min', 'm^3/s'))
427
+ clg_coil.setRatedTotalCoolingCapacity(UnitConversions.convert(heat_pump.cooling_capacity, 'Btu/hr', 'W'))
428
+ clg_coil.setRatedSensibleCoolingCapacity(UnitConversions.convert(hp_ap.cooling_capacity_sensible, 'Btu/hr', 'W'))
723
429
  hvac_map[heat_pump.id] << clg_coil
724
430
 
725
431
  # Heating Coil
726
-
727
- heat_cap_ft_spec = [0.67104926, -0.00210834, 0.00000000, 0.01491424, 0.00000000, 0.00000000]
728
- heat_power_ft_spec = [-0.46308105, 0.02008988, 0.00000000, 0.00300222, 0.00000000, 0.00000000]
729
- gshp_heat_cap_fT_coeff = convert_curve_gshp(heat_cap_ft_spec, false)
730
- gshp_heat_power_fT_coeff = convert_curve_gshp(heat_power_ft_spec, false)
731
-
732
- heating_eir = (1.0 - heat_pump.heating_efficiency_cop * (fan_adjust_kw + pump_adjust_kw)) / (heat_pump.heating_efficiency_cop * (1.0 - fan_adjust_kw))
733
-
734
- htg_coil = OpenStudio::Model::CoilHeatingWaterToAirHeatPumpEquationFit.new(model)
432
+ htg_cap_curve = create_curve_quad_linear(model, hp_ap.heat_cap_ft_spec[0], obj_name + ' htg cap curve')
433
+ htg_power_curve = create_curve_quad_linear(model, hp_ap.heat_power_ft_spec[0], obj_name + ' htg power curve')
434
+ htg_coil = OpenStudio::Model::CoilHeatingWaterToAirHeatPumpEquationFit.new(model, htg_cap_curve, htg_power_curve)
735
435
  htg_coil.setName(obj_name + ' htg coil')
736
- if not heat_pump.heating_capacity.nil?
737
- htg_coil.setRatedHeatingCapacity(UnitConversions.convert([heat_pump.heating_capacity, Constants.small].max, 'Btu/hr', 'W')) # Used by HVACSizing measure
738
- end
739
- htg_coil.setRatedHeatingCoefficientofPerformance(1.0 / heating_eir)
740
- htg_coil.setHeatingCapacityCoefficient1(gshp_heat_cap_fT_coeff[0])
741
- htg_coil.setHeatingCapacityCoefficient2(gshp_heat_cap_fT_coeff[1])
742
- htg_coil.setHeatingCapacityCoefficient3(gshp_heat_cap_fT_coeff[2])
743
- htg_coil.setHeatingCapacityCoefficient4(gshp_heat_cap_fT_coeff[3])
744
- htg_coil.setHeatingCapacityCoefficient5(gshp_heat_cap_fT_coeff[4])
745
- htg_coil.setHeatingPowerConsumptionCoefficient1(gshp_heat_power_fT_coeff[0])
746
- htg_coil.setHeatingPowerConsumptionCoefficient2(gshp_heat_power_fT_coeff[1])
747
- htg_coil.setHeatingPowerConsumptionCoefficient3(gshp_heat_power_fT_coeff[2])
748
- htg_coil.setHeatingPowerConsumptionCoefficient4(gshp_heat_power_fT_coeff[3])
749
- htg_coil.setHeatingPowerConsumptionCoefficient5(gshp_heat_power_fT_coeff[4])
436
+ htg_coil.setRatedHeatingCoefficientofPerformance(1.0 / hp_ap.heat_rated_eirs[0])
437
+ htg_coil.setRatedAirFlowRate(UnitConversions.convert(htg_cfm, 'cfm', 'm^3/s'))
438
+ htg_coil.setRatedWaterFlowRate(UnitConversions.convert(hp_ap.GSHP_Loop_flow, 'gal/min', 'm^3/s'))
439
+ htg_coil.setRatedHeatingCapacity(UnitConversions.convert(heat_pump.heating_capacity, 'Btu/hr', 'W'))
750
440
  hvac_map[heat_pump.id] << htg_coil
751
441
 
752
442
  # Supplemental Heating Coil
753
-
754
443
  htg_supp_coil = create_supp_heating_coil(model, obj_name, heat_pump)
755
444
  hvac_map[heat_pump.id] << htg_supp_coil
756
445
 
757
446
  # Ground Heat Exchanger
758
-
759
447
  ground_heat_exch_vert = OpenStudio::Model::GroundHeatExchangerVertical.new(model)
760
448
  ground_heat_exch_vert.setName(obj_name + ' exchanger')
761
- ground_heat_exch_vert.setBoreHoleRadius(UnitConversions.convert(bore_diameter / 2.0, 'in', 'm'))
762
- ground_heat_exch_vert.setGroundThermalConductivity(UnitConversions.convert(ground_conductivity, 'Btu/(hr*ft*R)', 'W/(m*K)'))
763
- ground_heat_exch_vert.setGroundThermalHeatCapacity(UnitConversions.convert(ground_conductivity / ground_diffusivity, 'Btu/(ft^3*F)', 'J/(m^3*K)'))
449
+ ground_heat_exch_vert.setBoreHoleRadius(UnitConversions.convert(hp_ap.bore_diameter / 2.0, 'in', 'm'))
450
+ ground_heat_exch_vert.setGroundThermalConductivity(UnitConversions.convert(hp_ap.ground_conductivity, 'Btu/(hr*ft*R)', 'W/(m*K)'))
451
+ ground_heat_exch_vert.setGroundThermalHeatCapacity(UnitConversions.convert(hp_ap.ground_conductivity / hp_ap.ground_diffusivity, 'Btu/(ft^3*F)', 'J/(m^3*K)'))
764
452
  ground_heat_exch_vert.setGroundTemperature(UnitConversions.convert(weather.data.AnnualAvgDrybulb, 'F', 'C'))
765
- ground_heat_exch_vert.setGroutThermalConductivity(UnitConversions.convert(grout_conductivity, 'Btu/(hr*ft*R)', 'W/(m*K)'))
766
- ground_heat_exch_vert.setPipeThermalConductivity(UnitConversions.convert(pipe_cond, 'Btu/(hr*ft*R)', 'W/(m*K)'))
767
- ground_heat_exch_vert.setPipeOutDiameter(UnitConversions.convert(pipe_od, 'in', 'm'))
768
- ground_heat_exch_vert.setUTubeDistance(UnitConversions.convert(shank_spacing, 'in', 'm'))
769
- ground_heat_exch_vert.setPipeThickness(UnitConversions.convert((pipe_od - pipe_id) / 2.0, 'in', 'm'))
453
+ ground_heat_exch_vert.setGroutThermalConductivity(UnitConversions.convert(hp_ap.grout_conductivity, 'Btu/(hr*ft*R)', 'W/(m*K)'))
454
+ ground_heat_exch_vert.setPipeThermalConductivity(UnitConversions.convert(hp_ap.pipe_cond, 'Btu/(hr*ft*R)', 'W/(m*K)'))
455
+ ground_heat_exch_vert.setPipeOutDiameter(UnitConversions.convert(hp_ap.pipe_od, 'in', 'm'))
456
+ ground_heat_exch_vert.setUTubeDistance(UnitConversions.convert(hp_ap.shank_spacing, 'in', 'm'))
457
+ ground_heat_exch_vert.setPipeThickness(UnitConversions.convert((hp_ap.pipe_od - hp_ap.pipe_id) / 2.0, 'in', 'm'))
770
458
  ground_heat_exch_vert.setMaximumLengthofSimulation(1)
771
459
  ground_heat_exch_vert.setGFunctionReferenceRatio(0.0005)
460
+ ground_heat_exch_vert.setDesignFlowRate(UnitConversions.convert(hp_ap.GSHP_Loop_flow, 'gal/min', 'm^3/s'))
461
+ ground_heat_exch_vert.setNumberofBoreHoles(hp_ap.GSHP_Bore_Holes.to_i)
462
+ ground_heat_exch_vert.setBoreHoleLength(UnitConversions.convert(hp_ap.GSHP_Bore_Depth, 'ft', 'm'))
463
+ ground_heat_exch_vert.removeAllGFunctions
464
+ for i in 0..(hp_ap.GSHP_G_Functions[0].size - 1)
465
+ ground_heat_exch_vert.addGFunction(hp_ap.GSHP_G_Functions[0][i], hp_ap.GSHP_G_Functions[1][i])
466
+ end
772
467
 
773
468
  # Plant Loop
774
-
775
469
  plant_loop = OpenStudio::Model::PlantLoop.new(model)
776
470
  plant_loop.setName(obj_name + ' condenser loop')
777
- if fluid_type == Constants.FluidWater
471
+ if hp_ap.fluid_type == Constants.FluidWater
778
472
  plant_loop.setFluidType('Water')
779
473
  else
780
- plant_loop.setFluidType({ Constants.FluidPropyleneGlycol => 'PropyleneGlycol', Constants.FluidEthyleneGlycol => 'EthyleneGlycol' }[fluid_type])
781
- plant_loop.setGlycolConcentration((frac_glycol * 100).to_i)
474
+ plant_loop.setFluidType({ Constants.FluidPropyleneGlycol => 'PropyleneGlycol', Constants.FluidEthyleneGlycol => 'EthyleneGlycol' }[hp_ap.fluid_type])
475
+ plant_loop.setGlycolConcentration((hp_ap.frac_glycol * 100).to_i)
782
476
  end
783
477
  plant_loop.setMaximumLoopTemperature(48.88889)
784
- plant_loop.setMinimumLoopTemperature(UnitConversions.convert(hw_design, 'F', 'C'))
478
+ plant_loop.setMinimumLoopTemperature(UnitConversions.convert(hp_ap.design_hw, 'F', 'C'))
785
479
  plant_loop.setMinimumLoopFlowRate(0)
786
480
  plant_loop.setLoadDistributionScheme('SequentialLoad')
787
481
  plant_loop.addSupplyBranchForComponent(ground_heat_exch_vert)
788
482
  plant_loop.addDemandBranchForComponent(htg_coil)
789
483
  plant_loop.addDemandBranchForComponent(clg_coil)
484
+ plant_loop.setMaximumLoopFlowRate(UnitConversions.convert(hp_ap.GSHP_Loop_flow, 'gal/min', 'm^3/s'))
790
485
  hvac_map[heat_pump.id] << plant_loop
791
486
 
792
487
  sizing_plant = plant_loop.sizingPlant
793
488
  sizing_plant.setLoopType('Condenser')
794
- sizing_plant.setDesignLoopExitTemperature(UnitConversions.convert(chw_design, 'F', 'C'))
795
- sizing_plant.setLoopDesignTemperatureDifference(UnitConversions.convert(design_delta_t, 'R', 'K'))
489
+ sizing_plant.setDesignLoopExitTemperature(UnitConversions.convert(hp_ap.design_chw, 'F', 'C'))
490
+ sizing_plant.setLoopDesignTemperatureDifference(UnitConversions.convert(hp_ap.design_delta_t, 'R', 'K'))
796
491
 
797
492
  setpoint_mgr_follow_ground_temp = OpenStudio::Model::SetpointManagerFollowGroundTemperature.new(model)
798
493
  setpoint_mgr_follow_ground_temp.setName(obj_name + ' condenser loop temp')
799
494
  setpoint_mgr_follow_ground_temp.setControlVariable('Temperature')
800
495
  setpoint_mgr_follow_ground_temp.setMaximumSetpointTemperature(48.88889)
801
- setpoint_mgr_follow_ground_temp.setMinimumSetpointTemperature(UnitConversions.convert(hw_design, 'F', 'C'))
496
+ setpoint_mgr_follow_ground_temp.setMinimumSetpointTemperature(UnitConversions.convert(hp_ap.design_hw, 'F', 'C'))
802
497
  setpoint_mgr_follow_ground_temp.setReferenceGroundTemperatureObjectType('Site:GroundTemperature:Deep')
803
498
  setpoint_mgr_follow_ground_temp.addToNode(plant_loop.supplyOutletNode)
804
499
 
805
500
  # Pump
806
-
807
- # Pump power set in hvac_sizing.rb
808
501
  pump = OpenStudio::Model::PumpVariableSpeed.new(model)
809
502
  pump.setName(obj_name + ' pump')
810
503
  pump.setMotorEfficiency(0.85)
@@ -817,11 +510,18 @@ class HVAC
817
510
  pump.setMinimumFlowRate(0)
818
511
  pump.setPumpControlType('Intermittent')
819
512
  pump.addToNode(plant_loop.supplyInletNode)
513
+ if heat_pump.cooling_capacity > 1.0
514
+ pump_w = heat_pump.pump_watts_per_ton * UnitConversions.convert(heat_pump.cooling_capacity, 'Btu/hr', 'ton')
515
+ else
516
+ pump_w = heat_pump.pump_watts_per_ton * UnitConversions.convert(heat_pump.heating_capacity, 'Btu/hr', 'ton')
517
+ end
518
+ pump_w = [pump_w, 1.0].max # prevent error if zero
519
+ pump.setRatedPowerConsumption(pump_w)
520
+ pump.setRatedFlowRate(calc_pump_rated_flow_rate(0.75, pump_w, pump.ratedPumpHead))
820
521
  hvac_map[heat_pump.id] << pump
821
522
  hvac_map[heat_pump.id] += disaggregate_fan_or_pump(model, pump, htg_coil, clg_coil, htg_supp_coil)
822
523
 
823
524
  # Pipes
824
-
825
525
  chiller_bypass_pipe = OpenStudio::Model::PipeAdiabatic.new(model)
826
526
  plant_loop.addSupplyBranchForComponent(chiller_bypass_pipe)
827
527
  coil_bypass_pipe = OpenStudio::Model::PipeAdiabatic.new(model)
@@ -834,14 +534,14 @@ class HVAC
834
534
  demand_outlet_pipe.addToNode(plant_loop.demandOutletNode)
835
535
 
836
536
  # Fan
837
-
838
- fan = create_supply_fan(model, obj_name, 1, heat_pump.fan_watts_per_cfm)
537
+ fan_cfm = [htg_cfm, clg_cfm].max
538
+ fan = create_supply_fan(model, obj_name, 1, heat_pump.fan_watts_per_cfm, fan_cfm)
839
539
  hvac_map[heat_pump.id] += disaggregate_fan_or_pump(model, fan, htg_coil, clg_coil, htg_supp_coil)
840
540
 
841
541
  # Unitary System
842
-
843
- air_loop_unitary = create_air_loop_unitary_system(model, obj_name, fan, htg_coil, clg_coil, htg_supp_coil, 40.0)
542
+ air_loop_unitary = create_air_loop_unitary_system(model, obj_name, fan, htg_coil, clg_coil, htg_supp_coil, htg_cfm, clg_cfm, 40.0)
844
543
  hvac_map[heat_pump.id] << air_loop_unitary
544
+ set_pump_power_ems_program(model, pump_w, pump, air_loop_unitary)
845
545
 
846
546
  if heat_pump.is_shared_system
847
547
  # Shared pump power per ANSI/RESNET/ICC 301-2019 Section 4.4.5.1 (pump runs 8760)
@@ -865,24 +565,11 @@ class HVAC
865
565
  end
866
566
 
867
567
  # Air Loop
868
-
869
- air_loop = create_air_loop(model, obj_name, air_loop_unitary, control_zone, sequential_heat_load_frac, sequential_cool_load_frac)
568
+ air_loop = create_air_loop(model, obj_name, air_loop_unitary, control_zone, sequential_heat_load_frac, sequential_cool_load_frac, fan_cfm)
870
569
  hvac_map[heat_pump.id] << air_loop
871
570
 
872
- # Store info for HVAC Sizing measure
873
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACSHR, heat_pump.cooling_shr.to_s)
874
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoGSHPCoil_BF_FT_SPEC, coil_bf_ft_spec.join(','))
875
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoGSHPCoilBF, coil_bf)
876
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACFracHeatLoadServed, heat_pump.fraction_heat_load_served)
877
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACFracCoolLoadServed, heat_pump.fraction_cool_load_served)
878
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoGSHPBoreSpacing, bore_spacing)
879
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoGSHPBoreHoles, bore_holes.to_s)
880
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoGSHPBoreDepth, bore_depth.to_s)
881
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoGSHPBoreConfig, bore_config.to_s)
882
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoGSHPUTubeSpacingType, u_tube_spacing_type)
883
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACCoolType, Constants.ObjectNameGroundSourceHeatPump)
884
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACHeatType, Constants.ObjectNameGroundSourceHeatPump)
885
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACPumpPower, heat_pump.pump_watts_per_ton)
571
+ # HVAC Installation Quality
572
+ apply_installation_quality(model, heat_pump, heat_pump, air_loop_unitary, htg_coil, clg_coil, control_zone)
886
573
  end
887
574
 
888
575
  def self.apply_water_loop_to_air_heat_pump(model, runner, heat_pump,
@@ -898,10 +585,11 @@ class HVAC
898
585
  obj_name = Constants.ObjectNameWaterLoopHeatPump
899
586
  sequential_heat_load_frac = calc_sequential_load_fraction(heat_pump.fraction_heat_load_served, remaining_heat_load_frac)
900
587
  sequential_cool_load_frac = 0.0
901
- hp_min_temp, supp_max_temp = get_heat_pump_temp_assumptions(heat_pump)
902
588
 
903
- # Cooling Coil
589
+ hp_ap = heat_pump.additional_properties
590
+ htg_cfm = heat_pump.heating_airflow_cfm
904
591
 
592
+ # Cooling Coil (none)
905
593
  clg_coil = nil
906
594
 
907
595
  # Heating Coil (model w/ constant efficiency)
@@ -911,35 +599,27 @@ class HVAC
911
599
  htg_coil.setName(obj_name + ' htg coil')
912
600
  htg_coil.setRatedCOP(heat_pump.heating_efficiency_cop)
913
601
  htg_coil.setDefrostTimePeriodFraction(0.00001) # Disable defrost; avoid E+ warning w/ value of zero
914
- htg_coil.setMinimumOutdoorDryBulbTemperatureforCompressorOperation(UnitConversions.convert(hp_min_temp, 'F', 'C'))
602
+ htg_coil.setMinimumOutdoorDryBulbTemperatureforCompressorOperation(UnitConversions.convert(hp_ap.hp_min_temp, 'F', 'C'))
603
+ htg_coil.setRatedTotalHeatingCapacity(UnitConversions.convert(heat_pump.heating_capacity, 'Btu/hr', 'W'))
604
+ htg_coil.setRatedAirFlowRate(htg_cfm)
915
605
  hvac_map[heat_pump.id] << htg_coil
916
606
 
917
607
  # Supplemental Heating Coil
918
-
919
608
  htg_supp_coil = create_supp_heating_coil(model, obj_name, heat_pump)
920
609
  hvac_map[heat_pump.id] << htg_supp_coil
921
610
 
922
611
  # Fan
923
-
924
- fan_power_installed = 0.5 # FIXME
925
- fan = create_supply_fan(model, obj_name, 1, fan_power_installed)
612
+ fan_power_installed = 0.0 # Use provided net COP
613
+ fan = create_supply_fan(model, obj_name, 1, fan_power_installed, htg_cfm)
926
614
  hvac_map[heat_pump.id] += disaggregate_fan_or_pump(model, fan, htg_coil, clg_coil, htg_supp_coil)
927
615
 
928
616
  # Unitary System
929
-
930
- air_loop_unitary = create_air_loop_unitary_system(model, obj_name, fan, htg_coil, clg_coil, htg_supp_coil, supp_max_temp)
617
+ air_loop_unitary = create_air_loop_unitary_system(model, obj_name, fan, htg_coil, clg_coil, htg_supp_coil, htg_cfm, nil, hp_ap.supp_max_temp)
931
618
  hvac_map[heat_pump.id] << air_loop_unitary
932
619
 
933
620
  # Air Loop
934
-
935
- air_loop = create_air_loop(model, obj_name, air_loop_unitary, control_zone, sequential_heat_load_frac, sequential_cool_load_frac)
621
+ air_loop = create_air_loop(model, obj_name, air_loop_unitary, control_zone, sequential_heat_load_frac, sequential_cool_load_frac, htg_cfm)
936
622
  hvac_map[heat_pump.id] << air_loop
937
-
938
- # Store info for HVAC Sizing measure
939
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACFracHeatLoadServed, heat_pump.fraction_heat_load_served)
940
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACFracCoolLoadServed, heat_pump.fraction_cool_load_served)
941
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACCoolType, Constants.ObjectNameWaterLoopHeatPump)
942
- air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACHeatType, Constants.ObjectNameWaterLoopHeatPump)
943
623
  end
944
624
 
945
625
  def self.apply_boiler(model, runner, heating_system,
@@ -965,7 +645,6 @@ class HVAC
965
645
  end
966
646
 
967
647
  # Plant Loop
968
-
969
648
  plant_loop = OpenStudio::Model::PlantLoop.new(model)
970
649
  plant_loop.setName(obj_name + ' hydronic heat loop')
971
650
  plant_loop.setFluidType('Water')
@@ -981,8 +660,8 @@ class HVAC
981
660
  loop_sizing.setLoopDesignTemperatureDifference(UnitConversions.convert(20.0, 'R', 'K'))
982
661
 
983
662
  # Pump
984
-
985
663
  pump_w = heating_system.electric_auxiliary_energy / 2.08
664
+ pump_w = [pump_w, 1.0].max # prevent error if zero
986
665
  pump = OpenStudio::Model::PumpVariableSpeed.new(model)
987
666
  pump.setName(obj_name + ' hydronic pump')
988
667
  pump.setRatedPowerConsumption(pump_w)
@@ -999,13 +678,9 @@ class HVAC
999
678
  hvac_map[heating_system.id] << pump
1000
679
 
1001
680
  # Boiler
1002
-
1003
681
  boiler = OpenStudio::Model::BoilerHotWater.new(model)
1004
682
  boiler.setName(obj_name)
1005
683
  boiler.setFuelType(EPlus.fuel_type(heating_system.heating_system_fuel))
1006
- if not heating_system.heating_capacity.nil?
1007
- boiler.setNominalCapacity(UnitConversions.convert([heating_system.heating_capacity, Constants.small].max, 'Btu/hr', 'W')) # Used by HVACSizing measure
1008
- end
1009
684
  if is_condensing
1010
685
  # Convert Rated Efficiency at 80F and 1.0PLR where the performance curves are derived from to Design condition as input
1011
686
  boiler_RatedHWRT = UnitConversions.convert(80.0 - 32.0, 'R', 'K')
@@ -1031,6 +706,7 @@ class HVAC
1031
706
  boiler.setOptimumPartLoadRatio(1.0)
1032
707
  boiler.setWaterOutletUpperTemperatureLimit(99.9)
1033
708
  boiler.setParasiticElectricLoad(0)
709
+ boiler.setNominalCapacity(UnitConversions.convert(heating_system.heating_capacity, 'Btu/hr', 'W'))
1034
710
  plant_loop.addSupplyBranchForComponent(boiler)
1035
711
  hvac_map[heating_system.id] << boiler
1036
712
  set_pump_power_ems_program(model, pump_w, pump, boiler)
@@ -1066,16 +742,21 @@ class HVAC
1066
742
  pipe_demand_outlet = OpenStudio::Model::PipeAdiabatic.new(model)
1067
743
  pipe_demand_outlet.addToNode(plant_loop.demandOutletNode)
1068
744
 
1069
- if heating_system.distribution_system.hydronic_and_air_type.to_s == HPXML::HydronicAndAirTypeFanCoil
745
+ bb_ua = UnitConversions.convert(heating_system.heating_capacity, 'Btu/hr', 'W') / UnitConversions.convert(UnitConversions.convert(loop_sizing.designLoopExitTemperature, 'C', 'F') - 10.0 - 95.0, 'R', 'K') * 3.0 # W/K
746
+ max_water_flow = UnitConversions.convert(heating_system.heating_capacity, 'Btu/hr', 'W') / UnitConversions.convert(20.0, 'R', 'K') / 4.186 / 998.2 / 1000.0 * 2.0 # m^3/s
747
+ fan_cfm = 400.0 * UnitConversions.convert(heating_system.heating_capacity, 'Btu/hr', 'ton') # CFM; assumes 400 cfm/ton
748
+
749
+ if heating_system.distribution_system.air_type.to_s == HPXML::AirTypeFanCoil
1070
750
  # Fan
1071
- fan = create_supply_fan(model, obj_name, 1, 0.0) # fan energy included in above pump via Electrix Auxiliar Energy (EAE)
751
+ fan = create_supply_fan(model, obj_name, 1, 0.0, fan_cfm) # fan energy included in above pump via Electric Auxiliary Energy (EAE)
1072
752
 
1073
753
  # Heating Coil
1074
754
  htg_coil = OpenStudio::Model::CoilHeatingWater.new(model, model.alwaysOnDiscreteSchedule)
755
+ htg_coil.setRatedCapacity(UnitConversions.convert(heating_system.heating_capacity, 'Btu/hr', 'W'))
756
+ htg_coil.setUFactorTimesAreaValue(bb_ua)
757
+ htg_coil.setMaximumWaterFlowRate(max_water_flow)
758
+ htg_coil.setPerformanceInputMethod('NominalCapacity')
1075
759
  htg_coil.setName(obj_name + ' htg coil')
1076
- if not heating_system.heating_capacity.nil?
1077
- htg_coil.setRatedCapacity(UnitConversions.convert([heating_system.heating_capacity, Constants.small].max, 'Btu/hr', 'W')) # Used by HVACSizing measure
1078
- end
1079
760
  plant_loop.addDemandBranchForComponent(htg_coil)
1080
761
 
1081
762
  # Cooling Coil (always off)
@@ -1099,6 +780,8 @@ class HVAC
1099
780
  zone_hvac.setMaximumColdWaterFlowRate(0.0)
1100
781
  zone_hvac.setCoolingConvergenceTolerance(0.001)
1101
782
  zone_hvac.setMaximumOutdoorAirFlowRate(0.0)
783
+ zone_hvac.setMaximumSupplyAirFlowRate(UnitConversions.convert(fan_cfm, 'cfm', 'm^3/s'))
784
+ zone_hvac.setMaximumHotWaterFlowRate(max_water_flow)
1102
785
  zone_hvac.addToThermalZone(control_zone)
1103
786
  hvac_map[heating_system.id] << zone_hvac
1104
787
  hvac_map[heating_system.id] += disaggregate_fan_or_pump(model, pump, zone_hvac, nil, nil)
@@ -1106,10 +789,11 @@ class HVAC
1106
789
  # Heating Coil
1107
790
  htg_coil = OpenStudio::Model::CoilHeatingWaterBaseboard.new(model)
1108
791
  htg_coil.setName(obj_name + ' htg coil')
1109
- if not heating_system.heating_capacity.nil?
1110
- htg_coil.setHeatingDesignCapacity(UnitConversions.convert([heating_system.heating_capacity, Constants.small].max, 'Btu/hr', 'W')) # Used by HVACSizing measure
1111
- end
1112
792
  htg_coil.setConvergenceTolerance(0.001)
793
+ htg_coil.setHeatingDesignCapacity(UnitConversions.convert(heating_system.heating_capacity, 'Btu/hr', 'W'))
794
+ htg_coil.setUFactorTimesAreaValue(bb_ua)
795
+ htg_coil.setMaximumWaterFlowRate(max_water_flow)
796
+ htg_coil.setHeatingDesignCapacityMethod('HeatingDesignCapacity')
1113
797
  plant_loop.addDemandBranchForComponent(htg_coil)
1114
798
  hvac_map[heating_system.id] << htg_coil
1115
799
 
@@ -1123,10 +807,6 @@ class HVAC
1123
807
 
1124
808
  control_zone.setSequentialHeatingFractionSchedule(zone_hvac, get_sequential_load_schedule(model, sequential_heat_load_frac))
1125
809
  control_zone.setSequentialCoolingFractionSchedule(zone_hvac, get_sequential_load_schedule(model, 0))
1126
-
1127
- # Store info for HVAC Sizing measure
1128
- zone_hvac.additionalProperties.setFeature(Constants.SizingInfoHVACFracHeatLoadServed, heating_system.fraction_heat_load_served)
1129
- zone_hvac.additionalProperties.setFeature(Constants.SizingInfoHVACHeatType, Constants.ObjectNameBoiler)
1130
810
  end
1131
811
 
1132
812
  def self.apply_electric_baseboard(model, runner, heating_system,
@@ -1138,22 +818,15 @@ class HVAC
1138
818
  sequential_heat_load_frac = calc_sequential_load_fraction(heating_system.fraction_heat_load_served, remaining_heat_load_frac)
1139
819
 
1140
820
  # Baseboard
1141
-
1142
821
  zone_hvac = OpenStudio::Model::ZoneHVACBaseboardConvectiveElectric.new(model)
1143
822
  zone_hvac.setName(obj_name)
1144
- if not heating_system.heating_capacity.nil?
1145
- zone_hvac.setNominalCapacity(UnitConversions.convert([heating_system.heating_capacity, Constants.small].max, 'Btu/hr', 'W')) # Used by HVACSizing measure
1146
- end
1147
823
  zone_hvac.setEfficiency(heating_system.heating_efficiency_percent)
824
+ zone_hvac.setNominalCapacity(UnitConversions.convert(heating_system.heating_capacity, 'Btu/hr', 'W'))
1148
825
  zone_hvac.addToThermalZone(control_zone)
1149
826
  hvac_map[heating_system.id] << zone_hvac
1150
827
 
1151
828
  control_zone.setSequentialHeatingFractionSchedule(zone_hvac, get_sequential_load_schedule(model, sequential_heat_load_frac))
1152
829
  control_zone.setSequentialCoolingFractionSchedule(zone_hvac, get_sequential_load_schedule(model, 0))
1153
-
1154
- # Store info for HVAC Sizing measure
1155
- zone_hvac.additionalProperties.setFeature(Constants.SizingInfoHVACFracHeatLoadServed, heating_system.fraction_heat_load_served)
1156
- zone_hvac.additionalProperties.setFeature(Constants.SizingInfoHVACHeatType, Constants.ObjectNameElectricBaseboard)
1157
830
  end
1158
831
 
1159
832
  def self.apply_unit_heater(model, runner, heating_system,
@@ -1163,10 +836,10 @@ class HVAC
1163
836
  hvac_map[heating_system.id] = []
1164
837
  obj_name = Constants.ObjectNameUnitHeater
1165
838
  sequential_heat_load_frac = calc_sequential_load_fraction(heating_system.fraction_heat_load_served, remaining_heat_load_frac)
1166
- airflow_cfm_per_ton = 350.0
1167
839
 
1168
- # Heating Coil
840
+ htg_ap = heating_system.additional_properties
1169
841
 
842
+ # Heating Coil
1170
843
  efficiency = heating_system.heating_efficiency_afue
1171
844
  efficiency = heating_system.heating_efficiency_percent if efficiency.nil?
1172
845
  if heating_system.heating_system_fuel == HPXML::FuelTypeElectricity
@@ -1179,39 +852,30 @@ class HVAC
1179
852
  htg_coil.setParasiticGasLoad(0)
1180
853
  htg_coil.setFuelType(EPlus.fuel_type(heating_system.heating_system_fuel))
1181
854
  end
855
+ htg_coil.setNominalCapacity(UnitConversions.convert(heating_system.heating_capacity, 'Btu/hr', 'W'))
1182
856
  htg_coil.setName(obj_name + ' htg coil')
1183
- if not heating_system.heating_capacity.nil?
1184
- htg_coil.setNominalCapacity(UnitConversions.convert([heating_system.heating_capacity, Constants.small].max, 'Btu/hr', 'W')) # Used by HVACSizing measure
1185
- end
1186
857
  hvac_map[heating_system.id] << htg_coil
1187
858
 
1188
859
  # Fan
1189
-
1190
- fan = create_supply_fan(model, obj_name, 1, 0.0) # Fan power assigned in hvac_sizing.rb
860
+ htg_cfm = heating_system.heating_airflow_cfm
861
+ fan_watts_per_cfm = heating_system.fan_watts / htg_cfm
862
+ fan = create_supply_fan(model, obj_name, 1, fan_watts_per_cfm, htg_cfm)
1191
863
  hvac_map[heating_system.id] += disaggregate_fan_or_pump(model, fan, htg_coil, nil, nil)
1192
864
 
1193
865
  # Unitary System
1194
-
1195
- unitary_system = create_air_loop_unitary_system(model, obj_name, fan, htg_coil, nil, nil)
866
+ unitary_system = create_air_loop_unitary_system(model, obj_name, fan, htg_coil, nil, nil, htg_cfm, nil)
1196
867
  unitary_system.setControllingZoneorThermostatLocation(control_zone)
1197
868
  unitary_system.addToThermalZone(control_zone)
1198
869
  hvac_map[heating_system.id] << unitary_system
1199
870
 
1200
871
  control_zone.setSequentialHeatingFractionSchedule(unitary_system, get_sequential_load_schedule(model, sequential_heat_load_frac))
1201
872
  control_zone.setSequentialCoolingFractionSchedule(unitary_system, get_sequential_load_schedule(model, 0))
1202
-
1203
- # Store info for HVAC Sizing measure
1204
- unitary_system.additionalProperties.setFeature(Constants.SizingInfoHVACRatedCFMperTonHeating, [airflow_cfm_per_ton].join(','))
1205
- unitary_system.additionalProperties.setFeature(Constants.SizingInfoHVACFracHeatLoadServed, heating_system.fraction_heat_load_served)
1206
- unitary_system.additionalProperties.setFeature(Constants.SizingInfoHVACHeatType, Constants.ObjectNameUnitHeater)
1207
- unitary_system.additionalProperties.setFeature(Constants.SizingInfoHVACFanWatts, heating_system.fan_watts)
1208
873
  end
1209
874
 
1210
875
  def self.apply_ideal_air_loads(model, runner, obj_name, sequential_cool_load_frac,
1211
876
  sequential_heat_load_frac, control_zone)
1212
877
 
1213
878
  # Ideal Air System
1214
-
1215
879
  ideal_air = OpenStudio::Model::ZoneHVACIdealLoadsAirSystem.new(model)
1216
880
  ideal_air.setName(obj_name)
1217
881
  ideal_air.setMaximumHeatingSupplyAirTemperature(50)
@@ -1236,62 +900,70 @@ class HVAC
1236
900
 
1237
901
  control_zone.setSequentialCoolingFractionSchedule(ideal_air, get_sequential_load_schedule(model, sequential_cool_load_frac))
1238
902
  control_zone.setSequentialHeatingFractionSchedule(ideal_air, get_sequential_load_schedule(model, sequential_heat_load_frac))
1239
-
1240
- # Store info for HVAC Sizing measure
1241
- ideal_air.additionalProperties.setFeature(Constants.SizingInfoHVACCoolType, Constants.ObjectNameIdealAirSystem)
1242
- ideal_air.additionalProperties.setFeature(Constants.SizingInfoHVACHeatType, Constants.ObjectNameIdealAirSystem)
1243
903
  end
1244
904
 
1245
- def self.apply_dehumidifier(model, runner, dehumidifier, living_space, hvac_map)
1246
- hvac_map[dehumidifier.id] = []
1247
-
1248
- water_removal_rate = dehumidifier.capacity
1249
- energy_factor = dehumidifier.energy_factor
1250
-
1251
- control_zone = living_space.thermalZone.get
1252
- obj_name = Constants.ObjectNameDehumidifier
905
+ def self.apply_dehumidifiers(model, runner, dehumidifiers, living_space, hvac_map)
906
+ dehumidifier_id = dehumidifiers[0].id # Syncs with SimulationOutputReport, which only looks at first dehumidifier ID
907
+ hvac_map[dehumidifier_id] = []
1253
908
 
1254
- avg_rh_setpoint = dehumidifier.rh_setpoint * 100.0 # (EnergyPlus uses 60 for 60% RH)
1255
- relative_humidity_setpoint_sch = OpenStudio::Model::ScheduleConstant.new(model)
1256
- relative_humidity_setpoint_sch.setName(Constants.ObjectNameRelativeHumiditySetpoint)
1257
- relative_humidity_setpoint_sch.setValue(avg_rh_setpoint)
909
+ if dehumidifiers.map { |d| d.rh_setpoint }.uniq.size > 1
910
+ fail 'All dehumidifiers must have the same setpoint but multiple setpoints were specified.'
911
+ end
1258
912
 
1259
913
  # Dehumidifier coefficients
1260
914
  # Generic model coefficients from Winkler, Christensen, and Tomerlin (2011)
1261
915
  w_coeff = [-1.162525707, 0.02271469, -0.000113208, 0.021110538, -0.0000693034, 0.000378843]
1262
916
  ef_coeff = [-1.902154518, 0.063466565, -0.000622839, 0.039540407, -0.000125637, -0.000176722]
1263
917
  pl_coeff = [0.90, 0.10, 0.0]
1264
- water_removal_curve = create_curve_biquadratic(model, w_coeff, 'DXDH-WaterRemove-Cap-fT', -100, 100, -100, 100)
1265
- energy_factor_curve = create_curve_biquadratic(model, ef_coeff, 'DXDH-EnergyFactor-fT', -100, 100, -100, 100)
1266
- part_load_frac_curve = create_curve_quadratic(model, pl_coeff, 'DXDH-PLF-fPLR', 0, 1, 0.7, 1)
1267
- if energy_factor.nil?
918
+
919
+ dehumidifiers.each do |d|
920
+ next unless d.energy_factor.nil?
921
+
1268
922
  # shift inputs tested under IEF test conditions to those under EF test conditions with performance curves
1269
- energy_factor, water_removal_rate = apply_dehumidifier_ief_to_ef_inputs(dehumidifier.type, w_coeff, ef_coeff, dehumidifier.integrated_energy_factor, water_removal_rate)
923
+ d.energy_factor, d.capacity = apply_dehumidifier_ief_to_ef_inputs(d.type, w_coeff, ef_coeff, d.integrated_energy_factor, d.capacity)
1270
924
  end
1271
925
 
926
+ total_capacity = dehumidifiers.map { |d| d.capacity }.sum
927
+ avg_energy_factor = dehumidifiers.map { |d| d.energy_factor * d.capacity }.sum / total_capacity
928
+ total_fraction_served = dehumidifiers.map { |d| d.fraction_served }.sum
929
+
930
+ control_zone = living_space.thermalZone.get
931
+ obj_name = Constants.ObjectNameDehumidifier
932
+
933
+ rh_setpoint = dehumidifiers[0].rh_setpoint * 100.0 # (EnergyPlus uses 60 for 60% RH)
934
+ relative_humidity_setpoint_sch = OpenStudio::Model::ScheduleConstant.new(model)
935
+ relative_humidity_setpoint_sch.setName(Constants.ObjectNameRelativeHumiditySetpoint)
936
+ relative_humidity_setpoint_sch.setValue(rh_setpoint)
937
+
938
+ capacity_curve = create_curve_biquadratic(model, w_coeff, 'DXDH-CAP-fT', -100, 100, -100, 100)
939
+ energy_factor_curve = create_curve_biquadratic(model, ef_coeff, 'DXDH-EF-fT', -100, 100, -100, 100)
940
+ part_load_frac_curve = create_curve_quadratic(model, pl_coeff, 'DXDH-PLF-fPLR', 0, 1, 0.7, 1)
941
+
1272
942
  # Calculate air flow rate by assuming 2.75 cfm/pint/day (based on experimental test data)
1273
- air_flow_rate = 2.75 * water_removal_rate
943
+ air_flow_rate = 2.75 * total_capacity
1274
944
 
945
+ # Humidity Setpoint
1275
946
  humidistat = OpenStudio::Model::ZoneControlHumidistat.new(model)
1276
947
  humidistat.setName(obj_name + ' humidistat')
1277
948
  humidistat.setHumidifyingRelativeHumiditySetpointSchedule(relative_humidity_setpoint_sch)
1278
949
  humidistat.setDehumidifyingRelativeHumiditySetpointSchedule(relative_humidity_setpoint_sch)
1279
950
  control_zone.setZoneControlHumidistat(humidistat)
1280
951
 
1281
- zone_hvac = OpenStudio::Model::ZoneHVACDehumidifierDX.new(model, water_removal_curve, energy_factor_curve, part_load_frac_curve)
952
+ # Dehumidifier
953
+ zone_hvac = OpenStudio::Model::ZoneHVACDehumidifierDX.new(model, capacity_curve, energy_factor_curve, part_load_frac_curve)
1282
954
  zone_hvac.setName(obj_name)
1283
955
  zone_hvac.setAvailabilitySchedule(model.alwaysOnDiscreteSchedule)
1284
- zone_hvac.setRatedWaterRemoval(UnitConversions.convert(water_removal_rate, 'pint', 'L'))
1285
- zone_hvac.setRatedEnergyFactor(energy_factor / dehumidifier.fraction_served)
956
+ zone_hvac.setRatedWaterRemoval(UnitConversions.convert(total_capacity, 'pint', 'L'))
957
+ zone_hvac.setRatedEnergyFactor(avg_energy_factor / total_fraction_served)
1286
958
  zone_hvac.setRatedAirFlowRate(UnitConversions.convert(air_flow_rate, 'cfm', 'm^3/s'))
1287
959
  zone_hvac.setMinimumDryBulbTemperatureforDehumidifierOperation(10)
1288
960
  zone_hvac.setMaximumDryBulbTemperatureforDehumidifierOperation(40)
1289
961
 
1290
962
  zone_hvac.addToThermalZone(control_zone)
1291
963
 
1292
- hvac_map[dehumidifier.id] << zone_hvac
1293
- if dehumidifier.fraction_served < 1.0
1294
- adjust_dehumidifier_load_EMS(dehumidifier.fraction_served, zone_hvac, model, living_space)
964
+ hvac_map[dehumidifier_id] << zone_hvac
965
+ if total_fraction_served < 1.0
966
+ adjust_dehumidifier_load_EMS(total_fraction_served, zone_hvac, model, living_space)
1295
967
  end
1296
968
  end
1297
969
 
@@ -1393,7 +1065,7 @@ class HVAC
1393
1065
  if has_ceiling_fan
1394
1066
  clg_ceiling_fan_offset = hvac_control.ceiling_fan_cooling_setpoint_temp_offset
1395
1067
  if not clg_ceiling_fan_offset.nil?
1396
- HVAC.get_default_ceiling_fan_months(weather).each_with_index do |operation, m|
1068
+ get_default_ceiling_fan_months(weather).each_with_index do |operation, m|
1397
1069
  next unless operation == 1
1398
1070
 
1399
1071
  clg_weekday_setpoints[m] = [clg_weekday_setpoints[m], Array.new(24, clg_ceiling_fan_offset)].transpose.map { |i| i.reduce(:+) }
@@ -1491,99 +1163,261 @@ class HVAC
1491
1163
  return clg_sp, clg_setup_sp, clg_setup_hrs_per_week, clg_setup_start_hr
1492
1164
  end
1493
1165
 
1494
- def self.get_hp_clg_curves(num_speeds, heat_pump, fan_power_rated, cool_c_d, runner)
1495
- if num_speeds == 1
1496
- cool_rated_airflow_rate = 394.2 # cfm/ton
1497
- cool_capacity_ratios = [1.0]
1498
- cool_fan_speed_ratios = [1.0]
1499
- cool_shrs = [heat_pump.cooling_shr]
1500
- cool_cap_ft_spec = [[3.68637657, -0.098352478, 0.000956357, 0.005838141, -0.0000127, -0.000131702]]
1501
- cool_eir_ft_spec = [[-3.437356399, 0.136656369, -0.001049231, -0.0079378, 0.000185435, -0.0001441]]
1502
- cool_cap_fflow_spec = [[0.718664047, 0.41797409, -0.136638137]]
1503
- cool_eir_fflow_spec = [[1.143487507, -0.13943972, -0.004047787]]
1504
- cool_eers = [calc_eer_cooling_1speed(heat_pump.cooling_efficiency_seer, fan_power_rated, cool_eir_ft_spec)]
1505
- elsif num_speeds == 2
1506
- cool_rated_airflow_rate = 344.1 # cfm/ton
1507
- cool_capacity_ratios = [0.72, 1.0]
1508
- cool_fan_speed_ratios = [0.86, 1.0]
1509
- cool_shrs = [heat_pump.cooling_shr - 0.014, heat_pump.cooling_shr] # TODO: is the following assumption correct (revisit Dylan's data?)? OR should value from HPXML be used for both stages?
1510
- cool_cap_ft_spec = [[3.998418659, -0.108728222, 0.001056818, 0.007512314, -0.0000139, -0.000164716],
1511
- [3.466810106, -0.091476056, 0.000901205, 0.004163355, -0.00000919, -0.000110829]]
1512
- cool_eir_ft_spec = [[-4.282911381, 0.181023691, -0.001357391, -0.026310378, 0.000333282, -0.000197405],
1513
- [-3.557757517, 0.112737397, -0.000731381, 0.013184877, 0.000132645, -0.000338716]]
1514
- cool_cap_fflow_spec = [[0.655239515, 0.511655216, -0.166894731],
1515
- [0.618281092, 0.569060264, -0.187341356]]
1516
- cool_eir_fflow_spec = [[1.639108268, -0.998953996, 0.359845728],
1517
- [1.570774717, -0.914152018, 0.343377302]]
1518
- cool_eers = calc_eers_cooling_2speed(runner, heat_pump.cooling_efficiency_seer, cool_c_d, cool_capacity_ratios, cool_fan_speed_ratios, fan_power_rated, cool_eir_ft_spec, cool_cap_ft_spec, true)
1519
- elsif num_speeds == 4
1520
- cool_rated_airflow_rate = 411.0 # cfm/ton
1521
- cool_capacity_ratios = [0.36, 0.51, 0.67, 1.0]
1522
- cool_fan_speed_ratios = [0.42, 0.54, 0.68, 1.0]
1523
- cool_shrs = [1.115, 1.026, 1.013, 1.0].map { |mult| heat_pump.cooling_shr * mult }
1524
- # The following coefficients were generated using NREL experimental performance mapping for the Carrier unit
1525
- cool_cap_coeff_perf_map = [[1.6516044444444447, 0.0698916049382716, -0.0005546296296296296, -0.08870160493827162, 0.0004135802469135802, 0.00029077160493827157],
1526
- [-6.84948049382716, 0.26946, -0.0019413580246913577, -0.03281469135802469, 0.00015694444444444442, 3.32716049382716e-05],
1527
- [-4.53543086419753, 0.15358543209876546, -0.0009345679012345678, 0.002666913580246914, -7.993827160493826e-06, -0.00011617283950617283],
1528
- [-3.500948395061729, 0.11738987654320988, -0.0006580246913580248, 0.007003148148148148, -2.8518518518518517e-05, -0.0001284259259259259],
1529
- [1.8769221728395058, -0.04768641975308643, 0.0006885802469135801, 0.006643395061728395, 1.4209876543209876e-05, -0.00024043209876543206]]
1530
- cool_cap_ft_spec = cool_cap_coeff_perf_map.select { |i| [0, 1, 2, 4].include? cool_cap_coeff_perf_map.index(i) }
1531
- cool_cap_ft_spec_3 = cool_cap_coeff_perf_map.select { |i| [0, 1, 4].include? cool_cap_coeff_perf_map.index(i) }
1532
- cool_eir_coeff_perf_map = [[2.896298765432099, -0.12487654320987657, 0.0012148148148148148, 0.04492037037037037, 8.734567901234567e-05, -0.0006348765432098764],
1533
- [6.428076543209876, -0.20913209876543212, 0.0018521604938271604, 0.024392592592592594, 0.00019691358024691356, -0.0006012345679012346],
1534
- [5.136356049382716, -0.1591530864197531, 0.0014151234567901232, 0.018665555555555557, 0.00020398148148148147, -0.0005407407407407407],
1535
- [1.3823471604938273, -0.02875123456790123, 0.00038302469135802463, 0.006344814814814816, 0.00024836419753086417, -0.00047469135802469134],
1536
- [-1.0411735802469133, 0.055261604938271605, -0.0004404320987654321, 0.0002154938271604939, 0.00017484567901234564, -0.0002017901234567901]]
1537
- cool_eir_ft_spec = cool_eir_coeff_perf_map.select { |i| [0, 1, 2, 4].include? cool_eir_coeff_perf_map.index(i) }
1538
- cool_eir_ft_spec_3 = cool_eir_coeff_perf_map.select { |i| [0, 1, 4].include? cool_eir_coeff_perf_map.index(i) }
1539
- cool_eir_fflow_spec = [[1, 0, 0]] * 4
1540
- cool_cap_fflow_spec = [[1, 0, 0]] * 4
1541
- cap_ratio_seer_3 = cool_capacity_ratios.select { |i| [0, 1, 3].include? cool_capacity_ratios.index(i) }
1542
- fan_speed_seer_3 = cool_fan_speed_ratios.select { |i| [0, 1, 3].include? cool_fan_speed_ratios.index(i) }
1543
- cool_eers = calc_eers_cooling_4speed(runner, heat_pump.cooling_efficiency_seer, cool_c_d, cap_ratio_seer_3, fan_speed_seer_3, fan_power_rated, cool_eir_ft_spec_3, cool_cap_ft_spec_3)
1544
- end
1545
- return cool_rated_airflow_rate, cool_fan_speed_ratios, cool_capacity_ratios, cool_shrs, cool_eers, cool_cap_ft_spec, cool_eir_ft_spec, cool_cap_fflow_spec, cool_eir_fflow_spec
1166
+ def self.set_cool_curves_ashp(heat_pump)
1167
+ hp_ap = heat_pump.additional_properties
1168
+ if hp_ap.num_speeds == 1
1169
+ # From "Improved Modeling of Residential Air Conditioners and Heat Pumps for Energy Calculations", Cutler at al
1170
+ # https://www.nrel.gov/docs/fy13osti/56354.pdf
1171
+ hp_ap.cool_rated_airflow_rate = 394.2 # cfm/ton of rated capacity
1172
+ hp_ap.cool_capacity_ratios = [1.0]
1173
+ hp_ap.cool_fan_speed_ratios = [1.0]
1174
+ hp_ap.cool_rated_shrs_net = [heat_pump.cooling_shr]
1175
+ hp_ap.cool_cap_ft_spec = [[3.68637657, -0.098352478, 0.000956357, 0.005838141, -0.0000127, -0.000131702]]
1176
+ hp_ap.cool_eir_ft_spec = [[-3.437356399, 0.136656369, -0.001049231, -0.0079378, 0.000185435, -0.0001441]]
1177
+ # Single stage systems have PSC or constant torque ECM blowers, so the airflow rate is affected by the static pressure losses.
1178
+ hp_ap.cool_cap_fflow_spec = [[0.718664047, 0.41797409, -0.136638137]]
1179
+ hp_ap.cool_eir_fflow_spec = [[1.143487507, -0.13943972, -0.004047787]]
1180
+ 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)]
1181
+ elsif hp_ap.num_speeds == 2
1182
+ # From "Improved Modeling of Residential Air Conditioners and Heat Pumps for Energy Calculations", Cutler at al
1183
+ # https://www.nrel.gov/docs/fy13osti/56354.pdf
1184
+ hp_ap.cool_rated_airflow_rate = 344.1 # cfm/ton
1185
+ hp_ap.cool_capacity_ratios = [0.72, 1.0]
1186
+ hp_ap.cool_fan_speed_ratios = [0.86, 1.0]
1187
+ hp_ap.cool_rated_shrs_net = [heat_pump.cooling_shr - 0.014, heat_pump.cooling_shr] # TODO: is the following assumption correct (revisit Dylan's data?)? OR should value from HPXML be used for both stages?
1188
+ hp_ap.cool_cap_ft_spec = [[3.998418659, -0.108728222, 0.001056818, 0.007512314, -0.0000139, -0.000164716],
1189
+ [3.466810106, -0.091476056, 0.000901205, 0.004163355, -0.00000919, -0.000110829]]
1190
+ hp_ap.cool_eir_ft_spec = [[-4.282911381, 0.181023691, -0.001357391, -0.026310378, 0.000333282, -0.000197405],
1191
+ [-3.557757517, 0.112737397, -0.000731381, 0.013184877, 0.000132645, -0.000338716]]
1192
+ # Most two stage systems have PSC or constant torque ECM blowers, so the airflow rate is affected by the static pressure losses.
1193
+ hp_ap.cool_cap_fflow_spec = [[0.655239515, 0.511655216, -0.166894731],
1194
+ [0.618281092, 0.569060264, -0.187341356]]
1195
+ hp_ap.cool_eir_fflow_spec = [[1.639108268, -0.998953996, 0.359845728],
1196
+ [1.570774717, -0.914152018, 0.343377302]]
1197
+ 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)
1198
+ elsif hp_ap.num_speeds == 4
1199
+ # From Carrier heat pump lab testing
1200
+ hp_ap.cool_rated_airflow_rate = 411.0 # cfm/ton
1201
+ hp_ap.cool_capacity_ratios = [0.36, 0.51, 0.67, 1.0]
1202
+ hp_ap.cool_fan_speed_ratios = [0.42, 0.54, 0.68, 1.0]
1203
+ hp_ap.cool_rated_shrs_net = [1.115, 1.026, 1.013, 1.0].map { |mult| heat_pump.cooling_shr * mult }
1204
+ hp_ap.cool_cap_coeff_perf_map = [[1.6516044444444447, 0.0698916049382716, -0.0005546296296296296, -0.08870160493827162, 0.0004135802469135802, 0.00029077160493827157],
1205
+ [-6.84948049382716, 0.26946, -0.0019413580246913577, -0.03281469135802469, 0.00015694444444444442, 3.32716049382716e-05],
1206
+ [-4.53543086419753, 0.15358543209876546, -0.0009345679012345678, 0.002666913580246914, -7.993827160493826e-06, -0.00011617283950617283],
1207
+ [-3.500948395061729, 0.11738987654320988, -0.0006580246913580248, 0.007003148148148148, -2.8518518518518517e-05, -0.0001284259259259259],
1208
+ [1.8769221728395058, -0.04768641975308643, 0.0006885802469135801, 0.006643395061728395, 1.4209876543209876e-05, -0.00024043209876543206]]
1209
+ 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) }
1210
+ 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) }
1211
+ hp_ap.cool_eir_coeff_perf_map = [[2.896298765432099, -0.12487654320987657, 0.0012148148148148148, 0.04492037037037037, 8.734567901234567e-05, -0.0006348765432098764],
1212
+ [6.428076543209876, -0.20913209876543212, 0.0018521604938271604, 0.024392592592592594, 0.00019691358024691356, -0.0006012345679012346],
1213
+ [5.136356049382716, -0.1591530864197531, 0.0014151234567901232, 0.018665555555555557, 0.00020398148148148147, -0.0005407407407407407],
1214
+ [1.3823471604938273, -0.02875123456790123, 0.00038302469135802463, 0.006344814814814816, 0.00024836419753086417, -0.00047469135802469134],
1215
+ [-1.0411735802469133, 0.055261604938271605, -0.0004404320987654321, 0.0002154938271604939, 0.00017484567901234564, -0.0002017901234567901]]
1216
+ 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) }
1217
+ 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) }
1218
+ # Variable speed systems have constant flow ECM blowers, so the air handler can always achieve the design airflow rate by sacrificing blower power.
1219
+ # So we assume that there is only one corresponding airflow rate for each compressor speed.
1220
+ hp_ap.cool_eir_fflow_spec = [[1, 0, 0]] * 4
1221
+ hp_ap.cool_cap_fflow_spec = [[1, 0, 0]] * 4
1222
+ hp_ap.cap_ratio_seer_3 = hp_ap.cool_capacity_ratios.select { |i| [0, 1, 3].include? hp_ap.cool_capacity_ratios.index(i) }
1223
+ 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) }
1224
+ 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)
1225
+ end
1546
1226
  end
1547
1227
 
1548
- def self.get_default_compressor_type(hvac_type, seer)
1549
- if [HPXML::HVACTypeCentralAirConditioner,
1550
- HPXML::HVACTypeHeatPumpAirToAir].include? hvac_type
1551
- if seer <= 15
1552
- return HPXML::HVACCompressorTypeSingleStage
1553
- elsif seer <= 21
1554
- return HPXML::HVACCompressorTypeTwoStage
1555
- elsif seer > 21
1556
- return HPXML::HVACCompressorTypeVariableSpeed
1228
+ def self.set_ashp_htg_curves(heat_pump)
1229
+ hp_ap = heat_pump.additional_properties
1230
+ if hp_ap.num_speeds == 1
1231
+ # From "Improved Modeling of Residential Air Conditioners and Heat Pumps for Energy Calculations", Cutler at al
1232
+ # https://www.nrel.gov/docs/fy13osti/56354.pdf
1233
+ hp_ap.heat_rated_airflow_rate = 384.1 # cfm/ton
1234
+ hp_ap.heat_capacity_ratios = [1.0]
1235
+ hp_ap.heat_fan_speed_ratios = [1.0]
1236
+ hp_ap.heat_eir_ft_spec = [[0.718398423, 0.003498178, 0.000142202, -0.005724331, 0.00014085, -0.000215321]]
1237
+ hp_ap.heat_cap_fflow_spec = [[0.694045465, 0.474207981, -0.168253446]]
1238
+ hp_ap.heat_eir_fflow_spec = [[2.185418751, -1.942827919, 0.757409168]]
1239
+ if heat_pump.heating_capacity_17F.nil?
1240
+ hp_ap.heat_cap_ft_spec = [[0.566333415, -0.000744164, -0.0000103, 0.009414634, 0.0000506, -0.00000675]]
1241
+ else
1242
+ hp_ap.heat_cap_ft_spec = calc_heat_cap_ft_spec_using_capacity_17F(heat_pump)
1243
+ end
1244
+ 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)]
1245
+ elsif hp_ap.num_speeds == 2
1246
+ # From "Improved Modeling of Residential Air Conditioners and Heat Pumps for Energy Calculations", Cutler at al
1247
+ # https://www.nrel.gov/docs/fy13osti/56354.pdf
1248
+ hp_ap.heat_rated_airflow_rate = 352.2 # cfm/ton
1249
+ hp_ap.heat_capacity_ratios = [0.72, 1.0]
1250
+ hp_ap.heat_fan_speed_ratios = [0.8, 1.0]
1251
+ hp_ap.heat_eir_ft_spec = [[0.36338171, 0.013523725, 0.000258872, -0.009450269, 0.000439519, -0.000653723],
1252
+ [0.981100941, -0.005158493, 0.000243416, -0.005274352, 0.000230742, -0.000336954]]
1253
+ hp_ap.heat_cap_fflow_spec = [[0.741466907, 0.378645444, -0.119754733],
1254
+ [0.76634609, 0.32840943, -0.094701495]]
1255
+ hp_ap.heat_eir_fflow_spec = [[2.153618211, -1.737190609, 0.584269478],
1256
+ [2.001041353, -1.58869128, 0.587593517]]
1257
+ if heat_pump.heating_capacity_17F.nil?
1258
+ hp_ap.heat_cap_ft_spec = [[0.335690634, 0.002405123, -0.0000464, 0.013498735, 0.0000499, -0.00000725],
1259
+ [0.306358843, 0.005376987, -0.0000579, 0.011645092, 0.0000591, -0.0000203]]
1260
+ else
1261
+ hp_ap.heat_cap_ft_spec = calc_heat_cap_ft_spec_using_capacity_17F(heat_pump)
1262
+ end
1263
+ 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)
1264
+ elsif hp_ap.num_speeds == 4
1265
+ # From Carrier heat pump lab testing
1266
+ hp_ap.heat_rated_airflow_rate = 296.9 # cfm/ton
1267
+ hp_ap.heat_capacity_ratios = [0.33, 0.56, 1.0, 1.17]
1268
+ hp_ap.heat_fan_speed_ratios = [0.63, 0.76, 1.0, 1.19]
1269
+ hp_ap.heat_eir_ft_spec = [[0.708311527, 0.020732093, 0.000391479, -0.037640031, 0.000979937, -0.001079042],
1270
+ [0.025480155, 0.020169585, 0.000121341, -0.004429789, 0.000166472, -0.00036447],
1271
+ [0.379003189, 0.014195012, 0.0000821046, -0.008894061, 0.000151519, -0.000210299],
1272
+ [0.690404655, 0.00616619, 0.000137643, -0.009350199, 0.000153427, -0.000213258]]
1273
+ hp_ap.heat_cap_fflow_spec = [[1, 0, 0]] * 4
1274
+ hp_ap.heat_eir_fflow_spec = [[1, 0, 0]] * 4
1275
+ if heat_pump.heating_capacity_17F.nil?
1276
+ hp_ap.heat_cap_ft_spec = [[0.304192655, -0.003972566, 0.0000196432, 0.024471251, -0.000000774126, -0.0000841323],
1277
+ [0.496381324, -0.00144792, 0.0, 0.016020855, 0.0000203447, -0.0000584118],
1278
+ [0.697171186, -0.006189599, 0.0000337077, 0.014291981, 0.0000105633, -0.0000387956],
1279
+ [0.555513805, -0.001337363, -0.00000265117, 0.014328826, 0.0000163849, -0.0000480711]]
1280
+ else
1281
+ hp_ap.heat_cap_ft_spec = calc_heat_cap_ft_spec_using_capacity_17F(heat_pump)
1557
1282
  end
1283
+ 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)
1558
1284
  end
1559
- return
1560
1285
  end
1561
1286
 
1562
- def self.get_default_ceiling_fan_power()
1563
- # Per ANSI/RESNET/ICC 301
1564
- return 42.6 # W
1565
- end
1287
+ def self.set_cool_curves_room_ac(cooling_system)
1288
+ clg_ap = cooling_system.additional_properties
1566
1289
 
1567
- def self.get_default_ceiling_fan_quantity(nbeds)
1568
- # Per ANSI/RESNET/ICC 301
1569
- return nbeds + 1
1290
+ # From "Improved Modeling of Residential Air Conditioners and Heat Pumps for Energy Calculations", Cutler at al
1291
+ # https://www.nrel.gov/docs/fy13osti/56354.pdf
1292
+ clg_ap.cool_cap_ft_spec = [[3.68637657, -0.098352478, 0.000956357, 0.005838141, -0.0000127, -0.000131702]]
1293
+ clg_ap.cool_eir_ft_spec = [[-3.437356399, 0.136656369, -0.001049231, -0.0079378, 0.000185435, -0.0001441]]
1294
+ clg_ap.cool_cap_fflow_spec = [[1, 0, 0]]
1295
+ clg_ap.cool_eir_fflow_spec = [[1, 0, 0]]
1570
1296
  end
1571
1297
 
1572
- def self.get_default_ceiling_fan_months(weather)
1573
- # Per ANSI/RESNET/ICC 301
1574
- months = [0] * 12
1575
- weather.data.MonthlyAvgDrybulbs.each_with_index do |val, m|
1576
- next unless val > 63.0 # deg-F
1298
+ def self.set_cool_curves_mshp(heat_pump, num_speeds)
1299
+ hp_ap = heat_pump.additional_properties
1577
1300
 
1578
- months[m] = 1
1579
- end
1580
- return months
1301
+ # From Daikin mini-split lab testing
1302
+ hp_ap.cool_cap_ft_spec = [[0.7531983499655835, 0.003618193903031667, 0.0, 0.006574385031351544, -6.87181191015432e-05, 0.0]] * num_speeds
1303
+ hp_ap.cool_eir_ft_spec = [[-0.06376924779982301, -0.0013360593470367282, 1.413060577993827e-05, 0.019433076486584752, -4.91395947154321e-05, -4.909341249475308e-05]] * num_speeds
1304
+ hp_ap.cool_cap_fflow_spec = [[1, 0, 0]] * num_speeds
1305
+ hp_ap.cool_eir_fflow_spec = [[1, 0, 0]] * num_speeds
1306
+
1307
+ hp_ap.cool_min_capacity_ratio = 0.4 # frac
1308
+ hp_ap.cool_max_capacity_ratio = 1.2 # frac
1309
+ hp_ap.cool_min_cfm_per_ton = 200.0 / hp_ap.cool_min_capacity_ratio # Convert cfm/ton of nominal rated capacity to cfm/ton of min capacity
1310
+ hp_ap.cool_max_cfm_per_ton = 425.0 / hp_ap.cool_max_capacity_ratio # Convert cfm/ton of nominal rated capacity to cfm/ton of max capacity
1581
1311
  end
1582
1312
 
1583
- def self.get_default_heating_and_cooling_seasons(weather)
1584
- # Calculates heating/cooling seasons from BAHSP definition
1313
+ def self.set_heat_curves_mshp(heat_pump, num_speeds)
1314
+ hp_ap = heat_pump.additional_properties
1585
1315
 
1586
- monthly_temps = weather.data.MonthlyAvgDrybulbs
1316
+ # From Daikin mini-split lab testing
1317
+ hp_ap.heat_eir_ft_spec = [[0.9999941697687026, 0.004684593830254383, 5.901286675833333e-05, -0.0028624467783091973, 1.3041120194135802e-05, -0.00016172918478765433]] * num_speeds
1318
+ hp_ap.heat_cap_fflow_spec = [[1, 0, 0]] * num_speeds
1319
+ hp_ap.heat_eir_fflow_spec = [[1, 0, 0]] * num_speeds
1320
+
1321
+ # Derive coefficients from user input for capacity retention at outdoor drybulb temperature X [C].
1322
+ if heat_pump.heating_capacity_17F.nil? || ((heat_pump.heating_capacity_17F == 0) && (heat_pump.heating_capacity == 0))
1323
+ cap_retention_frac = 0.25 # frac
1324
+ cap_retention_temp = -5.0 # deg-F
1325
+ else
1326
+ cap_retention_frac = heat_pump.heating_capacity_17F / heat_pump.heating_capacity
1327
+ cap_retention_temp = 17.0 # deg-F
1328
+ end
1329
+
1330
+ # Biquadratic: capacity multiplier = a + b*IAT + c*IAT^2 + d*OAT + e*OAT^2 + f*IAT*OAT
1331
+ x_A = UnitConversions.convert(cap_retention_temp, 'F', 'C')
1332
+ y_A = cap_retention_frac
1333
+ x_B = UnitConversions.convert(47.0, 'F', 'C') # 47F is the rating point
1334
+ y_B = 1.0 # Maximum capacity factor is 1 at the rating point, by definition (this is maximum capacity, not nominal capacity)
1335
+ oat_slope = (y_B - y_A) / (x_B - x_A)
1336
+ oat_intercept = y_A - (x_A * oat_slope)
1337
+
1338
+ # Coefficients for the indoor temperature relationship are retained from the generic curve (Daikin lab data).
1339
+ iat_slope = -0.010386676170938
1340
+ iat_intercept = 0.219274275
1341
+ a = oat_intercept + iat_intercept
1342
+ b = iat_slope
1343
+ c = 0
1344
+ d = oat_slope
1345
+ e = 0
1346
+ f = 0
1347
+ hp_ap.heat_cap_ft_spec = [HVAC.convert_curve_biquadratic([a, b, c, d, e, f], false)] * num_speeds
1348
+
1349
+ hp_ap.heat_min_capacity_ratio = 0.3 # frac
1350
+ hp_ap.heat_max_capacity_ratio = 1.2 # frac
1351
+ hp_ap.heat_min_cfm_per_ton = 200.0 / hp_ap.heat_min_capacity_ratio # Convert cfm/ton of nominal rated capacity to cfm/ton of min capacity
1352
+ hp_ap.heat_max_cfm_per_ton = 400.0 / hp_ap.heat_max_capacity_ratio # Convert cfm/ton of nominal rated capacity to cfm/ton of min capacity
1353
+ end
1354
+
1355
+ def self.set_curves_gshp(heat_pump)
1356
+ hp_ap = heat_pump.additional_properties
1357
+
1358
+ # E+ equation fit coil coefficients generated following approach in Tang's thesis:
1359
+ # See Appendix B of https://hvac.okstate.edu/sites/default/files/pubs/theses/MS/27-Tang_Thesis_05.pdf
1360
+ # Coefficients generated by catalog data: https://files.climatemaster.com/Genesis-GS-Series-Product-Catalog.pdf, p180
1361
+ # Data point taken as rated condition:
1362
+ # EWT: 80F EAT:80/67F, AFR: 1200cfm, WFR: 4.5gpm
1363
+ hp_ap.cool_cap_ft_spec = [[-1.57177156131221, 4.60343712716819, -2.15976622898044, 0.0590964827802021, 0.0194696644460315]]
1364
+ hp_ap.cool_power_ft_spec = [[-4.42471086639888, 0.658017281046304, 4.37331801294626, 0.174096187531254, -0.0526514790164159]]
1365
+ hp_ap.cool_sh_ft_spec = [[4.54172823345154, 14.7653304889134, -18.3541272090485, -0.74401391092935, 0.545560799548833, 0.0182620032235494]]
1366
+ hp_ap.cool_rated_shrs_gross = [heat_pump.cooling_shr]
1367
+ # FUTURE: Reconcile these fan/pump adjustments with ANSI/RESNET/ICC 301-2019 Section 4.4.5
1368
+ 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.
1369
+ 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.
1370
+ 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')
1371
+ hp_ap.cool_rated_eirs = [cool_eir]
1372
+
1373
+ # E+ equation fit coil coefficients from Tang's thesis:
1374
+ # See Appendix B Figure B.3 of https://hvac.okstate.edu/sites/default/files/pubs/theses/MS/27-Tang_Thesis_05.pdf
1375
+ # Coefficients generated by catalog data
1376
+ hp_ap.heat_cap_ft_spec = [[-5.12650150, -0.93997630, 7.21443206, 0.121065721, 0.051809805]]
1377
+ hp_ap.heat_power_ft_spec = [[-7.73235249, 6.43390775, 2.29152262, -0.175598629, 0.005888871]]
1378
+ 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))
1379
+ hp_ap.heat_rated_eirs = [heat_eir]
1380
+ end
1381
+
1382
+ def self.get_default_compressor_type(hvac_type, seer)
1383
+ if [HPXML::HVACTypeCentralAirConditioner,
1384
+ HPXML::HVACTypeHeatPumpAirToAir].include? hvac_type
1385
+ if seer <= 15
1386
+ return HPXML::HVACCompressorTypeSingleStage
1387
+ elsif seer <= 21
1388
+ return HPXML::HVACCompressorTypeTwoStage
1389
+ elsif seer > 21
1390
+ return HPXML::HVACCompressorTypeVariableSpeed
1391
+ end
1392
+ end
1393
+ return
1394
+ end
1395
+
1396
+ def self.get_default_ceiling_fan_power()
1397
+ # Per ANSI/RESNET/ICC 301
1398
+ return 42.6 # W
1399
+ end
1400
+
1401
+ def self.get_default_ceiling_fan_quantity(nbeds)
1402
+ # Per ANSI/RESNET/ICC 301
1403
+ return nbeds + 1
1404
+ end
1405
+
1406
+ def self.get_default_ceiling_fan_months(weather)
1407
+ # Per ANSI/RESNET/ICC 301
1408
+ months = [0] * 12
1409
+ weather.data.MonthlyAvgDrybulbs.each_with_index do |val, m|
1410
+ next unless val > 63.0 # deg-F
1411
+
1412
+ months[m] = 1
1413
+ end
1414
+ return months
1415
+ end
1416
+
1417
+ def self.get_default_heating_and_cooling_seasons(weather)
1418
+ # Calculates heating/cooling seasons from BAHSP definition
1419
+
1420
+ monthly_temps = weather.data.MonthlyAvgDrybulbs
1587
1421
  heat_design_db = weather.design.HeatingDrybulb
1588
1422
 
1589
1423
  # create basis lists with zero for every month
@@ -1757,32 +1591,36 @@ class HVAC
1757
1591
  sensors = { 'clg' => clg_object_sensor,
1758
1592
  'primary_htg' => htg_object_sensor,
1759
1593
  'backup_htg' => backup_htg_object_sensor }
1594
+ sensors = sensors.select { |m, s| !s.nil? }
1760
1595
 
1761
1596
  fan_or_pump_var = fan_or_pump.name.to_s.gsub(' ', '_')
1762
1597
 
1763
1598
  # Disaggregate electric fan/pump energy
1764
1599
  fan_or_pump_program = OpenStudio::Model::EnergyManagementSystemProgram.new(model)
1765
1600
  fan_or_pump_program.setName("#{fan_or_pump_var} disaggregate program")
1766
- sensors.each do |mode, sensor|
1767
- next if sensor.nil?
1768
-
1769
- fan_or_pump_program.addLine("Set #{fan_or_pump_var}_#{mode} = 0")
1770
- end
1771
- i = 0
1772
- sensors.each do |mode, sensor|
1773
- next if sensor.nil?
1774
-
1775
- if i == 0
1776
- fan_or_pump_program.addLine("If #{sensor.name} > 0")
1777
- elsif i == 2
1778
- fan_or_pump_program.addLine('Else')
1779
- else
1780
- fan_or_pump_program.addLine("ElseIf #{sensor.name} > 0")
1601
+ if htg_object.is_a?(OpenStudio::Model::ZoneHVACBaseboardConvectiveWater) || htg_object.is_a?(OpenStudio::Model::ZoneHVACFourPipeFanCoil)
1602
+ # Pump may occassionally run when baseboard isn't, so just assign all pump energy here
1603
+ mode, sensor = sensors.first
1604
+ if (sensors.size != 1) || (mode != 'primary_htg')
1605
+ fail 'Unexpected situation.'
1781
1606
  end
1782
1607
  fan_or_pump_program.addLine(" Set #{fan_or_pump_var}_#{mode} = #{fan_or_pump_sensor.name}")
1783
- i += 1
1608
+ else
1609
+ sensors.each do |mode, sensor|
1610
+ fan_or_pump_program.addLine("Set #{fan_or_pump_var}_#{mode} = 0")
1611
+ end
1612
+ sensors.each_with_index do |(mode, sensor), i|
1613
+ if i == 0
1614
+ fan_or_pump_program.addLine("If #{sensor.name} > 0")
1615
+ elsif i == 2
1616
+ fan_or_pump_program.addLine('Else')
1617
+ else
1618
+ fan_or_pump_program.addLine("ElseIf #{sensor.name} > 0")
1619
+ end
1620
+ fan_or_pump_program.addLine(" Set #{fan_or_pump_var}_#{mode} = #{fan_or_pump_sensor.name}")
1621
+ end
1622
+ fan_or_pump_program.addLine('EndIf')
1784
1623
  end
1785
- fan_or_pump_program.addLine('EndIf')
1786
1624
  hvac_objects << fan_or_pump_program
1787
1625
 
1788
1626
  fan_or_pump_program_calling_manager = OpenStudio::Model::EnergyManagementSystemProgramCallingManager.new(model)
@@ -1804,12 +1642,6 @@ class HVAC
1804
1642
  fan_or_pump_ems_output_var.setEMSProgramOrSubroutineName(fan_or_pump_program)
1805
1643
  fan_or_pump_ems_output_var.setUnits('J')
1806
1644
  hvac_objects << fan_or_pump_ems_output_var
1807
-
1808
- # Used by HEScore
1809
- # TODO: Move to HEScore project or reporting measure
1810
- outputVariable = OpenStudio::Model::OutputVariable.new(fan_or_pump_ems_output_var.name.to_s, model)
1811
- outputVariable.setReportingFrequency('monthly')
1812
- outputVariable.setKeyValue('*')
1813
1645
  end
1814
1646
 
1815
1647
  return hvac_objects
@@ -1878,14 +1710,12 @@ class HVAC
1878
1710
  htg_supp_coil.setParasiticGasLoad(0)
1879
1711
  htg_supp_coil.setFuelType(EPlus.fuel_type(fuel))
1880
1712
  end
1713
+ htg_supp_coil.setNominalCapacity(UnitConversions.convert(capacity, 'Btu/hr', 'W'))
1881
1714
  htg_supp_coil.setName(obj_name + ' ' + Constants.ObjectNameBackupHeatingCoil)
1882
- if not capacity.nil?
1883
- htg_supp_coil.setNominalCapacity(UnitConversions.convert([capacity, Constants.small].max, 'Btu/hr', 'W')) # Used by HVACSizing measure
1884
- end
1885
1715
  return htg_supp_coil
1886
1716
  end
1887
1717
 
1888
- def self.create_supply_fan(model, obj_name, num_speeds, fan_watts_per_cfm)
1718
+ def self.create_supply_fan(model, obj_name, num_speeds, fan_watts_per_cfm, fan_cfm)
1889
1719
  if num_speeds == 1
1890
1720
  fan = OpenStudio::Model::FanOnOff.new(model, model.alwaysOnDiscreteSchedule)
1891
1721
  else
@@ -1898,25 +1728,30 @@ class HVAC
1898
1728
  fan.setEndUseSubcategory('supply fan')
1899
1729
  fan.setMotorEfficiency(1.0)
1900
1730
  fan.setMotorInAirstreamFraction(1.0)
1731
+ fan.setMaximumFlowRate(UnitConversions.convert(fan_cfm, 'cfm', 'm^3/s'))
1901
1732
  return fan
1902
1733
  end
1903
1734
 
1904
- def self.create_air_loop_unitary_system(model, obj_name, fan, htg_coil, clg_coil, htg_supp_coil, supp_max_temp = nil)
1735
+ def self.create_air_loop_unitary_system(model, obj_name, fan, htg_coil, clg_coil, htg_supp_coil, htg_cfm, clg_cfm, supp_max_temp = nil)
1905
1736
  air_loop_unitary = OpenStudio::Model::AirLoopHVACUnitarySystem.new(model)
1906
1737
  air_loop_unitary.setName(obj_name + ' unitary system')
1907
1738
  air_loop_unitary.setAvailabilitySchedule(model.alwaysOnDiscreteSchedule)
1908
1739
  air_loop_unitary.setSupplyFan(fan)
1909
1740
  air_loop_unitary.setFanPlacement('BlowThrough')
1910
1741
  air_loop_unitary.setSupplyAirFanOperatingModeSchedule(model.alwaysOffDiscreteSchedule)
1742
+ air_loop_unitary.setSupplyAirFlowRateMethodDuringHeatingOperation('SupplyAirFlowRate')
1911
1743
  if htg_coil.nil?
1912
1744
  air_loop_unitary.setSupplyAirFlowRateDuringHeatingOperation(0.0)
1913
1745
  else
1914
1746
  air_loop_unitary.setHeatingCoil(htg_coil)
1747
+ air_loop_unitary.setSupplyAirFlowRateDuringHeatingOperation(UnitConversions.convert(htg_cfm, 'cfm', 'm^3/s'))
1915
1748
  end
1749
+ air_loop_unitary.setSupplyAirFlowRateMethodDuringCoolingOperation('SupplyAirFlowRate')
1916
1750
  if clg_coil.nil?
1917
1751
  air_loop_unitary.setSupplyAirFlowRateDuringCoolingOperation(0.0)
1918
1752
  else
1919
1753
  air_loop_unitary.setCoolingCoil(clg_coil)
1754
+ air_loop_unitary.setSupplyAirFlowRateDuringCoolingOperation(UnitConversions.convert(clg_cfm, 'cfm', 'm^3/s'))
1920
1755
  end
1921
1756
  if htg_supp_coil.nil?
1922
1757
  air_loop_unitary.setMaximumSupplyAirTemperature(UnitConversions.convert(120.0, 'F', 'C'))
@@ -1929,12 +1764,13 @@ class HVAC
1929
1764
  return air_loop_unitary
1930
1765
  end
1931
1766
 
1932
- def self.create_air_loop(model, obj_name, system, control_zone, sequential_heat_load_frac, sequential_cool_load_frac)
1767
+ def self.create_air_loop(model, obj_name, system, control_zone, sequential_heat_load_frac, sequential_cool_load_frac, airflow_cfm)
1933
1768
  air_loop = OpenStudio::Model::AirLoopHVAC.new(model)
1934
1769
  air_loop.setAvailabilitySchedule(model.alwaysOnDiscreteSchedule)
1935
1770
  air_loop.setName(obj_name + ' airloop')
1936
1771
  air_loop.zoneSplitter.setName(obj_name + ' zone splitter')
1937
1772
  air_loop.zoneMixer.setName(obj_name + ' zone mixer')
1773
+ air_loop.setDesignSupplyAirFlowRate(UnitConversions.convert(airflow_cfm, 'cfm', 'm^3/s'))
1938
1774
  system.addToNode(air_loop.supplyInletNode)
1939
1775
 
1940
1776
  if system.is_a? OpenStudio::Model::AirLoopHVACUnitarySystem
@@ -1945,6 +1781,7 @@ class HVAC
1945
1781
  air_terminal.setConstantMinimumAirFlowFraction(0)
1946
1782
  air_terminal.setFixedMinimumAirFlowRate(0)
1947
1783
  end
1784
+ air_terminal.setMaximumAirFlowRate(UnitConversions.convert(airflow_cfm, 'cfm', 'm^3/s'))
1948
1785
  air_terminal.setName(obj_name + ' terminal')
1949
1786
  air_loop.multiAddBranchForZone(control_zone, air_terminal)
1950
1787
 
@@ -1995,45 +1832,29 @@ class HVAC
1995
1832
  distribution_system = heating_system.distribution_system
1996
1833
  distribution_type = distribution_system.distribution_system_type
1997
1834
 
1998
- if distribution_type == HPXML::HVACDistributionTypeHydronic
1999
- # Shared boiler w/ baseboard/radiators/etc
2000
- if heating_system.shared_loop_watts.nil?
2001
- return 220.0 # kWh/yr, per ANSI/RESNET/ICC 301-2019 Table 4.5.2(5)
1835
+ if not heating_system.shared_loop_watts.nil?
1836
+ sp_kw = UnitConversions.convert(heating_system.shared_loop_watts, 'W', 'kW')
1837
+ n_dweq = heating_system.number_of_units_served.to_f
1838
+ if distribution_system.air_type == HPXML::AirTypeFanCoil
1839
+ aux_in = UnitConversions.convert(heating_system.fan_coil_watts, 'W', 'kW')
2002
1840
  else
2003
- sp_kw = UnitConversions.convert(heating_system.shared_loop_watts, 'W', 'kW')
2004
- n_dweq = heating_system.number_of_units_served.to_f
2005
- aux_in = 0.0
1841
+ aux_in = 0.0 # ANSI/RESNET/ICC 301-2019 Section 4.4.7.2
2006
1842
  end
2007
- elsif distribution_type == HPXML::HVACDistributionTypeHydronicAndAir
2008
- hydronic_and_air_type = distribution_system.hydronic_and_air_type
2009
- if hydronic_and_air_type == HPXML::HydronicAndAirTypeFanCoil
2010
- # Shared boiler w/ fan coil
2011
- if heating_system.shared_loop_watts.nil? || heating_system.fan_coil_watts.nil?
2012
- return 438.0 # kWh/yr, per ANSI/RESNET/ICC 301-2019 Table 4.5.2(5)
2013
- else
2014
- sp_kw = UnitConversions.convert(heating_system.shared_loop_watts, 'W', 'kW')
2015
- n_dweq = heating_system.number_of_units_served.to_f
2016
- aux_in = UnitConversions.convert(heating_system.fan_coil_watts, 'W', 'kW')
2017
- end
2018
- elsif hydronic_and_air_type == HPXML::HydronicAndAirTypeWaterLoopHeatPump
2019
- # Shared boiler w/ WLHP
2020
- if heating_system.shared_loop_watts.nil?
2021
- return 265.0 # kWh/yr, per ANSI/RESNET/ICC 301-2019 Table 4.5.2(5)
2022
- else
2023
- sp_kw = UnitConversions.convert(heating_system.shared_loop_watts, 'W', 'kW')
2024
- n_dweq = heating_system.number_of_units_served.to_f
2025
- aux_in = 0.0 # ANSI/RESNET/ICC 301-2019 Section 4.4.7.2
2026
- end
2027
- else
2028
- fail "Unexpected distribution type '#{hydronic_and_air_type}' for shared boiler."
1843
+ # ANSI/RESNET/ICC 301-2019 Equation 4.4-5
1844
+ return (((sp_kw / n_dweq) + aux_in) * 2080.0).round(2) # kWh/yr
1845
+ elsif distribution_type == HPXML::HVACDistributionTypeHydronic
1846
+ # kWh/yr, per ANSI/RESNET/ICC 301-2019 Table 4.5.2(5)
1847
+ if distribution_system.hydronic_type == HPXML::HydronicTypeWaterLoop # Shared boiler w/ WLHP
1848
+ return 265.0
1849
+ else # Shared boiler w/ baseboard/radiators/etc
1850
+ return 220.0
1851
+ end
1852
+ elsif distribution_type == HPXML::HVACDistributionTypeAir
1853
+ if distribution_system.air_type == HPXML::AirTypeFanCoil # Shared boiler w/ fan coil
1854
+ return 438.0
2029
1855
  end
2030
- else
2031
- fail "Unexpected distribution type '#{distribution_type}' for shared boiler."
2032
1856
  end
2033
1857
 
2034
- # ANSI/RESNET/ICC 301-2019 Equation 4.4-5
2035
- return ((sp_kw / n_dweq) + aux_in) * 2080.0 # kWh/yr
2036
-
2037
1858
  else # In-unit boilers
2038
1859
 
2039
1860
  if [HPXML::FuelTypeNaturalGas,
@@ -2059,7 +1880,9 @@ class HVAC
2059
1880
  end
2060
1881
  end
2061
1882
 
2062
- def self.calc_heat_cap_ft_spec_using_capacity_17F(num_speeds, heat_pump)
1883
+ def self.calc_heat_cap_ft_spec_using_capacity_17F(heat_pump)
1884
+ num_speeds = heat_pump.additional_properties.num_speeds
1885
+
2063
1886
  # Indoor temperature slope and intercept used if Q_17 is specified (derived using heat_cap_ft_spec)
2064
1887
  # NOTE: Using Q_17 assumes the same curve for all speeds
2065
1888
  if num_speeds == 1
@@ -2076,7 +1899,11 @@ class HVAC
2076
1899
  # Derive coefficients from user input for heating capacity at 47F and 17F
2077
1900
  # Biquadratic: capacity multiplier = a + b*IAT + c*IAT^2 + d*OAT + e*OAT^2 + f*IAT*OAT
2078
1901
  x_A = 17.0
2079
- y_A = heat_pump.heating_capacity_17F / heat_pump.heating_capacity
1902
+ if heat_pump.heating_capacity > 0
1903
+ y_A = heat_pump.heating_capacity_17F / heat_pump.heating_capacity
1904
+ else
1905
+ y_A = 0.5 # Arbitrary
1906
+ end
2080
1907
  x_B = 47.0 # 47F is the rating point
2081
1908
  y_B = 1.0
2082
1909
 
@@ -2105,22 +1932,18 @@ class HVAC
2105
1932
  return ((1.0 - 3.412 * (fan_power_rated * cfm_per_btuh)) / (eir / 3.412 + (fan_power_rated * cfm_per_btuh)))
2106
1933
  end
2107
1934
 
2108
- def self.calc_eers_from_eir_2speed(eer_2, fan_power_rated, is_heat_pump)
2109
- # Returns low and high stage eer A given high stage eer A
1935
+ def self.calc_eers_from_eir_2speed(eer_2, fan_power_rated)
1936
+ # Returns low and high stage EER A given high stage EER A
2110
1937
 
2111
1938
  eir_2_a = calc_eir_from_eer(eer_2, fan_power_rated)
2112
1939
 
2113
- if not is_heat_pump
2114
- eir_1_a = 0.8691 * eir_2_a + 0.0127 # Relationship derived using Dylan's data for two stage air conditioners
2115
- else
2116
- eir_1_a = 0.8887 * eir_2_a + 0.0083 # Relationship derived using Dylan's data for two stage heat pumps
2117
- end
1940
+ eir_1_a = 0.8887 * eir_2_a + 0.0083 # Relationship derived using Dylan's data for two stage heat pumps
2118
1941
 
2119
1942
  return [calc_eer_from_eir(eir_1_a, fan_power_rated), eer_2]
2120
1943
  end
2121
1944
 
2122
1945
  def self.calc_eers_from_eir_4speed(eer_nom, fan_power_rated, calc_type = 'seer')
2123
- # Returns eer A at minimum, intermediate, and nominal speed given eer A (and a fourth speed if calc_type != 'seer')
1946
+ # Returns EER A at minimum, intermediate, and nominal speed given EER A (and a fourth speed if calc_type != 'seer')
2124
1947
 
2125
1948
  eir_nom = calc_eir_from_eer(eer_nom, fan_power_rated)
2126
1949
 
@@ -2172,9 +1995,9 @@ class HVAC
2172
1995
  cop_ratios = [1.385171617, 1.183214059, 1.0, 0.95544453] # Updated based on Nordyne 3 ton heat pump
2173
1996
 
2174
1997
  # HSPF calculation is based on performance at three speeds
2175
- if calc_type.include? 'hspf'
1998
+ if calc_type == 'hspf'
2176
1999
  indices = [0, 1, 2]
2177
- else
2000
+ elsif calc_type == 'model'
2178
2001
  indices = [0, 1, 2, 3]
2179
2002
  end
2180
2003
 
@@ -2187,33 +2010,26 @@ class HVAC
2187
2010
  return cops_net
2188
2011
  end
2189
2012
 
2190
- def self.calc_biquad(coeff, in_1, in_2)
2191
- result = coeff[0] + coeff[1] * in_1 + coeff[2] * in_1 * in_1 + coeff[3] * in_2 + coeff[4] * in_2 * in_2 + coeff[5] * in_1 * in_2
2192
- return result
2193
- end
2194
-
2195
- def self.calc_eer_cooling_1speed(seer, fan_power_rated, coeff_eir)
2196
- # Directly calculate cooling coil net eer at condition A (95/80/67) using Seer
2197
-
2198
- c_d = get_cool_c_d(1, seer)
2013
+ def self.calc_eer_cooling_1speed(seer, c_d, fan_power_rated, coeff_eir)
2014
+ # Directly calculate cooling coil net EER at condition A (95/80/67) using SEER
2199
2015
 
2200
- # 1. Calculate eer_b using Seer and c_d
2016
+ # 1. Calculate EER_b using SEER and c_d
2201
2017
  eer_b = seer / (1.0 - 0.5 * c_d)
2202
2018
 
2203
- # 2. Calculate eir_b
2019
+ # 2. Calculate EIR_b
2204
2020
  eir_b = calc_eir_from_eer(eer_b, fan_power_rated)
2205
2021
 
2206
- # 3. Calculate eir_a using performance curves
2207
- eir_a = eir_b / calc_biquad(coeff_eir[0], 67.0, 82.0)
2022
+ # 3. Calculate EIR_a using performance curves
2023
+ eir_a = eir_b / MathTools.biquadratic(67.0, 82.0, coeff_eir[0])
2208
2024
  eer_a = calc_eer_from_eir(eir_a, fan_power_rated)
2209
2025
 
2210
2026
  return eer_a
2211
2027
  end
2212
2028
 
2213
- def self.calc_eers_cooling_2speed(runner, seer, c_d, capacity_ratios, fanspeed_ratios, fan_power_rated, coeff_eir, coeff_q, is_heat_pump = false)
2214
- # Iterate to find rated net eers given Seer using simple bisection method for two stage air conditioners
2029
+ def self.calc_eers_cooling_2speed(seer, c_d, capacity_ratios, fanspeed_ratios, fan_power_rated, coeff_eir, coeff_q)
2030
+ # Iterate to find rated net EERs given SEER using simple bisection method for two stage heat pumps
2215
2031
 
2216
- # Initial large bracket of eer (A condition) to span possible seer range
2032
+ # Initial large bracket of EER (A condition) to span possible SEER range
2217
2033
  eer_a = 5.0
2218
2034
  eer_b = 20.0
2219
2035
 
@@ -2224,10 +2040,10 @@ class HVAC
2224
2040
  err = 1
2225
2041
  eer_c = (eer_a + eer_b) / 2.0
2226
2042
  (1..iter_max).each do |n|
2227
- eers = calc_eers_from_eir_2speed(eer_a, fan_power_rated, is_heat_pump)
2043
+ eers = calc_eers_from_eir_2speed(eer_a, fan_power_rated)
2228
2044
  f_a = calc_seer_2speed(eers, c_d, capacity_ratios, fanspeed_ratios, fan_power_rated, coeff_eir, coeff_q) - seer
2229
2045
 
2230
- eers = calc_eers_from_eir_2speed(eer_c, fan_power_rated, is_heat_pump)
2046
+ eers = calc_eers_from_eir_2speed(eer_c, fan_power_rated)
2231
2047
  f_c = calc_seer_2speed(eers, c_d, capacity_ratios, fanspeed_ratios, fan_power_rated, coeff_eir, coeff_q) - seer
2232
2048
 
2233
2049
  if f_c == 0
@@ -2250,10 +2066,10 @@ class HVAC
2250
2066
  fail 'Two-speed cooling eers iteration failed to converge.'
2251
2067
  end
2252
2068
 
2253
- return calc_eers_from_eir_2speed(eer_c, fan_power_rated, is_heat_pump)
2069
+ return calc_eers_from_eir_2speed(eer_c, fan_power_rated)
2254
2070
  end
2255
2071
 
2256
- def self.calc_eers_cooling_4speed(runner, seer, c_d, capacity_ratios, fanspeed_ratios, fan_power_rated, coeff_eir, coeff_q)
2072
+ def self.calc_eers_cooling_4speed(seer, c_d, capacity_ratios, fanspeed_ratios, fan_power_rated, coeff_eir, coeff_q)
2257
2073
  # Iterate to find rated net eers given Seer using simple bisection method for two stage and variable speed air conditioners
2258
2074
 
2259
2075
  # Initial large bracket of eer (A condition) to span possible seer range
@@ -2298,17 +2114,17 @@ class HVAC
2298
2114
 
2299
2115
  def self.calc_seer_2speed(eers, c_d, capacity_ratios, fanspeed_ratios, fan_power_rated, coeff_eir, coeff_q)
2300
2116
  eir_A2 = calc_eir_from_eer(eers[1], fan_power_rated)
2301
- eir_B2 = eir_A2 * calc_biquad(coeff_eir[1], 67.0, 82.0)
2117
+ eir_B2 = eir_A2 * MathTools.biquadratic(67.0, 82.0, coeff_eir[1])
2302
2118
 
2303
2119
  eir_A1 = calc_eir_from_eer(eers[0], fan_power_rated)
2304
- eir_B1 = eir_A1 * calc_biquad(coeff_eir[0], 67.0, 82.0)
2305
- eir_F1 = eir_A1 * calc_biquad(coeff_eir[0], 67.0, 67.0)
2120
+ eir_B1 = eir_A1 * MathTools.biquadratic(67.0, 82.0, coeff_eir[0])
2121
+ eir_F1 = eir_A1 * MathTools.biquadratic(67.0, 67.0, coeff_eir[0])
2306
2122
 
2307
2123
  q_A2 = 1.0
2308
- q_B2 = q_A2 * calc_biquad(coeff_q[1], 67.0, 82.0)
2124
+ q_B2 = q_A2 * MathTools.biquadratic(67.0, 82.0, coeff_q[1])
2309
2125
 
2310
- q_B1 = q_A2 * capacity_ratios[0] * calc_biquad(coeff_q[0], 67.0, 82.0)
2311
- q_F1 = q_A2 * capacity_ratios[0] * calc_biquad(coeff_q[0], 67.0, 67.0)
2126
+ q_B1 = q_A2 * capacity_ratios[0] * MathTools.biquadratic(67.0, 82.0, coeff_q[0])
2127
+ q_F1 = q_A2 * capacity_ratios[0] * MathTools.biquadratic(67.0, 67.0, coeff_q[0])
2312
2128
 
2313
2129
  cfm_Btu_h = 400.0 / 12000.0
2314
2130
 
@@ -2365,20 +2181,20 @@ class HVAC
2365
2181
  tout_F = 67.0
2366
2182
 
2367
2183
  eir_A2 = calc_eir_from_eer(eers[n_max], fan_power_rated)
2368
- eir_B2 = eir_A2 * calc_biquad(coeff_eir[n_max], wBin, tout_B)
2184
+ eir_B2 = eir_A2 * MathTools.biquadratic(wBin, tout_B, coeff_eir[n_max])
2369
2185
 
2370
2186
  eir_Av = calc_eir_from_eer(eers[n_int], fan_power_rated)
2371
- eir_Ev = eir_Av * calc_biquad(coeff_eir[n_int], wBin, tout_E)
2187
+ eir_Ev = eir_Av * MathTools.biquadratic(wBin, tout_E, coeff_eir[n_int])
2372
2188
 
2373
2189
  eir_A1 = calc_eir_from_eer(eers[n_min], fan_power_rated)
2374
- eir_B1 = eir_A1 * calc_biquad(coeff_eir[n_min], wBin, tout_B)
2375
- eir_F1 = eir_A1 * calc_biquad(coeff_eir[n_min], wBin, tout_F)
2190
+ eir_B1 = eir_A1 * MathTools.biquadratic(wBin, tout_B, coeff_eir[n_min])
2191
+ eir_F1 = eir_A1 * MathTools.biquadratic(wBin, tout_F, coeff_eir[n_min])
2376
2192
 
2377
2193
  q_A2 = capacity_ratios[n_max]
2378
- q_B2 = q_A2 * calc_biquad(coeff_q[n_max], wBin, tout_B)
2379
- q_Ev = capacity_ratios[n_int] * calc_biquad(coeff_q[n_int], wBin, tout_E)
2380
- q_B1 = capacity_ratios[n_min] * calc_biquad(coeff_q[n_min], wBin, tout_B)
2381
- q_F1 = capacity_ratios[n_min] * calc_biquad(coeff_q[n_min], wBin, tout_F)
2194
+ q_B2 = q_A2 * MathTools.biquadratic(wBin, tout_B, coeff_q[n_max])
2195
+ q_Ev = capacity_ratios[n_int] * MathTools.biquadratic(wBin, tout_E, coeff_q[n_int])
2196
+ q_B1 = capacity_ratios[n_min] * MathTools.biquadratic(wBin, tout_B, coeff_q[n_min])
2197
+ q_F1 = capacity_ratios[n_min] * MathTools.biquadratic(wBin, tout_F, coeff_q[n_min])
2382
2198
 
2383
2199
  cfm_Btu_h = 400.0 / 12000.0
2384
2200
 
@@ -2545,7 +2361,7 @@ class HVAC
2545
2361
  return calc_cops_from_eir_2speed(cop_c, fan_power_rated)
2546
2362
  end
2547
2363
 
2548
- def self.calc_cops_heating_4speed(runner, hspf, c_d, capacity_ratios, fanspeed_ratios, fan_power_rated, coeff_eir, coeff_q)
2364
+ def self.calc_cops_heating_4speed(hspf, c_d, capacity_ratios, fanspeed_ratios, fan_power_rated, coeff_eir, coeff_q)
2549
2365
  # Iterate to find rated net cops given HSPF using simple bisection method for variable speed heat pumps
2550
2366
 
2551
2367
  # Initial large bracket of cop to span possible hspf range
@@ -2590,12 +2406,12 @@ class HVAC
2590
2406
 
2591
2407
  def self.calc_hspf_1speed(cop_47, c_d, fan_power_rated, coeff_eir, coeff_q)
2592
2408
  eir_47 = calc_eir_from_cop(cop_47, fan_power_rated)
2593
- eir_35 = eir_47 * calc_biquad(coeff_eir[0], 70.0, 35.0)
2594
- eir_17 = eir_47 * calc_biquad(coeff_eir[0], 70.0, 17.0)
2409
+ eir_35 = eir_47 * MathTools.biquadratic(70.0, 35.0, coeff_eir[0])
2410
+ eir_17 = eir_47 * MathTools.biquadratic(70.0, 17.0, coeff_eir[0])
2595
2411
 
2596
2412
  q_47 = 1.0
2597
2413
  q_35 = 0.7519
2598
- q_17 = q_47 * calc_biquad(coeff_q[0], 70.0, 17.0)
2414
+ q_17 = q_47 * MathTools.biquadratic(70.0, 17.0, coeff_q[0])
2599
2415
 
2600
2416
  cfm_Btu_h = 400.0 / 12000.0
2601
2417
 
@@ -2653,22 +2469,22 @@ class HVAC
2653
2469
 
2654
2470
  def self.calc_hspf_2speed(cops, c_d, capacity_ratios, fanspeed_ratios, fan_power_rated, coeff_eir, coeff_q)
2655
2471
  eir_47_H = calc_eir_from_cop(cops[1], fan_power_rated)
2656
- eir_35_H = eir_47_H * calc_biquad(coeff_eir[1], 70.0, 35.0)
2657
- eir_17_H = eir_47_H * calc_biquad(coeff_eir[1], 70.0, 17.0)
2472
+ eir_35_H = eir_47_H * MathTools.biquadratic(70.0, 35.0, coeff_eir[1])
2473
+ eir_17_H = eir_47_H * MathTools.biquadratic(70.0, 17.0, coeff_eir[1])
2658
2474
 
2659
2475
  eir_47_L = calc_eir_from_cop(cops[0], fan_power_rated)
2660
- eir_62_L = eir_47_L * calc_biquad(coeff_eir[0], 70.0, 62.0)
2661
- eir_35_L = eir_47_L * calc_biquad(coeff_eir[0], 70.0, 35.0)
2662
- eir_17_L = eir_47_L * calc_biquad(coeff_eir[0], 70.0, 17.0)
2476
+ eir_62_L = eir_47_L * MathTools.biquadratic(70.0, 62.0, coeff_eir[0])
2477
+ eir_35_L = eir_47_L * MathTools.biquadratic(70.0, 35.0, coeff_eir[0])
2478
+ eir_17_L = eir_47_L * MathTools.biquadratic(70.0, 17.0, coeff_eir[0])
2663
2479
 
2664
2480
  q_H47 = 1.0
2665
- q_H35 = q_H47 * calc_biquad(coeff_q[1], 70.0, 35.0)
2666
- q_H17 = q_H47 * calc_biquad(coeff_q[1], 70.0, 17.0)
2481
+ q_H35 = q_H47 * MathTools.biquadratic(70.0, 35.0, coeff_q[1])
2482
+ q_H17 = q_H47 * MathTools.biquadratic(70.0, 17.0, coeff_q[1])
2667
2483
 
2668
2484
  q_L47 = q_H47 * capacity_ratios[0]
2669
- q_L62 = q_L47 * calc_biquad(coeff_q[0], 70.0, 62.0)
2670
- q_L35 = q_L47 * calc_biquad(coeff_q[0], 70.0, 35.0)
2671
- q_L17 = q_L47 * calc_biquad(coeff_q[0], 70.0, 17.0)
2485
+ q_L62 = q_L47 * MathTools.biquadratic(70.0, 62.0, coeff_q[0])
2486
+ q_L35 = q_L47 * MathTools.biquadratic(70.0, 35.0, coeff_q[0])
2487
+ q_L17 = q_L47 * MathTools.biquadratic(70.0, 17.0, coeff_q[0])
2672
2488
 
2673
2489
  cfm_Btu_h = 400.0 / 12000.0
2674
2490
 
@@ -2773,21 +2589,21 @@ class HVAC
2773
2589
  tout_0 = 62.0
2774
2590
 
2775
2591
  eir_H1_2 = calc_eir_from_cop(cop_47[n_max], fan_power_rated)
2776
- eir_H3_2 = eir_H1_2 * calc_biquad(coeff_eir[n_max], tin, tout_3)
2592
+ eir_H3_2 = eir_H1_2 * MathTools.biquadratic(tin, tout_3, coeff_eir[n_max])
2777
2593
 
2778
2594
  eir_adjv = calc_eir_from_cop(cop_47[n_int], fan_power_rated)
2779
- eir_H2_v = eir_adjv * calc_biquad(coeff_eir[n_int], tin, tout_2)
2595
+ eir_H2_v = eir_adjv * MathTools.biquadratic(tin, tout_2, coeff_eir[n_int])
2780
2596
 
2781
2597
  eir_H1_1 = calc_eir_from_cop(cop_47[n_min], fan_power_rated)
2782
- eir_H0_1 = eir_H1_1 * calc_biquad(coeff_eir[n_min], tin, tout_0)
2598
+ eir_H0_1 = eir_H1_1 * MathTools.biquadratic(tin, tout_0, coeff_eir[n_min])
2783
2599
 
2784
2600
  q_H1_2 = capacity_ratios[n_max]
2785
- q_H3_2 = q_H1_2 * calc_biquad(coeff_q[n_max], tin, tout_3)
2601
+ q_H3_2 = q_H1_2 * MathTools.biquadratic(tin, tout_3, coeff_q[n_max])
2786
2602
 
2787
- q_H2_v = capacity_ratios[n_int] * calc_biquad(coeff_q[n_int], tin, tout_2)
2603
+ q_H2_v = capacity_ratios[n_int] * MathTools.biquadratic(tin, tout_2, coeff_q[n_int])
2788
2604
 
2789
2605
  q_H1_1 = capacity_ratios[n_min]
2790
- q_H0_1 = q_H1_1 * calc_biquad(coeff_q[n_min], tin, tout_0)
2606
+ q_H0_1 = q_H1_1 * MathTools.biquadratic(tin, tout_0, coeff_q[n_min])
2791
2607
 
2792
2608
  cfm_Btu_h = 400.0 / 12000.0
2793
2609
 
@@ -2890,29 +2706,46 @@ class HVAC
2890
2706
  return hspf
2891
2707
  end
2892
2708
 
2893
- def self.calc_cfms_ton_rated(rated_airflow_rate, fan_speed_ratios, capacity_ratios)
2894
- array = []
2895
- fan_speed_ratios.each_with_index do |fanspeed_ratio, i|
2896
- capacity_ratio = capacity_ratios[i]
2897
- array << fanspeed_ratio * rated_airflow_rate / capacity_ratio
2709
+ def self.set_cool_rated_cfm_per_ton(cooling_system)
2710
+ clg_ap = cooling_system.additional_properties
2711
+
2712
+ if cooling_system.is_a?(HPXML::CoolingSystem) && (cooling_system.cooling_system_type == HPXML::HVACTypeRoomAirConditioner)
2713
+ clg_ap.cool_rated_cfm_per_ton = [312.0] # medium speed
2714
+ else
2715
+ clg_ap.cool_rated_cfm_per_ton = []
2716
+ clg_ap.cool_fan_speed_ratios.each_with_index do |fanspeed_ratio, i|
2717
+ clg_ap.cool_rated_cfm_per_ton << fanspeed_ratio * clg_ap.cool_rated_airflow_rate / clg_ap.cool_capacity_ratios[i]
2718
+ end
2719
+ end
2720
+ end
2721
+
2722
+ def self.set_heat_rated_cfm_per_ton(heating_system)
2723
+ htg_ap = heating_system.additional_properties
2724
+
2725
+ if heating_system.is_a? HPXML::HeatingSystem
2726
+ htg_ap.heat_rated_cfm_per_ton = [350.0]
2727
+ else
2728
+ htg_ap.heat_rated_cfm_per_ton = []
2729
+ htg_ap.heat_fan_speed_ratios.each_with_index do |fanspeed_ratio, i|
2730
+ htg_ap.heat_rated_cfm_per_ton << fanspeed_ratio * htg_ap.heat_rated_airflow_rate / htg_ap.heat_capacity_ratios[i]
2731
+ end
2898
2732
  end
2899
- return array
2900
2733
  end
2901
2734
 
2902
2735
  def self.create_curve_biquadratic_constant(model)
2903
- const_biquadratic = OpenStudio::Model::CurveBiquadratic.new(model)
2904
- const_biquadratic.setName('ConstantBiquadratic')
2905
- const_biquadratic.setCoefficient1Constant(1)
2906
- const_biquadratic.setCoefficient2x(0)
2907
- const_biquadratic.setCoefficient3xPOW2(0)
2908
- const_biquadratic.setCoefficient4y(0)
2909
- const_biquadratic.setCoefficient5yPOW2(0)
2910
- const_biquadratic.setCoefficient6xTIMESY(0)
2911
- const_biquadratic.setMinimumValueofx(-100)
2912
- const_biquadratic.setMaximumValueofx(100)
2913
- const_biquadratic.setMinimumValueofy(-100)
2914
- const_biquadratic.setMaximumValueofy(100)
2915
- return const_biquadratic
2736
+ curve = OpenStudio::Model::CurveBiquadratic.new(model)
2737
+ curve.setName('ConstantBiquadratic')
2738
+ curve.setCoefficient1Constant(1)
2739
+ curve.setCoefficient2x(0)
2740
+ curve.setCoefficient3xPOW2(0)
2741
+ curve.setCoefficient4y(0)
2742
+ curve.setCoefficient5yPOW2(0)
2743
+ curve.setCoefficient6xTIMESY(0)
2744
+ curve.setMinimumValueofx(-100)
2745
+ curve.setMaximumValueofx(100)
2746
+ curve.setMinimumValueofy(-100)
2747
+ curve.setMaximumValueofy(100)
2748
+ return curve
2916
2749
  end
2917
2750
 
2918
2751
  def self.create_curve_quadratic_constant(model)
@@ -2929,15 +2762,15 @@ class HVAC
2929
2762
  end
2930
2763
 
2931
2764
  def self.create_curve_cubic_constant(model)
2932
- constant_cubic = OpenStudio::Model::CurveCubic.new(model)
2933
- constant_cubic.setName('ConstantCubic')
2934
- constant_cubic.setCoefficient1Constant(1)
2935
- constant_cubic.setCoefficient2x(0)
2936
- constant_cubic.setCoefficient3xPOW2(0)
2937
- constant_cubic.setCoefficient4xPOW3(0)
2938
- constant_cubic.setMinimumValueofx(-100)
2939
- constant_cubic.setMaximumValueofx(100)
2940
- return constant_cubic
2765
+ curve = OpenStudio::Model::CurveCubic.new(model)
2766
+ curve.setName('ConstantCubic')
2767
+ curve.setCoefficient1Constant(1)
2768
+ curve.setCoefficient2x(0)
2769
+ curve.setCoefficient3xPOW2(0)
2770
+ curve.setCoefficient4xPOW3(0)
2771
+ curve.setMinimumValueofx(-100)
2772
+ curve.setMaximumValueofx(100)
2773
+ return curve
2941
2774
  end
2942
2775
 
2943
2776
  def self.convert_curve_biquadratic(coeff, ip_to_si = true)
@@ -2964,29 +2797,6 @@ class HVAC
2964
2797
  end
2965
2798
  end
2966
2799
 
2967
- def self.convert_curve_gshp(coeff, gshp_to_biquadratic)
2968
- m1 = 32 - 273.15 * 1.8
2969
- m2 = 283 * 1.8
2970
- if gshp_to_biquadratic
2971
- biq_coeff = []
2972
- biq_coeff << coeff[0] - m1 * ((coeff[1] + coeff[2]) / m2)
2973
- biq_coeff << coeff[1] / m2
2974
- biq_coeff << 0
2975
- biq_coeff << coeff[2] / m2
2976
- biq_coeff << 0
2977
- biq_coeff << 0
2978
- return biq_coeff
2979
- else
2980
- gsph_coeff = []
2981
- gsph_coeff << coeff[0] + m1 * (coeff[1] + coeff[3])
2982
- gsph_coeff << m2 * coeff[1]
2983
- gsph_coeff << m2 * coeff[3]
2984
- gsph_coeff << 0
2985
- gsph_coeff << 0
2986
- return gsph_coeff
2987
- end
2988
- end
2989
-
2990
2800
  def self.create_curve_biquadratic(model, coeff, name, min_x, max_x, min_y, max_y)
2991
2801
  curve = OpenStudio::Model::CurveBiquadratic.new(model)
2992
2802
  curve.setName(name)
@@ -3069,40 +2879,67 @@ class HVAC
3069
2879
  return curve
3070
2880
  end
3071
2881
 
3072
- def self.create_dx_cooling_coil(model, obj_name, speed_indices, eirs, cap_ft_spec, eir_ft_spec, closs_fplr_spec, cap_fflow_spec, eir_fflow_spec, shrs_rated_gross, capacity, crankcase_kw, crankcase_temp, fan_power_rated)
3073
- num_speeds = speed_indices.size
2882
+ def self.create_curve_quad_linear(model, coeff, name)
2883
+ curve = OpenStudio::Model::CurveQuadLinear.new(model)
2884
+ curve.setName(name)
2885
+ curve.setCoefficient1Constant(coeff[0])
2886
+ curve.setCoefficient2w(coeff[1])
2887
+ curve.setCoefficient3x(coeff[2])
2888
+ curve.setCoefficient4y(coeff[3])
2889
+ curve.setCoefficient5z(coeff[4])
2890
+ return curve
2891
+ end
3074
2892
 
3075
- if num_speeds > 1
2893
+ def self.create_curve_quint_linear(model, coeff, name)
2894
+ curve = OpenStudio::Model::CurveQuintLinear.new(model)
2895
+ curve.setName(name)
2896
+ curve.setCoefficient1Constant(coeff[0])
2897
+ curve.setCoefficient2v(coeff[1])
2898
+ curve.setCoefficient3w(coeff[2])
2899
+ curve.setCoefficient4x(coeff[3])
2900
+ curve.setCoefficient5y(coeff[4])
2901
+ curve.setCoefficient6z(coeff[5])
2902
+ return curve
2903
+ end
2904
+
2905
+ def self.create_dx_cooling_coil(model, obj_name, cooling_system)
2906
+ clg_ap = cooling_system.additional_properties
2907
+
2908
+ if cooling_system.is_a? HPXML::CoolingSystem
2909
+ clg_type = cooling_system.cooling_system_type
2910
+ elsif cooling_system.is_a? HPXML::HeatPump
2911
+ clg_type = cooling_system.heat_pump_type
2912
+ end
2913
+
2914
+ if clg_ap.num_speeds > 1
3076
2915
  constant_biquadratic = create_curve_biquadratic_constant(model)
3077
2916
  end
3078
2917
 
3079
2918
  clg_coil = nil
3080
2919
 
3081
- for speed_idx in speed_indices
3082
- speed = speed_idx + 1
3083
- cap_ft_spec_si = convert_curve_biquadratic(cap_ft_spec[speed_idx])
3084
- eir_ft_spec_si = convert_curve_biquadratic(eir_ft_spec[speed_idx])
3085
- cap_ft_curve = create_curve_biquadratic(model, cap_ft_spec_si, "Cool-Cap-fT#{speed}", 13.88, 23.88, 18.33, 51.66)
3086
- eir_ft_curve = create_curve_biquadratic(model, eir_ft_spec_si, "Cool-eir-fT#{speed}", 13.88, 23.88, 18.33, 51.66)
3087
- plf_fplr_curve = create_curve_quadratic(model, closs_fplr_spec[speed_idx], "Cool-PLF-fPLR#{speed}", 0, 1, 0.7, 1)
3088
- cap_fff_curve = create_curve_quadratic(model, cap_fflow_spec[speed_idx], "Cool-Cap-fFF#{speed}", 0, 2, 0, 2)
3089
- eir_fff_curve = create_curve_quadratic(model, eir_fflow_spec[speed_idx], "Cool-eir-fFF#{speed}", 0, 2, 0, 2)
3090
-
3091
- if num_speeds == 1
2920
+ for i in 0..(clg_ap.num_speeds - 1)
2921
+ cap_ft_spec_si = convert_curve_biquadratic(clg_ap.cool_cap_ft_spec[i])
2922
+ eir_ft_spec_si = convert_curve_biquadratic(clg_ap.cool_eir_ft_spec[i])
2923
+ cap_ft_curve = create_curve_biquadratic(model, cap_ft_spec_si, "Cool-CAP-fT#{i + 1}", 13.88, 23.88, 18.33, 51.66)
2924
+ eir_ft_curve = create_curve_biquadratic(model, eir_ft_spec_si, "Cool-EIR-fT#{i + 1}", 13.88, 23.88, 18.33, 51.66)
2925
+ plf_fplr_curve = create_curve_quadratic(model, clg_ap.cool_plf_fplr_spec[i], "Cool-PLF-fPLR#{i + 1}", 0, 1, 0.7, 1)
2926
+ cap_fff_curve = create_curve_quadratic(model, clg_ap.cool_cap_fflow_spec[i], "Cool-CAP-fFF#{i + 1}", 0, 2, 0, 2)
2927
+ eir_fff_curve = create_curve_quadratic(model, clg_ap.cool_eir_fflow_spec[i], "Cool-EIR-fFF#{i + 1}", 0, 2, 0, 2)
2928
+
2929
+ if clg_ap.num_speeds == 1
3092
2930
  clg_coil = OpenStudio::Model::CoilCoolingDXSingleSpeed.new(model, model.alwaysOnDiscreteSchedule, cap_ft_curve, cap_fff_curve, eir_ft_curve, eir_fff_curve, plf_fplr_curve)
3093
- clg_coil.setRatedEvaporatorFanPowerPerVolumeFlowRate(fan_power_rated / UnitConversions.convert(1.0, 'cfm', 'm^3/s'))
3094
- if not crankcase_temp.nil?
3095
- clg_coil.setMaximumOutdoorDryBulbTemperatureForCrankcaseHeaterOperation(UnitConversions.convert(crankcase_temp, 'F', 'C'))
3096
- end
3097
- clg_coil.setRatedCOP(1.0 / eirs[speed_idx])
3098
- clg_coil.setRatedSensibleHeatRatio(shrs_rated_gross[speed_idx])
3099
- if not capacity.nil?
3100
- clg_coil.setRatedTotalCoolingCapacity(UnitConversions.convert([capacity, Constants.small].max, 'Btu/hr', 'W')) # Used by HVACSizing measure
2931
+ clg_coil.setRatedEvaporatorFanPowerPerVolumeFlowRate(clg_ap.fan_power_rated / UnitConversions.convert(1.0, 'cfm', 'm^3/s'))
2932
+ if not clg_ap.crankcase_temp.nil?
2933
+ clg_coil.setMaximumOutdoorDryBulbTemperatureForCrankcaseHeaterOperation(UnitConversions.convert(clg_ap.crankcase_temp, 'F', 'C'))
3101
2934
  end
2935
+ clg_coil.setRatedCOP(1.0 / clg_ap.cool_rated_eirs[i])
2936
+ clg_coil.setRatedSensibleHeatRatio(clg_ap.cool_rated_shrs_gross[i])
3102
2937
  clg_coil.setNominalTimeForCondensateRemovalToBegin(1000.0)
3103
2938
  clg_coil.setRatioOfInitialMoistureEvaporationRateAndSteadyStateLatentCapacity(1.5)
3104
2939
  clg_coil.setMaximumCyclingRate(3.0)
3105
2940
  clg_coil.setLatentCapacityTimeConstant(45.0)
2941
+ clg_coil.setRatedTotalCoolingCapacity(UnitConversions.convert(cooling_system.cooling_capacity, 'Btu/hr', 'W'))
2942
+ clg_coil.setRatedAirFlowRate(calc_rated_airflow(cooling_system.cooling_capacity, clg_ap.cool_rated_cfm_per_ton[0], 1.0))
3106
2943
  else
3107
2944
  if clg_coil.nil?
3108
2945
  clg_coil = OpenStudio::Model::CoilCoolingDXMultiSpeed.new(model)
@@ -3110,180 +2947,205 @@ class HVAC
3110
2947
  clg_coil.setApplyLatentDegradationtoSpeedsGreaterthan1(false)
3111
2948
  clg_coil.setFuelType(EPlus::FuelTypeElectricity)
3112
2949
  clg_coil.setAvailabilitySchedule(model.alwaysOnDiscreteSchedule)
3113
- if not crankcase_temp.nil?
3114
- clg_coil.setMaximumOutdoorDryBulbTemperatureforCrankcaseHeaterOperation(UnitConversions.convert(crankcase_temp, 'F', 'C'))
2950
+ if not clg_ap.crankcase_temp.nil?
2951
+ clg_coil.setMaximumOutdoorDryBulbTemperatureforCrankcaseHeaterOperation(UnitConversions.convert(clg_ap.crankcase_temp, 'F', 'C'))
3115
2952
  end
3116
2953
  end
3117
2954
  stage = OpenStudio::Model::CoilCoolingDXMultiSpeedStageData.new(model, cap_ft_curve, cap_fff_curve, eir_ft_curve, eir_fff_curve, plf_fplr_curve, constant_biquadratic)
3118
- stage.setGrossRatedCoolingCOP(1.0 / eirs[speed_idx])
3119
- stage.setGrossRatedSensibleHeatRatio(shrs_rated_gross[speed_idx])
3120
- if not capacity.nil?
3121
- stage.setGrossRatedTotalCoolingCapacity(UnitConversions.convert([capacity, Constants.small].max, 'Btu/hr', 'W')) # Used by HVACSizing measure
3122
- end
2955
+ stage.setGrossRatedCoolingCOP(1.0 / clg_ap.cool_rated_eirs[i])
2956
+ stage.setGrossRatedSensibleHeatRatio(clg_ap.cool_rated_shrs_gross[i])
3123
2957
  stage.setNominalTimeforCondensateRemovaltoBegin(1000)
3124
2958
  stage.setRatioofInitialMoistureEvaporationRateandSteadyStateLatentCapacity(1.5)
3125
2959
  stage.setRatedWasteHeatFractionofPowerInput(0.2)
3126
2960
  stage.setMaximumCyclingRate(3.0)
3127
2961
  stage.setLatentCapacityTimeConstant(45.0)
2962
+ stage.setGrossRatedTotalCoolingCapacity(UnitConversions.convert(cooling_system.cooling_capacity, 'Btu/hr', 'W') * clg_ap.cool_capacity_ratios[i])
2963
+ stage.setRatedAirFlowRate(calc_rated_airflow(cooling_system.cooling_capacity, clg_ap.cool_rated_cfm_per_ton[i], clg_ap.cool_capacity_ratios[i]))
3128
2964
  clg_coil.addStage(stage)
3129
2965
  end
3130
2966
  end
3131
2967
 
3132
2968
  clg_coil.setName(obj_name + ' clg coil')
3133
2969
  clg_coil.setCondenserType('AirCooled')
3134
- clg_coil.setCrankcaseHeaterCapacity(UnitConversions.convert(crankcase_kw, 'kW', 'W'))
2970
+ clg_coil.setCrankcaseHeaterCapacity(UnitConversions.convert(clg_ap.crankcase_kw, 'kW', 'W'))
3135
2971
 
3136
2972
  return clg_coil
3137
2973
  end
3138
2974
 
3139
- def self.create_dx_heating_coil(model, obj_name, speed_indices, eirs, cap_ft_spec, eir_ft_spec, closs_fplr_spec, cap_fflow_spec, eir_fflow_spec,
3140
- capacity, crankcase_kw, crankcase_temp, fan_power_rated, hp_min_temp, fraction_heat_load_served)
3141
- num_speeds = speed_indices.size
2975
+ def self.create_dx_heating_coil(model, obj_name, heating_system)
2976
+ htg_ap = heating_system.additional_properties
3142
2977
 
3143
- if num_speeds > 1
2978
+ if heating_system.is_a? HPXML::HeatingSystem
2979
+ htg_type = heating_system.heating_system_type
2980
+ elsif heating_system.is_a? HPXML::HeatPump
2981
+ htg_type = heating_system.heat_pump_type
2982
+ end
2983
+
2984
+ if htg_ap.num_speeds > 1
3144
2985
  constant_biquadratic = create_curve_biquadratic_constant(model)
3145
2986
  end
3146
2987
 
3147
2988
  htg_coil = nil
3148
2989
 
3149
- for speed_idx in speed_indices
3150
- speed = speed_idx + 1
3151
- cap_ft_spec_si = convert_curve_biquadratic(cap_ft_spec[speed_idx])
3152
- eir_ft_spec_si = convert_curve_biquadratic(eir_ft_spec[speed_idx])
3153
- cap_ft_curve = create_curve_biquadratic(model, cap_ft_spec_si, "HP_Heat-Cap-fT#{speed}", -100, 100, -100, 100)
3154
- eir_ft_curve = create_curve_biquadratic(model, eir_ft_spec_si, "HP_Heat-eir-fT#{speed}", -100, 100, -100, 100)
3155
- plf_fplr_curve = create_curve_quadratic(model, closs_fplr_spec[speed_idx], "HP_Heat-PLF-fPLR#{speed}", 0, 1, 0.7, 1)
3156
- cap_fff_curve = create_curve_quadratic(model, cap_fflow_spec[speed_idx], "HP_Heat-CAP-fFF#{speed}", 0, 2, 0, 2)
3157
- eir_fff_curve = create_curve_quadratic(model, eir_fflow_spec[speed_idx], "HP_Heat-eir-fFF#{speed}", 0, 2, 0, 2)
3158
-
3159
- if num_speeds == 1
2990
+ for i in 0..(htg_ap.num_speeds - 1)
2991
+ cap_ft_spec_si = convert_curve_biquadratic(htg_ap.heat_cap_ft_spec[i])
2992
+ eir_ft_spec_si = convert_curve_biquadratic(htg_ap.heat_eir_ft_spec[i])
2993
+ cap_ft_curve = create_curve_biquadratic(model, cap_ft_spec_si, "Heat-CAP-fT#{i + 1}", -100, 100, -100, 100)
2994
+ eir_ft_curve = create_curve_biquadratic(model, eir_ft_spec_si, "Heat-EIR-fT#{i + 1}", -100, 100, -100, 100)
2995
+ plf_fplr_curve = create_curve_quadratic(model, htg_ap.heat_plf_fplr_spec[i], "Heat-PLF-fPLR#{i + 1}", 0, 1, 0.7, 1)
2996
+ cap_fff_curve = create_curve_quadratic(model, htg_ap.heat_cap_fflow_spec[i], "Heat-CAP-fFF#{i + 1}", 0, 2, 0, 2)
2997
+ eir_fff_curve = create_curve_quadratic(model, htg_ap.heat_eir_fflow_spec[i], "Heat-EIR-fFF#{i + 1}", 0, 2, 0, 2)
2998
+
2999
+ if htg_ap.num_speeds == 1
3160
3000
  htg_coil = OpenStudio::Model::CoilHeatingDXSingleSpeed.new(model, model.alwaysOnDiscreteSchedule, cap_ft_curve, cap_fff_curve, eir_ft_curve, eir_fff_curve, plf_fplr_curve)
3161
- htg_coil.setRatedSupplyFanPowerPerVolumeFlowRate(fan_power_rated / UnitConversions.convert(1.0, 'cfm', 'm^3/s'))
3162
- htg_coil.setRatedCOP(1.0 / eirs[speed_idx])
3163
- if not capacity.nil?
3164
- htg_coil.setRatedTotalHeatingCapacity(UnitConversions.convert([capacity, Constants.small].max, 'Btu/hr', 'W')) # Used by HVACSizing measure
3165
- end
3166
- if not crankcase_temp.nil?
3167
- htg_coil.setMaximumOutdoorDryBulbTemperatureforCrankcaseHeaterOperation(UnitConversions.convert(crankcase_temp, 'F', 'C'))
3001
+ htg_coil.setRatedSupplyFanPowerPerVolumeFlowRate(htg_ap.fan_power_rated / UnitConversions.convert(1.0, 'cfm', 'm^3/s'))
3002
+ htg_coil.setRatedCOP(1.0 / htg_ap.heat_rated_eirs[i])
3003
+ if not htg_ap.crankcase_temp.nil?
3004
+ htg_coil.setMaximumOutdoorDryBulbTemperatureforCrankcaseHeaterOperation(UnitConversions.convert(htg_ap.crankcase_temp, 'F', 'C'))
3168
3005
  end
3006
+ htg_coil.setRatedTotalHeatingCapacity(UnitConversions.convert(heating_system.heating_capacity, 'Btu/hr', 'W'))
3007
+ htg_coil.setRatedAirFlowRate(calc_rated_airflow(heating_system.heating_capacity, htg_ap.heat_rated_cfm_per_ton[0], 1.0))
3169
3008
  else
3170
3009
  if htg_coil.nil?
3171
3010
  htg_coil = OpenStudio::Model::CoilHeatingDXMultiSpeed.new(model)
3172
3011
  htg_coil.setFuelType(EPlus::FuelTypeElectricity)
3173
3012
  htg_coil.setApplyPartLoadFractiontoSpeedsGreaterthan1(false)
3174
3013
  htg_coil.setAvailabilitySchedule(model.alwaysOnDiscreteSchedule)
3175
- if not crankcase_temp.nil?
3176
- htg_coil.setMaximumOutdoorDryBulbTemperatureforCrankcaseHeaterOperation(UnitConversions.convert(crankcase_temp, 'F', 'C'))
3014
+ if not htg_ap.crankcase_temp.nil?
3015
+ htg_coil.setMaximumOutdoorDryBulbTemperatureforCrankcaseHeaterOperation(UnitConversions.convert(htg_ap.crankcase_temp, 'F', 'C'))
3177
3016
  end
3178
3017
  end
3179
3018
  stage = OpenStudio::Model::CoilHeatingDXMultiSpeedStageData.new(model, cap_ft_curve, cap_fff_curve, eir_ft_curve, eir_fff_curve, plf_fplr_curve, constant_biquadratic)
3180
- stage.setGrossRatedHeatingCOP(1.0 / eirs[speed_idx])
3181
- if not capacity.nil?
3182
- stage.setGrossRatedHeatingCapacity(UnitConversions.convert([capacity, Constants.small].max, 'Btu/hr', 'W')) # Used by HVACSizing measure
3183
- end
3019
+ stage.setGrossRatedHeatingCOP(1.0 / htg_ap.heat_rated_eirs[i])
3184
3020
  stage.setRatedWasteHeatFractionofPowerInput(0.2)
3021
+ stage.setGrossRatedHeatingCapacity(UnitConversions.convert(heating_system.heating_capacity, 'Btu/hr', 'W') * htg_ap.heat_capacity_ratios[i])
3022
+ stage.setRatedAirFlowRate(calc_rated_airflow(heating_system.heating_capacity, htg_ap.heat_rated_cfm_per_ton[i], htg_ap.heat_capacity_ratios[i]))
3185
3023
  htg_coil.addStage(stage)
3186
3024
  end
3187
3025
  end
3188
3026
 
3189
3027
  htg_coil.setName(obj_name + ' htg coil')
3190
- htg_coil.setMinimumOutdoorDryBulbTemperatureforCompressorOperation(UnitConversions.convert(hp_min_temp, 'F', 'C'))
3028
+ htg_coil.setMinimumOutdoorDryBulbTemperatureforCompressorOperation(UnitConversions.convert(htg_ap.hp_min_temp, 'F', 'C'))
3191
3029
  htg_coil.setMaximumOutdoorDryBulbTemperatureforDefrostOperation(UnitConversions.convert(40.0, 'F', 'C'))
3192
- if fraction_heat_load_served > 0
3193
- defrost_eir_curve = create_curve_biquadratic(model, [0.1528, 0, 0, 0, 0, 0], 'Defrosteir', -100, 100, -100, 100) # Heating defrost curve for reverse cycle
3194
- htg_coil.setDefrostEnergyInputRatioFunctionofTemperatureCurve(defrost_eir_curve)
3195
- htg_coil.setDefrostStrategy('ReverseCycle')
3196
- htg_coil.setDefrostControl('Timed')
3197
- else
3198
- htg_coil.setDefrostTimePeriodFraction(0)
3030
+ defrost_eir_curve = create_curve_biquadratic(model, [0.1528, 0, 0, 0, 0, 0], 'Defrosteir', -100, 100, -100, 100) # Heating defrost curve for reverse cycle
3031
+ htg_coil.setDefrostEnergyInputRatioFunctionofTemperatureCurve(defrost_eir_curve)
3032
+ htg_coil.setDefrostStrategy('ReverseCycle')
3033
+ htg_coil.setDefrostControl('Timed')
3034
+ if heating_system.fraction_heat_load_served == 0
3035
+ htg_coil.setResistiveDefrostHeaterCapacity(0)
3199
3036
  end
3200
- htg_coil.setCrankcaseHeaterCapacity(UnitConversions.convert(crankcase_kw, 'kW', 'W'))
3037
+ htg_coil.setCrankcaseHeaterCapacity(UnitConversions.convert(htg_ap.crankcase_kw, 'kW', 'W'))
3201
3038
 
3202
3039
  return htg_coil
3203
3040
  end
3204
3041
 
3205
- def self.calc_cool_eirs(num_speeds, eers, fan_power_rated)
3206
- cool_eirs = []
3207
- (0...num_speeds).to_a.each do |speed|
3208
- eir = calc_eir_from_eer(eers[speed], fan_power_rated)
3209
- cool_eirs << eir
3042
+ def self.set_cool_rated_eirs(cooling_system)
3043
+ clg_ap = cooling_system.additional_properties
3044
+
3045
+ clg_ap.cool_rated_eirs = []
3046
+ (0...clg_ap.num_speeds).to_a.each do |speed|
3047
+ clg_ap.cool_rated_eirs << calc_eir_from_eer(clg_ap.cool_eers[speed], clg_ap.fan_power_rated)
3210
3048
  end
3211
- return cool_eirs
3212
3049
  end
3213
3050
 
3214
- def self.calc_heat_eirs(num_speeds, cops, fan_power_rated)
3215
- heat_eirs = []
3216
- (0...num_speeds).to_a.each do |speed|
3217
- eir = calc_eir_from_cop(cops[speed], fan_power_rated)
3218
- heat_eirs << eir
3051
+ def self.set_heat_rated_eirs(heating_system)
3052
+ htg_ap = heating_system.additional_properties
3053
+
3054
+ htg_ap.heat_rated_eirs = []
3055
+ (0...htg_ap.num_speeds).to_a.each do |speed|
3056
+ htg_ap.heat_rated_eirs << calc_eir_from_cop(htg_ap.heat_cops[speed], htg_ap.fan_power_rated)
3219
3057
  end
3220
- return heat_eirs
3221
3058
  end
3222
3059
 
3223
- def self.calc_shrs_rated_gross(num_speeds, shr_Rated_Net, fan_power_rated, cfms_ton_rated)
3224
- # Convert SHRs from net to gross
3225
- cool_shrs_rated_gross = []
3226
- (0...num_speeds).to_a.each do |speed|
3227
- qtot_net_nominal = 12000.0
3228
- qsens_net_nominal = qtot_net_nominal * shr_Rated_Net[speed]
3229
- qtot_gross_nominal = qtot_net_nominal + UnitConversions.convert(cfms_ton_rated[speed] * fan_power_rated, 'Wh', 'Btu')
3230
- qsens_gross_nominal = qsens_net_nominal + UnitConversions.convert(cfms_ton_rated[speed] * fan_power_rated, 'Wh', 'Btu')
3231
- cool_shrs_rated_gross << (qsens_gross_nominal / qtot_gross_nominal)
3232
-
3233
- # Make sure SHR's are in valid range based on E+ model limits.
3234
- # The following correlation was developed by Jon Winkler to test for maximum allowed SHR based on the 300 - 450 cfm/ton limits in E+
3235
- maxSHR = 0.3821066 + 0.001050652 * cfms_ton_rated[speed] - 0.01
3236
- cool_shrs_rated_gross[speed] = [cool_shrs_rated_gross[speed], maxSHR].min
3237
- minSHR = 0.60 # Approximate minimum SHR such that an ADP exists
3238
- cool_shrs_rated_gross[speed] = [cool_shrs_rated_gross[speed], minSHR].max
3239
- end
3240
-
3241
- return cool_shrs_rated_gross
3060
+ def self.set_cool_rated_shrs_gross(cooling_system)
3061
+ clg_ap = cooling_system.additional_properties
3062
+
3063
+ # Convert SHRs from net to gross.
3064
+ if cooling_system.is_a?(HPXML::CoolingSystem) && (cooling_system.cooling_system_type == HPXML::HVACTypeRoomAirConditioner)
3065
+ clg_ap.cool_rated_shrs_gross = [cooling_system.cooling_shr] # We don't model the fan separately, so set gross == net
3066
+ else
3067
+ clg_ap.cool_rated_shrs_gross = []
3068
+ (0...clg_ap.num_speeds).to_a.each do |speed|
3069
+ qtot_net_nominal = 12000.0
3070
+ qsens_net_nominal = qtot_net_nominal * clg_ap.cool_rated_shrs_net[speed]
3071
+ qtot_gross_nominal = qtot_net_nominal + UnitConversions.convert(clg_ap.cool_rated_cfm_per_ton[speed] * clg_ap.fan_power_rated, 'Wh', 'Btu')
3072
+ qsens_gross_nominal = qsens_net_nominal + UnitConversions.convert(clg_ap.cool_rated_cfm_per_ton[speed] * clg_ap.fan_power_rated, 'Wh', 'Btu')
3073
+ clg_ap.cool_rated_shrs_gross << (qsens_gross_nominal / qtot_gross_nominal)
3074
+
3075
+ # Make sure SHR's are in valid range based on E+ model limits.
3076
+ # The following correlation was developed by Jon Winkler to test for maximum allowed SHR based on the 300 - 450 cfm/ton limits in E+
3077
+ max_shr = 0.3821066 + 0.001050652 * clg_ap.cool_rated_cfm_per_ton[speed] - 0.01
3078
+ clg_ap.cool_rated_shrs_gross[speed] = [clg_ap.cool_rated_shrs_gross[speed], max_shr].min
3079
+ min_shr = 0.60 # Approximate minimum SHR such that an ADP exists
3080
+ clg_ap.cool_rated_shrs_gross[speed] = [clg_ap.cool_rated_shrs_gross[speed], min_shr].max
3081
+ end
3082
+ end
3242
3083
  end
3243
3084
 
3244
3085
  def self.calc_plr_coefficients(c_d)
3245
3086
  return [(1.0 - c_d), c_d, 0.0] # Linear part load model
3246
3087
  end
3247
3088
 
3248
- def self.get_cool_c_d(num_speeds, seer)
3089
+ def self.set_cool_c_d(cooling_system, num_speeds)
3090
+ clg_ap = cooling_system.additional_properties
3091
+
3249
3092
  # Degradation coefficient for cooling
3250
- if num_speeds == 1
3251
- if seer < 13.0
3252
- return 0.20
3093
+ if cooling_system.is_a?(HPXML::CoolingSystem) && (cooling_system.cooling_system_type == HPXML::HVACTypeRoomAirConditioner)
3094
+ clg_ap.cool_c_d = 0.22
3095
+ elsif num_speeds == 1
3096
+ if cooling_system.cooling_efficiency_seer < 13.0
3097
+ clg_ap.cool_c_d = 0.20
3253
3098
  else
3254
- return 0.07
3099
+ clg_ap.cool_c_d = 0.07
3255
3100
  end
3256
3101
  elsif num_speeds == 2
3257
- return 0.11
3258
- elsif num_speeds == 4
3259
- return 0.25
3260
- elsif num_speeds == 10
3261
- return 0.25
3102
+ clg_ap.cool_c_d = 0.11
3103
+ elsif num_speeds >= 4
3104
+ clg_ap.cool_c_d = 0.25
3262
3105
  end
3106
+
3107
+ # PLF curve
3108
+ clg_ap.cool_plf_fplr_spec = [calc_plr_coefficients(clg_ap.cool_c_d)] * num_speeds
3263
3109
  end
3264
3110
 
3265
- def self.get_heat_c_d(num_speeds, hspf)
3111
+ def self.set_heat_c_d(heating_system, num_speeds)
3112
+ htg_ap = heating_system.additional_properties
3113
+
3266
3114
  # Degradation coefficient for heating
3267
3115
  if num_speeds == 1
3268
- if hspf < 7.0
3269
- return 0.20
3116
+ if heating_system.heating_efficiency_hspf < 7.0
3117
+ htg_ap.heat_c_d = 0.20
3270
3118
  else
3271
- return 0.11
3119
+ htg_ap.heat_c_d = 0.11
3272
3120
  end
3273
3121
  elsif num_speeds == 2
3274
- return 0.11
3122
+ htg_ap.heat_c_d = 0.11
3275
3123
  elsif num_speeds == 4
3276
- return 0.24
3277
- elsif num_speeds == 10
3278
- return 0.40
3124
+ htg_ap.heat_c_d = 0.24
3125
+ elsif num_speeds == 10 # mini-split heat pump
3126
+ htg_ap.heat_c_d = 0.40
3279
3127
  end
3128
+
3129
+ htg_ap.heat_plf_fplr_spec = [calc_plr_coefficients(htg_ap.heat_c_d)] * num_speeds
3280
3130
  end
3281
3131
 
3282
- def self.get_fan_power_rated(seer)
3283
- if seer <= 15
3284
- return 0.365 # W/cfm
3132
+ def self.set_fan_power_rated(hvac_system)
3133
+ hvac_ap = hvac_system.additional_properties
3134
+
3135
+ if (hvac_system.is_a?(HPXML::CoolingSystem) && (hvac_system.cooling_system_type == HPXML::HVACTypeMiniSplitAirConditioner)) ||
3136
+ (hvac_system.is_a?(HPXML::HeatPump) && (hvac_system.heat_pump_type == HPXML::HVACTypeHeatPumpMiniSplit))
3137
+ if not hvac_system.distribution_system.nil?
3138
+ # Ducted, installed fan power may differ from rated fan power
3139
+ hvac_ap.fan_power_rated = 0.18 # W/cfm, ducted
3140
+ else
3141
+ # Ductless, installed and rated value should be equal
3142
+ hvac_ap.fan_power_rated = 0.07 # W/cfm
3143
+ hvac_system.fan_watts_per_cfm = hvac_ap.fan_power_rated # W/cfm
3144
+ end
3145
+ elsif hvac_system.cooling_efficiency_seer <= 15
3146
+ hvac_ap.fan_power_rated = 0.365 # W/cfm
3285
3147
  else
3286
- return 0.14 # W/cfm
3148
+ hvac_ap.fan_power_rated = 0.14 # W/cfm
3287
3149
  end
3288
3150
  end
3289
3151
 
@@ -3304,133 +3166,6 @@ class HVAC
3304
3166
  return pump_eff * pump_w / pump_head_pa # m3/s
3305
3167
  end
3306
3168
 
3307
- def self.existing_equipment(model, thermal_zone, runner)
3308
- # Returns a list of equipment objects
3309
-
3310
- equipment = []
3311
- hvac_types = []
3312
-
3313
- unitary_system_air_loops = get_unitary_system_air_loops(model, thermal_zone)
3314
- unitary_system_air_loops.each do |unitary_system_air_loop|
3315
- system, clg_coil, htg_coil, air_loop = unitary_system_air_loop
3316
- equipment << system
3317
-
3318
- hvac_type_cool = system.additionalProperties.getFeatureAsString(Constants.SizingInfoHVACCoolType)
3319
- hvac_types << hvac_type_cool.get if hvac_type_cool.is_initialized
3320
-
3321
- hvac_type_heat = system.additionalProperties.getFeatureAsString(Constants.SizingInfoHVACHeatType)
3322
- hvac_types << hvac_type_heat.get if hvac_type_heat.is_initialized
3323
- end
3324
-
3325
- ptacs = get_ptacs(model, thermal_zone)
3326
- ptacs.each do |ptac|
3327
- equipment << ptac
3328
- hvac_types << ptac.additionalProperties.getFeatureAsString(Constants.SizingInfoHVACCoolType).get
3329
- end
3330
-
3331
- evap_coolers = get_evap_coolers(model, thermal_zone)
3332
- evap_coolers.each do |evap_cooler|
3333
- equipment << evap_cooler
3334
- hvac_types << evap_cooler.additionalProperties.getFeatureAsString(Constants.SizingInfoHVACCoolType).get
3335
- end
3336
-
3337
- baseboards = get_baseboard_waters(model, thermal_zone)
3338
- baseboards.each do |baseboard|
3339
- equipment << baseboard
3340
- hvac_types << baseboard.additionalProperties.getFeatureAsString(Constants.SizingInfoHVACHeatType).get
3341
- end
3342
-
3343
- fancoils = get_fan_coils(model, thermal_zone)
3344
- fancoils.each do |fancoil|
3345
- equipment << fancoil
3346
- hvac_types << fancoil.additionalProperties.getFeatureAsString(Constants.SizingInfoHVACHeatType).get
3347
- end
3348
-
3349
- baseboards = get_baseboard_electrics(model, thermal_zone)
3350
- baseboards.each do |baseboard|
3351
- equipment << baseboard
3352
- hvac_types << baseboard.additionalProperties.getFeatureAsString(Constants.SizingInfoHVACHeatType).get
3353
- end
3354
-
3355
- unitary_system_hvac_map = get_unitary_system_hvac_map(model, thermal_zone)
3356
- unitary_system_hvac_map.each do |unitary_system_zone_hvac|
3357
- system, clg_coil, htg_coil = unitary_system_zone_hvac
3358
- next if htg_coil.nil?
3359
-
3360
- equipment << system
3361
- hvac_types << system.additionalProperties.getFeatureAsString(Constants.SizingInfoHVACHeatType).get
3362
- end
3363
-
3364
- ideal_air = get_ideal_air(model, thermal_zone)
3365
- if not ideal_air.nil?
3366
- equipment << ideal_air
3367
- hvac_types << ideal_air.additionalProperties.getFeatureAsString(Constants.SizingInfoHVACCoolType).get
3368
- hvac_types << ideal_air.additionalProperties.getFeatureAsString(Constants.SizingInfoHVACHeatType).get
3369
- end
3370
- return equipment
3371
- end
3372
-
3373
- def self.get_coils_from_hvac_equip(model, hvac_equip)
3374
- # Returns the clg coil, htg coil, and supp htg coil as applicable
3375
- clg_coil = nil
3376
- htg_coil = nil
3377
- supp_htg_coil = nil
3378
- if hvac_equip.is_a? OpenStudio::Model::AirLoopHVACUnitarySystem
3379
- htg_coil = get_coil_from_hvac_component(hvac_equip.heatingCoil)
3380
- clg_coil = get_coil_from_hvac_component(hvac_equip.coolingCoil)
3381
- supp_htg_coil = get_coil_from_hvac_component(hvac_equip.supplementalHeatingCoil)
3382
- elsif hvac_equip.is_a? OpenStudio::Model::ZoneHVACBaseboardConvectiveWater
3383
- htg_coil = get_coil_from_hvac_component(hvac_equip.heatingCoil)
3384
- elsif hvac_equip.is_a? OpenStudio::Model::ZoneHVACFourPipeFanCoil
3385
- htg_coil = get_coil_from_hvac_component(hvac_equip.heatingCoil)
3386
- elsif hvac_equip.is_a? OpenStudio::Model::ZoneHVACPackagedTerminalAirConditioner
3387
- htg_coil = get_coil_from_hvac_component(hvac_equip.heatingCoil)
3388
- if (not htg_coil.nil?) && (htg_coil.availabilitySchedule == model.alwaysOffDiscreteSchedule)
3389
- # Don't return coil if it is unused
3390
- htg_coil = nil
3391
- end
3392
- clg_coil = get_coil_from_hvac_component(hvac_equip.coolingCoil)
3393
- end
3394
- return clg_coil, htg_coil, supp_htg_coil
3395
- end
3396
-
3397
- def self.get_coil_from_hvac_component(hvac_component)
3398
- # Check for optional objects
3399
- if hvac_component.is_a? OpenStudio::Model::OptionalHVACComponent
3400
- return if not hvac_component.is_initialized
3401
-
3402
- hvac_component = hvac_component.get
3403
- end
3404
-
3405
- # Cooling coils
3406
- if hvac_component.to_CoilCoolingDXSingleSpeed.is_initialized
3407
- return hvac_component.to_CoilCoolingDXSingleSpeed.get
3408
- elsif hvac_component.to_CoilCoolingDXMultiSpeed.is_initialized
3409
- return hvac_component.to_CoilCoolingDXMultiSpeed.get
3410
- elsif hvac_component.to_CoilCoolingWaterToAirHeatPumpEquationFit.is_initialized
3411
- return hvac_component.to_CoilCoolingWaterToAirHeatPumpEquationFit.get
3412
- end
3413
-
3414
- # Heating coils
3415
- if hvac_component.to_CoilHeatingDXSingleSpeed.is_initialized
3416
- return hvac_component.to_CoilHeatingDXSingleSpeed.get
3417
- elsif hvac_component.to_CoilHeatingDXMultiSpeed.is_initialized
3418
- return hvac_component.to_CoilHeatingDXMultiSpeed.get
3419
- elsif hvac_component.to_CoilHeatingGas.is_initialized
3420
- return hvac_component.to_CoilHeatingGas.get
3421
- elsif hvac_component.to_CoilHeatingElectric.is_initialized
3422
- return hvac_component.to_CoilHeatingElectric.get
3423
- elsif hvac_component.to_CoilHeatingWaterBaseboard.is_initialized
3424
- return hvac_component.to_CoilHeatingWaterBaseboard.get
3425
- elsif hvac_component.to_CoilHeatingWater.is_initialized
3426
- return hvac_component.to_CoilHeatingWater.get
3427
- elsif hvac_component.to_CoilHeatingWaterToAirHeatPumpEquationFit.is_initialized
3428
- return hvac_component.to_CoilHeatingWaterToAirHeatPumpEquationFit.get
3429
- end
3430
-
3431
- return hvac_component
3432
- end
3433
-
3434
3169
  def self.get_unitary_system_from_air_loop_hvac(air_loop)
3435
3170
  # Returns the unitary system or nil
3436
3171
  air_loop.supplyComponents.each do |comp|
@@ -3441,201 +3176,52 @@ class HVAC
3441
3176
  return
3442
3177
  end
3443
3178
 
3444
- def self.get_evap_cooler_from_air_loop_hvac(air_loop)
3445
- # Returns the evap cooler or nil
3446
- air_loop.supplyComponents.each do |comp|
3447
- next unless comp.to_EvaporativeCoolerDirectResearchSpecial.is_initialized
3448
-
3449
- return comp.to_EvaporativeCoolerDirectResearchSpecial.get
3450
- end
3451
- return
3452
- end
3179
+ def self.set_cool_rated_cfm_per_ton_mshp(heat_pump, num_speeds)
3180
+ hp_ap = heat_pump.additional_properties
3453
3181
 
3454
- def self.get_unitary_system_air_loops(model, thermal_zone)
3455
- # Returns the unitary system(s), cooling coil(s), heating coil(s), and air loops(s) if available
3456
- unitary_system_air_loops = []
3457
- thermal_zone.airLoopHVACs.each do |air_loop|
3458
- system = get_unitary_system_from_air_loop_hvac(air_loop)
3459
- next if system.nil?
3460
-
3461
- clg_coil = nil
3462
- htg_coil = nil
3463
- if system.coolingCoil.is_initialized
3464
- clg_coil = system.coolingCoil.get
3465
- end
3466
- if system.heatingCoil.is_initialized
3467
- htg_coil = system.heatingCoil.get
3468
- end
3469
- unitary_system_air_loops << [system, clg_coil, htg_coil, air_loop]
3470
- end
3471
- return unitary_system_air_loops
3472
- end
3473
-
3474
- def self.get_unitary_system_hvac_map(model, thermal_zone)
3475
- # Returns the unitary system, cooling coil, and heating coil if available
3476
- unitary_system_hvac_map = []
3477
- thermal_zone.equipment.each do |equipment|
3478
- next unless equipment.to_AirLoopHVACUnitarySystem.is_initialized
3479
-
3480
- system = equipment.to_AirLoopHVACUnitarySystem.get
3481
- clg_coil = nil
3482
- htg_coil = nil
3483
- if system.coolingCoil.is_initialized
3484
- clg_coil = system.coolingCoil.get
3485
- end
3486
- if system.heatingCoil.is_initialized
3487
- htg_coil = system.heatingCoil.get
3488
- end
3489
- unitary_system_hvac_map << [system, clg_coil, htg_coil]
3490
- end
3491
- return unitary_system_hvac_map
3492
- end
3493
-
3494
- def self.get_ptacs(model, thermal_zone)
3495
- # Returns the PTAC(s) if available
3496
- ptacs = []
3497
- model.getZoneHVACPackagedTerminalAirConditioners.each do |ptac|
3498
- next unless thermal_zone.handle.to_s == ptac.thermalZone.get.handle.to_s
3499
-
3500
- ptacs << ptac
3501
- end
3502
- return ptacs
3503
- end
3504
-
3505
- def self.get_evap_coolers(model, thermal_zone)
3506
- # Returns the evaporative cooler if available
3507
- evap_coolers = []
3508
- thermal_zone.airLoopHVACs.each do |air_loop|
3509
- evap_cooler = get_evap_cooler_from_air_loop_hvac(air_loop)
3510
- next if evap_cooler.nil?
3511
-
3512
- evap_coolers << evap_cooler
3513
- end
3514
- return evap_coolers
3515
- end
3516
-
3517
- def self.get_baseboard_waters(model, thermal_zone)
3518
- # Returns the water baseboard if available
3519
- baseboards = []
3520
- model.getZoneHVACBaseboardConvectiveWaters.each do |baseboard|
3521
- next unless thermal_zone.handle.to_s == baseboard.thermalZone.get.handle.to_s
3522
-
3523
- baseboards << baseboard
3524
- end
3525
- return baseboards
3526
- end
3527
-
3528
- def self.get_fan_coils(model, thermal_zone)
3529
- # Returns the fan coil if available
3530
- fancoils = []
3531
- model.getZoneHVACFourPipeFanCoils.each do |fancoil|
3532
- next unless thermal_zone.handle.to_s == fancoil.thermalZone.get.handle.to_s
3533
-
3534
- fancoils << fancoil
3535
- end
3536
- return fancoils
3537
- end
3538
-
3539
- def self.get_baseboard_electrics(model, thermal_zone)
3540
- # Returns the electric baseboard if available
3541
- baseboards = []
3542
- model.getZoneHVACBaseboardConvectiveElectrics.each do |baseboard|
3543
- next unless thermal_zone.handle.to_s == baseboard.thermalZone.get.handle.to_s
3544
-
3545
- baseboards << baseboard
3546
- end
3547
- return baseboards
3548
- end
3549
-
3550
- def self.get_dehumidifiers(model, runner, thermal_zone)
3551
- # Returns the dehumidifier if available
3552
- dehums = []
3553
- model.getZoneHVACDehumidifierDXs.each do |dehum|
3554
- next unless thermal_zone.handle.to_s == dehum.thermalZone.get.handle.to_s
3555
-
3556
- dehums << dehum
3557
- end
3558
- return dehums
3559
- end
3560
-
3561
- def self.get_ideal_air(model, thermal_zone)
3562
- # Returns the heating ideal air loads system if available
3563
- model.getZoneHVACIdealLoadsAirSystems.each do |ideal_air|
3564
- next unless thermal_zone.handle.to_s == ideal_air.thermalZone.get.handle.to_s
3565
-
3566
- return ideal_air
3567
- end
3568
- return
3569
- end
3570
-
3571
- def self.has_ducted_equipment(model, air_loop)
3572
- if air_loop.name.to_s.include? Constants.ObjectNameEvaporativeCooler
3573
- system = air_loop
3574
- else
3575
- system = get_unitary_system_from_air_loop_hvac(air_loop)
3576
- end
3577
-
3578
- hvac_type_cool = system.additionalProperties.getFeatureAsString(Constants.SizingInfoHVACCoolType)
3579
- hvac_type_cool = hvac_type_cool.get if hvac_type_cool.is_initialized
3580
- hvac_type_heat = system.additionalProperties.getFeatureAsString(Constants.SizingInfoHVACHeatType)
3581
- hvac_type_heat = hvac_type_heat.get if hvac_type_heat.is_initialized
3582
-
3583
- if [Constants.ObjectNameCentralAirConditioner,
3584
- Constants.ObjectNameAirSourceHeatPump,
3585
- Constants.ObjectNameGroundSourceHeatPump].include? hvac_type_cool
3586
- return true
3587
- elsif Constants.ObjectNameFurnace == hvac_type_heat
3588
- return true
3589
- elsif [Constants.ObjectNameMiniSplitHeatPump, Constants.ObjectNameEvaporativeCooler].include? hvac_type_cool
3590
- is_ducted = system.additionalProperties.getFeatureAsBoolean(Constants.SizingInfoHVACSystemIsDucted).get
3591
- if is_ducted
3592
- return true
3593
- end
3594
- end
3595
-
3596
- return false
3597
- end
3598
-
3599
- def self.calc_mshp_cfms_ton_cooling(cap_min_per, cap_max_per, cfm_ton_min, cfm_ton_max, num_speeds, dB_rated, wB_rated, shr)
3600
- cool_capacity_ratios = [0.0] * num_speeds
3601
- cool_cfms_ton_rated = [0.0] * num_speeds
3602
- cool_shrs_rated = [0.0] * num_speeds
3182
+ dB_rated = 80.0 # deg-F
3183
+ wB_rated = 67.0 # deg-F
3603
3184
 
3604
- cap_nom_per = 1.0
3605
- cfm_ton_nom = ((cfm_ton_max - cfm_ton_min) / (cap_max_per - cap_min_per)) * (cap_nom_per - cap_min_per) + cfm_ton_min
3185
+ cool_nominal_capacity_ratio = 1.0
3186
+ cool_nominal_cfm_per_ton = ((hp_ap.cool_max_cfm_per_ton * hp_ap.cool_max_capacity_ratio - hp_ap.cool_min_cfm_per_ton * hp_ap.cool_min_capacity_ratio) /
3187
+ (hp_ap.cool_max_capacity_ratio - hp_ap.cool_min_capacity_ratio)) *
3188
+ (cool_nominal_capacity_ratio - hp_ap.cool_min_capacity_ratio) + hp_ap.cool_min_cfm_per_ton * hp_ap.cool_min_capacity_ratio
3606
3189
 
3607
3190
  p_atm = 14.696 # standard atmospheric pressure (psia)
3608
3191
 
3609
- ao = Psychrometrics.CoilAoFactor(dB_rated, wB_rated, p_atm, UnitConversions.convert(1, 'ton', 'kBtu/hr'), cfm_ton_nom, shr)
3192
+ ao = Psychrometrics.CoilAoFactor(dB_rated, wB_rated, p_atm, UnitConversions.convert(1, 'ton', 'kBtu/hr'), cool_nominal_cfm_per_ton, heat_pump.cooling_shr)
3193
+
3194
+ hp_ap.cool_capacity_ratios = []
3195
+ hp_ap.cool_rated_cfm_per_ton = []
3196
+ hp_ap.cool_rated_shrs_gross = []
3610
3197
 
3611
3198
  (0...num_speeds).each do |i|
3612
- cool_capacity_ratios[i] = cap_min_per + i * (cap_max_per - cap_min_per) / (num_speeds - 1)
3613
- cool_cfms_ton_rated[i] = cfm_ton_min + i * (cfm_ton_max - cfm_ton_min) / (num_speeds - 1)
3199
+ hp_ap.cool_capacity_ratios << hp_ap.cool_min_capacity_ratio + i * (hp_ap.cool_max_capacity_ratio - hp_ap.cool_min_capacity_ratio) / (num_speeds - 1)
3200
+ hp_ap.cool_rated_cfm_per_ton << (hp_ap.cool_min_cfm_per_ton * hp_ap.cool_min_capacity_ratio + i * (hp_ap.cool_max_cfm_per_ton * hp_ap.cool_max_capacity_ratio - hp_ap.cool_min_cfm_per_ton * hp_ap.cool_min_capacity_ratio) / (num_speeds - 1)) / hp_ap.cool_capacity_ratios[-1]
3614
3201
  # Calculate the SHR for each speed. Use minimum value of 0.98 to prevent E+ bypass factor calculation errors
3615
- cool_shrs_rated[i] = [Psychrometrics.CalculateSHR(dB_rated, wB_rated, p_atm, UnitConversions.convert(cool_capacity_ratios[i], 'ton', 'kBtu/hr'), cool_cfms_ton_rated[i], ao), 0.98].min
3202
+ hp_ap.cool_rated_shrs_gross[i] = [Psychrometrics.CalculateSHR(dB_rated, wB_rated, p_atm, UnitConversions.convert(hp_ap.cool_capacity_ratios[i], 'ton', 'kBtu/hr'), hp_ap.cool_rated_cfm_per_ton[i] * hp_ap.cool_capacity_ratios[i], ao), 0.98].min
3616
3203
  end
3617
-
3618
- return cool_cfms_ton_rated, cool_capacity_ratios, cool_shrs_rated
3619
3204
  end
3620
3205
 
3621
- def self.calc_mshp_cool_eirs(runner, seer, fan_power, c_d, num_speeds, cool_capacity_ratios, cool_cfms_ton_rated, cool_eir_ft_spec, cool_cap_ft_spec)
3206
+ def self.set_cool_rated_eirs_mshp(cooling_system, num_speeds)
3207
+ clg_ap = cooling_system.additional_properties
3208
+
3622
3209
  cops_norm = [1.901, 1.859, 1.746, 1.609, 1.474, 1.353, 1.247, 1.156, 1.079, 1.0]
3623
3210
  fan_powers_norm = [0.604, 0.634, 0.670, 0.711, 0.754, 0.800, 0.848, 0.898, 0.948, 1.0]
3624
3211
 
3625
- cool_eirs = [0.0] * num_speeds
3626
- fan_powers_rated = [0.0] * num_speeds
3627
- eers_Rated = [0.0] * num_speeds
3212
+ cop_max_speed = 3.5 # 3.5 is an initial guess, final value solved for below
3628
3213
 
3629
- cop_maxSpeed = 3.5 # 3.5 is an initial guess, final value solved for below
3214
+ fan_powers_rated = []
3215
+ eers_rated = []
3630
3216
 
3631
3217
  (0...num_speeds).each do |i|
3632
- fan_powers_rated[i] = fan_power * fan_powers_norm[i]
3633
- eers_Rated[i] = UnitConversions.convert(cop_maxSpeed, 'W', 'Btu/hr') * cops_norm[i]
3218
+ fan_powers_rated << clg_ap.fan_power_rated * fan_powers_norm[i]
3219
+ eers_rated << UnitConversions.convert(cop_max_speed, 'W', 'Btu/hr') * cops_norm[i]
3634
3220
  end
3635
3221
 
3636
- cop_maxSpeed_1 = cop_maxSpeed
3637
- cop_maxSpeed_2 = cop_maxSpeed
3638
- error = seer - calc_mshp_seer_4speed(eers_Rated, c_d, cool_capacity_ratios, cool_cfms_ton_rated, fan_powers_rated, true, cool_eir_ft_spec, cool_cap_ft_spec)
3222
+ cop_max_speed_1 = cop_max_speed
3223
+ cop_max_speed_2 = cop_max_speed
3224
+ 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)
3639
3225
  error1 = error
3640
3226
  error2 = error
3641
3227
 
@@ -3646,12 +3232,12 @@ class HVAC
3646
3232
  (1...itmax + 1).each do |n|
3647
3233
  final_n = n
3648
3234
  (0...num_speeds).each do |i|
3649
- eers_Rated[i] = UnitConversions.convert(cop_maxSpeed, 'W', 'Btu/hr') * cops_norm[i]
3235
+ eers_rated[i] = UnitConversions.convert(cop_max_speed, 'W', 'Btu/hr') * cops_norm[i]
3650
3236
  end
3651
3237
 
3652
- error = seer - calc_mshp_seer_4speed(eers_Rated, c_d, cool_capacity_ratios, cool_cfms_ton_rated, fan_powers_rated, true, cool_eir_ft_spec, cool_cap_ft_spec)
3238
+ 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)
3653
3239
 
3654
- cop_maxSpeed, cvg, cop_maxSpeed_1, error1, cop_maxSpeed_2, error2 = MathTools.Iterate(cop_maxSpeed, error, cop_maxSpeed_1, error1, cop_maxSpeed_2, error2, n, cvg)
3240
+ 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)
3655
3241
 
3656
3242
  if cvg
3657
3243
  break
@@ -3659,19 +3245,55 @@ class HVAC
3659
3245
  end
3660
3246
 
3661
3247
  if (not cvg) || (final_n > itmax)
3662
- cop_maxSpeed = UnitConversions.convert(0.547 * seer - 0.104, 'Btu/hr', 'W') # Correlation developed from JonW's MatLab scripts. Only used if an eer cannot be found.
3663
- runner.registerWarning('Mini-split heat pump cop iteration failed to converge. Setting to default value.')
3248
+ 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.
3664
3249
  end
3665
3250
 
3251
+ clg_ap.cool_rated_eirs = []
3252
+
3666
3253
  (0...num_speeds).each do |i|
3667
- cool_eirs[i] = calc_eir_from_eer(UnitConversions.convert(cop_maxSpeed, 'W', 'Btu/hr') * cops_norm[i], fan_powers_rated[i])
3254
+ clg_ap.cool_rated_eirs << calc_eir_from_eer(UnitConversions.convert(cop_max_speed, 'W', 'Btu/hr') * cops_norm[i], fan_powers_rated[i])
3668
3255
  end
3256
+ end
3669
3257
 
3670
- return cool_eirs
3258
+ def self.set_mshp_downselected_speed_indices(heat_pump)
3259
+ hp_ap = heat_pump.additional_properties
3260
+
3261
+ # Down-select to speed indices
3262
+
3263
+ # Cooling
3264
+ hp_ap.cool_cap_ft_spec = hp_ap.cool_cap_ft_spec.select.with_index { |x, i| hp_ap.speed_indices.include? i }
3265
+ hp_ap.cool_eir_ft_spec = hp_ap.cool_eir_ft_spec.select.with_index { |x, i| hp_ap.speed_indices.include? i }
3266
+ hp_ap.cool_cap_fflow_spec = hp_ap.cool_cap_fflow_spec.select.with_index { |x, i| hp_ap.speed_indices.include? i }
3267
+ hp_ap.cool_eir_fflow_spec = hp_ap.cool_eir_fflow_spec.select.with_index { |x, i| hp_ap.speed_indices.include? i }
3268
+ hp_ap.cool_plf_fplr_spec = hp_ap.cool_plf_fplr_spec.select.with_index { |x, i| hp_ap.speed_indices.include? i }
3269
+ 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 }
3270
+ hp_ap.cool_capacity_ratios = hp_ap.cool_capacity_ratios.select.with_index { |x, i| hp_ap.speed_indices.include? i }
3271
+ hp_ap.cool_rated_shrs_gross = hp_ap.cool_rated_shrs_gross.select.with_index { |x, i| hp_ap.speed_indices.include? i }
3272
+ hp_ap.cool_rated_eirs = hp_ap.cool_rated_eirs.select.with_index { |x, i| hp_ap.speed_indices.include? i }
3273
+ hp_ap.cool_fan_speed_ratios = []
3274
+ for i in 0..(hp_ap.speed_indices.size - 1)
3275
+ hp_ap.cool_fan_speed_ratios << hp_ap.cool_rated_cfm_per_ton[i] * hp_ap.cool_capacity_ratios[i] / (hp_ap.cool_rated_cfm_per_ton[-1] * hp_ap.cool_capacity_ratios[-1])
3276
+ end
3277
+
3278
+ if heat_pump.is_a? HPXML::HeatPump # Skip for mini-split air conditioner
3279
+ # Heating
3280
+ hp_ap.heat_eir_ft_spec = hp_ap.heat_eir_ft_spec.select.with_index { |x, i| hp_ap.speed_indices.include? i }
3281
+ hp_ap.heat_cap_fflow_spec = hp_ap.heat_cap_fflow_spec.select.with_index { |x, i| hp_ap.speed_indices.include? i }
3282
+ hp_ap.heat_eir_fflow_spec = hp_ap.heat_eir_fflow_spec.select.with_index { |x, i| hp_ap.speed_indices.include? i }
3283
+ hp_ap.heat_cap_ft_spec = hp_ap.heat_cap_ft_spec.select.with_index { |x, i| hp_ap.speed_indices.include? i }
3284
+ hp_ap.heat_plf_fplr_spec = hp_ap.heat_plf_fplr_spec.select.with_index { |x, i| hp_ap.speed_indices.include? i }
3285
+ 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 }
3286
+ hp_ap.heat_capacity_ratios = hp_ap.heat_capacity_ratios.select.with_index { |x, i| hp_ap.speed_indices.include? i }
3287
+ hp_ap.heat_rated_eirs = hp_ap.heat_rated_eirs.select.with_index { |x, i| hp_ap.speed_indices.include? i }
3288
+ hp_ap.heat_fan_speed_ratios = []
3289
+ for i in 0..(hp_ap.speed_indices.size - 1)
3290
+ hp_ap.heat_fan_speed_ratios << hp_ap.heat_rated_cfm_per_ton[i] * hp_ap.heat_capacity_ratios[i] / (hp_ap.heat_rated_cfm_per_ton[-1] * hp_ap.heat_capacity_ratios[-1])
3291
+ end
3292
+ end
3671
3293
  end
3672
3294
 
3673
- def self.calc_mshp_seer_4speed(eer_a, c_d, capacity_ratio, cfm_tons, fan_power_rated, is_heat_pump, cool_eir_ft_spec, cool_cap_ft_spec)
3674
- n_max = (eer_a.length - 1.0) - 3.0 # Don't use max speed; FIXME: this is different than calc_mshp_hspf_4speed?
3295
+ def self.calc_mshp_seer(eer_a, c_d, capacity_ratio, cfm_tons, fan_power_rated, cool_eir_ft_spec, cool_cap_ft_spec)
3296
+ n_max = (eer_a.length - 1.0) - 3.0 # Don't use max speed; FIXME: this is different than calc_mshp_hspf?
3675
3297
  n_min = 0
3676
3298
  n_int = (n_min + (n_max - n_min) / 3.0).ceil.to_i
3677
3299
 
@@ -3696,17 +3318,17 @@ class HVAC
3696
3318
  q_B1 = capacity_ratio[n_min] * MathTools.biquadratic(wBin, tout_B, cool_cap_ft_spec[n_min])
3697
3319
  q_F1 = capacity_ratio[n_min] * MathTools.biquadratic(wBin, tout_F, cool_cap_ft_spec[n_min])
3698
3320
 
3699
- q_A2_net = q_A2 - fan_power_rated[n_max] * UnitConversions.convert(1, 'W', 'Btu/hr') * cfm_tons[n_max] / UnitConversions.convert(1, 'ton', 'Btu/hr')
3700
- q_B2_net = q_B2 - fan_power_rated[n_max] * UnitConversions.convert(1, 'W', 'Btu/hr') * cfm_tons[n_max] / UnitConversions.convert(1, 'ton', 'Btu/hr')
3701
- q_Ev_net = q_Ev - fan_power_rated[n_int] * UnitConversions.convert(1, 'W', 'Btu/hr') * cfm_tons[n_int] / UnitConversions.convert(1, 'ton', 'Btu/hr')
3702
- q_B1_net = q_B1 - fan_power_rated[n_min] * UnitConversions.convert(1, 'W', 'Btu/hr') * cfm_tons[n_min] / UnitConversions.convert(1, 'ton', 'Btu/hr')
3703
- q_F1_net = q_F1 - fan_power_rated[n_min] * UnitConversions.convert(1, 'W', 'Btu/hr') * cfm_tons[n_min] / UnitConversions.convert(1, 'ton', 'Btu/hr')
3321
+ 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')
3322
+ 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')
3323
+ 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')
3324
+ 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')
3325
+ 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')
3704
3326
 
3705
- p_A2 = UnitConversions.convert(q_A2 * eir_A2, 'Btu', 'Wh') + fan_power_rated[n_max] * cfm_tons[n_max] / UnitConversions.convert(1, 'ton', 'Btu/hr')
3706
- p_B2 = UnitConversions.convert(q_B2 * eir_B2, 'Btu', 'Wh') + fan_power_rated[n_max] * cfm_tons[n_max] / UnitConversions.convert(1, 'ton', 'Btu/hr')
3707
- p_Ev = UnitConversions.convert(q_Ev * eir_Ev, 'Btu', 'Wh') + fan_power_rated[n_int] * cfm_tons[n_int] / UnitConversions.convert(1, 'ton', 'Btu/hr')
3708
- p_B1 = UnitConversions.convert(q_B1 * eir_B1, 'Btu', 'Wh') + fan_power_rated[n_min] * cfm_tons[n_min] / UnitConversions.convert(1, 'ton', 'Btu/hr')
3709
- p_F1 = UnitConversions.convert(q_F1 * eir_F1, 'Btu', 'Wh') + fan_power_rated[n_min] * cfm_tons[n_min] / UnitConversions.convert(1, 'ton', 'Btu/hr')
3327
+ 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')
3328
+ 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')
3329
+ 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')
3330
+ 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')
3331
+ 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')
3710
3332
 
3711
3333
  q_k1_87 = q_F1_net + (q_B1_net - q_F1_net) / (82.0 - 67.0) * (87 - 67.0)
3712
3334
  q_k2_87 = q_B2_net + (q_A2_net - q_B2_net) / (95.0 - 82.0) * (87.0 - 82.0)
@@ -3776,36 +3398,37 @@ class HVAC
3776
3398
  return seer
3777
3399
  end
3778
3400
 
3779
- def self.calc_mshp_cfms_ton_heating(cap_min_per, cap_max_per, cfm_ton_min, cfm_ton_max, num_speeds)
3780
- heat_capacity_ratios = [0.0] * num_speeds
3781
- heat_cfms_ton_rated = [0.0] * num_speeds
3401
+ def self.set_heat_rated_cfm_per_ton_mshp(heat_pump, num_speeds)
3402
+ hp_ap = heat_pump.additional_properties
3403
+
3404
+ hp_ap.heat_capacity_ratios = []
3405
+ hp_ap.heat_rated_cfm_per_ton = []
3782
3406
 
3783
3407
  (0...num_speeds).each do |i|
3784
- heat_capacity_ratios[i] = cap_min_per + i * (cap_max_per - cap_min_per) / (num_speeds - 1)
3785
- heat_cfms_ton_rated[i] = cfm_ton_min + i * (cfm_ton_max - cfm_ton_min) / (num_speeds - 1)
3408
+ hp_ap.heat_capacity_ratios << hp_ap.heat_min_capacity_ratio + i * (hp_ap.heat_max_capacity_ratio - hp_ap.heat_min_capacity_ratio) / (num_speeds - 1)
3409
+ hp_ap.heat_rated_cfm_per_ton << (hp_ap.heat_min_cfm_per_ton * hp_ap.heat_min_capacity_ratio + i * (hp_ap.heat_max_cfm_per_ton * hp_ap.heat_max_capacity_ratio - hp_ap.heat_min_cfm_per_ton * hp_ap.heat_min_capacity_ratio) / (num_speeds - 1)) / hp_ap.heat_capacity_ratios[-1]
3786
3410
  end
3787
-
3788
- return heat_cfms_ton_rated, heat_capacity_ratios
3789
3411
  end
3790
3412
 
3791
- def self.calc_mshp_heat_eirs(runner, hspf, fan_power, hp_min_temp, c_d, cool_cfms_ton_rated, num_speeds, heat_capacity_ratios, heat_cfms_ton_rated, heat_eir_ft_spec, heat_cap_ft_spec)
3792
- cops_norm = [1.792, 1.502, 1.308, 1.207, 1.145, 1.105, 1.077, 1.056, 1.041, 1]
3793
- fan_powers_norm = [0.577, 0.625, 0.673, 0.720, 0.768, 0.814, 0.861, 0.907, 0.954, 1]
3413
+ def self.set_heat_rated_eirs_mshp(heat_pump, num_speeds)
3414
+ hp_ap = heat_pump.additional_properties
3415
+
3416
+ cops_norm = [1.792, 1.502, 1.308, 1.207, 1.145, 1.105, 1.077, 1.056, 1.041, 1.0]
3417
+ fan_powers_norm = [0.577, 0.625, 0.673, 0.720, 0.768, 0.814, 0.861, 0.907, 0.954, 1.0]
3794
3418
 
3795
- heat_eirs = [0.0] * num_speeds
3796
- fan_powers_rated = [0.0] * num_speeds
3797
- cops_rated = [0.0] * num_speeds
3419
+ cop_max_speed = 3.25 # 3.35 is an initial guess, final value solved for below
3798
3420
 
3799
- cop_maxSpeed = 3.25 # 3.35 is an initial guess, final value solved for below
3421
+ fan_powers_rated = []
3422
+ cops_rated = []
3800
3423
 
3801
3424
  (0...num_speeds).each do |i|
3802
- fan_powers_rated[i] = fan_power * fan_powers_norm[i]
3803
- cops_rated[i] = cop_maxSpeed * cops_norm[i]
3425
+ fan_powers_rated << hp_ap.fan_power_rated * fan_powers_norm[i]
3426
+ cops_rated << cop_max_speed * cops_norm[i]
3804
3427
  end
3805
3428
 
3806
- cop_maxSpeed_1 = cop_maxSpeed
3807
- cop_maxSpeed_2 = cop_maxSpeed
3808
- error = hspf - calc_mshp_hspf_4speed(cops_rated, c_d, heat_capacity_ratios, heat_cfms_ton_rated, fan_powers_rated, hp_min_temp, heat_eir_ft_spec, heat_cap_ft_spec)
3429
+ cop_max_speed_1 = cop_max_speed
3430
+ cop_max_speed_2 = cop_max_speed
3431
+ 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.hp_min_temp, hp_ap.heat_eir_ft_spec, hp_ap.heat_cap_ft_spec)
3809
3432
 
3810
3433
  error1 = error
3811
3434
  error2 = error
@@ -3817,12 +3440,12 @@ class HVAC
3817
3440
  (1...itmax + 1).each do |n|
3818
3441
  final_n = n
3819
3442
  (0...num_speeds).each do |i|
3820
- cops_rated[i] = cop_maxSpeed * cops_norm[i]
3443
+ cops_rated[i] = cop_max_speed * cops_norm[i]
3821
3444
  end
3822
3445
 
3823
- error = hspf - calc_mshp_hspf_4speed(cops_rated, c_d, heat_capacity_ratios, cool_cfms_ton_rated, fan_powers_rated, hp_min_temp, heat_eir_ft_spec, heat_cap_ft_spec)
3446
+ 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.hp_min_temp, hp_ap.heat_eir_ft_spec, hp_ap.heat_cap_ft_spec)
3824
3447
 
3825
- cop_maxSpeed, cvg, cop_maxSpeed_1, error1, cop_maxSpeed_2, error2 = MathTools.Iterate(cop_maxSpeed, error, cop_maxSpeed_1, error1, cop_maxSpeed_2, error2, n, cvg)
3448
+ 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)
3826
3449
 
3827
3450
  if cvg
3828
3451
  break
@@ -3830,19 +3453,62 @@ class HVAC
3830
3453
  end
3831
3454
 
3832
3455
  if (not cvg) || (final_n > itmax)
3833
- cop_maxSpeed = UnitConversions.convert(0.4174 * hspf - 1.1134, 'Btu/hr', 'W') # Correlation developed from JonW's MatLab scripts. Only used if a cop cannot be found.
3834
- runner.registerWarning('Mini-split heat pump cop iteration failed to converge. Setting to default value.')
3456
+ cop_max_speed = UnitConversions.convert(0.4174 * hspf - 1.1134, 'Btu/hr', 'W') # Correlation developed from JonW's MatLab scripts. Only used if a cop cannot be found.
3835
3457
  end
3836
3458
 
3459
+ hp_ap.heat_rated_eirs = []
3837
3460
  (0...num_speeds).each do |i|
3838
- heat_eirs[i] = calc_eir_from_cop(cop_maxSpeed * cops_norm[i], fan_powers_rated[i])
3461
+ hp_ap.heat_rated_eirs << calc_eir_from_cop(cop_max_speed * cops_norm[i], fan_powers_rated[i])
3839
3462
  end
3463
+ end
3464
+
3465
+ def self.set_gshp_assumptions(heat_pump, weather)
3466
+ hp_ap = heat_pump.additional_properties
3840
3467
 
3841
- return heat_eirs
3468
+ 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
3469
+ hp_ap.design_delta_t = 10.0
3470
+ hp_ap.fluid_type = Constants.FluidPropyleneGlycol
3471
+ hp_ap.frac_glycol = 0.3
3472
+ if hp_ap.fluid_type == Constants.FluidWater
3473
+ 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
3474
+ else
3475
+ 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
3476
+ end
3477
+ hp_ap.ground_conductivity = 0.6 # Btu/h-ft-R
3478
+ hp_ap.ground_diffusivity = 0.0208
3479
+ hp_ap.grout_conductivity = 0.4 # Btu/h-ft-R
3480
+ hp_ap.bore_diameter = 5.0 # in
3481
+ hp_ap.pipe_size = 0.75 # in
3482
+ # Pipe nominal size conversion to pipe outside diameter and inside diameter,
3483
+ # only pipe sizes <= 2" are used here with DR11 (dimension ratio),
3484
+ if hp_ap.pipe_size == 0.75 # 3/4" pipe
3485
+ hp_ap.pipe_od = 1.050 # in
3486
+ hp_ap.pipe_id = 0.859 # in
3487
+ elsif hp_ap.pipe_size == 1.0 # 1" pipe
3488
+ hp_ap.pipe_od = 1.315 # in
3489
+ hp_ap.pipe_id = 1.076 # in
3490
+ elsif hp_ap.pipe_size == 1.25 # 1-1/4" pipe
3491
+ hp_ap.pipe_od = 1.660 # in
3492
+ hp_ap.pipe_id = 1.358 # in
3493
+ end
3494
+ hp_ap.pipe_cond = 0.23 # Btu/h-ft-R; Pipe thermal conductivity, default to high density polyethylene
3495
+ hp_ap.u_tube_spacing_type = 'b'
3496
+ # Calculate distance between pipes
3497
+ if hp_ap.u_tube_spacing_type == 'as'
3498
+ # Two tubes, spaced 1/8” apart at the center of the borehole
3499
+ hp_ap.u_tube_spacing = 0.125
3500
+ elsif hp_ap.u_tube_spacing_type == 'b'
3501
+ # Two tubes equally spaced between the borehole edges
3502
+ hp_ap.u_tube_spacing = 0.9661
3503
+ elsif hp_ap.u_tube_spacing_type == 'c'
3504
+ # Both tubes placed against outer edge of borehole
3505
+ hp_ap.u_tube_spacing = hp_ap.bore_diameter - 2 * hp_ap.pipe_od
3506
+ end
3507
+ hp_ap.shank_spacing = hp_ap.u_tube_spacing + hp_ap.pipe_od # Distance from center of pipe to center of pipe
3842
3508
  end
3843
3509
 
3844
- def self.calc_mshp_hspf_4speed(cop_47, c_d, capacity_ratio, cfm_tons, fan_power_rated, hp_min_temp, heat_eir_ft_spec, heat_cap_ft_spec)
3845
- n_max = (cop_47.length - 1.0) #-3 # Don't use max speed; FIXME: this is different than calc_mshp_seer_4speed?
3510
+ def self.calc_mshp_hspf(cop_47, c_d, capacity_ratio, cfm_tons, fan_power_rated, hp_min_temp, heat_eir_ft_spec, heat_cap_ft_spec)
3511
+ n_max = (cop_47.length - 1.0) #-3 # Don't use max speed; FIXME: this is different than calc_mshp_seer?
3846
3512
  n_min = 0
3847
3513
  n_int = (n_min + (n_max - n_min) / 3.0).ceil.to_i
3848
3514
 
@@ -3868,17 +3534,17 @@ class HVAC
3868
3534
  q_H1_1 = capacity_ratio[n_min]
3869
3535
  q_H0_1 = q_H1_1 * MathTools.biquadratic(tin, tout_0, heat_cap_ft_spec[n_min])
3870
3536
 
3871
- q_H1_2_net = q_H1_2 + fan_power_rated[n_max] * UnitConversions.convert(1, 'W', 'Btu/hr') * cfm_tons[n_max] / UnitConversions.convert(1, 'ton', 'Btu/hr')
3872
- q_H3_2_net = q_H3_2 + fan_power_rated[n_max] * UnitConversions.convert(1, 'W', 'Btu/hr') * cfm_tons[n_max] / UnitConversions.convert(1, 'ton', 'Btu/hr')
3873
- q_H2_v_net = q_H2_v + fan_power_rated[n_int] * UnitConversions.convert(1, 'W', 'Btu/hr') * cfm_tons[n_int] / UnitConversions.convert(1, 'ton', 'Btu/hr')
3874
- q_H1_1_net = q_H1_1 + fan_power_rated[n_min] * UnitConversions.convert(1, 'W', 'Btu/hr') * cfm_tons[n_min] / UnitConversions.convert(1, 'ton', 'Btu/hr')
3875
- q_H0_1_net = q_H0_1 + fan_power_rated[n_min] * UnitConversions.convert(1, 'W', 'Btu/hr') * cfm_tons[n_min] / UnitConversions.convert(1, 'ton', 'Btu/hr')
3537
+ 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')
3538
+ 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')
3539
+ 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')
3540
+ 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')
3541
+ 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')
3876
3542
 
3877
- p_H1_2 = q_H1_2 * eir_H1_2 + fan_power_rated[n_max] * UnitConversions.convert(1, 'W', 'Btu/hr') * cfm_tons[n_max] / UnitConversions.convert(1, 'ton', 'Btu/hr')
3878
- p_H3_2 = q_H3_2 * eir_H3_2 + fan_power_rated[n_max] * UnitConversions.convert(1, 'W', 'Btu/hr') * cfm_tons[n_max] / UnitConversions.convert(1, 'ton', 'Btu/hr')
3879
- p_H2_v = q_H2_v * eir_H2_v + fan_power_rated[n_int] * UnitConversions.convert(1, 'W', 'Btu/hr') * cfm_tons[n_int] / UnitConversions.convert(1, 'ton', 'Btu/hr')
3880
- p_H1_1 = q_H1_1 * eir_H1_1 + fan_power_rated[n_min] * UnitConversions.convert(1, 'W', 'Btu/hr') * cfm_tons[n_min] / UnitConversions.convert(1, 'ton', 'Btu/hr')
3881
- p_H0_1 = q_H0_1 * eir_H0_1 + fan_power_rated[n_min] * UnitConversions.convert(1, 'W', 'Btu/hr') * cfm_tons[n_min] / UnitConversions.convert(1, 'ton', 'Btu/hr')
3543
+ 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')
3544
+ 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')
3545
+ 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')
3546
+ 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')
3547
+ 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')
3882
3548
 
3883
3549
  q_H35_2 = 0.9 * (q_H3_2_net + 0.6 * (q_H1_2_net - q_H3_2_net))
3884
3550
  p_H35_2 = 0.985 * (p_H3_2 + 0.6 * (p_H1_2 - p_H3_2))
@@ -3991,29 +3657,37 @@ class HVAC
3991
3657
  return s
3992
3658
  end
3993
3659
 
3994
- def self.get_crankcase_assumptions(fraction_cool_load_served)
3995
- crankcase_kw = 0.05 * fraction_cool_load_served # From RESNET Publication No. 002-2017
3996
- crankcase_temp = 50.0 # From RESNET Publication No. 002-2017
3997
- return crankcase_kw, crankcase_temp
3660
+ def self.set_crankcase_assumptions(hvac_system)
3661
+ hvac_ap = hvac_system.additional_properties
3662
+
3663
+ if hvac_system.is_a?(HPXML::HeatPump) && (hvac_system.fraction_heat_load_served <= 0)
3664
+ hvac_ap.crankcase_kw = 0.0
3665
+ hvac_ap.crankcase_temp = nil
3666
+ elsif hvac_system.is_a?(HPXML::HeatPump) && (hvac_system.heat_pump_type == HPXML::HVACTypeHeatPumpMiniSplit)
3667
+ hvac_ap.crankcase_kw = 0.0
3668
+ hvac_ap.crankcase_temp = nil
3669
+ elsif hvac_system.is_a?(HPXML::CoolingSystem) && (hvac_system.cooling_system_type == HPXML::HVACTypeMiniSplitAirConditioner)
3670
+ hvac_ap.crankcase_kw = 0.0
3671
+ hvac_ap.crankcase_temp = nil
3672
+ else
3673
+ hvac_ap.crankcase_kw = 0.05 * hvac_system.fraction_cool_load_served # From RESNET Publication No. 002-2017
3674
+ hvac_ap.crankcase_temp = 50.0 # From RESNET Publication No. 002-2017
3675
+ end
3998
3676
  end
3999
3677
 
4000
- def self.get_heat_pump_temp_assumptions(heat_pump)
4001
- # Calculates:
4002
- # 1. Minimum temperature for HP compressor operation
4003
- # 2. Maximum temperature for HP supplemental heating operation
3678
+ def self.set_heat_pump_temperatures(heat_pump)
3679
+ hp_ap = heat_pump.additional_properties
3680
+
3681
+ # Sets:
3682
+ # 1. Minimum temperature (deg-F) for HP compressor operation
3683
+ # 2. Maximum temperature (deg-F) for HP supplemental heating operation
4004
3684
  if not heat_pump.backup_heating_switchover_temp.nil?
4005
- hp_min_temp = heat_pump.backup_heating_switchover_temp
4006
- supp_max_temp = heat_pump.backup_heating_switchover_temp
3685
+ hp_ap.hp_min_temp = heat_pump.backup_heating_switchover_temp
3686
+ hp_ap.supp_max_temp = heat_pump.backup_heating_switchover_temp
4007
3687
  else
4008
- supp_max_temp = 40.0
4009
- # Minimum temperature for Heat Pump operation:
4010
- if heat_pump.heat_pump_type == HPXML::HVACTypeHeatPumpMiniSplit
4011
- hp_min_temp = -30.0 # deg-F
4012
- else
4013
- hp_min_temp = 0.0 # deg-F
4014
- end
3688
+ hp_ap.supp_max_temp = 40.0
3689
+ hp_ap.hp_min_temp = -40.0
4015
3690
  end
4016
- return hp_min_temp, supp_max_temp
4017
3691
  end
4018
3692
 
4019
3693
  def self.get_default_duct_surface_area(duct_type, ncfl_ag, cfa_served, n_returns)
@@ -4053,19 +3727,271 @@ class HVAC
4053
3727
  return primary_duct_location, secondary_duct_location
4054
3728
  end
4055
3729
 
3730
+ def self.get_installation_quality_cooling_coeff(f_chg)
3731
+ if f_chg <= 0
3732
+ qgr_values = [-9.46E-01, 4.93E-02, -1.18E-03, -1.15E+00]
3733
+ p_values = [-3.13E-01, 1.15E-02, 2.66E-03, -1.16E-01]
3734
+ else
3735
+ qgr_values = [-1.63E-01, 1.14E-02, -2.10E-04, -1.40E-01]
3736
+ p_values = [2.19E-01, -5.01E-03, 9.89E-04, 2.84E-01]
3737
+ end
3738
+ ff_chg_values = [26.67, 35.0]
3739
+ return qgr_values, p_values, ff_chg_values
3740
+ end
3741
+
3742
+ def self.get_installation_quality_heating_coeff(f_chg)
3743
+ if f_chg <= 0
3744
+ qgr_values = [-0.0338595, 0.0202827, -2.6226343]
3745
+ p_values = [0.0615649, 0.0044554, -0.2598507]
3746
+ else
3747
+ qgr_values = [-0.0029514, 0.0007379, -0.0064112]
3748
+ p_values = [-0.0594134, 0.0159205, 1.8872153]
3749
+ end
3750
+ ff_chg_values = [8.33]
3751
+ return qgr_values, p_values, ff_chg_values
3752
+ end
3753
+
3754
+ def self.apply_installation_quality(model, heating_system, cooling_system, unitary_system, htg_coil, clg_coil, control_zone)
3755
+ if not cooling_system.nil?
3756
+ charge_defect_ratio = cooling_system.charge_defect_ratio
3757
+ cool_airflow_defect_ratio = cooling_system.airflow_defect_ratio
3758
+ end
3759
+ if not heating_system.nil?
3760
+ heat_airflow_defect_ratio = heating_system.airflow_defect_ratio
3761
+ end
3762
+ 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)
3763
+
3764
+ cool_airflow_rated_defect_ratio = []
3765
+ if (not clg_coil.nil?) && (cooling_system.fraction_cool_load_served > 0)
3766
+ clg_ap = cooling_system.additional_properties
3767
+ clg_cfm = cooling_system.cooling_airflow_cfm
3768
+ if clg_coil.to_CoilCoolingDXSingleSpeed.is_initialized
3769
+ cool_airflow_rated_defect_ratio = [UnitConversions.convert(clg_cfm, 'cfm', 'm^3/s') / clg_coil.ratedAirFlowRate.get - 1.0]
3770
+ elsif clg_coil.to_CoilCoolingDXMultiSpeed.is_initialized
3771
+ cool_airflow_rated_defect_ratio = clg_coil.stages.zip(clg_ap.cool_fan_speed_ratios).map { |stage, speed_ratio| UnitConversions.convert(clg_cfm * speed_ratio, 'cfm', 'm^3/s') / stage.ratedAirFlowRate.get - 1.0 }
3772
+ end
3773
+ end
3774
+
3775
+ heat_airflow_rated_defect_ratio = []
3776
+ if (not htg_coil.nil?) && (heating_system.fraction_heat_load_served > 0)
3777
+ htg_ap = heating_system.additional_properties
3778
+ htg_cfm = heating_system.heating_airflow_cfm
3779
+ if htg_coil.to_CoilHeatingDXSingleSpeed.is_initialized
3780
+ heat_airflow_rated_defect_ratio = [UnitConversions.convert(htg_cfm, 'cfm', 'm^3/s') / htg_coil.ratedAirFlowRate.get - 1.0]
3781
+ elsif htg_coil.to_CoilHeatingDXMultiSpeed.is_initialized
3782
+ heat_airflow_rated_defect_ratio = htg_coil.stages.zip(htg_ap.heat_fan_speed_ratios).map { |stage, speed_ratio| UnitConversions.convert(htg_cfm * speed_ratio, 'cfm', 'm^3/s') / stage.ratedAirFlowRate.get - 1.0 }
3783
+ end
3784
+ end
3785
+
3786
+ return if cool_airflow_rated_defect_ratio.empty? && heat_airflow_rated_defect_ratio.empty?
3787
+
3788
+ obj_name = "#{unitary_system.name} install quality"
3789
+
3790
+ tin_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Zone Mean Air Temperature')
3791
+ tin_sensor.setName("#{obj_name} tin s")
3792
+ tin_sensor.setKeyName(control_zone.name.to_s)
3793
+
3794
+ tout_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Zone Outdoor Air Drybulb Temperature')
3795
+ tout_sensor.setName("#{obj_name} tt s")
3796
+ tout_sensor.setKeyName(control_zone.name.to_s)
3797
+
3798
+ fault_program = OpenStudio::Model::EnergyManagementSystemProgram.new(model)
3799
+ fault_program.setName("#{obj_name} program")
3800
+
3801
+ f_chg = charge_defect_ratio.to_f
3802
+ fault_program.addLine("Set F_CH = #{f_chg.round(3)}")
3803
+
3804
+ if not cool_airflow_rated_defect_ratio.empty?
3805
+ if clg_coil.is_a? OpenStudio::Model::CoilCoolingDXSingleSpeed
3806
+ num_speeds = 1
3807
+ cool_cap_fff_curves = [clg_coil.totalCoolingCapacityFunctionOfFlowFractionCurve.to_CurveQuadratic.get]
3808
+ cool_eir_fff_curves = [clg_coil.energyInputRatioFunctionOfFlowFractionCurve.to_CurveQuadratic.get]
3809
+ elsif clg_coil.is_a? OpenStudio::Model::CoilCoolingDXMultiSpeed
3810
+ num_speeds = clg_coil.stages.size
3811
+ cool_cap_fff_curves = clg_coil.stages.map { |stage| stage.totalCoolingCapacityFunctionofFlowFractionCurve.to_CurveQuadratic.get }
3812
+ cool_eir_fff_curves = clg_coil.stages.map { |stage| stage.energyInputRatioFunctionofFlowFractionCurve.to_CurveQuadratic.get }
3813
+ else
3814
+ fail 'cooling coil not supported'
3815
+ end
3816
+ for speed in 0..(num_speeds - 1)
3817
+ cool_cap_fff_curve = cool_cap_fff_curves[speed]
3818
+ cool_cap_fff_act = OpenStudio::Model::EnergyManagementSystemActuator.new(cool_cap_fff_curve, 'Curve', 'Curve Result')
3819
+ cool_cap_fff_act.setName("#{obj_name} cap clg act")
3820
+
3821
+ cool_eir_fff_curve = cool_eir_fff_curves[speed]
3822
+ cool_eir_fff_act = OpenStudio::Model::EnergyManagementSystemActuator.new(cool_eir_fff_curve, 'Curve', 'Curve Result')
3823
+ cool_eir_fff_act.setName("#{obj_name} eir clg act")
3824
+
3825
+ # NOTE: heat pump (cooling) curves don't exhibit expected trends at extreme faults;
3826
+ fault_program.addLine("Set a1_AF_Qgr_c = #{cool_cap_fff_curve.coefficient1Constant}")
3827
+ fault_program.addLine("Set a2_AF_Qgr_c = #{cool_cap_fff_curve.coefficient2x}")
3828
+ fault_program.addLine("Set a3_AF_Qgr_c = #{cool_cap_fff_curve.coefficient3xPOW2}")
3829
+ fault_program.addLine("Set a1_AF_EIR_c = #{cool_eir_fff_curve.coefficient1Constant}")
3830
+ fault_program.addLine("Set a2_AF_EIR_c = #{cool_eir_fff_curve.coefficient2x}")
3831
+ fault_program.addLine("Set a3_AF_EIR_c = #{cool_eir_fff_curve.coefficient3xPOW2}")
3832
+
3833
+ qgr_values, p_values, ff_chg_values = get_installation_quality_cooling_coeff(f_chg)
3834
+
3835
+ fault_program.addLine("Set a1_CH_Qgr_c = #{qgr_values[0]}")
3836
+ fault_program.addLine("Set a2_CH_Qgr_c = #{qgr_values[1]}")
3837
+ fault_program.addLine("Set a3_CH_Qgr_c = #{qgr_values[2]}")
3838
+ fault_program.addLine("Set a4_CH_Qgr_c = #{qgr_values[3]}")
3839
+
3840
+ fault_program.addLine("Set a1_CH_P_c = #{p_values[0]}")
3841
+ fault_program.addLine("Set a2_CH_P_c = #{p_values[1]}")
3842
+ fault_program.addLine("Set a3_CH_P_c = #{p_values[2]}")
3843
+ fault_program.addLine("Set a4_CH_P_c = #{p_values[3]}")
3844
+
3845
+ ff_ch_c = 1.0 / (1.0 + (qgr_values[0] + (qgr_values[1] * ff_chg_values[0]) + (qgr_values[2] * ff_chg_values[1]) + (qgr_values[3] * f_chg)) * f_chg)
3846
+ fault_program.addLine("Set FF_CH_c = #{ff_ch_c.round(3)}")
3847
+
3848
+ fault_program.addLine('Set q0_CH = a1_CH_Qgr_c')
3849
+ fault_program.addLine("Set q1_CH = a2_CH_Qgr_c*#{tin_sensor.name}")
3850
+ fault_program.addLine("Set q2_CH = a3_CH_Qgr_c*#{tout_sensor.name}")
3851
+ fault_program.addLine('Set q3_CH = a4_CH_Qgr_c*F_CH')
3852
+ fault_program.addLine('Set Y_CH_Q_c = 1 + ((q0_CH+(q1_CH)+(q2_CH)+(q3_CH))*F_CH)')
3853
+
3854
+ fault_program.addLine('Set q0_AF_CH = a1_AF_Qgr_c')
3855
+ fault_program.addLine('Set q1_AF_CH = a2_AF_Qgr_c*FF_CH_c')
3856
+ fault_program.addLine('Set q2_AF_CH = a3_AF_Qgr_c*FF_CH_c*FF_CH_c')
3857
+ fault_program.addLine('Set p_CH_Q_c = Y_CH_Q_c/(q0_AF_CH+(q1_AF_CH)+(q2_AF_CH))')
3858
+
3859
+ fault_program.addLine('Set p1_CH = a1_CH_P_c')
3860
+ fault_program.addLine("Set p2_CH = a2_CH_P_c*#{tin_sensor.name}")
3861
+ fault_program.addLine("Set p3_CH = a3_CH_P_c*#{tout_sensor.name}")
3862
+ fault_program.addLine('Set p4_CH = a4_CH_P_c*F_CH')
3863
+ fault_program.addLine('Set Y_CH_COP_c = Y_CH_Q_c/(1 + (p1_CH+(p2_CH)+(p3_CH)+(p4_CH))*F_CH)')
3864
+
3865
+ fault_program.addLine('Set eir0_AF_CH = a1_AF_EIR_c')
3866
+ fault_program.addLine('Set eir1_AF_CH = a2_AF_EIR_c*FF_CH_c')
3867
+ fault_program.addLine('Set eir2_AF_CH = a3_AF_EIR_c*FF_CH_c*FF_CH_c')
3868
+ fault_program.addLine('Set p_CH_COP_c = Y_CH_COP_c*(eir0_AF_CH+(eir1_AF_CH)+(eir2_AF_CH))')
3869
+
3870
+ fault_program.addLine("Set FF_AF_c = 1.0 + #{cool_airflow_rated_defect_ratio[speed].round(3)}")
3871
+ fault_program.addLine('Set FF_AF_comb_c = FF_CH_c * FF_AF_c')
3872
+
3873
+ fault_program.addLine('Set q0_AF_comb = a1_AF_Qgr_c')
3874
+ fault_program.addLine('Set q1_AF_comb = a2_AF_Qgr_c*FF_AF_comb_c')
3875
+ fault_program.addLine('Set q2_AF_comb = a3_AF_Qgr_c*FF_AF_comb_c*FF_AF_comb_c')
3876
+ fault_program.addLine('Set p_AF_Q_c = q0_AF_comb+(q1_AF_comb)+(q2_AF_comb)')
3877
+
3878
+ fault_program.addLine('Set eir0_AF_comb = a1_AF_EIR_c')
3879
+ fault_program.addLine('Set eir1_AF_comb = a2_AF_EIR_c*FF_AF_comb_c')
3880
+ fault_program.addLine('Set eir2_AF_comb = a3_AF_EIR_c*FF_AF_comb_c*FF_AF_comb_c')
3881
+ fault_program.addLine('Set p_AF_COP_c = 1.0/(eir0_AF_comb+(eir1_AF_comb)+(eir2_AF_comb))')
3882
+
3883
+ fault_program.addLine("Set #{cool_cap_fff_act.name} = (p_CH_Q_c * p_AF_Q_c)")
3884
+ fault_program.addLine("Set #{cool_eir_fff_act.name} = (1.0 / (p_CH_COP_c * p_AF_COP_c))")
3885
+ end
3886
+ end
3887
+
3888
+ if not heat_airflow_rated_defect_ratio.empty?
3889
+
3890
+ if htg_coil.is_a? OpenStudio::Model::CoilHeatingDXSingleSpeed
3891
+ num_speeds = 1
3892
+ heat_cap_fff_curves = [htg_coil.totalHeatingCapacityFunctionofFlowFractionCurve.to_CurveQuadratic.get]
3893
+ heat_eir_fff_curves = [htg_coil.energyInputRatioFunctionofFlowFractionCurve.to_CurveQuadratic.get]
3894
+ elsif htg_coil.is_a? OpenStudio::Model::CoilHeatingDXMultiSpeed
3895
+ num_speeds = htg_coil.stages.size
3896
+ heat_cap_fff_curves = htg_coil.stages.map { |stage| stage.heatingCapacityFunctionofFlowFractionCurve.to_CurveQuadratic.get }
3897
+ heat_eir_fff_curves = htg_coil.stages.map { |stage| stage.energyInputRatioFunctionofFlowFractionCurve.to_CurveQuadratic.get }
3898
+ else
3899
+ fail 'heating coil not supported'
3900
+ end
3901
+ for speed in 0..(num_speeds - 1)
3902
+ heat_cap_fff_curve = heat_cap_fff_curves[speed]
3903
+ heat_cap_fff_act = OpenStudio::Model::EnergyManagementSystemActuator.new(heat_cap_fff_curve, 'Curve', 'Curve Result')
3904
+ heat_cap_fff_act.setName("#{obj_name} cap htg act")
3905
+
3906
+ heat_eir_fff_curve = heat_eir_fff_curves[speed]
3907
+ heat_eir_fff_act = OpenStudio::Model::EnergyManagementSystemActuator.new(heat_eir_fff_curve, 'Curve', 'Curve Result')
3908
+ heat_eir_fff_act.setName("#{obj_name} eir htg act")
3909
+
3910
+ fault_program.addLine("Set a1_AF_Qgr_h = #{heat_cap_fff_curve.coefficient1Constant}")
3911
+ fault_program.addLine("Set a2_AF_Qgr_h = #{heat_cap_fff_curve.coefficient2x}")
3912
+ fault_program.addLine("Set a3_AF_Qgr_h = #{heat_cap_fff_curve.coefficient3xPOW2}")
3913
+ fault_program.addLine("Set a1_AF_EIR_h = #{heat_eir_fff_curve.coefficient1Constant}")
3914
+ fault_program.addLine("Set a2_AF_EIR_h = #{heat_eir_fff_curve.coefficient2x}")
3915
+ fault_program.addLine("Set a3_AF_EIR_h = #{heat_eir_fff_curve.coefficient3xPOW2}")
3916
+
3917
+ qgr_values, p_values, ff_chg_values = get_installation_quality_heating_coeff(f_chg)
3918
+
3919
+ fault_program.addLine("Set a1_CH_Qgr_h = #{qgr_values[0]}")
3920
+ fault_program.addLine("Set a2_CH_Qgr_h = #{qgr_values[1]}")
3921
+ fault_program.addLine("Set a3_CH_Qgr_h = #{qgr_values[2]}")
3922
+
3923
+ fault_program.addLine("Set a1_CH_P_h = #{p_values[0]}")
3924
+ fault_program.addLine("Set a2_CH_P_h = #{p_values[1]}")
3925
+ fault_program.addLine("Set a3_CH_P_h = #{p_values[2]}")
3926
+
3927
+ ff_ch_h = 1 / (1 + (qgr_values[0] + qgr_values[1] * ff_chg_values[0] + qgr_values[2] * f_chg) * f_chg)
3928
+ fault_program.addLine("Set FF_CH_h = #{ff_ch_h.round(3)}")
3929
+
3930
+ fault_program.addLine('Set qh1_CH = a1_CH_Qgr_h')
3931
+ fault_program.addLine("Set qh2_CH = a2_CH_Qgr_h*#{tout_sensor.name}")
3932
+ fault_program.addLine('Set qh3_CH = a3_CH_Qgr_h*F_CH')
3933
+ fault_program.addLine('Set Y_CH_Q_h = 1 + ((qh1_CH+(qh2_CH)+(qh3_CH))*F_CH)')
3934
+
3935
+ fault_program.addLine('Set qh0_AF_CH = a1_AF_Qgr_h')
3936
+ fault_program.addLine('Set qh1_AF_CH = a2_AF_Qgr_h*FF_CH_h')
3937
+ fault_program.addLine('Set qh2_AF_CH = a3_AF_Qgr_h*FF_CH_h*FF_CH_h')
3938
+ fault_program.addLine('Set p_CH_Q_h = Y_CH_Q_h/(qh0_AF_CH + (qh1_AF_CH) +(qh2_AF_CH))')
3939
+
3940
+ fault_program.addLine('Set ph1_CH = a1_CH_P_h')
3941
+ fault_program.addLine("Set ph2_CH = a2_CH_P_h*#{tout_sensor.name}")
3942
+ fault_program.addLine('Set ph3_CH = a3_CH_P_h*F_CH')
3943
+ fault_program.addLine('Set Y_CH_COP_h = Y_CH_Q_h/(1 + ((ph1_CH+(ph2_CH)+(ph3_CH))*F_CH))')
3944
+
3945
+ fault_program.addLine('Set eirh0_AF_CH = a1_AF_EIR_h')
3946
+ fault_program.addLine('Set eirh1_AF_CH = a2_AF_EIR_h*FF_CH_h')
3947
+ fault_program.addLine('Set eirh2_AF_CH = a3_AF_EIR_h*FF_CH_h*FF_CH_h')
3948
+ fault_program.addLine('Set p_CH_COP_h = Y_CH_COP_h*(eirh0_AF_CH + (eirh1_AF_CH) + (eirh2_AF_CH))')
3949
+
3950
+ fault_program.addLine("Set FF_AF_h = 1.0 + #{heat_airflow_rated_defect_ratio[speed].round(3)}")
3951
+ fault_program.addLine('Set FF_AF_comb_h = FF_CH_h * FF_AF_h')
3952
+
3953
+ fault_program.addLine('Set qh0_AF_comb = a1_AF_Qgr_h')
3954
+ fault_program.addLine('Set qh1_AF_comb = a2_AF_Qgr_h*FF_AF_comb_h')
3955
+ fault_program.addLine('Set qh2_AF_comb = a3_AF_Qgr_h*FF_AF_comb_h*FF_AF_comb_h')
3956
+ fault_program.addLine('Set p_AF_Q_h = qh0_AF_comb+(qh1_AF_comb)+(qh2_AF_comb)')
3957
+
3958
+ fault_program.addLine('Set eirh0_AF_comb = a1_AF_EIR_h')
3959
+ fault_program.addLine('Set eirh1_AF_comb = a2_AF_EIR_h*FF_AF_comb_h')
3960
+ fault_program.addLine('Set eirh2_AF_comb = a3_AF_EIR_h*FF_AF_comb_h*FF_AF_comb_h')
3961
+ fault_program.addLine('Set p_AF_COP_h = 1.0/(eirh0_AF_comb+(eirh1_AF_comb)+(eirh2_AF_comb))')
3962
+
3963
+ fault_program.addLine("Set #{heat_cap_fff_act.name} = (p_CH_Q_h * p_AF_Q_h)")
3964
+ fault_program.addLine("Set #{heat_eir_fff_act.name} = 1.0 / (p_CH_COP_h * p_AF_COP_h)")
3965
+ end
3966
+ end
3967
+ program_calling_manager = OpenStudio::Model::EnergyManagementSystemProgramCallingManager.new(model)
3968
+ program_calling_manager.setName("#{obj_name} program manager")
3969
+ program_calling_manager.setCallingPoint('BeginTimestepBeforePredictor')
3970
+ program_calling_manager.addProgram(fault_program)
3971
+ end
3972
+
4056
3973
  def self.get_default_gshp_pump_power()
4057
3974
  return 30.0 # W/ton, per ANSI/RESNET/ICC 301-2019 Section 4.4.5 (closed loop)
4058
3975
  end
4059
3976
 
4060
- def self.apply_shared_systems(hpxml)
4061
- apply_shared_cooling_systems(hpxml)
4062
- apply_shared_heating_systems(hpxml)
4063
- HPXMLDefaults.apply_hvac(hpxml)
3977
+ def self.apply_shared_systems(hpxml = true)
3978
+ applied_clg = apply_shared_cooling_systems(hpxml)
3979
+ applied_htg = apply_shared_heating_systems(hpxml)
3980
+ return unless (applied_clg || applied_htg)
3981
+
3982
+ # Remove WLHP if not serving heating nor cooling
3983
+ hpxml.heat_pumps.each do |hp|
3984
+ next unless hp.heat_pump_type == HPXML::HVACTypeHeatPumpWaterLoopToAir
3985
+ next if hp.fraction_heat_load_served > 0
3986
+ next if hp.fraction_cool_load_served > 0
3987
+
3988
+ hp.delete
3989
+ end
4064
3990
 
4065
3991
  # Remove any orphaned HVAC distributions
4066
3992
  hpxml.hvac_distributions.each do |hvac_distribution|
4067
3993
  hvac_systems = []
4068
- (hpxml.heating_systems + hpxml.cooling_systems + hpxml.heat_pumps).each do |hvac_system|
3994
+ hpxml.hvac_systems.each do |hvac_system|
4069
3995
  next if hvac_system.distribution_system_idref.nil?
4070
3996
  next unless hvac_system.distribution_system_idref == hvac_distribution.id
4071
3997
 
@@ -4078,12 +4004,14 @@ class HVAC
4078
4004
  end
4079
4005
 
4080
4006
  def self.apply_shared_cooling_systems(hpxml)
4007
+ applied = false
4081
4008
  hpxml.cooling_systems.each do |cooling_system|
4082
4009
  next unless cooling_system.is_shared_system
4083
4010
 
4011
+ applied = true
4012
+ wlhp = nil
4084
4013
  distribution_system = cooling_system.distribution_system
4085
4014
  distribution_type = distribution_system.distribution_system_type
4086
- hydronic_and_air_type = distribution_system.hydronic_and_air_type
4087
4015
 
4088
4016
  # Calculate air conditioner SEER equivalent
4089
4017
  n_dweq = cooling_system.number_of_units_served.to_f
@@ -4095,17 +4023,16 @@ class HVAC
4095
4023
  cap = cooling_system.cooling_capacity
4096
4024
  chiller_input = UnitConversions.convert(cooling_system.cooling_efficiency_kw_per_ton * UnitConversions.convert(cap, 'Btu/hr', 'ton'), 'kW', 'W')
4097
4025
  if distribution_type == HPXML::HVACDistributionTypeHydronic
4098
- aux_dweq = 0.0
4099
- elsif distribution_type == HPXML::HVACDistributionTypeHydronicAndAir
4100
- if hydronic_and_air_type == HPXML::HydronicAndAirTypeFanCoil
4101
- aux_dweq = cooling_system.fan_coil_watts
4102
- elsif hydronic_and_air_type == HPXML::HydronicAndAirTypeWaterLoopHeatPump
4103
- aux_dweq = cooling_system.wlhp_cooling_capacity / cooling_system.wlhp_cooling_efficiency_eer
4026
+ if distribution_system.hydronic_type == HPXML::HydronicTypeWaterLoop
4027
+ wlhp = hpxml.heat_pumps.select { |hp| hp.heat_pump_type == HPXML::HVACTypeHeatPumpWaterLoopToAir }[0]
4028
+ aux_dweq = wlhp.cooling_capacity / wlhp.cooling_efficiency_eer
4104
4029
  else
4105
- fail "Unexpected distribution type '#{hydronic_and_air_type}' for chiller."
4030
+ aux_dweq = 0.0
4031
+ end
4032
+ elsif distribution_type == HPXML::HVACDistributionTypeAir
4033
+ if distribution_system.air_type == HPXML::AirTypeFanCoil
4034
+ aux_dweq = cooling_system.fan_coil_watts
4106
4035
  end
4107
- else
4108
- fail "Unexpected distribution type '#{distribution_type}' for chiller."
4109
4036
  end
4110
4037
  # ANSI/RESNET/ICC 301-2019 Equation 4.4-2
4111
4038
  seer_eq = (cap - 3.41 * aux - 3.41 * aux_dweq * n_dweq) / (chiller_input + aux + aux_dweq * n_dweq)
@@ -4113,16 +4040,12 @@ class HVAC
4113
4040
  elsif cooling_system.cooling_system_type == HPXML::HVACTypeCoolingTower
4114
4041
 
4115
4042
  # Cooling tower w/ water loop heat pump
4116
- if distribution_type == HPXML::HVACDistributionTypeHydronicAndAir
4117
- hydronic_and_air_type = distribution_system.hydronic_and_air_type
4118
- if hydronic_and_air_type == HPXML::HydronicAndAirTypeWaterLoopHeatPump
4119
- wlhp_cap = cooling_system.wlhp_cooling_capacity
4120
- wlhp_input = wlhp_cap / cooling_system.wlhp_cooling_efficiency_eer
4121
- else
4122
- fail "Unexpected distribution type '#{hydronic_and_air_type}' for cooling tower."
4043
+ if distribution_type == HPXML::HVACDistributionTypeHydronic
4044
+ if distribution_system.hydronic_type == HPXML::HydronicTypeWaterLoop
4045
+ wlhp = hpxml.heat_pumps.select { |hp| hp.heat_pump_type == HPXML::HVACTypeHeatPumpWaterLoopToAir }[0]
4046
+ wlhp_cap = wlhp.cooling_capacity
4047
+ wlhp_input = wlhp_cap / wlhp.cooling_efficiency_eer
4123
4048
  end
4124
- else
4125
- fail "Unexpected hydronic distribution type '#{distribution_type}' for cooling tower."
4126
4049
  end
4127
4050
  # ANSI/RESNET/ICC 301-2019 Equation 4.4-3
4128
4051
  seer_eq = (wlhp_cap - 3.41 * aux / n_dweq) / (wlhp_input + aux / n_dweq)
@@ -4131,36 +4054,75 @@ class HVAC
4131
4054
  fail "Unexpected cooling system type '#{cooling_system.cooling_system_type}'."
4132
4055
  end
4133
4056
 
4057
+ if seer_eq <= 0
4058
+ fail "Negative SEER equivalent calculated for cooling system '#{cooling_system.id}', double check inputs."
4059
+ end
4060
+
4134
4061
  cooling_system.cooling_system_type = HPXML::HVACTypeCentralAirConditioner
4135
- cooling_system.cooling_efficiency_seer = seer_eq
4062
+ cooling_system.cooling_efficiency_seer = seer_eq.round(2)
4063
+ cooling_system.cooling_efficiency_kw_per_ton = nil
4136
4064
  cooling_system.cooling_capacity = nil # Autosize the equipment
4065
+ cooling_system.is_shared_system = false
4066
+ cooling_system.number_of_units_served = nil
4067
+ cooling_system.shared_loop_watts = nil
4068
+ cooling_system.shared_loop_motor_efficiency = nil
4069
+ cooling_system.fan_coil_watts = nil
4137
4070
 
4138
4071
  # Assign new distribution system to air conditioner
4139
4072
  if distribution_type == HPXML::HVACDistributionTypeHydronic
4140
- # Assign DSE=1
4141
- hpxml.hvac_distributions.add(id: "#{cooling_system.id}AirDistributionSystem",
4142
- distribution_system_type: HPXML::HVACDistributionTypeDSE,
4143
- annual_cooling_dse: 1)
4144
- cooling_system.distribution_system_idref = hpxml.hvac_distributions[-1].id
4145
- elsif distribution_type == HPXML::HVACDistributionTypeHydronicAndAir
4146
- # Assign AirDistribution
4147
- hpxml.hvac_distributions << distribution_system.dup
4148
- hpxml.hvac_distributions[-1].id = "#{cooling_system.id}AirDistributionSystem"
4149
- hpxml.hvac_distributions[-1].distribution_system_type = HPXML::HVACDistributionTypeAir
4150
- cooling_system.distribution_system_idref = hpxml.hvac_distributions[-1].id
4073
+ if distribution_system.hydronic_type == HPXML::HydronicTypeWaterLoop
4074
+ # Assign WLHP air distribution
4075
+ cooling_system.distribution_system_idref = wlhp.distribution_system_idref
4076
+ wlhp.fraction_cool_load_served = 0.0
4077
+ wlhp.fraction_heat_load_served = 0.0
4078
+ else
4079
+ # Assign DSE=1
4080
+ hpxml.hvac_distributions.add(id: "#{cooling_system.id}AirDistributionSystem",
4081
+ distribution_system_type: HPXML::HVACDistributionTypeDSE,
4082
+ annual_cooling_dse: 1.0,
4083
+ annual_heating_dse: 1.0)
4084
+ cooling_system.distribution_system_idref = hpxml.hvac_distributions[-1].id
4085
+ end
4086
+ elsif (distribution_type == HPXML::HVACDistributionTypeAir) && (distribution_system.air_type == HPXML::AirTypeFanCoil)
4087
+ # Convert "fan coil" air distribution system to "regular velocity"
4088
+ if distribution_system.hvac_systems.size > 1
4089
+ # Has attached heating system, so create a copy specifically for the cooling system
4090
+ hpxml.hvac_distributions << distribution_system.dup
4091
+ hpxml.hvac_distributions[-1].id += "#{cooling_system.id}AirDistributionSystem"
4092
+ cooling_system.distribution_system_idref = hpxml.hvac_distributions[-1].id
4093
+ end
4094
+ hpxml.hvac_distributions[-1].air_type = HPXML::AirTypeRegularVelocity
4095
+ 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
4096
+ # Assign zero supply leakage
4097
+ hpxml.hvac_distributions[-1].duct_leakage_measurements.add(duct_type: HPXML::DuctTypeSupply,
4098
+ duct_leakage_units: HPXML::UnitsCFM25,
4099
+ duct_leakage_value: 0,
4100
+ duct_leakage_total_or_to_outside: HPXML::DuctLeakageToOutside)
4101
+ end
4102
+ 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
4103
+ # Assign zero return leakage
4104
+ hpxml.hvac_distributions[-1].duct_leakage_measurements.add(duct_type: HPXML::DuctTypeReturn,
4105
+ duct_leakage_units: HPXML::UnitsCFM25,
4106
+ duct_leakage_value: 0,
4107
+ duct_leakage_total_or_to_outside: HPXML::DuctLeakageToOutside)
4108
+ end
4151
4109
  end
4152
4110
  end
4111
+
4112
+ return applied
4153
4113
  end
4154
4114
 
4155
4115
  def self.apply_shared_heating_systems(hpxml)
4116
+ applied = false
4156
4117
  hpxml.heating_systems.each do |heating_system|
4157
4118
  next unless heating_system.is_shared_system
4158
4119
 
4120
+ applied = true
4159
4121
  distribution_system = heating_system.distribution_system
4160
4122
  distribution_type = distribution_system.distribution_system_type
4161
- hydronic_and_air_type = distribution_system.hydronic_and_air_type
4123
+ hydronic_type = distribution_system.hydronic_type
4162
4124
 
4163
- if heating_system.heating_system_type == HPXML::HVACTypeBoiler && hydronic_and_air_type.to_s == HPXML::HydronicAndAirTypeWaterLoopHeatPump
4125
+ if heating_system.heating_system_type == HPXML::HVACTypeBoiler && hydronic_type.to_s == HPXML::HydronicTypeWaterLoop
4164
4126
 
4165
4127
  # Shared boiler w/ water loop heat pump
4166
4128
  # Per ANSI/RESNET/ICC 301-2019 Section 4.4.7.2, model as:
@@ -4169,24 +4131,125 @@ class HVAC
4169
4131
  fraction_heat_load_served = heating_system.fraction_heat_load_served
4170
4132
 
4171
4133
  # Heat pump
4172
- hpxml.heat_pumps.add(id: "#{heating_system.id}_WLHP",
4173
- distribution_system_idref: heating_system.distribution_system_idref,
4174
- heat_pump_type: HPXML::HVACTypeHeatPumpWaterLoopToAir,
4175
- heat_pump_fuel: HPXML::FuelTypeElectricity,
4176
- heating_efficiency_cop: heating_system.wlhp_heating_efficiency_cop,
4177
- fraction_heat_load_served: fraction_heat_load_served * (1.0 / heating_system.wlhp_heating_efficiency_cop),
4178
- fraction_cool_load_served: 0.0)
4134
+ # If this approach is ever removed, also remove code in HVACSizing.apply_hvac_loads()
4135
+ wlhp = hpxml.heat_pumps.select { |hp| hp.heat_pump_type == HPXML::HVACTypeHeatPumpWaterLoopToAir }[0]
4136
+ wlhp.fraction_heat_load_served = fraction_heat_load_served * (1.0 / wlhp.heating_efficiency_cop)
4137
+ wlhp.fraction_cool_load_served = 0.0
4179
4138
 
4180
4139
  # Boiler
4181
- heating_system.electric_auxiliary_energy = get_default_boiler_eae(heating_system)
4182
- heating_system.fraction_heat_load_served = fraction_heat_load_served * (1.0 - 1.0 / heating_system.wlhp_heating_efficiency_cop)
4183
- heating_system.distribution_system_idref = "#{heating_system.id}_Baseboard"
4184
- hpxml.hvac_distributions.add(id: heating_system.distribution_system_idref,
4185
- distribution_system_type: HPXML::HVACDistributionTypeHydronic,
4186
- hydronic_type: HPXML::HydronicTypeBaseboard)
4140
+ heating_system.fraction_heat_load_served = fraction_heat_load_served * (1.0 - 1.0 / wlhp.heating_efficiency_cop)
4187
4141
  end
4188
4142
 
4189
4143
  heating_system.heating_capacity = nil # Autosize the equipment
4190
4144
  end
4145
+
4146
+ return applied
4147
+ end
4148
+
4149
+ def self.set_num_speeds(hvac_system)
4150
+ hvac_ap = hvac_system.additional_properties
4151
+
4152
+ if hvac_system.is_a?(HPXML::CoolingSystem) && (hvac_system.cooling_system_type == HPXML::HVACTypeRoomAirConditioner)
4153
+ hvac_ap.num_speeds = 1
4154
+ elsif (hvac_system.is_a?(HPXML::CoolingSystem) && (hvac_system.cooling_system_type == HPXML::HVACTypeMiniSplitAirConditioner)) ||
4155
+ (hvac_system.is_a?(HPXML::HeatPump) && (hvac_system.heat_pump_type == HPXML::HVACTypeHeatPumpMiniSplit))
4156
+ hvac_ap.speed_indices = [1, 3, 5, 9] # Speeds we model
4157
+ hvac_ap.num_speeds = hvac_ap.speed_indices.size
4158
+ elsif hvac_system.compressor_type == HPXML::HVACCompressorTypeSingleStage
4159
+ hvac_ap.num_speeds = 1
4160
+ elsif hvac_system.compressor_type == HPXML::HVACCompressorTypeTwoStage
4161
+ hvac_ap.num_speeds = 2
4162
+ elsif hvac_system.compressor_type == HPXML::HVACCompressorTypeVariableSpeed
4163
+ hvac_ap.num_speeds = 4
4164
+ end
4165
+ end
4166
+
4167
+ def self.calc_rated_airflow(capacity, rated_cfm_per_ton, capacity_ratio)
4168
+ return UnitConversions.convert(capacity, 'Btu/hr', 'ton') * UnitConversions.convert(rated_cfm_per_ton, 'cfm', 'm^3/s') * capacity_ratio
4169
+ end
4170
+
4171
+ def self.is_central_air_conditioner_and_furnace(hpxml, heating_system, cooling_system)
4172
+ if not (hpxml.heating_systems.include?(heating_system) && (heating_system.heating_system_type == HPXML::HVACTypeFurnace))
4173
+ return false
4174
+ end
4175
+ if not (hpxml.cooling_systems.include?(cooling_system) && (cooling_system.cooling_system_type == HPXML::HVACTypeCentralAirConditioner))
4176
+ return false
4177
+ end
4178
+
4179
+ return true
4180
+ end
4181
+
4182
+ def self.get_hpxml_hvac_systems(hpxml)
4183
+ # Returns a list of heating/cooling systems, incorporating whether
4184
+ # multiple systems are connected to the same distribution system
4185
+ # (e.g., a furnace + central air conditioner w/ the same ducts).
4186
+ hvac_systems = []
4187
+
4188
+ hpxml.cooling_systems.each do |cooling_system|
4189
+ heating_system = nil
4190
+ if is_central_air_conditioner_and_furnace(hpxml, cooling_system.attached_heating_system, cooling_system)
4191
+ heating_system = cooling_system.attached_heating_system
4192
+ end
4193
+ hvac_systems << { cooling: cooling_system,
4194
+ heating: heating_system }
4195
+ end
4196
+
4197
+ hpxml.heating_systems.each do |heating_system|
4198
+ if is_central_air_conditioner_and_furnace(hpxml, heating_system, heating_system.attached_cooling_system)
4199
+ next # Already processed combined AC+furnace
4200
+ end
4201
+ hvac_systems << { cooling: nil,
4202
+ heating: heating_system }
4203
+ end
4204
+
4205
+ hpxml.heat_pumps.each do |heat_pump|
4206
+ hvac_systems << { cooling: heat_pump,
4207
+ heating: heat_pump }
4208
+ end
4209
+
4210
+ return hvac_systems
4211
+ end
4212
+
4213
+ def self.ensure_nonzero_sizing_values(hpxml)
4214
+ min_capacity = 1.0 # Btuh
4215
+ min_airflow = 3.0 # cfm; E+ min airflow is 0.001 m3/s
4216
+ hpxml.heating_systems.each do |htg_sys|
4217
+ htg_sys.heating_capacity = [htg_sys.heating_capacity, min_capacity].max
4218
+ htg_sys.heating_airflow_cfm = [htg_sys.heating_airflow_cfm, min_airflow].max
4219
+ end
4220
+ hpxml.cooling_systems.each do |clg_sys|
4221
+ clg_sys.cooling_capacity = [clg_sys.cooling_capacity, min_capacity].max
4222
+ clg_sys.cooling_airflow_cfm = [clg_sys.cooling_airflow_cfm, min_airflow].max
4223
+ end
4224
+ hpxml.heat_pumps.each do |hp_sys|
4225
+ hp_sys.cooling_capacity = [hp_sys.cooling_capacity, min_capacity].max
4226
+ hp_sys.cooling_airflow_cfm = [hp_sys.cooling_airflow_cfm, min_airflow].max
4227
+ hp_sys.additional_properties.cooling_capacity_sensible = [hp_sys.additional_properties.cooling_capacity_sensible, min_capacity].max
4228
+ hp_sys.heating_capacity = [hp_sys.heating_capacity, min_capacity].max
4229
+ hp_sys.heating_airflow_cfm = [hp_sys.heating_airflow_cfm, min_airflow].max
4230
+ if not hp_sys.heating_capacity_17F.nil?
4231
+ hp_sys.heating_capacity_17F = [hp_sys.heating_capacity_17F, min_capacity].max
4232
+ end
4233
+ if not hp_sys.backup_heating_capacity.nil?
4234
+ hp_sys.backup_heating_capacity = [hp_sys.backup_heating_capacity, min_capacity].max
4235
+ end
4236
+ end
4237
+ end
4238
+
4239
+ def self.get_dehumidifier_default_values(capacity)
4240
+ rh_setpoint = 0.6
4241
+ if capacity <= 25.0
4242
+ ief = 0.79
4243
+ elsif capacity <= 35.0
4244
+ ief = 0.95
4245
+ elsif capacity <= 54.0
4246
+ ief = 1.04
4247
+ elsif capacity < 75.0
4248
+ ief = 1.20
4249
+ else
4250
+ ief = 1.82
4251
+ end
4252
+
4253
+ return { rh_setpoint: rh_setpoint, ief: ief }
4191
4254
  end
4192
4255
  end