openstudio-standards 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (120) hide show
  1. checksums.yaml +4 -4
  2. data/data/standards/OpenStudio_Standards.xlsx +0 -0
  3. data/data/standards/OpenStudio_Standards_boilers.json +62 -4
  4. data/data/standards/OpenStudio_Standards_chillers.json +778 -68
  5. data/data/standards/OpenStudio_Standards_construction_sets.json +52 -93
  6. data/data/standards/OpenStudio_Standards_curve_biquadratics.json +36 -36
  7. data/data/standards/OpenStudio_Standards_curve_quadratics.json +3 -3
  8. data/data/standards/OpenStudio_Standards_heat_pumps.json +840 -0
  9. data/data/standards/OpenStudio_Standards_heat_pumps_heating.json +352 -0
  10. data/data/standards/OpenStudio_Standards_heat_rejection.json +48 -0
  11. data/data/standards/OpenStudio_Standards_motors.json +270 -0
  12. data/data/standards/OpenStudio_Standards_space_types.json +10390 -2824
  13. data/data/standards/OpenStudio_Standards_unitary_acs.json +794 -18
  14. data/data/weather/USA_CO_Boulder-Broomfield-Jefferson.County.AP.724699_TMY3.ddy +538 -0
  15. data/data/weather/USA_CO_Boulder-Broomfield-Jefferson.County.AP.724699_TMY3.epw +8768 -0
  16. data/data/weather/USA_CO_Boulder-Broomfield-Jefferson.County.AP.724699_TMY3.stat +493 -0
  17. data/data/weather/USA_CO_Denver.Intl.AP.725650_TMY3.ddy +536 -0
  18. data/data/weather/USA_CO_Denver.Intl.AP.725650_TMY3.epw +8768 -0
  19. data/data/weather/USA_CO_Denver.Intl.AP.725650_TMY3.stat +554 -0
  20. data/data/weather/USA_CO_Fort.Collins.AWOS.724769_TMY3.ddy +536 -0
  21. data/data/weather/USA_CO_Fort.Collins.AWOS.724769_TMY3.epw +8768 -0
  22. data/data/weather/USA_CO_Fort.Collins.AWOS.724769_TMY3.stat +554 -0
  23. data/data/weather/envelope_info.csv +6 -0
  24. data/lib/openstudio-standards.rb +10 -11
  25. data/lib/openstudio-standards/btap/compliance.rb +251 -969
  26. data/lib/openstudio-standards/btap/envelope.rb +1 -1
  27. data/lib/openstudio-standards/btap/fileio.rb +37 -5
  28. data/lib/openstudio-standards/btap/geometry.rb +27 -17
  29. data/lib/openstudio-standards/btap/hvac.rb +80 -27
  30. data/lib/openstudio-standards/hvac_sizing/{HVACSizing.CoilHeatingDXMultiSpeed.rb → Siz.CoilHeatingDXMultiSpeed.rb} +0 -0
  31. data/lib/openstudio-standards/hvac_sizing/Siz.ControllerOutdoorAir.rb +30 -4
  32. data/lib/openstudio-standards/hvac_sizing/Siz.CoolingTowerTwoSpeed.rb +61 -5
  33. data/lib/openstudio-standards/hvac_sizing/Siz.CoolingTowerVariableSpeed.rb +37 -7
  34. data/lib/openstudio-standards/hvac_sizing/Siz.DistrictCooling.rb +27 -0
  35. data/lib/openstudio-standards/hvac_sizing/Siz.DistrictHeating.rb +27 -0
  36. data/lib/openstudio-standards/hvac_sizing/Siz.HeaderedPumpsConstantSpeed.rb +55 -0
  37. data/lib/openstudio-standards/hvac_sizing/Siz.HeaderedPumpsVariableSpeed.rb +55 -0
  38. data/lib/openstudio-standards/hvac_sizing/Siz.HeatingCoolingFuels.rb +51 -9
  39. data/lib/openstudio-standards/hvac_sizing/Siz.Model.rb +99 -17
  40. data/lib/openstudio-standards/hvac_sizing/Siz.PumpConstantSpeed.rb +1 -1
  41. data/lib/openstudio-standards/hvac_sizing/Siz.ThermalZone.rb +29 -6
  42. data/lib/openstudio-standards/hvac_sizing/Siz.WaterHeaterMixed.rb +16 -0
  43. data/lib/openstudio-standards/prototypes/Prototype.AirTerminalSingleDuctVAVReheat.rb +43 -48
  44. data/lib/openstudio-standards/prototypes/Prototype.ControllerWaterCoil.rb +5 -9
  45. data/lib/openstudio-standards/prototypes/Prototype.Fan.rb +68 -0
  46. data/lib/openstudio-standards/prototypes/Prototype.FanConstantVolume.rb +39 -43
  47. data/lib/openstudio-standards/prototypes/Prototype.FanOnOff.rb +49 -51
  48. data/lib/openstudio-standards/prototypes/Prototype.FanVariableVolume.rb +55 -61
  49. data/lib/openstudio-standards/prototypes/Prototype.FanZoneExhaust.rb +8 -10
  50. data/lib/openstudio-standards/prototypes/Prototype.HeatExchangerAirToAirSensibleAndLatent.rb +15 -20
  51. data/lib/openstudio-standards/prototypes/Prototype.Model.hvac.rb +330 -322
  52. data/lib/openstudio-standards/prototypes/Prototype.Model.rb +501 -446
  53. data/lib/openstudio-standards/prototypes/Prototype.Model.swh.rb +221 -230
  54. data/lib/openstudio-standards/prototypes/Prototype.add_objects.rb +0 -2
  55. data/lib/openstudio-standards/prototypes/Prototype.full_service_restaurant.rb +130 -137
  56. data/lib/openstudio-standards/prototypes/Prototype.high_rise_apartment.rb +374 -291
  57. data/lib/openstudio-standards/prototypes/Prototype.hospital.rb +146 -193
  58. data/lib/openstudio-standards/prototypes/Prototype.hvac_systems.rb +1315 -1113
  59. data/lib/openstudio-standards/prototypes/Prototype.large_hotel.rb +65 -88
  60. data/lib/openstudio-standards/prototypes/Prototype.large_office.rb +101 -156
  61. data/lib/openstudio-standards/prototypes/Prototype.medium_office.rb +46 -96
  62. data/lib/openstudio-standards/prototypes/Prototype.mid_rise_apartment.rb +113 -123
  63. data/lib/openstudio-standards/prototypes/Prototype.outpatient.rb +356 -345
  64. data/lib/openstudio-standards/prototypes/Prototype.primary_school.rb +48 -103
  65. data/lib/openstudio-standards/prototypes/Prototype.quick_service_restaurant.rb +115 -123
  66. data/lib/openstudio-standards/prototypes/Prototype.retail_standalone.rb +30 -39
  67. data/lib/openstudio-standards/prototypes/Prototype.retail_stripmall.rb +32 -45
  68. data/lib/openstudio-standards/prototypes/Prototype.secondary_school.rb +98 -258
  69. data/lib/openstudio-standards/prototypes/Prototype.small_hotel.rb +429 -474
  70. data/lib/openstudio-standards/prototypes/Prototype.small_office.rb +28 -36
  71. data/lib/openstudio-standards/prototypes/Prototype.strip_model.rb +7 -7
  72. data/lib/openstudio-standards/prototypes/Prototype.utilities.rb +172 -146
  73. data/lib/openstudio-standards/prototypes/Prototype.warehouse.rb +46 -53
  74. data/lib/openstudio-standards/standards/Standards.AirLoopHVAC.rb +885 -707
  75. data/lib/openstudio-standards/standards/Standards.AirTerminalSingleDuctParallelPIUReheat.rb +48 -57
  76. data/lib/openstudio-standards/standards/Standards.AirTerminalSingleDuctVAVReheat.rb +24 -31
  77. data/lib/openstudio-standards/standards/Standards.BoilerHotWater.rb +80 -93
  78. data/lib/openstudio-standards/standards/Standards.BuildingStory.rb +69 -0
  79. data/lib/openstudio-standards/standards/Standards.ChillerElectricEIR.rb +60 -72
  80. data/lib/openstudio-standards/standards/Standards.CoilCoolingDXMultiSpeed.rb +104 -108
  81. data/lib/openstudio-standards/standards/Standards.CoilCoolingDXSingleSpeed.rb +190 -198
  82. data/lib/openstudio-standards/standards/Standards.CoilCoolingDXTwoSpeed.rb +134 -146
  83. data/lib/openstudio-standards/standards/Standards.CoilHeatingDXMultiSpeed.rb +56 -60
  84. data/lib/openstudio-standards/standards/Standards.CoilHeatingDXSingleSpeed.rb +151 -161
  85. data/lib/openstudio-standards/standards/Standards.CoilHeatingGasMultiStage.rb +30 -34
  86. data/lib/openstudio-standards/standards/Standards.Construction.rb +116 -132
  87. data/lib/openstudio-standards/standards/Standards.CoolingTower.rb +138 -0
  88. data/lib/openstudio-standards/standards/Standards.CoolingTowerSingleSpeed.rb +11 -0
  89. data/lib/openstudio-standards/standards/Standards.CoolingTowerTwoSpeed.rb +11 -0
  90. data/lib/openstudio-standards/standards/Standards.CoolingTowerVariableSpeed.rb +16 -0
  91. data/lib/openstudio-standards/standards/Standards.Fan.rb +190 -236
  92. data/lib/openstudio-standards/standards/Standards.FanConstantVolume.rb +0 -2
  93. data/lib/openstudio-standards/standards/Standards.FanOnOff.rb +0 -2
  94. data/lib/openstudio-standards/standards/Standards.FanVariableVolume.rb +168 -14
  95. data/lib/openstudio-standards/standards/Standards.FanZoneExhaust.rb +0 -2
  96. data/lib/openstudio-standards/standards/Standards.HeaderedPumpsConstantSpeed.rb +33 -0
  97. data/lib/openstudio-standards/standards/Standards.HeaderedPumpsVariableSpeed.rb +83 -0
  98. data/lib/openstudio-standards/standards/Standards.HeatExchangerSensLat.rb +22 -0
  99. data/lib/openstudio-standards/standards/Standards.Model.rb +2385 -1622
  100. data/lib/openstudio-standards/standards/Standards.PlanarSurface.rb +83 -35
  101. data/lib/openstudio-standards/standards/Standards.PlantLoop.rb +805 -395
  102. data/lib/openstudio-standards/standards/Standards.Pump.rb +139 -119
  103. data/lib/openstudio-standards/standards/Standards.PumpConstantSpeed.rb +0 -2
  104. data/lib/openstudio-standards/standards/Standards.PumpVariableSpeed.rb +16 -15
  105. data/lib/openstudio-standards/standards/Standards.ScheduleCompact.rb +35 -0
  106. data/lib/openstudio-standards/standards/Standards.ScheduleConstant.rb +7 -13
  107. data/lib/openstudio-standards/standards/Standards.ScheduleRuleset.rb +144 -59
  108. data/lib/openstudio-standards/standards/Standards.Space.rb +1509 -1326
  109. data/lib/openstudio-standards/standards/Standards.SpaceType.rb +254 -262
  110. data/lib/openstudio-standards/standards/Standards.SubSurface.rb +105 -105
  111. data/lib/openstudio-standards/standards/Standards.Surface.rb +27 -31
  112. data/lib/openstudio-standards/standards/Standards.ThermalZone.rb +882 -157
  113. data/lib/openstudio-standards/standards/Standards.WaterHeaterMixed.rb +179 -69
  114. data/lib/openstudio-standards/standards/Standards.ZoneHVACComponent.rb +75 -0
  115. data/lib/openstudio-standards/utilities/logging.rb +31 -38
  116. data/lib/openstudio-standards/utilities/simulation.rb +118 -82
  117. data/lib/openstudio-standards/version.rb +1 -1
  118. data/lib/openstudio-standards/weather/Weather.Model.rb +382 -390
  119. data/lib/openstudio-standards/weather/Weather.stat_file.rb +159 -78
  120. metadata +59 -6
