openstudio-standards 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/data/standards/OpenStudio_Standards.xlsx +0 -0
  3. data/data/standards/OpenStudio_Standards_chillers.json +5 -5
  4. data/data/standards/OpenStudio_Standards_construction_sets.json +2 -2
  5. data/data/standards/OpenStudio_Standards_curve_cubics.json +12 -0
  6. data/data/standards/OpenStudio_Standards_heat_pumps.json +2126 -72
  7. data/data/standards/OpenStudio_Standards_heat_pumps_heating.json +766 -14
  8. data/data/standards/OpenStudio_Standards_heat_rejection.json +172 -0
  9. data/data/standards/OpenStudio_Standards_prototype_inputs.json +355 -267
  10. data/data/standards/OpenStudio_Standards_schedules.json +262 -10
  11. data/data/standards/OpenStudio_Standards_space_types.json +1466 -794
  12. data/data/standards/manage_OpenStudio_Standards.rb +19 -21
  13. data/data/weather/weather_info.csv +96 -0
  14. data/lib/openstudio-standards/btap/btap.rb +1 -1
  15. data/lib/openstudio-standards/btap/compliance.rb +135 -40
  16. data/lib/openstudio-standards/btap/envelope.rb +26 -5
  17. data/lib/openstudio-standards/btap/geometry.rb +11 -1
  18. data/lib/openstudio-standards/btap/hvac.rb +489 -56
  19. data/lib/openstudio-standards/btap/simmanager.rb +1 -1
  20. data/lib/openstudio-standards/hvac_sizing/HVACSizing.CoilHeatingDXMultiSpeed.rb +120 -0
  21. data/lib/openstudio-standards/hvac_sizing/Siz.CoilCoolingDXMultiSpeed.rb +151 -7
  22. data/lib/openstudio-standards/hvac_sizing/Siz.CoilHeatingGasMultiStage.rb +48 -7
  23. data/lib/openstudio-standards/hvac_sizing/Siz.Model.rb +14 -12
  24. data/lib/openstudio-standards/prototypes/Prototype.AirTerminalSingleDuctVAVReheat.rb +33 -7
  25. data/lib/openstudio-standards/prototypes/Prototype.Model.hvac.rb +123 -91
  26. data/lib/openstudio-standards/prototypes/Prototype.Model.rb +130 -45
  27. data/lib/openstudio-standards/prototypes/Prototype.Model.swh.rb +13 -7
  28. data/lib/openstudio-standards/prototypes/Prototype.full_service_restaurant.rb +332 -324
  29. data/lib/openstudio-standards/prototypes/Prototype.hospital.rb +401 -99
  30. data/lib/openstudio-standards/prototypes/Prototype.hvac_systems.rb +309 -222
  31. data/lib/openstudio-standards/prototypes/Prototype.large_hotel.rb +100 -80
  32. data/lib/openstudio-standards/prototypes/Prototype.large_office.rb +37 -22
  33. data/lib/openstudio-standards/prototypes/Prototype.medium_office.rb +68 -53
  34. data/lib/openstudio-standards/prototypes/Prototype.mid_rise_apartment.rb +109 -88
  35. data/lib/openstudio-standards/prototypes/Prototype.outpatient.rb +52 -4
  36. data/lib/openstudio-standards/prototypes/Prototype.primary_school.rb +230 -213
  37. data/lib/openstudio-standards/prototypes/Prototype.quick_service_restaurant.rb +225 -218
  38. data/lib/openstudio-standards/prototypes/Prototype.retail_standalone.rb +29 -17
  39. data/lib/openstudio-standards/prototypes/Prototype.retail_stripmall.rb +42 -32
  40. data/lib/openstudio-standards/prototypes/Prototype.secondary_school.rb +331 -314
  41. data/lib/openstudio-standards/prototypes/Prototype.small_hotel.rb +233 -219
  42. data/lib/openstudio-standards/prototypes/Prototype.small_office.rb +40 -32
  43. data/lib/openstudio-standards/prototypes/Prototype.warehouse.rb +19 -6
  44. data/lib/openstudio-standards/standards/Standards.AirLoopHVAC.rb +576 -555
  45. data/lib/openstudio-standards/standards/Standards.AirTerminalSingleDuctVAVReheat.rb +3 -1
  46. data/lib/openstudio-standards/standards/Standards.BoilerHotWater.rb +35 -17
  47. data/lib/openstudio-standards/standards/Standards.ChillerElectricEIR.rb +51 -23
  48. data/lib/openstudio-standards/standards/Standards.CoilCoolingDXMultiSpeed.rb +255 -0
  49. data/lib/openstudio-standards/standards/Standards.CoilHeatingDXMultiSpeed.rb +192 -0
  50. data/lib/openstudio-standards/standards/Standards.CoilHeatingGasMultiStage.rb +65 -0
  51. data/lib/openstudio-standards/standards/Standards.Fan.rb +37 -6
  52. data/lib/openstudio-standards/standards/Standards.Model.rb +28 -3
  53. data/lib/openstudio-standards/standards/Standards.SpaceType.rb +3 -1
  54. data/lib/openstudio-standards/standards/Standards.WaterHeaterMixed.rb +41 -15
  55. data/lib/openstudio-standards/version.rb +1 -1
  56. data/lib/openstudio-standards/weather/Weather.Model.rb +509 -5
  57. data/lib/openstudio-standards/weather/Weather.stat_file.rb +145 -5
  58. metadata +8 -3
  59. data/lib/openstudio-standards/btap/environment.rb +0 -718
@@ -3,12 +3,20 @@
3
3
  class OpenStudio::Model::Model
4
4
 
5
5
  def define_space_type_map(building_type, building_vintage, climate_zone)
6
-
7
- space_type_map = {
8
- 'WholeBuilding - Sm Office' => ['Perimeter_ZN_1', 'Perimeter_ZN_2', 'Perimeter_ZN_3', 'Perimeter_ZN_4', 'Core_ZN'],
9
- 'Attic' => ['Attic']
10
- }
11
-
6
+ space_type_map = nil
7
+
8
+ case building_vintage
9
+ when 'NECB 2011'
10
+ space_type_map ={
11
+ "- undefined -" => ["Attic"],
12
+ "Office - enclosed" => ["Core_ZN", "Perimeter_ZN_1", "Perimeter_ZN_2", "Perimeter_ZN_3", "Perimeter_ZN_4"]
13
+ }
14
+ else
15
+ space_type_map = {
16
+ 'WholeBuilding - Sm Office' => ['Perimeter_ZN_1', 'Perimeter_ZN_2', 'Perimeter_ZN_3', 'Perimeter_ZN_4', 'Core_ZN'],
17
+ 'Attic' => ['Attic']
18
+ }
19
+ end
12
20
  return space_type_map
13
21
 
14
22
  end
@@ -17,46 +25,46 @@ class OpenStudio::Model::Model
17
25
 
18
26
  system_to_space_map = [
19
27
  {
20
- 'type' => 'PSZ-AC',
21
- 'name' => 'PSZ-AC-2',
22
- 'space_names' =>
28
+ 'type' => 'PSZ-AC',
29
+ 'name' => 'PSZ-AC-2',
30
+ 'space_names' =>
23
31
  [
24
- 'Perimeter_ZN_1'
25
- ]
32
+ 'Perimeter_ZN_1'
33
+ ]
26
34
  },
27
35
  {
28
- 'type' => 'PSZ-AC',
29
- 'name' => 'PSZ-AC-3',
30
- 'space_names' =>
36
+ 'type' => 'PSZ-AC',
37
+ 'name' => 'PSZ-AC-3',
38
+ 'space_names' =>
31
39
  [
32
- 'Perimeter_ZN_2'
33
- ]
40
+ 'Perimeter_ZN_2'
41
+ ]
34
42
  },
35
43
  {
36
- 'type' => 'PSZ-AC',
37
- 'name' => 'PSZ-AC-4',
38
- 'space_names' =>
44
+ 'type' => 'PSZ-AC',
45
+ 'name' => 'PSZ-AC-4',
46
+ 'space_names' =>
39
47
  [
40
- 'Perimeter_ZN_3'
41
- ]
48
+ 'Perimeter_ZN_3'
49
+ ]
42
50
  },
43
51
  {
44
- 'type' => 'PSZ-AC',
45
- 'name' => 'PSZ-AC-5',
46
- 'space_names' =>
52
+ 'type' => 'PSZ-AC',
53
+ 'name' => 'PSZ-AC-5',
54
+ 'space_names' =>
47
55
  [
48
- 'Perimeter_ZN_4'
49
- ]
56
+ 'Perimeter_ZN_4'
57
+ ]
50
58
  },
51
59
  {
52
- 'type' => 'PSZ-AC',
53
- 'name' => 'PSZ-AC-1',
54
- 'space_names' =>
60
+ 'type' => 'PSZ-AC',
61
+ 'name' => 'PSZ-AC-1',
62
+ 'space_names' =>
55
63
  [
56
- 'Core_ZN'
57
- ]
64
+ 'Core_ZN'
65
+ ]
58
66
  }
59
- ]
67
+ ]
60
68
 
61
69
  return system_to_space_map
62
70
 
@@ -3,11 +3,23 @@
3
3
  class OpenStudio::Model::Model
4
4
 
5
5
  def define_space_type_map(building_type, building_vintage, climate_zone)
6
- space_type_map = {
7
- 'Bulk' => ['Zone3 Bulk Storage'],
8
- 'Fine' => ['Zone2 Fine Storage'],
9
- 'Office' => ['Zone1 Office']
10
- }
6
+ space_type_map = nil
7
+
8
+ case building_vintage
9
+
10
+ when 'NECB 2011'
11
+ space_type_map ={
12
+ "Warehouse - med/blk" => ["Zone3 Bulk Storage"],
13
+ "Warehouse - fine" => ["Zone2 Fine Storage"],
14
+ "Office - enclosed" => ["Zone1 Office"]
15
+ }
16
+ else
17
+ space_type_map = {
18
+ 'Bulk' => ['Zone3 Bulk Storage'],
19
+ 'Fine' => ['Zone2 Fine Storage'],
20
+ 'Office' => ['Zone1 Office']
21
+ }
22
+ end
11
23
  return space_type_map
12
24
  end
13
25
 
@@ -87,7 +99,7 @@ class OpenStudio::Model::Model
87
99
 
88
100
  def update_waterheater_loss_coefficient(building_vintage)
89
101
  case building_vintage
90
- when '90.1-2004', '90.1-2007', '90.1-2010', '90.1-2013'
102
+ when '90.1-2004', '90.1-2007', '90.1-2010', '90.1-2013', 'NECB 2011'
91
103
  self.getWaterHeaterMixeds.sort.each do |water_heater|
92
104
  water_heater.setOffCycleLossCoefficienttoAmbientTemperature(0.798542707)
93
105
  water_heater.setOnCycleLossCoefficienttoAmbientTemperature(0.798542707)
@@ -103,4 +115,5 @@ class OpenStudio::Model::Model
103
115
 
104
116
  end
105
117
 
118
+
106
119
  end
@@ -16,25 +16,25 @@ class OpenStudio::Model::AirLoopHVAC
16
16
  OpenStudio::logFree(OpenStudio::Warn, "openstudio.standards.AirLoopHVAC", "Damper positions not modified for DOE Ref Pre-1980 or DOE Ref 1980-2004 vintages.")
17
17
  return true
18
18
  end
19
-
19
+
20
20
  # First time adjustment:
21
21
  # Only applies to multi-zone vav systems
22
- # exclusion: for Outpatient: (1) both AHU1 and AHU2 in 'DOE Ref Pre-1980' and 'DOE Ref 1980-2004'
22
+ # exclusion: for Outpatient: (1) both AHU1 and AHU2 in 'DOE Ref Pre-1980' and 'DOE Ref 1980-2004'
23
23
  # (2) AHU1 in 2004-2013
24
24
  if self.is_multizone_vav_system && !(self.name.to_s.include? "Outpatient F1")
25
25
  self.adjust_minimum_vav_damper_positions
26
26
  end
27
-
27
+
28
28
  # Second time adjustment:
29
29
  # Only apply to 2010 and 2013 Outpatient (both AHU1 and AHU2)
30
30
  # TODO maybe apply to hospital as well?
31
31
  if (self.name.to_s.include? "Outpatient") && (template == '90.1-2010' || template == '90.1-2013')
32
32
  self.adjust_minimum_vav_damper_positions_outpatient
33
33
  end
34
-
34
+
35
35
  return true
36
-
37
- end
36
+
37
+ end
38
38
 
39
39
  # Apply all standard required controls to the airloop
40
40
  #
@@ -45,22 +45,22 @@ class OpenStudio::Model::AirLoopHVAC
45
45
  # @todo nightcycle control
46
46
  # @todo night fan shutoff
47
47
  def apply_standard_controls(template, climate_zone)
48
-
48
+
49
49
  # Energy Recovery Ventilation
50
50
  if self.is_energy_recovery_ventilator_required(template, climate_zone)
51
51
  self.apply_energy_recovery_ventilator
52
52
  end
53
-
53
+
54
54
  # Economizers
55
55
  self.set_economizer_limits(template, climate_zone)
56
- self.set_economizer_integration(template, climate_zone)
57
-
56
+ self.set_economizer_integration(template, climate_zone)
57
+
58
58
  # Multizone VAV Systems
59
59
  if self.is_multizone_vav_system
60
-
60
+
61
61
  # VAV Reheat Control
62
62
  self.set_vav_damper_action(template)
63
-
63
+
64
64
  # Multizone VAV Optimization
65
65
  # This rule does not apply to two hospital and one outpatient systems (TODO add hospital two systems as exception)
66
66
  if !(self.name.to_s.include? "Outpatient F1")
@@ -70,7 +70,7 @@ class OpenStudio::Model::AirLoopHVAC
70
70
  self.disable_multizone_vav_optimization
71
71
  end
72
72
  end
73
-
73
+
74
74
  # VAV Static Pressure Reset
75
75
  # assume all systems have DDC control of VAV terminals
76
76
  has_ddc = true
@@ -83,9 +83,9 @@ class OpenStudio::Model::AirLoopHVAC
83
83
  end
84
84
  end
85
85
  end
86
-
86
+
87
87
  end
88
-
88
+
89
89
  # Single zone systems
90
90
  # if self.thermalZones.size == 1
91
91
  # self.apply_single_zone_controls(template, climate_zone)
@@ -108,15 +108,15 @@ class OpenStudio::Model::AirLoopHVAC
108
108
  if self.is_supply_air_temperature_reset_required(template, climate_zone)
109
109
  self.enable_supply_air_temperature_reset_outdoor_temperature
110
110
  # self.enable_supply_air_temperature_reset_warmest_zone(template)
111
- end
112
-
111
+ end
112
+
113
113
  # Unoccupied shutdown
114
114
  if self.is_unoccupied_fan_shutoff_required(template)
115
115
  self.enable_unoccupied_fan_shutoff
116
116
  else
117
117
  self.setAvailabilitySchedule(self.model.alwaysOnDiscreteSchedule)
118
118
  end
119
-
119
+
120
120
  # Motorized OA damper
121
121
  if self.is_motorized_oa_damper_required(template, climate_zone)
122
122
  # Assume that the availability schedule has already been
@@ -125,16 +125,16 @@ class OpenStudio::Model::AirLoopHVAC
125
125
  else
126
126
  self.remove_motorized_oa_damper
127
127
  end
128
-
128
+
129
129
  # TODO Optimum Start
130
130
  # for systems exceeding 10,000 cfm
131
131
  # Don't think that OS will be able to do this.
132
132
  # OS currently only allows 1 availability manager
133
- # at a time on an AirLoopHVAC. If we add an
134
- # AvailabilityManager:OptimumStart, it
133
+ # at a time on an AirLoopHVAC. If we add an
134
+ # AvailabilityManager:OptimumStart, it
135
135
  # will replace the AvailabilityManager:NightCycle.
136
-
137
- end
136
+
137
+ end
138
138
 
139
139
  # Apply all PRM baseline required controls to the airloop.
140
140
  # Only applies those controls that differ from the normal
@@ -144,7 +144,7 @@ class OpenStudio::Model::AirLoopHVAC
144
144
  # @param (see #is_economizer_required)
145
145
  # @return [Bool] returns true if successful, false if not
146
146
  def apply_performance_rating_method_baseline_controls(template, climate_zone)
147
-
147
+
148
148
  # Economizers
149
149
  if self.is_performance_rating_method_baseline_economizer_required(template, climate_zone)
150
150
  self.apply_performance_rating_method_baseline_economizer(template, climate_zone)
@@ -153,7 +153,7 @@ class OpenStudio::Model::AirLoopHVAC
153
153
  # Multizone VAV Systems
154
154
  if self.is_multizone_vav_system
155
155
 
156
- # SAT Reset
156
+ # SAT Reset
157
157
  # G3.1.3.12 SAT reset required for all Multizone VAV systems,
158
158
  # even if not required by prescriptive section.
159
159
  case template
@@ -162,13 +162,13 @@ class OpenStudio::Model::AirLoopHVAC
162
162
  end
163
163
 
164
164
  end
165
-
165
+
166
166
  # Unoccupied shutdown
167
167
  self.enable_unoccupied_fan_shutoff
168
-
168
+
169
169
  return true
170
-
171
- end
170
+
171
+ end
172
172
 
173
173
  # Calculate and apply the performance rating method
174
174
  # baseline fan power to this air loop.
@@ -182,18 +182,18 @@ class OpenStudio::Model::AirLoopHVAC
182
182
  # if the proposed model had multiple fans (supply, return, exhaust, etc.)
183
183
  # return [Bool] true if successful, false if not.
184
184
  def set_performance_rating_method_baseline_fan_power(template)
185
-
185
+
186
186
  # Main AHU fans
187
-
187
+
188
188
  # Calculate the allowable fan motor bhp
189
189
  # for the entire airloop.
190
190
  allowable_fan_bhp = self.allowable_system_brake_horsepower(template)
191
191
 
192
192
  # Divide the allowable power evenly between the fans
193
193
  # on this airloop.
194
- all_fans = self.supply_return_exhaust_relief_fans
195
- allowable_fan_bhp = allowable_fan_bhp / all_fans.size
196
-
194
+ all_fans = self.supply_return_exhaust_relief_fans
195
+ allowable_fan_bhp = allowable_fan_bhp / all_fans.size
196
+
197
197
  # Set the motor efficiencies
198
198
  # for all fans based on the calculated
199
199
  # allowed brake hp. Then calculate the allowable
@@ -206,18 +206,18 @@ class OpenStudio::Model::AirLoopHVAC
206
206
  end
207
207
 
208
208
  # Fan powered terminal fans
209
-
209
+
210
210
  # Adjust each terminal fan
211
211
  self.demandComponents.each do |dc|
212
212
  next if dc.to_AirTerminalSingleDuctParallelPIUReheat.empty?
213
213
  pfp_term = dc.to_AirTerminalSingleDuctParallelPIUReheat.get
214
214
  pfp_term.set_performance_rating_method_baseline_fan_power(template)
215
215
  end
216
-
216
+
217
217
  return true
218
-
218
+
219
219
  end
220
-
220
+
221
221
  # Determine the fan power limitation pressure drop adjustment
222
222
  # Per Table 6.5.3.1.1B
223
223
  #
@@ -226,7 +226,7 @@ class OpenStudio::Model::AirLoopHVAC
226
226
  # units = horsepower
227
227
  # @todo Determine the presence of MERV filters and other stuff in Table 6.5.3.1.1B. May need to extend AirLoopHVAC data model
228
228
  def fan_power_limitation_pressure_drop_adjustment_brake_horsepower(template = "ASHRAE 90.1-2007")
229
-
229
+
230
230
  # Get design supply air flow rate (whether autosized or hard-sized)
231
231
  dsn_air_flow_m3_per_s = 0
232
232
  dsn_air_flow_cfm = 0
@@ -238,30 +238,30 @@ class OpenStudio::Model::AirLoopHVAC
238
238
  dsn_air_flow_m3_per_s = self.designSupplyAirFlowRate.get
