openstudio-standards 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
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