@@ -1,7 +1,6 @@
1
1
 
2
2
  # Reopen the OpenStudio class to add methods to apply standards to this object
3
3
  class OpenStudio::Model::WaterHeaterMixed
4
-
5
4
  # Applies the standard efficiency ratings and typical losses and paraisitic loads to this object.
6
5
  # Efficiency and skin loss coefficient (UA)
7
6
  # Per PNNL http://www.energycodes.gov/sites/default/files/documents/PrototypeModelEnhancements_2014_0.pdf
@@ -10,41 +9,38 @@ class OpenStudio::Model::WaterHeaterMixed
10
9
  # @param template [String] valid choices: 'DOE Ref Pre-1980', 'DOE Ref 1980-2004', '90.1-2004', '90.1-2007', '90.1-2010', '90.1-2013'
11
10
  # @param standards [Hash] the OpenStudio_Standards spreadsheet in hash format
12
11
  # @return [Bool] true if successful, false if not
13
- # @todo break parasitic/skin losses into a separate method in
14
- # Prototype.WaterHeaterMixed because not governed by standard?
15
- def setStandardEfficiency(template)
16
-
12
+ def apply_efficiency(template)
17
13
  # Get the capacity of the water heater
18
14
  # TODO add capability to pull autosized water heater capacity
19
15
  # if the Sizing:WaterHeater object is ever implemented in OpenStudio.