239
239
  dsn_air_flow_cfm = OpenStudio.convert(dsn_air_flow_m3_per_s, "m^3/s", "cfm").get
240
240
  OpenStudio::logFree(OpenStudio::Debug, "openstudio.standards.AirLoopHVAC", "* #{dsn_air_flow_cfm.round} cfm = Hard sized Design Supply Air Flow Rate.")
241
- end
242
-
241
+ end
242
+
243
243
  # TODO determine the presence of MERV filters and other stuff
244
244
  # in Table 6.5.3.1.1B
245
245
  # perhaps need to extend AirLoopHVAC data model
246
246
  has_fully_ducted_return_and_or_exhaust_air_systems = false
247
-
247
+
248
248
  # Calculate Fan Power Limitation Pressure Drop Adjustment (in wc)
249
249
  fan_pwr_adjustment_in_wc = 0
250
-
250
+
251
251
  # Fully ducted return and/or exhaust air systems
252
252
  if has_fully_ducted_return_and_or_exhaust_air_systems
253
253
  adj_in_wc = 0.5
254
254
  fan_pwr_adjustment_in_wc += adj_in_wc
255
255
  OpenStudio::logFree(OpenStudio::Info, "openstudio.standards.AirLoopHVAC","--Added #{adj_in_wc} in wc for Fully ducted return and/or exhaust air systems")
256
256
  end
257
-
257
+
258
258
  # Convert the pressure drop adjustment to brake horsepower (bhp)
259
259
  # assuming that all supply air passes through all devices
260
260
  fan_pwr_adjustment_bhp = fan_pwr_adjustment_in_wc*dsn_air_flow_cfm / 4131
261
261
  OpenStudio::logFree(OpenStudio::Debug, "openstudio.standards.AirLoopHVAC","For #{self.name}: Fan Power Limitation Pressure Drop Adjustment = #{(fan_pwr_adjustment_bhp.round(2))} bhp")
262
-
262
+
263
263
  return fan_pwr_adjustment_bhp
264
-
264
+
265
265
  end
266
266
 
267
267
  # Determine the allowable fan system brake horsepower
@@ -271,7 +271,7 @@ class OpenStudio::Model::AirLoopHVAC
271
271
  # @return [Double] allowable fan system brake horsepower
272
272
  # units = horsepower
273
273
  def allowable_system_brake_horsepower(template = "ASHRAE 90.1-2007")
274
-
274
+
275
275
  # Get design supply air flow rate (whether autosized or hard-sized)
276
276
  dsn_air_flow_m3_per_s = 0
277
277
  dsn_air_flow_cfm = 0
@@ -287,10 +287,10 @@ class OpenStudio::Model::AirLoopHVAC
287
287
 
288
288
  # Get the fan limitation pressure drop adjustment bhp
289
289
  fan_pwr_adjustment_bhp = self.fan_power_limitation_pressure_drop_adjustment_brake_horsepower
290
-
290
+
291
291
  # Determine the number of zones the system serves
292
292
  num_zones_served = self.thermalZones.size
293
-
293
+
294
294
  # Get the supply air fan and determine whether VAV or CAV system.
295
295
  # Assume that supply air fan is fan closest to the demand outlet node.
296
296
  # The fan may be inside of a piece of unitary equipment.
@@ -314,16 +314,16 @@ class OpenStudio::Model::AirLoopHVAC
314
314
  elsif fan.to_FanVariableVolume.is_initialized
315
315
  fan_pwr_limit_type = "variable volume"
316
316
  end
317
- end
317
+ end
318
318
  end
319
-
320
- # For 90.1-2010, single-zone VAV systems use the
319
+
320
+ # For 90.1-2010, single-zone VAV systems use the
321
321
  # constant volume limitation per 6.5.3.1.1
322
322
  if template == "ASHRAE 90.1-2010" && fan_pwr_limit_type = "variable volume" && num_zones_served == 1
323
323
  fan_pwr_limit_type = "constant volume"
324
324
  OpenStudio::logFree(OpenStudio::Info, "openstudio.standards.AirLoopHVAC","For #{self.name}: Using the constant volume limitation because single-zone VAV system.")
325
325
  end
326
-
326
+
327
327
  # Calculate the Allowable Fan System brake horsepower per Table G3.1.2.9
328
328
  allowable_fan_bhp = 0
329
329
  if fan_pwr_limit_type == "constant volume"
@@ -332,7 +332,7 @@ class OpenStudio::Model::AirLoopHVAC
332
332
  allowable_fan_bhp = dsn_air_flow_cfm*0.0013+fan_pwr_adjustment_bhp
333
333
  end
334
334
  OpenStudio::logFree(OpenStudio::Info, "openstudio.standards.AirLoopHVAC","For #{self.name}: Allowable brake horsepower = #{(allowable_fan_bhp).round(2)}HP based on #{dsn_air_flow_cfm.round} cfm and #{fan_pwr_adjustment_bhp.round(2)} bhp of adjustment.")
335
-
335
+
336
336
  # Calculate and report the total area for debugging/testing
337
337
  floor_area_served_m2 = self.floor_area_served
338
338
  floor_area_served_ft2 = OpenStudio.convert(floor_area_served_m2, 'm^2', 'ft^2').get
@@ -341,7 +341,7 @@ class OpenStudio::Model::AirLoopHVAC
341
341
  OpenStudio::logFree(OpenStudio::Debug, "openstudio.standards.AirLoopHVAC","For #{self.name}: area served = #{floor_area_served_ft2.round} ft^2.")
342
342
  OpenStudio::logFree(OpenStudio::Debug, "openstudio.standards.AirLoopHVAC","For #{self.name}: flow per area = #{cfm_per_ft2.round} cfm/ft^2.")
343
343
  OpenStudio::logFree(OpenStudio::Debug, "openstudio.standards.AirLoopHVAC","For #{self.name}: flow per hp = #{cfm_per_hp.round} cfm/hp.")
344
-
344
+
345
345
  return allowable_fan_bhp
346
346
 
347
347
  end
@@ -349,14 +349,14 @@ class OpenStudio::Model::AirLoopHVAC
349
349
  # Get all of the supply, return, exhaust, and relief fans on this system
350
350
  #
351
351
  # @return [Array] an array of FanConstantVolume, FanVariableVolume, and FanOnOff objects
352
- def supply_return_exhaust_relief_fans()
353
-
352
+ def supply_return_exhaust_relief_fans()
353
+
354
354
  # Fans on the supply side of the airloop directly, or inside of unitary equipment.
355
355
  fans = []
356
356
  sup_and_oa_comps = self.supplyComponents
357
357
  sup_and_oa_comps += self.oaComponents
358
358
  sup_and_oa_comps.each do |comp|
359
- if comp.to_FanConstantVolume.is_initialized
359
+ if comp.to_FanConstantVolume.is_initialized
360
360
  fans << comp.to_FanConstantVolume.get
361
361
  elsif comp.to_FanVariableVolume.is_initialized
362
362
  fans << comp.to_FanVariableVolume.get
@@ -376,33 +376,33 @@ class OpenStudio::Model::AirLoopHVAC
376
376
  elsif sup_fan.to_FanOnOff.is_initialized
377
377
  fans << sup_fan.to_FanOnOff.get
378
378
  elsif sup_fan.to_FanVariableVolume.is_initialized
379
- fans << sup_fan.to_FanVariableVolume.get
380
- end
379
+ fans << sup_fan.to_FanVariableVolume.get
380
+ end
381
381
  end
382
- end
383
-
382
+ end
383
+
384
384
  return fans
385
-
385
+
386
386
  end
387
-
387
+
388
388
  # Determine the total brake horsepower of the fans on the system
389
389
  # with or without the fans inside of fan powered terminals.
390
390
  #
391
391
  # @param include_terminal_fans [Bool] if true, power from fan powered terminals will be included
392
392
  # @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'
393
393
  # @return [Double] total brake horsepower of the fans on the system
394
- # units = horsepower
394
+ # units = horsepower
395
395
  def system_fan_brake_horsepower(include_terminal_fans = true, template = "ASHRAE 90.1-2007")
396
396
 
397
397
  # TODO get the template from the parent model itself?
398
398
  # Or not because maybe you want to see the difference between two standards?
399
399
  OpenStudio::logFree(OpenStudio::Info, "openstudio.standards.AirLoopHVAC","#{self.name}-Determining #{template} allowable system fan power.")
400
-
400
+
401
401
  # Get all fans
402
402
  fans = []
403
403
  # Supply, exhaust, relief, and return fans
404
404
  fans += self.supply_return_exhaust_relief_fans
405
-
405
+
406
406
  # Fans inside of fan-powered terminals
407
407
  if include_terminal_fans
408
408
  self.demandComponents.each do |comp|
@@ -415,45 +415,45 @@ class OpenStudio::Model::AirLoopHVAC
415
415
  term_fan = comp.to_AirTerminalSingleDuctParallelPIUReheat.get.fan
416
416
  if term_fan.to_FanConstantVolume.is_initialized
417
417
  fans << term_fan.to_FanConstantVolume.get
418
- end
418
+ end
419
419
  end
420
420
  end
421
421
  end
422
-
422
+
423
423
  # Loop through all fans on the system and
424
424
  # sum up their brake horsepower values.
425
425
  sys_fan_bhp = 0
426
426
  fans.sort.each do |fan|
427
427
  sys_fan_bhp += fan.brakeHorsepower
428
428
  end
429
-
429
+
430
430
  return sys_fan_bhp
431
-
432
- end
433
-
431
+
432
+ end
433
+
434
434
  # Set the fan pressure rises that will result in
435
435
  # the system hitting the baseline allowable fan power
436
436
  #
437
- # @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'
437
+ # @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'
438
438
  def set_baseline_fan_pressure_rise(template = "ASHRAE 90.1-2007")
439
439
 
440
440
  OpenStudio::logFree(OpenStudio::Info, "openstudio.standards.AirLoopHVAC", "#{self.name}-Setting #{template} baseline fan power.")
441
-
441
+
442
442
  # Get the total system bhp from the proposed system, including terminal fans
443
443
  proposed_sys_bhp = self.system_fan_brake_horsepower(true)
444
-
444
+
445
445
  # Get the allowable fan brake horsepower
446
446
  allowable_fan_bhp = self.allowable_system_brake_horsepower(template)
447
447
 
448
448
  # Get the fan power limitation from proposed system
449
449
  fan_pwr_adjustment_bhp = self.fan_power_limitation_pressure_drop_adjustment_brake_horsepower
450
-
450
+
451
451
  # Subtract the fan power adjustment
452
452
  allowable_fan_bhp = allowable_fan_bhp-fan_pwr_adjustment_bhp
453
-
453
+
454
454
  # Get all fans
455
- fans = self.supply_return_exhaust_relief_fans
456
-
455
+ fans = self.supply_return_exhaust_relief_fans
456
+
457
457
  # TODO improve description
458
458
  # Loop through the fans, changing the pressure rise
459
459
  # until the fan bhp is the same percentage of the baseline allowable bhp
@@ -464,27 +464,27 @@ class OpenStudio::Model::AirLoopHVAC
464
464
  next if fan.name.to_s.include?("UnitHeater Fan")
465
465
 
466
466
  OpenStudio::logFree(OpenStudio::Info, "#{fan.name}")
467
-
467
+
468
468
  # Get the bhp of the fan on the proposed system
469
469
  proposed_fan_bhp = fan.brakeHorsepower
470
-
470
+
471
471
  # Get the bhp of the fan on the proposed system
472
472
  proposed_fan_bhp_frac = proposed_fan_bhp / proposed_sys_bhp
473
-
473
+
474
474
  # Determine the target bhp of the fan on the baseline system
475
475
  baseline_fan_bhp = proposed_fan_bhp_frac*allowable_fan_bhp
476
476
  OpenStudio::logFree(OpenStudio::Info, "openstudio.standards.AirLoopHVAC", "* #{(baseline_fan_bhp).round(1)} bhp = Baseline fan brake horsepower.")
477
-
478
- # Set the baseline impeller eff of the fan,
477
+
478
+ # Set the baseline impeller eff of the fan,
479
479
  # preserving the proposed motor eff.
480
480
  baseline_impeller_eff = fan.baselineImpellerEfficiency(template)
481
481
  fan.changeImpellerEfficiency(baseline_impeller_eff)
482
482
  OpenStudio::logFree(OpenStudio::Info, "openstudio.standards.AirLoopHVAC", "* #{(baseline_impeller_eff*100).round(1)}% = Baseline fan impeller efficiency.")
483
-
483
+
484
484
  # Set the baseline motor efficiency for the specified bhp
485
485
  baseline_motor_eff = fan.standardMinimumMotorEfficiency(template, standards, allowable_fan_bhp)
486
486
  fan.changeMotorEfficiency(baseline_motor_eff)
487
-
487
+
488
488
  # Get design supply air flow rate (whether autosized or hard-sized)
489
489
  dsn_air_flow_m3_per_s = 0
490
490
  if fan.autosizedDesignSupplyAirFlowRate.is_initialized
@@ -496,7 +496,7 @@ class OpenStudio::Model::AirLoopHVAC
496
496
  dsn_air_flow_cfm = OpenStudio.convert(dsn_air_flow_m3_per_s, "m^3/s", "cfm").get
497
497
  OpenStudio::logFree(OpenStudio::Debug, "openstudio.standards.AirLoopHVAC", "* #{dsn_air_flow_cfm.round} cfm = User entered Design Supply Air Flow Rate.")
498
498
  end
499
-
499
+
500
500
  # Determine the fan pressure rise that will result in the target bhp
501
501
  # pressure_rise_pa = fan_bhp*746 / fan_motor_eff*fan_total_eff / dsn_air_flow_m3_per_s
502
502
  baseline_pressure_rise_pa = baseline_fan_bhp*746 / fan.motorEfficiency*fan.fanEfficiency / dsn_air_flow_m3_per_s
@@ -510,7 +510,7 @@ class OpenStudio::Model::AirLoopHVAC
510
510
  end
511
511
 
512
512
  end
513
-
513
+
514
514
  # Calculate the total bhp of the system to make sure it matches the goal
515
515
  calc_sys_bhp = self.system_fan_brake_horsepower(false)
516
516
  if ((calc_sys_bhp-allowable_fan_bhp) / allowable_fan_bhp).abs > 0.02
@@ -526,7 +526,7 @@ class OpenStudio::Model::AirLoopHVAC
526
526
  # @todo Change to pull water coil nominal capacity instead of design load; not a huge difference, but water coil nominal capacity not available in sizing table.
527
527
  # @todo Handle all additional cooling coil types. Currently only handles CoilCoolingDXSingleSpeed, CoilCoolingDXTwoSpeed, and CoilCoolingWater
528
528
  def total_cooling_capacity
529
-
529
+
530
530
  # Sum the cooling capacity for all cooling components
531
531
  # on the airloop, which may be inside of unitary systems.
532
532
  total_cooling_capacity_w = 0
@@ -542,7 +542,7 @@ class OpenStudio::Model::AirLoopHVAC
542
542
  OpenStudio::logFree(OpenStudio::Warn, 'openstudio.standards.AirLoopHVAC', "For #{self.name} capacity of #{coil.name} is not available, total cooling capacity of air loop will be incorrect when applying standard.")
543
543
  end
544
544
  # CoilCoolingDXTwoSpeed
545
- elsif sc.to_CoilCoolingDXTwoSpeed.is_initialized
545
+ elsif sc.to_CoilCoolingDXTwoSpeed.is_initialized
546
546
  coil = sc.to_CoilCoolingDXTwoSpeed.get
547
547
  if coil.ratedHighSpeedTotalCoolingCapacity.is_initialized
548
548
  total_cooling_capacity_w += coil.ratedHighSpeedTotalCoolingCapacity.get
@@ -560,7 +560,7 @@ class OpenStudio::Model::AirLoopHVAC
560
560
  OpenStudio::logFree(OpenStudio::Warn, 'openstudio.standards.AirLoopHVAC', "For #{self.name} capacity of #{coil.name} is not available, total cooling capacity of air loop will be incorrect when applying standard.")
561
561
  end
562
562
  # CoilCoolingWaterToAirHeatPumpEquationFit
563
- elsif sc.to_CoilCoolingWaterToAirHeatPumpEquationFit.is_initialized
563
+ elsif sc.to_CoilCoolingWaterToAirHeatPumpEquationFit.is_initialized
564
564
  coil = sc.to_CoilCoolingWaterToAirHeatPumpEquationFit.get
565
565
  if coil.ratedTotalCoolingCapacity.is_initialized
566
566
  total_cooling_capacity_w += coil.ratedTotalCoolingCapacity.get
@@ -584,7 +584,7 @@ class OpenStudio::Model::AirLoopHVAC
584
584
  OpenStudio::logFree(OpenStudio::Warn, 'openstudio.standards.AirLoopHVAC', "For #{self.name} capacity of #{coil.name} is not available, total cooling capacity of air loop will be incorrect when applying standard.")
585
585
  end
586
586
  # CoilCoolingDXTwoSpeed
587
- elsif clg_coil.to_CoilCoolingDXTwoSpeed.is_initialized
587
+ elsif clg_coil.to_CoilCoolingDXTwoSpeed.is_initialized
588
588
  coil = clg_coil.to_CoilCoolingDXTwoSpeed.get
589
589
  if coil.ratedHighSpeedTotalCoolingCapacity.is_initialized
590
590
  total_cooling_capacity_w += coil.ratedHighSpeedTotalCoolingCapacity.get
@@ -602,7 +602,7 @@ class OpenStudio::Model::AirLoopHVAC
602
602
  OpenStudio::logFree(OpenStudio::Warn, 'openstudio.standards.AirLoopHVAC', "For #{self.name} capacity of #{coil.name} is not available, total cooling capacity of air loop will be incorrect when applying standard.")
603
603
  end
604
604
  # CoilCoolingWaterToAirHeatPumpEquationFit
605
- elsif clg_coil.to_CoilCoolingWaterToAirHeatPumpEquationFit.is_initialized
605
+ elsif clg_coil.to_CoilCoolingWaterToAirHeatPumpEquationFit.is_initialized
606
606
  coil = clg_coil.to_CoilCoolingWaterToAirHeatPumpEquationFit.get
607
607
  if coil.ratedTotalCoolingCapacity.is_initialized
608
608
  total_cooling_capacity_w += coil.ratedTotalCoolingCapacity.get
@@ -627,7 +627,7 @@ class OpenStudio::Model::AirLoopHVAC
627
627
  OpenStudio::logFree(OpenStudio::Warn, 'openstudio.standards.AirLoopHVAC', "For #{self.name} capacity of #{coil.name} is not available, total cooling capacity of air loop will be incorrect when applying standard.")
628
628
  end
629
629
  # CoilCoolingDXTwoSpeed
630
- elsif clg_coil.to_CoilCoolingDXTwoSpeed.is_initialized
630
+ elsif clg_coil.to_CoilCoolingDXTwoSpeed.is_initialized
631
631
  coil = clg_coil.to_CoilCoolingDXTwoSpeed.get
632
632
  if coil.ratedHighSpeedTotalCoolingCapacity.is_initialized
633
633
  total_cooling_capacity_w += coil.ratedHighSpeedTotalCoolingCapacity.get
@@ -655,16 +655,16 @@ class OpenStudio::Model::AirLoopHVAC
655
655
  # CoilCoolingCooledBeam
656
656
  # CoilCoolingWaterToAirHeatPumpEquationFit
657
657
  # AirLoopHVACUnitaryHeatCoolVAVChangeoverBypass
658
- # AirLoopHVACUnitaryHeatPumpAirToAir
659
- # AirLoopHVACUnitaryHeatPumpAirToAirMultiSpeed
658
+ # AirLoopHVACUnitaryHeatPumpAirToAir
659
+ # AirLoopHVACUnitaryHeatPumpAirToAirMultiSpeed
660
660
  # AirLoopHVACUnitarySystem
661
661
  end
662
662
  end
663
663
 
