openstudio-standards 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (378) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.md +33 -0
  3. data/data/inventory/thermal_bridging.csv +90 -0
  4. data/data/standards/OpenStudio_Standards-deer-comstock.xlsx +0 -0
  5. data/data/standards/manage_OpenStudio_Standards.rb +1 -1
  6. data/data/standards/test_performance_expected_dd_results.csv +2014 -1891
  7. data/lib/openstudio-standards/btap/analysis.rb +8 -8
  8. data/lib/openstudio-standards/btap/bridging.rb +664 -645
  9. data/lib/openstudio-standards/btap/btap.model.rb +14 -14
  10. data/lib/openstudio-standards/btap/btap.rb +7 -7
  11. data/lib/openstudio-standards/btap/btap_result.rb +1 -1
  12. data/lib/openstudio-standards/btap/economics.rb +23 -23
  13. data/lib/openstudio-standards/btap/envelope.rb +8 -8
  14. data/lib/openstudio-standards/btap/equest.rb +1 -1
  15. data/lib/openstudio-standards/btap/geometry.rb +2 -2
  16. data/lib/openstudio-standards/btap/mpc.rb +7 -7
  17. data/lib/openstudio-standards/btap/schedules.rb +1 -1
  18. data/lib/openstudio-standards/btap/simmanager.rb +4 -4
  19. data/lib/openstudio-standards/btap/spaceloads.rb +26 -26
  20. data/lib/openstudio-standards/btap/utilities.rb +6 -6
  21. data/lib/openstudio-standards/btap/vintagizer.rb +1 -1
  22. data/lib/openstudio-standards/constructions/information.rb +83 -0
  23. data/lib/openstudio-standards/constructions/materials/modify.rb +72 -0
  24. data/lib/openstudio-standards/constructions/modify.rb +80 -0
  25. data/lib/openstudio-standards/create_typical/create_typical.rb +983 -0
  26. data/lib/openstudio-standards/create_typical/enumerations.rb +484 -0
  27. data/lib/openstudio-standards/create_typical/space_type_blend.rb +791 -0
  28. data/lib/openstudio-standards/create_typical/space_type_ratios.rb +494 -0
  29. data/lib/openstudio-standards/daylighting/space.rb +47 -0
  30. data/lib/openstudio-standards/geometry/create.rb +801 -0
  31. data/lib/openstudio-standards/geometry/create_bar.rb +2170 -0
  32. data/lib/openstudio-standards/geometry/information.rb +462 -0
  33. data/lib/openstudio-standards/geometry/modify.rb +48 -0
  34. data/lib/openstudio-standards/hvac/air_loop/information.rb +79 -0
  35. data/lib/openstudio-standards/hvac/cbecs_hvac.rb +616 -0
  36. data/lib/openstudio-standards/hvac/setpoint_managers/information.rb +91 -0
  37. data/lib/openstudio-standards/prototypes/ashrae_90_1/ashrae_90_1_2004/ashrae_90_1_2004.AirTerminalSingleDuctVAVReheat.rb +1 -1
  38. data/lib/openstudio-standards/prototypes/ashrae_90_1/ashrae_90_1_2007/ashrae_90_1_2007.AirTerminalSingleDuctVAVReheat.rb +1 -1
  39. data/lib/openstudio-standards/prototypes/ashrae_90_1/ashrae_90_1_2010/ashrae_90_1_2010.AirTerminalSingleDuctVAVReheat.rb +1 -1
  40. data/lib/openstudio-standards/prototypes/ashrae_90_1/ashrae_90_1_2010/ashrae_90_1_2010.Model.rb +1 -1
  41. data/lib/openstudio-standards/prototypes/ashrae_90_1/ashrae_90_1_2013/ashrae_90_1_2013.AirTerminalSingleDuctVAVReheat.rb +1 -1
  42. data/lib/openstudio-standards/prototypes/ashrae_90_1/ashrae_90_1_2013/ashrae_90_1_2013.Model.rb +2 -2
  43. data/lib/openstudio-standards/prototypes/ashrae_90_1/ashrae_90_1_2013/ashrae_90_1_2013.hvac_systems.rb +1 -1
  44. data/lib/openstudio-standards/prototypes/ashrae_90_1/ashrae_90_1_2016/ashrae_90_1_2016.AirTerminalSingleDuctVAVReheat.rb +1 -1
  45. data/lib/openstudio-standards/prototypes/ashrae_90_1/ashrae_90_1_2016/ashrae_90_1_2016.Model.rb +4 -36
  46. data/lib/openstudio-standards/prototypes/ashrae_90_1/ashrae_90_1_2016/ashrae_90_1_2016.hvac_systems.rb +1 -1
  47. data/lib/openstudio-standards/prototypes/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.AirTerminalSingleDuctVAVReheat.rb +1 -1
  48. data/lib/openstudio-standards/prototypes/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.Model.rb +4 -36
  49. data/lib/openstudio-standards/prototypes/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.Space.rb +3 -3
  50. data/lib/openstudio-standards/prototypes/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.hvac_systems.rb +1 -1
  51. data/lib/openstudio-standards/prototypes/ashrae_90_1/doe_ref_1980_2004/doe_ref_1980_2004.AirTerminalSingleDuctVAVReheat.rb +1 -1
  52. data/lib/openstudio-standards/prototypes/ashrae_90_1/doe_ref_1980_2004/doe_ref_1980_2004.Model.elevators.rb +1 -1
  53. data/lib/openstudio-standards/prototypes/ashrae_90_1/doe_ref_pre_1980/doe_ref_pre_1980.AirTerminalSingleDuctVAVReheat.rb +1 -1
  54. data/lib/openstudio-standards/prototypes/ashrae_90_1/doe_ref_pre_1980/doe_ref_pre_1980.CoilHeatingGas.rb +1 -1
  55. data/lib/openstudio-standards/prototypes/ashrae_90_1/doe_ref_pre_1980/doe_ref_pre_1980.Model.elevators.rb +1 -1
  56. data/lib/openstudio-standards/prototypes/ashrae_90_1/nrel_nze_ready_2017/nrel_zne_ready_2017.AirTerminalSingleDuctVAVReheat.rb +1 -1
  57. data/lib/openstudio-standards/prototypes/ashrae_90_1/ze_aedg_multifamily/ze_aedg_multifamily.AirTerminalSingleDuctVAVReheat.rb +1 -1
  58. data/lib/openstudio-standards/prototypes/common/buildings/Prototype.College.rb +7 -7
  59. data/lib/openstudio-standards/prototypes/common/buildings/Prototype.Courthouse.rb +8 -8
  60. data/lib/openstudio-standards/prototypes/common/buildings/Prototype.FullServiceRestaurant.rb +14 -14
  61. data/lib/openstudio-standards/prototypes/common/buildings/Prototype.HighRiseApartment.rb +9 -9
  62. data/lib/openstudio-standards/prototypes/common/buildings/Prototype.Hospital.rb +16 -16
  63. data/lib/openstudio-standards/prototypes/common/buildings/Prototype.Laboratory.rb +7 -7
  64. data/lib/openstudio-standards/prototypes/common/buildings/Prototype.LargeDataCenterHighITE.rb +8 -8
  65. data/lib/openstudio-standards/prototypes/common/buildings/Prototype.LargeDataCenterLowITE.rb +8 -8
  66. data/lib/openstudio-standards/prototypes/common/buildings/Prototype.LargeHotel.rb +11 -11
  67. data/lib/openstudio-standards/prototypes/common/buildings/Prototype.LargeOffice.rb +7 -7
  68. data/lib/openstudio-standards/prototypes/common/buildings/Prototype.LargeOfficeDetailed.rb +9 -9
  69. data/lib/openstudio-standards/prototypes/common/buildings/Prototype.MediumOffice.rb +8 -8
  70. data/lib/openstudio-standards/prototypes/common/buildings/Prototype.MediumOfficeDetailed.rb +11 -11
  71. data/lib/openstudio-standards/prototypes/common/buildings/Prototype.MidriseApartment.rb +9 -9
  72. data/lib/openstudio-standards/prototypes/common/buildings/Prototype.Outpatient.rb +19 -19
  73. data/lib/openstudio-standards/prototypes/common/buildings/Prototype.PrimarySchool.rb +10 -10
  74. data/lib/openstudio-standards/prototypes/common/buildings/Prototype.QuickServiceRestaurant.rb +13 -13
  75. data/lib/openstudio-standards/prototypes/common/buildings/Prototype.RetailStandalone.rb +6 -6
  76. data/lib/openstudio-standards/prototypes/common/buildings/Prototype.RetailStripmall.rb +6 -6
  77. data/lib/openstudio-standards/prototypes/common/buildings/Prototype.SecondarySchool.rb +9 -9
  78. data/lib/openstudio-standards/prototypes/common/buildings/Prototype.SmallDataCenterHighITE.rb +8 -8
  79. data/lib/openstudio-standards/prototypes/common/buildings/Prototype.SmallDataCenterLowITE.rb +8 -8
  80. data/lib/openstudio-standards/prototypes/common/buildings/Prototype.SmallHotel.rb +8 -8
  81. data/lib/openstudio-standards/prototypes/common/buildings/Prototype.SmallOffice.rb +8 -8
  82. data/lib/openstudio-standards/prototypes/common/buildings/Prototype.SmallOfficeDetailed.rb +11 -11
  83. data/lib/openstudio-standards/prototypes/common/buildings/Prototype.SuperMarket.rb +10 -10
  84. data/lib/openstudio-standards/prototypes/common/buildings/Prototype.SuperTallBuilding.rb +19 -19
  85. data/lib/openstudio-standards/prototypes/common/buildings/Prototype.TallBuilding.rb +18 -18
  86. data/lib/openstudio-standards/prototypes/common/buildings/Prototype.Warehouse.rb +6 -6
  87. data/lib/openstudio-standards/prototypes/common/do_not_edit_metaclasses.rb +957 -957
  88. data/lib/openstudio-standards/prototypes/common/objects/Prototype.AirConditionerVariableRefrigerantFlow.rb +1 -1
  89. data/lib/openstudio-standards/prototypes/common/objects/Prototype.AirTerminalSingleDuctVAVReheat.rb +1 -1
  90. data/lib/openstudio-standards/prototypes/common/objects/Prototype.CoilCoolingWaterToAirHeatPumpEquationFit.rb +84 -16
  91. data/lib/openstudio-standards/prototypes/common/objects/Prototype.CoilHeatingDXSingleSpeed.rb +1 -1
  92. data/lib/openstudio-standards/prototypes/common/objects/Prototype.CoilHeatingGas.rb +1 -1
  93. data/lib/openstudio-standards/prototypes/common/objects/Prototype.CoilHeatingWaterToAirHeatPumpEquationFit.rb +61 -10
  94. data/lib/openstudio-standards/prototypes/common/objects/Prototype.ControllerWaterCoil.rb +1 -1
  95. data/lib/openstudio-standards/prototypes/common/objects/Prototype.CoolingTower.rb +1 -1
  96. data/lib/openstudio-standards/prototypes/common/objects/Prototype.Fan.rb +1 -1
  97. data/lib/openstudio-standards/prototypes/common/objects/Prototype.FanConstantVolume.rb +1 -1
  98. data/lib/openstudio-standards/prototypes/common/objects/Prototype.FanOnOff.rb +1 -1
  99. data/lib/openstudio-standards/prototypes/common/objects/Prototype.FanVariableVolume.rb +1 -1
  100. data/lib/openstudio-standards/prototypes/common/objects/Prototype.FanZoneExhaust.rb +1 -1
  101. data/lib/openstudio-standards/prototypes/common/objects/Prototype.HeatExchangerAirToAirSensibleAndLatent.rb +2 -2
  102. data/lib/openstudio-standards/prototypes/common/objects/Prototype.Model.exterior_lights.rb +4 -4
  103. data/lib/openstudio-standards/prototypes/common/objects/Prototype.Model.hvac.rb +4 -4
  104. data/lib/openstudio-standards/prototypes/common/objects/Prototype.Model.rb +43 -30
  105. data/lib/openstudio-standards/prototypes/common/objects/Prototype.Model.swh.rb +1 -1
  106. data/lib/openstudio-standards/prototypes/common/objects/Prototype.ServiceWaterHeating.rb +18 -11
  107. data/lib/openstudio-standards/prototypes/common/objects/Prototype.SizingSystem.rb +1 -1
  108. data/lib/openstudio-standards/prototypes/common/objects/Prototype.hvac_systems.rb +774 -117
  109. data/lib/openstudio-standards/prototypes/common/objects/Prototype.radiant_system_controls.rb +340 -481
  110. data/lib/openstudio-standards/prototypes/common/objects/Prototype.refrigeration.rb +3 -3
  111. data/lib/openstudio-standards/prototypes/common/objects/Prototype.utilities.rb +3 -3
  112. data/lib/openstudio-standards/prototypes/common/prototype_metaprogramming.rb +22 -22
  113. data/lib/openstudio-standards/prototypes/deer/deer.Model.rb +1 -1
  114. data/lib/openstudio-standards/qaqc/calibration.rb +131 -0
  115. data/lib/openstudio-standards/qaqc/create_results.rb +983 -0
  116. data/lib/openstudio-standards/qaqc/envelope.rb +399 -0
  117. data/lib/openstudio-standards/qaqc/eui.rb +213 -0
  118. data/lib/openstudio-standards/qaqc/hvac.rb +1943 -0
  119. data/lib/openstudio-standards/qaqc/internal_loads.rb +568 -0
  120. data/lib/openstudio-standards/qaqc/reporting.rb +141 -0
  121. data/lib/openstudio-standards/qaqc/schedules.rb +129 -0
  122. data/lib/openstudio-standards/qaqc/service_water_heating.rb +273 -0
  123. data/lib/openstudio-standards/qaqc/weather_files.rb +497 -0
  124. data/lib/openstudio-standards/qaqc/zone_conditions.rb +278 -0
  125. data/lib/openstudio-standards/schedules/create.rb +364 -0
  126. data/lib/openstudio-standards/schedules/information.rb +169 -0
  127. data/lib/openstudio-standards/schedules/modify.rb +445 -0
  128. data/lib/openstudio-standards/standards/Standards.AirLoopHVAC.rb +110 -71
  129. data/lib/openstudio-standards/standards/Standards.AirTerminalSingleDuctParallelPIUReheat.rb +3 -3
  130. data/lib/openstudio-standards/standards/Standards.AirTerminalSingleDuctVAVReheat.rb +4 -4
  131. data/lib/openstudio-standards/standards/Standards.BoilerHotWater.rb +2 -1
  132. data/lib/openstudio-standards/standards/Standards.ChillerElectricEIR.rb +16 -10
  133. data/lib/openstudio-standards/standards/Standards.CoilCoolingDXSingleSpeed.rb +4 -4
  134. data/lib/openstudio-standards/standards/Standards.CoilCoolingDXTwoSpeed.rb +1 -1
  135. data/lib/openstudio-standards/standards/Standards.CoilCoolingWaterToAirHeatPumpEquationFit.rb +1 -1
  136. data/lib/openstudio-standards/standards/Standards.CoilDX.rb +4 -4
  137. data/lib/openstudio-standards/standards/Standards.CoilHeatingDXMultiSpeed.rb +1 -1
  138. data/lib/openstudio-standards/standards/Standards.CoilHeatingDXSingleSpeed.rb +5 -5
  139. data/lib/openstudio-standards/standards/Standards.CoilHeatingGas.rb +1 -1
  140. data/lib/openstudio-standards/standards/Standards.CoilHeatingGasMultiStage.rb +1 -1
  141. data/lib/openstudio-standards/standards/Standards.CoilHeatingWaterToAirHeatPumpEquationFit.rb +1 -1
  142. data/lib/openstudio-standards/standards/Standards.Construction.rb +17 -18
  143. data/lib/openstudio-standards/standards/Standards.CoolingTower.rb +6 -6
  144. data/lib/openstudio-standards/standards/Standards.CoolingTowerSingleSpeed.rb +1 -1
  145. data/lib/openstudio-standards/standards/Standards.CoolingTowerTwoSpeed.rb +1 -1
  146. data/lib/openstudio-standards/standards/Standards.CoolingTowerVariableSpeed.rb +1 -1
  147. data/lib/openstudio-standards/standards/Standards.Fan.rb +6 -12
  148. data/lib/openstudio-standards/standards/Standards.FanVariableVolume.rb +2 -2
  149. data/lib/openstudio-standards/standards/Standards.FluidCooler.rb +1 -1
  150. data/lib/openstudio-standards/standards/Standards.HeaderedPumpsVariableSpeed.rb +1 -1
  151. data/lib/openstudio-standards/standards/Standards.HeatExchangerSensLat.rb +3 -3
  152. data/lib/openstudio-standards/standards/Standards.Model.rb +411 -261
  153. data/lib/openstudio-standards/standards/Standards.PlanarSurface.rb +2 -2
  154. data/lib/openstudio-standards/standards/Standards.PlantLoop.rb +94 -29
  155. data/lib/openstudio-standards/standards/Standards.Pump.rb +2 -2
  156. data/lib/openstudio-standards/standards/Standards.ScheduleConstant.rb +2 -2
  157. data/lib/openstudio-standards/standards/Standards.ScheduleRuleset.rb +14 -14
  158. data/lib/openstudio-standards/standards/Standards.Space.rb +37 -30
  159. data/lib/openstudio-standards/standards/Standards.SpaceType.rb +38 -29
  160. data/lib/openstudio-standards/standards/Standards.SubSurface.rb +7 -7
  161. data/lib/openstudio-standards/standards/Standards.Surface.rb +13 -13
  162. data/lib/openstudio-standards/standards/Standards.ThermalZone.rb +109 -66
  163. data/lib/openstudio-standards/standards/Standards.WaterHeaterMixed.rb +11 -4
  164. data/lib/openstudio-standards/standards/Standards.ZoneHVACComponent.rb +6 -6
  165. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2004/ashrae_90_1_2004.AirLoopHVAC.rb +1 -1
  166. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2004/ashrae_90_1_2004.PlantLoop.rb +1 -1
  167. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2004/ashrae_90_1_2004.Space.rb +1 -1
  168. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2007/ashrae_90_1_2007.Space.rb +1 -1
  169. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2010/ashrae_90_1_2010.AirLoopHVAC.rb +4 -4
  170. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2010/ashrae_90_1_2010.AirTerminalSingleDuctVAVReheat.rb +1 -1
  171. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2010/ashrae_90_1_2010.Space.rb +4 -4
  172. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/ashrae_90_1_2013.AirLoopHVAC.rb +4 -4
  173. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/ashrae_90_1_2013.AirTerminalSingleDuctVAVReheat.rb +1 -1
  174. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/ashrae_90_1_2013.CoolingTowerVariableSpeed.rb +1 -1
  175. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/ashrae_90_1_2013.Model.rb +5 -21
  176. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/ashrae_90_1_2013.Space.rb +4 -4
  177. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/ashrae_90_1_2013.WaterHeaterMixed.rb +1 -1
  178. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/ashrae_90_1_2013.ZoneHVACComponent.rb +1 -1
  179. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2016/ashrae_90_1_2016.AirLoopHVAC.rb +36 -4
  180. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2016/ashrae_90_1_2016.AirTerminalSingleDuctVAVReheat.rb +1 -1
  181. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2016/ashrae_90_1_2016.CoolingTowerVariableSpeed.rb +1 -1
  182. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2016/ashrae_90_1_2016.Space.rb +4 -4
  183. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2016/ashrae_90_1_2016.ZoneHVACComponent.rb +1 -1
  184. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2016/comstock_ashrae_90_1_2016/comstock_ashrae_90_1_2016.AirLoopHVAC.rb +26 -0
  185. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.AirLoopHVAC.rb +53 -10
  186. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.AirTerminalSingleDuctVAVReheat.rb +1 -1
  187. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.CoolingTowerVariableSpeed.rb +1 -1
  188. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.Space.rb +6 -6
  189. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.ZoneHVACComponent.rb +2 -2
  190. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/comstock_ashrae_90_1_2019/comstock_ashrae_90_1_2019.AirLoopHVAC.rb +26 -0
  191. data/lib/openstudio-standards/standards/ashrae_90_1/data/ashrae_90_1.curves.json +211 -211
  192. data/lib/openstudio-standards/standards/ashrae_90_1/doe_ref_1980_2004/data/doe_ref_1980_2004.economizers.json +14 -14
  193. data/lib/openstudio-standards/standards/ashrae_90_1/doe_ref_1980_2004/doe_ref_1980_2004.AirLoopHVAC.rb +4 -4
  194. data/lib/openstudio-standards/standards/ashrae_90_1/doe_ref_1980_2004/doe_ref_1980_2004.Model.rb +1 -1
  195. data/lib/openstudio-standards/standards/ashrae_90_1/doe_ref_1980_2004/doe_ref_1980_2004.PlantLoop.rb +1 -1
  196. data/lib/openstudio-standards/standards/ashrae_90_1/doe_ref_pre_1980/data/doe_ref_pre_1980.economizers.json +14 -14
  197. data/lib/openstudio-standards/standards/ashrae_90_1/doe_ref_pre_1980/doe_ref_pre_1980.AirLoopHVAC.rb +4 -4
  198. data/lib/openstudio-standards/standards/ashrae_90_1/doe_ref_pre_1980/doe_ref_pre_1980.Model.rb +1 -1
  199. data/lib/openstudio-standards/standards/ashrae_90_1/doe_ref_pre_1980/doe_ref_pre_1980.PlantLoop.rb +1 -1
  200. data/lib/openstudio-standards/standards/ashrae_90_1/nrel_zne_ready_2017/nrel_zne_ready_2017.AirLoopHVAC.rb +6 -6
  201. data/lib/openstudio-standards/standards/ashrae_90_1/nrel_zne_ready_2017/nrel_zne_ready_2017.AirTerminalSingleDuctVAVReheat.rb +1 -1
  202. data/lib/openstudio-standards/standards/ashrae_90_1/nrel_zne_ready_2017/nrel_zne_ready_2017.CoolingTowerVariableSpeed.rb +1 -1
  203. data/lib/openstudio-standards/standards/ashrae_90_1/nrel_zne_ready_2017/nrel_zne_ready_2017.PlantLoop.rb +1 -1
  204. data/lib/openstudio-standards/standards/ashrae_90_1/nrel_zne_ready_2017/nrel_zne_ready_2017.Space.rb +4 -4
  205. data/lib/openstudio-standards/standards/ashrae_90_1/ze_aedg_multifamily/ze_aedg_multifamily.AirLoopHVAC.rb +6 -6
  206. data/lib/openstudio-standards/standards/ashrae_90_1/ze_aedg_multifamily/ze_aedg_multifamily.AirTerminalSingleDuctVAVReheat.rb +1 -1
  207. data/lib/openstudio-standards/standards/ashrae_90_1/ze_aedg_multifamily/ze_aedg_multifamily.CoolingTowerVariableSpeed.rb +1 -1
  208. data/lib/openstudio-standards/standards/ashrae_90_1/ze_aedg_multifamily/ze_aedg_multifamily.PlantLoop.rb +1 -1
  209. data/lib/openstudio-standards/standards/ashrae_90_1/ze_aedg_multifamily/ze_aedg_multifamily.Space.rb +4 -4
  210. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.AirLoopHVAC.rb +22 -28
  211. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.AirTerminalSingleDuctParallelPIUReheat.rb +1 -1
  212. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.AirTerminalSingleDuctVAVReheat.rb +2 -2
  213. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.BoilerHotWater.rb +1 -74
  214. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.ChillerElectricEIR.rb +7 -59
  215. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.CoilCoolingDXSingleSpeed.rb +1 -1
  216. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.CoilCoolingDXTwoSpeed.rb +1 -1
  217. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.CoilDX.rb +1 -1
  218. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.CoilHeatingDXSingleSpeed.rb +1 -1
  219. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.CoilHeatingGas.rb +1 -21
  220. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.DesignSpecificationOutdoorAir.rb +101 -0
  221. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.FanConstantVolume.rb +1 -1
  222. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.FanOnOff.rb +1 -1
  223. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.FanVariableVolume.rb +1 -1
  224. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.HeatExchangerSensLat.rb +1 -1
  225. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb +643 -526
  226. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.PlanarSurface.rb +8 -2
  227. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.PlantLoop.rb +17 -77
  228. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Space.rb +74 -16
  229. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.SpaceType.rb +96 -44
  230. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Surface.rb +6 -6
  231. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.ThermalZone.rb +18 -6
  232. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.ZoneHVACComponent.rb +1 -1
  233. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb +328 -74
  234. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/ashrae_90_1_prm_2019.Model.rb +0 -118
  235. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/ashrae_90_1_prm_2019.rb +2 -1
  236. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.heat_rejection.json +1 -1
  237. data/lib/openstudio-standards/standards/ashrae_90_1_prm/docs/baseline_outdoor_air.md +35 -0
  238. data/lib/openstudio-standards/standards/ashrae_90_1_prm/docs/set_plug_load_measures.md +1 -1
  239. data/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/ashrae_90_1_prm.UserData.rb +228 -0
  240. data/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/userdata_enums.rb +131 -0
  241. data/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/userdata_space.csv +1 -1
  242. data/lib/openstudio-standards/standards/cbes/cbes.AirLoopHVAC.rb +5 -5
  243. data/lib/openstudio-standards/standards/cbes/cbes.Model.rb +1 -1
  244. data/lib/openstudio-standards/standards/cbes/cbes.PlantLoop.rb +1 -1
  245. data/lib/openstudio-standards/standards/cbes/cbes.Space.rb +1 -1
  246. data/lib/openstudio-standards/standards/cbes/cbes_t24_2005/cbes_t24_2005.Space.rb +1 -1
  247. data/lib/openstudio-standards/standards/cbes/cbes_t24_2008/cbes_t24_2008.Space.rb +1 -1
  248. data/lib/openstudio-standards/standards/deer/deer.AirLoopHVAC.rb +109 -27
  249. data/lib/openstudio-standards/standards/deer/deer.Space.rb +1 -1
  250. data/lib/openstudio-standards/standards/deer/deer_1985/data/deer_1985.economizers.json +246 -4
  251. data/lib/openstudio-standards/standards/deer/deer_1996/data/deer_1996.economizers.json +246 -4
  252. data/lib/openstudio-standards/standards/deer/deer_2003/data/deer_2003.economizers.json +246 -4
  253. data/lib/openstudio-standards/standards/deer/deer_2003/deer_2003.ThermalZone.rb +18 -18
  254. data/lib/openstudio-standards/standards/deer/deer_2007/data/deer_2007.economizers.json +246 -4
  255. data/lib/openstudio-standards/standards/deer/deer_2007/deer_2007.ThermalZone.rb +18 -18
  256. data/lib/openstudio-standards/standards/deer/deer_2011/data/deer_2011.economizers.json +246 -4
  257. data/lib/openstudio-standards/standards/deer/deer_2011/deer_2011.ThermalZone.rb +18 -18
  258. data/lib/openstudio-standards/standards/deer/deer_2014/data/deer_2014.economizers.json +248 -6
  259. data/lib/openstudio-standards/standards/deer/deer_2014/deer_2014.Space.rb +3 -3
  260. data/lib/openstudio-standards/standards/deer/deer_2014/deer_2014.ThermalZone.rb +18 -18
  261. data/lib/openstudio-standards/standards/deer/deer_2015/data/deer_2015.economizers.json +248 -6
  262. data/lib/openstudio-standards/standards/deer/deer_2015/deer_2015.Space.rb +3 -3
  263. data/lib/openstudio-standards/standards/deer/deer_2015/deer_2015.ThermalZone.rb +18 -18
  264. data/lib/openstudio-standards/standards/deer/deer_2017/data/deer_2017.economizers.json +248 -6
  265. data/lib/openstudio-standards/standards/deer/deer_2017/deer_2017.Space.rb +3 -3
  266. data/lib/openstudio-standards/standards/deer/deer_2017/deer_2017.ThermalZone.rb +18 -18
  267. data/lib/openstudio-standards/standards/deer/deer_2020/data/deer_2020.economizers.json +248 -6
  268. data/lib/openstudio-standards/standards/deer/deer_2020/deer_2020.AirLoopHVAC.rb +18 -5
  269. data/lib/openstudio-standards/standards/deer/deer_2020/deer_2020.FanVariableVolume.rb +1 -1
  270. data/lib/openstudio-standards/standards/deer/deer_2020/deer_2020.Space.rb +3 -3
  271. data/lib/openstudio-standards/standards/deer/deer_2020/deer_2020.ThermalZone.rb +18 -18
  272. data/lib/openstudio-standards/standards/deer/deer_2025/data/deer_2025.economizers.json +248 -6
  273. data/lib/openstudio-standards/standards/deer/deer_2025/deer_2025.AirLoopHVAC.rb +3 -3
  274. data/lib/openstudio-standards/standards/deer/deer_2025/deer_2025.FanVariableVolume.rb +1 -1
  275. data/lib/openstudio-standards/standards/deer/deer_2025/deer_2025.Space.rb +3 -3
  276. data/lib/openstudio-standards/standards/deer/deer_2030/data/deer_2030.economizers.json +248 -6
  277. data/lib/openstudio-standards/standards/deer/deer_2030/data/deer_2030.heat_pumps.json +2 -2
  278. data/lib/openstudio-standards/standards/deer/deer_2030/deer_2030.AirLoopHVAC.rb +3 -3
  279. data/lib/openstudio-standards/standards/deer/deer_2030/deer_2030.FanVariableVolume.rb +1 -1
  280. data/lib/openstudio-standards/standards/deer/deer_2030/deer_2030.Space.rb +3 -3
  281. data/lib/openstudio-standards/standards/deer/deer_2035/data/deer_2035.economizers.json +248 -6
  282. data/lib/openstudio-standards/standards/deer/deer_2035/deer_2035.AirLoopHVAC.rb +3 -3
  283. data/lib/openstudio-standards/standards/deer/deer_2035/deer_2035.FanVariableVolume.rb +1 -1
  284. data/lib/openstudio-standards/standards/deer/deer_2035/deer_2035.Space.rb +3 -3
  285. data/lib/openstudio-standards/standards/deer/deer_2040/data/deer_2040.economizers.json +248 -6
  286. data/lib/openstudio-standards/standards/deer/deer_2040/deer_2040.AirLoopHVAC.rb +3 -3
  287. data/lib/openstudio-standards/standards/deer/deer_2040/deer_2040.FanVariableVolume.rb +1 -1
  288. data/lib/openstudio-standards/standards/deer/deer_2040/deer_2040.Space.rb +3 -3
  289. data/lib/openstudio-standards/standards/deer/deer_2045/data/deer_2045.economizers.json +260 -0
  290. data/lib/openstudio-standards/standards/deer/deer_2045/deer_2045.AirLoopHVAC.rb +3 -3
  291. data/lib/openstudio-standards/standards/deer/deer_2045/deer_2045.FanVariableVolume.rb +1 -1
  292. data/lib/openstudio-standards/standards/deer/deer_2045/deer_2045.Space.rb +3 -3
  293. data/lib/openstudio-standards/standards/deer/deer_2050/data/deer_2050.economizers.json +248 -6
  294. data/lib/openstudio-standards/standards/deer/deer_2050/deer_2050.AirLoopHVAC.rb +3 -3
  295. data/lib/openstudio-standards/standards/deer/deer_2050/deer_2050.FanVariableVolume.rb +1 -1
  296. data/lib/openstudio-standards/standards/deer/deer_2050/deer_2050.Space.rb +3 -3
  297. data/lib/openstudio-standards/standards/deer/deer_2055/data/deer_2055.economizers.json +248 -6
  298. data/lib/openstudio-standards/standards/deer/deer_2055/deer_2055.AirLoopHVAC.rb +3 -3
  299. data/lib/openstudio-standards/standards/deer/deer_2055/deer_2055.FanVariableVolume.rb +1 -1
  300. data/lib/openstudio-standards/standards/deer/deer_2055/deer_2055.Space.rb +3 -3
  301. data/lib/openstudio-standards/standards/deer/deer_2060/data/deer_2060.economizers.json +248 -6
  302. data/lib/openstudio-standards/standards/deer/deer_2060/deer_2060.AirLoopHVAC.rb +3 -3
  303. data/lib/openstudio-standards/standards/deer/deer_2060/deer_2060.FanVariableVolume.rb +1 -1
  304. data/lib/openstudio-standards/standards/deer/deer_2060/deer_2060.Space.rb +3 -3
  305. data/lib/openstudio-standards/standards/deer/deer_2065/data/deer_2065.economizers.json +248 -6
  306. data/lib/openstudio-standards/standards/deer/deer_2065/deer_2065.AirLoopHVAC.rb +3 -3
  307. data/lib/openstudio-standards/standards/deer/deer_2065/deer_2065.FanVariableVolume.rb +1 -1
  308. data/lib/openstudio-standards/standards/deer/deer_2065/deer_2065.Space.rb +3 -3
  309. data/lib/openstudio-standards/standards/deer/deer_2070/data/deer_2070.economizers.json +248 -6
  310. data/lib/openstudio-standards/standards/deer/deer_2070/deer_2070.AirLoopHVAC.rb +3 -3
  311. data/lib/openstudio-standards/standards/deer/deer_2070/deer_2070.FanVariableVolume.rb +1 -1
  312. data/lib/openstudio-standards/standards/deer/deer_2070/deer_2070.Space.rb +3 -3
  313. data/lib/openstudio-standards/standards/deer/deer_2075/data/deer_2075.economizers.json +248 -6
  314. data/lib/openstudio-standards/standards/deer/deer_2075/deer_2075.AirLoopHVAC.rb +3 -3
  315. data/lib/openstudio-standards/standards/deer/deer_2075/deer_2075.FanVariableVolume.rb +1 -1
  316. data/lib/openstudio-standards/standards/deer/deer_2075/deer_2075.Space.rb +3 -3
  317. data/lib/openstudio-standards/standards/deer/deer_pre_1975/data/deer_pre_1975.economizers.json +246 -4
  318. data/lib/openstudio-standards/standards/necb/BTAP1980TO2010/data/space_types.json +447 -223
  319. data/lib/openstudio-standards/standards/necb/BTAPPRE1980/building_envelope.rb +1 -1
  320. data/lib/openstudio-standards/standards/necb/BTAPPRE1980/data/space_types.json +447 -223
  321. data/lib/openstudio-standards/standards/necb/BTAPPRE1980/hvac_systems.rb +5 -2
  322. data/lib/openstudio-standards/standards/necb/ECMS/data/chiller_types.json +25 -0
  323. data/lib/openstudio-standards/standards/necb/ECMS/data/chillers.json +44 -0
  324. data/lib/openstudio-standards/standards/necb/ECMS/data/curves.json +225 -0
  325. data/lib/openstudio-standards/standards/necb/ECMS/ecms.rb +2 -2
  326. data/lib/openstudio-standards/standards/necb/ECMS/hvac_systems.rb +193 -73
  327. data/lib/openstudio-standards/standards/necb/ECMS/pv_ground.rb +1 -1
  328. data/lib/openstudio-standards/standards/necb/NECB2011/autozone.rb +10 -4
  329. data/lib/openstudio-standards/standards/necb/NECB2011/beps_compliance_path.rb +7 -7
  330. data/lib/openstudio-standards/standards/necb/NECB2011/building_envelope.rb +4 -5
  331. data/lib/openstudio-standards/standards/necb/NECB2011/data/chiller_types.json +32 -0
  332. data/lib/openstudio-standards/standards/necb/NECB2011/data/chillers.json +1 -1
  333. data/lib/openstudio-standards/standards/necb/NECB2011/data/constants.json +36 -0
  334. data/lib/openstudio-standards/standards/necb/NECB2011/data/fuel_type_sets.json +7 -7
  335. data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/NorthernEducation.osm +47587 -0
  336. data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/NorthernHealthCare.osm +49764 -0
  337. data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/Warehouse.osm +283 -297
  338. data/lib/openstudio-standards/standards/necb/NECB2011/data/space_type_unit_definitions.txt +2 -1
  339. data/lib/openstudio-standards/standards/necb/NECB2011/data/space_types.json +447 -223
  340. data/lib/openstudio-standards/standards/necb/NECB2011/data/standards_data.rb +3 -3
  341. data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_1_multi_speed.rb +1 -1
  342. data/lib/openstudio-standards/standards/necb/NECB2011/hvac_systems.rb +49 -27
  343. data/lib/openstudio-standards/standards/necb/NECB2011/necb_2011.rb +400 -202
  344. data/lib/openstudio-standards/standards/necb/NECB2011/service_water_heating.rb +4 -4
  345. data/lib/openstudio-standards/standards/necb/NECB2015/data/space_types.json +637 -318
  346. data/lib/openstudio-standards/standards/necb/NECB2015/hvac_systems.rb +18 -1
  347. data/lib/openstudio-standards/standards/necb/NECB2015/necb_2015.rb +3 -3
  348. data/lib/openstudio-standards/standards/necb/NECB2017/data/space_types.json +637 -318
  349. data/lib/openstudio-standards/standards/necb/NECB2017/hvac_systems.rb +1 -1
  350. data/lib/openstudio-standards/standards/necb/NECB2017/necb_2017.rb +3 -3
  351. data/lib/openstudio-standards/standards/necb/NECB2020/building_envelope.rb +1 -1
  352. data/lib/openstudio-standards/standards/necb/NECB2020/data/space_types.json +615 -307
  353. data/lib/openstudio-standards/standards/necb/NECB2020/service_water_heating.rb +4 -4
  354. data/lib/openstudio-standards/standards/necb/common/btap_data.rb +10 -5
  355. data/lib/openstudio-standards/standards/necb/common/btap_datapoint.rb +1 -1
  356. data/lib/openstudio-standards/utilities/assertion.rb +128 -0
  357. data/lib/openstudio-standards/utilities/logging.rb +2 -3
  358. data/lib/openstudio-standards/utilities/object_info.rb +39 -18
  359. data/lib/openstudio-standards/utilities/schedule_translator.rb +8 -6
  360. data/lib/openstudio-standards/utilities/simulation.rb +24 -11
  361. data/lib/openstudio-standards/utilities/sqlfile.rb +10 -5
  362. data/lib/openstudio-standards/version.rb +1 -1
  363. data/lib/openstudio-standards/weather/Weather.Model.rb +8 -9
  364. data/lib/openstudio-standards/weather/Weather.stat_file.rb +3 -3
  365. data/lib/openstudio-standards/weather/information.rb +35 -0
  366. data/lib/openstudio-standards.rb +69 -5
  367. metadata +54 -18
  368. data/License.txt +0 -65
  369. data/data/standards/OpenStudio_Standards-deer-ALL-comstock(space_types).xlsx +0 -0
  370. data/lib/openstudio-standards/hvac_sizing/Siz.AirLoopHVAC.rb +0 -59
  371. data/lib/openstudio-standards/hvac_sizing/Siz.CoilCoolingWater.rb +0 -13
  372. data/lib/openstudio-standards/hvac_sizing/Siz.HVACComponent.rb +0 -36
  373. data/lib/openstudio-standards/hvac_sizing/Siz.HeatingCoolingFuels.rb +0 -898
  374. data/lib/openstudio-standards/hvac_sizing/Siz.Model.rb +0 -126
  375. data/lib/openstudio-standards/hvac_sizing/Siz.ThermalZone.rb +0 -356
  376. data/lib/openstudio-standards/prototypes/ashrae_90_1/nrel_nze_ready_2017/nrel_zne_ready_2017.Model.rb +0 -35
  377. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.CoolingTower.rb +0 -110
  378. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.CoolingTowerVariableSpeed.rb +0 -5