20
- capacity_w = self.heaterMaximumCapacity
16
+ capacity_w = heaterMaximumCapacity
21
17
  if capacity_w.empty?
22
- OpenStudio::logFree(OpenStudio::Warn, "openstudio.standards.WaterHeaterMixed", "For #{self.name}, cannot find capacity, standard will not be applied.")
18
+ OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.WaterHeaterMixed', "For #{name}, cannot find capacity, standard will not be applied.")
23
19
  return false
24
20
  else
25
21
  capacity_w = capacity_w.get
26
22
  end
27
- capacity_btu_per_hr = OpenStudio.convert(capacity_w, "W", "Btu/hr").get
28
- capacity_kbtu_per_hr = OpenStudio.convert(capacity_w, "W", "kBtu/hr").get
29
-
23
+ capacity_btu_per_hr = OpenStudio.convert(capacity_w, 'W', 'Btu/hr').get
24
+ capacity_kbtu_per_hr = OpenStudio.convert(capacity_w, 'W', 'kBtu/hr').get
25
+
30
26
  # Get the volume of the water heater
31
27
  # TODO add capability to pull autosized water heater volume
32
- # if the Sizing:WaterHeater object is ever implemented in OpenStudio.
33
- volume_m3 = self.tankVolume
28
+ # if the Sizing:WaterHeater object is ever implemented in OpenStudio.
29
+ volume_m3 = tankVolume
34
30
  if volume_m3.empty?
35
- OpenStudio::logFree(OpenStudio::Warn, "openstudio.standards.WaterHeaterMixed", "For #{self.name}, cannot find volume, standard will not be applied.")
31
+ OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.WaterHeaterMixed', "For #{name}, cannot find volume, standard will not be applied.")
36
32
  return false
37
33
  else
38
34
  volume_m3 = volume_m3.get
39
35
  end
40
- volume_gal = OpenStudio.convert(volume_m3, "m^3", "gal").get
41
-
36
+ volume_gal = OpenStudio.convert(volume_m3, 'm^3', 'gal').get
37
+
42
38
  # Get the heater fuel type
43
- fuel_type = self.heaterFuelType
44
- if !(fuel_type == 'NaturalGas' || fuel_type == 'Electricity')
45
- OpenStudio::logFree(OpenStudio::Warn, "openstudio.standards.WaterHeaterMixed", "For #{self.name}, fuel type of #{fuel_type} is not yet supported, standard will not be applied.")
39
+ fuel_type = heaterFuelType
40
+ unless fuel_type == 'NaturalGas' || fuel_type == 'Electricity'
41
+ OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.WaterHeaterMixed', "For #{name}, fuel type of #{fuel_type} is not yet supported, standard will not be applied.")
46
42
  end
47
-
43
+
48
44
  # Calculate the water heater efficiency and
49
45
  # skin loss coefficient (UA)
50
46
  # Calculate the energy factor (EF)
@@ -54,102 +50,216 @@ class OpenStudio::Model::WaterHeaterMixed
54
50
  ua_btu_per_hr_per_f = nil