664
664
  return total_cooling_capacity_w
665
-
665
+
666
666
  end
667
-
667
+
668
668
  # Determine whether or not this system
669
669
  # is required to have an economizer.
670
670
  #
@@ -672,25 +672,25 @@ class OpenStudio::Model::AirLoopHVAC
672
672
  # @param climate_zone [String] valid choices: 'ASHRAE 169-2006-1A', 'ASHRAE 169-2006-1B', 'ASHRAE 169-2006-2A', 'ASHRAE 169-2006-2B',
673
673
  # 'ASHRAE 169-2006-3A', 'ASHRAE 169-2006-3B', 'ASHRAE 169-2006-3C', 'ASHRAE 169-2006-4A', 'ASHRAE 169-2006-4B', 'ASHRAE 169-2006-4C',
674
674
  # 'ASHRAE 169-2006-5A', 'ASHRAE 169-2006-5B', 'ASHRAE 169-2006-5C', 'ASHRAE 169-2006-6A', 'ASHRAE 169-2006-6B', 'ASHRAE 169-2006-7A',
675
- # 'ASHRAE 169-2006-7B', 'ASHRAE 169-2006-8A', 'ASHRAE 169-2006-8B'
675
+ # 'ASHRAE 169-2006-7B', 'ASHRAE 169-2006-8A', 'ASHRAE 169-2006-8B'
676
676
  # @return [Bool] returns true if an economizer is required, false if not
677
677
  def is_economizer_required(template, climate_zone)
678
-
678
+
679
679
  economizer_required = false
680
-
680
+
681
681
  return economizer_required if self.name.to_s.include? "Outpatient F1"
682
-
682
+
683
683
  # A big number of btu per hr as the minimum requirement
684
684
  infinity_btu_per_hr = 999999999999
685
685
  minimum_capacity_btu_per_hr = infinity_btu_per_hr
686
-
686
+
687
687
  # Determine if the airloop serves any computer rooms
688
688
  # / data centers, which changes the economizer.
689
689
  is_dc = false
690
690
  if self.data_center_area_served > 0
691
691
  is_dc = true
692
692
  end
693
-
693
+
694
694
  # Determine the minimum capacity that requires an economizer
695
695
  case template
696
696
  when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004', '90.1-2004', '90.1-2007'
@@ -734,7 +734,7 @@ class OpenStudio::Model::AirLoopHVAC
734
734
  'ASHRAE 169-2006-7B',
735
735
  'ASHRAE 169-2006-8A',
736
736
  'ASHRAE 169-2006-8B'
737
- minimum_capacity_btu_per_hr = 135000
737
+ minimum_capacity_btu_per_hr = 135000
738
738
  when 'ASHRAE 169-2006-3B',
739
739
  'ASHRAE 169-2006-3C',
740
740
  'ASHRAE 169-2006-4B',
@@ -744,7 +744,7 @@ class OpenStudio::Model::AirLoopHVAC
744
744
  'ASHRAE 169-2006-6B'
745
745
  minimum_capacity_btu_per_hr = 65000
746
746
  end
747
- else
747
+ else
748
748
  case climate_zone
749
749
  when 'ASHRAE 169-2006-1A',
750
750
  'ASHRAE 169-2006-1B'
@@ -772,7 +772,7 @@ class OpenStudio::Model::AirLoopHVAC
772
772
  when 'NECB 2011'
773
773
  minimum_capacity_btu_per_hr = 68243 # NECB requires economizer for cooling cap > 20 kW
774
774
  end
775
-
775
+
776
776
  # Check whether the system requires an economizer by comparing
777
777
  # the system capacity to the minimum capacity.
778
778
  total_cooling_capacity_w = self.total_cooling_capacity
@@ -789,20 +789,20 @@ class OpenStudio::Model::AirLoopHVAC
789
789
  OpenStudio::logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "#{self.name} does not require an economizer because the total cooling capacity of #{total_cooling_capacity_btu_per_hr.round} Btu/hr is less than the minimum capacity of #{minimum_capacity_btu_per_hr.round} Btu/hr for data centers.")
790
790
  else
791
791
  OpenStudio::logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "#{self.name} does not require an economizer because the total cooling capacity of #{total_cooling_capacity_btu_per_hr.round} Btu/hr is less than the minimum capacity of #{minimum_capacity_btu_per_hr.round} Btu/hr.")
792
- end
792
+ end
793
793
  end
794
-
794
+
795
795
  return economizer_required
796
-
796
+
797
797
  end
798
-
798
+
799
799
  # Set the economizer limits per the standard. Limits are based on the economizer
800
800
  # type currently specified in the ControllerOutdoorAir object on this air loop.
801
801
  #
802
802
  # @param (see #is_economizer_required)
803
803
  # @return [Bool] returns true if successful, false if not
804
804
  def set_economizer_limits(template, climate_zone)
805
-
805
+
806
806
  # EnergyPlus economizer types
807
807
  # 'NoEconomizer'
808
808
  # 'FixedDryBulb'
@@ -811,8 +811,8 @@ class OpenStudio::Model::AirLoopHVAC
811
811
  # 'DifferentialEnthalpy'
812
812
  # 'FixedDewPointAndDryBulb'
813
813
  # 'ElectronicEnthalpy'
814
- # 'DifferentialDryBulbAndEnthalpy'
815
-
814
+ # 'DifferentialDryBulbAndEnthalpy'
815
+
816
816
  # Get the OA system and OA controller
817
817
  oa_sys = self.airLoopHVACOutdoorAirSystem
818
818
  if oa_sys.is_initialized
@@ -822,12 +822,12 @@ class OpenStudio::Model::AirLoopHVAC
822
822
  end
823
823
  oa_control = oa_sys.getControllerOutdoorAir
824
824
  economizer_type = oa_control.getEconomizerControlType
825
-
825
+
826
826
  # Return false if no economizer is present
827
827
  if economizer_type == 'NoEconomizer'
828
828
  return false
829
829
  end
830
-
830
+
831
831
  # Determine the limits according to the type
832
832
  drybulb_limit_f = nil
833
833
  enthalpy_limit_btu_per_lb = nil
@@ -894,8 +894,8 @@ class OpenStudio::Model::AirLoopHVAC
894
894
  drybulb_limit_f = 75
895
895
  dewpoint_limit_f = 55
896
896
  end
897
- end
898
-
897
+ end
898
+
899
899
  # Set the limits
900
900
  case economizer_type
901
901
  when 'FixedDryBulb'
@@ -918,10 +918,10 @@ class OpenStudio::Model::AirLoopHVAC
918
918
  oa_control.setEconomizerMaximumLimitDewpointTemperature(dewpoint_limit_c)
919
919
  OpenStudio::logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "For #{self.name}: Economizer type = #{economizer_type}, dry bulb limit = #{drybulb_limit_f}F, dew-point limit = #{dewpoint_limit_f}F")
920
920
  end
921
- end
921
+ end
922
922
 
923
923
  return true
924
-
924
+
925
925
  end
926
926
 
927
927
  # For systems required to have an economizer, set the economizer
@@ -932,7 +932,7 @@ class OpenStudio::Model::AirLoopHVAC
932
932
  # @param (see #is_economizer_required)
933
933
  # @return [Bool] returns true if successful, false if not
934
934
  def set_economizer_integration(template, climate_zone)
935
-
935
+
936
936
  # Determine if the system is a VAV system based on the fan
937
937
  # which may be inside of a unitary system.
938
938
  is_vav = false
@@ -951,20 +951,20 @@ class OpenStudio::Model::AirLoopHVAC
951
951
  is_vav = true
952
952
  end
953
953
  end
954
- end
954
+ end
955
955
  end
956
956
 
957
957
  # Determine the number of zones the system serves
958
958
  num_zones_served = self.thermalZones.size
959
-
959
+
960
960
  # A big number of btu per hr as the minimum requirement
961
961
  infinity_btu_per_hr = 999999999999
962
962
  minimum_capacity_btu_per_hr = infinity_btu_per_hr
963
-
963
+
964
964
  # Determine if an integrated economizer is required
965
965
  integrated_economizer_required = true
966
966
  case template
967
- when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004', '90.1-2004', '90.1-2007'
967
+ when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004', '90.1-2004', '90.1-2007'
968
968
  minimum_capacity_btu_per_hr = 65000
969
969
  minimum_capacity_w = OpenStudio.convert(minimum_capacity_btu_per_hr, "Btu/hr", "W").get
970
970
  # 6.5.1.3 Integrated Economizer Control
@@ -1007,10 +1007,10 @@ class OpenStudio::Model::AirLoopHVAC
1007
1007
  integrated_economizer_required = true
1008
1008
  when 'NECB 2011'
1009
1009
  # this means that compressor allowed to turn on when economizer is open
1010
- # (NoLockout); as per 5.2.2.8(3)
1010
+ # (NoLockout); as per 5.2.2.8(3)
1011
1011
  integrated_economizer_required = true
1012
1012
  end
1013
-
1013
+
1014
1014
  # Get the OA system and OA controller
1015
1015
  oa_sys = self.airLoopHVACOutdoorAirSystem
1016
1016
  if oa_sys.is_initialized
@@ -1018,8 +1018,8 @@ class OpenStudio::Model::AirLoopHVAC
1018
1018
  else
1019
1019
  return false # No OA system
1020
1020
  end
1021
- oa_control = oa_sys.getControllerOutdoorAir
1022
-
1021
+ oa_control = oa_sys.getControllerOutdoorAir
1022
+
1023
1023
  # Apply integrated or non-integrated economizer
1024
1024
  if integrated_economizer_required
1025
1025
  oa_control.setLockoutType('NoLockout')
@@ -1028,22 +1028,22 @@ class OpenStudio::Model::AirLoopHVAC
1028
1028
  end
1029
1029
 
1030
1030
  return true
1031
-
1031
+
1032
1032
  end
1033
-
1033
+
1034
1034
  # Determine if an economizer is required per the PRM.
1035
1035
  #
1036
1036
  # @param (see #is_economizer_required)
1037
1037
  # @return [Bool] returns true if required, false if not
1038
1038
  def is_performance_rating_method_baseline_economizer_required(template, climate_zone)
1039
-
1039
+
1040
1040
  economizer_required = false
1041
-
1041
+
1042
1042
  # A big number of ft2 as the minimum requirement
1043
1043
  infinity_ft2 = 999999999999
1044
1044
  min_int_area_served_ft2 = infinity_ft2
1045
1045
  min_ext_area_served_ft2 = infinity_ft2
1046
-
1046
+
1047
1047
  # Determine the minimum capacity that requires an economizer
1048
1048
  case template
1049
1049
  when '90.1-2004'
@@ -1083,21 +1083,21 @@ class OpenStudio::Model::AirLoopHVAC
1083
1083
  'ASHRAE 169-2006-4A'
1084
1084
  min_int_area_served_ft2 = infinity_ft2 # No requirement
1085
1085
  min_ext_area_served_ft2 = infinity_ft2 # No requirement
1086
- else
1086
+ else
1087
1087
  min_int_area_served_ft2 = 0 # Always required
1088
1088
  min_ext_area_served_ft2 = 0 # Always required
1089
1089
  end
1090
1090
  end
1091
-
1091
+
1092
1092
  # Check whether the system requires an economizer by comparing
1093
1093
  # the system capacity to the minimum capacity.
1094
1094
  min_int_area_served_m2 = OpenStudio.convert(min_int_area_served_ft2, "ft^2", "m^2").get
1095
1095
  min_ext_area_served_m2 = OpenStudio.convert(min_ext_area_served_ft2, "ft^2", "m^2").get
1096
-
1096
+
1097
1097
  # Get the interior and exterior area served
1098
1098
  int_area_served_m2 = self.floor_area_served_interior_zones
1099
1099
  ext_area_served_m2 = self.floor_area_served_exterior_zones
1100
-
1100
+
1101
1101
  # Check the floor area exception
1102
1102
  if int_area_served_m2 < min_int_area_served_m2 && ext_area_served_m2 < min_ext_area_served_m2
1103
1103
  if min_int_area_served_ft2 == infinity_ft2 && min_ext_area_served_ft2 == infinity_ft2
@@ -1107,21 +1107,21 @@ class OpenStudio::Model::AirLoopHVAC
1107
1107
  end
1108
1108
  return economizer_required
1109
1109
  end
1110
-
1110
+
1111
1111
  # If here, economizer required
1112
1112
  economizer_required = true
1113
1113
  OpenStudio::logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "For #{self.name}: Economizer required for the performance rating method baseline.")
1114
-
1115
- return economizer_required
1114
+
1115
+ return economizer_required
1116
1116
 
1117
1117
  end
1118
-
1118
+
1119
1119
  # Apply the PRM economizer type and set temperature limits
1120
1120
  #
1121
1121
  # @param (see #is_economizer_required)
1122
1122
  # @return [Bool] returns true if successful, false if not
1123
1123
  def apply_performance_rating_method_baseline_economizer(template, climate_zone)
1124
-
1124
+
1125
1125
  # EnergyPlus economizer types
1126
1126
  # 'NoEconomizer'
1127
1127
  # 'FixedDryBulb'
@@ -1130,7 +1130,7 @@ class OpenStudio::Model::AirLoopHVAC
1130
1130
  # 'DifferentialEnthalpy'
1131
1131
  # 'FixedDewPointAndDryBulb'
1132
1132
  # 'ElectronicEnthalpy'
1133
- # 'DifferentialDryBulbAndEnthalpy'
1133
+ # 'DifferentialDryBulbAndEnthalpy'
1134
1134
 
1135
1135
  # Determine the type and limits
1136
1136
  economizer_type = nil
@@ -1178,7 +1178,7 @@ class OpenStudio::Model::AirLoopHVAC
1178
1178
  'ASHRAE 169-2006-7B',
1179
1179
  'ASHRAE 169-2006-8A',
1180
1180
  'ASHRAE 169-2006-8B'
1181
- economizer_type = 'FixedDryBulb'
1181
+ economizer_type = 'FixedDryBulb'
1182
1182
  drybulb_limit_f = 75
1183
1183
  when 'ASHRAE 169-2006-2A',
1184
1184
  'ASHRAE 169-2006-3A',
@@ -1188,14 +1188,14 @@ class OpenStudio::Model::AirLoopHVAC
1188
1188
  when 'ASHRAE 169-2006-5A',
1189
1189
  'ASHRAE 169-2006-6A',
1190
1190
  'ASHRAE 169-2006-7A'
1191
- economizer_type = 'FixedDryBulb'
1191
+ economizer_type = 'FixedDryBulb'
1192
1192
  drybulb_limit_f = 70
1193
1193
  else
1194
- economizer_type = 'FixedDryBulb'
1194
+ economizer_type = 'FixedDryBulb'
1195
1195
  drybulb_limit_f = 65
1196
1196
  end
1197
1197
  end
1198
-
1198
+
1199
1199
  # Get the OA system and OA controller
1200
1200
  oa_sys = self.airLoopHVACOutdoorAirSystem
1201
1201
  if oa_sys.is_initialized
@@ -1204,7 +1204,7 @@ class OpenStudio::Model::AirLoopHVAC
1204
1204
  return false # No OA system
1205
1205
  end
1206
1206
  oa_control = oa_sys.getControllerOutdoorAir
1207
-
1207
+
1208
1208
  # Set the limits
1209
1209
  case economizer_type
1210
1210
  when 'FixedDryBulb'
@@ -1227,12 +1227,12 @@ class OpenStudio::Model::AirLoopHVAC
1227
1227
  oa_control.setEconomizerMaximumLimitDewpointTemperature(dewpoint_limit_c)
1228
1228
  OpenStudio::logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "For #{self.name}: Economizer type = #{economizer_type}, dry bulb limit = #{drybulb_limit_f}F, dew-point limit = #{dewpoint_limit_f}F")
1229
1229
  end
1230
- end
1230
+ end
1231
1231
 
1232
1232
  return true
1233
1233
 
1234
1234
  end
1235
-
1235
+
1236
1236
  # Check the economizer type currently specified in the ControllerOutdoorAir object on this air loop
1237
1237
  # is acceptable per the standard.
1238
1238
  #
@@ -1240,7 +1240,7 @@ class OpenStudio::Model::AirLoopHVAC
1240
1240
  # @return [Bool] Returns true if allowable, if the system has no economizer or no OA system.
1241
1241
  # Returns false if the economizer type is not allowable.
1242
1242
  def is_economizer_type_allowable(template, climate_zone)
1243
-
1243
+
1244
1244
  # EnergyPlus economizer types
1245
1245
  # 'NoEconomizer'
1246
1246
  # 'FixedDryBulb'
@@ -1250,7 +1250,7 @@ class OpenStudio::Model::AirLoopHVAC
1250
1250
  # 'FixedDewPointAndDryBulb'
1251
1251
  # 'ElectronicEnthalpy'
1252
1252
  # 'DifferentialDryBulbAndEnthalpy'
1253
-
1253
+
1254
1254
  # Get the OA system and OA controller
1255
1255
  oa_sys = self.airLoopHVACOutdoorAirSystem
1256
1256
  if oa_sys.is_initialized
@@ -1260,12 +1260,12 @@ class OpenStudio::Model::AirLoopHVAC
1260
1260
  end
1261
1261
  oa_control = oa_sys.getControllerOutdoorAir
1262
1262
  economizer_type = oa_control.getEconomizerControlType
1263
-
1263
+
1264
1264
  # Return true if no economizer is present
1265
1265
  if economizer_type == 'NoEconomizer'
1266
1266
  return true
1267
1267
  end
1268
-
1268
+
1269
1269
  # Determine the minimum capacity that requires an economizer
1270
1270
  prohibited_types = []
1271
1271
  case template
@@ -1290,7 +1290,7 @@ class OpenStudio::Model::AirLoopHVAC
1290
1290
  'ASHRAE 169-2006-3A',
1291
1291
  'ASHRAE 169-2006-4A'
1292
1292
  prohibited_types = ['DifferentialDryBulb']
1293
- when
1293
+ when
1294
1294
  'ASHRAE 169-2006-5A',
1295
1295
  'ASHRAE 169-2006-6A',
1296
1296
  prohibited_types = []
@@ -1316,31 +1316,30 @@ class OpenStudio::Model::AirLoopHVAC
1316
1316
  'ASHRAE 169-2006-3A',
1317
1317
  'ASHRAE 169-2006-4A'
1318
1318
  prohibited_types = ['FixedDryBulb', 'DifferentialDryBulb']
1319
- when
1319
+ when
1320
1320
  'ASHRAE 169-2006-5A',
1321
1321
  'ASHRAE 169-2006-6A',
1322
1322
  prohibited_types = []
1323
1323
  end
1324
1324
  end
1325
-
1325
+
1326
1326
  # Check if the specified type is allowed
1327
1327
  economizer_type_allowed = true
1328
1328
  if prohibited_types.include?(economizer_type)
1329
1329
  economizer_type_allowed = false
1330
1330
  end
1331
-
1331
+
1332
1332
  return economizer_type_allowed
1333
-
1333
+
1334
1334
  end
1335
-
1335
+
1336
1336
  # Check if ERV is required on this airloop.
1337
1337
  #
1338
1338
  # @param (see #is_economizer_required)
1339
- # @return [Bool] Returns true if required, false if not.
1339
+ # @return [Bool] Returns true if required, false if not.
1340
1340
  # @todo Add exception logic for systems serving parking garage, warehouse, or multifamily
1341
1341
  def is_energy_recovery_ventilator_required(template, climate_zone)
1342
-
1343
- # ERV Not Applicable for AHUs that serve
1342
+ # ERV Not Applicable for AHUs that serve
1344
1343
  # parking garage, warehouse, or multifamily
1345
1344
  # if space_types_served_names.include?('PNNL_Asset_Rating_Apartment_Space_Type') ||
1346
1345
  # space_types_served_names.include?('PNNL_Asset_Rating_LowRiseApartment_Space_Type') ||
