openstudio-standards 0.2.16.rc2 → 0.2.17.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (189) hide show
  1. checksums.yaml +4 -4
  2. data/data/geometry/ASHRAECollege.osm +117 -117
  3. data/data/standards/manage_OpenStudio_Standards.rb +31 -4
  4. data/data/standards/test_performance_expected_dd_results.csv +287 -287
  5. data/lib/openstudio-standards/btap/geometry.rb +1 -1
  6. data/lib/openstudio-standards/hvac_sizing/Siz.HeatingCoolingFuels.rb +354 -2
  7. data/lib/openstudio-standards/hvac_sizing/Siz.ThermalZone.rb +79 -0
  8. data/lib/openstudio-standards/prototypes/common/buildings/Prototype.College.rb +1 -1
  9. data/lib/openstudio-standards/prototypes/common/buildings/Prototype.Laboratory.rb +1 -1
  10. data/lib/openstudio-standards/prototypes/common/do_not_edit_metaclasses.rb +3376 -63
  11. data/lib/openstudio-standards/prototypes/common/objects/Prototype.Fan.rb +12 -0
  12. data/lib/openstudio-standards/prototypes/common/objects/Prototype.Model.rb +3 -4
  13. data/lib/openstudio-standards/prototypes/common/objects/Prototype.SizingSystem.rb +1 -1
  14. data/lib/openstudio-standards/prototypes/common/objects/Prototype.hvac_systems.rb +168 -93
  15. data/lib/openstudio-standards/prototypes/common/objects/Prototype.utilities.rb +2 -4
  16. data/lib/openstudio-standards/prototypes/common/prototype_metaprogramming.rb +2 -1
  17. data/lib/openstudio-standards/refs/references.rb +3 -0
  18. data/lib/openstudio-standards/standards/Standards.AirLoopHVAC.rb +279 -6
  19. data/lib/openstudio-standards/standards/Standards.AirTerminalSingleDuctParallelPIUReheat.rb +50 -2
  20. data/lib/openstudio-standards/standards/Standards.ChillerElectricEIR.rb +4 -0
  21. data/lib/openstudio-standards/standards/Standards.CoilCoolingWaterToAirHeatPumpEquationFit.rb +0 -1
  22. data/lib/openstudio-standards/standards/Standards.Construction.rb +185 -3
  23. data/lib/openstudio-standards/standards/Standards.Fan.rb +14 -6
  24. data/lib/openstudio-standards/standards/Standards.HeatExchangerSensLat.rb +1 -0
  25. data/lib/openstudio-standards/standards/Standards.Model.rb +1752 -384
  26. data/lib/openstudio-standards/standards/Standards.PlanarSurface.rb +130 -9
  27. data/lib/openstudio-standards/standards/Standards.PlantLoop.rb +50 -3
  28. data/lib/openstudio-standards/standards/Standards.ScheduleCompact.rb +44 -0
  29. data/lib/openstudio-standards/standards/Standards.ScheduleConstant.rb +27 -0
  30. data/lib/openstudio-standards/standards/Standards.ScheduleRuleset.rb +543 -0
  31. data/lib/openstudio-standards/standards/Standards.Space.rb +665 -15
  32. data/lib/openstudio-standards/standards/Standards.SpaceType.rb +141 -4
  33. data/lib/openstudio-standards/standards/Standards.SubSurface.rb +2 -1
  34. data/lib/openstudio-standards/standards/Standards.Surface.rb +117 -0
  35. data/lib/openstudio-standards/standards/Standards.ThermalZone.rb +197 -49
  36. data/lib/openstudio-standards/standards/Standards.ZoneHVACComponent.rb +41 -0
  37. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2004/ashrae_90_1_2004.Model.rb +6 -8
  38. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2004/comstock_ashrae_90_1_2004/data/ashrae_90_1.schedules.json +45 -45
  39. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2004/comstock_ashrae_90_1_2004/data/comstock_ashrae_90_1_2004.spc_typ.json +7 -7
  40. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2004/data/ashrae_90_1_2004.spc_typ.json +19 -19
  41. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2007/comstock_ashrae_90_1_2007/data/ashrae_90_1.schedules.json +45 -45
  42. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2007/comstock_ashrae_90_1_2007/data/comstock_ashrae_90_1_2007.spc_typ.json +7 -7
  43. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2007/data/ashrae_90_1_2007.spc_typ.json +5 -5
  44. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2010/comstock_ashrae_90_1_2010/data/ashrae_90_1.schedules.json +45 -45
  45. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2010/comstock_ashrae_90_1_2010/data/comstock_ashrae_90_1_2010.spc_typ.json +9 -9
  46. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2010/data/ashrae_90_1_2010.spc_typ.json +3 -3
  47. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/comstock_ashrae_90_1_2013/data/ashrae_90_1.schedules.json +45 -45
  48. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/comstock_ashrae_90_1_2013/data/comstock_ashrae_90_1_2013.spc_typ.json +4 -4
  49. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/data/ashrae_90_1_2013.spc_typ.json +6 -6
  50. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2016/comstock_ashrae_90_1_2016/data/ashrae_90_1.schedules.json +45 -45
  51. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2016/comstock_ashrae_90_1_2016/data/comstock_ashrae_90_1_2016.spc_typ.json +5 -5
  52. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2016/data/ashrae_90_1_2016.spc_typ.json +6 -6
  53. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.AirLoopHVAC.rb +5 -5
  54. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/comstock_ashrae_90_1_2019/data/ashrae_90_1.schedules.json +45 -45
  55. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/comstock_ashrae_90_1_2019/data/comstock_ashrae_90_1_2019.spc_typ.json +5 -5
  56. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/data/ashrae_90_1_2019.spc_typ.json +6 -6
  57. data/lib/openstudio-standards/standards/ashrae_90_1/data/ashrae_90_1.constructions.json +2 -2
  58. data/lib/openstudio-standards/standards/ashrae_90_1/data/ashrae_90_1.fans.json +12 -0
  59. data/lib/openstudio-standards/standards/ashrae_90_1/doe_ref_1980_2004/comstock_doe_ref_1980_2004/data/ashrae_90_1.schedules.json +45 -45
  60. data/lib/openstudio-standards/standards/ashrae_90_1/doe_ref_1980_2004/comstock_doe_ref_1980_2004/data/comstock_doe_ref_1980_2004.spc_typ.json +10 -10
  61. data/lib/openstudio-standards/standards/ashrae_90_1/doe_ref_pre_1980/comstock_doe_ref_pre_1980/data/ashrae_90_1.schedules.json +45 -45
  62. data/lib/openstudio-standards/standards/ashrae_90_1/doe_ref_pre_1980/comstock_doe_ref_pre_1980/data/comstock_doe_ref_pre_1980.spc_typ.json +10 -10
  63. data/lib/openstudio-standards/standards/ashrae_90_1/nrel_zne_ready_2017/nrel_zne_ready_2017.AirLoopHVAC.rb +1 -0
  64. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.AirLoopHVAC.rb +792 -0
  65. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.AirTerminalSingleDuctParallelPIUReheat.rb +10 -0
  66. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.AirTerminalSingleDuctVAVReheat.rb +31 -0
  67. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.BoilerHotWater.rb +91 -0
  68. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.ChillerElectricEIR.rb +84 -0
  69. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.CoilCoolingDXSingleSpeed.rb +145 -0
  70. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.CoilCoolingDXTwoSpeed.rb +106 -0
  71. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.CoilDX.rb +71 -0
  72. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.CoilHeatingDXSingleSpeed.rb +194 -0
  73. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.CoilHeatingGas.rb +120 -0
  74. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.CoolingTower.rb +110 -0
  75. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.CoolingTowerVariableSpeed.rb +5 -0
  76. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Fan.rb +73 -0
  77. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.FanConstantVolume.rb +5 -0
  78. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.FanOnOff.rb +5 -0
  79. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.FanVariableVolume.rb +24 -0
  80. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.FanZoneExhaust.rb +5 -0
  81. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.HeatExchangerSensLat.rb +55 -0
  82. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb +3045 -0
  83. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.PlanarSurface.rb +187 -0
  84. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.PlantLoop.rb +450 -0
  85. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Space.rb +106 -0
  86. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.SpaceType.rb +666 -0
  87. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Surface.rb +54 -0
  88. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.ThermalZone.rb +168 -0
  89. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.ZoneHVACComponent.rb +132 -0
  90. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb +239 -0
  91. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/ashrae_90_1_prm_2019.Model.rb +176 -0
  92. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/ashrae_90_1_prm_2019.rb +25 -0
  93. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.boilers.json +52 -0
  94. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.chillers.json +112 -0
  95. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.climate_zone_sets.json +210 -0
  96. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.construction_properties.json +10384 -0
  97. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.construction_sets.json +133 -0
  98. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.furnaces.json +43 -0
  99. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.heat_pumps.json +119 -0
  100. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.heat_pumps_heating.json +130 -0
  101. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.heat_rejection.json +13 -0
  102. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.lpd_space_type.json +568 -0
  103. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.motors.json +264 -0
  104. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.prm_baseline_hvac.json +439 -0
  105. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.prm_constructions.json +685 -0
  106. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.prm_economizers.json +213 -0
  107. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.prm_ext_ltg.json +32 -0
  108. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.prm_heat_type.json +136 -0
  109. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.prm_hvac_bldg_type.json +32 -0
  110. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.prm_interior_lighting.json +1837 -0
  111. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.prm_swh_bldg_type.json +184 -0
  112. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.prm_wwr_bldg_type.json +84 -0
  113. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.unitary_acs.json +148 -0
  114. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.water_heaters.json +157 -0
  115. data/lib/openstudio-standards/standards/ashrae_90_1_prm/data/ashrae_90_1_prm.climate_zone_sets.json +210 -0
  116. data/lib/openstudio-standards/standards/ashrae_90_1_prm/data/ashrae_90_1_prm.curves.json +18329 -0
  117. data/lib/openstudio-standards/standards/ashrae_90_1_prm/data/ashrae_90_1_prm.fans.json +340 -0
  118. data/lib/openstudio-standards/standards/ashrae_90_1_prm/data/ashrae_90_1_prm.materials.json +49924 -0
  119. data/lib/openstudio-standards/standards/ashrae_90_1_prm/docs/baseline_building_rotation_exception.md +44 -0
  120. data/lib/openstudio-standards/standards/ashrae_90_1_prm/docs/check_pump_power_and_control.md +71 -0
  121. data/lib/openstudio-standards/standards/ashrae_90_1_prm/docs/dcv.md +68 -0
  122. data/lib/openstudio-standards/standards/ashrae_90_1_prm/docs/dcv_implementation.png +0 -0
  123. data/lib/openstudio-standards/standards/ashrae_90_1_prm/docs/elevators.md +14 -0
  124. data/lib/openstudio-standards/standards/ashrae_90_1_prm/docs/exhaust_air_energy_recovery.md +36 -0
  125. data/lib/openstudio-standards/standards/ashrae_90_1_prm/docs/f_c_factors.md +19 -0
  126. data/lib/openstudio-standards/standards/ashrae_90_1_prm/docs/fan_power_credits.md +15 -0
  127. data/lib/openstudio-standards/standards/ashrae_90_1_prm/docs/preheat_coil.md +59 -0
  128. data/lib/openstudio-standards/standards/ashrae_90_1_prm/docs/pump_power_control.md +46 -0
  129. data/lib/openstudio-standards/standards/ashrae_90_1_prm/docs/return_air_type.md +31 -0
  130. data/lib/openstudio-standards/standards/ashrae_90_1_prm/docs/set_baseline_wwr.md +191 -0
  131. data/lib/openstudio-standards/standards/ashrae_90_1_prm/docs/set_hw_and_chw_supply_water_temp_reset_control.md +24 -0
  132. data/lib/openstudio-standards/standards/ashrae_90_1_prm/docs/set_num_boilers_chillers_towers.md +49 -0
  133. data/lib/openstudio-standards/standards/ashrae_90_1_prm/docs/set_plug_load_measures.md +80 -0
  134. data/lib/openstudio-standards/standards/ashrae_90_1_prm/docs/set_space_lpd.md +73 -0
  135. data/lib/openstudio-standards/standards/ashrae_90_1_prm/docs/unenclosed_and_unconditioned_spaces.md +11 -0
  136. data/lib/openstudio-standards/standards/ashrae_90_1_prm/docs/unmet_load_hours.md +20 -0
  137. data/lib/openstudio-standards/standards/ashrae_90_1_prm/docs/vav_parallel_piu_terminals_fan_control.md +23 -0
  138. data/lib/openstudio-standards/standards/ashrae_90_1_prm/docs/vav_terminals_min_flow_setpoint.md +21 -0
  139. data/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/userdata_airloop_hvac.csv +1 -0
  140. data/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/userdata_airloop_hvac_doas.csv +1 -0
  141. data/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/userdata_building.csv +1 -0
  142. data/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/userdata_design_specification_outdoor_air.csv +1 -0
  143. data/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/userdata_electric_equipment.csv +1 -0
  144. data/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/userdata_exterior_lights.csv +1 -0
  145. data/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/userdata_gas_equipment.csv +1 -0
  146. data/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/userdata_lights.csv +1 -0
  147. data/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/userdata_space.csv +1 -0
  148. data/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/userdata_spacetype.csv +1 -0
  149. data/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/userdata_thermal_zone.csv +1 -0
  150. data/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/userdata_wateruse_connections.csv +1 -0
  151. data/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/userdata_wateruse_equipment.csv +1 -0
  152. data/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/userdata_wateruse_equipment_definition.csv +1 -0
  153. data/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/userdata_zone_hvac.csv +1 -0
  154. data/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/userdata_zone_infiltration.csv +1 -0
  155. data/lib/openstudio-standards/standards/cbes/data/cbes.fans.json +12 -0
  156. data/lib/openstudio-standards/standards/deer/data/deer.fans.json +12 -0
  157. data/lib/openstudio-standards/standards/necb/ECMS/data/heat_pumps.json +1 -1
  158. data/lib/openstudio-standards/standards/necb/ECMS/data/heat_pumps_heating.json +1 -1
  159. data/lib/openstudio-standards/standards/necb/ECMS/data/unitary_acs.json +24 -11
  160. data/lib/openstudio-standards/standards/necb/ECMS/erv.rb +13 -15
  161. data/lib/openstudio-standards/standards/necb/NECB2011/data/province_map.json +17 -0
  162. data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_3_and_8_multi_speed.rb +1 -1
  163. data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_3_and_8_single_speed.rb +1 -1
  164. data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_4.rb +2 -2
  165. data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_6.rb +6 -5
  166. data/lib/openstudio-standards/standards/necb/NECB2011/hvac_systems.rb +3 -2
  167. data/lib/openstudio-standards/standards/necb/NECB2011/necb_2011.rb +2 -3
  168. data/lib/openstudio-standards/standards/necb/NECB2020/data/chillers.json +2 -2
  169. data/lib/openstudio-standards/standards/necb/NECB2020/data/space_types.json +33 -924
  170. data/lib/openstudio-standards/standards/necb/NECB2020/data/unitary_acs.json +15 -15
  171. data/lib/openstudio-standards/standards/necb/common/btap_data.rb +135 -29
  172. data/lib/openstudio-standards/standards/necb/common/btap_datapoint.rb +16 -4
  173. data/lib/openstudio-standards/standards/necb/common/neb_end_use_prices.csv +40 -42
  174. data/lib/openstudio-standards/standards/necb/common/necb_reference_runs.csv +1 -1
  175. data/lib/openstudio-standards/standards/necb/common/space_type_upgrade_map.json +89 -89
  176. data/lib/openstudio-standards/utilities/array.rb +11 -0
  177. data/lib/openstudio-standards/utilities/logging.rb +48 -0
  178. data/lib/openstudio-standards/utilities/object_info.rb +20 -0
  179. data/lib/openstudio-standards/utilities/schedule_translator.rb +348 -0
  180. data/lib/openstudio-standards/utilities/sqlfile.rb +68 -0
  181. data/lib/openstudio-standards/version.rb +2 -2
  182. data/lib/openstudio-standards/weather/Weather.Model.rb +42 -55
  183. data/lib/openstudio-standards/weather/Weather.stat_file.rb +1 -1
  184. data/lib/openstudio-standards.rb +35 -1
  185. metadata +111 -6
  186. data/data/standards/OpenStudio_Standards-ashrae_90_1.xlsx +0 -0
  187. data/data/standards/OpenStudio_Standards-ashrae_90_1_28Jan2022.xlsx +0 -0
  188. data/data/standards/OpenStudio_Standards-ashrae_90_1_28_Jan2022_2.xlsx +0 -0
  189. data/data/standards/openstudio_standards_duplicates_log.csv +0 -143