55
51
  sl_btu_per_hr = nil
56
52
  case fuel_type
57
- when 'Electricity'
53
+ when 'Electricity'
58
54
  case template
59
- when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004','90.1-2004', '90.1-2007', '90.1-2010', '90.1-2013'
60
-
61
- if capacity_w <= 12000 # I think this should be 12000W, use variable capacity_w instead of capacity_btu_per_hr (as per PNNL doc)
55
+ when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004', '90.1-2004', '90.1-2007', '90.1-2010', '90.1-2013'
56
+
57
+ if capacity_w <= 12_000 # I think this should be 12000W, use variable capacity_w instead of capacity_btu_per_hr (as per PNNL doc)
62
58
  # Fixed water heater efficiency per PNNL
63
59
  water_heater_eff = 1
64
60
  # Calculate the minimum Energy Factor (EF)
65
- ef = 0.97 - (0.00132 * volume_gal)
61
+ base_ef, vol_drt = case template
62
+ when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004', '90.1-2004', '90.1-2007'
63
+ [0.93, 0.00132]
64
+ when '90.1-2010'
65
+ [0.97, 0.00132]
66
+ when '90.1-2013'
67
+ [0.97, 0.00035]
68
+ end
69
+
70
+ ef = base_ef - (vol_drt * volume_gal)
66
71
  # Calculate the skin loss coefficient (UA)
67
- ua_btu_per_hr_per_f = (41094*(1/ef - 1))/(24*67.5)
72
+ ua_btu_per_hr_per_f = (41_094 * (1 / ef - 1)) / (24 * 67.5)
68
73
  else
69
74
  # Fixed water heater efficiency per PNNL
70
75
  water_heater_eff = 1
71
- # Calculate the max allowable standby loss (SL)
72
- sl_btu_per_hr = 20 + (35*Math.sqrt(volume_gal))
73
76
  # Calculate the skin loss coefficient (UA)
74
- ua_btu_per_hr_per_f = sl_btu_per_hr/70
77
+ case template
78
+ when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004', '90.1-2004', '90.1-2007', '90.1-2010'
79
+ # Calculate the max allowable standby loss (SL)
80
+ sl_btu_per_hr = 20 + (35 * Math.sqrt(volume_gal))
81
+ # Calculate the skin loss coefficient (UA)
82
+ ua_btu_per_hr_per_f = sl_btu_per_hr / 70
83
+ when '90.1-2013'
84
+ # Calculate the percent loss per hr
85
+ hrly_loss_pct = (0.3 + 27 / volume_gal) / 100
86
+ # Convert to Btu/hr, assuming:
87
+ # Water at 120F, density = 8.25 lb/gal
88
+ # 1 Btu to raise 1 lb of water 1 F
89
+ # Therefore 8.25 Btu / gal of water * deg F
90
+ # 70F delta-T between water and zone
91
+ hrly_loss_btu_per_hr = hrly_loss_pct * volume_gal * 8.25 * 70
92
+ # Calculate the skin loss coefficient (UA)
93
+ ua_btu_per_hr_per_f = hrly_loss_btu_per_hr / 70
94
+ end
75
95
  end
76
96
 
77
97
  when 'NECB 2011'
78
98
  volume_l_per_s = volume_m3 * 1000
79
- if capacity_w <= 12000
99
+ if capacity_btu_per_hr <= OpenStudio.convert(12, 'kW', 'Btu/hr')
80
100
  # Fixed water heater efficiency per PNNL
81
101
  water_heater_eff = 1
82
- # Calculate the max allowable standby loss (SL)
83
- if volume_l_per_s < 270
84
- sl_w = 40 + 0.2 * volume_l_per_s # assume bottom inlet
85
- else
86
- sl_w = 0.472 * volume_l_per_s - 33.5
87
- end # assume bottom inlet
88
- sl_btu_per_hr = OpenStudio.convert(sl_w, "W", "Btu/hr").get
102
+ # Calculate the max allowable standby loss (SL)
103
+ sl_w = if volume_l_per_s < 270
104
+ 40 + 0.2 * volume_l_per_s # assume bottom inlet
105
+ else
106
+ 0.472 * volume_l_per_s - 33.5
107
+ end # assume bottom inlet
108
+ sl_btu_per_hr = OpenStudio.convert(sl_w, 'W', 'Btu/hr').get
89
109
  else
90
110
  # Fixed water heater efficiency per PNNL
91
111
  water_heater_eff = 1
92
112
  # Calculate the max allowable standby loss (SL) # use this - NECB does not give SL calculation for cap > 12 kW
93
- sl_btu_per_hr = 20 + (35*Math.sqrt(volume_gal))
113
+ sl_btu_per_hr = 20 + (35 * Math.sqrt(volume_gal))
94
114
  end
95
115
  # Calculate the skin loss coefficient (UA)
96
- ua_btu_per_hr_per_f = sl_btu_per_hr/70
116
+ ua_btu_per_hr_per_f = sl_btu_per_hr / 70
97
117
  end
98
-
118
+
99
119
  when 'NaturalGas'
100
- case template # TODO inconsistency; ref buildings don't calculate water heater UA the same way
120
+ case template # TODO: inconsistency; ref buildings don't calculate water heater UA the same way
101
121
  when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004'
102
122
  water_heater_eff = 0.78
103
123
  ua_btu_per_hr_per_f = 11.37
104
124
  when '90.1-2004', '90.1-2007', '90.1-2010', '90.1-2013', 'NECB 2011'