@@ -1349,22 +1348,41 @@ class OpenStudio::Model::AirLoopHVAC
1349
1348
  # OpenStudio::logFree(OpenStudio::Info, "openstudio.standards.AirLoopHVAC", "For #{self.name}, ERV not applicable because it because it serves parking garage, warehouse, or multifamily.")
1350
1349
  # return false
1351
1350
  # end
1352
-
1351
+
1353
1352
  erv_required = nil
1354
1353
  # ERV not applicable for medical AHUs (AHU1 in Outpatient), per AIA 2001 - 7.31.D2.
1355
1354
  if self.name.to_s.include? "Outpatient F1"
1356
1355
  erv_required = false
1357
1356
  return erv_required
1358
1357
  end
1359
-
1358
+
1359
+ # ERV not applicable for medical AHUs, per AIA 2001 - 7.31.D2.
1360
+ if self.name.to_s.include? "VAV_ER"
1361
+ erv_required = false
1362
+ return erv_required
1363
+ elsif self.name.to_s.include? "VAV_OR"
1364
+ erv_required = false
1365
+ return erv_required
1366
+ end
1367
+ case template
1368
+ when '90.1-2004', '90.1-2007'
1369
+ if self.name.to_s.include? "VAV_ICU"
1370
+ erv_required = false
1371
+ return erv_required
1372
+ elsif self.name.to_s.include? "VAV_PATRMS"
1373
+ erv_required = false
1374
+ return erv_required
1375
+ end
1376
+ end
1377
+
1360
1378
  # ERV Not Applicable for AHUs that have DCV
1361
- # or that have no OA intake.
1379
+ # or that have no OA intake.
1362
1380
  controller_oa = nil
1363
1381
  controller_mv = nil
1364
1382
  oa_system = nil
1365
1383
  if self.airLoopHVACOutdoorAirSystem.is_initialized
1366
1384
  oa_system = self.airLoopHVACOutdoorAirSystem.get
1367
- controller_oa = oa_system.getControllerOutdoorAir
1385
+ controller_oa = oa_system.getControllerOutdoorAir
1368
1386
  controller_mv = controller_oa.controllerMechanicalVentilation
1369
1387
  if controller_mv.demandControlledVentilation == true
1370
1388
  OpenStudio::logFree(OpenStudio::Info, "openstudio.standards.AirLoopHVAC", "For #{self.name}, ERV not applicable because DCV enabled.")
@@ -1375,6 +1393,7 @@ class OpenStudio::Model::AirLoopHVAC
1375
1393
  return false
1376
1394
  end
1377
1395
 
1396
+
1378
1397
  # Get the AHU design supply air flow rate
1379
1398
  dsn_flow_m3_per_s = nil
1380
1399
  if self.designSupplyAirFlowRate.is_initialized
@@ -1386,7 +1405,7 @@ class OpenStudio::Model::AirLoopHVAC
1386
1405
  return false
1387
1406
  end
1388
1407
  dsn_flow_cfm = OpenStudio.convert(dsn_flow_m3_per_s, 'm^3/s', 'cfm').get
1389
-
1408
+
1390
1409
  # Get the minimum OA flow rate
1391
1410
  min_oa_flow_m3_per_s = nil
1392
1411
  if controller_oa.minimumOutdoorAirFlowRate.is_initialized
@@ -1398,10 +1417,10 @@ class OpenStudio::Model::AirLoopHVAC
1398
1417
  return false
1399
1418
  end
1400
1419
  min_oa_flow_cfm = OpenStudio.convert(min_oa_flow_m3_per_s, 'm^3/s', 'cfm').get
1401
-
1420
+
1402
1421
  # Calculate the percent OA at design airflow
1403
1422
  pct_oa = min_oa_flow_m3_per_s/dsn_flow_m3_per_s
1404
-
1423
+
1405
1424
  case template
1406
1425
  when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004'
1407
1426
  erv_cfm = nil # Not required
@@ -1427,7 +1446,7 @@ class OpenStudio::Model::AirLoopHVAC
1427
1446
  erv_cfm = nil
1428
1447
  elsif pct_oa >= 0.7 && pct_oa < 0.8
1429
1448
  erv_cfm = 5000
1430
- elsif pct_oa >= 0.8
1449
+ elsif pct_oa >= 0.8
1431
1450
  erv_cfm = 5000
1432
1451
  end
1433
1452
  when 'ASHRAE 169-2006-1B', 'ASHRAE 169-2006-2B', 'ASHRAE 169-2006-5C'
@@ -1443,7 +1462,7 @@ class OpenStudio::Model::AirLoopHVAC
1443
1462
  erv_cfm = 12000
1444
1463
  elsif pct_oa >= 0.7 && pct_oa < 0.8
1445
1464
  erv_cfm = 5000
1446
- elsif pct_oa >= 0.8
1465
+ elsif pct_oa >= 0.8
1447
1466
  erv_cfm = 4000
1448
1467
  end
1449
1468
  when 'ASHRAE 169-2006-6B'
@@ -1459,9 +1478,9 @@ class OpenStudio::Model::AirLoopHVAC
1459
1478
  erv_cfm = 3500
1460
1479
  elsif pct_oa >= 0.7 && pct_oa < 0.8
1461
1480
  erv_cfm = 2500
1462
- elsif pct_oa >= 0.8
1481
+ elsif pct_oa >= 0.8
1463
1482
  erv_cfm = 1500
1464
- end
1483
+ end
1465
1484
  when 'ASHRAE 169-2006-1A', 'ASHRAE 169-2006-2A', 'ASHRAE 169-2006-3A', 'ASHRAE 169-2006-4A', 'ASHRAE 169-2006-5A', 'ASHRAE 169-2006-6A'
1466
1485
  if pct_oa < 0.3
1467
1486
  erv_cfm = nil
@@ -1475,9 +1494,9 @@ class OpenStudio::Model::AirLoopHVAC
1475
1494
  erv_cfm = 2000
1476
1495
  elsif pct_oa >= 0.7 && pct_oa < 0.8
1477
1496
  erv_cfm = 1000
1478
- elsif pct_oa >= 0.8
1497
+ elsif pct_oa >= 0.8
1479
1498
  erv_cfm = 0
1480
- end
1499
+ end
1481
1500
  when 'ASHRAE 169-2006-7A', 'ASHRAE 169-2006-7B', 'ASHRAE 169-2006-8A', 'ASHRAE 169-2006-8B'
1482
1501
  if pct_oa < 0.3
1483
1502
  erv_cfm = nil
@@ -1491,9 +1510,9 @@ class OpenStudio::Model::AirLoopHVAC
1491
1510
  erv_cfm = 0
1492
1511
  elsif pct_oa >= 0.7 && pct_oa < 0.8
1493
1512
  erv_cfm = 0
1494
- elsif pct_oa >= 0.8
1513
+ elsif pct_oa >= 0.8
1495
1514
  erv_cfm = 0
1496
- end
1515
+ end
1497
1516
  end
1498
1517
  when '90.1-2013'
1499
1518
  # Table 6.5.6.1-2
@@ -1517,7 +1536,7 @@ class OpenStudio::Model::AirLoopHVAC
1517
1536
  erv_cfm = 3000
1518
1537
  elsif pct_oa >= 0.7 && pct_oa < 0.8
1519
1538
  erv_cfm = 1500
1520
- elsif pct_oa >= 0.8
1539
+ elsif pct_oa >= 0.8
1521
1540
  erv_cfm = 0
1522
1541
  end
1523
1542
  when 'ASHRAE 169-2006-1A', 'ASHRAE 169-2006-2A', 'ASHRAE 169-2006-3A', 'ASHRAE 169-2006-4B', 'ASHRAE 169-2006-5B'
@@ -1543,39 +1562,39 @@ class OpenStudio::Model::AirLoopHVAC
1543
1562
  end
1544
1563
  when 'NECB 2011'
1545
1564
  # The NECB 2011 requirement is that systems with an exhaust heat content > 150 kW require an HRV
1546
- # The calculation for this is done below, to modify erv_required
1565
+ # The calculation for this is done below, to modify erv_required
1547
1566
  # erv_cfm set to nil here as placeholder, will lead to erv_required = false
1548
1567
  erv_cfm = nil
1549
1568
  end
1550
-
1569
+
1551
1570
  # Determine if an ERV is required
1552
1571
  # erv_required = nil
1553
1572
  if erv_cfm.nil?
1554
1573
  OpenStudio::logFree(OpenStudio::Info, "openstudio.standards.AirLoopHVAC", "For #{self.name}, ERV not required based on #{(pct_oa*100).round}% OA flow, design flow of #{dsn_flow_cfm.round}cfm, and climate zone #{climate_zone}.")
1555
- erv_required = false
1574
+ erv_required = false
1556
1575
  elsif dsn_flow_cfm < erv_cfm
1557
1576
  OpenStudio::logFree(OpenStudio::Info, "openstudio.standards.AirLoopHVAC", "For #{self.name}, ERV not required based on #{(pct_oa*100).round}% OA flow, design flow of #{dsn_flow_cfm.round}cfm, and climate zone #{climate_zone}. Does not exceed minimum flow requirement of #{erv_cfm}cfm.")
1558
- erv_required = false
1577
+ erv_required = false
1559
1578
  else
1560
1579
  OpenStudio::logFree(OpenStudio::Info, "openstudio.standards.AirLoopHVAC", "For #{self.name}, ERV required based on #{(pct_oa*100).round}% OA flow, design flow of #{dsn_flow_cfm.round}cfm, and climate zone #{climate_zone}. Exceeds minimum flow requirement of #{erv_cfm}cfm.")
1561
- erv_required = true
1580
+ erv_required = true
1562
1581
  end
1563
-
1582
+
1564
1583
  # This code modifies erv_required for NECB 2011
1565
1584
  # Calculation of exhaust heat content and check whether it is > 150 kW
1566
-
1567
- if template == 'NECB 2011'
1568
-
1585
+
1586
+ if template == 'NECB 2011'
1587
+
1569
1588
  # get all zones in the model
1570
1589
  zones = self.thermalZones
1571
-
1590
+
1572
1591
  # initialize counters
1573
1592
  sum_zone_oa = 0.0
1574
1593
  sum_zoneoaTimesheatDesignT = 0.0
1575
-
1594
+
1576
1595
  # zone loop
1577
1596
  zones.each do |zone|
1578
-
1597
+
1579
1598
  # get design heat temperature for each zone; this is equivalent to design exhaust temperature
1580
1599
  zone_sizing = zone.sizingZone
1581
1600
  heatDesignTemp = zone_sizing.zoneHeatingDesignSupplyAirTemperature
@@ -1584,77 +1603,77 @@ class OpenStudio::Model::AirLoopHVAC
1584
1603
  zone_oa = 0.0
1585
1604
  # outdoor defined at space level; get OA flow for all spaces within zone
1586
1605
  spaces = zone.spaces
1587
-
1606
+
1588
1607
  # space loop
1589
1608
  spaces.each do |space|
1590
1609
  if not space.designSpecificationOutdoorAir.empty? # if empty, don't do anything
1591
- outdoor_air = space.designSpecificationOutdoorAir.get
1592
-
1610
+ outdoor_air = space.designSpecificationOutdoorAir.get
1611
+
1593
1612
  # in bTAP, outdoor air specified as outdoor air per person (m3/s/person)
1594
1613
  oa_flow_per_person = outdoor_air.outdoorAirFlowperPerson
1595
1614
  num_people = space.peoplePerFloorArea * space.floorArea
1596
1615
  oa_flow = oa_flow_per_person * num_people # oa flow for the space
1597
1616
  zone_oa = zone_oa + oa_flow # add up oa flow for all spaces to get zone air flow
1598
- end
1599
-
1617
+ end
1618
+
1600
1619
  end # space loop
1601
-
1620
+
1602
1621
  sum_zone_oa = sum_zone_oa + zone_oa # sum of all zone oa flows to get system oa flow
1603
1622
  sum_zoneoaTimesheatDesignT = sum_zoneoaTimesheatDesignT + (zone_oa * heatDesignTemp) # calculated to get oa flow weighted average of design exhaust temperature
1604
-
1623
+
1605
1624
  end # zone loop
1606
-
1625
+
1607
1626
  # Calculate average exhaust temperature (oa flow weighted average)
1608
- avg_exhaust_temp = sum_zoneoaTimesheatDesignT / sum_zone_oa
1609
-
1610
- # for debugging/testing
1627
+ avg_exhaust_temp = sum_zoneoaTimesheatDesignT / sum_zone_oa
1628
+
1629
+ # for debugging/testing
1611
1630
  # puts "average exhaust temp = #{avg_exhaust_temp}"
1612
1631
  # puts "sum_zone_oa = #{sum_zone_oa}"
1613
-
1632
+
1614
1633
  # Get January winter design temperature
1615
1634
  # get model weather file name
1616
1635
  weather_file = BTAP::Environment::WeatherFile.new(self.model.weatherFile.get.path.get)
1617
-
1636
+
1618
1637
  # get winter(heating) design temp stored in array
1619
1638
  # Note that the NECB 2011 specifies using the 2.5% january design temperature
1620
1639
  # The outdoor temperature used here is the 0.4% heating design temperature of the coldest month, available in stat file
1621
1640
  outdoor_temp = weather_file.heating_design_info[1]
1622
-
1641
+
1623
1642
  # for debugging/testing
1624
- # puts "outdoor design temp = #{outdoor_temp}"
1625
-
1643
+ # puts "outdoor design temp = #{outdoor_temp}"
1644
+
1626
1645
  # Calculate exhaust heat content
1627
1646
  exhaust_heat_content = 0.00123 * sum_zone_oa * 1000.0 * (avg_exhaust_temp - outdoor_temp)
1628
-
1647
+
1629
1648
  # for debugging/testing
1630
1649
  # puts "exhaust heat content = #{exhaust_heat_content}"
1631
-
1632
-
1650
+
1651
+
1633
1652
  # Modify erv_required based on exhaust heat content
1634
1653
  if ( exhaust_heat_content > 150.0 ) then
1635
1654
  erv_required = true
1636
- OpenStudio::logFree(OpenStudio::Info, "openstudio.standards.AirLoopHVAC", "For #{self.name}, ERV required based on exhaust heat content.")
1655
+ OpenStudio::logFree(OpenStudio::Info, "openstudio.standards.AirLoopHVAC", "For #{self.name}, ERV required based on exhaust heat content.")
1637
1656
  else
1638
1657
  erv_required = false
1639
- OpenStudio::logFree(OpenStudio::Info, "openstudio.standards.AirLoopHVAC", "For #{self.name}, ERV not required based on exhaust heat content.")
1658
+ OpenStudio::logFree(OpenStudio::Info, "openstudio.standards.AirLoopHVAC", "For #{self.name}, ERV not required based on exhaust heat content.")
1640
1659
  end
1641
-
1642
-
1643
-
1660
+
1661
+
1662
+
1644
1663
  end # of NECB 2011 condition
1645
-
1664
+
1646
1665
  # for debugging/testing
1647
- # puts "erv_required = #{erv_required}"
1648
-
1666
+ # puts "erv_required = #{erv_required}"
1667
+
1649
1668
  return erv_required
1650
-
1651
- end
1652
-
1669
+
1670
+ end
1671
+
1653
1672
  # Add an ERV to this airloop.
1654
1673
  # Will be a rotary-type HX
1655
1674
  #
1656
1675
  # @param (see #is_economizer_required)
1657
- # @return [Bool] Returns true if required, false if not.
1676
+ # @return [Bool] Returns true if required, false if not.
1658
1677
  # @todo Add exception logic for systems serving parking garage, warehouse, or multifamily
1659
1678
  def apply_energy_recovery_ventilator()
1660
1679
 
@@ -1666,7 +1685,7 @@ class OpenStudio::Model::AirLoopHVAC
1666
1685
  OpenStudio::logFree(OpenStudio::Info, "openstudio.standards.AirLoopHVAC", "For #{self.name}, ERV cannot be added because the system has no OA intake.")
1667
1686
  return false
1668
1687
  end
1669
-
1688
+
1670
1689
  # Create an ERV
1671
1690
  erv = OpenStudio::Model::HeatExchangerAirToAirSensibleAndLatent.new(self.model)
1672
1691
  erv.setName("#{self.name} ERV")
@@ -1678,16 +1697,16 @@ class OpenStudio::Model::AirLoopHVAC
1678
1697
  erv.setLatentEffectivenessat100CoolingAirFlow(0.6)
1679
1698
  erv.setSensibleEffectivenessat75CoolingAirFlow(0.75)
1680
1699
  erv.setLatentEffectivenessat75CoolingAirFlow(0.6)
1681
- erv.setSupplyAirOutletTemperatureControl(true)
1700
+ erv.setSupplyAirOutletTemperatureControl(true)
1682
1701
  erv.setHeatExchangerType('Rotary')
1683
1702
  erv.setFrostControlType('ExhaustOnly')
1684
1703
  erv.setEconomizerLockout(true)
1685
1704
  erv.setThresholdTemperature(-23.3) # -10F
1686
1705
  erv.setInitialDefrostTimeFraction(0.167)
1687
1706
  erv.setRateofDefrostTimeFractionIncrease(1.44)
1688
-
1707
+
1689
1708
  # Add the ERV to the OA system
1690
- erv.addToNode(oa_system.outboardOANode.get)
1709
+ erv.addToNode(oa_system.outboardOANode.get)
1691
1710
 
1692
1711
  # Add a setpoint manager OA pretreat
1693
1712
  # to control the ERV
@@ -1696,8 +1715,8 @@ class OpenStudio::Model::AirLoopHVAC
1696
1715
  spm_oa_pretreat.setMaximumSetpointTemperature(99.0)
1697
1716
  spm_oa_pretreat.setMinimumSetpointHumidityRatio(0.00001)
1698
1717
  spm_oa_pretreat.setMaximumSetpointHumidityRatio(1.0)
1699
- # Reference setpoint node and
1700
- # Mixed air stream node are outlet
1718
+ # Reference setpoint node and
1719
+ # Mixed air stream node are outlet
1701
1720
  # node of the OA system
1702
1721
  mixed_air_node = oa_system.mixedAirModelObject.get.to_Node.get
1703
1722
  spm_oa_pretreat.setReferenceSetpointNode(mixed_air_node)
@@ -1715,34 +1734,34 @@ class OpenStudio::Model::AirLoopHVAC
1715
1734
 
1716
1735
  # Apply the prototype Heat Exchanger power assumptions.
1717
1736
  erv.setPrototypeNominalElectricPower
1718
-
1737
+
1719
1738
  return true
1720
-
1721
- end
1722
-
1739
+
1740
+ end
1741
+
1723
1742
  # Determine if multizone vav optimization is required.
1724
1743
  #
1725
1744
  # @param (see #is_economizer_required)
1726
- # @return [Bool] Returns true if required, false if not.
1727
- # @todo Add exception logic for
1745
+ # @return [Bool] Returns true if required, false if not.
1746
+ # @todo Add exception logic for
1728
1747
  # systems with AIA healthcare ventilation requirements
1729
1748
  # dual duct systems
1730
1749
  def is_multizone_vav_optimization_required(template, climate_zone)
1731
1750
 
1732
1751
  multizone_opt_required = false
1733
-
1752
+
1734
1753
  case template
1735
1754
  when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004', '90.1-2004', '90.1-2007'
1736
-
1755
+
1737
1756
  # Not required before 90.1-2010
1738
1757
  return multizone_opt_required
1739
-
1758
+
1740
1759
  when '90.1-2010', '90.1-2013'
1741
-
1760
+
1742
1761
  # Not required for systems with fan-powered terminals
1743
1762
  num_fan_powered_terminals = 0
1744
1763
  self.demandComponents.each do |comp|
1745
- if comp.to_AirTerminalSingleDuctParallelPIUReheat.is_initialized || comp.to_AirTerminalSingleDuctSeriesPIUReheat.is_initialized
1764
+ if comp.to_AirTerminalSingleDuctParallelPIUReheat.is_initialized || comp.to_AirTerminalSingleDuctSeriesPIUReheat.is_initialized
1746
1765
  num_fan_powered_terminals += 1