@@ -3,27 +3,29 @@ class Standard
3
3
  # @ref [References::CBERadiantSystems]
4
4
  # @param zone [OpenStudio::Model::ThermalZone>] zone to add radiant controls
5
5
  # @param radiant_loop [OpenStudio::Model::ZoneHVACLowTempRadiantVarFlow>] radiant loop in thermal zone
6
- # @param radiant_type [String] determines the surface of the radiant system for surface temperature output reporting
7
- # options are 'floor' and 'ceiling'
8
- # @param model_occ_hr_start [Double] Starting hour of building occupancy
9
- # @param model_occ_hr_end [Double] Ending hour of building occupancy
6
+ # @param radiant_temperature_control_type [String] determines the controlled temperature for the radiant system
7
+ # options are 'SurfaceFaceTemperature', 'SurfaceInteriorTemperature'
8
+ # @param use_zone_occupancy_for_control [Boolean] Set to true if radiant system is to use specific zone occupancy objects
9
+ # for CBE control strategy. If false, then it will use values in model_occ_hr_start and model_occ_hr_end
10
+ # for all radiant zones. default to true.
11
+ # @param occupied_percentage_threshold [Double] the minimum fraction (0 to 1) that counts as occupied
12
+ # if this parameter is set, the returned ScheduleRuleset will be 0 = unoccupied, 1 = occupied
13
+ # otherwise the ScheduleRuleset will be the weighted fractional occupancy schedule
14
+ # @param model_occ_hr_start [Double] Starting decimal hour of whole building occupancy
15
+ # @param model_occ_hr_end [Double] Ending decimal hour of whole building occupancy
10
16
  # @todo model_occ_hr_start and model_occ_hr_end from zone occupancy schedules