105
- if capacity_btu_per_hr <= 75000
106
- # Fixed water heater efficiency per PNNL
125
+ if capacity_btu_per_hr <= 75_000
126
+ # Fixed water heater thermal efficiency per PNNL
107
127
  water_heater_eff = 0.82
108
128
  # Calculate the minimum Energy Factor (EF)
109
- ef = 0.67 - (0.0019 * volume_gal)
129
+ base_ef, vol_drt = case template
130
+ when '90.1-2004', '90.1-2007'
131
+ [0.62, 0.0019]
132
+ when '90.1-2010'
133
+ [0.67, 0.0019]
134
+ when '90.1-2013'
135
+ [0.67, 0.0005]
136
+ end
137
+
138
+ ef = base_ef - (vol_drt * volume_gal)
139
+ # Calculate the Recovery Efficiency (RE)
140
+ # based on a fixed capacity of 75,000 Btu/hr
141
+ # and a fixed volume of 40 gallons by solving
142
+ # this system of equations:
143
+ # ua = (1/.95-1/re)/(67.5*(24/41094-1/(re*cap)))
144
+ # 0.82 = (ua*67.5+cap*re)/cap
145
+ cap = 75_000.0
146
+ re = (Math.sqrt(6724 * ef**2 * cap**2 + 40_409_100 * ef**2 * cap - 28_080_900 * ef * cap + 29_318_000_625 * ef**2 - 58_636_001_250 * ef + 29_318_000_625) + 82 * ef * cap + 171_225 * ef - 171_225) / (200 * ef * cap)
110
147
  # Calculate the skin loss coefficient (UA)
111
- # TODO solve system of equations {u = (1/.95-1/r)/(67.5*(24/41094-1/(r*75000))), 0.82 = (u*67.5+75000*r)/75000}
112
- # Assume recovery efficieny = 0.81 based on regression of prototype models instead
113
- re = 0.81
114
- ua_btu_per_hr_per_f = (1/ef-1/re)/(67.5*(24/41094-1/(re*capacity_btu_per_hr)))
148
+ # based on the actual capacity.
149
+ ua_btu_per_hr_per_f = (water_heater_eff - re) * capacity_btu_per_hr / 67.5
115
150
  else
116
151
  # Thermal efficiency requirement from 90.1
117
152
  et = 0.8
118
153
  # Calculate the max allowable standby loss (SL)
119
- sl_btu_per_hr = et*(capacity_btu_per_hr/800 + 110*Math.sqrt(volume_gal))
154
+ cap_adj, vol_drt = case template
155
+ when '90.1-2004', '90.1-2007', '90.1-2010'
156
+ [800, 110]
157
+ when '90.1-2013'
158
+ [799, 16.6]
159
+ end
160
+
161
+ sl_btu_per_hr = (capacity_btu_per_hr / cap_adj + vol_drt * Math.sqrt(volume_gal))
120
162
  # Calculate the skin loss coefficient (UA)
121
- ua_btu_per_hr_per_f = (sl_btu_per_hr*et)/70
163
+ ua_btu_per_hr_per_f = (sl_btu_per_hr * et) / 70
122
164
  # Calculate water heater efficiency
123
- water_heater_eff = (ua_btu_per_hr_per_f*70 + capacity_btu_per_hr*et)/capacity_btu_per_hr
165
+ water_heater_eff = (ua_btu_per_hr_per_f * 70 + capacity_btu_per_hr * et) / capacity_btu_per_hr
124
166
  end
125
167
  end
126
168
  end
127
-
169
+
128
170
  # Convert to SI
129
- ua_btu_per_hr_per_c = OpenStudio.convert(ua_btu_per_hr_per_f, "Btu/hr*R", "W/K").get
130
-
171
+ ua_btu_per_hr_per_c = OpenStudio.convert(ua_btu_per_hr_per_f, 'Btu/hr*R', 'W/K').get
172
+
131
173
  # Set the water heater properties
132
174
  # Efficiency
133
- self.setHeaterThermalEfficiency(water_heater_eff)
175
+ setHeaterThermalEfficiency(water_heater_eff)
134
176
  # Skin loss
135
- self.setOffCycleLossCoefficienttoAmbientTemperature(ua_btu_per_hr_per_c)
136
- self.setOnCycleLossCoefficienttoAmbientTemperature(ua_btu_per_hr_per_c)
137
- # TODO Parasitic loss (pilot light)
177
+ setOffCycleLossCoefficienttoAmbientTemperature(ua_btu_per_hr_per_c)
178
+ setOnCycleLossCoefficienttoAmbientTemperature(ua_btu_per_hr_per_c)
179
+ # TODO: Parasitic loss (pilot light)
138
180
  # PNNL document says pilot lights were removed, but IDFs
139
181
  # still have the on/off cycle parasitic fuel consumptions filled in
140
- self.setOnCycleParasiticFuelType(fuel_type)
141
- #self.setOffCycleParasiticFuelConsumptionRate(??)
142
- self.setOnCycleParasiticHeatFractiontoTank(0)
143
- self.setOffCycleParasiticFuelType(fuel_type)
144
- #self.setOffCycleParasiticFuelConsumptionRate(??)
145
- self.setOffCycleParasiticHeatFractiontoTank(0.8)
146
-
182
+ setOnCycleParasiticFuelType(fuel_type)
183
+ # self.setOffCycleParasiticFuelConsumptionRate(??)
184
+ setOnCycleParasiticHeatFractiontoTank(0)
185
+ setOffCycleParasiticFuelType(fuel_type)
186
+ # self.setOffCycleParasiticFuelConsumptionRate(??)
187
+ setOffCycleParasiticHeatFractiontoTank(0.8)
188
+
147
189
  # Append the name with standards information