1747
1766
  end
1748
1767
  end
@@ -1750,26 +1769,26 @@ class OpenStudio::Model::AirLoopHVAC
1750
1769
  OpenStudio::logFree(OpenStudio::Warn, "openstudio.standards.AirLoopHVAC", "For #{self.name}, multizone vav optimization is not required because the system has #{num_fan_powered_terminals} fan-powered terminals.")
1751
1770
  return multizone_opt_required
1752
1771
  end
1753
-
1772
+
1754
1773
  # Not required for systems that require an ERV
1755
1774
  if self.has_energy_recovery
1756
1775
  OpenStudio::logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "For #{self.name}: multizone vav optimization is not required because the system has Energy Recovery.")
1757
1776
  return multizone_opt_required
1758
1777
  end
1759
-
1778
+
1760
1779
  # Get the OA intake
1761
1780
  controller_oa = nil
1762
1781
  controller_mv = nil
1763
1782
  oa_system = nil
1764
1783
  if self.airLoopHVACOutdoorAirSystem.is_initialized
1765
1784
  oa_system = self.airLoopHVACOutdoorAirSystem.get
1766
- controller_oa = oa_system.getControllerOutdoorAir
1785
+ controller_oa = oa_system.getControllerOutdoorAir
1767
1786
  controller_mv = controller_oa.controllerMechanicalVentilation
1768
1787
  else
1769
1788
  OpenStudio::logFree(OpenStudio::Info, "openstudio.standards.AirLoopHVAC", "For #{self.name}, multizone optimization is not applicable because system has no OA intake.")
1770
1789
  return multizone_opt_required
1771
1790
  end
1772
-
1791
+
1773
1792
  # Get the AHU design supply air flow rate
1774
1793
  dsn_flow_m3_per_s = nil
1775
1794
  if self.designSupplyAirFlowRate.is_initialized
@@ -1781,7 +1800,7 @@ class OpenStudio::Model::AirLoopHVAC
1781
1800
  return multizone_opt_required
1782
1801
  end
1783
1802
  dsn_flow_cfm = OpenStudio.convert(dsn_flow_m3_per_s, 'm^3/s', 'cfm').get
1784
-
1803
+
1785
1804
  # Get the minimum OA flow rate
1786
1805
  min_oa_flow_m3_per_s = nil
1787
1806
  if controller_oa.minimumOutdoorAirFlowRate.is_initialized
@@ -1793,10 +1812,10 @@ class OpenStudio::Model::AirLoopHVAC
1793
1812
  return multizone_opt_required
1794
1813
  end
1795
1814
  min_oa_flow_cfm = OpenStudio.convert(min_oa_flow_m3_per_s, 'm^3/s', 'cfm').get
1796
-
1815
+
1797
1816
  # Calculate the percent OA at design airflow
1798
1817
  pct_oa = min_oa_flow_m3_per_s/dsn_flow_m3_per_s
1799
-
1818
+
1800
1819
  # Not required for systems where
1801
1820
  # exhaust is more than 70% of the total OA intake.
1802
1821
  if pct_oa > 0.7
@@ -1809,61 +1828,61 @@ class OpenStudio::Model::AirLoopHVAC
1809
1828
  # OpenStudio::logFree(OpenStudio::Warn, "openstudio.standards.AirLoopHVAC", "For #{controller_oa.name}: multizone optimization is not applicable because it is a dual duct system")
1810
1829
  # return multizone_opt_required
1811
1830
  # end
1812
-
1831
+
1813
1832
  # If here, multizone vav optimization is required
1814
1833
  multizone_opt_required = true
1815
-
1834
+
1816
1835
  return multizone_opt_required
1817
-
1836
+
1818
1837
  end
1819
-
1820
- end
1821
-
1838
+
1839
+ end
1840
+
1822
1841
  # Enable multizone vav optimization by changing the Outdoor Air Method
1823
1842
  # in the Controller:MechanicalVentilation object to 'VentilationRateProcedure'
1824
1843
  #
1825
- # @return [Bool] Returns true if required, false if not.
1844
+ # @return [Bool] Returns true if required, false if not.
1826
1845
  def enable_multizone_vav_optimization
1827
-
1846
+
1828
1847
  # Enable multizone vav optimization
1829
1848
  # at each timestep.
1830
1849
  if self.airLoopHVACOutdoorAirSystem.is_initialized
1831
1850
  oa_system = self.airLoopHVACOutdoorAirSystem.get
1832
- controller_oa = oa_system.getControllerOutdoorAir
1851
+ controller_oa = oa_system.getControllerOutdoorAir
1833
1852
  controller_mv = controller_oa.controllerMechanicalVentilation
1834
1853
  controller_mv.setSystemOutdoorAirMethod('VentilationRateProcedure')
1835
1854
  else
1836
1855
  OpenStudio::logFree(OpenStudio::Warn, "openstudio.standards.AirLoopHVAC", "For #{self.name}, cannot enable multizone vav optimization because the system has no OA intake.")
1837
1856
  return false
1838
1857
  end
1839
-
1840
- end
1841
-
1858
+
1859
+ end
1860
+
1842
1861
  # Disable multizone vav optimization by changing the Outdoor Air Method
1843
1862
  # in the Controller:MechanicalVentilation object to 'ZoneSum'
1844
1863
  #
1845
1864
  # @return [Bool] Returns true if required, false if not.
1846
1865
  def disable_multizone_vav_optimization
1847
-
1866
+
1848
1867
  # Disable multizone vav optimization
1849
1868
  # at each timestep.
1850
1869
  if self.airLoopHVACOutdoorAirSystem.is_initialized
1851
1870
  oa_system = self.airLoopHVACOutdoorAirSystem.get
1852
- controller_oa = oa_system.getControllerOutdoorAir
1871
+ controller_oa = oa_system.getControllerOutdoorAir
1853
1872
  controller_mv = controller_oa.controllerMechanicalVentilation
1854
1873
  controller_mv.setSystemOutdoorAirMethod('ZoneSum')
1855
1874
  else
1856
1875
  OpenStudio::logFree(OpenStudio::Warn, "openstudio.standards.AirLoopHVAC", "For #{self.name}, cannot disable multizone vav optimization because the system has no OA intake.")
1857
1876
  return false
1858
1877
  end
1859
-
1860
- end
1878
+
1879
+ end
1861
1880
 
1862
1881
  # Set the minimum VAV damper positions
1863
1882
  #
1864
- #
1883
+ #
1865
1884
  def set_minimum_vav_damper_positions(template)
1866
-
1885
+
1867
1886
  self.thermalZones.each do |zone|
1868
1887
  zone.equipment.each do |equip|
1869
1888
  if equip.to_AirTerminalSingleDuctVAVReheat.is_initialized
@@ -1873,39 +1892,41 @@ class OpenStudio::Model::AirLoopHVAC
1873
1892
  end
1874
1893
  end
1875
1894
  end
1876
-
1895
+
1877
1896
  return true
1878
-
1897
+
1879
1898
  end
1880
-
1899
+
1881
1900
  # Adjust minimum VAV damper positions to the values
1882
1901
  #
1883
1902
  # @param (see #is_economizer_required)
1884
- # @return [Bool] Returns true if required, false if not.
1903
+ # @return [Bool] Returns true if required, false if not.
1885
1904
  # @todo Add exception logic for systems serving parking garage, warehouse, or multifamily
1886
1905
  def adjust_minimum_vav_damper_positions
1887
-
1906
+
1888
1907
  # Total uncorrected outdoor airflow rate
1889
1908
  v_ou = 0.0
1890
1909
  self.thermalZones.each do |zone|
1891
1910
  v_ou += zone.outdoor_airflow_rate
1892
1911
  end
1912
+
1893
1913
  v_ou_cfm = OpenStudio.convert(v_ou, 'm^3/s', 'cfm').get
1894
-
1914
+
1895
1915
  # System primary airflow rate (whether autosized or hard-sized)
1896
1916
  v_ps = 0.0
1917
+
1897
1918
  if self.autosizedDesignSupplyAirFlowRate.is_initialized
1898
1919
  v_ps = self.autosizedDesignSupplyAirFlowRate.get
1899
1920
  else
1900
1921
  v_ps = self.designSupplyAirFlowRate.get
1901
1922
  end
1902
1923
  v_ps_cfm = OpenStudio.convert(v_ps, 'm^3/s', 'cfm').get
1903
-
1924
+
1904
1925
  # Average outdoor air fraction
1905
1926
  x_s = v_ou / v_ps
1906
-
1907
- OpenStudio::logFree(OpenStudio::Debug, 'openstudio.standards.AirLoopHVAC', "For #{self.name}: v_ou = #{v_ou_cfm.round} cfm, v_ps = #{v_ps_cfm.round} cfm, x_s = #{x_s.round(2)}.")
1908
-
1927
+
1928
+ OpenStudio::logFree(OpenStudio::Debug, 'openstudio.standards.AirLoopHVAC', "For #{self.name}: v_ou = #{v_ou_cfm.round} cfm, v_ps = #{v_ps_cfm.round} cfm, x_s = #{x_s.round(2)}.")
1929
+
1909
1930
  # Determine the zone ventilation effectiveness
1910
1931
  # for every zone on the system.
1911
1932
  # When ventilation effectiveness is too low,
@@ -1914,18 +1935,18 @@ class OpenStudio::Model::AirLoopHVAC
1914
1935
  e_vzs_adj = []
1915
1936
  num_zones_adj = 0
1916
1937
  self.thermalZones.sort.each do |zone|
1917
-
1938
+
1918
1939
  # Breathing zone airflow rate
1919
- v_bz = zone.outdoor_airflow_rate
1920
-
1940
+ v_bz = zone.outdoor_airflow_rate
1941
+
1921
1942
  # Zone air distribution, assumed 1 per PNNL
1922
- e_z = 1.0
1923
-
1943
+ e_z = 1.0
1944
+
1924
1945
  # Zone airflow rate
1925
- v_oz = v_bz / e_z
1926
-
1946
+ v_oz = v_bz / e_z
1947
+
1927
1948
  # Primary design airflow rate
1928
- # max of heating and cooling
1949
+ # max of heating and cooling
1929
1950
  # design air flow rates
1930
1951
  v_pz = 0.0
1931
1952
  clg_dsn_flow = zone.autosizedCoolingDesignAirFlowRate
@@ -1946,7 +1967,7 @@ class OpenStudio::Model::AirLoopHVAC
1946
1967
  else
1947
1968
  OpenStudio::logFree(OpenStudio::Warn, 'openstudio.standards.AirLoopHVAC', "For #{self.name}: #{zone.name} htg_dsn_flow could not be found.")
1948
1969
  end
1949
-
1970
+
1950
1971
  # Get the minimum damper position
1951
1972
  mdp = 1.0
1952
1973
  zone.equipment.each do |equip|
@@ -1966,46 +1987,46 @@ class OpenStudio::Model::AirLoopHVAC
1966
1987
  mdp = term.constantMinimumAirFlowFraction
1967
1988
  end
1968
1989
  end
1969
-
1990
+
1970
1991
  # Zone minimum discharge airflow rate
1971
1992
  v_dz = v_pz*mdp
1972
-
1993
+
1973
1994
  # Zone discharge air fraction
1974
1995
  z_d = v_oz / v_dz
1975
-
1996
+
1976
1997
  # Zone ventilation effectiveness
1977
1998
  e_vz = 1+x_s-z_d
1978
-
1999
+
1979
2000
  # Store the ventilation effectiveness
1980
2001
  e_vzs << e_vz
1981
-
2002
+
1982
2003
  OpenStudio::logFree(OpenStudio::Debug, 'openstudio.standards.AirLoopHVAC', "For #{self.name}: Zone #{zone.name} v_oz = #{v_oz.round(2)} m^3/s, v_pz = #{v_pz.round(2)} m^3/s, v_dz = #{v_dz.round(2)}, z_d = #{z_d.round(2)}.")
1983
-
2004
+
1984
2005
  # Check the ventilation effectiveness against
1985
2006
  # the minimum limit per PNNL and increase
1986
2007
  # as necessary.
1987
2008
  if e_vz < 0.6
1988
-
2009
+
1989
2010
  # Adjusted discharge air fraction
1990
2011
  z_d_adj = 1+x_s-0.6
1991
-
2012
+
1992
2013
  # Adjusted min discharge airflow rate
1993
2014
  v_dz_adj = v_oz / z_d_adj
1994
-
2015
+
1995
2016
  # Adjusted minimum damper position
1996
2017
  mdp_adj = v_dz_adj / v_pz
1997
-
2018
+
1998
2019
  # Don't allow values > 1
1999
2020
  if mdp_adj > 1.0
2000
2021
  mdp_adj = 1.0
2001
2022
  end
2002
-
2023
+
2003
2024
  # Zone ventilation effectiveness
2004
2025
  e_vz_adj = 1+x_s-z_d_adj
2005
-
2026
+
2006
2027
  # Store the ventilation effectiveness
2007
2028
  e_vzs_adj << e_vz_adj
2008
-
2029
+
2009
2030
  # Set the adjusted minimum damper position
2010
2031
  zone.equipment.each do |equip|
2011
2032
  if equip.to_AirTerminalSingleDuctVAVHeatAndCoolNoReheat.is_initialized
@@ -2022,46 +2043,46 @@ class OpenStudio::Model::AirLoopHVAC
2022
2043
  term.setConstantMinimumAirFlowFraction(mdp_adj)
2023
2044
  end
2024
2045
  end
2025
-
2046
+
2026
2047
  num_zones_adj += 1
2027
-
2048
+
2028
2049
  OpenStudio::logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "For #{self.name}: Zone #{zone.name} has a ventilation effectiveness of #{e_vz.round(2)}. Increasing to #{e_vz_adj.round(2)} by increasing minimum damper position from #{mdp.round(2)} to #{mdp_adj.round(2)}.")
2029
2050
 
2030
2051
  else
2031
2052
  # Store the unadjusted value
2032
2053
  e_vzs_adj << e_vz
2033
2054
  end
2034
-
2055
+
2035
2056
  end
2036
-
2057
+
2037
2058
  # Min system zone ventilation effectiveness
2038
2059
  e_v = e_vzs.min
2039
-
2040
- # Total system outdoor intake flow rate
2060
+
2061
+ # Total system outdoor intake flow rate
2041
2062
  v_ot = v_ou / e_v
2042
2063
  v_ot_cfm = OpenStudio.convert(v_ot, 'm^3/s', 'cfm').get
2043
-
2064
+
2044
2065
  # Min system zone ventilation effectiveness
2045
2066
  e_v_adj = e_vzs_adj.min
2046
-
2047
- # Total system outdoor intake flow rate
2067
+
2068
+ # Total system outdoor intake flow rate
2048
2069
  v_ot_adj = v_ou / e_v_adj
2049
2070
  v_ot_adj_cfm = OpenStudio.convert(v_ot_adj, 'm^3/s', 'cfm').get
2050
-
2071
+
2051
2072
  # Report out the results of the multizone calculations
2052
2073
  if num_zones_adj > 0
2053
2074
  OpenStudio::logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "For #{self.name}: the multizone outdoor air calculation method was applied. A simple summation of the zone outdoor air requirements gives a value of #{v_ou_cfm.round} cfm. Applying the multizone method gives a value of #{v_ot_cfm.round} cfm, with an original system ventilation effectiveness of #{e_v.round(2)}. After increasing the minimum damper position in #{num_zones_adj} critical zones, the resulting requirement is #{v_ot_adj_cfm.round} cfm with a system ventilation effectiveness of #{e_v_adj.round(2)}.")
2054
2075
  else
2055
2076
  OpenStudio::logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "For #{self.name}: the multizone outdoor air calculation method was applied. A simple summation of the zone requirements gives a value of #{v_ou_cfm.round} cfm. However, applying the multizone method requires #{v_ot_adj_cfm.round} cfm based on the ventilation effectiveness of the system.")
2056
2077
  end
2057
-
2078
+
2058
2079
  # Hard-size the sizing:system
2059
2080
  # object with the calculated min OA flow rate
2060
2081
  sizing_system = self.sizingSystem
2061
2082
  sizing_system.setDesignOutdoorAirFlowRate(v_ot_adj)
2062
-
2083
+
2063
2084
  return true
2064
-
2085
+
2065
2086
  end
2066
2087
 
2067
2088
  # For critical zones of Outpatient, if the minimum airflow rate required by the accreditation standard (AIA 2001) is significantly
@@ -2098,30 +2119,30 @@ class OpenStudio::Model::AirLoopHVAC
2098
2119
  end
2099
2120
  return true
2100
2121
  end
2101
-
2122
+
2102
2123
  # Determine if demand control ventilation (DCV) is
2103
2124
  # required for this air loop.
2104
2125
  #
2105
2126
  # @param (see #is_economizer_required)
2106
- # @return [Bool] Returns true if required, false if not.
2107
- # @todo Add exception logic for
2127
+ # @return [Bool] Returns true if required, false if not.
2128
+ # @todo Add exception logic for
2108
2129
  # systems that serve multifamily, parking garage, warehouse
2109
2130
  def is_demand_control_ventilation_required(template, climate_zone)
2110
-
2131
+
2111
2132
  dcv_required = false
2112
-
2133
+
2113
2134
  # Not required by the old vintages
2114
- if template == 'DOE Ref Pre-1980' || template == 'DOE Ref 1980-2004'
2115
- OpenStudio::logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "For #{self.name}: DCV is not required for any system.")
2135
+ if template == 'DOE Ref Pre-1980' || template == 'DOE Ref 1980-2004' || template == 'NECB 2011'
2136
+ OpenStudio::logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "For #{template} #{climate_zone}: #{self.name}: DCV is not required for any system.")
2116
2137
  return dcv_required
2117
2138
  end
2118
-
2139
+
2119
2140
  # Not required for systems that require an ERV
2120
2141
  if self.has_energy_recovery
2121
2142
  OpenStudio::logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "For #{self.name}: DCV is not required since the system has Energy Recovery.")
2122
2143
  return dcv_required
2123
2144
  end
2124
-
2145
+
2125
2146
  # Area, occupant density, and OA flow limits
2126
2147
  min_area_ft2 = 0
2127
2148
  min_occ_per_1000_ft2 = 0
@@ -2144,7 +2165,7 @@ class OpenStudio::Model::AirLoopHVAC
2144
2165
  min_oa_without_economizer_cfm = 3000
2145
2166
  min_oa_with_economizer_cfm = 750
2146
2167
  end
2147
-
2168
+
2148
2169
  # Get the area served and the number of occupants
2149
2170
  area_served_m2 = 0
2150
2171
  num_people = 0
@@ -2154,28 +2175,28 @@ class OpenStudio::Model::AirLoopHVAC
2154
2175
  num_people += space.numberOfPeople
2155
2176
  end
2156
2177
  end
2157
-
2178
+
2158
2179
  # Check the minimum area
2159
2180
  area_served_ft2 = OpenStudio.convert(area_served_m2, 'm^2', 'ft^2').get
2160
2181
  if area_served_ft2 < min_area_ft2
2161
2182
  OpenStudio::logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "For #{self.name}: DCV is not required since the system serves #{area_served_ft2.round} ft2, but the minimum size is #{min_area_ft2.round} ft2.")
2162
2183
  return dcv_required
2163
2184
  end
2164
-
2185
+
2165
2186
  # Check the minimum occupancy density
2166
2187
  occ_per_ft2 = num_people / area_served_ft2
2167
- occ_per_1000_ft2 = occ_per_ft2*1000
2168
-
2188
+ occ_per_1000_ft2 = occ_per_ft2*1000
2189
+
2169
2190
  if occ_per_1000_ft2 < min_occ_per_1000_ft2
2170
2191
  OpenStudio::logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "For #{self.name}: DCV is not required since the system occupant density is #{occ_per_1000_ft2.round} people/1000 ft2, but the minimum occupant density is #{min_occ_per_1000_ft2.round} people/1000 ft2.")
2171
2192
  return dcv_required
2172
2193
  end