11
17
  # @param proportional_gain [Double] Proportional gain constant (recommended 0.3 or less).
12
- # @param minimum_operation [Double] Minimum number of hours of operation for radiant system before it shuts off.
13
- # @param weekend_temperature_reset [Double] Weekend temperature reset for slab temperature setpoint in degree Celsius.
14
- # @param early_reset_out_arg [Double] Time at which the weekend temperature reset is removed.
15
18
  # @param switch_over_time [Double] Time limitation for when the system can switch between heating and cooling
16
19
  def model_add_radiant_proportional_controls(model, zone, radiant_loop,
17
- radiant_type: 'floor',
20
+ radiant_temperature_control_type: 'SurfaceFaceTemperature',
21
+ use_zone_occupancy_for_control: true,
22
+ occupied_percentage_threshold: 0.10,
18
23
  model_occ_hr_start: 6.0,
19
24
  model_occ_hr_end: 18.0,
20
25
  proportional_gain: 0.3,
21
- minimum_operation: 1,
22
- weekend_temperature_reset: 2,
23
- early_reset_out_arg: 20,
24
26
  switch_over_time: 24.0)
25
27
 
26
- zone_name = zone.name.to_s.gsub(/[ +-.]/, '_')
28
+ zone_name = ems_friendly_name(zone.name)
27
29
  zone_timestep = model.getTimestep.numberOfTimestepsPerHour