148
- self.setName("#{name} #{water_heater_eff.round(3)}Eff")
149
- OpenStudio::logFree(OpenStudio::Info, 'openstudio.model.WaterHeaterMixed', "For #{template}: #{self.name}; efficiency = #{water_heater_eff.round(3)}, skin-loss UA = #{ua_btu_per_hr_per_f.round}Btu/hr AKA #{ua_btu_per_hr_per_c.round(1)}W/K")
150
-
190
+ setName("#{name} #{water_heater_eff.round(3)} Therm Eff")
191
+ OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.WaterHeaterMixed', "For #{template}: #{name}; thermal efficiency = #{water_heater_eff.round(3)}, skin-loss UA = #{ua_btu_per_hr_per_f.round}Btu/hr")
192
+
193
+ return true
194
+ end
195
+
196
+ # Applies the correct fuel type for the water heaters
197
+ # in the baseline model. For most standards and for most building
198
+ # types, the baseline uses the same fuel type as the proposed.
199
+ # However, certain standards like 90.1-2013 require a change
200
+ # in some scenarios.
201
+ #
202
+ # @param building_type [String] the building type
203
+ # @return [Bool] returns true if successful, false if not.
204
+ def apply_prm_baseline_fuel_type(template, building_type)
205
+ # For all standards except 90.1-2013
206
+ # baseline is same as proposed per
207
+ # Table G3.1 item 11.b
208
+ unless template == '90.1-2013'
209
+ return true
210
+ end
211
+
212
+ # Determine the building-type specific
213
+ # fuel requirements from Table G3.1.1-2
214
+ new_fuel = nil
215
+ case building_type
216
+ when 'SecondarySchool', 'PrimarySchool', # School/university
217
+ 'SmallHotel', # Motel
218
+ 'LargeHotel', # Hotel
219
+ 'QuickServiceRestaurant', # Dining: Cafeteria/fast food
220
+ 'FullServiceRestaurant', # Dining: Family
221
+ 'MidriseApartment', 'HighriseApartment', # Multifamily
222
+ 'Hospital', # Hospital
223
+ 'Outpatient' # Health-care clinic
224
+ new_fuel = 'NaturalGas'
225
+ when 'SmallOffice', 'MediumOffice', 'LargeOffice', # Office
226
+ 'RetailStandalone', 'RetailStripmall', # Retail
227
+ 'Warehouse' # Warehouse
228
+ new_fuel = 'Electricity'
229
+ else
230
+ new_fuel = 'NaturalGas'
231
+ end
232
+
233
+ # Change the fuel type if necessary
234
+ old_fuel = heaterFuelType
235
+ unless new_fuel == old_fuel
236
+ setHeaterFuelType(new_fuel)
237
+ OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.WaterHeaterMixed', "For #{name}, changed baseline water heater fuel from #{old_fuel} to #{new_fuel}.")
238
+ end
239
+
151
240
  return true
152
-
153
241
  end
154
-
242
+
243
+ # Finds capacity in Btu/hr
244
+ #
245
+ # @return [Double] capacity in Btu/hr to be used for find object
246
+ def find_capacity()
247
+
248
+ # Get the coil capacity
249
+ capacity_w = nil
250
+ if self.heaterMaximumCapacity.is_initialized
251
+ capacity_w = self.heaterMaximumCapacity.get
252
+ elsif self.autosizedHeaterMaximumCapacity.is_initialized
253
+ capacity_w = self.autosizedHeaterMaximumCapacity.get
254
+ else
255
+ OpenStudio::logFree(OpenStudio::Warn, 'openstudio.standards.WaterHeaterMixed', "For #{self.name} capacity is not available.")
256
+ return false
257
+ end
258
+
259
+ # Convert capacity to Btu/hr
260
+ capacity_btu_per_hr = OpenStudio.convert(capacity_w, "W", "Btu/hr").get
261
+
262
+ return capacity_btu_per_hr
263
+
264
+ end
155
265
  end
