urbanopt-cli 0.5.1 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
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