@@ -0,0 +1,792 @@
1
+ class ASHRAE901PRM < Standard
2
+ # @!group AirLoopHVAC
3
+
4
+ # Shut off the system during unoccupied periods.
5
+ # During these times, systems will cycle on briefly if temperature drifts below setpoint.
6
+ # If the system already has a schedule other than Always-On, no change will be made.
7
+ # If the system has an Always-On schedule assigned, a new schedule will be created.
8
+ # In this case, occupied is defined as the total percent occupancy for the loop for all zones served.
9
+ # For stable baseline, schedule is Always-On for computer rooms and when health and safety exception is used
10
+ #
11
+ # @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
12
+ # @param min_occ_pct [Double] the fractional value below which the system will be considered unoccupied.
13
+ # @return [Bool] returns true if successful, false if not
14
+ def air_loop_hvac_enable_unoccupied_fan_shutoff(air_loop_hvac, min_occ_pct = 0.05)
15
+ if air_loop_hvac.additionalProperties.hasFeature('zone_group_type')
16
+ zone_group_type = air_loop_hvac.additionalProperties.getFeatureAsString('zone_group_type').get
17
+ else
18
+ zone_group_type = 'None'
19
+ end
20
+
21
+ if zone_group_type == 'computer_zones'
22
+ # Computer rooms are exempt from night cycle control
23
+ return false
24
+ end
25
+
26
+ # Check for user data exceptions for night cycling
27
+ # If any zone has the exception, then system will not cycle
28
+ health_safety_exception = false
29
+ air_loop_hvac.thermalZones.each do |thermal_zone|
30
+ if thermal_zone.additionalProperties.hasFeature('has_health_safety_night_cycle_exception')
31
+ exception = thermal_zone.additionalProperties.getFeatureAsBoolean('has_health_safety_night_cycle_exception').get
32
+ return false if exception == true
33
+ end
34
+ end
35
+
36
+ # Set the system to night cycle
37
+ # The fan of a parallel PIU terminal are set to only cycle during heating operation
38
+ # This is achieved using the CycleOnAnyCoolingOrHeatingZone; During cooling operation
39
+ # the load is met by running the central system which stays off during heating
40
+ # operation
41
+ air_loop_hvac.setNightCycleControlType('CycleOnAny')
42
+ if air_loop_hvac_has_parallel_piu_air_terminals?(air_loop_hvac)
43
+ avail_mgrs = air_loop_hvac.availabilityManagers
44
+ if !avail_mgrs.nil?
45
+ avail_mgrs.each do |avail_mgr|
46
+ if avail_mgr.to_AvailabilityManagerNightCycle.is_initialized
47
+ avail_mgr_nc = avail_mgr.to_AvailabilityManagerNightCycle.get
48
+ avail_mgr_nc.setControlType('CycleOnAnyCoolingOrHeatingZone')
49
+ zones = air_loop_hvac.thermalZones
50
+ avail_mgr_nc.setCoolingControlThermalZones(zones)
51
+ avail_mgr_nc.setHeatingZoneFansOnlyThermalZones(zones)
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ model = air_loop_hvac.model
58
+ # Check if schedule was stored in an additionalProperties field of the air loop
59
+ air_loop_name = air_loop_hvac.name
60
+ if air_loop_hvac.hasAdditionalProperties
61
+ if air_loop_hvac.additionalProperties.hasFeature('fan_sched_name')
62
+ fan_sched_name = air_loop_hvac.additionalProperties.getFeatureAsString('fan_sched_name').get
63
+ fan_sched = model.getScheduleRulesetByName(fan_sched_name).get
64
+ air_loop_hvac.setAvailabilitySchedule(fan_sched)
65
+ return true
66
+ end
67
+ end
68
+
69
+ # Check if already using a schedule other than always on
70
+ avail_sch = air_loop_hvac.availabilitySchedule
71
+ unless avail_sch == air_loop_hvac.model.alwaysOnDiscreteSchedule
72
+ OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "For #{air_loop_hvac.name}: Availability schedule is already set to #{avail_sch.name}. Will assume this includes unoccupied shut down; no changes will be made.")
73
+ return true
74
+ end
75
+
76
+ # Get the airloop occupancy schedule
77
+ loop_occ_sch = air_loop_hvac_get_occupancy_schedule(air_loop_hvac, occupied_percentage_threshold: min_occ_pct)
78
+ flh = schedule_ruleset_annual_equivalent_full_load_hrs(loop_occ_sch)
79
+ OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "For #{air_loop_hvac.name}: Annual occupied hours = #{flh.round} hr/yr, assuming a #{min_occ_pct} occupancy threshold. This schedule will be used as the HVAC operation schedule.")
80
+
81
+ # Set HVAC availability schedule to follow occupancy
82
+ air_loop_hvac.setAvailabilitySchedule(loop_occ_sch)
83
+ air_loop_hvac.supplyComponents.each do |comp|
84
+ if comp.to_AirLoopHVACUnitaryHeatPumpAirToAirMultiSpeed.is_initialized
85
+ comp.to_AirLoopHVACUnitaryHeatPumpAirToAirMultiSpeed.get.setSupplyAirFanOperatingModeSchedule(loop_occ_sch)
86
+ elsif comp.to_AirLoopHVACUnitarySystem.is_initialized
87
+ comp.to_AirLoopHVACUnitarySystem.get.setSupplyAirFanOperatingModeSchedule(loop_occ_sch)
88
+ end
89
+ end
90
+
91
+ return true
92
+ end
93
+
94
+ # Determine if the system is a multizone VAV system
95
+ #
96
+ # @return [Bool] Returns true if required, false if not.
97
+ def air_loop_hvac_multizone_vav_system?(air_loop_hvac)
98
+ return true if air_loop_hvac.name.to_s.include?('Sys5') || air_loop_hvac.name.to_s.include?('Sys6') || air_loop_hvac.name.to_s.include?('Sys7') || air_loop_hvac.name.to_s.include?('Sys8')
99
+
100
+ return false
101
+ end
102
+
103
+ # Determine if multizone vav optimization is required.
104
+ # Not required for stable baseline.
105
+ #
106
+ # @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
107
+ # @param climate_zone [String] ASHRAE climate zone, e.g. 'ASHRAE 169-2013-4A'
108
+ # @return [Bool] returns true if required, false if not
109
+ def air_loop_hvac_multizone_vav_optimization_required?(air_loop_hvac, climate_zone)
110
+ multizone_opt_required = false
111
+ return multizone_opt_required
112
+ end
113
+
114
+ # Determine whether the VAV damper control is single maximum or dual maximum control.
115
+ # Defaults to Single Maximum for stable baseline.
116
+ #
117
+ # @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
118
+ # @return [String] the damper control type: Single Maximum, Dual Maximum
119
+ def air_loop_hvac_vav_damper_action(air_loop_hvac)
120
+ damper_action = 'Single Maximum'
121
+ return damper_action
122
+ end
123
+
124
+ # Default occupancy fraction threshold for determining if the spaces on the air loop are occupied
125
+ def air_loop_hvac_unoccupied_threshold
126
+ # Use 10% based on PRM-RM
127
+ return 0.10
128
+ end
129
+
130
+ # Determine if the system economizer must be integrated or not.
131
+ # Always required for stable baseline if there is an economizer
132
+ #
133
+ # @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
134
+ # @param climate_zone [String] ASHRAE climate zone, e.g. 'ASHRAE 169-2013-4A'
135
+ # @return [Bool] returns true if required, false if not
136
+ def air_loop_hvac_integrated_economizer_required?(air_loop_hvac, climate_zone)
137
+ return true
138
+ end
139
+
140
+ # Determine the economizer type and limits for the the PRM
141
+ # Defaults to 90.1-2007 logic.
142
+ #
143
+ # @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
144
+ # @param climate_zone [String] ASHRAE climate zone, e.g. 'ASHRAE 169-2013-4A'
145
+ # @return [Array<Double>] [economizer_type, drybulb_limit_f, enthalpy_limit_btu_per_lb, dewpoint_limit_f]
146
+ def air_loop_hvac_prm_economizer_type_and_limits(air_loop_hvac, climate_zone)
147
+ economizer_type = 'NoEconomizer'
148
+ drybulb_limit_f = nil
149
+ enthalpy_limit_btu_per_lb = nil
150
+ dewpoint_limit_f = nil
151
+ climate_zone_code = climate_zone.split('-')[-1]
152
+
153
+ if ['0B', '1B', '2B', '3B', '3C', '4B', '4C', '5B', '5C', '6B', '7A', '7B', '8A', '8B'].include? climate_zone_code
154
+ economizer_type = 'FixedDryBulb'
155
+ drybulb_limit_f = 75
156
+ elsif ['5A', '6A'].include? climate_zone_code
157
+ economizer_type = 'FixedDryBulb'
158
+ drybulb_limit_f = 70
159
+ end
160
+
161
+ return [economizer_type, drybulb_limit_f, enthalpy_limit_btu_per_lb, dewpoint_limit_f]
162
+ end
163
+
164
+ # Determine if an economizer is required per the PRM.
165
+ #
166
+ # @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
167
+ # @param climate_zone [String] ASHRAE climate zone, e.g. 'ASHRAE 169-2013-4A'
168
+ # @return [Bool] returns true if required, false if not
169
+ def air_loop_hvac_prm_baseline_economizer_required?(air_loop_hvac, climate_zone)
170
+ economizer_required = false
171
+ baseline_system_type = air_loop_hvac.additionalProperties.getFeatureAsString('baseline_system_type').get
172
+ climate_zone_code = climate_zone.split('-')[-1]
173
+ # System type 3 through 8 and 11, 12 and 13
174
+ if ['SZ_AC', 'PSZ_AC', 'PVAV_Reheat', 'VAV_Reheat', 'SZ_VAV', 'PSZ_HP', 'SZ_CV', 'PSZ_HP', 'PVAV_PFP_Boxes', 'VAV_PFP_Boxes'].include? baseline_system_type
175
+ unless ['0A', '0B', '1A', '1B', '2A', '3A', '4A'].include? climate_zone_code
176
+ economizer_required = true
177
+ end
178
+ end
179
+
180
+ # System type 3 and 4 in computer rooms are subject to exceptions
181
+ if baseline_system_type == 'PSZ_AC' || baseline_system_type == 'PSZ_HP'
182
+ if air_loop_hvac.additionalProperties.hasFeature('zone_group_type')
183
+ if air_loop_hvac.additionalProperties.getFeatureAsString('zone_group_type').get == 'computer_zones'
184
+ economizer_required = false
185
+ end
186
+ end
187
+ end
188
+
189
+ # Check user_data in the zones
190
+ gas_phase_exception = false
191
+ open_refrigeration_exception = false
192
+ air_loop_hvac.thermalZones.each do |thermal_zone|
193
+ if thermal_zone.additionalProperties.hasFeature('economizer_exception_for_gas_phase_air_cleaning')
194
+ gas_phase_exception = true
195
+ end
196
+ if thermal_zone.additionalProperties.hasFeature('economizer_exception_for_open_refrigerated_cases')
197
+ open_refrigeration_exception = true
198
+ end
199
+ end
200
+ if gas_phase_exception || open_refrigeration_exception
201
+ economizer_required = false
202
+ end
203
+ return economizer_required
204
+ end
205
+
206
+ # Set fan curve for stable baseline to be VSD with fixed static pressure setpoint
207
+ # @return [string] name of appropriate curve for this code version
208
+ def air_loop_hvac_set_vsd_curve_type
209
+ return 'Multi Zone VAV with VSD and Fixed SP Setpoint'
210
+ end
211
+
212
+ # Calculate and apply the performance rating method
213
+ # baseline fan power to this air loop based on the
214
+ # system type that it represents.
215
+ #
216
+ # Fan motor efficiency will be set, and then
217
+ # fan pressure rise adjusted so that the
218
+ # fan power is the maximum allowable.
219
+ #
220
+ # Also adjusts the fan power and flow rates
221
+ # of any parallel PIU terminals on the system.
222
+ #
223
+ # return [Bool] true if successful, false if not.
224
+ def air_loop_hvac_apply_prm_baseline_fan_power(air_loop_hvac)
225
+ # Get system type associated with air loop
226
+ system_type = air_loop_hvac.additionalProperties.getFeatureAsString('baseline_system_type').get
227
+
228
+ # Find out if air loop represents a non mechanically cooled system
229
+ is_nmc = false
230
+ is_nmc = true if air_loop_hvac.additionalProperties.hasFeature('non_mechanically_cooled')
231
+
232
+ # Get all air loop fans
233
+ all_fans = air_loop_hvac_supply_return_exhaust_relief_fans(air_loop_hvac)
234
+
235
+ allowable_fan_bhp = 0.0
236
+ allowable_power_w = 0.0
237
+ fan_efficacy_w_per_cfm = 0.0
238
+ supply_fan_power_fraction = 0.0
239
+ return_fan_power_fraction = 0.0
240
+ relief_fan_power_fraction = 0.0
241
+ if system_type == 'PSZ_AC' ||
242
+ system_type == 'PSZ_HP' ||
243
+ system_type == 'PVAV_Reheat' ||
244
+ system_type == 'PVAV_PFP_Boxes' ||
245
+ system_type == 'VAV_Reheat' ||
246
+ system_type == 'VAV_PFP_Boxes' ||
247
+ system_type == 'SZ_VAV' ||
248
+ system_type == 'SZ_CV'
249
+
250
+ # Calculate the allowable fan motor bhp for the air loop
251
+ allowable_fan_bhp = air_loop_hvac_allowable_system_brake_horsepower(air_loop_hvac)
252
+
253
+ # Divide the allowable power based
254
+ # individual zone air flow
255
+ air_loop_total_zone_design_airflow = 0
256
+ air_loop_hvac.thermalZones.sort.each do |zone|
257
+ zone_air_flow = zone.designAirFlowRate.to_f
258
+ air_loop_total_zone_design_airflow += zone_air_flow
259
+ # Fractions variables are actually power at that point
260
+ supply_fan_power_fraction += zone_air_flow * zone.additionalProperties.getFeatureAsDouble('supply_fan_w').get
261
+ return_fan_power_fraction += zone_air_flow * zone.additionalProperties.getFeatureAsDouble('return_fan_w').get
262
+ relief_fan_power_fraction += zone_air_flow * zone.additionalProperties.getFeatureAsDouble('relief_fan_w').get
263
+ end
264
+ if air_loop_total_zone_design_airflow > 0
265
+ # Get average power for each category of fan
266
+ supply_fan_power_fraction /= air_loop_total_zone_design_airflow
267
+ return_fan_power_fraction /= air_loop_total_zone_design_airflow
268
+ relief_fan_power_fraction /= air_loop_total_zone_design_airflow
269
+ # Convert to power fraction
270
+ total_fan_avg_fan_w = (supply_fan_power_fraction + return_fan_power_fraction + relief_fan_power_fraction)
271
+ supply_fan_power_fraction /= total_fan_avg_fan_w
272
+ return_fan_power_fraction /= total_fan_avg_fan_w
273
+ relief_fan_power_fraction /= total_fan_avg_fan_w
274
+ else
275
+ Openstudio.logFree(OpenStudio::Error, "Total zone design airflow for #{air_loop_hvac.name} is 0.")
276
+ end
277
+ elsif system_type == 'PTAC' ||
278
+ system_type == 'PTHP' ||
279
+ system_type == 'Gas_Furnace' ||
280
+ system_type == 'Electric_Furnace'
281
+
282
+ # Determine allowable fan power
283
+ if !is_nmc
284
+ fan_efficacy_w_per_cfm = 0.3
285
+ else # is_nmc
286
+ fan_efficacy_w_per_cfm = 0.054
287
+ end
288
+
289
+ # Configuration is supply fan only
290
+ supply_fan_power_fraction = 1.0
291
+ end
292
+
293
+ supply_fan = air_loop_hvac_get_supply_fan(air_loop_hvac)
294
+ if supply_fan.nil?
295
+ OpenStudio.logFree(OpenStudio::Error, 'openstudio.ashrae_90_1_prm.AirLoopHVAC', "Supply not found on #{airloop.name}.")
296
+ end
297
+ supply_fan_max_flow = if supply_fan.autosizedMaximumFlowRate.is_initialized
298
+ supply_fan.autosizedMaximumFlowRate.get
299
+ else
300
+ supply_fan.maximumFlowRate.get
301
+ end
302
+
303
+ # Check that baseline system has the same
304
+ # types of fans as the proposed model, if
305
+ # not, create them. We assume that the
306
+ # system has at least a supply fan.
307
+ if return_fan_power_fraction > 0.0 && !air_loop_hvac.returnFan.is_initialized
308
+ # Create return fan
309
+ return_fan = supply_fan.clone(air_loop_hvac.model)
310
+ if return_fan.to_FanConstantVolume.is_initialized
311
+ return_fan = return_fan.to_FanConstantVolume.get
312
+ elsif return_fan.to_FanVariableVolume.is_initialized
313
+ return_fan = return_fan.to_FanVariableVolume.get
314
+ elsif return_fan.to_FanOnOff.is_initialized
315
+ return_fan = return_fan.to_FanOnOff.get
316
+ elsif return_fan.to_FanSystemModel.is_initialized
317
+ return_fan = return_fan.to_FanSystemModel.get
318
+ end
319
+ return_fan.setName("#{air_loop_hvac.name} Return Fan")
320
+ return_fan.addToNode(air_loop_hvac.returnAirNode.get)
321
+ return_fan.setMaximumFlowRate(supply_fan_max_flow)
322
+ end
323
+ if relief_fan_power_fraction > 0.0 && !air_loop_hvac.reliefFan.is_initialized
324
+ # Create return fan
325
+ relief_fan = supply_fan.clone(air_loop_hvac.model)
326
+ if relief_fan.to_FanConstantVolume.is_initialized
327
+ relief_fan = relief_fan.to_FanConstantVolume.get
328
+ elsif relief_fan.to_FanVariableVolume.is_initialized
329
+ relief_fan = relief_fan.to_FanVariableVolume.get
330
+ elsif relief_fan.to_FanOnOff.is_initialized
331
+ relief_fan = relief_fan.to_FanOnOff.get
332
+ elsif relief_fan.to_FanSystemModel.is_initialized
333
+ relief_fan = relief_fan.to_FanSystemModel.get
334
+ end
335
+ relief_fan.setName("#{air_loop_hvac.name} Relief Fan")
336
+ relief_fan.addToNode(air_loop_hvac.reliefAirNode.get)
337
+ relief_fan.setMaximumFlowRate(supply_fan_max_flow)
338
+ end
339
+
340
+ # Get all air loop fans
341
+ all_fans = air_loop_hvac_supply_return_exhaust_relief_fans(air_loop_hvac)
342
+
343
+ # Set the motor efficiencies
344
+ # for all fans based on the calculated
345
+ # allowed brake hp. Then calculate the allowable
346
+ # fan power for each fan and adjust
347
+ # the fan pressure rise accordingly
348
+ all_fans.each do |fan|
349
+ # Efficacy requirement
350
+ if fan_efficacy_w_per_cfm > 0
351
+ # Convert efficacy to metric
352
+ fan_efficacy_w_per_m3_per_s = OpenStudio.convert(fan_efficacy_w_per_cfm, 'm^3/s', 'cfm').get
353
+ fan_change_impeller_efficiency(fan, fan_baseline_impeller_efficiency(fan))
354
+
355
+ # Get fan BHP
356
+ fan_bhp = fan_brake_horsepower(fan)
357
+
358
+ # Set the motor efficiency, preserving the impeller efficiency.
359
+ # For zone HVAC fans, a bhp lookup of 0.5bhp is always used because
360
+ # they are assumed to represent a series of small fans in reality.
361
+ fan_apply_standard_minimum_motor_efficiency(fan, fan_bhp)
362
+
363
+ # Calculate a new pressure rise to hit the target W/cfm
364
+ fan_tot_eff = fan.fanEfficiency
365
+ fan_rise_new_pa = fan_efficacy_w_per_m3_per_s * fan_tot_eff
366
+ fan.setPressureRise(fan_rise_new_pa)
367
+ end
368
+
369
+ # BHP requirements
370
+ if allowable_fan_bhp > 0
371
+ fan_apply_standard_minimum_motor_efficiency(fan, allowable_fan_bhp)
372
+ allowable_power_w = allowable_fan_bhp * 746 / fan.motorEfficiency
373
+
374
+ # Breakdown fan power based on fan type
375
+ if supply_fan.name.to_s == fan.name.to_s
376
+ allowable_power_w *= supply_fan_power_fraction
377
+ elsif fan.airLoopHVAC.is_initialized
378
+ if fan.airLoopHVAC.get.returnFan.is_initialized
379
+ if fan.airLoopHVAC.get.returnFan.get.name.to_s == fan.name.to_s
380
+ allowable_power_w *= return_fan_power_fraction
381
+ end
382
+ end
383
+ if fan.airLoopHVAC.get.reliefFan.is_initialized
384
+ if fan.airLoopHVAC.get.reliefFan.get.name.to_s == fan.name.to_s
385
+ allowable_power_w *= relief_fan_power_fraction
386
+ end
387
+ end
388
+ end
389
+ fan_adjust_pressure_rise_to_meet_fan_power(fan, allowable_power_w)
390
+ end
391
+ end
392
+
393
+ return true unless system_type == 'PVAV_PFP_Boxes' || system_type == 'VAV_PFP_Boxes'
394
+
395
+ # Adjust fan powered terminal fans power
396
+ air_loop_hvac.demandComponents.each do |dc|
397
+ next if dc.to_AirTerminalSingleDuctParallelPIUReheat.empty?
398
+
399
+ pfp_term = dc.to_AirTerminalSingleDuctParallelPIUReheat.get
400
+ air_terminal_single_duct_parallel_piu_reheat_apply_prm_baseline_fan_power(pfp_term)
401
+ end
402
+
403
+ return true
404
+ end
405
+
406
+ # Determine the allowable fan system brake horsepower
407
+ # Per Section G3.1.2.9
408
+ #
409
+ # @return [Double] allowable fan system brake horsepower
410
+ # units = horsepower
411
+ def air_loop_hvac_allowable_system_brake_horsepower(air_loop_hvac)
412
+ # Get design supply air flow rate (whether autosized or hard-sized)
413
+ dsn_air_flow_m3_per_s = 0
414
+ dsn_air_flow_cfm = 0
415
+ if air_loop_hvac.autosizedDesignSupplyAirFlowRate.is_initialized
416
+ dsn_air_flow_m3_per_s = air_loop_hvac.autosizedDesignSupplyAirFlowRate.get
417
+ dsn_air_flow_cfm = OpenStudio.convert(dsn_air_flow_m3_per_s, 'm^3/s', 'cfm').get
418
+ OpenStudio.logFree(OpenStudio::Debug, 'openstudio.ashrae_90_1_prm.AirLoopHVAC', "* #{dsn_air_flow_cfm.round} cfm = Autosized Design Supply Air Flow Rate.")
419
+ else
420
+ dsn_air_flow_m3_per_s = air_loop_hvac.designSupplyAirFlowRate.get
421
+ dsn_air_flow_cfm = OpenStudio.convert(dsn_air_flow_m3_per_s, 'm^3/s', 'cfm').get
422
+ OpenStudio.logFree(OpenStudio::Debug, 'openstudio.ashrae_90_1_prm.AirLoopHVAC', "* #{dsn_air_flow_cfm.round} cfm = Hard sized Design Supply Air Flow Rate.")
423
+ end
424
+
425
+ # Get the fan limitation pressure drop adjustment bhp
426
+ fan_pwr_adjustment_bhp = air_loop_hvac_fan_power_limitation_pressure_drop_adjustment_brake_horsepower(air_loop_hvac)
427
+
428
+ # Get system type associated with air loop
429
+ system_type = air_loop_hvac.additionalProperties.getFeatureAsString('baseline_system_type').get
430
+
431
+ # Calculate the Allowable Fan System brake horsepower per Table G3.1.2.9
432
+ allowable_fan_bhp = 0.0
433
+ case system_type
434
+ when 'PSZ_HP', 'PSZ_AC' # 3, 4
435
+ allowable_fan_bhp = dsn_air_flow_cfm * 0.00094 + fan_pwr_adjustment_bhp
436
+ when
437
+ 'PVAV_Reheat', 'PVAV_PFP_Boxes', # 5, 6
438
+ 'VAV_Reheat', 'VAV_PFP_Boxes', # 7, 8
439
+ 'SZ_VAV' # 11
440
+ allowable_fan_bhp = dsn_air_flow_cfm * 0.0013 + fan_pwr_adjustment_bhp
441
+ when
442
+ 'SZ_CV' # 12, 13
443
+ allowable_fan_bhp = dsn_air_flow_cfm * 0.00094 + fan_pwr_adjustment_bhp
444
+ else
445
+ OpenStudio.logFree(OpenStudio::Error, 'openstudio.ashrae_90_1_prm.AirLoopHVAC', "Air loop #{air_loop_hvac.name} is not associated with a baseline system.")
446
+ end
447
+
448
+ return allowable_fan_bhp
449
+ end
450
+
451
+ # Check if an air loop in user model needs to have DCV per air loop related requiremends in ASHRAE 90.1-2019 6.4.3.8
452
+ #
453
+ # @author Xuechen (Jerry) Lei, PNNL
454
+ # @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
455
+ # @return [Boolean] flag of whether air loop in user model is required to have DCV
456
+ def user_model_air_loop_hvac_demand_control_ventilation_required?(air_loop_hvac)
457
+ # all zones in the same airloop in user model are set with the same value, so use the first zone under the loop
458
+ dcv_airloop_user_exception = air_loop_hvac.thermalZones[0].additionalProperties.getFeatureAsBoolean('airloop user specified DCV exception').get
459
+ return false if dcv_airloop_user_exception
460
+
461
+ # check the following conditions at airloop level
462
+ # has air economizer OR design outdoor airflow > 3000 cfm
463
+
464
+ has_economizer = air_loop_hvac_economizer?(air_loop_hvac)
465
+
466
+ if air_loop_hvac.airLoopHVACOutdoorAirSystem.is_initialized
467
+ oa_flow_m3_per_s = get_airloop_hvac_design_oa_from_sql(air_loop_hvac)
468
+ else
469
+ OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "For #{air_loop_hvac.name}, DCV not applicable because it has no OA intake.")
470
+ return false
471
+ end
472
+ oa_flow_cfm = OpenStudio.convert(oa_flow_m3_per_s, 'm^3/s', 'cfm').get
473
+
474
+ any_zones_req_dcv = false
475
+ air_loop_hvac.thermalZones.sort.each do |zone|
476
+ if user_model_zone_demand_control_ventilation_required?(zone)
477
+ any_zones_req_dcv = true
478
+ break
479
+ end
480
+ end
481
+
482
+ return true if any_zones_req_dcv && (has_economizer || (oa_flow_cfm > 3000))
483
+
484
+ return false
485
+ end
486
+
487
+ # Check if a zone in user model needs to have DCV per zone related requiremends in ASHRAE 90.1-2019 6.4.3.8
488
+ # @author Xuechen (Jerry) Lei, PNNL
489
+ # @param thermal_zone [OpenStudio::Model::ThermalZone] the thermal zone
490
+ # @return [Boolean] flag of whether thermal zone in user model is required to have DCV
491
+ def user_model_zone_demand_control_ventilation_required?(thermal_zone)
492
+ dcv_zone_user_exception = thermal_zone.additionalProperties.getFeatureAsBoolean('zone user specified DCV exception').get
493
+ return false if dcv_zone_user_exception
494
+
495
+ # check the following conditions at zone level
496
+ # zone > 500 sqft AND design occ > 25 ppl/ksqft
497
+
498
+ area_served_m2 = 0
499
+ num_people = 0
500
+ thermal_zone.spaces.each do |space|
501
+ area_served_m2 += space.floorArea
502
+ num_people += space.numberOfPeople
503
+ end
504
+ area_served_ft2 = OpenStudio.convert(area_served_m2, 'm^2', 'ft^2').get
505
+ occ_per_1000_ft2 = num_people / area_served_ft2 * 1000
506
+
507
+ return true if (area_served_ft2 > 500) && (occ_per_1000_ft2 > 25)
508
+
509
+ return false
510
+ end
511
+
512
+ # Check if the air loop in baseline model needs to have DCV
513
+ #
514
+ # @author Xuechen (Jerry) Lei, PNNL
515
+ # @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
516
+ # @return [Boolean] flag of whether the air loop in baseline is required to have DCV
517
+ def baseline_air_loop_hvac_demand_control_ventilation_required?(air_loop_hvac)
518
+ any_zone_req_dcv = false
519
+ air_loop_hvac.thermalZones.each do |zone|
520
+ if baseline_thermal_zone_demand_control_ventilation_required?(zone)
521
+ any_zone_req_dcv = true
522
+ end
523
+ end
524
+ return any_zone_req_dcv # baseline airloop needs dcv if any zone it serves needs dcv
525
+ end
526
+
527
+ # Check if the thermal zone in baseline model needs to have DCV
528
+ #
529
+ # @author Xuechen (Jerry) Lei, PNNL
530
+ # @param thermal_zone [OpenStudio::Model::ThermalZone] the thermal zone
531
+ # @return [Boolean] flag of whether thermal zone in baseline is required to have DCV
532
+ def baseline_thermal_zone_demand_control_ventilation_required?(thermal_zone)
533
+ # zone needs dcv if user model has dcv and baseline does not meet apxg exception
534
+ if thermal_zone.additionalProperties.hasFeature('apxg no need to have DCV')
535
+ # meaning it was served by an airloop in the user model, does not mean much here, conditional as a safeguard
536
+ # in case it was not served by an airloop in the user model
537
+ if !thermal_zone.additionalProperties.getFeatureAsBoolean('apxg no need to have DCV').get && # does not meet apxg exception (need to have dcv if user model has it
538
+ thermal_zone.additionalProperties.getFeatureAsBoolean('zone DCV implemented in user model').get
539
+ return true
540
+ end
541
+ end
542
+ return false
543
+ end
544
+
545
+ # Get the air loop HVAC design outdoor air flow rate by reading Standard 62.1 Summary from the sizing sql
546
+ # @author Xuechen (Jerry) Lei, PNNL
547
+ # @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
548
+ # @return [Float] Design outdoor air flow rate (m^3/s)
549
+ def get_airloop_hvac_design_oa_from_sql(air_loop_hvac)
550
+ return false unless air_loop_hvac.airLoopHVACOutdoorAirSystem.is_initialized
551
+
552
+ cooling_oa = air_loop_hvac.model.sqlFile.get.execAndReturnFirstDouble(
553
+ "SELECT Value FROM TabularDataWithStrings WHERE ReportName='Standard62.1Summary' AND ReportForString='Entire Facility' AND TableName = 'System Ventilation Requirements for Cooling' AND ColumnName LIKE 'Outdoor Air Intake Flow%Vot' AND RowName='#{air_loop_hvac.name.to_s.upcase}'"
554
+ )
555
+ heating_oa = air_loop_hvac.model.sqlFile.get.execAndReturnFirstDouble(
556
+ "SELECT Value FROM TabularDataWithStrings WHERE ReportName='Standard62.1Summary' AND ReportForString='Entire Facility' AND TableName = 'System Ventilation Requirements for Heating' AND ColumnName LIKE 'Outdoor Air Intake Flow%Vot' AND RowName='#{air_loop_hvac.name.to_s.upcase}'"
557
+ )
558
+ return [cooling_oa.to_f, heating_oa.to_f].max
559
+ end
560
+
561
+ # Set the minimum VAV damper positions.
562
+ #
563
+ # @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
564
+ # @param has_ddc [Bool] if true, will assume that there is DDC control of vav terminals.
565
+ # If false, assumes otherwise.
566
+ # @return [Bool] returns true if successful, false if not
567
+ def air_loop_hvac_apply_minimum_vav_damper_positions(air_loop_hvac, has_ddc = true)
568
+ air_loop_hvac.thermalZones.each do |zone|
569
+ zone.equipment.each do |equip|
570
+ if equip.to_AirTerminalSingleDuctVAVReheat.is_initialized
571
+ zone_oa = thermal_zone_outdoor_airflow_rate(zone)
572
+ vav_terminal = equip.to_AirTerminalSingleDuctVAVReheat.get
573
+ air_terminal_single_duct_vav_reheat_apply_minimum_damper_position(vav_terminal, zone_oa, has_ddc)
574
+ elsif equip.to_AirTerminalSingleDuctParallelPIUReheat.is_initialized
575
+ zone_oa = thermal_zone_outdoor_airflow_rate(zone)
576
+ fp_vav_terminal = equip.to_AirTerminalSingleDuctParallelPIUReheat.get
577
+ air_terminal_single_duct_parallel_piu_reheat_apply_minimum_primary_airflow_fraction(fp_vav_terminal, zone_oa)
578
+ end
579
+ end
580
+ end
581
+
582
+ return true
583
+ end
584
+
585
+ # Determine the limits for the type of economizer present on the AirLoopHVAC, if any.
586
+ #
587
+ # @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
588
+ # @param climate_zone [String] ASHRAE climate zone, e.g. 'ASHRAE 169-2013-4A'
589
+ # @return [Array<Double>] [drybulb_limit_f, enthalpy_limit_btu_per_lb, dewpoint_limit_f]
590
+ def air_loop_hvac_economizer_limits(air_loop_hvac, climate_zone)
591
+ drybulb_limit_f = nil
592
+ enthalpy_limit_btu_per_lb = nil
593
+ dewpoint_limit_f = nil
594
+
595
+ # Get the OA system and OA controller
596
+ oa_sys = air_loop_hvac.airLoopHVACOutdoorAirSystem
597
+ return [nil, nil, nil] unless oa_sys.is_initialized
598
+
599
+ oa_sys = oa_sys.get
600
+ oa_control = oa_sys.getControllerOutdoorAir
601
+ economizer_type = oa_control.getEconomizerControlType
602
+
603
+ case economizer_type
604
+ when 'NoEconomizer'
605
+ return [nil, nil, nil]
606
+ when 'FixedDryBulb'
607
+ climate_zone_code = climate_zone.split('-')[-1]
608
+ climate_zone_code = 7 if ['7A', '7B'].include? climate_zone_code
609
+ climate_zone_code = 8 if ['8A', '8B'].include? climate_zone_code
610
+ search_criteria = {
611
+ 'template' => template,
612
+ 'climate_id' => climate_zone_code
613
+ }
614
+ econ_limits = model_find_object(standards_data['prm_economizers'], search_criteria)
615
+ drybulb_limit_f = econ_limits['high_limit_shutoff']
616
+ when 'FixedEnthalpy'
617
+ enthalpy_limit_btu_per_lb = 28
618
+ when 'FixedDewPointAndDryBulb'
619
+ drybulb_limit_f = 75
620
+ dewpoint_limit_f = 55
621
+ end
622
+
623
+ return [drybulb_limit_f, enthalpy_limit_btu_per_lb, dewpoint_limit_f]
624
+ end
625
+
626
+ # Determine the fan power limitation pressure drop adjustment
627
+ # Per Table 6.5.3.1-2 (90.1-2019)
628
+ #
629
+ # @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
630
+ # @return [Double] fan power limitation pressure drop adjustment, in units of horsepower
631
+ def air_loop_hvac_fan_power_limitation_pressure_drop_adjustment_brake_horsepower(air_loop_hvac)
632
+ # Calculate Fan Power Limitation Pressure Drop Adjustment
633
+ fan_pwr_adjustment_bhp = 0
634
+
635
+ # Retrieve climate zone
636
+ climate_zone = air_loop_hvac.model.getClimateZones.getClimateZone(0)
637
+
638
+ # Check if energy recovery is required
639
+ is_energy_recovery_required = air_loop_hvac_energy_recovery_ventilator_required?(air_loop_hvac, climate_zone)
640
+
641
+ system_type = ''
642
+ # Get baseline system type if applicable
643
+ if air_loop_hvac.additionalProperties.hasFeature('baseline_system_type')
644
+ system_type = air_loop_hvac.additionalProperties.getFeatureAsString('baseline_system_type').to_s
645
+ end
646
+
647
+ air_loop_hvac.thermalZones.each do |zone|
648
+ # Take fan power deductions into account;
649
+ # Deductions are calculated based on the
650
+ # baseline model design.
651
+ # The only deduction that's applicable
652
+ # is the "System with central electric
653
+ # resistance heat" for system 6 and 8
654
+ if system_type == 'PVAV_PFP_Boxes' || system_type == 'VAV_PFP_Boxes'
655
+ if zone.additionalProperties.hasFeature('has_fan_power_deduction_system_with_central_electric_resistance_heat')
656
+ current_value = zone.additionalProperties.getFeatureAsDouble('has_fan_power_deduction_system_with_central_electric_resistance_heat')
657
+ zone.additionalProperties.setFeature('has_fan_power_deduction_system_with_central_electric_resistance_heat', current_value + 1.0)
658
+ else
659
+ zone.additionalProperties.setFeature('has_fan_power_deduction_system_with_central_electric_resistance_heat', 1.0)
660
+ end
661
+ end
662
+
663
+ # Determine fan power adjustment
664
+ fan_pwr_adjustment_bhp += thermal_zone_get_fan_power_limitations(zone, is_energy_recovery_required)
665
+ end
666
+
667
+ return fan_pwr_adjustment_bhp
668
+ end
669
+
670
+ # Set effectiveness value of an ERV's heat exchanger
671
+ #
672
+ # @param erv [OpenStudio::Model::HeatExchangerAirToAirSensibleAndLatent] ERV to apply efficiency values
673
+ # @param erv_type [String] ERV type: ERV or HRV
674
+ # @param heat_exchanger_type [String] Heat exchanger type: Rotary or Plate
675
+ # @return [OpenStudio::Model::HeatExchangerAirToAirSensibleAndLatent] ERV to apply efficiency values
676
+ def air_loop_hvac_apply_energy_recovery_ventilator_efficiency(erv, erv_type: 'ERV', heat_exchanger_type: 'Rotary')
677
+ heat_exchanger_air_to_air_sensible_and_latent_apply_effectiveness(erv)
678
+
679
+ return erv
680
+ end
681
+
682
+ # Determine the airflow limits that govern whether or not an ERV is required.
683
+ # Based on climate zone and % OA.
684
+ #
685
+ # @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
686
+ # @param climate_zone [String] ASHRAE climate zone, e.g. 'ASHRAE 169-2013-4A'
687
+ # @param pct_oa [Double] percentage of outdoor air
688
+ # @return [Double] the flow rate above which an ERV is required. if nil, ERV is never required.
689
+ def air_loop_hvac_energy_recovery_ventilator_flow_limit(air_loop_hvac, climate_zone, pct_oa)
690
+ if pct_oa < 0.7
691
+ erv_cfm = nil
692
+ else
693
+ # Heating thermostat setpoint threshold
694
+ temp_c = OpenStudio.convert(60, 'F', 'C').get
695
+
696
+ # Check for exceptions for each zone
697
+ air_loop_hvac.thermalZones.each do |thermal_zone|
698
+ # Get heating thermosat setpoint and comparing to heating thermostat setpoint threshold
699
+ tstat = thermal_zone.thermostat.get
700
+ if tstat.to_ThermostatSetpointDualSetpoint
701
+ tstat = tstat.to_ThermostatSetpointDualSetpoint.get
702
+ htg_sch = tstat.getHeatingSchedule
703
+ if htg_sch.is_initialized
704
+ htg_sch = htg_sch.get
705
+ if htg_sch.to_ScheduleRuleset.is_initialized
706
+ htg_sch = htg_sch.to_ScheduleRuleset.get
707
+ max_c = schedule_ruleset_annual_min_max_value(htg_sch)['max']
708
+ if max_c > temp_c
709
+ htd = true
710
+ end
711
+ elsif htg_sch.to_ScheduleConstant.is_initialized
712
+ htg_sch = htg_sch.to_ScheduleConstant.get
713
+ max_c = schedule_constant_annual_min_max_value(htg_sch)['max']
714
+ if max_c > temp_c
715
+ htd = true
716
+ end
717
+ elsif htg_sch.to_ScheduleCompact.is_initialized
718
+ htg_sch = htg_sch.to_ScheduleCompact.get
719
+ max_c = schedule_compact_annual_min_max_value(htg_sch)['max']
720
+ if max_c > temp_c
721
+ htd = true
722
+ end
723
+ else
724
+ OpenStudio.logFree(OpenStudio::Error, 'prm.log', "Zone #{thermal_zone.name} used an unknown schedule type for the heating setpoint; assuming heated.")
725
+ htd = true
726
+ end
727
+ end
728
+ elsif tstat.to_ZoneControlThermostatStagedDualSetpoint
729
+ tstat = tstat.to_ZoneControlThermostatStagedDualSetpoint.get
730
+ htg_sch = tstat.heatingTemperatureSetpointSchedule
731
+ if htg_sch.is_initialized
732
+ htg_sch = htg_sch.get
733
+ if htg_sch.to_ScheduleRuleset.is_initialized
734
+ htg_sch = htg_sch.to_ScheduleRuleset.get
735
+ max_c = schedule_ruleset_annual_min_max_value(htg_sch)['max']
736
+ if max_c > temp_c
737
+ htd = true
738
+ end
739
+ end
740
+ end
741
+ end
742
+
743
+ # Exception 1 - Systems heated to less than 60F since all baseline system provide cooling
744
+ if !htd
745
+ return nil
746
+ end
747
+
748
+ # Exception 2 - System exhausting toxic fumes
749
+ if thermal_zone.additionalProperties.hasFeature('exhaust_energy_recovery_exception_for_toxic_fumes_etc')
750
+ if thermal_zone.additionalProperties.getFeatureAsString('exhaust_energy_recovery_exception_for_toxic_fumes_etc').get == 'yes'
751
+ return nil
752
+ end
753
+ end
754
+
755
+ # Exception 3 - Commercial kitchen hoods
756
+ if thermal_zone.additionalProperties.hasFeature('exhaust_energy_recovery_exception_for_type1_kitchen_hoods')
757
+ if thermal_zone.additionalProperties.getFeatureAsString('exhaust_energy_recovery_exception_for_type1_kitchen_hoods').get == 'yes'
758
+ return nil
759
+ end
760
+ end
761
+
762
+ # Exception 6 - Distributed exhaust
763
+ if thermal_zone.additionalProperties.hasFeature('exhaust_energy_recovery_exception_for_type_distributed_exhaust')
764
+ if thermal_zone.additionalProperties.getFeatureAsString('exhaust_energy_recovery_exception_for_type_distributed_exhaust').get == 'yes'
765
+ return nil
766
+ end
767
+ end
768
+
769
+ # Exception 7 - Dehumidification
770
+ if thermal_zone.additionalProperties.hasFeature('exhaust_energy_recovery_exception_for_dehumidifcation_with_series_cooling_recovery')
771
+ if thermal_zone.additionalProperties.getFeatureAsString('exhaust_energy_recovery_exception_for_dehumidifcation_with_series_cooling_recovery').get == 'yes'
772
+ return nil
773
+ end
774
+ end
775
+ end
776
+
777
+ # Exception 4 - Heating systems in certain climate zones
778
+ if ['ASHRAE 169-2006-0A', 'ASHRAE 169-2006-0B', 'ASHRAE 169-2006-1A', 'ASHRAE 169-2006-1B', 'ASHRAE 169-2006-2A', 'ASHRAE 169-2006-2B', 'ASHRAE 169-2006-3A', 'ASHRAE 169-2006-3B', 'ASHRAE 169-2006-3C', 'ASHRAE 169-2013-0A', 'ASHRAE 169-2013-0B', 'ASHRAE 169-2013-1A', 'ASHRAE 169-2013-1B', 'ASHRAE 169-2013-2A', 'ASHRAE 169-2013-2B', 'ASHRAE 169-2013-3A', 'ASHRAE 169-2013-3B', 'ASHRAE 169-2013-3C'].include?(climate_zone)
779
+ if air_loop_hvac.additionalProperties.hasFeature('baseline_system_type')
780
+ system_type = air_loop_hvac.additionalProperties.getFeatureAsString('baseline_system_type').get
781
+ if system_type == 'Gas_Furnace' || system_type == 'Electric_Furnace'
782
+ return nil
783
+ end
784
+ end
785
+ end
786
+
787
+ erv_cfm = 5000
788
+ end
789
+
790
+ return erv_cfm
791
+ end
792
+ end