2173
-
2174
- # Get the min OA flow rate
2194
+
2195
+ # Get the min OA flow rate
2175
2196
  oa_flow_m3_per_s = 0
2176
2197
  if self.airLoopHVACOutdoorAirSystem.is_initialized
2177
2198
  oa_system = self.airLoopHVACOutdoorAirSystem.get
2178
- controller_oa = oa_system.getControllerOutdoorAir
2199
+ controller_oa = oa_system.getControllerOutdoorAir
2179
2200
  if controller_oa.minimumOutdoorAirFlowRate.is_initialized
2180
2201
  oa_flow_m3_per_s = controller_oa.minimumOutdoorAirFlowRate.get
2181
2202
  elsif controller_oa.autosizedMinimumOutdoorAirFlowRate.is_initialized
@@ -2186,8 +2207,8 @@ class OpenStudio::Model::AirLoopHVAC
2186
2207
  return dcv_required
2187
2208
  end
2188
2209
  oa_flow_cfm = OpenStudio.convert(oa_flow_m3_per_s, 'm^3/s', 'cfm').get
2189
-
2190
-
2210
+
2211
+
2191
2212
  # Check for min OA without an economizer OR has economizer
2192
2213
  if oa_flow_cfm < min_oa_without_economizer_cfm && self.has_economizer == false
2193
2214
  # Message if doesn't pass OA limit
@@ -2206,25 +2227,25 @@ class OpenStudio::Model::AirLoopHVAC
2206
2227
  OpenStudio::logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "For #{self.name}: DCV is not required since the system has an economizer, but the min oa flow is #{oa_flow_cfm.round} cfm, less than the minimum of #{min_oa_with_economizer_cfm.round} cfm for systems with an economizer.")
2207
2228
  return dcv_required
2208
2229
  end
2209
-
2230
+
2210
2231
  # If here, DCV is required
2211
2232
  dcv_required = true
2212
-
2233
+
2213
2234
  return dcv_required
2214
-
2215
- end
2235
+
2236
+ end
2216
2237
 
2217
2238
  # Enable demand control ventilation (DCV) for this air loop.
2218
2239
  #
2219
2240
  # @return [Bool] Returns true if required, false if not.
2220
2241
  def enable_demand_control_ventilation()
2221
-
2242
+
2222
2243
  # Get the OA intake
2223
2244
  controller_oa = nil
2224
2245
  controller_mv = nil
2225
2246
  if self.airLoopHVACOutdoorAirSystem.is_initialized
2226
2247
  oa_system = self.airLoopHVACOutdoorAirSystem.get
2227
- controller_oa = oa_system.getControllerOutdoorAir
2248
+ controller_oa = oa_system.getControllerOutdoorAir
2228
2249
  controller_mv = controller_oa.controllerMechanicalVentilation
2229
2250
  if controller_mv.demandControlledVentilation == true
2230
2251
  OpenStudio::logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "For #{self.name}: DCV was already enabled.")
@@ -2234,29 +2255,29 @@ class OpenStudio::Model::AirLoopHVAC
2234
2255
  OpenStudio::logFree(OpenStudio::Warn, 'openstudio.standards.AirLoopHVAC', "For #{self.name}: Could not enable DCV since the system has no OA intake.")
2235
2256
  return false
2236
2257
  end
2237
-
2258
+
2238
2259
  # Change the min flow rate in the controller outdoor air
2239
2260
  controller_oa.setMinimumOutdoorAirFlowRate(0.0)
2240
-
2261
+
2241
2262
  # Enable DCV in the controller mechanical ventilation
2242
2263
  controller_mv.setDemandControlledVentilation(true)
2243
2264
 
2244
2265
  return true
2245
2266
 
2246
2267
  end
2247
-
2268
+
2248
2269
  # Determine if the system required supply air temperature
2249
2270
  # (SAT) reset.
2250
2271
  #
2251
2272
  # @param (see #is_economizer_required)
2252
- # @return [Bool] Returns true if required, false if not.
2273
+ # @return [Bool] Returns true if required, false if not.
2253
2274
  def is_supply_air_temperature_reset_required(template, climate_zone)
2254
-
2275
+
2255
2276
  is_sat_reset_required = false
2256
-
2277
+
2257
2278
  # Only required for multizone VAV systems
2258
2279
  return is_sat_reset_required unless self.is_multizone_vav_system
2259
-
2280
+
2260
2281
  # Not required until 90.1-2010
2261
2282
  case template
2262
2283
  when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004', '90.1-2004', '90.1-2007'
@@ -2284,11 +2305,11 @@ class OpenStudio::Model::AirLoopHVAC
2284
2305
  'ASHRAE 169-2006-8A',
2285
2306
  'ASHRAE 169-2006-8B'
2286
2307
  is_sat_reset_required = true
2287
- OpenStudio::logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "For #{self.name}: Supply air temperature reset is required.")
2308
+ OpenStudio::logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "For #{self.name}: Supply air temperature reset is required.")
2288
2309
  return is_sat_reset_required
2289
2310
  end
2290
2311
  end
2291
-
2312
+
2292
2313
  end
2293
2314
 
2294
2315
  # Enable supply air temperature (SAT) reset based
@@ -2341,14 +2362,14 @@ class OpenStudio::Model::AirLoopHVAC
2341
2362
  # increased by 5F when outdoor air is below 50F, and reset
2342
2363
  # linearly when outdoor air is between 50F and 70F.
2343
2364
  #
2344
- # @return [Bool] Returns true if successful, false if not.
2365
+ # @return [Bool] Returns true if successful, false if not.
2345
2366
 
2346
2367
  def enable_supply_air_temperature_reset_outdoor_temperature()
2347
-
2368
+
2348
2369
  # for AHU1 in Outpatient, SAT is 52F constant, no reset
2349
2370
  return true if self.name.get == 'PVAV Outpatient F1'
2350
-
2351
- # Get the current setpoint and calculate
2371
+
2372
+ # Get the current setpoint and calculate
2352
2373
  # the new setpoint.
2353
2374
  sizing_system = self.sizingSystem
2354
2375
  sat_at_hi_oat_c = sizing_system.centralCoolingDesignSupplyAirTemperature
@@ -2358,13 +2379,13 @@ class OpenStudio::Model::AirLoopHVAC
2358
2379
  increase_f = 5.0
2359
2380
  sat_at_lo_oat_f = sat_at_hi_oat_f+increase_f
2360
2381
  sat_at_lo_oat_c = OpenStudio.convert(sat_at_lo_oat_f, 'F', 'C').get
2361
-
2382
+
2362
2383
  # Define the high and low outdoor air temperatures
2363
2384
  lo_oat_f = 50
2364
2385
  lo_oat_c = OpenStudio.convert(lo_oat_f, 'F', 'C').get
2365
2386
  hi_oat_f = 70
2366
2387
  hi_oat_c = OpenStudio.convert(hi_oat_f, 'F', 'C').get
2367
-
2388
+
2368
2389
  # Create a setpoint manager
2369
2390
  sat_oa_reset = OpenStudio::Model::SetpointManagerOutdoorAirReset.new(model)
2370
2391
  sat_oa_reset.setName("#{self.name} SAT Reset")
@@ -2373,22 +2394,22 @@ class OpenStudio::Model::AirLoopHVAC
2373
2394
  sat_oa_reset.setOutdoorLowTemperature(lo_oat_c)
2374
2395
  sat_oa_reset.setSetpointatOutdoorHighTemperature(sat_at_hi_oat_c)
2375
2396
  sat_oa_reset.setOutdoorHighTemperature(hi_oat_c)
2376
-
2397
+
2377
2398
  # Attach the setpoint manager to the
2378
2399
  # supply outlet node of the system.
2379
2400
  sat_oa_reset.addToNode(self.supplyOutletNode)
2380
-
2401
+
2381
2402
  OpenStudio::logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "For #{self.name}: Supply air temperature reset was enabled. When OAT > #{hi_oat_f.round}F, SAT is #{sat_at_hi_oat_f.round}F. When OAT < #{lo_oat_f.round}F, SAT is #{sat_at_lo_oat_f.round}F. It varies linearly in between these points.")
2382
-
2403
+
2383
2404
  return true
2384
-
2405
+
2385
2406
  end
2386
-
2407
+
2387
2408
  # Determine if the system has an economizer
2388
2409
  #
2389
- # @return [Bool] Returns true if required, false if not.
2410
+ # @return [Bool] Returns true if required, false if not.
2390
2411
  def has_economizer()
2391
-
2412
+
2392
2413
  # Get the OA system and OA controller
2393
2414
  oa_sys = self.airLoopHVACOutdoorAirSystem
2394
2415
  if oa_sys.is_initialized
@@ -2398,28 +2419,28 @@ class OpenStudio::Model::AirLoopHVAC
2398
2419
  end
2399
2420
  oa_control = oa_sys.getControllerOutdoorAir
2400
2421
  economizer_type = oa_control.getEconomizerControlType
2401
-
2422
+
2402
2423
  # Return false if no economizer is present
2403
2424
  if economizer_type == 'NoEconomizer'
2404
2425
  return false
2405
2426
  else
2406
2427
  return true
2407
2428
  end
2408
-
2429
+
2409
2430
  end
2410
-
2431
+
2411
2432
  # Determine if the system is a multizone VAV system
2412
2433
  #
2413
- # @return [Bool] Returns true if required, false if not.
2434
+ # @return [Bool] Returns true if required, false if not.
2414
2435
  def is_multizone_vav_system()
2415
-
2436
+
2416
2437
  is_multizone_vav_system = false
2417
-
2438
+
2418
2439
  # Must serve more than 1 zone
2419
2440
  if self.thermalZones.size < 2
2420
2441
  return is_multizone_vav_system
2421
2442
  end
2422
-
2443
+
2423
2444
  # Must be a variable volume system
2424
2445
  has_vav_fan = false
2425
2446
  self.supplyComponents.each do |comp|
@@ -2430,36 +2451,36 @@ class OpenStudio::Model::AirLoopHVAC
2430
2451
  if has_vav_fan == false
2431
2452
  return is_multizone_vav_system
2432
2453
  end
2433
-
2454
+
2434
2455
  # If here, it's a multizone VAV system
2435
2456
  is_multizone_vav_system = true
2436
-
2457
+
2437
2458
  return is_multizone_vav_system
2438
2459
 
2439
2460
  end
2440
-
2461
+
2441
2462
  # Determine if the system has energy recovery already
2442
2463
  #
2443
- # @return [Bool] Returns true if an ERV is present, false if not.
2464
+ # @return [Bool] Returns true if an ERV is present, false if not.
2444
2465
  def has_energy_recovery()
2445
-
2466
+
2446
2467
  has_erv = false
2447
-
2468
+
2448
2469
  # Get the OA system
2449
2470
  oa_sys = self.airLoopHVACOutdoorAirSystem
2450
2471
  if oa_sys.is_initialized
2451
2472
  oa_sys = oa_sys.get
2452
2473
  else
2453
2474
  return has_erv # No OA system
2454
- end
2455
-
2475
+ end
2476
+
2456
2477
  # Find any ERV on the OA system
2457
2478
  oa_sys.oaComponents.each do |oa_comp|
2458
2479
  if oa_comp.to_HeatExchangerAirToAirSensibleAndLatent.is_initialized
2459
2480
  has_erv = true
2460
2481
  end
2461
2482
  end
2462
-
2483
+
2463
2484
  return has_erv
2464
2485
 
2465
2486
  end
@@ -2471,13 +2492,13 @@ class OpenStudio::Model::AirLoopHVAC
2471
2492
  # @todo see if this impacts the sizing run.
2472
2493
  def set_vav_damper_action(template)
2473
2494
  damper_action = nil
2474
- case template
2495
+ case template
2475
2496
  when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004', '90.1-2004', 'NECB 2011'
2476
2497
  damper_action = 'Single Maximum'
2477
2498
  when '90.1-2007', '90.1-2010', '90.1-2013'
2478
2499
  damper_action = 'Dual Maximum'
2479
2500
  end
2480
-
2501
+
2481
2502
  # Interpret this as an EnergyPlus input
2482
2503
  damper_action_eplus = nil
2483
2504
  if damper_action == 'Single Maximum'
@@ -2485,7 +2506,7 @@ class OpenStudio::Model::AirLoopHVAC
2485
2506
  elsif damper_action == 'Dual Maximum'
2486
2507
  damper_action_eplus = 'Reverse'
2487
2508
  end
2488
-
2509
+
2489
2510
  # Set the control for any VAV reheat terminals
2490
2511
  # on this airloop.
2491
2512
  self.demandComponents.each do |equip|
@@ -2493,17 +2514,17 @@ class OpenStudio::Model::AirLoopHVAC
2493
2514
  term = equip.to_AirTerminalSingleDuctVAVReheat.get
2494
2515
  term.setDamperHeatingAction(damper_action_eplus)
2495
2516
  end
2496
- end
2497
-
2517
+ end
2518
+
2498
2519
  OpenStudio::logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "For #{self.name}: VAV damper action was set to #{damper_action} control.")
2499
-
2520
+
2500
2521
  return true
2501
-
2522
+
2502
2523
  end
2503
2524
 
2504
2525
  # Determine if a motorized OA damper is required
2505
2526
  def is_motorized_oa_damper_required(template, climate_zone)
2506
-
2527
+
2507
2528
  motorized_oa_damper_required = false
2508
2529
 
2509
2530
  if self.name.to_s.include? "Outpatient F1"
@@ -2511,7 +2532,7 @@ class OpenStudio::Model::AirLoopHVAC
2511
2532
  OpenStudio::logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "For #{self.name}: always has a damper, the minimum OA schedule is the same as airloop availability schedule.")
2512
2533
  return motorized_oa_damper_required
2513
2534
  end
2514
-
2535
+
2515
2536
  # If the system has an economizer, it must have
2516
2537
  # a motorized damper.
2517
2538
  if self.has_economizer
@@ -2521,11 +2542,11 @@ class OpenStudio::Model::AirLoopHVAC
2521
2542
  end
2522
2543
 
2523
2544
  # Determine the exceptions based on
2524
- # number of stories, climate zone, and
2545
+ # number of stories, climate zone, and
2525
2546
  # outdoor air intake rates.
2526
2547
  minimum_oa_flow_cfm = 0
2527
2548
  maximum_stories = 0
2528
- case template
2549
+ case template
2529
2550
  when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004'
2530
2551
  # Assuming that older buildings always
2531
2552
  # used backdraft gravity dampers
@@ -2561,22 +2582,22 @@ class OpenStudio::Model::AirLoopHVAC
2561
2582
  maximum_stories = 0
2562
2583
  end
2563
2584
  end
2564
-
2585
+
2565
2586
  # Get the number of stories
2566
2587
  num_stories = self.model.getBuildingStorys.size
2567
-
2588
+
2568
2589
  # Check the number of stories exception,
2569
2590
  # which is climate-zone dependent.
2570
2591
  if num_stories < maximum_stories
2571
2592
  OpenStudio::logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "For #{self.name}: Motorized OA damper not required because the building has #{num_stories} stories, less than the maximum of #{maximum_stories} stories for climate zone #{climate_zone}.")
2572
2593
  return motorized_oa_damper_required
2573
- end
2574
-
2575
- # Get the min OA flow rate
2594
+ end
2595
+
2596
+ # Get the min OA flow rate
2576
2597
  oa_flow_m3_per_s = 0
2577
2598
  if self.airLoopHVACOutdoorAirSystem.is_initialized
2578
2599
  oa_system = self.airLoopHVACOutdoorAirSystem.get
2579
- controller_oa = oa_system.getControllerOutdoorAir
2600
+ controller_oa = oa_system.getControllerOutdoorAir
2580
2601
  if controller_oa.minimumOutdoorAirFlowRate.is_initialized
2581
2602
  oa_flow_m3_per_s = controller_oa.minimumOutdoorAirFlowRate.get
2582
2603
  elsif controller_oa.autosizedMinimumOutdoorAirFlowRate.is_initialized
@@ -2586,8 +2607,8 @@ class OpenStudio::Model::AirLoopHVAC
2586
2607
  OpenStudio::logFree(OpenStudio::Info, "openstudio.standards.AirLoopHVAC", "For #{self.name}, Motorized OA damper not applicable because it has no OA intake.")
2587
2608
  return motorized_oa_damper_required
2588
2609
  end
2589
- oa_flow_cfm = OpenStudio.convert(oa_flow_m3_per_s, 'm^3/s', 'cfm').get
2590
-
2610
+ oa_flow_cfm = OpenStudio.convert(oa_flow_m3_per_s, 'm^3/s', 'cfm').get
2611
+
2591
2612
  # Check the OA flow rate exception
2592
2613
  if oa_flow_cfm < minimum_oa_flow_cfm
2593
2614
  OpenStudio::logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "For #{self.name}: Motorized OA damper not required because the system OA intake of #{oa_flow_cfm.round} cfm is less than the minimum threshold of #{minimum_oa_flow_cfm} cfm.")
@@ -2596,11 +2617,11 @@ class OpenStudio::Model::AirLoopHVAC
2596
2617
 
2597
2618
  # If here, motorized damper is required
2598
2619
  motorized_oa_damper_required = true
2599
-
2620
+
2600
2621
  return motorized_oa_damper_required
2601
2622
 
2602
2623
  end
2603
-
2624
+
2604
2625
  # Add a motorized damper by modifying the OA schedule
2605
2626
  # to require zero OA during unoccupied hours. This means
2606
2627
  # that even during morning warmup or nightcyling, no OA will
@@ -2608,15 +2629,15 @@ class OpenStudio::Model::AirLoopHVAC
2608
2629
  # If no occupancy schedule is supplied, one will be created.
2609
2630
  # In this case, occupied is defined as the total percent
2610
2631
  # occupancy for the loop for all zones served.
2611
- #
2632
+ #
2612
2633
  # @param min_occ_pct [Double] the fractional value below which
2613
2634
  # the system will be considered unoccupied.
2614
2635
  # @param occ_sch [OpenStudio::Model::Schedule] the occupancy schedule.
2615
2636
  # If not supplied, one will be created based on the supplied
2616
2637
  # occupancy threshold.
2617
- # @return [Bool] true if successful, false if not
2638
+ # @return [Bool] true if successful, false if not
2618
2639
  def add_motorized_oa_damper(min_occ_pct = 0.15, occ_sch = nil)
2619
-
2640
+
2620
2641
  # Get the airloop occupancy schedule if none supplied
2621
2642
  if occ_sch.nil?
2622
2643
  occ_sch = self.get_occupancy_schedule(min_occ_pct)
@@ -2625,7 +2646,7 @@ class OpenStudio::Model::AirLoopHVAC
2625
2646
  else
2626
2647
  OpenStudio::logFree(OpenStudio::Info, "openstudio.standards.AirLoopHVAC", "For #{self.name}: Setting motorized OA damper schedule to #{occ_sch.name}.")
2627
2648
  end
2628
-
2649
+
2629
2650
  # Get the OA system and OA controller
2630
2651
  oa_sys = self.airLoopHVACOutdoorAirSystem
2631
2652
  if oa_sys.is_initialized
@@ -2634,21 +2655,21 @@ class OpenStudio::Model::AirLoopHVAC
2634
2655
  return false # No OA system
2635
2656
  end
2636
2657
  oa_control = oa_sys.getControllerOutdoorAir
2637
-
2658
+
2638
2659
  # Set the minimum OA schedule to follow occupancy
2639
- oa_control.setMinimumOutdoorAirSchedule(occ_sch)
2640
-
2660
+ oa_control.setMinimumOutdoorAirSchedule(occ_sch)
2661
+
2641
2662
  return true
2642
-
2643
- end
2644
-
2663
+
2664
+ end
2665
+
2645
2666
  # Remove a motorized OA damper by modifying the OA schedule
2646
2667
  # to require full OA at all times. Whenever the fan operates,
2647
2668
  # the damper will be open and OA will be brought into the building.
2648
2669
  # This reflects the use of a backdraft gravity damper, and
2649
2670
  # increases building loads unnecessarily during unoccupied hours.
