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
@@ -786,6 +786,32 @@ class Standard
786
786
  return skylight_effective_aperture
787
787
  end
788
788
 
789
+ # Removes daylighting controls from model
790
+ #
791
+ # @param space [OpenStudio::Model::Space] OpenStudio space object
792
+ #
793
+ # @return [Boolean] Returns true if a sizing run is required
794
+ def space_remove_daylighting_controls(space)
795
+ # Retrieves daylighting control objects
796
+ existing_daylighting_controls = space.daylightingControls
797
+ unless existing_daylighting_controls.empty?
798
+ existing_daylighting_controls.each(&:remove)
799
+ OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Space', "For #{space.name}, removed #{existing_daylighting_controls.size} existing daylight controls before adding new controls.")
800
+ return true
801
+ end
802
+ return false
803
+ end
804
+
805
+ # Default for 2013 and earlier is to Add daylighting controls (sidelighting and toplighting) per the template
806
+ # @param space [OpenStudio::Model::Space] the space with daylighting
807
+ # @param remove_existing_controls [Bool] if true, will remove existing controls then add new ones
808
+ # @param draw_daylight_areas_for_debugging [Bool] If this argument is set to true,
809
+ # @return [boolean] true if successful
810
+ def space_set_baseline_daylighting_controls(space, remove_existing = false, draw_areas_for_debug = false)
811
+ added = space_add_daylighting_controls(space, remove_existing, draw_areas_for_debug)
812
+ return added
813
+ end
814
+
789
815
  # Adds daylighting controls (sidelighting and toplighting) per the template
790
816
  # @note This method is super complicated because of all the polygon/geometry math required.
791
817
  # and therefore may not return perfect results. However, it works well in most tested
@@ -797,9 +823,7 @@ class Standard
797
823
  # daylight areas will be added to the model as surfaces for visual debugging.
798
824
  # Yellow = toplighted area, Red = primary sidelighted area,
799
825
  # Blue = secondary sidelighted area, Light Blue = floor
800
- # @return [Hash] returns a hash of resulting areas (m^2).
801
- # Hash keys are: 'toplighted_area', 'primary_sidelighted_area',
802
- # 'secondary_sidelighted_area', 'total_window_area', 'total_skylight_area'
826
+ # @return [boolean] true if successful
803
827
  # @todo add a list of valid choices for template argument
804
828
  # @todo add exception for retail spaces
805
829
  # @todo add exception 2 for skylights with VT < 0.4
@@ -816,8 +840,7 @@ class Standard
816
840
  existing_daylighting_controls = space.daylightingControls
817
841
  unless existing_daylighting_controls.empty?
818
842
  if remove_existing_controls
819
- existing_daylighting_controls.each(&:remove)
820
- OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Space', "For #{space.name}, removed #{existing_daylighting_controls.size} existing daylight controls before adding new controls.")
843
+ space_remove_daylighting_controls(space)
821
844
  else
822
845
  OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Space', "For #{space.name}, daylight controls were already present, no additional controls added.")
823
846
  return false
@@ -1344,7 +1367,8 @@ class Standard
1344
1367
  return area_m2
1345
1368
  end
1346
1369
 
1347
- # Calculate the area of the exterior walls, including the area of the windows on these walls.
1370
+ # Calculate the area of the exterior walls, and roofs
1371
+ # including the area of the windows on these walls.
1348
1372
  #
1349
1373
  # @param space [OpenStudio::Model::Space] space object
1350
1374
  # @return [Double] area in m^2
@@ -1369,6 +1393,83 @@ class Standard
1369
1393
  return area_m2
1370
1394
  end
1371
1395
 
