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.
- checksums.yaml +4 -4
- data/data/standards/OpenStudio_Standards.xlsx +0 -0
- data/data/standards/OpenStudio_Standards_chillers.json +5 -5
- data/data/standards/OpenStudio_Standards_construction_sets.json +2 -2
- data/data/standards/OpenStudio_Standards_curve_cubics.json +12 -0
- data/data/standards/OpenStudio_Standards_heat_pumps.json +2126 -72
- data/data/standards/OpenStudio_Standards_heat_pumps_heating.json +766 -14
- data/data/standards/OpenStudio_Standards_heat_rejection.json +172 -0
- data/data/standards/OpenStudio_Standards_prototype_inputs.json +355 -267
- data/data/standards/OpenStudio_Standards_schedules.json +262 -10
- data/data/standards/OpenStudio_Standards_space_types.json +1466 -794
- data/data/standards/manage_OpenStudio_Standards.rb +19 -21
- data/data/weather/weather_info.csv +96 -0
- data/lib/openstudio-standards/btap/btap.rb +1 -1
- data/lib/openstudio-standards/btap/compliance.rb +135 -40
- data/lib/openstudio-standards/btap/envelope.rb +26 -5
- data/lib/openstudio-standards/btap/geometry.rb +11 -1
- data/lib/openstudio-standards/btap/hvac.rb +489 -56
- data/lib/openstudio-standards/btap/simmanager.rb +1 -1
- data/lib/openstudio-standards/hvac_sizing/HVACSizing.CoilHeatingDXMultiSpeed.rb +120 -0
- data/lib/openstudio-standards/hvac_sizing/Siz.CoilCoolingDXMultiSpeed.rb +151 -7
- data/lib/openstudio-standards/hvac_sizing/Siz.CoilHeatingGasMultiStage.rb +48 -7
- data/lib/openstudio-standards/hvac_sizing/Siz.Model.rb +14 -12
- data/lib/openstudio-standards/prototypes/Prototype.AirTerminalSingleDuctVAVReheat.rb +33 -7
- data/lib/openstudio-standards/prototypes/Prototype.Model.hvac.rb +123 -91
- data/lib/openstudio-standards/prototypes/Prototype.Model.rb +130 -45
- data/lib/openstudio-standards/prototypes/Prototype.Model.swh.rb +13 -7
- data/lib/openstudio-standards/prototypes/Prototype.full_service_restaurant.rb +332 -324
- data/lib/openstudio-standards/prototypes/Prototype.hospital.rb +401 -99
- data/lib/openstudio-standards/prototypes/Prototype.hvac_systems.rb +309 -222
- data/lib/openstudio-standards/prototypes/Prototype.large_hotel.rb +100 -80
- data/lib/openstudio-standards/prototypes/Prototype.large_office.rb +37 -22
- data/lib/openstudio-standards/prototypes/Prototype.medium_office.rb +68 -53
- data/lib/openstudio-standards/prototypes/Prototype.mid_rise_apartment.rb +109 -88
- data/lib/openstudio-standards/prototypes/Prototype.outpatient.rb +52 -4
- data/lib/openstudio-standards/prototypes/Prototype.primary_school.rb +230 -213
- data/lib/openstudio-standards/prototypes/Prototype.quick_service_restaurant.rb +225 -218
- data/lib/openstudio-standards/prototypes/Prototype.retail_standalone.rb +29 -17
- data/lib/openstudio-standards/prototypes/Prototype.retail_stripmall.rb +42 -32
- data/lib/openstudio-standards/prototypes/Prototype.secondary_school.rb +331 -314
- data/lib/openstudio-standards/prototypes/Prototype.small_hotel.rb +233 -219
- data/lib/openstudio-standards/prototypes/Prototype.small_office.rb +40 -32
- data/lib/openstudio-standards/prototypes/Prototype.warehouse.rb +19 -6
- data/lib/openstudio-standards/standards/Standards.AirLoopHVAC.rb +576 -555
- data/lib/openstudio-standards/standards/Standards.AirTerminalSingleDuctVAVReheat.rb +3 -1
- data/lib/openstudio-standards/standards/Standards.BoilerHotWater.rb +35 -17
- data/lib/openstudio-standards/standards/Standards.ChillerElectricEIR.rb +51 -23
- data/lib/openstudio-standards/standards/Standards.CoilCoolingDXMultiSpeed.rb +255 -0
- data/lib/openstudio-standards/standards/Standards.CoilHeatingDXMultiSpeed.rb +192 -0
- data/lib/openstudio-standards/standards/Standards.CoilHeatingGasMultiStage.rb +65 -0
- data/lib/openstudio-standards/standards/Standards.Fan.rb +37 -6
- data/lib/openstudio-standards/standards/Standards.Model.rb +28 -3
- data/lib/openstudio-standards/standards/Standards.SpaceType.rb +3 -1
- data/lib/openstudio-standards/standards/Standards.WaterHeaterMixed.rb +41 -15
- data/lib/openstudio-standards/version.rb +1 -1
- data/lib/openstudio-standards/weather/Weather.Model.rb +509 -5
- data/lib/openstudio-standards/weather/Weather.stat_file.rb +145 -5
- metadata +8 -3
- 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
|
-
|
8
|
-
|
9
|
-
|
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
|
-
|
21
|
-
|
22
|
-
|
28
|
+
'type' => 'PSZ-AC',
|
29
|
+
'name' => 'PSZ-AC-2',
|
30
|
+
'space_names' =>
|
23
31
|
[
|
24
|
-
|
25
|
-
|
32
|
+
'Perimeter_ZN_1'
|
33
|
+
]
|
26
34
|
},
|
27
35
|
{
|
28
|
-
|
29
|
-
|
30
|
-
|
36
|
+
'type' => 'PSZ-AC',
|
37
|
+
'name' => 'PSZ-AC-3',
|
38
|
+
'space_names' =>
|
31
39
|
[
|
32
|
-
|
33
|
-
|
40
|
+
'Perimeter_ZN_2'
|
41
|
+
]
|
34
42
|
},
|
35
43
|
{
|
36
|
-
|
37
|
-
|
38
|
-
|
44
|
+
'type' => 'PSZ-AC',
|
45
|
+
'name' => 'PSZ-AC-4',
|
46
|
+
'space_names' =>
|
39
47
|
[
|
40
|
-
|
41
|
-
|
48
|
+
'Perimeter_ZN_3'
|
49
|
+
]
|
42
50
|
},
|
43
51
|
{
|
44
|
-
|
45
|
-
|
46
|
-
|
52
|
+
'type' => 'PSZ-AC',
|
53
|
+
'name' => 'PSZ-AC-5',
|
54
|
+
'space_names' =>
|
47
55
|
[
|
48
|
-
|
49
|
-
|
56
|
+
'Perimeter_ZN_4'
|
57
|
+
]
|
50
58
|
},
|
51
59
|
{
|
52
|
-
|
53
|
-
|
54
|
-
|
60
|
+
'type' => 'PSZ-AC',
|
61
|
+
'name' => 'PSZ-AC-1',
|
62
|
+
'space_names' =>
|
55
63
|
[
|
56
|
-
|
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
|
-
|
8
|
-
|
9
|
-
|
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
|