28
30
 
29
31
  if model.version < OpenStudio::VersionString.new('3.1.1')
@@ -34,61 +36,56 @@ class Standard
34
36
  coil_heating_radiant = radiant_loop.heatingCoil.get.to_CoilHeatingLowTempRadiantVarFlow.get
35
37
  end
36
38
 
39
+ #####
40
+ # Define radiant system parameters
41
+ ####
42
+ # set radiant system temperature and setpoint control type
43
+ unless ['surfacefacetemperature', 'surfaceinteriortemperature'].include? radiant_temperature_control_type.downcase
44
+ OpenStudio.logFree(OpenStudio::Error, 'openstudio.Model.Model',
45
+ "Control sequences not compatible with '#{radiant_temperature_control_type}' radiant system control. Defaulting to 'SurfaceFaceTemperature'.")
46
+ radiant_temperature_control_type = 'SurfaceFaceTemperature'
47
+ end
48
+
49
+ radiant_loop.setTemperatureControlType(radiant_temperature_control_type)
50
+
37
51
  #####
38
52
  # List of schedule objects used to hold calculation results
39
53
  ####
40
54
 
41
- # cold water control actuator
42
- # Command to turn ON/OFF the cold water through the radiant system. 0=ON and 100=OFF
43
- # Large temperatures are used to ensure that the radiant system valve will fully open and close
55
+ # get existing switchover time schedule or create one if needed
56
+ sch_radiant_switchover = model.getScheduleRulesetByName('Radiant System Switchover')
57
+ if sch_radiant_switchover.is_initialized
58
+ sch_radiant_switchover = sch_radiant_switchover.get
59
+ else
60
+ sch_radiant_switchover = model_add_constant_schedule_ruleset(model,
61
+ switch_over_time,
62
+ name = 'Radiant System Switchover',
63
+ sch_type_limit: 'Dimensionless')
64
+ end
65
+
66
+ # set radiant system switchover schedule
67
+ radiant_loop.setChangeoverDelayTimePeriodSchedule(sch_radiant_switchover.to_Schedule.get)
68
+
69
+ # Calculated active slab heating and cooling temperature setpoint.
70
+ # radiant system cooling control actuator
44
71
  sch_radiant_clgsetp = model_add_constant_schedule_ruleset(model,
45
- 0.0,
72
+ 26.0,
46
73
  name = "#{zone_name}_Sch_Radiant_ClgSetP")
47
74
  coil_cooling_radiant.setCoolingControlTemperatureSchedule(sch_radiant_clgsetp)
48
75
  cmd_cold_water_ctrl = OpenStudio::Model::EnergyManagementSystemActuator.new(sch_radiant_clgsetp,
49
76
  'Schedule:Year',
50
77
  'Schedule Value')
51
- cmd_cold_water_ctrl.setName("#{zone_name}_CMD_COLD_WATER_CTRL")
78
+ cmd_cold_water_ctrl.setName("#{zone_name}_cmd_cold_water_ctrl")
52
79
 
53
- # hot water control actuator
54
- # Command to turn ON/OFF the hot water through the radiant system. 60=ON and -60=OFF.
55
- # Large temperatures are used to to ensure that the radiant system valve will fully open and close
80
+ # radiant system heating control actuator
56
81
  sch_radiant_htgsetp = model_add_constant_schedule_ruleset(model,
57
- -60.0,
82
+ 20.0,
58
83
  name = "#{zone_name}_Sch_Radiant_HtgSetP")
59
84
  coil_heating_radiant.setHeatingControlTemperatureSchedule(sch_radiant_htgsetp)
60
85
  cmd_hot_water_ctrl = OpenStudio::Model::EnergyManagementSystemActuator.new(sch_radiant_htgsetp,
61
86
  'Schedule:Year',
62
87
  'Schedule Value')
63
- cmd_hot_water_ctrl.setName("#{zone_name}_CMD_HOT_WATER_CTRL")
64
-
65
- # set schedule type limits for hot water control
66
- hot_water_schedule_type_limits = model.getScheduleTypeLimitsByName('Radiant_Hot_water_Ctrl_Temperature_Limits')
67
- if hot_water_schedule_type_limits.is_initialized
68
- hot_water_schedule_type_limits = hot_water_schedule_type_limits.get
69
- else
70
- hot_water_schedule_type_limits = OpenStudio::Model::ScheduleTypeLimits.new(model)
71
- hot_water_schedule_type_limits.setName('Radiant_Hot_water_Ctrl_Temperature_Limits')
72
- hot_water_schedule_type_limits.setLowerLimitValue(-60.0)
73
- hot_water_schedule_type_limits.setUpperLimitValue(100.0)
74
- hot_water_schedule_type_limits.setNumericType('Continuous')
75
- hot_water_schedule_type_limits.setUnitType('Temperature')
76
- end
77
- sch_radiant_htgsetp.setScheduleTypeLimits(hot_water_schedule_type_limits)
78
-
79
- # Calculated active slab heating and cooling temperature setpoint. Default temperature is taken at the slab surface.
80
- sch_slab_sp = model_add_constant_schedule_ruleset(model,
81
- 21.0,
82
- name = "#{zone_name}_Sch_Slab_SP")
83
- cmd_slab_sp = OpenStudio::Model::EnergyManagementSystemActuator.new(sch_slab_sp,
84
- 'Schedule:Year',
85
- 'Schedule Value')
86
- cmd_slab_sp.setName("#{zone_name}_CMD_SLAB_SP")
87
-
88
- # add output variable for slab setpoint temperature
89
- var = OpenStudio::Model::OutputVariable.new('Schedule Value', model)
90
- var.setKeyValue("#{zone_name}_Sch_Slab_SP")
91
- var.setReportingFrequency('Timestep')
88
+ cmd_hot_water_ctrl.setName("#{zone_name}_cmd_hot_water_ctrl")
92
89
 
93
90
  # Calculated cooling setpoint error. Calculated from upper comfort limit minus setpoint offset and 'measured' controlled zone temperature.