@@ -0,0 +1,75 @@
1
+ # open the class to add methods to apply HVAC efficiency standards
2
+ class OpenStudio::Model::ZoneHVACComponent
3
+ # Sets the fan power of zone level HVAC equipment
4
+ # (PTACs, PTHPs, Fan Coils, and Unit Heaters)
5
+ # based on the W/cfm specified in the standard.
6
+ #
7
+ # @param template [String] the template base requirements on
8
+ # @return [Bool] returns true if successful, false if not
9
+ def apply_prm_baseline_fan_power(template)
10
+ OpenStudio.logFree(OpenStudio::Debug, 'openstudio.model.ZoneHVACComponent', "Setting fan power for #{name}.")
11
+
12
+ # Convert this to the actual class type
13
+ zone_hvac = if to_ZoneHVACFourPipeFanCoil.is_initialized
14
+ to_ZoneHVACFourPipeFanCoil.get
15
+ elsif to_ZoneHVACUnitHeater.is_initialized
16
+ to_ZoneHVACUnitHeater.get
17
+ elsif to_ZoneHVACPackagedTerminalAirConditioner.is_initialized
18
+ to_ZoneHVACPackagedTerminalAirConditioner.get
19
+ elsif to_ZoneHVACPackagedTerminalHeatPump.is_initialized
20
+ to_ZoneHVACPackagedTerminalHeatPump.get
21
+ else
22
+ nil
23
+ end
24
+
25
+ # Do nothing for other types of zone HVAC equipment
26
+ if zone_hvac.nil?
27
+ return false
28
+ end
29
+
30
+ # Determine the W/cfm
31
+ fan_efficacy_w_per_cfm = 0.3
32
+
33
+ # Convert efficacy to metric
34
+ # 1 cfm = 0.0004719 m^3/s
35
+ fan_efficacy_w_per_m3_per_s = fan_efficacy_w_per_cfm / 0.0004719
36
+
37
+ # Get the fan
38
+ fan = if zone_hvac.supplyAirFan.to_FanConstantVolume.is_initialized
39
+ zone_hvac.supplyAirFan.to_FanConstantVolume.get
40
+ elsif zone_hvac.supplyAirFan.to_FanVariableVolume.is_initialized
41
+ zone_hvac.supplyAirFan.to_FanVariableVolume.get
42
+ elsif zone_hvac.supplyAirFan.to_FanOnOff.is_initialized
43
+ zone_hvac.supplyAirFan.to_FanOnOff.get
44
+ end
45
+
46
+ # Get the maximum flow rate through the fan
47
+ max_air_flow_rate = nil
48
+ if fan.autosizedMaximumFlowRate.is_initialized
49
+ max_air_flow_rate = fan.autosizedMaximumFlowRate.get
50
+ elsif fan.maximumFlowRate.is_initialized
51
+ max_air_flow_rate = fan.maximumFlowRate.get
52
+ end
53
+ max_air_flow_rate_cfm = OpenStudio.convert(max_air_flow_rate, 'm^3/s', 'ft^3/min').get
54
+
55
+ # Set the impeller efficiency
56
+ fan.change_impeller_efficiency(fan.baseline_impeller_efficiency(template))
57
+
58
+ # Set the motor efficiency, preserving the impeller efficency.
59
+ # For zone HVAC fans, a bhp lookup of 0.5bhp is always used because
60
+ # they are assumed to represent a series of small fans in reality.
61
+ fan.apply_standard_minimum_motor_efficiency(template, fan.brake_horsepower)
62
+
63
+ # Calculate a new pressure rise to hit the target W/cfm
64
+ fan_tot_eff = fan.fanEfficiency
65
+ fan_rise_new_pa = fan_efficacy_w_per_m3_per_s * fan_tot_eff
66
+ fan.setPressureRise(fan_rise_new_pa)
67
+
68
+ # Calculate the newly set efficacy
69
+ fan_power_new_w = fan_rise_new_pa * max_air_flow_rate / fan_tot_eff
70
+ fan_efficacy_new_w_per_cfm = fan_power_new_w / max_air_flow_rate_cfm
71
+ OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.ZoneHVACComponent', "For #{name}: fan efficacy set to #{fan_efficacy_new_w_per_cfm.round(2)} W/cfm.")
72
+
73
+ return true
74
+ end
75
+ end
@@ -8,18 +8,18 @@ $OPENSTUDIO_LOG.setLogLevel(OpenStudio::Debug)
8
8
  # debug @param [Boolean] If true, include the debug messages in the log
9
9
  # @return [Runner] The same Measure runner, with messages from the openstudio-standards library added
10
10
  def log_messages_to_runner(runner, debug = false)
11
-
12
11
  $OPENSTUDIO_LOG.logMessages.each do |msg|
13
12
  # DLM: you can filter on log channel here for now
14
- if /openstudio.*/.match(msg.logChannel) #/openstudio\.model\..*/
13
+ if /openstudio.*/ =~ msg.logChannel # /openstudio\.model\..*/
15
14
  # Skip certain messages that are irrelevant/misleading
16
- next if msg.logMessage.include?("Skipping layer") || # Annoying/bogus "Skipping layer" warnings
17
- msg.logChannel.include?("runmanager") || # RunManager messages
18
- msg.logChannel.include?("setFileExtension") || # .ddy extension unexpected
19
- msg.logChannel.include?("Translator") || # Forward translator and geometry translator
20
- msg.logMessage.include?("UseWeatherFile") || # 'UseWeatherFile' is not yet a supported option for YearDescription
21
- msg.logMessage.include?("EpwFile") # Successive data points (2004-Jan-31 to 2001-Feb-01, ending on line 753) are greater than 1 day apart in EPW file
22
-
15
+ next if msg.logMessage.include?('Skipping layer') || # Annoying/bogus "Skipping layer" warnings
16
+ msg.logChannel.include?('runmanager') || # RunManager messages
17
+ msg.logChannel.include?('setFileExtension') || # .ddy extension unexpected
18
+ msg.logChannel.include?('Translator') || # Forward translator and geometry translator
19
+ msg.logMessage.include?('UseWeatherFile') || # 'UseWeatherFile' is not yet a supported option for YearDescription
20
+ msg.logMessage.include?('Successive data points') || # Successive data points (2004-Jan-31 to 2001-Feb-01, ending on line 753) are greater than 1 day apart in EPW file
21
+ msg.logMessage.include?('has multiple parents') # Bogus errors about curves having multiple parents
22
+
23
23
  # Report the message in the correct way
24
24
  if msg.logLevel == OpenStudio::Info
25
25
  runner.registerInfo(msg.logMessage)
@@ -32,7 +32,6 @@ def log_messages_to_runner(runner, debug = false)
32
32
  end
33
33
  end
34
34
  end
35
-
36
35
  end
37
36
 
38
37
  # Log the info, warning, and error messages to a file.
@@ -40,33 +39,32 @@ end
40
39
  # debug @param [Boolean] If true, include the debug messages in the log