1396
+ # Calculate the space envelope area.
1397
+ # According to the 90.1 definition, building envelope include:
1398
+ # 1. "the elements of a building that separate conditioned spaces from the exterior"
1399
+ # 2. "the elements of a building that separate conditioned space from unconditioned
1400
+ # space or that enclose semiheated spaces through which thermal energy may be
1401
+ # transferred to or from the exterior, to or from unconditioned spaces or to or
1402
+ # from conditioned spaces."
1403
+ #
1404
+ # Outside boundary conditions currently supported:
1405
+ # - Adiabatic
1406
+ # - Surface
1407
+ # - Outdoors
1408
+ # - Foundation
1409
+ # - Ground
1410
+ # - GroundFCfactorMethod
1411
+ # - OtherSideCoefficients
1412
+ # - OtherSideConditionsModel
1413
+ # - GroundSlabPreprocessorAverage
1414
+ # - GroundSlabPreprocessorCore
1415
+ # - GroundSlabPreprocessorPerimeter
1416
+ # - GroundBasementPreprocessorAverageWall
1417
+ # - GroundBasementPreprocessorAverageFloor
1418
+ # - GroundBasementPreprocessorUpperWall
1419
+ # - GroundBasementPreprocessorLowerWall
1420
+ #
1421
+ # Surface type currently supported:
1422
+ # - Floor
1423
+ # - Wall
1424
+ # - RoofCeiling
1425
+ #
1426
+ # @param space [OpenStudio::Model::Space] OpenStudio space object
1427
+ # @param climate_zone [String] Climate zone, used for space heating/cooling thresholds
1428
+ #
1429
+ # @return [Double] area in m^2
1430
+ def space_envelope_area(space, climate_zone)
1431
+ area_m2 = 0.0
1432
+
1433
+ # Get the space conditioning type
1434
+ space_cond_type = space_conditioning_category(space)
1435
+
1436
+ # Loop through all surfaces in this space
1437
+ space.surfaces.sort.each do |surface|
1438
+ # Only account for spaces that are conditioned or semi-heated
1439
+ next unless space_cond_type != 'Unconditioned'
1440
+
1441
+ surf_cnt = false
1442
+
1443
+ # Conditioned space OR semi-heated space <-> exterior
1444
+ # Conditioned space OR semi-heated space <-> ground
1445
+ if surface.outsideBoundaryCondition == 'Outdoors' ||
1446
+ surface.isGroundSurface
1447
+ surf_cnt = true
1448
+ end
1449
+
1450
+ # Conditioned space OR semi-heated space <-> unconditioned spaces
1451
+ unless surf_cnt
1452
+ # TODO: add a case for 'Zone' when supported
1453
+ if surface.outsideBoundaryCondition == 'Surface'
1454
+ adj_space = surface.adjacentSurface.get.space.get
1455
+ adj_space_cond_type = space_conditioning_category(adj_space)
1456
+ surf_cnt = true unless adj_space_cond_type != 'Unconditioned'
1457
+ end
1458
+ end
1459
+
1460
+ if surf_cnt
1461
+ # This surface
1462
+ area_m2 += surface.netArea
1463
+ # Subsurfaces in this surface
1464
+ surface.subSurfaces.sort.each do |subsurface|
1465
+ area_m2 += subsurface.netArea
1466
+ end
1467
+ end
1468
+ end
1469
+
1470
+ return area_m2 * space.multiplier
1471
+ end
1472
+
1372
1473
  # Determine if the space is a plenum.
1373
1474
  # Assume it is a plenum if it is a supply or return plenum for an AirLoop,
1374
1475
  # if it is not part of the total floor area,
@@ -1460,12 +1561,24 @@ class Standard
1460
1561
  if space_type.is_initialized
1461
1562
  space_type = space_type.get
1462
1563
  # Get the space type data
1463
- space_type_properties = space_type_get_standards_data(space_type)
1464
- if space_type_properties.nil?
1465
- OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.Space', "Could not find space type properties for #{space_to_check.name}, assuming nonresidential.")
1466
- is_res = false
1564
+ if /prm/i !~ template
1565
+ # This is the PRM method for 2013 and prior
1566
+ space_type_properties = space_type_get_standards_data(space_type)
1567
+ if space_type_properties.nil?
1568
+ OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.Space', "Could not find space type properties for #{space_to_check.name}, assuming nonresidential.")
1569
+ is_res = false
1570
+ else
1571
+ is_res = space_type_properties['is_residential'] == 'Yes'
1572
+ end
1467
1573
  else
1468
- is_res = space_type_properties['is_residential'] == 'Yes'
1574
+ # This is the 2019 PRM method
1575
+ lighting_properties = interior_lighting_get_prm_data(space_type)
1576
+ if lighting_properties.empty?
1577
+ OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.Space', "Could not find lighting properties for #{space_to_check.name}, assuming nonresidential.")
1578
+ is_res = false
1579
+ else
1580
+ is_res = lighting_properties['isresidential'].to_s == '1'
1581
+ end
1469
1582
  end
1470
1583
  else
1471
1584
  OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.Space', "Could not find a space type for #{space_to_check.name}, assuming nonresidential.")
@@ -1480,8 +1593,14 @@ class Standard
1480
1593
  # @param space [OpenStudio::Model::Space] space object
1481
1594
  # @param climate_zone [String] ASHRAE climate zone, e.g. 'ASHRAE 169-2013-4A'
1482
1595
  # @return [String] NonResConditioned, ResConditioned, Semiheated, Unconditioned
1483
- # @todo add logic to detect indirectly-conditioned spaces
1484
- def space_conditioning_category(space, climate_zone)
1596
+ # @todo add logic to detect indirectly-conditioned spaces based on air transfer
1597
+ def space_conditioning_category(space)
1598
+ # Return space conditioning category if already assigned as an additional properties
1599
+ return space.additionalProperties.getFeatureAsString('space_conditioning_category').get if space.additionalProperties.hasFeature('space_conditioning_category')
1600
+
1601
+ # Get climate zone
1602
+ climate_zone = model_standards_climate_zone(space.model)
1603
+
1485
1604
  # Get the zone this space is inside