2650
2671
  def remove_motorized_oa_damper
2651
-
2672
+
2652
2673
  # Get the OA system and OA controller
2653
2674
  oa_sys = self.airLoopHVACOutdoorAirSystem
2654
2675
  if oa_sys.is_initialized
@@ -2657,13 +2678,13 @@ class OpenStudio::Model::AirLoopHVAC
2657
2678
  return false # No OA system
2658
2679
  end
2659
2680
  oa_control = oa_sys.getControllerOutdoorAir
2660
-
2681
+
2661
2682
  # Set the minimum OA schedule to always 1 (100%)
2662
2683
  oa_control.setMinimumOutdoorAirSchedule(self.model.alwaysOnDiscreteSchedule)
2663
2684
 
2664
2685
  return true
2665
-
2666
- end
2686
+
2687
+ end
2667
2688
 
2668
2689
  # This method creates a schedule where the value is zero when
2669
2690
  # the overall occupancy for all zones on the airloop is below
@@ -2671,7 +2692,7 @@ class OpenStudio::Model::AirLoopHVAC
2671
2692
  # greater than or equal to the threshold. This method is designed
2672
2693
  # to use the total number of people on the airloop, so if there is
2673
2694
  # a zone that is continuously occupied by a few people, but other
2674
- # zones that are intermittently occupied by many people, the
2695
+ # zones that are intermittently occupied by many people, the
2675
2696
  # first zone doesn't drive the entire system.
2676
2697
  #
2677
2698
  # @param occupied_percentage_threshold [Double] the minimum fraction (0 to 1) that counts as occupied
@@ -2699,7 +2720,7 @@ class OpenStudio::Model::AirLoopHVAC
2699
2720
  num_ppl = people.getNumberOfPeople(space.floorArea)
2700
2721
  if occ_schedules_num_occ[num_ppl_sch].nil?
2701
2722
  occ_schedules_num_occ[num_ppl_sch] = num_ppl
2702
- max_occ_on_airloop += num_ppl
2723
+ max_occ_on_airloop += num_ppl
2703
2724
  else
2704
2725
  occ_schedules_num_occ[num_ppl_sch] += num_ppl
2705
2726
  max_occ_on_airloop += num_ppl
@@ -2718,7 +2739,7 @@ class OpenStudio::Model::AirLoopHVAC
2718
2739
  num_ppl = people.getNumberOfPeople(space.floorArea)
2719
2740
  if occ_schedules_num_occ[num_ppl_sch].nil?
2720
2741
  occ_schedules_num_occ[num_ppl_sch] = num_ppl
2721
- max_occ_on_airloop += num_ppl
2742
+ max_occ_on_airloop += num_ppl
2722
2743
  else
2723
2744
  occ_schedules_num_occ[num_ppl_sch] += num_ppl
2724
2745
  max_occ_on_airloop += num_ppl
@@ -2727,13 +2748,13 @@ class OpenStudio::Model::AirLoopHVAC
2727
2748
  end
2728
2749
  end
2729
2750
  end
2730
-
2751
+
2731
2752
  OpenStudio::logFree(OpenStudio::Debug, "openstudio.standards.AirLoopHVAC", "#{self.name} has #{occ_schedules_num_occ.size} unique occ schedules.")
2732
2753
  occ_schedules_num_occ.each do |occ_sch, num_occ|
2733
2754
  OpenStudio::logFree(OpenStudio::Debug, "openstudio.standards.AirLoopHVAC", " #{occ_sch.name} - #{num_occ.round} people")
2734
2755
  end
2735
2756
  OpenStudio::logFree(OpenStudio::Debug, "openstudio.standards.AirLoopHVAC", " Total #{max_occ_on_airloop.round} people on #{self.name}")
2736
-
2757
+
2737
2758
  # For each day of the year, determine
2738
2759
  #time_value_pairs = []
2739
2760
  year = self.model.getYearDescription
@@ -2745,12 +2766,12 @@ class OpenStudio::Model::AirLoopHVAC
2745
2766
  times_on_this_day = []
2746
2767
  os_date = year.makeDate(i)
2747
2768
  day_of_week = os_date.dayOfWeek.valueName
2748
-
2769
+
2749
2770
  # Get the unique time indices and corresponding day schedules
2750
2771
  occ_schedules_day_schs = {}
2751
2772
  day_sch_num_occ = {}
2752
2773
  occ_schedules_num_occ.each do |occ_sch, num_occ|
2753
-
2774
+
2754
2775
  # Get the day schedules for this day
2755
2776
  # (there should only be one)
2756
2777
  day_schs = occ_sch.getDaySchedules(os_date, os_date)
@@ -2759,7 +2780,7 @@ class OpenStudio::Model::AirLoopHVAC
2759
2780
  times_on_this_day << time.toString
2760
2781
  end
2761
2782
  day_sch_num_occ[day_schs[0]] = num_occ
2762
-
2783
+
2763
2784
  end
2764
2785
 
2765
2786
  # Determine the total fraction for the airloop at each time
@@ -2777,7 +2798,7 @@ class OpenStudio::Model::AirLoopHVAC
2777
2798
  occ_frac = day_sch.getValue(os_time)
2778
2799
  tot_occ_at_time += occ_frac * num_occ
2779
2800
  end
2780
-
2801
+
2781
2802
  # Total fraction for the airloop at each time
2782
2803
  air_loop_occ_frac = tot_occ_at_time / max_occ_on_airloop
2783
2804
  occ_status = 0 # unoccupied
@@ -2794,35 +2815,35 @@ class OpenStudio::Model::AirLoopHVAC
2794
2815
  end
2795
2816
 
2796
2817
  # OpenStudio::logFree(OpenStudio::Debug, "openstudio.standards.AirLoopHVAC", "#{daily_times.join(', ')} #{daily_values.join(', ')}")
2797
-
2818
+
2798
2819
  # Simplify the daily times to eliminate intermediate
2799
2820
  # points with the same value as the following point.
2800
2821
  simple_daily_times = []
2801
2822
  simple_daily_os_times = []
2802
2823
  simple_daily_values = []
2803
2824
  simple_daily_occs = []
2804
- daily_values.each_with_index do |value, i|
2825
+ daily_values.each_with_index do |value, i|
2805
2826
  next if value == daily_values[i+1]
2806
2827
  simple_daily_times << daily_times[i]
2807
2828
  simple_daily_os_times << daily_os_times[i]
2808
2829
  simple_daily_values << daily_values[i]
2809
2830
  simple_daily_occs << daily_occs[i]
2810
2831
  end
2811
-
2832
+
2812
2833
  # OpenStudio::logFree(OpenStudio::Debug, "openstudio.standards.AirLoopHVAC", "#{simple_daily_times.join(', ')} {simple_daily_values.join(', ')}")
2813
-
2834
+
2814
2835
  # Store the daily values
2815
2836
  yearly_data << {'date'=>os_date,'day_of_week'=>day_of_week,'times'=>simple_daily_times,'values'=>simple_daily_values,'daily_os_times'=>simple_daily_os_times, 'daily_occs'=>simple_daily_occs}
2816
2837
 
2817
2838
  end
2818
-
2839
+
2819
2840
  # Create a TimeSeries from the data
2820
2841
  #time_series = OpenStudio::TimeSeries.new(times, values, 'unitless')
2821
2842
 
2822
2843
  # Make a schedule ruleset
2823
2844
  sch_name = "#{self.name} Occ Sch"
2824
2845
  sch_ruleset = OpenStudio::Model::ScheduleRuleset.new(self.model)
2825
- sch_ruleset.setName("#{sch_name}")
2846
+ sch_ruleset.setName("#{sch_name}")
2826
2847
 
2827
2848
  # Default - All Occupied
2828
2849
  day_sch = sch_ruleset.defaultDaySchedule
@@ -2834,7 +2855,7 @@ class OpenStudio::Model::AirLoopHVAC
2834
2855
  sch_ruleset.setWinterDesignDaySchedule(day_sch)
2835
2856
  day_sch = sch_ruleset.winterDesignDaySchedule
2836
2857
  day_sch.setName("#{sch_name} Winter Design Day")
2837
- day_sch.addValue(OpenStudio::Time.new(0, 24, 0, 0), 1)
2858
+ day_sch.addValue(OpenStudio::Time.new(0, 24, 0, 0), 1)
2838
2859
 
2839
2860
  # Summer Design Day - All Occupied
2840
2861
  day_sch = OpenStudio::Model::ScheduleDay.new(self.model)
@@ -2842,7 +2863,7 @@ class OpenStudio::Model::AirLoopHVAC
2842
2863
  day_sch = sch_ruleset.summerDesignDaySchedule
2843
2864
  day_sch.setName("#{sch_name} Summer Design Day")
2844
2865
  day_sch.addValue(OpenStudio::Time.new(0, 24, 0, 0), 1)
2845
-
2866
+
2846
2867
  # Create ruleset schedules, attempting to create
2847
2868
  # the minimum number of unique rules.
2848
2869
  ['Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday'].each do |day_of_week|
@@ -2857,7 +2878,7 @@ class OpenStudio::Model::AirLoopHVAC
2857
2878
  times = daily_data['times']
2858
2879
  values = daily_data['values']
2859
2880
  daily_occs = daily_data['daily_occs']
2860
-
2881
+
2861
2882
  # If the next (Monday, Tuesday, etc.)
2862
2883
  # is the same as today, keep going.
2863
2884
  # If the next is different, or if
@@ -2868,10 +2889,10 @@ class OpenStudio::Model::AirLoopHVAC
2868
2889
  next_day_values = yearly_data[i+7]['values']
2869
2890
  next if times == next_day_times && values == next_day_values
2870
2891
  end
2871
-
2892
+
2872
2893
  daily_os_times = daily_data['daily_os_times']
2873
2894
  daily_occs = daily_data['daily_occs']
2874
-
2895
+
2875
2896
  # If here, we need to make a rule to cover from the previous
2876
2897
  # rule to today
2877
2898
  OpenStudio::logFree(OpenStudio::Debug, "openstudio.standards.AirLoopHVAC", "Making a new rule for #{day_of_week} from #{end_of_prev_rule.to_s} to #{date}")
@@ -2885,7 +2906,7 @@ class OpenStudio::Model::AirLoopHVAC
2885
2906
  day_sch.addValue(time, value)
2886
2907
  OpenStudio::logFree(OpenStudio::Debug, "openstudio.standards.AirLoopHVAC", " Adding value #{time}, #{value}")
2887
2908
  end
2888
-
2909
+
2889
2910
  # Set the dates when the rule applies
2890
2911
  sch_rule.setStartDate(end_of_prev_rule)
2891
2912
  sch_rule.setEndDate(date)
@@ -2898,28 +2919,28 @@ class OpenStudio::Model::AirLoopHVAC
2898
2919
  sch_rule.setApplyFriday(true) if day_of_week == 'Friday'
2899
2920
  sch_rule.setApplySaturday(true) if day_of_week == 'Saturday'
2900
2921
  sch_rule.setApplySunday(true) if day_of_week == 'Sunday'
2901
-
2922
+
2902
2923
  # Reset the previous rule end date
2903
2924
  end_of_prev_rule = date + OpenStudio::Time.new(0, 24, 0, 0)
2904
-
2925
+
2905
2926
  end
2906
-
2927
+
2907
2928
  end
2908
2929
 
2909
2930
  return sch_ruleset
2910
-
2911
- end
2912
-
2931
+
2932
+ end
2933
+
2913
2934
  # Generate the EMS used to implement the economizer
2914
2935
  # and staging controls for packaged single zone units.
2915
2936
  # @note The resulting EMS doesn't actually get added to
2916
2937
  # the IDF yet.
2917
2938
  #
2918
2939
  def apply_single_zone_controls(template, climate_zone)
2919
-
2940
+
2920
2941
  # Number of stages is determined by the template
2921
2942
  num_stages = nil
2922
- case template
2943
+ case template
2923
2944
  when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004', 'NECB 2011'
2924
2945
  OpenStudio::logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "For #{self.name}: No special economizer controls were modeled.")
2925
2946
  return true
@@ -2928,19 +2949,19 @@ class OpenStudio::Model::AirLoopHVAC
2928
2949
  when '90.1-2010', '90.1-2013'
2929
2950
  num_stages = 2
2930
2951
  end
2931
-
2952
+
2932
2953
  # Scrub special characters from the system name
2933
2954
  sn = self.name.get.to_s
2934
2955
  snc = sn.gsub(/\W/,'').gsub('_','')
2935
-
2956
+
2936
2957
  # Get the zone name
2937
2958
  zone = self.thermalZones[0]
2938
2959
  zone_name = zone.name.get.to_s
2939
2960
  zn_name_clean = zone_name.gsub(/\W/,'_')
2940
-
2961
+
2941
2962
  # Zone air node
2942
- zone_air_node_name = zone.zoneAirNode.name.get
2943
-
2963
+ zone_air_node_name = zone.zoneAirNode.name.get
2964
+
2944
2965
  # Get the OA system and OA controller
2945
2966
  oa_sys = self.airLoopHVACOutdoorAirSystem
2946
2967
  if oa_sys.is_initialized
@@ -2951,7 +2972,7 @@ class OpenStudio::Model::AirLoopHVAC
2951
2972
  oa_control = oa_sys.getControllerOutdoorAir
2952
2973
  oa_control_name = oa_control.name.get
2953
2974
  oa_node_name = oa_sys.outboardOANode.get.name.get
2954
-
2975
+
2955
2976
  # Get the name of the min oa schedule
2956
2977
  min_oa_sch_name = nil
2957
2978
  if oa_control.minimumOutdoorAirSchedule.is_initialized
@@ -2959,7 +2980,7 @@ class OpenStudio::Model::AirLoopHVAC
2959
2980
  else
2960
2981
  min_oa_sch_name = self.model.alwaysOnDiscreteSchedule.name.get
2961
2982
  end
2962
-
2983
+
2963
2984
  # Get the supply fan
2964
2985
  if self.supplyFan.empty?
2965
2986
  OpenStudio::logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "For #{self.name}: No supply fan found, cannot apply DX fan/economizer control.")
@@ -2967,11 +2988,11 @@ class OpenStudio::Model::AirLoopHVAC
2967
2988
  end
2968
2989
  fan = self.supplyFan.get
2969
2990
  fan_name = fan.name.get
2970
-
2991
+
2971
2992
  # Supply outlet node
2972
2993
  sup_out_node = self.supplyOutletNode
2973
2994
  sup_out_node_name = sup_out_node.name.get
2974
-
2995
+
2975
2996
  # DX Cooling Coil
2976
2997
  dx_coil = nil
2977
2998
  self.supplyComponents.each do |equip|
@@ -2987,7 +3008,7 @@ class OpenStudio::Model::AirLoopHVAC
2987
3008
  end
2988
3009
  dx_coil_name = dx_coil.name.get
2989
3010
  dx_coilsys_name = "#{dx_coil_name} CoilSystem"
2990
-
3011
+
2991
3012
  # Heating Coil
2992
3013
  htg_coil = nil
2993
3014
  self.supplyComponents.each do |equip|
@@ -3004,7 +3025,7 @@ class OpenStudio::Model::AirLoopHVAC
3004
3025
  return false
3005
3026
  end
3006
3027
  htg_coil_name = htg_coil.name.get
3007
-
3028
+
3008
3029
  # Create an economizer maximum OA fraction schedule with
3009
3030
  # a maximum of 70% to reflect damper leakage per PNNL
3010
3031
  max_oa_sch_name = "#{snc}maxOASch"
@@ -3013,14 +3034,14 @@ class OpenStudio::Model::AirLoopHVAC
3013
3034
  max_oa_sch.defaultDaySchedule.setName("#{max_oa_sch_name}Default")
3014
3035
  max_oa_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0,24,0,0), 0.7)
3015
3036
  oa_control.setMaximumFractionofOutdoorAirSchedule(max_oa_sch)
3016
-
3037
+
3017
3038
  ems = "
3018
-
3039
+
3019
3040
  ! Sensors
3020
-
3041
+
3021
3042
  EnergyManagementSystem:Sensor,
3022
- #{snc}OASch,
3023
- #{min_oa_sch_name}, !- Output:Variable or Output:Meter Index Key Name,
3043
+ #{snc}OASch,
3044
+ #{min_oa_sch_name}, !- Output:Variable or Output:Meter Index Key Name,
3024
3045
  Schedule Value; !- Output:Variable or Output:Meter Name
3025
3046
 
3026
3047
  EnergyManagementSystem:Sensor,
@@ -3029,32 +3050,32 @@ class OpenStudio::Model::AirLoopHVAC
3029
3050
  System Node Temperature; !- Output:Variable or Output:Meter Name
3030
3051
 
3031
3052
  EnergyManagementSystem:Sensor,
3032
- #{snc}OAFlowMass,
3053
+ #{snc}OAFlowMass,
3033
3054
  #{oa_node_name}, !- Output:Variable or Output:Meter Index Key Name
3034
3055
  System Node Mass Flow Rate; !- Output:Variable or Output:Meter Name
3035
3056
 
3036
3057
  EnergyManagementSystem:Sensor,
3037
- #{snc}HeatingRTF,
3058
+ #{snc}HeatingRTF,
3038
3059
  #{htg_coil_name}, !- Output:Variable or Output:Meter Index Key Name
3039
3060
  Heating Coil Runtime Fraction; !- Output:Variable or Output:Meter Name
3040
3061
 
3041
3062
  EnergyManagementSystem:Sensor,
3042
- #{snc}RTF,
3063
+ #{snc}RTF,
3043
3064
  #{dx_coil_name}, !- Output:Variable or Output:Meter Index Key Name
3044
3065
  Cooling Coil Runtime Fraction; !- Output:Variable or Output:Meter Name
3045
3066
 
3046
3067
  EnergyManagementSystem:Sensor,
3047
- #{snc}SpeedRatio,
3068
+ #{snc}SpeedRatio,
3048
3069
  #{dx_coilsys_name}, !- Output:Variable or Output:Meter Index Key Name
3049
3070
  Coil System Compressor Speed Ratio; !- Output:Variable or Output:Meter Name
3050
3071
 
3051
3072
  EnergyManagementSystem:Sensor,
3052
- #{snc}DATRqd,
3073
+ #{snc}DATRqd,
3053
3074
  #{sup_out_node_name}, !- Output:Variable or Output:Meter Index Key Name
3054
3075
  System Node Setpoint Temperature; !- Output:Variable or Output:Meter Name
3055
3076
 
3056
3077
  EnergyManagementSystem:Sensor,
3057
- #{snc}EconoStatus,
3078
+ #{snc}EconoStatus,
3058
3079
  #{sn}, !- Output:Variable or Output:Meter Index Key Name
3059
3080
  Air System Outdoor Air Economizer Status; !- Output:Variable or Output:Meter Name
3060
3081
 
@@ -3066,19 +3087,19 @@ class OpenStudio::Model::AirLoopHVAC
3066
3087
  Fan Nominal Pressure Rise; !- Internal Data Type
3067
3088
 
3068
3089
  EnergyManagementSystem:InternalVariable,
3069
- #{snc}DesignFlowMass,
3090
+ #{snc}DesignFlowMass,
3070
3091
  #{oa_control_name},!- Internal Data Index Key Name
3071
3092
  Outdoor Air Controller Maximum Mass Flow Rate; !- Internal Data Type
3072
3093
 
3073
3094
  EnergyManagementSystem:InternalVariable,
3074
- #{snc}OADesignMass,
3095
+ #{snc}OADesignMass,
3075
3096
  #{oa_control_name},!- Internal Data Index Key Name
3076
3097
  Outdoor Air Controller Minimum Mass Flow Rate; !- Internal Data Type
3077
3098
 
3078
3099
  ! Actuators
3079
3100
 
3080
3101
  EnergyManagementSystem:Actuator,
3081
- #{snc}FanPressure,
3102
+ #{snc}FanPressure,
3082
3103
  #{fan_name}, !- Actuated Component Unique Name
3083
3104
  Fan, !- Actuated Component Type