94
91
  sch_csp_error = model_add_constant_schedule_ruleset(model,
@@ -97,7 +94,7 @@ class Standard
97
94
  cmd_csp_error = OpenStudio::Model::EnergyManagementSystemActuator.new(sch_csp_error,
98
95
  'Schedule:Year',
99
96
  'Schedule Value')
100
- cmd_csp_error.setName("#{zone_name}_CMD_CSP_ERROR")
97
+ cmd_csp_error.setName("#{zone_name}_cmd_csp_error")
101
98
 
102
99
  # Calculated heating setpoint error. Calculated from lower comfort limit plus setpoint offset and 'measured' controlled zone temperature.
103
100
  sch_hsp_error = model_add_constant_schedule_ruleset(model,
@@ -106,57 +103,12 @@ class Standard
106
103
  cmd_hsp_error = OpenStudio::Model::EnergyManagementSystemActuator.new(sch_hsp_error,
107
104
  'Schedule:Year',
108
105
  'Schedule Value')
109
- cmd_hsp_error.setName("#{zone_name}_CMD_HSP_ERROR")
110
-
111
- # Averaged radiant slab controlled temperature. Averaged over the last 24 hours.
112
- sch_avg_ctrl_temp = model_add_constant_schedule_ruleset(model,
113
- 20.0,
114
- name = "#{zone_name}_Sch_Avg_Ctrl_Temp")
115
- cmd_ctrl_temp_running_mean = OpenStudio::Model::EnergyManagementSystemActuator.new(sch_avg_ctrl_temp,
116
- 'Schedule:Year',
117
- 'Schedule Value')
118
- cmd_ctrl_temp_running_mean.setName("#{zone_name}_CMD_CTRL_TEMP_RUNNING_MEAN")
119
-
120
- # Averaged outdoor air temperature. Averaged over the last 24 hours.
121
- sch_oat_running_mean = model.getScheduleConstantByName('SCH_OAT_RUNNING_MEAN')
122
- if sch_oat_running_mean.is_initialized
123
- sch_oat_running_mean = sch_oat_running_mean.get
124
- else
125
- sch_oat_running_mean = model_add_constant_schedule_ruleset(model,
126
- 20.0,
127
- name = 'SCH_OAT_RUNNING_MEAN')
128
- end
129
-
130
- cmd_oat_running_mean = model.getEnergyManagementSystemActuatorByName('CMD_OAT_RUNNING_MEAN')
131
- if cmd_oat_running_mean.is_initialized
132
- cmd_oat_running_mean = cmd_oat_running_mean.get
133
- else
134
- cmd_oat_running_mean = OpenStudio::Model::EnergyManagementSystemActuator.new(sch_oat_running_mean,
135
- 'Schedule:Year',
136
- 'Schedule Value')
137
- cmd_oat_running_mean.setName('CMD_OAT_RUNNING_MEAN')
138
- end
106
+ cmd_hsp_error.setName("#{zone_name}_cmd_hsp_error")
139
107
 
140
108
  #####
141
109
  # List of global variables used in EMS scripts
142
110
  ####
143
111
 
144
- # Start of occupied time of zone. Valid from 1-24.
145
- occ_hr_start = model.getEnergyManagementSystemGlobalVariableByName('occ_hr_start')
146
- if occ_hr_start.is_initialized
147
- occ_hr_start = occ_hr_start.get
148
- else
149
- occ_hr_start = OpenStudio::Model::EnergyManagementSystemGlobalVariable.new(model, 'occ_hr_start')
150
- end
151
-
152
- # End of occupied time of zone. Valid from 1-24.
153
- occ_hr_end = model.getEnergyManagementSystemGlobalVariableByName('occ_hr_end')
154
- if occ_hr_end.is_initialized
155
- occ_hr_end = occ_hr_end.get
156
- else
157
- occ_hr_end = OpenStudio::Model::EnergyManagementSystemGlobalVariable.new(model, 'occ_hr_end')
158
- end
159
-
160
112
  # Proportional gain constant (recommended 0.3 or less).
161
113
  prp_k = model.getEnergyManagementSystemGlobalVariableByName('prp_k')
162
114
  if prp_k.is_initialized
@@ -165,55 +117,7 @@ class Standard
165
117
  prp_k = OpenStudio::Model::EnergyManagementSystemGlobalVariable.new(model, 'prp_k')
166
118
  end
167
119
 
168
- # mean outdoor dry-bulb air temperature
169
- mean_oat = model.getEnergyManagementSystemGlobalVariableByName('mean_oat')
170
- if mean_oat.is_initialized
171
- mean_oat = mean_oat.get
172
- else
173
- mean_oat = OpenStudio::Model::EnergyManagementSystemGlobalVariable.new(model, 'mean_oat')
174
- end
175
-
176
- # Is the day a weekend? 1=Weekend and 0=Not Weekend.
177
- weekend = model.getEnergyManagementSystemGlobalVariableByName('weekend')
178
- if weekend.is_initialized
179
- weekend = weekend.get
180
- else
181
- weekend = OpenStudio::Model::EnergyManagementSystemGlobalVariable.new(model, 'weekend')
182
- end
183
-
184
- # Is the building in unoccupied model? 1=Unoccupied and 0=Not Unoccupied.
185
- unoccupied = model.getEnergyManagementSystemGlobalVariableByName('unoccupied')
186
- if unoccupied.is_initialized
187
- unoccupied = unoccupied.get
188
- else
189
- unoccupied = OpenStudio::Model::EnergyManagementSystemGlobalVariable.new(model, 'unoccupied')
190
- end
191
-
192
- # Minimum number of hours of operation for radiant system before it shuts off.
193
- min_oper = model.getEnergyManagementSystemGlobalVariableByName('min_oper')
194
- if min_oper.is_initialized
195
- min_oper = min_oper.get
196
- else
197
- min_oper = OpenStudio::Model::EnergyManagementSystemGlobalVariable.new(model, 'min_oper')
198
- end
199
-
200
- # Weekend temperature reset for slab temperature setpoint in degree Celsius.
201
- wkend_temp_reset = model.getEnergyManagementSystemGlobalVariableByName('wkend_temp_reset')
202
- if wkend_temp_reset.is_initialized
203
- wkend_temp_reset = wkend_temp_reset.get
204
- else
205
- wkend_temp_reset = OpenStudio::Model::EnergyManagementSystemGlobalVariable.new(model, 'wkend_temp_reset')
206
- end
207
-
208
- # Time at which the weekend temperature reset is removed.
209
- early_reset_out = model.getEnergyManagementSystemGlobalVariableByName('early_reset_out')
210
- if early_reset_out.is_initialized
211
- early_reset_out = early_reset_out.get
212
- else
213
- early_reset_out = OpenStudio::Model::EnergyManagementSystemGlobalVariable.new(model, 'early_reset_out')
214
- end
215
-
216
- # Upper slab temperature setpoint limit
120
+ # Upper slab temperature setpoint limit (recommended no higher than 29C (84F))
217
121
  upper_slab_sp_lim = model.getEnergyManagementSystemGlobalVariableByName('upper_slab_sp_lim')
218
122
  if upper_slab_sp_lim.is_initialized
219
123
  upper_slab_sp_lim = upper_slab_sp_lim.get
@@ -221,7 +125,7 @@ class Standard
221
125
  upper_slab_sp_lim = OpenStudio::Model::EnergyManagementSystemGlobalVariable.new(model, 'upper_slab_sp_lim')
222
126
  end
223
127
 
224
- # Lower slab temperature setpoint limit
128
+ # Lower slab temperature setpoint limit (recommended no lower than 19C (66F))
225
129
  lower_slab_sp_lim = model.getEnergyManagementSystemGlobalVariableByName('lower_slab_sp_lim')
226
130
  if lower_slab_sp_lim.is_initialized
227
131
  lower_slab_sp_lim = lower_slab_sp_lim.get
@@ -229,7 +133,7 @@ class Standard
229
133
  lower_slab_sp_lim = OpenStudio::Model::EnergyManagementSystemGlobalVariable.new(model, 'lower_slab_sp_lim')
230
134
  end
231
135
 
232
- # Temperature offset used to modify.
136
+ # Temperature offset used as a safety factor for thermal control (recommend 0.5C (1F)).
233
137
  ctrl_temp_offset = model.getEnergyManagementSystemGlobalVariableByName('ctrl_temp_offset')
234
138
  if ctrl_temp_offset.is_initialized
235
139
  ctrl_temp_offset = ctrl_temp_offset.get
@@ -237,7 +141,17 @@ class Standard
237
141
  ctrl_temp_offset = OpenStudio::Model::EnergyManagementSystemGlobalVariable.new(model, 'ctrl_temp_offset')
238
142
  end
239
143
 
240
- # zone specific variables
144
+ # Hour where slab setpoint is to be changed
145
+ hour_of_slab_sp_change = model.getEnergyManagementSystemGlobalVariableByName('hour_of_slab_sp_change')
146
+ if hour_of_slab_sp_change.is_initialized
147
+ hour_of_slab_sp_change = hour_of_slab_sp_change.get
148
+ else
149
+ hour_of_slab_sp_change = OpenStudio::Model::EnergyManagementSystemGlobalVariable.new(model, 'hour_of_slab_sp_change')
150
+ end
151
+
152
+ #####
153
+ # List of zone specific variables used in EMS scripts
154
+ ####
241
155
 
242
156
  # Maximum 'measured' temperature in zone during occupied times. Default setup uses mean air temperature.
243
157
  # Other possible choices are operative and mean radiant temperature.
@@ -247,246 +161,189 @@ class Standard
247
161
  # Other possible choices are operative and mean radiant temperature.
248
162
  zone_min_ctrl_temp = OpenStudio::Model::EnergyManagementSystemGlobalVariable.new(model, "#{zone_name}_min_ctrl_temp")
249
163
 
250
- # mean temperature of control surface
251
- zone_mean_ctrl = OpenStudio::Model::EnergyManagementSystemGlobalVariable.new(model, "#{zone_name}_mean_ctrl")
252
-
253
- # Continuous operation where there is no active hydronic heating or cooling in thermal zone in hours.
254
- zone_cont_neutral_oper = OpenStudio::Model::EnergyManagementSystemGlobalVariable.new(model, "#{zone_name}_cont_neutral_oper")
255
-
256
- # Zone mode of thermal zone. -1=Heating, 1=Cooling, and 0=Neutral.
257
- zone_zone_mode = OpenStudio::Model::EnergyManagementSystemGlobalVariable.new(model, "#{zone_name}_zone_mode")
258
-
259
- # Amount of hours that building needs to be in neutral mode in order to switch over from heating to cooling or from cooling to heating.
260
- zone_switch_over_time = OpenStudio::Model::EnergyManagementSystemGlobalVariable.new(model, "#{zone_name}_switch_over_time")
261
-
262
- # Continuous operation when radiant system is active in hours.
263
- zone_cont_rad_oper = OpenStudio::Model::EnergyManagementSystemGlobalVariable.new(model, "#{zone_name}_cont_rad_oper")
264
-
265
- # Total time the radiant system was in cooling mode in the last 24 hours.
266
- # Calculated at one timestep before the end of occupied time.
267
- zone_daily_cool_sum = OpenStudio::Model::EnergyManagementSystemGlobalVariable.new(model, "#{zone_name}_daily_cool_sum")
268
-
269
- # Total time the radiant system was in heating mode in the last 24 hours.
270
- # Calculated at one timestep before the end of occupied time.
271
- zone_daily_heat_sum = OpenStudio::Model::EnergyManagementSystemGlobalVariable.new(model, "#{zone_name}_daily_heat_sum")
272
-
273
- # Total time the radiant system was in cooling mode for the previous day.
274
- zone_daily_cool_sum_one = OpenStudio::Model::EnergyManagementSystemGlobalVariable.new(model, "#{zone_name}_daily_cool_sum_one")
275
-
276
- # Total time the radiant system was in heating mode for the previous day.
277
- zone_daily_heat_sum_one = OpenStudio::Model::EnergyManagementSystemGlobalVariable.new(model, "#{zone_name}_daily_heat_sum_one")
278
-
279
164
  #####
280
165
  # List of 'sensors' used in the EMS programs
281
166
  ####
282
167
 
283
- # Outdoor air temperature.
284
- oat = model.getEnergyManagementSystemSensorByName('OAT')
285
- if oat.is_initialized
286
- oat = oat.get
287
- else
288
- oat = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Site Outdoor Air Drybulb Temperature')
289
- oat.setName('OAT')
290
- oat.setKeyName('Environment')
291
- end
292
-
293
- # Number of timesteps to average control temperature. (Currently unused)
294
- # avg_window_n = model.getEnergyManagementSystemSensorByName('avg_window_n')
295
- # if avg_window_n.is_initialized
296
- # avg_window_n = avg_window_n.get
297
- # else
298
- # avg_window_n = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Schedule Value')
299
- # avg_window_n.setName('avg_window_n')
300
- # avg_window_n.setKeyName('Sch_Slab_Ctrl_Avg_Window_N')
301
- # end
302
-
303
168
  # Controlled zone temperature for the zone.
304
169
  zone_ctrl_temperature = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Zone Air Temperature')
305
- zone_ctrl_temperature.setName("#{zone_name}_Ctrl_Temperature")
170
+ zone_ctrl_temperature.setName("#{zone_name}_ctrl_temperature")
306
171
  zone_ctrl_temperature.setKeyName(zone.name.get)
307
172
 
308
- # Active surface slab temperature. # Use largest surface in zone.
309
- surface_type = radiant_type == 'floor' ? 'Floor' : 'RoofCeiling'
310
- surfaces = []
311
- zone.spaces.each do |space|
312
- space.surfaces.each do |surface|
313
- surfaces << surface if surface.surfaceType == surface_type
314
- end
173
+ # check for zone thermostat and replace heat/cool schedules for radiant system control
174
+ # if there is no zone thermostat, then create one
175
+ zone_thermostat = zone.thermostatSetpointDualSetpoint
176
+
177
+ if zone_thermostat.is_initialized
178
+ OpenStudio.logFree(OpenStudio::Info, 'openstudio.Model.Model', "Replacing thermostat schedules in zone #{zone.name} for radiant system control.")
179
+ zone_thermostat = zone.thermostatSetpointDualSetpoint.get
180
+ else
181
+ OpenStudio.logFree(OpenStudio::Info, 'openstudio.Model.Model', "Zone #{zone.name} does not have a thermostat. Creating a thermostat for radiant system control.")
182
+ zone_thermostat = OpenStudio::Model::ThermostatSetpointDualSetpoint.new(model)
183
+ zone_thermostat.setName("#{zone_name}_Thermostat_DualSetpoint")
315
184
  end
316
- if surfaces.empty?
317
- OpenStudio.logFree(OpenStudio::Error, 'openstudio.Model.Model', "Zone #{zone.name} does not have floor surfaces; cannot add radiant system.")
318
- return false
185
+
186
+ # create new heating and cooling schedules to be used with all radiant systems
187
+ zone_htg_thermostat = model.getScheduleRulesetByName('Radiant System Heating Setpoint')
188
+ if zone_htg_thermostat.is_initialized
189
+ zone_htg_thermostat = zone_htg_thermostat.get
190
+ else
191
+ zone_htg_thermostat = model_add_constant_schedule_ruleset(model,
192
+ 20.0,
193
+ name = 'Radiant System Heating Setpoint',
194
+ sch_type_limit: 'Temperature')
319
195
  end
320
- zone_floor = surfaces.max_by(&:grossArea)
321
- zone_srf_temp = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Surface Inside Face Temperature')
322
- zone_srf_temp.setName("#{zone_name}_Srf_Temp")
323
- zone_srf_temp.setKeyName(zone_floor.name.get)
324
196
 
325
- # check for zone thermostats
326
- zone_thermostat = zone.thermostatSetpointDualSetpoint
327
- unless zone_thermostat.is_initialized
328
- OpenStudio.logFree(OpenStudio::Error, 'openstudio.Model.Model', "Zone #{zone.name} does not have thermostats.")
329
- return false
197
+ zone_clg_thermostat = model.getScheduleRulesetByName('Radiant System Cooling Setpoint')
198
+ if zone_clg_thermostat.is_initialized
199
+ zone_clg_thermostat = zone_clg_thermostat.get
200
+ else
201
+ zone_clg_thermostat = model_add_constant_schedule_ruleset(model,
202
+ 26.0,
203
+ name = 'Radiant System Cooling Setpoint',
204
+ sch_type_limit: 'Temperature')
330
205
  end
331
- zone_thermostat = zone.thermostatSetpointDualSetpoint.get
332
- zone_clg_thermostat = zone_thermostat.coolingSetpointTemperatureSchedule.get
333
- zone_htg_thermostat = zone_thermostat.heatingSetpointTemperatureSchedule.get
206
+
207
+ # implement new heating and cooling schedules
208
+ zone_thermostat.setHeatingSetpointTemperatureSchedule(zone_htg_thermostat)
209
+ zone_thermostat.setCoolingSetpointTemperatureSchedule(zone_clg_thermostat)
334
210
 
335
211
  # Upper comfort limit for the zone. Taken from existing thermostat schedules in the zone.
336
212
  zone_upper_comfort_limit = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Schedule Value')
337
- zone_upper_comfort_limit.setName("#{zone_name}_Upper_Comfort_Limit")
213
+ zone_upper_comfort_limit.setName("#{zone_name}_upper_comfort_limit")
338
214
  zone_upper_comfort_limit.setKeyName(zone_clg_thermostat.name.get)
339
215
 
340
216
  # Lower comfort limit for the zone. Taken from existing thermostat schedules in the zone.
341
217
  zone_lower_comfort_limit = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Schedule Value')
342
- zone_lower_comfort_limit.setName("#{zone_name}_Lower_Comfort_Limit")
218
+ zone_lower_comfort_limit.setName("#{zone_name}_lower_comfort_limit")
343
219
  zone_lower_comfort_limit.setKeyName(zone_htg_thermostat.name.get)
344
220
 
345
221
  # Radiant system water flow rate used to determine if there is active hydronic cooling in the radiant system.
346
222
  zone_rad_cool_operation = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'System Node Mass Flow Rate')
347
- zone_rad_cool_operation.setName("#{zone_name}_Rad_Cool_Operation")
223
+ zone_rad_cool_operation.setName("#{zone_name}_rad_cool_operation")
348
224
  zone_rad_cool_operation.setKeyName(coil_cooling_radiant.to_StraightComponent.get.inletModelObject.get.name.get)
349
225
 
350
226
  # Radiant system water flow rate used to determine if there is active hydronic heating in the radiant system.
351
227
  zone_rad_heat_operation = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'System Node Mass Flow Rate')
352
- zone_rad_heat_operation.setName("#{zone_name}_Rad_Heat_Operation")
228
+ zone_rad_heat_operation.setName("#{zone_name}_rad_heat_operation")
353
229
  zone_rad_heat_operation.setKeyName(coil_heating_radiant.to_StraightComponent.get.inletModelObject.get.name.get)
354
230
 
355
- # Last 24 hours trend for the outdoor air temperature.
356
- oat_trend = model.getEnergyManagementSystemTrendVariableByName('OAT_Trend')
357
- if oat_trend.is_initialized
358
- oat_trend = oat_trend.get
359
- else
360
- oat_trend = OpenStudio::Model::EnergyManagementSystemTrendVariable.new(model, oat)
361
- oat_trend.setName('OAT_Trend')
362
- oat_trend.setNumberOfTimestepsToBeLogged(zone_timestep * 24)
363
- end
231
+ # Radiant system switchover delay time period schedule
232
+ # used to determine if there is active hydronic cooling/heating in the radiant system.
233
+ zone_rad_switch_over = model.getEnergyManagementSystemSensorByName('radiant_switch_over_time')
364
234
 
365
- # Last 24 hours trend for active slab surface temperature.
366
- zone_srf_temp_trend = OpenStudio::Model::EnergyManagementSystemTrendVariable.new(model, zone_srf_temp)
367
- zone_srf_temp_trend.setName("#{zone_name}_Srf_Temp_Trend")
368
- zone_srf_temp_trend.setNumberOfTimestepsToBeLogged(zone_timestep * 24)
235
+ unless zone_rad_switch_over.is_initialized
236
+ zone_rad_switch_over = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Schedule Value')
237
+ zone_rad_switch_over.setName('radiant_switch_over_time')
238
+ zone_rad_switch_over.setKeyName(sch_radiant_switchover.name.get)
239
+ end
369
240
 
370
241
  # Last 24 hours trend for radiant system in cooling mode.
371
242
  zone_rad_cool_operation_trend = OpenStudio::Model::EnergyManagementSystemTrendVariable.new(model, zone_rad_cool_operation)
372
- zone_rad_cool_operation_trend.setName("#{zone_name}_Rad_Cool_Operation_Trend")
373
- zone_rad_cool_operation_trend.setNumberOfTimestepsToBeLogged(zone_timestep * 24)
243
+ zone_rad_cool_operation_trend.setName("#{zone_name}_rad_cool_operation_trend")
244
+ zone_rad_cool_operation_trend.setNumberOfTimestepsToBeLogged(zone_timestep * 48)
374
245
 
375
246
  # Last 24 hours trend for radiant system in heating mode.