1486
1605
  zone = space.thermalZone
1487
1606
 
@@ -1490,8 +1609,100 @@ class Standard
1490
1609
  return 'Unconditioned'
1491
1610
  end
1492
1611
 
1493
- # Get the category from the zone
1494
- cond_cat = zone.get.conditioning_category(climate_zone)
1612
+ # Return air plenums are indirectly conditioned spaces according to the
1613
+ # 90.1-2019 Performance Rating Method Reference Manual
1614
+ # #
1615
+ # Additionally, Section 2 of ASHRAE 90.1 states that indirectly
1616
+ # conditioned spaces are unconditioned spaces that are adjacent to
1617
+ # heated or cooled spaced and provided that air from these spaces is
1618
+ # intentionally transferred into the space at a rate exceeding 3 ach
1619
+ # which most if not all return air plenum do.
1620
+ space.model.getAirLoopHVACReturnPlenums.each do |return_air_plenum|
1621
+ if return_air_plenum.thermalZone.get.name.to_s == zone.get.name.to_s
1622
+ # Determine if residential
1623
+ res = thermal_zone_residential?(zone.get) ? true : false
1624
+
1625
+ OpenStudio.logFree(OpenStudio::Debug, 'openstudio.Standards.ThermalZone', "Zone #{zone.get.name} is (indirectly) conditioned (return air plenum).")
1626
+ cond_cat = res ? 'ResConditioned' : 'NonResConditioned'
1627
+
1628
+ return cond_cat
1629
+ end
1630
+ end
1631
+ # Following the same assumptions, we designate supply air plenums
1632
+ # as indirectly conditioned as well
1633
+ space.model.getAirLoopHVACSupplyPlenums.each do |supply_air_plenum|
1634
+ if supply_air_plenum.thermalZone.get.name.to_s == zone.get.name.to_s
1635
+ # Determine if residential
1636
+ res = thermal_zone_residential?(zone.get) ? true : false
1637
+
1638
+ OpenStudio.logFree(OpenStudio::Debug, 'openstudio.Standards.ThermalZone', "Zone #{zone.get.name} is (indirectly) conditioned (supply air plenum).")
1639
+ cond_cat = res ? 'ResConditioned' : 'NonResConditioned'
1640
+
1641
+ return cond_cat
1642
+ end
1643
+ end
1644
+
1645
+ # Get the category from the zone, this methods does NOT detect indirectly
1646
+ # conditioned spaces
1647
+ cond_cat = thermal_zone_conditioning_category(zone.get, climate_zone)
1648
+
1649
+ # Detect indirectly conditioned spaces based on UA sum product comparison
1650
+ if cond_cat == 'Unconditioned'
1651
+
1652
+ # Initialize UA sum product for surfaces adjacent to conditioned spaces
1653
+ cond_ua = 0
1654
+
1655
+ # Initialize UA sum product for surfaces adjacent to unconditoned spaces,
1656
+ # semi-heated spaces and outdoors
1657
+ otr_ua = 0
1658
+
1659
+ space.surfaces.sort.each do |surface|
1660
+ # Surfaces adjacent to other surfaces can be next to conditioned,
1661
+ # unconditioned or semi-heated spaces
1662
+ if surface.outsideBoundaryCondition == 'Surface'
1663
+
1664
+ # Retrieve adjacent space conditioning category
1665
+ adj_space = surface.adjacentSurface.get.space.get
1666
+ adj_zone = adj_space.thermalZone.get
1667
+ adj_space_cond_type = thermal_zone_conditioning_category(adj_zone, climate_zone)
1668
+
1669
+ # adj_zone == zone.get means that the surface is adjacent to its zone
1670
+ # This is translated by an adiabtic outside boundary condition, which are
1671
+ # assumed to be used only if the surface is adjacent to a conditioned space
1672
+ if adj_space_cond_type == 'ResConditioned' || adj_space_cond_type == 'NonResConditioned' || adj_zone == zone.get
1673
+ cond_ua += surface_subsurface_ua(surface)
1674
+ else
1675
+ otr_ua += surface_subsurface_ua(surface)
1676
+ end
1677
+
1678
+ # Adiabtic outside boundary condition are assumed to be used only if the
1679
+ # surface is adjacent to a conditioned space
1680
+ elsif surface.outsideBoundaryCondition == 'Adiabatic'
1681
+
1682
+ # If the surface is a floor and is located at the lowest floor of the
1683
+ # building it is assumed to be adjacent to an unconditioned space
1684
+ # (i.e. ground)
1685
+ if surface.surfaceType == 'Floor' && surface.space.get.buildingStory == find_lowest_story(surface.model)
1686
+ otr_ua += surface_subsurface_ua(surface)
1687
+ else
1688
+ cond_ua += surface_subsurface_ua(surface)
1689
+ end
1690
+
1691
+ # All other outside boundary conditions are assumed to be adjacent to either:
1692
+ # outdoors or ground and hence count towards the unconditioned UA product
1693
+ else
1694
+ otr_ua += surface_subsurface_ua(surface)
1695
+ end
1696
+ end
1697
+
1698
+ # Determine if residential
1699
+ res = thermal_zone_residential?(zone.get) ? true : false
1700
+
1701
+ return cond_cat unless cond_ua > otr_ua
1702
+
1703
+ OpenStudio.logFree(OpenStudio::Debug, 'openstudio.Standards.ThermalZone', "Zone #{zone.get.name} is (indirectly) conditioned because its conditioned UA product (#{cond_ua.round} W/K) exceeds its non-conditioned UA product (#{otr_ua.round} W/K).")
1704
+ cond_cat = res ? 'ResConditioned' : 'NonResConditioned'
1705
+ end
1495
1706
 