41
40
  # @return [Array<String>] The array of messages, which can be used elsewhere.
42
41
  def log_messages_to_file(file_path, debug = false)
43
-
44
42
  messages = []
45
43
 
46
- File.open(file_path, 'w') do |file|
47
-
44
+ File.open(file_path, 'w') do |file|
48
45
  $OPENSTUDIO_LOG.logMessages.each do |msg|
49
46
  # DLM: you can filter on log channel here for now
50
- if /openstudio.*/.match(msg.logChannel) #/openstudio\.model\..*/
47
+ if /openstudio.*/ =~ msg.logChannel # /openstudio\.model\..*/
51
48
  # Skip certain messages that are irrelevant/misleading
52
- next if msg.logMessage.include?("Skipping layer") || # Annoying/bogus "Skipping layer" warnings
53
- msg.logChannel.include?("runmanager") || # RunManager messages
54
- msg.logChannel.include?("setFileExtension") || # .ddy extension unexpected
55
- msg.logChannel.include?("Translator") || # Forward translator and geometry translator
56
- msg.logMessage.include?("UseWeatherFile") || # 'UseWeatherFile' is not yet a supported option for YearDescription
57
- msg.logMessage.include?("EpwFile") # Successive data points (2004-Jan-31 to 2001-Feb-01, ending on line 753) are greater than 1 day apart in EPW file
58
-
49
+ next if msg.logMessage.include?('Skipping layer') || # Annoying/bogus "Skipping layer" warnings
50
+ msg.logChannel.include?('runmanager') || # RunManager messages
51
+ msg.logChannel.include?('setFileExtension') || # .ddy extension unexpected
52
+ msg.logChannel.include?('Translator') || # Forward translator and geometry translator
53
+ msg.logMessage.include?('UseWeatherFile') || # 'UseWeatherFile' is not yet a supported option for YearDescription
54
+ msg.logMessage.include?('Successive data points') || # Successive data points (2004-Jan-31 to 2001-Feb-01, ending on line 753) are greater than 1 day apart in EPW file
55
+ msg.logMessage.include?('has multiple parents') # Bogus errors about curves having multiple parents
56
+
59
57
  # Report the message in the correct way
60
58
  if msg.logLevel == OpenStudio::Info
61
59
  s = "INFO #{msg.logMessage}"
62
60
  file.puts(s)
63
61
  messages << s
64
62
  elsif msg.logLevel == OpenStudio::Warn
65
- s = "WARN [#{msg.logChannel}] #{msg.logMessage}"
63
+ s = "WARN #{msg.logMessage}"
66
64
  file.puts(s)
67
65
  messages << s
68
66
  elsif msg.logLevel == OpenStudio::Error
69
- s = "ERROR [#{msg.logChannel}] #{msg.logMessage}"
67
+ s = "ERROR #{msg.logMessage}"
70
68
  file.puts(s)
71
69
  messages << s
72
70
  elsif msg.logLevel == OpenStudio::Debug && debug
@@ -76,40 +74,35 @@ def log_messages_to_file(file_path, debug = false)
76
74
  end
77
75
  end
78
76
  end
79
-
80
77
  end
81
-
78
+
82
79
  return messages
83
-
84
80
  end
85
81
 
86
82
  # Get an array of all messages of a given type in the log
87
83
  def get_logs(log_type = OpenStudio::Error)
88
-
89
84
  errors = []
90
85
 
91
86
  $OPENSTUDIO_LOG.logMessages.each do |msg|
92
- if /openstudio.*/.match(msg.logChannel)
87
+ if /openstudio.*/ =~ msg.logChannel
93
88
  # Skip certain messages that are irrelevant/misleading
94
- next if msg.logMessage.include?("Skipping layer") || # Annoying/bogus "Skipping layer" warnings
95
- msg.logChannel.include?("runmanager") || # RunManager messages
96
- msg.logChannel.include?("setFileExtension") || # .ddy extension unexpected
97
- msg.logChannel.include?("Translator") || # Forward translator and geometry translator
98
- msg.logMessage.include?("UseWeatherFile") || # 'UseWeatherFile' is not yet a supported option for YearDescription
99
- msg.logMessage.include?("EpwFile") # Successive data points (2004-Jan-31 to 2001-Feb-01, ending on line 753) are greater than 1 day apart in EPW file
89
+ next if msg.logMessage.include?('Skipping layer') || # Annoying/bogus "Skipping layer" warnings
90
+ msg.logChannel.include?('runmanager') || # RunManager messages
91
+ msg.logChannel.include?('setFileExtension') || # .ddy extension unexpected
92
+ msg.logChannel.include?('Translator') || # Forward translator and geometry translator
93
+ msg.logMessage.include?('UseWeatherFile') || # 'UseWeatherFile' is not yet a supported option for YearDescription
94
+ msg.logMessage.include?('Successive data points') || # Successive data points (2004-Jan-31 to 2001-Feb-01, ending on line 753) are greater than 1 day apart in EPW file
95
+ msg.logMessage.include?('has multiple parents') # Bogus errors about curves having multiple parents
100
96
  # Only fail on the errors
101
97
  if msg.logLevel == log_type
102
98
  errors << "[#{msg.logChannel}] #{msg.logMessage}"
103
99
  end
104
100
  end
105
- end
101
+ end
106
102
 
107
103
  return errors
108
-
109
104
  end
110
105
 
111
106
  def reset_log
112
-
113
107
  $OPENSTUDIO_LOG.resetStringStream
114
-
115
108
  end