376
247
  zone_rad_heat_operation_trend = OpenStudio::Model::EnergyManagementSystemTrendVariable.new(model, zone_rad_heat_operation)
377
- zone_rad_heat_operation_trend.setName("#{zone_name}_Rad_Heat_Operation_Trend")
378
- zone_rad_heat_operation_trend.setNumberOfTimestepsToBeLogged(zone_timestep * 24)
248
+ zone_rad_heat_operation_trend.setName("#{zone_name}_rad_heat_operation_trend")
249
+ zone_rad_heat_operation_trend.setNumberOfTimestepsToBeLogged(zone_timestep * 48)
250
+
251
+ # use zone occupancy objects for radiant system control if selected
252
+ if use_zone_occupancy_for_control
253
+
254
+ # get annual occupancy schedule for zone
255
+ occ_schedule_ruleset = thermal_zone_get_occupancy_schedule(zone,
256
+ sch_name: "#{zone.name} Radiant System Occupied Schedule",
257
+ occupied_percentage_threshold: occupied_percentage_threshold)
258
+ else
259
+
260
+ occ_schedule_ruleset = model.getScheduleRulesetByName('Whole Building Radiant System Occupied Schedule')
261
+ if occ_schedule_ruleset.is_initialized
262
+ occ_schedule_ruleset = occ_schedule_ruleset.get
263
+ else
264
+ # create occupancy schedules
265
+ occ_schedule_ruleset = OpenStudio::Model::ScheduleRuleset.new(model)
266
+ occ_schedule_ruleset.setName('Whole Building Radiant System Occupied Schedule')
267
+
268
+ start_hour = model_occ_hr_end.to_i
269
+ start_minute = ((model_occ_hr_end % 1) * 60).to_i
270
+ end_hour = model_occ_hr_start.to_i
271
+ end_minute = ((model_occ_hr_start % 1) * 60).to_i
272
+
273
+ if end_hour > start_hour
274
+ occ_schedule_ruleset.defaultDaySchedule.addValue(OpenStudio::Time.new(0, start_hour, start_minute, 0), 1.0)
275
+ occ_schedule_ruleset.defaultDaySchedule.addValue(OpenStudio::Time.new(0, end_hour, end_minute, 0), 0.0)
276
+ occ_schedule_ruleset.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), 1.0) if end_hour < 24
277
+ elsif start_hour > end_hour
278
+ occ_schedule_ruleset.defaultDaySchedule.addValue(OpenStudio::Time.new(0, end_hour, end_minute, 0), 0.0)
279
+ occ_schedule_ruleset.defaultDaySchedule.addValue(OpenStudio::Time.new(0, start_hour, start_minute, 0), 1.0)
280
+ occ_schedule_ruleset.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), 0.0) if start_hour < 24
281
+ else
282
+ occ_schedule_ruleset.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), 1.0)
283
+ end
284
+ end
285
+ end
286
+
287
+ # create ems sensor for zone occupied status
288
+ zone_occupied_status = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Schedule Value')
289
+ zone_occupied_status.setName("#{zone_name}_occupied_status")
290
+ zone_occupied_status.setKeyName(occ_schedule_ruleset.name.get)
291
+
292
+ # Last 24 hours trend for zone occupied status
293
+ zone_occupied_status_trend = OpenStudio::Model::EnergyManagementSystemTrendVariable.new(model, zone_occupied_status)
294
+ zone_occupied_status_trend.setName("#{zone_name}_occupied_status_trend")
295
+ zone_occupied_status_trend.setNumberOfTimestepsToBeLogged(zone_timestep * 48)
379
296
 
380
297
  #####
381
298
  # List of EMS programs to implement the proportional control for the radiant system.
382
299
  ####
383
300
 
384
301
  # Initialize global constant values used in EMS programs.
385
- set_constant_values_prg = model.getEnergyManagementSystemTrendVariableByName('Set_Constant_Values')
386
- unless set_constant_values_prg.is_initialized
302
+ set_constant_values_prg_body = <<-EMS
303
+ SET prp_k = #{proportional_gain},
304
+ SET ctrl_temp_offset = 0.5,
305
+ SET upper_slab_sp_lim = 29,
306
+ SET lower_slab_sp_lim = 19,
307
+ SET hour_of_slab_sp_change = 18
308
+ EMS
309
+
310
+ set_constant_values_prg = model.getEnergyManagementSystemProgramByName('Set_Constant_Values')
311
+ if set_constant_values_prg.is_initialized
312
+ set_constant_values_prg = set_constant_values_prg.get
313
+ else
387
314
  set_constant_values_prg = OpenStudio::Model::EnergyManagementSystemProgram.new(model)
388
315
  set_constant_values_prg.setName('Set_Constant_Values')
389
- set_constant_values_prg_body = <<-EMS
390
- SET occ_hr_start = #{model_occ_hr_start},
391
- SET occ_hr_end = #{model_occ_hr_end},
392
- SET prp_k = #{proportional_gain},
393
- SET min_oper = #{minimum_operation},
394
- SET ctrl_temp_offset = 0.5,
395
- SET wkend_temp_reset = #{weekend_temperature_reset},
396
- SET early_reset_out = #{early_reset_out_arg},
397
- SET upper_slab_sp_lim = 29,
398
- SET lower_slab_sp_lim = 19
399
- EMS
400
316
  set_constant_values_prg.setBody(set_constant_values_prg_body)
401
317
  end
402
318
 
403
- # Determine if it is a weekend or not a weekend schedule for the building.
404
- determine_weekend_prg = model.getEnergyManagementSystemTrendVariableByName('Determine_Weekend')
405
- unless determine_weekend_prg.is_initialized
406
- determine_weekend_prg = OpenStudio::Model::EnergyManagementSystemProgram.new(model)
407
- determine_weekend_prg.setName('Determine_Weekend')
408
- determine_weekend_prg_body = <<-EMS
409
- IF (DayOfWeek == 1) || (DayOfWeek == 7),
410
- SET weekend = 1,
411
- ELSEIF (DayOfWeek == 2) && (CurrentTime < occ_hr_start),
412
- SET weekend = 1,
413
- ELSEIF (DayOfWeek == 6) && (CurrentTime > occ_hr_end),
414
- SET weekend = 1,
415
- ELSE,
416
- SET weekend = 0,
417
- ENDIF
418
- EMS
419
- determine_weekend_prg.setBody(determine_weekend_prg_body)
420
- end
421
-
422
- # Determine if building is in unoccupied mode or not in unoccupied mode.
423
- determine_unoccupied_prg = model.getEnergyManagementSystemTrendVariableByName('Determine_Unoccupied')
424
- unless determine_unoccupied_prg.is_initialized
425
- determine_unoccupied_prg = OpenStudio::Model::EnergyManagementSystemProgram.new(model)
426
- determine_unoccupied_prg.setName('Determine_Unoccupied')
427
- determine_unoccupied_prg_body = <<-EMS
428
- IF (DayOfWeek == 1) || (DayOfWeek == 7),
429
- SET unoccupied = 0,
430
- ELSEIF (CurrentTime > occ_hr_end) || (CurrentTime < occ_hr_start),
431
- IF (DayOfWeek == 2) && (CurrentTime < occ_hr_start),
432
- SET unoccupied = 0,
433
- ELSEIF (DayOfWeek == 6) && (CurrentTime > occ_hr_end),
434
- SET unoccupied = 0,
435
- ELSE,
436
- SET unoccupied = 1,
437
- ENDIF,
438
- ELSE,
439
- SET unoccupied = 0,
440
- ENDIF
441
- EMS
442
- determine_unoccupied_prg.setBody(determine_unoccupied_prg_body)
443
- end
444
-
445
319
  # Initialize zone specific constant values used in EMS programs.
446
- set_constant_zone_values_prg = OpenStudio::Model::EnergyManagementSystemProgram.new(model)
447
- set_constant_zone_values_prg.setName("#{zone_name}_Set_Constant_Values")
448
320
  set_constant_zone_values_prg_body = <<-EMS
449
- SET #{zone_name}_max_ctrl_temp = #{zone_name}_Lower_Comfort_Limit,
450
- SET #{zone_name}_min_ctrl_temp = #{zone_name}_Upper_Comfort_Limit,
451
- SET #{zone_name}_cont_neutral_oper = 0,
452
- SET #{zone_name}_zone_mode = 0,
453
- SET #{zone_name}_switch_over_time = #{switch_over_time},
454
- SET #{zone_name}_CMD_CSP_ERROR = 0,
455
- SET #{zone_name}_CMD_HSP_ERROR = 0,
456
- SET #{zone_name}_CMD_SLAB_SP = #{zone_name}_Lower_Comfort_Limit,
457
- SET #{zone_name}_cont_rad_oper = 0,
458
- SET #{zone_name}_daily_cool_sum = 0,
459
- SET #{zone_name}_daily_heat_sum = 0,
460
- SET #{zone_name}_daily_cool_sum_one = 0,
461
- SET #{zone_name}_daily_heat_sum_one = 0
321
+ SET #{zone_name}_max_ctrl_temp = #{zone_name}_lower_comfort_limit,
322
+ SET #{zone_name}_min_ctrl_temp = #{zone_name}_upper_comfort_limit,
323
+ SET #{zone_name}_cmd_csp_error = 0,
324
+ SET #{zone_name}_cmd_hsp_error = 0,
325
+ SET #{zone_name}_cmd_cold_water_ctrl = #{zone_name}_upper_comfort_limit,
326
+ SET #{zone_name}_cmd_hot_water_ctrl = #{zone_name}_lower_comfort_limit
462
327
  EMS
463
- set_constant_zone_values_prg.setBody(set_constant_zone_values_prg_body)
464
328
 
465
- # Calculate temperature averages.
466
- calculate_trends_prg = OpenStudio::Model::EnergyManagementSystemProgram.new(model)
467
- calculate_trends_prg.setName("#{zone_name}_Calculate_Trends")
468
- calculate_trends_prg_body = <<-EMS
469
- SET mean_oat = @TrendAverage OAT_Trend 24/ZoneTimeStep,
470
- SET #{zone_name}_mean_ctrl = @TrendAverage #{zone_name}_Srf_Temp_Trend 24/ZoneTimeStep,
471
- SET CMD_OAT_RUNNING_MEAN = mean_oat + 0,
472
- SET #{zone_name}_CMD_CTRL_TEMP_RUNNING_MEAN = #{zone_name}_mean_ctrl + 0
473
- EMS
474
- calculate_trends_prg.setBody(calculate_trends_prg_body)
329
+ set_constant_zone_values_prg = OpenStudio::Model::EnergyManagementSystemProgram.new(model)
330
+ set_constant_zone_values_prg.setName("#{zone_name}_Set_Constant_Values")
331
+ set_constant_zone_values_prg.setBody(set_constant_zone_values_prg_body)
475
332
 
476
333
  # Calculate maximum and minimum 'measured' controlled temperature in the zone
477
334
  calculate_minmax_ctrl_temp_prg = OpenStudio::Model::EnergyManagementSystemProgram.new(model)
478
335
  calculate_minmax_ctrl_temp_prg.setName("#{zone_name}_Calculate_Extremes_In_Zone")
479
336
  calculate_minmax_ctrl_temp_prg_body = <<-EMS