1496
1707
  return cond_cat
1497
1708
  end
@@ -1582,6 +1793,421 @@ class Standard
1582
1793
  return load_w
1583
1794
  end
1584
1795
 
1796
+ # Create annual array of occupancy for the space: 1 = occupied, 0 = unoccupied
1797
+ # @author Doug Maddox, PNNL
1798
+ # @param space object
1799
+ # @return [Double] 8760 array of the occupancy flag
1800
+ def space_occupancy_annual_array(model, space)
1801
+ occ_sch_values = nil
1802
+ ppl_values = Array.new(8760, 0)
1803
+
1804
+ # Need to review all people objects in this space
1805
+ space_name = space.name.get
1806
+ space_type_name = space.spaceType.get.name.get
1807
+ people_objs = []
1808
+ model.getPeoples.sort.each do |people|
1809
+ parent_obj = people.parent.get.iddObjectType.valueName.to_s
1810
+ if parent_obj == 'OS_Space'
1811
+ # This object is associated with a single space
1812
+ # Check if it is the current space
1813
+ if space_name == people.space.get.name.get
1814
+ people_objs << people
1815
+ end
1816
+ elsif parent_obj == 'OS_SpaceType'
1817
+ # This object is associated with a space type
1818
+ # Check if it is the current space type
1819
+ if space_type_name == people.spaceType.get.name.get
1820
+ people_objs << people
1821
+ end
1822
+ end
1823
+ end
1824
+
1825
+ unoccupied_threshold = air_loop_hvac_unoccupied_threshold
1826
+ people_objs.each do |people|
1827
+ occ_sch = people.numberofPeopleSchedule
1828
+ if occ_sch.is_initialized
1829
+ occ_sch_obj = occ_sch.get
1830
+ occ_sch_values = get_8760_values_from_schedule(model, occ_sch_obj)
1831
+ # Flag = 1 if any schedule shows occupancy for a given hour
1832
+ if !occ_sch_values.nil?
1833
+ (0..8759).each do |ihr|
1834
+ ppl_values[ihr] = 1 if occ_sch_values[ihr] >= unoccupied_threshold
1835
+ end
1836
+ else
1837
+ OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.Space', "Failed to retrieve people schedule for #{space.name}. Assuming #{w_per_person}W/person.")
1838
+ end
1839
+ end
1840
+ end
1841
+
1842
+ return ppl_values
1843
+ end
1844
+
1845
+ # Determine the design internal gain (W) for
1846
+ # this space without space multipliers.
1847
+ # This includes People, Lights, Electric Equipment, and Gas Equipment.
1848
+ # This version accounts for operating schedules
1849
+ # and fraction lost for equipment
1850
+ # @author Doug Maddox, PNNL
1851
+ # @param space object
1852
+ # @param return_noncoincident_value [boolean] if true, return value is noncoincident peak; if false, return is array off coincident load
1853
+ # @return [Double] 8760 array of the design internal load, in W, for this space
1854
+ def space_internal_load_annual_array(model, space, return_noncoincident_value)
1855
+ # For each type of load, first convert schedules to 8760 arrays so coincident load can be determined
1856
+ ppl_values = Array.new(8760, 0)
1857
+ ltg_values = Array.new(8760, 0)
1858
+ load_values = Array.new(8760, 0)
1859
+ noncoincident_peak_load = 0
1860
+ space_name = space.name.get
1861
+ space_type_name = space.spaceType.get.name.get
1862
+
1863
+ # People
1864
+ # Make list of people objects for this space
1865
+ # Including those associated with space directly and those associated with space type
1866
+ ppl_total = 0
1867
+ people_objs = []
1868
+ model.getPeoples.sort.each do |people|
1869
+ parent_obj = people.parent.get.iddObjectType.valueName.to_s
1870
+ if parent_obj == 'OS_Space'
1871
+ # This object is associated with a single space
1872
+ # Check if it is the current space
1873
+ if space_name == people.space.get.name.get
1874
+ people_objs << people
1875
+ end
1876
+ elsif parent_obj == 'OS_SpaceType'
1877
+ # This object is associated with a space type
1878
+ # Check if it is the current space type
1879
+ if space_type_name == people.spaceType.get.name.get
1880
+ people_objs << people
1881
+ end
1882
+ end
1883
+ end
1884
+
1885
+ people_objs.each do |people|
1886
+ w_per_person = 125 # Initial assumption
1887
+ occ_sch_max = 1
1888
+ act_sch = people.activityLevelSchedule
1889
+ if people.isActivityLevelScheduleDefaulted
1890
+ # Check default schedule set
1891
+ unless space.spaceType.get.defaultScheduleSet.empty?
1892
+ unless space.spaceType.get.defaultScheduleSet.get.peopleActivityLevelSchedule.empty?
1893
+ act_sch = space.spaceType.get.defaultScheduleSet.get.peopleActivityLevelSchedule
1894
+ end
1895
+ end
1896
+ end
1897
+ if act_sch.is_initialized
1898
+ act_sch_obj = act_sch.get
1899
+ act_sch_values = get_8760_values_from_schedule(model, act_sch_obj)
1900
+ if !act_sch_values.nil?
1901
+ w_per_person = act_sch_values.max
1902
+ else
1903
+ OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.Space', "Failed to retrieve people activity schedule for #{space.name}. Assuming #{w_per_person}W/person.")
1904
+ end
1905
+ end
1906
+
1907
+ occ_sch_ruleset = nil
1908
+ occ_sch = people.numberofPeopleSchedule
1909
+ if people.isNumberofPeopleScheduleDefaulted
1910
+ # Check default schedule set
1911
+ unless space.spaceType.get.defaultScheduleSet.empty?
1912
+ unless space.spaceType.get.defaultScheduleSet.get.numberofPeopleSchedule.empty?
1913
+ occ_sch = space.spaceType.get.defaultScheduleSet.get.numberofPeopleSchedule
1914
+ end
1915
+ end
1916
+ end
1917
+ if occ_sch.is_initialized
1918
+ occ_sch_obj = occ_sch.get
1919
+ occ_sch_values = get_8760_values_from_schedule(model, occ_sch_obj)
1920
+ if !occ_sch_max.nil?
1921
+ occ_sch_max = occ_sch_values.max
1922
+ else
1923
+ OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.Space', "Failed to retrieve people schedule for #{space.name}. Assuming #{w_per_person}W/person.")
1924
+ end
1925
+ end
1926
+
1927
+ num_ppl = people.getNumberOfPeople(space.floorArea)
1928
+ ppl_total += num_ppl
1929
+
1930
+ act_sch_value = w_per_person
1931
+ occ_sch_value = occ_sch_max
1932
+ (0..8759).each do |ihr|
1933
+ act_sch_value = act_sch_values[ihr] unless act_sch_values.nil?
1934
+ occ_sch_value = occ_sch_values[ihr] unless occ_sch_values.nil?
1935
+ ppl_values[ihr] += num_ppl * act_sch_value * occ_sch_value
1936
+ end
1937
+ end
1938
+
1939
+ # Make list of lights objects for this space
1940
+ # Including those associated with space directly and those associated with space type
1941
+ # Note: in EnergyPlus, Lights are associated with zone or zonelist
1942
+ # In OS, they are associated with space or space type
1943
+ light_objs = []
1944
+ model.getLightss.sort.each do |light|
1945
+ parent_obj = light.parent.get.iddObjectType.valueName.to_s
1946
+ if parent_obj == 'OS_Space'
1947
+ # This object is associated with a single space
1948
+ # Check if it is the current space
1949
+ if space_name == light.space.get.name.get
1950
+ light_objs << light
1951
+ end
1952
+ elsif parent_obj == 'OS_SpaceType'
1953
+ # This object is associated with a space type
1954
+ # Check if it is the current space type
1955
+ if space_type_name == light.spaceType.get.name.get
1956
+ light_objs << light
1957
+ end
1958
+ end
1959
+ end
1960
+
1961
+ light_objs.each do |light|
1962
+ ltg_sch_ruleset = nil
1963
+ ltg_sch = light.schedule
1964
+ ltg_w = light.getLightingPower(space.floorArea, ppl_total)
1965
+
1966
+ if light.isScheduleDefaulted
1967
+ # Check default schedule set
1968
+ unless space.spaceType.get.defaultScheduleSet.empty?
1969
+ unless space.spaceType.get.defaultScheduleSet.get.lightingSchedule.empty?
1970
+ ltg_sch = space.spaceType.get.defaultScheduleSet.get.lightingSchedule
1971
+ end
1972
+ end
1973
+ end
1974
+ if ltg_sch.is_initialized
1975
+ ltg_sch_obj = ltg_sch.get
1976
+ ltg_sch_values = get_8760_values_from_schedule(model, ltg_sch_obj)
1977
+ if !ltg_sch_values.nil?
1978
+ ltg_sch_max = ltg_sch_values.max
1979
+ else
1980
+ OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.Space', "Failed to retreive lighting schedule for #{space.name}. Assuming #{ltg_w} W.")
1981
+ end
1982
+ end
1983
+
1984
+ if !ltg_sch_values.nil?
1985
+ ltg_sch_value = 1.0
1986
+ (0..8759).each do |ihr|
1987
+ ltg_sch_value = ltg_sch_values[ihr] unless ltg_sch_ruleset.nil?
1988
+ ltg_values[ihr] += ltg_w * ltg_sch_value
1989
+ end
1990
+ end
1991
+ end
1992
+
1993
+ # Luminaire Objects
1994
+ space.spaceType.get.luminaires.each do |light|
1995
+ ltg_sch_values = nil
1996
+ ltg_sch = light.schedule
1997
+ ltg_w = light.lightingPower(space.floorArea, ppl_total)
1998
+ # not sure if above line is valid, so calculate from parts instead until above can be verified
1999
+ ltg_w = light.getPowerPerFloorArea(space.floorArea) * space.floorArea
2000
+ ltg_w += light.getPowerPerPerson(ppl_total) * ppl_total
2001
+
2002
+ if light.isScheduleDefaulted
2003
+ # Check default schedule set
2004
+ unless space.spaceType.get.defaultScheduleSet.empty?
2005
+ unless space.spaceType.get.defaultScheduleSet.get.lightingSchedule.empty?
2006
+ ltg_sch = space.spaceType.get.defaultScheduleSet.get.lightingSchedule
2007
+ end
2008
+ end
2009
+ end
2010
+ if ltg_sch.is_initialized
2011
+ ltg_sch_obj = ltg_sch.get
2012
+ ltg_sch_values = get_8760_values_from_schedule(model, ltg_sch_obj)
2013
+ if !ltg_sch_values.nil?
2014
+ ltg_sch_max = ltg_sch_values.max
2015
+ else
2016
+ OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.Space', "Failed to retreive lighting schedule for luminaires for #{space.name}. Assuming #{ltg_w} W.")
2017
+ end
2018
+ end
2019
+
2020
+ if !ltg_sch_values.nil?
2021
+ ltg_sch_value = 1.0
2022
+ (0..8759).each do |ihr|
2023
+ ltg_sch_value = ltg_sch_values[ihr] unless ltg_sch_ruleset.nil?
2024
+ ltg_values[ihr] += ltg_w * ltg_sch_value
2025
+ end
2026
+ end
2027
+ end
2028
+
2029
+ # Equipment Loads
2030
+ eqp_type = 'electric equipment'
2031
+ equips = model.getElectricEquipments
2032
+ load_values = space_get_loads_for_all_equips(model, space, equips, eqp_type, ppl_total, load_values, return_noncoincident_value)
2033
+
2034
+ eqp_type = 'gas equipment'
2035
+ equips = model.getGasEquipments
2036
+ load_values = space_get_loads_for_all_equips(model, space, equips, eqp_type, ppl_total, load_values, return_noncoincident_value)
2037
+
2038
+ eqp_type = 'steam equipment'
2039
+ equips = model.getSteamEquipments
2040
+ load_values = space_get_loads_for_all_equips(model, space, equips, eqp_type, ppl_total, load_values, return_noncoincident_value)
2041
+
2042
+ eqp_type = 'hot water equipment'
2043
+ equips = model.getHotWaterEquipments
2044
+ load_values = space_get_loads_for_all_equips(model, space, equips, eqp_type, ppl_total, load_values, return_noncoincident_value)
2045
+
2046
+ eqp_type = 'other equipment'
2047
+ equips = model.getOtherEquipments
2048
+ load_values = space_get_loads_for_all_equips(model, space, equips, eqp_type, ppl_total, load_values, return_noncoincident_value)
2049
+
2050
+ # Add lighting and people to the load values array
2051
+ if return_noncoincident_value
2052
+ noncoincident_peak_load = load_values[0] + ppl_values.max + ltg_values.max
2053
+ return noncoincident_peak_load
2054
+ else
2055
+ (0..8759).each do |ihr|
2056
+ load_values[ihr] += ppl_values[ihr] + ltg_values[ihr]
2057
+ end
2058
+ return load_values
2059
+ end
2060
+ end
2061
+
2062
+ # Loops through a set of equipment objects of one type
2063
+ # For each applicable equipment object, call method to get annual gain values
2064
+ # This is useful for the Appendix G test for multizone systems
2065
+ # to determine whether specific zones should be isolated to PSZ based on
2066
+ # space loads that differ significantly from other zones on the multizone system
2067
+ #
2068
+ # @param model [OpenStudio::Model::Model] the model
2069
+ # @param space [OpenStudio::Model::Space] the space
2070
+ # @param equips [object] This is an array of equipment objects in the model
2071
+ # @param eqp_type [String] string description of the type of equipment object
2072
+ # @param ppl_total [Numeric] total number of people in the space
2073
+ # @param load_values [Array] 8760 array of load values for the equipment type
2074
+ # @param return_noncoincident_value [boolean] return a single peak value if true; return 8760 gain profile if false
2075
+ #
2076
+ # @return [Array] load values array; if return_noncoincident_value is true, array has only one value
2077
+ #
2078
+ def space_get_loads_for_all_equips(model, space, equips, eqp_type, ppl_total, load_values, return_noncoincident_value)
2079
+ space_name = space.name.get
2080
+ space_type_name = space.spaceType.get.name.get
2081
+ equips.sort.each do |equip|
2082
+ parent_obj = equip.parent.get.iddObjectType.valueName.to_s
2083
+ if parent_obj == 'OS_Space'
2084
+ # This object is associated with a single space
2085
+ # Check if it is the current space
2086
+ if space_name == equip.space.get.name.get
2087
+ euip_name = equip.name.get
2088
+ load_values = space_get_equip_annual_array(model, space, equip, eqp_type, ppl_total, load_values, return_noncoincident_value)
2089
+ end
2090
+ elsif parent_obj == 'OS_SpaceType'
2091
+ # This object is associated with a space type
2092
+ # Check if it is the current space type
2093
+ if space_type_name == equip.spaceType.get.name.get
2094
+ load_values = space_get_equip_annual_array(model, space, equip, eqp_type, ppl_total, load_values, return_noncoincident_value)
2095
+ end
2096
+ end
2097
+ end
2098
+ return load_values
2099
+ end
2100
+
2101
+ # Returns an 8760 array of load values for a specific type of load in a space.
2102
+ # This is useful for the Appendix G test for multizone systems
2103
+ # to determine whether specific zones should be isolated to PSZ based on
2104
+ # space loads that differ significantly from other zones on the multizone system
2105
+ #
2106
+ # @param model [OpenStudio::Model::Model] the model
2107
+ # @param space [OpenStudio::Model::Space] the space
2108
+ # @param equip [object] This can be any type of equipment object in the space
2109
+ # @param eqp_type [String] string description of the type of equipment object
2110
+ # @param ppl_total [Numeric] total number of people in the space
2111
+ # @param load_values [Array] 8760 array of load values for the equipment type
2112
+ # @param return_noncoincident_value [boolean] return a single peak value if true; return 8760 gain profile if false
2113
+ #
2114
+ # @return [Array] load values array; if return_noncoincident_value is true, array has only one value
2115
+ #
2116
+ def space_get_equip_annual_array(model, space, equip, eqp_type, ppl_total, load_values, return_noncoincident_value)
2117
+ # Get load schedule and load lost value depending on equipment type
2118
+ case eqp_type
2119
+ when 'electric equipment'
2120
+ load_sch = equip.schedule
2121
+ load_lost = equip.electricEquipmentDefinition.fractionLost # eqp-type-specific
2122
+ load_w = equip.getDesignLevel(space.floorArea, ppl_total) * (1 - load_lost)
2123
+
2124
+ if equip.isScheduleDefaulted
2125
+ # Check default schedule set
2126
+ unless space.spaceType.get.defaultScheduleSet.empty?
2127
+ unless space.spaceType.get.defaultScheduleSet.get.electricEquipmentSchedule.empty? # eqp-type-specific
2128
+ load_sch = space.spaceType.get.defaultScheduleSet.get.electricEquipmentSchedule # eqp-type-specific
2129
+ end
2130
+ end
2131
+ end
2132
+ when 'gas equipment'
2133
+ load_sch = equip.schedule
2134
+ load_lost = equip.gasEquipmentDefinition.fractionLost # eqp-type-specific
2135
+ load_w = equip.getDesignLevel(space.floorArea, ppl_total) * (1 - load_lost)
2136
+
2137
+ if equip.isScheduleDefaulted
2138
+ # Check default schedule set
2139
+ unless space.spaceType.get.defaultScheduleSet.empty?
2140
+ unless space.spaceType.get.defaultScheduleSet.get.gasEquipmentSchedule.empty? # eqp-type-specific
2141
+ load_sch = space.spaceType.get.defaultScheduleSet.get.gasEquipmentSchedule # eqp-type-specific
2142
+ end
2143
+ end
2144
+ end
2145
+ when 'steam equipment'
2146
+ load_sch = equip.schedule
2147
+ load_lost = equip.steamEquipmentDefinition.fractionLost # eqp-type-specific
2148
+ load_w = equip.getDesignLevel(space.floorArea, ppl_total) * (1 - load_lost)
2149
+
2150
+ if equip.isScheduleDefaulted
2151
+ # Check default schedule set
2152
+ unless space.spaceType.get.defaultScheduleSet.empty?
2153
+ unless space.spaceType.get.defaultScheduleSet.get.steamEquipmentSchedule.empty? # eqp-type-specific
2154
+ load_sch = space.spaceType.get.defaultScheduleSet.get.steamEquipmentSchedule # eqp-type-specific
2155
+ end
2156
+ end
2157
+ end
2158
+ when 'hot water equipment'
2159
+ load_sch = equip.schedule
2160
+ load_lost = equip.hotWaterEquipmentDefinition.fractionLost # eqp-type-specific
2161
+ load_w = equip.getDesignLevel(space.floorArea, ppl_total) * (1 - load_lost)
2162
+
2163
+ if equip.isScheduleDefaulted
2164
+ # Check default schedule set
2165
+ unless space.spaceType.get.defaultScheduleSet.empty?
2166
+ unless space.spaceType.get.defaultScheduleSet.get.hotWaterEquipmentSchedule.empty? # eqp-type-specific
2167
+ load_sch = space.spaceType.get.defaultScheduleSet.get.hotWaterEquipmentSchedule # eqp-type-specific
2168
+ end
2169
+ end
2170
+ end
2171
+ when 'other equipment'
2172
+ load_sch = equip.schedule
2173
+ load_lost = equip.otherEquipmentDefinition.fractionLost # eqp-type-specific
2174
+ load_w = equip.getDesignLevel(space.floorArea, ppl_total) * (1 - load_lost)
2175
+
2176
+ if equip.isScheduleDefaulted
2177
+ # Check default schedule set
2178
+ unless space.spaceType.get.defaultScheduleSet.empty?
2179
+ unless space.spaceType.get.defaultScheduleSet.get.otherEquipmentSchedule.empty? # eqp-type-specific
2180
+ load_sch = space.spaceType.get.defaultScheduleSet.get.otherEquipmentSchedule # eqp-type-specific
2181
+ end
2182
+ end
2183
+ end
2184
+ end
2185
+
2186
+ load_sch_ruleset = nil
2187
+ if load_sch.is_initialized
2188
+ load_sch_obj = load_sch.get
2189
+ load_sch_values = get_8760_values_from_schedule(model, load_sch_obj)
2190
+ if !load_sch_values.nil?
2191
+ load_sch_max = load_sch_values.max
2192
+ else
2193
+ OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.Space', "Failed to retreive schedule for equipment type #{eqp_type} in space #{space.name}. Assuming #{load_w} W.")
2194
+ end
2195
+ end
2196
+
2197
+ if return_noncoincident_value
2198
+ load_values[0] += load_w * load_sch_values.max
2199
+ else
2200
+ if !load_sch_values.nil?
2201
+ load_sch_value = 1.0
2202
+ (0..8759).each do |ihr|
2203
+ load_sch_value = load_sch_values[ihr]
2204
+ load_values[ihr] += load_w * load_sch_value
2205
+ end
2206
+ end
2207
+ end
2208
+ return load_values
2209
+ end
2210
+
1585
2211
  # will return a sorted array of array of spaces and connected area (Descending)
