honeybee-openstudio 2.31.0 → 2.31.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/honeybee-openstudio.gemspec +1 -1
- data/lib/honeybee/_defaults/model.json +21 -41
- data/lib/to_openstudio/hvac/radiant.rb +385 -11
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f9b620209ce330fea574204c6257db0a2e22f6e898de0d0b27a7d20360fd5296
|
4
|
+
data.tar.gz: 3f294beea759ed0789cd3928d023edbd4f97697c2179cb77d5e7be971d4ed0a7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dffa3a850ebe2f9b0bc03e67cba8329d1a8d7b4a4c7081cf0a751e3e423795dfb7b90028975efa92cf1d78405117b3dacd3d68e6f1e513ba93e772914ebe8475
|
7
|
+
data.tar.gz: 1b244c65a2df322052c5d522564199a0ac0e49b7dc1aadb7d6c297c24e4ed48d26d19305e3ec49caee382939ea96b7ea3f54aff3d4b02b1127d904e394b1560f
|
data/honeybee-openstudio.gemspec
CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = 'honeybee-openstudio'
|
7
|
-
spec.version = '2.31.
|
7
|
+
spec.version = '2.31.1'
|
8
8
|
spec.authors = ['Tanushree Charan', 'Dan Macumber', 'Chris Mackey', 'Mostapha Sadeghipour Roudsari']
|
9
9
|
spec.email = ['tanushree.charan@nrel.gov', 'chris@ladybug.tools']
|
10
10
|
|
@@ -3,7 +3,7 @@
|
|
3
3
|
"servers": [],
|
4
4
|
"info": {
|
5
5
|
"description": "Honeybee model schema.",
|
6
|
-
"version": "1.
|
6
|
+
"version": "1.49.0",
|
7
7
|
"title": "Honeybee Model Schema",
|
8
8
|
"contact": {
|
9
9
|
"name": "Ladybug Tools",
|
@@ -3531,10 +3531,7 @@
|
|
3531
3531
|
},
|
3532
3532
|
"story": {
|
3533
3533
|
"title": "Story",
|
3534
|
-
"description": "Text string for the story identifier to which this Room belongs. Rooms sharing the same story identifier are considered part of the same story in a Model.",
|
3535
|
-
"maxLength": 100,
|
3536
|
-
"minLength": 1,
|
3537
|
-
"pattern": "[.A-Za-z0-9_-]",
|
3534
|
+
"description": "Text string for the story identifier to which this Room belongs. Rooms sharing the same story identifier are considered part of the same story in a Model. Note that this property has no character restrictions.",
|
3538
3535
|
"type": "string"
|
3539
3536
|
}
|
3540
3537
|
},
|
@@ -8251,7 +8248,8 @@
|
|
8251
8248
|
"enum": [
|
8252
8249
|
"Floor",
|
8253
8250
|
"Ceiling",
|
8254
|
-
"FloorWithCarpet"
|
8251
|
+
"FloorWithCarpet",
|
8252
|
+
"CeilingMetalPanel"
|
8255
8253
|
],
|
8256
8254
|
"type": "string"
|
8257
8255
|
},
|
@@ -8334,14 +8332,14 @@
|
|
8334
8332
|
}
|
8335
8333
|
]
|
8336
8334
|
},
|
8337
|
-
"
|
8338
|
-
"
|
8339
|
-
"
|
8340
|
-
"
|
8341
|
-
|
8342
|
-
|
8343
|
-
|
8344
|
-
|
8335
|
+
"radiant_face_type": {
|
8336
|
+
"description": "Text to indicate which faces are thermally active by default. Note that this property has no effect when the rooms to which the HVAC system is assigned have constructions with internal source materials. In this case, those constructions will dictate the thermally active surfaces.",
|
8337
|
+
"default": "Floor",
|
8338
|
+
"allOf": [
|
8339
|
+
{
|
8340
|
+
"$ref": "#/components/schemas/RadiantFaceTypes"
|
8341
|
+
}
|
8342
|
+
]
|
8345
8343
|
},
|
8346
8344
|
"minimum_operation_time": {
|
8347
8345
|
"title": "Minimum Operation Time",
|
@@ -8358,15 +8356,6 @@
|
|
8358
8356
|
"exclusiveMinimum": 0,
|
8359
8357
|
"type": "number",
|
8360
8358
|
"format": "double"
|
8361
|
-
},
|
8362
|
-
"radiant_face_type": {
|
8363
|
-
"description": "Text to indicate which faces are thermally active by default. Note that this property has no effect when the rooms to which the HVAC system is assigned have constructions with internal source materials. In this case, those constructions will dictate the thermally active surfaces.",
|
8364
|
-
"default": "Floor",
|
8365
|
-
"allOf": [
|
8366
|
-
{
|
8367
|
-
"$ref": "#/components/schemas/RadiantFaceTypes"
|
8368
|
-
}
|
8369
|
-
]
|
8370
8359
|
}
|
8371
8360
|
},
|
8372
8361
|
"required": [
|
@@ -8977,14 +8966,14 @@
|
|
8977
8966
|
}
|
8978
8967
|
]
|
8979
8968
|
},
|
8980
|
-
"
|
8981
|
-
"
|
8982
|
-
"
|
8983
|
-
"
|
8984
|
-
|
8985
|
-
|
8986
|
-
|
8987
|
-
|
8969
|
+
"radiant_face_type": {
|
8970
|
+
"description": "Text to indicate which faces are thermally active by default. Note that this property has no effect when the rooms to which the HVAC system is assigned have constructions with internal source materials. In this case, those constructions will dictate the thermally active surfaces.",
|
8971
|
+
"default": "Floor",
|
8972
|
+
"allOf": [
|
8973
|
+
{
|
8974
|
+
"$ref": "#/components/schemas/RadiantFaceTypes"
|
8975
|
+
}
|
8976
|
+
]
|
8988
8977
|
},
|
8989
8978
|
"minimum_operation_time": {
|
8990
8979
|
"title": "Minimum Operation Time",
|
@@ -9001,15 +8990,6 @@
|
|
9001
8990
|
"exclusiveMinimum": 0,
|
9002
8991
|
"type": "number",
|
9003
8992
|
"format": "double"
|
9004
|
-
},
|
9005
|
-
"radiant_face_type": {
|
9006
|
-
"description": "Text to indicate which faces are thermally active by default. Note that this property has no effect when the rooms to which the HVAC system is assigned have constructions with internal source materials. In this case, those constructions will dictate the thermally active surfaces.",
|
9007
|
-
"default": "Floor",
|
9008
|
-
"allOf": [
|
9009
|
-
{
|
9010
|
-
"$ref": "#/components/schemas/RadiantFaceTypes"
|
9011
|
-
}
|
9012
|
-
]
|
9013
8993
|
}
|
9014
8994
|
},
|
9015
8995
|
"required": [
|
@@ -14118,7 +14098,7 @@
|
|
14118
14098
|
"version": {
|
14119
14099
|
"title": "Version",
|
14120
14100
|
"description": "Text string for the current version of the schema.",
|
14121
|
-
"default": "1.
|
14101
|
+
"default": "1.49.0",
|
14122
14102
|
"pattern": "([0-9]+)\\.([0-9]+)\\.([0-9]+)",
|
14123
14103
|
"type": "string",
|
14124
14104
|
"readOnly": true
|
@@ -54,20 +54,28 @@ class OpenStudio::Model::Model
|
|
54
54
|
case climate_zone
|
55
55
|
when '0', '1'
|
56
56
|
radiant_htg_dsgn_sup_wtr_temp_f = 90.0
|
57
|
+
cz_mult = 2
|
57
58
|
when '2', '2A', '2B'
|
58
59
|
radiant_htg_dsgn_sup_wtr_temp_f = 100.0
|
60
|
+
cz_mult = 2
|
59
61
|
when '3', '3A', '3B', '3C'
|
60
62
|
radiant_htg_dsgn_sup_wtr_temp_f = 100.0
|
63
|
+
cz_mult = 3
|
61
64
|
when '4', '4A', '4B', '4C'
|
62
65
|
radiant_htg_dsgn_sup_wtr_temp_f = 100.0
|
66
|
+
cz_mult = 4
|
63
67
|
when '5', '5A', '5B', '5C'
|
64
68
|
radiant_htg_dsgn_sup_wtr_temp_f = 110.0
|
69
|
+
cz_mult = 4
|
65
70
|
when '6', '6A', '6B'
|
66
71
|
radiant_htg_dsgn_sup_wtr_temp_f = 120.0
|
72
|
+
cz_mult = 4
|
67
73
|
when '7', '8'
|
68
74
|
radiant_htg_dsgn_sup_wtr_temp_f = 120.0
|
75
|
+
cz_mult = 5
|
69
76
|
else # unrecognized climate zone; default to climate zone 4
|
70
77
|
radiant_htg_dsgn_sup_wtr_temp_f = 100.0
|
78
|
+
cz_mult = 4
|
71
79
|
end
|
72
80
|
|
73
81
|
# create the hot water loop
|
@@ -120,11 +128,6 @@ class OpenStudio::Model::Model
|
|
120
128
|
end
|
121
129
|
|
122
130
|
# get the various controls for the radiant system
|
123
|
-
if rad_props[:proportional_gain]
|
124
|
-
proportional_gain = rad_props[:proportional_gain]
|
125
|
-
else
|
126
|
-
proportional_gain = 0.3
|
127
|
-
end
|
128
131
|
if rad_props[:minimum_operation_time]
|
129
132
|
minimum_operation = rad_props[:minimum_operation_time]
|
130
133
|
else
|
@@ -136,24 +139,34 @@ class OpenStudio::Model::Model
|
|
136
139
|
switch_over_time = 24
|
137
140
|
end
|
138
141
|
|
142
|
+
# get the start and end hour from the input zones
|
143
|
+
start_hour, end_hour = start_end_hour_from_zones_occupancy(zones)
|
144
|
+
|
139
145
|
# add radiant system to the conditioned zones
|
140
146
|
include_carpet = false
|
141
|
-
|
142
|
-
|
147
|
+
control_strategy = 'proportional_control'
|
148
|
+
if rad_props[:radiant_type]
|
149
|
+
radiant_type = rad_props[:radiant_type].downcase
|
143
150
|
if radiant_type == 'floorwithcarpet'
|
144
151
|
radiant_type = 'floor'
|
145
152
|
include_carpet = true
|
153
|
+
elsif radiant_type == 'ceilingmetalpanel'
|
154
|
+
control_strategy = 'default'
|
146
155
|
end
|
147
156
|
else
|
148
157
|
radiant_type = 'floor'
|
149
158
|
end
|
150
|
-
|
151
|
-
|
159
|
+
|
160
|
+
radiant_loops = model_add_low_temp_radiant(
|
161
|
+
std, conditioned_zones, hot_water_loop, chilled_water_loop,
|
152
162
|
radiant_type: radiant_type,
|
163
|
+
control_strategy: control_strategy,
|
153
164
|
include_carpet: include_carpet,
|
154
|
-
|
165
|
+
model_occ_hr_start: start_hour,
|
166
|
+
model_occ_hr_end: end_hour,
|
155
167
|
minimum_operation: minimum_operation,
|
156
|
-
switch_over_time: switch_over_time
|
168
|
+
switch_over_time: switch_over_time,
|
169
|
+
cz_mult: cz_mult)
|
157
170
|
|
158
171
|
# if the equipment includes a DOAS, then add it
|
159
172
|
if system_type.include? 'DOAS_'
|
@@ -161,4 +174,365 @@ class OpenStudio::Model::Model
|
|
161
174
|
end
|
162
175
|
|
163
176
|
end
|
177
|
+
|
178
|
+
# get the start and end hour from the occupancy schedules of thermal zones
|
179
|
+
def start_end_hour_from_zones_occupancy(thermal_zones, threshold: 0.1)
|
180
|
+
# set the default start and end hour in the event there's no occupancy
|
181
|
+
start_hour = 12
|
182
|
+
end_hour = 12
|
183
|
+
# loop through the occupancy schedules and get the lowest start hour; highest end hour
|
184
|
+
thermal_zones.each do |zone|
|
185
|
+
zone.spaces.each do |space|
|
186
|
+
# gather all of the people objects assigned to the sapce
|
187
|
+
peoples = []
|
188
|
+
unless space.spaceType.empty?
|
189
|
+
space_type = space.spaceType.get
|
190
|
+
unless space_type.people.empty?
|
191
|
+
space_type.people.each do |ppl|
|
192
|
+
peoples << ppl
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
space.people.each do |ppl|
|
197
|
+
peoples << ppl
|
198
|
+
end
|
199
|
+
# loop through the pople and gather all occupancy schedules
|
200
|
+
peoples.each do |people|
|
201
|
+
occupancy_sch_opt = people.numberofPeopleSchedule
|
202
|
+
unless occupancy_sch_opt.empty?
|
203
|
+
occupancy_sch = occupancy_sch_opt.get
|
204
|
+
if occupancy_sch.to_ScheduleRuleset.is_initialized
|
205
|
+
occupancy_sch = occupancy_sch.to_ScheduleRuleset.get
|
206
|
+
# gather all of the day schedules across the schedule ruleset
|
207
|
+
schedule_days, day_ids = [], []
|
208
|
+
required_days = [
|
209
|
+
occupancy_sch.defaultDaySchedule,
|
210
|
+
occupancy_sch.summerDesignDaySchedule,
|
211
|
+
occupancy_sch.winterDesignDaySchedule,
|
212
|
+
occupancy_sch.holidaySchedule
|
213
|
+
]
|
214
|
+
required_days.each do |day_sch|
|
215
|
+
unless day_ids.include? day_sch.nameString
|
216
|
+
schedule_days << day_sch
|
217
|
+
day_ids << day_sch.nameString
|
218
|
+
end
|
219
|
+
end
|
220
|
+
occupancy_sch.scheduleRules.each do |schedule_rule|
|
221
|
+
day_sch = schedule_rule.daySchedule
|
222
|
+
unless day_ids.include? day_sch.nameString
|
223
|
+
schedule_days << day_sch
|
224
|
+
day_ids << day_sch.nameString
|
225
|
+
end
|
226
|
+
end
|
227
|
+
# loop through the day schedules and see if the start and end hours should be changed
|
228
|
+
schedule_days.each do |day_sch|
|
229
|
+
time_until = [1]
|
230
|
+
day_sch.times.each do |time|
|
231
|
+
time_until << time.hours
|
232
|
+
end
|
233
|
+
final_time = time_until[-2]
|
234
|
+
day_sch.values.zip(time_until).each do |value, time|
|
235
|
+
if value > threshold
|
236
|
+
if time < start_hour
|
237
|
+
start_hour = time
|
238
|
+
end
|
239
|
+
if time > end_hour
|
240
|
+
end_hour = time
|
241
|
+
end
|
242
|
+
if time == final_time
|
243
|
+
start_hour = 1
|
244
|
+
end_hour = 24
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
# if no values were set, just set the system to be on all of the time
|
255
|
+
if start_hour == 12 or start_hour == 0
|
256
|
+
start_hour = 1
|
257
|
+
end
|
258
|
+
if end_hour == 12
|
259
|
+
end_hour = 24
|
260
|
+
end
|
261
|
+
return start_hour, end_hour
|
262
|
+
end
|
263
|
+
|
264
|
+
def model_add_low_temp_radiant(std,
|
265
|
+
thermal_zones,
|
266
|
+
hot_water_loop,
|
267
|
+
chilled_water_loop,
|
268
|
+
radiant_type: 'floor',
|
269
|
+
include_carpet: true,
|
270
|
+
carpet_thickness_in: 0.25,
|
271
|
+
model_occ_hr_start: 1.0,
|
272
|
+
model_occ_hr_end: 24.0,
|
273
|
+
control_strategy: 'proportional_control',
|
274
|
+
proportional_gain: 0.3,
|
275
|
+
minimum_operation: 1,
|
276
|
+
weekend_temperature_reset: 2,
|
277
|
+
early_reset_out_arg: 20,
|
278
|
+
switch_over_time: 24.0,
|
279
|
+
cz_mult: 4)
|
280
|
+
|
281
|
+
# create internal source constructions for surfaces
|
282
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.Model.Model', "Replacing constructions with new radiant slab constructions.")
|
283
|
+
|
284
|
+
# create materials
|
285
|
+
mat_concrete_3_5in = OpenStudio::Model::StandardOpaqueMaterial.new(self, 'MediumRough', 0.0889, 2.31, 2322, 832)
|
286
|
+
mat_concrete_3_5in.setName('Radiant Slab Concrete - 3.5 in.')
|
287
|
+
mat_concrete_1_5in = OpenStudio::Model::StandardOpaqueMaterial.new(self, 'MediumRough', 0.0381, 2.31, 2322, 832)
|
288
|
+
mat_concrete_1_5in.setName('Radiant Slab Concrete - 1.5 in')
|
289
|
+
|
290
|
+
metal_mat = OpenStudio::Model::StandardOpaqueMaterial.new(self, 'MediumSmooth', 0.003175, 30, 7680, 418)
|
291
|
+
metal_mat.setName('Radiant Metal Layer - 0.125 in')
|
292
|
+
air_gap_map = OpenStudio::Model::MasslessOpaqueMaterial.new(self, 'Smooth', 0.004572)
|
293
|
+
air_gap_map.setName('Generic Ceiling Air Gap - R 0.025')
|
294
|
+
|
295
|
+
mat_refl_roof_membrane = self.getStandardOpaqueMaterialByName('Roof Membrane - Highly Reflective')
|
296
|
+
if mat_refl_roof_membrane.is_initialized
|
297
|
+
mat_refl_roof_membrane = self.getStandardOpaqueMaterialByName('Roof Membrane - Highly Reflective').get
|
298
|
+
else
|
299
|
+
mat_refl_roof_membrane = OpenStudio::Model::StandardOpaqueMaterial.new(self, 'VeryRough', 0.0095, 0.16, 1121.29, 1460)
|
300
|
+
mat_refl_roof_membrane.setThermalAbsorptance(0.75)
|
301
|
+
mat_refl_roof_membrane.setSolarAbsorptance(0.45)
|
302
|
+
mat_refl_roof_membrane.setVisibleAbsorptance(0.7)
|
303
|
+
mat_refl_roof_membrane.setName('Roof Membrane - Highly Reflective')
|
304
|
+
end
|
305
|
+
|
306
|
+
if include_carpet
|
307
|
+
carpet_thickness_m = OpenStudio.convert(carpet_thickness_in / 12.0, 'ft', 'm').get
|
308
|
+
conductivity_si = 0.06
|
309
|
+
conductivity_ip = OpenStudio.convert(conductivity_si, 'W/m*K', 'Btu*in/hr*ft^2*R').get
|
310
|
+
r_value_ip = carpet_thickness_in * (1 / conductivity_ip)
|
311
|
+
mat_thin_carpet_tile = OpenStudio::Model::StandardOpaqueMaterial.new(self, 'MediumRough', carpet_thickness_m, conductivity_si, 288, 1380)
|
312
|
+
mat_thin_carpet_tile.setThermalAbsorptance(0.9)
|
313
|
+
mat_thin_carpet_tile.setSolarAbsorptance(0.7)
|
314
|
+
mat_thin_carpet_tile.setVisibleAbsorptance(0.8)
|
315
|
+
mat_thin_carpet_tile.setName("Radiant Slab Thin Carpet Tile R-#{r_value_ip.round(2)}")
|
316
|
+
end
|
317
|
+
|
318
|
+
# set exterior slab insulation thickness based on climate zone
|
319
|
+
slab_insulation_thickness_m = 0.0254 * cz_mult
|
320
|
+
mat_slab_insulation = OpenStudio::Model::StandardOpaqueMaterial.new(self, 'Rough', slab_insulation_thickness_m, 0.02, 56.06, 1210)
|
321
|
+
mat_slab_insulation.setName("Radiant Ground Slab Insulation - #{cz_mult} in.")
|
322
|
+
|
323
|
+
ext_insulation_thickness_m = 0.0254 * (cz_mult + 1)
|
324
|
+
mat_ext_insulation = OpenStudio::Model::StandardOpaqueMaterial.new(self, 'Rough', ext_insulation_thickness_m, 0.02, 56.06, 1210)
|
325
|
+
mat_ext_insulation.setName("Radiant Exterior Slab Insulation - #{cz_mult + 1} in.")
|
326
|
+
|
327
|
+
roof_insulation_thickness_m = 0.0254 * (cz_mult + 1) * 2
|
328
|
+
mat_roof_insulation = OpenStudio::Model::StandardOpaqueMaterial.new(self, 'Rough', roof_insulation_thickness_m, 0.02, 56.06, 1210)
|
329
|
+
mat_roof_insulation.setName("Radiant Exterior Ceiling Insulation - #{(cz_mult + 1) * 2} in.")
|
330
|
+
|
331
|
+
# create radiant internal source constructions
|
332
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.Model.Model', 'New constructions exclude the metal deck, as high thermal diffusivity materials cause errors in EnergyPlus internal source construction calculations.')
|
333
|
+
|
334
|
+
layers = []
|
335
|
+
layers << mat_slab_insulation
|
336
|
+
layers << mat_concrete_3_5in
|
337
|
+
layers << mat_concrete_1_5in
|
338
|
+
layers << mat_thin_carpet_tile if include_carpet
|
339
|
+
radiant_ground_slab_construction = OpenStudio::Model::ConstructionWithInternalSource.new(layers)
|
340
|
+
radiant_ground_slab_construction.setName('Radiant Ground Slab Construction')
|
341
|
+
radiant_ground_slab_construction.setSourcePresentAfterLayerNumber(2)
|
342
|
+
radiant_ground_slab_construction.setTemperatureCalculationRequestedAfterLayerNumber(3)
|
343
|
+
radiant_ground_slab_construction.setTubeSpacing(0.2286) # 9 inches
|
344
|
+
|
345
|
+
layers = []
|
346
|
+
layers << mat_ext_insulation
|
347
|
+
layers << mat_concrete_3_5in
|
348
|
+
layers << mat_concrete_1_5in
|
349
|
+
layers << mat_thin_carpet_tile if include_carpet
|
350
|
+
radiant_exterior_slab_construction = OpenStudio::Model::ConstructionWithInternalSource.new(layers)
|
351
|
+
radiant_exterior_slab_construction.setName('Radiant Exterior Slab Construction')
|
352
|
+
radiant_exterior_slab_construction.setSourcePresentAfterLayerNumber(2)
|
353
|
+
radiant_exterior_slab_construction.setTemperatureCalculationRequestedAfterLayerNumber(3)
|
354
|
+
radiant_exterior_slab_construction.setTubeSpacing(0.2286) # 9 inches
|
355
|
+
|
356
|
+
layers = []
|
357
|
+
layers << mat_concrete_3_5in
|
358
|
+
layers << mat_concrete_1_5in
|
359
|
+
layers << mat_thin_carpet_tile if include_carpet
|
360
|
+
radiant_interior_floor_slab_construction = OpenStudio::Model::ConstructionWithInternalSource.new(layers)
|
361
|
+
radiant_interior_floor_slab_construction.setName('Radiant Interior Floor Slab Construction')
|
362
|
+
radiant_interior_floor_slab_construction.setSourcePresentAfterLayerNumber(1)
|
363
|
+
radiant_interior_floor_slab_construction.setTemperatureCalculationRequestedAfterLayerNumber(2)
|
364
|
+
radiant_interior_floor_slab_construction.setTubeSpacing(0.2286) # 9 inches
|
365
|
+
|
366
|
+
layers = []
|
367
|
+
layers << mat_thin_carpet_tile if include_carpet
|
368
|
+
layers << mat_concrete_3_5in
|
369
|
+
layers << mat_concrete_1_5in
|
370
|
+
radiant_interior_ceiling_slab_construction = OpenStudio::Model::ConstructionWithInternalSource.new(layers)
|
371
|
+
radiant_interior_ceiling_slab_construction.setName('Radiant Interior Ceiling Slab Construction')
|
372
|
+
slab_src_loc = include_carpet ? 2 : 1
|
373
|
+
radiant_interior_ceiling_slab_construction.setSourcePresentAfterLayerNumber(slab_src_loc)
|
374
|
+
radiant_interior_ceiling_slab_construction.setTemperatureCalculationRequestedAfterLayerNumber(slab_src_loc + 1)
|
375
|
+
radiant_interior_ceiling_slab_construction.setTubeSpacing(0.2286) # 9 inches
|
376
|
+
|
377
|
+
layers = []
|
378
|
+
layers << mat_refl_roof_membrane
|
379
|
+
layers << mat_roof_insulation
|
380
|
+
layers << mat_concrete_3_5in
|
381
|
+
layers << mat_concrete_1_5in
|
382
|
+
radiant_ceiling_slab_construction = OpenStudio::Model::ConstructionWithInternalSource.new(layers)
|
383
|
+
radiant_ceiling_slab_construction.setName('Radiant Exterior Ceiling Slab Construction')
|
384
|
+
radiant_ceiling_slab_construction.setSourcePresentAfterLayerNumber(3)
|
385
|
+
radiant_ceiling_slab_construction.setTemperatureCalculationRequestedAfterLayerNumber(4)
|
386
|
+
radiant_ceiling_slab_construction.setTubeSpacing(0.2286) # 9 inches
|
387
|
+
|
388
|
+
layers = []
|
389
|
+
layers << mat_concrete_3_5in
|
390
|
+
layers << air_gap_map
|
391
|
+
layers << metal_mat
|
392
|
+
layers << metal_mat
|
393
|
+
radiant_interior_ceiling_metal_construction = OpenStudio::Model::ConstructionWithInternalSource.new(layers)
|
394
|
+
radiant_interior_ceiling_metal_construction.setName('Radiant Interior Ceiling Metal Construction')
|
395
|
+
radiant_interior_ceiling_metal_construction.setSourcePresentAfterLayerNumber(3)
|
396
|
+
radiant_interior_ceiling_metal_construction.setTemperatureCalculationRequestedAfterLayerNumber(4)
|
397
|
+
radiant_interior_ceiling_metal_construction.setTubeSpacing(0.1524) # 6 inches
|
398
|
+
|
399
|
+
layers = []
|
400
|
+
layers << mat_refl_roof_membrane
|
401
|
+
layers << mat_roof_insulation
|
402
|
+
layers << mat_concrete_3_5in
|
403
|
+
layers << air_gap_map
|
404
|
+
layers << metal_mat
|
405
|
+
layers << metal_mat
|
406
|
+
radiant_ceiling_metal_construction = OpenStudio::Model::ConstructionWithInternalSource.new(layers)
|
407
|
+
radiant_ceiling_metal_construction.setName('Radiant Ceiling Metal Construction')
|
408
|
+
radiant_ceiling_metal_construction.setSourcePresentAfterLayerNumber(5)
|
409
|
+
radiant_ceiling_metal_construction.setTemperatureCalculationRequestedAfterLayerNumber(6)
|
410
|
+
radiant_ceiling_metal_construction.setTubeSpacing(0.1524) # 6 inches
|
411
|
+
|
412
|
+
# default temperature controls for radiant system
|
413
|
+
zn_radiant_htg_dsgn_temp_f = 68.0
|
414
|
+
zn_radiant_htg_dsgn_temp_c = OpenStudio.convert(zn_radiant_htg_dsgn_temp_f, 'F', 'C').get
|
415
|
+
zn_radiant_clg_dsgn_temp_f = 74.0
|
416
|
+
zn_radiant_clg_dsgn_temp_c = OpenStudio.convert(zn_radiant_clg_dsgn_temp_f, 'F', 'C').get
|
417
|
+
|
418
|
+
htg_control_temp_sch = std.model_add_constant_schedule_ruleset(
|
419
|
+
self,
|
420
|
+
zn_radiant_htg_dsgn_temp_c,
|
421
|
+
name = "Zone Radiant Loop Heating Threshold Temperature Schedule - #{zn_radiant_htg_dsgn_temp_f.round(0)}F")
|
422
|
+
clg_control_temp_sch = std.model_add_constant_schedule_ruleset(
|
423
|
+
self,
|
424
|
+
zn_radiant_clg_dsgn_temp_c,
|
425
|
+
name = "Zone Radiant Loop Cooling Threshold Temperature Schedule - #{zn_radiant_clg_dsgn_temp_f.round(0)}F")
|
426
|
+
throttling_range_f = 4.0 # 2 degF on either side of control temperature
|
427
|
+
throttling_range_c = OpenStudio.convert(throttling_range_f, 'F', 'C').get
|
428
|
+
|
429
|
+
# make a low temperature radiant loop for each zone
|
430
|
+
radiant_loops = []
|
431
|
+
thermal_zones.each do |zone|
|
432
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.Model.Model', "Adding radiant loop for #{zone.name}.")
|
433
|
+
if zone.name.to_s.include? ':'
|
434
|
+
OpenStudio.logFree(OpenStudio::Error, 'openstudio.Model.Model', "Thermal zone '#{zone.name}' has a restricted character ':' in the name and will not work with some EMS and output reporting objects. Please rename the zone.")
|
435
|
+
end
|
436
|
+
|
437
|
+
# create radiant coils
|
438
|
+
if hot_water_loop
|
439
|
+
radiant_loop_htg_coil = OpenStudio::Model::CoilHeatingLowTempRadiantVarFlow.new(self, htg_control_temp_sch)
|
440
|
+
radiant_loop_htg_coil.setName("#{zone.name} Radiant Loop Heating Coil")
|
441
|
+
radiant_loop_htg_coil.setHeatingControlThrottlingRange(throttling_range_c)
|
442
|
+
hot_water_loop.addDemandBranchForComponent(radiant_loop_htg_coil)
|
443
|
+
else
|
444
|
+
OpenStudio.logFree(OpenStudio::Error, 'openstudio.Model.Model', 'Radiant loops require a hot water loop, but none was provided.')
|
445
|
+
end
|
446
|
+
|
447
|
+
if chilled_water_loop
|
448
|
+
radiant_loop_clg_coil = OpenStudio::Model::CoilCoolingLowTempRadiantVarFlow.new(self, clg_control_temp_sch)
|
449
|
+
radiant_loop_clg_coil.setName("#{zone.name} Radiant Loop Cooling Coil")
|
450
|
+
radiant_loop_clg_coil.setCoolingControlThrottlingRange(throttling_range_c)
|
451
|
+
chilled_water_loop.addDemandBranchForComponent(radiant_loop_clg_coil)
|
452
|
+
else
|
453
|
+
OpenStudio.logFree(OpenStudio::Error, 'openstudio.Model.Model', 'Radiant loops require a chilled water loop, but none was provided.')
|
454
|
+
end
|
455
|
+
|
456
|
+
radiant_avail_sch = self.alwaysOnDiscreteSchedule
|
457
|
+
radiant_loop = OpenStudio::Model::ZoneHVACLowTempRadiantVarFlow.new(self,
|
458
|
+
radiant_avail_sch,
|
459
|
+
radiant_loop_htg_coil,
|
460
|
+
radiant_loop_clg_coil)
|
461
|
+
|
462
|
+
# assign internal source construction to floors in zone
|
463
|
+
zone.spaces.each do |space|
|
464
|
+
space.surfaces.each do |surface|
|
465
|
+
if radiant_type == 'floor'
|
466
|
+
if surface.surfaceType == 'Floor'
|
467
|
+
if surface.outsideBoundaryCondition == 'Ground'
|
468
|
+
surface.setConstruction(radiant_ground_slab_construction)
|
469
|
+
elsif surface.outsideBoundaryCondition == 'Outdoors'
|
470
|
+
surface.setConstruction(radiant_exterior_slab_construction)
|
471
|
+
else # interior floor
|
472
|
+
surface.setConstruction(radiant_interior_floor_slab_construction)
|
473
|
+
end
|
474
|
+
end
|
475
|
+
elsif radiant_type == 'ceiling'
|
476
|
+
if surface.surfaceType == 'RoofCeiling'
|
477
|
+
if surface.outsideBoundaryCondition == 'Outdoors'
|
478
|
+
surface.setConstruction(radiant_ceiling_slab_construction)
|
479
|
+
else # interior ceiling
|
480
|
+
surface.setConstruction(radiant_interior_ceiling_slab_construction)
|
481
|
+
end
|
482
|
+
end
|
483
|
+
elsif radiant_type == 'ceilingmetalpanel'
|
484
|
+
if surface.surfaceType == 'RoofCeiling'
|
485
|
+
if surface.outsideBoundaryCondition == 'Outdoors'
|
486
|
+
surface.setConstruction(radiant_ceiling_metal_construction)
|
487
|
+
else # interior ceiling
|
488
|
+
surface.setConstruction(radiant_interior_ceiling_metal_construction)
|
489
|
+
end
|
490
|
+
end
|
491
|
+
end
|
492
|
+
end
|
493
|
+
end
|
494
|
+
|
495
|
+
# radiant loop surfaces
|
496
|
+
radiant_loop.setName("#{zone.name} Radiant Loop")
|
497
|
+
if radiant_type == 'floor'
|
498
|
+
radiant_loop.setRadiantSurfaceType('Floors')
|
499
|
+
elsif radiant_type == 'ceiling'
|
500
|
+
radiant_loop.setRadiantSurfaceType('Ceilings')
|
501
|
+
elsif radiant_type == 'ceilingmetalpanel'
|
502
|
+
radiant_loop.setRadiantSurfaceType('Ceilings')
|
503
|
+
end
|
504
|
+
|
505
|
+
# radiant loop layout details
|
506
|
+
radiant_loop.setHydronicTubingInsideDiameter(0.015875) # 5/8 in. ID, 3/4 in. OD
|
507
|
+
# @todo include a method to determine tubing length in the zone
|
508
|
+
# loop_length = 7*zone.floorArea
|
509
|
+
# radiant_loop.setHydronicTubingLength()
|
510
|
+
radiant_loop.setNumberofCircuits('CalculateFromCircuitLength')
|
511
|
+
radiant_loop.setCircuitLength(106.7)
|
512
|
+
|
513
|
+
# radiant loop controls
|
514
|
+
radiant_loop.setTemperatureControlType('MeanAirTemperature')
|
515
|
+
radiant_loop.addToThermalZone(zone)
|
516
|
+
radiant_loops << radiant_loop
|
517
|
+
|
518
|
+
# rename nodes before adding EMS code
|
519
|
+
std.rename_plant_loop_nodes(self)
|
520
|
+
|
521
|
+
# set radiant loop controls
|
522
|
+
if control_strategy == 'proportional_control'
|
523
|
+
std.model_add_radiant_proportional_controls(self, zone, radiant_loop,
|
524
|
+
radiant_type: radiant_type,
|
525
|
+
model_occ_hr_start: model_occ_hr_start,
|
526
|
+
model_occ_hr_end: model_occ_hr_end,
|
527
|
+
proportional_gain: proportional_gain,
|
528
|
+
minimum_operation: minimum_operation,
|
529
|
+
weekend_temperature_reset: weekend_temperature_reset,
|
530
|
+
early_reset_out_arg: early_reset_out_arg,
|
531
|
+
switch_over_time: switch_over_time)
|
532
|
+
end
|
533
|
+
end
|
534
|
+
|
535
|
+
return radiant_loops
|
536
|
+
end
|
537
|
+
|
164
538
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: honeybee-openstudio
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.31.
|
4
|
+
version: 2.31.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tanushree Charan
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: exe
|
13
13
|
cert_chain: []
|
14
|
-
date: 2022-03-
|
14
|
+
date: 2022-03-27 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: bundler
|