480
- IF ((CurrentTime >= occ_hr_start) && (CurrentTime <= occ_hr_end)),
481
- IF #{zone_name}_Ctrl_Temperature > #{zone_name}_max_ctrl_temp,
482
- SET #{zone_name}_max_ctrl_temp = #{zone_name}_Ctrl_Temperature,
337
+ IF (#{zone_name}_occupied_status == 1),
338
+ IF #{zone_name}_ctrl_temperature > #{zone_name}_max_ctrl_temp,
339
+ SET #{zone_name}_max_ctrl_temp = #{zone_name}_ctrl_temperature,
483
340
  ENDIF,
484
- IF #{zone_name}_Ctrl_Temperature < #{zone_name}_min_ctrl_temp,
485
- SET #{zone_name}_min_ctrl_temp = #{zone_name}_Ctrl_Temperature,
341
+ IF #{zone_name}_ctrl_temperature < #{zone_name}_min_ctrl_temp,
342
+ SET #{zone_name}_min_ctrl_temp = #{zone_name}_ctrl_temperature,
486
343
  ENDIF,
487
344
  ELSE,
488
- SET #{zone_name}_max_ctrl_temp = #{zone_name}_Lower_Comfort_Limit,
489
- SET #{zone_name}_min_ctrl_temp = #{zone_name}_Upper_Comfort_Limit,
345
+ SET #{zone_name}_max_ctrl_temp = #{zone_name}_lower_comfort_limit,
346
+ SET #{zone_name}_min_ctrl_temp = #{zone_name}_upper_comfort_limit,
490
347
  ENDIF
491
348
  EMS
492
349
  calculate_minmax_ctrl_temp_prg.setBody(calculate_minmax_ctrl_temp_prg_body)
@@ -495,148 +352,48 @@ class Standard
495
352
  calculate_errors_from_comfort_prg = OpenStudio::Model::EnergyManagementSystemProgram.new(model)
496
353
  calculate_errors_from_comfort_prg.setName("#{zone_name}_Calculate_Errors_From_Comfort")
497
354
  calculate_errors_from_comfort_prg_body = <<-EMS
498
- IF (CurrentTime >= (occ_hr_end - ZoneTimeStep)) && (CurrentTime <= (occ_hr_end)),
499
- SET #{zone_name}_CMD_CSP_ERROR = (#{zone_name}_Upper_Comfort_Limit - ctrl_temp_offset) - #{zone_name}_max_ctrl_temp,
500
- SET #{zone_name}_CMD_HSP_ERROR = (#{zone_name}_Lower_Comfort_Limit + ctrl_temp_offset) - #{zone_name}_min_ctrl_temp,
355
+ IF (CurrentTime == (hour_of_slab_sp_change - ZoneTimeStep)),
356
+ SET #{zone_name}_cmd_csp_error = (#{zone_name}_upper_comfort_limit - ctrl_temp_offset) - #{zone_name}_max_ctrl_temp,
357
+ SET #{zone_name}_cmd_hsp_error = (#{zone_name}_lower_comfort_limit + ctrl_temp_offset) - #{zone_name}_min_ctrl_temp,
501
358
  ENDIF
502
359
  EMS
503
360
  calculate_errors_from_comfort_prg.setBody(calculate_errors_from_comfort_prg_body)
504
361
 
505
- # Calculate time when there is no active hydronic heating or cooling.
506
- calculate_neutral_time_prg = OpenStudio::Model::EnergyManagementSystemProgram.new(model)
507
- calculate_neutral_time_prg.setName("#{zone_name}_Calculate_Neutral_Time")
508
- calculate_neutral_time_prg_body = <<-EMS
509
- IF (#{zone_name}_Rad_Cool_Operation > 0) || (#{zone_name}_Rad_Heat_Operation > 0),
510
- SET #{zone_name}_cont_neutral_oper = 0,
511
- ELSE,
512
- SET #{zone_name}_cont_neutral_oper = #{zone_name}_cont_neutral_oper + ZoneTimeStep,
513
- ENDIF
514
- EMS
515
- calculate_neutral_time_prg.setBody(calculate_neutral_time_prg_body)
516
-
517
- # Calculate time when there is active hydronic heating or cooling in thermal zone.
518
- calculate_continuous_radiant_operation_prg = OpenStudio::Model::EnergyManagementSystemProgram.new(model)
519
- calculate_continuous_radiant_operation_prg.setName("#{zone_name}_Calculate_Continuous_Radiant_Operation")
520
- calculate_continuous_radiant_operation_prg_body = <<-EMS
521
- IF (#{zone_name}_Rad_Cool_Operation > 0) || (#{zone_name}_Rad_Heat_Operation > 0),
522
- SET #{zone_name}_cont_rad_oper = #{zone_name}_cont_rad_oper + ZoneTimeStep,
523
- ELSE,
524
- SET #{zone_name}_cont_rad_oper = 0,
525
- ENDIF
526
- EMS
527
- calculate_continuous_radiant_operation_prg.setBody(calculate_continuous_radiant_operation_prg_body)
528
-
529
- # Determine if the zone is in cooling, heating, or neutral mode.
530
- determine_zone_mode_prg = OpenStudio::Model::EnergyManagementSystemProgram.new(model)
531
- determine_zone_mode_prg.setName("#{zone_name}_Determine_Zone_Mode")
532
- determine_zone_mode_prg_body = <<-EMS
533
- SET #{zone_name}_cont_cool_oper = @TrendSum #{zone_name}_Rad_Cool_Operation_Trend 24/ZoneTimeStep,
534
- SET #{zone_name}_cont_heat_oper = @TrendSum #{zone_name}_Rad_Heat_Operation_Trend 24/ZoneTimeStep,
535
- IF (#{zone_name}_zone_mode <> 0) && (#{zone_name}_cont_neutral_oper > #{zone_name}_switch_over_time),
536
- SET #{zone_name}_zone_mode = 0,
537
- ELSEIF (#{zone_name}_cont_cool_oper > 0) && (#{zone_name}_zone_mode == 0),
538
- SET #{zone_name}_zone_mode = 1,
539
- ELSEIF (#{zone_name}_cont_heat_oper > 0) && (#{zone_name}_zone_mode == 0),
540
- SET #{zone_name}_zone_mode = -1,
541
- ELSE,
542
- SET #{zone_name}_zone_mode = #{zone_name}_zone_mode,
543
- ENDIF
544
- EMS
545
- determine_zone_mode_prg.setBody(determine_zone_mode_prg_body)
546
-
547
- # Calculate the cumulative time for active hydronic cooling and heating.
548
- calculate_cumulative_sum_prg = OpenStudio::Model::EnergyManagementSystemProgram.new(model)
549
- calculate_cumulative_sum_prg.setName("#{zone_name}_Calculate_Cumulative_Sum")
550
- calculate_cumulative_sum_prg_body = <<-EMS
551
- IF (CurrentTime == (occ_hr_end - ZoneTimeStep)),
552
- SET #{zone_name}_daily_cool_sum_one = #{zone_name}_daily_cool_sum,
553
- SET #{zone_name}_daily_heat_sum_one = #{zone_name}_daily_heat_sum,
554
- SET #{zone_name}_daily_cool_sum = @TrendSum #{zone_name}_Rad_Cool_Operation_Trend 24/ZoneTimeStep,
555
- SET #{zone_name}_daily_heat_sum = @TrendSum #{zone_name}_Rad_Heat_Operation_Trend 24/ZoneTimeStep,
556
- ENDIF
557
- EMS
558
- calculate_cumulative_sum_prg.setBody(calculate_cumulative_sum_prg_body)
559
-
560
362
  # Calculate the new active slab temperature setpoint for heating and cooling
561
363
  calculate_slab_ctrl_setpoint_prg = OpenStudio::Model::EnergyManagementSystemProgram.new(model)
562
364
  calculate_slab_ctrl_setpoint_prg.setName("#{zone_name}_Calculate_Slab_Ctrl_Setpoint")
563
365
  calculate_slab_ctrl_setpoint_prg_body = <<-EMS
564
- IF (#{zone_name}_zone_mode >= 0),
565
- SET #{zone_name}_cont_cool_oper = @TrendSum #{zone_name}_Rad_Cool_Operation_Trend 24/ZoneTimeStep,
566
- IF (#{zone_name}_cont_cool_oper > 0) && (CurrentTime == occ_hr_end),
567
- SET #{zone_name}_CMD_SLAB_SP = #{zone_name}_CMD_SLAB_SP + (#{zone_name}_CMD_CSP_ERROR*prp_k),
568
- ENDIF,
569
- ELSEIF (#{zone_name}_zone_mode <= 0),
570
- SET #{zone_name}_cont_heat_oper = @TrendSum #{zone_name}_Rad_Heat_Operation_Trend 24/ZoneTimeStep,
571
- IF (#{zone_name}_cont_heat_oper > 0) && (CurrentTime == occ_hr_end),
572
- SET #{zone_name}_CMD_SLAB_SP = #{zone_name}_CMD_SLAB_SP + (#{zone_name}_CMD_HSP_ERROR*prp_k),
573
- ENDIF,
366
+ SET #{zone_name}_cont_cool_oper = @TrendSum #{zone_name}_rad_cool_operation_trend radiant_switch_over_time/ZoneTimeStep,
367
+ SET #{zone_name}_cont_heat_oper = @TrendSum #{zone_name}_rad_heat_operation_trend radiant_switch_over_time/ZoneTimeStep,
368
+ SET #{zone_name}_occupied_hours = @TrendSum #{zone_name}_occupied_status_trend 24/ZoneTimeStep,
369
+ IF (#{zone_name}_cont_cool_oper > 0) && (#{zone_name}_occupied_hours > 0) && (CurrentTime == hour_of_slab_sp_change),
370
+ SET #{zone_name}_cmd_hot_water_ctrl = #{zone_name}_cmd_hot_water_ctrl + (#{zone_name}_cmd_csp_error*prp_k),
371
+ ELSEIF (#{zone_name}_cont_heat_oper > 0) && (#{zone_name}_occupied_hours > 0) && (CurrentTime == hour_of_slab_sp_change),
372
+ SET #{zone_name}_cmd_hot_water_ctrl = #{zone_name}_cmd_hot_water_ctrl + (#{zone_name}_cmd_hsp_error*prp_k),
373
+ ELSE,
374
+ SET #{zone_name}_cmd_hot_water_ctrl = #{zone_name}_cmd_hot_water_ctrl,
574
375
  ENDIF,
575
- IF (#{zone_name}_CMD_SLAB_SP < lower_slab_sp_lim),
576
- SET #{zone_name}_CMD_SLAB_SP = lower_slab_sp_lim,
577
- ELSEIF (#{zone_name}_CMD_SLAB_SP > upper_slab_sp_lim),
578
- SET #{zone_name}_CMD_SLAB_SP = upper_slab_sp_lim,
376
+ IF (#{zone_name}_cmd_hot_water_ctrl < lower_slab_sp_lim),
377
+ SET #{zone_name}_cmd_hot_water_ctrl = lower_slab_sp_lim,
378
+ ELSEIF (#{zone_name}_cmd_hot_water_ctrl > upper_slab_sp_lim),
379
+ SET #{zone_name}_cmd_hot_water_ctrl = upper_slab_sp_lim,
579
380
  ENDIF,
381
+ SET #{zone_name}_cmd_cold_water_ctrl = #{zone_name}_cmd_hot_water_ctrl + 0.01
580
382
  EMS
581
383
  calculate_slab_ctrl_setpoint_prg.setBody(calculate_slab_ctrl_setpoint_prg_body)
582
384
 
583
- # Apply a weekend setback at the start of a weekend and remove the reset at the defined time.
584
- implement_setback_prg = OpenStudio::Model::EnergyManagementSystemProgram.new(model)
585
- implement_setback_prg.setName("#{zone_name}_Implement_setback")
586
- implement_setback_prg_body = <<-EMS
587
- IF early_reset_out > occ_hr_start,
588
- SET turn_on_day = 1,
589
- SET turn_on_hour = 24 - (early_reset_out - occ_hr_start),
590
- ELSE,
591
- SET turn_on_day = 2,
592
- SET turn_on_hour = occ_hr_start - early_reset_out,
593
- ENDIF,
594
- IF (CurrentTime == occ_hr_end) && (DayOfWeek == 6),
595
- SET #{zone_name}_CMD_SLAB_SP = #{zone_name}_CMD_SLAB_SP,
596
- ELSEIF (CurrentTime == turn_on_hour) && (DayOfWeek == turn_on_day),
597
- SET #{zone_name}_CMD_SLAB_SP = #{zone_name}_CMD_SLAB_SP,
598
- ENDIF
599
- EMS
600
- implement_setback_prg.setBody(implement_setback_prg_body)
601
-
602
- # Get design day size
603
- num_design_days = model.getDesignDays.size
604
- OpenStudio.logFree(OpenStudio::Warn, 'openstudio.Model.Model', "EMS code for radiant system operation depends on the number of design days being fixed. The model has #{num_design_days}. Do not change design days now that the model has EMS code dependent on them. ")
605
-
606
- # Turn radiant system ON/OFF for cooling or heating based on calculated setpoints and building mode.
607
- determine_radiant_operation_prg = OpenStudio::Model::EnergyManagementSystemProgram.new(model)
608
- determine_radiant_operation_prg.setName("#{zone_name}_Determine_Radiant_Operation")
609
- determine_radiant_operation_prg_body = <<-EMS
610
- IF (CurrentEnvironment) <= #{num_design_days} ! Operation during design days
611
- SET #{zone_name}_CMD_COLD_WATER_CTRL = 0,
612
- SET #{zone_name}_CMD_HOT_WATER_CTRL = -60,
613
- ELSE, ! Operation during annual simulation
614
- IF (#{zone_name}_zone_mode >= 0) && (#{zone_name}_Srf_Temp > #{zone_name}_CMD_SLAB_SP),
615
- SET #{zone_name}_CMD_COLD_WATER_CTRL = 0,
616
- SET #{zone_name}_CMD_HOT_WATER_CTRL = -60,
617
- ELSEIF (#{zone_name}_zone_mode >= 0) && (#{zone_name}_Srf_Temp < #{zone_name}_CMD_SLAB_SP) && (min_oper > #{zone_name}_cont_rad_oper) && (#{zone_name}_cont_rad_oper <> 0),
618
- SET #{zone_name}_CMD_COLD_WATER_CTRL = 0,
619
- SET #{zone_name}_CMD_HOT_WATER_CTRL = -60,
620
- ELSEIF (#{zone_name}_zone_mode <= 0) && (#{zone_name}_Srf_Temp < #{zone_name}_CMD_SLAB_SP),
621
- SET #{zone_name}_CMD_COLD_WATER_CTRL = 100,
622
- SET #{zone_name}_CMD_HOT_WATER_CTRL = 60,
623
- ELSEIF (#{zone_name}_zone_mode <= 0) && (#{zone_name}_Srf_Temp > #{zone_name}_CMD_SLAB_SP) && (min_oper > #{zone_name}_cont_rad_oper) && (#{zone_name}_cont_rad_oper <> 0),
624
- SET #{zone_name}_CMD_COLD_WATER_CTRL = 100,
625
- SET #{zone_name}_CMD_HOT_WATER_CTRL = 60,
626
- ELSE,
627
- SET #{zone_name}_CMD_COLD_WATER_CTRL = 60,
628
- SET #{zone_name}_CMD_HOT_WATER_CTRL = -60,
629
- ENDIF,
630
- ENDIF
631
- EMS
632
- determine_radiant_operation_prg.setBody(determine_radiant_operation_prg_body)
633
-
634
385
  #####
635
386
  # List of EMS program manager objects
636
387
  ####
637
- initialize_constant_parameters = model.getEnergyManagementSystemProgramCallingManagerByName('Set_Constant_Values')
388
+
389
+ initialize_constant_parameters = model.getEnergyManagementSystemProgramCallingManagerByName('Initialize_Constant_Parameters')
638
390
  if initialize_constant_parameters.is_initialized
639
391
  initialize_constant_parameters = initialize_constant_parameters.get
392
+ # add program if it does not exist in manager
393
+ existing_program_names = initialize_constant_parameters.programs.collect { |prg| prg.name.get.downcase }
394
+ unless existing_program_names.include? set_constant_values_prg.name.get.downcase
395
+ initialize_constant_parameters.addProgram(set_constant_values_prg)
396
+ end
640
397
  else
641
398
  initialize_constant_parameters = OpenStudio::Model::EnergyManagementSystemProgramCallingManager.new(model)
642
399
  initialize_constant_parameters.setName('Initialize_Constant_Parameters')
@@ -644,13 +401,18 @@ class Standard
644
401
  initialize_constant_parameters.addProgram(set_constant_values_prg)
645
402
  end
646
403
 
647
- initialize_constant_parameters_after_warmup = model.getEnergyManagementSystemProgramCallingManagerByName('Set_Constant_Values')
404
+ initialize_constant_parameters_after_warmup = model.getEnergyManagementSystemProgramCallingManagerByName('Initialize_Constant_Parameters_After_Warmup')
648
405
  if initialize_constant_parameters_after_warmup.is_initialized
649
406
  initialize_constant_parameters_after_warmup = initialize_constant_parameters_after_warmup.get
407
+ # add program if it does not exist in manager
408
+ existing_program_names = initialize_constant_parameters_after_warmup.programs.collect { |prg| prg.name.get.downcase }
409
+ unless existing_program_names.include? set_constant_values_prg.name.get.downcase
410
+ initialize_constant_parameters_after_warmup.addProgram(set_constant_values_prg)
411
+ end
650
412
  else
651
413
  initialize_constant_parameters_after_warmup = OpenStudio::Model::EnergyManagementSystemProgramCallingManager.new(model)
652
414
  initialize_constant_parameters_after_warmup.setName('Initialize_Constant_Parameters_After_Warmup')
653
- initialize_constant_parameters_after_warmup.setCallingPoint('BeginNewEnvironment')
415
+ initialize_constant_parameters_after_warmup.setCallingPoint('AfterNewEnvironmentWarmUpIsComplete')
654
416
  initialize_constant_parameters_after_warmup.addProgram(set_constant_values_prg)
655
417
  end
656
418
 
@@ -661,7 +423,7 @@ class Standard
661
423
 
662
424
  zone_initialize_constant_parameters_after_warmup = OpenStudio::Model::EnergyManagementSystemProgramCallingManager.new(model)
663
425
  zone_initialize_constant_parameters_after_warmup.setName("#{zone_name}_Initialize_Constant_Parameters_After_Warmup")
664
- zone_initialize_constant_parameters_after_warmup.setCallingPoint('BeginNewEnvironment')
426
+ zone_initialize_constant_parameters_after_warmup.setCallingPoint('AfterNewEnvironmentWarmUpIsComplete')
665
427
  zone_initialize_constant_parameters_after_warmup.addProgram(set_constant_zone_values_prg)
666
428
 
667
429
  average_building_temperature = OpenStudio::Model::EnergyManagementSystemProgramCallingManager.new(model)
@@ -669,42 +431,139 @@ class Standard
669
431
  average_building_temperature.setCallingPoint('EndOfZoneTimestepAfterZoneReporting')
670
432
  average_building_temperature.addProgram(calculate_minmax_ctrl_temp_prg)
671
433
  average_building_temperature.addProgram(calculate_errors_from_comfort_prg)
672
- average_building_temperature.addProgram(calculate_neutral_time_prg)
673
- average_building_temperature.addProgram(determine_zone_mode_prg)
674
- average_building_temperature.addProgram(calculate_trends_prg)
675
- average_building_temperature.addProgram(calculate_continuous_radiant_operation_prg)
676
- average_building_temperature.addProgram(calculate_cumulative_sum_prg)
677
434
 
678
435
  programs_at_beginning_of_timestep = OpenStudio::Model::EnergyManagementSystemProgramCallingManager.new(model)
679
436
  programs_at_beginning_of_timestep.setName("#{zone_name}_Programs_At_Beginning_Of_Timestep")
680
437
  programs_at_beginning_of_timestep.setCallingPoint('BeginTimestepBeforePredictor')
681
- programs_at_beginning_of_timestep.addProgram(determine_weekend_prg)
682
- programs_at_beginning_of_timestep.addProgram(determine_unoccupied_prg)
683
- programs_at_beginning_of_timestep.addProgram(determine_zone_mode_prg)
684
- programs_at_beginning_of_timestep.addProgram(implement_setback_prg)
685
438
  programs_at_beginning_of_timestep.addProgram(calculate_slab_ctrl_setpoint_prg)
686
- programs_at_beginning_of_timestep.addProgram(determine_radiant_operation_prg)
687
439
 
688
440
  #####
689
441
  # List of variables for output.
690
442
  ####
443
+
691
444
  zone_max_ctrl_temp_output = OpenStudio::Model::EnergyManagementSystemOutputVariable.new(model, zone_max_ctrl_temp)
692
445
  zone_max_ctrl_temp_output.setName("#{zone_name} Maximum occupied temperature in zone")
693
446
  zone_min_ctrl_temp_output = OpenStudio::Model::EnergyManagementSystemOutputVariable.new(model, zone_min_ctrl_temp)
694
447
  zone_min_ctrl_temp_output.setName("#{zone_name} Minimum occupied temperature in zone")
695
- zone_zone_mode_output = OpenStudio::Model::EnergyManagementSystemOutputVariable.new(model, zone_zone_mode)
696
- zone_zone_mode_output.setName("#{zone_name} Zone Mode of Operation")
697
- zone_cont_neutral_oper_output = OpenStudio::Model::EnergyManagementSystemOutputVariable.new(model, zone_cont_neutral_oper)
698
- zone_cont_neutral_oper_output.setName("#{zone_name} Number of Hours in Neutral Operation")
699
- zone_cont_rad_oper_output = OpenStudio::Model::EnergyManagementSystemOutputVariable.new(model, zone_cont_rad_oper)
700
- zone_cont_rad_oper_output.setName("#{zone_name} Number of Hours in Continuous Operation")
701
- zone_daily_cool_sum_output = OpenStudio::Model::EnergyManagementSystemOutputVariable.new(model, zone_daily_cool_sum)
702
- zone_daily_cool_sum_output.setName("#{zone_name} Daily Building Cool Operation")
703
- zone_daily_heat_sum_output = OpenStudio::Model::EnergyManagementSystemOutputVariable.new(model, zone_daily_heat_sum)
704
- zone_daily_heat_sum_output.setName("#{zone_name} Daily Building Heat Operation")
705
- zone_daily_cool_sum_one_output = OpenStudio::Model::EnergyManagementSystemOutputVariable.new(model, zone_daily_cool_sum_one)
706
- zone_daily_cool_sum_one_output.setName("#{zone_name} Daily Building Cool Operation One")
707
- zone_daily_heat_sum_one_output = OpenStudio::Model::EnergyManagementSystemOutputVariable.new(model, zone_daily_heat_sum_one)
708
- zone_daily_heat_sum_one_output.setName("#{zone_name} Daily Building Heat Operation One")
448
+ end
449
+
450
+ # Native EnergyPlus objects implement a control for a single thermal zone with a radiant system.
451
+ # @param zone [OpenStudio::Model::ThermalZone>] zone to add radiant controls
452
+ # @param radiant_loop [OpenStudio::Model::ZoneHVACLowTempRadiantVarFlow>] radiant loop in thermal zone
453
+ # @param radiant_temperature_control_type [String] determines the controlled temperature for the radiant system
454
+ # options are 'SurfaceFaceTemperature', 'SurfaceInteriorTemperature'
455
+ # @param slab_setpoint_oa_control [Bool] True if slab setpoint is to be varied based on outdoor air temperature
456
+ # @param switch_over_time [Double] Time limitation for when the system can switch between heating and cooling
457
+ # @param slab_sp_at_oat_low [Double] radiant slab temperature setpoint, in F, at the outdoor high temperature.
458
+ # @param slab_oat_low [Double] outdoor drybulb air temperature, in F, for low radiant slab setpoint.
459
+ # @param slab_sp_at_oat_high [Double] radiant slab temperature setpoint, in F, at the outdoor low temperature.
460
+ # @param slab_oat_high [Double] outdoor drybulb air temperature, in F, for high radiant slab setpoint.
461
+ def model_add_radiant_basic_controls(model, zone, radiant_loop,
462
+ radiant_temperature_control_type: 'SurfaceFaceTemperature',
463
+ slab_setpoint_oa_control: false,
464
+ switch_over_time: 24.0,
465
+ slab_sp_at_oat_low: 73,
466
+ slab_oat_low: 65,
467
+ slab_sp_at_oat_high: 68,
468
+ slab_oat_high: 80)
469
+
470
+ zone_name = zone.name.to_s.gsub(/[ +-.]/, '_')
471
+
472
+ if model.version < OpenStudio::VersionString.new('3.1.1')
473
+ coil_cooling_radiant = radiant_loop.coolingCoil.to_CoilCoolingLowTempRadiantVarFlow.get
474
+ coil_heating_radiant = radiant_loop.heatingCoil.to_CoilHeatingLowTempRadiantVarFlow.get
475
+ else
476
+ coil_cooling_radiant = radiant_loop.coolingCoil.get.to_CoilCoolingLowTempRadiantVarFlow.get
477
+ coil_heating_radiant = radiant_loop.heatingCoil.get.to_CoilHeatingLowTempRadiantVarFlow.get
478
+ end
479
+
480
+ #####
481
+ # Define radiant system parameters
482
+ ####
483
+ # set radiant system temperature and setpoint control type
484
+ unless ['surfacefacetemperature', 'surfaceinteriortemperature'].include? radiant_temperature_control_type.downcase
485
+ OpenStudio.logFree(OpenStudio::Error, 'openstudio.Model.Model',
486
+ "Control sequences not compatible with '#{radiant_temperature_control_type}' radiant system control. Defaulting to 'SurfaceFaceTemperature'.")
487
+ radiant_temperature_control_type = 'SurfaceFaceTemperature'
488
+ end
489
+
490
+ radiant_loop.setTemperatureControlType(radiant_temperature_control_type)
491
+
492
+ # get existing switchover time schedule or create one if needed
493
+ sch_radiant_switchover = model.getScheduleRulesetByName('Radiant System Switchover')
494
+ if sch_radiant_switchover.is_initialized
495
+ sch_radiant_switchover = sch_radiant_switchover.get
496
+ else
497
+ sch_radiant_switchover = model_add_constant_schedule_ruleset(model,
498
+ switch_over_time,
499
+ name = 'Radiant System Switchover',
500
+ sch_type_limit: 'Dimensionless')
501
+ end
502
+
503
+ # set radiant system switchover schedule
504
+ radiant_loop.setChangeoverDelayTimePeriodSchedule(sch_radiant_switchover.to_Schedule.get)
505
+
506
+ if slab_setpoint_oa_control
507
+ # get weather file from model
508
+ weather_file = model.getWeatherFile
509
+ if weather_file.initialized
510
+ # get annual outdoor dry bulb temperature
511
+ annual_oat = weather_file.file.get.data.collect { |dat| dat.dryBulbTemperature.get }
512
+
513
+ # calculate a nhrs rolling average from annual outdoor dry bulb temperature
514
+ nhrs = 24
515
+ last_nhrs_oat_in_year = annual_oat.last(nhrs - 1)
516
+ combined_oat = last_nhrs_oat_in_year + annual_oat
517
+ oat_rolling_average = combined_oat.each_cons(nhrs).map { |e| e.reduce(&:+).fdiv(nhrs).round(2) }
518
+
519
+ # use rolling average to calculate slab setpoint temperature
520
+
521
+ # convert temperature from IP to SI units
522
+ slab_sp_at_oat_low_si = OpenStudio.convert(slab_sp_at_oat_low, 'F', 'C').get
523
+ slab_oat_low_si = OpenStudio.convert(slab_oat_low, 'F', 'C').get
524
+ slab_sp_at_oat_high_si = OpenStudio.convert(slab_sp_at_oat_high, 'F', 'C').get
525
+ slab_oat_high_si = OpenStudio.convert(slab_oat_high, 'F', 'C').get
526
+
527
+ # calculate relationship between slab setpoint and slope
528
+ slope_num = slab_sp_at_oat_high_si - slab_sp_at_oat_low_si
529
+ slope_den = slab_oat_high_si - slab_oat_low_si
530
+ sp_and_oat_slope = slope_num.fdiv(slope_den).round(4)
531
+
532
+ slab_setpoint = oat_rolling_average.map { |e| (slab_sp_at_oat_low_si + ((e - slab_oat_low_si) * sp_and_oat_slope)).round(1) }
533
+
534
+ # input upper limits on slab setpoint
535
+ slab_sp_upper_limit = [slab_sp_at_oat_high_si, slab_sp_at_oat_low_si].max
536
+ slab_sp_lower_limit = [slab_sp_at_oat_high_si, slab_sp_at_oat_low_si].min
537
+ slab_setpoint.map! { |e| e > slab_sp_upper_limit ? slab_sp_upper_limit.round(1) : e }
538
+
539
+ # input lower limits on slab setpoint
540
+ slab_setpoint.map! { |e| e < slab_sp_lower_limit ? slab_sp_lower_limit.round(1) : e }
541
+
542
+ # create ruleset for slab setpoint
543
+ sch_type_limits_obj = model_add_schedule_type_limits(model, standard_sch_type_limit: 'Temperature')
544
+ sch_radiant_slab_setp = make_ruleset_sched_from_8760(model, slab_setpoint,
545
+ 'Sch_Radiant_SlabSetP_Based_On_Rolling_Mean_OAT',
546
+ sch_type_limits_obj)
547
+
548
+ coil_heating_radiant.setHeatingControlTemperatureSchedule(sch_radiant_slab_setp)
549
+ coil_cooling_radiant.setCoolingControlTemperatureSchedule(sch_radiant_slab_setp)
550
+ else
551
+ OpenStudio.logFree(OpenStudio::Error, 'openstudio.Model.Model',
552
+ 'Model does not have a weather file associated with it. Define to implement slab setpoint based on outdoor weather.')
553
+ end
554
+ else
555
+ # radiant system cooling control setpoint
556
+ slab_setpoint = 22
557
+ sch_radiant_clgsetp = model_add_constant_schedule_ruleset(model,
558
+ slab_setpoint + 0.1,
559
+ name = "#{zone_name}_Sch_Radiant_ClgSetP")
560
+ coil_cooling_radiant.setCoolingControlTemperatureSchedule(sch_radiant_clgsetp)
561
+
562
+ # radiant system heating control setpoint
563
+ sch_radiant_htgsetp = model_add_constant_schedule_ruleset(model,
564
+ slab_setpoint,
565
+ name = "#{zone_name}_Sch_Radiant_HtgSetP")
566
+ coil_heating_radiant.setHeatingControlTemperatureSchedule(sch_radiant_htgsetp)
567
+ end
709
568
  end
710
569
  end