1586
2212
  #
1587
2213
  # @param space [OpenStudio::Model::Space] space object
@@ -2305,6 +2931,30 @@ class Standard
2305
2931
  return overlap_area
2306
2932
  end
2307
2933
 
2934
+ # A function to check whether a space is a return / supply plenum.
2935
+ # This function only works on spaces used as a AirLoopSupplyPlenum or AirLoopReturnPlenum
2936
+ # @param [OpenStudio::Model::Space] space
2937
+ # @return boolean true if it is plenum, else false.
2938
+ def space_is_plenum(space)
2939
+ # Get the zone this space is inside
2940
+ zone = space.thermalZone
2941
+ # the zone is a return air plenum
2942
+ space.model.getAirLoopHVACReturnPlenums.each do |return_air_plenum|
2943
+ if return_air_plenum.thermalZone.get.name.to_s == zone.get.name.to_s
2944
+ # Determine if residential
2945
+ return true
2946
+ end
2947
+ end
2948
+ # the zone is a supply plenum
2949
+ space.model.getAirLoopHVACSupplyPlenums.each do |supply_air_plenum|
2950
+ if supply_air_plenum.thermalZone.get.name.to_s == zone.get.name.to_s
2951
+ return true
2952
+ end
2953
+ end
2954
+ # None match, return false
2955
+ return false
2956
+ end
2957
+
2308
2958
  # Determine if a space should be modeled with an occupancy standby mode
2309
2959
  #
2310
2960
  # @param space [OpenStudio::Model::Space] OpenStudio Space object