3084
3105
  Fan Pressure Rise; !- Actuated Component Control Type
@@ -3093,36 +3114,36 @@ class OpenStudio::Model::AirLoopHVAC
3093
3114
  #{snc}FanPwrExp, !- Erl Variable 1 Name
3094
3115
  #{snc}Stg1Spd, !- Erl Variable 2 Name
3095
3116
  #{snc}Stg2Spd, !- Erl Variable 3 Name
3096
- #{snc}HeatSpeed,
3097
- #{snc}VenSpeed,
3098
- #{snc}NumberofStages;
3117
+ #{snc}HeatSpeed,
3118
+ #{snc}VenSpeed,
3119
+ #{snc}NumberofStages;
3099
3120
 
3100
3121
  EnergyManagementSystem:Program,
3101
3122
  #{snc}EconomizerCTRLProg,
3102
- SET #{snc}TimestepEconEff = 0.7,
3103
- SET #{snc}MaxE = 0.7,
3123
+ SET #{snc}TimestepEconEff = 0.7,
3124
+ SET #{snc}MaxE = 0.7,
3104
3125
  SET #{snc}DATRqd = (#{snc}DATRqd*1.8)+32,
3105
3126
  SET OATF = (OATF*1.8)+32,
3106
3127
  SET OAwbF = (OAwbF*1.8)+32,
3107
3128
  IF #{snc}OAFlowMass > (#{snc}OADesignMass*#{snc}OASch),
3108
3129
  SET #{snc}EconoActive = 1,
3109
- ELSE,
3130
+ ELSE,
3110
3131
  SET #{snc}EconoActive = 0,
3111
- ENDIF,
3132
+ ENDIF,
3112
3133
  SET #{snc}dTNeeded = 75-#{snc}DATRqd,
3113
3134
  SET #{snc}CoolDesdT = ((98*0.15)+(75*(1-0.15)))-55,
3114
3135
  SET #{snc}CoolLoad = #{snc}dTNeeded/ #{snc}CoolDesdT,
3115
- IF #{snc}CoolLoad > 1,
3136
+ IF #{snc}CoolLoad > 1,
3116
3137
  SET #{snc}CoolLoad = 1,
3117
3138
  ELSEIF #{snc}CoolLoad < 0,
3118
3139
  SET #{snc}CoolLoad = 0,
3119
- ENDIF,
3140
+ ENDIF,
3120
3141
  IF #{snc}EconoActive == 1,
3121
3142
  SET #{snc}Stage = #{snc}NumberofStages,
3122
- IF #{snc}Stage == 2,
3143
+ IF #{snc}Stage == 2,
3123
3144
  IF #{snc}CoolLoad < 0.6,
3124
3145
  SET #{snc}TimestepEconEff = #{snc}MaxE,
3125
- ELSE,
3146
+ ELSE,
3126
3147
  SET #{snc}ECOEff = 0-2.18919863612305,
3127
3148
  SET #{snc}ECOEff = #{snc}ECOEff+(0-0.674461284910428*#{snc}CoolLoad),
3128
3149
  SET #{snc}ECOEff = #{snc}ECOEff+(0.000459106275872404*(OATF^2)),
@@ -3131,88 +3152,88 @@ class OpenStudio::Model::AirLoopHVAC
3131
3152
  SET #{snc}ECOEff = #{snc}ECOEff+(0-0.00382838660261133*(OAwbF^2)),
3132
3153
  SET #{snc}ECOEff = #{snc}ECOEff+(0.0000255567460240583*(OAwbF^3)),
3133
3154
  SET #{snc}TimestepEconEff = #{snc}ECOEff,
3134
- ENDIF,
3135
- ELSE,
3155
+ ENDIF,
3156
+ ELSE,
3136
3157
  SET #{snc}ECOEff = 2.36337942464462,
3137
3158
  SET #{snc}ECOEff = #{snc}ECOEff+(0-0.409939515512619*#{snc}CoolLoad),
3138
3159
  SET #{snc}ECOEff = #{snc}ECOEff+(0-0.0565205596792225*OAwbF),
3139
3160
  SET #{snc}ECOEff = #{snc}ECOEff+(0-0.0000632612294169389*(OATF^2)),
3140
3161
  SET #{snc}TimestepEconEff = #{snc}ECOEff+(0.000571724868775081*(OAwbF^2)),
3141
- ENDIF,
3162
+ ENDIF,
3142
3163
  IF #{snc}TimestepEconEff > #{snc}MaxE,
3143
3164
  SET #{snc}TimestepEconEff = #{snc}MaxE,
3144
3165
  ELSEIF #{snc}TimestepEconEff < (#{snc}OADesignMass*#{snc}OASch),
3145
3166
  SET #{snc}TimestepEconEff = (#{snc}OADesignMass*#{snc}OASch),
3146
- ENDIF,
3147
- ENDIF;
3167
+ ENDIF,
3168
+ ENDIF;
3148
3169
 
3149
3170
  EnergyManagementSystem:Program,
3150
- #{snc}SetFanPar,
3151
- IF #{snc}NumberofStages == 1,
3152
- Return,
3153
- ENDIF,
3171
+ #{snc}SetFanPar,
3172
+ IF #{snc}NumberofStages == 1,
3173
+ Return,
3174
+ ENDIF,
3154
3175
  SET #{snc}FanPwrExp = 2.2,
3155
3176
  SET #{snc}OAFrac = #{snc}OAFlowMass/#{snc}DesignFlowMass,
3156
3177
  IF #{snc}OAFrac < 0.66,
3157
3178
  SET #{snc}VenSpeed = 0.66,
3158
3179
  SET #{snc}Stg1Spd = 0.66,
3159
- ELSE,
3180
+ ELSE,
3160
3181
  SET #{snc}VenSpeed = #{snc}OAFrac,
3161
3182
  SET #{snc}Stg1Spd = #{snc}OAFrac,
3162
- ENDIF,
3183
+ ENDIF,
3163
3184
  SET #{snc}Stg2Spd = 1.0,
3164
3185
  SET #{snc}HeatSpeed = 1.0;
3165
3186
 
3166
3187
  EnergyManagementSystem:Program,
3167
- #{snc}FanControl,
3168
- IF #{snc}NumberofStages == 1,
3169
- Return,
3170
- ENDIF,
3188
+ #{snc}FanControl,
3189
+ IF #{snc}NumberofStages == 1,
3190
+ Return,
3191
+ ENDIF,
3171
3192
  IF #{snc}HeatingRTF > 0,
3172
3193
  SET #{snc}Heating = #{snc}HeatingRTF,
3173
3194
  SET #{snc}Ven = 1-#{snc}HeatingRTF,
3174
- SET #{snc}Eco = 0,
3175
- SET #{snc}Stage1 = 0,
3176
- SET #{snc}Stage2 = 0,
3177
- ELSE,
3195
+ SET #{snc}Eco = 0,
3196
+ SET #{snc}Stage1 = 0,
3197
+ SET #{snc}Stage2 = 0,
3198
+ ELSE,
3178
3199
  SET #{snc}Heating = 0,
3179
3200
  SET #{snc}EcoSpeed = #{snc}VenSpeed,
3180
3201
  IF #{snc}SpeedRatio == 0,
3181
- IF #{snc}RTF > 0,
3202
+ IF #{snc}RTF > 0,
3182
3203
  SET #{snc}Stage1 = #{snc}RTF,
3183
- SET #{snc}Stage2 = 0,
3204
+ SET #{snc}Stage2 = 0,
3184
3205
  SET #{snc}Ven = 1-#{snc}RTF,
3185
- SET #{snc}Eco = 0,
3206
+ SET #{snc}Eco = 0,
3186
3207
  IF #{snc}OAFlowMass > (#{snc}OADesignMass*#{snc}OASch),
3187
3208
  SET #{snc}Stg1Spd = 1.0,
3188
- ENDIF,
3189
- ELSE,
3190
- SET #{snc}Stage1 = 0,
3191
- SET #{snc}Stage2 = 0,
3209
+ ENDIF,
3210
+ ELSE,
3211
+ SET #{snc}Stage1 = 0,
3212
+ SET #{snc}Stage2 = 0,
3192
3213
  IF #{snc}OAFlowMass > (#{snc}OADesignMass*#{snc}OASch),
3193
- SET #{snc}Eco = 1.0,
3194
- SET #{snc}Ven = 0,
3195
- !Calculate the expected discharge air temperature if the system runs at its low speed
3214
+ SET #{snc}Eco = 1.0,
3215
+ SET #{snc}Ven = 0,
3216
+ !Calculate the expected discharge air temperature if the system runs at its low speed
3196
3217
  SET #{snc}ExpDAT = #{snc}DATRqd-(1-#{snc}VenSpeed)*#{zn_name_clean}Temp,
3197
3218
  SET #{snc}ExpDAT = #{snc}ExpDAT/#{snc}VenSpeed,
3198
3219
  IF OATF > #{snc}ExpDAT,
3199
3220
  SET #{snc}EcoSpeed = #{snc}Stg2Spd,
3200
- ENDIF,
3201
- ELSE,
3202
- SET #{snc}Eco = 0,
3203
- SET #{snc}Ven = 1.0,
3204
- ENDIF,
3205
- ENDIF,
3206
- ELSE,
3221
+ ENDIF,
3222
+ ELSE,
3223
+ SET #{snc}Eco = 0,
3224
+ SET #{snc}Ven = 1.0,
3225
+ ENDIF,
3226
+ ENDIF,
3227
+ ELSE,
3207
3228
  SET #{snc}Stage1 = 1-#{snc}SpeedRatio,
3208
3229
  SET #{snc}Stage2 = #{snc}SpeedRatio,
3209
- SET #{snc}Ven = 0,
3210
- SET #{snc}Eco = 0,
3230
+ SET #{snc}Ven = 0,
3231
+ SET #{snc}Eco = 0,
3211
3232
  IF #{snc}OAFlowMass > (#{snc}OADesignMass*#{snc}OASch),
3212
3233
  SET #{snc}Stg1Spd = 1.0,
3213
- ENDIF,
3214
- ENDIF,
3215
- ENDIF,
3234
+ ENDIF,
3235
+ ENDIF,
3236
+ ENDIF,
3216
3237
  ! For each mode, (percent time in mode)*(fanSpeer^PwrExp) is the contribution to weighted fan power over time step
3217
3238
  SET #{snc}FPR = #{snc}Ven*(#{snc}VenSpeed ^ #{snc}FanPwrExp),
3218
3239
  SET #{snc}FPR = #{snc}FPR+#{snc}Eco*(#{snc}EcoSpeed^#{snc}FanPwrExp),
@@ -3235,7 +3256,7 @@ class OpenStudio::Model::AirLoopHVAC
3235
3256
  #{snc}SetNumberofStages; !- Program Name 1
3236
3257
 
3237
3258
  EnergyManagementSystem:ProgramCallingManager,
3238
- #{snc}ECOManager,
3259
+ #{snc}ECOManager,
3239
3260
  InsideHVACSystemIterationLoop, !- EnergyPlus Model Calling Point
3240
3261
  #{snc}EconomizerCTRLProg; !- Program Name 1
3241
3262
 
@@ -3250,19 +3271,19 @@ class OpenStudio::Model::AirLoopHVAC
3250
3271
  #{snc}FanControl;
3251
3272
 
3252
3273
  "
3253
-
3274
+
3254
3275
  # Write the ems out
3255
- # File.open("#{Dir.pwd}/#{snc}_ems.idf", 'w') do |file|
3276
+ # File.open("#{Dir.pwd}/#{snc}_ems.idf", 'w') do |file|
3256
3277
  # file.puts ems
3257
3278
  # end
3258
-
3279
+
3259
3280
  return ems
3260
-
3281
+
3261
3282
  end
3262
-
3283
+
3263
3284
  # Determine if static pressure reset is required for this
3264
3285
  # system. For 90.1, this determination needs information
3265
- # about whether or not the system has DDC control over the
3286
+ # about whether or not the system has DDC control over the
3266
3287
  # VAV terminals.
3267
3288
  #
3268
3289
  # @todo Instead of requiring the input of whether a system
@@ -3276,11 +3297,11 @@ class OpenStudio::Model::AirLoopHVAC
3276
3297
  def is_static_pressure_reset_required(template, has_ddc)
3277
3298
 
3278
3299
  sp_reset_required = false
3279
-
3300
+
3280
3301
  # A big number of btu per hr as the minimum requirement
3281
3302
  infinity_btu_per_hr = 999999999999
3282
3303
  minimum_capacity_btu_per_hr = infinity_btu_per_hr
3283
-
3304
+
3284
3305
  # Determine the minimum capacity that requires an economizer
3285
3306
  case template
3286
3307
  when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004'
@@ -3295,9 +3316,9 @@ class OpenStudio::Model::AirLoopHVAC
3295
3316
  when 'NECB 2011'
3296
3317
  # static pressure reset not required
3297
3318
  end
3298
-
3319
+
3299
3320
  return sp_reset_required
3300
-
3321
+
3301
3322
  end
3302
3323
 
3303
3324
  # Determine if a system's fans must shut off when
@@ -3306,23 +3327,23 @@ class OpenStudio::Model::AirLoopHVAC
3306
3327
  # @param template [String]
3307
3328
  # @return [Bool] true if required, false if not
3308
3329
  def is_unoccupied_fan_shutoff_required(template)
3309
-
3330
+
3310
3331
  shutoff_required = true
3311
-
3332
+
3312
3333
  # Per 90.1 6.4.3.4.5, systems less than 0.75 HP
3313
3334
  # must turn off when unoccupied.
3314
3335
  minimum_fan_hp = nil
3315
3336
  case template
3316
- when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004', '90.1-2004', '90.1-2007', '90.1-2010', '90.1-2013'
3337
+ when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004', '90.1-2004', '90.1-2007', '90.1-2010', '90.1-2013', 'NECB 2011'
3317
3338
  minimum_fan_hp = 0.75
3318
3339
  end
3319
-
3340
+
3320
3341
  # Determine the system fan horsepower
3321
3342
  total_hp = 0.0
3322
3343
  self.supply_return_exhaust_relief_fans.each do |fan|
3323
3344
  total_hp += fan.motorHorsepower
3324
3345
  end
3325
-
3346
+
3326
3347
  # Check the HP exception
3327
3348
  if total_hp < minimum_fan_hp
3328
3349
  shutoff_required = false
@@ -3330,9 +3351,9 @@ class OpenStudio::Model::AirLoopHVAC
3330
3351
  end
3331
3352
 
3332
3353
  return shutoff_required
3333
-
3354
+
3334
3355
  end
3335
-
3356
+
3336
3357
  # Shut off the system during unoccupied periods.
3337
3358
  # During these times, systems will cycle on briefly
3338
3359
  # if temperature drifts below setpoint. For systems
@@ -3347,7 +3368,7 @@ class OpenStudio::Model::AirLoopHVAC
3347
3368
  # the system will be considered unoccupied.
3348
3369
  # @return [Bool] true if successful, false if not
3349
3370
  def enable_unoccupied_fan_shutoff(min_occ_pct = 0.15)
3350
-
3371
+
3351
3372
  # Set the system to night cycle
3352
3373
  night_cycle_type = 'CycleOnAny'
3353
3374
  # For VAV with PFP boxes, cycle zone fans only
@@ -3355,14 +3376,14 @@ class OpenStudio::Model::AirLoopHVAC
3355
3376
  night_cycle_type = 'CycleOnAnyZoneFansOnly'
3356
3377
  end
3357
3378
  self.setNightCycleControlType(night_cycle_type)
3358
-
3379
+
3359
3380
  # Check if already using a schedule other than always on
3360
3381
  avail_sch = self.availabilitySchedule
3361
3382
  unless avail_sch == self.model.alwaysOnDiscreteSchedule
3362
3383
  OpenStudio::logFree(OpenStudio::Info, "openstudio.standards.AirLoopHVAC", "For #{self.name}: Availability schedule is already set to #{avail_sch.name}. Will assume this includes unoccupied shut down; no changes will be made.")
3363
3384
  return true
3364
3385
  end
3365
-
3386
+
3366
3387
  # Get the airloop occupancy schedule
3367
3388
  loop_occ_sch = self.get_occupancy_schedule(min_occ_pct)
3368
3389
  flh = loop_occ_sch.annual_equivalent_full_load_hrs
@@ -3372,24 +3393,24 @@ class OpenStudio::Model::AirLoopHVAC
3372
3393
  self.setAvailabilitySchedule(loop_occ_sch)
3373
3394
 
3374
3395
  return true
3375
-
3396
+
3376
3397
  end
3377
-
3398
+
3378
3399
  # Calculate the total floor area of all zones attached
3379
3400
  # to the air loop, in m^2.
3380
3401
  #
3381
3402
  # return [Double] the total floor area of all zones attached
3382
3403
  # to the air loop, in m^2.
3383
3404
  def floor_area_served()
3384
-
3405
+
3385
3406
  total_area = 0.0
3386
-
3407
+
3387
3408
  self.thermalZones.each do |zone|
3388
3409
  total_area += zone.floorArea
3389
3410
  end
3390
3411
 
3391
3412
  return total_area
3392
-
3413
+
3393
3414
  end
3394
3415
 
3395
3416
  # Calculate the total floor area of all zones attached
@@ -3398,9 +3419,9 @@ class OpenStudio::Model::AirLoopHVAC
3398
3419
  # return [Double] the total floor area of all zones attached
3399
3420
  # to the air loop, in m^2.
3400
3421
  def floor_area_served_interior_zones()
3401
-
3422
+
3402
3423
  total_area = 0.0
3403
-
3424
+
3404
3425
  self.thermalZones.each do |zone|
3405
3426
  # Skip zones that have exterior surface area
3406
3427
  next if zone.exteriorSurfaceArea > 0
@@ -3408,18 +3429,18 @@ class OpenStudio::Model::AirLoopHVAC
3408
3429
  end
3409
3430
 
3410
3431
  return total_area
3411
-
3412
- end
3413
-
3432
+
3433
+ end
3434
+
3414
3435
  # Calculate the total floor area of all zones attached
3415
3436
  # to the air loop that have at least one exterior surface, in m^2.
3416
3437
  #
3417
3438
  # return [Double] the total floor area of all zones attached
3418
3439
  # to the air loop, in m^2.
3419
3440
  def floor_area_served_exterior_zones()
3420
-
3441
+
3421
3442
  total_area = 0.0
3422
-
3443
+
3423
3444
  self.thermalZones.each do |zone|
3424
3445
  # Skip zones that have no exterior surface area
3425
3446
  next if zone.exteriorSurfaceArea == 0
@@ -3427,7 +3448,7 @@ class OpenStudio::Model::AirLoopHVAC
3427
3448
  end
3428
3449
 
3429
3450
  return total_area
3430
-
3451
+
3431
3452
  end
3432
3453
 
3433
3454
  # find design_supply_air_flow_rate
@@ -3448,7 +3469,7 @@ class OpenStudio::Model::AirLoopHVAC
3448
3469
  return design_supply_air_flow_rate
3449
3470
 
3450
3471
  end
3451
-
3472
+
3452
3473
  # Determine how much data center
3453
3474
  # area the airloop serves.
3454
3475
  #
@@ -3459,9 +3480,9 @@ class OpenStudio::Model::AirLoopHVAC
3459
3480
  # of relying on the standards space type name to
3460
3481
  # identify a data center.
3461
3482
  def data_center_area_served()
3462
-
3483
+
3463
3484
  dc_area_m2 = 0.0
3464
-
3485
+
3465
3486
  self.thermalZones.each do |zone|
3466
3487
  zone.spaces.each do |space|
3467
3488
  # Skip spaces with no space type
@@ -3474,9 +3495,9 @@ class OpenStudio::Model::AirLoopHVAC
3474
3495
  dc_area_m2 += space.floorArea
3475
3496
  end
3476
3497
  end
3477
-
3498
+
3478
3499
  return dc_area_m2
3479
-
3500
+
3480
3501
  end
3481
-
3502
+
3482
3503
  end